FFT avec fenêtrage asymétrique?

17

Les fonctions de fenêtre non rectangulaires communes semblent toutes être symétriques. Y a-t-il jamais un cas où l'on voudrait utiliser une fonction de fenêtre non symétrique avant une FFT? (Dites si les données d'un côté de l'ouverture FFT étaient considérées comme un peu plus importantes que les données de l'autre, ou moins bruyantes, etc.)

Dans l'affirmative, quels types de fonctions de fenêtre asymétrique ont été étudiées et comment affectent-elles la réponse en fréquence par rapport à une fenêtre symétrique décalée (plus avec perte?)?

hotpaw2
la source
2
Généralement, des fenêtres sont utilisées car la FFT fonctionne sur de petits morceaux de signal, essayant de la faire ressembler localement à un signal stationnaire. Il n'y a donc pas de "côté" à préférer, le signal est supposé uniforme dans l'ensemble.
endolith
4
dans un algorithme d'analyse audio qui travaille sur des données en direct et a un retard de débit à craindre, parfois une fenêtre asymétrique peut être conçue avec un retard moins efficace que la fenêtre symétrique de la même longueur. si le comportement de cette fenêtre asymétrique (connue à l'avance) affecte les paramètres de sortie de cette analyse audio de manière connue, ces paramètres peuvent être compensés et vous conservez l'avantage d'un délai réduit.
robert bristow-johnson

Réponses:

9

Je vais utiliser la fenêtre raccourcie pour "fonction fenêtre".

Avec l'audio, tout traitement qui crée quelque chose de semblable à la pré-sonnerie ou au pré-écho sonnera comme un mp3 à faible débit binaire. Cela se produit lorsque l'énergie localisée d'un transitoire ou d'une impulsion est répartie vers l'arrière dans le temps, par exemple par modification des données spectrales dans les transformées par recouvrement telles que la transformée en cosinus discret modifiée par recouvrement (MDCT). Dans un tel traitement, l'audio est fenêtré par des fenêtres d'analyse qui se chevauchent , transformé, traité dans le domaine fréquentiel (comme les données compressées à un débit binaire plus petit), fenêtré à nouveau avec une fenêtre de synthèse et additionné ensemble. Le produit de la fenêtre d'analyse et de synthèse doit être tel que les fenêtres qui se chevauchent totalisent l'unité.

Traditionnellement, les fonctions de fenêtre utilisées étaient symétriques et leur largeur était un compromis entre la sélectivité en fréquence (fenêtre longue) et l'évitement des artefacts dans le domaine temporel (fenêtre courte). Plus la fenêtre est large, plus le traitement peut remonter dans le temps. Une solution plus récente consiste à utiliser une fenêtre asymétrique. Les deux fenêtres utilisées peuvent être des images miroir l'une de l'autre. La fenêtre d'analyse passe de pic à zéro rapide de sorte que les impulsions ne sont pas "détectées" longtemps à l'avance, et la fenêtre de syntheis passe de zéro à pic rapide, de sorte que les effets de tout traitement ne se propagent pas beaucoup en arrière dans le temps. Un autre avantage est une faible latence. Les fenêtres asymétriques peuvent avoir une bonne sélectivité en fréquence et peuvent remplacer les fenêtres symétriques de taille variable dans la compression audio, comme une sorte de panache. VoirM. Schnell, M. Schmidt, M. Jander, T. Albert, R. Geiger, V. Ruoppila, P. Ekstrand, M. Lutzky, B. Grill, «MPEG-4 Enhanced Low Delay AAC - un nouveau standard pour les hautes communication de qualité ” , 125e convention AES, San Francisco, CA, USA, préimpression 7503, octobre 2008 et un autre document de conférence où ils montrent également l'ampleur de la transformée de Fourier de leur fenêtre: Schnell, M., et al. 2007. Enhanced MPEG-4 Low Delay AAC - Communication de haute qualité à faible débit binaire. Dans la 122e Convention AES .

