Python 查找两个相似波形之间的时间偏移

Python 查找两个相似波形之间的时间偏移,python,numpy,signal-processing,correlation,Python,Numpy,Signal Processing,Correlation,我必须比较两种时间和电压波形。由于这些波形源的特殊性,其中一个可以是另一个的时移版本 我怎样才能知道是否有时间轮班?如果是的话,多少钱 我在Python中这样做,希望使用numpy/scipy库。如果一个库被另一个库时移,您将看到相关性的峰值。由于计算相关性很昂贵,因此最好使用FFT。因此,类似这样的方法应该会奏效: af = scipy.fft(a) bf = scipy.fft(b) c = scipy.ifft(af * scipy.conj(bf)) time_shift = argm

我必须比较两种时间和电压波形。由于这些波形源的特殊性,其中一个可以是另一个的时移版本

我怎样才能知道是否有时间轮班?如果是的话,多少钱


我在Python中这样做,希望使用numpy/scipy库。

如果一个库被另一个库时移,您将看到相关性的峰值。由于计算相关性很昂贵,因此最好使用FFT。因此,类似这样的方法应该会奏效:

af = scipy.fft(a)
bf = scipy.fft(b)
c = scipy.ifft(af * scipy.conj(bf))

time_shift = argmax(abs(c))

这取决于你的信号类型(周期性?…),取决于两个信号是否具有相同的振幅,以及你想要的精度

highBandWidth提到的相关函数可能确实适用于您。这很简单,你应该试一试


另一个更精确的选项是我用于高精度谱线拟合的选项:使用样条曲线对“主”信号建模,并用它拟合时移信号(如果需要,还可以缩放信号)。这会产生非常精确的时间偏移。这种方法的一个优点是不必研究相关函数。例如,您可以使用
interpolate.UnivariateSpline()
(来自SciPy)轻松创建样条曲线。SciPy返回一个函数,该函数可以很容易地与
优化配合。leastsq
()。

SciPy提供了一个相关函数,该函数可以很好地用于小输入,并且如果您想要非循环相关,这意味着信号不会环绕。请注意,在
mode='full'
中,signal.correlation返回的数组大小是信号大小之和减去一(即
len(a)+len(b)-1
),因此argmax的值与您预期的值相差(信号大小-1=20)

from scipy import signal, fftpack
import numpy
a = numpy.array([0, 1, 2, 3, 4, 3, 2, 1, 0, 1, 2, 3, 4, 3, 2, 1, 0, 0, 0, 0, 0])
b = numpy.array([0, 0, 0, 0, 0, 1, 2, 3, 4, 3, 2, 1, 0, 1, 2, 3, 4, 3, 2, 1, 0])
numpy.argmax(signal.correlate(a,b)) -> 16
numpy.argmax(signal.correlate(b,a)) -> 24
这两个不同的值对应于换档是在
a
还是
b

如果需要循环相关,并且对于大信号大小,可以使用卷积/傅里叶变换定理,但需要注意的是,相关与卷积非常相似,但并不完全相同

A = fftpack.fft(a)
B = fftpack.fft(b)
Ar = -A.conjugate()
Br = -B.conjugate()
numpy.argmax(numpy.abs(fftpack.ifft(Ar*B))) -> 4
numpy.argmax(numpy.abs(fftpack.ifft(A*Br))) -> 17
这两个值同样对应于您的解释是在
a
中移位还是在
b
中移位


负共轭是由于卷积翻转了其中一个函数,但在相关中没有翻转。您可以通过反转其中一个信号然后进行FFT,或者对信号进行FFT然后进行负共轭来撤消翻转。i、 e.以下是正确的:
Ar=-A.conjugate()=fft(A[:-1])
此函数对于实值信号可能更有效。它使用rfft和零填充输入,使其具有足够大的2次幂,以确保线性(即非圆形)相关性:

def rfft_xcorr(x, y):
    M = len(x) + len(y) - 1
    N = 2 ** int(np.ceil(np.log2(M)))
    X = np.fft.rfft(x, N)
    Y = np.fft.rfft(y, N)
    cxy = np.fft.irfft(X * np.conj(Y))
    cxy = np.hstack((cxy[:len(x)], cxy[N-len(y)+1:]))
    return cxy
返回值为length
M=len(x)+len(y)-1
(与
hstack
一起进行黑客攻击,以消除向上舍入到2次方的额外零)。非负滞后为
cxy[0]、cxy[1]、…、cxy[len(x)-1]
,而负滞后为
cxy[-1]、cxy[-2]、…、cxy[-len(y)+1]

为了匹配一个参考信号,我需要计算rfft\uxcorr(x,ref)并寻找峰值。例如:

