Search code examples
pythonnumpyjupytersympycomplex-numbers

How can I obtain the real or the imaginary part of a complex exponential function in Python


I am using Jupyter in particular. e.g from the equation e2+j, how can I seperate it in it's real part (e2) and into it's imaginary (ej)? I have tried: exp(complex(2,1)).real However the error that follows it is: 'Mul' object has no attribute 'real'. An other solution might be to implement the eulers formula to seperate it as cos(2)+j­·sin(1) but no success so far. Generally the problem is when complex numbers appear in power position rather than in usual format (2+j). If someone has any idea upon this matter would be greatly appreciated!

Important edit that fits more in my problem:

In my case the complex equation that i have, came through the dsolve() for a 2nd order differential equation. For the exp() element that exist in nympy this is a valid solution, it's not the same as an arbitary equation. However my equation is just a the above one regarding it's complexity

I include my code:

import scipy as sp
from sympy import*
import sympy as syp
from scipy.integrate import odeint

t, z, w, C2=symbols('t, z, w, C2')
x=Function('x')
eq=x(t).diff(t,2)+2*z*w*x(t).diff(t,1)+w**2*x(t)
sol=dsolve(eq,x(t),ics={x(0):0,x(t).diff(t,1).subs(t,0):2*C2*w*sqrt(z**2-1)})

next I want to substitute the z,w parameters in order to fit my data and then with a loop to make an array that takes the numerical solutions in order to plot them. I've tried the following:

for i in range(1000):
    step.append(i)
numdata=[]
for i in range(1000):
    numdata.append(N(sol.rhs.subs(t,i).subs(w,10).subs(z,0.001)))

However this can't work as the sol is an complex function. After this long journey I try to find (meaning of my life) ways to seperate the real and imaginary parts of this kind of function. Thank you for being with me so far, you are a hero reagrdless of the result.


Solution

  • sympy has re and im functions:

    In [113]: exp(complex(2,1))                                                                          
    Out[113]: 
                      1.0⋅ⅈ
    7.38905609893065⋅ℯ     
    
    In [114]: re(exp(complex(2,1)))                                                                      
    Out[114]: 3.99232404844127
    
    In [115]: im(exp(complex(2,1)))                                                                      
    Out[115]: 6.21767631236797
    
    In [116]: exp(complex(2,1)).evalf()                                                                  
    Out[116]: 3.99232404844127 + 6.21767631236797⋅ⅈ
    

    .real and .imag are attributes (possibly implemented as properties) of numpy arrays (and complex python numbers).

    Exploring sympy a bit more:

    In [152]: expand(exp(y),complex=True)                                                                
    Out[152]: 
       re(y)               re(y)           
    ⅈ⋅ℯ     ⋅sin(im(y)) + ℯ     ⋅cos(im(y))
    
    In [153]: expand(exp(complex(2,1)),complex=True)                                                     
    Out[153]: 3.99232404844127 + 6.21767631236797⋅ⅈ
    

    Your sol:

    In [157]: sol                                                                                        
    Out[157]: 
                     ⎛        ________⎞           ⎛        ________⎞
                     ⎜       ╱  2     ⎟           ⎜       ╱  2     ⎟
                 t⋅w⋅⎝-z - ╲╱  z  - 1 ⎠       t⋅w⋅⎝-z + ╲╱  z  - 1 ⎠
    x(t) = - C₂⋅ℯ                       + C₂⋅ℯ                      
    
    In [181]: f1 = sol.rhs.subs({w:10, z:0.001,C2:1})                                                    
    
    In [182]: f1                                                                                         
    Out[182]: 
       10⋅t⋅(-0.001 - 0.999999499999875⋅ⅈ)    10⋅t⋅(-0.001 + 0.999999499999875⋅ⅈ)
    - ℯ                                    + ℯ                                   
    

    Making a numpy compatible function:

    In [187]: f = lambdify(t, f1)                                                                        
    
    In [188]: print(f.__doc__)                                                                           
    Created with lambdify. Signature:
    
    func(t)
    
    Expression:
    
    -exp(10*t*(-0.001 - 0.999999499999875*I)) + exp(10*t*(-0.001 +...
    
    Source code:
    
    def _lambdifygenerated(t):
        return (-exp(10*t*(-0.001 - 0.999999499999875*1j)) + exp(10*t*(-0.001 + 0.999999499999875*1j)))
    
    
    Imported modules:
    

    evaluate it at a range of values:

    In [189]: f(np.arange(10))                                                                           
    Out[189]: 
    array([0.+0.j        , 0.-1.07720771j, 0.+1.78972745j, 0.-1.91766624j,
           0.+1.43181934j, 0.-0.49920326j, 0.-0.57406585j, 0.+1.44310044j,
           0.-1.83494157j, 0.+1.63413971j])
    

    same values with just sympy:

    In [199]: [im(f1.evalf(subs={t:i})) for i in range(10)]                                              
    Out[199]: 
    [0, -1.0772077135423, 1.78972744700845, -1.9176662437755, 1.43181934232583, -0.499203257243971, -0.
    574065847629935, 1.44310044143674, -1.83494157235822, 1.63413971490123]