使用scipy fft计算信号的自相关与直接计算得到的结果不同

5
我正在尝试使用自相关的性质,即自相关是功率谱的反傅里叶变换,来计算信号的自相关。然而,当我使用scipy(或numpy)fft来执行此操作并将其与自相关函数的直接计算进行比较时,我得到了错误的答案。具体来说,fft版本在大延迟时间下水平偏移一个小负值,这显然是错误的。以下是我的MWE及输出结果。我是否错误地使用了fft?
import numpy as np
import matplotlib.pyplot as pl
from scipy.fftpack import fft, ifft


def autocorrelation(x) :
    xp = (x - np.average(x))/np.std(x)
    f = fft(xp)
    p = np.absolute(f)**2
    pi = ifft(p)
    return np.real(pi)[:len(xp)/2]/(len(xp))

def autocorrelation2(x):
    maxdelay = len(x)/5
    N = len(x)
    mean = np.average(x)
    var = np.var(x)
    xp = (x - mean)/np.sqrt(var)
    autocorrelation = np.zeros(maxdelay)
    for r in range(maxdelay):
        for k in range(N-r):
            autocorrelation[r] += xp[k]*xp[k+r]
        autocorrelation[r] /= float(N-r)
    return autocorrelation


def autocorrelation3(x):
    xp = (x - np.mean(x))/np.std(x)
    result = np.correlate(xp, xp, mode='full')
    return result[result.size/2:]/len(xp)

def main():
    t = np.linspace(0,20,1024)
    x = np.exp(-t**2)
    pl.plot(t[:200], autocorrelation(x)[:200],label='scipy fft')
    pl.plot(t[:200], autocorrelation2(x)[:200],label='direct autocorrelation')
    pl.plot(t[:200], autocorrelation3(x)[:200],label='numpy correlate')
    pl.legend()
    pl.show()


if __name__=='__main__':
    main()

enter image description here

1个回答

11

离散傅里叶变换假设信号是周期性的。因此,在您基于fft的代码中,您正在计算一个环绕自相关。为避免这种情况,您需要进行某种形式的0填充:

def autocorrelation(x):
    xp = ifftshift((x - np.average(x))/np.std(x))
    n, = xp.shape
    xp = np.r_[xp[:n//2], np.zeros_like(xp), xp[n//2:]]
    f = fft(xp)
    p = np.absolute(f)**2
    pi = ifft(p)
    return np.real(pi)[:n//2]/(np.arange(n//2)[::-1]+n//2)

2
运行得很好。我应该注意到那个问题。谢谢! - KBriggs
你能帮忙确认一下(np.arange(n//2)[::-1]+n//2)这部分是否正确吗?因为我使用它得到了大于1.0的相关性。我认为np.arange(n,0,-1)[:n//2]更正确。 - Jason
@Jason 1) 自相关未归一化为[-1,1],因此值>1是完全可以的。2)话虽如此,你可能仍然正确,我的修正项可能是错误的。我太累了,无法自行检查,但为什么不运行一个简单的测试用例(如平坦信号)呢?那么你就会知道了。 - Paul Panzer
@Jason 你也可以直接通过比较我发布的另外两个函数来进行检查,它们会更慢一些但更易于解析。只要这三个函数都达成一致,我认为你是安全的。 - KBriggs
二维数组尺寸为 N x N,其时间复杂度是多少? - lordparthurnaax
@thephoenix01 如果我没记错的话,2D fft 的时间复杂度是O(N^2 log N)。 - Paul Panzer

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接