我正在编写程序性音频文件的应用程序,我必须分析我的新文件,获取其频谱并在其计算中更改它。
我想用快速傅立叶变换(FFT)来做到这一点。这是我的递归C#FFT:
void ft(float n, ref Complex[] f)
{
if (n > 1)
{
Complex[] g = new Complex[(int) n / 2];
Complex[] u = new Complex[(int) n / 2];
for (int i = 0; i < n / 2; i++)
{
g[i] = f[i * 2];
u[i] = f[i * 2 + 1];
}
ft(n / 2, ref g);
ft(n / 2, ref u);
for (int i = 0; i < n / 2; i++)
{
float a = i;
a = -2.0f * Mathf.PI * a / n;
float cos = Mathf.Cos(a);
float sin = Mathf.Sin(a);
Complex c1 = new Complex(cos, sin);
c1 = Complex.Multiply(u[i], c1);
f[i] = Complex.Add(g[i], c1);
f[i + (int) n / 2] = Complex.Subtract(g[i], c1);
}
}
}
鼓舞人心的例子是
然后我将结果与来自wolframalpha的结果进行了比较,输入相同0.6,0.7,0.8,0.9
,但结果不一样。我的结果是Wolfram的两倍,虚部是Wolfram的-2倍。
此外,wiki表示可以使用
计算FFT的倒数
但我比较输入和输出,它们是不同的。
有谁知道什么是错的?
答案 0 :(得分:2)
不同的实现通常使用离散傅立叶变换(DFT)的不同定义,并且具有相应的不同结果。实现之间的对应关系通常相当简单(例如缩放因子)。
更具体地说,您的实现基于以下DFT定义:
另一方面,默认情况下,Wolfram alpha使用a definition,在调整为基于0的索引后,它看起来像:
相应地,可以将您的实现结果转换为匹配Wolfram alpha&:#/ p>
void toWolframAlphaDefinition(ref Complex[] f)
{
float scaling = (float)(1.0/Math.Sqrt(f.Length));
for (int i = 0; i < f.Length; i++)
{
f[i] = scaling * Complex.Conjugate(f[i]);
}
}
现在,使用正向变换计算逆DFT,直接实现公式
你提供的将是:
void inverseFt(ref Complex[] f)
{
for (int i = 0; i < f.Length; i++)
{
f[i] = Complex.Conjugate(f[i]);
}
ft(f.Length, ref f);
float scaling = (float)(1.0 / f.Length);
for (int i = 0; i < f.Length; i++)
{
f[i] = scaling * Complex.Conjugate(f[i]);
}
}
在原始序列ft
上调用0.6, 0.7, 0.8, 0.9
可以获得转换后的序列3, -0.2+0.2j, -0.2, -0.2-0.2j
。
此变换序列的进一步调用inverseFt
应该会返回到原始序列0.6, 0.7, 0.8, 0.9
(在一些合理的浮点错误内),如this live demo所示。