3

试图理解我正在使用的 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) ... period = 18 个采样点

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

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

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

4

8 回答 8

2

如果忽略虚部,频率分布在 bin 之间是线性的:

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

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

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

于 2008-10-01T20:19:34.687 回答
2

如果您要提供示例数据集,这将很有帮助。

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

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

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

底线是,进行 fft 分析比简单地回收某处找到的 fft 例程需要更多的注意。

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

> 辛克斯[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.358
 [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.048275e-01 9.29
 [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.8228873e-01 9.6850
 [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.845440e-01 6.370
 [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.2533052e-01 6.279
 [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.8175268e-01 -5.358 e-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.0482751e-01 -9.27 e-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.8228873e-01 -9.65 e-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.845240e-01 -6.34 e-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.2533052e-01 -6.29 e-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.60126
[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
于 2008-10-02T02:07:28.190 回答
1

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

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

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

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

于 2008-09-26T11:16:55.387 回答
1

我对数学和信号处理也有点生疏,但有了额外的信息,我可以试一试。

如果您想知道每个 bin 的信号能量,您需要复数输出的幅度。所以只看真实的输出是不够的。即使输入只是实数。对于每个 bin,输出的大小是 sqrt(real^2 + imag^2),就像 pythagoras :-)

bin 0 到 449 是从 0 Hz 到 500 Hz 的正频率。bin 500 到 1000 是负频率,应该与真实信号的正频率相同。如果您每秒处理一个缓冲区,则频率和数组索引排列得很好。所以索引 6 处的峰值对应于 6Hz,所以这有点奇怪。这可能是因为您只查看实际输出数据,而实部和虚部数据结合起来会在索引 10 处给出预期峰值。频率应该线性映射到 bin。

0 处的峰值表示 DC 偏移。

于 2008-09-26T11:45:22.780 回答
1

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

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

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

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

于 2008-10-01T20:47:37.007 回答
1

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

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

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

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

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

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

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

于 2008-10-02T02:59:59.763 回答
1

另一种方法是为您正在寻找的每个音符中心频率制作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 个功率输出样本,指示该频率仓中的相对电平。

于 2009-01-04T17:30:03.160 回答
0

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

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

-瑞克

于 2009-04-03T04:07:01.543 回答