I've got some basic filter code setup (but not yet tested).

Dependencies:   BLE_API Queue mbed nRF51822

Fork of BLE_HeartRate by Bluetooth Low Energy

Committer:
roysandberg
Date:
Sun Jun 28 03:06:00 2015 +0000
Revision:
62:8e2fbe131b53
Working Beat Detection and Analysis

Who changed what in which revision?

UserRevisionLine numberNew contents of line
roysandberg 62:8e2fbe131b53 1 /*****************************************************************************
roysandberg 62:8e2fbe131b53 2 FILE: qrsdet.cpp
roysandberg 62:8e2fbe131b53 3 AUTHOR: Patrick S. Hamilton
roysandberg 62:8e2fbe131b53 4 REVISED: 12/04/2000
roysandberg 62:8e2fbe131b53 5 ___________________________________________________________________________
roysandberg 62:8e2fbe131b53 6
roysandberg 62:8e2fbe131b53 7 qrsdet.cpp: A QRS detector.
roysandberg 62:8e2fbe131b53 8 Copywrite (C) 2000 Patrick S. Hamilton
roysandberg 62:8e2fbe131b53 9
roysandberg 62:8e2fbe131b53 10 This file is free software; you can redistribute it and/or modify it under
roysandberg 62:8e2fbe131b53 11 the terms of the GNU Library General Public License as published by the Free
roysandberg 62:8e2fbe131b53 12 Software Foundation; either version 2 of the License, or (at your option) any
roysandberg 62:8e2fbe131b53 13 later version.
roysandberg 62:8e2fbe131b53 14
roysandberg 62:8e2fbe131b53 15 This software is distributed in the hope that it will be useful, but WITHOUT ANY
roysandberg 62:8e2fbe131b53 16 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
roysandberg 62:8e2fbe131b53 17 PARTICULAR PURPOSE. See the GNU Library General Public License for more
roysandberg 62:8e2fbe131b53 18 details.
roysandberg 62:8e2fbe131b53 19
roysandberg 62:8e2fbe131b53 20 You should have received a copy of the GNU Library General Public License along
roysandberg 62:8e2fbe131b53 21 with this library; if not, write to the Free Software Foundation, Inc., 59
roysandberg 62:8e2fbe131b53 22 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
roysandberg 62:8e2fbe131b53 23
roysandberg 62:8e2fbe131b53 24 You may contact the author by e-mail (pat@eplimited.edu) or postal mail
roysandberg 62:8e2fbe131b53 25 (Patrick Hamilton, E.P. Limited, 35 Medford St., Suite 204 Somerville,
roysandberg 62:8e2fbe131b53 26 MA 02143 USA). For updates to this software, please visit our website
roysandberg 62:8e2fbe131b53 27 (http://www.eplimited.com).
roysandberg 62:8e2fbe131b53 28 __________________________________________________________________________
roysandberg 62:8e2fbe131b53 29
roysandberg 62:8e2fbe131b53 30 This file contains functions for detecting QRS complexes in an ECG. The
roysandberg 62:8e2fbe131b53 31 QRS detector requires filter functions in qrsfilt.cpp and parameter
roysandberg 62:8e2fbe131b53 32 definitions in qrsdet.h. QRSDet is the only function that needs to be
roysandberg 62:8e2fbe131b53 33 visable outside of these files.
roysandberg 62:8e2fbe131b53 34
roysandberg 62:8e2fbe131b53 35 Syntax:
roysandberg 62:8e2fbe131b53 36 int QRSDet(int ecgSample, int init) ;
roysandberg 62:8e2fbe131b53 37
roysandberg 62:8e2fbe131b53 38 Description:
roysandberg 62:8e2fbe131b53 39 QRSDet() implements a modified version of the QRS detection
roysandberg 62:8e2fbe131b53 40 algorithm described in:
roysandberg 62:8e2fbe131b53 41
roysandberg 62:8e2fbe131b53 42 Hamilton, Tompkins, W. J., "Quantitative investigation of QRS
roysandberg 62:8e2fbe131b53 43 detection rules using the MIT/BIH arrhythmia database",
roysandberg 62:8e2fbe131b53 44 IEEE Trans. Biomed. Eng., BME-33, pp. 1158-1165, 1987.
roysandberg 62:8e2fbe131b53 45
roysandberg 62:8e2fbe131b53 46 Consecutive ECG samples are passed to QRSDet. QRSDet was
roysandberg 62:8e2fbe131b53 47 designed for a 200 Hz sample rate. QRSDet contains a number
roysandberg 62:8e2fbe131b53 48 of static variables that it uses to adapt to different ECG
roysandberg 62:8e2fbe131b53 49 signals. These variables can be reset by passing any value
roysandberg 62:8e2fbe131b53 50 not equal to 0 in init.
roysandberg 62:8e2fbe131b53 51
roysandberg 62:8e2fbe131b53 52 Note: QRSDet() requires filters in QRSFilt.cpp
roysandberg 62:8e2fbe131b53 53
roysandberg 62:8e2fbe131b53 54 Returns:
roysandberg 62:8e2fbe131b53 55 When a QRS complex is detected QRSDet returns the detection delay.
roysandberg 62:8e2fbe131b53 56
roysandberg 62:8e2fbe131b53 57 ****************************************************************/
roysandberg 62:8e2fbe131b53 58
roysandberg 62:8e2fbe131b53 59 #include <mbed.h>
roysandberg 62:8e2fbe131b53 60 //#include <mem.h> /* For memmov. */
roysandberg 62:8e2fbe131b53 61 //#include <math.h>
roysandberg 62:8e2fbe131b53 62 #include "qrsdet.h"
roysandberg 62:8e2fbe131b53 63 #define PRE_BLANK MS200
roysandberg 62:8e2fbe131b53 64
roysandberg 62:8e2fbe131b53 65 // External Prototypes.
roysandberg 62:8e2fbe131b53 66
roysandberg 62:8e2fbe131b53 67 int QRSFilter(int datum, int init) ;
roysandberg 62:8e2fbe131b53 68 int deriv1( int x0, int init ) ;
roysandberg 62:8e2fbe131b53 69
roysandberg 62:8e2fbe131b53 70 // Local Prototypes.
roysandberg 62:8e2fbe131b53 71
roysandberg 62:8e2fbe131b53 72 int Peak( int datum, int init ) ;
roysandberg 62:8e2fbe131b53 73 int median(int *array, int datnum) ;
roysandberg 62:8e2fbe131b53 74 int thresh(int qmedian, int nmedian) ;
roysandberg 62:8e2fbe131b53 75 int BLSCheck(int *dBuf,int dbPtr,int *maxder) ;
roysandberg 62:8e2fbe131b53 76
roysandberg 62:8e2fbe131b53 77 int earlyThresh(int qmedian, int nmedian) ;
roysandberg 62:8e2fbe131b53 78
roysandberg 62:8e2fbe131b53 79
roysandberg 62:8e2fbe131b53 80 double TH = 0.475 ;
roysandberg 62:8e2fbe131b53 81
roysandberg 62:8e2fbe131b53 82 int DDBuffer[DER_DELAY], DDPtr ; /* Buffer holding derivative data. */
roysandberg 62:8e2fbe131b53 83 int Dly = 0 ;
roysandberg 62:8e2fbe131b53 84
roysandberg 62:8e2fbe131b53 85 const int MEMMOVELEN = 7*sizeof(int);
roysandberg 62:8e2fbe131b53 86
roysandberg 62:8e2fbe131b53 87 int QRSDet( int datum, int init )
roysandberg 62:8e2fbe131b53 88 {
roysandberg 62:8e2fbe131b53 89 static int det_thresh, qpkcnt = 0 ;
roysandberg 62:8e2fbe131b53 90 static int qrsbuf[8], noise[8], rrbuf[8] ;
roysandberg 62:8e2fbe131b53 91 static int rsetBuff[8], rsetCount = 0 ;
roysandberg 62:8e2fbe131b53 92 static int nmedian, qmedian, rrmedian ;
roysandberg 62:8e2fbe131b53 93 static int count, sbpeak = 0, sbloc, sbcount = MS1500 ;
roysandberg 62:8e2fbe131b53 94 static int maxder, lastmax ;
roysandberg 62:8e2fbe131b53 95 static int initBlank, initMax ;
roysandberg 62:8e2fbe131b53 96 static int preBlankCnt, tempPeak ;
roysandberg 62:8e2fbe131b53 97
roysandberg 62:8e2fbe131b53 98 int fdatum, QrsDelay = 0 ;
roysandberg 62:8e2fbe131b53 99 int i, newPeak, aPeak ;
roysandberg 62:8e2fbe131b53 100
roysandberg 62:8e2fbe131b53 101 /* Initialize all buffers to 0 on the first call. */
roysandberg 62:8e2fbe131b53 102
roysandberg 62:8e2fbe131b53 103 if( init )
roysandberg 62:8e2fbe131b53 104 {
roysandberg 62:8e2fbe131b53 105 for(i = 0; i < 8; ++i)
roysandberg 62:8e2fbe131b53 106 {
roysandberg 62:8e2fbe131b53 107 noise[i] = 0 ; /* Initialize noise buffer */
roysandberg 62:8e2fbe131b53 108 rrbuf[i] = MS1000 ;/* and R-to-R interval buffer. */
roysandberg 62:8e2fbe131b53 109 }
roysandberg 62:8e2fbe131b53 110
roysandberg 62:8e2fbe131b53 111 qpkcnt = maxder = lastmax = count = sbpeak = 0 ;
roysandberg 62:8e2fbe131b53 112 initBlank = initMax = preBlankCnt = DDPtr = 0 ;
roysandberg 62:8e2fbe131b53 113 sbcount = MS1500 ;
roysandberg 62:8e2fbe131b53 114 QRSFilter(0,1) ; /* initialize filters. */
roysandberg 62:8e2fbe131b53 115 Peak(0,1) ;
roysandberg 62:8e2fbe131b53 116 }
roysandberg 62:8e2fbe131b53 117
roysandberg 62:8e2fbe131b53 118 fdatum = QRSFilter(datum,0) ; /* Filter data. */
roysandberg 62:8e2fbe131b53 119
roysandberg 62:8e2fbe131b53 120
roysandberg 62:8e2fbe131b53 121 /* Wait until normal detector is ready before calling early detections. */
roysandberg 62:8e2fbe131b53 122
roysandberg 62:8e2fbe131b53 123 aPeak = Peak(fdatum,0) ;
roysandberg 62:8e2fbe131b53 124
roysandberg 62:8e2fbe131b53 125 // Hold any peak that is detected for 200 ms
roysandberg 62:8e2fbe131b53 126 // in case a bigger one comes along. There
roysandberg 62:8e2fbe131b53 127 // can only be one QRS complex in any 200 ms window.
roysandberg 62:8e2fbe131b53 128
roysandberg 62:8e2fbe131b53 129 newPeak = 0 ;
roysandberg 62:8e2fbe131b53 130 if(aPeak && !preBlankCnt) // If there has been no peak for 200 ms
roysandberg 62:8e2fbe131b53 131 { // save this one and start counting.
roysandberg 62:8e2fbe131b53 132 tempPeak = aPeak ;
roysandberg 62:8e2fbe131b53 133 preBlankCnt = PRE_BLANK ; // MS200
roysandberg 62:8e2fbe131b53 134 }
roysandberg 62:8e2fbe131b53 135
roysandberg 62:8e2fbe131b53 136 else if(!aPeak && preBlankCnt) // If we have held onto a peak for
roysandberg 62:8e2fbe131b53 137 { // 200 ms pass it on for evaluation.
roysandberg 62:8e2fbe131b53 138 if(--preBlankCnt == 0)
roysandberg 62:8e2fbe131b53 139 newPeak = tempPeak ;
roysandberg 62:8e2fbe131b53 140 }
roysandberg 62:8e2fbe131b53 141
roysandberg 62:8e2fbe131b53 142 else if(aPeak) // If we were holding a peak, but
roysandberg 62:8e2fbe131b53 143 { // this ones bigger, save it and
roysandberg 62:8e2fbe131b53 144 if(aPeak > tempPeak) // start counting to 200 ms again.
roysandberg 62:8e2fbe131b53 145 {
roysandberg 62:8e2fbe131b53 146 tempPeak = aPeak ;
roysandberg 62:8e2fbe131b53 147 preBlankCnt = PRE_BLANK ; // MS200
roysandberg 62:8e2fbe131b53 148 }
roysandberg 62:8e2fbe131b53 149 else if(--preBlankCnt == 0)
roysandberg 62:8e2fbe131b53 150 newPeak = tempPeak ;
roysandberg 62:8e2fbe131b53 151 }
roysandberg 62:8e2fbe131b53 152
roysandberg 62:8e2fbe131b53 153 /* newPeak = 0 ;
roysandberg 62:8e2fbe131b53 154 if((aPeak != 0) && (preBlankCnt == 0))
roysandberg 62:8e2fbe131b53 155 newPeak = aPeak ;
roysandberg 62:8e2fbe131b53 156 else if(preBlankCnt != 0) --preBlankCnt ; */
roysandberg 62:8e2fbe131b53 157
roysandberg 62:8e2fbe131b53 158
roysandberg 62:8e2fbe131b53 159
roysandberg 62:8e2fbe131b53 160 /* Save derivative of raw signal for T-wave and baseline
roysandberg 62:8e2fbe131b53 161 shift discrimination. */
roysandberg 62:8e2fbe131b53 162
roysandberg 62:8e2fbe131b53 163 DDBuffer[DDPtr] = deriv1( datum, 0 ) ;
roysandberg 62:8e2fbe131b53 164 if(++DDPtr == DER_DELAY)
roysandberg 62:8e2fbe131b53 165 DDPtr = 0 ;
roysandberg 62:8e2fbe131b53 166
roysandberg 62:8e2fbe131b53 167 /* Initialize the qrs peak buffer with the first eight */
roysandberg 62:8e2fbe131b53 168 /* local maximum peaks detected. */
roysandberg 62:8e2fbe131b53 169
roysandberg 62:8e2fbe131b53 170 if( qpkcnt < 8 )
roysandberg 62:8e2fbe131b53 171 {
roysandberg 62:8e2fbe131b53 172 ++count ;
roysandberg 62:8e2fbe131b53 173 if(newPeak > 0) count = WINDOW_WIDTH ;
roysandberg 62:8e2fbe131b53 174 if(++initBlank == MS1000)
roysandberg 62:8e2fbe131b53 175 {
roysandberg 62:8e2fbe131b53 176 initBlank = 0 ;
roysandberg 62:8e2fbe131b53 177 qrsbuf[qpkcnt] = initMax ;
roysandberg 62:8e2fbe131b53 178 initMax = 0 ;
roysandberg 62:8e2fbe131b53 179 ++qpkcnt ;
roysandberg 62:8e2fbe131b53 180 if(qpkcnt == 8)
roysandberg 62:8e2fbe131b53 181 {
roysandberg 62:8e2fbe131b53 182 qmedian = median( qrsbuf, 8 ) ;
roysandberg 62:8e2fbe131b53 183 nmedian = 0 ;
roysandberg 62:8e2fbe131b53 184 rrmedian = MS1000 ;
roysandberg 62:8e2fbe131b53 185 sbcount = MS1500+MS150 ;
roysandberg 62:8e2fbe131b53 186 det_thresh = thresh(qmedian,nmedian) ;
roysandberg 62:8e2fbe131b53 187 }
roysandberg 62:8e2fbe131b53 188 }
roysandberg 62:8e2fbe131b53 189 if( newPeak > initMax )
roysandberg 62:8e2fbe131b53 190 initMax = newPeak ;
roysandberg 62:8e2fbe131b53 191 }
roysandberg 62:8e2fbe131b53 192
roysandberg 62:8e2fbe131b53 193 else /* Else test for a qrs. */
roysandberg 62:8e2fbe131b53 194 {
roysandberg 62:8e2fbe131b53 195 ++count ;
roysandberg 62:8e2fbe131b53 196 if(newPeak > 0)
roysandberg 62:8e2fbe131b53 197 {
roysandberg 62:8e2fbe131b53 198
roysandberg 62:8e2fbe131b53 199
roysandberg 62:8e2fbe131b53 200 /* Check for maximum derivative and matching minima and maxima
roysandberg 62:8e2fbe131b53 201 for T-wave and baseline shift rejection. Only consider this
roysandberg 62:8e2fbe131b53 202 peak if it doesn't seem to be a base line shift. */
roysandberg 62:8e2fbe131b53 203
roysandberg 62:8e2fbe131b53 204 if(!BLSCheck(DDBuffer, DDPtr, &maxder))
roysandberg 62:8e2fbe131b53 205 {
roysandberg 62:8e2fbe131b53 206
roysandberg 62:8e2fbe131b53 207
roysandberg 62:8e2fbe131b53 208 // Classify the beat as a QRS complex
roysandberg 62:8e2fbe131b53 209 // if the peak is larger than the detection threshold.
roysandberg 62:8e2fbe131b53 210
roysandberg 62:8e2fbe131b53 211 if(newPeak > det_thresh)
roysandberg 62:8e2fbe131b53 212 {
roysandberg 62:8e2fbe131b53 213 memmove(&qrsbuf[1], qrsbuf, MEMMOVELEN) ;
roysandberg 62:8e2fbe131b53 214 qrsbuf[0] = newPeak ;
roysandberg 62:8e2fbe131b53 215 qmedian = median(qrsbuf,8) ;
roysandberg 62:8e2fbe131b53 216 det_thresh = thresh(qmedian,nmedian) ;
roysandberg 62:8e2fbe131b53 217 memmove(&rrbuf[1], rrbuf, MEMMOVELEN) ;
roysandberg 62:8e2fbe131b53 218 rrbuf[0] = count - WINDOW_WIDTH ;
roysandberg 62:8e2fbe131b53 219 rrmedian = median(rrbuf,8) ;
roysandberg 62:8e2fbe131b53 220 sbcount = rrmedian + (rrmedian >> 1) + WINDOW_WIDTH ;
roysandberg 62:8e2fbe131b53 221 count = WINDOW_WIDTH ;
roysandberg 62:8e2fbe131b53 222
roysandberg 62:8e2fbe131b53 223 sbpeak = 0 ;
roysandberg 62:8e2fbe131b53 224
roysandberg 62:8e2fbe131b53 225 lastmax = maxder ;
roysandberg 62:8e2fbe131b53 226 maxder = 0 ;
roysandberg 62:8e2fbe131b53 227 QrsDelay = WINDOW_WIDTH + FILTER_DELAY ;
roysandberg 62:8e2fbe131b53 228 initBlank = initMax = rsetCount = 0 ;
roysandberg 62:8e2fbe131b53 229
roysandberg 62:8e2fbe131b53 230 // preBlankCnt = PRE_BLANK ;
roysandberg 62:8e2fbe131b53 231 }
roysandberg 62:8e2fbe131b53 232
roysandberg 62:8e2fbe131b53 233 // If a peak isn't a QRS update noise buffer and estimate.
roysandberg 62:8e2fbe131b53 234 // Store the peak for possible search back.
roysandberg 62:8e2fbe131b53 235
roysandberg 62:8e2fbe131b53 236
roysandberg 62:8e2fbe131b53 237 else
roysandberg 62:8e2fbe131b53 238 {
roysandberg 62:8e2fbe131b53 239 memmove(&noise[1],noise,MEMMOVELEN) ;
roysandberg 62:8e2fbe131b53 240 noise[0] = newPeak ;
roysandberg 62:8e2fbe131b53 241 nmedian = median(noise,8) ;
roysandberg 62:8e2fbe131b53 242 det_thresh = thresh(qmedian,nmedian) ;
roysandberg 62:8e2fbe131b53 243
roysandberg 62:8e2fbe131b53 244 // Don't include early peaks (which might be T-waves)
roysandberg 62:8e2fbe131b53 245 // in the search back process. A T-wave can mask
roysandberg 62:8e2fbe131b53 246 // a small following QRS.
roysandberg 62:8e2fbe131b53 247
roysandberg 62:8e2fbe131b53 248 if((newPeak > sbpeak) && ((count-WINDOW_WIDTH) >= MS360))
roysandberg 62:8e2fbe131b53 249 {
roysandberg 62:8e2fbe131b53 250 sbpeak = newPeak ;
roysandberg 62:8e2fbe131b53 251 sbloc = count - WINDOW_WIDTH ;
roysandberg 62:8e2fbe131b53 252 }
roysandberg 62:8e2fbe131b53 253 }
roysandberg 62:8e2fbe131b53 254 }
roysandberg 62:8e2fbe131b53 255 }
roysandberg 62:8e2fbe131b53 256
roysandberg 62:8e2fbe131b53 257 /* Test for search back condition. If a QRS is found in */
roysandberg 62:8e2fbe131b53 258 /* search back update the QRS buffer and det_thresh. */
roysandberg 62:8e2fbe131b53 259
roysandberg 62:8e2fbe131b53 260 if((count > sbcount) && (sbpeak > (det_thresh >> 1)))
roysandberg 62:8e2fbe131b53 261 {
roysandberg 62:8e2fbe131b53 262 memmove(&qrsbuf[1],qrsbuf,MEMMOVELEN) ;
roysandberg 62:8e2fbe131b53 263 qrsbuf[0] = sbpeak ;
roysandberg 62:8e2fbe131b53 264 qmedian = median(qrsbuf,8) ;
roysandberg 62:8e2fbe131b53 265 det_thresh = thresh(qmedian,nmedian) ;
roysandberg 62:8e2fbe131b53 266 memmove(&rrbuf[1],rrbuf,MEMMOVELEN) ;
roysandberg 62:8e2fbe131b53 267 rrbuf[0] = sbloc ;
roysandberg 62:8e2fbe131b53 268 rrmedian = median(rrbuf,8) ;
roysandberg 62:8e2fbe131b53 269 sbcount = rrmedian + (rrmedian >> 1) + WINDOW_WIDTH ;
roysandberg 62:8e2fbe131b53 270 QrsDelay = count = count - sbloc ;
roysandberg 62:8e2fbe131b53 271 QrsDelay += FILTER_DELAY ;
roysandberg 62:8e2fbe131b53 272 sbpeak = 0 ;
roysandberg 62:8e2fbe131b53 273 lastmax = maxder ;
roysandberg 62:8e2fbe131b53 274 maxder = 0 ;
roysandberg 62:8e2fbe131b53 275 initBlank = initMax = rsetCount = 0 ;
roysandberg 62:8e2fbe131b53 276 }
roysandberg 62:8e2fbe131b53 277 }
roysandberg 62:8e2fbe131b53 278
roysandberg 62:8e2fbe131b53 279 // In the background estimate threshold to replace adaptive threshold
roysandberg 62:8e2fbe131b53 280 // if eight seconds elapses without a QRS detection.
roysandberg 62:8e2fbe131b53 281
roysandberg 62:8e2fbe131b53 282 if( qpkcnt == 8 )
roysandberg 62:8e2fbe131b53 283 {
roysandberg 62:8e2fbe131b53 284 if(++initBlank == MS1000)
roysandberg 62:8e2fbe131b53 285 {
roysandberg 62:8e2fbe131b53 286 initBlank = 0 ;
roysandberg 62:8e2fbe131b53 287 rsetBuff[rsetCount] = initMax ;
roysandberg 62:8e2fbe131b53 288 initMax = 0 ;
roysandberg 62:8e2fbe131b53 289 ++rsetCount ;
roysandberg 62:8e2fbe131b53 290
roysandberg 62:8e2fbe131b53 291 // Reset threshold if it has been 8 seconds without
roysandberg 62:8e2fbe131b53 292 // a detection.
roysandberg 62:8e2fbe131b53 293
roysandberg 62:8e2fbe131b53 294 if(rsetCount == 8)
roysandberg 62:8e2fbe131b53 295 {
roysandberg 62:8e2fbe131b53 296 for(i = 0; i < 8; ++i)
roysandberg 62:8e2fbe131b53 297 {
roysandberg 62:8e2fbe131b53 298 qrsbuf[i] = rsetBuff[i] ;
roysandberg 62:8e2fbe131b53 299 noise[i] = 0 ;
roysandberg 62:8e2fbe131b53 300 }
roysandberg 62:8e2fbe131b53 301 qmedian = median( rsetBuff, 8 ) ;
roysandberg 62:8e2fbe131b53 302 nmedian = 0 ;
roysandberg 62:8e2fbe131b53 303 rrmedian = MS1000 ;
roysandberg 62:8e2fbe131b53 304 sbcount = MS1500+MS150 ;
roysandberg 62:8e2fbe131b53 305 det_thresh = thresh(qmedian,nmedian) ;
roysandberg 62:8e2fbe131b53 306 initBlank = initMax = rsetCount = 0 ;
roysandberg 62:8e2fbe131b53 307 sbpeak = 0 ;
roysandberg 62:8e2fbe131b53 308 }
roysandberg 62:8e2fbe131b53 309 }
roysandberg 62:8e2fbe131b53 310 if( newPeak > initMax )
roysandberg 62:8e2fbe131b53 311 initMax = newPeak ;
roysandberg 62:8e2fbe131b53 312 }
roysandberg 62:8e2fbe131b53 313
roysandberg 62:8e2fbe131b53 314 return(QrsDelay) ;
roysandberg 62:8e2fbe131b53 315 }
roysandberg 62:8e2fbe131b53 316
roysandberg 62:8e2fbe131b53 317 /**************************************************************
roysandberg 62:8e2fbe131b53 318 * peak() takes a datum as input and returns a peak height
roysandberg 62:8e2fbe131b53 319 * when the signal returns to half its peak height, or
roysandberg 62:8e2fbe131b53 320 **************************************************************/
roysandberg 62:8e2fbe131b53 321
roysandberg 62:8e2fbe131b53 322 int Peak( int datum, int init )
roysandberg 62:8e2fbe131b53 323 {
roysandberg 62:8e2fbe131b53 324 static int max = 0, timeSinceMax = 0, lastDatum ;
roysandberg 62:8e2fbe131b53 325 int pk = 0 ;
roysandberg 62:8e2fbe131b53 326
roysandberg 62:8e2fbe131b53 327 if(init)
roysandberg 62:8e2fbe131b53 328 max = timeSinceMax = 0 ;
roysandberg 62:8e2fbe131b53 329
roysandberg 62:8e2fbe131b53 330 if(timeSinceMax > 0)
roysandberg 62:8e2fbe131b53 331 ++timeSinceMax ;
roysandberg 62:8e2fbe131b53 332
roysandberg 62:8e2fbe131b53 333 if((datum > lastDatum) && (datum > max))
roysandberg 62:8e2fbe131b53 334 {
roysandberg 62:8e2fbe131b53 335 max = datum ;
roysandberg 62:8e2fbe131b53 336 if(max > 2)
roysandberg 62:8e2fbe131b53 337 timeSinceMax = 1 ;
roysandberg 62:8e2fbe131b53 338 }
roysandberg 62:8e2fbe131b53 339
roysandberg 62:8e2fbe131b53 340 else if(datum < (max >> 1))
roysandberg 62:8e2fbe131b53 341 {
roysandberg 62:8e2fbe131b53 342 pk = max ;
roysandberg 62:8e2fbe131b53 343 max = 0 ;
roysandberg 62:8e2fbe131b53 344 timeSinceMax = 0 ;
roysandberg 62:8e2fbe131b53 345 Dly = 0 ;
roysandberg 62:8e2fbe131b53 346 }
roysandberg 62:8e2fbe131b53 347
roysandberg 62:8e2fbe131b53 348 else if(timeSinceMax > MS95)
roysandberg 62:8e2fbe131b53 349 {
roysandberg 62:8e2fbe131b53 350 pk = max ;
roysandberg 62:8e2fbe131b53 351 max = 0 ;
roysandberg 62:8e2fbe131b53 352 timeSinceMax = 0 ;
roysandberg 62:8e2fbe131b53 353 Dly = 3 ;
roysandberg 62:8e2fbe131b53 354 }
roysandberg 62:8e2fbe131b53 355 lastDatum = datum ;
roysandberg 62:8e2fbe131b53 356 return(pk) ;
roysandberg 62:8e2fbe131b53 357 }
roysandberg 62:8e2fbe131b53 358
roysandberg 62:8e2fbe131b53 359 /********************************************************************
roysandberg 62:8e2fbe131b53 360 median returns the median of an array of integers. It uses a slow
roysandberg 62:8e2fbe131b53 361 sort algorithm, but these arrays are small, so it hardly matters.
roysandberg 62:8e2fbe131b53 362 ********************************************************************/
roysandberg 62:8e2fbe131b53 363
roysandberg 62:8e2fbe131b53 364 int median(int *array, int datnum)
roysandberg 62:8e2fbe131b53 365 {
roysandberg 62:8e2fbe131b53 366 int i, j, k, temp, sort[20] ;
roysandberg 62:8e2fbe131b53 367 for(i = 0; i < datnum; ++i)
roysandberg 62:8e2fbe131b53 368 sort[i] = array[i] ;
roysandberg 62:8e2fbe131b53 369 for(i = 0; i < datnum; ++i)
roysandberg 62:8e2fbe131b53 370 {
roysandberg 62:8e2fbe131b53 371 temp = sort[i] ;
roysandberg 62:8e2fbe131b53 372 for(j = 0; (temp < sort[j]) && (j < i) ; ++j) ;
roysandberg 62:8e2fbe131b53 373 for(k = i - 1 ; k >= j ; --k)
roysandberg 62:8e2fbe131b53 374 sort[k+1] = sort[k] ;
roysandberg 62:8e2fbe131b53 375 sort[j] = temp ;
roysandberg 62:8e2fbe131b53 376 }
roysandberg 62:8e2fbe131b53 377 return(sort[datnum>>1]) ;
roysandberg 62:8e2fbe131b53 378 }
roysandberg 62:8e2fbe131b53 379 /*
roysandberg 62:8e2fbe131b53 380 int median(int *array, int datnum)
roysandberg 62:8e2fbe131b53 381 {
roysandberg 62:8e2fbe131b53 382 long sum ;
roysandberg 62:8e2fbe131b53 383 int i ;
roysandberg 62:8e2fbe131b53 384
roysandberg 62:8e2fbe131b53 385 for(i = 0, sum = 0; i < datnum; ++i)
roysandberg 62:8e2fbe131b53 386 sum += array[i] ;
roysandberg 62:8e2fbe131b53 387 sum /= datnum ;
roysandberg 62:8e2fbe131b53 388 return(sum) ;
roysandberg 62:8e2fbe131b53 389 } */
roysandberg 62:8e2fbe131b53 390
roysandberg 62:8e2fbe131b53 391 /****************************************************************************
roysandberg 62:8e2fbe131b53 392 thresh() calculates the detection threshold from the qrs median and noise
roysandberg 62:8e2fbe131b53 393 median estimates.
roysandberg 62:8e2fbe131b53 394 ****************************************************************************/
roysandberg 62:8e2fbe131b53 395
roysandberg 62:8e2fbe131b53 396 int thresh(int qmedian, int nmedian)
roysandberg 62:8e2fbe131b53 397 {
roysandberg 62:8e2fbe131b53 398 int thrsh, dmed ;
roysandberg 62:8e2fbe131b53 399 double temp ;
roysandberg 62:8e2fbe131b53 400 dmed = qmedian - nmedian ;
roysandberg 62:8e2fbe131b53 401 /* thrsh = nmedian + (dmed>>2) + (dmed>>3) + (dmed>>4); */
roysandberg 62:8e2fbe131b53 402 temp = dmed ;
roysandberg 62:8e2fbe131b53 403 temp *= TH ;
roysandberg 62:8e2fbe131b53 404 dmed = temp ;
roysandberg 62:8e2fbe131b53 405 thrsh = nmedian + dmed ; /* dmed * THRESHOLD */
roysandberg 62:8e2fbe131b53 406 return(thrsh) ;
roysandberg 62:8e2fbe131b53 407 }
roysandberg 62:8e2fbe131b53 408
roysandberg 62:8e2fbe131b53 409 /***********************************************************************
roysandberg 62:8e2fbe131b53 410 BLSCheck() reviews data to see if a baseline shift has occurred.
roysandberg 62:8e2fbe131b53 411 This is done by looking for both positive and negative slopes of
roysandberg 62:8e2fbe131b53 412 roughly the same magnitude in a 220 ms window.
roysandberg 62:8e2fbe131b53 413 ***********************************************************************/
roysandberg 62:8e2fbe131b53 414
roysandberg 62:8e2fbe131b53 415 int BLSCheck(int *dBuf,int dbPtr,int *maxder)
roysandberg 62:8e2fbe131b53 416 {
roysandberg 62:8e2fbe131b53 417 int max, min, maxt, mint, t, x ;
roysandberg 62:8e2fbe131b53 418 max = min = 0 ;
roysandberg 62:8e2fbe131b53 419
roysandberg 62:8e2fbe131b53 420 return(0) ;
roysandberg 62:8e2fbe131b53 421
roysandberg 62:8e2fbe131b53 422 for(t = 0; t < MS220; ++t)
roysandberg 62:8e2fbe131b53 423 {
roysandberg 62:8e2fbe131b53 424 x = dBuf[dbPtr] ;
roysandberg 62:8e2fbe131b53 425 if(x > max)
roysandberg 62:8e2fbe131b53 426 {
roysandberg 62:8e2fbe131b53 427 maxt = t ;
roysandberg 62:8e2fbe131b53 428 max = x ;
roysandberg 62:8e2fbe131b53 429 }
roysandberg 62:8e2fbe131b53 430 else if(x < min)
roysandberg 62:8e2fbe131b53 431 {
roysandberg 62:8e2fbe131b53 432 mint = t ;
roysandberg 62:8e2fbe131b53 433 min = x;
roysandberg 62:8e2fbe131b53 434 }
roysandberg 62:8e2fbe131b53 435 if(++dbPtr == DER_DELAY)
roysandberg 62:8e2fbe131b53 436 dbPtr = 0 ;
roysandberg 62:8e2fbe131b53 437 }
roysandberg 62:8e2fbe131b53 438
roysandberg 62:8e2fbe131b53 439 *maxder = max ;
roysandberg 62:8e2fbe131b53 440 min = -min ;
roysandberg 62:8e2fbe131b53 441
roysandberg 62:8e2fbe131b53 442 /* Possible beat if a maximum and minimum pair are found
roysandberg 62:8e2fbe131b53 443 where the interval between them is less than 150 ms. */
roysandberg 62:8e2fbe131b53 444
roysandberg 62:8e2fbe131b53 445 if((max > (min>>3)) && (min > (max>>3)) &&
roysandberg 62:8e2fbe131b53 446 (abs(maxt - mint) < MS150))
roysandberg 62:8e2fbe131b53 447 return(0) ;
roysandberg 62:8e2fbe131b53 448
roysandberg 62:8e2fbe131b53 449 else
roysandberg 62:8e2fbe131b53 450 return(1) ;
roysandberg 62:8e2fbe131b53 451 }
roysandberg 62:8e2fbe131b53 452