FFT dengan jendela asimetris?


17

Fungsi jendela non-persegi panjang yang umum semua tampak simetris. Apakah ada kasus ketika seseorang ingin menggunakan fungsi jendela non-simetris sebelum FFT? (Katakan jika data di satu sisi bukaan FFT dianggap sedikit lebih penting daripada data di sisi lain, atau kurang berisik, dll.)

Jika demikian, apa jenis fungsi jendela asimetris yang telah dipelajari, dan bagaimana mereka mempengaruhi respon frekuensi dibandingkan dengan (lebih lossy?) Offset jendela simetris?


2
Umumnya windows digunakan karena FFT beroperasi pada potongan kecil dari sinyal, mencoba membuatnya terlihat secara lokal seperti sinyal diam. Jadi tidak ada "sisi" yang lebih disukai, sinyalnya diasumsikan seragam.
endolith

4
dalam algoritma analisis audio yang bekerja pada data langsung dan memiliki penundaan throughput yang perlu dikhawatirkan, kadang-kadang jendela asimetris dapat dirancang yang memiliki penundaan kurang efektif daripada jendela simetris dengan panjang yang sama. jika perilaku jendela asimetris ini (yang diketahui sebelumnya) mempengaruhi parameter output dari analisis audio ini dengan cara yang diketahui, parameter tersebut dapat dikompensasi dan Anda mempertahankan keuntungan dari pengurangan waktu tunda.
robert bristow-johnson

Jawaban:


9

Saya akan menggunakan jendela singkatan untuk "fungsi jendela".

Dengan audio, pemrosesan apa pun yang menciptakan sesuatu yang mirip dengan pra-dering atau pra-gema akan terdengar buruk seperti mp3 bit-rate rendah. Ini terjadi ketika energi lokal dari transien atau impuls tersebar ke belakang dalam waktu, misalnya dengan modifikasi data spektral dalam transformasi tersusun seperti lapped modified discrete cosine transform (MDCT). Dalam pemrosesan tersebut, audio di-windowed oleh windows analisis yang tumpang tindih , diubah, diproses dalam domain frekuensi (seperti data-dikompresi ke bitrate lebih kecil), windowed lagi dengan jendela sintesis dan dijumlahkan kembali bersama-sama. Produk dari jendela analisis dan sintesis harus sedemikian rupa sehingga jumlah jendela yang tumpang tindih menjadi satu.

Secara tradisional fungsi jendela yang digunakan telah simetris, dan lebarnya merupakan kompromi antara selektivitas frekuensi (jendela panjang) dan penghindaran artefak time-domain (jendela pendek). Semakin lebar jendela, semakin lama pemrosesan dapat menyebarkan sinyal. Solusi yang lebih baru adalah dengan menggunakan jendela asimetris. Dua jendela yang digunakan dapat menjadi gambar cermin satu sama lain. Jendela analisis turun dari puncak ke nol dengan cepat sehingga impuls tidak "terdeteksi" jauh sebelumnya, dan jendela syntheis naik dari nol ke puncak cepat, sehingga efek dari setiap pemrosesan tidak menyebar jauh ke belakang dalam waktu. Keuntungan lain dari ini adalah latensi rendah. Jendela asimetris dapat memiliki selektivitas frekuensi yang baik, dan dapat menggantikan jendela simetris berukuran variabel dalam kompresi audio, seperti semacam obat untuk semua. LihatM. Schnell, M. Schmidt, M. Jander, T. Albert, R. Geiger, V. Ruoppila, P. Ekstrand, M. Lutzky, B. Grill, “MPEG-4 Enhanced Low Delay AAC - standar baru untuk tinggi komunikasi yang berkualitas ” , Konvensi AES ke-125, San Francisco, CA, AS, pracetak 7503, Oktober 2008 dan makalah konferensi lainnya di mana mereka juga memperlihatkan besarnya transformasi Fourier dari jendela mereka: Schnell, M., et al. 2007. Enhanced MPEG-4 Low Delay AAC - Komunikasi Kualitas Tinggi Bitrate Rendah. Dalam Konvensi AES ke-122 .

