Python Numpy Correlate未提供偏移量

Python Numpy Correlate未提供偏移量,python,numpy,correlation,cross-correlation,Python,Numpy,Correlation,Cross Correlation,我正在尝试使用Python查看天文光谱,我正在使用numpy.correlate试图找到径向速度偏移。我将每个光谱与一个模板光谱进行比较。我遇到的问题是,无论我使用哪种光谱,numpy.correlate都指出,相关函数的最大值出现在零像素的移位时,即光谱已经对齐,这显然是不正确的。以下是一些相关代码: corr = np.correlate(temp_data, imag_data, mode='same') ax1.plot(delta_data, corr, c='g') ax1.plot

我正在尝试使用Python查看天文光谱,我正在使用numpy.correlate试图找到径向速度偏移。我将每个光谱与一个模板光谱进行比较。我遇到的问题是,无论我使用哪种光谱,numpy.correlate都指出,相关函数的最大值出现在零像素的移位时,即光谱已经对齐,这显然是不正确的。以下是一些相关代码:

corr = np.correlate(temp_data, imag_data, mode='same')
ax1.plot(delta_data, corr, c='g')
ax1.plot(delta_data, 100*temp_data, c='b')
ax1.plot(delta_data, 100*imag_data, c='r')
此代码的输出如下所示:

请注意,尽管模板(蓝色)和观察到的(红色)光谱清楚地显示了偏移,但互相关函数在零像素偏移处达到峰值。我希望看到的东西有点像(尽管不完全像;这只是我能产生的最接近的表现):

在这里,我在模板数据中引入了一个50像素的人工偏移量,现在它们大致对齐了。我想要的是,在这种情况下,峰值出现在50像素的偏移处,而不是在零处(我不在乎底部的光谱是否排列整齐,这只是为了视觉表现)。然而,尽管在网上工作和研究了几个小时,我还是找不到一个能描述这个问题的人,更不用说解决方案了。我尝试使用ScyPy的correlate和MatLib的xcorr,bot展示了同样的东西(尽管我相信它们本质上是相同的函数)


为什么互相关没有按我预期的方式工作,我如何使它以一种有用的方式工作?

你遇到的问题可能是因为你的光谱不是以零为中心的;它们的均方根值看起来大约为100,以您正在绘制的任何单位为单位。这是一个问题的原因,因为卷积/互相关函数必须用零填充光谱,以便在“相同”模式下计算完整响应。因此,即使你的信号最相似,偏移量大约为50个样本,但当两个信号没有完全对齐时,你只对重叠部分的乘积进行积分,并丢弃所有偏移值,因为它们乘以零。这是有问题的,因为你的光谱不是零均值,它们的相关性在重叠中几乎线性增加

请注意,互相关结果看起来像一个三角形脉冲,这是两个方形脉冲的互相关结果(c.f..这是因为你的光谱,一旦被填充,看起来就像一个从零到100左右轻微噪声值的脉冲的阶跃函数——实际上是矩形脉冲与高斯噪声的卷积。你可以尝试用
mode='full'
卷积来查看你正在相关的两个光谱的整个响应,或者,注意h
mode='valid'
您应该只得到一个值作为返回,因为您的两个光谱的长度完全相同,所以只有一个偏移量(零!)可以将它们完全对齐

为了避免这个问题,您可以尝试减去光谱的RMS值,使其以零为中心,或者在两侧的RMS值中填充两个光谱的长度

编辑: 为了回答你在评论中提出的问题,我想我会附上一张图表,以使我试图描述的观点更清楚一些

假设我们有两个向量的值,和你的光谱不完全一样,每个向量都有很大的偏移量

# Generate two noisy, but correlated series
t = np.linspace(0,250,250)
f = 10*np.exp(-((t-90)**2)/8) + np.random.randn(250) + 40
g = 10*np.exp(-((t-180)**2)/8) + np.random.randn(250) + 40

f在t=90附近有一个尖峰,而g在t=180附近有一个尖峰。因此,我们预计g和f的相关性在90个时间步(或频率槽,或任何你正在关联的函数的参数)的延迟附近有一个尖峰

但是为了得到与我们的输入形状相同的输出,如在
np.correlate(g,f,mode='same')
中,我们必须将g的一半长度用零“填充”在任意一侧(默认情况下,您可以用其他值填充)。如果我们不填充g(如
np.correlate(g,f,mode='valid')
),我们将只得到一个值作为回报(与零偏移的相关性),因为f和g是相同的长度,并且没有空间移动其中一个信号相对于另一个信号

当你在填充后计算g和f的相关性时,你会发现当信号的非零部分完全对齐时,它会达到峰值,也就是说,当原始f和g之间没有偏移时。这是因为信号的RMS值比零高得多——f和g的重叠大小更强烈地取决于n在这个高RMS水平上重叠的元素数量比每个函数周围相对较小的波动数量多。我们可以通过从每个序列中减去RMS水平来消除对相关性的巨大贡献。在下图中,右侧的灰线显示了零中心之前两个序列的互相关,teal线显示了之后的互相关。像你第一次尝试的那样,灰线是三角形,两个非零信号重叠。teal线更好地反映了两个信号波动之间的相关性,正如我们所期望的


我们需要看到一些导致意外输出的数据样本。我怀疑这与零填充有关。您是否尝试过截断一个序列?当信号长度相同时,未移位信号的相关性将最高,因为当信号移位时,它们的尾部不重叠,因此ca不能相乘。你的信号是否以0为中心,标准偏差为1?@Ballpoint Ben他/她也绘制了信号,但它们不是以0为中心。我认为基本上边界效应主导了相关性,但我不是SP方面的专家,我不确定如何修复。你可能应该写一个答案。非常感谢!减法g均方根值a
xcorr = np.correlate(g,f,'same')
xcorr_rms = np.correlate(g-40,f-40,'same')
fig, axes = plt.subplots(5,2,figsize=(18,18),gridspec_kw={'width_ratios':[5,2]})
for n, axis in enumerate(axes):
    offset = (0,75,125,215,250)[n]
    fp = np.pad(f,[offset,250-offset],mode='constant',constant_values=0.)
    gp = np.pad(g,[125,125],mode='constant',constant_values=0.)

    axis[0].plot(fp,color='purple',lw=1.65)
    axis[0].plot(gp,color='orange',lw=lw)
    axis[0].axvspan(max(125,offset),min(375,offset+250),color='blue',alpha=0.06)
    axis[0].axvspan(0,max(125,offset),color='brown',alpha=0.03)
    axis[0].axvspan(min(375,offset+250),500,color='brown',alpha=0.03)
    if n==0:
        axis[0].legend(['f','g'])
    axis[0].set_title('offset={}'.format(offset-125))


    axis[1].plot(xcorr/(40*40),color='gray')
    axis[1].plot(xcorr_rms,color='teal')
    axis[1].axvline(offset,-100,350,color='maroon',lw=5,alpha=0.5)
    if n == 0:
        axis[1].legend(["$g \star f$","$g' \star f'$","offset"],loc='upper left')

plt.show()