Numeryczne obliczanie częstotoliwości dźwięku

0

Mój problem przedstwia się tak - mam zapisane w pamięci pewną ilość próbek sygnału nagranego z mikrofonu. Zakładając, że nagrany został dźwięk posiadający hamoniczną wiodącą (np. dźwięk gitary elektrycznej) chciałbym się dowiedzieć jak się liczy tę czestotliwość numerycznie. Reasumując - program ma w tym aspekcie działać jak zwykły tuner muzyczny.

pozdrawiam

0

fft

0

To jest wlasnie moj problem, że FFT daje mi pewne dane, ale nie jestem pewien co potem z nimi zrobić, jaki jest ich sens. Domyślam się, że poszczególne wyrazy ciagu obliczonego za pomoca fft sa wartosciami zespolonymi tranformanty fouriera od pewnych czestoliwosci (tylko nie wiem dokladnie jakich). Nie wiem jednak jak z tych wartosci odczytac czestotliwosc wiodacą.

0

http://sirk.sytes.net/software/libs/kjdss/index.htm (plik kjdss\KJFFT.java)
Znajdziesz tam łatwą do przeniesienia implementację FFT, która wypluwa znormalizowane magnitudy w zakresie 0-1. Podając na wejście "sinusa" o amplitudzie {-2, +2} (sin(angle)*2), wyjściem będzie pojedyncza szpilka o magnitudzie +1.
Jej częstotliwość obliczysz znając lub zakładając częstotliwośc próbkowania - dla typowych 44100 sampli na sekundę, częstotliwość N-ej magnitudy obliczasz ze wzoru

frequency = N*base;
gdzie
base=44100/fftinputsize;
// dokładniej: base=(samplingrate/2) / (fftinputsize/2).
// fftinputsize to 2^x, rozmiar bufora wejściowego FFT.
// samplingrate/2 dlatego, że częstotliwość najwyższej/ostatniej magnitudy jest połową częst. próbkowania.

.

Z kolei konwersji magnitudy na wartość logarytmiczną dokonasz prostym wzoremdecibels = 20 * log10(magnitude / 1) gdzie 1 jest wartością wzorową, najwyższą możliwą magnitudą.
// w FFTW zamiast 1 trzeba wstawić fftinputsize/2, bynajmniej dla wersji sse1/float.
Wartość decibels będzie ujemna, jeżeli chcesz dodatnią to albo zamień miejscami dzielną i dzielnik w log10, albo zwyczajnie zmień znak wyniku.

0
Lukaszzzzzzz napisał(a)

Nie wiem jednak jak z tych wartosci odczytac czestotliwosc wiodacą.
Każda z wyznaczonych wartości odpowiada pewnej częstotliwości, jest to głośność danej częstotliwości. Częstotliwość wiodąca, to ta najgłośniejsza, czyli ta dla której wyznaczona wartość jest największa. Mając kilka wysokich wartości można się bawić w wyznaczanie średniej.

0
adf88 napisał(a)
Lukaszzzzzzz napisał(a)

Nie wiem jednak jak z tych wartosci odczytac czestotliwosc wiodacą.
Każda z wyznaczonych wartości odpowiada pewnej częstotliwości, jest to głośność danej częstotliwości. Częstotliwość wiodąca, to ta najgłośniejsza, czyli ta dla której wyznaczona wartość jest największa. Mając kilka wysokich wartości można się bawić w wyznaczanie średniej.

ale to dopiero po okienkowaniu, czyste dane z fft to siano :P

0

Ok, przedstawie jak wydaje mi się, że dtf działa żeby upewnić się czy dobrze wszystko rozumiem.

Tak więc, mamy pewny ciąg danych uzyskanych za pomocą próbkowania z pewną częstotliwością f. Wybieramy teraz z tego ciągu blok kolejnych N liczb (czy ten blok może się zaczynać w dowolnym miejscu danych wejściowych, czy np. tylko z początku?) W każdym razie mielimy go przez dtf i uzyskujemy N liczb zespolonych. Obliczamy ich modluły otrzymując N liczb rzeczywistych. Teraz k-ta liczba rzeczywista z tego ciągu jest amplitudą harmonicznej o częstotliwości k * f / N. Czy tak?

0

W wypowiedzi u góry pomijam takie efekty jak zniekształcenie widma przez pewne sztuczne nieciągłości, więc nie przejmuje się okienkowaniem.

0