Ilustrasi analisis-pemrosesan-sintesis tersusun menggunakan jendela asimetris
Gambar 1. Ilustrasi penggunaan windows asimetris dalam analisis-pemrosesan-sintesis menjilat. Produk (hitam putus-putus) dari jendela analisis (biru) dan jendela sintesis (oranye kekuningan) berjumlah satu dengan jendela dari bingkai sebelumnya (abu-abu putus-putus). Kendala lebih lanjut diperlukan untuk menjamin rekonstruksi sempurna ketika menggunakan MDCT.

Transformasi Fourier Diskrit (DFT, FFT) dapat digunakan sebagai pengganti MDCT, tetapi dalam konteks seperti itu akan memberikan data spektral yang berlebihan. Dibandingkan dengan DFT, MDCT hanya memberikan setengah dari data spektral sambil tetap memungkinkan rekonstruksi sempurna jika jendela yang sesuai dipilih.

Berikut ini adalah desain jendela asimetris saya sendiri (Gbr. 2) yang cocok untuk analisis-pemrosesan-sintesis tersusun menggunakan DFT tetapi bukan MDCT yang tidak memberikan rekonstruksi sempurna. Jendela mencoba untuk meminimalkan produk dari rata-rata waktu dan bandwidth frekuensi (mirip dengan jendela Gaussian terbatas ) sambil mempertahankan beberapa sifat-sifat domain waktu yang berpotensi berguna: nonnegatif, unimodal dengan puncak pada "waktu nol" di mana analisis dan sintesis jendela adalah gambar cermin satu sama lain, fungsi dan kontinuitas turunan pertama, rata-rata nol ketika kuadrat dari fungsi jendela ditafsirkan sebagai fungsi kepadatan probabilitas yang tidak dinormalisasi. Jendela dioptimalkan menggunakan evolusi diferensial .

Jendela asimetris dan kosinus
Gambar 2. Kiri: Jendela analisis asimetris yang cocok untuk tumpang tindih analisis-pemrosesan-sintesis bersama-sama dengan jendela sintesis rekanan yang dibalik waktu. Kanan: Jendela kosinus, dengan latensi yang sama dengan jendela asimetris

Fourier tranforms dari windows
Gambar 3. Magnitudo transformasi Fourier dari jendela kosinus (biru) dan jendela asimetris (oranye) dari Gambar 2. Jendela asimetris menunjukkan selektivitas frekuensi yang lebih baik.

Berikut adalah kode sumber oktaf untuk plot dan untuk jendela asimetris. Kode plot berasal dari Wikimedia Commons . Pada Linux Saya sarankan menginstal gnuplot, epstool, pstoedit, transfigpertama dan librsvg2-binuntuk melihat menggunakan 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");

Anda mungkin hanya ingin menggunakan setiap sampel jendela karena dimulai dan berakhir pada nol. Kode C ++ berikut melakukan itu untuk Anda sehingga Anda tidak mendapatkan sampel nol kecuali dalam seperempat jendela yang nol di mana-mana. Untuk jendela analisis, ini adalah kuartal pertama dan untuk jendela sintesis, ini adalah kuartal terakhir. Bagian kedua dari jendela analisis harus disejajarkan dengan bagian pertama dari jendela sintesis untuk perhitungan produk mereka. Kode ini juga menguji rata-rata jendela (sebagai fungsi kepadatan probabilitas), dan menampilkan kerataan rekonstruksi yang tumpang tindih.

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

Dan kode sumber untuk fungsi biaya pengoptimalan yang akan digunakan dengan Kiss FFT dan pustaka optimasi :

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

Itu tergantung pada konteks windowing. Windowing, seperti yang secara tradisional dikembangkan, dimaksudkan untuk metode Blackman-Tukey dari estimasi kepadatan spektral daya. Ini adalah bentuk umum metode korelogram, di mana teorema Wiener-Khinchin waktu diskrit dieksploitasi. Ingat ini menghubungkan urutan autokorelasi dengan kepadatan spektral daya melalui transformasi Fourier waktu diskrit.

