Computing with Complex Numbers

Python handles computation with relative ease. Python uses "j" for the imaginary number.

In [1]:
%pylab inline
Populating the interactive namespace from numpy and matplotlib

In [2]:
z1 = 1+2j
z1
Out[2]:
(1+2j)
In [3]:
z2 = 3-3j 
In [4]:
z1+z1, z1-z2
Out[4]:
((2+4j), (-2+5j))
In [5]:
z1*z2, z1/z2
Out[5]:
((9+3j), (-0.16666666666666666+0.5j))
In [6]:
abs(z1), angle(z1)
Out[6]:
(2.23606797749979, 1.1071487177940904)
In [7]:
abs(z1*z2)-abs(z1)*abs(z2)
Out[7]:
0.0
In [8]:
angle(z1*z2) - angle(z1) - angle(z2)
Out[8]:
0.0

Dividing and inverses

In [9]:
w = 1/z1
z1*w, angle(w)+angle(z1), angle(z1*w)
Out[9]:
((1+0j), 0.0, 0.0)
In [10]:
z1*conj(z1)-abs(z1)**2
Out[10]:
(-8.8817841970012523e-16+0j)

Euler's Formula

Euler's formula says \[\exp(\theta) = \cos(\theta) + j\sin(\theta)\].

If we put in a general complex number, we get the following: \[\exp(x+jy) = \exp(x)(\cos(y)+j\sin(y))\]

In [11]:
exp(z1)
Out[11]:
(-1.1312043837568135+2.4717266720048188j)
In [12]:
real(exp(z1)), imag(exp(z1))
Out[12]:
(array(-1.1312043837568135), array(2.4717266720048188))
In [13]:
exp(z1).real, exp(z1).imag
Out[13]:
(-1.1312043837568135, 2.4717266720048188)
In [14]:
x,y = z1.real, z1.imag
exp(z1) - exp(x)*(cos(y)+1j*sin(y))
Out[14]:
0j

Plotting Complex Numbers

In [15]:
z = 1+1j*sqrt(3)
a = array([z,1/z,conj(z),conj(1/z)])

#plot unit circle
t = linspace(0,2*pi,101)
plot(cos(t),sin(t))

#plot data
plot(a.real, a.imag,'ro')

#make box bigger
axes().set_aspect('equal')
m = max(max(abs(a.real)),max(abs(a.imag)))
xlim(-1.1*m,1.1*m),ylim(-1.1*m,1.1*m)

#draw horizontal and vertical axes
plot([0,0],[-1.1*m,1.1*m],'k',linewidth=0.5)
plot([-1.1*m,1.1*m],[0,0],'k',linewidth=0.5)

#annotate plot with labels
text(z.real+0.1, z.imag,'$z$',fontsize=15)
text((1/z).real+0.1, (1/z).imag, '$1/z$', fontsize=15)
text(conj(z).real+0.1, conj(z).imag, '$z^*$',fontsize=15)
text(conj(1/z).real+0.1, conj(1/z).imag, '$1/z^*$',fontsize=15)
Out[15]:
<matplotlib.text.Text at 0x10576d940>

Polynomials and Complex Roots

We could use functions in the numpy.polynomial library, but will use functions in the signal processing library instead. We need the signal library for other things, so let's start here.

In [16]:
import scipy.signal as sig

\(b\) below is our polynomial coefficients. In this case, \(b(x) = x^2 + 3x+2\).

In [17]:
b = array([1,3,2])

Square b(x).

In [18]:
convolve(b,b)
Out[18]:
array([ 1,  6, 13, 12,  4])

The zeros of this polynomial are -2 and -1. z below is a list of the zeros.

In [19]:
a = [1]
z, p, k = sig.tf2zpk(b,a)
z, p, k
Out[19]:
(array([-2., -1.]), array([], dtype=float64), 1.0)

We can invert the representation: given the zeros, compute the polynomial in the conventional monomial representation.

In [20]:
astar, bstar = sig.zpk2tf(z,p,k)
astar, bstar
Out[20]:
(array([ 1.,  3.,  2.]), array([ 1.]))

Ok, we've demonstrated how to factor polynomials. Now look at what happens when the zeros are complex.

In [21]:
b = array([1,0,1])
z,p,k = sig.tf2zpk(b,a)
z,p,k
Out[21]:
(array([-0.+1.j,  0.-1.j]), array([], dtype=float64), 1.0)
In [22]:
sig.zpk2tf(z,p,k)
Out[22]:
(array([ 1.,  0.,  1.]), array([ 1.]))
In [22]: