FFT z asymetrycznym okienkowaniem?

17

Wszystkie typowe funkcje okna innego niż prostokątne wydają się być symetryczne. Czy zdarza się, że przed FFT ktoś chciałby użyć niesymetrycznej funkcji okna? (Powiedz, czy dane po jednej stronie przysłony FFT były uważane za nieco ważniejsze niż dane po drugiej lub mniej zaszumione itp.)

Jeśli tak, jakie rodzaje asymetrycznych funkcji okna zostały zbadane i jak wpłynęłyby one na odpowiedź częstotliwościową w porównaniu z (bardziej stratnym?) Offsetowym oknem symetrycznym?

hotpaw2
źródło
2
Zasadniczo stosuje się okna, ponieważ FFT działa na małych fragmentach sygnału, starając się, aby wyglądał lokalnie jak sygnał stacjonarny. Zatem nie ma „strony” preferującej, zakłada się, że sygnał jest jednolity w całym tekście.
endolith
4
w algorytmie analizy dźwięku, który działa na danych na żywo i ma martwe opóźnienie przepustowości, czasami można zaprojektować okno asymetryczne, które ma mniej skuteczne opóźnienie niż okno symetryczne o tej samej długości. jeżeli zachowanie tego asymetrycznego okna (które jest znane z góry) wpływa w znany sposób na parametry wyjściowe tej analizy audio, parametry te można zrekompensować i zachować przewagę zmniejszonego opóźnienia.
Robert Bristol-Johnnson

Odpowiedzi:

9

Użyję okna skrótu do „funkcji okna”.

W przypadku audio każde przetwarzanie, które tworzy coś w rodzaju wstępnego dzwonienia lub echa, będzie brzmiało powolnie jak mp3 o niskiej przepływności. Dzieje się tak, gdy zlokalizowana energia stanu przejściowego lub impulsu rozkłada się w czasie, na przykład przez modyfikację danych widmowych w transformowanych zakładkach, takich jak modyfikowana dyskretna dyskretna transformacja kosinusowa (MDCT). W takim przetwarzaniu dźwięk jest okienkowany przez nakładające się okna analizy , transformowany, przetwarzany w dziedzinie częstotliwości (jak dane skompresowane do mniejszej przepływności), ponownie okienkowany za pomocą okna syntezy i sumowany z powrotem. Iloczyn okna analizy i syntezy musi być taki, aby nakładające się okna sumowały się do jedności.

Tradycyjnie używane funkcje okna były symetryczne, a ich szerokość była kompromisem między selektywnością częstotliwości (długie okno) a unikaniem artefaktów w dziedzinie czasu (krótkie okno). Im szersze okno, tym więcej czasu w czasie przetwarzanie może rozprzestrzenić sygnał. Nowszym rozwiązaniem jest zastosowanie okna asymetrycznego. Dwa użyte okna mogą być wzajemnie odbiciami lustrzanymi. Okno analizy spada od szczytu do zera szybko, dzięki czemu impulsy nie są „wykrywane” z dużym wyprzedzeniem, a okno syntezy rośnie od zera do szczytu szybko, tak że efekty jakiegokolwiek przetwarzania nie rozprzestrzeniają się znacznie w czasie. Kolejną zaletą tego jest małe opóźnienie. Asymetryczne okna mogą mieć dobrą selektywność częstotliwości i mogą zastąpić symetryczne okna o zmiennej wielkości w kompresji audio, jak rodzaj lekarstwa. WidziećM. Schnell, M. Schmidt, M. Jander, T. Albert, R. Geiger, V. Ruoppila, P. Ekstrand, M. Lutzky, B. Grill, „MPEG-4 Enhanced Low Delay AAC - nowy standard wysokich komunikacja wysokiej jakości ” , 125. konwencja AES, San Francisco, Kalifornia, USA, przedruk 7503, październik 2008 r oraz inny dokument konferencyjny, w którym pokazują one także wielkość transformaty Fouriera ich okna: Schnell, M., i in. 2007. Ulepszony AEG MPEG-4 o niskim opóźnieniu - komunikacja wysokiej jakości o niskiej przepływności. W 122. konwencji AES .

