在实际使用中,我们自己编写的fft函数肯定不如专门优化过的库,这里我们使用scipy。
1 2 3 import numpy as npimport matplotlib.pyplot as pltfrom scipy import fft
做一下数据准备:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 rate = 100 interval = 1 / rate t_start = 0 t_end = 1 t = np.arange(t_start, t_end, interval) def getSineSignal (amps, freqs, t ): x = np.zeros_like(t) for a, f in zip (amps, freqs): x += a * np.sin(2 * np.pi * f * t) return x amps = np.array([9 , 10 , 2.3 ]) freqs = np.array([2 , 1 , 10 ]) x = getSineSignal(amps, freqs, t) plt.figure(figsize=(8 ,6 )) plt.plot(t, x, 'r' ) plt.xlabel('t' ) plt.ylabel('x' ) plt.grid(True )
在scipy里的fft函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 fft.fft(x, n=None , axis=-1 , norm=None , overwrite_x=False , workers=None ) ''' x: 输入信号,一维或多维数组(通常为实数或复数) n: 变换的点数,默认为 x 的长度。如果指定 n, 信号会被截断或零填充到长度 n axis: 沿哪个轴进行 DFT,默认是 -1(最后一个轴) norm: 归一化方式: None(默认): 不归一化, DFT 输出直接为公式结果。 "forward": 除以 1(标准 DFT)。 "backward": 除以 N(逆变换归一化)。 "ortho": 除以 sqrt(N)(正交归一化)。 overwrite_x: 是否允许修改输入数组以节省内存。 workers: 并行计算的线程数,默认为 None(自动选择) '''
用之前的画图函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 X_k = fft.fft(x) N = X_k.size n = np.arange(N) T = N / rate freq = n / T plt.figure(figsize=(8 ,6 )) plt.stem(freq, abs (X_k), 'b' , markerfmt=' ' , basefmt='-b' ) plt.xlabel(r'$\omega$ ' +'(Hz)' ) plt.ylabel('DFT Amplitude ' +r'$|X(\omega)|$' ) plt.grid(True )
使用fft.fftfreq来画图,会自动画对称的频谱图
1 2 3 4 5 6 freq = fft.fftfreq(N, d=1 /rate) plt.figure(figsize=(8 ,6 )) plt.stem(freq, abs (X_k), 'b' , markerfmt=' ' , basefmt='-b' ) plt.xlabel(r'$\omega$ ' +'(Hz)' ) plt.ylabel('DFT Amplitude ' +r'$|X(\omega)|$' ) plt.grid(True )
逆变换ifft:
1 2 3 fft.ifft(x, n=None , axis=-1 , norm=None , overwrite_x=False , workers=None )
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 inv_x = fft.ifft(X_k) plt.figure(figsize = (14 , 5 )) plt.subplot(121 ) plt.plot(t, x, 'b' ) plt.xlabel('t' ) plt.ylabel('x' ) plt.title('Original Signal' ) plt.grid(True ) plt.subplot(122 ) plt.plot(t, inv_x, 'r' ) plt.xlabel('t' ) plt.ylabel('x' ) plt.title('Reconstructed Signal' ) plt.tight_layout() plt.grid(True )
rfft是专为实信号设计的 FFT,只计算正频率部分(k = 0 到 N//2),节省内存和计算量。
1 2 3 4 5 6 7 8 X_k_real = fft.rfft(x) freq_real = fft.rfftfreq(N, d=1 /rate) plt.figure(figsize=(8 ,6 )) plt.stem(freq_real, abs (X_k_real), 'b' , markerfmt=' ' , basefmt='-b' ) plt.xlabel(r'$\omega$ ' +'(Hz)' ) plt.ylabel('DFT Amplitude ' +r'$|X(\omega)|$' ) plt.grid(True )
irfft,逆变换,专门用于 rfft 的输出,将正频率部分转换回时域。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 inv_x_real = fft.irfft(X_k_real, n=N) plt.figure(figsize = (14 , 5 )) plt.subplot(121 ) plt.plot(t, x, 'b' ) plt.xlabel('t' ) plt.ylabel('x' ) plt.title('Original Signal' ) plt.grid(True ) plt.subplot(122 ) plt.plot(t, inv_x_real, 'r' ) plt.xlabel('t' ) plt.ylabel('x' ) plt.title('Reconstructed Signal' ) plt.tight_layout() plt.grid(True )