Реализовать окно Ханна

Я беру блоки входящих данных и пропускаю их через fftw, чтобы получить некоторую спектральную информацию. Кажется, все работает, однако я думаю, что у меня возникают некоторые проблемы с псевдонимами.

Я пытался понять, как реализовать окно hann в моих блоках данных. Google подвел меня для примеров. Любые идеи или ссылки, на которые я должен смотреть?

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

Обновить

Спасибо Оли за указание на проблему, которую я на самом деле пытаюсь исправить, это спектральная утечка, а НЕ алиасинг...


person Tim    schedule 24.08.2010    source источник


Ответы (6)


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];
}
person Joonas Pulakka    schedule 24.08.2010

Полную функцию, эквивалентную функции MATLAB hanning.m, можно найти здесь:

/*  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);
}
person herohuyongtao    schedule 25.07.2014

Не ответ на ваш вопрос, а отступление от вашей проблемы. Работа с окнами помогает решить проблемы с спектральной утечкой, а не с наложением псевдонимов.

Эффекты спектральной утечки возникают, когда частотные компоненты вашего сигнала не являются точными целыми дольными частями вашей частоты дискретизации.

Если у вас есть псевдонимы, то вы в корне облажались. Вам нужно будет либо увеличить частоту дискретизации, либо установить (лучший) фильтр сглаживания перед сэмплированием.

person Oliver Charlesworth    schedule 24.08.2010

Почему бы не использовать оконную реализацию Hann в Math.NET?

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

person Gordon Slysz    schedule 21.03.2017

Википедия — ваш друг: Окно Хэннинга

Наверняка ваш гуглинг выдал википедию?! В любом случае просто создайте функцию, которая возвращает массив длины N с коэффициентами Ханнинга, и умножьте этот массив на ваш dataIn[2048].

person Simon Walker    schedule 24.08.2010

Это нормально, но большинство людей, вероятно, хотят сделать это с тысячами массивов, заполненных данными. Вы можете заполнить массив только постоянными множителями один раз при инициализации вашей программы (используйте массив того же размера, который вы подаете в БПФ), а затем просто умножьте каждую точку в вашем реальном массиве на каждую точку в массиве множителей. Быстрее/дешевле, чем каждый раз перебирать все эти косинусы.

person Alan Corey    schedule 04.08.2017