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
classify.cpp
00001 /***************************************************************************** 00002 FILE: classify.cpp 00003 AUTHOR: Patrick S. Hamilton 00004 REVISED: 5/13/2001 00005 ___________________________________________________________________________ 00006 00007 classify.cpp: Classify a given beat. 00008 Copywrite (C) 2001 Patrick S. Hamilton 00009 00010 This file is free software; you can redistribute it and/or modify it under 00011 the terms of the GNU Library General Public License as published by the Free 00012 Software Foundation; either version 2 of the License, or (at your option) any 00013 later version. 00014 00015 This software is distributed in the hope that it will be useful, but WITHOUT ANY 00016 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 00017 PARTICULAR PURPOSE. See the GNU Library General Public License for more 00018 details. 00019 00020 You should have received a copy of the GNU Library General Public License along 00021 with this library; if not, write to the Free Software Foundation, Inc., 59 00022 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 00023 00024 You may contact the author by e-mail (pat@eplimited.edu) or postal mail 00025 (Patrick Hamilton, E.P. Limited, 35 Medford St., Suite 204 Somerville, 00026 MA 02143 USA). For updates to this software, please visit our website 00027 (http://www.eplimited.com). 00028 __________________________________________________________________________ 00029 00030 Classify.cpp contains functions for classifying beats. The only 00031 function that needs to be called externally from this file is Classify(). 00032 00033 Functions in classify.cpp require functions in the following files: 00034 match.cpp 00035 rythmchk.cpp 00036 classify.cpp 00037 rythmchk.cpp 00038 analbeat.cpp 00039 postclas.cpp 00040 00041 __________________________________________________________________________ 00042 00043 Revisions: 00044 5/13/02: 00045 Width constants tied to BEAT_SAMPLE_RATE in bdac.h 00046 00047 Arrays added to track the classifications and RR intervals for the 00048 most recent 8 beats, allowing GetRunCount to become a local function. 00049 RR intervals and classifications are now passed to PostClassify. 00050 00051 Determination of whether the dominant rhythm is regular is now made 00052 by examining the number of RR intervals classified as UNKNOWN in the 00053 last DM_BUFFER_LENGTH beats (180). If more than 60 are UNKNOWN 00054 the rhythm is too irregular to give any weight to whether the beat 00055 was premature or not. 00056 00057 *******************************************************************************/ 00058 00059 #include "ecgcodes.h" 00060 //#include <stdlib.h> // For abs() 00061 //#include <stdio.h> 00062 #include <mbed.h> 00063 #include "qrsdet.h" // For base sample rate. 00064 #include "bdac.h" 00065 #include "match.h" 00066 #include "rythmchk.h" 00067 #include "analbeat.h" 00068 #include "postclas.h" 00069 00070 // Detection Rule Parameters. 00071 00072 #define MATCH_LIMIT 1.3 // Threshold for template matching 00073 // without amplitude sensitivity. 00074 #define MATCH_WITH_AMP_LIMIT 2.5 // Threshold for matching index that 00075 // is amplitude sensitive. 00076 #define PVC_MATCH_WITH_AMP_LIMIT 0.9 // Amplitude sensitive limit for 00077 //matching premature beats 00078 #define BL_SHIFT_LIMIT 100 // Threshold for assuming a baseline shift. 00079 #define NEW_TYPE_NOISE_THRESHOLD 18 // Above this noise level, do not create 00080 // new beat types. 00081 #define NEW_TYPE_HF_NOISE_LIMIT 75 // Above this noise level, do not crate 00082 // new beat types. 00083 00084 #define MATCH_NOISE_THRESHOLD 0.7 // Match threshold below which noise 00085 // indications are ignored. 00086 00087 // TempClass classification rule parameters. 00088 00089 #define R2_DI_THRESHOLD 1.0 // Rule 2 dominant similarity index threshold 00090 #define R3_WIDTH_THRESHOLD BEAT_MS90 // Rule 3 width threshold. 00091 #define R7_DI_THRESHOLD 1.2 // Rule 7 dominant similarity index threshold 00092 #define R8_DI_THRESHOLD 1.5 // Rule 8 dominant similarity index threshold 00093 #define R9_DI_THRESHOLD 2.0 // Rule 9 dominant similarity index threshold 00094 #define R10_BC_LIM 3 // Rule 10 beat count limit. 00095 #define R10_DI_THRESHOLD 2.5 // Rule 10 dominant similarity index threshold 00096 #define R11_MIN_WIDTH BEAT_MS110 // Rule 11 minimum width threshold. 00097 #define R11_WIDTH_BREAK BEAT_MS140 // Rule 11 width break. 00098 #define R11_WIDTH_DIFF1 BEAT_MS40 // Rule 11 width difference threshold 1 00099 #define R11_WIDTH_DIFF2 BEAT_MS60 // Rule 11 width difference threshold 2 00100 #define R11_HF_THRESHOLD 45 // Rule 11 high frequency noise threshold. 00101 #define R11_MA_THRESHOLD 14 // Rule 11 motion artifact threshold. 00102 #define R11_BC_LIM 1 // Rule 11 beat count limit. 00103 #define R15_DI_THRESHOLD 3.5 // Rule 15 dominant similarity index threshold 00104 #define R15_WIDTH_THRESHOLD BEAT_MS100 // Rule 15 width threshold. 00105 #define R16_WIDTH_THRESHOLD BEAT_MS100 // Rule 16 width threshold. 00106 #define R17_WIDTH_DELTA BEAT_MS20 // Rule 17 difference threshold. 00107 #define R18_DI_THRESHOLD 1.5 // Rule 18 dominant similarity index threshold. 00108 #define R19_HF_THRESHOLD 75 // Rule 19 high frequency noise threshold. 00109 00110 // Dominant monitor constants. 00111 00112 #define DM_BUFFER_LENGTH 180 00113 #define IRREG_RR_LIMIT 60 00114 00115 // Local prototypes. 00116 00117 int HFNoiseCheck(int *beat) ; 00118 int TempClass(int rhythmClass, int morphType, int beatWidth, int domWidth, 00119 int domType, int hfNoise, int noiseLevel, int blShift, double domIndex) ; 00120 int DomMonitor(int morphType, int rhythmClass, int beatWidth, int rr, int reset) ; 00121 int GetDomRhythm(void) ; 00122 int GetRunCount(void) ; 00123 00124 // Local Global variables 00125 00126 int DomType ; 00127 int RecentRRs[8], RecentTypes[8] ; 00128 00129 /*************************************************************************** 00130 * Classify() takes a beat buffer, the previous rr interval, and the present 00131 * noise level estimate and returns a beat classification of NORMAL, PVC, or 00132 * UNKNOWN. The UNKNOWN classification is only returned. The beat template 00133 * type that the beat has been matched to is returned through the pointer 00134 * *beatMatch for debugging display. Passing anything other than 0 in init 00135 * resets the static variables used by Classify. 00136 ****************************************************************************/ 00137 00138 int Classify(int *newBeat,int rr, int noiseLevel, int *beatMatch, int *fidAdj, 00139 int init) 00140 { 00141 int rhythmClass, beatClass, i, beatWidth, blShift ; 00142 static int morphType, runCount = 0 ; 00143 double matchIndex, domIndex, mi2 ; 00144 int shiftAdj ; 00145 int domType, domWidth, onset, offset, amp ; 00146 int beatBegin, beatEnd, tempClass ; 00147 int hfNoise, isoLevel ; 00148 static int lastIsoLevel=0, lastRhythmClass = UNKNOWN, lastBeatWasNew = 0 ; 00149 00150 // If initializing... 00151 00152 if(init) 00153 { 00154 ResetRhythmChk() ; 00155 ResetMatch() ; 00156 ResetPostClassify() ; 00157 runCount = 0 ; 00158 DomMonitor(0, 0, 0, 0, 1) ; 00159 return(0) ; 00160 } 00161 00162 hfNoise = HFNoiseCheck(newBeat) ; // Check for muscle noise. 00163 rhythmClass = RhythmChk(rr) ; // Check the rhythm. 00164 00165 // Estimate beat features. 00166 00167 AnalyzeBeat(newBeat, &onset, &offset, &isoLevel, 00168 &beatBegin, &beatEnd, &) ; 00169 00170 blShift = abs(lastIsoLevel-isoLevel) ; 00171 lastIsoLevel = isoLevel ; 00172 00173 // Make isoelectric level 0. 00174 00175 for(i = 0; i < BEATLGTH; ++i) 00176 newBeat[i] -= isoLevel ; 00177 00178 // If there was a significant baseline shift since 00179 // the last beat and the last beat was a new type, 00180 // delete the new type because it might have resulted 00181 // from a baseline shift. 00182 00183 if( (blShift > BL_SHIFT_LIMIT) 00184 && (lastBeatWasNew == 1) 00185 && (lastRhythmClass == NORMAL) 00186 && (rhythmClass == NORMAL) ) 00187 ClearLastNewType() ; 00188 00189 lastBeatWasNew = 0 ; 00190 00191 // Find the template that best matches this beat. 00192 00193 BestMorphMatch(newBeat,&morphType,&matchIndex,&mi2,&shiftAdj) ; 00194 00195 // Disregard noise if the match is good. (New) 00196 00197 if(matchIndex < MATCH_NOISE_THRESHOLD) 00198 hfNoise = noiseLevel = blShift = 0 ; 00199 00200 // Apply a stricter match limit to premature beats. 00201 00202 if((matchIndex < MATCH_LIMIT) && (rhythmClass == PVC) && 00203 MinimumBeatVariation(morphType) && (mi2 > PVC_MATCH_WITH_AMP_LIMIT)) 00204 { 00205 morphType = NewBeatType(newBeat) ; 00206 lastBeatWasNew = 1 ; 00207 } 00208 00209 // Match if within standard match limits. 00210 00211 else if((matchIndex < MATCH_LIMIT) && (mi2 <= MATCH_WITH_AMP_LIMIT)) 00212 UpdateBeatType(morphType,newBeat,mi2,shiftAdj) ; 00213 00214 // If the beat isn't noisy but doesn't match, start a new beat. 00215 00216 else if((blShift < BL_SHIFT_LIMIT) && (noiseLevel < NEW_TYPE_NOISE_THRESHOLD) 00217 && (hfNoise < NEW_TYPE_HF_NOISE_LIMIT)) 00218 { 00219 morphType = NewBeatType(newBeat) ; 00220 lastBeatWasNew = 1 ; 00221 } 00222 00223 // Even if it is a noisy, start new beat if it was an irregular beat. 00224 00225 else if((lastRhythmClass != NORMAL) || (rhythmClass != NORMAL)) 00226 { 00227 morphType = NewBeatType(newBeat) ; 00228 lastBeatWasNew = 1 ; 00229 } 00230 00231 // If its noisy and regular, don't waste space starting a new beat. 00232 00233 else morphType = MAXTYPES ; 00234 00235 // Update recent rr and type arrays. 00236 00237 for(i = 7; i > 0; --i) 00238 { 00239 RecentRRs[i] = RecentRRs[i-1] ; 00240 RecentTypes[i] = RecentTypes[i-1] ; 00241 } 00242 RecentRRs[0] = rr ; 00243 RecentTypes[0] = morphType ; 00244 00245 lastRhythmClass = rhythmClass ; 00246 lastIsoLevel = isoLevel ; 00247 00248 // Fetch beat features needed for classification. 00249 // Get features from average beat if it matched. 00250 00251 if(morphType != MAXTYPES) 00252 { 00253 beatClass = GetBeatClass(morphType) ; 00254 beatWidth = GetBeatWidth(morphType) ; 00255 *fidAdj = GetBeatCenter(morphType)-FIDMARK ; 00256 00257 // If the width seems large and there have only been a few 00258 // beats of this type, use the actual beat for width 00259 // estimate. 00260 00261 if((beatWidth > offset-onset) && (GetBeatTypeCount(morphType) <= 4)) 00262 { 00263 beatWidth = offset-onset ; 00264 *fidAdj = ((offset+onset)/2)-FIDMARK ; 00265 } 00266 } 00267 00268 // If this beat didn't match get beat features directly 00269 // from this beat. 00270 00271 else 00272 { 00273 beatWidth = offset-onset ; 00274 beatClass = UNKNOWN ; 00275 *fidAdj = ((offset+onset)/2)-FIDMARK ; 00276 } 00277 00278 // Fetch dominant type beat features. 00279 00280 DomType = domType = DomMonitor(morphType, rhythmClass, beatWidth, rr, 0) ; 00281 domWidth = GetBeatWidth(domType) ; 00282 00283 // Compare the beat type, or actual beat to the dominant beat. 00284 00285 if((morphType != domType) && (morphType != 8)) 00286 domIndex = DomCompare(morphType,domType) ; 00287 else if(morphType == 8) 00288 domIndex = DomCompare2(newBeat,domType) ; 00289 else domIndex = matchIndex ; 00290 00291 // Update post classificaton of the previous beat. 00292 00293 PostClassify(RecentTypes, domType, RecentRRs, beatWidth, domIndex, rhythmClass) ; 00294 00295 // Classify regardless of how the morphology 00296 // was previously classified. 00297 00298 tempClass = TempClass(rhythmClass, morphType, beatWidth, domWidth, 00299 domType, hfNoise, noiseLevel, blShift, domIndex) ; 00300 00301 // If this morphology has not been classified yet, attempt to classify 00302 // it. 00303 00304 if((beatClass == UNKNOWN) && (morphType < MAXTYPES)) 00305 { 00306 00307 // Classify as normal if there are 6 in a row 00308 // or at least two in a row that meet rhythm 00309 // rules for normal. 00310 00311 runCount = GetRunCount() ; 00312 00313 // Classify a morphology as NORMAL if it is not too wide, and there 00314 // are three in a row. The width criterion prevents ventricular beats 00315 // from being classified as normal during VTACH (MIT/BIH 205). 00316 00317 if((runCount >= 3) && (domType != -1) && (beatWidth < domWidth+BEAT_MS20)) 00318 SetBeatClass(morphType,NORMAL) ; 00319 00320 // If there is no dominant type established yet, classify any type 00321 // with six in a row as NORMAL. 00322 00323 else if((runCount >= 6) && (domType == -1)) 00324 SetBeatClass(morphType,NORMAL) ; 00325 00326 // During bigeminy, classify the premature beats as ventricular if 00327 // they are not too narrow. 00328 00329 else if(IsBigeminy() == 1) 00330 { 00331 if((rhythmClass == PVC) && (beatWidth > BEAT_MS100)) 00332 SetBeatClass(morphType,PVC) ; 00333 else if(rhythmClass == NORMAL) 00334 SetBeatClass(morphType,NORMAL) ; 00335 } 00336 } 00337 00338 // Save morphology type of this beat for next classification. 00339 00340 *beatMatch = morphType ; 00341 00342 beatClass = GetBeatClass(morphType) ; 00343 00344 // If the morphology has been previously classified. 00345 // use that classification. 00346 // return(rhythmClass) ; 00347 00348 if(beatClass != UNKNOWN) 00349 return(beatClass) ; 00350 00351 if(CheckPostClass(morphType) == PVC) 00352 return(PVC) ; 00353 00354 // Otherwise use the temporary classification. 00355 00356 return(tempClass) ; 00357 } 00358 00359 /************************************************************************** 00360 * HFNoiseCheck() gauges the high frequency (muscle noise) present in the 00361 * beat template. The high frequency noise level is estimated by highpass 00362 * filtering the beat (y[n] = x[n] - 2*x[n-1] + x[n-2]), averaging the 00363 * highpass filtered signal over five samples, and finding the maximum of 00364 * this averaged highpass filtered signal. The high frequency noise metric 00365 * is then taken to be the ratio of the maximum averaged highpassed signal 00366 * to the QRS amplitude. 00367 **************************************************************************/ 00368 00369 #define AVELENGTH BEAT_MS50 00370 00371 int HFNoiseCheck(int *beat) 00372 { 00373 int maxNoiseAve = 0, i ; 00374 int sum=0, aveBuff[AVELENGTH], avePtr = 0 ; 00375 int qrsMax = 0, qrsMin = 0 ; 00376 00377 // Determine the QRS amplitude. 00378 00379 for(i = FIDMARK-BEAT_MS70; i < FIDMARK+BEAT_MS80; ++i) 00380 if(beat[i] > qrsMax) 00381 qrsMax = beat[i] ; 00382 else if(beat[i] < qrsMin) 00383 qrsMin = beat[i] ; 00384 00385 for(i = 0; i < AVELENGTH; ++i) 00386 aveBuff[i] = 0 ; 00387 00388 for(i = FIDMARK-BEAT_MS280; i < FIDMARK+BEAT_MS280; ++i) 00389 { 00390 sum -= aveBuff[avePtr] ; 00391 aveBuff[avePtr] = abs(beat[i] - (beat[i-BEAT_MS10]<<1) + beat[i-2*BEAT_MS10]) ; 00392 sum += aveBuff[avePtr] ; 00393 if(++avePtr == AVELENGTH) 00394 avePtr = 0 ; 00395 if((i < (FIDMARK - BEAT_MS50)) || (i > (FIDMARK + BEAT_MS110))) 00396 if(sum > maxNoiseAve) 00397 maxNoiseAve = sum ; 00398 } 00399 if((qrsMax - qrsMin)>=4) 00400 return((maxNoiseAve * (50/AVELENGTH))/((qrsMax-qrsMin)>>2)) ; 00401 else return(0) ; 00402 } 00403 00404 /************************************************************************ 00405 * TempClass() classifies beats based on their beat features, relative 00406 * to the features of the dominant beat and the present noise level. 00407 *************************************************************************/ 00408 00409 int TempClass(int rhythmClass, int morphType, 00410 int beatWidth, int domWidth, int domType, 00411 int hfNoise, int noiseLevel, int blShift, double domIndex) 00412 { 00413 00414 // Rule 1: If no dominant type has been detected classify all 00415 // beats as UNKNOWN. 00416 00417 if(domType < 0) 00418 return(UNKNOWN) ; 00419 00420 // Rule 2: If the dominant rhythm is normal, the dominant 00421 // beat type doesn't vary much, this beat is premature 00422 // and looks sufficiently different than the dominant beat 00423 // classify as PVC. 00424 00425 if(MinimumBeatVariation(domType) && (rhythmClass == PVC) 00426 && (domIndex > R2_DI_THRESHOLD) && (GetDomRhythm() == 1)) 00427 return(PVC) ; 00428 00429 // Rule 3: If the beat is sufficiently narrow, classify as normal. 00430 00431 if(beatWidth < R3_WIDTH_THRESHOLD) 00432 return(NORMAL) ; 00433 00434 // Rule 5: If the beat cannot be matched to any previously 00435 // detected morphology and it is not premature, consider it normal 00436 // (probably noisy). 00437 00438 if((morphType == MAXTYPES) && (rhythmClass != PVC)) // == UNKNOWN 00439 return(NORMAL) ; 00440 00441 // Rule 6: If the maximum number of beat types have been stored, 00442 // this beat is not regular or premature and only one 00443 // beat of this morphology has been seen, call it normal (probably 00444 // noisy). 00445 00446 if((GetTypesCount() == MAXTYPES) && (GetBeatTypeCount(morphType)==1) 00447 && (rhythmClass == UNKNOWN)) 00448 return(NORMAL) ; 00449 00450 // Rule 7: If this beat looks like the dominant beat and the 00451 // rhythm is regular, call it normal. 00452 00453 if((domIndex < R7_DI_THRESHOLD) && (rhythmClass == NORMAL)) 00454 return(NORMAL) ; 00455 00456 // Rule 8: If post classification rhythm is normal for this 00457 // type and its shape is close to the dominant shape, classify 00458 // as normal. 00459 00460 if((domIndex < R8_DI_THRESHOLD) && (CheckPCRhythm(morphType) == NORMAL)) 00461 return(NORMAL) ; 00462 00463 // Rule 9: If the beat is not premature, it looks similar to the dominant 00464 // beat type, and the dominant beat type is variable (noisy), classify as 00465 // normal. 00466 00467 if((domIndex < R9_DI_THRESHOLD) && (rhythmClass != PVC) && WideBeatVariation(domType)) 00468 return(NORMAL) ; 00469 00470 // Rule 10: If this beat is significantly different from the dominant beat 00471 // there have previously been matching beats, the post rhythm classification 00472 // of this type is PVC, and the dominant rhythm is regular, classify as PVC. 00473 00474 if((domIndex > R10_DI_THRESHOLD) 00475 && (GetBeatTypeCount(morphType) >= R10_BC_LIM) && 00476 (CheckPCRhythm(morphType) == PVC) && (GetDomRhythm() == 1)) 00477 return(PVC) ; 00478 00479 // Rule 11: if the beat is wide, wider than the dominant beat, doesn't 00480 // appear to be noisy, and matches a previous type, classify it as 00481 // a PVC. 00482 00483 if( (beatWidth >= R11_MIN_WIDTH) && 00484 (((beatWidth - domWidth >= R11_WIDTH_DIFF1) && (domWidth < R11_WIDTH_BREAK)) || 00485 (beatWidth - domWidth >= R11_WIDTH_DIFF2)) && 00486 (hfNoise < R11_HF_THRESHOLD) && (noiseLevel < R11_MA_THRESHOLD) && (blShift < BL_SHIFT_LIMIT) && 00487 (morphType < MAXTYPES) && (GetBeatTypeCount(morphType) > R11_BC_LIM)) // Rev 1.1 00488 00489 return(PVC) ; 00490 00491 // Rule 12: If the dominant rhythm is regular and this beat is premature 00492 // then classify as PVC. 00493 00494 if((rhythmClass == PVC) && (GetDomRhythm() == 1)) 00495 return(PVC) ; 00496 00497 // Rule 14: If the beat is regular and the dominant rhythm is regular 00498 // call the beat normal. 00499 00500 if((rhythmClass == NORMAL) && (GetDomRhythm() == 1)) 00501 return(NORMAL) ; 00502 00503 // By this point, we know that rhythm will not help us, so we 00504 // have to classify based on width and similarity to the dominant 00505 // beat type. 00506 00507 // Rule 15: If the beat is wider than normal, wide on an 00508 // absolute scale, and significantly different from the 00509 // dominant beat, call it a PVC. 00510 00511 if((beatWidth > domWidth) && (domIndex > R15_DI_THRESHOLD) && 00512 (beatWidth >= R15_WIDTH_THRESHOLD)) 00513 return(PVC) ; 00514 00515 // Rule 16: If the beat is sufficiently narrow, call it normal. 00516 00517 if(beatWidth < R16_WIDTH_THRESHOLD) 00518 return(NORMAL) ; 00519 00520 // Rule 17: If the beat isn't much wider than the dominant beat 00521 // call it normal. 00522 00523 if(beatWidth < domWidth + R17_WIDTH_DELTA) 00524 return(NORMAL) ; 00525 00526 // If the beat is noisy but reasonably close to dominant, 00527 // call it normal. 00528 00529 // Rule 18: If the beat is similar to the dominant beat, call it normal. 00530 00531 if(domIndex < R18_DI_THRESHOLD) 00532 return(NORMAL) ; 00533 00534 // If it's noisy don't trust the width. 00535 00536 // Rule 19: If the beat is noisy, we can't trust our width estimate 00537 // and we have no useful rhythm information, so guess normal. 00538 00539 if(hfNoise > R19_HF_THRESHOLD) 00540 return(NORMAL) ; 00541 00542 // Rule 20: By this point, we have no rhythm information, the beat 00543 // isn't particularly narrow, the beat isn't particulary similar to 00544 // the dominant beat, so guess a PVC. 00545 00546 return(PVC) ; 00547 00548 } 00549 00550 00551 /**************************************************************************** 00552 * DomMonitor, monitors which beat morphology is considered to be dominant. 00553 * The dominant morphology is the beat morphology that has been most frequently 00554 * classified as normal over the course of the last 120 beats. The dominant 00555 * beat rhythm is classified as regular if at least 3/4 of the dominant beats 00556 * have been classified as regular. 00557 *******************************************************************************/ 00558 00559 #define DM_BUFFER_LENGTH 180 00560 00561 int NewDom, DomRhythm ; 00562 int DMBeatTypes[DM_BUFFER_LENGTH], DMBeatClasses[DM_BUFFER_LENGTH] ; 00563 int DMBeatRhythms[DM_BUFFER_LENGTH] ; 00564 int DMNormCounts[8], DMBeatCounts[8], DMIrregCount = 0 ; 00565 00566 int DomMonitor(int morphType, int rhythmClass, int beatWidth, int rr, int reset) 00567 { 00568 static int brIndex = 0 ; 00569 int i, oldType, runCount, dom, max ; 00570 00571 // Fetch the type of the beat before the last beat. 00572 00573 i = brIndex - 2 ; 00574 if(i < 0) 00575 i += DM_BUFFER_LENGTH ; 00576 oldType = DMBeatTypes[i] ; 00577 00578 // If reset flag is set, reset beat type counts and 00579 // beat information buffers. 00580 00581 if(reset != 0) 00582 { 00583 for(i = 0; i < DM_BUFFER_LENGTH; ++i) 00584 { 00585 DMBeatTypes[i] = -1 ; 00586 DMBeatClasses[i] = 0 ; 00587 } 00588 00589 for(i = 0; i < 8; ++i) 00590 { 00591 DMNormCounts[i] = 0 ; 00592 DMBeatCounts[i] = 0 ; 00593 } 00594 DMIrregCount = 0 ; 00595 return(0) ; 00596 } 00597 00598 // Once we have wrapped around, subtract old beat types from 00599 // the beat counts. 00600 00601 if((DMBeatTypes[brIndex] != -1) && (DMBeatTypes[brIndex] != MAXTYPES)) 00602 { 00603 --DMBeatCounts[DMBeatTypes[brIndex]] ; 00604 DMNormCounts[DMBeatTypes[brIndex]] -= DMBeatClasses[brIndex] ; 00605 if(DMBeatRhythms[brIndex] == UNKNOWN) 00606 --DMIrregCount ; 00607 } 00608 00609 // If this is a morphology that has been detected before, decide 00610 // (for the purposes of selecting the dominant normal beattype) 00611 // whether it is normal or not and update the approporiate counts. 00612 00613 if(morphType != 8) 00614 { 00615 00616 // Update the buffers of previous beats and increment the 00617 // count for this beat type. 00618 00619 DMBeatTypes[brIndex] = morphType ; 00620 ++DMBeatCounts[morphType] ; 00621 DMBeatRhythms[brIndex] = rhythmClass ; 00622 00623 // If the rhythm appears regular, update the regular rhythm 00624 // count. 00625 00626 if(rhythmClass == UNKNOWN) 00627 ++DMIrregCount ; 00628 00629 // Check to see how many beats of this type have occurred in 00630 // a row (stop counting at six). 00631 00632 i = brIndex - 1 ; 00633 if(i < 0) i += DM_BUFFER_LENGTH ; 00634 for(runCount = 0; (DMBeatTypes[i] == morphType) && (runCount < 6); ++runCount) 00635 if(--i < 0) i += DM_BUFFER_LENGTH ; 00636 00637 // If the rhythm is regular, the beat width is less than 130 ms, and 00638 // there have been at least two in a row, consider the beat to be 00639 // normal. 00640 00641 if((rhythmClass == NORMAL) && (beatWidth < BEAT_MS130) && (runCount >= 1)) 00642 { 00643 DMBeatClasses[brIndex] = 1 ; 00644 ++DMNormCounts[morphType] ; 00645 } 00646 00647 // If the last beat was within the normal P-R interval for this beat, 00648 // and the one before that was this beat type, assume the last beat 00649 // was noise and this beat is normal. 00650 00651 else if(rr < ((FIDMARK-GetBeatBegin(morphType))*SAMPLE_RATE/BEAT_SAMPLE_RATE) 00652 && (oldType == morphType)) 00653 { 00654 DMBeatClasses[brIndex] = 1 ; 00655 ++DMNormCounts[morphType] ; 00656 } 00657 00658 // Otherwise assume that this is not a normal beat. 00659 00660 else DMBeatClasses[brIndex] = 0 ; 00661 } 00662 00663 // If the beat does not match any of the beat types, store 00664 // an indication that the beat does not match. 00665 00666 else 00667 { 00668 DMBeatClasses[brIndex] = 0 ; 00669 DMBeatTypes[brIndex] = -1 ; 00670 } 00671 00672 // Increment the index to the beginning of the circular buffers. 00673 00674 if(++brIndex == DM_BUFFER_LENGTH) 00675 brIndex = 0 ; 00676 00677 // Determine which beat type has the most beats that seem 00678 // normal. 00679 00680 dom = 0 ; 00681 for(i = 1; i < 8; ++i) 00682 if(DMNormCounts[i] > DMNormCounts[dom]) 00683 dom = i ; 00684 00685 max = 0 ; 00686 for(i = 1; i < 8; ++i) 00687 if(DMBeatCounts[i] > DMBeatCounts[max]) 00688 max = i ; 00689 00690 // If there are no normal looking beats, fall back on which beat 00691 // has occurred most frequently since classification began. 00692 00693 if((DMNormCounts[dom] == 0) || (DMBeatCounts[max]/DMBeatCounts[dom] >= 2)) // == 0 00694 dom = GetDominantType() ; 00695 00696 // If at least half of the most frequently occuring normal 00697 // type do not seem normal, fall back on choosing the most frequently 00698 // occurring type since classification began. 00699 00700 else if(DMBeatCounts[dom]/DMNormCounts[dom] >= 2) 00701 dom = GetDominantType() ; 00702 00703 // If there is any beat type that has been classfied as normal, 00704 // but at least 10 don't seem normal, reclassify it to UNKNOWN. 00705 00706 for(i = 0; i < 8; ++i) 00707 if((DMBeatCounts[i] > 10) && (DMNormCounts[i] == 0) && (i != dom) 00708 && (GetBeatClass(i) == NORMAL)) 00709 SetBeatClass(i,UNKNOWN) ; 00710 00711 // Save the dominant type in a global variable so that it is 00712 // accessable for debugging. 00713 00714 NewDom = dom ; 00715 return(dom) ; 00716 } 00717 00718 int GetNewDominantType(void) 00719 { 00720 return(NewDom) ; 00721 } 00722 00723 int GetDomRhythm(void) 00724 { 00725 if(DMIrregCount > IRREG_RR_LIMIT) 00726 return(0) ; 00727 else return(1) ; 00728 } 00729 00730 00731 void AdjustDomData(int oldType, int newType) 00732 { 00733 int i ; 00734 00735 for(i = 0; i < DM_BUFFER_LENGTH; ++i) 00736 { 00737 if(DMBeatTypes[i] == oldType) 00738 DMBeatTypes[i] = newType ; 00739 } 00740 00741 if(newType != MAXTYPES) 00742 { 00743 DMNormCounts[newType] = DMNormCounts[oldType] ; 00744 DMBeatCounts[newType] = DMBeatCounts[oldType] ; 00745 } 00746 00747 DMNormCounts[oldType] = DMBeatCounts[oldType] = 0 ; 00748 00749 } 00750 00751 void CombineDomData(int oldType, int newType) 00752 { 00753 int i ; 00754 00755 for(i = 0; i < DM_BUFFER_LENGTH; ++i) 00756 { 00757 if(DMBeatTypes[i] == oldType) 00758 DMBeatTypes[i] = newType ; 00759 } 00760 00761 if(newType != MAXTYPES) 00762 { 00763 DMNormCounts[newType] += DMNormCounts[oldType] ; 00764 DMBeatCounts[newType] += DMBeatCounts[oldType] ; 00765 } 00766 00767 DMNormCounts[oldType] = DMBeatCounts[oldType] = 0 ; 00768 00769 } 00770 00771 /*********************************************************************** 00772 GetRunCount() checks how many of the present beat type have occurred 00773 in a row. 00774 ***********************************************************************/ 00775 00776 int GetRunCount() 00777 { 00778 int i ; 00779 for(i = 1; (i < 8) && (RecentTypes[0] == RecentTypes[i]); ++i) ; 00780 return(i) ; 00781 } 00782 00783 00784 00785 00786 00787 00788 00789 00790 00791 00792
Generated on Sun Jul 24 2022 05:18:21 by
1.7.2
