scirs2_core/fixed_point/
mod.rs1#![cfg_attr(not(feature = "std"), no_std)]
60
61#[cfg(feature = "fixed-point")]
62use fixed::{types::*, FixedI32, FixedI64};
63
64use core::fmt;
65use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};
66
67#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
87pub struct Fixed32<const FRAC: u32> {
88 raw: i32,
89}
90
91impl<const FRAC: u32> Fixed32<FRAC> {
92 pub const ZERO: Self = Self { raw: 0 };
94
95 pub const ONE: Self = Self { raw: 1 << FRAC };
97
98 pub const MIN: Self = Self { raw: i32::MIN };
100
101 pub const MAX: Self = Self { raw: i32::MAX };
103
104 #[inline]
106 pub const fn from_raw(raw: i32) -> Self {
107 Self { raw }
108 }
109
110 #[inline]
112 pub const fn to_raw(self) -> i32 {
113 self.raw
114 }
115
116 #[inline]
118 pub const fn from_int(value: i32) -> Self {
119 Self { raw: value << FRAC }
120 }
121
122 #[inline]
124 pub const fn to_int(self) -> i32 {
125 self.raw >> FRAC
126 }
127
128 #[inline]
130 pub fn from_float(value: f32) -> Self {
131 let scale = (1u64 << FRAC) as f32;
132 Self {
133 raw: (value * scale) as i32,
134 }
135 }
136
137 #[inline]
139 pub fn to_float(self) -> f32 {
140 let scale = (1u64 << FRAC) as f32;
141 self.raw as f32 / scale
142 }
143
144 #[inline]
146 pub const fn abs(self) -> Self {
147 Self {
148 raw: self.raw.abs(),
149 }
150 }
151
152 pub fn sqrt(self) -> Self {
159 if self.raw <= 0 {
160 return Self::ZERO;
161 }
162
163 let scaled = (self.raw as u64) << FRAC;
165
166 let bits = 64 - scaled.leading_zeros();
169 let mut result: u64 = 1u64 << ((bits + 1) / 2);
170
171 for _ in 0..32 {
173 if result == 0 {
174 break;
175 }
176 let next = (result + scaled / result) >> 1;
177 if next >= result {
178 break; }
180 result = next;
181 }
182
183 Self { raw: result as i32 }
184 }
185
186 #[inline]
188 pub const fn saturating_add(self, rhs: Self) -> Self {
189 Self {
190 raw: self.raw.saturating_add(rhs.raw),
191 }
192 }
193
194 #[inline]
196 pub const fn saturating_sub(self, rhs: Self) -> Self {
197 Self {
198 raw: self.raw.saturating_sub(rhs.raw),
199 }
200 }
201
202 #[inline]
204 pub fn saturating_mul(self, rhs: Self) -> Self {
205 let result = (self.raw as i64 * rhs.raw as i64) >> FRAC;
206 Self {
207 raw: result.clamp(i32::MIN as i64, i32::MAX as i64) as i32,
208 }
209 }
210}
211
212impl<const FRAC: u32> Add for Fixed32<FRAC> {
214 type Output = Self;
215
216 #[inline]
217 fn add(self, rhs: Self) -> Self::Output {
218 Self {
219 raw: self.raw + rhs.raw,
220 }
221 }
222}
223
224impl<const FRAC: u32> AddAssign for Fixed32<FRAC> {
225 #[inline]
226 fn add_assign(&mut self, rhs: Self) {
227 self.raw += rhs.raw;
228 }
229}
230
231impl<const FRAC: u32> Sub for Fixed32<FRAC> {
232 type Output = Self;
233
234 #[inline]
235 fn sub(self, rhs: Self) -> Self::Output {
236 Self {
237 raw: self.raw - rhs.raw,
238 }
239 }
240}
241
242impl<const FRAC: u32> SubAssign for Fixed32<FRAC> {
243 #[inline]
244 fn sub_assign(&mut self, rhs: Self) {
245 self.raw -= rhs.raw;
246 }
247}
248
249impl<const FRAC: u32> Mul for Fixed32<FRAC> {
250 type Output = Self;
251
252 #[inline]
253 fn mul(self, rhs: Self) -> Self::Output {
254 let result = (self.raw as i64 * rhs.raw as i64) >> FRAC;
255 Self { raw: result as i32 }
256 }
257}
258
259impl<const FRAC: u32> MulAssign for Fixed32<FRAC> {
260 #[inline]
261 fn mul_assign(&mut self, rhs: Self) {
262 *self = *self * rhs;
263 }
264}
265
266impl<const FRAC: u32> Div for Fixed32<FRAC> {
267 type Output = Self;
268
269 #[inline]
270 fn div(self, rhs: Self) -> Self::Output {
271 let result = ((self.raw as i64) << FRAC) / rhs.raw as i64;
272 Self { raw: result as i32 }
273 }
274}
275
276impl<const FRAC: u32> DivAssign for Fixed32<FRAC> {
277 #[inline]
278 fn div_assign(&mut self, rhs: Self) {
279 *self = *self / rhs;
280 }
281}
282
283impl<const FRAC: u32> Neg for Fixed32<FRAC> {
284 type Output = Self;
285
286 #[inline]
287 fn neg(self) -> Self::Output {
288 Self { raw: -self.raw }
289 }
290}
291
292impl<const FRAC: u32> Default for Fixed32<FRAC> {
293 fn default() -> Self {
294 Self::ZERO
295 }
296}
297
298impl<const FRAC: u32> fmt::Display for Fixed32<FRAC> {
299 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
300 write!(f, "{}", self.to_float())
301 }
302}
303
304#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
321pub struct Fixed64<const FRAC: u32> {
322 raw: i64,
323}
324
325impl<const FRAC: u32> Fixed64<FRAC> {
326 pub const ZERO: Self = Self { raw: 0 };
328
329 pub const ONE: Self = Self { raw: 1 << FRAC };
331
332 #[inline]
334 pub const fn from_raw(raw: i64) -> Self {
335 Self { raw }
336 }
337
338 #[inline]
340 pub const fn to_raw(self) -> i64 {
341 self.raw
342 }
343
344 #[inline]
346 pub const fn from_int(value: i64) -> Self {
347 Self { raw: value << FRAC }
348 }
349
350 #[inline]
352 pub const fn to_int(self) -> i64 {
353 self.raw >> FRAC
354 }
355
356 #[inline]
358 pub fn from_float(value: f32) -> Self {
359 let scale = (1u64 << FRAC) as f32;
360 Self {
361 raw: (value * scale) as i64,
362 }
363 }
364
365 #[inline]
367 pub fn from_double(value: f64) -> Self {
368 let scale = (1u64 << FRAC) as f64;
369 Self {
370 raw: (value * scale) as i64,
371 }
372 }
373
374 #[inline]
376 pub fn to_float(self) -> f32 {
377 let scale = (1u64 << FRAC) as f32;
378 self.raw as f32 / scale
379 }
380
381 #[inline]
383 pub fn to_double(self) -> f64 {
384 let scale = (1u64 << FRAC) as f64;
385 self.raw as f64 / scale
386 }
387}
388
389impl<const FRAC: u32> Add for Fixed64<FRAC> {
391 type Output = Self;
392
393 #[inline]
394 fn add(self, rhs: Self) -> Self::Output {
395 Self {
396 raw: self.raw + rhs.raw,
397 }
398 }
399}
400
401impl<const FRAC: u32> Sub for Fixed64<FRAC> {
402 type Output = Self;
403
404 #[inline]
405 fn sub(self, rhs: Self) -> Self::Output {
406 Self {
407 raw: self.raw - rhs.raw,
408 }
409 }
410}
411
412impl<const FRAC: u32> Mul for Fixed64<FRAC> {
413 type Output = Self;
414
415 #[inline]
416 fn mul(self, rhs: Self) -> Self::Output {
417 let result = (self.raw as i128 * rhs.raw as i128) >> FRAC;
418 Self { raw: result as i64 }
419 }
420}
421
422impl<const FRAC: u32> Div for Fixed64<FRAC> {
423 type Output = Self;
424
425 #[inline]
426 fn div(self, rhs: Self) -> Self::Output {
427 let result = ((self.raw as i128) << FRAC) / rhs.raw as i128;
428 Self { raw: result as i64 }
429 }
430}
431
432impl<const FRAC: u32> Default for Fixed64<FRAC> {
433 fn default() -> Self {
434 Self::ZERO
435 }
436}
437
438impl<const FRAC: u32> fmt::Display for Fixed64<FRAC> {
439 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
440 write!(f, "{}", self.to_double())
441 }
442}
443
444pub mod types {
446 use super::*;
447
448 pub type Q16 = Fixed32<16>;
451
452 pub type Q24 = Fixed32<24>;
455
456 pub type Q8 = Fixed32<8>;
459
460 pub type Q32 = Fixed64<32>;
463}
464
465pub mod math {
467 use super::*;
468
469 pub fn sin<const FRAC: u32>(x: Fixed32<FRAC>) -> Fixed32<FRAC> {
473 let pi = Fixed32::<FRAC>::from_float(core::f32::consts::PI);
475 let two_pi = Fixed32::<FRAC>::from_float(2.0 * core::f32::consts::PI);
476
477 let mut angle = x;
478 while angle > pi {
479 angle -= two_pi;
480 }
481 while angle < -pi {
482 angle += two_pi;
483 }
484
485 let x2 = angle * angle;
487 let x3 = x2 * angle;
488 let x5 = x3 * x2;
489 let x7 = x5 * x2;
490
491 let term1 = angle;
492 let term2 = x3 / Fixed32::<FRAC>::from_int(6); let term3 = x5 / Fixed32::<FRAC>::from_int(120); let term4 = x7 / Fixed32::<FRAC>::from_int(5040); term1 - term2 + term3 - term4
497 }
498
499 pub fn cos<const FRAC: u32>(x: Fixed32<FRAC>) -> Fixed32<FRAC> {
501 let half_pi = Fixed32::<FRAC>::from_float(core::f32::consts::FRAC_PI_2);
502 sin(x + half_pi)
503 }
504
505 pub fn exp<const FRAC: u32>(x: Fixed32<FRAC>) -> Fixed32<FRAC> {
507 let mut result = Fixed32::<FRAC>::ONE;
509 let mut term = Fixed32::<FRAC>::ONE;
510
511 for n in 1..10 {
512 term = term * x / Fixed32::<FRAC>::from_int(n);
513 result += term;
514
515 if term.abs().to_raw().abs() < 4 {
517 break;
518 }
519 }
520
521 result
522 }
523
524 pub fn ln<const FRAC: u32>(x: Fixed32<FRAC>) -> Fixed32<FRAC> {
526 if x.to_raw() <= 0 {
527 return Fixed32::<FRAC>::MIN;
528 }
529
530 let one = Fixed32::<FRAC>::ONE;
533 let numerator = x - one;
534 let denominator = x + one;
535 let y = numerator / denominator;
536 let y2 = y * y;
537
538 let term1 = y;
539 let term2 = (y * y2) / Fixed32::<FRAC>::from_int(3);
540 let term3 = (y * y2 * y2) / Fixed32::<FRAC>::from_int(5);
541
542 Fixed32::<FRAC>::from_int(2) * (term1 + term2 + term3)
543 }
544}
545
546pub mod signal {
548 use super::*;
549
550 pub struct FirFilter<const FRAC: u32, const N: usize> {
563 coeffs: [Fixed32<FRAC>; N],
564 buffer: [Fixed32<FRAC>; N],
565 index: usize,
566 }
567
568 impl<const FRAC: u32, const N: usize> FirFilter<FRAC, N> {
569 pub fn new(coeffs: &[Fixed32<FRAC>; N]) -> Self {
571 Self {
572 coeffs: *coeffs,
573 buffer: [Fixed32::<FRAC>::ZERO; N],
574 index: 0,
575 }
576 }
577
578 pub fn process(&mut self, input: Fixed32<FRAC>) -> Fixed32<FRAC> {
580 self.buffer[self.index] = input;
582 self.index = (self.index + 1) % N;
583
584 let mut output = Fixed32::<FRAC>::ZERO;
586 for i in 0..N {
587 let buf_idx = (self.index + N - 1 - i) % N;
588 output += self.coeffs[i] * self.buffer[buf_idx];
589 }
590
591 output
592 }
593
594 pub fn reset(&mut self) {
596 self.buffer = [Fixed32::<FRAC>::ZERO; N];
597 self.index = 0;
598 }
599 }
600}
601
602#[cfg(test)]
603mod tests {
604 use super::*;
605
606 #[test]
607 fn test_fixed32_basic() {
608 let a = Fixed32::<16>::from_float(core::f32::consts::PI);
609 let b = Fixed32::<16>::from_float(2.0);
610
611 let sum = a + b;
612 assert!((sum.to_float() - (core::f32::consts::PI + 2.0)).abs() < 0.01);
613
614 let product = a * b;
615 assert!((product.to_float() - core::f32::consts::TAU).abs() < 0.01);
616 }
617
618 #[test]
619 fn test_fixed32_sqrt() {
620 let x = Fixed32::<16>::from_float(4.0);
621 let sqrt_x = x.sqrt();
622 assert!((sqrt_x.to_float() - 2.0).abs() < 0.1);
623 }
624
625 #[test]
626 fn test_fixed64_precision() {
627 let a = Fixed64::<32>::from_double(std::f64::consts::PI);
628 let b = Fixed64::<32>::from_double(2.0);
629
630 let product = a * b;
631 assert!((product.to_double() - std::f64::consts::TAU).abs() < 1e-9);
632 }
633
634 #[test]
635 fn test_math_functions() {
636 use math::*;
637
638 let x = Fixed32::<16>::from_float(0.0);
639 let sin_x = sin(x);
640 assert!((sin_x.to_float() - 0.0).abs() < 0.01);
641
642 let half_pi = Fixed32::<16>::from_float(core::f32::consts::FRAC_PI_2);
643 let sin_half_pi = sin(half_pi);
644 assert!((sin_half_pi.to_float() - 1.0).abs() < 0.1);
645 }
646
647 #[test]
648 fn test_fir_filter() {
649 use signal::*;
650
651 let coeffs = [Fixed32::<16>::from_float(0.2); 5];
652 let mut filter = FirFilter::new(&coeffs);
653
654 let input = Fixed32::<16>::from_float(1.0);
655 let output = filter.process(input);
656
657 assert!(output.to_float() > 0.0);
658 }
659}