Пока действует этот вариант, он значительно лучше Лайт варианта. Полностью переработана система отката ару (через поиск пика сигнала).
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
}