Skocz do zawartości

I2S - Szum po softowej zmianie głośności


Chev

Pomocna odpowiedź

Dzień dobry,

Bawię się ESP32 i piszę swoją bibliotekę audio wykorzystując do tego interfejs I2S, wzmacniacz mono MAX98357A i głośniczek 4 Ohmowy. Do tego mam dołączony kondensator 100nF (Vcc-GND) i 220uF (Vcc-GND). 

Dźwięki, które odtwarzam to pliki w formacie .wav. Generalnie wszystko ładnie działa na oryginalne plików - nie ma żadnych szumów podczas odtwarzania. Chciałbym móc regulować w sposób softowy głośność granych dźwięków bez angażowania do tego hardware'u (mogę przez PWN sterować wejściem SD, ale chcąc oszczędzić port chciałbym zrobić to jednak w sposób softowy). Obecnie robię to używając równania: wartość_aktualnej_próbki = wartość_aktualnej_próbki * (poziom_głośności / 100), gdzie poziom_głośności ustawiany jest w zakresie 0-100 i to powinno dawać głośność z zakresu 0-100%. 

Po testach, poziom 100% działa idealnie, a później im niżej tym większe pojawiają się szumy podczas odtwarzania. Przy poziomach poniżej 50% następuje jakieś dziwne wzmocnienie sygnału i mega zaszumienie (gra głośniej niż przy poziomie 100%). Sprawdziłem wartości jakie zapisywane są po dostosowywaniu głośności do odpowiedniego poziomu i sam kod generowany jest prawidłowo. Wydaje mi się, że problem jest bardziej sprzętowy niż programowy stąd pytanie do bardziej doświadczonych w audio, co może być problemem narastających szumów z obniżaniem głośności?

Dodam, że wszystko jest spięte na płytce stykowej i domyślam się, że przy niskich poziomach napięcia stosunek S/N jest na korzyść szumów i pewnie polutowanie wszystkiego na PCB sporo by pomogło, ale chciałbym się upewnić albo ulepszyć swój obwód przed polutowaniem wszystkiego.

 

Link do komentarza
Share on other sites

(edytowany)
10 minut temu, Elvis napisał:

A jakiego typu są te dane, tzn. jaki jest typ zmiennej "wartość_aktualnej_próbki"?

To są zmienne typu double, a później po obliczeniu rzutuje sobie to na uint8_t. Pomyłka jest maksymalnie o 1 bit przy takiej operacji, bo po rzutowaniu liczba jest zaokrąglona o 1 do góry lub w dół. Może to jest problem?

