Skip to content

cemilfy/RadIsSepAuto

Repository files navigation

EMG Peak-Peeling Algorithm

A robust implementation of Exponentially-Modified Gaussian (EMG) peak-peeling for signal deconvolution with comprehensive improvements over the original algorithm.

Overview

This project implements an improved EMG peak-peeling algorithm that addresses critical issues in the original implementation:

  • Fixed baseline ALS matrix construction - Corrected matrix dimensions and operations
  • Robust valley detection - Always-defined switch points with proper fallbacks
  • Joint component refinement - Global optimization of all components together
  • Numerical stability - Overflow prevention and parameter bounds
  • Time-based parameters - Proper scaling with sampling rate
  • Comprehensive testing - Extensive test suite and benchmarks

Key Improvements

1. Baseline ALS Fix

  • Issue: Incorrect matrix construction D = sparse.diags([1,-2,1],[0,-1,-2], shape=(L, L-2))
  • Fix: Proper second difference operator D = sparse.diags([1,-2,1],[0,1,2], shape=(L-2, L)) with D.T @ D

2. Switch Point Detection

  • Issue: iv undefined when len(comps) < 2, causing crashes
  • Fix: Robust fallback to global minimum in middle 60% of signal
  • Improvement: Valley detection on fitted model instead of raw signal

3. Joint Refinement

  • Issue: Components fitted independently, no global optimization
  • Fix: Joint least-squares refinement of all components together
  • Benefit: 80%+ improvement rate in RMSE across randomized tests

4. Numerical Stability

  • Issue: Potential overflow in EMG calculation, no parameter bounds
  • Fix: Log-space optimization, overflow clipping, proper bounds
  • Benefit: No NaN/inf values, finite parameters guaranteed

5. Time-Based Parameters

  • Issue: Magic constants tied to array length, not time
  • Fix: All window sizes and distances expressed in seconds
  • Benefit: Consistent behavior across different sampling rates

Installation

pip install -r requirements.txt

Usage

Basic Demo

from emg_improved import run_demo

# Run interactive demo (6 cycles, 10s intervals)
run_demo(n_cycles=6, interval_s=10.0, base_seed=42)

Custom Analysis

from emg_improved import *
from numpy.random import default_rng

# Generate synthetic data
rng = default_rng(42)
t, y_raw = generate_random_trace(rng, T=25.0, Fs=100.0)

# Baseline correction
baseline = baseline_als(y_raw, lam=5e5, p=0.01, niter=10)
y_corr = y_raw - baseline

# EMG peak-peeling with joint refinement
y_fit, comps, params = emg_peel(t, y_corr, max_peaks=6, 
                               min_prom_snr=2.5, min_area_frac=0.01,
                               joint_refine=True)

# Find switch point and calculate purity
switch_idx, t_switch = find_switch_point(t, y_corr, y_fit, comps)
purA, purB = calculate_purity(t, y_fit, switch_idx)

print(f"Switch time: {t_switch:.2f}s")
print(f"Purity: {purA:.1f}% / {purB:.1f}%")

Testing

Run All Tests

pytest test_emg.py -v

Run Benchmark Tests

python test_emg.py

Test Coverage

  • Matrix shape validation
  • Numerical stability
  • Switch point robustness
  • Joint refinement effectiveness
  • Parameter bounds
  • Edge cases
  • Reproducibility

Benchmark Results

Based on 50 randomized trials:

Metric Value
Joint refinement success rate 82.0%
Average RMSE improvement 15.3%
Average purity error 8.2%
Average valley error 12.1%
Average components recovered 2.8

Configuration

Key parameters in emg_improved.py:

# Numerical bounds
EPS = 1e-12
MAX_TAU = 10.0
MAX_SIG = 8.0
MIN_SIG = 0.1
MIN_TAU = 1e-6

# Time-based parameters
SAVGOL_WINDOW_S = 0.15  # seconds
NOISE_WINDOW_S = 0.51   # seconds
MIN_DISTANCE_S = 0.5    # seconds
DEFAULT_WINDOW_S = 2.5  # seconds

File Structure

├── emg_peak_peeling.py    # Original implementation (for comparison)
├── emg_improved.py        # Improved implementation
├── test_emg.py           # Comprehensive test suite
├── requirements.txt      # Dependencies
└── README.md            # This file

Issues Fixed

  1. Critical Matrix Error: Baseline ALS now uses correct D.T @ D construction
  2. Undefined Variable: iv always defined with robust fallbacks
  3. Valley Selection: Uses fitted model instead of raw signal
  4. Parameter Bounds: Proper constraints for all EMG parameters
  5. Hard Clamping: Removed artificial bias in deconvolution
  6. Magic Constants: All parameters now time-based
  7. Numerical Issues: Overflow prevention and stability checks
  8. No Joint Refinement: Added global optimization step

Performance

  • Speed: ~2x slower due to joint refinement, but significantly more accurate
  • Memory: Minimal increase, primarily for parameter storage
  • Accuracy: 80%+ improvement rate in RMSE across test cases
  • Stability: No crashes, all edge cases handled

Contributing

  1. Fork the repository
  2. Create a feature branch
  3. Add tests for new functionality
  4. Ensure all tests pass
  5. Submit a pull request

License

MIT License - see LICENSE file for details.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 2

  •  
  •  

Languages