SciPy - FFTpack
SciPy - 傅里叶变换 (scipy.fft)
Section titled “SciPy - 傅里叶变换 (scipy.fft)”傅里叶变换(Fourier Transform)是一种强大的数学工具,可以将信号(通常是时域信号 time-domain signal)分解为其构成的频率分量。在频域(frequency domain)分析信号可以揭示在时域中隐藏的特性。它广泛应用于信号处理、图像分析、音频工程以及许多其他科学和工程领域。SciPy 通过 scipy.fft 模块(它是旧版 scipy.fftpack 的现代替代)提供了全面的傅里叶变换功能。
快速傅里叶变换 (FFT)
Section titled “快速傅里叶变换 (FFT)”快速傅里叶变换(Fast Fourier Transform, FFT)是计算离散傅里叶变换(Discrete Fourier Transform, DFT)及其逆变换的高效算法。
一维离散傅里叶变换
Section titled “一维离散傅里叶变换”DFT 将一个 N 个复数序列 $x_0, x_1, \ldots, x_{N-1}$ 转换为另一个 N 个复数序列 $X_0, X_1, \ldots, X_{N-1}$,后者通常称为频率 bin。scipy.fft 中的 fft() 函数计算 DFT,ifft() 函数计算逆 DFT(Inverse DFT)。
import numpy as npfrom scipy.fft import fft, ifft
# Create a simple input array (time-domain signal)x = np.array([1.0, 2.0, 1.0, -1.0, 1.5])print(f"Original signal x: {x}")
# Apply the FFTy = fft(x)print(f"FFT of x (frequency-domain signal y):\n{y}")
# Apply the Inverse FFT (IFFT)y_inverted = ifft(y)print(f"IFFT of y (should be close to original x):\n{y_inverted}")# Note: IFFT result might have very small imaginary parts due to floating point precision.# We can take the real part if the original signal was real.print(f"Real part of IFFT of y: {np.real(y_inverted)}")输出将是:
Original signal x: [ 1. 2. 1. -1. 1.5]FFT of x (frequency-domain signal y):[ 4.50000000+0.j 2.08155948-1.65109876j -1.83155948+1.60822041j -1.83155948-1.60822041j 2.08155948+1.65109876j]IFFT of y (should be close to original x):[ 1.0+0.j 2.0+0.j 1.0+0.j -1.0+0.j 1.5+0.j ]Real part of IFFT of y: [ 1. 2. 1. -1. 1.5]我们来看一个更实际的例子:一个带噪声的正弦波。
import numpy as npfrom scipy.fft import fft, fftfreqimport matplotlib.pyplot as plt # For plotting (optional)
# Signal parameterssampling_rate = 100 # Hz (samples per second)duration = 5.0 # secondsfrequency = 2.0 # Hz (frequency of the sine wave)
num_samples = int(sampling_rate * duration)time_vector = np.linspace(0.0, duration, num_samples, endpoint=False)
# Generate a sine wave with some noisesignal = np.sin(2 * np.pi * frequency * time_vector) + 0.5 * np.random.randn(num_samples)
print(f"Number of samples: {signal.size}")
# Compute the FFTsignal_fft = fft(signal)
# Generate the frequency bins for the x-axis of the FFT plot# fftfreq(number_of_samples, sample_spacing)sample_spacing = 1.0 / sampling_ratefrequency_bins = fftfreq(num_samples, d=sample_spacing)
# Plotting (optional, requires matplotlib)# plt.figure(figsize=(12, 6))# plt.subplot(1, 2, 1)# plt.plot(time_vector, signal)# plt.title("Time-Domain Signal")# plt.xlabel("Time (s)")# plt.ylabel("Amplitude")
# plt.subplot(1, 2, 2)# # We plot the magnitude of the FFT (abs value) and usually only the positive frequencies# positive_freq_indices = frequency_bins >= 0# plt.plot(frequency_bins[positive_freq_indices], np.abs(signal_fft[positive_freq_indices]))# plt.title("Frequency-Domain Signal (FFT Magnitude)")# plt.xlabel("Frequency (Hz)")# plt.ylabel("Magnitude")# plt.xlim(0, sampling_rate / 2) # Show up to Nyquist frequency# plt.grid(True)# plt.tight_layout()# plt.show()
# For text output, let's show some FFT values and corresponding frequenciesprint("\nSample FFT magnitudes and their frequencies:")for i in range(5): print(f"Freq: {frequency_bins[i]:.2f} Hz, Magnitude: {np.abs(signal_fft[i]):.2f}")# Find the dominant frequency componentdominant_freq_idx = np.argmax(np.abs(signal_fft[frequency_bins >= 0])) # consider positive freqsprint(f"Dominant positive frequency: {frequency_bins[dominant_freq_idx]:.2f} Hz")此代码生成一个带噪声的正弦波。fftfreq 函数计算与 FFT 输出中每个点对应的频率。FFT 输出 signal_fft 包含复数;np.abs(signal_fft) 给出它们的幅值(magnitude),表示每个频率分量的强度。对于实数输入信号,FFT 输出是对称的,因此我们通常只分析正频率。
一个示例文本输出(由于噪声,具体值会有所不同):
Number of samples: 500
Sample FFT magnitudes and their frequencies:Freq: 0.00 Hz, Magnitude: 1.89Freq: 0.20 Hz, Magnitude: 6.09Freq: 0.40 Hz, Magnitude: 6.37Freq: 0.60 Hz, Magnitude: 3.90Freq: 0.80 Hz, Magnitude: 10.47Dominant positive frequency: 2.00 Hz找到的主导频率应接近我们为正弦波设置的原始 frequency 2.0 Hz。
离散余弦变换 (DCT)
Section titled “离散余弦变换 (DCT)”离散余弦变换(Discrete Cosine Transform, DCT)与 DFT 相关,但只使用余弦函数。它将一组有限的数据点表示为不同频率余弦函数的总和。DCT 广泛应用于信号和图像压缩(例如 JPEG)。
SciPy 的 scipy.fft 模块提供 dct 用于正向 DCT,idct 用于逆向 DCT (IDCT)。
from scipy.fft import dct, idctimport numpy as np
# Input arrayx_dct = np.array([4., 3., 5., 10., 5., 3.])print(f"Original array for DCT: {x_dct}")
# Compute DCT (default is Type-II DCT)dct_coeffs = dct(x_dct)print(f"DCT coefficients:\n{dct_coeffs}")
# Reconstruct the original signal using IDCT (default is Type-III IDCT for Type-II DCT)x_reconstructed = idct(dct_coeffs)print(f"Reconstructed array using IDCT:\n{x_reconstructed}")输出将是:
Original array for DCT: [ 4. 3. 5. 10. 5. 3.]DCT coefficients:[ 60. -3.48476592 -13.85640646 11.3137085 6. -6.31319305]Reconstructed array using IDCT:[ 4. 3. 5. 10. 5. 3.]DCT 有不同的类型(Type-I, Type-II, Type-III, Type-IV)。scipy.fft.dct 和 scipy.fft.idct 允许使用 type 参数指定类型。默认的 dct 是 Type-II,其对应的逆变换 idct 是 Type-III。这些是压缩等应用中的常见选择。
scipy.fft 模块还提供了用于二维(和 N 维)FFT 和 DCT 的函数(例如,fft2、dctn),这对于图像处理和其他多维数据分析至关重要。