Tutaj daję kod jak to wygląda:

   // buffer_size to długość bufora do którego ładowane są dane do wysłania przez I2S, standardowo 1024 
	
	for(int buffer_position = 0; buffer_position < buffer_size; buffer_position++)
        {
        	double tmp_calc = 0;
        	double CURRENT_VOLUME_RATE = 1; // tutaj równie dobrze może być (wartość_glośności / 100)
        	if(buffer[buffer_position] != 0)
        	{
        		tmp_calc = buffer[buffer_position] * CURRENT_VOLUME_RATE;
        		buffer[buffer_position] = static_cast <uint8_t> (tmp_calc);
        	}

 

Edytowano przez Chev
Link do komentarza
Share on other sites

Problemem raczej nie jest utrata jednego, najmniej znaczącego bitu.

Ale może warto zastanowić się jakie dane odbiera MAX98357A, czy to na pewno są bajty (uint8_t)? Z dokumentacji na szybko:

Cytat

The ICs operate using 16/24/32-bit data for I2S and left-justified modes as well as 16-bit or 32-bit data using TDM mode

O trybie 8-bitowym niewiele można wyczytać. A jeśli masz dane np. 16-bitowe, ale sobie każdy składowy bajt przemnożysz przez dany współczynnik, to niekoniecznie uzyskasz to czego oczekujesz. 

Powstaje też pytanie o znak danych, czy to na pewno uint8_t, albo prędzej uint16_t, czy raczej int16_t?

  • Lubię! 1
Link do komentarza
Share on other sites

Zarejestruj się lub zaloguj, aby ukryć tę reklamę.
Zarejestruj się lub zaloguj, aby ukryć tę reklamę.

jlcpcb.jpg

jlcpcb.jpg

Produkcja i montaż PCB - wybierz sprawdzone PCBWay!
   • Darmowe płytki dla studentów i projektów non-profit
   • Tylko 5$ za 10 prototypów PCB w 24 godziny
   • Usługa projektowania PCB na zlecenie
   • Montaż PCB od 30$ + bezpłatna dostawa i szablony
   • Darmowe narzędzie do podglądu plików Gerber
Zobacz również » Film z fabryki PCBWay

Na pewno bez znaku, bo tak mam eksportowany plik (unsigned int 8 bit). Co prawda wysyłam buffor (uint8_t) z 1024 próbkami przez I2S i dla głośności 100% jest wszystko okej, ale może faktycznie sam wzmacniacz oczekuje danych 16 bitowych, a to że obecnie działa jest przypadkiem i błędem polegającym na zasugerowaniu się typem samego pliku audio.

 

Przepiszę trochę kod i dam znać, bo chyba faktycznie powinienem ładować przez I2S dane typu uint16_t, a nie uint8_t.

Link do komentarza
Share on other sites

Skoro przy "pełnej głośności" dźwięk jest odtwarzany poprawnie, to pewnie I2S działa zgodnie z oczekiwaniami.

Problemem mogą być natomiast obliczenia. Załóżmy, że mamy dwie kolejne, 16-bitowe próbki o wartościach odpowiednio 255 i 256. Różnica między nimi jest niewielka, więc jeśli odtwarzamy je z 50% głośności oczekujemy też niewielkiej różnicy. Ale policzmy:

Dla 255 mamy szesnastkowo 0x00ff (starszy bajt 0, młodszy 0xff). Jak podzielimy 0x00 przez 2 (co daje 50%), mamy 0x00. Dzielenie 0xff przez 2 to jakieś 0x7f. Czyli wynik 0x007f, albo 127 dziesiętnie - wszystko wygląda ok.

Teraz liczymy dla 256. Wartość szesnastkowo 0x0100 (starszy bajt 0x01, młodszy 0x00). Dzielenie 0x01 przez 2 daje 0x00, czyli wynik to 0x0000... 

Program z wartości 255, 256 tworzy 127, 0 - czyli gwałtowną zmianę sygnału, a to już może być słyszalne.

Jeszcze gorzej może być w przypadku liczb ze znakiem - a warto upewnić się, czy aby nie są to dane int16_t. Przykładowo wikipedia coś o tym wspomina: https://en.wikipedia.org/wiki/I²S

  • Lubię! 1
Link do komentarza
Share on other sites

Jakby co, taki standarowy WAVE, jakość CD 44100 Hz to 16 bitów ze znakiem. Dwa bajty lewy, dwa bajty prawy i tak do końca. Poza nagłówkiem i meta danymi oczywiście. Little endian (PS. na Wiki piszą, że I2S MSB first). Może wysyła też, jak mówisz 1024 próbki (to ile bajtów wysyłasz?) i przypadkiem dzieli na pół jedną próbkę. W sumie po co double? Ciekawe rzeczy mogą się dziać. Np, usuwając jeden bajt z utworu, czy coś w tym stylu, wyszła prawie cała piosenka szum, widać po wykresie w Audacity, a końcówka piosenki wyłaniała się przez kilka sekund do postaci praktycznie bez szumu.

Edytowano przez matsobdev
Link do komentarza
Share on other sites

Bądź aktywny - zaloguj się lub utwórz konto!

Tylko zarejestrowani użytkownicy mogą komentować zawartość tej strony

Utwórz konto w ~20 sekund!

Zarejestruj nowe konto, to proste!

Zarejestruj się »

Zaloguj się

Posiadasz własne konto? Użyj go!

Zaloguj się »
×
×
  • Utwórz nowe...

Ważne informacje

Ta strona używa ciasteczek (cookies), dzięki którym może działać lepiej. Więcej na ten temat znajdziesz w Polityce Prywatności.