I've got some basic filter code setup (but not yet tested).
Dependencies: BLE_API Queue mbed nRF51822
Fork of BLE_HeartRate by
match.cpp@62:8e2fbe131b53, 2015-06-28 (annotated)
- 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?
User | Revision | Line number | New 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, &) ; |
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, &) ; |
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, &) ; |
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 |