VB FFT - 理解结果与频率的理解关系

时间:2008-09-26 10:01:30

标签: vba audio signal-processing fft

试图了解我正在使用的fft(快速傅立叶变换)例程(偷窃)(回收)

输入是512个数据点的数组,这是一个采样波形。 测试数据生成到此数组中。 fft将此阵列转换为频域。 试图理解fq数组中的频率,周期,采样率和位置之间的关系。我将举例说明:

========================================

采样率为1000个样本/秒。 以10Hz生成一组样本。

输入数组的峰值在arr(28),arr(128),arr(228)...... 期间= 100个样本点

fft数组中的峰值位于索引6处(不包括0处的巨大值)

========================================

采样率为8000个样本/秒 以440Hz生成一组样本

输入数组峰值包括arr(7),arr(25),arr(43),arr(61)...... 期间= 18个样本点

fft数组中的峰值位于索引29处(不包括0处的巨大值)

========================================

如何将fft阵列中峰值的索引与频率相关联?

8 个答案:

答案 0 :(得分:2)

如果忽略虚部,频率分布在二进制位上是线性的:

频率@i =(采样率/ 2)*(i / Nbins)。

因此,对于您的第一个示例,假设您有256个分档,最大分档对应的频率为1000/2 * 6/256 = 11.7 Hz。 由于您输入的是10Hz,我猜测bin 5(9.7Hz)也有很大的成分。 为了获得更好的准确性,您需要采取更多样本,以获得更小的容器。

你的第二个例子给出了8000/2 * 29/256 = 453Hz。再次,关闭,但你需要更多的垃圾箱。 你的分辨率只有4000/256 = 15.6Hz。

答案 1 :(得分:2)

如果您要提供样本数据集,将会很有帮助。

我的猜测是你有所谓的抽样工件。 DC(频率0)处的强信号表明情况就是这样。

您应该始终确保输入数据中的平均值为零 - 找到平均值并在调用fft之前从每个采样点中减去它是好的做法。

同样,您必须小心采样窗口工件。重要的是第一个和最后一个数据点接近零,否则从采样窗口外部到内部的“步骤”会产生以不同频率注入大量能量的效果。

最重要的是,进行fft分析需要更多的关注,而不仅仅是回收某处发现的fft例程。

以下是问题中描述的10Hz信号的前100个采样点,按摩以避免采样伪像

> sinx[1:100]
  [1]  0.000000e+00  6.279052e-02  1.253332e-01  1.873813e-01  2.486899e-01  3.090170e-01  3.681246e-01  4.257793e-01  4.817537e-01  5.358268e-01
 [11]  5.877853e-01  6.374240e-01  6.845471e-01  7.289686e-01  7.705132e-01  8.090170e-01  8.443279e-01  8.763067e-01  9.048271e-01  9.297765e-01
 [21]  9.510565e-01  9.685832e-01  9.822873e-01  9.921147e-01  9.980267e-01  1.000000e+00  9.980267e-01  9.921147e-01  9.822873e-01  9.685832e-01
 [31]  9.510565e-01  9.297765e-01  9.048271e-01  8.763067e-01  8.443279e-01  8.090170e-01  7.705132e-01  7.289686e-01  6.845471e-01  6.374240e-01
 [41]  5.877853e-01  5.358268e-01  4.817537e-01  4.257793e-01  3.681246e-01  3.090170e-01  2.486899e-01  1.873813e-01  1.253332e-01  6.279052e-02
 [51] -2.542075e-15 -6.279052e-02 -1.253332e-01 -1.873813e-01 -2.486899e-01 -3.090170e-01 -3.681246e-01 -4.257793e-01 -4.817537e-01 -5.358268e-01
 [61] -5.877853e-01 -6.374240e-01 -6.845471e-01 -7.289686e-01 -7.705132e-01 -8.090170e-01 -8.443279e-01 -8.763067e-01 -9.048271e-01 -9.297765e-01
 [71] -9.510565e-01 -9.685832e-01 -9.822873e-01 -9.921147e-01 -9.980267e-01 -1.000000e+00 -9.980267e-01 -9.921147e-01 -9.822873e-01 -9.685832e-01
 [81] -9.510565e-01 -9.297765e-01 -9.048271e-01 -8.763067e-01 -8.443279e-01 -8.090170e-01 -7.705132e-01 -7.289686e-01 -6.845471e-01 -6.374240e-01
 [91] -5.877853e-01 -5.358268e-01 -4.817537e-01 -4.257793e-01 -3.681246e-01 -3.090170e-01 -2.486899e-01 -1.873813e-01 -1.253332e-01 -6.279052e-02

这是fft频域的绝对值

 [1] 7.160038e-13 1.008741e-01 2.080408e-01 3.291725e-01 4.753899e-01 6.653660e-01 9.352601e-01 1.368212e+00 2.211653e+00 4.691243e+00 5.001674e+02
