ECG-Kit 1.0

File: <base>/common/BaselineWanderRemovalSplines.m (3,283 bytes)
%% Remove baseline wandering with the median estimation method
% Performs baseline wander removal with cubic splines method. Estimates the
% baseline wander in the PQ silence segment and then substract it from ECG.
%  
%  Sörnmo L, Laguna P. Bioelectrical Signal Processing in Cardiac
%  and Neurological Applications. Elsevier, 2005. ISBN
%  0-12-437552-9. Page 457.
%   
% Example
% 
%   [ ECG BaselineWander ] = BaselineWanderRemovalSplines( ECG, QRS_locations, sampling_rate)
% 
% Arguments:
%   + ECG: signal matrix, with the signals in columns.
%   + QRS_locations: sample location of the QRS complexes.
%   + sampling_rate: sampling rate of the ECG.
% 
% Output:
%   + ECG: clean ECG matrix.
%   + BaselineWander: estimation of the baseline wander signal.
% 
% See also BaselineWanderRemovalMedian
% 
% Author: Mariano Llamedo Soria llamedom@electron.frba.utn.edu.ar
% Version: 0.1 beta
% Birthdate: 01/01/2006
% Last update: 18/10/2014
% Copyright 2008-2015
function [ ECG BaselineWander ] = BaselineWanderRemovalSplines( ECG, QRS_locations, sampling_rate)

[ECG_size ECG_leads] = size(ECG);

QRS_locations = QRS_locations(QRS_locations > round(0.2*sampling_rate) & QRS_locations <= ECG_size );

cant_QRS = length(QRS_locations);

aux_idx = arrayfun(@(a)( QRS_locations(a) - round(0.2*sampling_rate): ...
                         min(ECG_size, QRS_locations(a) - round(0.1*sampling_rate))) , ...
                   1:cant_QRS, 'UniformOutput', false);

PQ_estimations = cell2mat(cellfun(@(a)(mean(ECG(a,:),1)), colvec(aux_idx), 'UniformOutput', false));
PQ_sample = cell2mat(cellfun(@(a)(mean(a)), colvec(aux_idx), 'UniformOutput', false));

% as spline is very memory-inneficient, we resample the PQ guide to ~25 Hz
sampling_rate_low = 25; % Hz
[ interp_k, deci_k ] = rat( sampling_rate_low / sampling_rate );
sampling_ratio = interp_k / deci_k;
ECG_size_decim = floor(ECG_size*sampling_ratio);

PQ_sample = round(PQ_sample * sampling_ratio );

eq_samples = find(diff(PQ_sample) == 0);

PQ_sample(eq_samples) = [];
PQ_estimations(eq_samples,:) = [];

if(PQ_sample(end) == ECG_size_decim)
    PQ_sample = PQ_sample(1:end-1);
    PQ_estimations = PQ_estimations(1:end-1,:);
end
if(PQ_sample(1) == 1)
    PQ_sample = PQ_sample(2:end);
    PQ_estimations = PQ_estimations(2:end,:);
end

% Spline diverges in many cases and could not fix it.
% BaselineWander = spline( [ 1       ; PQ_sample      ; ECG_size_decim  ], ...
%                 [ ECG(1,:); PQ_estimations ; ECG(end,:)]', ...
%                1:ECG_size_decim )';
BaselineWander = interp1(   [ 1       ; PQ_sample      ; ECG_size_decim  ], ... 
                            [ ECG(1,:); PQ_estimations ; ECG(end,:)], ...
                            1:ECG_size_decim, 'pchip' );

[BW_size BW_leads] = size(BaselineWander);
                        
if( BW_leads > BW_size)
    BaselineWander = BaselineWander';
end

% substract the upsampled signal
ECG_size_new = ceil(ECG_size_decim/sampling_ratio);
last_samples = ECG(ECG_size_new,:);
ECG(1:ECG_size_new,:) = ECG(1:ECG_size_new,:) - resample(BaselineWander, deci_k, interp_k);
ECG(ECG_size_new+1:end,:) = bsxfun( @minus, ECG(ECG_size_new+1:end,:), (last_samples - ECG(ECG_size_new,:)));