FFT con ventanas asimétricas?


17

Todas las funciones comunes de ventana no rectangular parecen ser simétricas. ¿Hay algún caso en el que uno quiera usar una función de ventana no simétrica antes de una FFT? (Digamos si los datos en un lado de la apertura FFT se consideraron un poco más importantes que los datos en el otro, o menos ruidosos, etc.)

Si es así, ¿qué tipos de funciones de ventana asimétrica se han estudiado y cómo afectarían a la respuesta de frecuencia en comparación con una ventana simétrica de compensación (¿más pérdida?)?


2
En general, las ventanas se usan porque la FFT está operando en pequeños fragmentos de una señal, tratando de hacer que se vea localmente como una señal estacionaria. Por lo tanto, no hay un "lado" para preferir, se supone que la señal es uniforme en todo momento.
endolito

44
En un algoritmo de análisis de audio que funciona con datos en vivo y tiene que preocuparse por el retraso del rendimiento, a veces se puede diseñar una ventana asimétrica que tenga un retraso menos efectivo que la ventana simétrica de la misma longitud. Si el comportamiento de esta ventana asimétrica (que se conoce de antemano) afecta los parámetros de salida de este análisis de audio de una manera conocida, esos parámetros pueden compensarse y usted conserva la ventaja de un retraso reducido.
robert bristow-johnson

Respuestas:


9

Usaré la ventana abreviada para "función de ventana".

Con el audio, cualquier procesamiento que cree algo parecido a un sonido previo o un eco previo sonará como un mp3 de baja velocidad de bits. Esto sucede cuando la energía localizada de un transitorio o un impulso se propaga hacia atrás en el tiempo, por ejemplo, mediante la modificación de los datos espectrales en transformaciones superpuestas, como la transformada discreta de coseno modificada (MDCT). En dicho procesamiento, el audio se abre mediante ventanas de análisis superpuestas , se transforma, se procesa en el dominio de frecuencia (como datos comprimidos a una tasa de bits más pequeña), se vuelve a abrir con una ventana de síntesis y se vuelven a resumir. El producto de la ventana de análisis y síntesis debe ser tal que las ventanas superpuestas sumen unidad.

Tradicionalmente, las funciones de ventana utilizadas han sido simétricas, y su ancho ha sido un compromiso entre la selectividad de frecuencia (ventana larga) y la evitación de artefactos en el dominio del tiempo (ventana corta). Cuanto más amplia sea la ventana, más tiempo atrás el procesamiento puede difundir la señal. Una solución más reciente es usar una ventana asimétrica. Las dos ventanas utilizadas pueden ser imágenes especulares entre sí. La ventana de análisis cae de pico a cero rápido para que los impulsos no se "detecten" con mucha anticipación, y la ventana de síntesis se eleva de cero a pico rápido, de modo que los efectos de cualquier procesamiento no se extiendan mucho hacia atrás en el tiempo. Otra ventaja de esto es la baja latencia. Las ventanas asimétricas pueden tener una buena selectividad de frecuencia y pueden reemplazar ventanas simétricas de tamaño variable en la compresión de audio, como una especie de remedio. VerM. Schnell, M. Schmidt, M. Jander, T. Albert, R. Geiger, V. Ruoppila, P. Ekstrand, M. Lutzky, B. Grill, “MPEG-4 Enhanced Low Delay AAC - un nuevo estándar para alto comunicación de calidad ” , 125a Convención AES, San Francisco, CA, EE. UU., preprint 7503, octubre de 2008 y otro documento de conferencia donde muestran también la magnitud de la transformación de Fourier de su ventana: Schnell, M., et al. 2007. Mejorado MPEG-4 Low Delay AAC - Baja tasa de bits de comunicación de alta calidad. En 122º Convenio AES .

Ilustración de análisis-procesamiento-síntesis lapeada usando ventanas asimétricas
Figura 1. Ilustración del uso de ventanas asimétricas en análisis-procesamiento-síntesis solapada. El producto (trazo negro) de la ventana de análisis (azul) y la ventana de síntesis (naranja amarillento) se unen con la ventana del cuadro anterior (trazo gris). Se necesitan más restricciones para garantizar una reconstrucción perfecta cuando se usa MDCT.

La transformada discreta de Fourier (DFT, FFT) podría usarse en lugar de MDCT, pero en tales contextos dará datos espectrales redundantes. En comparación con DFT, MDCT proporciona solo la mitad de los datos espectrales y, al mismo tiempo, permite una reconstrucción perfecta si se eligen ventanas adecuadas.

Aquí está mi propio diseño de ventana asimétrica (Fig. 2) adecuado para análisis-procesamiento-síntesis lapeado usando DFT pero no MDCT con el que no proporciona una reconstrucción perfecta. La ventana intenta minimizar el producto del ancho de banda del tiempo cuadrado medio y la frecuencia (de manera similar a la ventana gaussiana confinada ) al tiempo que conserva algunas propiedades de dominio del tiempo potencialmente útiles: no negativas, unimodales con el pico en el "tiempo cero" en torno al cual el análisis y la síntesis Las ventanas son imágenes especulares entre sí, función y continuidad de la primera derivada, media cero cuando el cuadrado de la función de ventana se interpreta como una función de densidad de probabilidad no normalizada. La ventana se optimizó utilizando la evolución diferencial .

