Skip to content

Signal Conditioning, Filtering & Quality Assessment (SQI)

In clinical electrocardiography and edge telemetry, raw biopotential measurements are susceptible to diverse physiological and electromagnetic disturbances. The AI ECG SDK (ecg_sdk) provides a robust, zero-phase signal conditioning suite and multi-metric Signal Quality Index (SQI) pipeline designed to prepare recordings for automated AI interpretation and clinical paper visualization.


1. Noise Archetypes in Electrocardiography

               FREQUENCY SPECTRUM OF NOISE IN CLINICAL ECG
  ┌───────────────────────┬──────────────────────┬───────────────────────┐
  │ Respiratory Wander    │ Diagnostic QRS Band  │ High-Frequency Noise  │
  │ (0.05 Hz — 0.5 Hz)    │ (0.5 Hz — 45.0 Hz)   │ (> 45.0 Hz & 50/60Hz) │
  └───────────────────────┴──────────────────────┴───────────────────────┘
  0 Hz                   0.5 Hz                 45 Hz                   125 Hz (Nyquist)
  1. Powerline Interference (50 Hz / 60 Hz): Electromagnetic induction from AC power grids, fluorescent lighting, and ungrounded biomedical equipment.
  2. Respiratory Baseline Wander (0.05–0.5 Hz): Mechanical chest movements during breathing, perspiration altering skin-electrode impedance, and patient body movements.
  3. Electromyographic (EMG) Muscle Noise (20–500 Hz): High-frequency biopotentials originating from skeletal muscle contractions (shivering, patient anxiety, speech).
  4. Electrode Motion Artifacts & Disconnections: High-amplitude step discontinuities, baseline saturation, or flatlines.

2. Digital Filtering Architecture

2.1 Zero-Phase Butterworth Bandpass Filter (0.5–45 Hz)

To maintain strict temporal alignment of \(P, Q, R, S, T\) fiducial wave onsets, peaks, and offsets, the SDK applies a 4th-order zero-phase Butterworth bandpass filter implemented via Second-Order Sections (SOS):

\[H(z) = \prod_{k=1}^{K} \frac{b_{0k} + b_{1k}z^{-1} + b_{2k}z^{-2}}{1 + a_{1k}z^{-1} + a_{2k}z^{-2}}\]
  • Forward-Backward Filtering (sosfiltfilt): Doubles the effective filter order (\(2 \times 4 = 8\text{th}\) order) while achieving exactly zero phase distortion (\(\theta(\omega) = 0\)): $\(y(t) = f^{-1}\Big(f\big(x(t)\big)\Big)\)$
  • Lower Cutoff (\(0.5\text{ Hz}\)): Attenuates slow respiration drift while preserving the low-frequency morphology of the \(T\)-wave.
  • Upper Cutoff (\(45.0\text{ Hz}\) / \(100.0\text{ Hz}\)): Rejects high-frequency EMG noise while preserving rapid QRS depolarization slopes (\(\Delta V / \Delta t\)).
from ecg_sdk.core.loaders import load_mitbih_record

# Load raw record and apply bandpass filtering
sig = load_mitbih_record("106", start_time=10.0, duration=10.0)
filtered_sig = sig.filter(lowcut=0.5, highcut=45.0, notch_freq=60.0)

2.2 IIR Notch Filter (50 Hz / 60 Hz Powerline Cancellation)

A digital Infinite Impulse Response (IIR) notch filter cancels line hum with a narrow rejection notch centered at \(f_0 \in \{50.0, 60.0\}\text{ Hz}\) and quality factor \(Q = f_0 / \Delta f \approx 30\):

\[H_{\text{notch}}(z) = b_0 \frac{1 - 2\cos(\omega_0)z^{-1} + z^{-2}}{1 - 2r\cos(\omega_0)z^{-1} + r^2 z^{-2}}\]
# Apply standalone 50 Hz powerline notch filter
from ecg_sdk.preprocessing.filters import iir_notch_filter

clean_lead = iir_notch_filter(sig.get_lead("II"), freq=50.0, fs=sig.sampling_rate, quality_factor=30.0)

3. Two-Stage Cascaded Median Baseline Wander Removal

Standard linear highpass filters can introduce undesirable phase distortions or artificial ST-segment depressions. Following de Chazal et al. (2004) and Clifford et al. (2006), the SDK provides a non-linear two-stage cascaded median filter:

