Skip to content

Latest commit

 

History

History
443 lines (370 loc) · 29.6 KB

File metadata and controls

443 lines (370 loc) · 29.6 KB

Wearable Real-Time ECG Monitor & Edge DSP Telemetry Pipeline

A deterministic, ultra-low-power biomedical embedded system designed for continuous electrocardiogram (ECG) acquisition, real-time edge QRS complex detection, and multi-service Bluetooth Low Energy (BLE) telemetry. Built on an ARM Cortex-M4F microcontroller, the system executes a real-time Pan-Tompkins digital signal processing (DSP) pipeline directly on digitized biopotential signals, achieving sub-millisecond peak detection with minimal CPU utilization.


System Architecture

The signal chain consists of a three-electrode analog front-end (AFE), a hardware timer-driven 12-bit Successive Approximation Register (SAADC) sampling stage, an on-chip single-precision floating-point DSP pipeline, and an asynchronous BLE GATT server streaming telemetric waveform and clinical metric packets to host visualizers.

+--------------------------------------------------------------------------------------------------+
|                                        ANALOG FRONT END (AFE)                                    |
|                                                                                                  |
|   +---------------+                                                                              |
|   |  LA Electrode |----+                                                                         |
|   +---------------+    |                                                                         |
|                        v                                                                         |
|   +---------------+  +---------------------+   +-------------------+   +---------------------+   |
|   |  RA Electrode |--| INA321 Inst. Amp    |-->| Active Bandpass   |-->| Final Gain Stage    |   |
|   +---------------+  | Gain = 5 V/V, CMRR  |   | 0.5 Hz - 40 Hz    |   | 0 - 3.3V Span Shift |   |
|                        +---------+---------+   +-------------------+   +----------+----------+   |
|                                  |                                                |              |
|   +---------------+              v                                                |              |
|   |  RL Electrode |<---+-------------------+                                      |              |
|   | (Driven Gnd)  |    | Right Leg Drive   |                                      |              |
|   +---------------+    | Active 60Hz Null  |                                      |              |
|                        +-------------------+                                      |              |
+-----------------------------------------------------------------------------------|--------------+
                                                                                    |
                                                          Analog Biopotential Signal| (Pin A0 / P0.02)
                                                                                    v
+--------------------------------------------------------------------------------------------------+
|                                    NORDIC nRF52840 MCU (ARM CORTEX-M4F)                          |
|                                                                                                  |
|  +-------------------------+      +-----------------------------------------------------------+  |
|  | Hardware Timer / Ticker |----->| 12-Bit SAADC Conversion (250 Hz / 4.0 ms Sampling Period) |  |
|  | Deterministic 4.000 ms  | ISR  +-----------------------------+-----------------------------+  |
|  +-------------------------+                                    |                                |
|                                                                 v                                |
|  +--------------------------------------------------------------------------------------------+  |
|  | ARM Cortex-M4F Hardware FPU: Pan-Tompkins Edge DSP Pipeline                                |  |
|  |                                                                                            |  |
|  |  +-----------------------+      +---------------------+      +--------------------------+  |  |
|  |  | 3rd-Order Butterworth |----->| 1st-Difference      |----->| Non-linear Squaring      |  |  |
|  |  | Bandpass (5 - 15 Hz)  |      | Derivative Filter   |      | Operator: y[n] = (x[n])^2|  |  |
|  |  | Direct Form II SOS    |      | y[n] = x[n]-x[n-1]  |      +------------+-------------+  |  |
|  |  +-----------------------+      +---------------------+                   |                |  |
|  |                                                                           v                |  |
|  |  +-----------------------+      +---------------------+      +--------------------------+  |  |
|  |  | Heart Rate & EMA      |<-----| Dual-Threshold      |<-----| Moving Window Integrator |  |  |
|  |  | BPM Calculation       | R-Pk | Adaptive Detection  |      | N = 37 Taps (148 ms)     |  |  |
|  |  | Instantaneous + Filter| Flag | Refractory: 350 ms  |      | O(1) Circular Buffer     |  |  |
|  |  +-----------+-----------+      +----------+----------+      +--------------------------+  |  |
|  +--------------|-----------------------------|-----------------------------------------------+  |
|                 |                             |                                                  |
|                 v (BPM Update)                v (Packed Word: [Bit 15: Peak Flag | Bits 0-11: ADC])
|  +--------------------------------------------------------------------------------------------+  |
|  | BLE GATT Server (2.4 GHz SoftDevice Transceiver)                                           |  |
|  |  - Standard Heart Rate Service (0x180D, Char 0x2A37): Real-time BPM Notifications          |  |
|  |  - Custom Waveform Service (0x19B10000, Char 0x19B10001): 10-Sample 20-Byte Batches (25Hz) |  |
|  |  - Standard Battery Service (0x180F, Char 0x2A19): LiPo State-of-Charge (0.1 Hz)           |  |
|  +--------------------------------------------+-----------------------------------------------+  |
+-----------------------------------------------|--------------------------------------------------+
                                                | BLE 5.0 Wireless Telemetry Stream
                                                | (Negotiated Interval: 15 ms - 30 ms)
                                                v
