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

时间:2020-03-06 14:46:33  来源:igfitidea点击:

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

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

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

采样率是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数组中峰的索引与频率相关联?

解决方案

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

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

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

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

我对数学和信号处理也有些不满意,但是有了其他信息,我可以试一试。

如果我们想知道每个仓的信号能量,则需要复数输出的幅度。因此,仅查看实际输出是不够的。即使输入仅是实数。对于每个bin,输出的大小为sqrt(real ^ 2 + imag ^ 2),就像pythagoras :-)

bin 0至449是0 Hz至500 Hz的正频率。 bin 500到1000是负频率,对于真实信号应与正频率相同。如果每秒处理一个缓冲区,则频率和数组索引会很好地对齐。因此,索引6处的峰值对应于6Hz,这有点奇怪。这可能是因为我们仅查看真实的输出数据,并且真实的和虚构的数据组合在一起以在索引10处给出预期的峰值。频率应线性映射到bin。

0处的峰值表示直流偏移。

如果忽略虚部,则频率分布在各个仓之间呈线性关系:

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

因此,对于第一个示例,假设我们有256个bin,最大的bin对应于1000/2 * 6/256 = 11.7 Hz的频率。
由于输入为10Hz,所以我猜想bin 5(9.7Hz)也有很大的分量。
为了获得更好的精度,我们需要获取更多的样本,以获取更小的箱柜。

第二个示例给出8000/2 * 29/256 = 453Hz。再次,关闭,但我们需要更多的垃圾箱。
我们在这里的分辨率仅为4000/256 = 15.6Hz。

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

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

我们提到一个在0处具有较大值的仓-这是频率为0的仓,即DC分量。如果这个值很大,那么大概价值观通常是积极的。 Bin n / 2(在情况下为256)是奈奎斯特频率,是采样率的一半,这是可以以此速率在采样信号中解析的最高频率。

如果信号是实信号,则仓n / 2 + 1至n-1将分别包含仓n / 2-1至1的复共轭。 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

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

例如1,我们应该获得以下信息:

替代文字http://home.comcast.net/~kootsoop/images/SINE1.jpg

对于另一个示例,我们应该获得

替代文字http://home.comcast.net/~kootsoop/images/SINE2.jpg

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

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

另一个途径是针对我们要查找的每个音符中心频率制定Goertzel算法。

一旦实现了该算法的一种实现,我们就可以使其采用所需参数来设置其中心频率。这样一来,我们就可以轻松运行其中的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个功率输出样本,这些样本指示该频率仓中的相对电平。

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

当房间安静时,来自声音API的值流应非常接近于0振幅,环境噪声会有轻微的+变化。如果房间中存在振动声(例如钢琴,长笛,声音),则数据流应显示基本为正弦波的正负两个方向的波,平均接近零。如果不是这种情况,则系统会出现一些功能!

-里克