1. FFT相关理论
1.1 离散傅里叶变换(DFT)
离散傅里叶变换(discrete Fourier transform) 傅里叶分析方法是信号分析的最基本方法,傅里叶变换是傅里叶分析的核心,通过它把信号从时间域变换到频率域,进而研究信号的频谱结构和变化规律。但是它的致命缺点是:计算量太大,时间复杂度太高,当采样点数太高的时候,计算缓慢,由此出现了DFT的快速实现,即下面的快速傅里叶变换FFT。
1.2 快速傅里叶变换(FFT)
计算量更小的离散傅里叶的一种实现方法。
1.3 归一化和取一半处理
比如有一个信号如下:
Y=A1+A2cos(2πω2+φ2)+A3cos(2πω3+φ3)+A4*cos(2πω4+φ4)
经过FFT之后,得到的“振幅图”中,
第一个峰值(频率位置)的模是A1的N倍,N为采样点,本例中为N=1400,此例中没有,因为信号没有常数项A1
第二个峰值(频率位置)的模是A2的N/2倍,N为采样点,
第三个峰值(频率位置)的模是A3的N/2倍,N为采样点,
第四个峰值(频率位置)的模是A4的N/2倍,N为采样点,
依次下去…
考虑到数量级较大,一般进行归一化处理,既然第一个峰值是A1的N倍,那么将每一个振幅值都除以N即可
FFT具有对称性,一般只需要用N的一半,前半部分即可。
2. FFT之后每个点的频率分辨率与采样频率(Fs)和采样点数(N)之间的关系
FFT频率分辨率=1/采样总时间=1/(N/Fs) = Fs/N(Hz)。
例如采样频率10k,采样点数1024,则FFT之后,频率分辨率=10k/1024=9.765625Hz。
3. 代码
import numpy as np
from scipy.fftpack import fft,ifft
import matplotlib.pyplot as plt
from matplotlib.pylab import mpl
mpl.rcParams['font.sans-serif'] = ['SimHei'] #显示中文
mpl.rcParams['axes.unicode_minus']=False #显示负号
Fs = 1000 #采样频率
N = 4096 #采样的总点数
Time = N/Fs; #采样时间N/Fs
x = np.arange(0,Time,1.0/Fs) #采样的x等差数列,0,Ts,2Ts,...,Time-Ts
half_x = x[range(int(N/2))] #取一半区间
k = np.arange(N)
fx = k / Time; #x轴归一化到采样频率。FFT频率分辨率=1/采样总时间(Hz),即采样时间为0.2s,则频率分辨率5Hz。即采样时间为5s,则频率分辨率0.2Hz。
half_fx = fx[range(int(N/2))]
#设置需要采样的信号,频率分量有200,400和600
y=1+2*np.sin(2*np.pi*200*x) + 3*np.sin(2*np.pi*400*x)
fft_y=fft(y) #快速傅里叶变换
abs_y=np.abs(fft_y) # 取复数的绝对值,即复数的模(双边频谱)
angle_y=np.angle(fft_y) #取复数的角度
normalization_y=abs_y/N #归一化处理(双边频谱)
normalization_half_y = normalization_y[range(int(N/2))] #由于对称性,只取一半区间(单边频谱)
plt.subplot(231)
plt.plot(x,y)
plt.xlabel('t/s')
plt.ylabel('Amplitude')
plt.title('原始波形')
plt.tight_layout() #设置默认的间距
plt.subplot(232)
plt.plot(fx,fft_y,'black')
plt.xlabel('Freq/Hz')
plt.ylabel('Amplitude振幅')
plt.title('双边振幅谱(未求振幅绝对值)',fontsize=9,color='black')
plt.subplot(233)
plt.plot(fx,abs_y,'r')
plt.xlabel('Freq/Hz')
plt.ylabel('Amplitude振幅')
plt.title('双边振幅谱(未归一化)',fontsize=9,color='red')
plt.subplot(234)
plt.plot(fx,angle_y,'violet')
plt.xlabel('Freq/Hz')
plt.ylabel('phase相位')
plt.title('双边相位谱(未归一化)',fontsize=9,color='violet')
##plt.subplot(234)
##plt.plot(x[0:50],y[0:50],'violet')
##plt.xlabel('t/s')
##plt.ylabel('Amplitude')
##plt.title('原始波形(部分))',fontsize=9,color='violet')
plt.subplot(235)
plt.plot(fx,normalization_y,'g')
plt.xlabel('Freq/Hz')
plt.ylabel('Amplitude振幅')
plt.title('双边振幅谱(归一化)',fontsize=9,color='green')
plt.subplot(236)
plt.plot(half_fx,normalization_half_y,'blue')
plt.xlabel('Freq/Hz')
plt.ylabel('Amplitude振幅')
plt.title('单边振幅谱(归一化)',fontsize=9,color='blue')
plt.show()