use num_complex::Complex32 as C32;
#[derive(Clone, Copy, Debug)]
pub struct Rotator {
z: C32, w: C32, renorm_ctr: u32,
}
impl Rotator {
#[inline]
pub fn new(freq_hz: f32, fs: f32) -> Self {
let phi = core::f32::consts::TAU * freq_hz / fs;
let (s, c) = phi.sin_cos(); Self {
z: C32::new(1.0, 0.0),
w: C32::new(c, s),
renorm_ctr: 0,
}
}
#[inline]
pub fn reset_phase(&mut self) {
self.z = C32::new(1.0, 0.0);
self.renorm_ctr = 0;
}
#[inline]
pub fn set_freq(&mut self, freq_hz: f32, fs: f32) {
let phi = core::f32::consts::TAU * freq_hz / fs;
let (s, c) = phi.sin_cos();
self.w = C32::new(c, s);
}
#[inline(always)]
pub fn next(&mut self) -> C32 {
let zr = self.z.re.mul_add(self.w.re, -self.z.im * self.w.im);
let zi = self.z.im.mul_add(self.w.re, self.z.re * self.w.im);
self.z = C32::new(zr, zi);
self.renorm_ctr = self.renorm_ctr.wrapping_add(1);
if (self.renorm_ctr & 0x3FF) == 0 { let r2 = self.z.re * self.z.re + self.z.im * self.z.im;
let inv = r2.sqrt().recip();
self.z.re *= inv;
self.z.im *= inv;
}
self.z
}
#[inline]
pub fn next_cs(&mut self) -> (f32, f32) {
let p = self.next();
(p.re, p.im)
}
#[inline]
pub fn rotate_block(&mut self, input: &[C32], out: &mut [C32]) {
let n = input.len().min(out.len());
for i in 0..n {
let p = self.next();
let a = input[i].re; let b = input[i].im;
out[i].re = a.mul_add(p.re, -b * p.im);
out[i].im = b.mul_add(p.re, a * p.im);
}
}
#[inline]
pub fn mix_usb_block(&mut self, input: &[C32], out: &mut [f32]) {
let n = input.len().min(out.len());
for i in 0..n {
let p = self.next();
out[i] = input[i].re.mul_add(p.re, input[i].im * p.im);
}
}
}