Ilustracja analizy syntezy czasowej z wykorzystaniem asymetrycznych okien
Ryc. 1. Ilustracja zastosowania okien asymetrycznych w analizie syntezy w analizie docierania. Iloczyn (czarny przerywany) okna analizy (niebieski) i okna syntezy (żółtawy pomarańczowy) sumuje się do jedności z oknem z poprzedniej ramki (szary przerywany). Konieczne są dalsze ograniczenia, aby zagwarantować idealną rekonstrukcję podczas korzystania z MDCT.

Zamiast MDCT można zastosować dyskretną transformatę Fouriera (DFT, FFT), ale w takich kontekstach da redundantne dane widmowe. W porównaniu do DFT, MDCT daje tylko połowę danych spektralnych, a jednocześnie umożliwia doskonałą rekonstrukcję, jeśli zostaną wybrane odpowiednie okna.

Oto mój własny asymetryczny projekt okna (ryc. 2) odpowiedni do analizy syntezy w trybie analizy z wykorzystaniem DFT, ale nie MDCT, dzięki której nie zapewnia idealnej rekonstrukcji. Okno próbuje zminimalizować iloczyn średnich kwadratowych pasm czasu i częstotliwości (podobnie do ograniczonego okna Gaussa ), zachowując niektóre potencjalnie przydatne właściwości w dziedzinie czasu: nieujemne, jednomodalne ze szczytem w „czasie zero”, wokół którego analiza i synteza okna to wzajemne odbicie lustrzane, funkcja i ciągłość pierwszej pochodnej, zero-średnia, gdy kwadrat funkcji okna jest interpretowany jako nienormalizowana funkcja gęstości prawdopodobieństwa. Okno zostało zoptymalizowane za pomocą ewolucji różnicowej .

Okno asymetryczne i cosinusowe
Ryc. 2. Po lewej: Asymetryczne okno analizy odpowiednie do nakładania się analizy-przetwarzania-resyntezy wraz z jego odwróconym w czasie oknem syntezy. Po prawej: okno Cosinus, z takim samym opóźnieniem jak okno asymetryczne

Przekroje Fouriera okien
Ryc. 3. Wielkość przekształceń Fouriera okna cosinus (niebieskiego) i okna asymetrycznego (pomarańczowego) z ryc. 2. Okno asymetryczne pokazuje lepszą selektywność częstotliwości.

Oto kod źródłowy Octave dla wykresów i okna asymetrycznego. Kod kreślenia pochodzi z Wikimedia Commons . W systemie Linux zalecam instalowanie gnuplot, epstool, pstoedit, transfigprzedelibrsvg2-bin do oglądania użyciu display.

pkg load signal

graphics_toolkit gnuplot
set (0, "defaultaxesfontname", "sans-serif")
set (0, "defaultaxesfontsize", 12) 
set (0, "defaultaxeslinewidth", 1)

