1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
use crate::sliding_window::View;
use crate::Echo;
#[derive(Clone)]
pub struct LaguerreFilter {
view: Box<dyn View>,
gamma: f64,
l0s: Vec<f64>,
l1s: Vec<f64>,
l2s: Vec<f64>,
l3s: Vec<f64>,
filts: Vec<f64>,
init: bool,
}
impl LaguerreFilter {
pub fn new(view: Box<dyn View>, gamma: f64) -> Box<Self> {
Box::new(LaguerreFilter {
view,
gamma,
l0s: vec![],
l1s: vec![],
l2s: vec![],
l3s: vec![],
filts: vec![],
init: true,
})
}
pub fn new_final(gamma: f64) -> Box<Self> {
Self::new(Echo::new(), gamma)
}
pub fn default() -> Box<Self> {
return LaguerreFilter::new_final(0.8);
}
}
impl View for LaguerreFilter {
fn update(&mut self, val: f64) {
self.view.update(val);
let val = self.view.last();
if self.init {
self.init = false;
self.l0s.push(val);
self.l1s.push(val);
self.l2s.push(val);
self.l3s.push(val);
self.filts
.push((self.l0s[0] + 2.0 * self.l1s[0] + 2.0 * self.l2s[0] + self.l3s[0]) / 6.0);
return;
}
self.l0s
.push((1.0 - self.gamma) * val + self.gamma * self.l0s[self.l0s.len() - 1]);
self.l1s.push(
-self.gamma * self.l0s[self.l0s.len() - 1]
+ self.l0s[self.l0s.len() - 2]
+ self.gamma * self.l1s[self.l1s.len() - 1],
);
self.l2s.push(
-self.gamma * self.l1s[self.l1s.len() - 1]
+ self.l1s[self.l1s.len() - 2]
+ self.gamma * self.l2s[self.l2s.len() - 1],
);
self.l3s.push(
-self.gamma * self.l2s[self.l2s.len() - 1]
+ self.l2s[self.l2s.len() - 2]
+ self.gamma * self.l3s[self.l3s.len() - 1],
);
self.filts.push(
(self.l0s[self.l0s.len() - 1]
+ 2.0 * self.l1s[self.l1s.len() - 1]
+ 2.0 * self.l2s[self.l2s.len() - 1]
+ self.l3s[self.l3s.len() - 1])
/ 6.0,
);
}
fn last(&self) -> f64 {
return self.filts[self.filts.len() - 1];
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::plot::plot_values;
use crate::test_data::TEST_DATA;
use rand::{thread_rng, Rng};
#[test]
fn laguerre_filter() {
let mut laguerre = LaguerreFilter::default();
let mut rng = thread_rng();
for _ in 0..10_000 {
let v = rng.gen::<f64>();
laguerre.update(v);
let last = laguerre.last();
assert!(last <= 1.0);
assert!(last >= 0.0);
}
}
#[test]
fn laguerre_filter_plot() {
let mut laguerre = LaguerreFilter::default();
let mut out: Vec<f64> = Vec::new();
for v in &TEST_DATA {
laguerre.update(*v);
out.push(laguerre.last());
}
let filename = "img/laguerre_filter.png";
plot_values(out, filename).unwrap();
}
}