[12] 5.293086e+00 2.742218e+00 1.891330e+00 1.462830e+00 1.203175e+00 1.028079e+00 9.014559e-01 8.052577e-01 7.294489e-01

答案 2 :(得分:1)

自从我完成FFT之后已经有一段时间了,但这就是我记得的内容

FFT通常将复数作为输入和输出。所以我不确定输入和输出的实部和虚部如何映射到数组。

我真的不明白你在做什么。在第一个例子中,您说您处理10Hz的样本缓冲区,采样率为1000 Hz?所以你应该每秒有10个缓冲区,每个缓冲区有100个样本。我不知道你的输入数组至少有228个样本。

通常输出缓冲器的前半部分是从0频率(= dc偏移)到1/2采样率的频率区间。而下半部分是负频率。如果你的输入只是真实数据,假想信号为0,则负频率相同。输出上的实/虚信号的关系包含来自输​​入信号的相位信息。

答案 3 :(得分:1)

我在数学和信号处理方面也有点生疏,但附加信息我可以试一试。

如果您想知道每个箱的信号能量,您需要复杂输出的幅度。所以只看实际输出是不够的。即使输入只是实数。对于每个bin,输出的幅度是sqrt(real ^ 2 + imag ^ 2),就像毕达哥拉斯一样: - )

bins 0到449是从0 Hz到500 Hz的正频率。箱500到1000是负频率,应该与实信号的正值相同。如果您处理一个缓冲区,则每隔一个频率和数组索引排列很好。因此,指数6处的峰值对应于6Hz,因此有点奇怪。这可能是因为您只查看实际输出数据,并将实数和虚数数据组合在一起,得到指数10处的预期峰值。频率应线性映射到二进制位。

0处的峰值表示DC偏移。

答案 4 :(得分:1)

bin i的频率为i *(samplerate / n),其中n是FFT输入窗口中的采样数。

如果您正在处理音频,由于音高与频率对数成正比,音频的音高分辨率会随着频率的增加而增加 - 很难准确地解析低频信号。为此,您需要使用更大的FFT窗口,这会降低时间分辨率。对于给定的采样率,存在频率与时间分辨率的权衡。

你提到一个大值为0的bin - 这是频率为0的bin,即DC组件。如果这个很大,那么大概你的价值观通常是正面的。 Bin n / 2(在你的情况下为256)是奈奎斯特频率,是采样率的一半,这是在此速率下采样信号中可以分辨的最高频率。

如果信号是真实的,则区间n / 2 + 1到n-1将分别包含区间n / 2-1到1的复共轭。 DC值仅出现一次。

答案 5 :(得分:1)

正如其他人所说,样本在频域中间隔相等(不是对数)。

例如1,你应该得到这个:

alt text http://home.comcast.net/~kootsoop/images/SINE1.jpg

对于另一个例子,你应该得到

alt text http://home.comcast.net/~kootsoop/images/SINE2.jpg

因此,关于峰值位置,您的答案似乎都是正确的。

我没有得到的是大型DC组件。您确定要生成正弦波作为输入吗?输入是否为负数?对于正弦波,如果您获得足够的周期,DC应该接近于零。

答案 6 :(得分:1)

另一种途径是制作您正在寻找的每个音符中心频率Goertzel's Algorithm

一旦算法的一个实现工作,你可以使它需要参数来设置它的中心频率。有了这个,您可以轻松地运行其中的88个或您在集合中需要的内容并扫描峰值。

Goertzel算法基本上是单个bin FFT。使用这种方法,你可以按照音符自然地放置你的箱子。

来自维基百科的一些伪代码:

s_prev = 0
s_prev2 = 0
coeff = 2*cos(2*PI*normalized_frequency);
for each sample, x[n],
  s = x[n] + coeff*s_prev - s_prev2;
  s_prev2 = s_prev;
  s_prev = s;
end
power = s_prev2*s_prev2 + s_prev*s_prev - coeff*s_prev2*s_prev;

表示前两个样本的两个变量将保留用于下一次迭代。然后,这可以在流应用程序中使用。我想也许功率计算也应该在循环内部。 (但是在Wiki文章中没有这样描述。)

在音调检测情况下,将有88个不同的系数,88对先前的样本,并且将产生88个功率输出样本,指示该频率仓中的相对水平。

答案 7 :(得分:0)

WaveyDavey说,他正在通过计算机的音频硬件从麦克风中捕获声音,但他的结果并非以零为中心。这听起来像是硬件问题。它应该以零为中心。

当房间安静时,来自声音API的值流应非常接近0幅度,环境噪声略有+ - 变化。如果房间中存在振动声音(例如钢琴,长笛,声音),则数据流应该显示基本上基于正弦波的正波和负波,并且平均值接近零。如果不是这种情况,系统会有一些恐惧!

-Rick