Ventana asimétrica y coseno
Figura 2. Izquierda: una ventana de análisis asimétrico adecuada para la superposición de análisis, procesamiento y superposición junto con su ventana de síntesis de contraparte inversa. Derecha: ventana de coseno, con la misma latencia que la ventana asimétrica

Transformaciones de Fourier de las ventanas
Figura 3. Magnitud de las transformadas de Fourier de la ventana del coseno (azul) y la ventana asimétrica (naranja) de la Fig. 2. La ventana asimétrica muestra una mejor selectividad de frecuencia.

Aquí está el código fuente de Octave para las parcelas y para la ventana asimétrica. El código de trazado proviene de Wikimedia Commons . En Linux te recomiendo instalar gnuplot, epstool, pstoedit, transfigprimero, y librsvg2-binpara su visualización utilizando 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");

Es posible que desee utilizar solo cada segunda muestra de la ventana porque comienza y termina en cero. El siguiente código de C ++ lo hace por usted para que no obtenga ninguna muestra de cero, excepto en un cuarto de la ventana que es cero en todas partes. Para la ventana de análisis, este es el primer trimestre y para la ventana de síntesis, este es el último trimestre. La segunda mitad de la ventana de análisis debe estar alineada con la primera mitad de la ventana de síntesis para el cálculo de su producto. El código también prueba la media de la ventana (como una función de densidad de probabilidad) y muestra la planitud de la reconstrucción superpuesta.

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

Y el código fuente para la función de costo de optimización que se utilizará con Kiss FFT y una biblioteca de optimización :

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

Depende del contexto de la ventana. Windowing, como se desarrolló tradicionalmente, estaba destinado al método Blackman-Tukey de densidad espectral de potencia de estimación. Esta es la forma general de los métodos de correlograma, mediante el cual se aprovecha el teorema de Wiener-Khinchin de tiempo discreto. Recuerde que esto relaciona la secuencia de autocorrelación con la densidad espectral de potencia a través de la transformada de Fourier de tiempo discreto.

Por lo tanto, las ventanas fueron diseñadas con varios criterios en mente. Primero, tenían que tener ganancia de unidad en el origen. Esto era para preservar la potencia en la secuencia de autocorrelación de la señal, ya que rxx [0] puede considerarse como la potencia de la muestra. A continuación, la ventana debe reducirse desde el origen. Esto es por varias razones. Primero, para ser una secuencia de autocorrelación válida, todos los otros retrasos deben ser menores o iguales que el origen. En segundo lugar, esto permitió una mayor ponderación de los rezagos más bajos, que se han calculado con gran confianza utilizando la mayoría de las muestras, y una ponderación pequeña o nula de los rezagos más altos, que tienen una variación creciente debido a la disminución de la cantidad de muestras de datos disponibles para su cálculo. Esto finalmente resulta en un lóbulo principal más amplio y, posteriormente, una resolución disminuida en la estimación de PSD,

Finalmente, también es muy deseable si las ventanas tienen un espectro no negativo. Esto se debe a que con el método Blackman-Tukey, puede pensar en el sesgo de la estimación final como la densidad espectral de potencia real convolucionada con el espectro de la ventana. Si este espectro de ventana tiene regiones negativas, es posible tener regiones negativas en su estimación de densidad espectral de potencia. Obviamente, esto no es deseado, ya que tiene poco significado físico en este contexto. Además, notará que no hay una operación de magnitud al cuadrado en el método Blackman-Tukey. Esto se debe a que, con una secuencia de autocorrelación real e incluso multiplicada por una ventana real e incluso, la transformada discreta de Fourier también será real e incluso. En la práctica, encontrará componentes negativos muy pequeños que generalmente se cuantifican.

Por estas razones, las ventanas también tienen una longitud extraña porque todas las secuencias de autocorrelación válidas también lo son. Ahora, lo que aún se puede hacer (y se hace) es la ventana en el contexto de los métodos del periodograma. Es decir, coloque en una ventana los datos y luego tome la magnitud al cuadrado de los datos en ventana. Esto no es equivalente al método Blackman-Tukey. Puede encontrar, a través de algunas derivaciones estadísticas, que se comportan de manera similar en promedio , pero no en general. Por ejemplo, es bastante común usar ventanas para cada segmento en el método de Welch o Bartlett para disminuir la varianza de las estimaciones. Entonces, en esencia, con estos métodos, la motivación es en parte la misma, pero diferente. La potencia se normaliza en estos métodos dividiendo la energía de la ventana, por ejemplo, en lugar de ponderar cuidadosamente los rezagos de la ventana.

Entonces, con suerte, esto contextualiza las ventanas y sus orígenes, y por qué son simétricas. Si tiene curiosidad acerca de por qué uno puede elegir una ventana asimétrica, considere las implicaciones de la propiedad de dualidad de la transformada de Fourier y lo que implica su estimación de densidad espectral de potencia para su aplicación. Salud.


1

El punto original de la ventana es asegurarse de que la señal (asumida periódicamente por el DFT) no tenga transitorios agudos al principio en comparación con el final. El costo es que las frecuencias hacia el centro de la ventana (simétrica) estarán más ponderadas y representadas en el DFT posterior.

Con todo eso en el fondo, me imagino que uno querría usar una ventana asimétrica para acentuar las características temporales locales en la señal que se analiza a través del DFT. Sin embargo, esto podría tener el costo de un ancho de lóbulo más amplio durante DFT, si los puntos finales de su señal no tienen aproximadamente la misma amplitud después de la ventana.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.