【问题标题】:Implement Hann Window实现 Hann 窗口
【发布时间】:2011-04-03 02:08:50
【问题描述】:

我获取输入数据块并通过 fftw 传递它们以获取一些光谱信息。一切似乎都正常,但我认为我遇到了一些别名问题。

我一直在尝试研究如何在我的数据块上实现一个 hann 窗口。谷歌让我失望了。我应该查看任何想法或链接?

double dataIn[2048] > /* windowing here? */ > FFT > double freqBins[2048]

更新

感谢 Oli 指出我实际上要解决的问题是频谱泄漏,而不是混叠...

【问题讨论】:

    标签: c signal-processing fft fftw


    【解决方案1】:

    http://en.wikipedia.org/wiki/Hann_function 。实现非常直接地遵循定义。只需将w(n) 函数用作乘数,循环遍历所有样本(随时更改n),就是这样。

    for (int i = 0; i < 2048; i++) {
        double multiplier = 0.5 * (1 - cos(2*PI*i/2047));
        dataOut[i] = multiplier * dataIn[i];
    }
    

    【讨论】:

      【解决方案2】:

      相当于MATLAB的hanning.m的完整函数可以在here找到:

      /*  function w = hanning(varargin)
      %   HANNING   Hanning window.
      %   HANNING(N) returns the N-point symmetric Hanning window in a column
      %   vector.  Note that the first and last zero-weighted window samples
      %   are not included.
      %
      %   HANNING(N,'symmetric') returns the same result as HANNING(N).
      %
      %   HANNING(N,'periodic') returns the N-point periodic Hanning window,
      %   and includes the first zero-weighted window sample.
      %
      %   NOTE: Use the HANN function to get a Hanning window which has the
      %          first and last zero-weighted samples.ep
          itype = 1 --> periodic
          itype = 0 --> symmetric
          default itype=0 (symmetric)
      
          Copyright 1988-2004 The MathWorks, Inc.
      %   $Revision: 1.11.4.3 $  $Date: 2007/12/14 15:05:04 $
      */
      
      float *hanning(int N, short itype)
      {
          int half, i, idx, n;
          float *w;
      
          w = (float*) calloc(N, sizeof(float));
          memset(w, 0, N*sizeof(float));
      
          if(itype==1)    //periodic function
              n = N-1;
          else
              n = N;
      
          if(n%2==0)
          {
              half = n/2;
              for(i=0; i<half; i++) //CALC_HANNING   Calculates Hanning window samples.
                  w[i] = 0.5 * (1 - cos(2*PI*(i+1) / (n+1)));
      
              idx = half-1;
              for(i=half; i<n; i++) {
                  w[i] = w[idx];
                  idx--;
              }
          }
          else
          {
              half = (n+1)/2;
              for(i=0; i<half; i++) //CALC_HANNING   Calculates Hanning window samples.
                  w[i] = 0.5 * (1 - cos(2*PI*(i+1) / (n+1)));
      
              idx = half-2;
              for(i=half; i<n; i++) {
                  w[i] = w[idx];
                  idx--;
              }
          }
      
          if(itype==1)    //periodic function
          {
              for(i=N-1; i>=1; i--)
                  w[i] = w[i-1];
              w[0] = 0.0;
          }
          return(w);
      }
      

      【讨论】:

        【解决方案3】:

        不是对您问题的回答,而是对您的问题的旁白。窗口化有助于解决光谱泄漏问题,而不是混叠问题。

        当波形的频率分量不是采样率的整数约数时,就会出现频谱泄漏效应。

        如果您有混叠,那么您基本上就完蛋了。您要么需要提高采样率,要么在采样之前放入(更好的)抗混叠滤波器。

        【讨论】:

          【解决方案4】:

          为什么不使用 Math.NET 的 Hann 窗口实现?

          double[] hannDoubles = MathNet.Numerics.Window.HannPeriodic(dataIn.Length);
          for (int i = 0; i < dataIn.Length; i++)
          {
              dataOut[i] = hannDoubles[i] * dataIn[i];
          }
          

          位于此处:https://numerics.mathdotnet.com/api/MathNet.Numerics/Window.htm

          【讨论】:

            【解决方案5】:

            维基百科是你的朋友:Hanning window

            你的谷歌搜索肯定想出了维基百科?!无论如何,只需创建一个函数,该函数返回一个长度为 N 且带有汉宁系数的数组,然后将该数组乘以您的 dataIn[2048]

            【讨论】:

              【解决方案6】:

              这很好,但大多数人可能希望在数以千计的充满数据的数组上执行此操作。您可以在程序初始化时填充一个仅包含常量乘数的数组(使用您提供给 FFT 的相同大小的数组),然后只需将实数数组中的每个点乘以乘数数组中的每个点。比每次都重新计算所有这些余弦更快/更便宜。

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 2013-09-26
                • 1970-01-01
                • 1970-01-01
                • 2015-06-16
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多