PhysioNet Cardiovascular Signal Toolbox 1.0.0
(8,914 bytes)
function out = run_sqrs(ecg,HRVparams,rs)
%out = run_sqrs(ecg,s,rs)
% OVERVIEW:
% QRS onset detector
% INPUT:
% ecg = single channel of ECG in digital values
% s = settings struct
% rs = resampling option; 1 = resample original signal, 0 = don't
% OUTPUT:
% out = sample points of onset of each QRS complex
% DEPENDENCIES & LIBRARIES:
% REFERENCE:
% REPO:
% https://github.com/cliffordlab/hrv_toolbox
% ORIGINAL SOURCE AND AUTHORS:
% Converted from sqrs.c at:
% http://www.physionet.org/physiotools/wfdb/app/sqrs.c
% to sqrs.m (Matlab) by J. Perry, July 2006
% sqrs.c (C) by G.B. Moody 27 October 1990
%
% Last revised by John: 25 February 2006
% Last revised by Gari: 07 February 2007
%
% 03-06-2017
% Edited by Adriana Vest
% Now requires settings struct HRVparams, which defines debug mode and
% sampling frequency, and resampling option rs.
% LICENSE AND COPYRIGHT:
% See Below
%
% if debug>0, then plot final data (default; debug=0)
%
% This algorithm is sensitive to high frequency noise, so you
% might want to use an FIR band-pass filter first.
%
% Avaialble under the GPL (see below)
%-------------------------------------------------------------------------------
% sqrs: Single-channel QRS detector
% Copyright (C) 1990-2006 George B. Moody
%
% This program is free software; you can redistribute it and/or
% modify it under the terms of the GNU General Public License as
% published by the Free Software Foundation; either version 2 of the
% License, or (at your option) any later version.
%
% This program is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
% General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with this program; if not, write to the Free Software
% Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
% 02111-1307, USA.
%
% You may contact the author by e-mail (george@mit.edu) or postal
% mail (MIT Room E25-505A, Cambridge, MA 02139 USA). For updates to
% this software, please visit PhysioNet (http://www.physionet.org/).
% _________________________________________________________________
%
% The detector algorithm is based on example 10 in the WFDB
% Programmer's Guide, which in turn is based on a Pascal program
% written by W.A.H. Engelse and C. Zeelenberg, "A single scan
% algorithm for QRS-detection and feature extraction", Computers in
% Cardiology 6:37-42 (1979). `sqrs' does not include the feature
% extraction capability of the Pascal program. The output of `sqrs'
% is an annotation file (with annotator name `qrs') in which all
% detected beats are labelled normal; the annotation file may also
% contain `artifact' annotations at locations which `sqrs' believes
% are noise-corrupted.
%
% 'sqrs' has been optimized for adult human ECGs. For other ECGs,
% it may be necessary to experiment with the input sampling
% frequency and the time constants indicated below.
%
% This program is provided as an example only, and is not intended
% for any clinical application. At the time the algorithm was
% originally published, its performance was typical of
% state-of-the-art QRS detectors. Recent designs, particularly
% those that can analyze two or more input signals, may exhibit
% significantly better performance.
%%
if nargin<2
error('Incorrect number of input arguments: must provide ECG signal and HRV paramters struct')
end
if nargin < 3
rs = 1;
end
%debug = s.debug;
debug = 0;
fs = HRVparams.Fs;
if ~rs
%% 1. Use Fs of Input
time = 0;
now = 10;
%freq = 256;
freq = fs;
ms160 = ceil(0.16*freq);
ms200 = ceil(0.2*freq);
s2 = ceil(2*freq);
scmin = 500;
% number of ADC units corresponding to scmin microvolts
% scmin = muvadu(signal, scmin);
scmax = 10 * scmin;
slopecrit = 10 * scmin;
maxslope = 0;
nslope = 0;
out = [];
while (now < length(ecg)) % && (to == 0)
filter = [1 4 6 4 1 -1 -4 -6 -4 -1] * ecg((now-9):now);
if (mod(time, s2) == 0)
% Adjust slope
if (nslope == 0)
slopecrit = max(slopecrit - slopecrit/16, scmin);
elseif (nslope >= 5)
slopecrit = min(slopecrit + slopecrit/16, scmax);
end
end
if (nslope == 0 && abs(filter) > slopecrit)
nslope = nslope + 1;
maxtime = ms160;
if (filter > 0)
sign = 1;
else
sign = -1;
end
qtime = time;
end
if (nslope ~= 0)
if (filter * sign < -slopecrit)
sign = -sign;
nslope = nslope + 1;
if (nslope > 4)
maxtime = ms200;
else
maxtime = ms160;
end
elseif (filter * sign > slopecrit && abs(filter) > maxslope)
maxslope = abs(filter);
end
if (maxtime < 0)
if (2 <= nslope && nslope <= 4)
slopecrit = slopecrit + ((maxslope/4) - slopecrit)/8;
if (slopecrit < scmin)
slopecrit = scmin;
elseif (slopecrit > scmax)
slopecrit = scmax;
end
out = [out; now - (time - qtime) - 4];
%annot.anntyp = NORMAL;
time = 0;
elseif (nslope >= 5)
out = [out; now - (time - qtime) - 4];
%annot.anntyp = ARFCT;
end
nslope = 0;
end
maxtime = maxtime - 1;
end
time = time + 1;
now = now + 1;
end
out=out-1; % adjust for 1 sample offset problem.
if debug > 0
plot(ecg,'b');
hold on;
plot(out,ecg(out),'m*');
end
elseif rs
%% 2. Resample at 256 Hz
% These time constants may need adjustment for pediatric or
% small mammal ECGs.
ecg_rs = resample(ecg,256,fs);
time = 0;
now = 10;
freq = 256;
ms160 = ceil(0.16*freq);
ms200 = ceil(0.2*freq);
s2 = ceil(2*freq);
%scmin = 500;
% ANV changed this to work with real units
scmin = 500;
% number of ADC units corresponding to scmin microvolts
% scmin = muvadu(ecg_rs, scmin);
scmax = 10 * scmin;
slopecrit = 10 * scmin;
maxslope = 0;
nslope = 0;
out = [];
while (now < length(ecg_rs)) % && (to == 0)
filter = [1 4 6 4 1 -1 -4 -6 -4 -1] * ecg_rs((now-9):now);
if (mod(time, s2) == 0)
% Adjust slope
if (nslope == 0)
slopecrit = max(slopecrit - slopecrit/16, scmin);
elseif (nslope >= 5)
slopecrit = min(slopecrit + slopecrit/16, scmax);
end
end
if (nslope == 0 && abs(filter) > slopecrit)
nslope = nslope + 1;
maxtime = ms160;
if (filter > 0)
sign = 1;
else
sign = -1;
end
qtime = time;
end
if (nslope ~= 0)
if (filter * sign < -slopecrit)
sign = -sign;
nslope = nslope + 1;
if (nslope > 4)
maxtime = ms200;
else
maxtime = ms160;
end
elseif (filter * sign > slopecrit && abs(filter) > maxslope)
maxslope = abs(filter);
end
if (maxtime < 0)
if (2 <= nslope && nslope <= 4)
slopecrit = slopecrit + ((maxslope/4) - slopecrit)/8;
if (slopecrit < scmin)
slopecrit = scmin;
elseif (slopecrit > scmax)
slopecrit = scmax;
end
out = [out; now - (time - qtime) - 4];
%annot.anntyp = NORMAL;
time = 0;
elseif (nslope >= 5)
out = [out; now - (time - qtime) - 4];
%annot.anntyp = ARFCT;
end
nslope = 0;
end
maxtime = maxtime - 1;
end
time = time + 1;
now = now + 1;
end
out=out-1; % adjust for 1 sample offset problem.
if debug > 0
plot(ecg_rs,'b');
hold on;
plot(out,ecg_rs(out),'m*');
end
end