# fourier_demo.py

## Complex numbers and the Fourier transform

Original code here.

### Complex numbers

#### Complex numbers in Python

creating complex numbers

`a = 2 + 1j`

`(2+1j)`

`print(a)`

`<class 'complex'>`

`print(type(a))`

`b = 2 - 3j`

`(4-2j)`

`print(a + b)`

accessing real and imaginary parts
`2.0`

`print(a.real)`

`1.0`

`print(a.imag)`

magnitude of a complex number
`2.23606797749979`

`print(abs(a))`

`cmath`---standard Python library for complex numbers

`import cmath`

phase of a complex number (measured in radians)
`0.4636476090008061`

`print(cmath.phase(a))`

Alternatively, convert complex numbers from rectangular to polar coordinates.

`mag, angle = cmath.polar(a)`

`(2+1j): magnitude = 2.23606797749979, angle = 0.4636476090008061`

`print('magnitude = {}, angle = {}'.format(mag, angle))`

Or convert from polar to rectangular coordinates
`(2+1j)`

`print(cmath.rect(mag, angle))`

Multiplying complex numbers ...
`(7-4j)`

`print(a * b)`

... is the same as multiplying the magnitudes and adding the phases

```mag2 = abs(a) * abs(b)
angle2 = cmath.phase(a) + cmath.phase(b)```

`(6.999999999999999-4j)`

`print(cmath.rect(mag2, angle2))`

#### Complex numbers in Numpy

`import numpy as np`

creating complex numpy arrays

`c = np.array([1 + 2j, 3 + 1j, 4 - 5j], dtype=complex)`

`[ 1.+2.j 3.+1.j 4.-5.j]`

`print(c)`

complex zeros

`z = np.zeros(3, dtype=complex)`

`[ 0.+0.j 0.+0.j 0.+0.j]`

`print(z)`

complex random numbers

```import random
r = random.random() + random.random() * 1j```

`(0.6589664597814023+0.23948971180747303j)` as one possible result

`print(r)`

magnitudes of a complex array
`[ 2.23606798 3.16227766 6.40312424]`

`print(np.absolute(c))`

phases of a complex array
`[ 1.10714872 0.32175055 -0.89605538]`

`print(np.angle(c))`

### Fast Fourier Transform (FFT) in Numpy

Indicator (or characterstic) function of a diminished seventh chord

`P = [1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0]`

FFT of the indicator function

`F_P = np.fft.fft(P)`

`[ 4.00000000e+00 +0.00000000e+00j -8.26946080e-16 +7.77156117e-16j`
`0.00000000e+00 +7.65713740e-16j 0.00000000e+00 +0.00000000e+00j`
`4.00000000e+00 -1.60410220e-15j -1.76491446e-15 +1.66533454e-15j`
`0.00000000e+00 +0.00000000e+00j -6.12323400e-17 -1.11022302e-16j`
`4.00000000e+00 -3.20820439e-15j 0.00000000e+00 +0.00000000e+00j`
`0.00000000e+00 +9.37968382e-16j 8.76736042e-16 +7.77156117e-16j]`

`print(F_P)`

Most of the values are 0 with miniscule floating-point errors. You can use the numpy `round` function to round numpy array values (including complex values) to a specified number of decimals.
`[ 4.+0.j -0.+0.j 0.+0.j 0.+0.j 4.-0.j -0.+0.j 0.+0.j -0.-0.j 4.-0.j` `0.+0.j 0.+0.j 0.+0.j]`

```print(np.round(F_P, 6))

```