+--------------------------------------------------------------------------------------------------+
|                               HOST CONSUMERS & TELEMETRY CLIENTS                                 |
|                                                                                                  |
|  +----------------------------------------------+  +------------------------------------------+  |
|  | Web Bluetooth Clinical Dashboard             |  | Python Real-Time Telemetry Plotter       |  |
|  | - 250 Hz Canvas Oscilloscope                 |  | - Direct Serial / Virtual COM Stream     |  |
|  | - 40-Sample Peak Lookback Realignment        |  | - Multi-Trace Filter & Threshold Visual  |  |
|  | - 20-Beat Rolling RMSSD HRV Engine           |  | - Matplotlib Dynamic Animation Loop      |  |
|  +----------------------------------------------+  +------------------------------------------+  |
+--------------------------------------------------------------------------------------------------+

Hardware & Electrical Specifications

Microcontroller & Compute Engine

  • SoC: Nordic Semiconductor nRF52840 (Seeed Studio XIAO form factor).
  • Core: 32-bit ARM Cortex-M4 with single-precision FPv4-SP-D16 hardware floating-point unit (FPU) clocked at 64 MHz.
  • On-Chip Memory: 1 MB Flash, 256 KB SRAM. Zero dynamic heap allocation (malloc/free omitted to guarantee deterministic execution and preclude heap fragmentation).
  • Analog-to-Digital Converter (SAADC):
    • Resolution: 12-bit mode ($2^{12} = 4096$ quantization levels, $0.805\text{ mV/LSB}$ over 3.3V reference).
    • Input: Single-ended channel on pin A0 (P0.02).
    • Acquisition Timing: Synchronized to a 250 Hz periodic tick ($4.000\text{ ms} \pm 1.0\ \mu\text{s}$).

Custom Analog Front-End (AFE)

  • Preamplification: Texas Instruments INA321 low-power instrumentation amplifier ($G = 5\text{ V/V}$, rail-to-rail output) providing high Common-Mode Rejection Ratio ($\text{CMRR} &gt; 94\text{ dB}$ at 60 Hz) to eliminate ambient electromagnetic coupling.
  • Active Filtering: 2nd-order analog active bandpass filter with corner frequencies set to $0.5\text{ Hz}$ (DC half-cell potential suppression and baseline wander elimination) and $40\text{ Hz}$ (electromyographic muscle artifact and high-frequency noise attenuation).
  • Right Leg Drive (RLD): Inverting operational amplifier loop referencing the common-mode potential of the differential inputs and actively injecting an inverted cancellation signal into the Right Leg (RL) electrode, suppressing common-mode 50/60 Hz mains interference.
  • Level Shifting: Intermediate active gain stage scaling the differential biopotential to the full-scale $0\text{--}3.3\text{ V}$ SAADC dynamic range, centered at a $1.65\text{ V}$ virtual ground.

