kobo_db_tools/statistics/imp/
brightness.rs1use crate::model::{BrightnessHistory, NaturalLightHistory};
2use crate::statistics::Statistics;
3
4impl Statistics for BrightnessHistory {
5 type Metric = ();
6
7 fn avg(&self) -> f64 {
8 if self.events.len() < 2 {
9 return self
10 .events
11 .first()
12 .map_or(0.0, |e| e.brightness.percentage as f64);
13 }
14
15 let mut weighted_sum = 0.0;
16 let mut total_duration = 0.0;
17
18 for i in 0..self.events.len() - 1 {
19 let current_event = &self.events[i];
20 let next_event = &self.events[i + 1];
21
22 let duration = (next_event.timestamp - current_event.timestamp).num_seconds() as f64;
23 if duration > 0.0 {
24 weighted_sum += current_event.brightness.percentage as f64 * duration;
25 total_duration += duration;
26 }
27 }
28
29 if total_duration == 0.0 {
30 self.events
31 .last()
32 .map_or(0.0, |e| e.brightness.percentage as f64)
33 } else {
34 weighted_sum / total_duration
35 }
36 }
37
38 fn calculate_percentile(&self, _metric: Self::Metric, _percentiles: &[f64]) -> Vec<f64> {
39 unimplemented!("Percentile calculation is not implemented for BrightnessHistory");
41 }
42}
43
44impl Statistics for NaturalLightHistory {
45 type Metric = ();
46
47 fn avg(&self) -> f64 {
48 if self.events.len() < 2 {
49 return self
50 .events
51 .first()
52 .map_or(0.0, |e| e.brightness.percentage as f64);
53 }
54
55 let mut weighted_sum = 0.0;
56 let mut total_duration = 0.0;
57
58 for i in 0..self.events.len() - 1 {
59 let current_event = &self.events[i];
60 let next_event = &self.events[i + 1];
61
62 let duration = (next_event.timestamp - current_event.timestamp).num_seconds() as f64;
63 if duration > 0.0 {
64 weighted_sum += current_event.brightness.percentage as f64 * duration;
65 total_duration += duration;
66 }
67 }
68
69 if total_duration == 0.0 {
70 self.events
71 .last()
72 .map_or(0.0, |e| e.brightness.percentage as f64)
73 } else {
74 weighted_sum / total_duration
75 }
76 }
77
78 fn calculate_percentile(&self, _metric: Self::Metric, percentiles: &[f64]) -> Vec<f64> {
79 let mut values: Vec<f64> = self
80 .events
81 .iter()
82 .map(|e| e.brightness.percentage as f64)
83 .collect();
84
85 if values.is_empty() {
86 return vec![0.0];
87 }
88
89 values.sort_by(|a, b| a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Less));
90 percentiles
91 .iter()
92 .map(|&p| {
93 let idx = ((p.clamp(0.0, 1.0)) * ((values.len() - 1) as f64)).round() as usize;
94 values.get(idx).copied().unwrap_or(0.0)
95 })
96 .collect()
97 }
98}