File
Blob: firmware/vendor/str0m/src/util/average.rs
| 1 | /// Exponential moving average |
| 2 | #[derive(Debug)] |
| 3 | pub struct MovingAverage { |
| 4 | smoothing_factor: f64, |
| 5 | average: Option<f64>, |
| 6 | variance: f64, |
| 7 | std: f64, |
| 8 | } |
| 9 | |
| 10 | impl MovingAverage { |
| 11 | pub fn new(smoothing_factor: f64) -> Self { |
| 12 | Self { |
| 13 | smoothing_factor, |
| 14 | average: None, |
| 15 | variance: 0.0, |
| 16 | std: 0.0, |
| 17 | } |
| 18 | } |
| 19 | |
| 20 | pub fn within_std(&self, value: f64, num_std: f64) -> bool { |
| 21 | let Some(average) = self.average else { |
| 22 | return false; |
| 23 | }; |
| 24 | |
| 25 | let floor = average - self.std * num_std; |
| 26 | let ceil = average + self.std * num_std; |
| 27 | |
| 28 | floor <= value && value <= ceil |
| 29 | } |
| 30 | |
| 31 | pub fn upper_range(&self, num_std: f64) -> Option<f64> { |
| 32 | if self.std == 0.0 { |
| 33 | return None; |
| 34 | } |
| 35 | |
| 36 | self.average.map(|avg| avg + num_std * self.std) |
| 37 | } |
| 38 | |
| 39 | pub fn lower_range(&self, num_std: f64) -> Option<f64> { |
| 40 | if self.std == 0.0 { |
| 41 | return None; |
| 42 | } |
| 43 | |
| 44 | self.average.map(|avg| avg - num_std * self.std) |
| 45 | } |
| 46 | |
| 47 | pub fn update(&mut self, value: f64) { |
| 48 | let average = match self.average { |
| 49 | Some(average) => { |
| 50 | let delta = value - average; |
| 51 | let new_average = average + self.smoothing_factor * delta; |
| 52 | let new_variance = (1.0 - self.smoothing_factor) |
| 53 | * (self.variance + self.smoothing_factor * delta.powf(2.0)); |
| 54 | |
| 55 | self.variance = new_variance; |
| 56 | self.std = new_variance.sqrt(); |
| 57 | |
| 58 | new_average |
| 59 | } |
| 60 | None => value, |
| 61 | }; |
| 62 | |
| 63 | self.average = Some(average); |
| 64 | } |
| 65 | |
| 66 | /// Returns the current average value, or None if no values have been added yet. |
| 67 | pub fn get(&self) -> Option<f64> { |
| 68 | self.average |
| 69 | } |
| 70 | |
| 71 | pub fn valid(&self) -> bool { |
| 72 | self.average.is_some() |
| 73 | } |
| 74 | |
| 75 | pub fn reset(&mut self) { |
| 76 | self.average = None; |
| 77 | self.std = 0.0; |
| 78 | self.variance = 0.0; |
| 79 | } |
| 80 | } |