demo_simulated_ECG: signal denoising using SASS
Ivan Selesnick selesi@nyu.edu 2013, revised 2016, 2017
Contents
Start
clear compute_rmse = @(err) sqrt(mean(abs(err(:)).^2));
Load data
% load simulated ECG s = load('data/simulated_ecg.txt'); % load simulated ECG plus noise y = load('data/simulated_ecg_noisy.txt'); sigma = 0.2; N = length(s); n = 0:N-1;
Display ECG signals
ax = [0 N -0.5 1.5]; figure(1) clf subplot(2, 1, 1) plot(n, s) title('Simulated ECG') axis(ax) subplot(2, 1, 2) plot(n, y) title('Noisy ECG'); axis(ax)
Parameters
% Filter parameters: % d : filter order parameter (the filter is of order 2d) % fc : cut-off frequency (0 < fc < 0.5) (cycles/sample) % SASS parameters % K : order of sparse derivative % lam : regularization parameter % Uncomment one of the following lines to select parameter values % PARAMVALS = 1; PARAMVALS = 2; switch PARAMVALS case 1 % low-pass filter parameters d = 1; % 2nd order filter fc = 0.03; % SASS parameters K = 2; lam = 1.3; case 2 % low-pass filter parameters d = 2; % 4th order filter fc = 0.03; % SASS parameters K = 2; lam = 1.52; end
SASS - run algorithm
[x, u] = sass_L1(y, d, fc, K, lam); % x : denoised signal % u : sparse order-K derivative RMSE = compute_rmse(s - x);
0 incorrectly locked zeros detected.
SASS - plot denoised signal
txt = sprintf('SASS (d = %d, fc = %.3f, K = %d, lam = %.2f), RMSE = %.3f', d, fc, K, lam, RMSE); figure(1) clf subplot(3, 1, 1) plot(n, y) title('Noisy ECG'); axis(ax) subplot(3, 1, 2) plot(n, x) title(txt) axis(ax) subplot(3, 1, 3) plot(u) xlim([0 N]) title('Sparse component') orient tall print('-dpdf', sprintf('figures/demo_simulated_ECG_%d', PARAMVALS))
Compare to low-pass filter
[A, B, B1] = ABfilt(d, fc, N, K); % Filter matrices (banded) H = @(x) A\(B*x); % H: high-pass filter L = @(x) x - H(x); % L: low-pass filter x_lpf = L(y); RMSE_lpf = compute_rmse(s - x_lpf); txt_lpf = sprintf('Low-pass filter, RMSE = %.3f', RMSE_lpf); figure(1) clf subplot(2, 1, 1) plot(n, x) title(txt) axis(ax) subplot(2, 1, 2) plot(n, x_lpf) title(txt_lpf) axis(ax) orient portrait print('-dpdf', sprintf('figures/demo_simulated_ECG_LPF_%d', PARAMVALS))
The low-pass filter recovers a low-pass signal (f) but significantly distorts the piecewise linear signal (g). Adjusting the low-pass filter helps to set the cuf-off frequency, fc. The cut-off frequency should be chosen so the low-pass filter preserves the low-frequency content of the signal.
SASS - optimality scatter plot
Verify the solution satisfies the optimality condition
[A, B, B1] = ABfilt(d, fc, N, K); % Filter matrices (banded) r = B1' * ((A*A')\(B*y-B1*u)) / lam; M = 1.2 * max(abs(u)); figure(1) clf plot([-M 0 0 M], [-1 -1 1 1], u, r, 'o') title('Verification of SASS optimality') axis([-M M -1.5 1.5]) orient portrait print -dpdf figures/demo_simulated_ECG_optimality_plot