我是否正确处理离线 FFT?

信息处理 算法 傅里叶变换 声音的 fft
2022-02-08 17:52:48

我需要一些帮助来澄清 FFT 及其代表的含义。我有一个包含压缩音频的缓冲区。由于限制,我无法处理完整的未压缩音频,但可以一次解压缩小片段。

假设我需要 10 秒的未压缩样本,我需要将其存储在适当 PCMaudiobuffer的大小中10 * 44100 * sizeof(float),并且我会有441000样本。然后我循环遍历这些441000长度为 1024(重叠 512)的样本。

for(int i =0; i < 441000; i += 512)
{
   //code to copy (i + 1024) from PCMaudiobuffer to tempbuffer. (not shown)

   //perform FFT
   InPlaceFFT(tempbuffer);

   //copy the first 512 values of the tempbuffer across to 
   //a new buffer so tempbuffer can be reused in the loop
   CopyArray(512, finalbuffer);
}

假设所有这些都是正确的,这就是我感到困惑的地方。我是否只将前 512 个值 (N/2) 复制到finalbuffer? (我正在使用 Accelerate 框架的 FFT 方法)。这是离线执行 FFT 的有效/正确方法吗?最后,我希望能够从finalbuffer. 为此,我只需每44100(1 秒)循环一次并计算幅度,还是 1 秒对于频谱来说通常太不准确?

我可能误解了这一切,所以请随时告诉我把所有这些都扔到窗外:) 感谢您的帮助,这很令人困惑!

编辑 关于此的 Apple 文档并不容易理解,但我使用的是vDSP_fft_zrip中概述的方法。(Apple 网站的格式有时会混淆锚点位置,因此您可能需要稍微向下滚动)。我发现这篇文章是关于如何使用它的有用指南。谢谢。

1个回答

您在问题中遗漏了一条重要信息,那就是 InPlaceFFT() 函数的原型定义。需要注意的最重要的事情是 FFT 返回复数值。可能是函数期望数据被格式化,使得实部和虚值交错,或者函数期望实部首先放在缓冲区中,而虚部放在缓冲区的末尾。缓冲。也可能是该函数返回数据位反转(请参阅此处http://en.wikipedia.org/wiki/Cooley%E2%80%93Tukey_FFT_algorithm的“数据重新排序、位反转和就地算法”部分)。

另一个潜在问题是作为参数传递的缓冲区的长度,即临时缓冲区。如果您确定 InPlaceFFT() 函数需要 float* 作为输入,您可能必须传递长度至少为 1024*sizeof(float) 或 2048*sizeof(float) 的缓冲区。如果 InPlaceFFT() 函数被限制为在实际输入上工作,则 1024 的缓冲区大小可能就足够了。但是您应该更好地查看 InPlaceFFT() 如何工作的文档,以了解临时缓冲区的大小应该有多大以及输出在返回后如何在临时缓冲区中布局。另一件看起来很奇怪的事情是您不需要将 FFT 大小传递给 InPlaceFFT()。

如果您确定采样率始终为 44.1kHz,则可以将 44.1kHz 硬编码到代码中,否则您可能希望通过将采样率加载到变量中并在代码中使用它来使代码更加灵活。

1024 点 FFT 返回 1024 个值(复数)。您只需要前 513 个输出值(这些值通常称为 bin),其余的原则上是多余的(尽管可以很方便地拥有)。如果你想计算幅度谱,你需要计算复数的绝对值(所以你的 abs() 函数应该对复数起作用),原则上你已经完成了。唯一要做的就是通过将索引 1 与索引 511 的值乘以 2 来更正它们。索引 0 和索引 512 处的值是真实的,不需要更正。如果您要在 GUI 中绘制幅度谱,您可能希望以 dB 为单位绘制幅度。因此,您需要计算幅度值的对数(以 10 为底)并乘以 20。

如果您可以使用 InPlaceFFT() 的文档更新您的帖子,那将会很有用。