function plotWindow (w, wname, wfilename = "", wspecifier = "", wfilespecifier = "")

  M = 32; % Fourier transform size as multiple of window length
  Q = 512; % Number of samples in time domain plot
  P = 40; % Maximum bin index drawn
  dr = 130; % Maximum attenuation (dB) drawn in frequency domain plot

  N = length(w);
  B = N*sum(w.^2)/sum(w)^2 % noise bandwidth (bins)

  k = [0 : 1/Q : 1];
  w2 = interp1 ([0 : 1/(N-1) : 1], w, k);

  if (M/N < Q)
    Q = M/N;
  endif

  figure('position', [1 1 1200 600])
  subplot(1,2,1)
  area(k,w2,'FaceColor', [0 0.4 0.6], 'edgecolor', [0 0 0], 'linewidth', 1)
  if (min(w) >= -0.01)
    ylim([0 1.05])
    set(gca,'YTick', [0 : 0.1 : 1])
  else
    ylim([-1 5])
    set(gca,'YTick', [-1 : 1 : 5])
  endif
  ylabel('amplitude')
  set(gca,'XTick', [0 : 1/8 : 1])
  set(gca,'XTickLabel',[' 0'; ' '; ' '; ' '; ' '; ' '; ' '; ' '; 'N-1'])
  grid('on')
  set(gca,'gridlinestyle','-')
  xlabel('samples')
  if (strcmp (wspecifier, ""))
    title(cstrcat(wname,' window'), 'interpreter', 'none')
  else
    title(cstrcat(wname,' window (', wspecifier, ')'), 'interpreter', 'none')
  endif
  set(gca,'Position',[0.094 0.17 0.38 0.71])

  H = abs(fft([w zeros(1,(M-1)*N)]));
  H = fftshift(H);
  H = H/max(H);
  H = 20*log10(H);
  H = max(-dr,H);
  k = ([1:M*N]-1-M*N/2)/M;
  k2 = [-P : 1/M : P];
  H2 = interp1 (k, H, k2);

  subplot(1,2,2)
  set(gca,'FontSize',28)
  h = stem(k2,H2,'-');
  set(h,'BaseValue',-dr)
  xlim([-P P])
  ylim([-dr 6])
  set(gca,'YTick', [0 : -10 : -dr])
  set(findobj('Type','line'),'Marker','none','Color',[0.8710 0.49 0])
  grid('on')
  set(findobj('Type','gridline'),'Color',[.871 .49 0])
  set(gca,'gridlinestyle','-')
  ylabel('decibels')
  xlabel('bins')
  title('Fourier transform')
  set(gca,'Position',[0.595 0.17 0.385 0.71])

  if (strcmp (wfilename, ""))
    wfilename = wname;
  endif
  if (strcmp (wfilespecifier, ""))
    wfilespecifier = wspecifier;
  endif
  if (strcmp (wfilespecifier, ""))
    savetoname = cstrcat('Window function and frequency response - ', wfilename, '.svg');
  else
    savetoname = cstrcat('Window function and frequency response - ', wfilename, ' (', wfilespecifier, ').svg');
  endif
  print(savetoname, '-dsvg', '-S1200,600')
  close

endfunction

N=2^17; % Window length, B is equal for Triangular and Bartlett from 2^17
k=0:N-1;

w = -cos(2*pi*k/(N-1));
w .*= w > 0;
plotWindow(w, "Cosine")

freqData = [0.66697133904805994131, -0.20556692772918355727, 0.49267389481655493588, -0.25062332863369246594, -0.42388422228212319087, 0.42317609537724842905, -0.03930334287740060856, -0.11936153294075849129, 0.30201210285940127687, -0.15541616804857899536, -0.16208119255594669039, 0.12843871362286504723, -0.04470810646117385351, -0.00521885027256757845, 0.07185811583185619522, -0.02835116723496184862, -0.01393644785822748498, 0.00780746224568363342, -0.00748496824751256583, 0.00119325723511989282, 0.00194602547595042175];
freqData(1) /= 2;
scale = freqData(1) + sum(freqData.*not(mod(1:length(freqData), 2)));
freqData /= scale;
w = freqData(1)*ones(1, N);
for bin = 1:(length(freqData)/2)
  w += freqData(bin*2)*cos(2*pi*bin*((1:N)-1)/N);
  w += freqData(bin*2+1)*sin(2*pi*bin*((1:N)-1)/N);
endfor
w(N/4+1:N/2+1) = 0;
w(N/8+2:N/4) = (1 - w(N/8:-1:2).*w(7*N/8+2:N))./w(7*N/8:-1:6*N/8+2);
w = shift(w, -N/2);
plotWindow(w, "Asymmetrical");

Możesz użyć tylko co drugą próbkę okna, ponieważ zaczyna się ona od zera. Poniższy kod C ++ robi to za Ciebie, więc nie dostajesz żadnych zerowych próbek, z wyjątkiem jednej czwartej okna, która jest wszędzie zerowa. Dla okna analizy jest to pierwszy kwartał, a dla okna syntezy - ostatni kwartał. Druga połowa okna analizy powinna być wyrównana z pierwszą połową okna syntezy w celu obliczenia ich produktu. Kod testuje również średnią okna (jako funkcję gęstości prawdopodobieństwa) i pokazuje płaskość nakładającej się rekonstrukcji.

#include <stdio.h>
#include <math.h>

