了解FFT输出

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

我是一名经验丰富的软件工程师,需要解读一些智能手机加速计读数,例如find主要频率。 不幸的是,我十五年前就读过大部分大学的EE课程,但在过去的几天里,我一直在阅读DFT和FFT(显然没有多大用处)。

请不要回答“去参加EE课”。 我实际上打算这样做,如果我的雇主将支付我。 🙂

所以这是我的问题:

我已经捕获了一个32赫兹的信号。 这是我在Excel中绘制的32分的1秒样本。

在这里输入图像说明

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

这个程序的输出如下。 我相信它正在运行一个就地FFT,所以它重新使用相同的缓冲区的input和输出。

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的概念,比如实部是分量余弦波的幅度,虚部是分量正弦波的幅度。 我也可以从“ 科学家和数字信号处理工程师指南 ” 这本伟大的书中看到这个图: 在这里输入图像说明

所以我的具体问题是:

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

  2. 我有一个在时间域的32点input。 FFT的输出不应该是用于实数的16元素arrays和用于虚数的16元素arrays? 为什么程序给我32和32的实际和虚构的数组输出?

  3. 与前面的问题相关,如何parsing输出数组中的索引? 假设我input了32个采样频率为32 Hz的样本,我的理解是16个元素的arrays输出应该使其索引均匀分布到1/2采样率(32 Hz),所以我正确理解每个元素数组表示(32 Hz * 1/2)/ 16 = 1 Hz?

  4. 为什么FFT输出有负值? 我认为这些值代表了正弦曲线的幅度。 例如,Real [3] = -1.075的输出对于频率为3的余弦波意味着-1.075的幅度。对吗? 振幅如何可能是负面的?

  1. 你既不应该寻找复数的真实或想象部分(那你的真实和想象的数组是什么)。 相反,您要查找定义为sqrt(real * real + imag * imag)的频率的大小。 这个数字永远是正数。 现在,你所要search的是最大值(忽略数组中的第一个条目,这是你的直stream偏移,并且没有频率相关的信息)。

  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赫兹每仓。 N / 2到N代表负频率(奇怪的概念,我知道)。 对于你的情况,他们不包含任何重要的信息,因为它们只是第一个N / 2频率的镜像。

  4. 每个垃圾箱的实际和虚拟部分形成一个复杂的数字。 如果实部和虚部都是负的,而频率本身的幅度是正的,那就没问题了(参见我对问题1的回答)。 我build议你阅读复数。 解释它们是如何工作的(以及它们为什么是有用的)超过了在单个堆栈溢出问题中可以解释的东西。

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

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

1)除了第一个值(即DC分量)之外,查找具有最高值的实数列中的索引。 你可能需要一个比32Hz高得多的采样率和一个更大的窗口大小,以获得有意义的结果。

2)arrays的后半部分是上半场的镜子。 例如,请注意,实数组(1.774)的最后一个元素与第二个元素(1.774)相同,而虚数组(1.474)的最后一个元素是第二个元素的负数

3)你可以在32Hz的采样速率下采集的最大频率是16Hz( 奈奎斯特限制 ),所以每一步都是2Hz。 如前所述,请记住,第一个元素是0 Hz(即DC偏移量)。

4)当然,负振幅是非常有意义的。 这只意味着信号被“翻转” – 标准的FFT基于余弦,在t = 0时通常具有值= 1,因此在时间= 0具有值= -1的信号将具有负的幅度。

请注意,即使使用窗口function,“出现频率最高”也可能会溅到多个FFT分档中。 因此,您可能需要使用更长的窗口,多个窗口或插值来更好地估计任何光谱峰值的频率。