czy ten blok może się zaczynać w dowolnym miejscu
Tak, byle ilość sampli ograniczona jego położeniem nie była znikoma w stosunku do pojemności wejścia FFT. Jeżeli tych sampli będzie mniej, to resztę trzeba dopełnić zerami, lub odpowiednio powielić sample.
Możesz np. obrobić pierwsze X sampli, następne X sampli, albo z przeplotem: X sampli z miejsca Y, X sampli z miejsca Y-X*0.9 ...
Powielanie ma tylko sens gdy sampli jest na prawdę mało - na przykład jeden okres sygnału, ale zazwyczaj wystarcza przemnożenie wyjścia transformacji przez iloraz rozmiaru wejścia i ilości wprowadzonych niezerowych sampli. Wtedy mamy zapewniony jednolity poziom transformaty, zależny jedynie od poziomu sygnału wejściowego.
Przykładowo mając bufor wejściowy fft o rozmiarze 32768 sampli i wprowadzajac tylko 16384 sampli (resztę dopełniasz zerami), warto jest pomnożyć "wyjście fft" przez 2 (32768/16384), by wynik był na takim samym poziomie jak by było przy wprowadzeniu 32768 sampli.

mielimy go przez dtf i uzyskujemy N liczb
Tych liczb jest N/2+1, gdzie N to najwyższa ilość próbek którą akceptuje wejście fft (fftInputSize).
Przykładowo mając fft przyjmujące 32768 sampli, będzie ono wypluwać 32768/2+1 liczb kompleksowych (lub rzeczywistych).

Teraz k-ta liczba [...]
Tak, przykład dla fft.input.size = 32768 i samplerate=44100. Wyjście FFT to amplitudy wielokrotności 1.34Hz (44100/32768). Ostatnia amplituda (index=(32768/2+1)-1=16384) odnosi się do częstotliwości 22050 (16384*1.34).

Zapewne masz program audacity, wiec zaimportuj do niego jakiegoś mp3, zaznacz fragment i kliknij View/PlotSpectrum. W nowym oknie rozmiar FFT jest domyślnie ustawiony na skromne 512, więc cały wykres ma rozdzielczość około 86Hz. Tak mała rozdzielczość jest zbyt niska w zakresie niskich częstotliwości, ale całkowicie wystarczająca w lewej części wykresu. Klikajac Export, program utworzy plik tekstowy z poziomami każdej częstotliwości z wykresu. Warto tam zajżeć by porównać własne wyniki.

Frequency (Hz)    Level (dB)
 43.066406	-28.865408
 86.132813	-28.287386
129.199219	-32.179745
172.265625	-36.389809
0

Tak więc niedawno wróciłem z wakacji i mogłem zabrać się do roboty. Przerobiłem wszystkie wasze odpowiedzi, jestem wdzięczny za nie gdyż były mi bardzo pomocne. Zaimplementowałem fft, okienkowanie, wypisywanie wyników. Poszło gładko. Testowałem to wszystko najpierw na sygnałach wzorcowych, to znaczy próbki generowałem sztucznie za pomocą różnych kombinacji sinusów i kosinusów. Wyniki były w porządku. Problem pojawił się gdy pobrałem próbki z plików wav nagranych rejestratorem dźwięku. Wyniki nie były jakieś kosmiczne, pojawiały się tylko pewne nieprawidłowości. Dla przykładu dla nagranego dźwięku kamertonu ( 440 Hz , nagranie bez żadnych pauz, o mniej więcej stalym natężeniu w czasie ) skok amplitudy na wyjściu następował już przy częstotliowści 220 Hz, potem zaobserwowałem tylko pojedyńczy skok dla 440 Hz. Na podstawie tego co wiem o akustyce jest to zły wynik. Jako że wszystkie testy matematyczne poszły gładko nie sądze aby było to spowodowane jakimś błędem w implementacji algorytmu. Coś mi się wydaje, że może próbki są trefne. Może rejestrator dźwięku stosuje jakąś metode kompresji, a ja odczytując dane z pliku bajt po bajcie jak leci zaburzam w ten sposób wynik. Proszę o sugestie.

0

Prawdopodobnie źle interpretujesz próbki z Wava. Możliwe, że pomyliłeś czy próbka jest zapisana jako liczba ze znakiem, czy bez znaku. Dla pewności narysuj (w programie oczywiście) te swoje próbki i zobacz czy nie ma dziwnych skoków amplitudy.
Inna możliwość, że pomyliłeś się w interpretacji co jest częstotliwością i popełniłeś ten błąd w obu kodach (w programie i w testach).

0

Co sądzicie o takim rzutowaniu próbek z pamięci na tablice double:

for( int i = 0 ; i < length ; i++ )
                samples[i] = (double) *( (short*)( data + 2*i ) );

gdzie data to wskaznik na char - początek próbek w pamięci. Short zajmuje dwa bajty i jest signed. Coś mi się wydaje, że gdzieś tutaj popełniam błąd.

0

Probóki są w formacie mono żeby nie było nieporozumień.

1 użytkowników online, w tym zalogowanych: 0, gości: 1