Illustration de l'analyse-traitement-synthèse par recouvrement à l'aide de fenêtres asymétriques
Figure 1. Illustration de l'utilisation de fenêtres asymétriques en analyse-traitement-synthèse par rodage. Le produit (noir en pointillés) de la fenêtre d'analyse (bleu) et de la fenêtre de synthèse (orange jaunâtre) correspond à l'unité avec la fenêtre de la trame précédente (gris en pointillés). Des contraintes supplémentaires sont nécessaires pour garantir une reconstruction parfaite lors de l'utilisation de MDCT.

La transformée de Fourier discrète (DFT, FFT) pourrait être utilisée à la place de MDCT, mais dans de tels contextes, elle donnera des données spectrales redondantes. Comparé à DFT, MDCT ne fournit que la moitié des données spectrales tout en permettant une reconstruction parfaite si des fenêtres appropriées sont choisies.

Voici ma propre conception de fenêtre asymétrique (Fig. 2) adaptée à l'analyse-traitement-synthèse chevauchante utilisant la DFT mais pas la MDCT avec laquelle elle ne donne pas une reconstruction parfaite. La fenêtre essaie de minimiser le produit des bandes passantes moyennes en temps et en fréquence (de manière similaire à la fenêtre gaussienne confinée ) tout en conservant certaines propriétés de domaine temporel potentiellement utiles: non négatives, unimodales avec le pic à "temps zéro" autour duquel l'analyse et la synthèse les fenêtres sont des images miroir les unes des autres, de la fonction et de la continuité de la première dérivée, à moyenne nulle lorsque le carré de la fonction de fenêtre est interprété comme une fonction de densité de probabilité non normalisée. La fenêtre a été optimisée par évolution différentielle .

Fenêtre asymétrique et cosinus
Figure 2. À gauche: une fenêtre d'analyse asymétrique adaptée au chevauchement analyse-traitement-resynthèse avec sa fenêtre de synthèse homologue inversée dans le temps. À droite: fenêtre cosinus, avec la même latence que la fenêtre asymétrique

Transformations de Fourier des fenêtres
Figure 3. Amplitude des transformées de Fourier de la fenêtre cosinus (bleu) et de la fenêtre asymétrique (orange) de la figure 2. La fenêtre asymétrique montre une meilleure sélectivité en fréquence.

Voici le code source d'Octave pour les tracés et pour la fenêtre asymétrique. Le code de traçage provient de Wikimedia Commons . Sur Linux , je recommande l' installation gnuplot, epstool, pstoedit, d' transfigabord et librsvg2-binpour l' affichage à l' aide 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");

Vous souhaiterez peut-être utiliser uniquement chaque deuxième échantillon de la fenêtre, car elle commence et se termine à zéro. Le code C ++ suivant fait cela pour vous afin que vous n'obteniez aucun échantillon zéro, sauf dans un quart de la fenêtre qui est nul partout. Pour la fenêtre d'analyse, c'est le premier trimestre et pour la fenêtre de synthèse, c'est le dernier trimestre. La seconde moitié de la fenêtre d'analyse doit être alignée avec la première moitié de la fenêtre de synthèse pour le calcul de leur produit. Le code teste également la moyenne de la fenêtre (en tant que fonction de densité de probabilité) et met en évidence la planéité de la reconstruction chevauchée.

#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;
}

Et le code source de la fonction de coût d'optimisation à utiliser avec Kiss FFT et une bibliothèque d'optimisation :

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
la source
3

Cela dépend du contexte du fenêtrage. Le fenêtrage, tel qu'il était traditionnellement développé, était destiné à la méthode Blackman-Tukey de densité spectrale de puissance d'estimation. C'est la forme générale des méthodes du corrélogramme, par laquelle le théorème de Wiener-Khinchin en temps discret est exploité. Rappelons que cela relie la séquence d'autocorrélation à la densité spectrale de puissance à travers la transformée de Fourier à temps discret.