int main() {
  const int windowSize = 400;
  double *analysisWindow = new double[windowSize];
  double *synthesisWindow = new double[windowSize];
  for (int k = 0; k < windowSize/4; k++) {
    analysisWindow[k] = 0;
  }
  for (int k = windowSize/4; k < windowSize*7/8; k++) {
    double x = 2 * M_PI * ((k+0.5)/windowSize - 1.75);
    analysisWindow[k] = 2.57392230162633461887-1.58661480271141974718*cos(x)+3.80257516644523141380*sin(x)
      -1.93437090055110760822*cos(2*x)-3.27163999159752183488*sin(2*x)+3.26617449847621266201*cos(3*x)
      -0.30335261753524439543*sin(3*x)-0.92126091064427817479*cos(4*x)+2.33100177294084742741*sin(4*x)
      -1.19953922321306438725*cos(5*x)-1.25098147932225423062*sin(5*x)+0.99132076607048635886*cos(6*x)
      -0.34506787787355830410*sin(6*x)-0.04028033685700077582*cos(7*x)+0.55461815542612269425*sin(7*x)
      -0.21882110175036428856*cos(8*x)-0.10756484378756643594*sin(8*x)+0.06025986430527170007*cos(9*x)
      -0.05777077835678736534*sin(9*x)+0.00920984524892982936*cos(10*x)+0.01501989089735343216*sin(10*x);
  }
  for (int k = 0; k < windowSize/8; k++) {
    analysisWindow[windowSize-1-k] = (1 - analysisWindow[windowSize*3/4-1-k]*analysisWindow[windowSize*3/4+k])/analysisWindow[windowSize/2+k];
  }
  printf("Analysis window:\n");
  for (int k = 0; k < windowSize; k++) {
    printf("%d\t%.10f\n", k, analysisWindow[k]);
  }
  double accu, accu2;
  for (int k = 0; k < windowSize; k++) {
    accu += k*analysisWindow[k]*analysisWindow[k];
    accu2 += analysisWindow[k]*analysisWindow[k];
  }
  for (int k = 0; k < windowSize; k++) {
    synthesisWindow[k] = analysisWindow[windowSize-1-k];
  }
  printf("\nSynthesis window:\n");
  for (int k = 0; k < windowSize; k++) {
    printf("%d\t%.10f\n", k, synthesisWindow[k]);
  }
  printf("Mean of square of analysis window as probability density function:\n%f", accu/accu2);
  printf("\nProduct of analysis and synthesis windows:\n");
  for (int k = 0; k < windowSize/2; k++) {
    printf("%d\t%.10f\n", k, analysisWindow[windowSize/2+k]*synthesisWindow[k]);
  }
  printf("\nSum of overlapping products of windows:\n");
  for (int k = 0; k < windowSize/4; k++) {
    printf("%d\t%.10f\n", k, analysisWindow[windowSize/2+k]*synthesisWindow[k]+analysisWindow[windowSize/2+k+windowSize/4]*synthesisWindow[k+windowSize/4]);
  }
  delete[] analysisWindow;
  delete[] synthesisWindow;
}

A kod źródłowy funkcji kosztu optymalizacji do użycia z Kiss FFT i biblioteką optymalizacji :

class WinProblem : public Opti::Problem {
private:
  int numParams;
  double *min;
  double *max;
  kiss_fft_scalar *timeData;
  kiss_fft_cpx *freqData;
  int smallSize;
  int bigSize;
  kiss_fftr_cfg smallFFTR;
  kiss_fftr_cfg smallIFFTR;
  kiss_fftr_cfg bigFFTR;
  kiss_fftr_cfg bigIFFTR;

public:
  // numParams must be odd
  WinProblem(int numParams, int smallSize, int bigSize, double* candidate = NULL) : numParams(numParams), smallSize(smallSize), bigSize(bigSize) {
    min = new double[numParams];
    max = new double[numParams];
    if (candidate != NULL) {
      for (int i = 0; i < numParams; i++) {
        min[i] = candidate[i]-fabs(candidate[i])*(1.0/65536);
        max[i] = candidate[i]+fabs(candidate[i])*(1.0/65536);
      }
    } else {
      for (int i = 0; i < numParams; i++) {
        min[i] = -1;
        max[i] = 1;
      }
    }
    timeData = new kiss_fft_scalar[bigSize];
    freqData = new kiss_fft_cpx[bigSize/2+1];
    smallFFTR = kiss_fftr_alloc(smallSize, 0, NULL, NULL);
    smallIFFTR = kiss_fftr_alloc(smallSize, 1, NULL, NULL);
    bigFFTR = kiss_fftr_alloc(bigSize, 0, NULL, NULL);
    bigIFFTR = kiss_fftr_alloc(bigSize, 1, NULL, NULL);
  }

