Автор Тема: Цифровая АРУ 0...1  (Прочитано 32659 раз)

0 Пользователей и 3 Гостей просматривают эту тему.

Оффлайн ra0ahc

  • Hero Member
  • *****
  • Сообщений: 4872
  • Сергей, RD6AH
Re: Цифровая АРУ 0...1
« Ответ #225 : Декабрь 04, 2020, 11:43:07 pm »
А вот тот же тест, но ворота 0. Алгоритм пытается сделать плоский эфир
Да да, я знаю, у меня ничего не получится )))

Оффлайн ra0ahc

  • Hero Member
  • *****
  • Сообщений: 4872
  • Сергей, RD6AH
Re: Цифровая АРУ 0...1
« Ответ #226 : Декабрь 04, 2020, 11:46:52 pm »
Вот 80 с web sdr
Ну что-то сильно хорошо получилось.
(ворота 0дб)
Да да, я знаю, у меня ничего не получится )))

Оффлайн 6Ж2П

  • Hero Member
  • *****
  • Сообщений: 507
Re: Цифровая АРУ 0...1
« Ответ #227 : Декабрь 05, 2020, 08:50:29 am »
Я не очень пойму, что хорошего, когда верхняя граница ровная как стол?

Оффлайн ra0ahc

  • Hero Member
  • *****
  • Сообщений: 4872
  • Сергей, RD6AH
Re: Цифровая АРУ 0...1
« Ответ #228 : Декабрь 05, 2020, 08:54:11 am »
Я не очень пойму, что хорошего, когда верхняя граница ровная как стол?
Это значит, что вылетов за пределы нету. Само ару работает ниже. Сегодня записи сделаю.
Кстати там есть задержка отпускания и плавный подъем усиления - все как и планировалось и все регулируется.
Понятие «Ворота» это как раз и есть промежуток в дБ который убирает плоскость эфира . Громкие будут слегка громче тихих.
« Последнее редактирование: Декабрь 05, 2020, 08:57:03 am от ra0ahc »
Да да, я знаю, у меня ничего не получится )))

Оффлайн 6Ж2П

  • Hero Member
  • *****
  • Сообщений: 507
Re: Цифровая АРУ 0...1
« Ответ #229 : Декабрь 05, 2020, 09:14:13 am »
Так что в итоге получиться должно, по задумкам? А то уже кажется, что это будет ровно та же аналоговая АРУ, только данные для управления извлекаются из цифрового потока, цифрой же и обрабатываются.

Оффлайн ra0ahc

  • Hero Member
  • *****
  • Сообщений: 4872
  • Сергей, RD6AH
Re: Цифровая АРУ 0...1
« Ответ #230 : Декабрь 05, 2020, 09:57:01 am »
 Новая АРУ
(вариант 4)
 lol22

float32_t max = 0.49905586f; //максималка 0.49975586fот -0.5 до +0.5 примерно для 12 бит
uint16_t count = 100;
uint8_t stopGoingUp = 0;

float32_t rmsFrame = 0;
uint16_t uOldPikIdx;
float32_t uOldPikV;
uint16_t wait = 20;
float32_t rate = 24000.0f;

