我正在尝试使用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的相关内容和MatLib的xcorr,并且bot也显示了同样的事情(虽然我认为它们基本上是相同的功能)。
为什么互相关不按照我的预期行事,如何让它以有用的方式行动?
答案 0 :(得分:3)
您遇到的问题可能是因为您的光谱不是以零为中心的;在您正在绘制的单位中,他们的RMS值看起来大约为100。这是一个问题的原因是因为卷积/互相关函数必须用零填充你的光谱,以便在"相同的"中计算完整的响应。模式。因此,即使您的信号与50个样本的偏移量最相似,但当两个信号未完全对齐时,您只对其重叠的乘积进行积分,并丢弃所有偏移值,因为它们会相乘零。这是有问题的,因为您的光谱不是零均值,并且它们的相关性在它们的重叠中几乎呈线性增加。
请注意,您的互相关结果看起来像一个三角形脉冲,这可能是您对两个方形脉冲( cf Convolution of a Rectangular "Pulse" With Itself的互相关所期望的结果。因为你的光谱一旦填充,看起来像一个阶跃函数,从零到一个大约100的微噪声值的脉冲 - 有效地是矩形脉冲与高斯噪声的卷积。你可以尝试用mode='full'
卷积来看你要关联的两个光谱的整个响应,或者注意到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')
,我们必须" pad" g 两侧,其长度的一半为零(默认情况下;您可以使用其他值填充。)如果我们不填充 g (在np.correlate(g,f,mode='valid')
中),我们只返回一个值(与零偏移的相关性),因为 f 和 g < / em>长度相同,没有空间将其中一个信号相对于另一个信号移位。
在填充之后计算 g 和 f 的相关性时,您会发现当非零部分信号时它达到峰值完全对齐,也就是说,当原始 f 和 g 之间存在无偏移时。这是因为信号的RMS值远高于零 - f 和 g 的重叠大小更强烈地取决于重叠的元素数量在这个高RMS水平而不是相对较小的波动,每个功能都围绕着它。我们可以通过从每个系列中减去RMS水平来消除对相关性的这种巨大贡献。在下图中,右边的灰线表示零中心前两个系列的互相关,而青色线表示之后的互相关。与第一次尝试一样,灰线是三角形,两个非零信号重叠。正如我们所希望的那样,蓝绿色线更好地反映了两个信号波动之间的相关性。
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()