Skip to main content

wavedet

A Python port of wavedet, the wavelet-based ECG delineator from ecg-kit (GPL-2.0, upstream dead since 2020-02). It marks P/QRS/T onsets, peaks, and offsets. Nothing else from the kit is ported.

wavedet delineation of QTDB sel16265, lead 0 — P/QRS/T peaks as dots, on/off boundaries as dashed lines

from wavedet import delineate

d = delineate(signal, fs=250)         # 1-D → single lead
d = delineate(signal_12lead, fs=500)  # 2-D (n, leads) → SLR multilead fusion
d.qrs, d.qrs_on, d.t_off, d.p_on      # np.ndarray[float], NaN = not found
d.per_lead[0].t_off                   # single-lead results retained

Parity

The goal is output parity with the MATLAB original, not per-function parity. The pass/fail bar, per mark type per record: ≥99% of marks bit-identical to MATLAB, 100% within ±1 sample, and an identical NaN pattern. tests/test_parity.py is that gate; it runs offline against committed goldens, so it stays runnable without MATLAB. PARITY.md reports the full-database comparison — the whole of QTDB + LUDB against MATLAB, with per-fiducial deviations and the wavelet-transform ulp that is the root cause of every divergence.

Development

uv run ruff check
uv run ruff format --check
uv run mypy src/
uv run pytest                  # gate against committed goldens

The goldens and the signals they were made from are both committed, so the gate needs neither MATLAB nor network. Because the gate is bit-exact and the wavelet transform's dot products route through BLAS, conftest.py pins OpenBLAS to a fixed, CPU-independent kernel (OPENBLAS_CORETYPE=Prescott); without it the last ~1e-14 — and so a few knife-edge marks — would vary by host CPU. uv run pytest --full-oracle additionally runs the port over the whole of QTDB + LUDB as a robustness sweep (downloads the databases via wfdb; no goldens).

Scope

Ported: single-lead wavedet, and SLR multilead (per-lead delineation fused by a k-nearest-neighbour rule; needs ≥3 leads).

Not ported: the VCG/3D spatial loop (delineate3D, delineateP3D, twave3D, optimline). It is dead code upstream and cannot be fed. Reaching it needs three commented-out regions of wavedet_3D.m restored, and even then there is no input path: leadsynth_flag is hardcoded to 0, and leadcalc.m — the Dower/Levkov transform that would synthesize the orthogonal XYZ leads it requires — is absent from the kit entirely. Leads I/II/III are not a substitute, since III = II − I makes the loop rank-2 and degenerates optimline's fit. optimline also depends on lsqnonlin, which has no bit-identical scipy equivalent, so its marks could not clear the parity gate anyway.

Authorship

Most of this port was written by an AI model (Claude Opus 4.8), under human direction and review. The parity gate and the PARITY.md full-database comparison are how that work was held to the MATLAB original.

License

GPL-2.0-only, inherited from ecg-kit. Its LICENSE.txt is the plain GPL-2 text with no "or later" grant, so this derived work cannot relicense upward.

Metadata

Release files for wavedet 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 wavedet 0.1.0
File Size Uploaded
wavedet-0.1.0.tar.gz 142.5 kB Details

Built distribution (wheel)

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

Total release size: 212.3 kB

Release files / wavedet-0.1.0.tar.gz

Download URL wavedet-0.1.0.tar.gz
Size 142.5 kB
Tags Source
SHA-256 checksum
How to use checksums
2b8a170f65a68143cd0cbd8818b49d54138b3c214551399fe49a044bbd7b03a2
BLAKE2b-256 checksum
How to use checksums
5ad07be30dd6a1c1ce8a60a2a2cf2f96670b91ae8484745d9d490c4971bd011d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.13.13

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

Download URL wavedet-0.1.0-py3-none-any.whl
Size 69.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
315d64ac0277912b3e53d1c0ef00d601d54364c04b46c3d1770c3011a7e1a1cd
BLAKE2b-256 checksum
How to use checksums
cd66c8ab458e71765128ca2f01626526e5e576921a014618c399040c1b0aa45e
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