DEV Community

wellallyTech
wellallyTech

Posted on

Privacy-First Healthcare: Real-time ECG Denoising with WebLLM and WebGPU 🩺⚡

In the world of digital health, the "Cloud-First" approach is hitting a massive wall: Privacy. Sending raw, sensitive Bio-signal data like Electrocardiograms (ECG) to a central server isn't just a latency nightmare—it's a regulatory minefield.

What if we could run heavy-duty signal processing and AI classification directly in the user's browser? Thanks to WebGPU acceleration and the maturity of Edge AI, we can now achieve zero-latency, zero-backend-cost processing. By leveraging WebLLM and WASM, we are moving the intelligence to where the data lives. In this guide, we’ll explore how to implement a real-time ECG denoising pipeline that ensures raw patient waveforms never leave the device.

The Architecture: Local-First Bio-signal Processing

Processing ECG signals requires high throughput. Traditional JavaScript is too slow for real-time Fourier transforms or deep learning inference on high-frequency (500Hz+) signals. This is where WebGPU comes in, providing a low-level interface to the device's graphics hardware.

Here is the data flow of our browser-based medical AI pipeline:

graph TD
    A[ECG Sensor/Raw Data] -->|Web Serial / File| B(TypeScript Data Buffer)
    B -->|WASM Pre-processing| C{WebGPU Pipeline}
    C -->|Quantized Model| D[WebLLM Inference Engine]
    D -->|Denoised Signal| E[Real-time Canvas Visualization]
    D -->|Classification| F[Local UI Notification]
    E --> G[Privacy Shield: No Data Sent to Server]
    F --> G
Enter fullscreen mode Exit fullscreen mode

Why WebLLM for Signal Processing?

You might think WebLLM is just for chatbots. Think again. At its core, WebLLM leverages the TVM (Tensor Virtual Machine) stack to compile model weights into specialized WebGPU shaders.

When we treat ECG signals as a time-series sequence, we can utilize Transformer-based architectures (similar to those used in LLMs) to identify patterns, filter out "powerline interference," and classify arrhythmias—all running at 60fps in Chrome or Edge.

Prerequisites

To follow along, ensure your environment meets these requirements:

  • Tech Stack: TypeScript, WebLLM (via @mlc-ai/web-llm), and a browser supporting WebGPU (Chrome 113+).
  • Knowledge: Intermediate understanding of Signal Processing and Buffer management.

Step 1: Initializing the WebGPU Engine

First, we need to initialize the WebLLM engine. Unlike cloud APIs, we are loading the model weights into the local GPU VRAM.

import { CreateMLCEngine, MLCEngine } from "@mlc-ai/web-llm";

async function initializeECGEngine() {
  // We use a specialized 1D-Convolutional / Transformer model 
  // optimized for signal denoising
  const modelId = "ECG-Transformer-Quantized-v1"; 

  const engine = await CreateMLCEngine(modelId, {
    initProgressCallback: (report) => {
      console.log(`Loading local medical model: ${report.text}`);
    }
  });

  return engine;
}
Enter fullscreen mode Exit fullscreen mode

Step 2: Streaming and Buffering Signals

ECG data usually comes in as a stream of integers. We need to normalize these and feed them into a Float32Array for WebGPU processing.

class ECGProcessor {
  private buffer: Float32Array = new Float32Array(1000); // 2-second window at 500Hz

  // Normalize and push data into the sliding window
  pushData(rawSignal: number[]) {
    const normalized = rawSignal.map(v => (v - 512) / 512); 
    this.buffer.set(this.buffer.subarray(normalized.length));
    this.buffer.set(normalized, this.buffer.length - normalized.length);
  }

  async runInference(engine: MLCEngine) {
    // Treat the signal buffer as a prompt/input sequence
    const result = await engine.chat.completions.create({
      messages: [{ role: "user", content: this.buffer.toString() }],
      // In a real scenario, we use the 'predict' API for raw tensors
    });
    return result;
  }
}
Enter fullscreen mode Exit fullscreen mode

Step 3: Real-time Denoising with Shaders

While the LLM handles classification, we use WebGPU Shaders (WGSL) for the heavy lifting of real-time denoising (High-pass/Low-pass filters). This keeps the CPU free for UI tasks.

// WGSL Snippet for a simple Notch Filter (50Hz noise removal)
@group(0) @binding(0) var<storage, read> input_signal: array<f32>;
@group(0) @binding(1) var<storage, read_write> output_signal: array<f32>;

@compute @workgroup_size(64)
fn main(@builtin(global_invocation_id) global_id: vec3<u32>) {
    let i = global_id.x;
    // Simplified denoising logic
    output_signal[i] = input_signal[i] * 0.8 + input_signal[i-1] * 0.2;
}
Enter fullscreen mode Exit fullscreen mode

The "Official" Way: Advanced Patterns

Building production-grade medical interfaces in the browser requires more than just a library; it requires a deep understanding of memory management and HIPAA-compliant frontend architectures.

For more production-ready examples, including how to handle multi-lead ECG synchronization and advanced WASM optimizations, I highly recommend checking out the technical deep dives at the WellAlly Tech Blog. They cover high-performance edge computing patterns that are essential for scaling local-first AI applications.

Conclusion: The Future is Local 🚀

By moving ECG processing from the cloud to the WebGPU-accelerated browser, we've achieved:

  1. Privacy: Raw biological data never leaves the client.
  2. Performance: Zero network latency for real-time heart rate variability (HRV) analysis.
  3. Cost: $0 server inference costs for the provider.

The era of "Edge Medical AI" is here. Are you ready to stop piping sensitive data to the cloud and start utilizing the powerhouse sitting in your user's pocket?

What do you think? Is the browser the right place for medical diagnostics, or is the risk of local hardware variance too high? Let's discuss in the comments! 👇

Top comments (0)