ECG and Cardiac Signal Processing
Process electrocardiogram (ECG) and photoplethysmography (PPG) signals for cardiovascular analysis. This module provides comprehensive tools for R-peak detection, waveform delineation, quality assessment, and heart rate analysis.
Overview
ECG and Cardiac Signal Processing
Overview
Process electrocardiogram (ECG) and photoplethysmography (PPG) signals for cardiovascular analysis. This module provides comprehensive tools for R-peak detection, waveform delineation, quality assessment, and heart rate analysis.
Main Processing Pipeline
ecg_process()
Complete automated ECG processing pipeline that orchestrates multiple steps.
signals, info = nk.ecg_process(ecg_signal, sampling_rate=1000, method='neurokit')
Pipeline steps:
- Signal cleaning (noise removal)
- R-peak detection
- Heart rate calculation
- Quality assessment
- QRS delineation (P, Q, S, T waves)
- Cardiac phase determination
Returns:
signals: DataFrame with cleaned ECG, peaks, rate, quality, cardiac phasesinfo: Dictionary with R-peak locations and processing parameters
Common methods:
'neurokit'(default): Comprehensive NeuroKit2 pipeline'biosppy': BioSPPy-based processing'pantompkins1985': Pan-Tompkins algorithm'hamilton2002','elgendi2010','engzeemod2012': Alternative methods
Preprocessing Functions
ecg_clean()
Remove noise from raw ECG signals using method-specific filtering.
cleaned_ecg = nk.ecg_clean(ecg_signal, sampling_rate=1000, method='neurokit')
Methods:
'neurokit': High-pass Butterworth filter (0.5 Hz) + powerline filtering'biosppy': FIR filtering between 0.67-45 Hz'pantompkins1985': Band-pass 5-15 Hz + derivative-based'hamilton2002': Band-pass 8-16 Hz'elgendi2010': Band-pass 8-20 Hz'engzeemod2012': FIR band-pass 0.5-40 Hz
Key parameters:
powerline: Remove 50 or 60 Hz powerline noise (default: 50)
ecg_peaks()
Detect R-peaks in ECG signals with optional artifact correction.
peaks_dict, info = nk.ecg_peaks(cleaned_ecg, sampling_rate=1000, method='neurokit', correct_artifacts=False)
Available methods (13+ algorithms):
'neurokit': Hybrid approach optimized for reliability'pantompkins1985': Classic Pan-Tompkins algorithm'hamilton2002': Hamilton's adaptive threshold'christov2004': Christov's adaptive method'gamboa2008': Gamboa's approach'elgendi2010': Elgendi's two moving averages'engzeemod2012': Modified Engelse-Zeelenberg'kalidas2017': XQRS-based'martinez2004','rodrigues2021','koka2022','promac': Advanced methods
Artifact correction:
Set correct_artifacts=True to apply Lipponen & Tarvainen (2019) correction:
- Detects ectopic beats, long/short intervals, missed beats
- Uses threshold-based detection with configurable parameters
Returns:
- Dictionary with
'ECG_R_Peaks'key containing peak indices
ecg_delineate()
Identify P, Q, S, T waves and their onsets/offsets.
waves, waves_peak = nk.ecg_delineate(cleaned_ecg, rpeaks, sampling_rate=1000, method='dwt')
Methods:
'dwt'(default): Discrete wavelet transform-based detection'peak': Simple peak detection around R-peaks'cwt': Continuous wavelet transform (Martinez et al., 2004)
Detected components:
- P waves:
ECG_P_Peaks,ECG_P_Onsets,ECG_P_Offsets - Q waves:
ECG_Q_Peaks - S waves:
ECG_S_Peaks - T waves:
ECG_T_Peaks,ECG_T_Onsets,ECG_T_Offsets - QRS complex: onsets and offsets
Returns:
waves: Dictionary with all wave indiceswaves_peak: Dictionary with peak amplitudes
ecg_quality()
Assess ECG signal integrity and quality.
quality = nk.ecg_quality(ecg_signal, rpeaks=None, sampling_rate=1000, method='averageQRS')
Methods:
'averageQRS'(default): Template matching correlation (Zhao & Zhang, 2018)- Returns quality scores 0-1 for each heartbeat
- Threshold: >0.6 = good quality
'zhao2018': Multi-index approach using kurtosis, power spectrum distribution
Use cases:
- Identify low-quality signal segments
- Filter out noisy heartbeats before analysis
- Validate R-peak detection accuracy
Analysis Functions
ecg_analyze()
High-level analysis that automatically selects event-related or interval-related mode.
analysis = nk.ecg_analyze(signals, sampling_rate=1000, method='auto')
Mode selection:
- Duration < 10 seconds → event-related analysis
- Duration ≥ 10 seconds → interval-related analysis
Returns: DataFrame with cardiac metrics appropriate for the analysis mode.
ecg_eventrelated()
Analyze stimulus-locked ECG epochs for event-related responses.
results = nk.ecg_eventrelated(epochs)
Computed metrics:
ECG_Rate_Baseline: Mean heart rate before stimulusECG_Rate_Min/Max: Minimum/maximum heart rate during epochECG_Phase_Atrial/Ventricular: Cardiac phase at stimulus onset- Rate dynamics across epoch time windows
Use case: Experimental paradigms with discrete trials (e.g., stimulus presentations, task events).
ecg_intervalrelated()
Analyze continuous ECG recordings for resting state or extended periods.
results = nk.ecg_intervalrelated(signals, sampling_rate=1000)
Computed metrics:
ECG_Rate_Mean: Average heart rate over interval- Comprehensive HRV metrics (delegates to
hrv()function)- Time domain: SDNN, RMSSD, pNN50, etc.
- Frequency domain: LF, HF, LF/HF ratio
- Nonlinear: Poincaré, entropy, fractal measures
Minimum duration:
- Basic rate: Any duration
- HRV frequency metrics: ≥60 seconds recommended, 1-5 minutes optimal
Utility Functions
ecg_rate()
Compute instantaneous heart rate from R-peak intervals.
heart_rate = nk.ecg_rate(peaks, sampling_rate=1000, desired_length=None)
Method:
- Calculates inter-beat intervals (IBIs) between consecutive R-peaks
- Converts to beats per minute (BPM): 60 / IBI
- Interpolates to match signal length if
desired_lengthspecified
Returns:
- Array of instantaneous heart rate values
ecg_phase()
Determine atrial and ventricular systole/diastole phases.
cardiac_phase = nk.ecg_phase(ecg_cleaned, rpeaks, delineate_info)
Phases computed:
ECG_Phase_Atrial: Atrial systole (1) vs. diastole (0)ECG_Phase_Ventricular: Ventricular systole (1) vs. diastole (0)ECG_Phase_Completion_Atrial/Ventricular: Percentage of phase completion (0-1)
Use case:
- Cardiac-locked stimulus presentation
- Psychophysiology experiments timing events to cardiac cycle
ecg_segment()
Extract individual heartbeats for morphological analysis.
heartbeats = nk.ecg_segment(ecg_cleaned, rpeaks, sampling_rate=1000)
Returns:
- Dictionary of epochs, each containing one heartbeat
- Centered on R-peak with configurable pre/post windows
- Useful for beat-to-beat morphology comparison
ecg_invert()
Detect and correct inverted ECG signals automatically.
corrected_ecg, is_inverted = nk.ecg_invert(ecg_signal, sampling_rate=1000)
Method:
- Analyzes QRS complex polarity
- Flips signal if predominantly negative
- Returns corrected signal and inversion status
ecg_rsp()
Extract ECG-derived respiration (EDR) as respiratory proxy signal.
edr_signal = nk.ecg_rsp(ecg_cleaned, sampling_rate=1000, method='vangent2019')
Methods:
'vangent2019': Bandpass filtering 0.1-0.4 Hz'charlton2016': Bandpass 0.15-0.4 Hz'soni2019': Bandpass 0.08-0.5 Hz
Use case:
- Estimate respiration when direct respiratory signal unavailable
- Multi-modal physiological analysis
Simulation and Visualization
ecg_simulate()
Generate synthetic ECG signals for testing and validation.
synthetic_ecg = nk.ecg_simulate(duration=10, sampling_rate=1000, heart_rate=70, method='ecgsyn', noise=0.01)
Methods:
'ecgsyn': Realistic dynamical model (McSharry et al., 2003)- Simulates P-QRS-T complex morphology
- Physiologically plausible waveforms
'simple': Faster wavelet-based approximation- Gaussian-like QRS complexes
- Less realistic but computationally efficient
Key parameters:
heart_rate: Average BPM (default: 70)heart_rate_std: Heart rate variability magnitude (default: 1)noise: Gaussian noise level (default: 0.01)random_state: Seed for reproducibility
ecg_plot()
Visualize processed ECG with detected R-peaks and signal quality.
nk.ecg_plot(signals, info)
Displays:
- Raw and cleaned ECG signals
- Detected R-peaks overlaid
- Heart rate trace
- Signal quality indicators
ECG-Specific Considerations
Sampling Rate Recommendations
- Minimum: 250 Hz for basic R-peak detection
- Recommended: 500-1000 Hz for waveform delineation
- High-resolution: 2000+ Hz for detailed morphology analysis
Signal Duration Requirements
- R-peak detection: Any duration (≥2 beats minimum)
- Basic heart rate: ≥10 seconds
- HRV time domain: ≥60 seconds
- HRV frequency domain: 1-5 minutes (optimal)
- Ultra-low frequency HRV: ≥24 hours
Common Issues and Solutions
Poor R-peak detection:
- Try different methods:
method='pantompkins1985'often robust - Ensure adequate sampling rate (≥250 Hz)
- Check for inverted ECG: use
ecg_invert() - Apply artifact correction:
correct_artifacts=True
Noisy signal:
- Use appropriate cleaning method for noise type
- Adjust powerline frequency if outside US/Europe
- Consider signal quality assessment before analysis
Missing waveform components:
- Increase sampling rate (≥500 Hz for delineation)
- Try different delineation methods (
'dwt','peak','cwt') - Verify signal quality with
ecg_quality()
Integration with Other Signals
ECG + RSP: Respiratory Sinus Arrhythmia
# Process both signals
ecg_signals, ecg_info = nk.ecg_process(ecg, sampling_rate=1000)
rsp_signals, rsp_info = nk.rsp_process(rsp, sampling_rate=1000)
# Compute RSA
rsa = nk.hrv_rsa(ecg_info['ECG_R_Peaks'], rsp_signals['RSP_Clean'], sampling_rate=1000)
Multi-modal Integration
# Process multiple signals at once
bio_signals, bio_info = nk.bio_process(
ecg=ecg_signal,
rsp=rsp_signal,
eda=eda_signal,
sampling_rate=1000
)
References
- Pan, J., & Tompkins, W. J. (1985). A real-time QRS detection algorithm. IEEE transactions on biomedical engineering, 32(3), 230-236.
- Hamilton, P. (2002). Open source ECG analysis. Computers in cardiology, 101-104.
- Martinez, J. P., Almeida, R., Olmos, S., Rocha, A. P., & Laguna, P. (2004). A wavelet-based ECG delineator: evaluation on standard databases. IEEE Transactions on biomedical engineering, 51(4), 570-581.
- Lipponen, J. A., & Tarvainen, M. P. (2019). A robust algorithm for heart rate variability time series artefact correction using novel beat classification. Journal of medical engineering & technology, 43(3), 173-181.