Cálculo automático da autocorrelação usando FFTs

12

Estou tentando calcular uma autocorrelação em uma plataforma em que a única primitiva acelerada que tenho disponível é a (I) FFT. Estou tendo um problema.

Eu o prototipei no MATLAB . Estou, no entanto, um pouco confuso. Eu assumi que ele funciona da seguinte forma (isso é da memória, desculpe-me se eu entendi um pouco errado).

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

No entanto, recebo um resultado diferente do uso da xcorrfunção Agora, espero não obter o lado esquerdo da correlação automática (pois é um reflexo do lado direito e, portanto, não é necessário). No entanto, o problema é que meu lado direito parece refletir-se em torno do ponto médio. O que significa efetivamente que recebo cerca da metade da quantidade de dados que estou esperando.

Então, tenho certeza de que devo estar fazendo algo muito simples errado, mas não consigo descobrir o que.

Goz
fonte
1
Seja cuidadoso. A menos que os dados sejam determinísticos, normalmente podemos estimar apenas a sequência de autocorrelação. Existem duas versões comuns de estimativas de autocorrelação: tendenciosa e imparcial. Resultados não tendenciosos em estimativas de autocorrelação que são estatisticamente imparciais. No entanto, a variação pode ser muito grande para atrasos de ordem alta, causando problemas se a estimativa de autocorrelação for usada em inversões de matriz, por exemplo. As amostras enviesadas exibem viés estatístico, mas com menos variância (e erro quadrático médio). Ambos são estatisticamente consistentes. Você tem uma estimativa tendenciosa não normalizada acima.
22912 Bryan

Respostas:

16

pichenettes está certo, é claro. A FFT implementa uma convolução circular enquanto o xcorr () é baseado em uma convolução linear. Além disso, você também precisa quadrado o valor absoluto no domínio da frequência. Aqui está um trecho de código que lida com todo o preenchimento zero, deslocamento e truncamento.

%% 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
fonte
Uau, que trabalhou uma beleza. Uma versão C direta (single threaded, no SIMD) do meu pitch tracker foi executada em 0,8 segundos, usando o método acima, em oposição a uma versão baseada em primitivo intel performance que foi executada em 0,4 segundos. Isso é incrível! Obrigado
Goz 04/04
7

2N-1NN-1

pichenettes
fonte
3

N2N-1[-(N-1),N-1]0 0

2N-12N-12N-12N-1

N2N-1N

N-1N2N-10 02N-12N-1

Em resumo: você deveria ter feito isso (para ser adaptado à sua linguagem de programação):

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

Ou no MATLAB:

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

A principal razão para a saída desejada da função xcorr não ser semelhante à aplicação das funções FFT e IFFT é porque, ao aplicar essa função aos sinais, o resultado final é circularmente complicado .

A principal diferença entre Convolução Linear e Convolução Circular pode ser encontrada em Convolução Linear e Circular .

O problema pode ser resolvido inicialmente preenchendo o sinal com zero e truncando a saída final do IFFT .

Venu
fonte