FFT con finestre asimmetriche?


17

Le funzioni comuni delle finestre non rettangolari sembrano tutte simmetriche. C'è mai un caso in cui si vorrebbe usare una funzione finestra non simmetrica prima di una FFT? (Dire se i dati su un lato dell'apertura FFT erano considerati un po 'più importanti dei dati sull'altro, o meno rumorosi, ecc.)

In tal caso, quali tipi di funzioni asimmetriche della finestra sono state studiate e in che modo influenzerebbero la risposta in frequenza rispetto a una finestra simmetrica offset (più con perdita?)?


2
Generalmente le finestre vengono utilizzate perché FFT funziona su piccoli pezzi di un segnale, cercando di farlo apparire localmente come un segnale stazionario. Quindi non esiste un "lato" da preferire, si presume che il segnale sia uniforme dappertutto.
endolith

4
in un algoritmo di analisi audio che sta lavorando su dati live e che ha un ritardo di throughput di cui preoccuparsi, a volte può essere progettata una finestra asimmetrica che ha un ritardo meno efficace rispetto alla finestra simmetrica della stessa lunghezza. se il comportamento di questa finestra asimmetrica (che è noto in anticipo) influenza i parametri di uscita di questa analisi audio in modo noto, tali parametri possono essere compensati e si mantiene il vantaggio di un ritardo ridotto.
robert bristow-johnson il

Risposte:


9

Userò la finestra abbreviata per "funzione finestra".

Con l'audio, qualsiasi elaborazione che crea qualcosa di simile al pre-squillo o al pre-eco suonerà come un mp3 a bassa velocità di bit. Ciò accade quando l'energia localizzata di un transiente o di un impulso viene diffusa all'indietro nel tempo, ad esempio modificando i dati spettrali in trasformate lappate come la trasformata di coseno discreta modificata lappata (MDCT). In tale elaborazione, l'audio è coperto da finestre di analisi sovrapposte , trasformato, elaborato in un dominio di frequenza (come i dati compressi in un bitrate più piccolo), nuovamente finestra con una finestra di sintesi e riassunto insieme. Il prodotto della finestra di analisi e sintesi deve essere tale che le finestre sovrapposte si sommino all'unità.

Tradizionalmente le funzioni della finestra utilizzate erano simmetriche e la loro larghezza era un compromesso tra selettività di frequenza (finestra lunga) ed evitamento di artefatti nel dominio del tempo (finestra corta). Più ampia è la finestra, più indietro nel tempo l'elaborazione può diffondere il segnale. Una soluzione più recente consiste nell'utilizzare una finestra asimmetrica. Le due finestre utilizzate possono essere immagini speculari l'una dell'altra. La finestra di analisi scende rapidamente da picco a zero in modo tale che gli impulsi non vengano "rilevati" molto in anticipo e la finestra di sintassi sale da zero a picco rapidamente, in modo che gli effetti di qualsiasi elaborazione non si diffondano molto indietro nel tempo. Un altro vantaggio è la bassa latenza. Le finestre asimmetriche possono avere una buona selettività in frequenza e possono sostituire finestre simmetriche di dimensioni variabili nella compressione audio, come una sorta di cura generale. VedereM. Schnell, M. Schmidt, M. Jander, T. Albert, R. Geiger, V. Ruoppila, P. Ekstrand, M. Lutzky, B. Grill, “MPEG-4 Enhanced Low Ritard AAC - un nuovo standard per comunicazione di qualità ” , 125a Convenzione AES, San Francisco, California, USA, prestampa 7503, ottobre 2008 e un altro documento della conferenza in cui mostrano anche la grandezza della trasformata di Fourier della loro finestra: Schnell, M., et al. 2007. Enhanced MPEG-4 Low Ritard AAC - Comunicazione di alta qualità a basso contenuto di bitrate. Nella 122a Convenzione AES .

Illustrazione di analisi lappate-elaborazione-sintesi usando finestre asimmetriche
Figura 1. Illustrazione dell'uso di finestre asimmetriche nella sintesi elaborata di analisi-elaborazione. Il prodotto (tratteggiato in nero) della finestra di analisi (blu) e della finestra di sintesi (arancione giallastro) si somma all'unità con la finestra della cornice precedente (tratteggiata grigia). Sono necessari ulteriori vincoli per garantire una ricostruzione perfetta quando si utilizza MDCT.

La trasformata discreta di Fourier (DFT, FFT) potrebbe essere utilizzata al posto di MDCT, ma in tali contesti fornirà dati spettrali ridondanti. Rispetto a DFT, MDCT fornisce solo la metà dei dati spettrali pur consentendo una ricostruzione perfetta se si scelgono finestre adatte.

Ecco il mio design asimmetrico della finestra (Fig. 2) adatto per l'analisi-elaborazione-sintesi lappata usando DFT ma non MDCT con cui non offre una ricostruzione perfetta. La finestra cerca di minimizzare il prodotto della larghezza di banda del tempo e della frequenza quadrata media (analogamente alla finestra gaussiana confinata ) mantenendo alcune proprietà del dominio del tempo potenzialmente utili: non negativo, unimodale con il picco a "tempo zero" attorno al quale l'analisi e la sintesi le finestre sono immagini speculari l'una dell'altra, funzione e prima continuità derivativa, media zero quando il quadrato della funzione finestra è interpretato come una funzione di densità di probabilità non normalizzata. La finestra è stata ottimizzata utilizzando l' evoluzione differenziale .

Finestra asimmetrica e coseno
Figura 2. Sinistra: una finestra di analisi asimmetrica adatta per analisi-elaborazione-risintesi sovrapposte insieme alla finestra di sintesi della controparte invertita nel tempo. A destra: finestra del coseno, con la stessa latenza della finestra asimmetrica

