#[derive(Debug, Clone, Copy)]
pub struct PllFilter {
alpha: f64,
beta: f64,
}
impl PllFilter {
pub fn from_bandwidth(bandwidth_hz: f64, sample_rate: f64) -> Self {
let alpha = bandwidth_hz / sample_rate;
let beta = alpha.sqrt();
Self { alpha, beta }
}
pub fn from_gains(alpha: f64, beta: f64) -> Self {
Self { alpha, beta }
}
pub fn alpha(&self) -> f64 {
self.alpha
}
pub fn beta(&self) -> f64 {
self.beta
}
pub fn update(&self, error: f64) -> (f64, f64) {
let freq_adj = error * self.alpha;
let phase_adj = error * self.beta;
(freq_adj, phase_adj)
}
pub fn update_cycles(&self, error_cycles: f64) -> (f64, f64) {
self.update(error_cycles) }
pub fn set_gains(&mut self, alpha: f64, beta: f64) {
self.alpha = alpha;
self.beta = beta;
}
pub fn set_bandwidth(&mut self, bandwidth_hz: f64, sample_rate: f64) {
self.alpha = bandwidth_hz / sample_rate;
self.beta = self.alpha.sqrt();
}
}
impl Default for PllFilter {
fn default() -> Self {
Self::from_bandwidth(0.1, 100000.0)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_pll_filter_creation() {
let pll = PllFilter::from_bandwidth(0.03, 171000.0);
let expected_alpha = 0.03 / 171000.0;
assert!((pll.alpha() - expected_alpha).abs() < 1e-15);
assert!((pll.beta() - expected_alpha.sqrt()).abs() < 1e-10);
}
#[test]
fn test_pll_filter_gains() {
let pll = PllFilter::from_gains(0.001, 0.05);
assert!((pll.alpha() - 0.001).abs() < 1e-10);
assert!((pll.beta() - 0.05).abs() < 1e-10);
}
#[test]
fn test_pll_filter_update() {
let pll = PllFilter::from_gains(0.1, 0.2);
let error = 1.0;
let (freq_adj, phase_adj) = pll.update(error);
assert!((freq_adj - 0.1).abs() < 1e-10);
assert!((phase_adj - 0.2).abs() < 1e-10);
}
#[test]
fn test_pll_filter_update_cycles() {
let pll = PllFilter::from_gains(0.1, 0.2);
let error_cycles = 1.0;
let (freq_adj_cycles, phase_adj_cycles) = pll.update_cycles(error_cycles);
assert!((freq_adj_cycles - 0.1).abs() < 1e-10);
assert!((phase_adj_cycles - 0.2).abs() < 1e-10);
}
#[test]
fn test_pll_filter_set_bandwidth() {
let mut pll = PllFilter::default();
pll.set_bandwidth(0.5, 100000.0);
let expected_alpha = 0.5 / 100000.0;
assert!((pll.alpha() - expected_alpha).abs() < 1e-15);
assert!((pll.beta() - expected_alpha.sqrt()).abs() < 1e-10);
}
#[test]
fn test_pll_filter_set_gains() {
let mut pll = PllFilter::default();
pll.set_gains(0.02, 0.03);
assert!((pll.alpha() - 0.02).abs() < 1e-10);
assert!((pll.beta() - 0.03).abs() < 1e-10);
}
#[test]
fn test_pll_filter_default() {
let pll = PllFilter::default();
let expected_alpha = 0.1 / 100000.0;
assert!((pll.alpha() - expected_alpha).abs() < 1e-15);
}
#[test]
fn test_pll_filter_zero_error() {
let pll = PllFilter::from_bandwidth(10.0, 100000.0);
let (freq_adj, phase_adj) = pll.update(0.0);
assert_eq!(freq_adj, 0.0);
assert_eq!(phase_adj, 0.0);
}
}