MATLAB :快速傅⾥叶变换(FFT )
快速傅⾥叶变换介绍
傅⽴叶原理表明:任何连续测量的时序或信号,都可以表⽰为不同频率的余弦(或正弦)波信号的⽆限叠加。FFT 是离散傅⽴叶变换的快速算法,可以将⼀个信号变换到频域。那其在实际应⽤中,有哪些⽤途呢?
1. 有些信号在时域上是很难看出什么特征的,但是如果变换到频域之后,就很容易看出特征(频率,幅值,初相位);
2. FFT 可以将⼀个信号的频谱提取出来,进⾏频谱分析,为后续滤波准备;
3. 通过对⼀个系统的输⼊信号和输出信号进⾏快速傅⾥叶变换后,两者进⾏对⽐,对系统可以有⼀个初步认识。
假设采样频率 ,信号频率 ,信号长度 ,采样点数 。那么 FFT 之后结果就是⼀个为  点的复数。每⼀个点就对应着⼀个频率点。这个点的模值,就是该频率值下的幅度特性。
具体跟原始信号的幅度有什么关系呢?
1. 假设原始信号的峰值为 ,那么 FFT 的结果的每个点(除了第⼀个点直流分量之外)的模值就是  的  倍,⽽第⼀个点就是直流分量(即 0 Hz),它的模值是直流分量的  倍;
2. 每个点的相位呢,就是在该频率下的信号的相位。第⼀个点表⽰直流分量,它的相位是该频率的初相位,MATLAB 以  为底的,若信号时正弦形式 ,则变成  即可。
采样频率 ,被  个点平均分成  等份,每个点的频率依次增加。为了⽅便进⾏ FFT 运算,通常  取⼤于信号长度 L 的 2 的整数次⽅。
例如某点  所表⽰的频率为: 。由上⾯的公式可以看出, 所能分辨到频率为为 。如果采样频率  为1024Hz,采样点数为 1024 点,则可以分辨到 1Hz。
1024Hz 的采样率采样 1024 点,刚好是 1 秒,也就是说,采样 1 秒时间的信号并做 FFT,则结果可以分析到 1Hz。如果采样2秒时间的信号,则 N 为2048,并做 FFT,则结果可以分析到 0.5Hz。
如果要提⾼频率分辨⼒,则必须增加采样点数,也即采样时间。频率分辨率和采样时间是倒数关系。
matlab求傅里叶变换假设 FFT 之后某点  ⽤复数  表⽰,该复数的模就是,相位就是 。根据以上的结果,就可以计算出 n 点(n≠1,且n<=N/2)对应的信号的表达式为:,即;对于  点的信号,是直流分量,幅度即为 。
由于 FFT 结果的对称性,通常我们只使⽤前半部分的结果,即⼩于采样频率⼀半的结果。
例⼦
假设我们有⼀个信号,它含有 5V 的直流分量,频率为 50Hz、相位为 -30 度、幅度为 7V 的交流信号以及⼀个频率为 90Hz、相位为 90度、幅度为 3V 的交流信号。数学表达式为:
我们以 128Hz 的采样率对这个信号进⾏采样,总共采样 256 点。按照我们上⾯的分析,,我们可以知道,每两个点之间的间距就是 0.5Hz。我们的信号有3个频率:0Hz、15Hz、40Hz
出于编程⽅便,因为直流分量的幅值 ,其他点幅值为 ,故直流分量最后要除以 2 才是对的。
⼀般 FFT 所⽤数据点数  与原含有信号数据点数  相同,这样的频谱图具有较⾼的质量,可减⼩因补零或截断⽽产⽣的影响。Matlab 代码
Fs F L N N A A N /2N cos sin (t )cos (t −π/2)Fs N −1N N n Fn =(n −1)∗Fs /N Fn Fs /N Fs n a +bi An =sqrt (a ∗a +b ∗b )Pn =atan 2(b ,a )A /(N /2)∗n cos (2π∗Fn ∗t +Pn )2∗An /N ∗cos (2∗pi ∗Fn ∗t +Pn )n =1A /N 1x =5+7cos (2π∗15∗t −30π/180)+3cos (2π∗40∗t −90π/180)
Fn =(n −1)∗Fs /N A /N 1A /(N /2)n N L
clear
Fs =128;%采样频率
T =1/Fs;%采样时间
L =256;%信号长度
t =(0:L-1)*T;%时间
x =5+7*cos(2*pi*15*t -30*pi/180)+3*cos(2*pi*40*t -90*pi/180);%cos为底原始信号
y = x + randn(size(t));%添加噪声
figure;
plot(t,y)
title('加噪声的信号')
xlabel('时间(s)')
N =2^nextpow2(L);%采样点数,采样点数越⼤,分辨的频率越精确,N>=L,超出的部分信号补为0 Y = fft(y,N)/N*2;%除以N乘以2才是真实幅值,N越⼤,幅值精度越⾼
f = Fs/N*(0:1:N-1);%频率
A =abs(Y);%幅值
P = angle(Y);%相值
figure;
subplot(211);plot(f(1:N/2),A(1:N/2));%函数fft返回值的数据结构具有对称性,因此我们只取前⼀半title('幅值频谱')
xlabel('频率(Hz)')
ylabel('幅值')
subplot(212);plot(f(1:N/2),P(1:N/2));
title('相位谱频')
xlabel('频率(Hz)')
ylabel('相位')