我可以使用numpy的内置功能来计算自相关:
<Grid RowSpacing="3" ColumnSpacing="3">
然而,由此产生的相关性自然是嘈杂的。我可以对数据进行分区,并计算每个结果窗口的相关性,然后将它们全部平均以计算更清晰的自相关,类似于numpy.correlate(x,x,mode='same')
。在signal.welch
或numpy
中是否有一个方便的功能可以做到这一点,如果我自己计算分区并循环遍历数据,可能比我得到的更快?
这是由@kazemakase回答的动机。我试图用一些用于生成下图的代码来表明我的意思。
可以看出@kazemakase是正确的,因为AC功能自然地平均了噪音。然而,AC的平均值具有更快的优势!如果通过FFT使用循环卷积计算相关性,scipy
似乎可以缩放为np.correlate
而不是O(n^2)
。
O(nlogn)
答案 0 :(得分:2)
TL-DR:要降低自相关函数中的噪声,请增加信号的长度 x 。
对光谱估计中的数据进行分区和平均是一个有趣的想法。我希望它能起作用......
自相关定义为
我们说我们将数据分成两个窗口。他们的自相关变得
请注意它们在属性限制方面的区别。基本上,我们将自相关的总和分为两部分。当我们将它们重新组合在一起时,我们又恢复了原来的自相关性!所以我们没有获得任何收益。
结论是,在numpy / scipy中没有实现这样的东西,因为没有必要这样做。
说明:
我希望很容易看到这扩展到任意数量的分区。
为了保持简单,我将标准化排除在外。如果您将 Rxx 除以 n ,将部分 Rxx 除以 n / 2 ,则会得到Rxx / n == (Rxx1 * 2/n + Rxx2 * 2/n) / 2
。即归一化部分自相关的平均值等于完全归一化的自相关。
为了让它更简单我假设信号 x 可以被索引超出0和 n -1的限制。实际上,如果信号存储在阵列中,这通常是不可能的。在这种情况下,完全和部分化自相关之间存在一个小差异,随着滞后 l 而增加。不幸的是,这只是精度的损失而且不会降低噪音。
代码异端!我不相信你的邪恶数学!
当然,我们可以尝试一下,看:
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()
虽然我们使用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()