Power Subsystem & Battery Management

  • Operating Source: Single-cell Lithium-Polymer (LiPo) battery ($3.7\text{ V}$ nominal, $4.2\text{ V}$ float).
  • Quiescent Current Budget: Active current draw $&lt; 15\text{ mA}$ during peak 2.4 GHz radio bursts; baseline consumption $&lt; 5\text{ mA}$ during sustained connection.
  • Hardware Battery Sensing: Integrated resistor divider controlled via GPIO P0.14 (VBAT_ENABLE) to prevent parasitic current draw. Analog readout via P0.31 (PIN_VBAT) is sampled at 0.1 Hz and mapped through a calibrated piecewise linear State-of-Charge (SoC) transfer model:
Battery Voltage ($V_{\text{bat}}$) Discharge State State-of-Charge ($\text{SoC}$) Transfer Equation
$V \ge 4.20\text{ V}$ Fully Charged / Float $100%$
$3.80\text{ V} \le V &lt; 4.20\text{ V}$ Nominal Linear Plateau $40% + \left(\frac{V - 3.80}{4.20 - 3.80}\right) \times 60%$
$3.70\text{ V} \le V &lt; 3.80\text{ V}$ Knee Transition Region $20% + \left(\frac{V - 3.70}{3.80 - 3.70}\right) \times 20%$
$3.30\text{ V} \le V &lt; 3.70\text{ V}$ Final Discharge Cliff $\left(\frac{V - 3.30}{3.70 - 3.30}\right) \times 20%$
$V &lt; 3.30\text{ V}$ Cutoff / Depleted $0%$

Edge DSP & Algorithm Implementation

The embedded detection engine implements the Pan-Tompkins QRS detection algorithm mapped onto single-precision 32-bit floating-point registers.

Raw ADC (250Hz) 
    │
    ▼
┌────────────────────────────────────────────────────────┐
│ 1. 3rd-Order Butterworth Bandpass (5 - 15 Hz)          │
│    - Direct Form II Transposed Second-Order Sections   │
│    - Attenuates P/T-waves, baseline drift, 60Hz hum    │
└────────────────────────────────────────────────────────┘
    │
    ▼
┌────────────────────────────────────────────────────────┐
│ 2. 1st-Difference Derivative Filter                    │
│    - y[n] = x[n] - x[n-1]                              │
│    - Highlights high-slope QRS complex transitions     │
└────────────────────────────────────────────────────────┘
    │
    ▼
┌────────────────────────────────────────────────────────┐
│ 3. Non-linear Squaring Operator                        │
│    - y[n] = (x[n])^2                                   │
│    - Forces positive energy & non-linearly boosts QRS  │
└────────────────────────────────────────────────────────┘
    │
    ▼
┌────────────────────────────────────────────────────────┐
│ 4. Moving Window Integrator (MWI)                      │
│    - Window N = 37 samples (~148 ms @ 250 Hz)          │
│    - O(1) circular ring buffer with running accumulator│
└────────────────────────────────────────────────────────┘
    │
    ▼
┌────────────────────────────────────────────────────────┐
│ 5. Adaptive Dual-Threshold & Refractory Engine         │
│    - 350 ms physiological refractory lockout period    │
│    - Continuous apex search during lockout             │
│    - Dynamic signal / noise peak tracking & decay      │
└────────────────────────────────────────────────────────┘
    │
    ▼
R-Peak Event Flag + Instantaneous Filtered Heart Rate (BPM)

1. Second-Order Sections (SOS) Biquad Bandpass Filter

A 3rd-order Butterworth bandpass filter ($5\text{--}15\text{ Hz}$ at $f_s = 250\text{ Hz}$) is partitioned into 3 cascaded Direct Form II Transposed Second-Order Sections (SOS). This architecture preserves numerical stability and prevents coefficient quantization drift common in high-order polynomial implementations:

$$y_k[n] = b_{0,k} x_k[n] + w_{k,0}[n-1]$$ $$w_{k,0}[n] = b_{1,k} x_k[n] - a_{1,k} y_k[n] + w_{k,1}[n-1]$$ $$w_{k,1}[n] = b_{2,k} x_k[n] - a_{2,k} y_k[n]$$

$$\text{SOS} = \begin{bmatrix} 1.56701035 \times 10^{-3} & 3.13402070 \times 10^{-3} & 1.56701035 \times 10^{-3} & 1.0 & -1.73356294 & 0.775679511 \\ 1.00000000 & 0.00000000 & -1.00000000 & 1.0 & -1.71760092 & 0.833876287 \\ 1.00000000 & -2.00000000 & 1.00000000 & 1.0 & -1.91702538 & 0.933967717 \end{bmatrix}$$

