python中自相关函数的快速降噪方法?

python中自相关函数的快速降噪方法?,python,numpy,scipy,correlation,Python,Numpy,Scipy,Correlation,我可以使用numpy的内置功能计算自相关: numpy.correlate(x,x,mode='same') 然而,由此产生的相关性自然是有噪声的。我可以对数据进行分区,计算每个结果窗口上的相关性,然后对它们进行平均,以计算更清晰的自相关性,类似于signal.welch所做的。在numpy或scipy中是否有一个方便的函数可以做到这一点,可能比我自己计算分区并循环数据更快 更新 这是由@kazemakase答案引起的。我试图用一些代码来说明我的意思,这些代码用于生成下图 可以看出,@kazem

我可以使用numpy的内置功能计算自相关:
numpy.correlate(x,x,mode='same')

然而,由此产生的相关性自然是有噪声的。我可以对数据进行分区,计算每个结果窗口上的相关性,然后对它们进行平均,以计算更清晰的自相关性,类似于
signal.welch
所做的。在
numpy
scipy
中是否有一个方便的函数可以做到这一点,可能比我自己计算分区并循环数据更快

更新 这是由@kazemakase答案引起的。我试图用一些代码来说明我的意思,这些代码用于生成下图

可以看出,@kazemakase是正确的,AC函数自然地将噪声平均化。然而,AC的平均值具有更快的优势<代码>np。如果通过FFT使用循环卷积计算相关性,则相关性似乎按缓慢的
O(n^2)
进行缩放,而不是我预期的
O(nlogn)


TL-DR:要减少自相关函数中的噪声,请增加信号x的长度


在谱估计中,对数据进行分区和平均是一个有趣的想法。我希望它能起作用

自相关定义为

假设我们将数据划分为两个窗口。它们的自相关性变得

请注意,它们只是在计算范围上有所不同。基本上,我们将自相关的总和分为两部分。当我们把这些加在一起时,我们回到了原始的自相关!所以我们没有得到任何东西

结论是,在numpy/scipy中没有实现这样的东西,因为这样做没有意义

备注:

  • 我希望很容易看到它扩展到了任意数量的分区

  • 为了保持简单,我省略了标准化。如果将Rxx除以n,将部分Rxx除以n/2,则得到
    Rxx/n==(Rxx1*2/n+Rxx2*2/n)/2
    。即,归一化部分自相关的平均值等于完全归一化自相关

  • 为了使它更简单,我假设信号x的索引可以超出0和n-1的限制。实际上,如果信号存储在阵列中,这通常是不可能的。在这种情况下,完全自相关和部分自相关之间有一个很小的差异,随着滞后l的增加而增加。不幸的是,这仅仅是精度的损失,并不能减少噪音

  • 代码异教徒!我不相信你邪恶的数学

    当然,我们可以尝试一下,看看:

    虽然我们使用了8段来平均ACF,但噪声级在视觉上保持不变

    好吧,这就是为什么它不起作用,但解决方案是什么

    好消息是:自相关已经是一种降噪技术了嗯,至少在某种程度上:ACF的一个应用是发现被噪声隐藏的周期性信号

    由于噪声(理想情况下)的平均值为零,因此它的影响会随着我们总结的元素越多而减小。换句话说,您可以通过使用更长的信号来减少自相关中的噪声。(我想这可能不适用于所有类型的噪声,但适用于通常的高斯白噪声及其相关噪声。)

    请注意,随着数据采样的增加,噪音会越来越低:

    import matplotlib.pyplot as plt
    import numpy as np
    
    for n in [2**6, 2**8, 2**12]:
        x = np.random.randn(n)
    
        rx = np.correlate(x, x, mode='same') / n  # ACF
        l1 = np.arange(-n//2, n//2)  # Lags
    
        plt.plot(l1, rx, label='n={}'.format(n))
    
    plt.legend()    
    plt.xlim(-20, 20)
    plt.show()
    

    @CrazyIvan抱歉,我编辑了我的答案-我确实使用了
    相同的
    选项。你可能会在这个帖子中找到一些帮助:谢谢你的回复,我编辑了我的答案,我仍然在测试一些东西,但你的分析当然是正确的。我无法反驳数学,现在回想起来似乎很明显,所以谢谢你!我确实发现,
    np.correlate
    在大型数据集上的速度非常慢,分区允许更快的计算。不确定你是否找到了相同的答案?@Jack看起来像,所以你的O(n^2)断言似乎是正确的。如果您有大型阵列,请查看哪个阵列具有基于FFT的实现。
    import matplotlib.pyplot as plt
    import numpy as np
    
    n = 2**16
    n_segments = 8
    
    x = np.random.randn(n)  # data
    
    rx = np.correlate(x, x, mode='same') / n  # ACF
    l1 = np.arange(-n//2, n//2)  # Lags
    
    segments = x.reshape(n_segments, -1)
    m = segments.shape[1]
    
    rs = []
    for y in segments:
        ry = np.correlate(y, y, mode='same') / m  # partial ACF
        rs.append(ry)
    
    l2 = np.arange(-m//2, m//2)  # lags of partial ACFs
    
    plt.plot(l1, rx, label='full ACF')
    plt.plot(l2, np.mean(rs, axis=0), label='partial ACF')
    plt.xlim(-m, m)
    plt.legend()
    plt.show()
    
    import matplotlib.pyplot as plt
    import numpy as np
    
    for n in [2**6, 2**8, 2**12]:
        x = np.random.randn(n)
    
        rx = np.correlate(x, x, mode='same') / n  # ACF
        l1 = np.arange(-n//2, n//2)  # Lags
    
        plt.plot(l1, rx, label='n={}'.format(n))
    
    plt.legend()    
    plt.xlim(-20, 20)
    plt.show()