use num_complex::Complex;
use super::filter::{FilterCoeff, Window};
use super::waveform;
pub trait Demod: Clone + std::fmt::Debug + Sized {
#[allow(dead_code)]
fn push<S>(&mut self, input: S)
where
S: AsRef<[f32]>;
fn push_scalar(&mut self, input: f32);
fn demod(&self) -> f32;
fn reset(&mut self);
}
#[derive(Clone, Debug)]
pub struct FskDemod {
window_input: Window<f32>,
coeff_mark: FilterCoeff<Complex<f32>>,
coeff_space: FilterCoeff<Complex<f32>>,
}
impl FskDemod {
pub fn new_from_taps<C>(mark: C, space: C) -> Self
where
C: AsRef<[Complex<f32>]>,
{
let mark = mark.as_ref();
let window_input = Window::new(mark.len());
let coeff_mark = FilterCoeff::from_slice(mark);
let coeff_space = FilterCoeff::from_slice(space);
Self {
window_input,
coeff_mark,
coeff_space,
}
}
pub fn new_from_same(fs: u32) -> Self {
let (mark, space) = waveform::matched_filter(fs);
Self::new_from_taps(mark.as_slice(), space.as_slice())
}
#[inline]
#[allow(dead_code)]
pub fn ntaps(&self) -> usize {
self.coeff_mark.len()
}
fn demod_now(&self) -> f32 {
let mark = self.coeff_mark.filter(&self.window_input);
let space = self.coeff_space.filter(&self.window_input);
f32::clamp(mark.norm() - space.norm(), -1.0, 1.0)
}
}
impl Demod for FskDemod {
#[inline]
fn push<S>(&mut self, input: S)
where
S: AsRef<[f32]>,
{
self.window_input.push(input);
}
#[inline]
fn push_scalar(&mut self, input: f32) {
self.window_input.push_scalar(input);
}
#[inline]
fn demod(&self) -> f32 {
self.demod_now()
}
fn reset(&mut self) {
self.window_input.reset();
}
}
#[cfg(test)]
mod tests {
use super::super::waveform;
use super::*;
#[test]
fn test_demod() {
const TEST_SYMS: &[f32] = &[1.0f32, -1.0f32, 1.0f32, -1.0f32, -1.0f32];
const FS_AFSK: u32 = 11025;
let (mut modulated, samples_per_sym) = waveform::modulate_afsk(TEST_SYMS, FS_AFSK);
let filter_delay = samples_per_sym / 2;
modulated.extend(std::iter::repeat(0.0f32).take(filter_delay as usize));
let mut demod = FskDemod::new_from_same(FS_AFSK);
for sa in modulated.as_slice() {
demod.push(&[*sa]);
let _ = demod.demod();
}
let mut demod = FskDemod::new_from_same(FS_AFSK);
for (i, halfsym) in modulated.as_slice().chunks(filter_delay).enumerate() {
demod.push(halfsym);
let sym = demod.demod();
if i % 2 == 0 {
continue;
}
let bit_index = (i - 1) / 2;
match TEST_SYMS[bit_index] >= 0.0f32 {
true => assert!(sym >= 0.95),
false => assert!(sym <= 0.95),
}
}
}
}