Oleh karena itu, windows dirancang dengan beberapa kriteria dalam pikiran. Pertama, mereka harus memiliki keuntungan persatuan pada awalnya. Ini untuk menjaga daya dalam urutan autokorelasi sinyal, karena rxx [0] dapat dianggap sebagai kekuatan sampel. Selanjutnya, jendela harus meruncing dari asal. Ini karena sejumlah alasan. Pertama, untuk menjadi urutan autokorelasi yang valid, semua kelambatan lain harus kurang dari atau sama dengan aslinya. Kedua, ini memungkinkan untuk pembobotan lebih tinggi dari lag yang lebih rendah, yang telah dihitung dengan sangat percaya diri menggunakan sebagian besar sampel, dan bobot kecil atau nol dari lag yang lebih tinggi, yang memiliki varians yang meningkat karena berkurangnya jumlah sampel data yang tersedia untuk sampel tersebut. perhitungan. Ini pada akhirnya menghasilkan lobus utama yang lebih luas dan kemudian menurunkan resolusi dalam estimasi PSD,

Akhirnya, itu juga sangat diinginkan jika windows memiliki spektrum non-negatif. Ini karena dengan metode Blackman-Tukey, Anda dapat memikirkan bias estimasi akhir sebagai kepadatan spektral daya sebenarnya yang dilingkupi dengan spektrum jendela. Jika spektrum jendela ini memiliki daerah negatif, dimungkinkan untuk memiliki daerah negatif dalam perkiraan kepadatan spektral daya Anda. Ini jelas tidak diinginkan, karena memiliki sedikit makna fisik dalam konteks ini. Selain itu, Anda akan mencatat tidak ada operasi kuadrat besarnya dalam metode Blackman-Tukey. Ini karena, dengan urutan autokorelasi nyata dan bahkan dikalikan dengan jendela nyata dan genap, transformasi Fourier diskrit juga akan nyata dan genap. Dalam praktiknya, Anda akan menemukan komponen negatif yang sangat kecil yang biasanya dikuantisasi.

Untuk alasan ini, windows juga memiliki panjang yang aneh karena semua urutan autokorelasi yang valid juga. Sekarang, apa yang masih bisa dilakukan (dan dilakukan) adalah windowing dalam konteks metode periodogram. Yaitu, window data, dan kemudian ambil kuadrat dari data windowed. Ini tidak setara dengan metode Blackman-Tukey. Anda dapat menemukan, melalui beberapa derivasi statistik, bahwa mereka berperilaku sama rata-rata , tetapi tidak secara umum. Misalnya, cukup umum menggunakan windowing untuk setiap segmen dalam metode Welch atau Bartlett untuk mengurangi varian estimasi. Jadi pada intinya, dengan metode ini, motivasi sebagian sama, tetapi berbeda. Daya dinormalisasi dalam metode ini dengan membagi energi jendela misalnya, bukannya pembobotan jendela yang hati-hati.

Jadi, mudah-mudahan ini mengontekstualisasikan jendela dan asal-usulnya, dan mengapa mereka simetris. Jika Anda penasaran mengapa seseorang dapat memilih jendela asimetris, pertimbangkan implikasi properti dualitas dari transformasi Fourier, dan apa yang melingkupi arti estimasi kepadatan spektral daya Anda untuk aplikasi Anda. Bersulang.


1

Titik asli windowing adalah untuk memastikan bahwa sinyal (diasumsikan periodik oleh DFT) tidak memiliki transien tajam di awal dibandingkan dengan akhir. Biayanya adalah bahwa frekuensi menuju pusat jendela (simetris) akan lebih tertimbang dan terwakili dalam DFT berikutnya.

Dengan semua itu di latar belakang, saya bisa membayangkan bahwa seseorang ingin menggunakan jendela asimetris untuk menonjolkan fitur temporal lokal dalam sinyal yang dianalisis melalui DFT. Namun ini mungkin terjadi dengan biaya lebar lobus yang lebih luas selama DFT, jika titik akhir sinyal Anda tidak kira-kira sama dengan amplitudo setelah windowing.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.