Почему кросс-корреляция Python Scipy не работает при заполнении одного из входов - PullRequest
0 голосов
/ 21 июня 2019

Функция кросскорреляции Сципи просто не работает для определенного 1d массива, и я не могу понять, почему. Приведенный ниже код демонстрирует проблему, просто попробуйте с одним следом, а затем с другим.

Этот вопрос немного связан с кросс-корреляцией и Кросс-корреляция Python, не возвращающая правильное смещение

#!/usr/bin/python3

import numpy as np
from scipy import signal
import matplotlib.pyplot as plt

def _main():
    """
    trace = np.array([0.00000000000000001, 0.00000000000000002, 0.00000000000000001, 0.00000000000000002, 0.00000000000000001, 0.00000000000000002, 0.00000000000000001, 0.00000000000000002, 0.00000000000000001, 0.00000000000000002, # down the step
                      0.99999999999999998, 0.99999999999999999, 0.99999999999999998, 0.99999999999999999, 0.99999999999999998, 0.99999999999999999, 0.99999999999999998, 0.99999999999999999, 0.99999999999999998, 0.99999999999999999, 0.99999999999999998, # up the step
                      0.00000000000000001, 0.00000000000000002, 0.00000000000000001, 0.00000000000000002, 0.00000000000000001, 0.00000000000000002, 0.00000000000000001, 0.00000000000000002, 0.00000000000000001, 0.00000000000000002]) # down the step
    """
    trace = np.array([0.51231204949426460, 0.47472182808002383, 0.48806029762272723, 0.51352464310119930, 0.58506742537603330, 0.62993314829830390, 0.57657927012749040, 0.55369158834668990, 0.56255864527226200, 0.61576098682569510,
                      0.62955418648769630, 0.64236215760241170, 0.69063835641941580, 0.75073729780384960, 0.86896478361172370, 0.92216712516515690, 0.91329988783884970, 0.92807831604813670, 0.99113300320800610, 0.99999999999999990, 0.91527040506699960, 
                      0.80098377331469030, 0.71723934679539750, 0.68275634764039450, 0.65812563395824950, 0.63250963159524040, 0.59999708953480900, 0.55172083058422660, 0.54975037348965490, 0.57011178351142090, 0.52807534544936740])


    left_padded_trace = np.pad(trace, (10, 0), mode='constant', constant_values=trace.min())
    center_padded_trace = np.pad(trace, (5, 5), mode='constant', constant_values=trace.min())
    right_padded_trace = np.pad(trace, (0, 10), mode='constant', constant_values=trace.min())

    correlation1 = signal.correlate(center_padded_trace, left_padded_trace, mode='full', method='fft')
    correlation2 = signal.correlate(center_padded_trace, center_padded_trace, mode='full', method='fft')
    correlation3 = signal.correlate(center_padded_trace, right_padded_trace, mode='full', method='fft')

    corr_peak_index1 = np.argmax(correlation1)
    corr_max1 = np.max(correlation1)

    corr_peak_index2 = np.argmax(correlation2)
    corr_max2 = np.max(correlation2)

    corr_peak_index3 = np.argmax(correlation3)
    corr_max3 = np.max(correlation3)

    offset1 = corr_peak_index1-(center_padded_trace.size-1)
    offset2 = corr_peak_index2-(center_padded_trace.size-1)
    offset3 = corr_peak_index3-(center_padded_trace.size-1)

    print("Corr1: {}, Corr2: {}, Corr3: {}".format(corr_peak_index1, corr_peak_index2, corr_peak_index3))
    print("Offset1: {}, Offset2: {}, Offset3: {}".format(offset1, offset2, offset3))

    plt.figure(1)

    plt.subplot(311)
    plt.plot(range(0, center_padded_trace.size), center_padded_trace, 'r-',
            range(offset1, left_padded_trace.size+offset1), left_padded_trace, 'b--',
            range(0, correlation1.size), correlation1/corr_max1, 'g-',
            [corr_peak_index1], [1], 'k+')

    plt.subplot(312)
    plt.plot(range(0, center_padded_trace.size), center_padded_trace, 'r-',
            range(offset2, center_padded_trace.size+offset2), center_padded_trace, 'b--',
            range(0, correlation2.size), correlation2/corr_max2, 'g-',
            [corr_peak_index2], [1], 'k+')

    plt.subplot(313)
    plt.plot(range(0, center_padded_trace.size), center_padded_trace, 'r-',
            range(offset3, right_padded_trace.size+offset3), right_padded_trace, 'b--',
            range(0, correlation3.size), correlation3/corr_max3, 'g-',
            [corr_peak_index3], [1], 'k+')

    plt.show()

