Domanda

Devo confrontare due forme d'onda time-vs-tensione. A causa della particolarità delle fonti di queste forme d'onda, uno di loro può essere un tempo spostato la versione dell'altro.

Come posso trovare se v'è un cambiamento di tempo? e se sì, quanto è esso.

Sto facendo questo in Python e desiderio di utilizzare NumPy / SciPy librerie.

È stato utile?

Soluzione

SciPy fornisce una funzione di correlazione che funziona bene per le piccole input e anche se si desidera che la correlazione non circolare il che significa che il segnale non avvolgere intorno. nota che nel mode='full', la dimensione della matrice restituita da signal.correlation è somma delle dimensioni segnale meno uno (cioè len(a) + len(b) - 1), quindi il valore da argmax è disattivata (dimensioni del segnale -1 = 20) da ciò che sembrano aspettarsi .

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

I due diversi valori corrispondono se il cambio è in a o b.

Se si desidera correlazione circolare e di grandi dimensioni del segnale, è possibile utilizzare la convoluzione / trasformata di Fourier teorema con l'avvertenza che la correlazione è molto simile ma non identico a convoluzione.

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

di nuovo i due valori corrispondono a se la vostra interpretazione di un cambiamento di a o un cambiamento di b.

La coniugazione negativo deriva convoluzione capovolgimento una delle funzioni, ma in correlazione non c'è capovolgimento. È possibile annullare pinneggiata invertendo uno dei segnali e quindi prendere la FFT, o prendendo la FFT del segnale e poi con il coniugato negativo. vale a dire quanto segue è vero: Ar = -A.conjugate() = fft(a[::-1])

Altri suggerimenti

Se uno è in differita da parte dell'altro, si vedrà un picco nel correlazione. Poiché il calcolo della correlazione è costoso, è meglio usare FFT. Quindi, qualcosa di simile a questo dovrebbe funzionare:

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

time_shift = argmax(abs(c))

Questa funzione è probabilmente più efficace per i segnali a valori reali. Esso utilizza rfft e zero pastiglie gli ingressi a una potenza di 2 abbastanza grande da garantire lineare (cioè non circolare) correlazione:

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

Il valore di ritorno è di lunghezza M = len(x) + len(y) - 1 (messo insieme con hstack per rimuovere gli zeri aggiuntivi da arrotondamento a una potenza di 2). I ritardi non negativi sono cxy[0], cxy[1], ..., cxy[len(x)-1], mentre i ritardi negativi sono cxy[-1], cxy[-2], ..., cxy[-len(y)+1].

Per abbinare un segnale di riferimento, mi piacerebbe calcolare rfft_xcorr(x, ref) e cercare il picco. Ad esempio:

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

Non è un modo robusto per abbinare i segnali, ma è semplice e veloce.

Dipende dal tipo di segnale che avete (periodica? ...), dal fatto che entrambi i segnali hanno la stessa ampiezza, e su quello che la precisione che si sta cercando.

La funzione di correlazione di cui parla High-bandwidth potrebbe effettivamente funzionare per voi. E 'abbastanza semplice che si dovrebbe fare un tentativo.

Un altro, l'opzione più precisa è quella che uso per alta precisione raccordo riga spettrale: si modella il segnale "master" con una spline e in forma il segnale in differita con esso (anche se può scalare il segnale, se necessario ). Questo produce molto precise salti nel tempo. Un vantaggio di questo approccio è che non c'è bisogno di studiare la funzione di correlazione. È possibile per esempio creare la spline facilmente con interpolate.UnivariateSpline() (da SciPy). SciPy restituisce una funzione, che viene poi montata facilmente con optimize.leastsq ().

Ecco un'altra opzione:

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))] )
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top