use crate::types::{q15, q31};
pub const CORDIC_K_Q15: q15 = q15::from_bits(19898);
pub const CORDIC_K_Q31: q31 = q31::from_bits(1304065792);
pub const CORDIC_ITERATIONS: usize = 16;
pub const ATAN_TABLE_Q15: [q15; 16] = [
q15::from_bits(25736), q15::from_bits(15193), q15::from_bits(8027), q15::from_bits(4075), q15::from_bits(2045), q15::from_bits(1024), q15::from_bits(512), q15::from_bits(256), q15::from_bits(128), q15::from_bits(64), q15::from_bits(32), q15::from_bits(16), q15::from_bits(8), q15::from_bits(4), q15::from_bits(2), q15::from_bits(1), ];
pub const ATAN_TABLE_Q31: [q31; 16] = [
q31::from_bits(1686629713), q31::from_bits(995716174), q31::from_bits(526057390), q31::from_bits(267073177), q31::from_bits(134079828), q31::from_bits(67098489), q31::from_bits(33556754), q31::from_bits(16779316), q31::from_bits(8389776), q31::from_bits(4194903), q31::from_bits(2097453), q31::from_bits(1048727), q31::from_bits(524363), q31::from_bits(262182), q31::from_bits(131091), q31::from_bits(65545), ];
pub fn cordic_sin_cos_q15(angle_rad: q15) -> (q15, q15) {
let mut x: i32 = CORDIC_K_Q15.to_bits() as i32;
let mut y: i32 = 0;
let mut z: i32 = angle_rad.to_bits() as i32;
for i in 0..CORDIC_ITERATIONS {
let (x_new, y_new, z_new) = if z >= 0 {
(
x - (y >> i),
y + (x >> i),
z - (ATAN_TABLE_Q15[i].to_bits() as i32),
)
} else {
(
x + (y >> i),
y - (x >> i),
z + (ATAN_TABLE_Q15[i].to_bits() as i32),
)
};
x = x_new;
y = y_new;
z = z_new;
}
let sin = q15::from_bits(y.clamp(i16::MIN as i32, i16::MAX as i32) as i16);
let cos = q15::from_bits(x.clamp(i16::MIN as i32, i16::MAX as i32) as i16);
(sin, cos)
}
pub fn cordic_sin_cos_q31(angle_rad: q31) -> (q31, q31) {
let mut x: i64 = CORDIC_K_Q31.to_bits() as i64;
let mut y: i64 = 0;
let mut z: i64 = angle_rad.to_bits() as i64;
for i in 0..CORDIC_ITERATIONS {
let (x_new, y_new, z_new) = if z >= 0 {
(
x - (y >> i),
y + (x >> i),
z - (ATAN_TABLE_Q31[i].to_bits() as i64),
)
} else {
(
x + (y >> i),
y - (x >> i),
z + (ATAN_TABLE_Q31[i].to_bits() as i64),
)
};
x = x_new;
y = y_new;
z = z_new;
}
let sin = q31::from_bits(y.clamp(i32::MIN as i64, i32::MAX as i64) as i32);
let cos = q31::from_bits(x.clamp(i32::MIN as i64, i32::MAX as i64) as i32);
(sin, cos)
}
pub fn cordic_cartesian_to_polar_q15(x_in: q15, y_in: q15) -> (q15, q15) {
if x_in == q15::ZERO && y_in == q15::ZERO {
return (q15::ZERO, q15::ZERO);
}
let mut x = (x_in.to_bits() as i32).abs();
let mut y = y_in.to_bits() as i32;
let mut z: i32 = 0;
for i in 0..CORDIC_ITERATIONS {
let (x_new, y_new, z_new) = if y < 0 {
(
x - (y >> i),
y + (x >> i),
z - (ATAN_TABLE_Q15[i].to_bits() as i32),
)
} else {
(
x + (y >> i),
y - (x >> i),
z + (ATAN_TABLE_Q15[i].to_bits() as i32),
)
};
x = x_new;
y = y_new;
z = z_new;
}
let mag = q15::from_bits(
((x * CORDIC_K_Q15.to_bits() as i32) >> 15).clamp(0, i16::MAX as i32) as i16,
);
let mut angle = q15::from_bits(z.clamp(i16::MIN as i32, i16::MAX as i32) as i16);
if x_in < q15::ZERO {
angle = if angle >= q15::ZERO {
q15::from_bits(
(25736 * 4 - angle.to_bits() as i32).clamp(i16::MIN as i32, i16::MAX as i32)
as i16,
)
} else {
q15::from_bits(
(-25736 * 4 - angle.to_bits() as i32).clamp(i16::MIN as i32, i16::MAX as i32)
as i16,
)
};
}
(mag, angle)
}
pub fn cordic_atan2_q15(y: q15, x: q15) -> q15 {
let (_, angle) = cordic_cartesian_to_polar_q15(x, y);
angle
}
pub fn cordic_sqrt_q15(x: q15) -> q15 {
if x <= q15::ZERO {
return q15::ZERO;
}
let mut out = q15::ZERO;
let _ = crate::fast_math::sqrt_q15(x, &mut out);
out
}