use crate::kernel::{Complex, Float};
pub fn build_chirp_y<T: Float>(n: usize, a: Complex<T>, w: Complex<T>) -> Vec<Complex<T>> {
let mut out = Vec::with_capacity(n);
for idx in 0..n {
let i = T::from_usize(idx);
let a_term = complex_pow_real(a, -i);
let w_exp = i * i / T::TWO;
let w_term = complex_pow_real(w, w_exp);
out.push(a_term * w_term);
}
out
}
pub fn build_chirp_filter<T: Float>(
n: usize,
m: usize,
l: usize,
w: Complex<T>,
) -> Vec<Complex<T>> {
let mut h = vec![Complex::zero(); l];
for idx in 0..m {
let m_f = T::from_usize(idx);
let exp = m_f * m_f / T::TWO;
h[idx] = complex_pow_real(w, -exp);
}
for idx in 1..n {
let m_f = T::from_usize(idx);
let exp = m_f * m_f / T::TWO;
h[l - idx] = complex_pow_real(w, -exp);
}
h
}
pub fn build_chirp_post<T: Float>(m: usize, w: Complex<T>) -> Vec<Complex<T>> {
let mut out = Vec::with_capacity(m);
for idx in 0..m {
let k = T::from_usize(idx);
let exp = k * k / T::TWO;
out.push(complex_pow_real(w, exp));
}
out
}
#[inline]
pub(crate) fn complex_pow_real<T: Float>(z: Complex<T>, p: T) -> Complex<T> {
let r_sq = z.re * z.re + z.im * z.im;
let theta = num_traits::Float::atan2(z.im, z.re);
let eps16 = T::from_f64(16.0) * num_traits::Float::epsilon();
let diff = if r_sq > T::ONE {
r_sq - T::ONE
} else {
T::ONE - r_sq
};
if diff < eps16 {
Complex::cis(p * theta)
} else {
let r = num_traits::Float::sqrt(r_sq);
let r_p = num_traits::Float::powf(r, p);
Complex::from_polar(r_p, p * theta)
}
}