Learning how to use complex numbers with python

Learning how to use complex numbers with python

I've recntly appreciated that complex numbers are not just for mathematicians, but have have far reaching applications in applied physics and engineering. I am interested in using complex numbers for dynamics work, as well as vectors, but find them fasinating. Euler's Idendity is my favorite equation and I feel an obligation to understand it better.

eulers identity

$$ {e^{i \pi}} + 1 = 0 $$

How can something so seemingly simple be so powerful? Lets take a look.

Python has a built in complex math library, but I am just going to use numpy.

In [1]:
# numpy library
import numpy as np
import matplotlib.pyplot as pl

Lets define 2 real numbers

In [2]:
x = 2
y = 4

and we can define a single, new number, but it is complex, python uses j to indicate the imaginary number

In [3]:
z = complex(x,y)
z
Out[3]:
(2+4j)

Here is another way to define a complex number that is slightly less verbose, but a little more cryptic

In [4]:
z = x + y*1j
z
Out[4]:
(2+4j)

to view the real and imaginary parts, use the attributes

In [5]:
z.real
Out[5]:
2.0
In [6]:
z.imag
Out[6]:
4.0

To find the magnitude, or modulus of the complex number you can use

In [7]:
zmag = np.sqrt( z.real**2 + z.imag**2 )
zmag
Out[7]:
4.47213595499958

or

In [8]:
zmag = np.abs(z)
zmag
Out[8]:
4.47213595499958

or using the conjugate property

In [9]:
zmag = np.sqrt(z * z.conjugate() )
zmag
Out[9]:
(4.47213595499958+0j)

to get angle information of our vectors, we can use the phase() method

In [10]:
zang = np.angle(z)
zang, np.rad2deg(zang)
Out[10]:
(1.1071487177940904, 63.43494882292201)

and if you still can't let go of trig yet, here is a check to confirm the angle

In [11]:
np.arctan(4/2)
Out[11]:
1.1071487177940904

so our vector is about 63 deg, that looks about right

In [12]:
pl.plot([0, z.real], [0, z.imag],'-o')
pl.title('Our complex number')
pl.xlabel('Re')
pl.ylabel('Im')
pl.xlim([-5, 5])
pl.ylim([-5, 5])
Out[12]:
(-5.0, 5.0)

the complex conjugate sounds scary, but simply reverses the sign which flips the vertical, imginary axis

In [13]:
zc = z.conjugate()
zc
Out[13]:
(2-4j)
In [14]:
pl.plot([0, z.real], [0, z.imag],'-o', label= 'first complex number')
pl.plot([0, zc.real], [0, zc.imag],'-o', label='conjugate')
pl.xlim([-5, 5])
pl.ylim([-5, 5])
pl.title('complex number with complex conjugate')
pl.xlabel('Re')
pl.ylabel('Im')
pl.legend()
Out[14]:
<matplotlib.legend.Legend at 0x1ff145c5bb0>

another amazing property of complex numbers is the ease of rotating vectors. This can be acomplished by multiplying by j for 90 deg, pi/2 rotation

In [15]:
zr = z * 1j
zr
Out[15]:
(-4+2j)
In [16]:
pl.plot([0, zr.real], [0, zr.imag],'-o')
pl.title('complex number rotated by j, or pi/2')
pl.xlabel('Re')
pl.ylabel('Im')
pl.xlim([-5, 5])
pl.ylim([-5, 5])
Out[16]:
(-5.0, 5.0)

Arrays of complex numbers are just as easy to handle. Let's create an numpy array of complex numbers, inspect the properties, and plot them

In [17]:
# numpy complex
a = np.array([1+2j, 3+4j, 4.7+2j])
a
Out[17]:
array([1. +2.j, 3. +4.j, 4.7+2.j])
In [18]:
a.imag, a.real
Out[18]:
(array([2., 4., 2.]), array([1. , 3. , 4.7]))
In [19]:
np.angle(a)
Out[19]:
array([1.10714872, 0.92729522, 0.4023211 ])
In [20]:
np.conjugate(a)
Out[20]:
array([1. -2.j, 3. -4.j, 4.7-2.j])
In [21]:
np.abs(a)
Out[21]:
array([2.23606798, 5.        , 5.10783712])
In [22]:
for z in a:
    pl.plot([0, z.real], [0, z.imag],'-o')
    pl.plot([0, zc.real], [0, zc.imag],'-o')
    pl.xlim([-5, 5])
    pl.ylim([-5, 5])
    pl.title('array of complex numbers plotted')
    pl.xlabel('Re')
    pl.ylabel('Im')

