Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Грамотный AGC для вокодера
Форум разработчиков электроники ELECTRONIX.ru > Цифровая обработка сигналов - ЦОС (DSP) > Алгоритмы ЦОС (DSP)
sigmaN
После разборок с эходавами и прочими неприятностями, решил прикрутить к своей железяке АРУ.
Ибо получается что или ничего не слышно, или дунет ветерок, а динамик аж трищит - на лицо необходимость регулировки.

Собственно, после недолгих раздумий, действовал так:
Определил верхний порог: AGC_MINTHRESHOLD
нижний порог: AGC_MAXTHRESHOLD

На асме зарулил функцию, быстро считающую сумму квадратов переданного ей буфера из 320 отсчётов сигнала
И сам AGC
Код
unsigned long do_agc(int *input, int len){
    //считаем энергию сигнала
    agc_currEnergy=my_sqrsum(input,len);

    if(agc_currEnergy==0)
        return agc_currEnergy; //AGC не требуется - на выход
    if(agc_currEnergy>=AGC_MINTHRESHOLD && agc_currEnergy<=AGC_MAXTHRESHOLD)
        return agc_currEnergy; //AGC не требуется
    else
    if(agc_currEnergy<AGC_MINTHRESHOLD){ //надо бы усилить
        agc_multiplier=sqrt((double)AGC_MINTHRESHOLD/(double)agc_currEnergy);
    }
    else
    if(agc_currEnergy>AGC_MAXTHRESHOLD){//придётся сделать немного потише :)
        agc_multiplier=sqrt((double)AGC_MAXTHRESHOLD/(double)agc_currEnergy);
    }
    
//а теперь подправим сигнал
    while(len--)
        *input++=(int)((double)*input * agc_multiplier);
    
    return agc_currEnergy;
}


От нижнего порога в итоге пришлось отказаться, т.к. регулировка чувствительности микрофона "железными" средствами аудиокодека вроде позволяет добиться неплохой чувствительности.
Верхний тоже вроде режет лишку и с диким теском, от того, что ты подул в микрофон вроде покончено.

Но в целом мне не нравится работа АРУ. Оно то и понятно, ведь то, что я сделал - достаточно тривиально.
Погуглить пробовал, но не так усердно, как мог бы.

Вот прошу пару подсказок.
Также, подозреваю, что и вокодер работал бы эффективнее и качественнее, при наличии грамотно спроектированного и настроенного AGC.

Традиционно, с громоздким и прожорливым Speex препроцессором связываться не хотелось-бы.
Беглого взгляда на функцию, реализующую AGC в speex хватило, чтобы понять, что там наворочено много всего и половина из этого мне не нужна.

Да и заодно практика будет.

В общем покритикуйте мою реализацию плиз. И дайте совет как бы завернуть так, чтобы и голос был loud and clear и в момент громких всплесков было всё хорошо. Ну а я пока параллельно буду гуглить и напрягать CPU:)
des00
Цитата(sigmaN @ Sep 6 2009, 18:48) *
Да и заодно практика будет.


