我对Matlab中FFT函数的使用有一些疑问。
这是一个wav文件的FFT曲线图,用于录制弹奏的A弦吉他(仅一次)。
我是用文件的audioread做的:
a = audioread(a.wav))
然后写下
plot(abs(fft(a)))
。
正如您所看到的,它的形状非常糟糕。 首先,我们可以看到存在某种对称性。这是“环绕效应”吗? 我应该用零填充我的信号吗?
我们还可以看到价值是巨大的。它高达200000赫兹。 我们当然对高价值(我对可听见的声音起作用)不感兴趣。
我该怎么办? 我应该简单地将频率切换到24000 Hz以上吗?还有其他特别的事吗?
非常感谢你的帮助: - )
(并原谅可能不好的英语!)
答案 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));
您可以看到峰值几乎正好在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;
现在峰值处于+ - 100Hz,正如您对余弦所期望的那样。
长话短说:找出采样频率并创建频率向量。然后使用fftshift
绘制双面光谱,或者只是忽略负频率,因为FFT对于实际输入值始终是对称的。
答案 1 :(得分:2)
输出的右半部分是负频率内容(实际上,它存在是因为你的吉他弦允许波一次向两个方向传播)。
你的x轴现在也不是频率,它是FFT系数指数。
您应该通过
绘制FFTplot([(-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