了解FFT输出


87

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

我是一位经验丰富的软件工程师,需要解释一些智能手机加速度计的读数,例如查找主频率。不幸的是,我15年前睡过大部分大学的EE课程,但最近几天我一直在阅读DFT和FFT(显然没有用)。

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

所以这是我的问题:

我已经捕获到32 Hz的信号。这是我在Excel中绘制的32分的1秒示例。

在此处输入图片说明

然后,我从哥伦比亚大学获得了一些用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的概念,例如,实部是分量余弦波的幅度,虚部是分量正弦波的幅度。我也可以从伟大的著作“数字信号处理科学家和工程师指南”中遵循以下图表: 在此处输入图片说明

所以我的具体问题是:

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

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

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

  4. 为什么FFT输出为负值?我认为这些值代表正弦波的振幅。例如,对于频率为3的余弦波,Real [3] = -1.075的输出应表示幅度为-1.075。振幅如何为负?


您想从加速度计读数中计算出什么:速度,距离?加速度计读数的噪声遵循高斯分布,我看不到正弦波的拟合将如何解决这一问题。
阿里

2
应该删除Java标记,因为它比特定语言更通用
user3791372

从哥伦比亚大学的角度来看,这根本没有效率。这是使用蝴蝶查询表对Cooley-Tucky进行的简单,未优化的实现,并且位反转是手动完成的,而不是使用现有的库函数
Mark Jeronimus

@MarkJeronimus:您能推荐使用Java的高效FFT实现吗?如果我没记错的话,我选择哥伦比亚大学代码的原因是FFTW库太复杂而无法在Android智能手机上运行。
stackoverflowuser2010,

我发现了一些分散的“优化”实现,但是它们基本上是N个大小一个算法,因此,如果需要一定范围的大小,则需要所有这些例程。实际上,我主要使用了Intel Integrated Performance Primitives(是的,从Java到JNA),但这不是免费的。在家里,我基本上使用与您链接的算法相同的算法,但在2005年使用教科书从零开始编写了该算法。它只是FFT(快速傅立叶变换),因此没有什么“快速”可以证明其名称为“快速FFT”。
Mark Jeronimus

Answers:


85
  1. 您既不应寻找复数的实数或虚数部分(即实数和虚数数组是什么)。相反,您要查找定义为sqrt的频率幅度(实数*实数+ imag * imag)。该数字将始终为正。现在,您需要搜索的只是最大值(忽略阵列中的第一个条目。这是您的DC偏移,不包含任何与频率相关的信息)。

  2. 由于使用的是复数到复数FFT,因此可以获得32个实数和32个虚数输出。请记住,通过将零个虚部扩展为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的大小)。在您的情况下,这简化为每个bin 1 Hz。N / 2至N档表示负频率(奇怪的概念,我知道)。对于您而言,它们不包含任何重要信息,因为它们只是前N / 2个频率的镜像。

  4. 每个bin的实部和虚部都形成一个复数。实部和虚部为负数而频率本身的幅度为正数也可以(请参阅我对问题1的回答)。我建议您阅读复数。解释它们的工作方式(以及为什么有用)超出了单个stackoverflow-question中可能解释的范围。

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


1
谢谢。关于1:我看到了这个Matlab页面,其中显示了频谱(mathworks.com/help/techdoc/ref/fft.html)。在该页面上是标题为“ y(t)的单幅振幅谱”的图。是否按照您的建议绘制了频率幅度,即sqrt(real ^ 2 + img ^ 2)?关于3:我仍然没有得到每个bin 2Hz的结果。在我的情况下,N = 32和freq = 32,对吗?因此,有N / 2 = 32/2 = 16个bin,最高频率(Nyquist)为freq / 2 = 32/2 = 16 Hz,导致每16个bin 16 Hz,每个bin 1 Hz?
stackoverflowuser2010

1
是的,该图显示了频谱的大小-| Y(f)|。绝对值条表示幅度。Bin宽度=采样率/ FFT大小。您的采样率为32 hz,FFT大小为32。是的,您对bin的宽度是正确的!
马特·蒙塔格

固定箱频率。
安德烈Chalella

1
好的答案,谢谢!抱歉,我参加聚会有点晚了,但是也许您可以回答我,频率幅度的多少单位(如您在第1点中提到的)是多少?就我而言,来自加速度计的值信号(是m / s ^ 2)。我不太清楚。
MarkusWüstenberg2014年

迷人!我的音乐可视化频率条全部从左到右镜像;答案#2解释了这一点!疯!!
Ryan S

11

您已经有了一些不错的答案,但是我要补充一点,您真的需要在FFT之前将窗函数应用于时域数据,否则由于频谱泄漏,您的频谱中会出现讨厌的伪影。


我很高兴自回答这个问题以来已经花费了很多时间。但是,您能否详细说明您的意思是什么人工制品?
MattHusz

1
@MattHusz:这些人工制品起源的总称是“光谱泄漏”-我现在在答案中添加了一个链接,以对此进行解释。我能描述这种效果的最好方法是,由于隐含的矩形窗口,您的频谱将被“抹去”。
Paul R

6

1)在第一个数组(这是DC分量)之外,在实际数组中查找具有最高值的索引。您可能需要大大高于32 Hz的采样率和更大的窗口大小,才能获得有意义的结果。

2)两个阵列的后半部分是前半部分的镜像。例如,请注意,实数数组(1.774)的最后一个元素与第二个元素(1.774)相同,而虚数数组(1.474)的最后一个元素是第二个元素负数

3)您可以以32 Hz的采样率获得的最大频率为16 Hz(奈奎斯特极限),因此每一步为2 Hz。如前所述,请记住第一个元素为0 Hz(即DC偏移)。

4)当然,负振幅是完全合理的。这仅表示信号“翻转”了-标准FFT基于余弦,通常在t = 0时值为1,因此在时间= 0时值为-1的信号将具有负振幅。


谢谢回复。(1)您的意思是我可以忽略虚数(正弦)数组吗?如果是,为什么?正弦分量肯定很重要吗?(2)为什么会发生这种镜像?仅仅是FFT算法的结果吗?大多数人都忽略镜像的一半吗?(3)如何计算2Hz的步长?我了解16Hz的奈奎斯特极限,因此,如果有16个(非镜像)数组元素,每个元素必须分别为16 Hz / 16 = 1 Hz?(4)为了找到主频率,我是否只是获取输出阵列中振幅值的绝对值?
stackoverflowuser2010

您不应在真实数组中寻找最大值,也不能忽略正弦/ I数组。相反,您需要复合复矢量的大小。发生镜像是因为一半的输入(I数组)全为零,因此结果具有一半的自由度。如果您的数据严格是真实的,则可以忽略它。
2011年

@duskwuff非常感谢:如果我找不到您要回答的问题,您给了我要发布的问题的答案:如何解释FFT的第二部分。我想修改数据并执行相反的运算,但我一直只得到一半的结果,因为在那部分我修改了错误的数据。再次感谢。
马丁

(3),到目前为止,step = 2Hz的值对我而言仍然是隐式的。我们有16个垃圾箱,由长度为16的数组表示。我们需要描述从0Hz到16Hz的所有频率。我假设每个垃圾箱都描述了这个范围的一部分,不是吗?
2013年

@krafter我认为它减半了,因为您不能从单个值推断出频率(因为没有重复)。
JVE999

5

请注意,即使具有窗口功能,“出现频率最高”也可能会溅入多个FFT仓中。因此,您可能必须使用更长的窗口,多个窗口或内插法才能更好地估计任何光谱峰的频率。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.