1#![no_std]
8
9pub type Angle = u16; pub type Fixed = i16; #[cfg(feature = "lut")]
25mod lut_impl {
26 use super::{Angle, Fixed};
27 const QUADRANT_BITS: u32 = 14;
28 const LUT_SIZE: usize = 256;
29 const LUT_BITS: u32 = 8;
30 const LUT_MASK: u32 = (1 << (QUADRANT_BITS - LUT_BITS)) - 1;
31
32 static SIN_LUT: [Fixed; 257] = include!("sin_table.rs.inc");
34
35 #[inline(always)]
36 pub fn sin_fixed(angle: Angle) -> Fixed {
37 let quadrant = (angle >> QUADRANT_BITS) as usize;
38 let idx = (angle & 0x3FFF) as u32;
39 let lut_idx = (idx >> (QUADRANT_BITS - LUT_BITS)) as usize;
40 let frac = (idx & LUT_MASK) as i32;
41
42 match quadrant {
43 0 => interpolate(SIN_LUT[lut_idx], SIN_LUT[lut_idx + 1], frac),
44 1 => interpolate(SIN_LUT[LUT_SIZE - lut_idx], SIN_LUT[LUT_SIZE - lut_idx - 1], frac),
45 2 => -interpolate(SIN_LUT[lut_idx], SIN_LUT[lut_idx + 1], frac),
46 _ => -interpolate(SIN_LUT[LUT_SIZE - lut_idx], SIN_LUT[LUT_SIZE - lut_idx - 1], frac),
47 }
48 }
49
50 #[inline(always)]
51 fn interpolate(y0: Fixed, y1: Fixed, frac: i32) -> Fixed {
52 let y0_32 = y0 as i32;
53 let y1_32 = y1 as i32;
54 (y0_32 + (((y1_32 - y0_32) * frac) >> (QUADRANT_BITS - LUT_BITS))) as Fixed
55 }
56}
57
58#[cfg(feature = "lut")]
60pub use lut_impl::sin_fixed;
61
62#[cfg(feature = "lut")]
63#[inline(always)]
64pub fn cos(angle: Angle) -> Fixed {
65 sin_fixed(angle.wrapping_add(16384))
66}
67
68#[cfg(feature = "lut")]
69#[inline(always)]
70pub fn sin_cos(angle: Angle) -> (Fixed, Fixed) {
71 (sin_fixed(angle), cos(angle))
72}
73
74#[cfg(feature = "taylor")]
78pub mod taylor_impl {
79 use super::{Angle, Fixed};
80
81 pub fn sin_taylor(angle: Angle) -> Fixed {
82 let x_input = if angle > 32768 { 65536 - angle as i32 } else { angle as i32 };
83 let x = if x_input > 16384 { 32768 - x_input } else { x_input };
84
85 let x_rad = (x * 51472) >> 14;
86
87 let x2 = (x_rad * x_rad) >> 15;
88 let x3 = (x2 * x_rad) >> 15;
89 let x5 = (((x3 * x2) >> 15) * x2) >> 15;
90
91 let term3 = (x3 * 5461) >> 15;
92 let term5 = (x5 * 273) >> 15;
93
94 let res = (x_rad - term3 + term5) as Fixed;
96
97 if angle > 32768 { -res } else { res }
98 }
99}
100#[cfg(feature = "fast-sin")]
104pub mod fast_impl {
105 use super::{Angle, Fixed};
106
107 pub fn sin_fast(angle: Angle) -> Fixed {
108 let x = (angle & 0x7FFF) as i32;
110 let pi = 32768i32;
111
112 let x_pi_x = (x * (pi - x)) >> 15; let num = (x_pi_x as i64) * 16;
118 let den = (5 * 32768) - ((4 * x_pi_x) >> 0); let res = (num * 32767) / den as i64;
122
123 let val = res as Fixed;
124 if angle > 32768 { -val } else { val }
125 }
126}
127#[inline(always)]
132pub fn to_fixed(x: f32) -> Fixed { (x * 32767.0) as Fixed }
133
134#[inline(always)]
135pub fn from_fixed(x: Fixed) -> f32 { (x as f32) / 32767.0 }
136
137#[inline(always)]
138pub fn radians_to_angle(rads: f32) -> Angle {
139 let scale = 65536.0 / (2.0 * core::f32::consts::PI);
140 (rads * scale) as i32 as u16
141}
142
143#[cfg(test)]
147mod tests {
148 extern crate std;
149 use super::*;
150 use core::f32::consts::PI;
151
152 #[cfg(feature = "lut")]
153 #[test]
154 fn test_sin_fixed_precision() {
155 assert!((sin_fixed(0) - 0).abs() <= 1);
157 assert!((sin_fixed(16384) - 32767).abs() <= 1); assert!((sin_fixed(32768) - 0).abs() <= 1); assert!((sin_fixed(49152) - (-32767)).abs() <= 1); let res_raw = sin_fixed(8192);
164 let expected_raw = 23203;
165
166 assert_eq!(res_raw, expected_raw, "Erreur de précision à 45°");
167 }
168
169 #[cfg(feature = "lut")]
170 #[test]
171 fn test_cos_fixed() {
172 assert!((cos(0) - 32767).abs() <= 1);
173 assert!(cos(16384).abs() <= 1);
174 assert!((cos(32768) - (-32767)).abs() <= 1);
175 }
176
177 #[cfg(feature = "taylor")]
178 #[test]
179 fn test_taylor_accuracy() {
180 let res = taylor_impl::sin_taylor(8192); let expected = 23170;
182 assert!((res - expected).abs() < 1000); }
184 #[cfg(feature = "fast-sin")]
185 #[test]
186 fn test_fast_sin_approximation() {
187 let res = fast_impl::sin_fast(5461);
189 let expected = 16384;
190 assert!((res - expected).abs() < 1500, "Valeur reçue: {}", res);
192 }
193 #[test]
194 fn test_radians_to_angle_wrapping() {
195 assert_eq!(radians_to_angle(0.0), 0);
196 assert_eq!(radians_to_angle(2.0 * PI), 0);
197 let a = radians_to_angle(-PI / 2.0);
199 assert!(a == 49152 || a == 49151);
200 }
201
202 #[test]
203 fn test_fixed_conversion_roundtrip() {
204 let original = 0.5f32;
205 let fixed = to_fixed(original);
206 let back = from_fixed(fixed);
207 assert!((original - back).abs() < 0.0001);
208 }
209
210 #[test]
211 fn test_sin_cos_simultaneous() {
212 #[cfg(feature = "lut")]
213 {
214 let (s, c) = sin_cos(0);
215 assert_eq!(s, 0);
216 assert_eq!(c, 32767);
217 }
218 }
219}