///@brief АРУ
///@param buffer
void agcDo(float32_t *buffer) {
    float32_t rmsPik = 0;
    float32_t agcMetrTemp = 0;
    float32_t pit1 = -1;
    float32_t pit2 = 0;
    uint8_t wasVariant = 0;
    uint16_t pikCount = 0;
    if (tim > 0)tim--; //уменьшение задержки
    stopGoingUp = 0;

    for (uint16_t i = 0; i < FRAME_SIZE; i++) {
        float32_t a;
        //a = (buffer[i] < 0.0f) ? -1.0f * buffer[i] : buffer[i];// adc V
        a = fabsf(buffer[i]);
        // seach min
        if (a > 0)nowAgc = max / a;
        else nowAgc = max / 0.000005f;


        uint16_t upIdx = i;
        uint16_t upIdxNow;

        float32_t pikBuf;
        uint8_t exit = 1;
        uint8_t exitYN = 0;
        uint16_t wait = 2;// 1msec

        uint16_t uPikIxxPlus = 0;
        uint16_t uPikIxxMinus = 0;
        float32_t uPikVPlus = 0; //V + pik
        float32_t uPikVMinus = 0;//V - pik
        //direction
        int direction = 1;//напрвление вниз (отрицательная синусоида)
        if (i + 1 < FRAME_SIZE) {
            if (buffer[i] <= 0 || buffer[i + 1] < 0) direction = 0;//напрвление вверх (положительная синусоида)
        } else {
            if (buffer[i] <= 0 || buffer[i - 1] > 0) direction = 0;//напрвление вверх (положительная синусоида)
        }
        while (exit) { //поиск пика в блоке от 0 до 0
            exit = 0;//выходим
            float32_t p1 = fabsf(buffer[upIdx]);//feature
            if (direction) {//+++++++++++++++++++++++++++++
                //если условие остановило в ++ то добиваем его до 0
                if ((buffer[upIdx] > 0 && !exitYN)) {
                    if (p1 > uPikVPlus) {
                        uPikVPlus = p1;
                        uPikIxxPlus = upIdx;
                    }
                    if (upIdx + 1 < FRAME_SIZE) {
                        upIdx++;
                        exit = 1;//не выходим
                    }
                }
                //если условие остановило в -- то добиваем его до 0 и выходим
                if ((buffer[upIdx] < 0)) {
                    exitYN = 1; //не дадим пред условию сработать
                    if (p1 >= uPikVMinus) {
                        uPikVMinus = p1;
                        uPikIxxMinus = upIdx;

                    }
                    if (upIdx + 1 < FRAME_SIZE) {
                        upIdx++;//
                        exit = 1;//не выходим
                    }
                }

            } else { //------------------------
                //going up
                //если условие остановило в -- то добиваем его до 0 и выходим
                if ((buffer[upIdx] <= 0 && !exitYN)) {
                    if (p1 > uPikVMinus) {
                        uPikVMinus = p1;
                        uPikIxxMinus = upIdx;
                    }
                    if (upIdx + 1 < FRAME_SIZE) {
                        upIdx++;
                        exit = 1;//не выходим
                    }
                }
                //если условие остановило в ++ то добиваем его до 0
                if ((buffer[upIdx] > 0)) {//
                    exitYN = 1; //не дадим пред условию сработать
                    if (p1 > uPikVPlus) {
                        uPikVPlus = p1;
                        uPikIxxPlus = upIdx;
                    }
                    if (upIdx + 1 < FRAME_SIZE) {
                        upIdx++;//
                        exit = 1;//не выходим
                    }
                }
            }

        }//while

        if (upIdx > i + 1) { //если блок не пустой то...

            upIdx -= 1;
            float32_t locNowAgc;


            if (uPikVPlus > uPikVMinus) {
                locNowAgc = max / (uPikVPlus);
                pikBuf = uPikVPlus;
            } else {
                locNowAgc = max / (uPikVMinus + 0.000001f);
                pikBuf = uPikVMinus;
            }

            //типа среднее значение этого блока. исползуется для отката .
            rmsPik += (uPikVPlus + uPikVMinus) / 2.0f;
            pikCount++;//количество синусоид, нужен для расчета среднего пика по блоку
            //agcLevel == текущий уровень ару
            if (locNowAgc <= agcLevel) { // всплеск или питч V, идем вниз || wasVariant..........................
                stopGoingUp = 0;
                //заполним блок
                //               if (i > 0) {

                for (uint16_t z = i; z <= upIdx; z++) {
                    buffer[z] *= locNowAgc;
                }


//                } else {//механизм сочленения с пред фреймом ...ждем первого нуля
//                    exit = 1;
//                    uint16_t idx0 = 0;
//                    while (exit) {
//                        exit = 0;//выходим
//                        if (direction) {//+++++++++++++++++++++++++++++
//                            if (buffer[idx0] > 0 && idx0 < upIdx) {
//                                idx0++;
//                                exit = 1;//не выходим
//                            }
//                        } else { //------------------------
//                            //going up
//                            if (buffer[idx0] <= 0 && idx0 < upIdx) {
//                                idx0++;
//                                exit = 1;//не выходим
//                            }
//                        }
//                    }//while
//                    for (uint16_t z = 0; z <= upIdx; z++) {
//                        //if (z <= idx0)
////                            buffer[z] *= agcLevel +
////                                         (locNowAgc - agcLevel) / (idx0 - z + 1);//применить старый коэфф
//                            if (z < idx0)
//                                buffer[z] *= agcLevel;//применить старый коэфф agcLevel
//                            else
//                                buffer[z] *= locNowAgc;//применить новый коэфф
//                    }
//                }

                //откат усиления назад по блоку
                //убират стук
                uint16_t d = 0;
                uint16_t dmax = (i - 500 >= 0 ? 500 : i);
                while (d < dmax && i - d > 0) {
                    float32_t dx = locNowAgc / agcLevel;
                    d++;
                    buffer[i - d] *= dx + d * (1 - dx) / dmax;
                }

                //питч детектор
                stopGoingUp = 0;
                //tim = wait;//задежка отпускания
                if ((pit2 < pit1 && pit1 < pikBuf)) {//не питч
                    agcLevel = locNowAgc;
                } else if ((pit2 < pit1 && pit1 > pikBuf)) {//питч
                    agcLevel -= (agcLevel - locNowAgc) / 4;
                } else {
                    agcLevel -= (agcLevel - locNowAgc) / 2;
                }
                tim = wait;
                //  agcLevel = locNowAgc;
                pit2 = pit1;
                pit1 = pikBuf;

            } else {//идем вверх/////////////////////////////////////////////////////////////////////
                float32_t cc;
                float32_t sred = agcLevel / locNowAgc;
                float32_t rmsNow = (rmsFrame + rmsPik / pikCount) / 2.0f;

                if (tim == 0) {//подождали и начинаем
                    cc = agcLevel + (sred / rmsNow) / 1000;
                    //проверим можем нет еще откатить
                    if (pikBuf * cc < max - 0.0f
                        && !stopGoingUp
                            ) {//дельта отката 0.4
                        agcLevel = cc;
                    } else {
                        stopGoingUp = 1; //остановить откат
                    }
                }
                //заполним период
                for (uint16_t z = i; z <= upIdx; z++) {
                    buffer[z] *= agcLevel;//применить новый коэфф
                }
            }
            i = upIdx; // след цикл будет стратовать от upIdx

        } else { //это сетуация редкая но тоже надо . сделано по класике одного замера
            stopGoingUp = 0;
            if (nowAgc < agcLevel) { // всплеск V
                agcLevel = nowAgc;
                tim = wait;//задежка отпускания
            }
//            float32_t f = a * agcLevel;
            //контроль вылета в out
//            if (f > max) {//out
//                if (buffer[i] >= 0) buffer[i] = max;//max
//                else buffer[i] = -max;//max
//                // agcLevel = 1;
//            } else
            buffer[i] *= agcLevel;

        }

        if (a > agcMetrTemp) agcMetrTemp = a; //s-meter макс V
    }//for

    //средний V за этот блок и прошлые (отсчет по пикам)
    //нужен для ограничения усиления при снятия сигнала
    float32_t mm = rmsPik / pikCount;

    if (mm > rmsFrame)rmsFrame = mm;
    else rmsFrame = (rmsFrame + mm) / 2.0f;

    agcMetr = agcMetrTemp; //s-meter
}
Да да, я знаю, у меня ничего не получится )))

