kasturi rangan raghavan / Mbed 2 deprecated QRS_cpp

Dependencies:   mbed

Committer:
kasturir
Date:
Mon Sep 27 22:51:19 2010 +0000
Revision:
0:906c21fbf97c

        

Who changed what in which revision?

UserRevisionLine numberNew contents of line
kasturir 0:906c21fbf97c 1 #ifndef ECG_THIRD_EPLIMITED_QRSDET2_INL_H_
kasturir 0:906c21fbf97c 2 #define ECG_THIRD_EPLIMITED_QRSDET2_INL_H_
kasturir 0:906c21fbf97c 3 // Modified to OOP class sturcture
kasturir 0:906c21fbf97c 4 // Author: Kasturi Rangan Raghavan
kasturir 0:906c21fbf97c 5 /*****************************************************************************
kasturir 0:906c21fbf97c 6 FILE: qrsdet2.cpp
kasturir 0:906c21fbf97c 7 AUTHOR: Patrick S. Hamilton
kasturir 0:906c21fbf97c 8 REVISED: 7/08/2002
kasturir 0:906c21fbf97c 9 ___________________________________________________________________________
kasturir 0:906c21fbf97c 10
kasturir 0:906c21fbf97c 11 qrsdet2.cpp: A QRS detector.
kasturir 0:906c21fbf97c 12 Copywrite (C) 2002 Patrick S. Hamilton
kasturir 0:906c21fbf97c 13
kasturir 0:906c21fbf97c 14 This file is free software; you can redistribute it and/or modify it under
kasturir 0:906c21fbf97c 15 the terms of the GNU Library General Public License as published by the Free
kasturir 0:906c21fbf97c 16 Software Foundation; either version 2 of the License, or (at your option) any
kasturir 0:906c21fbf97c 17 later version.
kasturir 0:906c21fbf97c 18
kasturir 0:906c21fbf97c 19 This software is distributed in the hope that it will be useful, but WITHOUT ANY
kasturir 0:906c21fbf97c 20 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
kasturir 0:906c21fbf97c 21 PARTICULAR PURPOSE. See the GNU Library General Public License for more
kasturir 0:906c21fbf97c 22 details.
kasturir 0:906c21fbf97c 23
kasturir 0:906c21fbf97c 24 You should have received a copy of the GNU Library General Public License along
kasturir 0:906c21fbf97c 25 with this library; if not, write to the Free Software Foundation, Inc., 59
kasturir 0:906c21fbf97c 26 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
kasturir 0:906c21fbf97c 27
kasturir 0:906c21fbf97c 28 You may contact the author by e-mail (pat@eplimited.edu) or postal mail
kasturir 0:906c21fbf97c 29 (Patrick Hamilton, E.P. Limited, 35 Medford St., Suite 204 Somerville,
kasturir 0:906c21fbf97c 30 MA 02143 USA). For updates to this software, please visit our website
kasturir 0:906c21fbf97c 31 (http://www.eplimited.com).
kasturir 0:906c21fbf97c 32 __________________________________________________________________________
kasturir 0:906c21fbf97c 33
kasturir 0:906c21fbf97c 34 This file contains functions for detecting QRS complexes in an ECG. The
kasturir 0:906c21fbf97c 35 QRS detector requires filter functions in qrsfilt.cpp and parameter
kasturir 0:906c21fbf97c 36 definitions in qrsdet.h. QRSDet is the only function that needs to be
kasturir 0:906c21fbf97c 37 visable outside of these files.
kasturir 0:906c21fbf97c 38
kasturir 0:906c21fbf97c 39 Syntax:
kasturir 0:906c21fbf97c 40 int QRSDet(int ecgSample, int init) ;
kasturir 0:906c21fbf97c 41
kasturir 0:906c21fbf97c 42 Description:
kasturir 0:906c21fbf97c 43 QRSDet() implements a modified version of the QRS detection
kasturir 0:906c21fbf97c 44 algorithm described in:
kasturir 0:906c21fbf97c 45
kasturir 0:906c21fbf97c 46 Hamilton, Tompkins, W. J., "Quantitative investigation of QRS
kasturir 0:906c21fbf97c 47 detection rules using the MIT/BIH arrhythmia database",
kasturir 0:906c21fbf97c 48 IEEE Trans. Biomed. Eng., BME-33, pp. 1158-1165, 1987.
kasturir 0:906c21fbf97c 49
kasturir 0:906c21fbf97c 50 Consecutive ECG samples are passed to QRSDet. QRSDet was
kasturir 0:906c21fbf97c 51 designed for a 200 Hz sample rate. QRSDet contains a number
kasturir 0:906c21fbf97c 52 of static variables that it uses to adapt to different ECG
kasturir 0:906c21fbf97c 53 signals. These variables can be reset by passing any value
kasturir 0:906c21fbf97c 54 not equal to 0 in init.
kasturir 0:906c21fbf97c 55
kasturir 0:906c21fbf97c 56 Note: QRSDet() requires filters in QRSFilt.cpp
kasturir 0:906c21fbf97c 57
kasturir 0:906c21fbf97c 58 Returns:
kasturir 0:906c21fbf97c 59 When a QRS complex is detected QRSDet returns the detection delay.
kasturir 0:906c21fbf97c 60
kasturir 0:906c21fbf97c 61 ****************************************************************/
kasturir 0:906c21fbf97c 62
kasturir 0:906c21fbf97c 63 /* For memmove. */
kasturir 0:906c21fbf97c 64 #ifdef __STDC__
kasturir 0:906c21fbf97c 65 #include <string.h>
kasturir 0:906c21fbf97c 66 #else
kasturir 0:906c21fbf97c 67 #include <mem.h>
kasturir 0:906c21fbf97c 68 #endif
kasturir 0:906c21fbf97c 69
kasturir 0:906c21fbf97c 70 #include "qrsfilt-inl.h"
kasturir 0:906c21fbf97c 71
kasturir 0:906c21fbf97c 72
kasturir 0:906c21fbf97c 73 namespace qrsdet {
kasturir 0:906c21fbf97c 74
kasturir 0:906c21fbf97c 75 int mean(int *array, int datnum);
kasturir 0:906c21fbf97c 76
kasturir 0:906c21fbf97c 77 int detection_thresh(int qmean, int nmean);
kasturir 0:906c21fbf97c 78
kasturir 0:906c21fbf97c 79
kasturir 0:906c21fbf97c 80 // TODO(krr) : Where to put this?
kasturir 0:906c21fbf97c 81 const int MEMMOVELEN = 7*sizeof(int);
kasturir 0:906c21fbf97c 82
kasturir 0:906c21fbf97c 83
kasturir 0:906c21fbf97c 84 class QRSDet2 {
kasturir 0:906c21fbf97c 85 public:
kasturir 0:906c21fbf97c 86 QRSDet2(const QRSFilterParams& params)
kasturir 0:906c21fbf97c 87 : qrs_filter(params),
kasturir 0:906c21fbf97c 88 peak_detector(params),
kasturir 0:906c21fbf97c 89 first_derivative_filter(params.get_d_length()),
kasturir 0:906c21fbf97c 90 bls_check_buffer(params) {
kasturir 0:906c21fbf97c 91 rsetCount = 0;
kasturir 0:906c21fbf97c 92 sbcount = params.get_ms(1500);
kasturir 0:906c21fbf97c 93 ms_preblank_ = params.get_ms(200);
kasturir 0:906c21fbf97c 94 ms_360_ = params.get_ms(360);
kasturir 0:906c21fbf97c 95 ms_1000_ = params.get_ms(1000);
kasturir 0:906c21fbf97c 96 ms_1650_ = params.get_ms(1650);
kasturir 0:906c21fbf97c 97 ms_window_length_ = params.get_window_length();
kasturir 0:906c21fbf97c 98 ms_filter_delay_ = params.get_filter_delay();
kasturir 0:906c21fbf97c 99
kasturir 0:906c21fbf97c 100 for (int i = 0; i < 8; i++) {
kasturir 0:906c21fbf97c 101 noise[i] = 0; /* Initialize noise buffer */
kasturir 0:906c21fbf97c 102 rrbuf[i] = ms_1000_;/* and R-to-R interval buffer. */
kasturir 0:906c21fbf97c 103 }
kasturir 0:906c21fbf97c 104 qpkcnt = maxder = lastmax = count = sbpeak = 0 ;
kasturir 0:906c21fbf97c 105 initBlank = initMax = preBlankCnt = 0 ;
kasturir 0:906c21fbf97c 106 }
kasturir 0:906c21fbf97c 107
kasturir 0:906c21fbf97c 108 int Process(int datum) {
kasturir 0:906c21fbf97c 109 int fdatum, QrsDelay = 0;
kasturir 0:906c21fbf97c 110 int newPeak, aPeak;
kasturir 0:906c21fbf97c 111 fdatum = qrs_filter.Process(datum);
kasturir 0:906c21fbf97c 112 /* Wait until normal detector is ready before calling early detections. */
kasturir 0:906c21fbf97c 113 aPeak = peak_detector.Process(fdatum);
kasturir 0:906c21fbf97c 114 if (aPeak < QRSDet2::MIN_PEAK_AMP)
kasturir 0:906c21fbf97c 115 aPeak = 0;
kasturir 0:906c21fbf97c 116
kasturir 0:906c21fbf97c 117 // Hold any peak that is detected for 200 ms
kasturir 0:906c21fbf97c 118 // in case a bigger one comes along. There
kasturir 0:906c21fbf97c 119 // can only be one QRS complex in any 200 ms window.
kasturir 0:906c21fbf97c 120
kasturir 0:906c21fbf97c 121 newPeak = 0;
kasturir 0:906c21fbf97c 122 if (aPeak && !preBlankCnt) {
kasturir 0:906c21fbf97c 123 // If there has been no peak for 200 ms
kasturir 0:906c21fbf97c 124 // save this one and start counting.
kasturir 0:906c21fbf97c 125 tempPeak = aPeak;
kasturir 0:906c21fbf97c 126 preBlankCnt = ms_preblank_;
kasturir 0:906c21fbf97c 127 } else if (!aPeak && preBlankCnt) {
kasturir 0:906c21fbf97c 128 // If we have held onto a peak for
kasturir 0:906c21fbf97c 129 // 200 ms pass it on for evaluation.
kasturir 0:906c21fbf97c 130 if (--preBlankCnt == 0)
kasturir 0:906c21fbf97c 131 newPeak = tempPeak ;
kasturir 0:906c21fbf97c 132 } else if (aPeak) {
kasturir 0:906c21fbf97c 133 // If we were holding a peak, but
kasturir 0:906c21fbf97c 134 // this ones bigger, save it and
kasturir 0:906c21fbf97c 135 if (aPeak > tempPeak) {
kasturir 0:906c21fbf97c 136 // start counting to 200 ms again.
kasturir 0:906c21fbf97c 137 tempPeak = aPeak ;
kasturir 0:906c21fbf97c 138 preBlankCnt = ms_preblank_;
kasturir 0:906c21fbf97c 139 } else if (--preBlankCnt == 0) {
kasturir 0:906c21fbf97c 140 newPeak = tempPeak ;
kasturir 0:906c21fbf97c 141 }
kasturir 0:906c21fbf97c 142 }
kasturir 0:906c21fbf97c 143
kasturir 0:906c21fbf97c 144 // Save derivative of raw signal for T-wave and baseline
kasturir 0:906c21fbf97c 145 // shift discrimination.
kasturir 0:906c21fbf97c 146 int deriv_datum = first_derivative_filter.Process(datum);
kasturir 0:906c21fbf97c 147 bls_check_buffer.Process(deriv_datum);
kasturir 0:906c21fbf97c 148
kasturir 0:906c21fbf97c 149 // Initialize the qrs peak buffer with the first eight
kasturir 0:906c21fbf97c 150 // local maximum peaks detected.
kasturir 0:906c21fbf97c 151 if (qpkcnt < 8) {
kasturir 0:906c21fbf97c 152 ++count;
kasturir 0:906c21fbf97c 153 if (newPeak > 0)
kasturir 0:906c21fbf97c 154 count = ms_window_length_;
kasturir 0:906c21fbf97c 155 if (++initBlank == ms_1000_) {
kasturir 0:906c21fbf97c 156 initBlank = 0;
kasturir 0:906c21fbf97c 157 qrsbuf[qpkcnt] = initMax;
kasturir 0:906c21fbf97c 158 initMax = 0;
kasturir 0:906c21fbf97c 159 ++qpkcnt;
kasturir 0:906c21fbf97c 160 if (qpkcnt == 8) {
kasturir 0:906c21fbf97c 161 qmean = mean(qrsbuf, 8) ;
kasturir 0:906c21fbf97c 162 nmean = 0 ;
kasturir 0:906c21fbf97c 163 rrmean = ms_1000_ ;
kasturir 0:906c21fbf97c 164 sbcount = ms_1650_ ;
kasturir 0:906c21fbf97c 165 det_thresh = detection_thresh(qmean,nmean) ;
kasturir 0:906c21fbf97c 166 }
kasturir 0:906c21fbf97c 167 }
kasturir 0:906c21fbf97c 168 if (newPeak > initMax)
kasturir 0:906c21fbf97c 169 initMax = newPeak ;
kasturir 0:906c21fbf97c 170 }
kasturir 0:906c21fbf97c 171
kasturir 0:906c21fbf97c 172 else /* Else test for a qrs. */
kasturir 0:906c21fbf97c 173 {
kasturir 0:906c21fbf97c 174 ++count ;
kasturir 0:906c21fbf97c 175 if(newPeak > 0)
kasturir 0:906c21fbf97c 176 {
kasturir 0:906c21fbf97c 177
kasturir 0:906c21fbf97c 178
kasturir 0:906c21fbf97c 179 /* Check for maximum derivative and matching minima and maxima
kasturir 0:906c21fbf97c 180 for T-wave and baseline shift rejection. Only consider this
kasturir 0:906c21fbf97c 181 peak if it doesn't seem to be a base line shift. */
kasturir 0:906c21fbf97c 182
kasturir 0:906c21fbf97c 183 if(!bls_check_buffer.BLSCheck(&maxder))
kasturir 0:906c21fbf97c 184 {
kasturir 0:906c21fbf97c 185
kasturir 0:906c21fbf97c 186
kasturir 0:906c21fbf97c 187 // Classify the beat as a QRS complex
kasturir 0:906c21fbf97c 188 // if the peak is larger than the detection threshold.
kasturir 0:906c21fbf97c 189
kasturir 0:906c21fbf97c 190 if(newPeak > det_thresh)
kasturir 0:906c21fbf97c 191 {
kasturir 0:906c21fbf97c 192 memmove(&qrsbuf[1], qrsbuf, MEMMOVELEN) ;
kasturir 0:906c21fbf97c 193 qrsbuf[0] = newPeak ;
kasturir 0:906c21fbf97c 194 qmean = mean(qrsbuf,8) ;
kasturir 0:906c21fbf97c 195 det_thresh = detection_thresh(qmean,nmean) ;
kasturir 0:906c21fbf97c 196 memmove(&rrbuf[1], rrbuf, MEMMOVELEN) ;
kasturir 0:906c21fbf97c 197 rrbuf[0] = count - ms_window_length_ ;
kasturir 0:906c21fbf97c 198 rrmean = mean(rrbuf,8) ;
kasturir 0:906c21fbf97c 199 sbcount = rrmean + (rrmean >> 1) + ms_window_length_ ;
kasturir 0:906c21fbf97c 200 count = ms_window_length_ ;
kasturir 0:906c21fbf97c 201
kasturir 0:906c21fbf97c 202 sbpeak = 0 ;
kasturir 0:906c21fbf97c 203
kasturir 0:906c21fbf97c 204 lastmax = maxder ;
kasturir 0:906c21fbf97c 205 maxder = 0 ;
kasturir 0:906c21fbf97c 206 QrsDelay = ms_window_length_ + ms_filter_delay_ ;
kasturir 0:906c21fbf97c 207 initBlank = initMax = rsetCount = 0 ;
kasturir 0:906c21fbf97c 208 }
kasturir 0:906c21fbf97c 209
kasturir 0:906c21fbf97c 210 // If a peak isn't a QRS update noise buffer and estimate.
kasturir 0:906c21fbf97c 211 // Store the peak for possible search back.
kasturir 0:906c21fbf97c 212
kasturir 0:906c21fbf97c 213
kasturir 0:906c21fbf97c 214 else
kasturir 0:906c21fbf97c 215 {
kasturir 0:906c21fbf97c 216 memmove(&noise[1],noise,MEMMOVELEN) ;
kasturir 0:906c21fbf97c 217 noise[0] = newPeak ;
kasturir 0:906c21fbf97c 218 nmean = mean(noise,8) ;
kasturir 0:906c21fbf97c 219 det_thresh = detection_thresh(qmean,nmean) ;
kasturir 0:906c21fbf97c 220
kasturir 0:906c21fbf97c 221 // Don't include early peaks (which might be T-waves)
kasturir 0:906c21fbf97c 222 // in the search back process. A T-wave can mask
kasturir 0:906c21fbf97c 223 // a small following QRS.
kasturir 0:906c21fbf97c 224
kasturir 0:906c21fbf97c 225 if((newPeak > sbpeak) && ((count-ms_window_length_) >= ms_360_))
kasturir 0:906c21fbf97c 226 {
kasturir 0:906c21fbf97c 227 sbpeak = newPeak ;
kasturir 0:906c21fbf97c 228 sbloc = count - ms_window_length_ ;
kasturir 0:906c21fbf97c 229 }
kasturir 0:906c21fbf97c 230 }
kasturir 0:906c21fbf97c 231 }
kasturir 0:906c21fbf97c 232 }
kasturir 0:906c21fbf97c 233
kasturir 0:906c21fbf97c 234 /* Test for search back condition. If a QRS is found in */
kasturir 0:906c21fbf97c 235 /* search back update the QRS buffer and det_thresh. */
kasturir 0:906c21fbf97c 236
kasturir 0:906c21fbf97c 237 if((count > sbcount) && (sbpeak > (det_thresh >> 1)))
kasturir 0:906c21fbf97c 238 {
kasturir 0:906c21fbf97c 239 memmove(&qrsbuf[1],qrsbuf,MEMMOVELEN) ;
kasturir 0:906c21fbf97c 240 qrsbuf[0] = sbpeak ;
kasturir 0:906c21fbf97c 241 qmean = mean(qrsbuf,8) ;
kasturir 0:906c21fbf97c 242 det_thresh = detection_thresh(qmean,nmean) ;
kasturir 0:906c21fbf97c 243 memmove(&rrbuf[1],rrbuf,MEMMOVELEN) ;
kasturir 0:906c21fbf97c 244 rrbuf[0] = sbloc ;
kasturir 0:906c21fbf97c 245 rrmean = mean(rrbuf,8) ;
kasturir 0:906c21fbf97c 246 sbcount = rrmean + (rrmean >> 1) + ms_window_length_ ;
kasturir 0:906c21fbf97c 247 QrsDelay = count = count - sbloc ;
kasturir 0:906c21fbf97c 248 QrsDelay += ms_filter_delay_;
kasturir 0:906c21fbf97c 249 sbpeak = 0 ;
kasturir 0:906c21fbf97c 250 lastmax = maxder ;
kasturir 0:906c21fbf97c 251 maxder = 0 ;
kasturir 0:906c21fbf97c 252
kasturir 0:906c21fbf97c 253 initBlank = initMax = rsetCount = 0 ;
kasturir 0:906c21fbf97c 254 }
kasturir 0:906c21fbf97c 255 }
kasturir 0:906c21fbf97c 256
kasturir 0:906c21fbf97c 257 // In the background estimate threshold to replace adaptive threshold
kasturir 0:906c21fbf97c 258 // if eight seconds elapses without a QRS detection.
kasturir 0:906c21fbf97c 259
kasturir 0:906c21fbf97c 260 if( qpkcnt == 8 )
kasturir 0:906c21fbf97c 261 {
kasturir 0:906c21fbf97c 262 if(++initBlank == ms_1000_)
kasturir 0:906c21fbf97c 263 {
kasturir 0:906c21fbf97c 264 initBlank = 0 ;
kasturir 0:906c21fbf97c 265 rsetBuff[rsetCount] = initMax ;
kasturir 0:906c21fbf97c 266 initMax = 0 ;
kasturir 0:906c21fbf97c 267 ++rsetCount ;
kasturir 0:906c21fbf97c 268
kasturir 0:906c21fbf97c 269 // Reset threshold if it has been 8 seconds without
kasturir 0:906c21fbf97c 270 // a detection.
kasturir 0:906c21fbf97c 271
kasturir 0:906c21fbf97c 272 if(rsetCount == 8)
kasturir 0:906c21fbf97c 273 {
kasturir 0:906c21fbf97c 274 for(int i = 0; i < 8; ++i)
kasturir 0:906c21fbf97c 275 {
kasturir 0:906c21fbf97c 276 qrsbuf[i] = rsetBuff[i] ;
kasturir 0:906c21fbf97c 277 noise[i] = 0 ;
kasturir 0:906c21fbf97c 278 }
kasturir 0:906c21fbf97c 279 qmean = mean( rsetBuff, 8 ) ;
kasturir 0:906c21fbf97c 280 nmean = 0 ;
kasturir 0:906c21fbf97c 281 rrmean = ms_1000_;
kasturir 0:906c21fbf97c 282 sbcount = ms_1650_;
kasturir 0:906c21fbf97c 283 det_thresh = detection_thresh(qmean,nmean) ;
kasturir 0:906c21fbf97c 284 initBlank = initMax = rsetCount = 0 ;
kasturir 0:906c21fbf97c 285 }
kasturir 0:906c21fbf97c 286 }
kasturir 0:906c21fbf97c 287 if( newPeak > initMax )
kasturir 0:906c21fbf97c 288 initMax = newPeak ;
kasturir 0:906c21fbf97c 289 }
kasturir 0:906c21fbf97c 290
kasturir 0:906c21fbf97c 291 return(QrsDelay);
kasturir 0:906c21fbf97c 292 }
kasturir 0:906c21fbf97c 293 private:
kasturir 0:906c21fbf97c 294 int det_thresh, qpkcnt;
kasturir 0:906c21fbf97c 295 int qrsbuf[8], noise[8], rrbuf[8];
kasturir 0:906c21fbf97c 296 int rsetBuff[8], rsetCount;
kasturir 0:906c21fbf97c 297 int nmean, qmean, rrmean;
kasturir 0:906c21fbf97c 298 int count, sbpeak, sbloc, sbcount;
kasturir 0:906c21fbf97c 299 int maxder, lastmax;
kasturir 0:906c21fbf97c 300 int initBlank, initMax;
kasturir 0:906c21fbf97c 301 int preBlankCnt, tempPeak;
kasturir 0:906c21fbf97c 302 QRSFilter qrs_filter;
kasturir 0:906c21fbf97c 303 PeakDetector peak_detector;
kasturir 0:906c21fbf97c 304 DerivFilter first_derivative_filter;
kasturir 0:906c21fbf97c 305 BLSCheckBuffer bls_check_buffer;
kasturir 0:906c21fbf97c 306 size_t ms_preblank_;
kasturir 0:906c21fbf97c 307 size_t ms_360_;
kasturir 0:906c21fbf97c 308 size_t ms_1000_;
kasturir 0:906c21fbf97c 309 size_t ms_1650_;
kasturir 0:906c21fbf97c 310 size_t ms_window_length_;
kasturir 0:906c21fbf97c 311 size_t ms_filter_delay_;
kasturir 0:906c21fbf97c 312
kasturir 0:906c21fbf97c 313 // Prevents detections of peaks smaller than 150 uV.
kasturir 0:906c21fbf97c 314 static const int MIN_PEAK_AMP = 7;
kasturir 0:906c21fbf97c 315 };
kasturir 0:906c21fbf97c 316
kasturir 0:906c21fbf97c 317
kasturir 0:906c21fbf97c 318 } // namespace qrsdet
kasturir 0:906c21fbf97c 319
kasturir 0:906c21fbf97c 320 #endif // ECG_THIRD_EPLIMITED_QRSDET2_INL_H_