The Discrete Fourier Transform is a mathematical operation that converts a sequence of discrete-time samples into a sequence of discrete-frequency components. Given a sequence $x[n]$ of length $N$, the DFT $X[k]$ is defined as:
$$X[k] = \sum_{n=0}^{N-1} x[n] e^{-j\frac{2\pi}{N}kn}, \quad k = 0, 1, \cdots, N-1$$
The DFT provides information about the frequency content of the signal. However, the computational complexity of the direct DFT calculation is $O(N^2)$, which can be very slow for large $N$.
The Fast Fourier Transform is an algorithm that computes the DFT more efficiently. It reduces the computational complexity from $O(N^2)$ to $O(N \log N)$. There are several FFT algorithms, such as the Cooley - Tukey algorithm, which is the most commonly used one.
In the FFT result, the frequency axis is related to the sampling rate $f_s$ and the length of the input sequence $N$. The frequency resolution $\Delta f$ is given by $\Delta f=\frac{f_s}{N}$. The frequency values corresponding to the FFT output $X[k]$ are $f_k = k\Delta f$ for $k = 0, 1, \cdots, N - 1$.
NumPy provides several functions for performing FFT operations. The most commonly used ones are:
numpy.fft.fft()
: Computes the one-dimensional discrete Fourier Transform.numpy.fft.ifft()
: Computes the one-dimensional inverse discrete Fourier Transform.numpy.fft.fftfreq()
: Returns the sample frequencies for the FFT result.Here is a simple example of using these functions:
import numpy as np
import matplotlib.pyplot as plt
# Generate a simple sine wave
fs = 100 # Sampling rate
T = 1 # Duration in seconds
t = np.linspace(0, T, fs, endpoint=False)
f = 5 # Frequency of the sine wave
x = np.sin(2 * np.pi * f * t)
# Perform FFT
X = np.fft.fft(x)
# Get the frequency axis
freqs = np.fft.fftfreq(len(x), 1/fs)
# Plot the original signal
plt.figure(figsize=(12, 6))
plt.subplot(2, 1, 1)
plt.plot(t, x)
plt.title('Original Signal')
plt.xlabel('Time [s]')
plt.ylabel('Amplitude')
# Plot the magnitude spectrum
plt.subplot(2, 1, 2)
plt.plot(freqs, np.abs(X))
plt.title('Magnitude Spectrum')
plt.xlabel('Frequency [Hz]')
plt.ylabel('Magnitude')
plt.tight_layout()
plt.show()
In this code, we first generate a sine wave with a frequency of 5 Hz and a sampling rate of 100 Hz. Then we perform the FFT using np.fft.fft()
and get the frequency axis using np.fft.fftfreq()
. Finally, we plot the original signal and its magnitude spectrum.
FFT is widely used for analyzing the frequency components of a signal. For example, in audio processing, we can use FFT to analyze the frequency content of a sound signal. In vibration analysis, FFT can be used to identify the dominant frequencies in a vibration signal.
FFT can be used for filtering signals in the frequency domain. We can multiply the FFT result of a signal by a filter function in the frequency domain and then perform the inverse FFT to get the filtered signal in the time domain.
The convolution theorem states that the convolution of two signals in the time domain is equivalent to the multiplication of their Fourier transforms in the frequency domain. We can use FFT to perform convolution more efficiently.
If the sampling rate and the length of the input sequence are not considered correctly when calculating the frequency axis, the frequency values in the FFT result may be incorrect.
Leakage occurs when the input signal is not periodic within the window of the FFT. This can cause the energy of a single frequency component to spread over multiple frequency bins in the FFT result. To reduce leakage, windowing functions can be applied to the input signal.
Zero padding is often used to increase the frequency resolution. However, it does not increase the actual information in the signal. Over - zero - padding can lead to unnecessary computational overhead.
The FFT size should be chosen based on the length of the input signal and the desired frequency resolution. A power of 2 FFT size is usually preferred for better computational efficiency.
To reduce leakage, windowing functions such as the Hamming window or the Hanning window can be applied to the input signal before performing the FFT.
import numpy as np
import matplotlib.pyplot as plt
# Generate a simple sine wave
fs = 100 # Sampling rate
T = 1 # Duration in seconds
t = np.linspace(0, T, fs, endpoint=False)
f = 5 # Frequency of the sine wave
x = np.sin(2 * np.pi * f * t)
# Apply Hamming window
window = np.hamming(len(x))
x_windowed = x * window
# Perform FFT on the original and windowed signals
X = np.fft.fft(x)
X_windowed = np.fft.fft(x_windowed)
freqs = np.fft.fftfreq(len(x), 1/fs)
# Plot the magnitude spectra
plt.figure(figsize=(12, 6))
plt.subplot(2, 1, 1)
plt.plot(freqs, np.abs(X))
plt.title('Magnitude Spectrum without Windowing')
plt.xlabel('Frequency [Hz]')
plt.ylabel('Magnitude')
plt.subplot(2, 1, 2)
plt.plot(freqs, np.abs(X_windowed))
plt.title('Magnitude Spectrum with Hamming Window')
plt.xlabel('Frequency [Hz]')
plt.ylabel('Magnitude')
plt.tight_layout()
plt.show()
In this code, we apply a Hamming window to the input signal and compare the magnitude spectra of the original and windowed signals.
NumPy’s FFT capabilities provide a powerful and efficient way to perform Fourier analysis in Python. By understanding the core concepts, typical usage scenarios, common pitfalls, and best practices, users can apply FFT effectively in real - world situations such as signal analysis, filtering, and convolution.