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.
Upgrading from 0.5? See MIGRATING.md for the 0.6 breaking changes (removed width-suffixed aliases/wrappers and the duplicate
filtering::Dsm/XorShift32).
#![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. Filters, PID, Hilbert transform, CFFT/BFP and complex-math are implemented once as genericDspSamplecode and verified bit-exact against the per-width kernels they replace, and the 0.5-era width-suffixed aliases and wrappers were removed in 0.6 (see MIGRATING.md). - 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 96% 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 established
#![no_std], integer-first DSP crate, used in production by
Stabilizer. embedded-dsp ports and re-verifies idsp's
fixed-point/integer algorithms — a superset where they overlap — and adds transforms, audio/vision,
sensor fusion, control, and tooling on top. The table below is checked against idsp 0.22.1; honest
gaps are marked and explained after 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 | ✅ EqFilter/EqShape/BiquadType validating builder, every RBJ type incl. IHo, plus WebAudioFilter |
✅ 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 | ✅ embedded-dsp-py (PyO3, abi3) |
✅ (py / numpy) |
| Interactive WebAssembly studio | ✅ | ❌ |
Legend: ✅ full support · ➖ partial/alternative coverage ·
Where idsp still leads: nowhere in API surface. The one deliberate omission is Major (block/lane
scratch-buffer traversal), argued below; the Python lead is closed by embedded-dsp-py, a PyO3 stable-ABI
module exposing the audio-EQ designer, FIR, and biquad cascades.
CORDIC modes. idsp's linear mul and hyperbolic cosh_sinh are correct only inside a ±0.5/
±0.3 band (an upstream sign bug); div and the circular/hyperbolic modes this crate ports are fine
and bit-matched, pinned by tests/idsp_cordic_probe.rs. embedded-dsp implements hyperbolic
vectoring instead of rotation: both outputs are representable across their full domain, measure to
~6e-9, and have no band or panicking input — reaching |z| ≈ 0.63 at Q1.31 full scale, about twice
what idsp's rotation mode manages.
Major (stage-by-stage block traversal). Not ported: Chain<A, B> is homogeneous over one sample
type, so the intermediate-type problem Major solves doesn't arise here — it's just &mut [T]. Only
Buffer/ChunkInOut have real block specializations; every other stage is per-sample, where
sample-major is already optimal. The manual one-liner (a.block(&x, &mut scratch); b.block(&scratch, &mut y)) already gets the same effect; a caller-owned-scratch helper is worth adding only once a
block-capable stage — most likely the FIRs — needs it.
| 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 (generic HilbertTransform<T>), 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.6.0"
# Bare-metal #![no_std] with libm
embedded-dsp = { version = "0.6.0", default-features = false, features = ["libm", "full"] }
# Minimal firmware footprint (only FIR/Biquad filtering + basic math)
embedded-dsp = { version = "0.6.0", 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.
