MathNet.Numerics 中的傅立叶变换(卷积)有什么问题? - C#

What is wrong with my Fourier Transformation (Convolution) in MathNet.Numerics? - C#

我正在尝试使用 MathNet.Numerics's FFT(快速傅立叶变换)在 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 被一些奇怪的背景损坏 sound/noise,即使我没有在 FFT 和 IFFT 之间做任何事情。

我错过了什么?

MathNet.Numerics.IntegralTransform.Fourier 的当前实现(参见 Fourier.cs and Fourier.Bluestein.cs) 对任何不是 2 的幂的 FFT 长度使用 Bluestein's algorithm

此算法涉及创建 Bluestein 序列(其中包括与 n2 成比例的项),直到版本 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;
}

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

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

:此观察结果基于 MathNet.Numerics 的 3.6.0 版,尽管该限制似乎存在于早期版本中(Bluestein 序列代码有远至版本 2.1.1 没有显着变化)。


更新 2015/04/26:

在我发布这篇文章并在 an similar issue on github bugtracking 上发表评论后,问题很快在 MathNet.Numerics 中得到解决。该修复程序现在应该在 3.7.0 版中可用。但是请注意,出于性能原因,您可能仍希望填充为 2 的幂,尤其是因为您已经需要为线性卷积进行零填充。