use super::{MonitorReport, Series};
use crate::iq::Cf64;
use serde::{Deserialize, Serialize};
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
#[serde(default)]
pub struct LockSettings {
pub smoothing: f64,
}
impl Default for LockSettings {
fn default() -> Self {
LockSettings { smoothing: 0.05 }
}
}
pub struct LockMonitor {
settings: LockSettings,
prev_prompt: Option<Cf64>,
fli: f64,
pli: Series,
fli_s: Series,
}
impl LockMonitor {
pub fn new(label: &str, settings: LockSettings) -> Self {
LockMonitor {
settings,
prev_prompt: None,
fli: 0.0,
pli: Series::new("pli", "1", Some(label)),
fli_s: Series::new("fli", "1", Some(label)),
}
}
pub fn instantaneous_fli(prev: Cf64, cur: Cf64) -> f64 {
let d = Cf64::new(
cur.re * prev.re + cur.im * prev.im,
cur.im * prev.re - cur.re * prev.im,
);
let p = super::norm_sqr(d);
if p == 0.0 {
0.0
} else {
(d.re * d.re - d.im * d.im) / p
}
}
pub fn push(&mut self, t_s: f64, prompt: Cf64, pli: f64) {
if let Some(prev) = self.prev_prompt {
let f = Self::instantaneous_fli(prev, prompt);
self.fli += self.settings.smoothing * (f - self.fli);
self.fli_s.push(t_s, self.fli);
}
self.prev_prompt = Some(prompt);
self.pli.push(t_s, pli);
}
pub fn report(&self) -> MonitorReport {
MonitorReport {
series: vec![self.pli.clone(), self.fli_s.clone()],
..MonitorReport::default()
}
}
}