2016-10-05 16 views
8

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

Примечание: На любом треке могут быть дополнительные или отсутствующие наборы.

Я нашел некоторую информацию о взаимной корреляции (например, https://dsp.stackexchange.com/questions/736/how-do-i-implement-cross-correlation-to-prove-two-audio-files-are-similar), которая выглядела многообещающей.

Я предположил, что каждый звуковой дорожки составляет 10 секунд в продолжительности, и представлял звуковые натисков как пики с «квадратной волны» с частотой дискретизации 44,1 кГц:

import numpy as np 

rfft = np.fft.rfft 
irfft = np.fft.irfft 

track_1 = np.array([..., 5.2, 5.5, 7.0, ...]) 
# The onset in track_2 at 8.0 is "extra," it has no 
# corresponding onset in track_1 
track_2 = np.array([..., 7.2, 7.45, 8.0, 9.0, ...]) 
frequency = 44100 
num_samples = 10 * frequency 
wave_1 = np.zeros(num_samples) 
wave_1[(track_1 * frequency).astype(int)] = 1 
wave_2 = np.zeros(num_samples) 
wave_2[(track_2 * frequency).astype(int)] = 1 
xcor = irfft(rfft(wave_1) * np.conj(rfft(wave_2))) 
offset = xcor.argmax() 

Этот подход не является особенно быстро, но я смог получить довольно последовательные результаты даже при довольно низких частотах. Однако ... я понятия не имею, если это хорошая идея! Есть ли лучший способ найти это смещение, чем кросс-корреляция?

Редактировать: добавлено примечание о недостающих и дополнительных onsets.

+0

Вы показываете 'track_1' и' track_2' как нерегулярно разнесенные, тогда вы умножаете их на 'frequency' при построении' wave_1' и 'wave_2'. Предполагается ли, что «track_1» и «track_2» являются отметками времени, которые вы пытаетесь сопоставить, или они должны быть звуковыми формами без добавления звуковых сигналов? Или это время начала «звукового сигнала»? – Brian

+0

'track_1' и' track_2' - это время начала каждого звукового сигнала. 'wave_1' и' wave_2' являются, если хотите, суммированием дельта-функций Дирака для поиска взаимной корреляции. – user1475412

ответ

3

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

import numpy as np 

frequency = 44100 
num_samples = 10 * frequency 
actual_time_delay = 0.020 
timestamp_noise = 0.001 

# Assumes track_1 and track_2 are timestamps of beeps, with a delay and noise added 
track_1 = np.array([1,2,10000]) 
track_2 = np.array([1,2,10000]) + actual_time_delay*frequency + 
      frequency*np.random.uniform(-timestamp_noise,timestamp_noise,len(track_1)) 

calculated_time_delay = np.mean(track_2 - track_1)/frequency 
print('Calculated time delay (s):',calculated_time_delay) 

Это дает примерно 0.020 с в зависимости от случайных ошибок, вносимых и примерно так же быстро, как он получает.

EDIT: Если необходимо обработать лишние или отсутствующие метки времени, код можно изменить следующим образом. По существу, если ошибка случайной случайности времени ограничена, тогда выполняйте статистическую «режимную» функцию при задержках между всеми значениями. Все, что связано с оценкой случайности случайности, группируется вместе и идентифицируется, тогда исходные идентифицированные задержки затем усредняются.

import numpy as np 
from scipy.stats import mode 

frequency = 44100 
num_samples = 10 * frequency 
actual_time_delay = 0.020 

# Assumes track_1 and track_2 are timestamps of beeps, with a delay, noise added, 
# and extra/missing beeps 
timestamp_noise = 0.001 
timestamp_noise_threshold = 0.002 
track_1 = np.array([1,2,5,10000,100000,200000]) 
track_2 = np.array([1,2,44,10000,30000]) + actual_time_delay*frequency 
track_2 = track_2 + frequency*np.random.uniform(-timestamp_noise,timestamp_noise,len(track_2)) 

deltas = [] 
for t1 in track_1: 
    for t2 in track_2: 
     deltas.append(t2 - t1) 
sorted_deltas = np.sort(deltas)/frequency 
truncated_deltas = np.array(sorted_deltas/(timestamp_noise_threshold)+0.5, 
dtype=int)*timestamp_noise_threshold 

truncated_time_delay = min(mode(truncated_deltas).mode,key=abs) 
calculated_time_delay = np.mean(sorted_deltas[truncated_deltas == truncated_time_delay]) 

print('Calculated time delay (s):',calculated_time_delay) 

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

+0

В данный момент я не могу изучить это ближе, но похоже, что это не удержит других видов «шума» на дорожках, таких как пропущенные значения или дополнительные значения. Это правильно? – user1475412

+0

Значит, он должен обрабатывать отсутствующие/дополнительные звуковые сигналы? Ты прав, он не справится с этим. – Brian

+0

Да, извините. Я должен был сделать это ясно. Я отредактирую вопрос. – user1475412

3

Да, это имеет смысл. Это обычно делается в Matlab. Вот ссылка на аналогичной заявки:

http://www.mathworks.com/help/signal/ug/cross-correlation-of-delayed-signal-in-noise.html

Несколько соображений

Кросс-корреляция обычно используется в случаях, когда сигнал в вопросе слишком много шума. Если у вас нет шума, чтобы беспокоиться о том, что я бы использовал другой метод.

+0

Ну, моя забота - это «квадратная волна». Если начальный массив 'track_1' равен' [1, 2, 1000000] ', он создаст гораздо больший массив ввода (' wave_1'), чем '[1, 2, 3]', хотя оба имеют 3 элемента. – user1475412

+0

«Если у вас нет шума, чтобы беспокоиться о том, что я бы использовал другой метод». Можете ли вы порекомендовать другой метод? – user1475412

+0

Предположим, что у меня есть две функции: 'f1()' и 'g()' где 'g()' - это известный шаблон без шума, а f1() - ваши образцы звука. Я бы сместил 'g()' над 'f1()' sample-wise и вычислил там разницу 'h1 (s) = integ [f1 (s) -g (s-S) ds]'. Тогда я найду все локальные максимумы. Это те места, где существует эта функция. Сделайте то же самое для h2 (s) = интеграл [f2 (s) -g (s-S) ds] '. Затем сдвиньте h2_max() по h1_max(), пока не получите минимальное горизонтальное различие от ваших локальных максимумов. –