Menghitung autokorelasi secara efisien menggunakan FFT

12

Saya mencoba menghitung autokorelasi pada platform di mana satu-satunya primitif akselerasi yang saya miliki adalah (I) FFT. Saya mengalami masalah.

Saya membuat prototipe di MATLAB . Namun, saya agak bingung. Saya berasumsi bahwa itu bekerja hanya sebagai berikut (ini dari memori jadi minta maaf jika saya salah sedikit).

 autocorr = ifft( complex( abs( fft( inputData ) ), 0 ) )

Namun saya mendapatkan hasil yang berbeda dari yang saya dapatkan dari menggunakan xcorrfungsi. Sekarang saya sepenuhnya berharap untuk tidak mendapatkan sisi kiri dari korelasi otomatis (karena ini merupakan cerminan dari sisi kanan dan karenanya tidak diperlukan pula). Namun, masalahnya adalah sisi kanan saya tampaknya, dengan sendirinya, tercermin di sekitar titik tengah. Yang secara efektif berarti saya mendapatkan sekitar setengah jumlah data yang saya harapkan.

Jadi saya yakin saya pasti melakukan kesalahan yang sangat sederhana, tetapi saya tidak tahu apa yang terjadi.

Goz
sumber
1
Hati-hati. Kecuali jika data bersifat deterministik, kita biasanya hanya dapat memperkirakan urutan autokorelasi. Ada dua versi umum estimasi autokorelasi: bias dan tidak memihak. Hasil yang tidak sesuai dalam estimasi autokorelasi yang secara statistik tidak bias. Namun, varians bisa sangat besar untuk keterlambatan orde tinggi, yang mengarah ke masalah jika estimasi autokorelasi digunakan dalam inversi matriks misalnya. Sampel yang bias menunjukkan bias statistik tetapi dengan varians yang lebih sedikit (dan mean square error). Keduanya konsisten secara statistik. Anda memiliki estimasi bias yang tidak dinormalkan di atas.
Bryan

Jawaban:

16

pichenettes benar, tentu saja. FFT mengimplementasikan konvolusi melingkar sementara xcorr () didasarkan pada konvolusi linier. Selain itu, Anda perlu menguadratkan nilai absolut dalam domain frekuensi juga. Berikut ini adalah cuplikan kode yang menangani semua bantalan nol, geser & terpotong.

%% Cross correlation through a FFT
n = 1024;
x = randn(n,1);
% cross correlation reference
xref = xcorr(x,x);

%FFT method based on zero padding
fx = fft([x; zeros(n,1)]); % zero pad and FFT
x2 = ifft(fx.*conj(fx)); % abs()^2 and IFFT
% circulate to get the peak in the middle and drop one
% excess zero to get to 2*n-1 samples
x2 = [x2(n+2:end); x2(1:n)];
% calculate the error
d = x2-xref; % difference, this is actually zero
fprintf('Max error = %6.2f\n',max(abs(d)));
Hilmar
sumber
Wow itu berhasil. Versi C lurus (Single threaded, no SIMD) dari pelacak pitch saya berjalan dalam 0,8 detik menggunakan metode di atas yang bertentangan dengan versi berbasis kinerja primitif intel yang berjalan dalam 0,4 detik. Itu luar biasa! Terima kasih
Goz
7

Matlab's xcorr menghitung FFT, di mana adalah panjang data input (yaitu, input diisi dengan nol). Ini menghindari masalah sirkularitas.N N - 12N1NN1

pichenettes
sumber
3

Untuk menguraikan sedikit lebih banyak pada jawaban sebelumnya, menghitung korelasi-otomatis dari sinyal panjang menghasilkan korelasi-otomatis (sampel) ukuran . Sebenarnya, seharusnya tidak terbatas, tetapi korelasi otomatis di luar sama dengan .N[ - ( N - 1 ) , N - 1 ] 02N1[(N1),N1]0

Sekarang, Anda ingin menggunakan transformasi Fourier diskrit (DFT) untuk menghitungnya, dan rumusnya memang DFT terbalik dari besarnya kuadrat dari DFT sinyal Anda. Tetapi pikirkanlah: jika kita mengambil sebaliknya dan menghitung DFT dari korelasi-otomatis, Anda berakhir dengan spektrum ukuran , jika Anda tidak ingin kehilangan sampel di jalan! Spektrum itu harus berukuran , dan itulah alasan mengapa Anda perlu memberi sinyal nol pada domain waktu Anda hingga , menghitung DFT (pada poin ), dan melanjutkannya.2 N - 1 2 N - 1 2 N - 12N12N12N12N1

Cara lain untuk melihat ini adalah dengan menganalisis apa yang terjadi jika Anda menghitung DFT pada titik : ini setara dengan downsampling (frekuensi kontinu) waktu diskrit Anda Fourier transform (DTFT). Mengambil korelasi-otomatis, yang seharusnya dari ukuran , dengan spektrum yang kurang-sampel dari ukuran karena itu mengarah ke waktu aliasing (pichenettes sirkularitas bicarakan), yang menjelaskan mengapa Anda memiliki pola simetris ini di "kanan sisi "jika output Anda.2 N - 1 NN2N1N

Sebenarnya, kode yang disediakan oleh Hilmar juga berfungsi, karena selama Anda nol-pad hingga lebih dari ukuran (dalam kasusnya, ia menghitung FT ukuran ), Anda "mengambil-sampel" FT Anda , dan Anda masih mendapatkan sampel "bermanfaat" (yang lainnya harus s). Jadi, untuk efisiensi, hanya nol-pad ke , itu yang Anda butuhkan (well, mungkin Anda lebih baik zero-pad hingga kekuatan 2 dari , jika Anda menggunakan FFT).N 2 N - 1 0 2 N - 1 2 N - 1N1N2N102N12N1

Singkatnya: Anda harus melakukan ini (disesuaikan dengan bahasa pemrograman Anda):

autocorr = ifft( complex( abs(fft(inputData, n=2*N-1))**2, 0 ) )

Atau di MATLAB:

autocorr = ifft(abs(fft(inputData, 2*N-1)).^2)
Jean-louis Durrieu
sumber
0

Alasan utama untuk output yang diinginkan dari fungsi xcorr menjadi tidak sama dengan penerapan fungsi FFT dan IFFT adalah karena ketika menerapkan fungsi ini untuk sinyal hasil akhir berbelit-belit .

Perbedaan utama antara Konvolusi Linier dan Konvolusi Sirkular dapat ditemukan pada Konvolusi Linier dan Sirkular .

Masalahnya dapat diselesaikan dengan Awalnya nol-padding sinyal dan memotong output akhir IFFT .

Venu
sumber