A high-performance #![no_std] Rust Digital Signal Processing library designed for microcontrollers (Cortex-M, RISC-V, AVR, Xtensa), bare-metal DSP, and real-time audio/sensor pipelines.
#![no_std]First: Purecorecompatibility with zero heap allocations.- Fixed & Float Parity: CMSIS-style
f32,f64, andq7/q15/q31— interoperable with thefixedcrate (optionalfixedfeature, enabled by default) with zero-dependency fallback newtypes — plus the polymorphicDspSampletrait. - Hardware Acceleration: ARM Cortex-M assembly intrinsics (
smlad,smlald,ssat,qadd16) viacortex-m-dsp, with portable SWAR vector fallbacks. - Pure-Integer CORDIC Engine: Shift-and-add
sin,cos,atan2, polar conversion, andsqrtrequiring no hardware multipliers. - Streaming Pipelines: Zero-allocation
DspNodecomposable processing chains (Chain,Gain,Limiter). - Production Tested: CI runs the full test suite on the host and
cargo check --all-targets --all-featuresplus ano_stdbuild on six embedded/WebAssembly targets (thumbv6m-none-eabi,thumbv7em-none-eabi,thumbv7em-none-eabihf,thumbv8m.main-none-eabihf,riscv32imc-unknown-none-elf,wasm32-unknown-unknown), and enforces a 97% line-coverage floor on the library.
🌐 Launch Live WebAssembly Studio — Run real-time filter design, spectral forensics, and micro-benchmarks directly in your browser.
An interactive desktop & browser testbench inspired by DSP-Testbench and embedded-nn:
# Run native desktop GUI
cargo run -p embedded-dsp-studio-
Dual Signal Lab: Anti-aliased PolyBLEP oscillators (Saw/Square/Triangle/Sine), chirp sweeps (linear/exponential), pink noise (
$1/f$ ), white noise, and Dirac impulse. - Filter & Pipeline Rack: Real-time sweepable Biquad IIR filters, Andrew Simper 2x oversampled State Variable Filters (SVF), Audio EQ Cookbook shelves, and Q15 quantization floor.
- Forensics & Analyzer: 4096-point FFT magnitude, Welch PSD, oscilloscope, Lissajous phase goniometer, and true RMS/peak meters.
- Impulse Response Analyzer: 4096-sample freeze buffer with settling time, peak gain, and energy measurements.
-
WAV & CSV Export/Import: Export forensic snapshots and waveforms directly to 16-bit PCM
.wavor.csvfiles. -
Zero-Allocation MCU Codegen: Generates instant C (CMSIS-DSP) and
#![no_std]Rust code snippets tuned in the GUI.
idsp (0.22, by Robert Jördens / QUARTIQ) is the other well-established
#![no_std], integer-first DSP crate; Stabilizer is its
comprehensive production user. embedded-dsp ports and re-verifies idsp's fixed-point and integer
algorithms, so for the algorithms the two share it is a superset — and it adds transforms, audio and
vision, sensor fusion, control, and tooling on top.
The table is checked against idsp 0.22.1. Honest differences are marked, including the places where
idsp still has more to offer; those are also called out below the table.
| Feature | embedded-dsp |
idsp |
|---|---|---|
#![no_std], zero-allocation |
✅ | ✅ |
Fixed point q7/q15/q31 + fixed interop |
✅ | ✅ (i8/i16/i32/i64) |
cossin LUT (i32) |
✅ ~5e-6 RMS | ✅ ~4e-6 RMS |
atan2 (i32) |
✅ ~1.3e-6 rad | ✅ ~1.3e-6 rad |
Integer PLL / reciprocal RPLL |
✅ | ✅ |
Integer lowpass (IntLowpass<N>), unwrap, saturating_scale_i32 |
✅ | ✅ |
| CORDIC modes | ✅ circular + hyperbolic (vectoring), no band or panicking input | ➖ circular and linear div are correct; mul/cosh_sinh limited to a ±0.5 band by a bug (see note) |
Biquad f32/f64 DF1 + DF2T |
✅ | ✅ |
Biquad i32 clamping / anti-windup / guard bits |
✅ | ✅ |
| Biquad fixed-point noise shaping | ✅ | ✅ |
Biquad generic integer i8/i16/i32/i64 |
✅ BiquadInt<T> |
✅ |
Biquad DF1 wide (Q32.32) / dither actions |
✅ | ✅ |
Control-plane settings via miniconf |
✅ config::BiquadSettings |
✅ |
| Audio EQ builder / WebAudio export | ➖ individual RBJ biquad_*_coeffs functions |
✅ iir::coefficients::{Filter, Shape, Type, WebAudio} |
| Normal-form IIR | ✅ arbitrary numerator | p.im·z⁻¹ factor |
| Wave digital allpass filters | ✅ | ✅ |
| PI²D² controller builder (per-action limits) | ✅ PidBuilder |
✅ |
| Half-band Type I–IV linear-phase FIR | ✅ | ✅ |
| Half-band cascades with known-good taps | ✅ rates 2/4/8/16/32, 140 dB + 98 dB | ✅ rates 2/4/8/16/32, 140 dB |
| CIC decimator/interpolator | ✅ | ✅ |
| General FIR, LMS/NLMS | ✅ | ➖ |
| FFT (CFFT/RFFT/BFP Q15/Q31), DCT, DWT, Hartley, Hilbert | ✅ | ❌ |
| Goertzel, Mel/MFCC, VAD, compressor/gate | ✅ | ❌ |
| Welch/Burg PSD analysis | ✅ | ➖ |
| Kalman | ✅ const-generic, EKF, square-root, and composable models (Estimate/Dynamics/Transition/Observation, vector + optional measurements, control input) |
➖ composable Transition/Observation only, with scalar measurements and linear models |
| 2D vision, beamforming, GCC-PHAT, quaternions, matrices | ✅ | ❌ |
| Lock-in amplifier | ✅ | ✅ |
| Dither + MASH delta-sigma | ✅ | ✅ |
| Resampling (polyphase, fractional, half-band) | ✅ | ➖ |
| Swept-sine stimulus | ✅ Sweep + AccuOsc + Farina inverse_filter |
✅ Sweep::inverse_filter |
| Block/lane block processing | ✅ DspNode, Split/SplitProcess, Lanes, Pair, Parallel, ByLane, typed View/ViewMut (FrameMajor/LaneMajor, as_layout), chunk bridges (ChunkInOut, PerFrame, FnSplitProcess), gated Buffer |
✅ same ideas in dsp-process; the scratch-buffer Major is deliberately not mirrored (see note) |
| Companding (G.711 µ/A-law) | ✅ | ❌ |
| In-repo micro-benchmarks | ✅ | ✅ (tests/embedded) |
| Python bindings | ❌ | ✅ (py / numpy) |
| Interactive WebAssembly studio | ✅ | ❌ |
Legend: ✅ full support · ➖ partial/alternative coverage ·
Where idsp still leads. It publishes Python bindings for offline analysis and filter design.
Everything else in the table is either at parity or an embedded-dsp advantage — including the typed
view framework, the chunk bridges and the gated Buffer, which this crate now carries natively
rather than depending on dsp-process for. The one piece deliberately not mirrored is Major; see
the note below.
Note on the extra CORDIC modes. idsp also advertises linear (mul/div) and hyperbolic
rotation (cosh_sinh) modes. Measured against idsp 0.22.1, pinned by tests/idsp_cordic_probe.rs:
div— correct (z + y/x). Not ported: a fixed-point divide is one instruction here.mul— correct only for|z| ≤ 0.5, folding toy + x(1 − z)above it.cosh_sinh— correct only to|z| ≈ 0.3, sign-flipping past0.5.
The band is an upstream bug: the linear table's first entry reads −1.0 where the angle must be
+1.0. Upstream also panics on idsp::div(i32::MIN, 0, 0), since i32::MIN is −1.0 in Q31 and
every vectoring mode negates x. Both reported upstream.
This crate implements hyperbolic vectoring instead: both outputs are representable across their
full domains, measure to ~6e-9, and have no band or panicking input. Rotation mode is capped by the
format, not the algorithm: cosh grows like e^z, so Q1.31 reaches |z| ≈ 0.63 at full scale —
about twice what idsp manages.
Note on Major. dsp-process also ships Major, which traverses a composition stage by stage
over a whole block, materialising the intermediate signal in explicit scratch, as opposed to the
default Minor where one sample walks through every stage. It is not ported, for three reasons:
- The composition it needs does not exist here. Upstream's
Major<P, U>threads scratch between stages of a tuple-seq composition (Minor<(C0, C1), U>). Ours isChain<A, B>, homogeneous over one sample type, so the type-level problem it solves — what is the intermediate type between stage i and i+1 — does not arise. Here it is just&mut [T]. - The payoff needs stages with real
blockspecializations. Count ours:BufferandChunkInOut. Everything else is a recursive per-sample stage — biquads, single-pole, PLL, AGC, DSM — where sample-major is already optimal, because keeping that stage's state hot in registers is the point. - The capability is already reachable in one line.
a.block(&x, &mut scratch); b.block(&scratch, &mut y);is stage-major traversal. What the upstream type adds is doing it automatically for a composed tuple and owning the scratch — neither of which is worth a type parameter that propagates through every bound and combinator.
If it is ever built, the shape would be a method taking caller-owned scratch rather than a
Major<C, U> wrapper, because scratch length is the cache dial this whole trade-off is about, and
caller-owned scratch can live in a static or in DMA-visible memory. The trigger to build it is
concrete: a stage gaining a block path worth exploiting, which today means the FIRs, whose stages
are per-sample.
| Category | Key Algorithms & Structs |
|---|---|
| Filtering & Design | FIR, Biquad IIR (DF-I & Transposed DF-II), LMS/NLMS, Butterworth/Chebyshev/elliptic design, Kaiser-windowed sinc FIR, RRC/RC/GMSK-TX pulses, Windowed-Sinc, |
| Spectral & Transforms | CFFT, RFFT (packed), Block Floating-Point FFT (cfft_bfp_q15/q31), Hilbert Transform FIR & Analytic Signal (HilbertTransformF32/Q15), Real Cepstrum, DCT-IV, FWHT, Haar, Hartley, Daubechies-4 DWT, Welch & Burg AR PSD. |
| Audio & Voice | Goertzel tone detector, Mel & Generalized filterbanks, MFCC, Q15 VAD, Dynamics Compressor with soft knee, Noise Gate, streaming AGC. |
| Control & Power | FOC current/speed PID, Clarke & Park transforms, SOGI-PLL (grid synchronization/resolvers), Costas Loop carrier recovery. |
| Analog modem | FM phase-accum mod/demod, DSB-AM envelope, SSB USB/LSB (reuses Hilbert transformer). |
| Sensor Fusion & Spatial | Square-Root Kalman Filter (SquareRootKalmanFilter), EKF, composable Kalman models (kalman_compose: Estimate, Dynamics, Transition, Observation, VectorObservation, Direct, Optional), 2D Spatial/Vision (Sobel, Median, DCT-II), Delay-and-Sum Beamformer, GCC-PHAT TDoA locator. |
| Multi-rate & Resampling | CIC Decimator/Interpolator with bit-growth normalization, Polyphase Decimation & Interpolation (Float & Q15), fractional linear resampler, arbitrary-rate polyphase resampler, Gardner symbol sync. |
| FEC | CRC-8/16/24/32, 8-bit checksum, Hamming(7,4) nibble/byte codecs. |
| Sequences | Maximal-length LFSR (MSequence) for PN sequences and additive scramble. |
| Signal Generation | PolyBLEP anti-aliased oscillator (PolyBlepOscillator: saw/square/triangle/sine), white & Kellett pink noise, linear/exponential ChirpSweep, exponential swept-sine Sweep with delta-sigma fractional phase (AccuOsc, Accu<T>) and its Farina inverse filter (Sweep::inverse_filter) for impulse-response measurement. |
| Math, CORDIC & Numerics |
BFloat16 (50% SRAM buffer reduction), FloatFloat (~48-bit double-single extended precision on f32 FPU), Fast Bit-Manip Log/Pow/dB (fast_log2_f32, fast_pow2_f32, fast_gain_to_db_f32), EFT (two_sum_f32/two_sum_f64, two_prod_f32/two_prod_f64, two_diff_f32, two_div_f32), Horner polynomials & roots, strided dot products, CORDIC engine (circular sin/cos, polar, atan2, sqrt + hyperbolic sqrt_atanh2, atanh), Complex math, Quaternions (nalgebra interop), 8 window types (Hanning, Hamming, Blackman, Blackman-Harris, Bartlett, Welch, flat-top, Kaiser) with apply_window_f32/apply_window_q15, G.711 |
Add to your Cargo.toml:
[dependencies]
# Standard std environment (all modules enabled)
embedded-dsp = "0.5.1"
# Bare-metal #![no_std] with libm
embedded-dsp = { version = "0.5.1", default-features = false, features = ["libm", "full"] }
# Minimal firmware footprint (only FIR/Biquad filtering + basic math)
embedded-dsp = { version = "0.5.1", default-features = false, features = ["libm", "filtering", "basic-math"] }use embedded_dsp::*;
fn main() {
// 1. Fixed-Point Saturating Addition
let a = [q15::from_bits(20000), q15::from_bits(25000)];
let b = [q15::from_bits(15000), q15::from_bits(10000)];
let mut out = [q15::ZERO; 2];
add_q15(&a, &b, &mut out); // [I1F15::MAX, I1F15::MAX] (saturated)
// 2. Biquad Filter Cascade
let coeffs = biquad_lowpass_coeffs(1000.0, 48000.0, core::f32::consts::FRAC_1_SQRT_2);
let mut filter = BiquadCascade::<5, 4>::new(coeffs);
let input = [1.0f32, 0.5, -0.2, 0.1];
let mut filtered = [0.0f32; 4];
filter.process(&input, &mut filtered);
// 3. Robust Square-Root Kalman Sensor Filter
let mut kf = KalmanFilter1D::new(0.0, 1.0, 0.01, 0.1);
kf.predict(0.0);
let _est = kf.update(10.2);
// 4. In-Place FFT
let mut fft_buf = [0.0f32; 128]; // 64 complex pairs [re, im, ...]
cfft_f32(&mut fft_buf, 64, 0, 1);
}Need copy-paste code for real-world projects? Check the embedded-dsp Cookbook:
- Motor Control: Sensorless Field-Oriented Control (FOC) with Clarke/Park and Space-Vector PWM.
- Real-Time Audio DMA: DC-Blocker + Biquad Peaking EQ + Peak Limiter streaming pipeline.
- Machine Health: Vibration spectrum analysis and bearing fault detection using Burg AR PSD.
- Multi-rate ADC: High-speed Cascaded Integrator-Comb (CIC) decimation.
- Acoustic Edge AI: Voice Activity Detection (VAD) & MFCC feature extraction.
- Streaming Pipeline: Composing modular
DspNodesignal processing chains.
Run any included example directly with cargo:
cargo run --example basic_usage
cargo run --example motor_control_foc
cargo run --example audio_speech_pipeline
cargo run --example sensor_fusion_navigation
cargo run --example filter_workbench_and_analysis
cargo run --example spectral_radar_transforms
cargo run --example spatial_vision_processing
cargo run --release --example perf_comparisonNative micro-benchmarks (run in CI, results attached to the job summary):
cargo bench -p embedded-dsp --bench dsp_benchmarksBare-metal cycle counts on Cortex-M are in tests/embedded and include the
integer primitives shared with idsp (cossin, atan2, IntPll).
Dual-licensed under either MIT or Apache-2.0 at your option. See LICENSE-MIT and LICENSE-APACHE.
