离散傅立叶变换
我目前正在尝试编写一些傅里叶变换算法。我从数学定义中描述的简单 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;
}
}
因此,我使用以下代码测试了该算法:
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);
}
转换工作正常,但前提是 numberValues 是抽样频率的倍数(在本例中:120、240、360) ,...)。这是我对 240 个值的结果:
转型进展顺利。
如果我尝试计算 280 个值,我会得到以下结果:
如果更改计算值的数量,为什么会得到不正确的结果? 我不确定我的问题是我的代码有问题还是对 DFT 数学定义的误解。无论哪种方式,有人可以帮助我解决我的问题吗?谢谢。
I am currently trying to write some fourier transform algorithm. I started with a simple DFT algorithm as described in the mathematical definition:
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;
}
}
So I tested this algorithm with the following code:
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);
}
The transformation works fine, but only if numberValues is a multiple number of the samplingFrequency (in this case: 120, 240, 360,...). Thats my result for 240 values:
The transformation just worked fine.
If i am trying to calculate 280 values I get this result:
Why I am getting a incorrect result if I change the number of my calculated values?
I am not sure if my problem here is a problem with my code or a misunderstanding of the mathematical definition of the DFT. In either way, can anybody help me with my problem? Thanks.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
您遇到的情况称为频谱泄漏。
这是因为傅立叶变换的基础数学假定从-无穷大到+无穷大的连续函数。因此,您提供的样本范围实际上会重复无限次。如果窗口中没有完整数量的波形周期,则两端将不会对齐,并且您将得到不连续性,其表现为频率涂抹到任一侧。
处理此问题的正常方法称为窗口化。然而,这确实有一个缺点,因为它会导致幅度略有偏差。这是将要处理的整个样本窗口乘以某个函数的过程,该函数在窗口的两端趋向于 0,导致两端对齐,但会产生一些幅度失真,因为此过程会降低总信号功率。
总而言之,您的代码没有错误,结果也符合预期。可以使用窗函数来减少伪影,但这会影响幅度的准确性。您将需要调查并确定哪种解决方案最适合您的项目要求。
What you are experiencing is called Spectral Leakage.
This is caused because the underlying mathematics of the Fourier transform assumes a continuous function from -infinity to + infinity. So the range of samples you provide is effectively repeated an infinite number of times. If you don't have a complete number of cycles of the waveform in the window the ends won't line up and you will get a discontinuity which manifests its self as the frequency smearing out to either side.
The normal way to handle this is called Windowing. However, this does come with a downside as it causes the amplitudes to be slightly off. This is the process of multiply the whole window of samples you are going to process by some function which tends towards 0 at both ends of the window causing the ends to line up but with some amplitude distortion because this process lowers the total signal power.
So to summarise there is no error in your code, and the result is as expected. The artefacts can be reduced using a window function, however this will effect the accuracy of the amplitudes. You will need to investigate and determine what solution best fits the requirements of your project.
对于非周期性正弦曲线,您不会得到错误的结果。而且它们不仅仅是“文物”。您的结果实际上是更完整的 DFT 结果,这是您在周期性正弦曲线中看不到的。这些其他非零值包含有用的信息,例如可用于对单个非周期性孔径正弦曲线的频率进行插值。
DFT 可以被认为是将矩形窗口与正弦波进行卷积。这会产生(非常接近)一个 Sinc 函数,该函数具有无限的范围,但对于恰好以 DFT bin 为中心的任何正弦曲线,其中心 DFT bin 之外的每个 DFT bin 频率恰好为零。仅当频率在 FFT 孔径中完全具有周期性时才会发生这种情况,而对于其他任何频率都不会发生这种情况。 Sinc 函数有很多“驼峰”,它们都隐藏在您的第一个图中。
You are NOT getting the incorrect result for a non-periodic sinusoid. And they are not just "artifacts". Your result is actually the more complete DFT result which you don't see with a periodic sinusoid. Those other non-zero values contain useful information which can be used to, for example, interpolate the frequency of a single non-periodic-in-aperture sinusoid.
A DFT can be thought of as convolving a rectangular window with your sine wave. This produces (something very close to) a Sinc function, which has infinite extent, BUT just happens to be zero at every DFT bin frequency other than its central DFT bin for any sinusoid centered exactly on a DFT bin. This happens only when the frequency is exactly periodic in the FFT aperture, not for any other. The Sinc function has lots of "humps" which are all hidden in your first plot.