Оффлайн ra0ahc

  • Hero Member
  • *****
  • Сообщений: 4872
  • Сергей, RD6AH
Re: Цифровая АРУ 0...1
« Ответ #231 : Декабрь 05, 2020, 10:00:11 am »
Так что в итоге получиться должно, по задумкам? А то уже кажется, что это будет ровно та же аналоговая АРУ, только данные для управления извлекаются из цифрового потока, цифрой же и обрабатываются.

В идеале не должны хвосты разлива спектра быть. Вот сейчас их видно но не слышно.
(на спектре 3кГц и выше голубые полоски. Это как раз и есть разлив спектра)

И кстати, аналоговое ару никогда не будет такой ровной. Всегда будет присутствовать первый выброс в несколько дб (чем меньше вылет - тем лучше). А в цифре можно сделать абсолютно ровное все. Пример: при аналоге морзянка будет подстукивать при первом включении.

http://analogtrx.com/SMF/index.php?topic=100.msg5857#msg5857

это приме моего ару в аналоге. Тест примерно похож на то , что показал с свип амплитудой
« Последнее редактирование: Декабрь 05, 2020, 10:08:02 am от ra0ahc »
Да да, я знаю, у меня ничего не получится )))

Оффлайн 6Ж2П

  • Hero Member
  • *****
  • Сообщений: 507
Re: Цифровая АРУ 0...1
« Ответ #232 : Декабрь 05, 2020, 05:43:44 pm »
В идеале не должны хвосты разлива спектра быть
В аналоговом режиме расширение спектра можно посчитать сразу по Фурье, перемножив две временные функции - сигнала и Ку(t) тракта под действием АРУ, затем посчитав интеграл Фурье для полученной функции. Рассматривая в частотной области, произведение двух функций во временной области есть свёртка в частотной. Из второго очевидно, что спектр расширится на величину, равную  максимальной частоте в спектре функции сигнала Ку(t). Понятно, что при оценке ширины спектра мы должны задавать некую нижнюю границу для амплитуды плотности спектральных составляющих, ниже которой считаем, что составляющих нет. При работе аналоговой АРУ максимальные компоненты в спектре Ку(t) появляются при резком её изменении, что происходит при появлении мощного сигнала. Учитывая, что всегда есть определённая задержка между сигналом и управлением, получаем, что пик спектральных составляющих функции Ку(t) попадает как раз на время, когда сигнал тоже практически максимального уровня, ограниченного только линейностью тракта или принудительно лимитером. Вот тут и возникает всплеск расширения спектра. Если сигнал управления действовал бы ещё до появления мощного сигнала, то он промодулировал бы сигнал обычного уровня или ещё меньшего, в случае прослушивания шума (мы же не выводим шум на уровень нормальной громкости).

