БПФ с асимметричным окном?

17

Все обычные непрямоугольные оконные функции кажутся симметричными. Есть ли когда-нибудь случай, когда кто-то захочет использовать несимметричную оконную функцию перед БПФ? (Скажите, если данные на одной стороне апертуры БПФ считались немного более важными, чем данные на другой, или менее шумными и т. Д.)

Если да, то какие виды асимметричных оконных функций были изучены и как они влияют на частотную характеристику по сравнению с симметричным окном со смещением (с большими потерями?)?

hotpaw2
источник
2
Обычно окна используются, потому что БПФ работает с небольшими порциями сигнала, пытаясь заставить его локально выглядеть как стационарный сигнал. Таким образом, нет предпочтительной «стороны», сигнал считается равномерным во всем.
эндолит
4
в алгоритме анализа звука, который работает с живыми данными и имеет задержку пропускной способности, о которой следует беспокоиться, иногда может быть создано асимметричное окно, которое имеет менее эффективную задержку, чем симметричное окно той же длины. если поведение этого асимметричного окна (которое известно заранее) влияет на выходные параметры этого аудио анализа известным способом, эти параметры могут быть скомпенсированы, и вы сохраните преимущество уменьшенной задержки.
Роберт Бристоу-Джонсон

Ответы:

9

Я буду использовать сокращенное окно для «оконной функции».

Со звуком любая обработка, которая создает что-то похожее на предварительный звонок или предварительное эхо, будет звучать неряшливо, как mp3 с низкой скоростью передачи. Это происходит, когда локализованная энергия переходного процесса или импульса распространяется во времени назад, например, путем модификации спектральных данных в перекрывающихся преобразованиях, таких как перекрывающееся модифицированное дискретное косинусное преобразование (MDCT). При такой обработке аудио обрабатывается окнами с перекрывающимися окнами анализа , преобразуется, обрабатывается в частотной области (например, данные сжимаются до меньшего битрейта), снова отображается в окне синтеза и суммируется обратно вместе. Продукт окна анализа и синтеза должен быть таким, чтобы перекрывающиеся окна сводились к единице.

Традиционно используемые оконные функции были симметричными, а их ширина была компромиссом между частотной избирательностью (длинное окно) и предотвращением артефактов во временной области (короткое окно). Чем шире окно, тем больше времени назад обработка может распространить сигнал. Более свежим решением является использование асимметричного окна. Два используемых окна могут быть зеркальным отображением друг друга. Окно анализа быстро падает с пика до нуля, так что импульсы не «детектируются» заблаговременно, а окно синтеза быстро поднимается с нуля до пика, так что эффекты любой обработки не сильно распространяются во времени. Еще одним преимуществом этого является низкая задержка. Асимметричные окна могут иметь хорошую частотную избирательность и могут заменять симметричные окна переменного размера при сжатии звука, как своего рода лекарство от всех болезней. ВидетьМ. Шнелл, М. Шмидт, М. Джандер, Т. Альберт, Р. Гейгер, В. Руоппила, П. Экстранд, М. Луцки, Б. Гриль, «MPEG-4 Enhanced Low Delay AAC - новый стандарт для высоких качественная связь » , 125-я Конвенция AES, Сан-Франциско, Калифорния, США, препринт 7503, октябрь 2008 г. и другой документ для конференций, где они также показывают величину преобразования Фурье своего окна: Schnell, M., et al. 2007. Улучшенный MPEG-4 с низкой задержкой AAC - связь с низким битрейтом и высоким качеством. В 122-й конвенции AES .

Иллюстрация перекрывающегося анализа-обработки-синтеза с использованием асимметричных окон
Рисунок 1. Иллюстрация использования асимметричных окон в совмещенном анализе-обработке-синтезе. Произведение (черным пунктиром) окна анализа (синего цвета) и окна синтеза (желтовато-оранжевого цвета) суммируется с единицей из окна предыдущего кадра (серого цвета). Необходимы дополнительные ограничения, чтобы гарантировать идеальную реконструкцию при использовании MDCT.

Дискретное преобразование Фурье (DFT, FFT) может быть использовано вместо MDCT, но в таких случаях дает избыточные спектральные данные. По сравнению с DFT, MDCT дает только половину спектральных данных, в то же время обеспечивая идеальную реконструкцию, если выбраны подходящие окна.

Вот мой собственный асимметричный дизайн окна (рис. 2), подходящий для перекрывающегося анализа-обработки-синтеза с использованием DFT, но не MDCT, с которым он не дает идеальной реконструкции. Окно пытается минимизировать произведение среднеквадратичных значений ширины полосы времени и частоты (аналогично ограниченному окну Гаусса ), сохраняя при этом некоторые потенциально полезные свойства во временной области: неотрицательные, унимодальные с пиком в «нулевом времени», вокруг которого анализируются и синтезируются окна являются зеркальными отображениями друг друга, непрерывности функции и первой производной, среднего значения нуля, когда квадрат оконной функции интерпретируется как ненормализованная функция плотности вероятности. Окно было оптимизировано с использованием дифференциальной эволюции .

