Skip to main content

cbtop/frequency_control/
variance.rs

1//! Frequency variance measurement and statistics.
2
3/// Frequency variance measurement
4#[derive(Debug, Clone, Default)]
5pub struct FrequencyVariance {
6    /// Mean frequency in MHz
7    pub mean_mhz: f64,
8    /// Standard deviation in MHz
9    pub std_dev_mhz: f64,
10    /// Coefficient of variation (%)
11    pub cv_percent: f64,
12    /// Minimum frequency in MHz
13    pub min_mhz: f64,
14    /// Maximum frequency in MHz
15    pub max_mhz: f64,
16    /// Number of samples
17    pub sample_count: usize,
18}
19
20impl FrequencyVariance {
21    /// Compute variance statistics from a set of frequency samples (MHz).
22    pub fn from_samples(readings: &[f64]) -> Self {
23        if readings.is_empty() {
24            return Self::default();
25        }
26        let n = readings.len() as f64;
27        let mean = readings.iter().sum::<f64>() / n;
28        let var = readings.iter().map(|x| (x - mean).powi(2)).sum::<f64>() / (n - 1.0).max(1.0);
29        let std_dev = var.sqrt();
30        let cv = if mean > 0.0 {
31            std_dev / mean * 100.0
32        } else {
33            0.0
34        };
35        Self {
36            mean_mhz: mean,
37            std_dev_mhz: std_dev,
38            cv_percent: cv,
39            min_mhz: readings.iter().copied().fold(f64::INFINITY, f64::min),
40            max_mhz: readings.iter().copied().fold(f64::NEG_INFINITY, f64::max),
41            sample_count: readings.len(),
42        }
43    }
44
45    /// Check if variance is acceptable (<3% CV)
46    pub fn is_stable(&self) -> bool {
47        self.cv_percent < 3.0
48    }
49
50    /// Get range in MHz
51    pub fn range_mhz(&self) -> f64 {
52        self.max_mhz - self.min_mhz
53    }
54}