Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: BLE_API Queue mbed nRF51822
Fork of BLE_HeartRate by
rythmchk.cpp
00001 /***************************************************************************** 00002 FILE: rythmchk.cpp 00003 AUTHOR: Patrick S. Hamilton 00004 REVISED: 5/13/2002 00005 10/9/2001: 1.1 Call premature for 12.5% difference with very regular 00006 rhythms. If short after VV go to QQ. 00007 5/13/2002: Check for NNVNNNV pattern when last interval was QQ. 00008 ___________________________________________________________________________ 00009 00010 rythmchk.cpp: Rhythm Check 00011 Copywrite (C) 2001 Patrick S. Hamilton 00012 00013 This file is free software; you can redistribute it and/or modify it under 00014 the terms of the GNU Library General Public License as published by the Free 00015 Software Foundation; either version 2 of the License, or (at your option) any 00016 later version. 00017 00018 This software is distributed in the hope that it will be useful, but WITHOUT ANY 00019 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 00020 PARTICULAR PURPOSE. See the GNU Library General Public License for more 00021 details. 00022 00023 You should have received a copy of the GNU Library General Public License along 00024 with this library; if not, write to the Free Software Foundation, Inc., 59 00025 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 00026 00027 You may contact the author by e-mail (pat@eplimited.edu) or postal mail 00028 (Patrick Hamilton, E.P. Limited, 35 Medford St., Suite 204 Somerville, 00029 MA 02143 USA). For updates to this software, please visit our website 00030 (http://www.eplimited.com). 00031 __________________________________________________________________________ 00032 00033 Rythmchk.cpp contains functions for classifying RR intervals as either 00034 NORMAL, PVC, or UNKNOWN. Intervals classified as NORMAL are presumed to 00035 end with normal beats, intervals classified as PVC are presumed to end 00036 with a premature contraction, and intervals classified as unknown do 00037 not fit any pattern that the rhythm classifier recognizes. 00038 00039 NORMAL intervals can be part of a normal (regular) rhythm, normal beats 00040 following a premature beats, or normal beats following runs of ventricular 00041 beats. PVC intervals can be short intervals following a regular rhythm, 00042 short intervals that are part of a run of short intervals following a 00043 regular rhythm, or short intervals that are part of a bigeminal rhythm. 00044 00045 **************************************************************************/ 00046 00047 #include <mbed.h> 00048 #include "qrsdet.h" // For time intervals. 00049 #include "ecgcodes.h" // Defines codes of NORMAL, PVC, and UNKNOWN. 00050 //#include <stdlib.h> // For abs() 00051 00052 // Define RR interval types. 00053 00054 #define QQ 0 // Unknown-Unknown interval. 00055 #define NN 1 // Normal-Normal interval. 00056 #define NV 2 // Normal-PVC interval. 00057 #define VN 3 // PVC-Normal interval. 00058 #define VV 4 // PVC-PVC interval. 00059 00060 #define RBB_LENGTH 8 00061 #define LEARNING 0 00062 #define READY 1 00063 00064 #define BRADY_LIMIT MS1500 00065 00066 // Local prototypes. 00067 int RRMatch(int rr0,int rr1) ; 00068 int RRShort(int rr0,int rr1) ; 00069 int RRShort2(int *rrIntervals, int *rrTypes) ; 00070 int RRMatch2(int rr0,int rr1) ; 00071 00072 // Global variables. 00073 int RRBuffer[RBB_LENGTH], RRTypes[RBB_LENGTH], BeatCount = 0; 00074 int ClassifyState = LEARNING ; 00075 00076 int BigeminyFlag ; 00077 00078 /*************************************************************************** 00079 ResetRhythmChk() resets static variables used for rhythm classification. 00080 ****************************************************************************/ 00081 00082 void ResetRhythmChk(void) 00083 { 00084 BeatCount = 0 ; 00085 ClassifyState = LEARNING ; 00086 } 00087 00088 /***************************************************************************** 00089 RhythmChk() takes an R-to-R interval as input and, based on previous R-to-R 00090 intervals, classifys the interval as NORMAL, PVC, or UNKNOWN. 00091 ******************************************************************************/ 00092 00093 int RhythmChk(int rr) 00094 { 00095 int i, regular = 1 ; 00096 int NNEst, NVEst ; 00097 00098 BigeminyFlag = 0 ; 00099 00100 // Wait for at least 4 beats before classifying anything. 00101 00102 if(BeatCount < 4) 00103 { 00104 if(++BeatCount == 4) 00105 ClassifyState = READY ; 00106 } 00107 00108 // Stick the new RR interval into the RR interval Buffer. 00109 00110 for(i = RBB_LENGTH-1; i > 0; --i) 00111 { 00112 RRBuffer[i] = RRBuffer[i-1] ; 00113 RRTypes[i] = RRTypes[i-1] ; 00114 } 00115 00116 RRBuffer[0] = rr ; 00117 00118 if(ClassifyState == LEARNING) 00119 { 00120 RRTypes[0] = QQ ; 00121 return(UNKNOWN) ; 00122 } 00123 00124 // If we couldn't tell what the last interval was... 00125 00126 if(RRTypes[1] == QQ) 00127 { 00128 for(i = 0, regular = 1; i < 3; ++i) 00129 if(RRMatch(RRBuffer[i],RRBuffer[i+1]) == 0) 00130 regular = 0 ; 00131 00132 // If this, and the last three intervals matched, classify 00133 // it as Normal-Normal. 00134 00135 if(regular == 1) 00136 { 00137 RRTypes[0] = NN ; 00138 return(NORMAL) ; 00139 } 00140 00141 // Check for bigeminy. 00142 // Call bigeminy if every other RR matches and 00143 // consecutive beats do not match. 00144 00145 for(i = 0, regular = 1; i < 6; ++i) 00146 if(RRMatch(RRBuffer[i],RRBuffer[i+2]) == 0) 00147 regular = 0 ; 00148 for(i = 0; i < 6; ++i) 00149 if(RRMatch(RRBuffer[i],RRBuffer[i+1]) != 0) 00150 regular = 0 ; 00151 00152 if(regular == 1) 00153 { 00154 BigeminyFlag = 1 ; 00155 if(RRBuffer[0] < RRBuffer[1]) 00156 { 00157 RRTypes[0] = NV ; 00158 RRTypes[1] = VN ; 00159 return(PVC) ; 00160 } 00161 else 00162 { 00163 RRTypes[0] = VN ; 00164 RRTypes[1] = NV ; 00165 return(NORMAL) ; 00166 } 00167 } 00168 00169 // Check for NNVNNNV pattern. 00170 00171 if(RRShort(RRBuffer[0],RRBuffer[1]) && RRMatch(RRBuffer[1],RRBuffer[2]) 00172 && RRMatch(RRBuffer[2]*2,RRBuffer[3]+RRBuffer[4]) && 00173 RRMatch(RRBuffer[4],RRBuffer[0]) && RRMatch(RRBuffer[5],RRBuffer[2])) 00174 { 00175 RRTypes[0] = NV ; 00176 RRTypes[1] = NN ; 00177 return(PVC) ; 00178 } 00179 00180 // If the interval is not part of a 00181 // bigeminal or regular pattern, give up. 00182 00183 else 00184 { 00185 RRTypes[0] = QQ ; 00186 return(UNKNOWN) ; 00187 } 00188 } 00189 00190 // If the previous two beats were normal... 00191 00192 else if(RRTypes[1] == NN) 00193 { 00194 00195 if(RRShort2(RRBuffer,RRTypes)) 00196 { 00197 if(RRBuffer[1] < BRADY_LIMIT) 00198 { 00199 RRTypes[0] = NV ; 00200 return(PVC) ; 00201 } 00202 else RRTypes[0] = QQ ; 00203 return(UNKNOWN) ; 00204 } 00205 00206 00207 // If this interval matches the previous interval, then it 00208 // is regular. 00209 00210 else if(RRMatch(RRBuffer[0],RRBuffer[1])) 00211 { 00212 RRTypes[0] = NN ; 00213 return(NORMAL) ; 00214 } 00215 00216 // If this interval is short.. 00217 00218 else if(RRShort(RRBuffer[0],RRBuffer[1])) 00219 { 00220 00221 // But matches the one before last and the one before 00222 // last was NN, this is a normal interval. 00223 00224 if(RRMatch(RRBuffer[0],RRBuffer[2]) && (RRTypes[2] == NN)) 00225 { 00226 RRTypes[0] = NN ; 00227 return(NORMAL) ; 00228 } 00229 00230 // If the rhythm wasn't bradycardia, call it a PVC. 00231 00232 else if(RRBuffer[1] < BRADY_LIMIT) 00233 { 00234 RRTypes[0] = NV ; 00235 return(PVC) ; 00236 } 00237 00238 // If the regular rhythm was bradycardia, don't assume that 00239 // it was a PVC. 00240 00241 else 00242 { 00243 RRTypes[0] = QQ ; 00244 return(UNKNOWN) ; 00245 } 00246 } 00247 00248 // If the interval isn't normal or short, then classify 00249 // it as normal but don't assume normal for future 00250 // rhythm classification. 00251 00252 else 00253 { 00254 RRTypes[0] = QQ ; 00255 return(NORMAL) ; 00256 } 00257 } 00258 00259 // If the previous beat was a PVC... 00260 00261 else if(RRTypes[1] == NV) 00262 { 00263 00264 if(RRShort2(&RRBuffer[1],&RRTypes[1])) 00265 { 00266 /* if(RRMatch2(RRBuffer[0],RRBuffer[1])) 00267 { 00268 RRTypes[0] = VV ; 00269 return(PVC) ; 00270 } */ 00271 00272 if(RRMatch(RRBuffer[0],RRBuffer[1])) 00273 { 00274 RRTypes[0] = NN ; 00275 RRTypes[1] = NN ; 00276 return(NORMAL) ; 00277 } 00278 else if(RRBuffer[0] > RRBuffer[1]) 00279 { 00280 RRTypes[0] = VN ; 00281 return(NORMAL) ; 00282 } 00283 else 00284 { 00285 RRTypes[0] = QQ ; 00286 return(UNKNOWN) ; 00287 } 00288 00289 00290 } 00291 00292 // If this interval matches the previous premature 00293 // interval assume a ventricular couplet. 00294 00295 else if(RRMatch(RRBuffer[0],RRBuffer[1])) 00296 { 00297 RRTypes[0] = VV ; 00298 return(PVC) ; 00299 } 00300 00301 // If this interval is larger than the previous 00302 // interval, assume that it is NORMAL. 00303 00304 else if(RRBuffer[0] > RRBuffer[1]) 00305 { 00306 RRTypes[0] = VN ; 00307 return(NORMAL) ; 00308 } 00309 00310 // Otherwise don't make any assumputions about 00311 // what this interval represents. 00312 00313 else 00314 { 00315 RRTypes[0] = QQ ; 00316 return(UNKNOWN) ; 00317 } 00318 } 00319 00320 // If the previous beat followed a PVC or couplet etc... 00321 00322 else if(RRTypes[1] == VN) 00323 { 00324 00325 // Find the last NN interval. 00326 00327 for(i = 2; (RRTypes[i] != NN) && (i < RBB_LENGTH); ++i) ; 00328 00329 // If there was an NN interval in the interval buffer... 00330 if(i != RBB_LENGTH) 00331 { 00332 NNEst = RRBuffer[i] ; 00333 00334 // and it matches, classify this interval as NORMAL. 00335 00336 if(RRMatch(RRBuffer[0],NNEst)) 00337 { 00338 RRTypes[0] = NN ; 00339 return(NORMAL) ; 00340 } 00341 } 00342 00343 else NNEst = 0 ; 00344 for(i = 2; (RRTypes[i] != NV) && (i < RBB_LENGTH); ++i) ; 00345 if(i != RBB_LENGTH) 00346 NVEst = RRBuffer[i] ; 00347 else NVEst = 0 ; 00348 if((NNEst == 0) && (NVEst != 0)) 00349 NNEst = (RRBuffer[1]+NVEst) >> 1 ; 00350 00351 // NNEst is either the last NN interval or the average 00352 // of the most recent NV and VN intervals. 00353 00354 // If the interval is closer to NN than NV, try 00355 // matching to NN. 00356 00357 if((NVEst != 0) && 00358 (abs(NNEst - RRBuffer[0]) < abs(NVEst - RRBuffer[0])) && 00359 RRMatch(NNEst,RRBuffer[0])) 00360 { 00361 RRTypes[0] = NN ; 00362 return(NORMAL) ; 00363 } 00364 00365 // If this interval is closer to NV than NN, try 00366 // matching to NV. 00367 00368 else if((NVEst != 0) && 00369 (abs(NNEst - RRBuffer[0]) > abs(NVEst - RRBuffer[0])) && 00370 RRMatch(NVEst,RRBuffer[0])) 00371 { 00372 RRTypes[0] = NV ; 00373 return(PVC) ; 00374 } 00375 00376 // If equally close, or we don't have an NN or NV in the buffer, 00377 // who knows what it is. 00378 00379 else 00380 { 00381 RRTypes[0] = QQ ; 00382 return(UNKNOWN) ; 00383 } 00384 } 00385 00386 // Otherwise the previous interval must have been a VV 00387 00388 else 00389 { 00390 00391 // Does this match previous VV. 00392 00393 if(RRMatch(RRBuffer[0],RRBuffer[1])) 00394 { 00395 RRTypes[0] = VV ; 00396 return(PVC) ; 00397 } 00398 00399 // If this doesn't match a previous VV interval, assume 00400 // any new interval is recovery to Normal beat. 00401 00402 else 00403 { 00404 if(RRShort(RRBuffer[0],RRBuffer[1])) 00405 { 00406 RRTypes[0] = QQ ; 00407 return(UNKNOWN) ; 00408 } 00409 else 00410 { 00411 RRTypes[0] = VN ; 00412 return(NORMAL) ; 00413 } 00414 } 00415 } 00416 } 00417 00418 00419 /*********************************************************************** 00420 RRMatch() test whether two intervals are within 12.5% of their mean. 00421 ************************************************************************/ 00422 00423 int RRMatch(int rr0,int rr1) 00424 { 00425 if(abs(rr0-rr1) < ((rr0+rr1)>>3)) 00426 return(1) ; 00427 else return(0) ; 00428 } 00429 00430 /************************************************************************ 00431 RRShort() tests whether an interval is less than 75% of the previous 00432 interval. 00433 *************************************************************************/ 00434 00435 int RRShort(int rr0, int rr1) 00436 { 00437 if(rr0 < rr1-(rr1>>2)) 00438 return(1) ; 00439 else return(0) ; 00440 } 00441 00442 /************************************************************************* 00443 IsBigeminy() allows external access to the bigeminy flag to check whether 00444 a bigeminal rhythm is in progress. 00445 **************************************************************************/ 00446 00447 int IsBigeminy(void) 00448 { 00449 return(BigeminyFlag) ; 00450 } 00451 00452 /************************************************************************** 00453 Check for short interval in very regular rhythm. 00454 **************************************************************************/ 00455 00456 int RRShort2(int *rrIntervals, int *rrTypes) 00457 { 00458 int rrMean = 0, i, nnCount ; 00459 00460 for(i = 1, nnCount = 0; (i < 7) && (nnCount < 4); ++i) 00461 if(rrTypes[i] == NN) 00462 { 00463 ++nnCount ; 00464 rrMean += rrIntervals[i] ; 00465 } 00466 00467 // Return if there aren't at least 4 normal intervals. 00468 00469 if(nnCount != 4) 00470 return(0) ; 00471 rrMean >>= 2 ; 00472 00473 00474 for(i = 1, nnCount = 0; (i < 7) && (nnCount < 4); ++i) 00475 if(rrTypes[i] == NN) 00476 { 00477 if(abs(rrMean-rrIntervals[i]) > (rrMean>>4)) 00478 i = 10 ; 00479 } 00480 00481 if((i < 9) && (rrIntervals[0] < (rrMean - (rrMean>>3)))) 00482 return(1) ; 00483 else 00484 return(0) ; 00485 } 00486 00487 int RRMatch2(int rr0,int rr1) 00488 { 00489 if(abs(rr0-rr1) < ((rr0+rr1)>>4)) 00490 return(1) ; 00491 else return(0) ; 00492 }
Generated on Sun Jul 24 2022 05:18:22 by
1.7.2
