Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(380)

Side by Side Diff: webrtc/common_audio/smoothing_filter.cc

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

Powered by Google App Engine
This is Rietveld 408576698