基于python的快速傅里叶变换FFT(一)

FFT可以将一个信号变换到频域。有些信号在时域上是很难看出什么特征的,但是如果变换到频域之后,就很容易看出特征了。这就是很多信号分析采用FFT变换的原因。另外,FFT可以将一个信号的频谱提取出来,这在频谱分析方面也是经常用的。

知识点

1、FFT——离散傅里叶变换(DFT)的快速算法。它是根据离散傅氏变换的奇、偶、虚、实等特性,对离散傅立叶变换的算法进行改进获得的。
2、假设采样频率为Fs,信号频率F,采样点数为N。那么FFT之后结果就是一个为N点的复数。每一个点就对应着一个频率点。这个点的模值,就是该频率值下的幅度特性。
3、假设采样频率为Fs,采样点数为N,做FFT之后,某一点n(n从1开始)表示的频率为:Fn=(n-1)*Fs/N;该点的模值除以N/2就是对应该频率下的信号的幅度(对于直流信号是除以N);该点的相位即是对应该频率下的信号的相位。相位的计算可用函数atan2(b,a)计算。atan2(b,a)是求坐标为(a,b)点的角度值,范围从-pi到pi。要精确到xHz,则需要采样长度为1/x秒的信号,并做FFT。要提高频率分辨率,就需要增加采样点数,这在一些实际的应用中是不现实的,需要在较短的时间内完成分析。解决这个问题的方法有频率细分法,比较简单的方法是采样比较短时间的信号,然后在后面补充一定数量的0,使其长度达到需要的点数,再做FFT,这在一定程度上能够提高频率分辨力。
4、由于FFT结果的对称性,通常我们只使用前半部分的结果,即小于采样频率一半的结果。

代码实现

准备工作:安装matplotlib包,打开命令窗口,进入安装python下的scripts路径,输入pip install matplotlib。安装成功后会显示如下图:

opencv傅里叶变换 PYTHON python 傅里叶分析_采样频率


其他包的安装步骤类似。

import numpy as np
from scipy.fftpack import fft,ifft
import matplotlib.pyplot as plt
import seaborn


#采样点选择1400个,因为设置的信号频率分量最高为600Hz,根据采样定理知采样频率要大于信号频率2倍,所以这里设置采样频率为1400Hz(即一秒内有1400个采样点)
x=np.linspace(0,1,1400)

#设置需要采样的信号,频率分量有180,390和600
y=7*np.sin(2*np.pi*180*x) + 1.5*np.sin(2*np.pi*390*x)+5.1*np.sin(2*np.pi*600*x)

yy=fft(y)                     #快速傅里叶变换
yreal = yy.real               # 获取实数部分
yimag = yy.imag               # 获取虚数部分

yf=abs(fft(y))                # 取模
yf1=abs(fft(y))/((len(x)/2))           #归一化处理
yf2 = yf1[range(int(len(x)/2))]  #由于对称性,只取一半区间

xf = np.arange(len(y))        # 频率
xf1 = xf
xf2 = xf[range(int(len(x)/2))]  #取一半区间

#原始波形
plt.subplot(221)
plt.plot(x[0:50],y[0:50])
plt.title('Original wave')
#混合波的FFT(双边频率范围)
plt.subplot(222)
plt.plot(xf,yf,'r') #显示原始信号的FFT模值
plt.title('FFT of Mixed wave(two sides frequency range)',fontsize=7,color='#7A378B')  #注意这里的颜色可以查询颜色代码表
#混合波的FFT(归一化)
plt.subplot(223)
plt.plot(xf1,yf1,'g')
plt.title('FFT of Mixed wave(normalization)',fontsize=9,color='r')

plt.subplot(224)
plt.plot(xf2,yf2,'b')
plt.title('FFT of Mixed wave)',fontsize=10,color='#F08080')


plt.show()

实现结果

opencv傅里叶变换 PYTHON python 傅里叶分析_傅里叶变换_02

结果验证

假设我们有一个信号,它含有一个频率为180Hz,幅度为7V的交流信号;一个频率为390Hz,幅度为1.5V的交流信号;一个频率为600Hz,幅度为5.1V的交流信号。用数学表达式就是如下:

y=7*np.sin(2*np.pi*180*x) + 1.5*np.sin(2*np.pi*390*x)+5.1*np.sin(2*np.pi*600*x)


从图中我们可以看到,在第181点、第391点、和第601点附近有比较大的值。分别计算这三个点的模值,结果如下:
181点: 4900
391点:1030
601点:2600
按照公式,可以计算出180Hz信号的幅度为:4900/(N/2)=384/(1400/2)=7;390Hz信号的幅度为:1030/(N/2)=1030/(1400/2)=1.5。可见,从频谱分析出来的幅度是正确的。
注:600Hz信号的幅度异常,具体原因为检查出来,后期更新。