Skip to main content

embedded_dsp/
types.rs

1//! Data types, status codes, complex structures, and fixed-point helper types.
2
3#[allow(non_camel_case_types)]
4pub type q7 = i8;
5#[allow(non_camel_case_types)]
6pub type q15 = i16;
7#[allow(non_camel_case_types)]
8pub type q31 = i32;
9#[allow(non_camel_case_types)]
10pub type q63 = i64;
11#[allow(non_camel_case_types)]
12pub type f32_t = f32;
13#[allow(non_camel_case_types)]
14pub type f64_t = f64;
15
16/// Error status returned by functions in `embedded-dsp`.
17#[derive(Debug, Clone, Copy, PartialEq, Eq)]
18#[repr(i8)]
19pub enum Status {
20    /// Operation succeeded without error.
21    Success = 0,
22    /// One or more arguments are invalid.
23    ArgumentError = -1,
24    /// Length of data buffer is invalid or mismatching.
25    LengthError = -2,
26    /// Matrix dimensions are incompatible.
27    SizeMismatch = -3,
28    /// NaN or Infinity was produced during computation.
29    NanInf = -4,
30    /// Matrix is singular and cannot be inverted.
31    Singular = -5,
32    /// Test or verification failed.
33    TestFailure = -6,
34    /// Matrix decomposition failed.
35    DecompositionFailure = -7,
36}
37
38/// Representation of a complex number with real and imaginary components.
39#[derive(Debug, Clone, Copy, PartialEq, Default)]
40#[repr(C)]
41pub struct Complex<T> {
42    pub real: T,
43    pub imag: T,
44}
45
46impl<T> Complex<T> {
47    #[inline(always)]
48    pub const fn new(real: T, imag: T) -> Self {
49        Self { real, imag }
50    }
51}
52
53/// Helper function for saturating multiplication in Q15 format.
54#[inline(always)]
55pub fn q15_mult(a: q15, b: q15) -> q15 {
56    let mul = (a as i32 * b as i32) >> 15;
57    mul.clamp(i16::MIN as i32, i16::MAX as i32) as i16
58}
59
60/// Helper function for saturating multiplication in Q31 format.
61#[inline(always)]
62pub fn q31_mult(a: q31, b: q31) -> q31 {
63    let mul = (a as i64 * b as i64) >> 31;
64    mul.clamp(i32::MIN as i64, i32::MAX as i64) as i32
65}
66
67/// Helper function for saturating multiplication in Q7 format.
68#[inline(always)]
69pub fn q7_mult(a: q7, b: q7) -> q7 {
70    let mul = (a as i32 * b as i32) >> 7;
71    mul.clamp(i8::MIN as i32, i8::MAX as i32) as i8
72}
73
74// ─────────────────────────────────────────────────────────────────────────────
75// Strongly-typed Fixed-Point Newtypes (Q15, Q31)
76// ─────────────────────────────────────────────────────────────────────────────
77
78/// Strongly-typed Q1.15 fixed-point number stored in an `i16`.
79///
80/// Range is `[-1.0, 0.999969482421875]`.
81/// Provides operator overloading (`+`, `-`, `*`, `/`) with saturating fixed-point arithmetic.
82#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
83#[repr(transparent)]
84pub struct Q15(pub i16);
85
86impl Q15 {
87    /// Zero representation (`0.0`).
88    pub const ZERO: Self = Self(0);
89    /// Maximum positive value (`0.999969482...` = `32767`).
90    pub const ONE: Self = Self(i16::MAX);
91    /// Minimum representable value (`-1.0` = `-32768`).
92    pub const MIN: Self = Self(i16::MIN);
93    /// Maximum representable value (`0.999969482...` = `32767`).
94    pub const MAX: Self = Self(i16::MAX);
95    /// Smallest positive step (`1 / 32768`).
96    pub const DELTA: Self = Self(1);
97
98    /// Create from raw integer bits.
99    #[inline(always)]
100    pub const fn from_bits(bits: i16) -> Self {
101        Self(bits)
102    }
103
104    /// Retrieve raw integer bits.
105    #[inline(always)]
106    pub const fn to_bits(self) -> i16 {
107        self.0
108    }
109
110    /// Convert from `f32` with rounding and saturation to `[-1.0, 0.999969]`.
111    #[inline(always)]
112    pub fn from_f32(v: f32) -> Self {
113        let scaled = v * 32768.0 + if v >= 0.0 { 0.5 } else { -0.5 };
114        Self(scaled.clamp(-32768.0, 32767.0) as i16)
115    }
116
117    /// Convert to `f32`.
118    #[inline(always)]
119    pub fn to_f32(self) -> f32 {
120        self.0 as f32 / 32768.0
121    }
122
123    /// Saturating addition.
124    #[inline(always)]
125    pub const fn saturating_add(self, rhs: Self) -> Self {
126        Self(self.0.saturating_add(rhs.0))
127    }
128
129    /// Saturating subtraction.
130    #[inline(always)]
131    pub const fn saturating_sub(self, rhs: Self) -> Self {
132        Self(self.0.saturating_sub(rhs.0))
133    }
134
135    /// Saturating Q15 multiplication.
136    #[inline(always)]
137    pub fn saturating_mul(self, rhs: Self) -> Self {
138        Self(q15_mult(self.0, rhs.0))
139    }
140
141    /// Saturating Q15 division with division-by-zero protection.
142    #[inline(always)]
143    pub fn saturating_div(self, rhs: Self) -> Self {
144        if rhs.0 == 0 {
145            if self.0 >= 0 { Self::MAX } else { Self::MIN }
146        } else {
147            let num = (self.0 as i32) << 15;
148            let res = num / (rhs.0 as i32);
149            Self(res.clamp(i16::MIN as i32, i16::MAX as i32) as i16)
150        }
151    }
152
153    /// Absolute value (saturating at `Self::MAX` for `-1.0`).
154    #[inline(always)]
155    pub const fn abs(self) -> Self {
156        if self.0 == i16::MIN {
157            Self::MAX
158        } else {
159            Self(self.0.abs())
160        }
161    }
162
163    /// Clamp to `[min, max]`.
164    #[inline(always)]
165    pub fn clamp(self, min: Self, max: Self) -> Self {
166        Self(self.0.clamp(min.0, max.0))
167    }
168}
169
170impl core::ops::Add for Q15 {
171    type Output = Self;
172    #[inline(always)]
173    fn add(self, rhs: Self) -> Self {
174        self.saturating_add(rhs)
175    }
176}
177
178impl core::ops::Sub for Q15 {
179    type Output = Self;
180    #[inline(always)]
181    fn sub(self, rhs: Self) -> Self {
182        self.saturating_sub(rhs)
183    }
184}
185
186impl core::ops::Mul for Q15 {
187    type Output = Self;
188    #[inline(always)]
189    fn mul(self, rhs: Self) -> Self {
190        self.saturating_mul(rhs)
191    }
192}
193
194impl core::ops::Div for Q15 {
195    type Output = Self;
196    #[inline(always)]
197    fn div(self, rhs: Self) -> Self {
198        self.saturating_div(rhs)
199    }
200}
201
202impl core::ops::Neg for Q15 {
203    type Output = Self;
204    #[inline(always)]
205    fn neg(self) -> Self {
206        if self.0 == i16::MIN {
207            Self::MAX
208        } else {
209            Self(-self.0)
210        }
211    }
212}
213
214impl core::ops::AddAssign for Q15 {
215    #[inline(always)]
216    fn add_assign(&mut self, rhs: Self) {
217        *self = *self + rhs;
218    }
219}
220
221impl core::ops::SubAssign for Q15 {
222    #[inline(always)]
223    fn sub_assign(&mut self, rhs: Self) {
224        *self = *self - rhs;
225    }
226}
227
228impl core::ops::MulAssign for Q15 {
229    #[inline(always)]
230    fn mul_assign(&mut self, rhs: Self) {
231        *self = *self * rhs;
232    }
233}
234
235impl core::ops::DivAssign for Q15 {
236    #[inline(always)]
237    fn div_assign(&mut self, rhs: Self) {
238        *self = *self / rhs;
239    }
240}
241
242impl From<i16> for Q15 {
243    #[inline(always)]
244    fn from(v: i16) -> Self {
245        Self(v)
246    }
247}
248
249impl From<Q15> for i16 {
250    #[inline(always)]
251    fn from(v: Q15) -> Self {
252        v.0
253    }
254}
255
256impl From<f32> for Q15 {
257    #[inline(always)]
258    fn from(v: f32) -> Self {
259        Self::from_f32(v)
260    }
261}
262
263impl From<Q15> for f32 {
264    #[inline(always)]
265    fn from(v: Q15) -> Self {
266        v.to_f32()
267    }
268}
269
270/// Strongly-typed Q1.31 fixed-point number stored in an `i32`.
271///
272/// Range is `[-1.0, 0.9999999995343387]`.
273/// Provides operator overloading (`+`, `-`, `*`, `/`) with saturating fixed-point arithmetic.
274#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
275#[repr(transparent)]
276pub struct Q31(pub i32);
277
278impl Q31 {
279    /// Zero representation (`0.0`).
280    pub const ZERO: Self = Self(0);
281    /// Maximum positive value (`~1.0` = `i32::MAX`).
282    pub const ONE: Self = Self(i32::MAX);
283    /// Minimum representable value (`-1.0` = `i32::MIN`).
284    pub const MIN: Self = Self(i32::MIN);
285    /// Maximum representable value (`~1.0` = `i32::MAX`).
286    pub const MAX: Self = Self(i32::MAX);
287    /// Smallest positive step (`1 / 2^31`).
288    pub const DELTA: Self = Self(1);
289
290    /// Create from raw integer bits.
291    #[inline(always)]
292    pub const fn from_bits(bits: i32) -> Self {
293        Self(bits)
294    }
295
296    /// Retrieve raw integer bits.
297    #[inline(always)]
298    pub const fn to_bits(self) -> i32 {
299        self.0
300    }
301
302    /// Convert from `f32` with rounding and saturation.
303    #[inline(always)]
304    pub fn from_f32(v: f32) -> Self {
305        let scaled = v as f64 * 2147483648.0 + if v >= 0.0 { 0.5 } else { -0.5 };
306        Self(scaled.clamp(-2147483648.0, 2147483647.0) as i32)
307    }
308
309    /// Convert to `f32`.
310    #[inline(always)]
311    pub fn to_f32(self) -> f32 {
312        (self.0 as f64 / 2147483648.0) as f32
313    }
314
315    /// Convert from `f64` with rounding and saturation.
316    #[inline(always)]
317    pub fn from_f64(v: f64) -> Self {
318        let scaled = v * 2147483648.0 + if v >= 0.0 { 0.5 } else { -0.5 };
319        Self(scaled.clamp(-2147483648.0, 2147483647.0) as i32)
320    }
321
322    /// Convert to `f64`.
323    #[inline(always)]
324    pub fn to_f64(self) -> f64 {
325        self.0 as f64 / 2147483648.0
326    }
327
328    /// Saturating addition.
329    #[inline(always)]
330    pub const fn saturating_add(self, rhs: Self) -> Self {
331        Self(self.0.saturating_add(rhs.0))
332    }
333
334    /// Saturating subtraction.
335    #[inline(always)]
336    pub const fn saturating_sub(self, rhs: Self) -> Self {
337        Self(self.0.saturating_sub(rhs.0))
338    }
339
340    /// Saturating Q31 multiplication.
341    #[inline(always)]
342    pub fn saturating_mul(self, rhs: Self) -> Self {
343        Self(q31_mult(self.0, rhs.0))
344    }
345
346    /// Saturating Q31 division with division-by-zero protection.
347    #[inline(always)]
348    pub fn saturating_div(self, rhs: Self) -> Self {
349        if rhs.0 == 0 {
350            if self.0 >= 0 { Self::MAX } else { Self::MIN }
351        } else {
352            let num = (self.0 as i64) << 31;
353            let res = num / (rhs.0 as i64);
354            Self(res.clamp(i32::MIN as i64, i32::MAX as i64) as i32)
355        }
356    }
357
358    /// Absolute value (saturating at `Self::MAX` for `-1.0`).
359    #[inline(always)]
360    pub const fn abs(self) -> Self {
361        if self.0 == i32::MIN {
362            Self::MAX
363        } else {
364            Self(self.0.abs())
365        }
366    }
367
368    /// Clamp to `[min, max]`.
369    #[inline(always)]
370    pub fn clamp(self, min: Self, max: Self) -> Self {
371        Self(self.0.clamp(min.0, max.0))
372    }
373}
374
375impl core::ops::Add for Q31 {
376    type Output = Self;
377    #[inline(always)]
378    fn add(self, rhs: Self) -> Self {
379        self.saturating_add(rhs)
380    }
381}
382
383impl core::ops::Sub for Q31 {
384    type Output = Self;
385    #[inline(always)]
386    fn sub(self, rhs: Self) -> Self {
387        self.saturating_sub(rhs)
388    }
389}
390
391impl core::ops::Mul for Q31 {
392    type Output = Self;
393    #[inline(always)]
394    fn mul(self, rhs: Self) -> Self {
395        self.saturating_mul(rhs)
396    }
397}
398
399impl core::ops::Div for Q31 {
400    type Output = Self;
401    #[inline(always)]
402    fn div(self, rhs: Self) -> Self {
403        self.saturating_div(rhs)
404    }
405}
406
407impl core::ops::Neg for Q31 {
408    type Output = Self;
409    #[inline(always)]
410    fn neg(self) -> Self {
411        if self.0 == i32::MIN {
412            Self::MAX
413        } else {
414            Self(-self.0)
415        }
416    }
417}
418
419impl core::ops::AddAssign for Q31 {
420    #[inline(always)]
421    fn add_assign(&mut self, rhs: Self) {
422        *self = *self + rhs;
423    }
424}
425
426impl core::ops::SubAssign for Q31 {
427    #[inline(always)]
428    fn sub_assign(&mut self, rhs: Self) {
429        *self = *self - rhs;
430    }
431}
432
433impl core::ops::MulAssign for Q31 {
434    #[inline(always)]
435    fn mul_assign(&mut self, rhs: Self) {
436        *self = *self * rhs;
437    }
438}
439
440impl core::ops::DivAssign for Q31 {
441    #[inline(always)]
442    fn div_assign(&mut self, rhs: Self) {
443        *self = *self / rhs;
444    }
445}
446
447impl From<i32> for Q31 {
448    #[inline(always)]
449    fn from(v: i32) -> Self {
450        Self(v)
451    }
452}
453
454impl From<Q31> for i32 {
455    #[inline(always)]
456    fn from(v: Q31) -> Self {
457        v.0
458    }
459}
460
461impl From<f32> for Q31 {
462    #[inline(always)]
463    fn from(v: f32) -> Self {
464        Self::from_f32(v)
465    }
466}
467
468impl From<Q31> for f32 {
469    #[inline(always)]
470    fn from(v: Q31) -> Self {
471        v.to_f32()
472    }
473}
474
475// ─────────────────────────────────────────────────────────────────────────────
476// Unified DSP Sample Trait
477// ─────────────────────────────────────────────────────────────────────────────
478
479/// Unified numerical sample trait implemented for both floating-point and fixed-point numbers.
480///
481/// Enables writing generic filters, delay lines, oscillators, and processing blocks that operate
482/// seamlessly with `f32`, `f64`, `Q15`, and `Q31`.
483pub trait DspSample:
484    Copy
485    + Default
486    + PartialEq
487    + PartialOrd
488    + core::ops::Add<Output = Self>
489    + core::ops::Sub<Output = Self>
490    + core::ops::Mul<Output = Self>
491    + core::ops::Neg<Output = Self>
492{
493    /// Additive identity (`0.0`).
494    const ZERO: Self;
495    /// Multiplicative identity or normalized unity (`1.0`).
496    const ONE: Self;
497
498    /// Saturating addition.
499    fn sat_add(self, rhs: Self) -> Self;
500    /// Saturating subtraction.
501    fn sat_sub(self, rhs: Self) -> Self;
502    /// Saturating multiplication.
503    fn sat_mul(self, rhs: Self) -> Self;
504    /// Saturating division.
505    fn sat_div(self, rhs: Self) -> Self;
506    /// Absolute value.
507    fn abs_val(self) -> Self;
508    /// Convert to floating-point `f32`.
509    fn to_f32(self) -> f32;
510    /// Convert from floating-point `f32`.
511    fn from_f32(val: f32) -> Self;
512}
513
514impl DspSample for f32 {
515    const ZERO: Self = 0.0;
516    const ONE: Self = 1.0;
517
518    #[inline(always)]
519    fn sat_add(self, rhs: Self) -> Self {
520        self + rhs
521    }
522
523    #[inline(always)]
524    fn sat_sub(self, rhs: Self) -> Self {
525        self - rhs
526    }
527
528    #[inline(always)]
529    fn sat_mul(self, rhs: Self) -> Self {
530        self * rhs
531    }
532
533    #[inline(always)]
534    fn sat_div(self, rhs: Self) -> Self {
535        self / rhs
536    }
537
538    #[inline(always)]
539    fn abs_val(self) -> Self {
540        if self < 0.0 { -self } else { self }
541    }
542
543    #[inline(always)]
544    fn to_f32(self) -> f32 {
545        self
546    }
547
548    #[inline(always)]
549    fn from_f32(val: f32) -> Self {
550        val
551    }
552}
553
554impl DspSample for f64 {
555    const ZERO: Self = 0.0;
556    const ONE: Self = 1.0;
557
558    #[inline(always)]
559    fn sat_add(self, rhs: Self) -> Self {
560        self + rhs
561    }
562
563    #[inline(always)]
564    fn sat_sub(self, rhs: Self) -> Self {
565        self - rhs
566    }
567
568    #[inline(always)]
569    fn sat_mul(self, rhs: Self) -> Self {
570        self * rhs
571    }
572
573    #[inline(always)]
574    fn sat_div(self, rhs: Self) -> Self {
575        self / rhs
576    }
577
578    #[inline(always)]
579    fn abs_val(self) -> Self {
580        if self < 0.0 { -self } else { self }
581    }
582
583    #[inline(always)]
584    fn to_f32(self) -> f32 {
585        self as f32
586    }
587
588    #[inline(always)]
589    fn from_f32(val: f32) -> Self {
590        val as f64
591    }
592}
593
594impl DspSample for Q15 {
595    const ZERO: Self = Self::ZERO;
596    const ONE: Self = Self::ONE;
597
598    #[inline(always)]
599    fn sat_add(self, rhs: Self) -> Self {
600        self.saturating_add(rhs)
601    }
602
603    #[inline(always)]
604    fn sat_sub(self, rhs: Self) -> Self {
605        self.saturating_sub(rhs)
606    }
607
608    #[inline(always)]
609    fn sat_mul(self, rhs: Self) -> Self {
610        self.saturating_mul(rhs)
611    }
612
613    #[inline(always)]
614    fn sat_div(self, rhs: Self) -> Self {
615        self.saturating_div(rhs)
616    }
617
618    #[inline(always)]
619    fn abs_val(self) -> Self {
620        self.abs()
621    }
622
623    #[inline(always)]
624    fn to_f32(self) -> f32 {
625        self.to_f32()
626    }
627
628    #[inline(always)]
629    fn from_f32(val: f32) -> Self {
630        Self::from_f32(val)
631    }
632}
633
634impl DspSample for Q31 {
635    const ZERO: Self = Self::ZERO;
636    const ONE: Self = Self::ONE;
637
638    #[inline(always)]
639    fn sat_add(self, rhs: Self) -> Self {
640        self.saturating_add(rhs)
641    }
642
643    #[inline(always)]
644    fn sat_sub(self, rhs: Self) -> Self {
645        self.saturating_sub(rhs)
646    }
647
648    #[inline(always)]
649    fn sat_mul(self, rhs: Self) -> Self {
650        self.saturating_mul(rhs)
651    }
652
653    #[inline(always)]
654    fn sat_div(self, rhs: Self) -> Self {
655        self.saturating_div(rhs)
656    }
657
658    #[inline(always)]
659    fn abs_val(self) -> Self {
660        self.abs()
661    }
662
663    #[inline(always)]
664    fn to_f32(self) -> f32 {
665        self.to_f32()
666    }
667
668    #[inline(always)]
669    fn from_f32(val: f32) -> Self {
670        Self::from_f32(val)
671    }
672}
673
674// ─────────────────────────────────────────────────────────────────────────────
675// Complex Number Operations
676// ─────────────────────────────────────────────────────────────────────────────
677
678impl<T: core::ops::Add<Output = T>> core::ops::Add for Complex<T> {
679    type Output = Self;
680    #[inline(always)]
681    fn add(self, rhs: Self) -> Self {
682        Self {
683            real: self.real + rhs.real,
684            imag: self.imag + rhs.imag,
685        }
686    }
687}
688
689impl<T: core::ops::Sub<Output = T>> core::ops::Sub for Complex<T> {
690    type Output = Self;
691    #[inline(always)]
692    fn sub(self, rhs: Self) -> Self {
693        Self {
694            real: self.real - rhs.real,
695            imag: self.imag - rhs.imag,
696        }
697    }
698}
699
700impl<T: core::ops::Neg<Output = T>> core::ops::Neg for Complex<T> {
701    type Output = Self;
702    #[inline(always)]
703    fn neg(self) -> Self {
704        Self {
705            real: -self.real,
706            imag: -self.imag,
707        }
708    }
709}
710
711impl<T: Copy + core::ops::Add<Output = T> + core::ops::Sub<Output = T> + core::ops::Mul<Output = T>>
712    core::ops::Mul for Complex<T>
713{
714    type Output = Self;
715    #[inline(always)]
716    fn mul(self, rhs: Self) -> Self {
717        Self {
718            real: self.real * rhs.real - self.imag * rhs.imag,
719            imag: self.real * rhs.imag + self.imag * rhs.real,
720        }
721    }
722}
723
724impl<T: Copy + core::ops::Mul<Output = T>> core::ops::Mul<T> for Complex<T> {
725    type Output = Self;
726    #[inline(always)]
727    fn mul(self, scalar: T) -> Self {
728        Self {
729            real: self.real * scalar,
730            imag: self.imag * scalar,
731        }
732    }
733}