LCOV - code coverage report
Current view: top level - media/webrtc/trunk/webrtc/common_audio - smoothing_filter.cc (source / functions) Hit Total Coverage
Test: output.info Lines: 0 50 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 6 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  *  Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
       3             :  *
       4             :  *  Use of this source code is governed by a BSD-style license
       5             :  *  that can be found in the LICENSE file in the root of the source
       6             :  *  tree. An additional intellectual property rights grant can be found
       7             :  *  in the file PATENTS.  All contributing project authors may
       8             :  *  be found in the AUTHORS file in the root of the source tree.
       9             :  */
      10             : 
      11             : #include "webrtc/common_audio/smoothing_filter.h"
      12             : 
      13             : #include <cmath>
      14             : 
      15             : namespace webrtc {
      16             : 
      17           0 : SmoothingFilterImpl::SmoothingFilterImpl(int init_time_ms, const Clock* clock)
      18             :     : init_time_ms_(init_time_ms),
      19             :       // Duing the initalization time, we use an increasing alpha. Specifically,
      20             :       //   alpha(n) = exp(-powf(init_factor_, n)),
      21             :       // where |init_factor_| is chosen such that
      22             :       //   alpha(init_time_ms_) = exp(-1.0f / init_time_ms_),
      23           0 :       init_factor_(init_time_ms_ == 0 ? 0.0f : powf(init_time_ms_,
      24           0 :                                                     -1.0f / init_time_ms_)),
      25             :       // |init_const_| is to a factor to help the calculation during
      26             :       // initialization phase.
      27           0 :       init_const_(init_time_ms_ == 0
      28           0 :                       ? 0.0f
      29           0 :                       : init_time_ms_ -
      30           0 :                             powf(init_time_ms_, 1.0f - 1.0f / init_time_ms_)),
      31           0 :       clock_(clock) {
      32           0 :   UpdateAlpha(init_time_ms_);
      33           0 : }
      34             : 
      35             : SmoothingFilterImpl::~SmoothingFilterImpl() = default;
      36             : 
      37           0 : void SmoothingFilterImpl::AddSample(float sample) {
      38           0 :   const int64_t now_ms = clock_->TimeInMilliseconds();
      39             : 
      40           0 :   if (!init_end_time_ms_) {
      41             :     // This is equivalent to assuming the filter has been receiving the same
      42             :     // value as the first sample since time -infinity.
      43           0 :     state_ = last_sample_ = sample;
      44           0 :     init_end_time_ms_ = rtc::Optional<int64_t>(now_ms + init_time_ms_);
      45           0 :     last_state_time_ms_ = now_ms;
      46           0 :     return;
      47             :   }
      48             : 
      49           0 :   ExtrapolateLastSample(now_ms);
      50           0 :   last_sample_ = sample;
      51             : }
      52             : 
      53           0 : rtc::Optional<float> SmoothingFilterImpl::GetAverage() {
      54           0 :   if (!init_end_time_ms_) {
      55             :     // |init_end_time_ms_| undefined since we have not received any sample.
      56           0 :     return rtc::Optional<float>();
      57             :   }
      58           0 :   ExtrapolateLastSample(clock_->TimeInMilliseconds());
      59           0 :   return rtc::Optional<float>(state_);
      60             : }
      61             : 
      62           0 : bool SmoothingFilterImpl::SetTimeConstantMs(int time_constant_ms) {
      63           0 :   if (!init_end_time_ms_ || last_state_time_ms_ < *init_end_time_ms_) {
      64           0 :     return false;
      65             :   }
      66           0 :   UpdateAlpha(time_constant_ms);
      67           0 :   return true;
      68             : }
      69             : 
      70           0 : void SmoothingFilterImpl::UpdateAlpha(int time_constant_ms) {
      71           0 :   alpha_ = time_constant_ms == 0 ? 0.0f : exp(-1.0f / time_constant_ms);
      72           0 : }
      73             : 
      74           0 : void SmoothingFilterImpl::ExtrapolateLastSample(int64_t time_ms) {
      75           0 :   RTC_DCHECK_GE(time_ms, last_state_time_ms_);
      76           0 :   RTC_DCHECK(init_end_time_ms_);
      77             : 
      78           0 :   float multiplier = 0.0f;
      79             : 
      80           0 :   if (time_ms <= *init_end_time_ms_) {
      81             :     // Current update is to be made during initialization phase.
      82             :     // We update the state as if the |alpha| has been increased according
      83             :     //   alpha(n) = exp(-powf(init_factor_, n)),
      84             :     // where n is the time (in millisecond) since the first sample received.
      85             :     // With algebraic derivation as shown in the Appendix, we can find that the
      86             :     // state can be updated in a similar manner as if alpha is a constant,
      87             :     // except for a different multiplier.
      88           0 :     if (init_time_ms_ == 0) {
      89             :       // This means |init_factor_| = 0.
      90           0 :       multiplier = 0.0f;
      91           0 :     } else if (init_time_ms_ == 1) {
      92             :       // This means |init_factor_| = 1.
      93           0 :       multiplier = exp(last_state_time_ms_ - time_ms);
      94             :     } else {
      95             :       multiplier =
      96           0 :           exp(-(powf(init_factor_, last_state_time_ms_ - *init_end_time_ms_) -
      97           0 :                 powf(init_factor_, time_ms - *init_end_time_ms_)) /
      98           0 :               init_const_);
      99             :     }
     100             :   } else {
     101           0 :     if (last_state_time_ms_ < *init_end_time_ms_) {
     102             :       // The latest state update was made during initialization phase.
     103             :       // We first extrapolate to the initialization time.
     104           0 :       ExtrapolateLastSample(*init_end_time_ms_);
     105             :       // Then extrapolate the rest by the following.
     106             :     }
     107           0 :     multiplier = powf(alpha_, time_ms - last_state_time_ms_);
     108             :   }
     109             : 
     110           0 :   state_ = multiplier * state_ + (1.0f - multiplier) * last_sample_;
     111           0 :   last_state_time_ms_ = time_ms;
     112           0 : }
     113             : 
     114             : }  // namespace webrtc
     115             : 
     116             : // Appendix: derivation of extrapolation during initialization phase.
     117             : // (LaTeX syntax)
     118             : // Assuming
     119             : //   \begin{align}
     120             : //     y(n) &= \alpha_{n-1} y(n-1) + \left(1 - \alpha_{n-1}\right) x(m) \\*
     121             : //          &= \left(\prod_{i=m}^{n-1} \alpha_i\right) y(m) +
     122             : //             \left(1 - \prod_{i=m}^{n-1} \alpha_i \right) x(m)
     123             : //   \end{align}
     124             : // Taking $\alpha_{n} = \exp(-\gamma^n)$, $\gamma$ denotes init\_factor\_, the
     125             : // multiplier becomes
     126             : //   \begin{align}
     127             : //     \prod_{i=m}^{n-1} \alpha_i
     128             : //     &= \exp\left(-\sum_{i=m}^{n-1} \gamma^i \right) \\*
     129             : //     &= \begin{cases}
     130             : //          \exp\left(-\frac{\gamma^m - \gamma^n}{1 - \gamma} \right)
     131             : //          & \gamma \neq 1 \\*
     132             : //          m-n & \gamma = 1
     133             : //        \end{cases}
     134             : //   \end{align}
     135             : // We know $\gamma = T^{-\frac{1}{T}}$, where $T$ denotes init\_time\_ms\_. Then
     136             : // $1 - \gamma$ approaches zero when $T$ increases. This can cause numerical
     137             : // difficulties. We multiply $T$ (if $T > 0$) to both numerator and denominator
     138             : // in the fraction. See.
     139             : //   \begin{align}
     140             : //     \frac{\gamma^m - \gamma^n}{1 - \gamma}
     141             : //     &= \frac{T^\frac{T-m}{T} - T^\frac{T-n}{T}}{T - T^{1-\frac{1}{T}}}
     142             : //   \end{align}

Generated by: LCOV version 1.13