думаю что скажу чушь, т.к. именно со звуком не работал. Но при приеме радиосигналов я делаю ару по средней мощности с учетом запаса на пик-фактор сигнала и использую ПИ-звено регулирования. Использования П звена для быстро изменяющихся сигналов ИМХО не верно.
uriy
Вот хотели тоже использовать. В результате кроме ухудшения разборчивости ничего хорошего не получили. Вы сравните две ваши железки на разборчивость речи с АРУ и без АРУ. Для проверки привлеките стороннего человека, пусть он слушает на приеме, а вы читайте какой-нибудь текст на совершенно отвлеченную тему на передающей стороне. Именно текст, а не отсчет один, два, три, четыре... Есть кодеки со встроенным аналоговым АРУ я взял SSM2603 от AD правда до программы дело не дошло, я больше железячник. Плата пока так и лежит без дела.
litv
АРУ - вычисляем мощность, ставим ФНЧ на нее с полосой 50 Гц , корректируем сигнал по мощности раз ,применяем примерно раз 0.1 секунды.
thermit
http://www.rane.com/note155.html
DRUID3
Цитата(sigmaN @ Sep 7 2009, 02:48) *
Код
unsigned long do_agc(int *input, int len){
    //считаем энергию сигнала
    agc_currEnergy=my_sqrsum(input,len);

Считать нужно скользящим средним, а не для буфера. Иначе это будет не АРУ а "бла-бла-бла" по звучанию...

Цитата(sigmaN @ Sep 7 2009, 02:48) *
Код
    if(agc_currEnergy==0)
        return agc_currEnergy; //AGC не требуется - на выход

Бесполезнйший участок кода отбирающий ресурсы, и компилятор никогда не догадается, что условие заведомо не выполнимое.

Цитата(sigmaN @ Sep 7 2009, 02:48) *
Код
    if(agc_currEnergy>=AGC_MINTHRESHOLD && agc_currEnergy<=AGC_MAXTHRESHOLD)
        return agc_currEnergy; //AGC не требуется

Жжоте! А я думал у АРУ постоянно действующая петля...

Цитата(sigmaN @ Sep 7 2009, 02:48) *
Код
    else
    if(agc_currEnergy<AGC_MINTHRESHOLD){ //надо бы усилить
        agc_multiplier=sqrt((double)AGC_MINTHRESHOLD/(double)agc_currEnergy);
    }

Жесть!

Цитата(sigmaN @ Sep 7 2009, 02:48) *
Код
    else
    if(agc_currEnergy>AGC_MAXTHRESHOLD){//придётся сделать немного потише :)
        agc_multiplier=sqrt((double)AGC_MAXTHRESHOLD/(double)agc_currEnergy);
    }

...и получается у нас ограничитель, и ни разу не АРУ smile.gif . Где сокрыта постоянная времени?

На CQHAM я приводил код АРУ в моем ее понимании smile.gif . Вобщем она мало чем отличается от аналогового прототипа по сути и от рекомендаций Лайонса так же.
Рабочий код остался у меня на работе которую я покинул 3 года назад, но кое что я "тянул домой", подождите немного я гляну есть ли код.

Работает обычная АРУ так - скользящий измеритель мощности на периоде(в аналоговой технике обычный АМ-детектор) через время задерживающую цепочку (а иначе прощайте слабые звуки, в "аналоге" это RC-цепочка в простейшем случае) управляет через линейный элемент ("аналог" - полевой транзистор без питания - т.е. как управляемое сопротивление - включенный как аттенюатор по схеме обычного делителя напряжения или в цепь ОС) управляет масштабом напряжения сигнала("веса" сэмплов для ЦОС).

Чего у Вас нет - времени срабатывания/отпускания. А это принципиально отличие АРУ от банального ограничителя. Вот с таким кодом как у Вас звук будет похож на работу жесткого (причем нелинейного biggrin.gif ) клипера для армейской SSB станции, можно продать код в студию спецэффектов wink.gif .

Далее - очень важна сама форма функции срабатывания/нарастания - Лайонс рекомендует простейший случай - экспоненту(переходной процесс в "аналоговом" RC-звене) - но в серьезной аппаратуре(как аудио, так и связной - от армейской до кол-центров) она обычно сложнее, и лучше всего если ее может задавать пользователь...

Цитата(litv @ Sep 7 2009, 08:45) *
АРУ - вычисляем мощность, ставим ФНЧ на нее с полосой 50 Гц , корректируем сигнал по мощности раз ,применяем примерно раз 0.1 секунды.

Не совсем понял, но если имеется ввиду коррекция применительно к буферам, то это не верно. АРУ работает непрерывно, обновляясь с частотой дискретизации. ФНЧ тоже не совсем то, фильтр низких частот имеет отклик по природе близкий интегратору, но ФНЧ - не интегратор. Попытка сделать хороший ФНЧ отдалит нас еще больше от искомой цели - получим много ненужных пульсаций в переходном процессе.

Цитата(des00 @ Sep 7 2009, 06:01) *
думаю что скажу чушь, т.к. именно со звуком не работал. Но при приеме радиосигналов я делаю ару по средней мощности с учетом запаса на пик-фактор сигнала и использую ПИ-звено регулирования. Использования П звена для быстро изменяющихся сигналов ИМХО не верно.

ПИ - это пропорционально интегрирующее?
А просто П - это пропорциональное?

Тогда Вы конечно же правы! Все верно!

P.S.: Еще добавлю, что если перемудрить с функцией обратной связи и на ней появится участок на котором прирост реакции обратен по знаку приросту воздействия - получится неплохой релаксационный генератор biggrin.gif , как на тунельном диоде...
Z0Rk
Цитата(DRUID3 @ Sep 7 2009, 15:15) *
ФНЧ тоже не совсем то, фильтр низких частот имеет отклик по природе близкий интегратору, но ФНЧ - не интегратор. Попытка сделать хороший ФНЧ отдалит нас еще больше от искомой цели - получим много ненужных пульсаций в переходном процессе.

как же не ФНЧ то? просто за прямоугольностью не надо гнаться, фильтр должен быть достаточно коротким. Кроме того скажу банальность, без пульсаций систем обратной связи не бывает.
sigmaN
Ну по-моему мне какраз ограничитель и нужен по сути....только вот лепил я его не туда. Надо на выход, а я на вход smile.gif)
И мои негодования какраз и связаны с тем, что вокодеры плохо дружат с "клипированным" сигналом, а мой код какраз таки и подрезает сигнал(другим фокусам не обучен).
dch
Цитата(DRUID3 @ Sep 7 2009, 15:15) *
Жжоте! А я думал у АРУ постоянно действующая петля...