def match(x, ref):
    cxy = rfft_xcorr(x, ref)
    index = np.argmax(cxy)
    if index < len(x):
        return index
    else: # negative lag
        return index - len(cxy)   

In [1]: ref = np.array([1,2,3,4,5])
In [2]: x = np.hstack(([2,-3,9], 1.5 * ref, [0,3,8]))
In [3]: match(x, ref)
Out[3]: 3
In [4]: x = np.hstack((1.5 * ref, [0,3,8], [2,-3,-9]))
In [5]: match(x, ref)
Out[5]: 0
In [6]: x = np.hstack((1.5 * ref[1:], [0,3,8], [2,-3,-9,1]))
In [7]: match(x, ref)
Out[7]: -1
def匹配(x,ref):
cxy=rfft\u xcorr(x,ref)
索引=np.argmax(cxy)
如果索引
这不是一种可靠的匹配信号的方法,但它又快又简单。

这里有另一个选项:

from scipy import signal, fftpack

def get_max_correlation(original, match):
    z = signal.fftconvolve(original, match[::-1])
    lags = np.arange(z.size) - (match.size - 1)
    return ( lags[np.argmax(np.abs(z))] )
大宗报价

(一个非常晚的答案)要找到两个信号之间的时间偏移:使用FTs的时间偏移特性,使偏移可以短于采样间隔,然后计算时间偏移波形和参考波形之间的二次差。当有n个移位波形且移位的多重性时,它会很有用,就像n个接收器对相同的入射波等距排列一样。你也可以用频率的函数代替静态时间偏移来修正色散

代码如下所示:

import numpy as np
import matplotlib.pyplot as plt
from scipy.fftpack import fft, ifft, fftshift, fftfreq
from scipy import signal

#  generating a test signal
dt = 0.01
t0 = 0.025
n = 512
freq = fftfreq(n, dt)

time = np.linspace(-n * dt / 2, n * dt / 2, n)
y = signal.gausspulse(time, fc=10, bw=0.3) + np.random.normal(0, 1, n) / 100
Y = fft(y)
# time-shift of 0.235; could be a dispersion curve, so y2 would be dispersive
Y2 = Y * np.exp(-1j * 2 * np.pi * freq * 0.235)  
y2 = ifft(Y2).real

# scan possible time-shifts
error = []
timeshifts = np.arange(-100, 100) * dt / 2  # could be dispersion curves instead
for ts in timeshifts:
    Y2_shifted = Y2 * np.exp(1j * 2 * np.pi * freq * ts)
    y2_shifted = ifft(Y2_shifted).real
    error.append(np.sum((y2_shifted - y) ** 2))

# show the results
ts_final = timeshifts[np.argmin(error)]
print(ts_final)

Y2_shifted = Y2 * np.exp(1j * 2 * np.pi * freq * ts_final)
y2_shifted = ifft(Y2_shifted).real

plt.subplot(221)
plt.plot(time, y, label="y")
plt.plot(time, y2, label="y2")
plt.xlabel("time")
plt.legend()

plt.subplot(223)
plt.plot(time, y, label="y")
plt.plot(time, y2_shifted, label="y_shifted")
plt.xlabel("time")
plt.legend()

plt.subplot(122)
plt.plot(timeshifts, error, label="error")
plt.xlabel("timeshifts")
plt.legend()

plt.show()

我试着按照你的建议去做,因为手头的案子结果不对。示例:>>>a21阵列([0,1,2,3,4,3,2,2,1,0,1,2,3,4,3,2,2,1,0,0,0])>>>a22阵列([0,0,0,0,0,1,2,3,2,1,1,2,3,4,3,3,3,2,2,2,2,1,1,1])>>>fa21=np fft.fft(a21)>>fa22=np fft.abs(a22)>>c=np fft.fft.ifft(fa21*U=ArgC>>>>时间偏移20正如您所见,实际时间偏移是4点而不是20点。我是不是遗漏了什么?-1。不正确,因为
c
只是
a
b
卷积,不相关。时间倒转会把事情搞得一团糟,不会产生预期的结果。你说得对,史蒂夫。我把答案写得很粗略。我已经纠正了它,以反映共轭。谢谢编辑。(这只适用于真实信号,但我想我们可以假设。)有没有办法找到哪个信号领先?谢谢你的回答。这是我第一次看到有意义的东西。现在还有一个问题,根据时间偏移值的“符号”,我将减去或添加时间偏移。怎么拿到牌子?等等。。。你为什么需要底片?我认为你不需要底片。设x(t)具有变换x(f)。通过时间反转,x(-t)具有变换x(-f)。如果x(t)是实的,那么x(-f)=conj(x(f))。因此,如果x(t)是实的,那么x(-t)具有变换conj(x(f))。史蒂夫:谢谢。昨晚我在推导它的时候犯了一个错误。谢谢你的回答——它是h