所谓发散问题就是在自适应滤波的过程中出现了权值不收敛的问题,一般是由于参考信号与近场数据时间点没有对齐引起的。当滤波器的权值不收敛的时候,自适应滤波器就不能正常的跟踪参考信号产生正确的的合成回声,以至于无法完成回声消除的功能,甚至自适应滤波器会产生一些乱七八糟的信号,淹没近端信号或产生音爆。
综上,回声消除过程中要对回声消除的残差进行监控,如果残差信号的能量超过了近场信号的数据,就说明出现了发散现象,此时要对残差信号进行修正;如果出现了残差信号的能量远超过近场信号能量的情况,说明自适应滤波器的权值已经严重偏离正常的收敛位置,应该讲滤波器的系数置零,避免出现音爆。
这个功能与添加舒适噪声一样,是非线性滤波处理的一部分。
static void OverdriveAndSuppressSSE2(AecCore* aec,
float hNl[PART_LEN1],
const float hNlFb,
float efw[2][PART_LEN1]) {
int i;
// 将向量元素全部设置为hNlFb
const __m128 vec_hNlFb = _mm_set1_ps(hNlFb);
// 设置单位向量
const __m128 vec_one = _mm_set1_ps(1.0f);
// 设置负单位向量
const __m128 vec_minus_one = _mm_set1_ps(-1.0f);
// 设置发散Sm?
const __m128 vec_overDriveSm = _mm_set1_ps(aec->overDriveSm);
// 向量计算
for (i = 0; i + 3 < PART_LEN1; i += 4) {
// Weight subbands,子带加权?
// 载入数据
__m128 vec_hNl = _mm_loadu_ps(&hNl[i]);
const __m128 vec_weightCurve = _mm_loadu_ps(&WebRtcAec_weightCurve[i]);
// 数据比较,选取较大的元素
const __m128 bigger = _mm_cmpgt_ps(vec_hNl, vec_hNlFb);
// 加权曲线*vec_hNlFb
const __m128 vec_weightCurve_hNlFb = _mm_mul_ps(vec_weightCurve, vec_hNlFb);
// 加权曲线*单位向量
const __m128 vec_one_weightCurve = _mm_sub_ps(vec_one, vec_weightCurve);
// 单位加权曲线进行非线性处理
const __m128 vec_one_weightCurve_hNl =
_mm_mul_ps(vec_one_weightCurve, vec_hNl);
// 与bigger进行与非逻辑运算
const __m128 vec_if0 = _mm_andnot_ps(bigger, vec_hNl);
// 两组数据进行与运算
const __m128 vec_if1 = _mm_and_ps(
bigger, _mm_add_ps(vec_weightCurve_hNlFb, vec_one_weightCurve_hNl));
// 两组数据进行或运算
vec_hNl = _mm_or_ps(vec_if0, vec_if1);
// 计算新的hNl
{
const __m128 vec_overDriveCurve =
_mm_loadu_ps(&WebRtcAec_overDriveCurve[i]);
const __m128 vec_overDriveSm_overDriveCurve =
_mm_mul_ps(vec_overDriveSm, vec_overDriveCurve);
vec_hNl = mm_pow_ps(vec_hNl, vec_overDriveSm_overDriveCurve);
_mm_storeu_ps(&hNl[i], vec_hNl);
}
// 抑制残差信号,生成新的残差功率efw序列
{
// 载入误差信号功率的实部与虚部
__m128 vec_efw_re = _mm_loadu_ps(&efw[0][i]);
__m128 vec_efw_im = _mm_loadu_ps(&efw[1][i]);
// 分别进行非线性处理
vec_efw_re = _mm_mul_ps(vec_efw_re, vec_hNl);
vec_efw_im = _mm_mul_ps(vec_efw_im, vec_hNl);
// Ooura fft returns incorrect sign on imaginary component. It matters
// here because we are making an additive change with comfort noise.
vec_efw_im = _mm_mul_ps(vec_efw_im, vec_minus_one);
_mm_storeu_ps(&efw[0][i], vec_efw_re);
_mm_storeu_ps(&efw[1][i], vec_efw_im);
}
}
// 对efw进行更新
for (; i < PART_LEN1; i++) {
// Weight subbands
if (hNl[i] > hNlFb) {
hNl[i] = WebRtcAec_weightCurve[i] * hNlFb +
(1 - WebRtcAec_weightCurve[i]) * hNl[i];
}
hNl[i] = powf(hNl[i], aec->overDriveSm * WebRtcAec_overDriveCurve[i]);
// Suppress error signal
efw[0][i] *= hNl[i];
efw[1][i] *= hNl[i];
// Ooura fft returns incorrect sign on imaginary component. It matters
// here because we are making an additive change with comfort noise.
efw[1][i] *= -1;
}
}