Поскольку смещение, добавляемое заполнением, одинаково, и единственное отличие заключается в изменении входной трассы, результаты с точки зрения сдвига и выравнивания по корреляции должны быть одинаковыми, но это не так.

Для первой трассы (более искусственный шаг) корреляции и смещения: (1 - с левой стороны, 2 - по центру и 3 - с правой))

  • Corr1: 35, Corr2: 40, Corr3: 45
  • Смещение 1: -5, Смещение 2: 0, Смещение 3: 5

Для второго следа (более естественного),

  • Corr1: 40, Corr2: 40, Corr3: 40
  • Смещение 1: 0, Смещение 2: 0, Смещение 3: 0

следует за сюжетами:

  • График для синтетического следа (первый в коде) Plot for the synthetic trace

  • Участок для естественного следа (второй в коде) Plot for the natural trace

Решение

См. Ответ и комментарии Пола Панцера ниже.

Проблема с исходным кодом с ненулевым заполнением.

При смещении массива с ненулевыми значениями значение взаимной корреляции становится все более высоким, и на пик воздействуют. Следующий код и изображения демонстрируют этот эффект:

    trace = np.array([0.51231204949426460, 0.47472182808002383, 0.48806029762272723, 0.51352464310119930, 0.58506742537603330, 0.62993314829830390, 0.57657927012749040, 0.55369158834668990, 0.56255864527226200, 0.61576098682569510, 0.62955418648769630, 0.64236215760241170, 0.69063835641941580, 0.75073729780384960, 0.86896478361172370, 0.92216712516515690, 0.91329988783884970, 0.92807831604813670, 0.99113300320800610, 0.99999999999999990, 0.91527040506699960, 0.80098377331469030, 0.71723934679539750, 0.68275634764039450, 0.65812563395824950, 0.63250963159524040, 0.59999708953480900, 0.55172083058422660, 0.54975037348965490, 0.57011178351142090, 0.52807534544936740])

    for padding_value in np.arange(0, trace.min(), trace.min()/10):
        left_padded_trace = np.pad(trace, (10, 0), mode='constant', constant_values=padding_value)
        center_padded_trace = np.pad(trace, (5, 5), mode='constant', constant_values=padding_value)

        correlation = signal.correlate(center_padded_trace, left_padded_trace, mode='full', method='fft')

        corr_peak_index = np.argmax(correlation)

        plt.figure(2)
        plt.subplot(211)
        plt.title('Left Padded Trace')
        plt.xticks([])
        plt.plot(left_padded_trace)
        plt.subplot(212)
        plt.title('Centered Padded Trace')
        plt.plot(center_padded_trace)

        plt.figure(3)
        plt.plot(range(0, correlation.size), correlation)
        plt.plot([corr_peak_index], [correlation[corr_peak_index]], 'k+')

    plt.show()

Результаты представлены ниже. Видно, что с увеличением значения заполнения пик корреляции перемещается в центр.

  • Трассировки с различными уровнями заполнения, от 0 до минимума enter image description here

    • Значения корреляции и пик enter image description here

Ответы [ 2 ]

1 голос
/ 21 июня 2019

Разница объясняется тем, что вы дополняете минимум, который не равен нулю в случае второй трассы.Как следствие, вы не можете ожидать, что пик просто сместится со смещением.Вместо этого вы получаете сдвинутую пиковую кривую плюс треугольник, который масштабируется с минимумом.

summary

import numpy as np
from scipy import signal
import matplotlib.pyplot as plt

