Heart-rate distribution¶
Key: heart_rate · Family: physiological · Better: lower ↓ · Per-lead: yes ·
Uses: fs
heart_rate asks: do the synthetic ECGs beat at the same rates as the real ones? It
detects R peaks in every recording, converts the RR intervals to a heart rate, and compares
the real and synthetic heart-rate distributions.
Try it¶
Top: an example synthetic strip with the R peaks the detector finds (the same detector as ECGEN-Eval). Bottom: heart-rate histograms of 300 real and 300 synthetic recordings.
Interactive demo loading… (needs JavaScript)
What to notice:
- Too fast shifts the histogram; the divergence rises quickly once they stop overlapping.
- Tachycardia (150 bpm): the detector still finds every beat. Its 0.2 s refractory period allows rates up to 300 bpm.
- Too uniform: the right mean heart rate is not enough. A generator that always produces 72 bpm misses the real variety between patients.
How it works¶
For each lead:
- Detect R peaks with a slope-energy QRS detector (in the spirit of Pan & Tompkins):
- band-pass the signal to 5–15 Hz, which keeps the steep QRS slopes and suppresses P and T waves, baseline wander and high-frequency noise;
- square the derivative and average it over 120 ms, giving a "QRS energy" signal;
- take energy peaks above 0.2 × its 99th percentile, at least 0.2 s apart (up to 300 bpm);
- move each detection to the largest absolute band-passed sample nearby, so inverted QRS complexes (aVR) are found too.
- Heart rate per recording = 60 / mean RR interval.
- Histogram real and synthetic heart rates with 50 bins over their joint range.
- Compute the Jensen–Shannon divergence between the histograms.
The score is the mean over leads.
The math¶
\[
\mathrm{HR} = \frac{60}{\overline{RR}}\ \text{bpm},
\qquad
\text{score} = \mathrm{JS}\big(\mathrm{hist}(\mathrm{HR}^{r}),\ \mathrm{hist}(\mathrm{HR}^{s})\big)
\in [0, \ln 2]
\]
Reading the score¶
- 0 means identical heart-rate distributions. Also check the means and standard deviations
in
extra(real_hr_mean,synth_hr_mean, …), which are easier to interpret. - R-peak detection runs on each lead. On PTB-XL it matches the reference heart rate within 5 bpm in about 91 % of lead recordings; limb leads III and aVF with small QRS complexes are the least reliable, so per-lead scores vary.
- An amplitude threshold on the raw signal (used in ECGEN-Eval 0.5 and earlier) confuses tall T waves with R peaks. The slope-based detector avoids this, which allows the short refractory period needed for tachycardia.
- For a clinically detailed comparison (PR, QRS, QT intervals and more) use Clinical Features.
Use it with ECGEN-Eval¶
from ecgen_eval import load_ecg_npy, AVAILABLE_METRICS
real = load_ecg_npy("real.npy", fs=500)
synth = load_ecg_npy("synth.npy", fs=500)
hr = AVAILABLE_METRICS["heart_rate"](fs=real.fs)
result = hr.compute(real.data, synth.data, lead_names=real.lead_names)
print(result.score, result.extra["II"]) # real/synth HR mean and std for lead II
Parameters are in the Metric Reference.
Learn more¶
- Pan & Tompkins, A Real-Time QRS Detection Algorithm, IEEE TBME 1985.
- Heart-Rate Variability looks at how the beat timing varies within a recording.