Асимметричное и косинусное окно
Рисунок 2. Слева: асимметричное окно анализа, подходящее для перекрывающегося анализа-обработки-повторного синтеза вместе с обратным по времени окном синтеза аналога. Справа: окно косинуса, с той же задержкой, что и у асимметричного окна

Фурье-трансформ окон
Рисунок 3. Величина преобразований Фурье окна косинуса (синего цвета) и асимметричного окна (оранжевого цвета) на рисунке 2. Несимметричное окно показывает лучшую частотную избирательность.

Вот исходный код Octave для графиков и асимметричного окна. Код для заимствования взят из Wikimedia Commons . В Linux я рекомендую установить gnuplot, epstool, pstoedit, transfigпервый и librsvg2-binдля просмотра с помощью 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");

Возможно, вы захотите использовать только каждый второй образец окна, потому что оно начинается и заканчивается в нуле. Следующий код C ++ делает это за вас, поэтому вы не получите никаких нулевых выборок, за исключением одной четверти окна, которая везде равна нулю. Для окна анализа это первый квартал, а для окна синтеза - последний квартал. Вторая половина окна анализа должна быть выровнена с первой половиной окна синтеза для расчета их продукта. Код также проверяет среднее значение окна (как функцию плотности вероятности) и демонстрирует плоскостность перекрывающейся реконструкции.

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

И исходный код функции стоимости оптимизации, которая будет использоваться с Kiss FFT и библиотекой оптимизации :

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

Это зависит от контекста окон. Оконное управление, как оно традиционно разрабатывалось, было предназначено для метода оценки спектральной плотности мощности Блэкмана-Тьюки. Это общий вид методов коррелограмм, в которых используется теорема Винера-Хинчина с дискретным временем. Напомним, это связывает автокорреляционную последовательность со спектральной плотностью мощности через дискретное временное преобразование Фурье.

Поэтому окна были разработаны с учетом нескольких критериев. Во-первых, они должны были получить единство в начале координат. Это должно было сохранить мощность в последовательности автокорреляции сигнала, так как rxx [0] можно рассматривать как мощность выборки. Далее окно должно сужаться от начала координат. Это по ряду причин. Во-первых, чтобы быть действительной последовательностью автокорреляции, все другие лаги должны быть меньше или равны началу координат. Во-вторых, это учитывало более высокий вес более низких лагов, которые были рассчитаны с большой достоверностью с использованием большинства выборок, и небольшой или нулевой вес более высоких лагов, которые имеют увеличивающуюся дисперсию из-за уменьшения количества выборок данных, доступных для их расчет. В конечном итоге это приводит к расширению основного лепестка и, как следствие, снижению разрешения в оценке PSD,

Наконец, также желательно, чтобы окна имели неотрицательный спектр. Это связано с тем, что с помощью метода Блэкмена-Тьюки можно представить смещение окончательной оценки как истинную спектральную плотность мощности, свернутую со спектром окна. Если у этого спектра окна есть отрицательные области, возможно иметь отрицательные области в вашей оценке спектральной плотности мощности. Это, очевидно, нежелательно, так как в этом контексте имеет мало физического значения. Кроме того, вы заметите, что в методе Блэкмена-Тьюки нет операции возведения в квадрат. Это связано с тем, что при действительной и равномерной последовательности автокорреляции, умноженной на реальное и четное окно, дискретное преобразование Фурье также будет действительным и четным. На практике вы найдете очень маленькие отрицательные компоненты, которые обычно квантуется.

По этим причинам окна также имеют нечетную длину, потому что все действительные последовательности автокорреляции также. Теперь то, что еще можно сделать (и делается), - это управление окнами в контексте методов периодограммы. То есть, окно данных, а затем взять квадрат величины оконных данных. Это не эквивалентно методу Блэкмена-Тьюки. Через некоторые статистические выводы вы можете обнаружить, что они ведут себя аналогично в среднем , но не в целом. Например, для уменьшения дисперсии оценок достаточно использовать окна для каждого сегмента в методе Уэлча или Бартлетта. Таким образом, по сути, с этими методами мотивация отчасти одинакова, но различна. В этих методах мощность нормализуется, например, путем деления энергии окна вместо тщательного взвешивания оконных лагов.

Итак, мы надеемся, что это контекстуализирует окна и их происхождение, и почему они симметричны. Если вам интересно, почему можно выбрать асимметричное окно, рассмотрите последствия свойства двойственности преобразования Фурье и то, что свертка для оценки вашей спектральной плотности мощности означает для вашего приложения. Приветствия.

Bryan
источник
1

Первоначальная задача управления окнами - убедиться, что сигнал (предполагаемый периодическим с помощью DFT) не имеет резких переходных процессов в начале по сравнению с концом. Стоимость состоит в том, что частоты к центру (симметричного) окна будут более взвешенными и представлены в последующем ДПФ.

Имея все это на заднем плане, я могу себе представить, что можно использовать асимметричное окно, чтобы подчеркнуть локальные временные особенности в сигнале, который анализируется с помощью ДПФ. Однако это может происходить за счет более широкой ширины лепестка во время ДПФ, если конечные точки вашего сигнала не имеют примерно одинаковую амплитуду после оконного преобразования.

ошалевший
источник