Par conséquent, les fenêtres ont été conçues en fonction de plusieurs critères. D'abord, ils devaient avoir un gain d'unité à l'origine. Il s'agissait de préserver la puissance dans la séquence d'autocorrélation du signal, car rxx [0] peut être considéré comme la puissance de l'échantillon. Ensuite, la fenêtre devrait s'effiler depuis l'origine. C'est pour plusieurs raisons. Premièrement, pour être une séquence d'autocorrélation valide, tous les autres décalages doivent être inférieurs ou égaux à l'origine. Deuxièmement, cela a permis une pondération plus élevée des décalages inférieurs, qui ont été calculés avec une grande confiance en utilisant la plupart des échantillons, et une pondération faible ou nulle des décalages supérieurs, qui ont une variance croissante en raison de la quantité décroissante d'échantillons de données disponibles pour leur calcul. Cela se traduit finalement par un lobe principal plus large et par la suite une diminution de la résolution dans l'estimation du PSD,

Enfin, il est également très souhaitable que les fenêtres aient un spectre non négatif. En effet, avec la méthode Blackman-Tukey, vous pouvez penser au biais de l'estimation finale comme la densité spectrale de puissance réelle convolue avec le spectre de la fenêtre. Si ce spectre de fenêtre a des régions négatives, il est possible d'avoir des régions négatives dans votre estimation de densité spectrale de puissance. Ceci n'est évidemment pas souhaité, car il a peu de signification physique dans ce contexte. De plus, vous remarquerez qu'il n'y a pas d'opération de magnitude au carré dans la méthode Blackman-Tukey. En effet, avec une séquence d'autocorrélation réelle et régulière multipliée par une fenêtre réelle et régulière, la transformée de Fourier discrète sera également réelle et régulière. En pratique, vous trouverez de très petites composantes négatives qui sont généralement quantifiées.

Pour ces raisons, les fenêtres sont également de longueur impaire car toutes les séquences d'autocorrélation valides le sont également. Maintenant, ce qui peut encore être fait (et est fait) est le fenêtrage dans le contexte des méthodes du périodogramme. C'est-à-dire, fenêtrer les données, puis prendre la grandeur au carré des données fenêtrées. Ce n'est pas équivalent à la méthode Blackman-Tukey. Vous pouvez constater, grâce à certaines dérivations statistiques, qu'ils se comportent de la même manière en moyenne , mais pas en général. Par exemple, il est assez courant d'utiliser le fenêtrage pour chaque segment dans la méthode de Welch ou Bartlett pour diminuer la variance des estimations. Donc, en substance, avec ces méthodes, la motivation est en partie la même, mais différente. La puissance est normalisée dans ces méthodes en divisant par exemple l'énergie de la fenêtre, au lieu de pondérer soigneusement les décalages de la fenêtre.

Donc, j'espère que cela contextualise les fenêtres et leurs origines, et pourquoi elles sont symétriques. Si vous êtes curieux de savoir pourquoi on peut choisir une fenêtre asymétrique, considérez les implications de la propriété de dualité de la transformée de Fourier et ce que la convolution de votre estimation de densité spectrale de puissance signifie pour votre application. À votre santé.

Bryan
la source
1

Le point d'origine du fenêtrage est de s'assurer que le signal (supposé périodique par la DFT) n'a pas de transitoires nets au début par rapport à la fin. Le coût est que les fréquences vers le centre de la fenêtre (symétrique) seront plus pondérées et représentées dans la DFT suivante.

Avec tout cela en arrière-plan, je peux imaginer que l'on voudrait utiliser une fenêtre asymétrique pour accentuer les caractéristiques temporelles locales dans le signal analysé via la DFT. Cependant, cela pourrait se faire au prix d'une largeur de lobe plus grande pendant la DFT, si les points d'extrémité de votre signal ne sont pas à peu près la même amplitude après le fenêtrage.

Spacey
la source