use super::{Stream, Tag};
use num_complex::Complex;
use std::f32::consts::PI;
pub struct PhaseSearchEMA {
rot: usize,
bits: Vec<u32>,
ma: Vec<f32>,
max_idx: usize,
phase: Vec<Complex<f32>>,
n_phases: usize,
n_search: usize,
n_delay: usize,
weight: f32,
}
impl PhaseSearchEMA {
pub fn with_params(n_delay: usize) -> Self {
const N_PHASES: usize = 16;
const N_SEARCH: usize = 1;
const WEIGHT: f32 = 0.85;
let mut phase = Vec::with_capacity(N_PHASES / 2);
for j in 0..(N_PHASES / 2) {
let angle = PI * (j as f32 + 0.5) / (N_PHASES as f32 / 2.0);
phase.push(Complex::new(angle.cos(), angle.sin()));
}
Self {
rot: 0,
bits: vec![0; N_PHASES],
ma: vec![0.0; N_PHASES],
max_idx: 0,
phase,
n_phases: N_PHASES,
n_search: N_SEARCH,
n_delay,
weight: WEIGHT,
}
}
}
impl Stream<Complex<f32>, f32> for PhaseSearchEMA {
fn receive(&mut self, data: &[Complex<f32>], _tag: &mut Tag) -> Vec<f32> {
let mut output = Vec::with_capacity(data.len());
for &sample in data {
let (re, im) = match self.rot {
0 => (sample.re, sample.im),
1 => (-sample.im, sample.re),
2 => (-sample.re, -sample.im),
3 => (sample.im, -sample.re),
_ => unreachable!(),
};
self.rot = (self.rot + 1) & 3;
for j in 0..(self.n_phases / 2) {
let a = re * self.phase[j].re;
let b = im * self.phase[j].im;
let t1 = a + b;
self.bits[j] = (self.bits[j] << 1) | if t1 > 0.0 { 1 } else { 0 };
self.ma[j] = self.weight * self.ma[j] + (1.0 - self.weight) * t1.abs();
let t2 = a - b;
self.bits[self.n_phases - 1 - j] =
(self.bits[self.n_phases - 1 - j] << 1) | if t2 > 0.0 { 1 } else { 0 };
self.ma[self.n_phases - 1 - j] =
self.weight * self.ma[self.n_phases - 1 - j] + (1.0 - self.weight) * t2.abs();
if !self.ma[j].is_finite() {
self.ma[j] = 0.0;
}
if !self.ma[self.n_phases - 1 - j].is_finite() {
self.ma[self.n_phases - 1 - j] = 0.0;
}
}
let start_idx = (self.max_idx + self.n_phases - self.n_search) & (self.n_phases - 1);
let mut max_val = self.ma[start_idx];
self.max_idx = start_idx;
for p in 0..(self.n_search * 2 + 1) {
let idx = (start_idx + p) & (self.n_phases - 1);
if self.ma[idx] > max_val {
max_val = self.ma[idx];
self.max_idx = idx;
}
}
let b2 = (self.bits[self.max_idx] >> (self.n_delay + 1)) & 1;
let b1 = (self.bits[self.max_idx] >> self.n_delay) & 1;
let b = if (b1 ^ b2) != 0 { 1.0 } else { -1.0 };
output.push(b);
}
output
}
fn reset(&mut self) {
self.rot = 0;
self.bits.fill(0);
self.ma.fill(0.0);
self.max_idx = 0;
}
}