Webrtc delay-base-bwe代码分析(3): OveruseEstimator模块
2017-05-22 19:32
766 查看
@(webrtc)[webrtc, congestion control]
公式:
变量:
Webrtc delay-base-bwe代码分析(3): OveruseEstimator模块
该模块是一个卡尔曼滤波,根据当前到达时间差和传输大小的值,对到达时间差进行滤波,计算更精准的到达时间差。0. 卡尔曼滤波基础公式
从参考文档中获得基础公式及对应变量意义。公式:
变量:
1. OveruseEstimator的卡尔曼滤波公式
2. 代码分析
2.1 update
void OveruseEstimator::Update(int64_t t_delta, double ts_delta, int size_delta, BandwidthUsage current_hypothesis) { const double min_frame_period = UpdateMinFramePeriod(ts_delta); const double t_ts_delta = t_delta - ts_delta; double fs_delta = size_delta; ++num_of_deltas_; if (num_of_deltas_ > kDeltaCounterMax) { num_of_deltas_ = kDeltaCounterMax; } // Update the Kalman filter. // 误差矩阵 // 加上协方差,为配置初始化值。 // process_noise_ Q // P(k) = AP(k - 1)AT + Q // 预测方程2 // 2.3 E_[0][0] += process_noise_[0]; E_[1][1] += process_noise_[1]; if ((current_hypothesis == kBwOverusing && offset_ < prev_offset_) || (current_hypothesis == kBwUnderusing && offset_ > prev_offset_)) { E_[1][1] += 10 * process_noise_[1]; } // h观测矩阵 // 2.2 const double h[2] = {fs_delta, 1.0}; // P * h转置 // 2.4 const double Eh[2] = {E_[0][0]*h[0] + E_[0][1]*h[1], E_[1][0]*h[0] + E_[1][1]*h[1]}; // t_ts_delta 为 zk,residual为 zk - H * xk // 2.7 const double residual = t_ts_delta - slope_*h[0] - offset_; const bool in_stable_state = (current_hypothesis == kBwNormal); const double max_residual = 3.0 * sqrt(var_noise_); // We try to filter out very late frames. For instance periodic key // frames doesn't fit the Gaussian model well. if (fabs(residual) < max_residual) { UpdateNoiseEstimate(residual, min_frame_period, in_stable_state); } else { UpdateNoiseEstimate(residual < 0 ? -max_residual : max_residual, min_frame_period, in_stable_state); } // denom = h * P * ht + R,var_noise为测量噪声协方差 // 2.5 const double denom = var_noise_ + h[0]*Eh[0] + h[1]*Eh[1]; // K卡尔曼增益矩阵 // K(k) = Eh / (HPkHT + R) // 校正方程3 // 2.6 const double K[2] = {Eh[0] / denom, Eh[1] / denom}; // Ikh I-Kh // 2.9 const double IKh[2][2] = {{1.0 - K[0]*h[0], -K[0]*h[1]}, {-K[1]*h[0], 1.0 - K[1]*h[1]}}; const double e00 = E_[0][0]; const double e01 = E_[0][1]; // Update state. // 使用IKh更新误差矩阵 // P(k) = (I - Kh)P(k - 1) // 校准方程5 // 2.10 E_[0][0] = e00 * IKh[0][0] + E_[1][0] * IKh[0][1]; E_[0][1] = e01 * IKh[0][0] + E_[1][1] * IKh[0][1]; E_[1][0] = e00 * IKh[1][0] + E_[1][0] * IKh[1][1]; E_[1][1] = e01 * IKh[1][0] + E_[1][1] * IKh[1][1]; // The covariance matrix must be positive semi-definite. bool positive_semi_definite = E_[0][0] + E_[1][1] >= 0 && E_[0][0] * E_[1][1] - E_[0][1] * E_[1][0] >= 0 && E_[0][0] >= 0; assert(positive_semi_definite); if (!positive_semi_definite) { LOG(LS_ERROR) << "The over-use estimator's covariance matrix is no longer " "semi-definite."; } // 2.8 slope_ = slope_ + K[0] * residual; prev_offset_ = offset_; offset_ = offset_ + K[1] * residual; }
2.2 噪声更新
// 这个函数主要提供下面函数需要用到的ts_delta,这里不是直接使用 // 本次的ts_delta,而是根据历史时间窗口中最小时间值作为噪声估计中的ts_delta // 这个函数就是在一个固定的时间窗口中按时间顺序存放每一个ts_delta // 当数量超过时就从最早的时间开始pop // 然后遍历整个时间窗口选择最小的时间差值。 double OveruseEstimator::UpdateMinFramePeriod(double ts_delta) { double min_frame_period = ts_delta; if (ts_delta_hist_.size() >= kMinFramePeriodHistoryLength) { ts_delta_hist_.pop_front(); } std::list<double>::iterator it = ts_delta_hist_.begin(); for (; it != ts_delta_hist_.end(); it++) { min_frame_period = std::min(*it, min_frame_period); } ts_delta_hist_.push_back(ts_delta); return min_frame_period; } void OveruseEstimator::UpdateNoiseEstimate(double residual, double ts_delta, bool stable_state) { // 仅在Normal状态下更新噪声值。 if (!stable_state) { return; } // Faster filter during startup to faster adapt to the jitter level // of the network. |alpha| is tuned for 30 frames per second, but is scaled // according to |ts_delta|. double alpha = 0.01; if (num_of_deltas_ > 10*30) { alpha = 0.002; } // Only update the noise estimate if we're not over-using. |beta| is a // function of alpha and the time delta since the previous update. // 时间差越大,残差的比重越小 // 由于上面函数控制一个时间窗口,因此一个时间窗口内,其权重基本固定。 const double beta = pow(1 - alpha, ts_delta * 30.0 / 1000.0); // 更新均值 avg_noise_ = beta * avg_noise_ + (1 - beta) * residual; // 利用方差更新噪声值。 var_noise_ = beta * var_noise_ + (1 - beta) * (avg_noise_ - residual) * (avg_noise_ - residual); if (var_noise_ < 1) { var_noise_ = 1; } }
参考文档
1 卡尔曼滤波简介相关文章推荐
- Webrtc delay-base-bwe代码分析(4): OveruseDetector模块
- Webrtc delay-base-bwe代码分析(2): InterArrival模块
- Webrtc delay-base-bwe代码分析(5): AimdRateControl模块
- Webrtc delay-base-bwe代码分析(6): 整体分析
- Webrtc delay-base-bwe代码分析(1): RateStatistics模块
- 0.driverbase-自旋锁(SpinLock)wrk代码分析
- cocos2d-x 3.0 示例代码分析3:BaseTest
- wojilu系统的ORM代码解析-[源代码结构分析,ObjectBase基类分析]
- chrome代码中base::JSONReader类的阅读分析(一)
- C++卷积神经网络实例:tiny_cnn代码详解(10)——layer_base和layer类结构分析
- 结合代码分析--BaseServlet存在的意义(刚接触servlet的必看)
- python中BaseHTTPServer.py代码阅读分析
- 《linux 内核完全剖析》 由逻辑地址转换成线性地址代码分析 get_base get_limit 代码分析笔记
- OSChina App代码分析之BaseApplication
- osworkflow的config代码分析
- ORACLE常见错误代码的分析与解决(三)
- NT,2000,XP 的 CDROM 引导扇区代码分析
- XY52代码整理和分析
- 一个方向控制射击小游戏的代码分析!(AS1.0)
- little c原代码分析[一]