如何在纯正弦波的窗口数据集上正确运行FFT

时间:2016-12-07 17:32:56

标签: c# fft mathdotnet

我正在尝试使用Math.Net,特别是FFT部分。我试图从纯正弦波中提取频域信息。这是代码:

private void Form1_Load(object sender, EventArgs e)
        {
            //Set up the wave and derive some useful info
            Double WaveFreq = 500;
            Double WavePeriod = 1 / WaveFreq;
            Double SampleFreq = 20000;
            Double SampleTime = (1 / SampleFreq);

            //Generate the wave using the above parameters
            var points = Generate.Sinusoidal(100000, SampleFreq, WaveFreq, 1);

            //Array to hold our complex numbers
            var data = new Complex[points.Length];

            //Set up the series to display our raw wave
            Series WaveSeries = new Series("Waveform");
            WaveSeries.ChartType = SeriesChartType.Line;

            //Creat the series for displaying the FFT
            Series FFTSeries = new Series("FFT Test");
            FFTSeries.ChartType = SeriesChartType.Column;

            //Populate both the wave series and the data array
            for (int i = 0; i < points.Length; i++)
            {
                Double x = SampleTime * i;
                WaveSeries.Points.AddXY(x, points[i]);
                data[i] = new Complex(x, points[i]);
            }

            //Create the window to evaluate (using a window 5 times wider than the wavelength of the lowest ferequency being measured)
            int WindowWidth = (int)Math.Round((1 / WaveFreq) / (1 / SampleFreq) * 5 + 0.5f);
            var HannWindow = Window.HannPeriodic(WindowWidth);
            var window = new Complex[WindowWidth];

            for(int i = 0; i < WindowWidth; i++)
            {
                var y = data[i].Imaginary * HannWindow[i];
                window[i] = new Complex(data[i].Real, y);
            }

            //Perform the FFT
            Fourier.Forward(window);

            //Add the calculated FFT to our FFTSeries
            foreach(Complex sample in window)
            {
                FFTSeries.Points.AddXY(sample.Phase, sample.Magnitude);
            }

            chart2.Series.Add(WaveSeries);
            chart2.ChartAreas[0].AxisX.Minimum = 0;
            chart2.ChartAreas[0].AxisX.Maximum = .01;
            chart2.ChartAreas[0].AxisY.Minimum = -2;
            chart2.ChartAreas[0].AxisY.Maximum = 2;

            chart1.Series.Add(FFTSeries);
            chart1.ChartAreas[0].AxisX.Minimum = 0;
            chart1.ChartAreas[0].AxisX.Maximum = 1000;
            chart1.ChartAreas[0].AxisY.Minimum = 0;
            chart1.ChartAreas[0].AxisY.Maximum = 5;

        }

如您所见,我正在以500Hz的频率生成正弦波,以20kHz采样并生成10k样本。

输出如下(左侧为FFT,右侧为波形) enter image description here

FFT绝对没有显示(除了0Hz附近的1.8的峰值)!我怀疑这可能是窗口的错误,但对于我的生活,我看不出它是什么。

我感谢任何帮助!

2 个答案:

答案 0 :(得分:3)

似乎对复杂的数字存在一些误解。在你的代码中,它们似乎像点(x,y-tuples)一样使用,但它们与点完全无关。实数据点的复数等价物是一个数组,其中复数数字的实部与实际数据点匹配,虚部全部为零。基本上:

var window = new Complex[WindowWidth];
for (int i = 0; i < WindowWidth; i++)
{
    window[i] = new Complex(points[i] * HannWindow[i], 0.0);
}

如果您需要一种简单的方法来获得频率图的正确x轴,您可以使用FrequencyScale函数,如下所示:

var scale = Fourier.FrequencyScale(WindowWidth, SampleFreq);
for (int i = 0; i < WindowWidth; i++)
{
    FFTSeries.Points.AddXY(scale[i], window[i].Magnitude);
}

你应该在索引5处看到一个尖峰,根据计算的scale数组,它对应于频率500,它与你的波频率相匹配。

请注意,FFT例程返回包含负频率的全频谱,因此您还应该在频率-500处看到相同大小的尖峰。

答案 1 :(得分:0)

FFT绝对存在,但您映射的比例是错误的。

只需更改X轴,您就会看到它

chart1.ChartAreas[0].AxisX.Maximum = 10;

虽然我不是数学网专家所以我看起来像你生成的正弦波形状也不对,所以我不知道。该中心似乎不是零。