Trasformazioni di Fourier delle finestre
Figura 3. Magnitudo delle trasformate di Fourier della finestra del coseno (blu) e della finestra asimmetrica (arancione) di Fig. 2. La finestra asimmetrica mostra una migliore selettività di frequenza.

Ecco il codice sorgente di Octave per i grafici e per la finestra asimmetrica. Il codice di tracciamento proviene da Wikimedia Commons . Su Linux vi consiglio di installare gnuplot, epstool, pstoedit, transfigprima e librsvg2-binper la visualizzazione di utilizzo 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");

È possibile che si desideri utilizzare solo un secondo campione della finestra perché inizia e termina a zero. Il seguente codice C ++ lo fa per te in modo da non ottenere alcun campione zero tranne che in un quarto della finestra che è zero ovunque. Per la finestra di analisi questo è il primo trimestre e per la finestra di sintesi questo è l'ultimo trimestre. La seconda metà della finestra di analisi dovrebbe essere allineata con la prima metà della finestra di sintesi per il calcolo del loro prodotto. Il codice verifica anche la media della finestra (come funzione di densità di probabilità) e mostra la planarità della ricostruzione sovrapposta.

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

E il codice sorgente per la funzione di costo di ottimizzazione da utilizzare con Kiss FFT e una libreria di ottimizzazione :

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

3

Dipende dal contesto delle finestre. Il windowing, come era tradizionalmente sviluppato, era inteso per il metodo Blackman-Tukey di densità spettrale di stima della potenza. Questa è la forma generale dei metodi del correlogramma, per cui viene sfruttato il teorema di Wiener-Khinchin a tempo discreto. Ricordiamo che ciò collega la sequenza di autocorrelazione alla densità spettrale di potenza attraverso la trasformata di Fourier a tempo discreto.

Pertanto, le finestre sono state progettate tenendo conto di diversi criteri. In primo luogo, dovevano avere un guadagno unitario all'origine. Questo per preservare la potenza nella sequenza di autocorrelazione del segnale, poiché rxx [0] può essere considerato come la potenza di campionamento. Successivamente, la finestra dovrebbe rastremarsi rispetto all'origine. Questo è per una serie di motivi. Innanzitutto, per essere una sequenza di autocorrelazione valida, tutti gli altri ritardi devono essere inferiori o uguali all'origine. In secondo luogo, ciò ha consentito una maggiore ponderazione dei ritardi inferiori, che sono stati calcolati con grande sicurezza utilizzando la maggior parte dei campioni, e una ponderazione piccola o nulla dei ritardi superiori, che hanno una varianza crescente a causa della quantità decrescente di campioni di dati disponibili per i loro calcolo. Ciò si traduce in definitiva in un lobo principale più ampio e successivamente una riduzione della risoluzione nella stima del PSD,

Infine, è anche molto desiderato se le finestre hanno uno spettro non negativo. Questo perché con il metodo Blackman-Tukey, puoi pensare al bias della stima finale come alla vera densità spettrale di potenza contorta con lo spettro delle finestre. Se questo spettro di finestre ha regioni negative, è possibile avere regioni negative nella stima della densità spettrale di potenza. Questo ovviamente non è desiderato, poiché ha poco significato fisico in questo contesto. Inoltre, noterai che non vi sono operazioni al quadrato di magnitudo nel metodo Blackman-Tukey. Questo perché, con una sequenza di autocorrelazione reale e persino moltiplicata per una finestra reale e uniforme, anche la trasformata di Fourier discreta sarà reale e uniforme. In pratica, troverai componenti negativi molto piccoli che di solito vengono quantizzati.

Per questi motivi, le finestre hanno anche una lunghezza dispari perché anche tutte le sequenze di autocorrelazione valide lo sono. Ora, ciò che può ancora essere fatto (e fatto) è il windowing nel contesto dei metodi periodogramma. Cioè, finestra i dati e quindi prendere la grandezza al quadrato dei dati con finestra. Questo non equivale al metodo Blackman-Tukey. È possibile scoprire, attraverso alcune derivazioni statistiche, che si comportano in modo simile in media , ma non in generale. Ad esempio, è abbastanza comune utilizzare le finestre per ogni segmento nel metodo di Welch o Bartlett per ridurre la varianza delle stime. Quindi, in sostanza, con questi metodi, la motivazione è in parte la stessa, ma diversa. La potenza viene normalizzata in questi metodi dividendo l'energia della finestra, ad esempio, anziché un'attenta ponderazione dei ritardi della finestra.

Quindi, si spera che questo contestualizzi le finestre e le loro origini e perché siano simmetrici. Se sei curioso di sapere perché si può scegliere una finestra asimmetrica, considera le implicazioni della proprietà della dualità della trasformata di Fourier e cosa significa pervolgere la stima della densità spettrale di potenza per la tua applicazione. Saluti.


1

Il punto originale di windowing è assicurarsi che il segnale (assunto periodicamente dal DFT) non abbia transitori netti all'inizio rispetto alla fine. Il costo è che le frequenze verso il centro della finestra (simmetrica) saranno più ponderate e rappresentate nel DFT successivo.

Con tutto ciò sullo sfondo, posso immaginare che si vorrebbe usare una finestra asimmetrica per accentuare le caratteristiche temporali locali nel segnale analizzato tramite il DFT. Tuttavia, ciò potrebbe comportare il costo di una larghezza del lobo più ampia durante il DFT, se i punti finali del segnale non hanno all'incirca la stessa ampiezza dopo il windowing.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.