  double *getMin() {
    return min;
  }

  double *getMax() {
    return max;
  }

// ___                                                            __ 1     
// |  \    |       |       |       |       |       |       |     / |       
// |   \   |       |       |       |       |       |       |    /  |       
// |    \_ |       |       |       |       |       |       |   /   |
// |      \|__     |       |       |       |       |       |  /|   |       
// |       |  -----|_______|___    |       |       |       | / |   |       
// |       |       |       |   ----|       |       |       |/  |   |       
// --------------------------------x-----------------------x---|---- 0
// 0      1/8     2/8     3/8     4/8     5/8     6/8     7/8 15/16 
// |-------------------------------|                       |-------|
//            zeroStarts                                   winStarts
//
// f(x) = 0 if 4/8 < x < 7/8
// f(-x)f(x) + f(-x+1/8)f(x-1/8) = 1 if 0 < x < 1/8

  double costFunction(double *params, double compare, int print) {
    double penalty = 0;
    double accu = params[0]/2;
    for (int i = 1; i < numParams; i += 2) {
      accu += params[i];
    }
    if (print) {
      printf("%.20f", params[0]/2/accu);
      for (int i = 1; i < numParams; i += 2) {
        printf("+%.20fcos(%d pi x)", params[i]/accu, (i+1)/2);
        printf("+%.20fsin(%d pi x)", params[i+1]/accu, (i+1)/2);
      }
      printf("\n");
    }
    if (accu != 0) {
      for (int i = 0; i < numParams; i++) {
        params[i] /= accu;
      }
    }
    const int zeroStarts = 4; // Normally 4
    const int winStarts = 2; // Normally 1
    int i = 0;
    int j = 0;
    freqData[j].r = params[i++];
    freqData[j++].i = 0;
    for (; i < numParams;) {
      freqData[j].r = params[i++];
      freqData[j++].i = params[i++];
    }
    for (; j <= smallSize/2;) {
      freqData[j].r = 0;
      freqData[j++].i = 0;
    }
    kiss_fftri(smallIFFTR, freqData, timeData);
    double scale = 1.0/timeData[0];
    double tilt = 0;
    double tilt2 = 0;
    for (int i = 2; i < numParams; i += 2) {
      if ((i/2)%2) {
        tilt2 += (i/2)*params[i]*scale;
      } else {
        tilt2 -= (i/2)*params[i]*scale;
      }
      tilt += (i/2)*params[i]*scale;
    }
    penalty += fabs(tilt);
    penalty += fabs(tilt2);
    double accu2 = 0;
    for (int i = 0; i < smallSize; i++) {
      timeData[i] *= scale;
    }
    penalty += fabs(timeData[zeroStarts*smallSize/8]);
    penalty += fabs(timeData[winStarts*smallSize/16]*timeData[smallSize-winStarts*smallSize/16]-0.5);
    for (int i = 1; i < winStarts*smallSize/16; i++) {
      // Last 16th
      timeData[bigSize-winStarts*smallSize/16+i] = timeData[smallSize-winStarts*smallSize/16+i];
      accu2 += timeData[bigSize-winStarts*smallSize/16+i]*timeData[bigSize-winStarts*smallSize/16+i];
    }
    // f(-1/8+i)*f(1/8-i) + f(i)*f(-i) = 1
    // => f(-1/8+i) = (1 - f(i)*f(-i))/f(1/8-i)   
    // => f(-1/16) = (1 - f(1/16)*f(-1/16))/f(1/16)
    //             = 1/(2 f(1/16))
    for (int i = 1; i < winStarts*smallSize/16; i++) {
      // 2nd last 16th
      timeData[bigSize-winStarts*smallSize/8+i] = (1 - timeData[i]*timeData[bigSize-i])/timeData[winStarts*smallSize/8-i];
      accu2 += timeData[bigSize-winStarts*smallSize/8+i]*timeData[bigSize-winStarts*smallSize/8+i];
    }
    // Between 2nd last and last 16th
    timeData[bigSize-winStarts*smallSize/16] = 1/(2*timeData[winStarts*smallSize/16]);
    accu2 += timeData[bigSize-winStarts*smallSize/16]*timeData[bigSize-winStarts*smallSize/16];
    for (int i = zeroStarts*smallSize/8; i <= bigSize-winStarts*smallSize/8; i++) {
      timeData[i] = 0;
    }
    for (int i = 0; i < zeroStarts*smallSize/8; i++) {
      accu2 += timeData[i]*timeData[i];
    }
    if (print > 1) {
      printf("\n");
      for (int x = 0; x < bigSize; x++) {
        printf("%d,%f\n", x, timeData[x]);
      }
    }
    scale = 1/sqrt(accu2);
    if (print) {
      printf("sqrt(accu2) = %f\n", sqrt(accu2));
    }
    double tSpread = 0;
    timeData[0] *= scale;
    double tMean = 0;
    for (int i = 1; i <= zeroStarts*smallSize/8; i++) {
      timeData[i] *= scale;
      //      tSpread += ((double)i)*((double)i)*(timeData[i]*timeData[i]);
      double x_0 = timeData[i-1]*timeData[i-1];
      double x_1 = timeData[i]*timeData[i];
      tSpread += ((double)i)*((double)i)*(x_0 + x_1)*0.5 - ((double)i)*(2.0/3*x_0 + 1.0/3*x_1) + 0.25*x_0 + 1.0/12*x_1;
      double slope = timeData[i]-timeData[i-1];
      if (slope > 0) {
        penalty += slope+1;
      }
      tMean += x_1*i;
      if (timeData[i] < 0) {
        penalty -= timeData[i];
      }
    }
    double x_0 = timeData[0]*timeData[0];
    for (int i = 1; i <= winStarts*smallSize/8; i++) {
      timeData[bigSize-i] *= scale;
      double x_1 = timeData[bigSize-i]*timeData[bigSize-i];
      tSpread += ((double)i)*((double)i)*(x_0 + x_1)*0.5 - ((double)i)*(2.0/3*x_0 + 1.0/3*x_1) + 0.25*x_0 + 1.0/12*x_1;
      x_0 = x_1;        
      tMean += x_1*(-i);
    }
    tMean /= smallSize;
    penalty += fabs(tMean);
    if (tMean > 0) {
      penalty += 1;
    }
    tSpread /= ((double)smallSize)*((double)smallSize); 
    if (print) {
      printf("tSpread = %f\n", tSpread);
    }
    kiss_fftr(bigFFTR, timeData, freqData);
    double fSpread = 0;
    x_0 = freqData[0].r*freqData[0].r;
    for (int i = 1; i <= bigSize/2; i++) {
      double x_1 = freqData[i].r*freqData[i].r+freqData[i].i*freqData[i].i;
      fSpread += ((double)i)*((double)i)*(x_0 + x_1)*0.5 - ((double)i)*(2.0/3*x_0 + 1.0/3*x_1) + 0.25*x_0 + 1.0/12*x_1;
      x_0 = x_1;
    }
    if (print > 1) {
      for (int i = 0; i <= bigSize/2; i++) {
        printf("%d,%f,%f\n", i, freqData[i].r, freqData[i].i);
      }
    }
    fSpread /= bigSize; // Includes kiss_fft scaling
    if (print) {
      printf("fSpread = %f\n", fSpread);
      printf("%f,%f,%f\n", tSpread, fSpread, tSpread*fSpread);
    }
    return tSpread*fSpread + penalty;
  }

