Skip to main content

Wavelet-based ECG delineator, ported from ecg-kit MATLAB with output parity

Project description

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.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

wavedet-0.1.0.tar.gz (142.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

wavedet-0.1.0-py3-none-any.whl (69.8 kB view details)

Uploaded Python 3

File details

Details for the file wavedet-0.1.0.tar.gz.

File metadata

  • Download URL: wavedet-0.1.0.tar.gz
  • Upload date:
  • Size: 142.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.13

File hashes

Hashes for wavedet-0.1.0.tar.gz
Algorithm Hash digest
SHA256 2b8a170f65a68143cd0cbd8818b49d54138b3c214551399fe49a044bbd7b03a2
MD5 fb7239e7d72711b37db813e4a7c0b415
BLAKE2b-256 5ad07be30dd6a1c1ce8a60a2a2cf2f96670b91ae8484745d9d490c4971bd011d

See more details on using hashes here.

File details

Details for the file wavedet-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: wavedet-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 69.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.13

File hashes

Hashes for wavedet-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 315d64ac0277912b3e53d1c0ef00d601d54364c04b46c3d1770c3011a7e1a1cd
MD5 cbf8c1823163da2196683db3cb629ee6
BLAKE2b-256 cd66c8ab458e71765128ca2f01626526e5e576921a014618c399040c1b0aa45e

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page