3

我正在尝试使用MathNet.Numerics'sFFT(快速傅立叶变换)在 2 个音频文件之间进行简单的卷积,但是在 IFFT 之后我得到了一些奇怪的背景声音。

我测试了是卷积还是转换导致了问题,我发现问题已经在 FFT -> IFFT (Inverze FFT) 转换中显示出来。

我的简单 FFT 和 IFFT 代码:

float[] sound; //here are stored my samples

Complex[] complexInput = new Complex[sound.Length];
for (int i = 0; i < complexInput.Length; i++)
{
      Complex tmp = new Complex(sound[i],0);
      complexInput[i] = tmp;
 }

MathNet.Numerics.IntegralTransforms.Fourier.Forward(complexInput);

//do some stuff

MathNet.Numerics.IntegralTransforms.Fourier.Inverse(complexInput);

float[] outSamples = new float[complexInput.Length];

for (int i = 0; i < outSamples.Length; i++)
     outSamples[i] = (float)complexInput[i].Real;

在此之后outSamples,即使我没有在 FFT 和 IFFT 之间做任何事情,它们也会被一些奇怪的背景声音/噪音破坏。

我错过了什么?

4

1 回答 1

4

MathNet.Numerics.IntegralTransform.Fourier(参见Fourier.cs和)的当前实现对任何非 2 次方的 FFT 长度Fourier.Bluestein.cs使用Bluestein 算法。

该算法涉及创建 Bluestein 序列(其中包括与 n 2成比例的项),直到版本 3.6.0 使用以下代码:

static Complex[] BluesteinSequence(int n)
{
  double s = Constants.Pi/n;
  var sequence = new Complex[n];

  for (int k = 0; k < sequence.Length; k++)
  {
    double t = s*(k*k); // <--------------------- (k*k) 32-bit int expression
    sequence[k] = new Complex(Math.Cos(t), Math.Sin(t));
  }

  return sequence;
}

n对于大于 46341 的任何大小(k*k),此实现中的中间表达式使用算术(根据MSDN 整数类型参考表int的 32 位类型)计算,这会导致. 因此,当前的实现仅支持输入数组大小,即 2 的幂或 2 的非幂,最高为 46341(包括在内)。kMathNet.Numerics.IntegralTransfom.Fourier

因此,对于大型输入数组,解决方法可能是将输入填充到 2 的下一个幂。

注意:此观察基于 3.6.0 版本MathNet.Numerics,尽管在早期版本中似乎存在限制(早在 2.1.1 版本之前,Bluestein 序列代码没有显着变化)。


2015 年 4 月 26 日更新

在我发布此内容并在 github bugtracking 上对类似问题发表评论后,该问题很快在MathNet.Numerics. 该修复程序现在应该在 3.7.0 版中可用。但是请注意,出于性能原因,您可能仍希望填充为 2 的幂,特别是因为您已经需要对线性卷积进行零填充。

于 2015-04-22T14:44:00.340 回答