тут наверное идет речь не о ару , а какой то нормализации входного сигнала , как этот термин в цифровой обработке называется?
uriy
Цитата
только вот лепил я его не туда. Надо на выход, а я на вход
В смысле вы что хотите цифровой модемный сигнал зарезать? Вы его так только испортите и приемник его не сможет декодировать.
fontp
Цитата(uriy @ Sep 8 2009, 07:52) *
В смысле вы что хотите цифровой модемный сигнал зарезать? Вы его так только испортите и приемник его не сможет декодировать.


Он хочет зарезать речь.
И простейший способ сделать это - посмотреть как это делается в звуковой аналоговой аппаратуре и сделать также.
Там пиковый детектор (или квадратичный с малым временем интегрирования) с минимальным временем срабатывания (для быстрой атаки) и схема отпускания с большой постоянной времени 0.5-2 сек. Диод и включеные с ним последовательно, между собой в параллель конденсатор и резистор.
G = max (P, 0.9999*G + 0.0001*P), P уровень сигнала - abs(X) в простейшем случае. Вот эта величина управляет усилением обратнопропорциональным образом.
Можно, конечно, изучить теорию AGC и построить более грамотное АРУ по науке - логарифмический AGC с петлевым фильтром.
А можно ничего не учить и сделать так как сделано во всех японских магнитофончиках по аналогии ))
Alex11
У нас в аппаратуре записи речи сделано так (и работает это очень прилично): считается средний квадрат отсчетов по буферу, затем сравнивается с двумя порогами - если выше верхнего, то множитель для сигнала домножается на коэффициент К1 > 1, если ниже нижнего, то домножается на коэффициент K2 < 1, если между порогами - множитель не изменяется. Время реакции определяется длиной буфера и значениями коэффициентов. При этом лучше сделать так, чтобы реакция на большой сигнал была более быстрой, а на маленький - медленнее. Для речи длину буфера нужно делать не меньше, чем на 50 мс, а лучше на 100.
thermit
Ну, вот пример ограничителя уровня речевого сигнала.
Цитата
clear all;

L=-12;%dB
thr=10^(L/20);

mem=0;
x=sin(2*pi*0.00125*(0:9999)).*(rand(1,10000)-0.5)*2;

ba=0.52712919549841;
br=0.000935728268489977;


y=[];
for i=1:length(x)
t=abs(x(i));
if(t>mem)
mem=mem+(t-mem)*ba;%attack
else
mem=mem+(t-mem)*br;%release
end;
t=mem;%*0.5*pi;
if(t>thr)
k=thr/t;
else
k=1;
end;
y=[y k*x(i)];
end;

plot(x);
hold on;
plot(y,'g');
Z0Rk
Вообщем все что надо для начала построения цифрового АРУ описано здесь
http://www.mstu.ru/forum/index.php/topic,5...9.html#msg92419
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.