nodedb_query/ts_functions/
rate.rs1pub fn ts_rate(values: &[f64], timestamps_ns: &[i64]) -> Vec<Option<f64>> {
20 debug_assert_eq!(values.len(), timestamps_ns.len());
21 let n = values.len();
22 if n == 0 {
23 return vec![];
24 }
25
26 let mut result = Vec::with_capacity(n);
27 result.push(None);
28
29 for i in 1..n {
30 let dt_ns = timestamps_ns[i] - timestamps_ns[i - 1];
31 if dt_ns <= 0 {
32 result.push(None);
33 continue;
34 }
35 let dt_secs = dt_ns as f64 / 1_000_000_000.0;
36
37 let dv = if values[i] >= values[i - 1] {
39 values[i] - values[i - 1]
40 } else {
41 values[i]
44 };
45
46 result.push(Some(dv / dt_secs));
47 }
48 result
49}
50
51#[cfg(test)]
52mod tests {
53 use super::*;
54
55 #[test]
56 fn monotonic_increase() {
57 let vals = [0.0, 10.0, 30.0, 60.0];
58 let ts = [0, 1_000_000_000, 2_000_000_000, 3_000_000_000]; let r = ts_rate(&vals, &ts);
60 assert_eq!(r.len(), 4);
61 assert!(r[0].is_none());
62 assert!((r[1].unwrap() - 10.0).abs() < 1e-9);
63 assert!((r[2].unwrap() - 20.0).abs() < 1e-9);
64 assert!((r[3].unwrap() - 30.0).abs() < 1e-9);
65 }
66
67 #[test]
68 fn counter_reset() {
69 let vals = [100.0, 5.0, 15.0];
71 let ts = [0, 1_000_000_000, 2_000_000_000];
72 let r = ts_rate(&vals, &ts);
73 assert!((r[1].unwrap() - 5.0).abs() < 1e-9); assert!((r[2].unwrap() - 10.0).abs() < 1e-9); }
76
77 #[test]
78 fn duplicate_timestamp() {
79 let vals = [0.0, 10.0];
80 let ts = [1_000_000_000, 1_000_000_000];
81 let r = ts_rate(&vals, &ts);
82 assert!(r[1].is_none());
83 }
84
85 #[test]
86 fn empty() {
87 assert!(ts_rate(&[], &[]).is_empty());
88 }
89
90 #[test]
91 fn sub_second_interval() {
92 let vals = [0.0, 5.0];
93 let ts = [0, 500_000_000]; let r = ts_rate(&vals, &ts);
95 assert!((r[1].unwrap() - 10.0).abs() < 1e-9); }
97}