2016-10-05 2 views
8

Ich möchte den Offset zwischen zwei Arrays von Zeitstempeln finden. Sie könnten beispielsweise den Beginn von Signaltönen in zwei Audiospuren darstellen.Macht es Sinn Kreuzkorrelation auf Arrays von Zeitstempeln zu verwenden?

Hinweis: In beiden Spuren können zusätzliche oder fehlende Onsets vorhanden sein.

Ich fand einige Informationen über Kreuzkorrelation (z.B. https://dsp.stackexchange.com/questions/736/how-do-i-implement-cross-correlation-to-prove-two-audio-files-are-similar), die vielversprechend aussahen.

nahm ich, dass jede Audiospur 10 Sekunden Dauer ist, und repräsentiert den Piepton Onsets wie die Spitzen einer „Rechteckwelle“ mit einer Abtastrate von 44,1 kHz:

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() 

Dieser Ansatz ist nicht besonders schnell, aber ich konnte ziemlich konsistente Ergebnisse erzielen, selbst bei ziemlich niedrigen Frequenzen. Allerdings ... ich habe keine Ahnung, ob das eine gute Idee ist! Gibt es einen besseren Weg, diesen Offset als die Kreuzkorrelation zu finden?

Bearbeiten: Notiz über fehlende und zusätzliche Onsets hinzugefügt.

+0

Sie zeigen 'track_1' und' track_2' als unregelmäßige Abstände, dann multiplizieren Sie sie mit 'frequency', wenn Sie' wave_1' und 'wave_2' aufbauen. Sind "track_1" und "track_2" die Zeitstempeln, die Sie korrelieren möchten, oder sollen es die Audio-Wellenformen sein, ohne dass die Signaltöne hinzugefügt wurden? Oder sind sie die Anfangszeiten des "Piep"? – Brian

+0

'track_1' und' track_2' sind die Anfangszeiten jedes Pieptons. "wave_1" und "wave_2" sind jeweils eine Summe von Dirac-Delta-Funktionen, um die Kreuzkorrelation zu finden. – user1475412

Antwort

3

Wenn track_1 und track_2 Zeitstempel von Signaltönen sind und beide alle Signaltöne erfassen, ist es nicht erforderlich, eine Wellenform zu erstellen und eine Kreuzkorrelation durchzuführen. Finden Sie einfach die durchschnittliche Verzögerung zwischen den beiden Reihen von Piep-Zeitstempel:

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) 

Diese etwa 0.020 s ergeben eingeführt in Abhängigkeit von den zufälligen Fehlern und ist etwa so schnell wie es geht.

EDIT: Wenn zusätzliche oder fehlende Zeitstempel behandelt werden müssen, dann könnte der Code wie folgt geändert werden. Wenn der Fehler bei der Timestamp-Zufälligkeit begrenzt ist, dann führen Sie im Wesentlichen eine statistische "Modus" -Funktion für die Verzögerungen zwischen allen Werten aus. Alles innerhalb der Timestamp-Zufälligkeitsgrenze wird zusammen gruppiert und identifiziert, und dann werden die ursprünglich identifizierten Verzögerungen gemittelt.

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) 

Offensichtlich, wenn zu viele Töne fehlen oder zusätzliche Signalton existieren dann der Code beginnt irgendwann zum Scheitern verurteilt, aber im Allgemeinen sollte es funktionieren gut und wird viel schneller als zu versuchen, eine ganze Wellenform und Durchführung Korrelation zu erzeugen, .

+0

Ich kann das im Moment nicht näher untersuchen, aber es sieht so aus, als würde es anderen Arten von "Rauschen" in den Spuren nicht standhalten, wie fehlende Werte oder zusätzliche Werte. Ist das richtig? – user1475412

+0

Also muss es auch mit fehlenden/zusätzlichen Signaltönen umgehen? Du hast Recht, das wird nicht funktionieren. – Brian

+0

Ja, tut mir leid. Ich hätte das klar machen müssen. Ich werde die Frage bearbeiten. – user1475412

3

Ja, es macht Sinn. Dies wird üblicherweise in Matlab gemacht. Hier ist ein Link zu einer ähnlichen Anwendung:

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

Mehrere Überlegungen

Kreuzkorrelation üblicherweise für Zeiten verwendet wird, wenn das Signal in Frage zu viel Lärm hat. Wenn Sie keinen Lärm haben, um den Sie sich sorgen müssen, würde ich eine andere Methode verwenden.

+0

Nun, meine Sorge ist der "Rechteckwelle" Teil davon. Wenn das Onset-Array 'track_1'' [1, 2, 1000000] 'ist, erzeugt es ein viel größeres Eingabearray (' wave_1') als '[1, 2, 3]', obwohl beide drei Elemente haben. – user1475412

+0

"Wenn Sie keinen Lärm haben, um den Sie sich kümmern müssen, würde ich jedoch eine andere Methode verwenden." Können Sie eine andere Methode empfehlen? – user1475412

+0

Angenommen, ich hätte zwei Funktionen 'f1()' und 'g()', wobei 'g()' das bekannte Muster ohne Rauschen ist und f1() Ihre Audio-Samples sind. Ich würde 'g()' über 'f1()' sample weise und Computer dort Unterschied 'h1 (s) = integral [f1 (s) -g (s-S) ds]' schieben. Dann würde ich alle lokalen Maxima finden. Das sind die Orte, an denen das Feature existiert. Tun Sie das gleiche für 'h2 (s) = ganzzahlig [f2 (s) -g (s-S) ds]'. Dann verschiebe h2_max() über h1_max(), bis du die geringste horizontale Differenz von deinen lokalen Maxima erreichst. –

Verwandte Themen