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: classify.cpp
roysandberg 62:8e2fbe131b53 3 AUTHOR: Patrick S. Hamilton
roysandberg 62:8e2fbe131b53 4 REVISED: 5/13/2001
roysandberg 62:8e2fbe131b53 5 ___________________________________________________________________________
roysandberg 62:8e2fbe131b53 6
roysandberg 62:8e2fbe131b53 7 classify.cpp: Classify a given beat.
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 Classify.cpp contains functions for classifying beats. The only
roysandberg 62:8e2fbe131b53 31 function that needs to be called externally from this file is Classify().
roysandberg 62:8e2fbe131b53 32
roysandberg 62:8e2fbe131b53 33 Functions in classify.cpp require functions in the following files:
roysandberg 62:8e2fbe131b53 34 match.cpp
roysandberg 62:8e2fbe131b53 35 rythmchk.cpp
roysandberg 62:8e2fbe131b53 36 classify.cpp
roysandberg 62:8e2fbe131b53 37 rythmchk.cpp
roysandberg 62:8e2fbe131b53 38 analbeat.cpp
roysandberg 62:8e2fbe131b53 39 postclas.cpp
roysandberg 62:8e2fbe131b53 40
roysandberg 62:8e2fbe131b53 41 __________________________________________________________________________
roysandberg 62:8e2fbe131b53 42
roysandberg 62:8e2fbe131b53 43 Revisions:
roysandberg 62:8e2fbe131b53 44 5/13/02:
roysandberg 62:8e2fbe131b53 45 Width constants tied to BEAT_SAMPLE_RATE in bdac.h
roysandberg 62:8e2fbe131b53 46
roysandberg 62:8e2fbe131b53 47 Arrays added to track the classifications and RR intervals for the
roysandberg 62:8e2fbe131b53 48 most recent 8 beats, allowing GetRunCount to become a local function.
roysandberg 62:8e2fbe131b53 49 RR intervals and classifications are now passed to PostClassify.
roysandberg 62:8e2fbe131b53 50
roysandberg 62:8e2fbe131b53 51 Determination of whether the dominant rhythm is regular is now made
roysandberg 62:8e2fbe131b53 52 by examining the number of RR intervals classified as UNKNOWN in the
roysandberg 62:8e2fbe131b53 53 last DM_BUFFER_LENGTH beats (180). If more than 60 are UNKNOWN
roysandberg 62:8e2fbe131b53 54 the rhythm is too irregular to give any weight to whether the beat
roysandberg 62:8e2fbe131b53 55 was premature or not.
roysandberg 62:8e2fbe131b53 56
roysandberg 62:8e2fbe131b53 57 *******************************************************************************/
roysandberg 62:8e2fbe131b53 58
roysandberg 62:8e2fbe131b53 59 #include "ecgcodes.h"
roysandberg 62:8e2fbe131b53 60 //#include <stdlib.h> // For abs()
roysandberg 62:8e2fbe131b53 61 //#include <stdio.h>
roysandberg 62:8e2fbe131b53 62 #include <mbed.h>
roysandberg 62:8e2fbe131b53 63 #include "qrsdet.h" // For base sample rate.
roysandberg 62:8e2fbe131b53 64 #include "bdac.h"
roysandberg 62:8e2fbe131b53 65 #include "match.h"
roysandberg 62:8e2fbe131b53 66 #include "rythmchk.h"
roysandberg 62:8e2fbe131b53 67 #include "analbeat.h"
roysandberg 62:8e2fbe131b53 68 #include "postclas.h"
roysandberg 62:8e2fbe131b53 69
roysandberg 62:8e2fbe131b53 70 // Detection Rule Parameters.
roysandberg 62:8e2fbe131b53 71
roysandberg 62:8e2fbe131b53 72 #define MATCH_LIMIT 1.3 // Threshold for template matching
roysandberg 62:8e2fbe131b53 73 // without amplitude sensitivity.
roysandberg 62:8e2fbe131b53 74 #define MATCH_WITH_AMP_LIMIT 2.5 // Threshold for matching index that
roysandberg 62:8e2fbe131b53 75 // is amplitude sensitive.
roysandberg 62:8e2fbe131b53 76 #define PVC_MATCH_WITH_AMP_LIMIT 0.9 // Amplitude sensitive limit for
roysandberg 62:8e2fbe131b53 77 //matching premature beats
roysandberg 62:8e2fbe131b53 78 #define BL_SHIFT_LIMIT 100 // Threshold for assuming a baseline shift.
roysandberg 62:8e2fbe131b53 79 #define NEW_TYPE_NOISE_THRESHOLD 18 // Above this noise level, do not create
roysandberg 62:8e2fbe131b53 80 // new beat types.
roysandberg 62:8e2fbe131b53 81 #define NEW_TYPE_HF_NOISE_LIMIT 75 // Above this noise level, do not crate
roysandberg 62:8e2fbe131b53 82 // new beat types.
roysandberg 62:8e2fbe131b53 83
roysandberg 62:8e2fbe131b53 84 #define MATCH_NOISE_THRESHOLD 0.7 // Match threshold below which noise
roysandberg 62:8e2fbe131b53 85 // indications are ignored.
roysandberg 62:8e2fbe131b53 86
roysandberg 62:8e2fbe131b53 87 // TempClass classification rule parameters.
roysandberg 62:8e2fbe131b53 88
roysandberg 62:8e2fbe131b53 89 #define R2_DI_THRESHOLD 1.0 // Rule 2 dominant similarity index threshold
roysandberg 62:8e2fbe131b53 90 #define R3_WIDTH_THRESHOLD BEAT_MS90 // Rule 3 width threshold.
roysandberg 62:8e2fbe131b53 91 #define R7_DI_THRESHOLD 1.2 // Rule 7 dominant similarity index threshold
roysandberg 62:8e2fbe131b53 92 #define R8_DI_THRESHOLD 1.5 // Rule 8 dominant similarity index threshold
roysandberg 62:8e2fbe131b53 93 #define R9_DI_THRESHOLD 2.0 // Rule 9 dominant similarity index threshold
roysandberg 62:8e2fbe131b53 94 #define R10_BC_LIM 3 // Rule 10 beat count limit.
roysandberg 62:8e2fbe131b53 95 #define R10_DI_THRESHOLD 2.5 // Rule 10 dominant similarity index threshold
roysandberg 62:8e2fbe131b53 96 #define R11_MIN_WIDTH BEAT_MS110 // Rule 11 minimum width threshold.
roysandberg 62:8e2fbe131b53 97 #define R11_WIDTH_BREAK BEAT_MS140 // Rule 11 width break.
roysandberg 62:8e2fbe131b53 98 #define R11_WIDTH_DIFF1 BEAT_MS40 // Rule 11 width difference threshold 1
roysandberg 62:8e2fbe131b53 99 #define R11_WIDTH_DIFF2 BEAT_MS60 // Rule 11 width difference threshold 2
roysandberg 62:8e2fbe131b53 100 #define R11_HF_THRESHOLD 45 // Rule 11 high frequency noise threshold.
roysandberg 62:8e2fbe131b53 101 #define R11_MA_THRESHOLD 14 // Rule 11 motion artifact threshold.
roysandberg 62:8e2fbe131b53 102 #define R11_BC_LIM 1 // Rule 11 beat count limit.
roysandberg 62:8e2fbe131b53 103 #define R15_DI_THRESHOLD 3.5 // Rule 15 dominant similarity index threshold
roysandberg 62:8e2fbe131b53 104 #define R15_WIDTH_THRESHOLD BEAT_MS100 // Rule 15 width threshold.
roysandberg 62:8e2fbe131b53 105 #define R16_WIDTH_THRESHOLD BEAT_MS100 // Rule 16 width threshold.
roysandberg 62:8e2fbe131b53 106 #define R17_WIDTH_DELTA BEAT_MS20 // Rule 17 difference threshold.
roysandberg 62:8e2fbe131b53 107 #define R18_DI_THRESHOLD 1.5 // Rule 18 dominant similarity index threshold.
roysandberg 62:8e2fbe131b53 108 #define R19_HF_THRESHOLD 75 // Rule 19 high frequency noise threshold.
roysandberg 62:8e2fbe131b53 109
roysandberg 62:8e2fbe131b53 110 // Dominant monitor constants.
roysandberg 62:8e2fbe131b53 111
roysandberg 62:8e2fbe131b53 112 #define DM_BUFFER_LENGTH 180
roysandberg 62:8e2fbe131b53 113 #define IRREG_RR_LIMIT 60
roysandberg 62:8e2fbe131b53 114
roysandberg 62:8e2fbe131b53 115 // Local prototypes.
roysandberg 62:8e2fbe131b53 116
roysandberg 62:8e2fbe131b53 117 int HFNoiseCheck(int *beat) ;
roysandberg 62:8e2fbe131b53 118 int TempClass(int rhythmClass, int morphType, int beatWidth, int domWidth,
roysandberg 62:8e2fbe131b53 119 int domType, int hfNoise, int noiseLevel, int blShift, double domIndex) ;
roysandberg 62:8e2fbe131b53 120 int DomMonitor(int morphType, int rhythmClass, int beatWidth, int rr, int reset) ;
roysandberg 62:8e2fbe131b53 121 int GetDomRhythm(void) ;
roysandberg 62:8e2fbe131b53 122 int GetRunCount(void) ;
roysandberg 62:8e2fbe131b53 123
roysandberg 62:8e2fbe131b53 124 // Local Global variables
roysandberg 62:8e2fbe131b53 125
roysandberg 62:8e2fbe131b53 126 int DomType ;
roysandberg 62:8e2fbe131b53 127 int RecentRRs[8], RecentTypes[8] ;
roysandberg 62:8e2fbe131b53 128
roysandberg 62:8e2fbe131b53 129 /***************************************************************************
roysandberg 62:8e2fbe131b53 130 * Classify() takes a beat buffer, the previous rr interval, and the present
roysandberg 62:8e2fbe131b53 131 * noise level estimate and returns a beat classification of NORMAL, PVC, or
roysandberg 62:8e2fbe131b53 132 * UNKNOWN. The UNKNOWN classification is only returned. The beat template
roysandberg 62:8e2fbe131b53 133 * type that the beat has been matched to is returned through the pointer
roysandberg 62:8e2fbe131b53 134 * *beatMatch for debugging display. Passing anything other than 0 in init
roysandberg 62:8e2fbe131b53 135 * resets the static variables used by Classify.
roysandberg 62:8e2fbe131b53 136 ****************************************************************************/
roysandberg 62:8e2fbe131b53 137
roysandberg 62:8e2fbe131b53 138 int Classify(int *newBeat,int rr, int noiseLevel, int *beatMatch, int *fidAdj,
roysandberg 62:8e2fbe131b53 139 int init)
roysandberg 62:8e2fbe131b53 140 {
roysandberg 62:8e2fbe131b53 141 int rhythmClass, beatClass, i, beatWidth, blShift ;
roysandberg 62:8e2fbe131b53 142 static int morphType, runCount = 0 ;
roysandberg 62:8e2fbe131b53 143 double matchIndex, domIndex, mi2 ;
roysandberg 62:8e2fbe131b53 144 int shiftAdj ;
roysandberg 62:8e2fbe131b53 145 int domType, domWidth, onset, offset, amp ;
roysandberg 62:8e2fbe131b53 146 int beatBegin, beatEnd, tempClass ;
roysandberg 62:8e2fbe131b53 147 int hfNoise, isoLevel ;
roysandberg 62:8e2fbe131b53 148 static int lastIsoLevel=0, lastRhythmClass = UNKNOWN, lastBeatWasNew = 0 ;
roysandberg 62:8e2fbe131b53 149
roysandberg 62:8e2fbe131b53 150 // If initializing...
roysandberg 62:8e2fbe131b53 151
roysandberg 62:8e2fbe131b53 152 if(init)
roysandberg 62:8e2fbe131b53 153 {
roysandberg 62:8e2fbe131b53 154 ResetRhythmChk() ;
roysandberg 62:8e2fbe131b53 155 ResetMatch() ;
roysandberg 62:8e2fbe131b53 156 ResetPostClassify() ;
roysandberg 62:8e2fbe131b53 157 runCount = 0 ;
roysandberg 62:8e2fbe131b53 158 DomMonitor(0, 0, 0, 0, 1) ;
roysandberg 62:8e2fbe131b53 159 return(0) ;
roysandberg 62:8e2fbe131b53 160 }
roysandberg 62:8e2fbe131b53 161
roysandberg 62:8e2fbe131b53 162 hfNoise = HFNoiseCheck(newBeat) ; // Check for muscle noise.
roysandberg 62:8e2fbe131b53 163 rhythmClass = RhythmChk(rr) ; // Check the rhythm.
roysandberg 62:8e2fbe131b53 164
roysandberg 62:8e2fbe131b53 165 // Estimate beat features.
roysandberg 62:8e2fbe131b53 166
roysandberg 62:8e2fbe131b53 167 AnalyzeBeat(newBeat, &onset, &offset, &isoLevel,
roysandberg 62:8e2fbe131b53 168 &beatBegin, &beatEnd, &amp) ;
roysandberg 62:8e2fbe131b53 169
roysandberg 62:8e2fbe131b53 170 blShift = abs(lastIsoLevel-isoLevel) ;
roysandberg 62:8e2fbe131b53 171 lastIsoLevel = isoLevel ;
roysandberg 62:8e2fbe131b53 172
roysandberg 62:8e2fbe131b53 173 // Make isoelectric level 0.
roysandberg 62:8e2fbe131b53 174
roysandberg 62:8e2fbe131b53 175 for(i = 0; i < BEATLGTH; ++i)
roysandberg 62:8e2fbe131b53 176 newBeat[i] -= isoLevel ;
roysandberg 62:8e2fbe131b53 177
roysandberg 62:8e2fbe131b53 178 // If there was a significant baseline shift since
roysandberg 62:8e2fbe131b53 179 // the last beat and the last beat was a new type,
roysandberg 62:8e2fbe131b53 180 // delete the new type because it might have resulted
roysandberg 62:8e2fbe131b53 181 // from a baseline shift.
roysandberg 62:8e2fbe131b53 182
roysandberg 62:8e2fbe131b53 183 if( (blShift > BL_SHIFT_LIMIT)
roysandberg 62:8e2fbe131b53 184 && (lastBeatWasNew == 1)
roysandberg 62:8e2fbe131b53 185 && (lastRhythmClass == NORMAL)
roysandberg 62:8e2fbe131b53 186 && (rhythmClass == NORMAL) )
roysandberg 62:8e2fbe131b53 187 ClearLastNewType() ;
roysandberg 62:8e2fbe131b53 188
roysandberg 62:8e2fbe131b53 189 lastBeatWasNew = 0 ;
roysandberg 62:8e2fbe131b53 190
roysandberg 62:8e2fbe131b53 191 // Find the template that best matches this beat.
roysandberg 62:8e2fbe131b53 192
roysandberg 62:8e2fbe131b53 193 BestMorphMatch(newBeat,&morphType,&matchIndex,&mi2,&shiftAdj) ;
roysandberg 62:8e2fbe131b53 194
roysandberg 62:8e2fbe131b53 195 // Disregard noise if the match is good. (New)
roysandberg 62:8e2fbe131b53 196
roysandberg 62:8e2fbe131b53 197 if(matchIndex < MATCH_NOISE_THRESHOLD)
roysandberg 62:8e2fbe131b53 198 hfNoise = noiseLevel = blShift = 0 ;
roysandberg 62:8e2fbe131b53 199
roysandberg 62:8e2fbe131b53 200 // Apply a stricter match limit to premature beats.
roysandberg 62:8e2fbe131b53 201
roysandberg 62:8e2fbe131b53 202 if((matchIndex < MATCH_LIMIT) && (rhythmClass == PVC) &&
roysandberg 62:8e2fbe131b53 203 MinimumBeatVariation(morphType) && (mi2 > PVC_MATCH_WITH_AMP_LIMIT))
roysandberg 62:8e2fbe131b53 204 {
roysandberg 62:8e2fbe131b53 205 morphType = NewBeatType(newBeat) ;
roysandberg 62:8e2fbe131b53 206 lastBeatWasNew = 1 ;
roysandberg 62:8e2fbe131b53 207 }
roysandberg 62:8e2fbe131b53 208
roysandberg 62:8e2fbe131b53 209 // Match if within standard match limits.
roysandberg 62:8e2fbe131b53 210
roysandberg 62:8e2fbe131b53 211 else if((matchIndex < MATCH_LIMIT) && (mi2 <= MATCH_WITH_AMP_LIMIT))
roysandberg 62:8e2fbe131b53 212 UpdateBeatType(morphType,newBeat,mi2,shiftAdj) ;
roysandberg 62:8e2fbe131b53 213
roysandberg 62:8e2fbe131b53 214 // If the beat isn't noisy but doesn't match, start a new beat.
roysandberg 62:8e2fbe131b53 215
roysandberg 62:8e2fbe131b53 216 else if((blShift < BL_SHIFT_LIMIT) && (noiseLevel < NEW_TYPE_NOISE_THRESHOLD)
roysandberg 62:8e2fbe131b53 217 && (hfNoise < NEW_TYPE_HF_NOISE_LIMIT))
roysandberg 62:8e2fbe131b53 218 {
roysandberg 62:8e2fbe131b53 219 morphType = NewBeatType(newBeat) ;
roysandberg 62:8e2fbe131b53 220 lastBeatWasNew = 1 ;
roysandberg 62:8e2fbe131b53 221 }
roysandberg 62:8e2fbe131b53 222
roysandberg 62:8e2fbe131b53 223 // Even if it is a noisy, start new beat if it was an irregular beat.
roysandberg 62:8e2fbe131b53 224
roysandberg 62:8e2fbe131b53 225 else if((lastRhythmClass != NORMAL) || (rhythmClass != NORMAL))
roysandberg 62:8e2fbe131b53 226 {
roysandberg 62:8e2fbe131b53 227 morphType = NewBeatType(newBeat) ;
roysandberg 62:8e2fbe131b53 228 lastBeatWasNew = 1 ;
roysandberg 62:8e2fbe131b53 229 }
roysandberg 62:8e2fbe131b53 230
roysandberg 62:8e2fbe131b53 231 // If its noisy and regular, don't waste space starting a new beat.
roysandberg 62:8e2fbe131b53 232
roysandberg 62:8e2fbe131b53 233 else morphType = MAXTYPES ;
roysandberg 62:8e2fbe131b53 234
roysandberg 62:8e2fbe131b53 235 // Update recent rr and type arrays.
roysandberg 62:8e2fbe131b53 236
roysandberg 62:8e2fbe131b53 237 for(i = 7; i > 0; --i)
roysandberg 62:8e2fbe131b53 238 {
roysandberg 62:8e2fbe131b53 239 RecentRRs[i] = RecentRRs[i-1] ;
roysandberg 62:8e2fbe131b53 240 RecentTypes[i] = RecentTypes[i-1] ;
roysandberg 62:8e2fbe131b53 241 }
roysandberg 62:8e2fbe131b53 242 RecentRRs[0] = rr ;
roysandberg 62:8e2fbe131b53 243 RecentTypes[0] = morphType ;
roysandberg 62:8e2fbe131b53 244
roysandberg 62:8e2fbe131b53 245 lastRhythmClass = rhythmClass ;
roysandberg 62:8e2fbe131b53 246 lastIsoLevel = isoLevel ;
roysandberg 62:8e2fbe131b53 247
roysandberg 62:8e2fbe131b53 248 // Fetch beat features needed for classification.
roysandberg 62:8e2fbe131b53 249 // Get features from average beat if it matched.
roysandberg 62:8e2fbe131b53 250
roysandberg 62:8e2fbe131b53 251 if(morphType != MAXTYPES)
roysandberg 62:8e2fbe131b53 252 {
roysandberg 62:8e2fbe131b53 253 beatClass = GetBeatClass(morphType) ;
roysandberg 62:8e2fbe131b53 254 beatWidth = GetBeatWidth(morphType) ;
roysandberg 62:8e2fbe131b53 255 *fidAdj = GetBeatCenter(morphType)-FIDMARK ;
roysandberg 62:8e2fbe131b53 256
roysandberg 62:8e2fbe131b53 257 // If the width seems large and there have only been a few
roysandberg 62:8e2fbe131b53 258 // beats of this type, use the actual beat for width
roysandberg 62:8e2fbe131b53 259 // estimate.
roysandberg 62:8e2fbe131b53 260
roysandberg 62:8e2fbe131b53 261 if((beatWidth > offset-onset) && (GetBeatTypeCount(morphType) <= 4))
roysandberg 62:8e2fbe131b53 262 {
roysandberg 62:8e2fbe131b53 263 beatWidth = offset-onset ;
roysandberg 62:8e2fbe131b53 264 *fidAdj = ((offset+onset)/2)-FIDMARK ;
roysandberg 62:8e2fbe131b53 265 }
roysandberg 62:8e2fbe131b53 266 }
roysandberg 62:8e2fbe131b53 267
roysandberg 62:8e2fbe131b53 268 // If this beat didn't match get beat features directly
roysandberg 62:8e2fbe131b53 269 // from this beat.
roysandberg 62:8e2fbe131b53 270
roysandberg 62:8e2fbe131b53 271 else
roysandberg 62:8e2fbe131b53 272 {
roysandberg 62:8e2fbe131b53 273 beatWidth = offset-onset ;
roysandberg 62:8e2fbe131b53 274 beatClass = UNKNOWN ;
roysandberg 62:8e2fbe131b53 275 *fidAdj = ((offset+onset)/2)-FIDMARK ;
roysandberg 62:8e2fbe131b53 276 }
roysandberg 62:8e2fbe131b53 277
roysandberg 62:8e2fbe131b53 278 // Fetch dominant type beat features.
roysandberg 62:8e2fbe131b53 279
roysandberg 62:8e2fbe131b53 280 DomType = domType = DomMonitor(morphType, rhythmClass, beatWidth, rr, 0) ;
roysandberg 62:8e2fbe131b53 281 domWidth = GetBeatWidth(domType) ;
roysandberg 62:8e2fbe131b53 282
roysandberg 62:8e2fbe131b53 283 // Compare the beat type, or actual beat to the dominant beat.
roysandberg 62:8e2fbe131b53 284
roysandberg 62:8e2fbe131b53 285 if((morphType != domType) && (morphType != 8))
roysandberg 62:8e2fbe131b53 286 domIndex = DomCompare(morphType,domType) ;
roysandberg 62:8e2fbe131b53 287 else if(morphType == 8)
roysandberg 62:8e2fbe131b53 288 domIndex = DomCompare2(newBeat,domType) ;
roysandberg 62:8e2fbe131b53 289 else domIndex = matchIndex ;
roysandberg 62:8e2fbe131b53 290
roysandberg 62:8e2fbe131b53 291 // Update post classificaton of the previous beat.
roysandberg 62:8e2fbe131b53 292
roysandberg 62:8e2fbe131b53 293 PostClassify(RecentTypes, domType, RecentRRs, beatWidth, domIndex, rhythmClass) ;
roysandberg 62:8e2fbe131b53 294
roysandberg 62:8e2fbe131b53 295 // Classify regardless of how the morphology
roysandberg 62:8e2fbe131b53 296 // was previously classified.
roysandberg 62:8e2fbe131b53 297
roysandberg 62:8e2fbe131b53 298 tempClass = TempClass(rhythmClass, morphType, beatWidth, domWidth,
roysandberg 62:8e2fbe131b53 299 domType, hfNoise, noiseLevel, blShift, domIndex) ;
roysandberg 62:8e2fbe131b53 300
roysandberg 62:8e2fbe131b53 301 // If this morphology has not been classified yet, attempt to classify
roysandberg 62:8e2fbe131b53 302 // it.
roysandberg 62:8e2fbe131b53 303
roysandberg 62:8e2fbe131b53 304 if((beatClass == UNKNOWN) && (morphType < MAXTYPES))
roysandberg 62:8e2fbe131b53 305 {
roysandberg 62:8e2fbe131b53 306
roysandberg 62:8e2fbe131b53 307 // Classify as normal if there are 6 in a row
roysandberg 62:8e2fbe131b53 308 // or at least two in a row that meet rhythm
roysandberg 62:8e2fbe131b53 309 // rules for normal.
roysandberg 62:8e2fbe131b53 310
roysandberg 62:8e2fbe131b53 311 runCount = GetRunCount() ;
roysandberg 62:8e2fbe131b53 312
roysandberg 62:8e2fbe131b53 313 // Classify a morphology as NORMAL if it is not too wide, and there
roysandberg 62:8e2fbe131b53 314 // are three in a row. The width criterion prevents ventricular beats
roysandberg 62:8e2fbe131b53 315 // from being classified as normal during VTACH (MIT/BIH 205).
roysandberg 62:8e2fbe131b53 316
roysandberg 62:8e2fbe131b53 317 if((runCount >= 3) && (domType != -1) && (beatWidth < domWidth+BEAT_MS20))
roysandberg 62:8e2fbe131b53 318 SetBeatClass(morphType,NORMAL) ;
roysandberg 62:8e2fbe131b53 319
roysandberg 62:8e2fbe131b53 320 // If there is no dominant type established yet, classify any type
roysandberg 62:8e2fbe131b53 321 // with six in a row as NORMAL.
roysandberg 62:8e2fbe131b53 322
roysandberg 62:8e2fbe131b53 323 else if((runCount >= 6) && (domType == -1))
roysandberg 62:8e2fbe131b53 324 SetBeatClass(morphType,NORMAL) ;
roysandberg 62:8e2fbe131b53 325
roysandberg 62:8e2fbe131b53 326 // During bigeminy, classify the premature beats as ventricular if
roysandberg 62:8e2fbe131b53 327 // they are not too narrow.
roysandberg 62:8e2fbe131b53 328
roysandberg 62:8e2fbe131b53 329 else if(IsBigeminy() == 1)
roysandberg 62:8e2fbe131b53 330 {
roysandberg 62:8e2fbe131b53 331 if((rhythmClass == PVC) && (beatWidth > BEAT_MS100))
roysandberg 62:8e2fbe131b53 332 SetBeatClass(morphType,PVC) ;
roysandberg 62:8e2fbe131b53 333 else if(rhythmClass == NORMAL)
roysandberg 62:8e2fbe131b53 334 SetBeatClass(morphType,NORMAL) ;
roysandberg 62:8e2fbe131b53 335 }
roysandberg 62:8e2fbe131b53 336 }
roysandberg 62:8e2fbe131b53 337
roysandberg 62:8e2fbe131b53 338 // Save morphology type of this beat for next classification.
roysandberg 62:8e2fbe131b53 339
roysandberg 62:8e2fbe131b53 340 *beatMatch = morphType ;
roysandberg 62:8e2fbe131b53 341
roysandberg 62:8e2fbe131b53 342 beatClass = GetBeatClass(morphType) ;
roysandberg 62:8e2fbe131b53 343
roysandberg 62:8e2fbe131b53 344 // If the morphology has been previously classified.
roysandberg 62:8e2fbe131b53 345 // use that classification.
roysandberg 62:8e2fbe131b53 346 // return(rhythmClass) ;
roysandberg 62:8e2fbe131b53 347
roysandberg 62:8e2fbe131b53 348 if(beatClass != UNKNOWN)
roysandberg 62:8e2fbe131b53 349 return(beatClass) ;
roysandberg 62:8e2fbe131b53 350
roysandberg 62:8e2fbe131b53 351 if(CheckPostClass(morphType) == PVC)
roysandberg 62:8e2fbe131b53 352 return(PVC) ;
roysandberg 62:8e2fbe131b53 353
roysandberg 62:8e2fbe131b53 354 // Otherwise use the temporary classification.
roysandberg 62:8e2fbe131b53 355
roysandberg 62:8e2fbe131b53 356 return(tempClass) ;
roysandberg 62:8e2fbe131b53 357 }
roysandberg 62:8e2fbe131b53 358
roysandberg 62:8e2fbe131b53 359 /**************************************************************************
roysandberg 62:8e2fbe131b53 360 * HFNoiseCheck() gauges the high frequency (muscle noise) present in the
roysandberg 62:8e2fbe131b53 361 * beat template. The high frequency noise level is estimated by highpass
roysandberg 62:8e2fbe131b53 362 * filtering the beat (y[n] = x[n] - 2*x[n-1] + x[n-2]), averaging the
roysandberg 62:8e2fbe131b53 363 * highpass filtered signal over five samples, and finding the maximum of
roysandberg 62:8e2fbe131b53 364 * this averaged highpass filtered signal. The high frequency noise metric
roysandberg 62:8e2fbe131b53 365 * is then taken to be the ratio of the maximum averaged highpassed signal
roysandberg 62:8e2fbe131b53 366 * to the QRS amplitude.
roysandberg 62:8e2fbe131b53 367 **************************************************************************/
roysandberg 62:8e2fbe131b53 368
roysandberg 62:8e2fbe131b53 369 #define AVELENGTH BEAT_MS50
roysandberg 62:8e2fbe131b53 370
roysandberg 62:8e2fbe131b53 371 int HFNoiseCheck(int *beat)
roysandberg 62:8e2fbe131b53 372 {
roysandberg 62:8e2fbe131b53 373 int maxNoiseAve = 0, i ;
roysandberg 62:8e2fbe131b53 374 int sum=0, aveBuff[AVELENGTH], avePtr = 0 ;
roysandberg 62:8e2fbe131b53 375 int qrsMax = 0, qrsMin = 0 ;
roysandberg 62:8e2fbe131b53 376
roysandberg 62:8e2fbe131b53 377 // Determine the QRS amplitude.
roysandberg 62:8e2fbe131b53 378
roysandberg 62:8e2fbe131b53 379 for(i = FIDMARK-BEAT_MS70; i < FIDMARK+BEAT_MS80; ++i)
roysandberg 62:8e2fbe131b53 380 if(beat[i] > qrsMax)
roysandberg 62:8e2fbe131b53 381 qrsMax = beat[i] ;
roysandberg 62:8e2fbe131b53 382 else if(beat[i] < qrsMin)
roysandberg 62:8e2fbe131b53 383 qrsMin = beat[i] ;
roysandberg 62:8e2fbe131b53 384
roysandberg 62:8e2fbe131b53 385 for(i = 0; i < AVELENGTH; ++i)
roysandberg 62:8e2fbe131b53 386 aveBuff[i] = 0 ;
roysandberg 62:8e2fbe131b53 387
roysandberg 62:8e2fbe131b53 388 for(i = FIDMARK-BEAT_MS280; i < FIDMARK+BEAT_MS280; ++i)
roysandberg 62:8e2fbe131b53 389 {
roysandberg 62:8e2fbe131b53 390 sum -= aveBuff[avePtr] ;
roysandberg 62:8e2fbe131b53 391 aveBuff[avePtr] = abs(beat[i] - (beat[i-BEAT_MS10]<<1) + beat[i-2*BEAT_MS10]) ;
roysandberg 62:8e2fbe131b53 392 sum += aveBuff[avePtr] ;
roysandberg 62:8e2fbe131b53 393 if(++avePtr == AVELENGTH)
roysandberg 62:8e2fbe131b53 394 avePtr = 0 ;
roysandberg 62:8e2fbe131b53 395 if((i < (FIDMARK - BEAT_MS50)) || (i > (FIDMARK + BEAT_MS110)))
roysandberg 62:8e2fbe131b53 396 if(sum > maxNoiseAve)
roysandberg 62:8e2fbe131b53 397 maxNoiseAve = sum ;
roysandberg 62:8e2fbe131b53 398 }
roysandberg 62:8e2fbe131b53 399 if((qrsMax - qrsMin)>=4)
roysandberg 62:8e2fbe131b53 400 return((maxNoiseAve * (50/AVELENGTH))/((qrsMax-qrsMin)>>2)) ;
roysandberg 62:8e2fbe131b53 401 else return(0) ;
roysandberg 62:8e2fbe131b53 402 }
roysandberg 62:8e2fbe131b53 403
roysandberg 62:8e2fbe131b53 404 /************************************************************************
roysandberg 62:8e2fbe131b53 405 * TempClass() classifies beats based on their beat features, relative
roysandberg 62:8e2fbe131b53 406 * to the features of the dominant beat and the present noise level.
roysandberg 62:8e2fbe131b53 407 *************************************************************************/
roysandberg 62:8e2fbe131b53 408
roysandberg 62:8e2fbe131b53 409 int TempClass(int rhythmClass, int morphType,
roysandberg 62:8e2fbe131b53 410 int beatWidth, int domWidth, int domType,
roysandberg 62:8e2fbe131b53 411 int hfNoise, int noiseLevel, int blShift, double domIndex)
roysandberg 62:8e2fbe131b53 412 {
roysandberg 62:8e2fbe131b53 413
roysandberg 62:8e2fbe131b53 414 // Rule 1: If no dominant type has been detected classify all
roysandberg 62:8e2fbe131b53 415 // beats as UNKNOWN.
roysandberg 62:8e2fbe131b53 416
roysandberg 62:8e2fbe131b53 417 if(domType < 0)
roysandberg 62:8e2fbe131b53 418 return(UNKNOWN) ;
roysandberg 62:8e2fbe131b53 419
roysandberg 62:8e2fbe131b53 420 // Rule 2: If the dominant rhythm is normal, the dominant
roysandberg 62:8e2fbe131b53 421 // beat type doesn't vary much, this beat is premature
roysandberg 62:8e2fbe131b53 422 // and looks sufficiently different than the dominant beat
roysandberg 62:8e2fbe131b53 423 // classify as PVC.
roysandberg 62:8e2fbe131b53 424
roysandberg 62:8e2fbe131b53 425 if(MinimumBeatVariation(domType) && (rhythmClass == PVC)
roysandberg 62:8e2fbe131b53 426 && (domIndex > R2_DI_THRESHOLD) && (GetDomRhythm() == 1))
roysandberg 62:8e2fbe131b53 427 return(PVC) ;
roysandberg 62:8e2fbe131b53 428
roysandberg 62:8e2fbe131b53 429 // Rule 3: If the beat is sufficiently narrow, classify as normal.
roysandberg 62:8e2fbe131b53 430
roysandberg 62:8e2fbe131b53 431 if(beatWidth < R3_WIDTH_THRESHOLD)
roysandberg 62:8e2fbe131b53 432 return(NORMAL) ;
roysandberg 62:8e2fbe131b53 433
roysandberg 62:8e2fbe131b53 434 // Rule 5: If the beat cannot be matched to any previously
roysandberg 62:8e2fbe131b53 435 // detected morphology and it is not premature, consider it normal
roysandberg 62:8e2fbe131b53 436 // (probably noisy).
roysandberg 62:8e2fbe131b53 437
roysandberg 62:8e2fbe131b53 438 if((morphType == MAXTYPES) && (rhythmClass != PVC)) // == UNKNOWN
roysandberg 62:8e2fbe131b53 439 return(NORMAL) ;
roysandberg 62:8e2fbe131b53 440
roysandberg 62:8e2fbe131b53 441 // Rule 6: If the maximum number of beat types have been stored,
roysandberg 62:8e2fbe131b53 442 // this beat is not regular or premature and only one
roysandberg 62:8e2fbe131b53 443 // beat of this morphology has been seen, call it normal (probably
roysandberg 62:8e2fbe131b53 444 // noisy).
roysandberg 62:8e2fbe131b53 445
roysandberg 62:8e2fbe131b53 446 if((GetTypesCount() == MAXTYPES) && (GetBeatTypeCount(morphType)==1)
roysandberg 62:8e2fbe131b53 447 && (rhythmClass == UNKNOWN))
roysandberg 62:8e2fbe131b53 448 return(NORMAL) ;
roysandberg 62:8e2fbe131b53 449
roysandberg 62:8e2fbe131b53 450 // Rule 7: If this beat looks like the dominant beat and the
roysandberg 62:8e2fbe131b53 451 // rhythm is regular, call it normal.
roysandberg 62:8e2fbe131b53 452
roysandberg 62:8e2fbe131b53 453 if((domIndex < R7_DI_THRESHOLD) && (rhythmClass == NORMAL))
roysandberg 62:8e2fbe131b53 454 return(NORMAL) ;
roysandberg 62:8e2fbe131b53 455
roysandberg 62:8e2fbe131b53 456 // Rule 8: If post classification rhythm is normal for this
roysandberg 62:8e2fbe131b53 457 // type and its shape is close to the dominant shape, classify
roysandberg 62:8e2fbe131b53 458 // as normal.
roysandberg 62:8e2fbe131b53 459
roysandberg 62:8e2fbe131b53 460 if((domIndex < R8_DI_THRESHOLD) && (CheckPCRhythm(morphType) == NORMAL))
roysandberg 62:8e2fbe131b53 461 return(NORMAL) ;
roysandberg 62:8e2fbe131b53 462
roysandberg 62:8e2fbe131b53 463 // Rule 9: If the beat is not premature, it looks similar to the dominant
roysandberg 62:8e2fbe131b53 464 // beat type, and the dominant beat type is variable (noisy), classify as
roysandberg 62:8e2fbe131b53 465 // normal.
roysandberg 62:8e2fbe131b53 466
roysandberg 62:8e2fbe131b53 467 if((domIndex < R9_DI_THRESHOLD) && (rhythmClass != PVC) && WideBeatVariation(domType))
roysandberg 62:8e2fbe131b53 468 return(NORMAL) ;
roysandberg 62:8e2fbe131b53 469
roysandberg 62:8e2fbe131b53 470 // Rule 10: If this beat is significantly different from the dominant beat
roysandberg 62:8e2fbe131b53 471 // there have previously been matching beats, the post rhythm classification
roysandberg 62:8e2fbe131b53 472 // of this type is PVC, and the dominant rhythm is regular, classify as PVC.
roysandberg 62:8e2fbe131b53 473
roysandberg 62:8e2fbe131b53 474 if((domIndex > R10_DI_THRESHOLD)
roysandberg 62:8e2fbe131b53 475 && (GetBeatTypeCount(morphType) >= R10_BC_LIM) &&
roysandberg 62:8e2fbe131b53 476 (CheckPCRhythm(morphType) == PVC) && (GetDomRhythm() == 1))
roysandberg 62:8e2fbe131b53 477 return(PVC) ;
roysandberg 62:8e2fbe131b53 478
roysandberg 62:8e2fbe131b53 479 // Rule 11: if the beat is wide, wider than the dominant beat, doesn't
roysandberg 62:8e2fbe131b53 480 // appear to be noisy, and matches a previous type, classify it as
roysandberg 62:8e2fbe131b53 481 // a PVC.
roysandberg 62:8e2fbe131b53 482
roysandberg 62:8e2fbe131b53 483 if( (beatWidth >= R11_MIN_WIDTH) &&
roysandberg 62:8e2fbe131b53 484 (((beatWidth - domWidth >= R11_WIDTH_DIFF1) && (domWidth < R11_WIDTH_BREAK)) ||
roysandberg 62:8e2fbe131b53 485 (beatWidth - domWidth >= R11_WIDTH_DIFF2)) &&
roysandberg 62:8e2fbe131b53 486 (hfNoise < R11_HF_THRESHOLD) && (noiseLevel < R11_MA_THRESHOLD) && (blShift < BL_SHIFT_LIMIT) &&
roysandberg 62:8e2fbe131b53 487 (morphType < MAXTYPES) && (GetBeatTypeCount(morphType) > R11_BC_LIM)) // Rev 1.1
roysandberg 62:8e2fbe131b53 488
roysandberg 62:8e2fbe131b53 489 return(PVC) ;
roysandberg 62:8e2fbe131b53 490
roysandberg 62:8e2fbe131b53 491 // Rule 12: If the dominant rhythm is regular and this beat is premature
roysandberg 62:8e2fbe131b53 492 // then classify as PVC.
roysandberg 62:8e2fbe131b53 493
roysandberg 62:8e2fbe131b53 494 if((rhythmClass == PVC) && (GetDomRhythm() == 1))
roysandberg 62:8e2fbe131b53 495 return(PVC) ;
roysandberg 62:8e2fbe131b53 496
roysandberg 62:8e2fbe131b53 497 // Rule 14: If the beat is regular and the dominant rhythm is regular
roysandberg 62:8e2fbe131b53 498 // call the beat normal.
roysandberg 62:8e2fbe131b53 499
roysandberg 62:8e2fbe131b53 500 if((rhythmClass == NORMAL) && (GetDomRhythm() == 1))
roysandberg 62:8e2fbe131b53 501 return(NORMAL) ;
roysandberg 62:8e2fbe131b53 502
roysandberg 62:8e2fbe131b53 503 // By this point, we know that rhythm will not help us, so we
roysandberg 62:8e2fbe131b53 504 // have to classify based on width and similarity to the dominant
roysandberg 62:8e2fbe131b53 505 // beat type.
roysandberg 62:8e2fbe131b53 506
roysandberg 62:8e2fbe131b53 507 // Rule 15: If the beat is wider than normal, wide on an
roysandberg 62:8e2fbe131b53 508 // absolute scale, and significantly different from the
roysandberg 62:8e2fbe131b53 509 // dominant beat, call it a PVC.
roysandberg 62:8e2fbe131b53 510
roysandberg 62:8e2fbe131b53 511 if((beatWidth > domWidth) && (domIndex > R15_DI_THRESHOLD) &&
roysandberg 62:8e2fbe131b53 512 (beatWidth >= R15_WIDTH_THRESHOLD))
roysandberg 62:8e2fbe131b53 513 return(PVC) ;
roysandberg 62:8e2fbe131b53 514
roysandberg 62:8e2fbe131b53 515 // Rule 16: If the beat is sufficiently narrow, call it normal.
roysandberg 62:8e2fbe131b53 516
roysandberg 62:8e2fbe131b53 517 if(beatWidth < R16_WIDTH_THRESHOLD)
roysandberg 62:8e2fbe131b53 518 return(NORMAL) ;
roysandberg 62:8e2fbe131b53 519
roysandberg 62:8e2fbe131b53 520 // Rule 17: If the beat isn't much wider than the dominant beat
roysandberg 62:8e2fbe131b53 521 // call it normal.
roysandberg 62:8e2fbe131b53 522
roysandberg 62:8e2fbe131b53 523 if(beatWidth < domWidth + R17_WIDTH_DELTA)
roysandberg 62:8e2fbe131b53 524 return(NORMAL) ;
roysandberg 62:8e2fbe131b53 525
roysandberg 62:8e2fbe131b53 526 // If the beat is noisy but reasonably close to dominant,
roysandberg 62:8e2fbe131b53 527 // call it normal.
roysandberg 62:8e2fbe131b53 528
roysandberg 62:8e2fbe131b53 529 // Rule 18: If the beat is similar to the dominant beat, call it normal.
roysandberg 62:8e2fbe131b53 530
roysandberg 62:8e2fbe131b53 531 if(domIndex < R18_DI_THRESHOLD)
roysandberg 62:8e2fbe131b53 532 return(NORMAL) ;
roysandberg 62:8e2fbe131b53 533
roysandberg 62:8e2fbe131b53 534 // If it's noisy don't trust the width.
roysandberg 62:8e2fbe131b53 535
roysandberg 62:8e2fbe131b53 536 // Rule 19: If the beat is noisy, we can't trust our width estimate
roysandberg 62:8e2fbe131b53 537 // and we have no useful rhythm information, so guess normal.
roysandberg 62:8e2fbe131b53 538
roysandberg 62:8e2fbe131b53 539 if(hfNoise > R19_HF_THRESHOLD)
roysandberg 62:8e2fbe131b53 540 return(NORMAL) ;
roysandberg 62:8e2fbe131b53 541
roysandberg 62:8e2fbe131b53 542 // Rule 20: By this point, we have no rhythm information, the beat
roysandberg 62:8e2fbe131b53 543 // isn't particularly narrow, the beat isn't particulary similar to
roysandberg 62:8e2fbe131b53 544 // the dominant beat, so guess a PVC.
roysandberg 62:8e2fbe131b53 545
roysandberg 62:8e2fbe131b53 546 return(PVC) ;
roysandberg 62:8e2fbe131b53 547
roysandberg 62:8e2fbe131b53 548 }
roysandberg 62:8e2fbe131b53 549
roysandberg 62:8e2fbe131b53 550
roysandberg 62:8e2fbe131b53 551 /****************************************************************************
roysandberg 62:8e2fbe131b53 552 * DomMonitor, monitors which beat morphology is considered to be dominant.
roysandberg 62:8e2fbe131b53 553 * The dominant morphology is the beat morphology that has been most frequently
roysandberg 62:8e2fbe131b53 554 * classified as normal over the course of the last 120 beats. The dominant
roysandberg 62:8e2fbe131b53 555 * beat rhythm is classified as regular if at least 3/4 of the dominant beats
roysandberg 62:8e2fbe131b53 556 * have been classified as regular.
roysandberg 62:8e2fbe131b53 557 *******************************************************************************/
roysandberg 62:8e2fbe131b53 558
roysandberg 62:8e2fbe131b53 559 #define DM_BUFFER_LENGTH 180
roysandberg 62:8e2fbe131b53 560
roysandberg 62:8e2fbe131b53 561 int NewDom, DomRhythm ;
roysandberg 62:8e2fbe131b53 562 int DMBeatTypes[DM_BUFFER_LENGTH], DMBeatClasses[DM_BUFFER_LENGTH] ;
roysandberg 62:8e2fbe131b53 563 int DMBeatRhythms[DM_BUFFER_LENGTH] ;
roysandberg 62:8e2fbe131b53 564 int DMNormCounts[8], DMBeatCounts[8], DMIrregCount = 0 ;
roysandberg 62:8e2fbe131b53 565
roysandberg 62:8e2fbe131b53 566 int DomMonitor(int morphType, int rhythmClass, int beatWidth, int rr, int reset)
roysandberg 62:8e2fbe131b53 567 {
roysandberg 62:8e2fbe131b53 568 static int brIndex = 0 ;
roysandberg 62:8e2fbe131b53 569 int i, oldType, runCount, dom, max ;
roysandberg 62:8e2fbe131b53 570
roysandberg 62:8e2fbe131b53 571 // Fetch the type of the beat before the last beat.
roysandberg 62:8e2fbe131b53 572
roysandberg 62:8e2fbe131b53 573 i = brIndex - 2 ;
roysandberg 62:8e2fbe131b53 574 if(i < 0)
roysandberg 62:8e2fbe131b53 575 i += DM_BUFFER_LENGTH ;
roysandberg 62:8e2fbe131b53 576 oldType = DMBeatTypes[i] ;
roysandberg 62:8e2fbe131b53 577
roysandberg 62:8e2fbe131b53 578 // If reset flag is set, reset beat type counts and
roysandberg 62:8e2fbe131b53 579 // beat information buffers.
roysandberg 62:8e2fbe131b53 580
roysandberg 62:8e2fbe131b53 581 if(reset != 0)
roysandberg 62:8e2fbe131b53 582 {
roysandberg 62:8e2fbe131b53 583 for(i = 0; i < DM_BUFFER_LENGTH; ++i)
roysandberg 62:8e2fbe131b53 584 {
roysandberg 62:8e2fbe131b53 585 DMBeatTypes[i] = -1 ;
roysandberg 62:8e2fbe131b53 586 DMBeatClasses[i] = 0 ;
roysandberg 62:8e2fbe131b53 587 }
roysandberg 62:8e2fbe131b53 588
roysandberg 62:8e2fbe131b53 589 for(i = 0; i < 8; ++i)
roysandberg 62:8e2fbe131b53 590 {
roysandberg 62:8e2fbe131b53 591 DMNormCounts[i] = 0 ;
roysandberg 62:8e2fbe131b53 592 DMBeatCounts[i] = 0 ;
roysandberg 62:8e2fbe131b53 593 }
roysandberg 62:8e2fbe131b53 594 DMIrregCount = 0 ;
roysandberg 62:8e2fbe131b53 595 return(0) ;
roysandberg 62:8e2fbe131b53 596 }
roysandberg 62:8e2fbe131b53 597
roysandberg 62:8e2fbe131b53 598 // Once we have wrapped around, subtract old beat types from
roysandberg 62:8e2fbe131b53 599 // the beat counts.
roysandberg 62:8e2fbe131b53 600
roysandberg 62:8e2fbe131b53 601 if((DMBeatTypes[brIndex] != -1) && (DMBeatTypes[brIndex] != MAXTYPES))
roysandberg 62:8e2fbe131b53 602 {
roysandberg 62:8e2fbe131b53 603 --DMBeatCounts[DMBeatTypes[brIndex]] ;
roysandberg 62:8e2fbe131b53 604 DMNormCounts[DMBeatTypes[brIndex]] -= DMBeatClasses[brIndex] ;
roysandberg 62:8e2fbe131b53 605 if(DMBeatRhythms[brIndex] == UNKNOWN)
roysandberg 62:8e2fbe131b53 606 --DMIrregCount ;
roysandberg 62:8e2fbe131b53 607 }
roysandberg 62:8e2fbe131b53 608
roysandberg 62:8e2fbe131b53 609 // If this is a morphology that has been detected before, decide
roysandberg 62:8e2fbe131b53 610 // (for the purposes of selecting the dominant normal beattype)
roysandberg 62:8e2fbe131b53 611 // whether it is normal or not and update the approporiate counts.
roysandberg 62:8e2fbe131b53 612
roysandberg 62:8e2fbe131b53 613 if(morphType != 8)
roysandberg 62:8e2fbe131b53 614 {
roysandberg 62:8e2fbe131b53 615
roysandberg 62:8e2fbe131b53 616 // Update the buffers of previous beats and increment the
roysandberg 62:8e2fbe131b53 617 // count for this beat type.
roysandberg 62:8e2fbe131b53 618
roysandberg 62:8e2fbe131b53 619 DMBeatTypes[brIndex] = morphType ;
roysandberg 62:8e2fbe131b53 620 ++DMBeatCounts[morphType] ;
roysandberg 62:8e2fbe131b53 621 DMBeatRhythms[brIndex] = rhythmClass ;
roysandberg 62:8e2fbe131b53 622
roysandberg 62:8e2fbe131b53 623 // If the rhythm appears regular, update the regular rhythm
roysandberg 62:8e2fbe131b53 624 // count.
roysandberg 62:8e2fbe131b53 625
roysandberg 62:8e2fbe131b53 626 if(rhythmClass == UNKNOWN)
roysandberg 62:8e2fbe131b53 627 ++DMIrregCount ;
roysandberg 62:8e2fbe131b53 628
roysandberg 62:8e2fbe131b53 629 // Check to see how many beats of this type have occurred in
roysandberg 62:8e2fbe131b53 630 // a row (stop counting at six).
roysandberg 62:8e2fbe131b53 631
roysandberg 62:8e2fbe131b53 632 i = brIndex - 1 ;
roysandberg 62:8e2fbe131b53 633 if(i < 0) i += DM_BUFFER_LENGTH ;
roysandberg 62:8e2fbe131b53 634 for(runCount = 0; (DMBeatTypes[i] == morphType) && (runCount < 6); ++runCount)
roysandberg 62:8e2fbe131b53 635 if(--i < 0) i += DM_BUFFER_LENGTH ;
roysandberg 62:8e2fbe131b53 636
roysandberg 62:8e2fbe131b53 637 // If the rhythm is regular, the beat width is less than 130 ms, and
roysandberg 62:8e2fbe131b53 638 // there have been at least two in a row, consider the beat to be
roysandberg 62:8e2fbe131b53 639 // normal.
roysandberg 62:8e2fbe131b53 640
roysandberg 62:8e2fbe131b53 641 if((rhythmClass == NORMAL) && (beatWidth < BEAT_MS130) && (runCount >= 1))
roysandberg 62:8e2fbe131b53 642 {
roysandberg 62:8e2fbe131b53 643 DMBeatClasses[brIndex] = 1 ;
roysandberg 62:8e2fbe131b53 644 ++DMNormCounts[morphType] ;
roysandberg 62:8e2fbe131b53 645 }
roysandberg 62:8e2fbe131b53 646
roysandberg 62:8e2fbe131b53 647 // If the last beat was within the normal P-R interval for this beat,
roysandberg 62:8e2fbe131b53 648 // and the one before that was this beat type, assume the last beat
roysandberg 62:8e2fbe131b53 649 // was noise and this beat is normal.
roysandberg 62:8e2fbe131b53 650
roysandberg 62:8e2fbe131b53 651 else if(rr < ((FIDMARK-GetBeatBegin(morphType))*SAMPLE_RATE/BEAT_SAMPLE_RATE)
roysandberg 62:8e2fbe131b53 652 && (oldType == morphType))
roysandberg 62:8e2fbe131b53 653 {
roysandberg 62:8e2fbe131b53 654 DMBeatClasses[brIndex] = 1 ;
roysandberg 62:8e2fbe131b53 655 ++DMNormCounts[morphType] ;
roysandberg 62:8e2fbe131b53 656 }
roysandberg 62:8e2fbe131b53 657
roysandberg 62:8e2fbe131b53 658 // Otherwise assume that this is not a normal beat.
roysandberg 62:8e2fbe131b53 659
roysandberg 62:8e2fbe131b53 660 else DMBeatClasses[brIndex] = 0 ;
roysandberg 62:8e2fbe131b53 661 }
roysandberg 62:8e2fbe131b53 662
roysandberg 62:8e2fbe131b53 663 // If the beat does not match any of the beat types, store
roysandberg 62:8e2fbe131b53 664 // an indication that the beat does not match.
roysandberg 62:8e2fbe131b53 665
roysandberg 62:8e2fbe131b53 666 else
roysandberg 62:8e2fbe131b53 667 {
roysandberg 62:8e2fbe131b53 668 DMBeatClasses[brIndex] = 0 ;
roysandberg 62:8e2fbe131b53 669 DMBeatTypes[brIndex] = -1 ;
roysandberg 62:8e2fbe131b53 670 }
roysandberg 62:8e2fbe131b53 671
roysandberg 62:8e2fbe131b53 672 // Increment the index to the beginning of the circular buffers.
roysandberg 62:8e2fbe131b53 673
roysandberg 62:8e2fbe131b53 674 if(++brIndex == DM_BUFFER_LENGTH)
roysandberg 62:8e2fbe131b53 675 brIndex = 0 ;
roysandberg 62:8e2fbe131b53 676
roysandberg 62:8e2fbe131b53 677 // Determine which beat type has the most beats that seem
roysandberg 62:8e2fbe131b53 678 // normal.
roysandberg 62:8e2fbe131b53 679
roysandberg 62:8e2fbe131b53 680 dom = 0 ;
roysandberg 62:8e2fbe131b53 681 for(i = 1; i < 8; ++i)
roysandberg 62:8e2fbe131b53 682 if(DMNormCounts[i] > DMNormCounts[dom])
roysandberg 62:8e2fbe131b53 683 dom = i ;
roysandberg 62:8e2fbe131b53 684
roysandberg 62:8e2fbe131b53 685 max = 0 ;
roysandberg 62:8e2fbe131b53 686 for(i = 1; i < 8; ++i)
roysandberg 62:8e2fbe131b53 687 if(DMBeatCounts[i] > DMBeatCounts[max])
roysandberg 62:8e2fbe131b53 688 max = i ;
roysandberg 62:8e2fbe131b53 689
roysandberg 62:8e2fbe131b53 690 // If there are no normal looking beats, fall back on which beat
roysandberg 62:8e2fbe131b53 691 // has occurred most frequently since classification began.
roysandberg 62:8e2fbe131b53 692
roysandberg 62:8e2fbe131b53 693 if((DMNormCounts[dom] == 0) || (DMBeatCounts[max]/DMBeatCounts[dom] >= 2)) // == 0
roysandberg 62:8e2fbe131b53 694 dom = GetDominantType() ;
roysandberg 62:8e2fbe131b53 695
roysandberg 62:8e2fbe131b53 696 // If at least half of the most frequently occuring normal
roysandberg 62:8e2fbe131b53 697 // type do not seem normal, fall back on choosing the most frequently
roysandberg 62:8e2fbe131b53 698 // occurring type since classification began.
roysandberg 62:8e2fbe131b53 699
roysandberg 62:8e2fbe131b53 700 else if(DMBeatCounts[dom]/DMNormCounts[dom] >= 2)
roysandberg 62:8e2fbe131b53 701 dom = GetDominantType() ;
roysandberg 62:8e2fbe131b53 702
roysandberg 62:8e2fbe131b53 703 // If there is any beat type that has been classfied as normal,
roysandberg 62:8e2fbe131b53 704 // but at least 10 don't seem normal, reclassify it to UNKNOWN.
roysandberg 62:8e2fbe131b53 705
roysandberg 62:8e2fbe131b53 706 for(i = 0; i < 8; ++i)
roysandberg 62:8e2fbe131b53 707 if((DMBeatCounts[i] > 10) && (DMNormCounts[i] == 0) && (i != dom)
roysandberg 62:8e2fbe131b53 708 && (GetBeatClass(i) == NORMAL))
roysandberg 62:8e2fbe131b53 709 SetBeatClass(i,UNKNOWN) ;
roysandberg 62:8e2fbe131b53 710
roysandberg 62:8e2fbe131b53 711 // Save the dominant type in a global variable so that it is
roysandberg 62:8e2fbe131b53 712 // accessable for debugging.
roysandberg 62:8e2fbe131b53 713
roysandberg 62:8e2fbe131b53 714 NewDom = dom ;
roysandberg 62:8e2fbe131b53 715 return(dom) ;
roysandberg 62:8e2fbe131b53 716 }
roysandberg 62:8e2fbe131b53 717
roysandberg 62:8e2fbe131b53 718 int GetNewDominantType(void)
roysandberg 62:8e2fbe131b53 719 {
roysandberg 62:8e2fbe131b53 720 return(NewDom) ;
roysandberg 62:8e2fbe131b53 721 }
roysandberg 62:8e2fbe131b53 722
roysandberg 62:8e2fbe131b53 723 int GetDomRhythm(void)
roysandberg 62:8e2fbe131b53 724 {
roysandberg 62:8e2fbe131b53 725 if(DMIrregCount > IRREG_RR_LIMIT)
roysandberg 62:8e2fbe131b53 726 return(0) ;
roysandberg 62:8e2fbe131b53 727 else return(1) ;
roysandberg 62:8e2fbe131b53 728 }
roysandberg 62:8e2fbe131b53 729
roysandberg 62:8e2fbe131b53 730
roysandberg 62:8e2fbe131b53 731 void AdjustDomData(int oldType, int newType)
roysandberg 62:8e2fbe131b53 732 {
roysandberg 62:8e2fbe131b53 733 int i ;
roysandberg 62:8e2fbe131b53 734
roysandberg 62:8e2fbe131b53 735 for(i = 0; i < DM_BUFFER_LENGTH; ++i)
roysandberg 62:8e2fbe131b53 736 {
roysandberg 62:8e2fbe131b53 737 if(DMBeatTypes[i] == oldType)
roysandberg 62:8e2fbe131b53 738 DMBeatTypes[i] = newType ;
roysandberg 62:8e2fbe131b53 739 }
roysandberg 62:8e2fbe131b53 740
roysandberg 62:8e2fbe131b53 741 if(newType != MAXTYPES)
roysandberg 62:8e2fbe131b53 742 {
roysandberg 62:8e2fbe131b53 743 DMNormCounts[newType] = DMNormCounts[oldType] ;
roysandberg 62:8e2fbe131b53 744 DMBeatCounts[newType] = DMBeatCounts[oldType] ;
roysandberg 62:8e2fbe131b53 745 }
roysandberg 62:8e2fbe131b53 746
roysandberg 62:8e2fbe131b53 747 DMNormCounts[oldType] = DMBeatCounts[oldType] = 0 ;
roysandberg 62:8e2fbe131b53 748
roysandberg 62:8e2fbe131b53 749 }
roysandberg 62:8e2fbe131b53 750
roysandberg 62:8e2fbe131b53 751 void CombineDomData(int oldType, int newType)
roysandberg 62:8e2fbe131b53 752 {
roysandberg 62:8e2fbe131b53 753 int i ;
roysandberg 62:8e2fbe131b53 754
roysandberg 62:8e2fbe131b53 755 for(i = 0; i < DM_BUFFER_LENGTH; ++i)
roysandberg 62:8e2fbe131b53 756 {
roysandberg 62:8e2fbe131b53 757 if(DMBeatTypes[i] == oldType)
roysandberg 62:8e2fbe131b53 758 DMBeatTypes[i] = newType ;
roysandberg 62:8e2fbe131b53 759 }
roysandberg 62:8e2fbe131b53 760
roysandberg 62:8e2fbe131b53 761 if(newType != MAXTYPES)
roysandberg 62:8e2fbe131b53 762 {
roysandberg 62:8e2fbe131b53 763 DMNormCounts[newType] += DMNormCounts[oldType] ;
roysandberg 62:8e2fbe131b53 764 DMBeatCounts[newType] += DMBeatCounts[oldType] ;
roysandberg 62:8e2fbe131b53 765 }
roysandberg 62:8e2fbe131b53 766
roysandberg 62:8e2fbe131b53 767 DMNormCounts[oldType] = DMBeatCounts[oldType] = 0 ;
roysandberg 62:8e2fbe131b53 768
roysandberg 62:8e2fbe131b53 769 }
roysandberg 62:8e2fbe131b53 770
roysandberg 62:8e2fbe131b53 771 /***********************************************************************
roysandberg 62:8e2fbe131b53 772 GetRunCount() checks how many of the present beat type have occurred
roysandberg 62:8e2fbe131b53 773 in a row.
roysandberg 62:8e2fbe131b53 774 ***********************************************************************/
roysandberg 62:8e2fbe131b53 775
roysandberg 62:8e2fbe131b53 776 int GetRunCount()
roysandberg 62:8e2fbe131b53 777 {
roysandberg 62:8e2fbe131b53 778 int i ;
roysandberg 62:8e2fbe131b53 779 for(i = 1; (i < 8) && (RecentTypes[0] == RecentTypes[i]); ++i) ;
roysandberg 62:8e2fbe131b53 780 return(i) ;
roysandberg 62:8e2fbe131b53 781 }
roysandberg 62:8e2fbe131b53 782
roysandberg 62:8e2fbe131b53 783
roysandberg 62:8e2fbe131b53 784
roysandberg 62:8e2fbe131b53 785
roysandberg 62:8e2fbe131b53 786
roysandberg 62:8e2fbe131b53 787
roysandberg 62:8e2fbe131b53 788
roysandberg 62:8e2fbe131b53 789
roysandberg 62:8e2fbe131b53 790
roysandberg 62:8e2fbe131b53 791
roysandberg 62:8e2fbe131b53 792