  double costFunction(double *params, double compare) {
    return costFunction(params, compare, false);
  }

  int getNumDimensions() {
    return numParams;
  }

  ~WinProblem() {
    delete[] min;
    delete[] max;
    delete[] timeData;
    delete[] freqData;
    KISS_FFT_FREE(smallFFTR);
    KISS_FFT_FREE(smallIFFTR);
    KISS_FFT_FREE(bigFFTR);
    KISS_FFT_FREE(bigIFFTR);
  }
};
Olli Niemitalo
źródło
3

To zależy od kontekstu okienkowania. Tradycyjnie opracowane okienkowanie było przeznaczone dla metody szacowania gęstości widmowej mocy Blackmana-Tukeya. Jest to ogólna forma metod korelogramu, w której wykorzystuje się twierdzenie Wienera-Khinchina o czasie dyskretnym. Przypomnijmy, że wiąże to sekwencję autokorelacji z gęstością widmową mocy w dyskretnym czasie transformaty Fouriera.

Dlatego okna zostały zaprojektowane z uwzględnieniem kilku kryteriów. Po pierwsze, musieli mieć zysk jedności u źródła. Miało to na celu zachowanie mocy w sekwencji autokorelacji sygnału, ponieważ rxx [0] można traktować jako moc próbki. Następnie okno powinno zwężać się od początku. Jest to z wielu powodów. Po pierwsze, aby być prawidłową sekwencją autokorelacji, wszystkie inne opóźnienia muszą być mniejsze lub równe początkowi. Po drugie, pozwoliło to na wyższą wagę niższych opóźnień, które zostały obliczone z dużą pewnością przy użyciu większości próbek, oraz małą lub zerową wagę wyższych opóźnień, które mają rosnącą wariancję ze względu na malejącą liczbę próbek danych dostępnych dla ich obliczenie. To ostatecznie skutkuje szerszym płatem głównym, a następnie zmniejszoną rozdzielczością w oszacowaniu PSD,

