如何使用 FFT 或 DFT 重新采样音频

信息处理 声音的 插值 重采样 C#
2022-01-07 04:13:11

我通过首先执行 FFT 来对语音音频进行下采样,然后只获取我需要的部分结果,然后执行逆 FFT。但是,只有当我使用的频率都是 2 的幂次方时,它才能正常工作,比如从 32768 到 8192 的下采样。我对 32k 数据执行 FFT,丢弃数据的前 3/4,然后执行对剩余的 1/4 进行逆 FFT。

但是,每当我尝试对未正确排列的数据执行此操作时,都会发生以下两种情况之一:我正在使用的数学库 (Aforge.Math) 会出现问题,因为我的样本不是 2 的幂。如果我尝试对样本进行零填充以使它们成为二的幂,那么它会在另一端出现乱码。我也尝试改用 DFT,但它最终变得异常缓慢(这需要实时完成)。

在初始 FFT 和最后的逆 FFT 上,我将如何正确地对 FFT 数据进行零填充?假设我有一个 44.1khz 的样本需要达到 16khz,我目前正在尝试这样的事情,样本大小为 1000。

  1. 最后将输入数据填充到 1024
  2. 执行 FFT
  3. 将前 512 个项目读入一个数组(我只需要前 362 个,但需要 ^2)
  4. 执行逆 FFT
  5. 将前 362 个项目读入音频播放缓冲区

由此,我最终得到了垃圾。做同样的事情但由于样本已经是 ^2 而不必在第 1 步和第 3 步填充,会给出正确的结果。

3个回答

第一步是验证您的起始采样率和目标采样率都是有理数因为它们是整数,所以它们自动是有理数。如果其中一个不是有理数,仍然可以改变采样率,但这是一个非常不同的过程并且更加困难。

下一步是考虑这两个采样率。在这种情况下,起始采样率为 44100,这会影响到22325272. 目标采样率,16000,因素2753. 因此,要将起始采样率转换为目标率,我们必须通过以下方式抽取3272并插值255.

无论您想如何重新采样数据,都必须完成前面的步骤。现在让我们谈谈如何使用 FFT 来实现。使用 FFT 重新采样的技巧是选择 FFT 长度,以使一切顺利进行。这意味着选择一个是抽取率倍数的 FFT 长度(在本例中为 441)。为了示例的目的,我们选择 FFT 长度 441,尽管我们可以选择 882、1323 或 441 的任何其他正倍数。

要了解这是如何工作的,有助于将其可视化。您从一个音频信号开始,在频域中看起来类似于下图。 44.1 kHz 采样率

当您完成处理后,您希望将采样率降低到 16 kHz,但您希望失真尽可能小。换句话说,您只需将上图中的所有内容保持在 -8 kHz 到 +8 kHz 之间,并放弃其他所有内容。结果如下图。 在此处输入图像描述

请注意,采样率不是按比例缩放的,它们只是为了说明概念。

选择作为抽取因子倍数的 FFT 长度的好处在于,您可以简单地通过删除 FFT 结果的一部分来重新采样,然后对剩下的内容进行反 FFT。在我们的示例中,您对 441 个数据样本进行 FFT,从而在频域中获得 441 个复杂样本。我们要抽取 441 并插值 160 (255),因此我们保留了代表 -8 kHz 到 +8 kHz 频率的 160 个样本。然后我们对这些样本进行反 FFT 和 presto!您有 160 个以 16 kHz 采样的时域样本。

您可能会怀疑,有几个潜在的问题。我将逐一介绍并解释如何克服它们。

  1. 如果您的数据不是抽取因子的倍数,您会怎么做?您可以通过用足够的零填充数据的末尾以使其成为抽取因子的倍数来轻松克服这一问题。数据在 FFT 之前被填充。

  2. 尽管我解释的方法非常简单,但它也很不理想,因为它会在时域中引入振铃和其他令人讨厌的伪影。您可以通过在删除高频数据之前过滤频域数据来避免这种情况。你可以通过 FFT'ing 你的长度过滤器来做到这一点l,填充您的数据(在 FFT 之前)至少l1零(请注意,数据样本的数量和填充样本的数量都必须是抽取因子的正倍数 - 您可以增加填充长度以满足此约束),对填充数据进行 FFT,乘以频域数据和滤波器,然后将高频 (> 8 kHz) 结果混叠为低频 (< 8 kHz) 结果,然后丢弃高频结果。不幸的是,由于频域中的过滤本身就是一个很大的话题,我将无法在这个答案中更详细地介绍。不过,我要说的是,如果您过滤并处理多个数据块中的数据,您将需要实现Overlap-and-AddOverlap-and-Save以使过滤连续。

我希望这有帮助。

编辑:频域样本的起始数量和频域样本的目标数量之间的差异需要是偶数,以便您可以从结果的正侧删除与结果的负侧相同数量的样本。在我们的示例中,起始样本数是抽取率,即 441,目标样本数是插值率,即 160。差异为 279,不是偶数。解决方案是将 FFT 长度加倍到 882,这导致目标样本数也加倍到 320。现在差异是偶数,您可以毫无问题地删除适当的频域样本。

虽然上面的答案真的很完整:

这是它的要点:

  1. 要对信号进行下采样,它需要是一个整数。在对信号进行下采样之前,您需要对信号进行过滤。
  2. 您可以通过首先对信号进行上采样/插值来实现有理数下采样。
  3. 上采样只是插入零,然后过滤信号。
  4. 所以要达到3/4的采样率。通过在每个信号样本之间插入 4 个零来对信号进行上采样。应用过滤器。然后过滤信号并删除每 4 个信号样本中的每 3 个。

这方面的详细信息:

http://www.ws.binghamton.edu/fowler/fowler%20personal%20page/EE523_files/Ch_14_1%20Subband%20Intro%20&%20Multirate%20(PPT).pdf

另外:除非绝对必要,否则不要计算 FFT 来计算 IFFT。这是一个非常缓慢的过程,并且被认为不适合大多数信号处理任务。FFT 通常用于分析问题或仅在频域中应用信号处理。

正如 Bjorn Roche 所说,为此使用 FFT 将非常无效。但是在这里它以一种非常简单的方式使用频域中的上采样滤波器和下采样方法。

1 - 获取长度为 N 的所需矢量信号。

2 - 执行 N 点 FFT。

3 - 在 FFT 向量的中间用 160*N 个零填充 FFT。

4 - 执行 IFFT

5 - 从 441 个样本中选择一个,丢弃其他 440 个。

您将留下一个长度为 N*160/441 的向量,这将是您的重采样信号。

如您所见,您正在做很多无意义的计算,因为大部分结果将被丢弃。但是,如果您可以访问执行 FFT 的代码,您实际上可以稍微调整一下,以便它只计算您最终会得到的 IFFT 结果,而不是您将丢弃的结果。

希望能帮助到你。