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
match.cpp
00001 /***************************************************************************** 00002 FILE: match.cpp 00003 AUTHOR: Patrick S. Hamilton 00004 REVISED: 5/13/2002 00005 ___________________________________________________________________________ 00006 00007 match.cpp: Match beats to previous beats. 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 Match.cpp contains functions for managing template matching of beats and 00031 managing of feature data associated with each beat type. These 00032 functions are called functions in classify.cpp. Beats are matched to 00033 previoiusly detected beats types based on how well they match point by point 00034 in a MATCH_LENGTH region centered on FIDMARK (R-wave location). The following 00035 is a list of functions that are available for calling by classify. 00036 00037 ResetMatch -- Resets global variables used in template matching. 00038 CompareBeats -- Measures the difference between two beats with 00039 beats scaled to produce the best match. 00040 CompareBeats2 -- Measures the difference between two beats without 00041 beat scaling. 00042 NewBeatType -- Start a new beat type with the present beat. 00043 BestMorphMatch -- Finds the beat template that best matches a new beat. 00044 UpdateBeatType -- Updates existing beat template and associated features 00045 based on a new beat. 00046 GetDominantType -- Returns the NORMAL beat type that has occorred most often. 00047 ClearLastNewType -- Removes the last new beat type from the possible beat 00048 types. 00049 DomCompare -- Compares the template for a given beat type to the template 00050 of the dominant normal beat type. 00051 DomCompare2 -- Compares a given beat template to the templat of the 00052 dominant normal beat type. 00053 00054 PostClassify -- Classifies beats based on preceding and following beats 00055 and R-to-R intervals. 00056 00057 ResetPostClassify -- Resets variables used for post classification. 00058 00059 CheckPostClass -- Check type classification based on last eight post 00060 classifications. 00061 00062 CheckPCClass -- Check post beat rhythm classification for the last eight 00063 beats. 00064 00065 A number of simple functions allow access to beat features while maintaining 00066 some level of encapsulation: 00067 00068 GetTypesCount -- Returns number of beat types that have been detected. 00069 GetBeatTypeCount -- Returns the number of beats of a given type 00070 that have been detected. 00071 GetBeatWidth -- Returns the width estimate for a given beat type. 00072 SetBeatClass -- Associates a beat classification with a beat type. 00073 GetBeatBegin -- Returns the beginning point for a given beat type. 00074 GetBeatEnd -- Returns the ending point for a given beat type. 00075 00076 ******************************************************************************/ 00077 //#include <stdlib.h> 00078 //#include <stdio.h> 00079 #include <mbed.h> 00080 #include "ecgcodes.h" 00081 00082 #include "bdac.h" 00083 #define MATCH_LENGTH BEAT_MS300 // Number of points used for beat matching. 00084 #define MATCH_LIMIT 1.2 // Match limit used testing whether two 00085 // beat types might be combined. 00086 #define COMBINE_LIMIT 0.8 // Limit used for deciding whether two types 00087 // can be combined. 00088 00089 #define MATCH_START (FIDMARK-(MATCH_LENGTH/2)) // Starting point for beat matching 00090 #define MATCH_END (FIDMARK+(MATCH_LENGTH/2)) // End point for beat matching. 00091 #define MAXPREV 8 // Number of preceeding beats used as beat features. 00092 #define MAX_SHIFT BEAT_MS40 00093 00094 // Local prototypes. 00095 00096 int NoiseCheck(int *beat) ; 00097 double CompareBeats(int *beat1, int *beat2, int *shiftAdj) ; 00098 double CompareBeats2(int *beat1, int *beat2, int *shiftAdj) ; 00099 void UpdateBeat(int *aveBeat, int *newBeat, int shift) ; 00100 void BeatCopy(int srcBeat, int destBeat) ; 00101 int MinimumBeatVariation(int type) ; 00102 00103 // External prototypes. 00104 00105 void AnalyzeBeat(int *beat, int *onset, int *offset, int *isoLevel, 00106 int *beatBegin, int *beatEnd, int *amp) ; 00107 void AdjustDomData(int oldType, int newType) ; 00108 void CombineDomData(int oldType, int newType) ; 00109 00110 // Global variables. 00111 00112 int BeatTemplates[MAXTYPES][BEATLGTH] ; 00113 int BeatCounts[MAXTYPES] ; 00114 int BeatWidths[MAXTYPES] ; 00115 int BeatClassifications[MAXTYPES] ; 00116 int BeatBegins[MAXTYPES] ; 00117 int BeatEnds[MAXTYPES] ; 00118 int BeatsSinceLastMatch[MAXTYPES] ; 00119 int BeatAmps[MAXTYPES] ; 00120 int BeatCenters[MAXTYPES] ; 00121 double MIs[MAXTYPES][8] ; 00122 00123 // Need access to these in postclas.cpp when beat types are combined 00124 // and moved. 00125 00126 extern int PostClass[MAXTYPES][8] ; 00127 extern int PCRhythm[MAXTYPES][8] ; 00128 00129 int TypeCount = 0 ; 00130 00131 /*************************************************************************** 00132 ResetMatch() resets static variables involved with template matching. 00133 ****************************************************************************/ 00134 00135 void ResetMatch(void) 00136 { 00137 int i, j ; 00138 TypeCount = 0 ; 00139 for(i = 0; i < MAXTYPES; ++i) 00140 { 00141 BeatCounts[i] = 0 ; 00142 BeatClassifications[i] = UNKNOWN ; 00143 for(j = 0; j < 8; ++j) 00144 { 00145 MIs[i][j] = 0 ; 00146 } 00147 } 00148 } 00149 00150 /************************************************************************** 00151 CompareBeats() takes two beat buffers and compares how well they match 00152 point-by-point. Beat2 is shifted and scaled to produce the closest 00153 possible match. The metric returned is the sum of the absolute 00154 differences between beats divided by the amplitude of the beats. The 00155 shift used for the match is returned via the pointer *shiftAdj. 00156 ***************************************************************************/ 00157 00158 #define MATCH_START (FIDMARK-(MATCH_LENGTH/2)) 00159 #define MATCH_END (FIDMARK+(MATCH_LENGTH/2)) 00160 00161 double CompareBeats(int *beat1, int *beat2, int *shiftAdj) 00162 { 00163 int i, max, min, magSum, shift ; 00164 long beatDiff, meanDiff, minDiff, minShift ; 00165 double metric, scaleFactor, tempD ; 00166 00167 // Calculate the magnitude of each beat. 00168 00169 max = min = beat1[MATCH_START] ; 00170 for(i = MATCH_START+1; i < MATCH_END; ++i) 00171 if(beat1[i] > max) 00172 max = beat1[i] ; 00173 else if(beat1[i] < min) 00174 min = beat1[i] ; 00175 00176 magSum = max - min ; 00177 00178 i = MATCH_START ; 00179 max = min = beat2[i] ; 00180 for(i = MATCH_START+1; i < MATCH_END; ++i) 00181 if(beat2[i] > max) 00182 max = beat2[i] ; 00183 else if(beat2[i] < min) 00184 min = beat2[i] ; 00185 00186 // magSum += max - min ; 00187 scaleFactor = magSum ; 00188 scaleFactor /= max-min ; 00189 magSum *= 2 ; 00190 00191 // Calculate the sum of the point-by-point 00192 // absolute differences for five possible shifts. 00193 00194 for(shift = -MAX_SHIFT; shift <= MAX_SHIFT; ++shift) 00195 { 00196 for(i = FIDMARK-(MATCH_LENGTH>>1), meanDiff = 0; 00197 i < FIDMARK + (MATCH_LENGTH>>1); ++i) 00198 { 00199 tempD = beat2[i+shift] ; 00200 tempD *= scaleFactor ; 00201 meanDiff += beat1[i]- tempD ; // beat2[i+shift] ; 00202 } 00203 meanDiff /= MATCH_LENGTH ; 00204 00205 for(i = FIDMARK-(MATCH_LENGTH>>1), beatDiff = 0; 00206 i < FIDMARK + (MATCH_LENGTH>>1); ++i) 00207 { 00208 tempD = beat2[i+shift] ; 00209 tempD *= scaleFactor ; 00210 beatDiff += abs(beat1[i] - meanDiff- tempD) ; // beat2[i+shift] ) ; 00211 } 00212 00213 00214 if(shift == -MAX_SHIFT) 00215 { 00216 minDiff = beatDiff ; 00217 minShift = -MAX_SHIFT ; 00218 } 00219 else if(beatDiff < minDiff) 00220 { 00221 minDiff = beatDiff ; 00222 minShift = shift ; 00223 } 00224 } 00225 00226 metric = minDiff ; 00227 *shiftAdj = minShift ; 00228 metric /= magSum ; 00229 00230 // Metric scales inversely with match length. 00231 // algorithm was originally tuned with a match 00232 // length of 30. 00233 00234 metric *= 30 ; 00235 metric /= MATCH_LENGTH ; 00236 return(metric) ; 00237 } 00238 00239 /*************************************************************************** 00240 CompareBeats2 is nearly the same as CompareBeats above, but beat2 is 00241 not scaled before calculating the match metric. The match metric is 00242 then the sum of the absolute differences divided by the average amplitude 00243 of the two beats. 00244 ****************************************************************************/ 00245 00246 double CompareBeats2(int *beat1, int *beat2, int *shiftAdj) 00247 { 00248 int i, max, min, shift ; 00249 int mag1, mag2 ; 00250 long beatDiff, meanDiff, minDiff, minShift ; 00251 double metric ; 00252 00253 // Calculate the magnitude of each beat. 00254 00255 max = min = beat1[MATCH_START] ; 00256 for(i = MATCH_START+1; i < MATCH_END; ++i) 00257 if(beat1[i] > max) 00258 max = beat1[i] ; 00259 else if(beat1[i] < min) 00260 min = beat1[i] ; 00261 00262 mag1 = max - min ; 00263 00264 i = MATCH_START ; 00265 max = min = beat2[i] ; 00266 for(i = MATCH_START+1; i < MATCH_END; ++i) 00267 if(beat2[i] > max) 00268 max = beat2[i] ; 00269 else if(beat2[i] < min) 00270 min = beat2[i] ; 00271 00272 mag2 = max-min ; 00273 00274 // Calculate the sum of the point-by-point 00275 // absolute differences for five possible shifts. 00276 00277 for(shift = -MAX_SHIFT; shift <= MAX_SHIFT; ++shift) 00278 { 00279 for(i = FIDMARK-(MATCH_LENGTH>>1), meanDiff = 0; 00280 i < FIDMARK + (MATCH_LENGTH>>1); ++i) 00281 meanDiff += beat1[i]- beat2[i+shift] ; 00282 meanDiff /= MATCH_LENGTH ; 00283 00284 for(i = FIDMARK-(MATCH_LENGTH>>1), beatDiff = 0; 00285 i < FIDMARK + (MATCH_LENGTH>>1); ++i) 00286 beatDiff += abs(beat1[i] - meanDiff- beat2[i+shift]) ; ; 00287 00288 if(shift == -MAX_SHIFT) 00289 { 00290 minDiff = beatDiff ; 00291 minShift = -MAX_SHIFT ; 00292 } 00293 else if(beatDiff < minDiff) 00294 { 00295 minDiff = beatDiff ; 00296 minShift = shift ; 00297 } 00298 } 00299 00300 metric = minDiff ; 00301 *shiftAdj = minShift ; 00302 metric /= (mag1+mag2) ; 00303 00304 // Metric scales inversely with match length. 00305 // algorithm was originally tuned with a match 00306 // length of 30. 00307 00308 metric *= 30 ; 00309 metric /= MATCH_LENGTH ; 00310 00311 return(metric) ; 00312 } 00313 00314 /************************************************************************ 00315 UpdateBeat() averages a new beat into an average beat template by adding 00316 1/8th of the new beat to 7/8ths of the average beat. 00317 *************************************************************************/ 00318 00319 void UpdateBeat(int *aveBeat, int *newBeat, int shift) 00320 { 00321 int i ; 00322 long tempLong ; 00323 00324 for(i = 0; i < BEATLGTH; ++i) 00325 { 00326 if((i+shift >= 0) && (i+shift < BEATLGTH)) 00327 { 00328 tempLong = aveBeat[i] ; 00329 tempLong *= 7 ; 00330 tempLong += newBeat[i+shift] ; 00331 tempLong >>= 3 ; 00332 aveBeat[i] = tempLong ; 00333 } 00334 } 00335 } 00336 00337 /******************************************************* 00338 GetTypesCount returns the number of types that have 00339 been detected. 00340 *******************************************************/ 00341 00342 int GetTypesCount(void) 00343 { 00344 return(TypeCount) ; 00345 } 00346 00347 /******************************************************** 00348 GetBeatTypeCount returns the number of beats of a 00349 a particular type have been detected. 00350 ********************************************************/ 00351 00352 int GetBeatTypeCount(int type) 00353 { 00354 return(BeatCounts[type]) ; 00355 } 00356 00357 /******************************************************* 00358 GetBeatWidth returns the QRS width estimate for 00359 a given type of beat. 00360 *******************************************************/ 00361 int GetBeatWidth(int type) 00362 { 00363 return(BeatWidths[type]) ; 00364 } 00365 00366 /******************************************************* 00367 GetBeatCenter returns the point between the onset and 00368 offset of a beat. 00369 ********************************************************/ 00370 00371 int GetBeatCenter(int type) 00372 { 00373 return(BeatCenters[type]) ; 00374 } 00375 00376 /******************************************************* 00377 GetBeatClass returns the present classification for 00378 a given beat type (NORMAL, PVC, or UNKNOWN). 00379 ********************************************************/ 00380 00381 int GetBeatClass(int type) 00382 { 00383 if(type == MAXTYPES) 00384 return(UNKNOWN) ; 00385 return(BeatClassifications[type]) ; 00386 } 00387 00388 /****************************************************** 00389 SetBeatClass sets up a beat classifation for a 00390 given type. 00391 ******************************************************/ 00392 00393 void SetBeatClass(int type, int beatClass) 00394 { 00395 BeatClassifications[type] = beatClass ; 00396 } 00397 00398 /****************************************************************************** 00399 NewBeatType starts a new beat type by storing the new beat and its 00400 features as the next available beat type. 00401 ******************************************************************************/ 00402 00403 int NewBeatType(int *newBeat ) 00404 { 00405 int i, onset, offset, isoLevel, beatBegin, beatEnd ; 00406 int mcType, amp ; 00407 00408 // Update count of beats since each template was matched. 00409 00410 for(i = 0; i < TypeCount; ++i) 00411 ++BeatsSinceLastMatch[i] ; 00412 00413 if(TypeCount < MAXTYPES) 00414 { 00415 for(i = 0; i < BEATLGTH; ++i) 00416 BeatTemplates[TypeCount][i] = newBeat[i] ; 00417 00418 BeatCounts[TypeCount] = 1 ; 00419 BeatClassifications[TypeCount] = UNKNOWN ; 00420 AnalyzeBeat(&BeatTemplates[TypeCount][0],&onset,&offset, &isoLevel, 00421 &beatBegin, &beatEnd, &) ; 00422 BeatWidths[TypeCount] = offset-onset ; 00423 BeatCenters[TypeCount] = (offset+onset)/2 ; 00424 BeatBegins[TypeCount] = beatBegin ; 00425 BeatEnds[TypeCount] = beatEnd ; 00426 BeatAmps[TypeCount] = amp ; 00427 00428 BeatsSinceLastMatch[TypeCount] = 0 ; 00429 00430 ++TypeCount ; 00431 return(TypeCount-1) ; 00432 } 00433 00434 // If we have used all the template space, replace the beat 00435 // that has occurred the fewest number of times. 00436 00437 else 00438 { 00439 // Find the template with the fewest occurances, 00440 // that hasn't been matched in at least 500 beats. 00441 00442 mcType = -1 ; 00443 00444 if(mcType == -1) 00445 { 00446 mcType = 0 ; 00447 for(i = 1; i < MAXTYPES; ++i) 00448 if(BeatCounts[i] < BeatCounts[mcType]) 00449 mcType = i ; 00450 else if(BeatCounts[i] == BeatCounts[mcType]) 00451 { 00452 if(BeatsSinceLastMatch[i] > BeatsSinceLastMatch[mcType]) 00453 mcType = i ; 00454 } 00455 } 00456 00457 // Adjust dominant beat monitor data. 00458 00459 AdjustDomData(mcType,MAXTYPES) ; 00460 00461 // Substitute this beat. 00462 00463 for(i = 0; i < BEATLGTH; ++i) 00464 BeatTemplates[mcType][i] = newBeat[i] ; 00465 00466 BeatCounts[mcType] = 1 ; 00467 BeatClassifications[mcType] = UNKNOWN ; 00468 AnalyzeBeat(&BeatTemplates[mcType][0],&onset,&offset, &isoLevel, 00469 &beatBegin, &beatEnd, &) ; 00470 BeatWidths[mcType] = offset-onset ; 00471 BeatCenters[mcType] = (offset+onset)/2 ; 00472 BeatBegins[mcType] = beatBegin ; 00473 BeatEnds[mcType] = beatEnd ; 00474 BeatsSinceLastMatch[mcType] = 0 ; 00475 BeatAmps[mcType] = amp ; 00476 return(mcType) ; 00477 } 00478 } 00479 00480 /*************************************************************************** 00481 BestMorphMatch tests a new beat against all available beat types and 00482 returns (via pointers) the existing type that best matches, the match 00483 metric for that type, and the shift used for that match. 00484 ***************************************************************************/ 00485 00486 void BestMorphMatch(int *newBeat,int *matchType,double *matchIndex, double *mi2, 00487 int *shiftAdj) 00488 { 00489 int type, i, bestMatch, nextBest, minShift, shift, temp ; 00490 int bestShift2, nextShift2 ; 00491 double bestDiff2, nextDiff2; 00492 double beatDiff, minDiff, nextDiff=10000 ; 00493 00494 if(TypeCount == 0) 00495 { 00496 *matchType = 0 ; 00497 *matchIndex = 1000 ; // Make sure there is no match so a new beat is 00498 *shiftAdj = 0 ; // created. 00499 return ; 00500 } 00501 00502 // Compare the new beat to all type beat 00503 // types that have been saved. 00504 00505 for(type = 0; type < TypeCount; ++type) 00506 { 00507 beatDiff = CompareBeats(&BeatTemplates[type][0],newBeat,&shift) ; 00508 if(type == 0) 00509 { 00510 bestMatch = 0 ; 00511 minDiff = beatDiff ; 00512 minShift = shift ; 00513 } 00514 else if(beatDiff < minDiff) 00515 { 00516 nextBest = bestMatch ; 00517 nextDiff = minDiff ; 00518 bestMatch = type ; 00519 minDiff = beatDiff ; 00520 minShift = shift ; 00521 } 00522 else if((TypeCount > 1) && (type == 1)) 00523 { 00524 nextBest = type ; 00525 nextDiff = beatDiff ; 00526 } 00527 else if(beatDiff < nextDiff) 00528 { 00529 nextBest = type ; 00530 nextDiff = beatDiff ; 00531 } 00532 } 00533 00534 // If this beat was close to two different 00535 // templates, see if the templates which template 00536 // is the best match when no scaling is used. 00537 // Then check whether the two close types can be combined. 00538 00539 if((minDiff < MATCH_LIMIT) && (nextDiff < MATCH_LIMIT) && (TypeCount > 1)) 00540 { 00541 // Compare without scaling. 00542 00543 bestDiff2 = CompareBeats2(&BeatTemplates[bestMatch][0],newBeat,&bestShift2) ; 00544 nextDiff2 = CompareBeats2(&BeatTemplates[nextBest][0],newBeat,&nextShift2) ; 00545 if(nextDiff2 < bestDiff2) 00546 { 00547 temp = bestMatch ; 00548 bestMatch = nextBest ; 00549 nextBest = temp ; 00550 temp = minDiff ; 00551 minDiff = nextDiff ; 00552 nextDiff = temp ; 00553 minShift = nextShift2 ; 00554 *mi2 = bestDiff2 ; 00555 } 00556 else *mi2 = nextDiff2 ; 00557 00558 beatDiff = CompareBeats(&BeatTemplates[bestMatch][0],&BeatTemplates[nextBest][0],&shift) ; 00559 00560 if((beatDiff < COMBINE_LIMIT) && 00561 ((*mi2 < 1.0) || (!MinimumBeatVariation(nextBest)))) 00562 { 00563 00564 // Combine beats into bestMatch 00565 00566 if(bestMatch < nextBest) 00567 { 00568 for(i = 0; i < BEATLGTH; ++i) 00569 { 00570 if((i+shift > 0) && (i + shift < BEATLGTH)) 00571 { 00572 BeatTemplates[bestMatch][i] += BeatTemplates[nextBest][i+shift] ; 00573 BeatTemplates[bestMatch][i] >>= 1 ; 00574 } 00575 } 00576 00577 if((BeatClassifications[bestMatch] == NORMAL) || (BeatClassifications[nextBest] == NORMAL)) 00578 BeatClassifications[bestMatch] = NORMAL ; 00579 else if((BeatClassifications[bestMatch] == PVC) || (BeatClassifications[nextBest] == PVC)) 00580 BeatClassifications[bestMatch] = PVC ; 00581 00582 BeatCounts[bestMatch] += BeatCounts[nextBest] ; 00583 00584 CombineDomData(nextBest,bestMatch) ; 00585 00586 // Shift other templates over. 00587 00588 for(type = nextBest; type < TypeCount-1; ++type) 00589 BeatCopy(type+1,type) ; 00590 00591 } 00592 00593 // Otherwise combine beats it nextBest. 00594 00595 else 00596 { 00597 for(i = 0; i < BEATLGTH; ++i) 00598 { 00599 BeatTemplates[nextBest][i] += BeatTemplates[bestMatch][i] ; 00600 BeatTemplates[nextBest][i] >>= 1 ; 00601 } 00602 00603 if((BeatClassifications[bestMatch] == NORMAL) || (BeatClassifications[nextBest] == NORMAL)) 00604 BeatClassifications[nextBest] = NORMAL ; 00605 else if((BeatClassifications[bestMatch] == PVC) || (BeatClassifications[nextBest] == PVC)) 00606 BeatClassifications[nextBest] = PVC ; 00607 00608 BeatCounts[nextBest] += BeatCounts[bestMatch] ; 00609 00610 CombineDomData(bestMatch,nextBest) ; 00611 00612 // Shift other templates over. 00613 00614 for(type = bestMatch; type < TypeCount-1; ++type) 00615 BeatCopy(type+1,type) ; 00616 00617 00618 bestMatch = nextBest ; 00619 } 00620 --TypeCount ; 00621 BeatClassifications[TypeCount] = UNKNOWN ; 00622 } 00623 } 00624 *mi2 = CompareBeats2(&BeatTemplates[bestMatch][0],newBeat,&bestShift2) ; 00625 *matchType = bestMatch ; 00626 *matchIndex = minDiff ; 00627 *shiftAdj = minShift ; 00628 } 00629 00630 /*************************************************************************** 00631 UpdateBeatType updates the beat template and features of a given beat type 00632 using a new beat. 00633 ***************************************************************************/ 00634 00635 void UpdateBeatType(int matchType,int *newBeat, double mi2, 00636 int shiftAdj) 00637 { 00638 int i,onset,offset, isoLevel, beatBegin, beatEnd ; 00639 int amp ; 00640 00641 // Update beats since templates were matched. 00642 00643 for(i = 0; i < TypeCount; ++i) 00644 { 00645 if(i != matchType) 00646 ++BeatsSinceLastMatch[i] ; 00647 else BeatsSinceLastMatch[i] = 0 ; 00648 } 00649 00650 // If this is only the second beat, average it with the existing 00651 // template. 00652 00653 if(BeatCounts[matchType] == 1) 00654 for(i = 0; i < BEATLGTH; ++i) 00655 { 00656 if((i+shiftAdj >= 0) && (i+shiftAdj < BEATLGTH)) 00657 BeatTemplates[matchType][i] = (BeatTemplates[matchType][i] + newBeat[i+shiftAdj])>>1 ; 00658 } 00659 00660 // Otherwise do a normal update. 00661 00662 else 00663 UpdateBeat(&BeatTemplates[matchType][0], newBeat, shiftAdj) ; 00664 00665 // Determine beat features for the new average beat. 00666 00667 AnalyzeBeat(&BeatTemplates[matchType][0],&onset,&offset,&isoLevel, 00668 &beatBegin, &beatEnd, &) ; 00669 00670 BeatWidths[matchType] = offset-onset ; 00671 BeatCenters[matchType] = (offset+onset)/2 ; 00672 BeatBegins[matchType] = beatBegin ; 00673 BeatEnds[matchType] = beatEnd ; 00674 BeatAmps[matchType] = amp ; 00675 00676 ++BeatCounts[matchType] ; 00677 00678 for(i = MAXPREV-1; i > 0; --i) 00679 MIs[matchType][i] = MIs[matchType][i-1] ; 00680 MIs[matchType][0] = mi2 ; 00681 00682 } 00683 00684 00685 /**************************************************************************** 00686 GetDominantType returns the NORMAL beat type that has occurred most 00687 frequently. 00688 ****************************************************************************/ 00689 00690 int GetDominantType(void) 00691 { 00692 int maxCount = 0, maxType = -1 ; 00693 int type, totalCount ; 00694 00695 for(type = 0; type < MAXTYPES; ++type) 00696 { 00697 if((BeatClassifications[type] == NORMAL) && (BeatCounts[type] > maxCount)) 00698 { 00699 maxType = type ; 00700 maxCount = BeatCounts[type] ; 00701 } 00702 } 00703 00704 // If no normals are found and at least 300 beats have occurred, just use 00705 // the most frequently occurring beat. 00706 00707 if(maxType == -1) 00708 { 00709 for(type = 0, totalCount = 0; type < TypeCount; ++type) 00710 totalCount += BeatCounts[type] ; 00711 if(totalCount > 300) 00712 for(type = 0; type < TypeCount; ++type) 00713 if(BeatCounts[type] > maxCount) 00714 { 00715 maxType = type ; 00716 maxCount = BeatCounts[type] ; 00717 } 00718 } 00719 00720 return(maxType) ; 00721 } 00722 00723 00724 /*********************************************************************** 00725 ClearLastNewType removes the last new type that was initiated 00726 ************************************************************************/ 00727 00728 void ClearLastNewType(void) 00729 { 00730 if(TypeCount != 0) 00731 --TypeCount ; 00732 } 00733 00734 /**************************************************************** 00735 GetBeatBegin returns the offset from the R-wave for the 00736 beginning of the beat (P-wave onset if a P-wave is found). 00737 *****************************************************************/ 00738 00739 int GetBeatBegin(int type) 00740 { 00741 return(BeatBegins[type]) ; 00742 } 00743 00744 /**************************************************************** 00745 GetBeatEnd returns the offset from the R-wave for the end of 00746 a beat (T-wave offset). 00747 *****************************************************************/ 00748 00749 int GetBeatEnd(int type) 00750 { 00751 return(BeatEnds[type]) ; 00752 } 00753 00754 int GetBeatAmp(int type) 00755 { 00756 return(BeatAmps[type]) ; 00757 } 00758 00759 00760 /************************************************************************ 00761 DomCompare2 and DomCompare return similarity indexes between a given 00762 beat and the dominant normal type or a given type and the dominant 00763 normal type. 00764 ************************************************************************/ 00765 00766 double DomCompare2(int *newBeat, int domType) 00767 { 00768 int shift ; 00769 return(CompareBeats2(&BeatTemplates[domType][0],newBeat,&shift)) ; 00770 } 00771 00772 double DomCompare(int newType, int domType) 00773 { 00774 int shift ; 00775 return(CompareBeats2(&BeatTemplates[domType][0],&BeatTemplates[newType][0], 00776 &shift)) ; 00777 } 00778 00779 /************************************************************************* 00780 BeatCopy copies beat data from a source beat to a destination beat. 00781 *************************************************************************/ 00782 00783 void BeatCopy(int srcBeat, int destBeat) 00784 { 00785 int i ; 00786 00787 // Copy template. 00788 00789 for(i = 0; i < BEATLGTH; ++i) 00790 BeatTemplates[destBeat][i] = BeatTemplates[srcBeat][i] ; 00791 00792 // Move feature information. 00793 00794 BeatCounts[destBeat] = BeatCounts[srcBeat] ; 00795 BeatWidths[destBeat] = BeatWidths[srcBeat] ; 00796 BeatCenters[destBeat] = BeatCenters[srcBeat] ; 00797 for(i = 0; i < MAXPREV; ++i) 00798 { 00799 PostClass[destBeat][i] = PostClass[srcBeat][i] ; 00800 PCRhythm[destBeat][i] = PCRhythm[srcBeat][i] ; 00801 } 00802 00803 BeatClassifications[destBeat] = BeatClassifications[srcBeat] ; 00804 BeatBegins[destBeat] = BeatBegins[srcBeat] ; 00805 BeatEnds[destBeat] = BeatBegins[srcBeat] ; 00806 BeatsSinceLastMatch[destBeat] = BeatsSinceLastMatch[srcBeat]; 00807 BeatAmps[destBeat] = BeatAmps[srcBeat] ; 00808 00809 // Adjust data in dominant beat monitor. 00810 00811 AdjustDomData(srcBeat,destBeat) ; 00812 } 00813 00814 /******************************************************************** 00815 Minimum beat variation returns a 1 if the previous eight beats 00816 have all had similarity indexes less than 0.5. 00817 *********************************************************************/ 00818 00819 int MinimumBeatVariation(int type) 00820 { 00821 int i ; 00822 for(i = 0; i < MAXTYPES; ++i) 00823 if(MIs[type][i] > 0.5) 00824 i = MAXTYPES+2 ; 00825 if(i == MAXTYPES) 00826 return(1) ; 00827 else return(0) ; 00828 } 00829 00830 /********************************************************************** 00831 WideBeatVariation returns true if the average similarity index 00832 for a given beat type to its template is greater than WIDE_VAR_LIMIT. 00833 ***********************************************************************/ 00834 00835 #define WIDE_VAR_LIMIT 0.50 00836 00837 int WideBeatVariation(int type) 00838 { 00839 int i, n ; 00840 double aveMI ; 00841 00842 n = BeatCounts[type] ; 00843 if(n > 8) 00844 n = 8 ; 00845 00846 for(i = 0, aveMI = 0; i <n; ++i) 00847 aveMI += MIs[type][i] ; 00848 00849 aveMI /= n ; 00850 if(aveMI > WIDE_VAR_LIMIT) 00851 return(1) ; 00852 else return(0) ; 00853 } 00854 00855 00856
Generated on Sun Jul 24 2022 05:18:21 by
1.7.2
