Skip to main content

opendsp

Numpy-only DSP primitives for biosignal analysis. A small, focused scipy.signal / PyWavelets subset implemented in pure NumPy, with optional backends (scipy, numba, torchaudio) for speed when available.

opendsp is the shared DSP layer underneath the open biosignal family (openvital, openecg, openeeg). The primitives here are modality-agnostic — bandpass filtering, peak-finding, wavelets, resampling — and don't belong to any single signal type.

Why

scipy.signal is excellent but heavy: scipy + its scipy.sparse / BLAS backing pulls 30+ MB and is awkward to install in stripped-down inference environments (Lambda, edge boxes, TFLite runners). opendsp matches scipy's coefficient output to within ~1e-12 on the filter orders biosignal pipelines actually use (2 and 4), so you can keep your filter design code identical while shrinking your deploy image.

Installation

pip install opendsp

# Optional speed backends (auto-selected on first lfilter call):
pip install opendsp[speed-scipy]   # ~10x speedup, C-backed
pip install opendsp[speed-numba]   # near-C after JIT warmup
pip install opendsp[speed-torch]   # GPU/MKL via torchaudio

Set OPENDSP_LFILTER_BACKEND (one of scipy, numba, torch, numpy) to force a specific backend — useful for benchmarking or reproducibility-sensitive contexts.

API

import opendsp

# Butterworth IIR design (scipy.signal.butter drop-in)
b, a = opendsp.butter(4, 0.1, btype="low")
b, a = opendsp.butter(4, [0.01, 0.4], btype="band")

# Direct filtering
y = opendsp.lfilter(b, a, x)
y = opendsp.filtfilt(b, a, x)   # zero-phase forward-backward

# Convenience bandpass (combines butter + filtfilt)
y = opendsp.band_pass(x, srate=128, fl=0.5, fh=30, order=4)

# Peak finding (scipy.signal.find_peaks subset)
peaks, props = opendsp.find_peaks(x, height=0.5, distance=10,
                                   prominence=0.1)

# Wavelets (PyWavelets minimal subset)
coeffs = opendsp.wavedec(x, "db2", level=4)
y = opendsp.waverec(coeffs, "db2")
cwt = opendsp.cwt(x, scales=[1, 2, 4, 8], wavelet="gaus1")

# Resampling
y = opendsp.resample(x, dest_len=1000)
y = opendsp.resample_hz(x, srate_from=500, srate_to=128)

# Misc primitives biosignal pipelines need
y = opendsp.interp_undefined(x)             # NaN-aware linear interp
y = opendsp.savitzky_golay(x, window_size=91, order=3)
y = opendsp.moving_average(x, N=10)
y = opendsp.rank_normalize(x)               # amplitude-invariant
y = opendsp.remove_baseline_wander(x, fs=500, cutoff_hz=0.5)

Algorithms

  • Butterworth: analog prototype poles → bilinear-transform pre-warping → digital (z, p, k) → polynomial (b, a). Matches scipy exactly because both follow Oppenheim & Schafer §7.1.
  • filtfilt: reflect-pad ↔ forward ↔ reverse ↔ forward ↔ reverse ↔ trim, with initial conditions set via the lfilter_zi steady-state method.
  • find_peaks: strict-left/non-strict-right local maxima (scipy's convention), height filter, greedy-from-largest distance filter, Wim Spalt's two-sided prominence walk.
  • wavedec/waverec: DWT with mode='symmetric' boundary extension (PyWavelets default). Daubechies-2 ships built-in; pass a 4-tuple (lo_d, hi_d, lo_r, hi_r) for any other wavelet.
  • cwt: Gaussian 1st derivative continuous wavelet transform — the one used by ECG annotators. Other mother wavelets: pass pywt.

Scope

opendsp is intentionally narrow:

  • ✓ Linear-time-invariant filter design + application
  • ✓ Peak / extremum detection
  • ✓ Wavelet decomposition (DWT + CWT)
  • ✓ Resampling, smoothing, interpolation primitives

What it deliberately does not include:

  • ✗ Spectral analysis higher than 1-D periodogram / FFT helpers (use scipy.signal.welch / numpy.fft directly)
  • ✗ Adaptive filters, Kalman, ML-based denoising
  • ✗ Modality-specific features (QRS, BSR, SEF95 etc. — those live in openecg, openeeg, openvital)

If you find yourself reaching for one of those, you probably want scipy.signal or one of the modality libs above.

License

Apache-2.0. See LICENSE.

Release files for opendsp 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for opendsp 0.1.0
File Size Uploaded
opendsp-0.1.0.tar.gz 20.6 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for opendsp 0.1.0
File Interpreter ABI Platform
opendsp-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 41.2 kB

Release files / opendsp-0.1.0.tar.gz

Download URL opendsp-0.1.0.tar.gz
Size 20.6 kB
Tags Source
SHA-256 checksum
How to use checksums
6c7c5464af47ee41a77fd6b4a6ede84e5c3a8f067667ab50c50b53a41cce4c6d
BLAKE2b-256 checksum
How to use checksums
a151e97390ad6f2d83d77732a9d949e38404da8852a5fba31673c3df33b73f11
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.13.13

Release files / opendsp-0.1.0-py3-none-any.whl

Download URL opendsp-0.1.0-py3-none-any.whl
Size 20.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
c812f62308856386e4184568522f699e68cb6dff18068ec1ac3672311b8096da
BLAKE2b-256 checksum
How to use checksums
13a25e4241f7ab88b68dcdab5d0072f2ed7cc2dcdf525b1edf661f816cda8f13
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.13.13

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page