📄 lec.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 ----------------------------------------*/
/* the min erl we expect to be at least is 3 dB */
#define _ERL_OK_CNT (3)
/* only reused constants */
#define _ZC_NOISE_START LEC_DB(15)
/*--------------------- public vars ---------------------------------------*/
/*--------------------- local vars ----------------------------------------*/
#if defined (_dsp)
#endif
/*--------------------- local functions -----------------------------------*/
/*-------------------------------------------------------------------------*/
static void _vad_init
/*-------------------------------------------------------------------------*/
(
LEC_tVad *p,
S16 sEnNoise
)
{
p->sZcNoise = _ZC_NOISE_START;
p->sEnNoise = sEnNoise;
p->sEnNoiseMax = sEnNoise;
}
/*-------------------------------------------------------------------------*/
static S16 _vad_process
/*-------------------------------------------------------------------------*/
(
LEC_tVad *pVad,
S16 *psData
)
{
S16 sState = pVad->sState;
pVad->slEnergy = lec_pkt_energy(psData);
pVad->sEn = lec_en2log(pVad->slEnergy);
pVad->sZc = lec_pkt_zc(psData);
lec_vad_logic(pVad);
return (pVad->sState - sState);
}
/*-------------------------------------------------------------------------*/
static void _test_erl
/*-------------------------------------------------------------------------*/
(
LEC_tDb *pDb,
LEC_tSc *pSc
)
{
S32 slTmp = lec_pkt_energy(pSc->psRx);
pSc->sRxEn = lec_en2log(slTmp);
slTmp = pDb->asTxEn[2];
slTmp += pDb->asTxEn[3];
slTmp >>= 1;
pSc->sErl = (S16)slTmp - pSc->sRxEn;
/* we do not want to adapt on short spikes. there are very big chances
that it will bring no good at all, so we delay the start of
adaptation till we know for sure that it is not a transient process.
we end adaptation as soon as we see active RX. actually, it is
usually preceeded by a (possibly, very short) DT period
as a transition between TX and RX dominances.
*/
if (pSc->sErl > pDb->Cfg.sErlMin)
{
pDb->sErlOkCnt++;
if (pDb->sErlOkCnt > _ERL_OK_CNT)
{
pDb->sErlOkCnt = _ERL_OK_CNT;
pSc->uFlags |= LEC_FLAG_ERL_OK;
}
}
else
{
pDb->sErlOkCnt--;
if (pDb->sErlOkCnt < 0)
pDb->sErlOkCnt = 0;
}
}
/*-------------------------------------------------------------------------*/
static void _update_history
/*-------------------------------------------------------------------------*/
(
LEC_tDb *pDb,
LEC_tSc *pSc
)
{
/* shift old data in delay line one section down */
lec_pkts_cpy(
pDb->psHst,
pDb->psHst + ILEC_FR_SZ,
LEC_HST_FRAMES - 1);
/* add the new section to the end of the delay line */
lec_pkts_cpy(
pDb->psHst + (LEC_HST_SZ - ILEC_FR_SZ),
pSc->psTx,
1);
}
/*-------------------------------------------------------------------------*/
static void _ec_process
/*-------------------------------------------------------------------------*/
(
LEC_tDb *pDb,
LEC_tSc *pSc
)
{
lec_analyse_tx(pDb, pSc);
_test_erl(pDb, pSc);
lec_cancel_pkt(pDb, pSc, pSc->asErr1);
pSc->sErr1En = lec_en2log(lec_pkt_energy(pSc->asErr1));
pSc->sExpectedErrorEn = pSc->sRxEn - pDb->Adf2.sErleAveraged;
pSc->sStepSize = 0;
pSc->uAdaptMode = 0;
pSc->uFltCpyMode = 3;
if ((!(pDb->Cfg.uControl & ILEC_CMD_ADAPT_OFF)) &&
(pSc->uFlags & LEC_FLAG_ERL_OK) &&
(pDb->uTone == 0) &&
(!(pSc->uFlags & LEC_FLAG_HIRCV)))
{
pSc->uFlags |= LEC_FLAG_ADAPT;
if (!pDb->Adf2.uConverged)
{
pSc->uAdaptMode = 1;
lec_adapt_fast(pDb, pSc);
}
else
{
pSc->uAdaptMode = 2;
lec_adapt_slow(pDb, pSc);
}
}
lec_compare_adfs(pDb, pSc);
_vad_process(&pDb->VadErr, pSc->asErr1);
lec_convergence_control(pDb, pSc);
/* RxNoiseLevel is slowly rising from -80dBm */
if (pDb->VadErr.sState == LEC_VAD_ST_IDLE)
{
// noise level shall not be higher than backgrownd noise,
// the constant is empiric
lec_avrg(&pDb->sRxNoiseLevel, pDb->VadErr.sEnNoise, Q15(0.01));
}
lec_double_talk_detector(pDb, pSc);
lec_non_linear_processor(pDb, pSc);
lec_update_flt(pDb, pSc);
_update_history(pDb, pSc);
}
/*-------------------------------------------------------------------------*/
static void _update_statistics
/*-------------------------------------------------------------------------*/
(
LEC_tDb *pDb,
LEC_tSc *pSc
)
{
LEC_MIKET_tStts *pStts = &(pDb->Stts);
pStts->uFlags = 0;
if (pSc->uFlags & LEC_FLAG_ADAPT)
pStts->uFlags |= (1<<0);
if (pDb->VadErr.sState >= LEC_VAD_ST_ACTIVE)
pStts->uFlags |= (1<<1);
if (pSc->sTxEn >= LEC_DB(-35))
pStts->uFlags |= (1<<2);
if (pDb->uIsDT)
pStts->uFlags |= (1<<3);
if (pDb->Cfg.uControl & ILEC_CMD_ADAPT_OFF)
pStts->uFlags |= (1<<4);
if (pSc->uFlags & LEC_FLAG_ERL_OK)
pStts->uFlags |= (1<<5);
if (pDb->uTone)
pStts->uFlags |= (1<<6);
if (pSc->uFlags & LEC_FLAG_HIRCV)
pStts->uFlags |= (1<<7);
pStts->uFlags |= (pSc->uNlpMode << 8);
pStts->uFlags |= (pSc->uAdaptMode << 12);
pStts->sTxEn = (S16)((pSc->sTxEn * (65536L/17)) >> 16);
pStts->sRxInEn = (S16)((pSc->sRxEn * (65536L/17)) >> 16);
pStts->sErrEn = (S16)((pDb->VadErr.sEn * (65536L/17)) >> 16);
pStts->sErl = (S16)((pDb->Adf1.sERL * (65536L/17)) >> 16);
pStts->sErle = (S16)((pDb->Adf1.sErleAveraged * (65536L/17)) >> 16);
}
/*-------------------------------------------------------------------------*/
static void _reset_db
/*-------------------------------------------------------------------------*/
(
LEC_tDb *pDb,
U16 uZeroFilter
)
{
memset(pDb->psHst, 0, LEC_HST_SZ*sizeof(S16));
memset(pDb->psTxF, 0, LEC_HST_SZ*sizeof(S16));
if (uZeroFilter)
{
memset(pDb->asAdf1, 0, LEC_FLT2_SZ*sizeof(S16));
memset(pDb->asAdf2, 0, LEC_FLT2_SZ*sizeof(S16));
}
{
S16 *psHst = pDb->psHst;
ILEC_tCfg Cfg = pDb->Cfg;
memset(pDb, 0, sizeof(LEC_tDb));
pDb->Cfg = Cfg;
pDb->psHst = psHst;
pDb->psTxF = psHst + LEC_HST_SZ;
}
/* init db */
_vad_init(
&pDb->VadErr, // pDb
LEC_DB(-40) // en noise max
);
pDb->sRxNoiseLevel = LEC_DB(-70);
pDb->sClipLevel = LEC_DB(-70);
pDb->Adf2.sERL = pDb->Cfg.sErlMin;
}
/*--------------------- public functions ---------------------------------*/
/*-------------------------------------------------------------------------*/
void LEC_MIKET_init_db
/*-------------------------------------------------------------------------*/
(
void *p2db, /* data base */
const ILEC_tCfg *pCfg,
S16 *pHst /* tx history */
)
{
LEC_tDb *pDb = (LEC_tDb *)p2db;
pDb->psHst = pHst;
pDb->psTxF = pHst + LEC_HST_SZ;
pDb->Cfg = *pCfg;
pDb->Cfg.sErlMin *= 17;
pDb->Cfg.sClipThr *= 17;
_reset_db(pDb, TRUE);
}
/*-------------------------------------------------------------------------*/
void LEC_MIKET_control
/*-------------------------------------------------------------------------*/
(
void *p2db,
S16 sCmd,
ILEC_Status *pStatus
)
{
LEC_tDb *pDb = (LEC_tDb *)p2db;
if (pDb != NULL)
{
if (sCmd & ILEC_CMD_RESET)
{
/* do NOT zero filter coeffs */
U16 uZeroFilter = TRUE;
if (sCmd & ILEC_CMD_PRESERVE_ADF)
{
uZeroFilter = FALSE;
};
_reset_db(pDb, uZeroFilter);
sCmd &= ~(ILEC_CMD_RESET | ILEC_CMD_PRESERVE_ADF);
}
pDb->Cfg.uControl = sCmd;
}
pStatus->size = sizeof(ILEC_Status);
}
/*-------------------------------------------------------------------------*/
void LEC_MIKET_process
/*-------------------------------------------------------------------------*/
(
void *p2db,
void *p2sc,
S16 *psTx,
S16 *psRx,
S16 sIsTone
)
{
LEC_tDb *pDb = (LEC_tDb *)p2db;
LEC_tSc *pSc = (LEC_tSc *)p2sc;
if (pDb->Cfg.uControl & ILEC_CMD_OFF)
{
return;
}
else
{
memset(pSc, 0, sizeof(LEC_tSc));
pSc->psTx = psTx;
pSc->psRx = psRx;
if (sIsTone)
pSc->uFlags |= LEC_FLAG_TONE;
if (pDb->Cfg.uControl & ILEC_CMD_LOOPBACK)
{
S16 k;
for (k = 0; k < ILEC_FR_SZ; k++)
{
pSc->psRx[k] = (pDb->psHst[k + 83])>>2;
}
}
_ec_process(pDb, pSc);
_update_statistics(pDb, pSc);
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -