美文网首页webrtc技术探讨 webrtc
webrtc视频接收端带宽预测(二)---卡尔曼滤波

webrtc视频接收端带宽预测(二)---卡尔曼滤波

作者: ai___believe | 来源:发表于2017-06-08 14:52 被阅读384次

本文主要参考文章 http://www.xuebuyuan.com/1248366.html
接收端估计结合文档http://tools.ietf.org/html/draft-alvestrand-rtcweb-congestion-02以及源码webrtc/modules/remote_bitrate_estimator/overuse_detector.cc
添加了一些自己的理解。

webrtc中的带宽自适应算法分为两种:
1、发端带宽控制 
原理是由rtcp中的丢包统计来动态的增加或减少带宽,在减少带宽时使用TFRC算法来增加平滑度。
2、收端带宽估算
原理是并由收到rtp数据,估出带宽;用卡尔曼滤波,对每一帧的发送时间和接收时间进行分析,从而得出网络带宽利用情况,修正估出的带宽。

两种算法相辅相成,收端将估算的带宽发送给发端,发端结合收到的带宽以及丢包率,调整发送的带宽。

下面具体分析两种算法:


2 接收端带宽估算算法分析

Each frame is assigned a receive time t(i), which corresponds to the
time at which the whole frame has been received (ignoring any packet
losses). A frame is delayed relative to its predecessor if t(i)-t(i-
1)>T(i)-T(i-1), i.e., if the arrival time difference is larger than
the timestamp difference.
We define the (relative) inter-arrival time, d(i) as
d(i) = t(i)-t(i-1)-(T(i)-T(i-1))
Since the time ts to send a frame of size L over a path with a
capacity of C is roughly
ts = L/C
we can model the inter-arrival time as

d(i) = (L(i)-L(i-1))/C+ w(i) = dL(i)/C+w(i)

带宽估算模型:

d(i) = dL(i) / c + w(i) 

其中,d(i)两帧数据的网络传输时间差,dL(i)两帧数据的大小差, c为网络传输能力, w(i)是我们关注的重点, 它主要由三个因素决定:发送速率, 网络路由能力, 以及网络传输能力。w(i)符合高斯分布, 有如下结论:当w(i)增加是,占用过多带宽(over-using);当w(i)减少时,占用较少带宽(under-using);为0时,用到恰好的带宽。所以,只要我们能计算出w(i),即能判断目前的网络使用情况,从而增加或减少发送的速率。

可进一步表示成

 d(i) = dL(i) / C(i) + m(i) + v(i) 

其中,dL(i)两帧数据的大小差, c为网络传输能力,m(i)为网络抖动(可能大于0:比之前的网络延迟增大;也可以小于0:比之前的网络延迟减小),v(i)为测量误差

kalman-filters算法原理:
  • theta_hat(i) = [1/C_hat(i) m_hat(i)]^T // i时间点的状态由C, m共同表示,theta_hat(i)即此时的估算值
  • z(i) = d(i) - h_bar(i)^T * theta_hat(i-1) //d(i)为测试值,可以很容易计算出, 后面的可以认为是d(i-1)对d(i)的估算值, 因此z(i)就是d(i)的偏差,即residual
  • theta_hat(i) = theta_hat(i-1) + z(i) * k_bar(i) //好了,这个就是我们要的结果,关键是k值的选取,下面两个公式即是取k值的。最优估计值
  • k_bar(i) = (E(i-1) * h_bar(i)) / (var_v_hat + h_bar(i)^T * E(i-1) * h_bar(i))//k_bar(i)为卡尔曼增益,(var_v_hat + h_bar(i)^T * E(i-1) * h_bar(i))即为代码中的denom
  • E(i) = (I - K_bar(i) * h_bar(i)^T) * E(i-1) + Q(i) // h_bar(i)由帧的数据包大小算出,E(i)为估计误差协方差阵, Q(i)为过程噪声协方差
    由此可见,需要设置初始状态、非测量值的变量有E(0),Q(1),C_hat(0),m_hat(0),
    我们只需要知道当前帧的长度,发送时间,接收时间以及前一帧的状态,就可以计算出网络使用情况。

结合卡尔曼滤波的数学公式,可以看出基本匹配。

Paste_Image.png

接下来具体看一下代码

void OveruseDetector::UpdateKalman(int64_t t_delta,  
                                   double ts_delta,  
                                   uint32_t frame_size,  
                                   uint32_t prev_frame_size) {  
  const double min_frame_period = UpdateMinFramePeriod(ts_delta);  //最近60帧中,发送间隔最小值
  const double drift = CurrentDrift();  
  // Compensate for drift  
  const double t_ts_delta = t_delta - ts_delta / drift;  //即d(i)  
  double fs_delta = static_cast<double>(frame_size) - prev_frame_size;   
  
  // Update the Kalman filter  
  const double scale_factor =  min_frame_period / (1000.0 / 30.0);  
  E_[0][0] += process_noise_[0] * scale_factor;  //过程噪声协方差
  E_[1][1] += process_noise_[1] * scale_factor;  
  
  if ((hypothesis_ == kBwOverusing && offset_ < prev_offset_) ||  
      (hypothesis_ == kBwUnderusing && offset_ > prev_offset_)) {  
    E_[1][1] += 10 * process_noise_[1] * scale_factor;  
  }  
  
  const double h[2] = {fs_delta, 1.0}; //即h_bar  
  const double Eh[2] = {E_[0][0]*h[0] + E_[0][1]*h[1],  
                        E_[1][0]*h[0] + E_[1][1]*h[1]};  
  
  const double residual = t_ts_delta - slope_*h[0] - offset_; //即z(i), slope为1/C  
  
  const bool stable_state =  
      (BWE_MIN(num_of_deltas_, 60) * fabsf(offset_) < threshold_);  
  // We try to filter out very late frames. For instance periodic key  
  // frames doesn't fit the Gaussian model well.  
  if (fabsf(residual) < 3 * sqrt(var_noise_)) {  
    UpdateNoiseEstimate(residual, min_frame_period, stable_state);  
  } else {  
    UpdateNoiseEstimate(3 * sqrt(var_noise_), min_frame_period, stable_state);  
  }  
  
  const double denom = var_noise_ + h[0]*Eh[0] + h[1]*Eh[1];  
  
  const double K[2] = {Eh[0] / denom,  
                       Eh[1] / denom}; //即k_bar  
  
  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  
  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];  
  
  // Covariance matrix, must be positive semi-definite  
  assert(E_[0][0] + E_[1][1] >= 0 &&  
         E_[0][0] * E_[1][1] - E_[0][1] * E_[1][0] >= 0 &&  
         E_[0][0] >= 0);  
  
  
  slope_ = slope_ + K[0] * residual; //1/C  
  prev_offset_ = offset_;  
  offset_ = offset_ + K[1] * residual; //theta_hat(i)  
  
  Detect(ts_delta);  
}  
更新噪声估计

The variance var_v = sigma(v,i)^2 is estimated using an exponential
averaging filter, modified for variable sampling rate

var_v_hat = beta*sigma(v,i-1)^2 + (1-beta)*z(i)^2
beta = (1-alpha)^(30/(1000 * f_max))

where

f_max = max {1/(T(j) - T(j-1))}

for j in i-K+1...i is the highest rate at which frames have been captured by the camera the last K frames and alpha is a filter coefficient typically chosen as a
number in the interval [0.1, 0.001]. Since our assumption that v(i)
should be zero mean WGN is less accurate in some cases, we have
introduced an additional outlier filter around the updates of
var_v_hat. If z(i) > 3 var_v_hat the filter is updated with 3
sqrt(var_v_hat) rather than z(i). For instance v(i) will not be
white in situations where packets are sent at a higher rate than the
channel capacity, in which case they will be queued behind each
other.

结合代码可见,

var_v_hat = beta*sigma(v,i-1)^2 + (1-beta)*z(i)^2

并没有用z(i),而是用avg_noise_ -z(i)。

If z(i) > 3 var_v_hat the filter is updated with 3
sqrt(var_v_hat) rather than z(i)

这句话的实现内容如下:

  if (fabsf(residual) < 3 * sqrt(var_noise_)) {  
    UpdateNoiseEstimate(residual, min_frame_period, stable_state);  
  } else {  
    UpdateNoiseEstimate(3 * sqrt(var_noise_), min_frame_period, stable_state);  
  }  

可见,webrtc中使用的卡尔曼滤波器是一个自适应的滤波器,即噪声方差自适应变化。

void OveruseEstimator::UpdateNoiseEstimate(double residual,//测量值和预测值之差
                                           double ts_delta,//最小采样间隔
                                           bool stable_state) {
  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.1;// [0.1, 0.001]
  if (num_of_deltas_ > 10*kFrameNumberPerSec) {
    alpha = 0.001;
  }
  // 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 * kFrameNumberPerSec/ 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;
  }
}
过载检测

The offset estimate m(i) is compared with a threshold gamma_1. An
estimate above the threshold is considered as an indication of over-
use. Such an indication is not enough for the detector to signal
over-use to the rate control subsystem. Not until over-use has been
detected for at least gamma_2 milliseconds and at least gamma_3
frames, a definitive over-use will be signaled. However, if the
offset estimate m(i) was decreased in the last update, over-use will
not be signaled even if all the above conditions are met. Similarly,
the opposite state, under-use, is detected when m(i) < -gamma_1. If
neither over-use nor under-use is detected, the detector will be in
the normal state.
评价:思想正确,但是在具体实现要按实际设置gamma_1,gamma_2,gamma_3。
以及其他状态的阀值。

BandwidthUsage OveruseDetector::Detect(double ts_delta) {  
 if (num_of_deltas_ < 2) {  
   return kBwNormal;  
 }  
 const double T = BWE_MIN(num_of_deltas_, 60) * offset_; //即gamma_1  
 if (fabsf(T) > threshold_) {  
   if (offset_ > 0) {  
     if (time_over_using_ == -1) {  
       // Initialize the timer. Assume that we've been  
       // over-using half of the time since the previous  
       // sample.  
       time_over_using_ = ts_delta / 2;  
     } else {  
       // Increment timer  
       time_over_using_ += ts_delta;  
     }  
     over_use_counter_++;  
     if (time_over_using_ > kOverUsingTimeThreshold  //kOverUsingTimeThreshold是gamma_2, gamama_3=1  
         && over_use_counter_ > 1) {  
       if (offset_ >= prev_offset_) {  
         time_over_using_ = 0;  
         over_use_counter_ = 0;  
         hypothesis_ = kBwOverusing;  
       }  
     }  
   } else {  
     time_over_using_ = -1;  
     over_use_counter_ = 0;  
hypothesis_ = kBwUnderusing;  
   }  
 } else {  
   time_over_using_ = -1;  
   over_use_counter_ = 0;  
   hypothesis_ = kBwNormal;  
 }
UpdateThreshold(T, now_ms);  
return hypothesis_;  
}  
更新阀值
void OveruseDetector::UpdateThreshold(double modified_offset, int64_t now_ms) {
  if (!in_experiment_)
    return;

  if (last_update_ms_ == -1)
    last_update_ms_ = now_ms;

  if (fabs(modified_offset) > threshold_ + kMaxAdaptOffsetMs) {
    // Avoid adapting the threshold to big latency spikes, caused e.g.,
    // by a sudden capacity drop.
    last_update_ms_ = now_ms;
    return;
  }

  const double k = fabs(modified_offset) < threshold_ ? k_down_ : k_up_;
  const int64_t kMaxTimeDeltaMs = 100;
  int64_t time_delta_ms = std::min(now_ms - last_update_ms_, kMaxTimeDeltaMs);
  threshold_ +=
      k * (fabs(modified_offset) - threshold_) * time_delta_ms;

  const double kMinThreshold = 6;
  const double kMaxThreshold = 600;
  threshold_ = std::min(std::max(threshold_, kMinThreshold), kMaxThreshold);

  last_update_ms_ = now_ms;
}

注意:

threshold_ 和offset之前是一种相互影响的关系。

码率控制

Rate control
The rate control at the receiving side is designed to increase the
receive-side estimate of the available bandwidth A_hat as long as the
detected state is normal. Doing that assures that we, sooner or
later, will reach the available bandwidth of the channel and detect
an over-use.
As soon as over-use has been detected the receive-side estimate of
the available bandwidth is decreased. In this way we get a recursive
and adaptive estimate of the available bandwidth.
In this document we make the assumption that the rate control
subsystem is executed periodically and that this period is constant.
The rate control subsystem has 3 states: Increase, Decrease and Hold.
"Increase" is the state when no congestion is detected; "Decrease" is
the state where congestion is detected, and "Hold" is a state that
waits until built-up queues have drained before going to "increase"
state.
The state transitions (with blank fields meaning "remain in state") are:

Paste_Image.png

参考文档:

http://www.swarthmore.edu/NatSci/echeeve1/Ref/Kalman/ScalarKalman.html
http://tools.ietf.org/html/draft-alvestrand-rtcweb-congestion-02

相关文章

  • webrtc视频接收端带宽预测(二)---卡尔曼滤波

    本文主要参考文章 http://www.xuebuyuan.com/1248366.html接收端估计结合文档ht...

  • webrtc视频接收端带宽预测(三)---AimdRateCon

    本文主要探讨AimdRateControl.cc文件中的相关机制,这个Aimd就是加增乘减,就是通过之前得到的ov...

  • webrtc视频接收端带宽预测(一)---参数输入

    收包到触发远端估算流程: inter_arrival.cc中函数分析如下: timestamp:rtp包中的时间戳...

  • 卡尔曼滤波

    为什么看卡尔曼滤波 因为想要对变化/趋势进行预测,应用偏向于机械等故障类的预测。也看了不少卡尔曼滤波相关的东西,大...

  • OveruseEstimator

    从名称看是“过度使用预测”,是一个卡尔曼滤波,卡尔曼滤波的作用是根据上一个预测值和本次的实际值结合来预测下一个值,...

  • 卡尔曼滤波及其无人驾驶应用

    无人驾驶汽车系统感知模块的重要技术——卡尔曼滤波,应用包括:卡尔曼滤波与行人状态估计扩展卡尔曼滤波(EKF)与传感...

  • webrtc带宽预测---发送端预测

    SR RR 通过RR包,将丢包率信息回传给发送端,根据丢包率做发送端带宽估计。接收RTCP包,以及对应处理流程基本...

  • iOS-卡尔曼滤波算法

    一:前言 滤波算法 用于过滤掉连续的数据中出现偏差较大的数据 二:卡尔曼滤波算法 <0>卡尔曼滤波的原理请自行百度...

  • 2019-01-06

    卡尔曼滤波视频学习记录 资源来源:Michel van Biezen SPECIAL TOPICS THE KAL...

  • 图文并茂,卡曼滤波

    ​卡尔曼滤波是如何工作? 看图说话! 我务必向大家介绍卡尔曼滤波器(Kalman Filter),因为它之所能, ...

网友评论

  • zwggwz:请教一个问题,多谢。接收端码率评估与jitterbuffer均用到KalmanFilter,它们是分开进行的,那么评估的网络带宽值相同么?有何区别呢?
    ai___believe:@zwggwz 用法不一样

本文标题:webrtc视频接收端带宽预测(二)---卡尔曼滤波

本文链接:https://www.haomeiwen.com/subject/ubftqxtx.html