2021-02-10 01:30:50 +08:00
|
|
|
use super::{lowpass::Lowpass, Complex};
|
|
|
|
use generic_array::typenum::U3;
|
2021-01-21 21:55:33 +08:00
|
|
|
|
2021-02-10 01:30:50 +08:00
|
|
|
#[derive(Clone, Default)]
|
2021-01-21 21:55:33 +08:00
|
|
|
pub struct Lockin {
|
2021-02-10 01:30:50 +08:00
|
|
|
state: [Lowpass<U3>; 2],
|
2021-02-10 16:46:49 +08:00
|
|
|
k: u8,
|
2021-01-21 21:55:33 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Lockin {
|
2021-02-01 03:32:44 +08:00
|
|
|
/// Create a new Lockin with given IIR coefficients.
|
2021-02-10 16:46:49 +08:00
|
|
|
pub fn new(k: u8) -> Self {
|
2021-02-10 01:30:50 +08:00
|
|
|
let lp = Lowpass::default();
|
2021-02-01 19:37:44 +08:00
|
|
|
Self {
|
2021-02-10 01:30:50 +08:00
|
|
|
state: [lp.clone(), lp.clone()],
|
|
|
|
k,
|
2021-01-21 21:55:33 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-01 03:32:44 +08:00
|
|
|
/// Update the lockin with a sample taken at a given phase.
|
|
|
|
pub fn update(&mut self, sample: i32, phase: i32) -> Complex<i32> {
|
2021-01-21 21:55:33 +08:00
|
|
|
// Get the LO signal for demodulation.
|
2021-02-01 03:32:44 +08:00
|
|
|
let lo = Complex::from_angle(phase);
|
2021-01-21 21:55:33 +08:00
|
|
|
|
|
|
|
// Mix with the LO signal, filter with the IIR lowpass,
|
|
|
|
// return IQ (in-phase and quadrature) data.
|
|
|
|
// Note: 32x32 -> 64 bit multiplications are pretty much free.
|
|
|
|
Complex(
|
2021-02-10 01:30:50 +08:00
|
|
|
self.state[0]
|
|
|
|
.update(((sample as i64 * lo.0 as i64) >> 32) as _, self.k),
|
|
|
|
self.state[1]
|
|
|
|
.update(((sample as i64 * lo.1 as i64) >> 32) as _, self.k),
|
2021-01-21 21:55:33 +08:00
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|