FFT快速傅里叶变换
理解FFT
在开发天灵硕火时,不免要涉及到音频特征的提取。而音频的特征就包含在音频的频谱空间(频域)中,FFT(快速离散傅立叶变换),可以将一个信号快速变换到频域。
先科普相关概念,可以参考这篇文章: 如果看了此文你还不懂傅里叶变换,那就过来掐死我吧【完整版】
虽然有了基本概念,但是要想完全理解FFT还是得通过亲自实验一下,看看频谱的威力。
假设我们有一个信号,它含有2V的直流分量,频率为50Hz、 相位为-30度、幅度为3V的交流信号,以及一个频率为75Hz、 相位为90度、幅度为1.5V的交流信号。
用数学表达式就是如下(t为时间):
\[S=2+3\cos(2\pi50t-\frac{30}{180}\pi)+1.5\cos(2\pi75t+\frac{90}{180}\pi)\]式中cos参数为弧度,所以-30度和90度要分别换算成弧度。 我们以256Hz的采样率对这个信号进行采样,总共采样256点。 按照我们上面的分析,Fn=(n-1)*Fs/N,我们可以知道,每两个 点之间的间距就是1Hz,第n个点的频率就是n-1。我们的信号 有3个频率:0Hz、50Hz、75Hz,应该分别在第1个点、第51个点、 第76个点上出现峰值,其它各点应该接近0。实际情况如何呢?
在octave中输入以下代码:
% 假设我们有一个信号,它含有2V的直流分量,频率为50Hz、
% 相位为-30度、幅度为3V的交流信号,以及一个频率为75Hz、
% 相位为90度、幅度为1.5V的交流信号。
Frequence1=50; % 频率1
Frequence2=75; % 频率2
FrequenceSampling=256; % 采样频率
TimeSampling = 1/FrequenceSampling; % 采样间隔
NumberSampling=FrequenceSampling*1; % 采样数 1秒
Tx = (0: NumberSampling-1) * TimeSampling;
Vy = 2 + 3 * cos(2 * pi * 50 * Tx + 30 / 180 * pi) + 1.5 * cos(2 * pi * 75 * Tx + 90 / 180 * pi);
figure(1)
subplot(3,1,1)
plot(Tx, Vy); % 直接输出信号
title('wave sample for 0Hz, 50Hz, 75Hz');
xlabel("Time (Sec)");
ylabel('voltage (V)');
grid;
subplot(3,1,2);
FFTy = fft(Vy);
Fx = (FrequenceSampling/NumberSampling)*(0:(NumberSampling/2));
Ay = (FFTy/NumberSampling);
Ay = Ay(1:NumberSampling/2+1);
Ay(2:end-1) = 2*Ay(2:end-1); % 第一个点是直流,不需要乘以2,第二个点开始需要乘以2得到正确的幅值。
plot(Fx, abs(Ay)); % 输出幅值,频谱
title('Amplitude Spectrum');
xlabel("Frequence (Hz)");
ylabel("voltage (V)");
grid;
subplot(3,1,3);
phs = angle(Ay); % 计算相位
plot(Fx,phs/pi*180); % 输出相位
title('Phase Spectrum');
xlabel 'Frequency (Hz)';
ylabel 'Phase (deg)';
grid;
运行结果:
运行结果可以看到FFT能准确的找到信号的频率以及相位。