rlcapstone.ai

Teaching a network to read a heartbeat

A 1D convolutional network that classifies individual heartbeats from an ECG into four clinical categories — and a first-hand look at why ECG models that score 96% in the lab can score 44% in the real world.

Not a medical device. This is an educational study of signal classification on a public research dataset. It does not diagnose heart conditions and must not be used for any medical decision. Read the full disclaimer.

Try it in your browser →
Classifies real heartbeats on your device — nothing is uploaded.

Get the Android app
ECG Check · Android (arm64) · ~22 MB · v1.0.0

Prefer a native app? Download the APK and sideload it. It runs the same on-device model as the browser demo — offline, nothing uploaded.

Download APK →
How to install (sideloading)
  1. On your Android phone, open this page and tap Download APK.
  2. When prompted, allow your browser to “install unknown apps” (Android asks once, for safety).
  3. Open the downloaded file and tap Install.

Educational app — not a medical device and not a diagnosis. It is distributed outside the Play Store and signed with a debug key, so Android will warn you before installing; that warning is expected for a sideloaded educational build. Built for arm64 phones (essentially all Android phones from the last several years). Android only — an iOS build can be produced from the same code.

At a glance

TaskClassify each heartbeat into 4 AAMI classes (Normal, Supraventricular, Ventricular, Fusion)
DataMIT-BIH Arrhythmia Database — 48 records, ~100,000 labelled beats
SignalSingle lead (MLII), 360 Hz, one 260-sample window per beat
Model1D CNN — 4 conv blocks, 77k parameters (312 KB)
Honest resultOn unseen patients: 70% accuracy, but 44% macro-recall — strong on ventricular beats, weak on supraventricular
DeploymentONNX, running on-device in the browser demo (28 KB model)

Why not just "accuracy"?

About 90% of heartbeats in this dataset are normal. So a lazy model that labels every beat "normal" already scores 90% accuracy — while catching exactly zero of the abnormal beats that matter. For a screening task that's the worst possible model dressed up as a good one. The metric we actually track is macro-recall: the average of the per-class catch rates, which only rises when the model handles the rare, important classes too.

From signal to beats

Each MIT-BIH record is a half-hour, two-channel ECG with a cardiologist's mark on every heartbeat. The pipeline reads the standard MLII lead, cuts a 260-sample (~0.7 s) window centered on each beat, normalizes it, and maps the fine-grained annotation symbols into the four AAMI super-classes. One decision matters more than any other here: the train/test split is by patient, not by beat. Splitting by beat lets the same person's heartbeats appear in both sets, and the model quietly learns to recognize people instead of arrhythmias — which is exactly the trap the next section walks into.

Progress across iterations

Every iteration is recapped here as it ships. The chart below tells the story of v1 on its own: during training, validation macro-recall climbs past 96% and looks excellent. But that validation set shares patients with the training data. On the real test — 22 completely unseen patients — the honest macro-recall is 44%. The gap between the climbing line and that number is the whole lesson.

What v1 learned, and what it didn't

The per-class breakdown is where it gets interesting. On unseen patients the model catches 86% of ventricular beats — genuinely useful — but only 9% of supraventricular beats. That isn't random; it's a clue about what the model can and can't perceive.

A ventricular beat has a distinctly mis-shapen waveform, so a model that reads shape spots it easily. A supraventricular beat, by contrast, often looks almost identical in shape to a normal beat — what makes it abnormal is its timing: it arrives early. Our v1 model sees each beat in isolation, with no sense of rhythm, so it is structurally blind to the one feature that defines the class it fails on.

What's next (v2)

The fix follows directly from the diagnosis: give the model timing. Adding RR-interval features — how long since the previous beat, and until the next — lets it perceive prematurity, the hallmark of supraventricular beats. That is the next iteration, and its result will appear in the progress table above so you can see whether the theory holds.