# Embedded DSP algorithms
[](https://github.com/quartiq/idsp/releases)
[](https://crates.io/crates/idsp)
[](https://docs.rs/idsp)
[](https://matrix.to/#/#quartiq:matrix.org)
[](https://github.com/quartiq/idsp/actions/workflows/ci.yml)
This crate contains some tuned DSP algorithms for general and especially embedded use.
Many of the algorithms are implemented on integer (fixed point) datatypes.
One comprehensive user for these algorithms is [Stabilizer](https://github.com/quartiq/stabilizer).
## Showcase examples
The repository examples are small composite DSP graphs built from `idsp` and
`dsp-process` primitives:
* `cargo run --example ddc_lockin --features std`: real-input DDC / lock-in with shared biquad state
* `cargo run --example fm_disc --features std`: FM discriminator receiver core using `cossin()`/`atan2()`
* `cargo run --example polyphase_channelizer --features std`: static 4-channel polyphase analysis bank
## Fixed point
### Cosine/Sine
[`cossin()`] uses a small (128 element or 512 byte) midpoint LUT, smart octant (un)mapping, and first-order interpolation to compute both cosine and sine (i.e. the complex signal) at once given a phase input. The pointwise quadrature error is about 4e-6 RMS and 9e-6 max. As a coherent DDS driven by an [`Accu`], the midpoint interpolation gives a predictable dominant complex spur pair at `±(8*2^7)f = ±1024f` from the carrier at about -120.4 dBc. The implementation remains small and fast with about 40 Cortex-M instructions per call (23.5 cycles on Cortex-M7, see `tests/embedded`).
### Two-argument arcus-tangens
[`atan2()`] returns a phase given a complex signal (a pair of in-phase/`x`/cosine and quadrature/`y`/sine). It uses a small reciprocal LUT with one Newton step followed by a fixed-point odd polynomial. The measured phase error is about 1.3e-6 rad RMS and 2.3e-6 rad max on the repository test grid, i.e. about 22.5 bit RMS and 21.4 bit max accuracy. The bias is minimal. It takes about 52 cycles on Cortex-M7 (see `tests/embedded`).
### CORDIC
[`sqrt_atan2`] etc: complete family of CORDIC mode reference implementations.
## PLL, RPLL
[`PLL`], [`RPLL`]: High accuracy, zero-assumption, fully robust, forward and reciprocal PLLs with dynamically adjustable time constant and arbitrary (in the Nyquist sampling sense) capture range, and noise shaping.
## `Unwrapper`, `Accu`, `Uniform`, `Triangular`, `saturating_scale()`
[`Unwrapper`], [`Accu`], [`Uniform`], [`Triangular`], [`saturating_scale()`]:
Tools to handle, track, and unwrap phase signals or generate them.
## Float and Fixed point
## IIR/Biquad
[`iir::Biquad`] and [`iir::BiquadClamp`] are fixed point (`i8`, `i16`, `i32`, `i64`) and floating point (`f32`, `f64`) biquad IIR filters.
Robust and clean clipping and offset (anti-windup, no derivative kick, dynamically adjustable gains and gain limits) suitable for PID controller applications.
Four kinds of filter action are supported for each Biquad: Direct Form 1, Direct Form 2 Transposed, Direct Form 1 with noise shaping,
and Direct Form 1 with wide output.
Coefficient sharing for multiple lanes/channels is implemented through [`dsp_process::SplitProcess`], [`dsp_process::Lanes`].
Miniconf-backed control-plane configuration is available through `iir::config` with the `miniconf` feature.
### Comparison
This is a rough feature comparison of several available `biquad` crates, with no claim for completeness, accuracy, or even fairness.
TL;DR: `idsp` is as fast or faster, and offers more features.
| Feature\Crate | [`biquad-rs`](https://crates.io/crates/biquad) | [`fixed-filters`](https://crates.io/crates/fixed-filters) | `idsp::iir` |
|---|---|---|---|
| Floating point `f32`/`f64` | ✅ | ❌ | ✅ |
| Fixed point `i32` | ❌ | ✅ | ✅ |
| Parametric fixed point `i32` | ❌ | ✅ | ✅ |
| Fixed point `i8`/`i16`/`i64`/`i128` | ❌ | ❌ | ✅ |
| DF2T | ✅ | ❌ | ✅ |
| Limiting/Clamping | ❌ | ✅ | ✅ |
| Fixed point accumulator guard bits | ❌ | ❌ | ✅ |
| Summing junction offset | ❌ | ❌ | ✅ |
| Fixed point noise shaping | ❌ | ❌ | ✅ |
| Wide output storage and feedback | ❌ | ❌ | ✅ |
| Configuration/state decoupling/multi-channel | ❌ | ❌ | ✅ |
| `f32` parameter audio filter builder | ✅ | ✅ | ✅ |
| `f64` parameter audio filter builder | ✅ | ❌ | ✅ |
| `Q` fixed point parameter audio filter builder | ❌ | ❌ | ✅ |
| Additional filter shapes (I/HO) | ❌ | ❌ | ✅ |
| `f32` PI builder | ❌ | ✅ | ✅ |
| `f32/f64` PI²D² builder | ❌ | ❌ | ✅ |
| `Q` fixed point PI²D² builder | ❌ | ❌ | ✅ |
| PI²D² builder limits | ❌ | ❌ | ✅ |
| Support for fixed point `a1=-2` second order integrator | ❌ | ❌ | ✅ |
The benchmarks and results comparing `idsp` and `biquad-rs` are in `tests/embedded`.
`idsp`'s biquad can process one `i32` sample every 8.5 cycles and one `f32` sample every 12 cycles on a Cortex-M7.
## State variable, normal form, wave digital filter
[`iir::svf`] is a simple IIR state variable filter simultaneously providing highpass, lowpass,
bandpass, and notch filtering of a signal.
[`iir::normal`] is a Normal Form IIR filter for narrowband applications.
[`iir::wdf`] has wave digital allpass filters that can be combined in a coupled [`dsp_process::Pair`].
[`Cic`] generic cascaded integrator comb lowpass reference implementation.
## `Lowpass`, `Lockin`
[`Lowpass`], [`Lockin`] are fast, infinitely cascadable, first- and second-order lowpass and the corresponding integration into a lockin amplifier algorithm.
## FIR filters
[`hbf::EvenSymmetric`], [`hbf::OddAntiSymmetric`], [`hbf::EvenAntiSymmetric`], [`hbf::OddSymmetric`]: Type I-IV linear phase FIR filters.
[`hbf::HbfDec`], [`hbf::HbfInt`]:
Fast symmetric FIR filters, optimized half-band filters, half-band filter decimators and integators and cascades.
[`hbf::HbfDec32`], [`hbf::HbfInt32`] etc: HBF cascades with known-good coefficients for rate changes 2, 4, 8, 16, and 32.
These are used in [`stabilizer-stream`](https://github.com/quartiq/stabilizer-stream) for online PSD calculation for
arbitrarily low offset frequencies.
## Delta Sigma modulator/noise shaper
[`Dsm`] is a delta sigma modulator/noise shaper in MASH-(1)^K architecture.