ECGApp is a cross-platform mobile application (iOS ) for real-time ECG signal acquisition, processing, and classification using deep learning models.
- Key Features
- App Settings
- Used Deep Learning Models
- Datasets Used
- Evaluation & Metrics
- Signal Format
- Import & Interoperability
- Use Cases
- Tech Stack
- Medical Disclaimer
-
π Connect to external BLE ECG sensors (e.g., ESP32, Arduino)
-
π Real-time signal visualization (zoom, pan, rescale)
-
βΊ Record ECG to local
.jsonand.datand.heaformat -
π§ AI-based classification:
- Heart rhythm classification (e.g. NSR, AF, PVC)
- Beat-type classification near QRS centers (e.g. N, V, S)
- Waveform segmentation per sample into
P,QRS,Twaves for morphological analysis
-
π Browse, view, share or delete saved recordings
ECGApp includes a configurable Settings panel for adjusting signal processing and model parameters:
- πΆ Sample Rate In: Set to match your BLE ECG device (e.g., 128β―Hz)
- π§ Demographics: Select user age and sex (used in AI model input)
- π Y-Axis Range: Adjust ECG chart amplitude (Β±1 to Β±10β―mV)
- π Dark Mode: Toggle light/dark UI
- π Debug Info: Enable detailed internal logging
All settings are applied in real time. Correct configuration ensures accurate AI classification and visualization.
Lightweight SE-enhanced MobileNet 1D CNN with demographic inputs.
- Input: 10-second 1-lead ECG (5000 samples of 500hz signal), age (normalized), sex (0/1)
- Output: Single-label rhythm class (softmax)
- Deployment: Converted via ONNX β TensorFlow β CoreML / TFLite
- Datasets: CPSC 2018, CPSC Extra, PTB-XL, Georgia Dataset
β Conv1D(1 β 16, kernel=7, stride=2, padding=3)
β BatchNorm1d(16)
β SiLU
β DepthwiseConv1D(16 β 16, kernel=5, stride=2, padding=2, groups=16)
β PointwiseConv1D(16 β 32, kernel=1)
β BatchNorm1d(32)
β SiLU
β SEBlock(32):
β AdaptiveAvgPool1d(1)
β Linear(32 β 4) β ReLU
β Linear(4 β 32) β Sigmoid
β Multiply input Γ scale
β Dropout(0.1)
β DepthwiseConv1D(32 β 32, kernel=5, stride=2, padding=2, groups=32)
β PointwiseConv1D(32 β 64, kernel=1)
β BatchNorm1d(64)
β SiLU
β SEBlock(64):
β AdaptiveAvgPool1d(1)
β Linear(64 β 8) β ReLU
β Linear(8 β 64) β Sigmoid
β Multiply input Γ scale
β Dropout(0.1)
β DepthwiseConv1D(64 β 64, kernel=5, stride=2, padding=2, groups=64)
β PointwiseConv1D(64 β 128, kernel=1)
β BatchNorm1d(128)
β SiLU
β SEBlock(128):
β AdaptiveAvgPool1d(1)
β Linear(128 β 16) β ReLU
β Linear(16 β 128) β Sigmoid
β Multiply input Γ scale
β Dropout(0.1)
β DepthwiseConv1D(128 β 128, kernel=5, stride=1, padding=2, groups=128)
β PointwiseConv1D(128 β 128, kernel=1)
β BatchNorm1d(128)
β SiLU
β SEBlock(128):
β AdaptiveAvgPool1d(1)
β Linear(128 β 16) β ReLU
β Linear(16 β 128) β Sigmoid
β Multiply input Γ scale
β Dropout(0.1)
Trained on beats centered on QRS complexes from:
-
MIT-BIH Arrhythmia Database (mitdb)
-
INCART 12-lead Arrhythmia Database (incartdb)
-
SVDB
-
Input: 1D ECG window centered at QRS (540 samples of 360 hz signal)
-
Output: Beat class (N, V, S , F, Q )
-
Deployment: Used for inference after R-peak detection
ECGClassifier:
Input: (B, 1, T) (np. 540 prΓ³bek @ 360 Hz)
FEATURE EXTRACTION
β Conv1D(1 β 32, kernel=7, stride=2, padding=3)
β BatchNorm1d(32) β ReLU
β ResidualBlock(32):
β Conv1D(32 β 32, kernel=3, padding=1)
β BatchNorm1d(32) β ReLU
β Conv1D(32 β 32, kernel=3, padding=1)
β BatchNorm1d(32)
β Skip connection + ReLU
β SEBlock(32):
β AdaptiveAvgPool1d(1)
β Conv1D(32 β 4, kernel=1) β ReLU
β Conv1D(4 β 32, kernel=1) β Sigmoid
β Multiply (channel-wise scaling)
β Conv1D(32 β 64, kernel=5, stride=2, padding=2)
β BatchNorm1d(64) β ReLU
β ResidualBlock(64):
β Conv1D(64 β 64, kernel=3, padding=1)
β BatchNorm1d(64) β ReLU
β Conv1D(64 β 64, kernel=3, padding=1)
β BatchNorm1d(64)
β Skip connection + ReLU
β SEBlock(64):
β AdaptiveAvgPool1d(1)
β Conv1D(64 β 8, kernel=1) β ReLU
β Conv1D(8 β 64, kernel=1) β Sigmoid
β Multiply (channel-wise scaling)
CLASSIFICATION HEAD
β AdaptiveAvgPool1d(1)
β Flatten: (B, 64)
β Linear(64 β 32)
β ReLU
β Dropout(0.5)
β Linear(32 β num_classes)
Output:
β Shape: (B, num_classes) β logits of classes.
Lightweight 1D U-Net model for per-sample waveform classification trained on LUDB dataset.
- Input: 10-second 1-lead ECG segment (2000 samples of 500 Hz signal, lead II)
- Output: Per-sample waveform class (none, P, QRS, T) using softmax over 4 classes
- Deployment: Converted to CoreML (UnetModel.mlpackage) for real-time waveform segmentation
- Datasets: LUDB (Lobachevsky University Database), 200 manually annotated 12-lead ECGs
UNet1D:
Input: (B, 1, 2000)
ENCODER / DOWNSAMPLING
β Block 1:
β Conv1D(1 β 4, kernel=9, padding=4)
β BatchNorm1d(4) β ReLU
β Conv1D(4 β 4, kernel=9, padding=4)
β BatchNorm1d(4) β ReLU
β MaxPool1D(kernel=2) # β T/2
β Block 2:
β Conv1D(4 β 8, kernel=9, padding=4)
β BatchNorm1d(8) β ReLU
β Conv1D(8 β 8, kernel=9, padding=4)
β BatchNorm1d(8) β ReLU
β MaxPool1D(kernel=2) # β T/4
β Block 3:
β Conv1D(8 β 16, kernel=9, padding=4)
β BatchNorm1d(16) β ReLU
β Conv1D(16 β 16, kernel=9, padding=4)
β BatchNorm1d(16) β ReLU
β MaxPool1D(kernel=2) # β T/8
β Block 4:
β Conv1D(16 β 32, kernel=9, padding=4)
β BatchNorm1d(32) β ReLU
β Conv1D(32 β 32, kernel=9, padding=4)
β BatchNorm1d(32) β ReLU
β MaxPool1D(kernel=2) # β T/16
BOTTLENECK
β Conv1D(32 β 64, kernel=9, padding=4)
β BatchNorm1d(64) β ReLU
β Conv1D(64 β 64, kernel=9, padding=4)
β BatchNorm1d(64) β ReLU
DECODER / UPSAMPLING
β TransposedConv1D(64 β 32, kernel=8, stride=2, padding=3)
β Pad to match enc4 β Concat([up, enc4]) β (64 channels)
β Conv1D(64 β 32) β BN β ReLU β Conv1D β BN β ReLU
β TransposedConv1D(32 β 16, kernel=8, stride=2, padding=3)
β Pad to match enc3 β Concat([up, enc3]) β (32 channels)
β Conv1D(32 β 16) β BN β ReLU β Conv1D β BN β ReLU
β TransposedConv1D(16 β 8, kernel=8, stride=2, padding=3)
β Pad to match enc2 β Concat([up, enc2]) β (16 channels)
β Conv1D(16 β 8) β BN β ReLU β Conv1D β BN β ReLU
β TransposedConv1D(8 β 4, kernel=8, stride=2, padding=3)
β Pad to match enc1 β Concat([up, enc1]) β (8 channels)
β Conv1D(8 β 4) β BN β ReLU β Conv1D β BN β ReLU
OUTPUT
β Final Conv1D(4 β num_classes, kernel=1) # Pointwise convolution
β Output shape: (B, num_classes, T)
β Permute to (B, T, num_classes) for per-sample classification
| Dataset | Role | Format | Notes |
|---|---|---|---|
| CPSC 2018 | Rhythm classification | mat | 1-lead, SNOMED codes |
| CPSC 2018 Extra | Rhythm classification | mat | Additional records |
| PTB-XL | Rhythm classification | mat | With age and sex demographic data |
| Georgia | Rhythm classification | mat | 12-lead |
| MIT-BIH (mitdb) | Beat classification | dat | 360 Hz, QRS annotated |
| INCARTDB | Beat classification | dat | 12-lead, annotated |
| SVDB | Beat classification | dat | Supraventricular focus |
| LUDB | Wave classification | dat | Waves focus |
All signals were:
- Resampled to 500 Hz (rhythm and wave) or 360 Hz (beat)
- Normalized and denoised using wavelet transform (
bior2.6) - Lead II extracted and used as input
This application is not a certified medical device.
-
It has not been evaluated by any regulatory authorities (FDA, CE, EMA).
-
It is not intended for:
- Diagnosing or monitoring medical conditions
- Emergency or therapeutic use
-
AI predictions are experimental and may be inaccurate or misleading.
-
Signal quality may be affected by noise, motion, or hardware limitations.
-
If you experience symptoms (e.g., chest pain, arrhythmia, dizziness), contact a qualified physician immediately.
This app is intended only for research, prototyping, and educational purposes.
Use of this application is entirely at your own risk.
- ECG signal acquisition for biomedical prototyping
- BLE hardware integration (Arduino/ESP32)
- Testing real-time AI classification on mobile
- Study of rhythm and beat-type classification models
- SwiftUI + CoreBluetooth (iOS frontend)
- PyTorch, Keras/TensorFlow (model training)
- ONNX β TensorFlow β CoreML / TFLite (deployment)
- WFDB, SciPy, PyWavelets (signal preprocessing)
Each model is evaluated with task-specific metrics:
- β Accuracy, macro/weighted F1-score
- β Per-class precision and recall
- β Confusion matrix (10-class)
- β
NSR fallback threshold:
softmax max < 0.4β fallback to NSR (59118001)
- β Per-beat accuracy (N, V, S, F, Q)
- β Inference on 540-sample QRS-centered segments
- β Real-time aggregation of beat-type predictions
- β Sample-wise F1-score and accuracy
- β Onset/offset match with Β±150 sample tolerance
- β Segment-wise precision, recall, and F1-score
- β Overlay visualization: predicted vs. true waveforms
{
"fs": 500,
"leads": ["II"],
"signals": [[0.003, 0.002, 0.005]],
"start_time": "2025-06-01T12:01:00Z",
"end_time": "2025-06-01T12:01:10Z"
}- fs: Sampling frequency (Hz)
- leads: Array of lead names (e.g., ["II"])
- signals: List of signal arrays (1 per lead)
- start_time, end_time: ISO 8601 timestamps
record123 1 500 5000
record123.dat 16 1000 16 0 0 200 0 II
# age: 26
# sex: M
# duration: 10 seconds
# start_time: 2025-06-01T12:01:00Z
# end_time: 2025-06-01T12:01:10Z
# Recorded via ECG mobile app
- Line 1: <record_name> <n_signals> <n_samples>
- Line 2: <bit_res> <adc_zero> <init_val> <adc_resolution> 0
- Comments (#) include age, sex, start/end time, duration
Signal samples saved as Int16, scaled by gain Written in little-endian format Lead order matches .hea
The app supports importing ECG files in multiple formats:
.dat+.hea(WFDB-compliant):- e.g., MITDB, INCARTDB, LUDB
.jsonformat exported by the ECGApp
All imported signals are parsed and normalized, including:
- Sampling frequency (
fs) - Number of samples
- Gain, resolution, zero offset
- Lead name (e.g., II)
Supported encoding:
- π§© 16-bit integer (
format 16) - β Single-lead inputs (Lead II preferred)
ECGApp fully integrates with the iOS Files system, enabling secure cloud-based data access:
- π€ Export ECG recordings to iCloud Drive for backup or manual inspection
- π₯ Import
.dat/.hea/.jsonfiles from iCloud, USB, or AirDrop - π Seamlessly transfer data between iPhone, iPad, or Mac
- π Files are available under Files β ECGApp β On My iPhone
This makes it easy to analyze, review, or back up ECG sessions securely.
All ECG data is processed and stored locally on the userβs device.
No recordings or personal information are sent to external servers.
- π± All AI inference and signal analysis are performed on-device
- βοΈ If the user chooses to share recordings via iCloud, AirDrop, or Files, the transfer is secure and user-controlled
- π The app does not collect, upload, or transmit any data automatically
- β No third-party analytics, tracking, or background syncing
Users have full control over their data:
- π Access and manage saved recordings (
.json,.dat,.hea) - π Manually delete or export any file
- π Bluetooth connections are limited to approved UUIDs only
Your data remains yours β private, secure, and under your control.
- π‘ Multi-lead ECG support (e.g., V1, V5, aVR)
- π§ͺ Personalized on-device model fine-tuning
- π©Ί AI-based tagging of symptoms and abnormalities
- π Long-term trend tracking and visualization
MIT License β For research and non-commercial use only.
Marcin Sztukowski student of Jagiellonian University in Krakow