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