Это как раз те участки в которых нет питчей и ару их поднимает. И длина у них почти с фрейм (1024 замера ацп)
Цифровая АРУ 0...1
243433 просмотров, 284 ответов — стр. 9 из 19
12 ноября 2020 г. в 10:32#121
Я понял, что это за всплески 
Это как раз те участки в которых нет питчей и ару их поднимает. И длина у них почти с фрейм (1024 замера ацп)
Это как раз те участки в которых нет питчей и ару их поднимает. И длина у них почти с фрейм (1024 замера ацп)
12 ноября 2020 г. в 11:28#122
rms-детектор спасет отца русской демократии. Не надо за пички цеплятся. Их надо просто срезать лимитером после ару
13 ноября 2020 г. в 01:18#123
ну хорошо, rms, а дальше что с ним делать. Занижать битность ?
Есть у меня мысль ... питч чаще всего приходит в одной полярности и очень большой амплитуды. Так вот, а что если мне смотреть следующий за питчем пик и сделать вывод был это сигнал или просто вылет. Если второй пик тоже мощный то с большой долей вероятности это сигнал и нужно включать задержку с занижением амплитуды, а если следующий питчек мал и не является выбросом - то первый был питчек и мы не включаем задержку, а просто просаживаем питчек по амплитуде. Своеобразный шумодав получается.
Есть у меня мысль ... питч чаще всего приходит в одной полярности и очень большой амплитуды. Так вот, а что если мне смотреть следующий за питчем пик и сделать вывод был это сигнал или просто вылет. Если второй пик тоже мощный то с большой долей вероятности это сигнал и нужно включать задержку с занижением амплитуды, а если следующий питчек мал и не является выбросом - то первый был питчек и мы не включаем задержку, а просто просаживаем питчек по амплитуде. Своеобразный шумодав получается.
13 ноября 2020 г. в 01:52#124
я же говорил шумодав получится 
13 ноября 2020 г. в 05:41#125
Пока получается полная фигня
13 ноября 2020 г. в 06:52#126
google("feedforward agc");
14 ноября 2020 г. в 10:35#127
google("feedforward agc");спасибо я посмотрю обязательно.
14 ноября 2020 г. в 10:42#128
Война с питчиками оказалась весьма интересная.
веселья аж на 3 дня и три ночи. Цепануло так цепануло.

Вроде победил, но с одной оговоркой. Нужно вводить дельту на откат ару к максимальным усилениям. Что это значит: если постоянно держать сигнал около 1, без дельты, то происходит "стробирование" сигнала и постоянная качка то усиливаем то ослабляем. В наушниках как море и прибой со случайными времменными задержками. Кстати, самый честный сигнал для испытания ару - это розовый шум
он сразу все косяки вытаскивает.
Вот пример когда ару пытается держать 1 без дельты:
На водопаде хорошо видно стробирование сигнала по амплитуде. (я еще работаю над этим)
PS Контроль питчиков идет в 1мсек. Идет замер 2 пиков по 1мсек с контролем перехода через 0, то есть, там не ровно 1 мсек - плавает в зависимости от сигнала. Так вот, если второй пик не содержит больших амплитуд, то мы оставляем уровень ару до появления питчика. Ну конечно же сам питчик прижимается к нормальному уровню без перегруза.

Вроде победил, но с одной оговоркой. Нужно вводить дельту на откат ару к максимальным усилениям. Что это значит: если постоянно держать сигнал около 1, без дельты, то происходит "стробирование" сигнала и постоянная качка то усиливаем то ослабляем. В наушниках как море и прибой со случайными времменными задержками. Кстати, самый честный сигнал для испытания ару - это розовый шум
он сразу все косяки вытаскивает. Вот пример когда ару пытается держать 1 без дельты:
На водопаде хорошо видно стробирование сигнала по амплитуде. (я еще работаю над этим)
PS Контроль питчиков идет в 1мсек. Идет замер 2 пиков по 1мсек с контролем перехода через 0, то есть, там не ровно 1 мсек - плавает в зависимости от сигнала. Так вот, если второй пик не содержит больших амплитуд, то мы оставляем уровень ару до появления питчика. Ну конечно же сам питчик прижимается к нормальному уровню без перегруза.
14 ноября 2020 г. в 10:53#129
Новый вариант с контролем питчиков
Код: [Выделить]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
}
Код: [Выделить]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
}
14 ноября 2020 г. в 10:59#130
А вот так уже с дельтой по откату
14 ноября 2020 г. в 11:02#131
При этом на нормальном сигнале эта дельта не сказывается. Наверное будет заметна только в динамике.
14 ноября 2020 г. в 04:34#132
Сложный алгоритм работы ару приведет к тому что она будет жить своей жизнью и "дышать" вам в уши.
14 ноября 2020 г. в 04:50#133
Я ещё не закончил , но уже надоедает. Посмотрел алгоритм feed forward - это мы уже пошли. Шум сложнее всего обрабатывать. Все не предсказуемо. Длина фрейма всего 20 мсек сильно не наанализируешь. Но вообще я начал с левого ската , потом полупериод, потом период и сейчас уже несколько периодов длиной в 1 мсек анализирую. Я даже меж фреймовое сопряжение сделал. Выглядит страшно, но там просто много условий, а они выполняются в один такт. Пока я столкнулся с тем , что я не знаю до куда откатывать ару - это всегда сюрприз. Попадаешь в тихий участок без питчеков ару откатывает ещё (даёт усиление) и тут питчик прилетает и система сразу реагирует сильным снижением усиления. Причём может несколько секунд быть все ок , а потом прилетает. Но я ещё думаю. Далеко продвинулся. Но толи где-то ошибка либо просто не все учёл.
14 ноября 2020 г. в 07:41#134
Интересный эффект обнаружил

Борьба с питчиками привела к компрессии
Вот фото отката (после снятия сильного сигнала) ару начинает усиление и в правом верхнем углу хорошо видно как алгоритм начинает борьбу с питчиками и глатает их и при этом происходит компрессия сигнала. Естественно потом ару "просыпается" и скидывает вниз усиление.

Борьба с питчиками привела к компрессии
Вот фото отката (после снятия сильного сигнала) ару начинает усиление и в правом верхнем углу хорошо видно как алгоритм начинает борьбу с питчиками и глатает их и при этом происходит компрессия сигнала. Естественно потом ару "просыпается" и скидывает вниз усиление.
14 ноября 2020 г. в 11:30#135
И я снова удалил практически всё. Нужен был новый подход.
Наверное Андрей прав (опять) и нужно сигнал на лимиттер садить иногда.
Наверное Андрей прав (опять) и нужно сигнал на лимиттер садить иногда.