Automatyczna regulacja wzmocnienia dźwięku: implementacja AGC dla systemów embedded
Algorytm AGC (Automatic Gain Control) normalizuje poziom sygnału w czasie rzeczywistym, eliminując potrzebę ręcznej regulacji. W systemach komunikacyjnych na Linuksie z ALSA rozwiązuje to problem nierównej głośności z różnych źródeł. Implementacja jest zoptymalizowana pod format S16_LE, 8000 Hz, mono, z opóźnieniem do 500 ms i obciążeniem CPU poniżej 3%.
Cel — przetwarzanie krótkich transmisji głosowych bez uśredniania całego pliku. Testy obejmują kryteria subiektywne (rozumialność mowy) i obiektywne (redukcja zakresu dynamicznego).
Analiza gotowych rozwiązań: AI i wtyczki
Model Nvidia studiovoice normalizuje głośność i tłumi szumy, ale wymaga resamplingu z 48 kHz do 8 kHz, co zwiększa opóźnienie. Lokalne użycie jest niemożliwe z powodu zależności.
Wtyczka ALSA speex (oparta na speexdsp) aktywowana parametrami agc on i agc_level (1–32768). Konfiguracja w /etc/asound.conf:
pcm.agc_pcm {
type speex
agc on
agc_level 23400
slave.pcm "dev_out"
}
pcm.test_agc {
type plug
slave.pcm agc_pcm
}
Test: arecord -D dev_in | aplay -D test_agc. Problemy: początkowe tłumienie, efekt „trzasków” z powodu underrun, niedokumentowane frames i filter_length. Rozwiązanie — rezygnacja.
FFmpeg dynaudnorm: analiza algorytmu
Filtr dynaudnorm idealnie pasuje: ffmpeg -f alsa -i dev_in -filter:a "dynaudnorm=f=20:g=33:m=100:c=1" output.wav.
Parametry:
f=20— ramka 20 ms dla krótkich transmisji;g=33— wygładzanie gaussowskie (równowaga opóźnienia i płynności);m=100— maks. wzmocnienie (powiązane z poziomem głośności);c=1— korekcja DC (usuwa przesunięcia od zakłóceń).
Algorytm:
- Wejściowa ramka o rozmiarze F;
- Korekcja DC;
- Wyszukiwanie szczytu;
- Obliczenie współczynnika wzmocnienia;
- Filtr Gaussa do wygładzania;
- Wzmocnienie i wyjście.
Filtr nie tłumi szumów. Alternatywy: afftdn, anlmdn, arnndn w FFmpeg lub ALSA rnnoise na RNN.
Własna implementacja w C++20
Prototyp w Python/Jupyter symuluje przetwarzanie w czasie rzeczywistym: obsługa buforów po 20 ms bez ładowania całego pliku. Oscylogramy potwierdzają kompresję zakresu dynamicznego.
Rezultat: C++20, klasy AutomaticGainControl i GaussianFilter. Struktura projektu:
libagc— statyczna biblioteka;agc_pipe— narzędzie do potoku;- Wtyczka ALSA
libasound_module_pcm_agc.so.
Opcje agc_pipe:
Allowed options:
-h [ --help ] Print help
-m [ --msec ] arg (=20) Frame length in msec
-c [ --channel ] arg (=1) Channels to filter
-r [ --rate ] arg (=8000) Sample rate
-f [ --filter ] arg (=13) Gaussian filter size
-p [ --peak ] arg (=0.950000) Max peak value
-g [ --gain ] arg (=100) Max gain value
-v [ --verbose ] Enable verbose logs
Test: arecord -D <input> -f S16_LE -t raw | ./agc_pipe -f 7 -g 99 | aplay -D <output> -f S16_LE -t raw.
Wydajność: +3% CPU przy jednym źródle, opóźnienie ~400 ms (FrameLenMs=20, FilterSize=13). Używa std::span dla bezpieczeństwa.
Co jest najważniejsze
- AGC zmniejsza zakres dynamiczny bez utraty zrozumiałości mowy;
- Korekcja DC jest niezbędna do eliminacji artefaktów sprzętowych;
- Filtr Gaussa zapewnia płynne przejścia, minimalizując przeciążenia;
- Implementacja w C++20 z programowaniem obiektowym przewyższa FFmpeg pod względem utrzymania i rozszerzalności;
- Nadaje się do embedded VoIP: niskie obciążenie, małe opóźnienia.
— Editorial Team
Brak komentarzy.