def _main(offset=0, trace_idx=0):
    trace = [np.array([0.00000000000000001, 0.00000000000000002, 0.00000000000000001, 0.00000000000000002, 0.00000000000000001, 0.00000000000000002, 0.00000000000000001, 0.00000000000000002, 0.00000000000000001, 0.00000000000000002, # down the step
                      0.99999999999999998, 0.99999999999999999, 0.99999999999999998, 0.99999999999999999, 0.99999999999999998, 0.99999999999999999, 0.99999999999999998, 0.99999999999999999, 0.99999999999999998, 0.99999999999999999, 0.99999999999999998, # up the step
                       0.00000000000000001, 0.00000000000000002, 0.00000000000000001, 0.00000000000000002, 0.00000000000000001, 0.00000000000000002, 0.00000000000000001, 0.00000000000000002, 0.00000000000000001, 0.00000000000000002]), # down the step
    np.array([0.51231204949426460, 0.47472182808002383, 0.48806029762272723, 0.51352464310119930, 0.58506742537603330, 0.62993314829830390, 0.57657927012749040, 0.55369158834668990, 0.56255864527226200, 0.61576098682569510,
                      0.62955418648769630, 0.64236215760241170, 0.69063835641941580, 0.75073729780384960, 0.86896478361172370, 0.92216712516515690, 0.91329988783884970, 0.92807831604813670, 0.99113300320800610, 0.99999999999999990, 0.91527040506699960, 
                      0.80098377331469030, 0.71723934679539750, 0.68275634764039450, 0.65812563395824950, 0.63250963159524040, 0.59999708953480900, 0.55172083058422660, 0.54975037348965490, 0.57011178351142090, 0.52807534544936740])][trace_idx]

    trace += offset - trace.min()

    left_padded_trace = np.pad(trace, (10, 0), mode='constant', constant_values=trace.min())
    center_padded_trace = np.pad(trace, (5, 5), mode='constant', constant_values=trace.min())
    right_padded_trace = np.pad(trace, (0, 10), mode='constant', constant_values=trace.min())

    correlation1 = signal.correlate(center_padded_trace, left_padded_trace, mode='full', method='fft')
    correlation2 = signal.correlate(center_padded_trace, center_padded_trace, mode='full', method='fft')
    correlation3 = signal.correlate(center_padded_trace, right_padded_trace, mode='full', method='fft')

    corr_peak_index1 = np.argmax(correlation1)
    corr_max1 = np.max(correlation1)

    corr_peak_index2 = np.argmax(correlation2)
    corr_max2 = np.max(correlation2)

    corr_peak_index3 = np.argmax(correlation3)
    corr_max3 = np.max(correlation3)

    offset1 = corr_peak_index1-(center_padded_trace.size-1)
    offset2 = corr_peak_index2-(center_padded_trace.size-1)
    offset3 = corr_peak_index3-(center_padded_trace.size-1)

    return offset1, offset2, offset3

    print("Corr1: {}, Corr2: {}, Corr3: {}".format(corr_peak_index1, corr_peak_index2, corr_peak_index3))
    print("Offset1: {}, Offset2: {}, Offset3: {}".format(offset1, offset2, offset3))

    plt.figure(1)

    plt.subplot(311)
    plt.plot(range(0, center_padded_trace.size), center_padded_trace, 'r-',
            range(offset1, left_padded_trace.size+offset1), left_padded_trace, 'b--',
            range(0, correlation1.size), correlation1/corr_max1, 'g-',
            [corr_peak_index1], [1], 'k+')

    plt.subplot(312)
    plt.plot(range(0, center_padded_trace.size), center_padded_trace, 'r-',
            range(offset2, center_padded_trace.size+offset2), center_padded_trace, 'b--',
            range(0, correlation2.size), correlation2/corr_max2, 'g-',
            [corr_peak_index2], [1], 'k+')

    plt.subplot(313)
    plt.plot(range(0, center_padded_trace.size), center_padded_trace, 'r-',
            range(offset3, right_padded_trace.size+offset3), right_padded_trace, 'b--',
            range(0, correlation3.size), correlation3/corr_max3, 'g-',
            [corr_peak_index3], [1], 'k+')

    plt.show()


x = np.arange(200)*0.01
y1 = np.array([*map(_main, x)])

y2 = np.array([*map(_main, x, np.ones(x.size,int))])

plt.figure(1)
plt.subplot(211)
plt.title('synthetic')
plt.plot(x,y1)
plt.legend(('left-shifted input', 'centered input', 'right-shifted input'))
plt.subplot(212)
plt.title('natural')
plt.plot(x,y2)
plt.ylabel('x-offset of result')
plt.xlabel('y-offset')
plt.savefig("summary.png")
0 голосов
/ 21 июня 2019

Режим использования = действительный

scipy.signal.correlate(in1, in2, mode='valid', method='auto')
modestr {‘full’, ‘valid’, ‘same’}, optional

Строка, указывающая размер выходного сигнала:

full Выход - полная дискретная линейная взаимная корреляция входов.(По умолчанию)

valid Выходные данные состоят только из тех элементов, которые не зависят от нуля.В режиме> 'valid' либо in1, либо in2 должны быть как минимум такими же большими, как и другие, в каждом> измерении.

same Выходные данные имеют тот же размер, что и in1, центрированные относительно «полного» выхода..

Обработка сигналов (scipy.signal.correlate)

...