Wreszcie jest również wysoce pożądane, jeśli okna mają nieujemne spektrum. Wynika to z faktu, że w metodzie Blackmana-Tukeya można myśleć o odchyleniu ostatecznego oszacowania jako o rzeczywistej gęstości widmowej mocy splecionej z widmem okna. Jeśli to okno ma regiony ujemne, możliwe jest, że w oszacowaniu gęstości widmowej mocy znajdują się regiony ujemne. Jest to oczywiście niepożądane, ponieważ w tym kontekście ma niewielkie znaczenie fizyczne. Ponadto zauważysz, że w metodzie Blackmana-Tukeya nie ma operacji kwadratu wielkości. Wynika to z faktu, że przy rzeczywistej i parzystej sekwencji autokorelacji pomnożonej przez rzeczywiste i równe okno, dyskretna transformata Fouriera będzie również rzeczywista i parzysta. W praktyce znajdziesz bardzo małe ujemne składniki, które zwykle są kwantyzowane.

Z tych powodów okna mają również nieparzystą długość, ponieważ wszystkie prawidłowe sekwencje autokorelacji są również. Teraz to, co wciąż można zrobić (i zrobić), jest w kontekście metod periodogramu. Oznacza to, że należy okienkować dane, a następnie wziąć do kwadratu wielkość okienkowanych danych. Nie jest to równoważne z metodą Blackmana-Tukeya. Na podstawie niektórych pochodnych statystycznych można stwierdzić, że zachowują się one średnio podobnie , ale ogólnie nie. Na przykład dość często stosuje się okienkowanie dla każdego segmentu w metodzie Welcha lub Bartletta, aby zmniejszyć wariancję oszacowań. Zasadniczo dzięki tym metodom motywacja jest częściowo taka sama, ale inna. Moc jest znormalizowana w tych metodach, dzieląc na przykład energię okna, zamiast ostrożnego ważenia opóźnień okna.

Mamy więc nadzieję, że to kontekstualizuje okna i ich pochodzenie oraz dlaczego są one symetryczne. Jeśli zastanawiasz się, dlaczego można wybrać okno asymetryczne, zastanów się nad implikacjami właściwości dualności transformacji Fouriera i tym, co oznacza splot oszacowania gęstości widmowej mocy dla twojego zastosowania. Twoje zdrowie.

Bryan
źródło
1

Pierwotnym punktem okienkowania jest upewnienie się, że (zakładany okresowo przez DFT) sygnał nie ma ostrych stanów przejściowych na początku w porównaniu do końca. Kosztem jest to, że częstotliwości w kierunku środka okna (symetrycznego) będą bardziej ważone i przedstawione w kolejnym DFT.

Mając to wszystko w tle, mogę sobie wyobrazić, że można by użyć asymetrycznego okna, aby zaakcentować lokalne cechy czasowe w analizowanym sygnale za pomocą DFT. Może to jednak nastąpić kosztem szerszej szerokości płata podczas DFT, jeśli punkty końcowe twojego sygnału nie będą w przybliżeniu tej samej amplitudy po okienkowaniu.

Spacey
źródło