FFT với cửa sổ bất đối xứng?


17

Các hàm cửa sổ không phải hình chữ nhật thông thường dường như đều đối xứng. Có bao giờ một trường hợp khi một người muốn sử dụng một chức năng cửa sổ không đối xứng trước một FFT? (Nói nếu dữ liệu ở một bên của khẩu độ FFT được coi là quan trọng hơn một chút so với dữ liệu ở phía bên kia, hoặc ít ồn hơn, v.v.)

Nếu vậy, những loại chức năng cửa sổ không đối xứng nào đã được nghiên cứu, và chúng sẽ ảnh hưởng đến đáp ứng tần số như thế nào so với cửa sổ đối xứng bù (mất nhiều hơn?)?


2
Nói chung, các cửa sổ được sử dụng vì FFT đang hoạt động trên các khối nhỏ của tín hiệu, cố gắng làm cho nó trông giống như tín hiệu đứng yên. Vì vậy, không có "bên" nào thích hơn, tín hiệu được giả sử là đồng nhất trong suốt.
endolith

4
trong một thuật toán phân tích âm thanh đang làm việc trên dữ liệu trực tiếp và có độ trễ thông lượng để lo lắng, đôi khi một cửa sổ không đối xứng có thể được thiết kế có độ trễ ít hiệu quả hơn so với cửa sổ đối xứng có cùng độ dài. nếu hành vi của cửa sổ không đối xứng này (được biết trước) ảnh hưởng đến các tham số đầu ra của phân tích âm thanh này theo cách đã biết, các tham số đó có thể được bù và bạn vẫn giữ được lợi thế giảm độ trễ.
robert bristow-johnson

Câu trả lời:


9

Tôi sẽ sử dụng cửa sổ tốc ký cho "chức năng cửa sổ".

Với âm thanh, bất kỳ quá trình xử lý nào tạo ra một cái gì đó giống với tiếng chuông trước hoặc tiếng vang trước sẽ nghe có vẻ chậm chạp như một bản mp3 tốc độ bit thấp. Điều này xảy ra khi năng lượng cục bộ của một thoáng qua hoặc một xung được truyền ngược thời gian, ví dụ như bằng cách sửa đổi dữ liệu quang phổ trong các biến đổi bị mất hiệu lực như biến đổi cosine rời rạc đã sửa đổi (MDCT). Trong quá trình xử lý như vậy, âm thanh được cửa sổ bằng các cửa sổ phân tích chồng chéo , được chuyển đổi, xử lý trong miền tần số (như dữ liệu được nén thành bitrate nhỏ hơn), được cửa sổ lại với một cửa sổ tổng hợp và gộp lại với nhau. Sản phẩm của cửa sổ phân tích và tổng hợp phải sao cho các cửa sổ chồng chéo tổng hợp lại.

Theo truyền thống, các chức năng của cửa sổ được sử dụng là đối xứng và chiều rộng của chúng là một sự thỏa hiệp giữa tính chọn lọc tần số (cửa sổ dài) và tránh giả tạo miền thời gian (cửa sổ ngắn). Cửa sổ càng rộng, thời gian xử lý càng có thể lan truyền tín hiệu. Một giải pháp gần đây hơn là sử dụng cửa sổ không đối xứng. Hai cửa sổ được sử dụng có thể là hình ảnh phản chiếu của nhau. Cửa sổ phân tích giảm từ cực đại xuống 0 nhanh để các xung không được "phát hiện" trước nhiều và cửa sổ tổng hợp tăng từ 0 lên cực đại nhanh, do đó các hiệu ứng của bất kỳ quá trình xử lý nào không bị lan truyền ngược thời gian. Một ưu điểm khác của điều này là độ trễ thấp. Các cửa sổ không đối xứng có thể có độ chọn lọc tần số tốt và có thể thay thế các cửa sổ đối xứng có kích thước thay đổi trong nén âm thanh, giống như một kiểu chữa bệnh. XemM. Schnell, M. Schmidt, M. Jander, T. Albert, R. Geiger, V. Ruoppila, P. Ekstrand, M. Lutzky, B. Grill, MPEG MPEG-4 Tăng cường độ trễ thấp AAC - một tiêu chuẩn mới cho cao truyền thông chất lượng , Hội nghị AES lần thứ 125, San Francisco, CA, Hoa Kỳ, bản in trước 7503, tháng 10 năm 2008 và một tài liệu hội nghị khác, nơi họ cũng cho thấy mức độ biến đổi Fourier của cửa sổ của họ: Schnell, M., et al. Năm 2007 , độ trễ thấp MPEG-4 AAC - Truyền thông chất lượng cao bitrate thấp. Trong Công ước AES lần thứ 122 .

