6

我想知道我是否以正确的方式在 MATLAB 中使用傅立叶变换。我想要一首歌中频率的所有平均幅度。出于测试目的,我使用了贝多芬“为 Elise”的免费 mp3 下载,我使用Audacity将其转换为 8 kHz 单声道文件。

我的 MATLAB 代码如下:

clear all % be careful

% load file
% Für Elise Recording by Valentina Lisitsa 
% from http://www.forelise.com/recordings/valentina_lisitsa
% Converted to 8 kHz mono using Audacity
allSamples = wavread('fur_elise_valentina_lisitsa_8khz_mono.wav');


% apply windowing function
w = hanning(length(allSamples));
allSamples = allSamples.*w;


% FFT needs input of length 2^x
NFFT = 2^nextpow2(length(allSamples))


% Apply FFT
fftBuckets=fft(allSamples, NFFT); 
fftBuckets=fftBuckets(1:(NFFT/2+1)); % because of symetric/mirrored values


% calculate single side amplitude spectrum, 
% normalize by dividing by NFFT to get the 
% popular way of displaying amplitudes
% in a range of 0 to 1
fftBuckets = (2*abs(fftBuckets))/NFFT; 

% plot it: max possible frequency is 4000, because sampling rate of input
% is 8000 Hz
x = linspace(1,4000,length(fftBuckets));
bar(x,fftBuckets);

然后输出如下所示: 在此处输入图像描述

  1. 有人可以告诉我我的代码是否正确吗?我特别想知道 0 附近的峰值。
  2. 为了规范化,我必须除以NFFTorlength(allSamples)吗?
  3. 对我来说,这看起来并不像条形图,但我想这是由于我正在绘制的许多值?

感谢您的任何提示!

4

2 回答 2

6
  1. 取决于你对“正确”的定义。我认为,这是按照您的意图进行的,但它可能不是很有用。我建议改用 2D频谱图,因为您将获得有关频率内容的时间本地化信息。

  2. 标准化 FFT 输出没有一种正确的方法。有各种不同的约定(参见例如这里的讨论)。您的代码中的注释说您想要 0 到 1 的范围;如果您的输入值在 -1 到 1 的范围内,那么除以箱数即可实现。

  3. 嗯,没错!

我还建议以对数刻度(以分贝为单位)绘制 y 轴,因为这大致是人耳解释响度的方式。

于 2012-07-03T11:22:58.400 回答
2

有两件事让我感到震惊:

  1. 我不确定你为什么在你的情节中包含 DC (index = 1) 组件。没什么大不了的,但当然那个 bin 不包含频率数据
  2. 我认为除以length(allSamples)比除以更可能是正确的NFFT。原因是,如果您希望 DC 分量等于输入数据的平均值,那么除以length(allSamples)是正确的做法。

但是,就像 Oli 所说的那样,在您确切知道要计算的内容之前,您无法真正说出“正确的”归一化是什么。我倾向于使用 FFT 来估计功率谱,所以我想要像“DAC / rt-Hz”这样的单位,这会导致与你想要像“DAC / Hz”这样的东西不同的归一化。

最终,没有什么可以替代您想从 FFT 中得到什么(包括单位),并为自己制定正确的归一化应该是什么(必要时从 FFT 的定义开始)。

您还应该知道,MATLABfft不需要使用 2 的幂的数组长度(尽管这样做可能会导致 FFT 运行得更快)。因为零填充会引入一些振铃,所以您需要考虑它是否适合您的应用程序。

最后,如果周期图/功率谱确实是您想要的,MATLAB 提供了类似的函数periodogrampwelch以及其他可能有用的函数。

于 2012-07-03T16:03:53.690 回答