Filter state memory occupies only $3 \times 2 \times 4\text{ bytes} = 24\text{ bytes}$ of SRAM (w[3][2]), ensuring persistent zero-copy execution across interrupt ticks.

2. Derivative Filter

A two-point first-difference filter approximates continuous-time differentiation, isolating high-slope QRS transitions while attenuating lower-frequency P- and T-wave components:

$$d[n] = x_{\text{filtered}}[n] - x_{\text{filtered}}[n-1]$$

3. Non-Linear Squaring

The differentiated sequence is squared point-by-point:

$$s[n] = (d[n])^2$$

This enforces positive definiteness and non-linearly amplifies the dominant QRS complex energy relative to background myoelectric and residual baseline fluctuations.

4. Moving Window Integration (MWI)

Waveform integration extracts the QRS complex envelope. The integration window is selected to match typical physiological QRS duration ($150\text{ ms}$):

$$N = \lfloor 0.150 \times f_s \rfloor = \lfloor 0.150 \times 250 \rfloor = 37\text{ samples (148 ms)}$$

$$I[n] = \frac{1}{N} \sum_{k=0}^{N-1} s[n - k]$$

To maintain deterministic execution within the $4.0\text{ ms}$ sampling window, the integration is implemented as an $O(1)$ ring buffer (mwi_buffer[37]) using a running sum accumulator:

mwi_sum -= mwi_buffer[mwi_ptr];
mwi_buffer[mwi_ptr] = squared;
mwi_sum += squared;
mwi_ptr = (mwi_ptr + 1) % 37;
float integrated = mwi_sum / 37.0f;

5. Adaptive Dual-Thresholding & Refractory Logic

  • Refractory Lockout Period ($T_{\text{refractory}} = 350\text{ ms}$): In human physiology, cardiac ventricular depolarization cannot reoccur immediately due to myocardial cell refractory limits. When an R-peak is flagged, a $350\text{ ms}$ blind window is initiated to reject large T-waves. During this window, apex tracking runs continuously: $$PEAK_{\text{signal}} = \max(PEAK_{\text{signal}}, I[n])$$
  • Signal Peak Update (Valid QRS Event): When $I[n] > \text{Threshold}I$ and $t - t{\text{last}} \ge T_{\text{refractory}}$: $$\text{Threshold}I \leftarrow 0.125 \times PEAK{\text{signal}} + 0.875 \times \text{Threshold}I$$ $$PEAK{\text{signal}} \leftarrow I[n]$$
  • Noise Peak Update & Dynamic Threshold Decay: When $I[n] \le \text{Threshold}I$: $$PEAK{\text{noise}} \leftarrow I[n]$$ $$\text{Threshold}F \leftarrow 0.125 \times PEAK{\text{noise}} + 0.875 \times \text{Threshold}_F$$ $$\text{Threshold}_I \leftarrow \text{Threshold}_I \times 0.9995$$ $$\text{Threshold}_I \leftarrow \max(\text{Threshold}_I, 2000.0)$$

6. Heart Rate & Outlier Rejection

For each confirmed R-peak at timestamp $t_n$: $$\Delta t_n = t_n - t_{n-1}\quad (\text{ms})$$ $$\text{BPM}_{\text{inst}} = \frac{60000}{\Delta t_n}$$

Readings outside physiological limits ($30\text{ BPM} \le \text{BPM}{\text{inst}} \le 240\text{ BPM}$) are rejected. Valid instantaneous heart rates are smoothed via an Exponential Moving Average (EMA) to suppress ectopic beat jitter: $$\text{BPM} \leftarrow 0.70 \times \text{BPM} + 0.30 \times \text{BPM}{\text{inst}}$$


Firmware & Concurrency Model

The firmware is structured around an interrupt-driven super-loop topology. The architecture ensures separation between time-critical sampling and non-deterministic radio I/O.

