Analiza dźwięku i czasu pogłosu w pomieszczeniach z wykorzystaniem Python

Czy kiedykolwiek pomyślałeś, że jako web developer będziesz zajmował się analizą dźwięku? Ja też nie. Jednak, gdy na horyzoncie pojawił się projekt dla polskiego lidera w produkcji mebli akustycznych, stwierdziłem — dobra, spróbuję. Cel — stworzyć aplikację internetową, która pozwoli nagrać i przeanalizować dźwięk, tak aby obliczyć czas pogłosu pomieszczenia.


Tomasz Trzos
. Programista backend w Startup Development House. Jego ulubionymi językami jest ruby i python. Pracuje również z technologiami: Ruby on Rails, Docker i Kubernetes oraz rozwija swoje umiejętności z zakresu devops na platformie Google Cloud Platform. Wolny czas poświęca na ściganie się zdalnie sterowanymi samochodami i budowanie dronów.


Innymi słowy, jako klient chce wiedzieć czy wstawić małą, czy dużą ściankę pochłaniającą dźwięk oraz gdzie najlepiej ją postawić. Spore wyzwanie jeśli akurat nie jesteś akustykiem, czyż nie? Na szczęście z pomocą przyszedł Python i sporo bibliotek, dzięki którym udało mi się zmierzyć z tym wyzwaniem.

Chcesz nauczyć się jak analizować dźwięk? W tym artykule przeprowadzę Cię przez cały proces — od odczytania danych z pliku do ich wizualizacji i obliczania czasu pogłosu.

Odczytanie pliku WAV

Pierwsze co musimy zrobić to odczytanie pliku i uzyskanie danych, z którymi będziemy pracowali. W języku Python nie jest to zbyt trudne. Jedyne czego potrzebujemy to biblioteka “SciPy”, która jest całkiem obszerna, ale skupmy się tylko na pakiecie “scipy.io.wavfile”. Aby porównać wyniki z tymi opisanymi w artykule możesz pobrać plik dźwiękowy z nagranym silnym sygnałem (wykorzystywanym do obliczania czasu pogłosu):
download (uważaj na poziom głośności swoich słuchawek).

Powyższa metoda zwraca dwie wartości: częstotliwość próbkowania (ang. sample rate) i tablicę danych, która zawiera wartości różnego typu i w różnych przedziałach (w zależności od formatu pliku WAV).

W przypadku naszego pliku jest to typ int16 NumPy dtype. Poniżej zaprezentowałem fragment kodu, który w łatwy sposób pozwoli sprawdzić podstawowe informacje na temat pliku WAV.

Wizualizacja dźwięku: amplituda sygnału cyfrowego

Co możemy zrobić z danymi wyciągniętymi w poprzednim kroku? Możemy skorzystać z kolejnej ciekawej biblioteki wykorzystywanej do generowania wielu różnych wykresów: matplotlib. To, czego szukamy, to wykres przebiegu sygnału cyfrowego. Możesz porównać swój wynik z wykresem, który wygenerowałem z wykorzystaniem edytora audio: Audacity.

Otrzymaliśmy dane w zakresie od -2,15 do 2,15-1. W łatwy sposób możemy je przeskalować do wartości z zakresu od -1 do 1. Wystarczy podzielić wszystkie wartości przez 215. Następnie musimy przygotować tablicę, której długość będzie taka sama jak tablica z danymi pochodzącymi z pliku. Elementy tej tablicy będą zawierały dane dotyczące czasu (w sekundach), co pozwoli nam na przedstawienie przebiegu sygnału w czasie. Do przygotowania takiej tablicy wykorzystamy bibliotekę Numpy, która bardzo ułatwia obliczenia na tablicach. Kolejny krok to wykorzystanie funkcji “plot” z biblioteki matplotlib i voilá — mamy gotowy wykres.

Wizualizacja dźwięku: spektrogram

Do obliczenia czasu pogłosu potrzebujemy poziomu decybeli w określonym czasie. Możesz próbować rozwiązać ten problem krok po kroku, ale ja wykorzystałem metodę “specgram” z biblioteki matplotlib, która zwraca wszystko czego potrzebujemy. Skupmy się na tym jak uzyskać spektrogram i w następnym kroku zajmiemy się obliczaniem czasu pogłosu. Tak jak w poprzedniej części — możesz porównać swój spektrogram ze spektrogramem wygenerowanym przez program Audacity.

Nie chciałem skupiać się na analizie funkcji ‘specgram’, więc jeśli chcesz dowiedzieć więcej na ten temat to zachęcam Cię do sprawdzenia dokumentacji funkcji: matplotlib.pyplot.specgram.

Wartość decybeli dla określonej częstotliwości

Czas pogłosu pomieszczenia

Powinniśmy wiedzieć, że czas pogłosu to całkiem ważna kwestia, ponieważ rozmowa w pomieszczeniu gdzie czas pogłosu jest zbyt wysoki jest bardzo uciążliwa, a dźwięk słyszymy tak jakbyśmy rozmawiali wewnątrz studni. Po przeczytaniu dalszej części artykułu i wykonaniu poniższych kroków będziesz w stanie sprawdzić czas pogłosu pomieszczenia.

1. Znajdź maksymalną wartość decybeli w tablicy

2. “Przytnij” tablice tak, aby przycięta tablica z danymi dźwięku zaczynała się od maksymalnej wartości

3. Znajdź wartość max-5dB

4. “Przytnij” tablice tak, aby przycięta tablica z danymi dźwięku zaczynała się od max-5dB

5. Znajdź wartość max-25dB

6. Oblicz, po którym amplituda spadnie z max-5dB do max-25dB (RT20)

7. Pomnóż swój czas przez 3 i w rezultacie otrzymasz RT60

Zdaję sobie sprawę, że może to być niejasne dlatego z pomocą przyjdzie nam poniższy kod:

  • zielone kółko: wartość maksymalna,
  • żółte kółko: max-5dB,
  • czerwone kółko: max-25dB.

W ten sposób otrzymaliśmy algorytm, który działa na ‘surowym’ sygnale i nie jest odporny na zakłócenia dźwięku. Aby poprawić nasze wyniki powinniśmy obliczyć czas pogłosu na danych, które zostaną w jakiś sposób znormalizowane. Najlepszym wyborem dla tego problemu jest regresja liniowa.

Regresja liniowa

Ulepszony algorytm do obliczenia czasu pogłosu pomieszczeń

Następny krok to zmiana naszego algorytmu do obliczania czasu pogłosu, aby wyliczał go w taki sam sposób jak poprzednio, ale korzystając z regresji liniowej. Prawie skończyliśmy, ale spójrzmy jeszcze na poniższy kod:

W porządku, to wszystko! Właśnie napisałeś skrypt, który pozwala sprawdzić czas pogłosu w Twoim pokoju. Rozwiązanie i kod zaprezentowany w artykule był nieco uproszczony w porównaniu z rozwiązaniem wykorzystanym w projekcie dla naszego klienta, ale wystarcza do sprawdzenia czasu pogłosu we własnym pokoju.

Dziękuję wszystkim za czas poświęcony na artykuł. Tak jak wspomniałem na wstępie — nie jestem specjalistą z dziedziny dźwięku i akustyki oraz na co dzień programuję w ruby, dlatego jeśli ktoś ma jakieś ciekawe spostrzeżenia to zapraszam do kontaktu!


Zdjęcie główne artykułu pochodzi z stocksnap.io.

Zapraszamy do dyskusji

Patronujemy

 
 
Polecamy
Jak backendowcy mogą ułatwić pracę frontendowcom. Devdebata