cd /news/machine-learning/real-time-arrhythmia-detection-at-th… · home topics machine-learning article
[ARTICLE · art-42801] src=dev.to ↗ pub= topic=machine-learning verified=true sentiment=↑ positive

Real-Time Arrhythmia Detection at the Edge: Deploying TinyML on ESP32 for Raw ECG Analysis

A developer built a real-time arrhythmia detector using TinyML on an ESP32 microcontroller, processing raw ECG data locally with TensorFlow Lite for Microcontrollers. The system uses a quantized 1D-CNN model trained on the MIT-BIH Arrhythmia Database to classify heart rhythms, enabling low-latency, privacy-preserving health monitoring on wearable devices.

read3 min views1 publishedJun 29, 2026

In the world of wearable health technology, the holy grail has always been moving intelligence from the cloud to the edge. Waiting for a cloud server to analyze your heart rhythm is not just a latency issue—it's a privacy and battery life concern. Today, we are diving deep into TinyML, Edge AI, and ECG signal processing to build a real-time abnormality detector.

By leveraging TensorFlow Lite for Microcontrollers and the versatile ESP32, we can process raw electrocardiogram (ECG) data locally. This approach ensures low-latency detection of arrhythmias while keeping sensitive medical data on-device. If you've been looking to bridge the gap between high-level deep learning and low-level embedded systems, you're in the right place!

The pipeline involves capturing a high-frequency analog signal, cleaning it, and feeding it into a quantized Convolutional Neural Network (CNN). Here is how the data flows through our ESP32:

graph TD
    A[Raw ECG Signal/Sensor] -->|ADC Sampling| B(Preprocessing: Bandpass Filter)
    B --> C{Buffer Management}
    C -->|Windowed Segment| D[TFLite Micro Inference Engine]
    D --> E{CNN Model Classification}
    E -->|Normal| F[Log: Sinus Rhythm]
    E -->|Abnormal| G[Trigger Alert: Arrhythmia]
    G -->|Bluetooth/Wi-Fi| H[Mobile Dashboard]

To follow this advanced guide, you'll need:

Before we touch the C++ code, we need a model. Typically, we use the MIT-BIH Arrhythmia Database to train a 1D-CNN. The crucial step is Post-Training Quantization.

Since the ESP32 doesn't have a dedicated NPU, we convert our 32-bit float model into an 8-bit integer (INT8) model. This reduces the size by 4x and speeds up inference significantly without a massive drop in accuracy.

We need to load the model as a byte array and set up the TFLite interpreter. Here is a simplified implementation of the inference loop.

#include <TensorFlowLite.h>
#include "model_data.h" // Your exported INT8 model
#include "tensorflow/lite/micro/all_ops_resolver.h"
#include "tensorflow/lite/micro/micro_interpreter.h"

// Constants for the ECG window
const int kTensorArenaSize = 30 * 1024; // 30KB Arena
uint8_t tensor_arena[kTensorArenaSize];

// TFLite globals
tflite::MicroInterpreter* interpreter = nullptr;
TfLiteTensor* input = nullptr;

void setup() {
    Serial.begin(115200);

    // 1. Load the model
    static tflite::MicroMutableOpResolver<5> resolver;
    resolver.AddConv2D();
    resolver.AddMaxPool2D();
    resolver.AddFullyConnected();
    resolver.AddSoftmax();
    resolver.AddReshape();

    static tflite::MicroInterpreter static_interpreter(
        tflite::GetModel(g_model_data), resolver, tensor_arena, kTensorArenaSize);
    interpreter = &static_interpreter;
    interpreter->AllocateTensors();

    input = interpreter->input(0);
}

void loop() {
    // 2. Simulate/Read ECG Data (Sampled at 125Hz or 250Hz)
    float sample = analogRead(34); 
    // ... [Preprocessing Logic: Normalization & Filtering] ...

    // 3. Fill the Input Tensor
    for (int i = 0; i < input->dims->data[1]; i++) {
        input->data.f[i] = processed_samples[i]; 
    }

    // 4. Run Inference
    TfLiteStatus invoke_status = interpreter->Invoke();
    if (invoke_status != kTfLiteOk) {
        Serial.println("Inference failed!");
        return;
    }

    // 5. Analyze Results
    float normal_score = interpreter->output(0)->data.f[0];
    float abnormal_score = interpreter->output(0)->data.f[1];

    if (abnormal_score > 0.8) {
        Serial.println("⚠️ Warning: Abnormal Heart Rhythm Detected!");
    }
}

When moving from a prototype to a production-grade wearable, you'll encounter challenges like signal noise from muscle movement (EMG) and power consumption. For those looking to implement robust noise-cancellation algorithms or more efficient memory management in TinyML deployments, I highly recommend checking out more production-ready examples.

Pro-Tip: For a deep dive into advanced signal processing patterns and optimizing TensorFlow Lite for mission-critical edge applications, visit the[WellAlly Tech Blog]. They provide excellent resources on scaling these localized AI models to enterprise-grade health solutions.

Raw ECG data is messy. You'll need a digital Bandpass Filter (usually 0.5Hz to 40Hz) to remove baseline wander and high-frequency noise. In C++, this can be implemented as a simple IIR filter to keep the computational overhead low on the ESP32.

// Example: Simple Low-pass filter component
float lowPass(float input, float prevOutput, float alpha) {
    return prevOutput + alpha * (input - prevOutput);
}

Deploying a CNN on an ESP32 for real-time ECG analysis isn't just a "cool project"—it's a glimpse into the future of decentralized healthcare. By processing data locally, we respect user privacy and reduce the load on our infrastructure.

What's next for your TinyML journey?

Happy hacking! 🚀💻

If you enjoyed this tutorial, don't forget to ❤️ and bookmark it! For more advanced Edge AI content, keep an eye on my profile or visit the official WellAlly Blog.

── more in #machine-learning 4 stories · sorted by recency
── more on @esp32 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain — perfect for shipping the agent you just read about.

$git push zahid main
Live at https://your-agent.zahid.host
Get free account → Pricing
from €0/mo · no card required
LIVE [news/real-time-arrhythmia…] indexed:0 read:3min 2026-06-29 ·