And finally, I think the most incredible part of eulers equation is the ability to represent oscillations, or sinusoidal functions. Let's create an array of 24 numbers from 0-2pi and from that, using euler's idendity, create 24 complex numbers and see what happens

In [23]:
n = 24
narr = np.linspace(0, 2*np.pi, n+1)
narr, np.rad2deg(narr)
Out[23]:
(array([0.        , 0.26179939, 0.52359878, 0.78539816, 1.04719755,
        1.30899694, 1.57079633, 1.83259571, 2.0943951 , 2.35619449,
        2.61799388, 2.87979327, 3.14159265, 3.40339204, 3.66519143,
        3.92699082, 4.1887902 , 4.45058959, 4.71238898, 4.97418837,
        5.23598776, 5.49778714, 5.75958653, 6.02138592, 6.28318531]),
 array([  0.,  15.,  30.,  45.,  60.,  75.,  90., 105., 120., 135., 150.,
        165., 180., 195., 210., 225., 240., 255., 270., 285., 300., 315.,
        330., 345., 360.]))
In [24]:
w = np.e ** ( narr *  1j )
w
Out[24]:
array([ 1.00000000e+00+0.00000000e+00j,  9.65925826e-01+2.58819045e-01j,
        8.66025404e-01+5.00000000e-01j,  7.07106781e-01+7.07106781e-01j,
        5.00000000e-01+8.66025404e-01j,  2.58819045e-01+9.65925826e-01j,
        6.12323400e-17+1.00000000e+00j, -2.58819045e-01+9.65925826e-01j,
       -5.00000000e-01+8.66025404e-01j, -7.07106781e-01+7.07106781e-01j,
       -8.66025404e-01+5.00000000e-01j, -9.65925826e-01+2.58819045e-01j,
       -1.00000000e+00+1.22464680e-16j, -9.65925826e-01-2.58819045e-01j,
       -8.66025404e-01-5.00000000e-01j, -7.07106781e-01-7.07106781e-01j,
       -5.00000000e-01-8.66025404e-01j, -2.58819045e-01-9.65925826e-01j,
       -1.83697020e-16-1.00000000e+00j,  2.58819045e-01-9.65925826e-01j,
        5.00000000e-01-8.66025404e-01j,  7.07106781e-01-7.07106781e-01j,
        8.66025404e-01-5.00000000e-01j,  9.65925826e-01-2.58819045e-01j,
        1.00000000e+00-2.44929360e-16j])

PLotting the real and imaginary part reveals the beauty of the equation. We can easily create sinusoidal motion with this equation!

In [25]:
pl.plot(w.real, '-o', label='Re')
pl.plot(w.imag, '-o', label='Im')
pl.legend()
pl.title('eulers idenity components')
Out[25]:
Text(0.5, 1.0, 'eulers idenity components')
In [26]:
pl.plot(w.real, w.imag, '-o')
pl.xlabel('Re')
pl.ylabel('Im')
#pl.title(r'plotting $ \frac{ {e^{k2\pi i}} }{{n}}$a for n=30 and k=[0,n]',fontsize=20)
pl.title(r'plotting $e^{kj}$ for n=24 and k=[0,2$\pi$]',fontsize=18)
Out[26]:
Text(0.5, 1.0, 'plotting $e^{kj}$ for n=24 and k=[0,2$\\pi$]')

of course, this is evident from the complete idendity which has a cos() as the horizontal and the vertical is a sin()

$$ {e^{kj}} = cos(k) + j*sin(k) $$

Thanks for reading and stay curious!

In [27]:
## bonus, simple way to export your notebook to html
# !jupyter nbconvert "complex math notes with python.ipynb" --to html

Comments

Comments powered by Disqus