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
.
Отрицательное сопряжение связано с переворачиванием одной из функций сверткой, но в корреляции переворот отсутствует. Вы можете отменить переключение, изменив один из сигналов и затем взяв БПФ, или взяв БПФ сигнала, а затем взяв отрицательное сопряжение. то есть верно следующее: Ar = -A.conjugate() = fft(a[::-1])