了解FFT输出

我需要一些帮助来理解DFT / FFT计算的输出。

我是一名经验丰富的软件工程师,需要解释一些智能手机加速度计读数,例如查找主要频率。不幸的是,十五年前,我睡遍了大部分大学EE课程,但在过去的几天里,我一直在阅读DFT和FFT(显然无济于事)。

请不要回答“去上EE课”。如果我的雇主愿意付钱给我,我实际上打算这样做。:)

所以这是我的问题:

我捕获了一个32 Hz的信号。下面是一个 1 秒的 32 点示例,我在 Excel 中绘制了该示例。

enter image description here

然后,我从哥伦比亚大学得到了一些用Java编写的FFT代码(在遵循了“Java中可靠和快速的FFT”帖子中的建议之后)。

该程序的输出如下所示。我相信它正在运行一个就地FFT,因此它重新使用相同的缓冲区进行输入和输出。

Before: 

Re: [0.887  1.645  2.005  1.069  1.069  0.69  1.046  1.847  0.808  0.617  0.792  1.384  1.782  0.925  0.751  0.858  0.915  1.006  0.985  0.97  1.075  1.183  1.408  1.575  1.556  1.282  1.06  1.061  1.283  1.701  1.101  0.702  ]

Im: [0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  ]

After: 

Re: [37.054  1.774  -1.075  1.451  -0.653  -0.253  -1.686  -3.602  0.226  0.374  -0.194  -0.312  -1.432  0.429  0.709  -0.085  0.0090  -0.085  0.709  0.429  -1.432  -0.312  -0.194  0.374  0.226  -3.602  -1.686  -0.253  -0.653  1.451  -1.075  1.774  ]

Im: [0.0  1.474  -0.238  -2.026  -0.22  -0.24  -5.009  -1.398  0.416  -1.251  -0.708  -0.713  0.851  1.882  0.379  0.021  0.0  -0.021  -0.379  -1.882  -0.851  0.713  0.708  1.251  -0.416  1.398  5.009  0.24  0.22  2.026  0.238  -1.474  ]

所以,在这一点上,我不能对输出进行正面或反面的处理。我理解DFT概念,例如实部是分量余弦波的振幅,虚部是分量正弦波的振幅。我也可以按照《数字信号处理科学家和工程师指南》中的这张图:enter image description here

所以我的具体问题是:

  1. 从FFT的输出中,我如何找到“最常出现的频率”?这是我对加速度计数据分析的一部分。我应该读取实(余弦)还是虚(正弦)数组?

  2. 我在时域中有一个32点输入。FFT 的输出难道不应该是实数的 16 元素数组和虚数的 16 元素数组吗?为什么程序给我32号的实数和虚数阵列输出?

  3. 与上一个问题相关,如何解析输出数组中的索引?鉴于我输入的32个样本以32 Hz采样,我的理解是,16个元素的数组输出的索引应该均匀分布到采样率(32 Hz)的1/2,所以我理解数组的每个元素表示(32 Hz * 1/2)/ 16 = 1 Hz是否正确?

  4. 为什么FFT输出有负值?我认为这些值表示正弦波的振幅。例如,Real[ 3 ] = -1.075的输出应该意味着频率为3的余弦波的幅度为-1.075。是吗?振幅怎么可能是负的?


答案 1
  1. 你既不应该寻找复数的实数或想象部分(你的实数和虚数组是什么)。相反,您要查找定义为 sqrt(实数 * 实数 + imag * imag)的频率的大小。此数字将始终为正数。现在,您只需搜索最大值(忽略数组中的第一个条目。这是您的直流失调,不携带任何与频率相关的信息)。

  2. 您将获得 32 个实数输出和 32 个虚数输出,因为您使用的是从复杂到复杂的 FFT。请记住,您已将 32 个样本转换为 64 个值(或 32 个复数值),方法是使用零个虚部进行扩展。这导致对称FFT输出,其中频率结果出现两次。一旦准备好在输出0到N/2中使用,一旦在输出中镜像N/2到N。在你的例子中,最简单的方法是简单地忽略输出N / 2到N。你不需要它们,它们只是你如何计算FFT的人工制品。

  3. 频率到 fft-bin 方程为 (bin_id * freq/2) / (N/2),其中 freq 是采样频率(又名 32 Hz,N 是 FFT 的大小)。在您的情况下,这简化为每个箱子1 Hz。条柱 N/2 到 N 表示负频率(我知道这是一个奇怪的概念)。对于您的情况,它们不包含任何重要信息,因为它们只是第一个N / 2频率的镜像。

  4. 每个条柱的实部和虚部形成一个复数。如果实部和虚部为负,而频率本身的大小为正,则没关系(请参阅我对问题1的回答)。我建议你仔细阅读复数。解释它们是如何工作的(以及为什么它们有用)超出了在单个堆栈溢出问题中可以解释的内容。

注意:您可能还想了解什么是自相关,以及如何使用它来查找信号的基频。我有一种感觉,这就是你真正想要的。


答案 2

你已经有了一些很好的答案,但我只想补充一点,你真的需要在FFT之前对你的时域数据应用一个窗口函数,否则由于频谱泄漏,你的频谱中会得到令人讨厌的伪影。


推荐