flowchart LR
    A[Raw ECG x_t] --> B[Stage 1: 200ms Median Filter]
    B -->|Suppresses P and QRS| C[Stage 2: 600ms Median Filter]
    C -->|Suppresses T-Wave| D[Estimated Baseline b_t]
    A --> E[Subtraction]
    D --> E
    E --> F[Baseline-Corrected ECG x_tilde_t]
  1. Stage 1 (\(w_1 = 200\text{ ms}\)): Strips narrow \(P\)-waves and \(QRS\) complexes (\(\approx 0.20 \cdot f_s\) samples).
  2. Stage 2 (\(w_2 = 600\text{ ms}\)): Strips broader \(T\)-waves (\(\approx 0.60 \cdot f_s\) samples), extracting the continuous isoelectric drift \(\mathbf{b}(t)\).
  3. Subtraction: \(\tilde{\mathbf{x}}(t) = \mathbf{x}(t) - \mathbf{b}(t)\).
# Remove baseline wander and inspect the extracted baseline trend
cleaned_sig, baseline = sig.remove_baseline(
    method="cascaded_median",
    window1_ms=200.0,
    window2_ms=600.0,
    return_baseline=True,
)

4. Multi-Metric Signal Quality Index (SQI) Engine

Prior to feeding biopotentials into diagnostic AI models or downstream feature extraction, the SDK assesses data quality across 5 electrophysiological dimensions (Clifford et al., 2012; Orphanidou et al., 2015):

Index Formula & Definition Physiological Interpretation
\(p\text{SQI}\) \(\frac{\int_{5\text{Hz}}^{15\text{Hz}} S(f)\,df}{\int_{5\text{Hz}}^{40\text{Hz}} S(f)\,df}\) Power Spectrum QRS Concentration: High values (\(0.4\text{--}0.9\)) indicate dominant, well-formed QRS energy.
\(k\text{SQI}\) \(\kappa = \frac{\mathbb{E}[(x - \mu)^4]}{\sigma^4}\) Kurtosis (4th Moment): Clean ECG with sharp R-peaks has \(\kappa > 5.0\). Gaussian noise has \(\kappa \approx 3.0\).
\(s\text{SQI}\) \(\gamma = \frac{\mathbb{E}[(x - \mu)^3]}{\sigma^3}\) Skewness (3rd Moment): Quantifies biopotential distribution asymmetry around the isoelectric line.
\(\text{basSQI}\) \(\frac{\int_{0\text{Hz}}^{0.5\text{Hz}} S(f)\,df}{\int_{0.5\text{Hz}}^{40\text{Hz}} S(f)\,df}\) Baseline Drift Ratio: Low values indicate negligible respiratory baseline drift.
\(\text{hfSQI}\) \(\frac{\int_{45\text{Hz}}^{f_{\text{nyq}}} S(f)\,df}{\int_{0.5\text{Hz}}^{40\text{Hz}} S(f)\,df}\) High-Frequency Noise Ratio: Low values confirm absence of severe EMG tremor or powerline noise.

4.1 Composite Quality Score & Decision Gating

The composite index \(\text{cSQI} \in [0.0, 1.0]\) combines individual metric scores into a standardized clinical acceptability classification:

\[\text{cSQI} = 0.35 \cdot \hat{p}_{\text{SQI}} + 0.30 \cdot \hat{k}_{\text{SQI}} + 0.20 \cdot (1 - \hat{b}_{\text{SQI}}) + 0.15 \cdot (1 - \hat{h}_{\text{SQI}})\]
  • "excellent" (\(\text{cSQI} \ge 0.75\)): Ideal for deep learning delineation and automated biomarker extraction.
  • "acceptable" (\(0.60 \le \text{cSQI} < 0.75\)): Clinically diagnostic; minor baseline drift or noise present.
  • "unusable" (\(\text{cSQI} < 0.60\)): Saturated, flatlined, or corrupted by severe motion artifacts. Downstream AI inference should be gated and an alert raised.
# Assess multi-lead signal quality
quality_report = sig.assess_quality(acceptance_threshold=0.60)
print(quality_report.summary())

5. End-to-End Code Example

import ecg_sdk
from ecg_sdk.core.loaders import load_mitbih_record

# 1. Load record with 250 Hz harmonization
sig = load_mitbih_record("106", start_time=10.0, duration=8.0, target_fs=250.0)

# 2. Assess initial quality
raw_sqi = sig.assess_quality()
print("Raw Quality:", raw_sqi.overall_grade, f"({raw_sqi.overall_sqi:.3f})")

# 3. Apply conditioning pipeline
clean_sig = sig.filter(lowcut=0.5, highcut=45.0, notch_freq=60.0).remove_baseline()

# 4. Assess conditioned quality
clean_sqi = clean_sig.assess_quality()
print("Cleaned Quality:", clean_sqi.overall_grade, f"({clean_sqi.overall_sqi:.3f})")

# 5. Render 1:1 clinical paper plot
clean_sig.plot_clinical(lead="MLII", display_mode="digital", grid_style="clinical_red")