Timeline (4.0 ms Period / 250 Hz Rate)
| ISR |<-- DSP Exec (~25 us) -->|<-------------- System ON Idle Sleep (~3970 us) -------------->|
+-----+-------------------------+---------------------------------------------------------------+
|     |                         |                                                               |
0 us  5 us                      30 us                                                        4000 us
^     ^                         ^
|     |                         +-- Low-power WFI (Wait-For-Interrupt) sleep
|     +-- ADC conversion, Pan-Tompkins filter, buffer staging, conditional BLE write
+-- Hardware Timer / Ticker fires; sets volatile data_ready flag (< 1 us)

Deterministic Timing & Resource Management

  1. Interrupt Service Routine (ISR): An mbed::Ticker hardware timer generates an interrupt every $4.000\text{ ms}$ ($250\text{ Hz}$). The ISR executes in $&lt; 1\ \mu\text{s}$, performing only a single atomic write: data_ready = true;. This prevents nested interrupt priority inversion and eliminates stack bloat.
  2. Main Super-Loop Processing:
    • SAADC 12-bit conversion: $\approx 10\ \mu\text{s}$.
    • Pan-Tompkins DSP execution: $\approx 15\ \mu\text{s}$ (accelerated via the ARM Cortex-M4F single-cycle hardware floating-point unit instructions: VMUL.F32, VADD.F32, VMLA.F32).
    • Total active processing time: $\approx 25\ \mu\text{s}$ per $4.0\text{ ms}$ interval.
    • CPU Idle Time: $&gt; 99.3%$. The core remains in System ON low-power state (WFI sleep) between sampling intervals.

BLE GATT Architecture & Packet Packing

Radio telemetry utilizes the Nordic SoftDevice BLE 5.0 stack via ArduinoBLE.

  • Connection Interval: Negotiated to $12\text{--}24$ units ($15.0\text{--}30.0\text{ ms}$) to prevent packet buffer overflow while minimizing radio active time.
  • GATT Services & Characteristics:
Service Name Service UUID Characteristic UUID Properties Payload / Frequency
Heart Rate Service 0x180D 0x2A37 (HR Measurement) Notify 2 Bytes: [Flags (0x00), uint8_t BPM] (Sent on valid beat)
ECG Waveform Service 19B10000-E8F2-537E-4F6C-D104768A1214 19B10001-E8F2-537E-4F6C-D104768A1214 Notify 20 Bytes: 10 $\times$ 16-bit packed samples ($25\text{ Hz}$ packet rate)
Battery Service 0x180F 0x2A19 (Battery Level) Read, Notify 1 Byte: uint8_t Percentage (Polled every $10\text{ s}$)
  • Waveform Telemetry Bit-Packing Scheme: To stream raw 12-bit ADC biopotentials alongside hardware-synchronized R-peak markers without increasing packet overhead, individual samples are packed into a single 16-bit integer:
    Bit 15            Bits 14-12        Bits 11-0
    +---------------+-----------------+---------------------------------------+
    | R-Peak Marker | Unused / Parity | 12-Bit Unsigned ADC Value (0 - 4095)  |
    +---------------+-----------------+---------------------------------------+
    
    int16_t packed_data = (raw_val & 0x0FFF);
    if (is_peak_detected) {
        packed_data |= 0x8000; // Flag R-peak in MSB
    }
    Every 10 samples ($40\text{ ms}$ of real-time data), the 20-byte buffer is transmitted via a single GATT notification burst, consuming only $500\text{ bytes/s}$ ($4.0\text{ kbps}$) of BLE throughput.

Verification & Benchmarks

The DSP engine and telemetry pipeline were validated through an offline algorithmic simulation and Hardware-in-the-Loop (HIL) testing against the gold-standard PhysioNet MIT-BIH Arrhythmia Database (Record 100).

                PHYSIOMETRIC VALIDATION WORKFLOW
                
  PhysioNet MIT-BIH Record 100 (360 Hz)
                 │
                 ▼
  simulation/pan_tompkins_poc.py (Polyphase Resampling -> 250 Hz)
                 │
        ┌────────┴──────────────────────────┐
        ▼                                   ▼
  C++ Array Header                   Keysight AWG Export
  (firmware/include/test_signal.h)   (AWG_MITBIH_100_VOLTS.csv)
  1250 Samples (5 sec playback)      0.5V - 2.5V pk-pk ASCII
        │                                   │
        ▼                                   ▼
  nRF52840 Internal ROM Playback     Physical AFE Electrode Injection
        │                                   │
        └─────────────────┬─────────────────┘
                          │
                          ▼
            SAADC / Edge DSP Execution
                          │
                          ▼
            Clinical Metric Benchmarking