Minh họa của phân tích-xử lý-tổng hợp sử dụng các cửa sổ không đối xứng
Hình 1. Minh họa về việc sử dụng các cửa sổ không đối xứng trong phân tích-xử lý-tổng hợp. Sản phẩm (nét đứt màu đen) của cửa sổ phân tích (màu xanh) và cửa sổ tổng hợp (màu vàng cam) tổng hợp với cửa sổ từ khung trước đó (màu xám nét đứt). Cần có các ràng buộc hơn nữa để đảm bảo tái thiết hoàn hảo khi sử dụng MDCT.

Biến đổi Fourier rời rạc (DFT, FFT) có thể được sử dụng thay vì MDCT, nhưng trong các bối cảnh như vậy sẽ cung cấp dữ liệu phổ dự phòng. So với DFT, MDCT chỉ cung cấp một nửa dữ liệu phổ trong khi vẫn cho phép tái tạo hoàn hảo nếu các cửa sổ phù hợp được chọn.

Dưới đây là thiết kế cửa sổ không đối xứng của riêng tôi (Hình 2) phù hợp cho phân tích-xử lý-tổng hợp bằng cách sử dụng DFT nhưng không phải MDCT mà nó không cho phép tái tạo hoàn hảo. Cửa sổ cố gắng giảm thiểu sản phẩm của băng thông thời gian và tần số trung bình bình phương (tương tự như cửa sổ Gaussian bị giới hạn ) trong khi vẫn giữ một số thuộc tính miền thời gian có thể hữu ích: không âm, không đồng nhất với cực đại tại "thời gian 0" xung quanh phân tích và tổng hợp các cửa sổ là hình ảnh phản chiếu của nhau, hàm và tính liên tục đạo hàm đầu tiên, không có nghĩa khi bình phương của hàm cửa sổ được hiểu là hàm mật độ xác suất không chuẩn hóa. Cửa sổ được tối ưu hóa bằng cách sử dụng tiến hóa khác biệt .

Cửa sổ bất đối xứng và cosin
Hình 2. Bên trái: Cửa sổ phân tích không đối xứng phù hợp cho quá trình phân tích-xử lý-tổng hợp chồng chéo cùng với cửa sổ tổng hợp đối ứng ngược thời gian của nó. Phải: Cửa sổ Cosine, có cùng độ trễ với cửa sổ không đối xứng

Fourier tranforms của các cửa sổ
Hình 3. Độ lớn của các biến đổi Fourier của cửa sổ cosin (màu xanh) và cửa sổ không đối xứng (màu cam) của Hình 2. Cửa sổ không đối xứng cho thấy độ chọn lọc tần số tốt hơn.

Dưới đây là mã nguồn Octave cho các ô và cho cửa sổ bất đối xứng. Mã âm mưu đến từ Wikimedia Commons . Trên Linux Tôi khuyên bạn nên cài đặt gnuplot, epstool, pstoedit, transfigđầu tiên và librsvg2-binđể xem sử dụng 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");

Bạn có thể chỉ muốn sử dụng mỗi mẫu thứ hai của cửa sổ vì nó bắt đầu và kết thúc ở mức 0. Mã C ++ sau đây thực hiện điều đó cho bạn để bạn không nhận được bất kỳ mẫu 0 nào ngoại trừ trong một phần tư cửa sổ bằng không ở mọi nơi. Đối với cửa sổ phân tích, đây là quý đầu tiên và đối với cửa sổ tổng hợp thì đây là quý cuối cùng. Nửa sau của cửa sổ phân tích phải được căn chỉnh với nửa đầu của cửa sổ tổng hợp để tính toán sản phẩm của họ. Mã này cũng kiểm tra giá trị trung bình của cửa sổ (dưới dạng hàm mật độ xác suất) và hiển thị độ phẳng của cấu trúc lại chồng chéo.

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

Và mã nguồn cho hàm chi phí tối ưu hóa sẽ được sử dụng với Kiss FFTthư viện tối ưu hóa :

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

Nó phụ thuộc vào bối cảnh của cửa sổ. Cửa sổ, như đã được phát triển theo truyền thống, được dành cho phương pháp Blackman - Tukey về mật độ phổ công suất ước tính. Đây là dạng tổng quát của các phương pháp tương quan, theo đó định lý Wiener-Khinchin thời gian rời rạc được khai thác. Nhớ lại điều này liên quan đến chuỗi tự tương quan với mật độ phổ công suất thông qua biến đổi Fourier thời gian rời rạc.