ПС Хвосты есть и будут всегда, вопрос в их уровне.
« Последнее редактирование: Декабрь 05, 2020, 05:48:30 pm от 6Ж2П »

Оффлайн ra0ahc

  • Hero Member
  • *****
  • Сообщений: 4872
  • Сергей, RD6AH
Re: Цифровая АРУ 0...1
« Ответ #233 : Декабрь 05, 2020, 06:07:49 pm »
вот "эта" щербинка разливает спектр и ее слышно
Да да, я знаю, у меня ничего не получится )))

Оффлайн ra0ahc

  • Hero Member
  • *****
  • Сообщений: 4872
  • Сергей, RD6AH
Re: Цифровая АРУ 0...1
« Ответ #234 : Декабрь 05, 2020, 06:09:25 pm »
Понятно, что при оценке ширины спектра мы должны задавать некую нижнюю границу для амплитуды плотности спектральных составляющих, ниже которой считаем, что составляющих нет.
Мы ее слышать не должны. Это всего лишь недоработки алгоритма. Надо копать.
Да да, я знаю, у меня ничего не получится )))

Оффлайн 6Ж2П

  • Hero Member
  • *****
  • Сообщений: 507
Re: Цифровая АРУ 0...1
« Ответ #235 : Декабрь 05, 2020, 07:16:45 pm »
А объективно, в цифрах, сколько это?
Вы сейчас проверяете на реальном сигнале? Это окончательная проверка должна быть. Входной сигнал ведь можно сгенерировать программно, обработать, просмотреть спектр, временную характеристику. Для всего этого вообще ничего не надо, кроме компьютера.

У Вас там три точки, где уширение спектра, две очень существенные. На осциллограмме видно только одно место, где первая производная испытывает разрыв. Спектр в большем интервале времени показан?
« Последнее редактирование: Декабрь 05, 2020, 07:22:04 pm от 6Ж2П »

Оффлайн ra0ahc

  • Hero Member
  • *****
  • Сообщений: 4872
  • Сергей, RD6AH
Re: Цифровая АРУ 0...1
« Ответ #236 : Декабрь 05, 2020, 07:26:55 pm »
Я беру сигнал без ару с тульского сдр. Он полностью оцифрован и там разливов нет.

Походу как я не бегал от стыковки фрэймов никуда от нее не деться. Вот на фото не с того появляется козявка. По алгоритму: он вообще не должен в этом месте что-то править, однако правит. Вариант один...это 2 периода с обеих сторон фрейма (с начала и с конца). 
Да да, я знаю, у меня ничего не получится )))

Оффлайн 6Ж2П

  • Hero Member
  • *****
  • Сообщений: 507
Re: Цифровая АРУ 0...1
« Ответ #237 : Декабрь 05, 2020, 07:32:52 pm »
по виду, там сшивка прямым отрезком.
Цитировать
Стандарт натуральной цифровой записи звука обозначается, как РСМ (Pulse Code Modulation) Wave. В процессе записи через определенные промежутки времени регистрируется текущая амплитуда звуковой волны, в результате чего получаются как бы моментальные снимки (фреймы) звуковой волны. Из последовательности этих фреймов и состоит звукозапись, носящая название waveform.
Здесь фрейм, это просто амплитуда в моменты дискретизации, у Вас фрейм, это что?
« Последнее редактирование: Декабрь 05, 2020, 07:35:56 pm от 6Ж2П »

Оффлайн ra0ahc

  • Hero Member
  • *****
  • Сообщений: 4872
  • Сергей, RD6AH
Re: Цифровая АРУ 0...1
« Ответ #238 : Декабрь 05, 2020, 07:37:15 pm »
Сшивок больше нет. Прохожусь плавным коэффициентом  Х....1 назад . Я последний (первый по очереди) вообще на 1 умножаю.

Фрэйм 1024 ацп замеров
Да да, я знаю, у меня ничего не получится )))

Оффлайн 6Ж2П

  • Hero Member
  • *****
  • Сообщений: 507
Re: Цифровая АРУ 0...1
« Ответ #239 : Декабрь 05, 2020, 08:12:24 pm »
Я так и подумал, что у Вас фрейм это набор отсчётов.
Я про сшивку не в алгоритме, а смотря на кривую сигнала. Там очевидная вставка прямого отрезка.