我目前正在尝试编写一些傅里叶变换算法.我从一个简单的DFT算法开始,如数学定义中所述:
public class DFT {
public static Complex[] Transform(Complex[] input) {
int N = input.Length;
Complex[] output = new Complex[N];
double arg = -2.0 * Math.PI / (double)N;
for (int n = 0; n < N; n++) {
output[n] = new Complex();
for (int k = 0; k < N; k++)
output[n] += input[k] * Complex.Polar(1, arg * (double)n * (double)k);
}
return output;
}
}
Run Code Online (Sandbox Code Playgroud)
所以我用以下代码测试了这个算法:
private int samplingFrequency = 120;
private int numberValues = 240;
private void doCalc(object sender, EventArgs e) {
Complex[] input = new Complex[numberValues];
Complex[] output = new Complex[numberValues];
double t = 0;
double y = 0;
for (int i = 0; i < numberValues; i++) {
t = (double)i / (double)samplingFrequency;
y = Math.Sin(2 * Math.PI * t);
input[i] = new Complex(y, 0);
}
output = DFT.Transform(input);
printFunc(input);
printAbs(output);
}
Run Code Online (Sandbox Code Playgroud)
转换工作正常,但只有numberValues是samplingFrequency的多个数字(在这种情况下:120,240,360,...).这是我的240个值的结果:
http://s1.directupload.net/images/110928/n3m8hqg6.jpg
转型工作正常.
如果我想计算280个值,我得到这个结果:
http://s7.directupload.net/images/110928/qizoiqbt.jpg
如果我更改计算值的数量,为什么我得到的结果不正确?我不确定我的问题是否是我的代码问题或对DFT的数学定义的误解.无论哪种方式,任何人都可以帮我解决我的问题吗?谢谢.
Cha*_*pax 29
你所经历的是光谱泄漏.
这是因为傅立叶变换的基础数学假定从-infinity到+ infinity的连续函数.因此,您提供的样本范围有效地重复了无数次.如果你在窗口中没有完整数量的波形循环,那么末端就不会排成一行,你将会出现一个不连续的现象,表明它的自身随着频率向外抹黑.
处理此问题的常用方法称为窗口化.然而,这确实有一个缺点,因为它导致幅度稍微偏离.这是将要处理的样本的整个窗口乘以某个函数的过程,该函数在窗口的两端趋向于0,导致端部对齐但具有一些幅度失真,因为该过程降低了总信号功率.
总而言之,您的代码中没有错误,结果与预期一致.可以使用窗函数来减少伪影,但是这将影响幅度的准确性.您需要调查并确定最适合您项目要求的解决方案.
您没有得到非周期性正弦曲线的错误结果.它们不仅仅是"文物".您的结果实际上是更完整的DFT结果,您没有看到周期性正弦曲线.那些其他非零值包含有用信息,这些信息可用于例如内插单个非周期性孔径正弦波的频率.
DFT可以被认为是用正弦波卷积矩形窗口.这产生(非常接近)Sinc函数,其具有无限范围,但是在除了其中心DFT仓之外的每个DFT仓频率恰好为零,对于任何正好在DFT仓上居中的正弦曲线.只有当频率在FFT孔径中精确周期时才会发生这种情况,而不是任何其他频率.Sinc功能有很多"驼峰",都隐藏在你的第一个情节中.