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 的幂,尤其是因为您已经需要为线性卷积进行零填充。
我正在尝试使用 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 的幂,尤其是因为您已经需要为线性卷积进行零填充。