2011-01-14 52 views
14

我必須比較兩個時間與電壓波形。由於這些波形源的特殊性,其中一個可以是另一個的時移版本。找到兩個相似波形之間的時間偏移

我怎樣才能找到是否有時間轉移?如果是的話,多少錢。

我在Python中這樣做,並希望使用numpy/scipy庫。

回答

28

scipy提供了一個相關函數,它可以很好地適用於小輸入,並且如果你想要非循環相關意味着信號不會環繞。請注意,在mode='full'中,由signal.correlation返回的數組的大小是輸入信號大小的總和 - 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 

的兩個不同的值對應於換檔是否處於ab

如果你想循環相關和大信號的大小,你可以使用卷積/傅立葉變換定理與相關性非常相似但不相同的卷積。

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,然後取負共軛來撤消翻轉。即以下事實:Ar = -A.conjugate() = fft(a[::-1])

9

如果其中一個被另一個時間移位,您將在相關性中看到一個峯值。由於計算相關性很昂貴,所以最好使用FFT。所以,這樣的事情應該工作:

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

time_shift = argmax(abs(c)) 
+1

我試着做你認爲是什麼,在手的情況下它給了一個錯誤的結果。 示例: >>> a21 array([0,1,2,3,4,3,2,1,0,1,2,3,4,3,2,1,0,0,0 ,0,0]) >>> a22 array([0,0,0,0,0,1,2,3,4,3,2,1,0,1,2,3,4,3 ,2,1,0]) >>> fa21 = np.fft.fft(a21) >>> fa22 = np.fft.fft(a22) >>> c = np.fft.ifft(fa21 * FA22) >>> time_shift = np.argmax(ABS(C)) >>> time_shift 正如你所看到的,實際的時移爲4分,而不是20 我在這裏失去了一些東西? – Vishal 2011-01-14 09:14:35

+1

-1。不正確,因爲`c`只是```與`b`卷積,不相關。時間反轉會讓事情變得糟糕,而不會給出理想的結果。 – 2011-01-14 14:44:51

+1

你是對的史蒂夫。我寫了一個大概的答案。我已經糾正它以反映共軛。 – highBandWidth 2011-01-14 17:05:57

2

這取決於信號的類型你有(定期...?),兩個信號是否具有相同的幅度,以及你在找什麼精度。

highBandWidth提到的相關函數可能確實適合您。很簡單,你應該試試看。

另一個更精確的選項是我用於高精度譜線擬合的一個選項:用樣條線對您的「主」信號進行建模,並使用它來擬合時移信號(如果需要可能縮放信號是)。這產生了非常精確的時間變化。這種方法的一個優點是你不必研究相關函數。例如,您可以使用interpolate.UnivariateSpline()(來自SciPy)輕鬆創建樣條曲線。 SciPy返回一個函數,然後很容易使用optimize.leastsq()。

6

該函數對於實值信號可能更有效。它使用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 

返回值是長度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_xcorr(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 

這不是匹配信號的可靠方法,但它很快捷。

1

這裏的另一種選擇:

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))]) 
相關問題