FFTを使用した自己相関の効率的な計算


12

私が利用できる唯一の加速プリミティブが(I)FFTであるプラットフォームで自己相関を計算しようとしています。でも問題があります。

MATLABでプロトタイプを作成しました。しかし、私は少し混乱しています。私はそれが次のように単純に機能すると仮定しました(これはメモリからのものですので、少し間違っている場合はおologiesびします)。

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

ただし、xcorr関数を使用した場合とは異なる結果が得られます。今、私は完全に自己相関の左側を取得しないことを期待しています(それは右側の反映であり、したがってとにかく必要ないため)。ただし、問題は、右側が中間点の周りに反映されているように見えることです。これは事実上、私が期待しているデータの約半分の量を取得することを意味しています。

だから私は非常に単純な間違ったことをしなければならないと確信していますが、私は何を理解できないのです。


1
注意してください。データが確定的でない限り、通常、自己相関シーケンスのみを推定できます。自己相関推定には、バイアスとバイアスのない2つの一般的なバージョンがあります。統計的に偏りのない自己相関推定値に偏りのない結果。ただし、高次のラグでは分散が非常に大きくなる可能性があり、たとえば行列の反転で自己相関推定を使用すると問題が発生します。バイアスされたサンプルは、統計的バイアスを示しますが、分散(および平均二乗誤差)は小さくなります。両方とも統計的に一貫しています。上記の非正規化バイアス推定値があります。
ブライアン

回答:


16

もちろん、ピケネットは正しいです。FFTは循環たたみ込みを実装し、xcorr()は線形たたみ込みに基づいています。さらに、周波数領域の絶対値も二乗する必要があります。以下は、ゼロのパディング、シフト、切り捨てをすべて処理するコードスニペットです。

%% 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)));

うわー、それは素晴らしく働いた。私のピッチトラッカーのストレートCバージョン(シングルスレッド、SIMDなし)は、0.4秒で実行されたIntelパフォーマンスプリミティブベースのバージョンとは対照的に、上記の方法を使用して0.8秒で実行されました。すごい!ありがとう
ゴズ


3

N2N1[N1N1]0

2N12N12N12N1

N2N1N

N1N2N102N12N1

要するに、あなたはこれを行うべきでした(あなたのプログラミング言語に適応させるために):

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

またはMATLABで:

autocorr = ifft(abs(fft(inputData, 2*N-1)).^2)

0

xcorr関数の目的の出力がFFTおよびIFFT関数の適用の出力と似ていない主な理由は、これらの関数を信号に適用している間、最終結果が循環的に畳み込まれるためです。

線形畳み込みと巡回畳み込みの主な違いはで見つけることができるリニアおよび巡回畳み込み

この問題は、最初に信号をゼロパディングしIFFTの最終出力を切り捨てることで解決できます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.