Ideą autokorelacji jest zapewnienie miary podobieństwa między sygnałem a samym sobą przy danym opóźnieniu. Można podejść do tego na kilka sposobów, ale do celów wykrywania wysokości / tempa można potraktować to jako procedurę wyszukiwania. Innymi słowy, przechodzisz przez sygnał próbka po próbce i wykonujesz korelację między oknem odniesienia a opóźnionym oknem. Korelacja przy „opóźnieniu 0” będzie globalnym maksimum, ponieważ porównujesz odniesienie do pełnej kopii samego siebie. W miarę postępów korelacja z konieczności się zmniejszy, ale w przypadku sygnału okresowego w pewnym momencie zacznie się ponownie zwiększać, a następnie osiągnie lokalne maksimum. Odległość między „opóźnieniem 0” a pierwszym pikiem daje oszacowanie wysokości / tempa. Sposób w jaki ja
Obliczanie korelacji między próbkami może być bardzo drogie obliczeniowo przy wysokich częstotliwościach próbkowania, dlatego zwykle stosuje się podejście oparte na FFT. Biorąc FFT interesującego segmentu, mnożąc go przez jego złożony koniugat , a następnie biorąc odwrotną FFT da ci cykliczną autokorelację . W kodzie (przy użyciu numpy ):
freqs = numpy.fft.rfft(signal)
autocorr = numpy.fft.irfft(freqs * numpy.conj(freqs))
Efektem będzie zmniejszenie ilości szumu w sygnale (który nie jest skorelowany z samym sobą) w stosunku do składowych okresowych (które z definicji są podobne do siebie). Powtórzenie autokorelacji (tj. Mnożenie sprzężone) przed podjęciem odwrotnej transformacji jeszcze bardziej zmniejszy szum. Rozważ przykład fali sinusoidalnej zmieszanej z białym szumem. Poniższy wykres przedstawia falę sinusoidalną 440 Hz, tę samą falę sinusoidalną „zepsutą” przez szum, cykliczną autokorelację fali szumowej i podwójną autokorelację:
Zwróć uwagę, jak pierwszy szczyt obu sygnałów autokorelacji znajduje się dokładnie na końcu pierwszego cyklu oryginalnego sygnału. To jest szczyt, którego szukasz, aby określić okresowość (w tym przypadku wysokość). Pierwszy sygnał autokorelacji jest nadal nieco „poruszający”, więc aby wykonać detekcję piku, konieczne byłoby pewne wygładzenie. Dwukrotna autokorelacja w dziedzinie częstotliwości osiąga to samo (i jest stosunkowo szybka). Zauważ, że przez „falisty” mam na myśli wygląd sygnału po zbliżeniu, a nie zapad, który pojawia się na środku wykresu. Druga połowa cyklicznej autokorelacji będzie zawsze odbiciem lustrzanym pierwszej połowy, więc ten typ „zanurzenia” jest typowy. Aby wyjaśnić algorytm, oto jak wyglądałby kod:
freqs = numpy.fft.rfft(signal)
auto1 = freqs * numpy.conj(freqs)
auto2 = auto1 * numpy.conj(auto1)
result = numpy.fft.irfft(auto2)
To, czy trzeba wykonać więcej niż jedną autokorelację, zależy od ilości szumu w sygnale.
Oczywiście istnieje wiele subtelnych odmian tego pomysłu i nie zamierzam się tutaj zajmować. Najbardziej wszechstronny zasięg, jaki widziałem (w kontekście wykrywania wysokości tonu), to Cyfrowe przetwarzanie sygnałów mowy Rabinera i Schafera.
Teraz, czy autokorelacja będzie wystarczająca do wykrycia tempa. Odpowiedź brzmi: tak i nie. Możesz uzyskać informacje o tempie (w zależności od sygnału źródłowego), ale może być trudno zrozumieć, co to znaczy we wszystkich przypadkach. Na przykład, oto wykres dwóch pętli breakbeat, a następnie wykres cyklicznej autokorelacji całej sekwencji:
Dla odniesienia, oto odpowiedni dźwięk:
Rzeczywiście, w środku znajduje się ładny skok odpowiadający punktowi pętli, ale powstał z przetworzenia dość długiego segmentu. Ponadto, jeśli nie byłby to dokładny egzemplarz (np. Gdyby było w nim oprzyrządowanie), kolec nie byłby tak czysty. Autokorelacja z pewnością będzie przydatna w wykrywaniu tempa, ale prawdopodobnie sama w sobie nie będzie wystarczająca dla złożonego materiału źródłowego. Na przykład, nawet jeśli znajdziesz skok, skąd wiesz, czy jest to pełny takt, ćwierćnuta, półnuta, czy coś innego? W tym przypadku jest wystarczająco jasne, że jest to pełna miara, ale nie zawsze tak będzie. Proponuję bawić się przy użyciu prądu przemiennego na prostszych sygnałach, dopóki wewnętrzne funkcje nie staną się jasne, a następnie zadać kolejne pytanie o wykrywanie tempa w ogóle (ponieważ jest to „większy”