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: match.cpp
roysandberg 62:8e2fbe131b53 3 AUTHOR: Patrick S. Hamilton
roysandberg 62:8e2fbe131b53 4 REVISED: 5/13/2002
roysandberg 62:8e2fbe131b53 5 ___________________________________________________________________________
roysandberg 62:8e2fbe131b53 6
roysandberg 62:8e2fbe131b53 7 match.cpp: Match beats to previous beats.
roysandberg 62:8e2fbe131b53 8 Copywrite (C) 2001 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 Match.cpp contains functions for managing template matching of beats and
roysandberg 62:8e2fbe131b53 31 managing of feature data associated with each beat type. These
roysandberg 62:8e2fbe131b53 32 functions are called functions in classify.cpp. Beats are matched to
roysandberg 62:8e2fbe131b53 33 previoiusly detected beats types based on how well they match point by point
roysandberg 62:8e2fbe131b53 34 in a MATCH_LENGTH region centered on FIDMARK (R-wave location). The following
roysandberg 62:8e2fbe131b53 35 is a list of functions that are available for calling by classify.
roysandberg 62:8e2fbe131b53 36
roysandberg 62:8e2fbe131b53 37 ResetMatch -- Resets global variables used in template matching.
roysandberg 62:8e2fbe131b53 38 CompareBeats -- Measures the difference between two beats with
roysandberg 62:8e2fbe131b53 39 beats scaled to produce the best match.
roysandberg 62:8e2fbe131b53 40 CompareBeats2 -- Measures the difference between two beats without
roysandberg 62:8e2fbe131b53 41 beat scaling.
roysandberg 62:8e2fbe131b53 42 NewBeatType -- Start a new beat type with the present beat.
roysandberg 62:8e2fbe131b53 43 BestMorphMatch -- Finds the beat template that best matches a new beat.
roysandberg 62:8e2fbe131b53 44 UpdateBeatType -- Updates existing beat template and associated features
roysandberg 62:8e2fbe131b53 45 based on a new beat.
roysandberg 62:8e2fbe131b53 46 GetDominantType -- Returns the NORMAL beat type that has occorred most often.
roysandberg 62:8e2fbe131b53 47 ClearLastNewType -- Removes the last new beat type from the possible beat
roysandberg 62:8e2fbe131b53 48 types.
roysandberg 62:8e2fbe131b53 49 DomCompare -- Compares the template for a given beat type to the template
roysandberg 62:8e2fbe131b53 50 of the dominant normal beat type.
roysandberg 62:8e2fbe131b53 51 DomCompare2 -- Compares a given beat template to the templat of the
roysandberg 62:8e2fbe131b53 52 dominant normal beat type.
roysandberg 62:8e2fbe131b53 53
roysandberg 62:8e2fbe131b53 54 PostClassify -- Classifies beats based on preceding and following beats
roysandberg 62:8e2fbe131b53 55 and R-to-R intervals.
roysandberg 62:8e2fbe131b53 56
roysandberg 62:8e2fbe131b53 57 ResetPostClassify -- Resets variables used for post classification.
roysandberg 62:8e2fbe131b53 58
roysandberg 62:8e2fbe131b53 59 CheckPostClass -- Check type classification based on last eight post
roysandberg 62:8e2fbe131b53 60 classifications.
roysandberg 62:8e2fbe131b53 61
roysandberg 62:8e2fbe131b53 62 CheckPCClass -- Check post beat rhythm classification for the last eight
roysandberg 62:8e2fbe131b53 63 beats.
roysandberg 62:8e2fbe131b53 64
roysandberg 62:8e2fbe131b53 65 A number of simple functions allow access to beat features while maintaining
roysandberg 62:8e2fbe131b53 66 some level of encapsulation:
roysandberg 62:8e2fbe131b53 67
roysandberg 62:8e2fbe131b53 68 GetTypesCount -- Returns number of beat types that have been detected.
roysandberg 62:8e2fbe131b53 69 GetBeatTypeCount -- Returns the number of beats of a given type
roysandberg 62:8e2fbe131b53 70 that have been detected.
roysandberg 62:8e2fbe131b53 71 GetBeatWidth -- Returns the width estimate for a given beat type.
roysandberg 62:8e2fbe131b53 72 SetBeatClass -- Associates a beat classification with a beat type.
roysandberg 62:8e2fbe131b53 73 GetBeatBegin -- Returns the beginning point for a given beat type.
roysandberg 62:8e2fbe131b53 74 GetBeatEnd -- Returns the ending point for a given beat type.
roysandberg 62:8e2fbe131b53 75
roysandberg 62:8e2fbe131b53 76 ******************************************************************************/
roysandberg 62:8e2fbe131b53 77 //#include <stdlib.h>
roysandberg 62:8e2fbe131b53 78 //#include <stdio.h>
roysandberg 62:8e2fbe131b53 79 #include <mbed.h>
roysandberg 62:8e2fbe131b53 80 #include "ecgcodes.h"
roysandberg 62:8e2fbe131b53 81
roysandberg 62:8e2fbe131b53 82 #include "bdac.h"
roysandberg 62:8e2fbe131b53 83 #define MATCH_LENGTH BEAT_MS300 // Number of points used for beat matching.
roysandberg 62:8e2fbe131b53 84 #define MATCH_LIMIT 1.2 // Match limit used testing whether two
roysandberg 62:8e2fbe131b53 85 // beat types might be combined.
roysandberg 62:8e2fbe131b53 86 #define COMBINE_LIMIT 0.8 // Limit used for deciding whether two types
roysandberg 62:8e2fbe131b53 87 // can be combined.
roysandberg 62:8e2fbe131b53 88
roysandberg 62:8e2fbe131b53 89 #define MATCH_START (FIDMARK-(MATCH_LENGTH/2)) // Starting point for beat matching
roysandberg 62:8e2fbe131b53 90 #define MATCH_END (FIDMARK+(MATCH_LENGTH/2)) // End point for beat matching.
roysandberg 62:8e2fbe131b53 91 #define MAXPREV 8 // Number of preceeding beats used as beat features.
roysandberg 62:8e2fbe131b53 92 #define MAX_SHIFT BEAT_MS40
roysandberg 62:8e2fbe131b53 93
roysandberg 62:8e2fbe131b53 94 // Local prototypes.
roysandberg 62:8e2fbe131b53 95
roysandberg 62:8e2fbe131b53 96 int NoiseCheck(int *beat) ;
roysandberg 62:8e2fbe131b53 97 double CompareBeats(int *beat1, int *beat2, int *shiftAdj) ;
roysandberg 62:8e2fbe131b53 98 double CompareBeats2(int *beat1, int *beat2, int *shiftAdj) ;
roysandberg 62:8e2fbe131b53 99 void UpdateBeat(int *aveBeat, int *newBeat, int shift) ;
roysandberg 62:8e2fbe131b53 100 void BeatCopy(int srcBeat, int destBeat) ;
roysandberg 62:8e2fbe131b53 101 int MinimumBeatVariation(int type) ;
roysandberg 62:8e2fbe131b53 102
roysandberg 62:8e2fbe131b53 103 // External prototypes.
roysandberg 62:8e2fbe131b53 104
roysandberg 62:8e2fbe131b53 105 void AnalyzeBeat(int *beat, int *onset, int *offset, int *isoLevel,
roysandberg 62:8e2fbe131b53 106 int *beatBegin, int *beatEnd, int *amp) ;
roysandberg 62:8e2fbe131b53 107 void AdjustDomData(int oldType, int newType) ;
roysandberg 62:8e2fbe131b53 108 void CombineDomData(int oldType, int newType) ;
roysandberg 62:8e2fbe131b53 109
roysandberg 62:8e2fbe131b53 110 // Global variables.
roysandberg 62:8e2fbe131b53 111
roysandberg 62:8e2fbe131b53 112 int BeatTemplates[MAXTYPES][BEATLGTH] ;
roysandberg 62:8e2fbe131b53 113 int BeatCounts[MAXTYPES] ;
roysandberg 62:8e2fbe131b53 114 int BeatWidths[MAXTYPES] ;
roysandberg 62:8e2fbe131b53 115 int BeatClassifications[MAXTYPES] ;
roysandberg 62:8e2fbe131b53 116 int BeatBegins[MAXTYPES] ;
roysandberg 62:8e2fbe131b53 117 int BeatEnds[MAXTYPES] ;
roysandberg 62:8e2fbe131b53 118 int BeatsSinceLastMatch[MAXTYPES] ;
roysandberg 62:8e2fbe131b53 119 int BeatAmps[MAXTYPES] ;
roysandberg 62:8e2fbe131b53 120 int BeatCenters[MAXTYPES] ;
roysandberg 62:8e2fbe131b53 121 double MIs[MAXTYPES][8] ;
roysandberg 62:8e2fbe131b53 122
roysandberg 62:8e2fbe131b53 123 // Need access to these in postclas.cpp when beat types are combined
roysandberg 62:8e2fbe131b53 124 // and moved.
roysandberg 62:8e2fbe131b53 125
roysandberg 62:8e2fbe131b53 126 extern int PostClass[MAXTYPES][8] ;
roysandberg 62:8e2fbe131b53 127 extern int PCRhythm[MAXTYPES][8] ;
roysandberg 62:8e2fbe131b53 128
roysandberg 62:8e2fbe131b53 129 int TypeCount = 0 ;
roysandberg 62:8e2fbe131b53 130
roysandberg 62:8e2fbe131b53 131 /***************************************************************************
roysandberg 62:8e2fbe131b53 132 ResetMatch() resets static variables involved with template matching.
roysandberg 62:8e2fbe131b53 133 ****************************************************************************/
roysandberg 62:8e2fbe131b53 134
roysandberg 62:8e2fbe131b53 135 void ResetMatch(void)
roysandberg 62:8e2fbe131b53 136 {
roysandberg 62:8e2fbe131b53 137 int i, j ;
roysandberg 62:8e2fbe131b53 138 TypeCount = 0 ;
roysandberg 62:8e2fbe131b53 139 for(i = 0; i < MAXTYPES; ++i)
roysandberg 62:8e2fbe131b53 140 {
roysandberg 62:8e2fbe131b53 141 BeatCounts[i] = 0 ;
roysandberg 62:8e2fbe131b53 142 BeatClassifications[i] = UNKNOWN ;
roysandberg 62:8e2fbe131b53 143 for(j = 0; j < 8; ++j)
roysandberg 62:8e2fbe131b53 144 {
roysandberg 62:8e2fbe131b53 145 MIs[i][j] = 0 ;
roysandberg 62:8e2fbe131b53 146 }
roysandberg 62:8e2fbe131b53 147 }
roysandberg 62:8e2fbe131b53 148 }
roysandberg 62:8e2fbe131b53 149
roysandberg 62:8e2fbe131b53 150 /**************************************************************************
roysandberg 62:8e2fbe131b53 151 CompareBeats() takes two beat buffers and compares how well they match
roysandberg 62:8e2fbe131b53 152 point-by-point. Beat2 is shifted and scaled to produce the closest
roysandberg 62:8e2fbe131b53 153 possible match. The metric returned is the sum of the absolute
roysandberg 62:8e2fbe131b53 154 differences between beats divided by the amplitude of the beats. The
roysandberg 62:8e2fbe131b53 155 shift used for the match is returned via the pointer *shiftAdj.
roysandberg 62:8e2fbe131b53 156 ***************************************************************************/
roysandberg 62:8e2fbe131b53 157
roysandberg 62:8e2fbe131b53 158 #define MATCH_START (FIDMARK-(MATCH_LENGTH/2))
roysandberg 62:8e2fbe131b53 159 #define MATCH_END (FIDMARK+(MATCH_LENGTH/2))
roysandberg 62:8e2fbe131b53 160
roysandberg 62:8e2fbe131b53 161 double CompareBeats(int *beat1, int *beat2, int *shiftAdj)
roysandberg 62:8e2fbe131b53 162 {
roysandberg 62:8e2fbe131b53 163 int i, max, min, magSum, shift ;
roysandberg 62:8e2fbe131b53 164 long beatDiff, meanDiff, minDiff, minShift ;
roysandberg 62:8e2fbe131b53 165 double metric, scaleFactor, tempD ;
roysandberg 62:8e2fbe131b53 166
roysandberg 62:8e2fbe131b53 167 // Calculate the magnitude of each beat.
roysandberg 62:8e2fbe131b53 168
roysandberg 62:8e2fbe131b53 169 max = min = beat1[MATCH_START] ;
roysandberg 62:8e2fbe131b53 170 for(i = MATCH_START+1; i < MATCH_END; ++i)
roysandberg 62:8e2fbe131b53 171 if(beat1[i] > max)
roysandberg 62:8e2fbe131b53 172 max = beat1[i] ;
roysandberg 62:8e2fbe131b53 173 else if(beat1[i] < min)
roysandberg 62:8e2fbe131b53 174 min = beat1[i] ;
roysandberg 62:8e2fbe131b53 175
roysandberg 62:8e2fbe131b53 176 magSum = max - min ;
roysandberg 62:8e2fbe131b53 177
roysandberg 62:8e2fbe131b53 178 i = MATCH_START ;
roysandberg 62:8e2fbe131b53 179 max = min = beat2[i] ;
roysandberg 62:8e2fbe131b53 180 for(i = MATCH_START+1; i < MATCH_END; ++i)
roysandberg 62:8e2fbe131b53 181 if(beat2[i] > max)
roysandberg 62:8e2fbe131b53 182 max = beat2[i] ;
roysandberg 62:8e2fbe131b53 183 else if(beat2[i] < min)
roysandberg 62:8e2fbe131b53 184 min = beat2[i] ;
roysandberg 62:8e2fbe131b53 185
roysandberg 62:8e2fbe131b53 186 // magSum += max - min ;
roysandberg 62:8e2fbe131b53 187 scaleFactor = magSum ;
roysandberg 62:8e2fbe131b53 188 scaleFactor /= max-min ;
roysandberg 62:8e2fbe131b53 189 magSum *= 2 ;
roysandberg 62:8e2fbe131b53 190
roysandberg 62:8e2fbe131b53 191 // Calculate the sum of the point-by-point
roysandberg 62:8e2fbe131b53 192 // absolute differences for five possible shifts.
roysandberg 62:8e2fbe131b53 193
roysandberg 62:8e2fbe131b53 194 for(shift = -MAX_SHIFT; shift <= MAX_SHIFT; ++shift)
roysandberg 62:8e2fbe131b53 195 {
roysandberg 62:8e2fbe131b53 196 for(i = FIDMARK-(MATCH_LENGTH>>1), meanDiff = 0;
roysandberg 62:8e2fbe131b53 197 i < FIDMARK + (MATCH_LENGTH>>1); ++i)
roysandberg 62:8e2fbe131b53 198 {
roysandberg 62:8e2fbe131b53 199 tempD = beat2[i+shift] ;
roysandberg 62:8e2fbe131b53 200 tempD *= scaleFactor ;
roysandberg 62:8e2fbe131b53 201 meanDiff += beat1[i]- tempD ; // beat2[i+shift] ;
roysandberg 62:8e2fbe131b53 202 }
roysandberg 62:8e2fbe131b53 203 meanDiff /= MATCH_LENGTH ;
roysandberg 62:8e2fbe131b53 204
roysandberg 62:8e2fbe131b53 205 for(i = FIDMARK-(MATCH_LENGTH>>1), beatDiff = 0;
roysandberg 62:8e2fbe131b53 206 i < FIDMARK + (MATCH_LENGTH>>1); ++i)
roysandberg 62:8e2fbe131b53 207 {
roysandberg 62:8e2fbe131b53 208 tempD = beat2[i+shift] ;
roysandberg 62:8e2fbe131b53 209 tempD *= scaleFactor ;
roysandberg 62:8e2fbe131b53 210 beatDiff += abs(beat1[i] - meanDiff- tempD) ; // beat2[i+shift] ) ;
roysandberg 62:8e2fbe131b53 211 }
roysandberg 62:8e2fbe131b53 212
roysandberg 62:8e2fbe131b53 213
roysandberg 62:8e2fbe131b53 214 if(shift == -MAX_SHIFT)
roysandberg 62:8e2fbe131b53 215 {
roysandberg 62:8e2fbe131b53 216 minDiff = beatDiff ;
roysandberg 62:8e2fbe131b53 217 minShift = -MAX_SHIFT ;
roysandberg 62:8e2fbe131b53 218 }
roysandberg 62:8e2fbe131b53 219 else if(beatDiff < minDiff)
roysandberg 62:8e2fbe131b53 220 {
roysandberg 62:8e2fbe131b53 221 minDiff = beatDiff ;
roysandberg 62:8e2fbe131b53 222 minShift = shift ;
roysandberg 62:8e2fbe131b53 223 }
roysandberg 62:8e2fbe131b53 224 }
roysandberg 62:8e2fbe131b53 225
roysandberg 62:8e2fbe131b53 226 metric = minDiff ;
roysandberg 62:8e2fbe131b53 227 *shiftAdj = minShift ;
roysandberg 62:8e2fbe131b53 228 metric /= magSum ;
roysandberg 62:8e2fbe131b53 229
roysandberg 62:8e2fbe131b53 230 // Metric scales inversely with match length.
roysandberg 62:8e2fbe131b53 231 // algorithm was originally tuned with a match
roysandberg 62:8e2fbe131b53 232 // length of 30.
roysandberg 62:8e2fbe131b53 233
roysandberg 62:8e2fbe131b53 234 metric *= 30 ;
roysandberg 62:8e2fbe131b53 235 metric /= MATCH_LENGTH ;
roysandberg 62:8e2fbe131b53 236 return(metric) ;
roysandberg 62:8e2fbe131b53 237 }
roysandberg 62:8e2fbe131b53 238
roysandberg 62:8e2fbe131b53 239 /***************************************************************************
roysandberg 62:8e2fbe131b53 240 CompareBeats2 is nearly the same as CompareBeats above, but beat2 is
roysandberg 62:8e2fbe131b53 241 not scaled before calculating the match metric. The match metric is
roysandberg 62:8e2fbe131b53 242 then the sum of the absolute differences divided by the average amplitude
roysandberg 62:8e2fbe131b53 243 of the two beats.
roysandberg 62:8e2fbe131b53 244 ****************************************************************************/
roysandberg 62:8e2fbe131b53 245
roysandberg 62:8e2fbe131b53 246 double CompareBeats2(int *beat1, int *beat2, int *shiftAdj)
roysandberg 62:8e2fbe131b53 247 {
roysandberg 62:8e2fbe131b53 248 int i, max, min, shift ;
roysandberg 62:8e2fbe131b53 249 int mag1, mag2 ;
roysandberg 62:8e2fbe131b53 250 long beatDiff, meanDiff, minDiff, minShift ;
roysandberg 62:8e2fbe131b53 251 double metric ;
roysandberg 62:8e2fbe131b53 252
roysandberg 62:8e2fbe131b53 253 // Calculate the magnitude of each beat.
roysandberg 62:8e2fbe131b53 254
roysandberg 62:8e2fbe131b53 255 max = min = beat1[MATCH_START] ;
roysandberg 62:8e2fbe131b53 256 for(i = MATCH_START+1; i < MATCH_END; ++i)
roysandberg 62:8e2fbe131b53 257 if(beat1[i] > max)
roysandberg 62:8e2fbe131b53 258 max = beat1[i] ;
roysandberg 62:8e2fbe131b53 259 else if(beat1[i] < min)
roysandberg 62:8e2fbe131b53 260 min = beat1[i] ;
roysandberg 62:8e2fbe131b53 261
roysandberg 62:8e2fbe131b53 262 mag1 = max - min ;
roysandberg 62:8e2fbe131b53 263
roysandberg 62:8e2fbe131b53 264 i = MATCH_START ;
roysandberg 62:8e2fbe131b53 265 max = min = beat2[i] ;
roysandberg 62:8e2fbe131b53 266 for(i = MATCH_START+1; i < MATCH_END; ++i)
roysandberg 62:8e2fbe131b53 267 if(beat2[i] > max)
roysandberg 62:8e2fbe131b53 268 max = beat2[i] ;
roysandberg 62:8e2fbe131b53 269 else if(beat2[i] < min)
roysandberg 62:8e2fbe131b53 270 min = beat2[i] ;
roysandberg 62:8e2fbe131b53 271
roysandberg 62:8e2fbe131b53 272 mag2 = max-min ;
roysandberg 62:8e2fbe131b53 273
roysandberg 62:8e2fbe131b53 274 // Calculate the sum of the point-by-point
roysandberg 62:8e2fbe131b53 275 // absolute differences for five possible shifts.
roysandberg 62:8e2fbe131b53 276
roysandberg 62:8e2fbe131b53 277 for(shift = -MAX_SHIFT; shift <= MAX_SHIFT; ++shift)
roysandberg 62:8e2fbe131b53 278 {
roysandberg 62:8e2fbe131b53 279 for(i = FIDMARK-(MATCH_LENGTH>>1), meanDiff = 0;
roysandberg 62:8e2fbe131b53 280 i < FIDMARK + (MATCH_LENGTH>>1); ++i)
roysandberg 62:8e2fbe131b53 281 meanDiff += beat1[i]- beat2[i+shift] ;
roysandberg 62:8e2fbe131b53 282 meanDiff /= MATCH_LENGTH ;
roysandberg 62:8e2fbe131b53 283
roysandberg 62:8e2fbe131b53 284 for(i = FIDMARK-(MATCH_LENGTH>>1), beatDiff = 0;
roysandberg 62:8e2fbe131b53 285 i < FIDMARK + (MATCH_LENGTH>>1); ++i)
roysandberg 62:8e2fbe131b53 286 beatDiff += abs(beat1[i] - meanDiff- beat2[i+shift]) ; ;
roysandberg 62:8e2fbe131b53 287
roysandberg 62:8e2fbe131b53 288 if(shift == -MAX_SHIFT)
roysandberg 62:8e2fbe131b53 289 {
roysandberg 62:8e2fbe131b53 290 minDiff = beatDiff ;
roysandberg 62:8e2fbe131b53 291 minShift = -MAX_SHIFT ;
roysandberg 62:8e2fbe131b53 292 }
roysandberg 62:8e2fbe131b53 293 else if(beatDiff < minDiff)
roysandberg 62:8e2fbe131b53 294 {
roysandberg 62:8e2fbe131b53 295 minDiff = beatDiff ;
roysandberg 62:8e2fbe131b53 296 minShift = shift ;
roysandberg 62:8e2fbe131b53 297 }
roysandberg 62:8e2fbe131b53 298 }
roysandberg 62:8e2fbe131b53 299
roysandberg 62:8e2fbe131b53 300 metric = minDiff ;
roysandberg 62:8e2fbe131b53 301 *shiftAdj = minShift ;
roysandberg 62:8e2fbe131b53 302 metric /= (mag1+mag2) ;
roysandberg 62:8e2fbe131b53 303
roysandberg 62:8e2fbe131b53 304 // Metric scales inversely with match length.
roysandberg 62:8e2fbe131b53 305 // algorithm was originally tuned with a match
roysandberg 62:8e2fbe131b53 306 // length of 30.
roysandberg 62:8e2fbe131b53 307
roysandberg 62:8e2fbe131b53 308 metric *= 30 ;
roysandberg 62:8e2fbe131b53 309 metric /= MATCH_LENGTH ;
roysandberg 62:8e2fbe131b53 310
roysandberg 62:8e2fbe131b53 311 return(metric) ;
roysandberg 62:8e2fbe131b53 312 }
roysandberg 62:8e2fbe131b53 313
roysandberg 62:8e2fbe131b53 314 /************************************************************************
roysandberg 62:8e2fbe131b53 315 UpdateBeat() averages a new beat into an average beat template by adding
roysandberg 62:8e2fbe131b53 316 1/8th of the new beat to 7/8ths of the average beat.
roysandberg 62:8e2fbe131b53 317 *************************************************************************/
roysandberg 62:8e2fbe131b53 318
roysandberg 62:8e2fbe131b53 319 void UpdateBeat(int *aveBeat, int *newBeat, int shift)
roysandberg 62:8e2fbe131b53 320 {
roysandberg 62:8e2fbe131b53 321 int i ;
roysandberg 62:8e2fbe131b53 322 long tempLong ;
roysandberg 62:8e2fbe131b53 323
roysandberg 62:8e2fbe131b53 324 for(i = 0; i < BEATLGTH; ++i)
roysandberg 62:8e2fbe131b53 325 {
roysandberg 62:8e2fbe131b53 326 if((i+shift >= 0) && (i+shift < BEATLGTH))
roysandberg 62:8e2fbe131b53 327 {
roysandberg 62:8e2fbe131b53 328 tempLong = aveBeat[i] ;
roysandberg 62:8e2fbe131b53 329 tempLong *= 7 ;
roysandberg 62:8e2fbe131b53 330 tempLong += newBeat[i+shift] ;
roysandberg 62:8e2fbe131b53 331 tempLong >>= 3 ;
roysandberg 62:8e2fbe131b53 332 aveBeat[i] = tempLong ;
roysandberg 62:8e2fbe131b53 333 }
roysandberg 62:8e2fbe131b53 334 }
roysandberg 62:8e2fbe131b53 335 }
roysandberg 62:8e2fbe131b53 336
roysandberg 62:8e2fbe131b53 337 /*******************************************************
roysandberg 62:8e2fbe131b53 338 GetTypesCount returns the number of types that have
roysandberg 62:8e2fbe131b53 339 been detected.
roysandberg 62:8e2fbe131b53 340 *******************************************************/
roysandberg 62:8e2fbe131b53 341
roysandberg 62:8e2fbe131b53 342 int GetTypesCount(void)
roysandberg 62:8e2fbe131b53 343 {
roysandberg 62:8e2fbe131b53 344 return(TypeCount) ;
roysandberg 62:8e2fbe131b53 345 }
roysandberg 62:8e2fbe131b53 346
roysandberg 62:8e2fbe131b53 347 /********************************************************
roysandberg 62:8e2fbe131b53 348 GetBeatTypeCount returns the number of beats of a
roysandberg 62:8e2fbe131b53 349 a particular type have been detected.
roysandberg 62:8e2fbe131b53 350 ********************************************************/
roysandberg 62:8e2fbe131b53 351
roysandberg 62:8e2fbe131b53 352 int GetBeatTypeCount(int type)
roysandberg 62:8e2fbe131b53 353 {
roysandberg 62:8e2fbe131b53 354 return(BeatCounts[type]) ;
roysandberg 62:8e2fbe131b53 355 }
roysandberg 62:8e2fbe131b53 356
roysandberg 62:8e2fbe131b53 357 /*******************************************************
roysandberg 62:8e2fbe131b53 358 GetBeatWidth returns the QRS width estimate for
roysandberg 62:8e2fbe131b53 359 a given type of beat.
roysandberg 62:8e2fbe131b53 360 *******************************************************/
roysandberg 62:8e2fbe131b53 361 int GetBeatWidth(int type)
roysandberg 62:8e2fbe131b53 362 {
roysandberg 62:8e2fbe131b53 363 return(BeatWidths[type]) ;
roysandberg 62:8e2fbe131b53 364 }
roysandberg 62:8e2fbe131b53 365
roysandberg 62:8e2fbe131b53 366 /*******************************************************
roysandberg 62:8e2fbe131b53 367 GetBeatCenter returns the point between the onset and
roysandberg 62:8e2fbe131b53 368 offset of a beat.
roysandberg 62:8e2fbe131b53 369 ********************************************************/
roysandberg 62:8e2fbe131b53 370
roysandberg 62:8e2fbe131b53 371 int GetBeatCenter(int type)
roysandberg 62:8e2fbe131b53 372 {
roysandberg 62:8e2fbe131b53 373 return(BeatCenters[type]) ;
roysandberg 62:8e2fbe131b53 374 }
roysandberg 62:8e2fbe131b53 375
roysandberg 62:8e2fbe131b53 376 /*******************************************************
roysandberg 62:8e2fbe131b53 377 GetBeatClass returns the present classification for
roysandberg 62:8e2fbe131b53 378 a given beat type (NORMAL, PVC, or UNKNOWN).
roysandberg 62:8e2fbe131b53 379 ********************************************************/
roysandberg 62:8e2fbe131b53 380
roysandberg 62:8e2fbe131b53 381 int GetBeatClass(int type)
roysandberg 62:8e2fbe131b53 382 {
roysandberg 62:8e2fbe131b53 383 if(type == MAXTYPES)
roysandberg 62:8e2fbe131b53 384 return(UNKNOWN) ;
roysandberg 62:8e2fbe131b53 385 return(BeatClassifications[type]) ;
roysandberg 62:8e2fbe131b53 386 }
roysandberg 62:8e2fbe131b53 387
roysandberg 62:8e2fbe131b53 388 /******************************************************
roysandberg 62:8e2fbe131b53 389 SetBeatClass sets up a beat classifation for a
roysandberg 62:8e2fbe131b53 390 given type.
roysandberg 62:8e2fbe131b53 391 ******************************************************/
roysandberg 62:8e2fbe131b53 392
roysandberg 62:8e2fbe131b53 393 void SetBeatClass(int type, int beatClass)
roysandberg 62:8e2fbe131b53 394 {
roysandberg 62:8e2fbe131b53 395 BeatClassifications[type] = beatClass ;
roysandberg 62:8e2fbe131b53 396 }
roysandberg 62:8e2fbe131b53 397
roysandberg 62:8e2fbe131b53 398 /******************************************************************************
roysandberg 62:8e2fbe131b53 399 NewBeatType starts a new beat type by storing the new beat and its
roysandberg 62:8e2fbe131b53 400 features as the next available beat type.
roysandberg 62:8e2fbe131b53 401 ******************************************************************************/
roysandberg 62:8e2fbe131b53 402
roysandberg 62:8e2fbe131b53 403 int NewBeatType(int *newBeat )
roysandberg 62:8e2fbe131b53 404 {
roysandberg 62:8e2fbe131b53 405 int i, onset, offset, isoLevel, beatBegin, beatEnd ;
roysandberg 62:8e2fbe131b53 406 int mcType, amp ;
roysandberg 62:8e2fbe131b53 407
roysandberg 62:8e2fbe131b53 408 // Update count of beats since each template was matched.
roysandberg 62:8e2fbe131b53 409
roysandberg 62:8e2fbe131b53 410 for(i = 0; i < TypeCount; ++i)
roysandberg 62:8e2fbe131b53 411 ++BeatsSinceLastMatch[i] ;
roysandberg 62:8e2fbe131b53 412
roysandberg 62:8e2fbe131b53 413 if(TypeCount < MAXTYPES)
roysandberg 62:8e2fbe131b53 414 {
roysandberg 62:8e2fbe131b53 415 for(i = 0; i < BEATLGTH; ++i)
roysandberg 62:8e2fbe131b53 416 BeatTemplates[TypeCount][i] = newBeat[i] ;
roysandberg 62:8e2fbe131b53 417
roysandberg 62:8e2fbe131b53 418 BeatCounts[TypeCount] = 1 ;
roysandberg 62:8e2fbe131b53 419 BeatClassifications[TypeCount] = UNKNOWN ;
roysandberg 62:8e2fbe131b53 420 AnalyzeBeat(&BeatTemplates[TypeCount][0],&onset,&offset, &isoLevel,
roysandberg 62:8e2fbe131b53 421 &beatBegin, &beatEnd, &amp) ;
roysandberg 62:8e2fbe131b53 422 BeatWidths[TypeCount] = offset-onset ;
roysandberg 62:8e2fbe131b53 423 BeatCenters[TypeCount] = (offset+onset)/2 ;
roysandberg 62:8e2fbe131b53 424 BeatBegins[TypeCount] = beatBegin ;
roysandberg 62:8e2fbe131b53 425 BeatEnds[TypeCount] = beatEnd ;
roysandberg 62:8e2fbe131b53 426 BeatAmps[TypeCount] = amp ;
roysandberg 62:8e2fbe131b53 427
roysandberg 62:8e2fbe131b53 428 BeatsSinceLastMatch[TypeCount] = 0 ;
roysandberg 62:8e2fbe131b53 429
roysandberg 62:8e2fbe131b53 430 ++TypeCount ;
roysandberg 62:8e2fbe131b53 431 return(TypeCount-1) ;
roysandberg 62:8e2fbe131b53 432 }
roysandberg 62:8e2fbe131b53 433
roysandberg 62:8e2fbe131b53 434 // If we have used all the template space, replace the beat
roysandberg 62:8e2fbe131b53 435 // that has occurred the fewest number of times.
roysandberg 62:8e2fbe131b53 436
roysandberg 62:8e2fbe131b53 437 else
roysandberg 62:8e2fbe131b53 438 {
roysandberg 62:8e2fbe131b53 439 // Find the template with the fewest occurances,
roysandberg 62:8e2fbe131b53 440 // that hasn't been matched in at least 500 beats.
roysandberg 62:8e2fbe131b53 441
roysandberg 62:8e2fbe131b53 442 mcType = -1 ;
roysandberg 62:8e2fbe131b53 443
roysandberg 62:8e2fbe131b53 444 if(mcType == -1)
roysandberg 62:8e2fbe131b53 445 {
roysandberg 62:8e2fbe131b53 446 mcType = 0 ;
roysandberg 62:8e2fbe131b53 447 for(i = 1; i < MAXTYPES; ++i)
roysandberg 62:8e2fbe131b53 448 if(BeatCounts[i] < BeatCounts[mcType])
roysandberg 62:8e2fbe131b53 449 mcType = i ;
roysandberg 62:8e2fbe131b53 450 else if(BeatCounts[i] == BeatCounts[mcType])
roysandberg 62:8e2fbe131b53 451 {
roysandberg 62:8e2fbe131b53 452 if(BeatsSinceLastMatch[i] > BeatsSinceLastMatch[mcType])
roysandberg 62:8e2fbe131b53 453 mcType = i ;
roysandberg 62:8e2fbe131b53 454 }
roysandberg 62:8e2fbe131b53 455 }
roysandberg 62:8e2fbe131b53 456
roysandberg 62:8e2fbe131b53 457 // Adjust dominant beat monitor data.
roysandberg 62:8e2fbe131b53 458
roysandberg 62:8e2fbe131b53 459 AdjustDomData(mcType,MAXTYPES) ;
roysandberg 62:8e2fbe131b53 460
roysandberg 62:8e2fbe131b53 461 // Substitute this beat.
roysandberg 62:8e2fbe131b53 462
roysandberg 62:8e2fbe131b53 463 for(i = 0; i < BEATLGTH; ++i)
roysandberg 62:8e2fbe131b53 464 BeatTemplates[mcType][i] = newBeat[i] ;
roysandberg 62:8e2fbe131b53 465
roysandberg 62:8e2fbe131b53 466 BeatCounts[mcType] = 1 ;
roysandberg 62:8e2fbe131b53 467 BeatClassifications[mcType] = UNKNOWN ;
roysandberg 62:8e2fbe131b53 468 AnalyzeBeat(&BeatTemplates[mcType][0],&onset,&offset, &isoLevel,
roysandberg 62:8e2fbe131b53 469 &beatBegin, &beatEnd, &amp) ;
roysandberg 62:8e2fbe131b53 470 BeatWidths[mcType] = offset-onset ;
roysandberg 62:8e2fbe131b53 471 BeatCenters[mcType] = (offset+onset)/2 ;
roysandberg 62:8e2fbe131b53 472 BeatBegins[mcType] = beatBegin ;
roysandberg 62:8e2fbe131b53 473 BeatEnds[mcType] = beatEnd ;
roysandberg 62:8e2fbe131b53 474 BeatsSinceLastMatch[mcType] = 0 ;
roysandberg 62:8e2fbe131b53 475 BeatAmps[mcType] = amp ;
roysandberg 62:8e2fbe131b53 476 return(mcType) ;
roysandberg 62:8e2fbe131b53 477 }
roysandberg 62:8e2fbe131b53 478 }
roysandberg 62:8e2fbe131b53 479
roysandberg 62:8e2fbe131b53 480 /***************************************************************************
roysandberg 62:8e2fbe131b53 481 BestMorphMatch tests a new beat against all available beat types and
roysandberg 62:8e2fbe131b53 482 returns (via pointers) the existing type that best matches, the match
roysandberg 62:8e2fbe131b53 483 metric for that type, and the shift used for that match.
roysandberg 62:8e2fbe131b53 484 ***************************************************************************/
roysandberg 62:8e2fbe131b53 485
roysandberg 62:8e2fbe131b53 486 void BestMorphMatch(int *newBeat,int *matchType,double *matchIndex, double *mi2,
roysandberg 62:8e2fbe131b53 487 int *shiftAdj)
roysandberg 62:8e2fbe131b53 488 {
roysandberg 62:8e2fbe131b53 489 int type, i, bestMatch, nextBest, minShift, shift, temp ;
roysandberg 62:8e2fbe131b53 490 int bestShift2, nextShift2 ;
roysandberg 62:8e2fbe131b53 491 double bestDiff2, nextDiff2;
roysandberg 62:8e2fbe131b53 492 double beatDiff, minDiff, nextDiff=10000 ;
roysandberg 62:8e2fbe131b53 493
roysandberg 62:8e2fbe131b53 494 if(TypeCount == 0)
roysandberg 62:8e2fbe131b53 495 {
roysandberg 62:8e2fbe131b53 496 *matchType = 0 ;
roysandberg 62:8e2fbe131b53 497 *matchIndex = 1000 ; // Make sure there is no match so a new beat is
roysandberg 62:8e2fbe131b53 498 *shiftAdj = 0 ; // created.
roysandberg 62:8e2fbe131b53 499 return ;
roysandberg 62:8e2fbe131b53 500 }
roysandberg 62:8e2fbe131b53 501
roysandberg 62:8e2fbe131b53 502 // Compare the new beat to all type beat
roysandberg 62:8e2fbe131b53 503 // types that have been saved.
roysandberg 62:8e2fbe131b53 504
roysandberg 62:8e2fbe131b53 505 for(type = 0; type < TypeCount; ++type)
roysandberg 62:8e2fbe131b53 506 {
roysandberg 62:8e2fbe131b53 507 beatDiff = CompareBeats(&BeatTemplates[type][0],newBeat,&shift) ;
roysandberg 62:8e2fbe131b53 508 if(type == 0)
roysandberg 62:8e2fbe131b53 509 {
roysandberg 62:8e2fbe131b53 510 bestMatch = 0 ;
roysandberg 62:8e2fbe131b53 511 minDiff = beatDiff ;
roysandberg 62:8e2fbe131b53 512 minShift = shift ;
roysandberg 62:8e2fbe131b53 513 }
roysandberg 62:8e2fbe131b53 514 else if(beatDiff < minDiff)
roysandberg 62:8e2fbe131b53 515 {
roysandberg 62:8e2fbe131b53 516 nextBest = bestMatch ;
roysandberg 62:8e2fbe131b53 517 nextDiff = minDiff ;
roysandberg 62:8e2fbe131b53 518 bestMatch = type ;
roysandberg 62:8e2fbe131b53 519 minDiff = beatDiff ;
roysandberg 62:8e2fbe131b53 520 minShift = shift ;
roysandberg 62:8e2fbe131b53 521 }
roysandberg 62:8e2fbe131b53 522 else if((TypeCount > 1) && (type == 1))
roysandberg 62:8e2fbe131b53 523 {
roysandberg 62:8e2fbe131b53 524 nextBest = type ;
roysandberg 62:8e2fbe131b53 525 nextDiff = beatDiff ;
roysandberg 62:8e2fbe131b53 526 }
roysandberg 62:8e2fbe131b53 527 else if(beatDiff < nextDiff)
roysandberg 62:8e2fbe131b53 528 {
roysandberg 62:8e2fbe131b53 529 nextBest = type ;
roysandberg 62:8e2fbe131b53 530 nextDiff = beatDiff ;
roysandberg 62:8e2fbe131b53 531 }
roysandberg 62:8e2fbe131b53 532 }
roysandberg 62:8e2fbe131b53 533
roysandberg 62:8e2fbe131b53 534 // If this beat was close to two different
roysandberg 62:8e2fbe131b53 535 // templates, see if the templates which template
roysandberg 62:8e2fbe131b53 536 // is the best match when no scaling is used.
roysandberg 62:8e2fbe131b53 537 // Then check whether the two close types can be combined.
roysandberg 62:8e2fbe131b53 538
roysandberg 62:8e2fbe131b53 539 if((minDiff < MATCH_LIMIT) && (nextDiff < MATCH_LIMIT) && (TypeCount > 1))
roysandberg 62:8e2fbe131b53 540 {
roysandberg 62:8e2fbe131b53 541 // Compare without scaling.
roysandberg 62:8e2fbe131b53 542
roysandberg 62:8e2fbe131b53 543 bestDiff2 = CompareBeats2(&BeatTemplates[bestMatch][0],newBeat,&bestShift2) ;
roysandberg 62:8e2fbe131b53 544 nextDiff2 = CompareBeats2(&BeatTemplates[nextBest][0],newBeat,&nextShift2) ;
roysandberg 62:8e2fbe131b53 545 if(nextDiff2 < bestDiff2)
roysandberg 62:8e2fbe131b53 546 {
roysandberg 62:8e2fbe131b53 547 temp = bestMatch ;
roysandberg 62:8e2fbe131b53 548 bestMatch = nextBest ;
roysandberg 62:8e2fbe131b53 549 nextBest = temp ;
roysandberg 62:8e2fbe131b53 550 temp = minDiff ;
roysandberg 62:8e2fbe131b53 551 minDiff = nextDiff ;
roysandberg 62:8e2fbe131b53 552 nextDiff = temp ;
roysandberg 62:8e2fbe131b53 553 minShift = nextShift2 ;
roysandberg 62:8e2fbe131b53 554 *mi2 = bestDiff2 ;
roysandberg 62:8e2fbe131b53 555 }
roysandberg 62:8e2fbe131b53 556 else *mi2 = nextDiff2 ;
roysandberg 62:8e2fbe131b53 557
roysandberg 62:8e2fbe131b53 558 beatDiff = CompareBeats(&BeatTemplates[bestMatch][0],&BeatTemplates[nextBest][0],&shift) ;
roysandberg 62:8e2fbe131b53 559
roysandberg 62:8e2fbe131b53 560 if((beatDiff < COMBINE_LIMIT) &&
roysandberg 62:8e2fbe131b53 561 ((*mi2 < 1.0) || (!MinimumBeatVariation(nextBest))))
roysandberg 62:8e2fbe131b53 562 {
roysandberg 62:8e2fbe131b53 563
roysandberg 62:8e2fbe131b53 564 // Combine beats into bestMatch
roysandberg 62:8e2fbe131b53 565
roysandberg 62:8e2fbe131b53 566 if(bestMatch < nextBest)
roysandberg 62:8e2fbe131b53 567 {
roysandberg 62:8e2fbe131b53 568 for(i = 0; i < BEATLGTH; ++i)
roysandberg 62:8e2fbe131b53 569 {
roysandberg 62:8e2fbe131b53 570 if((i+shift > 0) && (i + shift < BEATLGTH))
roysandberg 62:8e2fbe131b53 571 {
roysandberg 62:8e2fbe131b53 572 BeatTemplates[bestMatch][i] += BeatTemplates[nextBest][i+shift] ;
roysandberg 62:8e2fbe131b53 573 BeatTemplates[bestMatch][i] >>= 1 ;
roysandberg 62:8e2fbe131b53 574 }
roysandberg 62:8e2fbe131b53 575 }
roysandberg 62:8e2fbe131b53 576
roysandberg 62:8e2fbe131b53 577 if((BeatClassifications[bestMatch] == NORMAL) || (BeatClassifications[nextBest] == NORMAL))
roysandberg 62:8e2fbe131b53 578 BeatClassifications[bestMatch] = NORMAL ;
roysandberg 62:8e2fbe131b53 579 else if((BeatClassifications[bestMatch] == PVC) || (BeatClassifications[nextBest] == PVC))
roysandberg 62:8e2fbe131b53 580 BeatClassifications[bestMatch] = PVC ;
roysandberg 62:8e2fbe131b53 581
roysandberg 62:8e2fbe131b53 582 BeatCounts[bestMatch] += BeatCounts[nextBest] ;
roysandberg 62:8e2fbe131b53 583
roysandberg 62:8e2fbe131b53 584 CombineDomData(nextBest,bestMatch) ;
roysandberg 62:8e2fbe131b53 585
roysandberg 62:8e2fbe131b53 586 // Shift other templates over.
roysandberg 62:8e2fbe131b53 587
roysandberg 62:8e2fbe131b53 588 for(type = nextBest; type < TypeCount-1; ++type)
roysandberg 62:8e2fbe131b53 589 BeatCopy(type+1,type) ;
roysandberg 62:8e2fbe131b53 590
roysandberg 62:8e2fbe131b53 591 }
roysandberg 62:8e2fbe131b53 592
roysandberg 62:8e2fbe131b53 593 // Otherwise combine beats it nextBest.
roysandberg 62:8e2fbe131b53 594
roysandberg 62:8e2fbe131b53 595 else
roysandberg 62:8e2fbe131b53 596 {
roysandberg 62:8e2fbe131b53 597 for(i = 0; i < BEATLGTH; ++i)
roysandberg 62:8e2fbe131b53 598 {
roysandberg 62:8e2fbe131b53 599 BeatTemplates[nextBest][i] += BeatTemplates[bestMatch][i] ;
roysandberg 62:8e2fbe131b53 600 BeatTemplates[nextBest][i] >>= 1 ;
roysandberg 62:8e2fbe131b53 601 }
roysandberg 62:8e2fbe131b53 602
roysandberg 62:8e2fbe131b53 603 if((BeatClassifications[bestMatch] == NORMAL) || (BeatClassifications[nextBest] == NORMAL))
roysandberg 62:8e2fbe131b53 604 BeatClassifications[nextBest] = NORMAL ;
roysandberg 62:8e2fbe131b53 605 else if((BeatClassifications[bestMatch] == PVC) || (BeatClassifications[nextBest] == PVC))
roysandberg 62:8e2fbe131b53 606 BeatClassifications[nextBest] = PVC ;
roysandberg 62:8e2fbe131b53 607
roysandberg 62:8e2fbe131b53 608 BeatCounts[nextBest] += BeatCounts[bestMatch] ;
roysandberg 62:8e2fbe131b53 609
roysandberg 62:8e2fbe131b53 610 CombineDomData(bestMatch,nextBest) ;
roysandberg 62:8e2fbe131b53 611
roysandberg 62:8e2fbe131b53 612 // Shift other templates over.
roysandberg 62:8e2fbe131b53 613
roysandberg 62:8e2fbe131b53 614 for(type = bestMatch; type < TypeCount-1; ++type)
roysandberg 62:8e2fbe131b53 615 BeatCopy(type+1,type) ;
roysandberg 62:8e2fbe131b53 616
roysandberg 62:8e2fbe131b53 617
roysandberg 62:8e2fbe131b53 618 bestMatch = nextBest ;
roysandberg 62:8e2fbe131b53 619 }
roysandberg 62:8e2fbe131b53 620 --TypeCount ;
roysandberg 62:8e2fbe131b53 621 BeatClassifications[TypeCount] = UNKNOWN ;
roysandberg 62:8e2fbe131b53 622 }
roysandberg 62:8e2fbe131b53 623 }
roysandberg 62:8e2fbe131b53 624 *mi2 = CompareBeats2(&BeatTemplates[bestMatch][0],newBeat,&bestShift2) ;
roysandberg 62:8e2fbe131b53 625 *matchType = bestMatch ;
roysandberg 62:8e2fbe131b53 626 *matchIndex = minDiff ;
roysandberg 62:8e2fbe131b53 627 *shiftAdj = minShift ;
roysandberg 62:8e2fbe131b53 628 }
roysandberg 62:8e2fbe131b53 629
roysandberg 62:8e2fbe131b53 630 /***************************************************************************
roysandberg 62:8e2fbe131b53 631 UpdateBeatType updates the beat template and features of a given beat type
roysandberg 62:8e2fbe131b53 632 using a new beat.
roysandberg 62:8e2fbe131b53 633 ***************************************************************************/
roysandberg 62:8e2fbe131b53 634
roysandberg 62:8e2fbe131b53 635 void UpdateBeatType(int matchType,int *newBeat, double mi2,
roysandberg 62:8e2fbe131b53 636 int shiftAdj)
roysandberg 62:8e2fbe131b53 637 {
roysandberg 62:8e2fbe131b53 638 int i,onset,offset, isoLevel, beatBegin, beatEnd ;
roysandberg 62:8e2fbe131b53 639 int amp ;
roysandberg 62:8e2fbe131b53 640
roysandberg 62:8e2fbe131b53 641 // Update beats since templates were matched.
roysandberg 62:8e2fbe131b53 642
roysandberg 62:8e2fbe131b53 643 for(i = 0; i < TypeCount; ++i)
roysandberg 62:8e2fbe131b53 644 {
roysandberg 62:8e2fbe131b53 645 if(i != matchType)
roysandberg 62:8e2fbe131b53 646 ++BeatsSinceLastMatch[i] ;
roysandberg 62:8e2fbe131b53 647 else BeatsSinceLastMatch[i] = 0 ;
roysandberg 62:8e2fbe131b53 648 }
roysandberg 62:8e2fbe131b53 649
roysandberg 62:8e2fbe131b53 650 // If this is only the second beat, average it with the existing
roysandberg 62:8e2fbe131b53 651 // template.
roysandberg 62:8e2fbe131b53 652
roysandberg 62:8e2fbe131b53 653 if(BeatCounts[matchType] == 1)
roysandberg 62:8e2fbe131b53 654 for(i = 0; i < BEATLGTH; ++i)
roysandberg 62:8e2fbe131b53 655 {
roysandberg 62:8e2fbe131b53 656 if((i+shiftAdj >= 0) && (i+shiftAdj < BEATLGTH))
roysandberg 62:8e2fbe131b53 657 BeatTemplates[matchType][i] = (BeatTemplates[matchType][i] + newBeat[i+shiftAdj])>>1 ;
roysandberg 62:8e2fbe131b53 658 }
roysandberg 62:8e2fbe131b53 659
roysandberg 62:8e2fbe131b53 660 // Otherwise do a normal update.
roysandberg 62:8e2fbe131b53 661
roysandberg 62:8e2fbe131b53 662 else
roysandberg 62:8e2fbe131b53 663 UpdateBeat(&BeatTemplates[matchType][0], newBeat, shiftAdj) ;
roysandberg 62:8e2fbe131b53 664
roysandberg 62:8e2fbe131b53 665 // Determine beat features for the new average beat.
roysandberg 62:8e2fbe131b53 666
roysandberg 62:8e2fbe131b53 667 AnalyzeBeat(&BeatTemplates[matchType][0],&onset,&offset,&isoLevel,
roysandberg 62:8e2fbe131b53 668 &beatBegin, &beatEnd, &amp) ;
roysandberg 62:8e2fbe131b53 669
roysandberg 62:8e2fbe131b53 670 BeatWidths[matchType] = offset-onset ;
roysandberg 62:8e2fbe131b53 671 BeatCenters[matchType] = (offset+onset)/2 ;
roysandberg 62:8e2fbe131b53 672 BeatBegins[matchType] = beatBegin ;
roysandberg 62:8e2fbe131b53 673 BeatEnds[matchType] = beatEnd ;
roysandberg 62:8e2fbe131b53 674 BeatAmps[matchType] = amp ;
roysandberg 62:8e2fbe131b53 675
roysandberg 62:8e2fbe131b53 676 ++BeatCounts[matchType] ;
roysandberg 62:8e2fbe131b53 677
roysandberg 62:8e2fbe131b53 678 for(i = MAXPREV-1; i > 0; --i)
roysandberg 62:8e2fbe131b53 679 MIs[matchType][i] = MIs[matchType][i-1] ;
roysandberg 62:8e2fbe131b53 680 MIs[matchType][0] = mi2 ;
roysandberg 62:8e2fbe131b53 681
roysandberg 62:8e2fbe131b53 682 }
roysandberg 62:8e2fbe131b53 683
roysandberg 62:8e2fbe131b53 684
roysandberg 62:8e2fbe131b53 685 /****************************************************************************
roysandberg 62:8e2fbe131b53 686 GetDominantType returns the NORMAL beat type that has occurred most
roysandberg 62:8e2fbe131b53 687 frequently.
roysandberg 62:8e2fbe131b53 688 ****************************************************************************/
roysandberg 62:8e2fbe131b53 689
roysandberg 62:8e2fbe131b53 690 int GetDominantType(void)
roysandberg 62:8e2fbe131b53 691 {
roysandberg 62:8e2fbe131b53 692 int maxCount = 0, maxType = -1 ;
roysandberg 62:8e2fbe131b53 693 int type, totalCount ;
roysandberg 62:8e2fbe131b53 694
roysandberg 62:8e2fbe131b53 695 for(type = 0; type < MAXTYPES; ++type)
roysandberg 62:8e2fbe131b53 696 {
roysandberg 62:8e2fbe131b53 697 if((BeatClassifications[type] == NORMAL) && (BeatCounts[type] > maxCount))
roysandberg 62:8e2fbe131b53 698 {
roysandberg 62:8e2fbe131b53 699 maxType = type ;
roysandberg 62:8e2fbe131b53 700 maxCount = BeatCounts[type] ;
roysandberg 62:8e2fbe131b53 701 }
roysandberg 62:8e2fbe131b53 702 }
roysandberg 62:8e2fbe131b53 703
roysandberg 62:8e2fbe131b53 704 // If no normals are found and at least 300 beats have occurred, just use
roysandberg 62:8e2fbe131b53 705 // the most frequently occurring beat.
roysandberg 62:8e2fbe131b53 706
roysandberg 62:8e2fbe131b53 707 if(maxType == -1)
roysandberg 62:8e2fbe131b53 708 {
roysandberg 62:8e2fbe131b53 709 for(type = 0, totalCount = 0; type < TypeCount; ++type)
roysandberg 62:8e2fbe131b53 710 totalCount += BeatCounts[type] ;
roysandberg 62:8e2fbe131b53 711 if(totalCount > 300)
roysandberg 62:8e2fbe131b53 712 for(type = 0; type < TypeCount; ++type)
roysandberg 62:8e2fbe131b53 713 if(BeatCounts[type] > maxCount)
roysandberg 62:8e2fbe131b53 714 {
roysandberg 62:8e2fbe131b53 715 maxType = type ;
roysandberg 62:8e2fbe131b53 716 maxCount = BeatCounts[type] ;
roysandberg 62:8e2fbe131b53 717 }
roysandberg 62:8e2fbe131b53 718 }
roysandberg 62:8e2fbe131b53 719
roysandberg 62:8e2fbe131b53 720 return(maxType) ;
roysandberg 62:8e2fbe131b53 721 }
roysandberg 62:8e2fbe131b53 722
roysandberg 62:8e2fbe131b53 723
roysandberg 62:8e2fbe131b53 724 /***********************************************************************
roysandberg 62:8e2fbe131b53 725 ClearLastNewType removes the last new type that was initiated
roysandberg 62:8e2fbe131b53 726 ************************************************************************/
roysandberg 62:8e2fbe131b53 727
roysandberg 62:8e2fbe131b53 728 void ClearLastNewType(void)
roysandberg 62:8e2fbe131b53 729 {
roysandberg 62:8e2fbe131b53 730 if(TypeCount != 0)
roysandberg 62:8e2fbe131b53 731 --TypeCount ;
roysandberg 62:8e2fbe131b53 732 }
roysandberg 62:8e2fbe131b53 733
roysandberg 62:8e2fbe131b53 734 /****************************************************************
roysandberg 62:8e2fbe131b53 735 GetBeatBegin returns the offset from the R-wave for the
roysandberg 62:8e2fbe131b53 736 beginning of the beat (P-wave onset if a P-wave is found).
roysandberg 62:8e2fbe131b53 737 *****************************************************************/
roysandberg 62:8e2fbe131b53 738
roysandberg 62:8e2fbe131b53 739 int GetBeatBegin(int type)
roysandberg 62:8e2fbe131b53 740 {
roysandberg 62:8e2fbe131b53 741 return(BeatBegins[type]) ;
roysandberg 62:8e2fbe131b53 742 }
roysandberg 62:8e2fbe131b53 743
roysandberg 62:8e2fbe131b53 744 /****************************************************************
roysandberg 62:8e2fbe131b53 745 GetBeatEnd returns the offset from the R-wave for the end of
roysandberg 62:8e2fbe131b53 746 a beat (T-wave offset).
roysandberg 62:8e2fbe131b53 747 *****************************************************************/
roysandberg 62:8e2fbe131b53 748
roysandberg 62:8e2fbe131b53 749 int GetBeatEnd(int type)
roysandberg 62:8e2fbe131b53 750 {
roysandberg 62:8e2fbe131b53 751 return(BeatEnds[type]) ;
roysandberg 62:8e2fbe131b53 752 }
roysandberg 62:8e2fbe131b53 753
roysandberg 62:8e2fbe131b53 754 int GetBeatAmp(int type)
roysandberg 62:8e2fbe131b53 755 {
roysandberg 62:8e2fbe131b53 756 return(BeatAmps[type]) ;
roysandberg 62:8e2fbe131b53 757 }
roysandberg 62:8e2fbe131b53 758
roysandberg 62:8e2fbe131b53 759
roysandberg 62:8e2fbe131b53 760 /************************************************************************
roysandberg 62:8e2fbe131b53 761 DomCompare2 and DomCompare return similarity indexes between a given
roysandberg 62:8e2fbe131b53 762 beat and the dominant normal type or a given type and the dominant
roysandberg 62:8e2fbe131b53 763 normal type.
roysandberg 62:8e2fbe131b53 764 ************************************************************************/
roysandberg 62:8e2fbe131b53 765
roysandberg 62:8e2fbe131b53 766 double DomCompare2(int *newBeat, int domType)
roysandberg 62:8e2fbe131b53 767 {
roysandberg 62:8e2fbe131b53 768 int shift ;
roysandberg 62:8e2fbe131b53 769 return(CompareBeats2(&BeatTemplates[domType][0],newBeat,&shift)) ;
roysandberg 62:8e2fbe131b53 770 }
roysandberg 62:8e2fbe131b53 771
roysandberg 62:8e2fbe131b53 772 double DomCompare(int newType, int domType)
roysandberg 62:8e2fbe131b53 773 {
roysandberg 62:8e2fbe131b53 774 int shift ;
roysandberg 62:8e2fbe131b53 775 return(CompareBeats2(&BeatTemplates[domType][0],&BeatTemplates[newType][0],
roysandberg 62:8e2fbe131b53 776 &shift)) ;
roysandberg 62:8e2fbe131b53 777 }
roysandberg 62:8e2fbe131b53 778
roysandberg 62:8e2fbe131b53 779 /*************************************************************************
roysandberg 62:8e2fbe131b53 780 BeatCopy copies beat data from a source beat to a destination beat.
roysandberg 62:8e2fbe131b53 781 *************************************************************************/
roysandberg 62:8e2fbe131b53 782
roysandberg 62:8e2fbe131b53 783 void BeatCopy(int srcBeat, int destBeat)
roysandberg 62:8e2fbe131b53 784 {
roysandberg 62:8e2fbe131b53 785 int i ;
roysandberg 62:8e2fbe131b53 786
roysandberg 62:8e2fbe131b53 787 // Copy template.
roysandberg 62:8e2fbe131b53 788
roysandberg 62:8e2fbe131b53 789 for(i = 0; i < BEATLGTH; ++i)
roysandberg 62:8e2fbe131b53 790 BeatTemplates[destBeat][i] = BeatTemplates[srcBeat][i] ;
roysandberg 62:8e2fbe131b53 791
roysandberg 62:8e2fbe131b53 792 // Move feature information.
roysandberg 62:8e2fbe131b53 793
roysandberg 62:8e2fbe131b53 794 BeatCounts[destBeat] = BeatCounts[srcBeat] ;
roysandberg 62:8e2fbe131b53 795 BeatWidths[destBeat] = BeatWidths[srcBeat] ;
roysandberg 62:8e2fbe131b53 796 BeatCenters[destBeat] = BeatCenters[srcBeat] ;
roysandberg 62:8e2fbe131b53 797 for(i = 0; i < MAXPREV; ++i)
roysandberg 62:8e2fbe131b53 798 {
roysandberg 62:8e2fbe131b53 799 PostClass[destBeat][i] = PostClass[srcBeat][i] ;
roysandberg 62:8e2fbe131b53 800 PCRhythm[destBeat][i] = PCRhythm[srcBeat][i] ;
roysandberg 62:8e2fbe131b53 801 }
roysandberg 62:8e2fbe131b53 802
roysandberg 62:8e2fbe131b53 803 BeatClassifications[destBeat] = BeatClassifications[srcBeat] ;
roysandberg 62:8e2fbe131b53 804 BeatBegins[destBeat] = BeatBegins[srcBeat] ;
roysandberg 62:8e2fbe131b53 805 BeatEnds[destBeat] = BeatBegins[srcBeat] ;
roysandberg 62:8e2fbe131b53 806 BeatsSinceLastMatch[destBeat] = BeatsSinceLastMatch[srcBeat];
roysandberg 62:8e2fbe131b53 807 BeatAmps[destBeat] = BeatAmps[srcBeat] ;
roysandberg 62:8e2fbe131b53 808
roysandberg 62:8e2fbe131b53 809 // Adjust data in dominant beat monitor.
roysandberg 62:8e2fbe131b53 810
roysandberg 62:8e2fbe131b53 811 AdjustDomData(srcBeat,destBeat) ;
roysandberg 62:8e2fbe131b53 812 }
roysandberg 62:8e2fbe131b53 813
roysandberg 62:8e2fbe131b53 814 /********************************************************************
roysandberg 62:8e2fbe131b53 815 Minimum beat variation returns a 1 if the previous eight beats
roysandberg 62:8e2fbe131b53 816 have all had similarity indexes less than 0.5.
roysandberg 62:8e2fbe131b53 817 *********************************************************************/
roysandberg 62:8e2fbe131b53 818
roysandberg 62:8e2fbe131b53 819 int MinimumBeatVariation(int type)
roysandberg 62:8e2fbe131b53 820 {
roysandberg 62:8e2fbe131b53 821 int i ;
roysandberg 62:8e2fbe131b53 822 for(i = 0; i < MAXTYPES; ++i)
roysandberg 62:8e2fbe131b53 823 if(MIs[type][i] > 0.5)
roysandberg 62:8e2fbe131b53 824 i = MAXTYPES+2 ;
roysandberg 62:8e2fbe131b53 825 if(i == MAXTYPES)
roysandberg 62:8e2fbe131b53 826 return(1) ;
roysandberg 62:8e2fbe131b53 827 else return(0) ;
roysandberg 62:8e2fbe131b53 828 }
roysandberg 62:8e2fbe131b53 829
roysandberg 62:8e2fbe131b53 830 /**********************************************************************
roysandberg 62:8e2fbe131b53 831 WideBeatVariation returns true if the average similarity index
roysandberg 62:8e2fbe131b53 832 for a given beat type to its template is greater than WIDE_VAR_LIMIT.
roysandberg 62:8e2fbe131b53 833 ***********************************************************************/
roysandberg 62:8e2fbe131b53 834
roysandberg 62:8e2fbe131b53 835 #define WIDE_VAR_LIMIT 0.50
roysandberg 62:8e2fbe131b53 836
roysandberg 62:8e2fbe131b53 837 int WideBeatVariation(int type)
roysandberg 62:8e2fbe131b53 838 {
roysandberg 62:8e2fbe131b53 839 int i, n ;
roysandberg 62:8e2fbe131b53 840 double aveMI ;
roysandberg 62:8e2fbe131b53 841
roysandberg 62:8e2fbe131b53 842 n = BeatCounts[type] ;
roysandberg 62:8e2fbe131b53 843 if(n > 8)
roysandberg 62:8e2fbe131b53 844 n = 8 ;
roysandberg 62:8e2fbe131b53 845
roysandberg 62:8e2fbe131b53 846 for(i = 0, aveMI = 0; i <n; ++i)
roysandberg 62:8e2fbe131b53 847 aveMI += MIs[type][i] ;
roysandberg 62:8e2fbe131b53 848
roysandberg 62:8e2fbe131b53 849 aveMI /= n ;
roysandberg 62:8e2fbe131b53 850 if(aveMI > WIDE_VAR_LIMIT)
roysandberg 62:8e2fbe131b53 851 return(1) ;
roysandberg 62:8e2fbe131b53 852 else return(0) ;
roysandberg 62:8e2fbe131b53 853 }
roysandberg 62:8e2fbe131b53 854
roysandberg 62:8e2fbe131b53 855
roysandberg 62:8e2fbe131b53 856