Matlab中的FFT:环绕效果,值范围

时间:2015-02-18 14:58:27

标签: matlab signal-processing fft

我对Matlab中FFT函数的使用有一些疑问。

这是一个wav文件的FFT曲线图,用于录制弹奏的A弦吉他(仅一次)。

我是用文件的audioread做的:

a = audioread(a.wav))

然后写下

plot(abs(fft(a)))

enter image description here

正如您所看到的,它的形状非常糟糕。 首先,我们可以看到存在某种对称性。这是“环绕效应”吗? 我应该用零填充我的信号吗?

我们还可以看到价值是巨大的。它高达200000赫兹。 我们当然对高价值(我对可听见的声音起作用)不感兴趣。

我该怎么办? 我应该简单地将频率切换到24000 Hz以上吗?还有其他特别的事吗?

非常感谢你的帮助: - )

(并原谅可能不好的英语!)

3 个答案:

答案 0 :(得分:4)

图中的x轴没有单位赫兹(Hz)。您创建绘图的方式,它将是频率向量中频率的索引。由于您的输入信号似乎长约200'000个样本,因此FFT也很长。如果您希望轴以赫兹为单位,则必须创建一个频率向量,其中包含FFT中每个样本的相应频率。

我将在一个简单的示例中向您展示如何执行此操作,您可以根据自己的需要进行调整:

首先让我们创建一些测试信号:

fs = 8000;               % sampling frequency: 8kHz
t = 0:1/fs:0.1;          % create a time vector
x = cos(2*pi*100*t);     % Testsignal: cosine with 100Hz

现在我们计算FFT。由于FFT例程仅适用于长度为2的幂的向量,我们计算FFT长度然后进行FFT。

NFFT = 2^nextpow2(length(t));
X = fft(x,NFFT);

FFT的频率分辨率为fs/NFFT。由于FFT矢量的长度为NFFT且频率从零(DC)开始,因此频率矢量为

f = (0:(NFFT-1)) * fs/NFFT;

所以我们可以创建一个情节:

plot(f,abs(X));

FFT

您可以看到峰值几乎正好在100Hz,正如我们指定的那样。接下来你会注意到:我们的采样频率是fs=8000Hz,因此根据奈奎斯特定理,最大频率可以是fs/2 = 4000Hz。高于4000Hz的部分是频率轴的负部分,由于混叠,在4000Hz和8000Hz之间可见。

现在,MATLAB提供函数fftshift来重新排列向量x,以便从-fs / 2到+ fs / 2而不是0到fs绘制图。它唯一能做的是,它需要4000Hz到8000Hz之间的部分并将其移动到-4000Hz到0Hz。 因此,您必须相应地创建频率向量。

X_shifted = fftshift(X);
f_shifted = (-NFFT/2:NFFT/2-1) * fs/NFFT;

FFT shift

现在峰值处于+ - 100Hz,正如您对余弦所期望的那样。

长话短说:找出采样频率并创建频率向量。然后使用fftshift绘制双面光谱,或者只是忽略负频率,因为FFT对于实际输入值始终是对称的。

答案 1 :(得分:2)

输出的右半部分是负频率内容(实际上,它存在是因为你的吉他弦允许波一次向两个方向传播)。

你的x轴现在也不是频率,它是FFT系数指数。

您应该通过

绘制FFT
plot([(-numel(a)/2):(numel(a)/2-1)] * fs / numel(a), 20*log10(abs(fftshift(fft(a)))))

其中fs是采样频率。

为了更深入地理解你应该阅读一个很好的教程,我能够找到一个看起来不错的教程:http://www.gaussianwaves.com/2014/07/how-to-plot-fft-using-matlab-fft-of-basic-signals-sine-and-cosine-waves/

答案 2 :(得分:1)

嗯...

首先,您的老师应该提供这些信息。

接下来,我假设您知道数字音频信号是什么。当然,你必须明白,MATLAB并不关心矢量内部是否有关于模拟音频信号的数据,印度马铃薯生长的统计数据,非洲的降雨量或太阳风暴的数量。当您创建audiorecorder类的对象并向其传递矢量时,MATLAB会将相应的信号发送到您的扬声器。通过相应的信号,I表示模拟电流将具有的值。

下一点是,如何计算这些值,但为此你应该看看DA / AD转换。

与音频再现一样,傅里叶变换系数也遵循相同的方式。 MATLAB不关心fft函数中传递的内容。它只是做计算。

这些计算只是计算序列/信号/ what_ever的离散傅立叶变换的一种快速有效的方法。实际方法称为傅立叶变换。它只适用于笔和纸#34;因为它实际上要求" analogue"信息。如果我们在数字域(即在计算机内)移动,那么我们有离散傅里叶变换。这也很慢。为了使它快速,一些聪明的人找到了位处理(字面意思)的方法,并减少了到目前为止的必要计算。此方法称为 FAST 傅里叶变换。 请注意粗体,这只是算法,而不是算法的实现,

该算法正在以各种方式实施。一个可以被认为是最快的,但也是一个昂贵的。这种方式是FFTw,我认为是由麻省理工学院开发的...您可以通过在MATLAB help fft中编写并查看帮助文本的最后一个条目或查看文档来检查它。必须说有其他相当快速的FFT实现,如Ooras(如果我正确地写名称)和KissFFT。

无论哪种方式,FFT只是一个DFT,并且它意味着它保留所有DFT属性,作为"反射"你可以观察到。

对于音频,x轴的单位,如果不处理它们而只是plot(abs(fft(a))),则 FREQUENCY BIN INDEX 。没有频率,没有样本,没有其他任何东西。频率仓索引。没什么,没什么。

所以你现在应该拥有的问题是:"这个bin是什么以及如何与音频信号中的频率相关联#34;。

FFT有一个权衡。您可以看到整个信号(缩小时间),也可以对频率进行很好的分析(放大频率),或者只是分析信号的帧(放大时间)和更低的频率细节(缩小频率)。这是一个折衷的原因是因为如果你只是对整个信号进行FFT,你可以观察到平均值"每个频率仓中包含的能量。如果您想了解这种能量如何随信号的变化而变化,您必须拥有帧,从而降低频率分析。

信号的频率仓和实际频率的关系可以由FFT的ΔF给出。 ΔF由公式计算:

Df = Fs/N

其中Df是delta f(也称为fft分析),Fs是采样频率,N是传递给FFT的采样量。因此,给定相同的F,例如, 44100Hz,如果您有44100个样本的信号,则FFT将具有1Hz的分析。如果您有22050个样本的信号,则FFT将进行2 Hz的分析。

这意味着每个FFT系数将代表Df指定的频率范围内的能量。

所以,如果你想在x轴上有Hertz,你应该制作X值的矢量,然后用信号绘制它。

以下是示例代码(可能有错误......我没有检查):

[signal, fs] = audioread('a.wav'); % Load your wav file
Df = fs/max(size(signal)); % Calculate the Df
f = 0:Df:fs; % Construct the frequency vector for the X axes

signal_f = abs(fft(signal)); % Get the FFT of the signal
plot(f, signal_f(1:length(f)) % Plot the frequency vector and only the valuable information in signal_f