Skip to content

Getting Started

This guide walks you through the core concepts and verified workflows of the AI ECG SDK (ecg_sdk).


1. Universal ECG Ingestion with load_ecg

The SDK provides a single, high-level factory function load_ecg that intelligently dispatches to PhysioNet databases, local files (CSV/WFDB), in-memory arrays/DataFrames, and synthetic generators.

from ecg_sdk import load_ecg, list_physionet_databases

# 1. Stream MIT-BIH Arrhythmia record from PhysioNet via URI
sig_mit = load_ecg("physionet:mitdb/100", start_time=0.0, duration=5.0)
print(f"PhysioNet MIT-BIH: {sig_mit}")

# 2. Stream St. Petersburg INCART 12-lead ECG from PhysioNet
sig_incart = load_ecg("I01", database="incartdb", duration=5.0)
print(f"INCART 12-Lead:    {sig_incart}")

# 3. Generate on-the-fly synthetic ventricular ectopy (PVC)
sig_synth = load_ecg("synthetic:pvc", duration=6.0)
print(f"Synthetic Signal:  {sig_synth}")
PhysioNet MIT-BIH: ECGSignal(record='100', leads=['MLII', 'V5'], fs=360.0Hz, duration=5.00s, shape=(1800, 2))
INCART 12-Lead:    ECGSignal(record='I01', leads=['I', 'II', 'III', 'aVR', 'aVL', 'aVF', 'V1', 'V2', 'V3', 'V4', 'V5', 'V6'], fs=257.0Hz, duration=5.00s, shape=(1285, 12))
Synthetic Signal:  ECGSignal(record='SYNTH_PVC', leads=['Lead_I', 'Lead_II'], fs=250.0Hz, duration=6.00s, shape=(1500, 2))

2. Ingestion Standardization (target_fs & normalize)

Different benchmark databases operate at heterogeneous sampling rates (MIT-BIH at \(360\text{ Hz}\), INCART at \(257\text{ Hz}\), PTB-XL at \(500\text{ Hz}\), SVDB at \(128\text{ Hz}\)).

To prepare cross-dataset records for neural networks or feature extractors, load_ecg provides automatic sampling frequency standardization (target_fs) and amplitude normalization (normalize) at load time. Ground-truth cardiologist annotations (r_peaks) are automatically scaled proportionally!

from ecg_sdk import load_ecg

# 1. Stream MIT-BIH (native 360 Hz) and standardize to 250 Hz with Z-Score normalization
sig_mit_std = load_ecg(
    "physionet:mitdb/100",
    start_time=0.0,
    duration=5.0,
    target_fs=250.0,      # Automatically resamples from 360 Hz to 250 Hz & scales R-peak annotations!
    normalize="zscore",   # Centers each lead to mean=0, std=1
    load_annotations=True
)
print(f"Standardized MIT-BIH (360Hz -> 250Hz, Z-Score): {sig_mit_std}")

ann = sig_mit_std.metadata.get("annotations", {})
print(f"Proportionally Scaled R-Peaks: {len(ann.get('r_peaks', []))} beats (Indices: {ann.get('r_peaks', [])[:4]})")

# 2. Stream INCART 12-lead (native 257 Hz) standardized to 250 Hz
sig_incart_std = load_ecg("I01", database="incartdb", duration=5.0, target_fs=250.0)
print(f"Standardized INCART (257Hz -> 250Hz):          {sig_incart_std}")
Standardized MIT-BIH (360Hz -> 250Hz, Z-Score): ECGSignal(record='100', leads=['MLII', 'V5'], fs=250.0Hz, duration=5.00s, shape=(1250, 2))
Proportionally Scaled R-Peaks: 7 beats (Indices: [ 12  53 257 460])
Standardized INCART (257Hz -> 250Hz):          ECGSignal(record='I01', leads=['I', 'II', 'III', 'aVR', 'aVL', 'aVF', 'V1', 'V2', 'V3', 'V4', 'V5', 'V6'], fs=250.0Hz, duration=5.00s, shape=(1250, 12))

3. Exploring Supported PhysioNet Databases

Inspect available datasets and standard MIT-BIH benchmark records directly from Python:

from ecg_sdk import list_physionet_databases, list_mitbih_records

