📄 lecmse.cpp
字号:
/*-------------------------------------------------------------------------*
* *
* THIS IS AN UNPUBLISHED WORK CONTAINING CONFIDENTIAL AND PROPRIETARY *
* INFORMATION. IF PUBLICATION OCCURS, THE FOLLOWING NOTICE APPLIES: *
* "COPYRIGHT 2001 MICHAEL TSIROULNIKOV, ALL RIGHTS RESERVED" *
* *
*-------------------------------------------------------------------------*/
#if !defined _dsp
#include <memory.h>
#include <math.h>
#include <stdlib.h>
#else
#include <string.h> /* memcpy() */
#endif
#include "stddefs.h"
#include "leci.h"
/*--------------------- local defs ----------------------------------------*/
#define _ERL_MAX LEC_DB(25)
#define _ERL_DIFF LEC_DB(0.5)
#define _MSE_MIN LEC_DB(-8)
/*--------------------- public vars ---------------------------------------*/
/*--------------------- local vars ----------------------------------------*/
#if defined (_dsp)
#endif
/*--------------------- local functions -----------------------------------*/
/*-------------------------------------------------------------------------*/
static void _get_mse_erl
/*-------------------------------------------------------------------------*/
(
LEC_tDb *pDb,
LEC_tSc *pSc
)
{
S16 *psAdf = pDb->asAdf2;
S32 slEn0;
S32 slEn1;
S16 sEn0;
S16 sEn1;
S16 k;
slEn0 = lec_pkt_energy(psAdf);
slEn1 = 0;
for (k = 0; k < LEC_FRAMES; k++)
{
psAdf += ILEC_FR_SZ;
slEn1 += lec_pkt_energy(psAdf);
}
sEn0 = -lec_en2log(slEn0)+350;
sEn1 = -lec_en2log(slEn1)+350; // this is ERL
// if MSE is ok, then this sERL is better to use than sErlAveraged
// 1024 = 6Db per 1 shift
pSc->sERL = sEn1 + pDb->Adf2.sShift*1024; // <<10;
pSc->sMSE = sEn1 - sEn0 + LEC_DB(6); // < 0 if OK, and shall be much < 0
/// ERL stabilization
// if some degree of convergence achieved,
// i.e. the filter is different from pure 0
// then do averaging, otherwise - it's too early
if (pSc->sERL < _ERL_MAX)
{
lec_avrg(&pDb->Adf2.sERL,pSc->sERL, Q15(0.03));
}
}
/*-------------------------------------------------------------------------*/
static void _set_update_flt_mode_not_converged
/*-------------------------------------------------------------------------*/
(
LEC_tDb *pDb,
LEC_tSc *pSc
)
{
if (
// flt 2 is better than flt 1 in terms of ERLE
(pDb->sErrOverrideCnt > LEC_DB(10)) &&
// if MSE is somethings more or less real
(pDb->Adf2.sMSE < 0) &&
// if flt2 is better than flt 1 in terms of MSE
(pDb->Adf2.sMSE < pDb->Adf1.sMSE) &&
// flt 2 is improving
(pDb->Adf2.sMSE > pSc->sMSE)
)
{
pSc->uFltCpyMode = 1;
}
else // keep adapting
{
pSc->uFltCpyMode = 3;
}
}
/*-------------------------------------------------------------------------*/
static void _set_update_flt_mode_converged_dt
/*-------------------------------------------------------------------------*/
(
LEC_tDb *pDb,
LEC_tSc *pSc
)
{
pSc->uFltCpyMode = 3;
// no copy, keep converging, unless convergence is very good.
if (pDb->sErrOverrideCnt > LEC_DB(20))
{
S16 sErleDlt = pDb->sErrOverrideCnt;
S16 sMseDlt = pDb->Adf2.sMSE - pDb->Adf1.sMSE;
sErleDlt = (S16)((Q15(0.80) * (S32)sErleDlt)>>16);
if ((sErleDlt - sMseDlt) > 0)
{
pSc->uFltCpyMode = 1;
}
}
else if (pDb->sErrOverrideCnt > LEC_DB(10))
{
// flt2 is at least as good as flt1 in terms of MSE
if ((pDb->Adf2.sMSE < (pDb->Adf1.sMSE + LEC_DB(0.25))) &&
// current flt2 is good
(pDb->Adf2.sMSE > pSc->sMSE))
{
pSc->uFltCpyMode = 1;
}
}
}
/*-------------------------------------------------------------------------*/
static void _set_update_flt_mode_converged
/*-------------------------------------------------------------------------*/
(
LEC_tDb *pDb,
LEC_tSc *pSc
)
{
// flt 2 is much better than flt 1 in terms of ERLE
if (pDb->sErrOverrideCnt > LEC_DB(10))
{
pSc->uFltCpyMode = 1;
}
// flt 2 is somehow better than flt 1 in terms of ERLE
else if ((pDb->sErrOverrideCnt > LEC_DB(5)) &&
// even if MSE1 and MSE 2 are about the same
(pDb->Adf2.sMSE < (pDb->Adf1.sMSE + LEC_DB(0.5))) &&
// current MSE is alright
(pDb->Adf2.sMSE > pSc->sMSE))
{
pSc->uFltCpyMode = 1;
}
// flt 2 is better than flt 1 in terms of ERLE,
// continuous update
else if ((pDb->sErrOverrideCnt > LEC_DB(0.5)) &&
// and MSE
(pDb->Adf2.sMSE < pDb->Adf1.sMSE) &&
// and current MSE is alright
(pDb->Adf2.sMSE > pSc->sMSE))
{
pSc->uFltCpyMode = 1;
}
else // no visible improvements
{
// keep adapting
if (pSc->sMSE < (pDb->Adf1.sMSE + LEC_DB(5)))
{
pSc->uFltCpyMode = 3;
}
else // or reset back to 1: screwed up...
{
pSc->uFltCpyMode = 2;
}
}
}
/*-------------------------------------------------------------------------*/
static void _set_update_flt_mode
/*-------------------------------------------------------------------------*/
(
LEC_tDb *pDb,
LEC_tSc *pSc
)
{
S16 sMseCoef = 0;
_get_mse_erl(pDb, pSc);
// actions:
// if ERL is still unstable
if (abs(pSc->sERL - pDb->Adf2.sERL) > _ERL_DIFF)
{
// if erl has not stabilized yet, do not copy in any case
pSc->uFltCpyMode = 3;
sMseCoef = Q15(0.25);
}
else // erl has stabilized
{
// if not converged yet
if (pDb->Adf1.sMSE > _MSE_MIN)
{
sMseCoef = Q15(0.125);
_set_update_flt_mode_not_converged(pDb, pSc);
}
else // may be converged
{
if (pDb->uIsDT)
{
sMseCoef = Q15(0.25);
_set_update_flt_mode_converged_dt(pDb, pSc);
}
else // no double talk recognized
{
sMseCoef = Q15(0.05);
_set_update_flt_mode_converged(pDb, pSc);
} /* if : DT */
} /* if : converged */
} /* if: ERL stabilized */
lec_avrg(&pDb->Adf2.sMSE, pSc->sMSE, sMseCoef);
}
/*-------------------- public functions -----------------------------------*/
/*-------------------------------------------------------------------------*/
void lec_convergence_control
/*-------------------------------------------------------------------------*/
(
LEC_tDb *pDb,
LEC_tSc *pSc
)
{
pSc->sErle = pSc->sRxEn - pDb->VadErr.sEn;
if ((pSc->sErle > 0) && (!pDb->uIsDT))
{
S32 sl = pSc->sErle * (S32) (pSc->sJ0 - 5500);//4096);
sl >>= (15+2);
if (sl < 0) sl = 0;
pDb->Adf2.slAcc += sl;
if (pDb->Adf2.slAcc >= LEC_SLACC_MAX)
{
pDb->Adf2.slAcc = LEC_SLACC_MAX;
if (pDb->Adf2.uConverged == 1)
{
lec_shift_adf2(pDb, pSc);
}
pDb->Adf2.uConverged = 2;
}
else if (pDb->Adf2.slAcc > LEC_SLACC_MAX/2)
{
pDb->Adf2.uConverged = 1;
}
else
{
pDb->Adf2.uConverged = 0;
}
}
}
/*-------------------------------------------------------------------------*/
void lec_compare_adfs
/*-------------------------------------------------------------------------*/
(
LEC_tDb *pDb,
LEC_tSc *pSc
)
{
// if any adaptation happened
if (pSc->uAdaptMode & 0x000c )
{
pSc->sErr2En = lec_en2log(lec_pkt_energy(pSc->asErr2));
pDb->sErrOverrideCnt += (pSc->sErr1En - pSc->sErr2En)>>5;
if (pSc->sErr2En < pSc->sErr1En)
{
pSc->uFlags |= LEC_FLAG_ERROVERIDE;
/* prevent wrap-around */
if (pDb->sErrOverrideCnt > LEC_DB(70))
pDb->sErrOverrideCnt = LEC_DB(70);
/* if DT, do not make actual copy...
flt2 can get pretty crazy, doing all kinds of crazy stuff
we collect ErrOverrideCnt and that's it.
*/
if (!pDb->uIsDT)
lec_pkts_cpy(pSc->asErr1, pSc->asErr2, 1);
}
else /* use error from cancellation */
{
/* limit from below, by a small negative value,
to prevent spurious triggering of 2-1 copy.
*/
if (pDb->sErrOverrideCnt < LEC_DB(-6))
pDb->sErrOverrideCnt = LEC_DB(-6);
}
_set_update_flt_mode(pDb, pSc);
}
else ; // adaptation was off
}
/*-------------------------------------------------------------------------*/
void lec_update_flt
/*-------------------------------------------------------------------------*/
(
LEC_tDb *pDb,
LEC_tSc *pSc
)
{
switch(pSc->uFltCpyMode)
{
case 1: // flt1 (main filter) update
pDb->Adf1 = pDb->Adf2;
pDb->sErrOverrideCnt = 0;
lec_pkts_cpy(
pDb->asAdf1,
pDb->asAdf2,
LEC_FLT2_SZ/ILEC_FR_SZ
);
break;
case 2: // flt2 override - it got corrupted
pDb->Adf2 = pDb->Adf1;
// enforce re-test that ERL is OK, and insert a waiting period.
pDb->Adf2.sERL = 0;
pDb->sErrOverrideCnt = 0;
lec_pkts_cpy(
pDb->asAdf2,
pDb->asAdf1,
LEC_FLT2_SZ/ILEC_FR_SZ
);
break;
case 3:
default:
// do not copy, but continue to adapt
break;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -