使用 FFT 有效地计算自相关

信息处理 matlab 声音的 fft 自相关
2021-12-24 06:17:09

我试图在一个平台上计算自相关,我唯一可用的加速原语是(I)FFT。我有一个问题。

我在MATLAB中对其进行了原型设计。然而,我有点困惑。我假设它的工作原理如下(这是记忆中的,如果我弄错了,请道歉)。

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

但是,我得到的结果与使用该xcorr函数得到的结果不同。现在我完全期望不要得到自动相关的左侧(因为它是右侧的反映,因此无论如何都不需要)。然而,问题是我的右手边似乎是,本身,反映在中间点附近。这实际上意味着我得到的数据量大约是预期的一半。

所以我确定我一定是在做一些非常简单的错误,但我就是不知道是什么。

4个回答

当然,pichenettes 是对的。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)));

Matlab 的 xcorr 计算一个2N1FFT,其中N是输入数据的长度(即,输入用N1零)。这避免了循环问题。

为了详细说明前面的答案,计算长度信号的自相关N导致大小的(采样)自相关2N1. 嗯,实际上,它应该是无限的,但是外部的自相关[(N1),N1]等于0反正。

现在,您希望使用离散傅里叶变换 (DFT) 来计算它,并且该公式确实是信号 DFT 平方幅度的逆 DFT。但是想一想:如果我们反过来计算自相关的 DFT,你最终会得到一个大小谱2N1,如果您不想在途中丢失样品!因此,该频谱必须具有大小2N1,这就是为什么您需要将时域信号补零的原因2N1,计算 DFT(在2N1点),然后继续。

另一种看待这一点的方法是分析如果你计算 DFT 会发生什么N要点:这相当于对您的(连续频率)离散时间傅里叶变换(DTFT)进行下采样。检索自相关,它应该是大小2N1, 具有采样不足的大小谱N因此会导致时间混叠(循环性 pichenettes 正在谈论),这解释了为什么如果您的输出在“右手边”有这种对称图案。

实际上,Hilmar 提供的代码也可以,因为只要你零填充到超过N1(在他的例子中,他计算了一个 FT 的大小N),你“过度采样”你的 FT,你仍然得到你的2N1“有用”的样本(其他的应该是0s)。因此,为了提高效率,只需零填充即可2N1,这就是您所需要的(好吧,也许您最好将零填充到 2 的下一个幂2N1,如果您使用 FFT)。

简而言之:您应该这样做(以适应您的编程语言):

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

或者在 MATLAB 中:

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

xcorr函数的期望输出与FFTIFFT函数的应用不同的主要原因是因为在将这些函数应用于信号时,最终结果是循环卷积的。

线性卷积和圆形卷积之间的主要区别可以在线性和圆形卷积中找到。

该问题可以通过最初对信号进行零填充并截断IFFT的最终输出来解决