Do đó, các cửa sổ được thiết kế với một số tiêu chí trong tâm trí. Đầu tiên, họ phải có được sự thống nhất ở nguồn gốc. Điều này là để bảo toàn năng lượng trong chuỗi tự tương quan của tín hiệu, vì rxx [0] có thể được coi là công suất mẫu. Tiếp theo, cửa sổ nên thuôn từ gốc. Đây là một số lý do. Đầu tiên, để trở thành một chuỗi tự tương quan hợp lệ, tất cả các độ trễ khác phải nhỏ hơn hoặc bằng gốc. Thứ hai, điều này cho phép trọng số cao hơn của độ trễ thấp hơn, được tính toán với độ tin cậy cao khi sử dụng hầu hết các mẫu và trọng số nhỏ hoặc bằng 0 của độ trễ cao hơn, có độ chênh lệch tăng do số lượng mẫu dữ liệu có sẵn cho chúng giảm phép tính. Điều này cuối cùng dẫn đến một thùy chính rộng hơn và sau đó giảm độ phân giải trong ước tính PSD,

Cuối cùng, nó cũng rất mong muốn nếu các cửa sổ có phổ không âm. Điều này là do với phương pháp Blackman-Tukey, bạn có thể nghĩ về độ lệch của ước tính cuối cùng là mật độ phổ công suất thực được kết hợp với phổ cửa sổ. Nếu phổ cửa sổ này có các vùng âm, thì có thể có các vùng âm trong ước tính mật độ phổ công suất của bạn. Điều này rõ ràng là không mong muốn, vì nó có rất ít ý nghĩa vật lý trong bối cảnh này. Ngoài ra, bạn sẽ lưu ý rằng không có hoạt động bình phương cường độ trong phương pháp Blackman-Tukey. Điều này là do, với một chuỗi thực và tự tương quan nhân với một cửa sổ thực và thậm chí, biến đổi Fourier rời rạc cũng sẽ là số thực và thậm chí. Trong thực tế, bạn sẽ tìm thấy các thành phần tiêu cực rất nhỏ thường được lượng tử hóa.

Vì những lý do này, các cửa sổ cũng có độ dài lẻ vì tất cả các chuỗi tự tương quan hợp lệ là tốt. Bây giờ, những gì vẫn có thể được thực hiện (và được thực hiện) là cửa sổ trong bối cảnh của các phương thức biểu đồ. Đó là, cửa sổ dữ liệu, và sau đó lấy bình phương độ lớn của dữ liệu cửa sổ. Điều này không tương đương với phương pháp Blackman-Tukey. Bạn có thể tìm thấy, thông qua một số dẫn xuất thống kê, rằng chúng hoạt động tương tự trung bình , nhưng không nói chung. Ví dụ: việc sử dụng cửa sổ cho từng phân đoạn trong phương pháp của Welch hoặc Bartlett là khá phổ biến để giảm phương sai của các ước tính. Vì vậy, về bản chất, với các phương pháp này, động lực là một phần giống nhau, nhưng khác nhau. Công suất được chuẩn hóa trong các phương pháp này bằng cách phân chia năng lượng cửa sổ chẳng hạn, thay vì cân nhắc cẩn thận độ trễ của cửa sổ.

Vì vậy, hy vọng điều này bối cảnh hóa các cửa sổ và nguồn gốc của chúng, và tại sao chúng là đối xứng. Nếu bạn tò mò về lý do tại sao người ta có thể chọn một cửa sổ không đối xứng, hãy xem xét ý nghĩa của tính chất đối ngẫu của biến đổi Fourier và ước tính mật độ phổ công suất của bạn có ý nghĩa gì đối với ứng dụng của bạn. Chúc mừng.


1

Điểm ban đầu của cửa sổ là đảm bảo rằng tín hiệu (được định kỳ bởi DFT) không có quá độ sắc nét ở đầu so với cuối. Chi phí là tần số hướng về trung tâm của cửa sổ (đối xứng) sẽ có trọng số hơn và được biểu thị trong DFT tiếp theo.

Với tất cả những gì ở phía sau, tôi có thể tưởng tượng rằng người ta sẽ muốn sử dụng một cửa sổ không đối xứng để làm nổi bật các đặc điểm tạm thời cục bộ trong tín hiệu được phân tích thông qua DFT. Tuy nhiên, điều này có thể phải trả giá bằng chiều rộng thùy rộng hơn trong DFT, nếu các điểm cuối của tín hiệu của bạn không có cùng biên độ sau khi cửa sổ.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.