Игорь 2
Трансиверы, передатчики, РПУ => Software Defined Radio (SDR) => Тема начата: ra0ahc от Октябрь 10, 2020, 04:11:30 pm
-
Начал поползновения с цифровой АРУ.
Пока столкнулся с некоторым не пониманием. Значения амплитуду логарифмическое и пока я ключик подобрать не могу, выскакивает за границы.
-
Вот пока , что удалось. На входе то есть то нет синус с шумом.
-
Вот этот провал это момент появления сигнала, при этом ару улетает в 0. Долго думал почему так. Амплитуда взлетает во всем спектре. Но у меня после ару стоит еще один фир фильтр на 3кгц поэтому скачок только в спектре 3 кгц.
-
без шума вот так выглядит
-
Немного изменил расчет дельты возврата.
-
Красный трек - это то, что Вы в сильносигналку пускаете? cr123
-
это с динамика нч
-
Поподробней, я ничего не понял... dontt44
-
это симуляция работы ару.
синус генерится бесконечный, а дальше как бы попадает в дсп . я его подхватываю и обрабатываю, фир , ару и еще один фир.
дальше уже обработанный сигнал идет на цап где я его программой и смотрю и наушниками слушаю.
ну и синус то есть то нет через 1 сек период.
вот я и разглядываю как ведет себя цифровое ару
-
Возьмите готовую реализацию из того же поверсдр например или еще откуда-то. Нафига лисапед изобретать?
-
Так всё-таки, на красном-то что за картинка? cr123
-
Возьмите готовую реализацию из того же поверсдр например или еще откуда-то. Нафига лисапед изобретать?
Не интересно так.
Так всё-таки, на красном-то что за картинка? cr123
Да это лог осцил. Реакция ару на подачу и на снятия.
-
А, вон оно что... lllol
-
Ну пока тупик. Пропуск с 0 уровнем одного блока пролетает, при переходе 0->1 (слабый сигнала - сильный сигнал)
-
Одну часть победил.
Теперь плавно без ступенек.
-
Теперь плавно без ступенек.
Перепад уровней на входе те же 40 дБ? cr123
Кстати, не помню уже, как название поправлять, но АРУ всё-таки, цифровАя... dontt44
-
Перепад уровней на входе те же 40 дБ?
Често, не знаю. Амплитуды от балды поставил.
-
1yep
-
но АРУ всё-таки, цифровАя.
вот вот , настоящая женщина!
(завтра поправлю)
-
Пока застрял. Походу надо математику пересчитывать.
-
Проблема получается в том, что в одном фрейме может быть сигнал как низкого уровня так и большого уровня. Изменение амплитуды происходит скачкообразно. И если сильный сигнал приходится к концы фрейма, то расчет общей амплитуды приводит к тому, что часть с низким уровнем сигнала провалится и образует провал и сильный стук в наушниках . И все это будет внизу пока не дойдет очередь до сильного сигнала в этом фрейме. Вот и получается, что надо ару считать внутри фрэйма. И это усложняет все расчеты.
Вот пока так я научился обрабатывать этот скачок внутри фрэйма. Длина фрэйма 22мСек
-
Линейное снижение амплитуды не катит no88. Нужно что-то другое. Именно линейное снижение амплитуды дает такой эффект, сперва провал потом скачок. Нужен другой закон например экспонента.
-
А забыть про фреймы и каждую квадратуру обсчитывать исходя из состояния заряда воображаемых конденсаторв?
-
А забыть про фреймы и каждую квадратуру обсчитывать исходя из состояния заряда воображаемых конденсаторв?
"кондеры" тоже надо заряжать и разрежать и если обнаружена квадратура с высоким сигналом то нужно как то плавно к ней готовится и как-то плавно зарядить кондер. Иначе будет стук-стук. Я понимаю, что в природе нет моментальных сигналов и они как-то нарастают и как-то плавно спадают , и все же надо чтобы было плавно. Вообщем то можно и забить, но есть возможность с импульсной помехой побороться.
-
Да... со стук стук я поборолся доп фильтром за детектором
-
https://youtu.be/hNtaXETcAjQ
Кстати вот запись работы...
-
Я тоже сделал фильтр за детектором.
Ну вот так если каждый замер обслуживать, а не фрейм
-
https://youtu.be/hNtaXETcAjQ
Кстати вот запись работы...
Я так понял - это новый на 157?
-
Да. Это он. Но тут вроде ничего из особенностей не используется кроме fft 1024. А что за выброс на графике Снимок экрана 2020-10-11 в 14.13.12.png?
-
Вот на суд, что получилось
Здесь переменная амплитуда и переменное время смены амплитуды
https://drive.google.com/file/d/16t-HwrUr-_jusRCDANxMCG1j21P4E_Hn/view?usp=sharing
-
А что за выброс на графике Снимок экрана 2020-10-11 в 14.13.12.png?
Да там что угодно может быть. Синус рисуется идеальный и после ару фазы не совпали (на много не совпали) и получатся ступенька. А ее собаку уже ничем не убрать.
Фильтр после ару на 3 кгц - работает.
ару вот
float32_t a;
if (tim > 0)tim--;
for (int i = 0; i < FRAME_SIZE; i++) {
a = (pFirOutTemp[i ] < 0) ? -1.0f * (pFirOutTemp[i ]) : pFirOutTemp[i ];
nowAgc = 1 / a;
if (nowAgc < agcLevel) {
agcLevel = nowAgc;
tim = 6; //задержка отпускания
} else {
if (tim == 0) {
agcLevel += 0.02f; //нарастание
}
}
pFirOutTemp[i ] *= agcLevel;
}
-
Выбросы есть длительностью 0.7мСек и ампл 2.5дб
Да и то, мне кажется это артефакты звуковой платы.
-
Разместил на цкьюхаме тему эту lllol lllol lllol
один ответ lllol lllol про то , что всё очень не понятно.
-
Ладно, что ржать то, тема очень узкая и тяжелая, что я хотел ? cr123 10 человек в принципе понимает о чем речь и лишь немногие хотят хоть что-то обсудить. lol22
-
При такой реализации у вас АРУ будет цепляться за любые "пички"
-
При такой реализации у вас АРУ будет цепляться за любые "пички"
Я знаю.
-
Цепляться надо, но вот с отпусканием можно поработать. Там всё ару работает к 1. Это выглядит как интеллектуальное ару, с переменным фронтом отпускания и переменной задержкой
-
Вот ару которая у меня в сдр трудилась. Алгоритм сдерт со статей Gerald Youngblood, K5SDR (http://) в QEX.
procedure TDSPAGCYB.DataEvent;
var px: PFloat32;
pf: PFloatArray absolute px;
j: Integer;
bf: TBuffer;
Vpk, Gain, GainStep, val: TFloat32;
AGCHang,ms1: integer;
begin
bf:=InputPin.Get;
if bf <> nil then begin
if Enabled and (HangTime > 0) then begin
AGCHang:=Round((1000*bf.Size)/(1.0*HangTime*bf.SampleRate));
ms1:=(bf.SampleRate+500) div 1000; // samples per 1 msec
if ms1 > bf.Size then ms1:=bf.Size;
if ms1 = 0 then ms1:=1;
px:=bf_Data(bf);
if AGCHang < 1 then AGCHang:=1
else if AGCHang >= MAX_Hang then AGCHang:=MAX_Hang;
Inc(AGCLoop);
if AGCLoop >= AGCHang then AGCLoop:=0;
// Get peak magnitude
Vpk:=0;
for j:=bf.Size-1 downto 0 do begin
val:=Abs(px^);
if val > Vpk then Vpk:=val;
Inc(px);
end;
if Vpk > 0 then begin
bf_Write(bf);
// AGC gain factor with 6 dB headroom
Gb[AGCLoop]:=NormalLevel/Vpk;
// Find peak gain reduction (Min)
Gain:=1e+6;
for j:=AGCHang-1 downto 0 do begin
if Gb[j] < Gain then Gain:=Gb[j];
end;
// Limit Gain to MaxGain
if Gain > MaxGain then Gain:=MaxGain;
// agc
pf:=bf_Data(bf);
if Gain < PrevGain then begin
// AGC Gain is decreasing
GainStep := (PrevGain - Gain) / ms1; // 44 Sample ramp = 1 ms attack time
for j:=0 to ms1-1 do // Ramp Gain down over 1 ms period
pf[j]:=pf[j]*(PrevGain - ((j + 1) * GainStep));
//for j:=ms1 to bf.Size-1 do // Multiply remaining Envelope by Gain
// pf[j]:=pf[j] * Gain;
MulConst_Buff(@pf[ms1],bf.Size-ms1,Gain);
end else if Gain > PrevGain then begin
// AGC Gain is increasing
GainStep := (Gain - PrevGain) / ms1; // 44 Sample ramp = 1 ms attack time
for j:=0 to ms1-1 do // Ramp Gain down over 1 ms period
pf[j]:=pf[j]*(PrevGain + ((j + 1) * GainStep));
//for j:=ms1 to bf.Size-1 do // Multiply remaining Envelope by Gain
// pf[j]:=pf[j] * Gain;
MulConst_Buff(@pf[ms1],bf.Size-ms1,Gain);
end else
MulConst_Buff(px,bf.Size,Gain); // Multiply Envelope by AGC gain
PrevGain:=Gain; // Save Gain for next loop
PropertyChanged(idCurrentGain);
end;
end else if MaxGain > 0 then begin
bf_Write(bf);
MulConst_Buff(bf_Data(bf),bf.Size,MaxGain);
end;
OutputPin.Put(bf);
end;
end;
-
Да тот же алгоритм самый. Мусора многовато. Может для Паскаля это нормально, но С не простит по скорости такое расточительство по циклам.
Про пиччи я ничего не увидел. Да их надо убирать через среднее значение АРУ за период, а это совсем другая история.
-
Разместил на цкьюхаме тему эту
Если бы там хоть слышали об этой теме - давно бы забросали г... м да еще с ветиляторами. Здесь (на форуме) очень много посетителей оттель, боящихся задать простой вопрос Мэтрам из боязни быть высмеянными. (Посмотрите мой вопрос по ДПФ для поддверждения месным аматорам прописных истин). Там куча просмотров "молчаливым большинством".
-
Ага lllol
-
Да тот же алгоритм самый
Тот да не тот :) Посмотрите внимательно как усиление выбирается и для чего буфер длиной равной времени отпускания сделан
-
Ага lllol
Да, ретротема. 8 лет назад когда я еще писал что-то на сикухаме я рассказывал народу в этой теме о QER-фильтрах, доку выкладывал, рассчеты. Наткнулся на глухую стену непонимания и нежелания понимать. Это сейчас все такие умные на кверы перешли, а тогда моя "Стрекоза" была наверное первой конструкцией в рунете с таким фильтром на QER
-
Немного запутанно , но в принципе понятно.
Ещё из темы анализа это автонотч и приём телеграфа, но лучше фт8
-
Автонотч делается элементарно как LMS невысокого порядка с вычитанием
-
Кто знает... автонотч lms. Через минут пятнадцать работы начинает превращать звук в какафонию.
На cmsis dsp. Куда бежать?
-
C cmsis не работал. У LMS есть коэффициенты отвечающие за скорость адаптации. Может там подкрутить чего?
-
Кто знает... автонотч lms. Через минут пятнадцать работы начинает превращать звук в какафонию.
На cmsis dsp. Куда бежать?
https://www.keil.com/pack/doc/CMSIS/DSP/html/group__LMS.html
-
А можно немного подробней о коэффициентах, которы прописаны в LMS фильтре
void arm_lms_init_f32 ( arm_lms_instance_f32 * S,
uint16_t numTaps,
float32_t * pCoeffs,
float32_t * pState,
float32_t mu,
uint32_t blockSize
)
Parameters
[in] S points to an instance of the floating-point LMS filter structure
[in] numTaps number of filter coefficients
[in] pCoeffs points to coefficient buffer
[in] pState points to state buffer
[in] mu step size that controls filter coefficient updates
[in] blockSize number of samples to process
Returns
none
Details
pCoeffs points to the array of filter coefficients stored in time reversed order:
{b[numTaps-1], b[numTaps-2], b[N-2], ..., b[1], b[0]}
The initial filter coefficients serve as a starting point for the adaptive filter. pState points to an array of length numTaps+blockSize-1 samples, where blockSize is the number of input samples processed by each call to arm_lms_f32().
-
Они как-то похожи на то, что я рассчитал для ФИР фильтра?
-
LMS это обычный FIR по структуре. Но его коэффициенты постоянно пересчитываются (адаптируются)
-
А что в качестве референса использовать? Шум белый?
-
void arm_lms_norm_f32 ( arm_lms_norm_instance_f32 * S ,
const float32_t * pSrc ,
float32_t * pRef ,
float32_t * pOut ,
float32_t * pErr ,
uint32_t размер блока
)
Параметры
[в] S указывает на экземпляр структуры нормализованного фильтра LMS с плавающей запятой
[в] pSrc указывает на блок входных данных
[в] pRef указывает на блок справочных данных
[вне] pOut указывает на блок выходных данных
[вне] pErr указывает на блок данных об ошибке
[в] размер блока количество образцов для обработки
-
Решил вернуться к АРУ
Разобрал по косточкам алгоритм Андрея. Не нашел я обработку питчей. Простое плавное изменение множителя в оба направления. При этом ищется пик из всех значений .
// Find peak gain reduction (Min)
Gain:=1e+6;
for j:=AGCHang-1 downto 0 do begin
if Gb[j] < Gain then Gain:=Gb[j];
end;
то есть алгоритм реагирует на всплески амплитуды и после срабатывает полная задержка.
-
Алгоритм изначально не мой а Янглблуда - я давал ссыль на статьи в QEX. Там на васике но еще проще - возможно имеет смысл оригинал почитать. Сейчас я бы так уже не делал. Мне больше понравилась реализация с удержанием ДД принимаемых сигналов на заданном уровне (http://dspview.com/viewtopic.php?f=8&t=261). В цифре это совсем не сложно получается - делал на ADAU1761 (http://dspview.com/viewtopic.php?f=9&t=263), на обычном проце еще проще. Суть в том что АРУ цепляется не за максимальный уровень а за минимальный, тоесть за шум эфира. При этом постоянная времени АРУ достаточно большая - единицы секунд. А после АРУ стоит компрессор который имеет порог +20..+30дб выше чем уровень шума. Итого имеем прозрачный эфир, слабые и громкие станции хорошо различаются. Хлопков нет т.к. АРУ за пички и прочее не цепляется. Постоянная времени срабатывания компрессора берется достаточно маленькая. Дополнительно за компрессором можно поставить жесткий лимитер на всякий пожарный
-
Интересно , надо покурить. Игорь того же мнения относительно шума и сигнала. Честнее конечно мерить сигнал - шум .
-
Игорь того же мнения относительно шума и сигнала.
Я бы так не сказал - написанное Андреем вообще не укладывается в моей голове - что там за что цепляется - не пойму. Нужна хотя бы блок-схема с подробным описанием. 1yep Зато, явно указано то, что АРУ у него медленная, несколько секунд, а это явно говорит о том, что пока она включится в работу при появлении мощной станции, в работе будут компрессор и лимитер, что само по себе явный ацтой - длительная компрессия на приёме - это же не наши методы и явное искажение динамики.
В последней моей АРУ, напомню, так же можно назвать скоростную ветку компрессором, но она работает при номинальных установках АРУ во временном диапазоне 5...30 мс после всплеска, дальше в работу вступает обычная АРУ, это никак не секунды, поэтому, и субъективно воспринимается нормально - компрессия незаметна, ну, и понятно, что без лимитера подобные устройства вообще делать нельзя, т. к., до момента срабатывания скоростной ветки (те же примерно 5 мс), сигнал на НЧ выходе будет существенно превышать номинальный уровень, а как это скажется на последующем тракте, не всегда можно с точностью предсказать.
Существенным плюсом цифры перед аналогом в этом случае, является возможность работы с предсказанием, т. е., без первого выброса при резком всплеске, неизбежного в моём варианте - ставить нулевое время срабатывания у скоростной АРУ нельзя - при работе в помехах лажа получается.
Но, опять же, этот неизбежный выброс ушами, фактически, не слышен, так что, к цифровизации своей АРУ пока что не стремлюсь... lol22
-
АРУ у него медленная, несколько секунд, а это явно говорит о том, что пока она включится в работу при появлении мощной станции
Вы ничего не поняли. И даже не пытались. АРУ у меня не цепляется за громкие станции - я об этом писал раз надцать уже. Она отслеживает шумовую дорожку и корректирует усиление тракта так, чтобы шум эфира был на заданное количество дб ниже порога срабаывания компрессора/лимитера
надо покурить
На адау получилось достаточно много блоков т.к. там потокое программирование. На сях да еще если ффт есть будет проще. Ищем минимальную амплитуду бина, усредняем по времени, рассчитываем усиление чтобы привести амплитуду шума к заданному уровню. Дальше я использовал PeakRMS компрессор с минимальным временем срабатывания, а сам сигнал подавал на него с задержкой
-
И даже не пытались.
Ну почему, я попытался, но не понял. dontt44
И сейчас тоже пытаюсь, но, опять не понимаю. 1yep dontt44
К примеру, вот, типа, Вы отслеживаете какую-то шумовую дорожку, а, положим, на частоте идёт постоянный радиообмен, ну, и за что там Ваша АРУ будет цепляться, где она эту самую шумовую дорожку возьмёт? 44443
-
если ффт есть будет проще
Это есть. Идея пока понятна. В отсутствии станции не поднимать амплитуду до "1" . Я тут подумал, получается 2 ару расчета: первый приводим к нужному уровню "0.5" шумовую дорожку, второй расчет получается, все что выше шумового уровня идет в прогрессивную компрессию до "1"
Никогда компрессор не использовал на приеме )))
-
и за что там Ваша АРУ
Игорь, там используется ффт панорамы для определения уровня шума на широком диапазоне частот. Кстати это же значения используется для определения старта панорамы снизу. Ару для панорамы
-
Игорь, там используется ффт панорамы для определения уровня шума на широком диапазоне частот.
Так, один фиг, неувязочка выходит - шумы на широком диапазоне смотрим, а слушаем 3 кГц. Это же разные вещи. cr123
Впрочем, ни на чём не настаиваю, каждый сам творец своей АРУ... dontt44 lol22
-
К примеру, вот, типа, Вы отслеживаете какую-то шумовую дорожку, а, положим, на частоте идёт постоянный радиообмен, ну, и за что там Ваша АРУ будет цепляться, где она эту самую шумовую дорожку возьмёт?
За минимальный уровень в паузах. Причем не возьмет (в будущем когда-то) а уже вполне уверенно берет при обработке во временной области. У меня тоже были опасения что при длительном бла-бла-бла на частоте привязка шумовой дорожки будет "уплывать". Но на практике оказалось что все нормально - речь это вам не музыка. Но постоянная времени достаточно большая - единицы/десятки секунд.
-
За минимальный уровень в паузах.
Так паузы бывают разные. Бывают между словами, когда шум при мощной станции определяется ни столько шумом эфира, сколько шумом комнаты, из которой ведётся передача, бывает между серией передач, где реально только шум эфира.
Бывают в речи шипящие звуки, которые тоже вряд ли от шума отличить, и, их может быть очень много, если у человека проблемы с дикцией. dontt44 1yep
Кроме того, как уже писал ранее, сама идея длительной работы компрессора на приём (более 30 мс на мои уши) вряд ли оправдана - убивать в явном виде динамику корреспондента - не самая хорошая идея.
На мой взгляд, идея убитая ещё при рождении, тем не менее, отговаривать не собираюсь... cr123
-
Ппц. Я вам рассказываю что сделано и работает, а вы мне рассказываете что пепелацы не летают потому что не соответствуют вашим представлениям о кошерности летательных аппаратов.
-
Я вам рассказываю что сделано и работает,
А я Вам рассказываю не про то, что это не работает, а про то, что даже на первый беглый взгляд, там глюков может быть выше крыши.
Дайте хотя бы 10-минутную запись работы этого чуда в загруженном диапазоне с шумами. cr123
-
Вам не понравится. Это вообще странная технология, хотя может что то не понимаю. 20-30 дБ между Макс и шумом , это значит, что громкие станции будут компрессированными dontt44 и шум будет слышно всегда
-
Вам не понравится.
А я это знаю. 44443
Мне моя нравится, работает именно так, как мне и нужно было. 1999
Это, как раз, тот случай, когда аналоговое решение не прогадывает любому цифровому. cr123 pl33 lol22
А слушать слабые станции на 30 дБ слабее сильных, это для меня вообще что-то запредельное.
-
А кто же спорит ? Речь о чем-то новеньком.
-
20-30 дБ между Макс и шумом , это значит, что громкие станции будут компрессированными dontt44 и шум будет слышно всегда
Динамический диапазон сигналов на выходе такой АРУ можно выставить любым по своему усмотрению. Начиная от совсем плоского эфира и одинаковой громкости всех станций (но и сильным уровнем шума в паузах), так и 40-50дб когда вы шума эфира вообще не услышите в паузах
-
Тем не менее, опять же хотелось услышать реальную работу в зашумленном эфире.
Лично мне до сих пор непонятно, откуда там возьмётся какая-то прозрачность, про которую Вы писали - АРУ, типа, вообще, можно сказать, не при делах - она, по Вашим же словам, отрабатывает чуть не десятки секунд, а вся быстрая обработка предоставлена компрессору и лимитеру, успешно превращающим сигнал в кашу, и доводящим, к примеру, двухтоновый сигнал в сплошной частокол, за примерами ходить далеко не нужно - см., к примеру, мой ВЧ компрессор, это же реально крутая компрессия с нулевым временем срабатывания, и малым отпускания, там все картинки налицо, но то ж, пардон, устройство, СПЕЦИАЛЬНО искажающее сигнал для пробойности, и ни о какой "прозрачности" подобного сигнала даже речи быть не может... pl33
-
Кстати, Андрей, пытался сейчас кое что повторить из вашего алгоритма и нашел серьезный косяк. Там ару срабатывает на фрейм целиком, с нарастанием в 1мсек. Если в этот участок попадет скачок то будет стук стук, или всплеск или перегруз даже. Такой подход на обработку громких сигналов ставить нельзя. Так, что пока остается подход Геннадия: изменение ару на протяжении всего фрейма в зависимости от уровня. У вас, если там будет (условно) три скачка (в начале, в середине и в конце с нарастанием) то ваш алгоритм сразу начнет ару загрублять (1мс) и туда попадет первый всплеск (который даст стук стук) потом провал будет пока не придет самый громкий всплеск где уже будет ару актуально.
С новым алгоритмом пока не дал ладу...думаю над ним пока.
-
Я думаю в новом алгоритме есть резон. Ну смотрите, мы делаем компрессоры , которые ломают сигнал лишь бы энергетики туда дать. А какая разница с приемом? Если человек работает без компрессора, то мы ему "включим" компрессор как бы. lllol и по идеи если слабая станция работает без компрессора, то вероятность улучшения приема имеет место быть.
-
Если человек работает без компрессора, то мы ему "включим" компрессор как бы.
Компрессия повышает пробойность только в том случае, когда исходник чистый, в этом случае, по крайней мере, перемножения полезного сигнала на мусор не происходит, а при приёме, именно этот нежелательный момент и произойдёт.
По моим наблюдениям, и статистике от сторонних людей, эфир карёжить компрессией нельзя категорически - появляющиеся лишние компоненты существенно снижают прозрачность... lllol
-
Попробовал компрессор по приему cr123 cr123
Сделал из хорошего приемника - плохой )))
-
44443
-
Попробовал компрессор по приему
Так компрессор компрессору рознь. Поиграйтесь параметрами. В адау например там их есть несколько
-
Потратил целый день на всякие алгоритмы, но не нашел лучше варианта Андрея. Кстати беру свои слова назад, алгоритм Андрея работает мягко. Да, есть провалы перед всплеском, но это не слышно, только видно. Напомню, алгоритм Андрея делает ару на фрейм, причем, первую 1 мсек нарастание идет плавно (это основная фишка алгоритма). И можно было бы бросить дальше что -то придумывать , но башка рукам покоя не дает.
Вот мой алгоритм (потом фишки расскажу)
uint16_t countBack = 10;
void agcDo(float32_t *buffer) {
float32_t agcMetrTemp = 0;
if (tim > 0)tim--; //уменьшение задержки
for (uint16_t i = 0; i < FRAME_SIZE; i++) {
float32_t a;
a = (buffer[i] < 0.0f) ? -buffer[i] : buffer[i];// adc V
nowAgc = 1.0f / a; //coeff --> 1, nowAgc=чем меньше - тем сильнее загибаем pOutLms, 1 макс усиление.
if (a > agcMetrTemp) agcMetrTemp = a; //s-meter макс V
if (nowAgc < agcLevel) {
tim = 40;//задержка отпускания
agcLevel = nowAgc;
} else {
if (nowAgc > agcLevel) {
float32_t s = (1.0f / agcLevel);//скорость нарастания
if (tim == 0) {//активное нарастание
agcLevel += s;/// 0.01f;//скорость нарастания
} else {
if (!countBack) {//спокойное нарастание через шаг
agcLevel += 0.001f;
countBack = 5;// шаг , делаем плавное нарастание через 5 замеров
//если делать каждый шаг - растет имд
} else countBack--;
}
}
}
buffer[i] *= agcLevel;
}
agcMetr = agcMetrTemp; //s-meter
}
-
Вот так это выглядит.
Сперва плавный подъем потом основной. Зачем это надо? При долгом прослушивании музыки и эфира через всю системы (музыка в 3 кГц cr123) обнаружил, что иногда в тихих местах начинает срабатывать основной возврат (откат ару) и это прям сильно все портит. Тоже самое в эфире, когда человек говорит и иногда ару приспичевает сработать и это дает "ПШИК" . Я вспонил, что боролся с этим в Монстре и вспомнил как rrr7777 мелкий дрифт ару туда-сюда, без задействования основной задержки. Просто постепенно +1 уе или -1 уе даю пока не придет что то серьезное - тогда полный запуск
PS на снимке во время возврата есть всплеск и опять назад - это так комп чудит совместно с видоуз. В нормальной жизни его нет.
-
Причем в генераторных условиях все достаточно обыденно, но в реалях это работает и дает мягкую подтяжку , стробирование сигнала в то время как основная задержка еще держит. Так же это все не плохо работает на шумовой дорожке - нет "ПШШШ" неожиданных.
-
А где же работа компрессора, который должен был сразу резко поднять усиление, и АРУ, которая цепляется за шум, и имеет время отрабатывания несколько секунд?
Или это что-то другое? cr123
-
Вот запись 80м
Ару мое, фильтра мои.
СДР в Туле.
https://drive.google.com/file/d/1CJ-NMpZv79WvvCWnEGPIBw1HtxoT6Qc-/view?usp=sharing
-
А где же работа компрессора, который должен был сразу резко поднять усиление, и АРУ, которая цепляется за шум, и имеет время отрабатывания несколько секунд?
Или это что-то другое? cr123
Шутите lllol
Я понял , что имел ввиду Андрей. Громкие станции должны звучать громче. Мы страниц 10 исписали когда я Монстра на прием запустил.
-
После вчерашнего разговора с Игорем , нашёл серьёзный косяк в работе ару. Раньше я только догадывался , что где то косяк , а после разговора как лампочка зажглась id99
Когда в рамках одного фрейма идёт коррекция, то это выглядит вот "так" ! Нужен другой подход. Этот алгоритм обязательно будет стучать. И чем ниже частота тем сильнее это будет появляться. Зато теперь понятно почему когда я музыку слушал и там били низы зачастую проскакивал стук.
На фото оригинал и обработанный алгоритмом ару.
-
Буду пробовать так (абсолютные значения замеров):
Нужно обрабатывать СКАТ , а не искать только пики.
-
После вчерашнего разговора с Игорем , нашёл серьёзный косяк в работе ару.
Честно говоря, вообще не понимаю, в чём там могут быть проблемы. dontt44
Ставим АЦП, приведённый на вход максимальный сигнал должен быть -10 дБ от его перегрузки, т. е., её перегруз исключён по определению, разве что, на то время, пока сильносигнальная АРУ не отработает, а это единицы миллисекунд.
По умолчанию, выходной сигнал ЦАП вычисляется как 3162*вход АЦП (+70 дБ). Как только входной сигнал на АЦП превышает -80 дБ от максимума (как раз, сумма 70 и 10), коэффициент усиления пропорционально роняем, удерживая уровень на выходе ЦАП на пиках равным, на этом этапе можно и интегрирование сделать, допустив перегрузку ЦАП на коротких импульсах, он же, кстати, будет и лимитером работать по нулевому уровню.
Никто не запрещает работать в номинале на уровне -6 дБ от максимума ЦАП, получится лимитер +6 дБ, или те же 3 дБ, как у меня в последних версиях монстра.
Можно две петли сделать, как у меня - быструю и медленную - с одной все хотелки получить проблематично. 1yep
Естественно, после лимитера должен быть ФНЧ, в противном случае, расширение спектра на пиках будет слушаться ацтойно.
И никаких проблем нет, от слова вообще - полное повторение моего аналогового алгоритма АРУ, в котором никаких глюков нет и в помине, и адекватной реальной замены которому с полной объективной выкладкой получившихся результатов, а не только фантазиями, которых я и сам мастер нагнать 500 вариантов, пока что никто не придумал... pl33 lllol lol22
-
Нарвался на пульсации блока питания компьютера cr123
ару стремится даже их отработать.
-
Еще просидел. Теперь я знаю как компрессор делается, но к ару это мало отношение имеет. Бился, бился - все равно компрессор выходит и всё dontt44
ОПЯТЬ ВСЕ УДАЛИЛ .
-
По выше нарисованному чертежу новой ару сделал алгоритм.
Как то работате.
На рисунке стыковка шума (максимальное усиление) и два тона (с максимальной амплитудой мин усиление)
-
Да Вы ступеньки покажите с однотоновым перепадом 60 дБ, т. е., идёт 10 мкВ, потом 10 мВ, потом - назад, переходная характеристика интересна... cr123
-
Терпение rrr7777
Есть еще варианты при который алгоритм "улетает"
-
Да, сложная задача... 44443
Положим, хотите АРУ с временем срабатывания 20 мс, отпускания - 2 с.
Берёте интеграл модуля по времени от того, что загнано в буфер (он у Вас, по-моему, как раз-то 20 мс.), если величина превышает заданный порог (величина порога зависит от выставленного в данный момент усиления в ЦАП), пропорционально скидываете усиление в ЦАП, и всё в порядке - перегруз по среднему уровню исключён, выброса не будет, в отличие от аналогового аналога.
Отпускание - по 2-секундной экспоненте, повторю - вместе с ростом усиления ЦАП, пропорционально снижается порог срабатывания интегратора (чтобы средний уровень на выходе ЦАП держать), у меня эта фигня ещё в конце 80-х работала, как АРУ без выбросов, правда, на весьма примитивной элементной базе - по-моему, вообще 8-битки были с процом размером с коробок спичек lllol, и никаких проблем.
.. lol22
-
Причём, ЧТО ВАЖНО - у меня не было никаких кусочных разбиваний - 256 выборок грузились в сдвиговый регистр, и обновлялись с каждой новой выборкой.
Работа по кускам, когда Вы грузите 20 мс, потом их скидываете, и загоняете новые, обрабатывая их ПО ОТДЕЛЬНОСТИ, по самой своей природе НЕ СМОЖЕТ адекватно работать АРУ.
Простой пример - на конце последней выборки всплеск, и на начале следующей - тоже, тот же самый. Интегрирование по выборкам не даст превышение порога, а интегрирование по последней половине первой, и началу последующей - даст.
Т. е., есть временнАя неопределённость алгоритма - всплеск на границе фреймов не отработается, а в середине - да.
Только непрерывно, тогда и будет Вам счастье. Кусками даже голову не морочьте, ибо там ацтой по определению... lllol
-
Я еще на пути Джедая 8) , пока не сдаемся. Есть моменты, которые у меня в голове не укладываются. Наверное надо паузу сделать.
-
Ну как-то так
переход -45дб -5дб на разных частотах.
-
Да не, то фигня какая-то. Должна быть одна вполне явная синусоида, потом, не менее явная другая... lllol
-
Пока воюю с вот таким всплеском.
Пока даже физику не могу понять , что раскачивает . Сейчас ару по скату работает.
-
Лайт версия
Работает
плавное от -5 до -45
и резкое от -45 до -5дб
Совмещение частот вроде норм.
Косяк: ару должно работать 0...1 , а сейчас работает 0...0.8, ставишь даже предел 0.9 сразу на всплесках проскакивает инверсный float . Уже целый день борюсь с этим перегрузом (инверсия float) . У меня уже программа больше из защит и проверок состоит, нежели сам алгоритм.
-
УФ
Новое АРУ по скату.
float32_t adcMin = 1;
float32_t nextAdc;
float32_t ampMax = 0;
uint8_t isMin = 0;
float32_t max = 0.8f;
void agcDo(float32_t *buffer) {
float32_t agcMetrTemp = 0;
uint16_t countBack = 10;
uint16_t idx = 0;
uint16_t idxMin = 0;
if (tim > 0)tim--; //уменьшение задержки
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]);
if (a > 0)nowAgc = max / a; //coeff --> 1, nowAgc=чем меньше - тем сильнее загибаем pOutLms, 1 макс усиление.
else nowAgc = max / 0.0001f;
if (nowAgc < agcLevel) { // всплеск V
tim = 10;//задежка отпускания
uint16_t downIdx = i;
uint16_t upIdx = i;
uint16_t exit = 1;
int direction = 0;//напрвление вниз (отрицательная синусоида)
if (buffer[i] > 0) direction = 1;//напрвление вверх (положительная синусоида)
while (exit) {
exit = 0;//выходим
if (direction) {//++
//going up
if (buffer[upIdx] <= buffer[upIdx + 1] && upIdx + 1 < FRAME_SIZE) {
upIdx++;
exit = 1;//не выходим
}
//go down
if (buffer[downIdx] >= buffer[downIdx - 1] && downIdx - 1 >= 0) {//&& buffer[downIdx - 1] >= 0
downIdx--;
exit = 1;//не выходим
}
} else { //--
//going up
if (buffer[upIdx] >= buffer[upIdx + 1] && upIdx + 1 < FRAME_SIZE) {
upIdx++;
exit = 1;//не выходим
}
//go down
if (buffer[downIdx] <= buffer[downIdx - 1] && downIdx - 1 >= 0) {// && buffer[downIdx - 1] <= 0
downIdx--;
exit = 1;//не выходим
}
}
}//while
if ((upIdx > downIdx) && i > 0 && i < FRAME_SIZE - 1) {
if (buffer[upIdx] != 0)
nowAgc = max / fabsf(buffer[upIdx]);//максимальное значение
else nowAgc = max / 0.0002f;
for (uint16_t z = downIdx; z <= upIdx; z++) {
double_t f = fabsf(buffer[z]) * nowAgc;
if (f > max) {//out
if (buffer[z] > 0) buffer[z] = max;
else buffer[z] = -max;
} else if (f > 0)//norm
buffer[z] *= nowAgc;
else {//out
if (buffer[z] >= 0) buffer[z] = 0.0002f;
else buffer[z] = -0.0002f;
}
}
i = upIdx;
} else {
double_t f = a * nowAgc;
if (f > max) {//out
if (buffer[i] > 0) buffer[i] = max;
else buffer[i] = -max;
} else if (f > 0)//norm
buffer[i] *= nowAgc;
else {//out
if (buffer[i] >= 0) buffer[i] = 0.0002f;
else buffer[i] = -0.0002f;
}
// //защита от прегруза
// if (buffer[i] < -max)buffer[i] = -(max-0.5f);
// if (buffer[i] > max) buffer[i] = max-0.5f;
//
}
agcLevel = nowAgc;
} else {//если спад V
double_t f;
float32_t cc = agcLevel + 0.005f;
if (tim == 0)f = a * cc;
else f = a * agcLevel;
if (f > max) {//out
if (buffer[i] > 0) buffer[i] = max;
else buffer[i] = -max;
} else if (f > 0) {//norm
if (tim == 0) {
agcLevel = cc;
buffer[i] *= cc;
} else buffer[i] *= agcLevel;
} else {//out
if (buffer[i] >= 0) buffer[i] = 0.0002f;
else buffer[i] = -0.0002f;
}
// //guard
// if (buffer[i] < -max)buffer[i] = -(max-0.5f);
// if (buffer[i] > max) buffer[i] = max-0.5f;
}
if (a > agcMetrTemp) agcMetrTemp = a; //s-meter макс V
}
// защита от перегруза
// for (uint16_t i = 0; i < FRAME_SIZE; i++) {
// if (buffer[i] < -max) buffer[i] = -max+0.2f;
// if (buffer[i] > max) buffer[i] = max-0.2f;
//
// }
agcMetr = agcMetrTemp; //s-meter
}
-
На фото и проблема и решение ее
Я целяком в реверсе опускаю скат и ступеньки не получается
-
Нашёл ошибки , будут уточнения по алгоритму .
Например , откат ару вещь тоже сложная. Ее можно только на пиках откатывать с контролем на два шага вперёд.
-
Игорь, есть вопрос.
Я правильно подключаю ацп ?
-
А то по ходу я с ветряными мельницами воюю. Может я неправильно подключил цап или ацп к звуковой?
фото : это без работы ару . И там появляется переходный процесс. А если со звуковой на звуковую (разные) то все ок , синусоида перетекает ровно без переходноо процесса.
Может просадка напряжения ...??
-
Я повально подключаю ацп ?
Правильно. 1yep
А по поводу переходного процесса - Вы откуда сигнал берёте?
-
Выход на наушники
-
Я не про то. Кто формирует сигнал со ступенчатым перепадом? И зачем брать такие низкие частоты? dontt44
-
По низким в основном и происходят искажения. Это связано с там , что больше точек при оцифровки. Ну или еще по каким причинам хз .
Игорь, какие будут (схемные решения) рекомендации по выходу ЦАП?
У меня сейчас просто последовательно емкость 10.0
-
Игорь, какие будут (схемные решения) рекомендации по выходу ЦАП?
Поставьте 10 мкФ, после него - 1 кОм на землю. Если Ваш ЦАП такие нагрузки выдерживает.
Частота среза - 16 Гц, Вам хватит за глаза.... lol22
-
Ну в общем провел еще несколько тестов.
Однозначно это глючит АЦП. При серьезном скачке идет провал. Этот провал полностью отсутствует когда со звуковой на звуковую напрямик подаешь. Смоделировал синус внутри системы - этого провала тоже нет.
Вывод можно сделать один: референсное питание ацп и мои полпитания на входе ацп - отличаются.
Нужно и реф питание ацп и полпитание на входе ацп питать от одного источника, а моем случаи между ними есть дроссель и за дросселем емкости.
-
Оставлю я пока проблему ацп. Да и нет так сильно она влияет. Есть другая проблема, питчки. Они дергаю ару и как следствие систему отката и выглядит это так:
(подан белый шум макс амплитуды)
-
Соответственно на каждый взлет срабатывает система ару, а потом опять откат, и так в бесконечном цикле. Туда - сюда колбасит.
Нужно окно, гистерезис
-
Пока действует этот вариант, он значительно лучше Лайт варианта. Полностью переработана система отката ару (через поиск пика сигнала).
float32_t max = 0.5f;
void agcDo(float32_t *buffer) {
float32_t agcMetrTemp = 0;
if (tim > 0)tim--; //уменьшение задержки
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; //coeff --> 1, nowAgc=чем меньше - тем сильнее загибаем pOutLms, 1 макс усиление.
else nowAgc = max / 0.00005f;
if (nowAgc < agcLevel) { // всплеск V
tim = 10;//задежка отпускания
uint16_t downIdx = i;
uint16_t upIdx = i;
uint16_t exit = 1;
int direction = 0;//напрвление вниз (отрицательная синусоида)
if (buffer[i] > 0) direction = 1;//напрвление вверх (положительная синусоида)
while (exit) {
exit = 0;//выходим
if (direction) {//++
//going up
if (buffer[upIdx] <= buffer[upIdx + 1] && upIdx + 1 < FRAME_SIZE) {
upIdx++;
exit = 1;//не выходим
}
//go down
// if (((buffer[downIdx] >= buffer[downIdx - 1] && buffer[downIdx] > 0) || buffer[downIdx - 1] < 0) && downIdx - 1 >= 0) {//&& buffer[downIdx - 1] >= 0
if (buffer[downIdx - 1] >= 0 && downIdx - 1 >= 0) {//&& buffer[downIdx - 1] >= 0
downIdx--;
exit = 1;//не выходим
}
} else { //--
//going up
if (buffer[upIdx] >= buffer[upIdx + 1] && upIdx + 1 < FRAME_SIZE) {
upIdx++;
exit = 1;//не выходим
}
//go down
// if (((buffer[downIdx] <= buffer[downIdx - 1] && buffer[downIdx] < 0) || buffer[downIdx - 1] > 0) && downIdx - 1 >= 0) {// && buffer[downIdx - 1] <= 0
if (buffer[downIdx - 1] <= 0 && downIdx - 1 >= 0) {// && buffer[downIdx - 1] <= 0
downIdx--;
exit = 1;//не выходим
}
}
}//while
if ((upIdx > downIdx) && i > 0 && i < FRAME_SIZE - 1) {
if (buffer[upIdx] != 0) {
nowAgc = max / fabsf(buffer[upIdx]);//максимальное значение
} else nowAgc = max / max;
for (uint16_t z = downIdx; z <= upIdx; z++) {
if (z < i) buffer[z] *= nowAgc / agcLevel; //там уже применен коэфф
else buffer[z] *= nowAgc;//применить новый коэфф
}
i = upIdx;
} else {
float32_t f = a * nowAgc;
if (f > max) {//out
if (buffer[i] >= 0) buffer[i] = max;//max
else buffer[i] = -max;//max
nowAgc = 1;
}else buffer[i] *= nowAgc;
}
agcLevel = nowAgc;
} else {//если спад V
float32_t f = fabsf(buffer[i + 1]);
if(tim == 0 && a < f && f >= fabsf(buffer[i + 2]) && i < FRAME_SIZE - 2 ) {
float32_t cc = agcLevel + 0.005f;
if ( f * cc < max ) {
agcLevel = cc;
} else {
cc = agcLevel + 0.0005f;
if ( f * cc < max ) {
agcLevel = cc;
}
}
}
if( a < f && f >= fabsf(buffer[i + 2]) && i < FRAME_SIZE - 2 )
agcLevel += 0.00001f;
if (a * agcLevel <= max)
buffer[i] *= agcLevel;
else {
if (buffer[i] >= 0) buffer[i] = max;//max
else buffer[i] = -max;//max
agcLevel = max;
}
}
if (a > agcMetrTemp) agcMetrTemp = a; //s-meter макс V
}
agcMetr = agcMetrTemp; //s-meter
}
-
Всё удалил. Делаю новый алгоритм. cr123
-
Соответственно на каждый взлет срабатывает система ару, а потом опять откат, и так в бесконечном цикле. Туда - сюда колбасит.
Нужно окно, гистерезис
А скорость атаки и скорость отпускания регулируется?
-
Скорость атаки понятие отсутствует, а отпускание и угол отпускания само сабой.
-
Сейчас воюю над этим (белый шум макс уровня на входе)
фото
с ару
и без ару
-
Думаю над питчиками cr123
-
Скорость атаки в моем понимании скорость реакции на входной импульс. В компрессорах ее так называют.
И еще вы фазу сигнала рвете при регулировании? птички от разрыва фазы могут быть.
ФЧХ посмотрите Во время регулирования.
Спектр при zerospan у анализатора передний фронт при атаке на выходе АРУ какой? ...если можно конечно посмотреть на нем так...
-
В цифре такого нет . В цифре сперва обрабатывается данные и только потом они воспроизводятся. Поэтому всегда задержка есть. И понятие атаки нет, либо ее можно сделать так как захочешь. Пока есть над чем подумать и сделать.
-
И еще вы фазу сигнала рвете при регулировании?
так об этом и речь, что я работаю со скатом целиком, а сейчас вообще с полупериодом как раз чтобы сигнал не портить.
-
Я понял, что это за всплески lol22
Это как раз те участки в которых нет питчей и ару их поднимает. И длина у них почти с фрейм (1024 замера ацп)
-
rms-детектор спасет отца русской демократии. Не надо за пички цеплятся. Их надо просто срезать лимитером после ару
-
ну хорошо, rms, а дальше что с ним делать. Занижать битность ?
Есть у меня мысль ... питч чаще всего приходит в одной полярности и очень большой амплитуды. Так вот, а что если мне смотреть следующий за питчем пик и сделать вывод был это сигнал или просто вылет. Если второй пик тоже мощный то с большой долей вероятности это сигнал и нужно включать задержку с занижением амплитуды, а если следующий питчек мал и не является выбросом - то первый был питчек и мы не включаем задержку, а просто просаживаем питчек по амплитуде. Своеобразный шумодав получается.
-
я же говорил шумодав получится lol22
-
Пока получается полная фигня
-
google("feedforward agc");
-
google("feedforward agc");
спасибо я посмотрю обязательно.
-
Война с питчиками оказалась весьма интересная. lol22 lol22 веселья аж на 3 дня и три ночи. Цепануло так цепануло. 44443 44443
Вроде победил, но с одной оговоркой. Нужно вводить дельту на откат ару к максимальным усилениям. Что это значит: если постоянно держать сигнал около 1, без дельты, то происходит "стробирование" сигнала и постоянная качка то усиливаем то ослабляем. В наушниках как море и прибой со случайными времменными задержками. Кстати, самый честный сигнал для испытания ару - это розовый шум cr123 он сразу все косяки вытаскивает.
Вот пример когда ару пытается держать 1 без дельты:
На водопаде хорошо видно стробирование сигнала по амплитуде. (я еще работаю над этим)
PS Контроль питчиков идет в 1мсек. Идет замер 2 пиков по 1мсек с контролем перехода через 0, то есть, там не ровно 1 мсек - плавает в зависимости от сигнала. Так вот, если второй пик не содержит больших амплитуд, то мы оставляем уровень ару до появления питчика. Ну конечно же сам питчик прижимается к нормальному уровню без перегруза.
-
Новый вариант с контролем питчиков
float32_t max = 0.49975586f;
uint16_t count = 100;
float32_t pit1 = 0;
float32_t pit2 = 0;
void agcDo(float32_t *buffer) {
float32_t agcMetrTemp = 0;
if (tim > 0)tim--; //уменьшение задержки
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; //coeff --> 1, nowAgc=чем меньше - тем сильнее загибаем pOutLms, 1 макс усиление.
else nowAgc = max / 0.00005f;
uint16_t upIdx = i;
float32_t pikBuf = 0;
uint16_t exit = 1;
int direction = 0;//напрвление вниз (отрицательная синусоида)
if (buffer[i] >= 0) direction = 1;//напрвление вверх (положительная синусоида)
while (exit) {
exit = 0;//выходим
uint16_t idx1 = (uint16_t) (upIdx + 1);
float32_t p1 = fabsf(buffer[idx1]);
if (idx1 < FRAME_SIZE) {
if (direction) {//+++++++++++++++++++++++++++++
if ((buffer[upIdx] < 0 && buffer[idx1] >= 0) || (upIdx - i < 48)) {
upIdx++;
if (p1 > pikBuf) {
pikBuf = p1;
}
exit = 1;//не выходим
}
} else { //------------------------
//going up
if ((buffer[upIdx] > 0 && buffer[idx1] <= 0) || (upIdx - i < 48)) {
upIdx++;
if (p1 > pikBuf) {
pikBuf = p1;
}
exit = 1;//не выходим
}
}
}
}//while
if (upIdx > i) upIdx--;
if (upIdx > i) {
float32_t locNowAgc;
if (!pit1) {
pit1 = pikBuf;
pit2 = 0;
} else {
pit2 = pikBuf;
}
//проверка на 0
if (pikBuf != 0) {
locNowAgc = max / pikBuf;//максимальное значение
} else locNowAgc = max / 0.00005f;
//agcLevel == текущий уровень ару
if (locNowAgc < agcLevel) { // всплеск или питч V, идем вниз
//заполним полупериод
if (i) {
for (uint16_t z = i; z <= upIdx; z++) {
buffer[z] *= locNowAgc;//применить новый коэфф
}
} else {//механизм сочленения с пред фреймом ...ждем первого нуля
if (buffer[0] >= 0) direction = 1;//напрвление вверх (положительная синусоида)
exit = 1;
uint16_t idx0=0;
while (exit) {
exit = 0;//выходим
if (direction) {//+++++++++++++++++++++++++++++
if (buffer[idx0] >= 0) {
idx0++;
exit = 1;//не выходим
}
} else { //------------------------
//going up
if (buffer[idx0] <= 0 ) {
idx0++;
exit = 1;//не выходим
}
}
}//while
for (uint16_t z = 0; z <= upIdx; z++) {
if(z<=idx0)buffer[z] *= agcLevel;//применить старый коэфф
else buffer[z] *= locNowAgc;//применить новый коэфф
}
}
if (pit1 && pit2) { //если есть оба пика (модуль амплитуды)
if (pit1 > pit2) {
agcLevel = (max / pit2); // ставим текущий уровень ару по пику2
tim = 10;//задежка отпускания
}
//если сигнал продолжает наращивать амплитуду то будем ждать пока не перестанет
//обнуляем содержимое пик1 и пишим туда текущее пик2 (пик2 всегда текущие)
if (pit2 >= pit1) {//смотрим следующий питч если
pit1 = pit2;
pit2 = 0;
} else {
pit1 = pit2 = 0;//запускаем заново поиск пиков питчей
}
}
} else {//идем вверх
if (tim == 0) {//подождали и начинаем
float32_t bb = pikBuf;
//расчет сколько будем откатывать .....сложно всё надо еще думать
float32_t cc = agcLevel + (sqrtf(agcLevel) / 200) * (upIdx - i);
if (bb * cc < max-0.0f) {
agcLevel = cc;
}
}
//заполним полупериод
for (uint16_t z = i; z <= upIdx; z++) {
buffer[z] *= agcLevel;//применить новый коэфф
}
}
i = upIdx; // след цикл будет стратовать от upIdx
} else { //это сидуация редкая но тоже надо . сделано по класике одного замера
if (nowAgc < agcLevel) { // всплеск V
agcLevel = nowAgc;
tim = 10;//задежка отпускания
}
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
agcMetr = agcMetrTemp; //s-meter
}
-
А вот так уже с дельтой по откату
-
При этом на нормальном сигнале эта дельта не сказывается. Наверное будет заметна только в динамике.
-
Сложный алгоритм работы ару приведет к тому что она будет жить своей жизнью и "дышать" вам в уши.
-
Я ещё не закончил , но уже надоедает. Посмотрел алгоритм feed forward - это мы уже пошли. Шум сложнее всего обрабатывать. Все не предсказуемо. Длина фрейма всего 20 мсек сильно не наанализируешь. Но вообще я начал с левого ската , потом полупериод, потом период и сейчас уже несколько периодов длиной в 1 мсек анализирую. Я даже меж фреймовое сопряжение сделал. Выглядит страшно, но там просто много условий, а они выполняются в один такт. Пока я столкнулся с тем , что я не знаю до куда откатывать ару - это всегда сюрприз. Попадаешь в тихий участок без питчеков ару откатывает ещё (даёт усиление) и тут питчик прилетает и система сразу реагирует сильным снижением усиления. Причём может несколько секунд быть все ок , а потом прилетает. Но я ещё думаю. Далеко продвинулся. Но толи где-то ошибка либо просто не все учёл.
-
Интересный эффект обнаружил cr123 cr123 cr123
Борьба с питчиками привела к компрессии
Вот фото отката (после снятия сильного сигнала) ару начинает усиление и в правом верхнем углу хорошо видно как алгоритм начинает борьбу с питчиками и глатает их и при этом происходит компрессия сигнала. Естественно потом ару "просыпается" и скидывает вниз усиление.
-
И я снова удалил практически всё. Нужен был новый подход.
Наверное Андрей прав (опять) и нужно сигнал на лимиттер садить иногда.
-
Ну вот пока , что удалось на розовом шуме сделать. С компрессией. Все питчи автоматом съедает.
-
нужно сигнал на лимиттер садить иногда.
У меня, напомню, совсем короткие пички (типа, до 2 мс, точное время уже не помню) именно на лимитер и садятся, отрабатывать их АРУ смысла не вижу никакого.. dontt44 pl33
-
Я вообщем то все понимаю, но только не могу до конца понять от куда этот хвост появляется ? no88 Собственно с ним и борюсь уже три дня.
Ну вот какой участок осциллограммы дает этот хвост?
-
Любое амплитудное вмешательство в исходник расширяет его спектр, и тем сильнее, чем с большей частотой (большей крутизной) Вы осуществляете регулирование, от этого уйти нельзя, это по определению.
Если стоит лимитер, или скоростная АРУ, рубящая пички, НЧ фильтр за ней очень полезен, гляньте, к примеру, на модуль 0913... 123123 pl33
-
У меня стоит фильтр 300-ого порядка после ару
-
стоит фильтр 300-ого порядка после ару
Зачем так много? Уменьшите порядок до разумного :)
-
Основной 800-ого порядка
-
Любое амплитудное вмешательство в исходник расширяет его спектр
Даже если от 0 до 0 я это делаю?
Я определяю начало периода и конец (через 1мс) тоже 0 или около того, и только потом умножаю на коэффициент.
Причем когда я это делаю на увеличение амплитуды то все ок хвоста нет, а на уменьшение почти всегда. Либо где-то не увидел не стыковку амплитуд либо еще что.
-
Я определяю начало периода и конец (через 1мс) тоже 0 или около того, и только потом умножаю на коэффициент.
А какая разница? Это же, фактически, АМ со всеми вытекающими. cr123
-
Вот пример в котором алгоритм цепляется за питчики и запускает задержку и второй - это с поглощением питчиков.
Смотрим на водопад 123123
Ну вот как раз "лимиттер" дает на водопаде лес.
-
Это обычный шум? cr123
-
Это розовый шум!! и на него ару ох сильно реагирует.
-
Сделал !!!
Новая версия. Работает даже если стробировать сигнал около 1 !!! Без дельты. С дельтой вооще огонь cr123
float32_t max = 0.49975586f; //максималка от -0.5 до +0.5 примерно для 12 бит
uint16_t count = 100;
float32_t pit1 = -1;
float32_t pit2 = 0;
uint8_t stopGoingUp = 0;
float32_t rmsPik = 0;
float32_t rmsFrame = 0;
void agcDo(float32_t *buffer) {
float32_t agcMetrTemp = 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;
float32_t pikBuf = -1;
uint8_t exit = 1;
uint8_t exitYN = 0;
uint16_t wait = 48;// 1msec
int direction = 0;//напрвление вниз (отрицательная синусоида)
if (buffer[i] > 0) direction = 1;//напрвление вверх (положительная синусоида)
if (buffer[i] == 0) exit = 0; //пропустим поиск пика в блоке
while (exit) { //поиск пика в блоке от 0 до 0
exit = 0;//выходим
float32_t p1 = fabsf(buffer[upIdx]);//feature
if (upIdx < FRAME_SIZE) {
if (direction) {//+++++++++++++++++++++++++++++
//если условие остановило в ++ то добиваем его до 0
if ((buffer[upIdx] >= 0 && !exitYN) || (upIdx - i < wait)) {
upIdx++;
if (p1 > pikBuf) {
pikBuf = p1;
}
exit = 1;//не выходим
}
//если условие остановило в -- то добиваем его до 0 и выходим
if (((buffer[upIdx] < 0)) && (upIdx - i >= wait)) {
upIdx++;
exitYN = 1; //не дадим пред условию сработать
if (p1 > pikBuf) {
pikBuf = p1;
}
exit = 1;//не выходим
}
} else { //------------------------
//going up
//если условие остановило в -- то добиваем его до 0 и выходим
if ((buffer[upIdx] <= 0 && !exitYN) || (upIdx - i < wait)) {
upIdx++;
if (p1 > pikBuf) {
pikBuf = p1;
}
exit = 1;//не выходим
}
//если условие остановило в ++ то добиваем его до 0
if (((buffer[upIdx] > 0)) && (upIdx - i >= wait)) {
upIdx++;
exitYN = 1; //не дадим пред условию сработать
if (p1 > pikBuf) {
pikBuf = p1;
}
exit = 1;//не выходим
}
}
//добавим блок если в нем есть глобальный пик (выброс)
if (upIdx - i >= wait && max / pikBuf < agcLevel) {
if (256 + upIdx < FRAME_SIZE) wait = 256;
}
}
}//while
if (upIdx > i) { //если блок не пустой то...
float32_t locNowAgc;
//проверка на 0
if (pikBuf != 0) {
locNowAgc = max / pikBuf;//максимальное значение
} else locNowAgc = max / 0.00005f;
//типа среднее значение . исползуется для отката .
rmsPik = (rmsPik + pikBuf) / 2.0f;
//agcLevel == текущий уровень ару
if (locNowAgc < agcLevel) { // всплеск или питч V, идем вниз ..........................
stopGoingUp=0;
//заполним блок
if (i) {
for (uint16_t z = i; z <= upIdx; z++) {
buffer[z] *= locNowAgc;//применить новый коэфф
}
} else {//механизм сочленения с пред фреймом ...ждем первого нуля
if (buffer[0] > 0) direction = 1;//напрвление вверх (положительная синусоида)
exit = 1;
uint16_t idx0 = 0;
while (exit) {
exit = 0;//выходим
if (direction) {//+++++++++++++++++++++++++++++
if (buffer[idx0] > 0) {
idx0++;
exit = 1;//не выходим
}
} else { //------------------------
//going up
if (buffer[idx0] < 0) {
idx0++;
exit = 1;//не выходим
}
}
}//while
for (uint16_t z = 0; z <= upIdx; z++) {
if (z <= idx0)buffer[z] *= agcLevel;//применить старый коэфф
else buffer[z] *= locNowAgc;//применить новый коэфф
}
}
if ((pit2< pit1 && pit1 > pikBuf ) ) {//смотрим следующий питч если
agcLevel -= (agcLevel - locNowAgc) / 5;
} else {
// agcLevel = locNowAgc;
agcLevel -= (agcLevel - locNowAgc) / 2;
}
if ((pit2< pit1 && pit1 < pikBuf )) {//смотрим следующий питч если
// agcLevel = locNowAgc;
agcLevel -= (agcLevel - locNowAgc) / 1;
}
pit2 = pit1;
pit1 = pikBuf;
tim = 30;//задежка отпускания
// }
} else {//идем вверх/////////////////////////////////////////////////////////////////////
float32_t cc ;
if (tim == 0) {//подождали и начинаем
cc = agcLevel + (locNowAgc - agcLevel) / 600;
//проверим можем нет еще откатить
if (rmsFrame * 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 { //это ситуация редкая но тоже надо . сделано по классике одного замера
if (nowAgc < agcLevel) { // всплеск V
agcLevel -= (agcLevel - nowAgc) / 2;
// tim = 10;//задежка отпускания
}
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
rmsFrame=(rmsFrame+rmsPik)/2.0f; // глобальный меж фреймовый средничок нужен для отката до какого-то уровня.
agcMetr = agcMetrTemp; //s-meter
}
-
вот алгоритм убирания питчиков
if ((pit2< pit1 && pit1 > pikBuf ) ) {//смотрим следующий питч если
agcLevel -= (agcLevel - locNowAgc) / 5;
} else {
agcLevel -= (agcLevel - locNowAgc) / 2;
}
if ((pit2< pit1 && pit1 < pikBuf )) {//смотрим следующий питч если
agcLevel -= (agcLevel - locNowAgc) / 1;
}
pit2 = pit1;
pit1 = pikBuf;
pit1 pit2 - это глобальные амплитуды всплесков, которые требуют занижать амплитуду
agcLevel - самая главная переменная в ару !
pikBuf - текущий пик
locNowAgc - значение лимиттера по которому был опущен пик
-
Очень много контроля и самое главное был косяк: пропуск применения главного множителя, отсюда и сигнал ломался. Сейчас тоже проскакиваю нестыковки. Скорей всего межфреймомые дела. И достаточно редко. И ару ОЧЕНЬ не любит низкие частоты 150Гц и ниже. Запустил музыку и ару посчитало, что низы - это ступенька. cr123
-
Это розовый шум!!
Какой же он розовый? Судя по спектру, это всё-таки, белый шум - спектр ровный.
Да и откуда там розовому взяться, только при косячном приёмнике - напомню, розовый шум имеет спектр -6 дБ/октава. cr123
-
Так и есть. Поэтому я им и пользовался для тестов, у него, у шума, низов больше и сигнал более сложный получается чем белый (по структуре). На белом ставишь вроде нормально работает, переключаешь на розовый и упс, идут завалы.
-
Нашел утечку памяти и еще пару досадных ошибок (логических, это же анализ cr123)
Теперь так:
(там где дельта 0 то это стробирование около 1, алгоритм пытается держать 1 без диапазона гистерезиса по усилению, ну и там где дельта 0.3 - это как раз гистерезис)
-
Вот так сейчас
float32_t max = 0.49975586f; //максималка от -0.5 до +0.5 примерно для 12 бит
uint16_t count = 100;
uint8_t stopGoingUp = 0;
float32_t rmsPik = 0;
float32_t rmsFrame = 0;
void agcDo(float32_t *buffer) {
float32_t agcMetrTemp = 0;
float32_t pit1 = -1;
float32_t pit2 = 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 = -1;
uint8_t exit = 1;
uint8_t exitYN = 0;
uint16_t wait = 48;// 1msec
int direction = 0;//напрвление вниз (отрицательная синусоида)
if (buffer[i] > 0) direction = 1;//напрвление вверх (положительная синусоида)
if (buffer[i] == 0) exit = 0; //пропустим поиск пика в блоке
while (exit) { //поиск пика в блоке от 0 до 0
exit = 0;//выходим
float32_t p1 = fabsf(buffer[upIdx]);//feature
upIdxNow = upIdx;
if (direction) {//+++++++++++++++++++++++++++++
//если условие остановило в ++ то добиваем его до 0
if ((buffer[upIdx] >= 0 && !exitYN) || (upIdx - i < wait)) {
if (p1 > pikBuf) {
pikBuf = p1;
}
if (upIdx + 1 < FRAME_SIZE) {
upIdx++;
exit = 1;//не выходим
}
}
//если условие остановило в -- то добиваем его до 0 и выходим
if ((buffer[upIdxNow] < 0) && (upIdxNow - i >= wait)) {
exitYN = 1; //не дадим пред условию сработать
if (p1 > pikBuf) {
pikBuf = p1;
}
if (upIdxNow + 1 < FRAME_SIZE) {
upIdx++;
exit = 1;//не выходим
}
}
} else { //------------------------
//going up
//если условие остановило в -- то добиваем его до 0 и выходим
if ((buffer[upIdx] <= 0 && !exitYN) || (upIdx - i < wait)) {
if (p1 > pikBuf) {
pikBuf = p1;
}
if (upIdx + 1 < FRAME_SIZE) {
upIdx++;
exit = 1;//не выходим
}
}
//если условие остановило в ++ то добиваем его до 0
if ((buffer[upIdxNow] > 0) && (upIdxNow - i >= wait)) {
exitYN = 1; //не дадим пред условию сработать
if (p1 > pikBuf) {
pikBuf = p1;
}
if (upIdxNow + 1 < FRAME_SIZE) {
upIdx++;
exit = 1;//не выходим
}
}
}
//добавим блок если в нем есть глобальный пик (выброс)
if (upIdx - i >= wait && max / pikBuf > agcLevel) {
if (256 + upIdx < FRAME_SIZE) wait = 256;
}
}//while
if (upIdx > i) { //если блок не пустой то...
//upIdx--;
float32_t locNowAgc;
//проверка на 0
if (pikBuf != 0) {
locNowAgc = max / pikBuf;//максимальное значение
} else locNowAgc = max / 0.00005f;
//типа среднее значение . исползуется для отката .
rmsPik = (rmsPik + pikBuf) / 2.0f;
//agcLevel == текущий уровень ару
if (locNowAgc < agcLevel) { // всплеск или питч V, идем вниз ..........................
stopGoingUp = 0;
//заполним блок
if (i > 0) {
for (uint16_t z = i; z <= upIdx; z++) {
buffer[z] *= locNowAgc;//применить новый коэфф
}
} else {//механизм сочленения с пред фреймом ...ждем первого нуля
if (buffer[0] > 0) direction = 1;//напрвление вверх (положительная синусоида)
exit = 1;
uint16_t idx0 = 0;
while (exit) {
exit = 0;//выходим
if (direction) {//+++++++++++++++++++++++++++++
if (buffer[idx0] > 0) {
idx0++;
exit = 1;//не выходим
}
} else { //------------------------
//going up
if (buffer[idx0] < 0) {
idx0++;
exit = 1;//не выходим
}
}
}//while
for (uint16_t z = 0; z <= upIdx; z++) {
if (z <= idx0)buffer[z] *= agcLevel;//применить старый коэфф
else buffer[z] *= locNowAgc;//применить новый коэфф
}
}
tim = 10;//задежка отпускания
if ((pit2 < pit1 && pit1 < pikBuf)) {//смотрим следующий питч если
agcLevel = locNowAgc;
// agcLevel -= (agcLevel - locNowAgc) / 1;
tim = 30;//задежка отпускания
} else if ((pit2 < pit1 && pit1 > pikBuf)) {//смотрим следующий питч если
agcLevel -= (agcLevel - locNowAgc) / 5;
} else {
agcLevel -= (agcLevel - locNowAgc) / 2;
}
pit2 = pit1;
pit1 = pikBuf;
} else {//идем вверх/////////////////////////////////////////////////////////////////////
float32_t cc;
if (tim == 0) {//подождали и начинаем
cc = agcLevel + (locNowAgc - agcLevel) / 600;
//проверим можем нет еще откатить
if (rmsFrame * cc < max - 0.3f && !stopGoingUp) {//дельта отката 0.4
agcLevel = cc;
} else stopGoingUp = 1; //остановить откат
}
//заполним полупериод
for (uint16_t z = i; z <= upIdx; z++) {
buffer[z] *= agcLevel;//применить новый коэфф
}
}
i = upIdx; // след цикл будет стратовать от upIdx
} else { //это сидуация редкая но тоже надо . сделано по класике одного замера
if (nowAgc < agcLevel) { // всплеск V
agcLevel -= (agcLevel - nowAgc) / 2;
// tim = 10;//задежка отпускания
}
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
rmsFrame = (rmsFrame + rmsPik) / 2.0f;
agcMetr = agcMetrTemp; //s-meter
-
дерьмо пришло к нам в семью сегодня ночью
грёбанный вирус , забирает близких cry333
-
dontt44 У сестры тоже все болеют... no88
-
розовый шум имеет спектр -6 дБ/октава.
Нет, спад 3дб/октава
-
спад 3дб/октава
Согласен... dontt44
-
Замеры, замеры, замеры
Идет CW WW
Запись с WEB SDR Тульского.
3 варианта записи
1. Тульский АРУ выключен, работает только моя платка и мое АРУ
2. Работает Тульское АРУ и мое АРУ
3. Только Тульский WEB SDR, моя платка отключена физически.
PS несложно заметить, что мое ару спасает на 2-3 дб тульское ару, а если вообще без меня то стучит безбожно морзянка и всплески до 10дб ....это абзац.
-
...
-
А я тут опять сел за АРУ
Проблема в том , что нельзя просто применить коэффициент к полупериоду, и даже к полному периоду. И даже нельзя применить последовательное наращивание коэффициента. Все это приводит к изменению синуса (как на картинке).
На фото как раз работа ару по полупериоду. Такой подход стучит и это видно на анализаторе.
-
Что делать? dontt44 Нужно восстанавливать синусоиду. Мне кажется от пика до пика следующей полуволны. И работать нужно по разному. Тот пик который мы занижаем (реакция на всплеск) мы просто умножаем на 0.ХХ коэффициент и тем самым мы этот полупериод прижимаем ближе к 0. НО! с предыдущем пиком нельзя также делать, у него растет горб. Там нужен другой коэффициент, и причем пик этой полуволны трогать нельзя он должен остаться. Смежные скаты полуволн похожи на улитку. С каждым шагом увеличивается радиус улитки.
Вот я и говорю, синусоиду нужно восстанавливать.
-
Вот этот более наглядней
-
Если идет от 0 изменение амплитуды , то вроде все ок, легкое расширение спектра и всё, но если точка изменение амплитуды отстоит от 0 то спектр разливается почти до конца. Не так конечно как при ступеньке, но все же его видно и слышно.
-
Эксперименты продолжаются. Надо почти полностью алгоритм переделывать. Сейчас я меняю амплитуду скачкообразно внутри системы без АЦП
-
А любое изменение формы даёт расширение спектра, как правило, если будут какие-то острые углы, то расширение с более длинным хвостом, если плавное - с более коротким. dontt44
Кстати, в искажении спектра нескольких периодов трагедии-то нет никакой, я уже выпал из темы - Вы по какой-то ПЧ типа 15...20 кГц работаете, или же, прямо на НЧ пытаетесь работать? cr123
-
Прямо по НЧ ару делаю, полностью цифровую
-
как правило, если будут какие-то острые углы, то расширение с более длинным хвостом, если плавное - с более коротким
Вот и я про то же, нифига нельзя проходить одним множителем по положительной и отрицательной полуволне, даже не так.... по скату правому+ и смежному ему левому-
Там расчет надо другой.
-
А всё-таки, напомните - Вы на НЧ АРУ делаете, или же на низкой ПЧ? cr123
-
Прям 0-3кГц
-
Прям 0-3кГц
Тогда примите мои соболезнования - это путь в никуда... dontt44 pl33 lol22
-
Спортивный зуд покоя не дает cr123
Уже лучше чем в web сдр получилось. Хочу полностью от этого стука уйти.
Да и алгоритм одинаковый, что для вч что для нч. Это же цифра.
-
Спортивный зуд покоя не дает
Да направьте его в конструктивное русло - насколько помню, у Вас же была какая-то ПЧ, типа 10...30 кГц, именно по ней и нужно работать, альтернативы просто нет иной, не может быть физически универсального алгоритма для частот, отличающихся на порядок - там же хотя бы тайминги должны быть разными.
В точности та же фигня, что и с компрессированием... lol22
-
Да неее, Игорь, здесь тема DDC там по другому ни как. Там же только цифра и нет ПЧ вообще. Битность на входе потом перенос на низкие частоты и всё, 32 бита чистого оцифрованного звука. Вот по нему и надо АРУ пройтись.
-
А, понял. 1yep dontt44 pl33
-
Пока не поддается lllol
Нужно больше математики.
Алгоритм написал и переделал.
(на фото какой-то из вариантов, причем не самый лучший)
-
Такое ощущение, что вписался еще какой-то переходный процесс по входу звуковой. Почему кривая синусоида ?
Скорость нарастания скатов левого и правого разная?
(на фото стандартные константы для + и для - полуволн)
-
Этот кривой синус только на переходном процессе, или всё время? cr123
-
Только на переходном процессе.
-
У Вас же, как помню, с буфером работа, сделайте отработку АРУ за пару миллисекунд до появления сигнала... cr123
-
по скату правому+ и смежному ему левому
я строил правильную синусоиду между отрицательным и положительным экстремумами, пренебрегая где там уровень нуля. Получалось очень гладко, потому что сшивалось там где производная ноль - в плагине Адоба Аудишена. Сейчас надо бы в СТМ32 попробовать...
-
сшивалось там где производная ноль
Кстати, правильный ход - минимум мусора на сшивке. А при переходе через ноль производная максимальна... 1yep 1999 lol22
-
Очень интересно. Простым нарастанием коэффициента не получилось всё равно ломается синус.
Там блин скаты по нарастание у полупериода не симметричны. А идея просто заново нарисовать скат осень хорошая. Математику Не подкинете ? cr123
-
t= 2*(pikIdxPlus-pikIdxMinus)
-------------------------------
24000
f=1/t ;// частота синуса , который надо нарисовать
амплитуды не симметричные.
А=|pikVPlus| + |pikVMinus| ; //amplituda sin
//смещение амплитуды относительно 0 вверх вниз, потом просто добавить к результату
Smeschenie= (|pikVPlus| - |pikVMinus|)/2 ;
рисовать синус надо будет от PI/2 до 3PI/4 те от -1 до 1 фаза
Шаг
delta = (float32_t) ((2 * 3.14159265359 *f) / 24000);
float32_t phase=PI/2;
for (int i = pikIdxPlus; i <= pikIdxMinus; i += 1) {
saiTxBank[saiTxBankNowNumber][ i ] =A * arm_sin_f32(phase)+Smeschenie;
phase += delta;
}
-
Пока так ....
Один скат выровнял, но еще что то есть ..
-
О! восстановил
На фотках то один фронт восстанавливается, то другой. (все в центре)
Та просто 4 вариант прихода полуволн:
#define mP 1 //minus PLUS
#define pM 2 //plus MINUS
#define Mp 3 //MINUS plus
#define Pm 4 //PLUS minus
Два я сделал остались еще 2 самых сложных
..один из вариантов
if (variant == mP) {
if (z < uPikIxxMinus) {
buffer[z] *= locPik;
}
if (z >= uPikIxxMinus && z<=uPikIxxPlus ) {
float32_t rate = 24000.0f;
float32_t t = 2.0f * (uPikIxxPlus - uPikIxxMinus -0.0f) / rate;
float32_t freqS = 1.0f / t;
float32_t Am = (uPikVPlus*locNowAgc + uPikVMinus*locPik)/2.0f;
float32_t Sm = (uPikVPlus*locNowAgc - uPikVMinus*locPik) / 2.0f;
float32_t deltaFreq = (2.0f * PI * freqS) / rate;
float32_t phase = PI / 2.0f;
uint16_t ii;
for ( ii = uPikIxxMinus; ii <= uPikIxxPlus; ii += 1) {
buffer[ii] = -Am * arm_sin_f32(phase) - Sm;
phase += deltaFreq;
}
z=ii;
}
if (z>uPikIxxPlus) {//пиковая полуволна
buffer[z] *= locNowAgc;
}
-
Вот так музыка.... уже диких всплесков нету lol22
маленький успех.
-
Математику Не подкинете
на самом деле если подвигать точку пересечения нуля вправо/влево, там обязательно существует точка где обе синусоиды (разного периода!) сшиваются гладко - с равными односторонними производными. Поскриплю мозгами вспомню. А пока более простой вариант: как провести косинусоиду если известны оба соседних экстремума и время между ними. Когда оба экстремума одинаковы а = в то вырождается в обычный косинус.
-
Спасибо, вы тоже самое написали что и я до чего допер. lol22
Сшивается идеально!
-
Сейчас сижу думаю....у меня один скат восстанавливает синус, а потом всё... а надо бы еще следующий тоже причесать, но не могу условие подобрать по которому будет запускаться алгоритм именно "этого" ската, ведь АРУ уже отработало и следующий пик не является новым максимумом.
Короче надо поспать с этой мыслью...хотя направление я уже понял куда топать.
-
по моему опыту, ловить точку пересечения нуля бесполезно - там шум всегда вырубает любой навороченный алгоритм. А экстремумы почти всегда торчат из шума и легко определяются. Их достаточно чтобы восстановить любую кривую между ними. Даже не синусоиду а степенные функции проводил - на слух (мой) почти без разницы.
-
Да так и есть. Так и сделано.
-
Вот восстановленный скат
-
Если завтра время будет переделаю весь алгоритм в очередной раз.
Направление однозначно правильное.
Я сейчас прыгаю по полному периоду, а завтра попробую скакать только от пика до пика.
-
О! я ваааще огонь алгоритм придумал! Там вообще без разницы шум не шум.
...берем два полупериода (включая шум внутри, который не пересекает 0). Ищем Максимум. И если надо занижать - занижаем полностью полупериод и бросаем его. Смотрим следующий полупериод...если он опять требует занижения - занижаем и восстанавливаем левый скат. Потом опять берем полупериод и его не надо уже занижать, то просто восстанавливаем опять левый скат. И так далее
Особенность этого подхода в том что нужно искать два ближайших к краю пика, и пофиг что между ними.
Вот так работать будет !
-
Если я правильно понял, то Вы собираетесь сделать почти искусственный (синтезированный) сигнал из исходного.
ПС Не знаю, к чему приведут поиски решения, но я бы обратил внимание на замечание Игоря про ПЧ, пусть и очень низкую. О том, что здесь нет ПЧ я помню, напоминать не требуется. Поясню, почему поддерживаю Игоря. Здесь мыслится принципиальное математическое ограничение на корректность обработки непосредственно на НЧ при полосе 0,3 - 3,0 кГц. Это широкополосный сигнал и ориентироваться на набор неких пиковых данных о сигнале, для последующего его воссоздания (синтезирования) по этим отсчётам, в принципе невозможно (информация в каком-то объёме обязательно будет теряться), ибо нарушение теоремы отсчётов/Котельникова. А вот применение ПЧ, даже очень низкой, например 19 кГц, кардинально меняет картину.
-
искусственный (синтезированный) сигнал из исходного
это сводится к философскому вопросу что есть голос и чем он отличается от последовательности "неких пиковых данных", соединенных гладкими синусоидами. Я пробовал сделать это, программируя плагин Адоба Аудишена - голос пропадал в грохоте, который то и шумом назвать нельзя. Скорее всего надо учитывать и экстремумы второго порядка, которые с одной стороны нуля.. но это усложнение теряет смысл казалось бы простого алгоритма синтеза.
-
в широкополосном сигнале принципиально невозможен подход с заменой реального сигнала на последовательность "неких пиковых данных" и последующей аппроксимацией отрезками синусоид между точками. Это легко понять и без высшей математики, если рассмотреть период времени, когда преобладает амплитуда самой низкой частоты, на которую наложено много меньшее напряжение максимальной частоты. Реальный сигнал будет виден на осциллографе, как постоянный сдвиг нулевого отсчёта для уровня ВЧ компоненты по закону изменения НЧ компоненты, пиковые же данные оставят информацию только об НЧ компоненте. Получится некий суррогат фильтра НЧ с плавающей частотой среза, а при компонентах близкого уровня, должна быть "каша".
-
Сколько времени потрачено а конца и края пока не видно. АРУ должна быть простая и безмозглая как валенок. И работать она должна не по максимуму сигнала а по минимуму, приводя ДД сигнала к комфортному
-
Все получится. У монстров сдр-строения же получается и у нас получится.
Я вот много уже картинок показывал , и там у полупериода оба ската с щербинками , даже если один скат наладить сигнал на слух становится чище и щелчки превращаются в глухие удары.
Да, я ломаю сигнал если в одном полупериода больше одного пика ... будет один ))) это своеобразный фильтр получается . По сути это и есть фильтр очень качественный и жесткий, но иначе спектр разливается.
-
С нч частотами очень все плохо, я уже говорил об этом. Чисто математически если мы хотим уменьшить задержку сигнала при прохождении через ару и тд, то надо снижать размер буфера и это приведёт к тому , что мы не сможем обработать период нч частоты. Придётся просто прижимать его к 0 множителем и стук будет обязательно. Конечно установка фнч 1000 порядка перед и 500 порядка после АРУ помогает, но не сильно. Всплески (у меня сейчас) не дотягивают 30-40 дБ до пика сигнала при такой расстановке фнч. Но лучший результат если сперва 500 потом 1000 порядка поставить ))) но это самообман. Фнч и так проц грузит ого как.
-
Можете уточнить, зачем уменьшать задержку на столько?
-
например adau1701 практически нет задержки.
У меня при 24000 частоте и 1024 замеров в блоке- задержка около 50мс потом полетело в цап еще столько на ацп итого 100мс задержка только в моей системе.
В аналоге эта цифра в районе нескольких мс (зависит от КФ или ЭМФ)
-
итого 100мс задержка только в моей системе
Сергей, чем больше мозгов вы пытаетесь впихнуть в АРУ тем больше будет эта задержка. Как человек с высшим тматьматическим я могу сказать вам что при устремлении ее (задержки) к бесконечности АРУ станет ну просто идеальной. Но совершенно бесполезной :)
ЗЫ а за 100мс задержки телеграфисты вас могут и ... тапками закидать rrr7777
-
Здесь сейчас не важно какая будет задержка, она уменьшится в 2 раза при переходе на 48000 и будет 50мс, потом можно уменьшить буфер до 512 замеров и будет 25мс , но уже проблемы будут с процессором. Геннадий, когда-нибудь запустит стм157 на 800МГц - вот на нем можно будет эксперименты делать и с 25мс. и даже с 96кГц сэмплированием - вот тогда это будет практически аналоговый звук.
АРУ вов всех вариантах будет ...либо работать либо стучать.
Да, лист программы очень серьезный...для не профессионала. Там же сплошные условия. Если не все учесть результат один - будет стучать )))
-
Не поможет вам увеличение семплирования, поверьте. Только проц нагрузите
-
Так, ну я синус восстановил , разлива спектра нет, но я все равно слышу момент появления тональника в виде легко «ух»
Приеду посмотрю , что там получилось с музыкой, маленько времени не хватило.
-
Причём , я поставил самые кабальные режимы работы ару. Минимальная задержка 100 мс и очень агрессивное восстановление уровня после снятия сильного сигнала.
Кстати, восстановление тоже малёк разливает спектр. По идеи , восстановление после снятия сигнала тоже надо синус восстанавливать
-
Не помогло nea33
На фото видно где восстановление прошло
-
Как и ожидалось, алгоритм сметает часть информации под синус.
-
Широкополосный сигнал.
-
Да, зато как с тональником все красиво
-
Начинаем все с начала. 123123
Есть идея. Не рисовать синус.
-
Вашу бы энергию да в мирное русло. То направление куда вы пытаетесь идти - тупиковое. Если бы там все было хорошо - были бы реализации в том числе и в исходных кодах. Но их нет
-
Фигня, я это часто слышу.
Вот теперь "так" будем думать....
600Гц + 2900Гц
-
Текущая работа ару (ожидаемо съедала все вторичные пики) как здесь на фото, отсюда полный швах в наушниках.
-
Отпала тема восстановления скатов полностью. Был проделан вариант при котором просто скат сжимается в соответствии с sin от 0 до 1 это значит , что пик который не надо сжимать localAGCmax (множитель) умножается на 0 и пик остается на месте, а тот пик который надо занизить по итогу (по закону sin) localAGCmax умножается на 1 и пик слетает вниз в соответствии с расчетом.
Короче была сделана попытка реализовать алгоритм резинки которая растягивается в середине и применить его к скату.
Результат тот же - где-то все ломается хотя глазом на осциллограмме не видно. И иногда алгоритм уходил в конкретный блуд, который я не смог найти.
-
Новая тема ! cr123
Надо собирать данные за несколько фрэймов и не поднимать усиление выше "чем..."
тем самы сделать ворота, про которые я сам много раз писал и делал.
Вот пример ворот (sweep амплитуды ) он не дает падать меньше чем на 4дБ
отсюда и будем плисать
-
А я сделал , что хотел.
lol22
-
Да ладно... cr123
-
Оказалось морзянка самым лучшим тестером.
Лучший вариант получил при воротах 7-8дб с учетом анипитч. Завтра покажу все, сейчас уже глаза не видят.
-
Кстати, Игорь, я сделал по итогу как вы говорили... плавный спад усиления к пику за 5-10мс
А так же полностью переделал системы возврата усиления ...там еще та песТня.
-
Вот пример ворот (sweep амплитуды ) он не дает падать меньше чем на 4дБ
отсюда и будем плисать
А теперь переверните график алгоритм вверх ногами :) Есть шумовая дорожка. Не дадим сигналы превысить ее более чем на N дб :)
-
Вот интересный тест свипом амплитуды 0..-50дб
(смотреть на водопад)
-
А теперь переверните график алгоритм вверх ногами Есть шумовая дорожка. Не дадим сигналы превысить ее более чем на N дб
то есть сигнал-шум всего навсего N дб будет. В чем прикол?
-
А вот тот же тест, но ворота 0. Алгоритм пытается сделать плоский эфир
-
Вот 80 с web sdr
Ну что-то сильно хорошо получилось.
(ворота 0дб)
-
Я не очень пойму, что хорошего, когда верхняя граница ровная как стол?
-
Я не очень пойму, что хорошего, когда верхняя граница ровная как стол?
Это значит, что вылетов за пределы нету. Само ару работает ниже. Сегодня записи сделаю.
Кстати там есть задержка отпускания и плавный подъем усиления - все как и планировалось и все регулируется.
Понятие «Ворота» это как раз и есть промежуток в дБ который убирает плоскость эфира . Громкие будут слегка громче тихих.
-
Так что в итоге получиться должно, по задумкам? А то уже кажется, что это будет ровно та же аналоговая АРУ, только данные для управления извлекаются из цифрового потока, цифрой же и обрабатываются.
-
Новая АРУ
(вариант 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
}
-
Так что в итоге получиться должно, по задумкам? А то уже кажется, что это будет ровно та же аналоговая АРУ, только данные для управления извлекаются из цифрового потока, цифрой же и обрабатываются.
В идеале не должны хвосты разлива спектра быть. Вот сейчас их видно но не слышно.
(на спектре 3кГц и выше голубые полоски. Это как раз и есть разлив спектра)
И кстати, аналоговое ару никогда не будет такой ровной. Всегда будет присутствовать первый выброс в несколько дб (чем меньше вылет - тем лучше). А в цифре можно сделать абсолютно ровное все. Пример: при аналоге морзянка будет подстукивать при первом включении.
http://analogtrx.com/SMF/index.php?topic=100.msg5857#msg5857
это приме моего ару в аналоге. Тест примерно похож на то , что показал с свип амплитудой
-
В идеале не должны хвосты разлива спектра быть
В аналоговом режиме расширение спектра можно посчитать сразу по Фурье, перемножив две временные функции - сигнала и Ку(t) тракта под действием АРУ, затем посчитав интеграл Фурье для полученной функции. Рассматривая в частотной области, произведение двух функций во временной области есть свёртка в частотной. Из второго очевидно, что спектр расширится на величину, равную максимальной частоте в спектре функции сигнала Ку(t). Понятно, что при оценке ширины спектра мы должны задавать некую нижнюю границу для амплитуды плотности спектральных составляющих, ниже которой считаем, что составляющих нет. При работе аналоговой АРУ максимальные компоненты в спектре Ку(t) появляются при резком её изменении, что происходит при появлении мощного сигнала. Учитывая, что всегда есть определённая задержка между сигналом и управлением, получаем, что пик спектральных составляющих функции Ку(t) попадает как раз на время, когда сигнал тоже практически максимального уровня, ограниченного только линейностью тракта или принудительно лимитером. Вот тут и возникает всплеск расширения спектра. Если сигнал управления действовал бы ещё до появления мощного сигнала, то он промодулировал бы сигнал обычного уровня или ещё меньшего, в случае прослушивания шума (мы же не выводим шум на уровень нормальной громкости).
ПС Хвосты есть и будут всегда, вопрос в их уровне.
-
вот "эта" щербинка разливает спектр и ее слышно
-
Понятно, что при оценке ширины спектра мы должны задавать некую нижнюю границу для амплитуды плотности спектральных составляющих, ниже которой считаем, что составляющих нет.
Мы ее слышать не должны. Это всего лишь недоработки алгоритма. Надо копать.
-
А объективно, в цифрах, сколько это?
Вы сейчас проверяете на реальном сигнале? Это окончательная проверка должна быть. Входной сигнал ведь можно сгенерировать программно, обработать, просмотреть спектр, временную характеристику. Для всего этого вообще ничего не надо, кроме компьютера.
У Вас там три точки, где уширение спектра, две очень существенные. На осциллограмме видно только одно место, где первая производная испытывает разрыв. Спектр в большем интервале времени показан?
-
Я беру сигнал без ару с тульского сдр. Он полностью оцифрован и там разливов нет.
Походу как я не бегал от стыковки фрэймов никуда от нее не деться. Вот на фото не с того появляется козявка. По алгоритму: он вообще не должен в этом месте что-то править, однако правит. Вариант один...это 2 периода с обеих сторон фрейма (с начала и с конца).
-
по виду, там сшивка прямым отрезком.
Стандарт натуральной цифровой записи звука обозначается, как РСМ (Pulse Code Modulation) Wave. В процессе записи через определенные промежутки времени регистрируется текущая амплитуда звуковой волны, в результате чего получаются как бы моментальные снимки (фреймы) звуковой волны. Из последовательности этих фреймов и состоит звукозапись, носящая название waveform.
Здесь фрейм, это просто амплитуда в моменты дискретизации, у Вас фрейм, это что?
-
Сшивок больше нет. Прохожусь плавным коэффициентом Х....1 назад . Я последний (первый по очереди) вообще на 1 умножаю.
Фрэйм 1024 ацп замеров
-
Я так и подумал, что у Вас фрейм это набор отсчётов.
Я про сшивку не в алгоритме, а смотря на кривую сигнала. Там очевидная вставка прямого отрезка.
-
Это не вставка, это так выглядит переходный процесс если точки не в синусе. Это так цепи ЦАПа и входные цепи звуковой платы изображают. Вообщем переходный процесс.
-
Будем залазить в предыдущий фрейм, который уже ушел под управления ДМА для выброса этого буфера в ЦАП. Фрэйм 1024 точек, мне надо залезти с конца точек на 50 или около того. Надеюсь ДМА еще не успеет дойти до этих мест, а то буде коллизия, когда и ДМА и ПРОЦ будут обращаться к одной и тойже ячейке памяти. Неприятная ситуация будет.
-
Новая АРУ
(вариант 4)
Это язык Си для STM32, насколько понимаю.
А это корректный код Вы вставили для обозрения?
if (a > 0)nowAgc = max / a;
else nowAgc = max / 0.000005f;
нет пробела после условия и далее нет двух пар фигурных скобок
float32_t почему так записывается тип float ? Зачем там 32_t ?
-
Если один оператор после if или else то {} можно не ставить. float32_t это float , но такая запись в листинге программы очень хорошо выхватывается на фоне всего.
Код корректный ....это вы так шутите ))) ?
-
еще короче :)
nowAgc = max / (a > 0? a : 0.000005f);
-
А пробел тоже можно не ставить?
То есть, допустимы оба варианта записи типа с плавающей запятой, один просто float, второй с явным указанием разрядности числа? А float16_t тоже можно применять, как и для целочисленных переменных?
Шуток никаких нет, я спросил у Вас, вместо того, чтобы лезть в среду Си и проверять, это мне надо было комбайн целый запускать, не двумя кликами реализуется.
-
еще короче
ага, для постоянно работающих с Си нормально наверное, а для обучающегося лучше не спешить с сокращениями. Один написал в теле цикла вместо индекса a[i+1] a[i++], а потом долго искал ошибку.
ПС ra0ahc, давно подумываю тоже попрограммировать STM, но никак не соберусь. Подскажете, если что, для начала в технической части, по отладочным платам, или как они там называются? Один кристалл же никуда не приткнёшь, надо на плате распаянный иметь
-
Nucleo H7 - есть ваше всё
Среда разработки от ST у них сейчас неплохая среда.
float16_t не бывает, только float64_t cr123
-
if (a)nowAgc = max / a;
else nowAgc = max / 0.000005f;
и
nowAgc = max /(a?a: 0.000005f);
мне кажется первый будет работать быстрее(на сколько я помню ассемблер там один такт на это условие)...хотя фиг знает
в нашем случаи
nowAgc = max /(a+0.000005f); тоже будет работать и не на что не повлияет. Всеравно потом приводит к 12 битам.
-
Одинаково они будут работать. Оптимизаторы в компиляторах давно уже заоптимизированы :)
-
от ST у них сейчас неплохая среда
Как называется среда что на картинке? А то я запускаю Geany c Ubuntu и компилирую руками.
-
CLion от JetBrains
-
Просидел еще пару дней ...
Сделал "залаз" в соседний фрейм - однозначно помогло, прям сильно.
Остались "вот такие" фантомы ....убился искать какое событие из вызывает.
Ну в а целом (смотрим на панораму) без этих аномалий уже можно сказать, что это "ОНО"
-
НАШЕЛ ГДЕ КОСЯК
Вот записи в разных режимах.
Залетов и вылетов в аут не заметил.
https://drive.google.com/drive/folders/1Qnh064SKTlaO3RvhifW4HqcNGI8yzb9P?usp=sharing
-
SSB CW
Скорость АРУ - нормальная. Ворота 4дб. Задержка на отпускания 100мс
-
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 uOldPStartIdx;
float32_t uOldPikV;
uint16_t wait = 5;
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;
uint16_t pikCount = 0;
if (tim > 0)tim--; //уменьшение задержки
stopGoingUp = 0;
uint16_t uLastNullIdx = 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;
float32_t pikBuf;
uint8_t exit = 1;
uint8_t exitYN = 0;
uint16_t wait = 0;// 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;
exit = 1;
}
//центральная точка
if ((buffer[upIdx] > 0 && buffer[upIdx + 1] <= 0) && upIdx + 1 < FRAME_SIZE && !exitYN) {
uLastNullIdx = upIdx;
}
//если условие остановило в -- то добиваем его до 0 и выходим
if ((buffer[upIdx] <= 0)) {
exitYN = 1; //не дадим пред условию сработать
if (p1 > uPikVMinus) uPikVMinus = p1;
exit = 1;
}
} else { //------------------------
//going up
//если условие остановило в -- то добиваем его до 0 и выходим
if ((buffer[upIdx] <= 0 && !exitYN)) {
if (p1 > uPikVMinus) uPikVMinus = p1;
exit = 1;
}
//центральная точка
if ((buffer[upIdx] <= 0 && buffer[upIdx + 1] > 0) && upIdx + 1 < FRAME_SIZE && !exitYN) {
uLastNullIdx = upIdx;
}
//если условие остановило в ++ то добиваем его до 0
if ((buffer[upIdx] > 0)) {//
exitYN = 1; //не дадим пред условию сработать
if (p1 > uPikVPlus) uPikVPlus = p1;
exit = 1;
}
}
if (upIdx + 1 < FRAME_SIZE && exit) upIdx++;
else exit = 0;//выходим
}//while
if (upIdx + 1 == FRAME_SIZE) {} else upIdx -= 1;
if (upIdx > i) { //если блок не пустой то...
//upIdx -= 1;
float32_t locNowAgc;
if (uPikVPlus > uPikVMinus) {
locNowAgc = max / (uPikVPlus ? uPikVPlus : 0.000001f);
pikBuf = (uPikVPlus ? uPikVPlus : 0.000001f);
} else {
locNowAgc = max / (uPikVMinus ? uPikVMinus : 0.000001f);
pikBuf = (uPikVMinus ? uPikVMinus : 0.000001f);
}
//типа среднее значение этого блока. исползуется для отката .
rmsPik += (uPikVPlus + uPikVMinus) / 2.0f;
pikCount++;//количество синусоид, нужен для расчета среднего пика по блоку
//agcLevel == текущий уровень ару
if (locNowAgc <= agcLevel) { // всплеск или питч V, идем вниз || wasVariant..........................
stopGoingUp = 0;
//заполним блок
for (uint16_t z = i; z <= upIdx; z++) {//(upIdx+1==FRAME_SIZE?uLastNullIdx:upIdx)
buffer[z] *= locNowAgc;
}
//откат усиления назад по блоку
//убират стук
if (locNowAgc != agcLevel) {
uint16_t d = 0;
float32_t dx = locNowAgc / agcLevel;
if (i == 0) {
uint16_t dmax =(( (uint16_t) (FRAME_SIZE - uOldPStartIdx))) ;
uint16_t index = 1;
uint16_t srI=FRAME_SIZE/2;
if(dmax<50)dmax=200;
while (d < dmax-1) {
uint8_t o = (uint8_t) (dacTxBankNawNumber ? 0 : 1);
d++;
int buf0 = (int) (pOutDac[o][srI - index] >>16) - 2047;
int buf1 = (int) (pOutDac[o][srI - index] & 0x0000ffff) - 2047;
// if (d < FRAME_SIZE - uLastNullIdx && uLastNullIdx > 0)
// pOutDac[o][FRAME_SIZE - index] = ((uint32_t) (buf0 * dx + 2047)) << 16;
// else
pOutDac[o][srI - index] = ((uint32_t) (buf0 * (dx + d * (1 - dx) / dmax) + 2047))<< 16;
d++;
// if (d < FRAME_SIZE - uLastNullIdx && uLastNullIdx > 0)
// pOutDac[o][FRAME_SIZE - index] |= ((uint32_t) (buf1 * dx + 2047)) ;
// else
pOutDac[o][srI - index] |=
((uint32_t) (buf1 * (dx + d * (1 - dx) / dmax) + 2047)) ;
index++;
// pOutDac[o][srI - index]=0xffffffff;
}
// buffer[i]=0;
} else {
float32_t dmax = (i - uOldPStartIdx);
if (dmax <= 0 || uOldPStartIdx == 0) dmax = i;
while (d < dmax) {
d++;
buffer[i - d] *= dx + d * (1 - dx) / dmax;
}
}
}
//питч детектор
stopGoingUp = 0;
//tim = wait;//задежка отпускания
if ((pit2 < pit1 && pit1 < pikBuf)) {//не питч
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;
float32_t oldAgcLevel = agcLevel;
if (tim == 0 && upIdx + 10 < FRAME_SIZE && i > 100) {//подождали и начинаем x
cc = agcLevel + (sred / rmsNow) / 50.5f;
//проверим можем нет еще откатить
if (pikBuf * cc < max - 0.2f && !stopGoingUp) {//дельта отката 0.4
agcLevel = cc;
} else {
stopGoingUp = 1; //остановить откат
}
}
float32_t kof = agcLevel / oldAgcLevel;
uint16_t dmax = (upIdx - i);
//заполним период
for (uint16_t z = i; z <= upIdx; z++) {
buffer[z] *= oldAgcLevel * (kof + (upIdx - z) * (1 - kof) / dmax);//применить новый коэфф
}
}
uOldPStartIdx = i;
i = upIdx; // след цикл будет стратовать от upIdx
} else { //это сетуация редкая но тоже надо . сделано по класике одного замера
stopGoingUp = 0;
if (nowAgc < agcLevel) { // всплеск V
// tim = wait;//задежка отпускания
buffer[i] *= nowAgc;
} else {
buffer[i] *= agcLevel;
}
uOldPStartIdx = i;
}
uLastNullIdx = 0; //на случай если больше не будет центра
if (a > agcMetrTemp) agcMetrTemp = a; //s-meter макс V
}//for
// buffer[0] = 0;
//средний V за этот блок и прошлые (отсчет по пикам)
//нужен для ограничения усиления при снятия сигнала
float32_t mm = rmsPik / pikCount;
if (mm > rmsFrame)rmsFrame = mm;
else rmsFrame = (rmsFrame + mm) / 2.0f;
agcMetr = agcMetrTemp; //s-meter
}
-
Убрал все лишнее и написал коменты
loat32_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 uOldPStartIdx;
uint16_t wait = 20;//задержка возврата ару, в блоках 40мс каждый блок
///@brief АРУ
///@param buffer
void agcDo(float32_t *buffer) {
float32_t rmsPik = 0;
float32_t agcMetrTemp = 0;
float32_t pit1 = -1;
float32_t pit2 = 0;
uint16_t pikCount = 0;
if (tim > 0)tim--; //уменьшение задержки
stopGoingUp = 0;
for (uint16_t i = 0; i < FRAME_SIZE; i++) {
float32_t a;
a = fabsf(buffer[i]);
if (a > 0)nowAgc = max / a;
else nowAgc = max / (a?a:0.000005f);
uint16_t upIdx = i;
float32_t pikBuf = 0;
uint8_t exit = 1;
uint8_t exitYN = 0;
//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) {//+++++++++++++++++++++++++++++
if ((buffer[upIdx] > 0 && !exitYN)) {
if (p1 > pikBuf) pikBuf = p1;
exit = 1;
}
if (buffer[upIdx] <=0 ) {// добиваем его до 0 и выходим
exitYN = 1; //не дадим пред условию сработать
if (p1 > pikBuf) pikBuf = p1;
exit = 1;
}
} else { //------------------------
//going up
if ((buffer[upIdx] <= 0 && !exitYN)) {
if (p1 > pikBuf) pikBuf = p1;
exit = 1;
}
if (buffer[upIdx] >0 ) {// добиваем его до 0
exitYN = 1; //не дадим пред условию сработать
if (p1 > pikBuf) pikBuf = p1;
exit = 1;
}
}
if (upIdx + 1 < FRAME_SIZE && exit) upIdx++;
else exit = 0;//выходим
}//while
if (upIdx + 1 == FRAME_SIZE) {} else upIdx -= 1;
if (upIdx > i) { //если блок не пустой то...
//upIdx -= 1;
float32_t locNowAgc;
locNowAgc = max / (pikBuf ? pikBuf : 0.000001f);
//типа среднее значение этого блока. используется для отката .
rmsPik += pikBuf;
pikCount++;//количество синусоид, нужен для расчета среднего пика по блоку
//agcLevel == текущий уровень ару
if (locNowAgc <= agcLevel) { // всплеск или питч V, идем вниз ..........................
stopGoingUp = 0;
//заполним блок
for (uint16_t z = i; z <= upIdx; z++) {
buffer[z] *= locNowAgc;
}
//откат усиления назад по блоку
//убирает стук
if (locNowAgc != agcLevel) {
uint16_t d = 0;
float32_t dx = locNowAgc / agcLevel;
//если начало фрэйма
if (i == 0) {//лезим в старый буфер который уже летит в цап
uint16_t dmax = (uint16_t) (FRAME_SIZE - uOldPStartIdx);
uint16_t index = 1;
uint16_t srI = FRAME_SIZE / 2;//в цап летят 16 битные данные
if (dmax < 50)dmax = 200;//нагло , можно уменьшить
while (d < dmax - 1) {
uint8_t o = (uint8_t) (dacTxBankNawNumber ? 0 : 1);
d++;
//плавное уменьшение назад по старомы фрейму от dx до 1
int buf0 = (int) (pOutDac[o][srI - index] >> 16) - 2047;
int buf1 = (int) (pOutDac[o][srI - index] & 0x0000ffff) - 2047;
//первые 16 бит
pOutDac[o][srI - index] = ((uint32_t) (buf0 * (dx + d * (1 - dx) / dmax) + 2047)) << 16;
d++;
//вторые 16 бит
pOutDac[o][srI - index] |=
((uint32_t) (buf1 * (dx + d * (1 - dx) / dmax) + 2047));
index++;
}
} else {//просто откат на один период с уменьшением.
float32_t dmax = (i - uOldPStartIdx);
if (dmax <= 0 || uOldPStartIdx == 0) dmax = i;
//плавное уменьшение назад по фрейму от dx до 1
while (d < dmax) {
d++;
buffer[i - d] *= dx + d * (1 - dx) / dmax;
}
}
}
stopGoingUp = 0;
//питч детектор
//нужно добавить еще уменьшение скорости отката и потом его возрат
//для полной обработки питчиков
if ((pit2 < pit1 && pit1 < pikBuf)) {//не питч
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;
float32_t oldAgcLevel = agcLevel;
//первый период и последний не поднимаем
if (tim == 0 && upIdx + 10 < FRAME_SIZE && i > 100) {//подождали и начинаем x
cc = agcLevel + (sred / rmsNow) / 50.5f; // скорость отката 200...0.5
//проверим можем нет еще откатить
if (pikBuf * cc < max - 0.2f && !stopGoingUp) {//дельта ВОРОТА 0.3=8дб
agcLevel = cc;
} else {
stopGoingUp = 1; //остановить откат
}
}
float32_t kof = agcLevel / oldAgcLevel;
uint16_t dmax = (upIdx - i);
//заполним период , плавно!!!
for (uint16_t z = i; z <= upIdx; z++) {
buffer[z] *= oldAgcLevel * (kof + (upIdx - z) * (1 - kof) / dmax);//применить новый коэфф
}
}
uOldPStartIdx = i;
i = upIdx; // след цикл будет стратовать от upIdx
} else { //это ситуация редкая, но тоже надо . сделано по класике одного замера
stopGoingUp = 0;
if (nowAgc < agcLevel) buffer[i] *= nowAgc;
else buffer[i] *= agcLevel;
uOldPStartIdx = i;
}
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
}
-
Скорость АРУ - нормальная. Ворота 4дб. Задержка на отпускания 100мс
Вы обрезаете ось времени на спектрограмме? Не видно интервалы времени.
Что за сигнал подаёте?
По спектрограмме видно, что АРУ в постоянной работе у Вас, спектр постоянно разлетается на всю высоту (ширину полосы 7 кГц)
-
Он и будет разливаться вы же сами говорили. Просто раньше прям ступеньки проскакивали и их капец как слышно , а сегодня я победил их. Вверху чёрный водопад и на нем видно разлив на сколько.
Там фишка в чем с этим разливом: если нужно резко убрать усиление то мы умножаем на понижающий коэффициент часть фрейма у меня это один период от 0 до 0. Так появляются изломы ко лове спектр разливаю жестко и далеко и его слышно хоть и нет перегрузки по напряжению , просто цок в наушниках и все. Так вот, мне нужно сгладить этот перелом . Я беру и начинаю идти обратно плавно изменяя этот коэффициент. Эта обратная дороги моде в один период выйти , а может и в пару мс. И чем плавнее мы идём тем меньше разлив. Пока все просто . Теперь возьмём крайние варианты, а точнее переход между фреймами, там самое веселое было прогнать плавным коэффициентом. Прогнал - заработало. Теперь нам надо сделать тоже само с тем когда сил ней сигнал уходит и нам надо усилить сигнал тоже перемножив его на коэффициент. И там тоже происходит разлив спектра , поэтому я и там сделал плавный коэффициент и всё получилось.
-
Не смотрел, как у Вас в коде написано, потому мог не так понять со слов, но показалось, что делаете подобное тому, как я графики обрабатываю. Прохожу по всем значениям весовой функцией а-ля кривая Гаусса, только количество точек маленькое - 5, 7.
Вы не откомментировали, почему АРУ постоянно в работе, что за сигнал?
-
Интересные у вас задачки , я про ваши графики. Вроде что то подобное для фильтрация импульс использовать надо. Рисуем ачх потом как раз проходим импульсом по нему и типа фильтр готов.
Про ару
Я специально загнал ару в самый жесткий режим : почти мгновенный откат, 0дб ворота- типа плоский эфир, 0 время задержки (вообще не ждём и сразу после снятия сигнала начинаем поднимать усиление) . По этому кажется что ару постоянно работает ... хотя так и есть. Сигнал реального эфира с вэб сдр Тульского сайта, там я отключаю ихнее ару и на вход своей платы завожу сигнал без ару , и уже ару работает в моей платке. Понятно , что я не смогу получить такую же чуйку из-за 12 битного ацп у меня, ну да не суть , я же ару делал с не приставку к компу. Этот алгоритм может быть будет работать в ddc трансивере на базе Аиста с новым процессором.
-
Немного теории.
-
скорее так (см. ниже):
"АРУ с задержкой" звучит лучше, где "угол преломления" около RS: 56-58.
Так не теряем усиление при слабых сигналах, а эфир чист, "прозрачен" на низких уровнях, и уровень немного повышается на сильных (напр. не нужно смотреть на S-метр, кто сильнее), а и усиление в ограничение никогда не доходит, даже при самых сильных входных сигналах.
диаграмма взята из:
Исследование систем автоматической регулировки усиления (ару) и автоматической подстройки частоты (апч) (https://gigabaza.ru/doc/45247.html)
-
Нет, Веселин, это другое. Нам же нужно тихий сигнал поднимать до уровня идеальной ару прямо с самого 0. Нам надо слышать "шум эфира" . Нет там на выходе спада выходного сигнала на наушники до 0, мы всегда слышим шум достаточной громкости.
-
"АРУ с задержкой" звучит лучше,
Даже спорить не буду. Просто задержку во времени сложно изобразить. Она (задержка) будет задерживать откат усиления после снятия сильного сигнала. Хотя это всего лишь переменная настройки АРУ - можно делать и "с" и "без" задержки
-
Да, "АРУ с задержкой" точно так, см. начало х-ки.
А "задержка" в имени (и в действии), ето задержка по уровень (реакции по уровень), а не по время (откат усиления после снятия сильного сигнала).
(А все действия условно без задержки по время реакции. Если необходимо - то интегратор: аналоговой или у вас - с цифровой метод: повторяем или постепенно уменьшаем уровень с нач. уровнем предыдущего накопления)). Пфу, нет у меня русс. слова, вероятно говорим для тех же вещей, но теряется при переводе BG-RU, RU-BG, sorry).
-
График не правильный. Увы, но в нем ошибка. Либо мы в терминологии запутались.
Я имею ввиду, что если вытащить антенну , то мы услышим шум точно такой же , что и с антенной (понятно другого оттенка) по уровню. А на этом графике, если вытащить антенну то в наушниках будет 0. Понятно, что это можно регулировать "воротами", что собственно и сделано. Из экспериментов я пришел к выводу, что 7-9дб ворот -это в самый раз.
-
А "задержка" в имени (и в действии)
А зачем она? Это пережитки аналогового радио, там всегда будет всплеск работы ару из-за задержак работы цепей обратной связи (скаты кф и эмф)
Кстати, он всегда "бьет по ушам"
-
там всегда будет всплеск работы ару
Ето всплеск только при АРУ при НЧ детекция сигнала для АРУ.
При детекция по ПЧ нет такой. Почему запутались не знаю, там реакция мгновенная (начальная).
Послушайте, померите какое нибудь старое радио. Там у почти всех АРУ с детекция с помощью ПЧ сигнала.
Всплеск началной нет. Мгновенно.
Точно "удар по ушам" мне не нравится в АРУ по НЧ, и он только при НЧ-АРУ, где сигнал для рег. цепь взят через детекция НЧ.
(при детектор по ПЧ: "есть много полу-синусоид за эти напр. 0,1 микросекунды".
при детектор по НЧ (300-3000 Hz) полу-синусоид для детекции примерно 1000...3000 раза меньше)
А если предположить, что энергия больше в басах, отношение становится довольно грубо.
-
Немного истории lllol
Всё-таки 5 вариантов было. Учитывая полное отсутствие практики в математики , пришлось на «пальцах» саму себе помогать lllol
-
Ето всплеск только при АРУ при НЧ детекция сигнала для АРУ.
Нет, он всегда будет, вопрос сколько по времени. У ЭМФ и КФ есть задержка, вот она всему виной. Сигнал вылетит пока не сработает АРУ.
Делал сам, тестил сам. Есть целая ветка, как я боролся с всплеском когда делал Монстро-DSP.
-
Все сложно, и я говорю конечно "на первое приближение" мгновенно. Вы понимаете меня.
t детекция 200 Hz >> много раз t детекция 9000200 Hz начало фронта.
Не понимаю как не работает так. Даже при RS-53 на 59+60 фронт очень прямоугольный с детекция по ПЧ. Сплеск нет. Что детекторовали для АРУ в Монстро-DSP? сигнал ПЧ? или сигнал НЧ?
-
Все сложно, и я говорил конечно "на первое приближение" мгновенно. Вы понимаете меня.
t детекция 200 Hz >> много раз t детекция 9000200 Hz начало фронта.
Не понимаю как не работает так, даже при RS-53 на 59+60 фронт очень прямоугольный.
Что детекторовали? сигнал ПЧ?
Для аналогового радио - это работает. Точнее не работает, НЧ детекция - плохо. Но для цифрового радио -это нормально. Там всегда будет задержка (особенности технологии) и в это время можно успеть сделать нормальный сигнал без выбросов по амплитуде.
-
Да, понял. Нет ПЧ в тип цифрового радио (обработка НЧ), как выбрали. Идем на метод с дорогой АЦП :). С все ц. обработки - после антенны.
-
График не правильный.
График правильный, там нарисован идеальный усилитель и его принцип регулировки усиления, усилитель который не шумит, а на его вход подаётся сигнал. Шум ли это эфира, полезный ли сигнал или даже свой собственный шум, приведённый ко входу, значения не имеет.
-
У ЭМФ и КФ есть задержка, вот она всему виной. Сигнал вылетит пока не сработает АРУ.
Но эти ФОС ведь не обязательно находятся в петле обратной связи, какая разница тогда сколько они задержки вносят?
-
У ЭМФ и КФ есть задержка, вот она всему виной. Сигнал вылетит пока не сработает АРУ.
Но эти ФОС ведь не обязательно находятся в петле обратной связи, какая разница тогда сколько они задержки вносят?
Еще как находятся. Они фильтруют потом этот сигнал уже попадает в петлю АРУ а потом опять фильтруют, ПЧ то 2. Да вообще то песня старая.
А график как усилитель - наверное да правильный, но как ару нет нет и еще раз нет.
-
Все сложно, и я говорю конечно "на первое приближение" мгновенно. Вы понимаете меня.
t детекция 200 Hz >> много раз t детекция 9000200 Hz начало фронта.
ВЧ сигнал имеют огибающую и эти много ВЧ импульсов, при АРУ по ПЧ, будут заряжать конденсатор фильтра АРУ лишь до текущего уровня огибающей, а для работы АРУ нужен некий средний уровень именно огибающей. В этом плане как раз отличий сразу и не видно, могу предположить, что огибающая по ВЧ имеет немного меньший диапазон чем НЧ сигнал, пики сигнала прижаты.
-
Они фильтруют потом этот сигнал уже попадает в петлю АРУ а потом опять фильтруют, ПЧ то 2
Это я немного не в курсе конкретно этого изделия, в таком случае в аналоговом АРУ надо две петли, по каждой ПЧ.
-
У Игоря в Монстре так и есть, 2 петли АРУ. Это жесть. Я задолбался их уравновешивать. Они последовательно идут. В цифре этого ничего нет. Есть только сигнал в 16 бит - "и делай с ним что хош"
-
Я задолбался их уравновешивать.
А я, сколько делал, пока что не морозился на эту тему ни разу... cr123 pl33
-
Так у вас цап и ацп не было ))))
-
cr123
-
Продолжение тут
http://analogtrx.com/SMF/index.php?topic=667.0