2016-12-07 627 views
2

Math.Net, 특히 FFT 부분을 실험하려고합니다. 순수한 사인파에서 주파수 도메인 정보를 추출하려고합니다. 당신이 볼 수 있듯이, 내가 20kHz의에서 샘플링 및 10K 샘플을 생성는 500Hz의 주파수에서 사인파를 생성하고순수 사인파의 창 데이터 세트에서 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; 

     } 

: 여기에 코드입니다.

출력은 다음과 같다 (FFT 왼쪽, 오른쪽 파) enter image description here

는 FFT는 (0Hz에서 약 1.8의 피크 잡담)이 전혀 없음을 보여준다! 나는 그것이 아마 windowing과의 오류라고 생각한다. 그러나 나 자신의 삶에 대해 그것이 무엇인지 나는 알 수 없다.

감사합니다.

+0

이 복제하려고 할 때 Window.HannPeriodic 함수를 찾을 수 없습니다. MathNet 문서에 있지만 Window.Hann 만 사용하면 컴파일 할 수 있습니다. 내가 놓친 게 있니? –

+1

@KelsonBall 3.14.0-beta3 버전입니다. –

답변

3

복소수에 대한 오해가있는 것으로 보입니다. 귀하의 코드에서 그들은 점 (x, y-tuples)처럼 사용되는 것처럼 보입니다. 그러나 그들은 전혀 포인트와 관련이 없습니다. 실제 데이터 포인트의 복잡한 등가물은 복소수의 실수 부분이 실제 데이터 요소와 일치하고 허수 부분이 모두 0 인 배열입니다. 기본적으로 :

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

당신은 스파이크를 볼 수 : 당신이 당신의 주파수 플롯에 대한 올바른 x 축를 얻을 수있는 쉬운 방법을해야하는 경우

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

, 당신의 라인을 함께 FrequencyScale 기능을 사용할 수 있습니다 계산 된 scale 배열에 따라 주파수 500에 해당하는 인덱스 5에서 웨이브 주파수와 일치합니다.

FFT 루틴은 음수를 포함하는 전체 스펙트럼을 반환하므로 주파수 -500에서도 같은 크기의 스파이크가 표시되어야합니다.

+0

아 감사합니다. 나는 지금 나의 잘못을 이해한다. 나는'https://msdn.microsoft.com/en-us/library/system.numerics.complex (v = vs.110) .aspx'에서 특히 다음과 같은 내용을 읽었습니다. "복소수의 실수 부분 x 축 (수평축)에, 허수 부는 y 축에 위치합니다. "그래서 저는 여러분이 포인트 값을 입력했다고 가정 했으므로, '실제'광고'가상 '속성은 복합체를 계산할 것입니다 동등한. –

+0

빠른 후속 조치로서 FFT를 "정상화"해야하는 방법에 대해 읽었습니다. 이것이 진폭을 현실과 일치시키는 데 필요한 단계 일 수 있습니까? 현재 진폭은 주파수가 2 개 빈 사이에있는 위치에 따라 달라지는 것 같습니다.나는 이것이 윈도 잉의 효과라는 것을 알고 있지만 그것을 교정하는 방법을 모른다. 이 리소스를 사용할 수 있습니까? 내 가정에서 맞습니까? –

+0

아마 FFT 스케일링을 참조할까요? 이것을'FourierOptions' 인수로 제어 할 수 있지만 기본적으로 parseval의 정리 (시간 공간 에너지 = 주파수 공간 에너지)를 만족하도록 이미 대칭으로 스케일됩니다. 이것은 예를 들어 MATLAB은 비대칭으로 비례하여 스스로 크기를 조정해야합니다. –

0

FFT가 분명히 있지만 사용자가 매핑 한 눈금이 잘못되었습니다.

은 그냥 X 축을 변경하고 당신은 볼 것이다 그것을

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

그것은 또한 당신은 내가 더 수학 순 전문가입니다하지 못했습니다 비록 내가 모르는되지 생성 정현파 형태처럼 보인다. 센터는 0이 아닌 것 같습니다.

+0

안녕하세요. 필자는 FFT 차트의 y 축이 해당 주파수에서 파도의 진폭을 일대일로 나타낼 것이라고 생각했습니다. 지금은 그렇지 않다는 것을 알 수 있습니다. FFT 그래프에서 어떻게 진폭을 해석해야하는지 설명 할 수 있습니까? 감사합니다 –