1. Algorithm Benchmarking vs. Ground Truth

Record 100 contains baseline clinical ECG recorded from Lead MLII. The raw $360\text{ Hz}$ data was resampled to $250\text{ Hz}$ via polyphase filtering and processed through both the Python verification model (simulation/pan_tompkins_poc.py) and the on-device firmware implementation (manual_tests/03_alg_simulation).

  • Ground-Truth Heart Rate: $75.4\text{ BPM}$ (consistent across PhysioNet clinical annotations).
  • Firmware Detected Heart Rate: $75.2\text{ BPM}$ ($\Delta = 0.2\text{ BPM}$, $&lt; 0.3%$ relative error).
  • RR Interval Standard Deviation: $0.0384\text{ s}$ ($38.4\text{ ms}$).

2. Hardware-in-the-Loop (HIL) Signal Injection

  • Arbitrary Waveform Generation: simulation/signal_csv_gen.py normalizes Record 100 and scales the biopotential to a $2.0\text{ V}$ peak-to-peak swing ($0.5\text{ V}$ to $2.5\text{ V}$), formatting the signal into pure ASCII CSV (AWG_MITBIH_100_VOLTS.csv).
  • Bench Setup: A Keysight function/arbitrary waveform generator drives the generated CSV directly into the physical instrumentation amplifier inputs. This validates that the AFE common-mode rejection, active filtering, and firmware thresholding maintain lock under realistic electrode impedance and input swing conditions.
  • Firmware ROM Regression Suite: A 1250-sample ($5.0\text{ s}$) pre-scaled array stored in Flash (firmware/include/test_signal.h) allows deterministic on-chip regression testing without external hardware dependencies.

3. Latency & Telemetry Metrics

  • Sampling Rate: $250.0\text{ Hz}$ ($4.000\text{ ms}$ interval).
  • Sample-to-Decision Latency: $&lt; 50\ \mu\text{s}$ (Time from SAADC conversion to R-peak classification).
  • Wireless Transmission Latency: $40\text{ ms}$ batching window + $15\text{--}30\text{ ms}$ BLE connection interval = $55\text{--}70\text{ ms}$ end-to-end telemetry display latency.
  • BLE Bandwidth Consumption: $4.0\text{ kbps}$ active payload throughput ($&lt; 5%$ of BLE 1M PHY practical capacity).

Host Visualizers & Clinical Dashboards

1. Web Bluetooth Clinical Monitor (webpage/index.html)

A zero-dependency browser-based monitoring application built with the Web Bluetooth API:

  • Real-Time Canvas Oscilloscope: Renders an interactive 250 Hz continuous sweep trace with a 6-second window (1500 points).
  • 40-Sample Peak Lookback Realignment: The Moving Window Integrator (148 ms window) introduces a small algorithmic phase delay. The visualizer implements a 40-sample retroactive window search upon receiving the hardware R-peak flag, snapping the visual marker directly onto the true electrical apex of the QRS complex.
  • Real-Time HRV Calculation (RMSSD): Tracks sample intervals between flagged R-peaks and computes the Root Mean Square of Successive Differences over a 20-beat rolling buffer:

$$\text{RMSSD} = \sqrt{\frac{1}{M-1} \sum_{j=1}^{M-1} \left( \text{RR}_{j+1} - \text{RR}_j \right)^2}$$

2. Python Real-Time Telemetry Plotter (simulation/realtime_plotter.py)

A dual-axis serial telemetry monitor utilizing matplotlib.animation:

  • Top Trace: Raw 12-bit SAADC biopotential data ($0\text{--}4095$).
  • Bottom Trace: MWI integrated signal energy alongside the dynamically decaying adaptive threshold line ($\text{Threshold}_I$) and smoothed BPM readouts.

