Cálculo eficiente de la autocorrelación utilizando FFT

12

Estoy tratando de calcular una autocorrelación en una plataforma donde la única primitiva acelerada que tengo disponible es la (I) FFT. Aunque tengo un problema.

Lo prototipé en MATLAB . Sin embargo, estoy un poco confundido. Supuse que funciona simplemente de la siguiente manera (esto es de memoria, así que disculpas si me equivoco un poco).

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

Sin embargo, obtengo un resultado diferente al que obtengo al usar la xcorrfunción. Ahora espero no obtener el lado izquierdo de la correlación automática (ya que es un reflejo del lado derecho y, por lo tanto, no es necesario de todos modos). Sin embargo, el problema es que mi lado derecho parece reflejarse alrededor del punto medio. Lo que efectivamente significa que obtengo aproximadamente la mitad de la cantidad de datos que estoy esperando.

Así que estoy seguro de que debo estar haciendo algo muy simple, pero no puedo entender qué.

Goz
fuente
1
Ten cuidado. A menos que los datos sean deterministas, típicamente solo podemos estimar la secuencia de autocorrelación. Hay dos versiones comunes de las estimaciones de autocorrelación: sesgada e imparcial. Resultados imparciales en estimaciones de autocorrelación que son estadísticamente imparciales. Sin embargo, la varianza puede ser muy grande para los retrasos de alto orden, lo que genera problemas si la estimación de autocorrelación se utiliza en inversiones de matriz, por ejemplo. Las muestras sesgadas exhiben sesgo estadístico pero con menos varianza (y error cuadrático medio). Ambos son estadísticamente consistentes. Tiene una estimación sesgada no normalizada arriba.
Bryan

Respuestas:

16

pichenettes tiene razón, por supuesto. La FFT implementa una convolución circular mientras que xcorr () se basa en una convolución lineal. Además, también debe cuadrar el valor absoluto en el dominio de frecuencia. Aquí hay un fragmento de código que maneja todo el relleno, desplazamiento y truncamiento de cero.

%% 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
fuente
Guau, eso funcionó una belleza. Una versión C directa (Single thread, no SIMD) de mi rastreador de tono se ejecutó en 0.8 segundos utilizando el método anterior en lugar de una versión basada en primitivo de rendimiento de Intel que se ejecutó en 0.4 segundos. ¡Eso es increíble! Gracias
Goz
7

2N1NN1

pichenettes
fuente
3

N2N1[(N1),N1]0

2N12N12N12N1

N2N1N

N1N2N102N12N1

En resumen: debería haber hecho esto (para adaptarse a su lenguaje de programación):

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

O en MATLAB:

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

La razón principal para que la salida deseada de la función xcorr no sea similar a la de la aplicación de la función FFT e IFFT es porque al aplicar estas funciones a las señales, el resultado final es circularmente enrevesado .

La principal diferencia entre la convolución lineal y la convolución circular se puede encontrar en la convolución lineal y circular .

El problema puede resolverse inicialmente rellenando con cero la señal y truncando la salida final de IFFT .

Venu
fuente