# View available PhysioNet databases
dbs = list_physionet_databases()
print("Available Benchmark Databases:")
for db_id, info in list(dbs.items())[:5]:
    print(f"  • {db_id:<10}: {info['name']} (fs={info.get('nominal_fs', 'N/A')} Hz)")

# List all 48 MIT-BIH records
records = list_mitbih_records()
print(f"\nTotal MIT-BIH Records: {len(records)} ({records[:8]}...)")
Available Benchmark Databases:
  • mitdb     : MIT-BIH Arrhythmia Database (fs=360.0 Hz)
  • incartdb  : St. Petersburg INCART 12-lead Arrhythmia Database (fs=257.0 Hz)
  • ptb-xl    : PTB-XL 12-Lead Diagnostic ECG Database (fs=500.0 Hz)
  • nstdb     : MIT-BIH Noise Stress Test Database (fs=360.0 Hz)
  • afdb      : MIT-BIH Atrial Fibrillation Database (fs=250.0 Hz)

Total MIT-BIH Records: 48 (['100', '101', '102', '103', '104', '105', '106', '107']...)

4. Clinical ECG Paper Plotting ("paper" vs "digital" Modes)

The SDK provides authentic clinical ECG paper plotting with 1:1 physical millimeter scale as default (display_mode="paper"), and an expanded screen-optimized mode (display_mode="digital"):

  • Paper Mode (display_mode="paper" — Default): 1:1 physical metric scale (\(25\text{ mm/s}, 10\text{ mm/mV}\)) formatted to standard thermal rolls (\(50\text{ mm}\) channel width) or US Letter/A4 diagnostic sheets.
  • Digital Mode (display_mode="digital"): Enlarged responsive layout tailored for monitors and Jupyter notebooks.
  • Sparse Tick Formatting (sparse_ticks=True): Unclutters the axes with clean labels (e.g. time_tick_step=1.0s, voltage_tick_step=0.5mV) while retaining the full \(100\%\) millimeter grid.
from ecg_sdk import load_ecg
import matplotlib.pyplot as plt

# Ingest MIT-BIH Record 101 in physical mV standardized to 250 Hz
sig_101 = load_ecg("physionet:mitdb/101", duration=6.0, target_fs=250.0, load_annotations=True)
ann = sig_101.metadata.get("annotations", {})

# Plot on 1:1 physical ECG paper with sparse tick labels
fig, ax = sig_101.plot_clinical(
    lead="MLII",
    display_mode="paper",
    sparse_ticks=True,
    time_tick_step=1.0,
    voltage_tick_step=0.5,
    grid_style="clinical_pink",
    r_peaks=ann.get("r_peaks"),
    show_calibration_pulse=True,
    title="PHYSIONET MIT-BIH RECORD 101 — 1:1 PHYSICAL PAPER MODE"
)
plt.show()

PhysioNet MIT-BIH Record 100


Loading Ventricular Ectopy (PVCs) on Clinical Red Paper

# Load MIT-BIH Record 106 with frequent Premature Ventricular Contractions
sig_106 = load_ecg("physionet:mitdb/106", start_time=10.0, duration=6.0, target_fs=250.0, load_annotations=True)
ann_106 = sig_106.metadata.get("annotations", {})

fig, ax = sig_106.plot_clinical(
    lead="MLII",
    display_mode="paper",
    grid_style="clinical_red",
    r_peaks=ann_106.get("r_peaks"),
    show_calibration_pulse=True,
    title="PHYSIONET MIT-BIH RECORD 106 (VENTRICULAR ECTOPY & PVCS)"
)
plt.show()

PhysioNet MIT-BIH Record 106


5. Saving and Loading CSV Records

Export and reload signals losslessly with comma-separated values:

from ecg_sdk import generate_synthetic_ecg, save_to_csv, load_csv_record

# Generate synthetic recording
sig = generate_synthetic_ecg(duration=4.0, sampling_rate=200.0)

# Save to disk
save_to_csv(sig, "patient_01.csv")

# Load back
loaded = load_csv_record("patient_01.csv", sampling_rate=200.0)
print(f"Loaded: {loaded}")
Loaded: ECGSignal(record='patient_01', leads=['Lead_I', 'Lead_II'], fs=200.0Hz, duration=4.00s, shape=(800, 2))