VB FFT-难以理解结果与频率的关系
试图了解我正在使用的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振幅,环境噪声会有轻微的+变化。如果房间中存在振动声(例如钢琴,长笛,声音),则数据流应显示基本为正弦波的正负两个方向的波,平均接近零。如果不是这种情况,则系统会出现一些功能!
-里克