webRTC AEC 发散处理与抑制算法

所谓发散问题就是在自适应滤波的过程中出现了权值不收敛的问题,一般是由于参考信号与近场数据时间点没有对齐引起的。当滤波器的权值不收敛的时候,自适应滤波器就不能正常的跟踪参考信号产生正确的的合成回声,以至于无法完成回声消除的功能,甚至自适应滤波器会产生一些乱七八糟的信号,淹没近端信号或产生音爆。

综上,回声消除过程中要对回声消除的残差进行监控,如果残差信号的能量超过了近场信号的数据,就说明出现了发散现象,此时要对残差信号进行修正;如果出现了残差信号的能量远超过近场信号能量的情况,说明自适应滤波器的权值已经严重偏离正常的收敛位置,应该讲滤波器的系数置零,避免出现音爆。

这个功能与添加舒适噪声一样,是非线性滤波处理的一部分。

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;
  }
}

猜你喜欢

转载自blog.csdn.net/ljl86400/article/details/81080206