There was no article focusing on [Formula → Implementation], so I will spell it. Introducing this time is the simplest one called radix-2 of Cooley-Tukey type FFT.
First, the DFT (Discrete Fourier Transform) is expressed by the following equation.
By using $ (6) (7) (8) $ for $ (5) $, the DFT can finally be rewritten as follows.
Since $ F_ {even} (t) $ and $ F_ {odd} (t) $ are common, $ F (t) $ and $ F (t + \ frac {N} {2}) $ are calculated at the same time. That's why you want it. This is the mechanism for reducing the amount of calculation.
Based on the above, let's move on to implementation.
Let's write an FFT function in Python. Here's the basic idea. After dividing the input data into even elements and odd elements and performing FFT (recursive) like $ (3) (4) $, 0 ~ (N / 2)-using $ (9) (10) $ Calculate the 1st and N / 2 ~ N-1th. Therefore, the FFT is a recursive function.
def FFT(f):
#f:Input data of size N
N = len(f)
if N == 1: #When N is 1, the input data is returned as it is
return f[0]
f_even = f[0:N:2] #Even-numbered element of f
f_odd = f[1:N:2] #Odd element of f
F_even = FFT(f_even) #(3)FFT on even-numbered elements
F_odd = FFT(f_odd) #(4)FFT on even-numbered elements
W_N = np.exp(-1j * (2 * np.pi * np.arange(0, N // 2)) / N) #t is 0~N/2-Array that calculated W up to the first
F = np.zeros(N, dtype ='complex') #FFT output
F[0:N//2] = F_even + W_N * F_odd #(9)Calculate(t:0~N/2-1)
F[N//2:N] = F_even - W_N * F_odd #(10)Calculate(t:N/2~N-1)
return F
Let's check if we can get the same output as numpy FFT. Create a composite wave of two sine waves with the following parameters and use this as an input.
import numpy as np
import matplotlib.pyplot as plt
N = 64 #The number of data
n = np.arange(N)
f1 = 2 #Cycle 1
f2 = 5 #Cycle 2
A1 = 3 #Amplitude 1
A2 = 5 #Amplitude 2
INPUT_f = A1 * np.sin(f1 * 2 * np.pi * (n/N)) + A2 * np.sin(f2 * 2 * np.pi * (n/N)) #Synthesis of two sine waves
#display
plt.figure(figsize=(10, 5))
plt.style.use('seaborn')
plt.plot(INPUT_f)
Perform an FFT. Since the output of the FFT is a complex number, the amplitude component is extracted by multiplying it by the absolute value and visualized here.
OUTPUT_F_numpy = np.fft.fft(INPUT_f) #numpy version
OUTPUT_F_original = FFT(INPUT_f) #Self-made version
plt.figure(figsize=(10, 5))
plt.subplot(1,2,1) #Amplitude component display(numpy version)
plt.title('numpy_ver')
plt.plot(np.abs(OUTPUT_F_numpy))
plt.subplot(1,2,2) #Amplitude component display(Self-made version)
plt.title('original')
plt.plot(np.abs(OUTPUT_F_original))
I got the same result safely.
Recommended Posts