Fourier Transforms
Fourier Transforms
June 6, 2024
In [3]: sr = 100.0
ts = 1.0/sr
t = np.arange(0,1,ts)
freq = 1.
x = 3*np.sin(2*np.pi*freq*t)
freq = 4
x += np.sin(2*np.pi*freq*t)
freq = 7
x += 0.5* np.sin(2*np.pi*freq*t)
def DFT(x):
N = len(x)
n = np.arange(N)
k = n.reshape(N, 1)
e = np.exp(-2j * np.pi * k * n / N)
X = np.dot(e, x)
return X
X = DFT(x)
N = len(X)
n = np.arange(N)
1
T = N/sr
freq = n/T
plt.figure(figsize = (8, 6))
plt.stem(freq, abs(X), "b", markerfmt=" ", basefmt="-b")
plt.xlabel("Freq (Hz)")
plt.ylabel("DFT Amplitude |X(freq)|")
plt.show()
In [4]: freq = 1.
x = 3*np.sin(2*np.pi*freq*t)
freq = 4
x += np.sin(2*np.pi*freq*t)
freq = 7
x += 0.5* np.sin(2*np.pi*freq*t)
2
[ 0.00000000e+00 6.49951092e-01 1.24301000e+00 1.73098263e+00
2.08154121e+00 2.28261600e+00 2.34327722e+00 2.29102039e+00
2.16602580e+00 2.01350931e+00 1.87561275e+00 1.78433917e+00
1.75681059e+00 1.79365925e+00 1.88074856e+00 1.99377423e+00
2.10474409e+00 2.18898123e+00 2.23120727e+00 2.22945607e+00
2.19600566e+00 2.15511222e+00 2.13796970e+00 2.17587843e+00
2.29297677e+00 2.50000000e+00 2.79035655e+00 3.13938578e+00
3.50706391e+00 3.84376807e+00 4.09811869e+00 4.22550953e+00
4.19578177e+00 3.99863534e+00 3.64577057e+00 3.16934473e+00
2.61699766e+00 2.04432572e+00 1.50614412e+00 1.04809007e+00
7.00042246e-01 4.72482828e-01 3.56371693e-01 3.26445884e-01
3.47223767e-01 3.80502964e-01 3.92885361e-01 3.61888418e-01
2.79502648e-01 1.52571317e-01 3.06161700e-16 -1.52571317e-01
-2.79502648e-01 -3.61888418e-01 -3.92885361e-01 -3.80502964e-01
-3.47223767e-01 -3.26445884e-01 -3.56371693e-01 -4.72482828e-01
-7.00042246e-01 -1.04809007e+00 -1.50614412e+00 -2.04432572e+00
-2.61699766e+00 -3.16934473e+00 -3.64577057e+00 -3.99863534e+00
-4.19578177e+00 -4.22550953e+00 -4.09811869e+00 -3.84376807e+00
-3.50706391e+00 -3.13938578e+00 -2.79035655e+00 -2.50000000e+00
-2.29297677e+00 -2.17587843e+00 -2.13796970e+00 -2.15511222e+00
-2.19600566e+00 -2.22945607e+00 -2.23120727e+00 -2.18898123e+00
-2.10474409e+00 -1.99377423e+00 -1.88074856e+00 -1.79365925e+00
-1.75681059e+00 -1.78433917e+00 -1.87561275e+00 -2.01350931e+00
-2.16602580e+00 -2.29102039e+00 -2.34327722e+00 -2.28261600e+00
-2.08154121e+00 -1.73098263e+00 -1.24301000e+00 -6.49951092e-01]
In [7]: X = DFT(x)
# calculate the frequency
N = len(X)
n = np.arange(N)
T = N/sr
print("the value of T is: ",T)
freq = n/T
plt.figure(figsize = (8, 6))
3
plt.stem(freq, abs(X), "b", markerfmt=" ", basefmt="-b")
plt.xlabel("Freq (Hz)")
plt.ylabel("DFT Amplitude |X(freq)|")
plt.show()
In [ ]: n_oneside = N//2
# get the one side frequency
f_oneside = freq[:n_oneside]
# normalize the amplitude
X_oneside =X[:n_oneside]/n_oneside
plt.figure(figsize = (12, 6))
plt.subplot(121)
plt.stem(f_oneside, abs(X_oneside), "b", markerfmt=" ", basefmt="-b")
plt.xlabel("Freq (Hz)")
plt.ylabel("DFT Amplitude |X(freq)|")
plt.subplot(122)
plt.stem(f_oneside, abs(X_oneside), "b", markerfmt=" ", basefmt="-b")
plt.xlabel("Freq (Hz)")
4
plt.xlim(0, 10)
plt.tight_layout()
plt.show()
[-1.37667655e-14+0.00000000e+00j -1.36313052e-14-1.50000000e+02j
2.25440429e-14+1.04743232e-14j -1.61609726e-14+7.20914309e-15j
-4.53405371e-14-5.00000000e+01j -1.26558963e-14-3.78790318e-15j
1.05357830e-14-1.71572004e-15j 1.93281229e-14-2.50000000e+01j
1.15899682e-14-3.59790266e-14j -2.12861338e-14+7.19502279e-15j
1.77121157e-14+3.52493083e-15j -1.32959968e-14+2.98753109e-14j
-2.77039445e-14+1.27860910e-14j -5.91343476e-14-5.19418237e-14j
-2.40408701e-14-1.94515350e-14j 3.94428298e-14-8.91983966e-15j
2.96515218e-14-1.13687270e-14j 1.43660736e-13+1.30067597e-13j
4.92303027e-14-8.14017890e-14j 2.57484215e-14-1.22350955e-13j
-1.28073177e-13-2.92548660e-14j -2.67955631e-14-8.92824634e-14j
3.80052003e-14-1.76086427e-14j 4.14320011e-14+6.85421309e-14j
-1.37518001e-14+3.67234063e-14j 7.72582802e-14+6.44010731e-15j
1.55207218e-13-1.27198308e-16j 1.15562868e-13-8.37436003e-14j
2.12897571e-14-3.24967810e-14j 3.17414107e-14+1.59037202e-13j
1.14623282e-13+5.12476281e-14j -5.07904388e-15+1.53242121e-13j
-2.09946831e-13+1.56739986e-14j 4.14427806e-14+4.61058526e-14j
-6.72160801e-15-3.96464670e-14j -1.23435136e-13-4.09817497e-13j
5
1.21038840e-13+1.01552278e-13j 7.08691550e-14+9.68297358e-14j
-3.35261778e-13-6.88793394e-14j -8.94166019e-14+5.41631485e-14j
-3.13325854e-14-1.07774816e-14j 1.63603410e-13-1.53435539e-14j
-1.33994646e-13+1.24048870e-14j -1.78264251e-13+1.29674049e-13j
1.07655451e-14-6.32297131e-14j -7.52730732e-15-1.26257290e-13j
2.40113567e-13-9.23705556e-14j -4.88312807e-13+5.78485471e-13j
-6.05033392e-14+5.75512708e-14j -6.80016339e-14+1.42108547e-14j
-2.97539771e-14+6.18945917e-14j 4.62374277e-14-1.42108547e-13j
-4.25174684e-13+3.23391700e-13j 2.74661917e-14-9.81325795e-14j
-1.45116905e-14+1.10134124e-13j -1.56380676e-14+1.37538743e-13j
2.89985931e-14+9.07698523e-14j -2.59585923e-13+1.95399252e-13j
1.93434729e-14-2.54042364e-13j -6.49195424e-14+8.09796049e-14j
2.25428830e-13+1.17133480e-13j 9.17262677e-14-1.05033437e-13j
5.40081303e-13-8.73193476e-14j 3.18097883e-14+3.78513168e-13j
5.56987753e-13+4.31108732e-14j 2.77059866e-13-5.00015920e-13j
7.75527592e-15+5.63077179e-14j 3.50987358e-13-1.00376618e-13j
6.97273752e-13-2.27704871e-13j -4.56266005e-14-4.01127949e-13j
3.22464033e-13+4.12209274e-13j -9.66747615e-14+1.81265833e-13j
-1.12621647e-13-1.88051363e-13j -3.63991340e-13-1.15624938e-13j
-2.58242277e-13+2.22828590e-13j 3.77321763e-13-1.77787850e-13j
-9.31666879e-14+6.82647164e-13j 1.14693397e-13+5.89745733e-14j
-1.21263885e-13-6.02976264e-13j -3.05629817e-13-8.00061104e-14j
4.89916705e-13-1.73729959e-13j 1.12462297e-14-5.77425046e-14j
-3.81603668e-14-3.83571682e-13j -2.32246240e-13-1.62598926e-13j
2.85742988e-13+2.15787223e-13j 4.49425598e-13-1.23746251e-13j
-8.47226315e-15-1.76475405e-13j -3.05142730e-13-2.56508361e-13j
-8.18365100e-14+5.64040240e-15j 3.58387291e-14-2.40169388e-13j
4.31194269e-13-1.59457736e-13j -1.62423944e-13-6.95458677e-14j
-2.52443700e-13+4.33295480e-13j -8.08430863e-13+2.50000000e+01j
2.65056489e-13-4.39714213e-13j -5.22415163e-13-1.48211154e-14j
3.44034403e-13+5.00000000e+01j 3.41750414e-14-1.21668376e-13j
6.03813597e-16+3.49809439e-13j 3.18332913e-12+1.50000000e+02j]
6
image1.png!
image2.png
7
image1.png!
2. Note that the input signal to FFT should have a length of power of 2. If it is not, then you
need to fill up zeros to the next power of 2 size
8
X_odd = FFT(x[1::2])
factor = np.exp(-2j*np.pi*np.arange(N)/ N)
X = np.concatenate(\
[X_even+factor[:int(N/2)]*X_odd,
X_even+factor[int(N/2):]*X_odd])
return X
In [ ]: # sampling rate
sr = 128
# sampling interval
ts = 1.0/sr
t = np.arange(0,1,ts)
freq = 1.
x = 3*np.sin(2*np.pi*freq*t)
freq = 4
x += np.sin(2*np.pi*freq*t)
freq = 7
x += 0.5* np.sin(2*np.pi*freq*t)
plt.figure(figsize = (8, 6))
plt.plot(t, x, "r")
plt.ylabel("Amplitude")
plt.show()
9
3.4 Que: Use the FFT function to calculate the Fourier transform of the above signal.
Plot the amplitude spectrum for both the two- and one-sided frequencies.
In [ ]: X=FFT(x)
# calculate the frequency
N = len(X)
n = np.arange(N)
T = N/sr
freq = n/T
plt.figure(figsize = (12, 6))
plt.subplot(121)
plt.stem(freq, abs(X), "b", markerfmt=" ", basefmt="-b")
plt.xlabel("Freq (Hz)")
plt.ylabel("FFT Amplitude |X(freq)|")
# Get the one-sided spectrum
n_oneside = N//2
# get the one side frequency
f_oneside = freq[:n_oneside]
# normalize the amplitude
X_oneside =X[:n_oneside]/n_oneside
plt.subplot(122)
plt.stem(f_oneside, abs(X_oneside), "b", markerfmt=" ", basefmt="-b")
plt.xlabel("Freq (Hz)")
plt.ylabel("Normalized FFT Amplitude |X(freq)|")
plt.tight_layout()
plt.show()
10
image1.png!
3.5 QUE: Generate a simple signal of length 2048, and record the time it will take to
run the FFT; compare the speed with the DFT.
3.6 FFT IN PYTHON
3.6.1 Python has very mature FFT functions both in NumPy and SciPy
3.6.2 Que Use the fft and ifft functions from NumPy to calculate the FFT amplitude spectrum
and inverse FFT to obtain the original signal. Plot both results. Time the fft function
using this 2000-length signal.
3.7 TOPIC 2: INTERPOLATION
3.7.1 2.1 Assume we have a dataset consisting of independent data values, xi , and dependent
data values, yi where $ i = 1, . . . , n $. We would like to find an estimation function y′ ( xi )
such that y( xi ) = yi for every point in our dataset. This means the estimation function
goes through our data points. Given a new x , we can interpolate its function value using
y′ ( x ). In this context, y′ ( x ) is called an interpolation function. The Figure below shows
the interpolation problem statement.
3.8 Some of the Interpolation methods are:
1. LINEAR INTERPOLATION
11
image1.png!
12
image1.png!
image1.png!
image1.png!
image1.png!
13
image1.png!
plt.plot(x, y, "ro")
plt.title("Cubic Spline Interpolation")
plt.xlabel("x")
plt.ylabel("y")
plt.show()
In [ ]:
14
image1.png!
3.12.5 It is often useful to approximate functions by using an Nth order Taylor series approx-
imation of a function, which is a truncation of its Taylor expansion at some$ n = N$.
This technique is especially powerful especially when there is a point around which
we have knowledge about a function and all its derivatives.
3.12.6 Example: Use Python to plot the sin function along with the first, third, fifth, and sev-
enth order Taylor series approximations. Note that this involves the zeroth to third
terms in the formula given earlier.
In [ ]: import numpy as np
import matplotlib.pyplot as plt
plt.style.use("seaborn-poster")
x = np.linspace(-np.pi, np.pi, 200)
y = np.zeros(len(x))
labels = ["First Order", "Third Order", "Fifth Order", "Seventh Order"]
plt.figure(figsize = (10,8))
for n, label in zip(range(4), labels):
y=y+((-1)**n*(x)**(2*n+1))/np.math.factorial(2*n+1)
plt.plot(x,y, label = label)
plt.plot(x, np.sin(x), "k", label = "Analytic")
plt.grid()
plt.title("Taylor Series Approximations of Various Orders")
plt.xlabel("x")
plt.ylabel("y")
plt.legend()
plt.show()
15
4 Topic 4: NUMERICAL DIFFERENTIATION
4.0.1 A numerical grid can be defined as an evenly spaced set of points over the domain of a
function (i.e., the independent variable), over some interval. The spacing or step size of
a numerical grid is the distance between adjacent points on the grid. For the purpose of
this text, if x is a numerical grid, then x j is the j th point in the numerical grid, and h is
the spacing between x j1 and x j . The Figure below shows an example of a numerical grid.
4.0.2 The purpose of the numerical differentiation is to derive the methods of approximating
the derivative of f ( x ) over a numerical grid and determine its accuracy
4.1 USING FINITE DIFFERENCE TO APPROXIMATE DERIVATIVES
4.1.1 The derivative f ′ ( x ) of a function f ( x ) at the point x = a is defined as
16
Backward difference.png!
Backward difference.png!
Backward difference.png!
17
Substituting O(h) into the previous equation gives
This gives the forward difference formula for approximating derivatives as
4.3 EXAMPLE:
4.3.1 Consider the function f ( x ) = cos( x ). We know that the derivative of cos( x ) is sin( x ). Al-
though in practice we may not know the underlying function we are finding the deriva-
tive for, we use the simple example to illustrate the aforementioned numerical differen-
tiation methods and their accuracy. The following code computes the derivatives numer-
ically
In [ ]: import numpy as np
import matplotlib.pyplot as plt
plt.style.use("seaborn-poster")
%matplotlib inline
# step size
h = 0.1
# define grid
x = np.arange(0, 2*np.pi, h)
# compute function
y = np.cos(x)
# compute vector of forward differences
forward_diff = np.diff(y)/h
print('The forward solutions are: ', forward_diff)
# compute corresponding grid
x_diff = x[:-1:]
# compute exact solution
exact_solution = -np.sin(x_diff)
print('the exact solution are: ', exact_solution)
# Plot solution
plt.figure(figsize = (12, 8))
plt.plot(x_diff, forward_diff, "-", \
label = "Finite difference approximation")
plt.plot(x_diff, exact_solution, label = "Exact solution")
plt.legend()
plt.show()
18
Backward difference.png!
19