Repository Structure

wearable-heart-monitor/
├── firmware/                              # Embedded C++ Firmware (PlatformIO / Nordic nRF52)
│   ├── include/                           # Firmware Header Files
│   │   └── test_signal.h                  # 1250-Sample MIT-BIH Record 100 ROM Dataset
│   ├── src/
│   │   └── main.cpp                       # Production Firmware: Ticker, SAADC, DSP, BLE Services
│   ├── manual_tests/                      # Subsystem Milestones & Verification Test Harnesses
│   │   ├── 01_blink/                      # GPIO & Core Clockbringup
│   │   ├── 02_adc_sampling/               # Bare-Metal NRF_TIMER1 & SAADC Register Validation
│   │   ├── 03_alg_simulation/             # ROM-based Pan-Tompkins Algorithmic Benchmark
│   │   ├── 04_adc_with_alg/               # Live SAADC + Pan-Tompkins + Serial Diagnostics
│   │   ├── 05_adc_dsp_ble_integration/    # Pan-Tompkins + Standard BLE Heart Rate Service
│   │   └── 06_live_waveform_integration/  # Multi-Service Architecture (Waveform + HR + Battery)
│   └── platformio.ini                     # Build Targets, Linker Flags, and Dependencies
│
├── simulation/                            # DSP Modeling & Hardware-in-the-Loop Validation Suite
│   ├── pan_tompkins_poc.py                # Python DSP Model & MIT-BIH Verification Pipeline
│   ├── playback_gen.py                    # C++ Header Generation Utility from PhysioNet Records
│   ├── signal_csv_gen.py                  # Strict ASCII CSV Generator for Keysight AWG Hardware
│   ├── realtime_plotter.py                # Matplotlib Serial Telemetry Stream Visualizer
│   ├── requirements.txt                   # Python Environment Dependencies
│   └── data/                              # Local WFDB Datasets (Record 100)
│
├── webpage/                               # Production Web Bluetooth Clinical Visualizer
│   └── index.html                         # Real-Time Canvas Trace, Peak Lookback, RMSSD HRV
│
├── visualisation/                         # Interactive System Architecture & Signal Path Tracing
│   └── index.html                         # SVG Schematic & Power Distribution Explorer
│
├── docs/                                  # Architectural Schematics & Hardware Diagrams
│   └── system_diagram.png                 # Detailed Hardware Block Diagram
│
├── AWG_MITBIH_100.csv                     # Keysight AWG Normalized Waveform
├── AWG_MITBIH_100_VOLTS.csv               # Keysight AWG Scaled Analog Voltage Injection File
└── README.md                              # System Specification Document

Build & Flash Instructions

Prerequisites

  1. Toolchain: Install PlatformIO Core (CLI) or the PlatformIO IDE extension.
  2. Hardware: Seeed Studio XIAO nRF52840 connected via USB-C.

Compile & Flash Firmware

# Clone the repository
git clone https://github.com/SaheelFaisal/wearable-heart-monitor.git
cd wearable-heart-monitor/firmware

# Compile the firmware using the Nordic nRF52 toolchain
pio run

# Flash to the connected target MCU
pio run -t upload

# Launch serial telemetry monitor (115200 baud)
pio device monitor -b 115200

To compile a specific validation milestone instead of the production target, adjust src_dir in firmware/platformio.ini:

[platformio]
; src_dir = src
src_dir = manual_tests/06_live_waveform_integration

Python Simulation & Serial Diagnostics Setup

# Navigate to the simulation directory
cd ../simulation

# Install scientific dependencies
pip install -r requirements.txt

# Run the MIT-BIH Record 100 algorithmic validation model
python pan_tompkins_poc.py

# Launch the real-time serial telemetry plotter (Update COM port in script as needed)
python realtime_plotter.py

Launching the Web Bluetooth Dashboard

  1. Open Google Chrome, Microsoft Edge, or any browser with Web Bluetooth API support.
  2. Open webpage/index.html directly in the browser (or serve via a local HTTP server):
    python -m http.server 8000
  3. Navigate to http://localhost:8000/webpage/index.html.
  4. Click Connect Device and pair with ECG HEART RATE MONITOR.