I've got some basic filter code setup (but not yet tested).
Dependencies: BLE_API Queue mbed nRF51822
Fork of BLE_HeartRate by
postclas.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: postclas.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 | postclas.cpp: Post classifier |
roysandberg | 62:8e2fbe131b53 | 8 | Copywrite (C) 2002 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 | This file contains functions for classifying beats based after the |
roysandberg | 62:8e2fbe131b53 | 31 | following beat is detected. |
roysandberg | 62:8e2fbe131b53 | 32 | |
roysandberg | 62:8e2fbe131b53 | 33 | ResetPostClassify() -- Resets static variables used by |
roysandberg | 62:8e2fbe131b53 | 34 | PostClassify() |
roysandberg | 62:8e2fbe131b53 | 35 | PostClassify() -- classifies each beat based on six preceding |
roysandberg | 62:8e2fbe131b53 | 36 | beats and the following beat. |
roysandberg | 62:8e2fbe131b53 | 37 | CheckPostClass() -- classifys beat type based on the last |
roysandberg | 62:8e2fbe131b53 | 38 | eight post classifications of that beat. |
roysandberg | 62:8e2fbe131b53 | 39 | CheckPCRhythm() -- returns the classification of the RR interval |
roysandberg | 62:8e2fbe131b53 | 40 | for this type of beat based its previous eight RR intervals. |
roysandberg | 62:8e2fbe131b53 | 41 | |
roysandberg | 62:8e2fbe131b53 | 42 | ****************************************************************/ |
roysandberg | 62:8e2fbe131b53 | 43 | |
roysandberg | 62:8e2fbe131b53 | 44 | #include <mbed.h> |
roysandberg | 62:8e2fbe131b53 | 45 | #include "bdac.h" |
roysandberg | 62:8e2fbe131b53 | 46 | #include "ecgcodes.h" |
roysandberg | 62:8e2fbe131b53 | 47 | |
roysandberg | 62:8e2fbe131b53 | 48 | // External Prototypes. |
roysandberg | 62:8e2fbe131b53 | 49 | |
roysandberg | 62:8e2fbe131b53 | 50 | double DomCompare(int newType, int domType) ; |
roysandberg | 62:8e2fbe131b53 | 51 | int GetBeatTypeCount(int type) ; |
roysandberg | 62:8e2fbe131b53 | 52 | |
roysandberg | 62:8e2fbe131b53 | 53 | // Records of post classifications. |
roysandberg | 62:8e2fbe131b53 | 54 | |
roysandberg | 62:8e2fbe131b53 | 55 | int PostClass[MAXTYPES][8], PCInitCount = 0 ; |
roysandberg | 62:8e2fbe131b53 | 56 | int PCRhythm[MAXTYPES][8] ; |
roysandberg | 62:8e2fbe131b53 | 57 | |
roysandberg | 62:8e2fbe131b53 | 58 | /********************************************************************** |
roysandberg | 62:8e2fbe131b53 | 59 | Resets post classifications for beats. |
roysandberg | 62:8e2fbe131b53 | 60 | **********************************************************************/ |
roysandberg | 62:8e2fbe131b53 | 61 | |
roysandberg | 62:8e2fbe131b53 | 62 | void ResetPostClassify() |
roysandberg | 62:8e2fbe131b53 | 63 | { |
roysandberg | 62:8e2fbe131b53 | 64 | int i, j ; |
roysandberg | 62:8e2fbe131b53 | 65 | for(i = 0; i < MAXTYPES; ++i) |
roysandberg | 62:8e2fbe131b53 | 66 | for(j = 0; j < 8; ++j) |
roysandberg | 62:8e2fbe131b53 | 67 | { |
roysandberg | 62:8e2fbe131b53 | 68 | PostClass[i][j] = 0 ; |
roysandberg | 62:8e2fbe131b53 | 69 | PCRhythm[i][j] = 0 ; |
roysandberg | 62:8e2fbe131b53 | 70 | } |
roysandberg | 62:8e2fbe131b53 | 71 | PCInitCount = 0 ; |
roysandberg | 62:8e2fbe131b53 | 72 | } |
roysandberg | 62:8e2fbe131b53 | 73 | |
roysandberg | 62:8e2fbe131b53 | 74 | /*********************************************************************** |
roysandberg | 62:8e2fbe131b53 | 75 | Classify the previous beat type and rhythm type based on this beat |
roysandberg | 62:8e2fbe131b53 | 76 | and the preceding beat. This classifier is more sensitive |
roysandberg | 62:8e2fbe131b53 | 77 | to detecting premature beats followed by compensitory pauses. |
roysandberg | 62:8e2fbe131b53 | 78 | ************************************************************************/ |
roysandberg | 62:8e2fbe131b53 | 79 | |
roysandberg | 62:8e2fbe131b53 | 80 | void PostClassify(int *recentTypes, int domType, int *recentRRs, int width, double mi2, |
roysandberg | 62:8e2fbe131b53 | 81 | int rhythmClass) |
roysandberg | 62:8e2fbe131b53 | 82 | { |
roysandberg | 62:8e2fbe131b53 | 83 | static int lastRC, lastWidth ; |
roysandberg | 62:8e2fbe131b53 | 84 | static double lastMI2 ; |
roysandberg | 62:8e2fbe131b53 | 85 | int i, regCount, pvcCount, normRR ; |
roysandberg | 62:8e2fbe131b53 | 86 | double mi3 ; |
roysandberg | 62:8e2fbe131b53 | 87 | |
roysandberg | 62:8e2fbe131b53 | 88 | // If the preceeding and following beats are the same type, |
roysandberg | 62:8e2fbe131b53 | 89 | // they are generally regular, and reasonably close in shape |
roysandberg | 62:8e2fbe131b53 | 90 | // to the dominant type, consider them to be dominant. |
roysandberg | 62:8e2fbe131b53 | 91 | |
roysandberg | 62:8e2fbe131b53 | 92 | if((recentTypes[0] == recentTypes[2]) && (recentTypes[0] != domType) |
roysandberg | 62:8e2fbe131b53 | 93 | && (recentTypes[0] != recentTypes[1])) |
roysandberg | 62:8e2fbe131b53 | 94 | { |
roysandberg | 62:8e2fbe131b53 | 95 | mi3 = DomCompare(recentTypes[0],domType) ; |
roysandberg | 62:8e2fbe131b53 | 96 | for(i = regCount = 0; i < 8; ++i) |
roysandberg | 62:8e2fbe131b53 | 97 | if(PCRhythm[recentTypes[0]][i] == NORMAL) |
roysandberg | 62:8e2fbe131b53 | 98 | ++regCount ; |
roysandberg | 62:8e2fbe131b53 | 99 | if((mi3 < 2.0) && (regCount > 6)) |
roysandberg | 62:8e2fbe131b53 | 100 | domType = recentTypes[0] ; |
roysandberg | 62:8e2fbe131b53 | 101 | } |
roysandberg | 62:8e2fbe131b53 | 102 | |
roysandberg | 62:8e2fbe131b53 | 103 | // Don't do anything until four beats have gone by. |
roysandberg | 62:8e2fbe131b53 | 104 | |
roysandberg | 62:8e2fbe131b53 | 105 | if(PCInitCount < 3) |
roysandberg | 62:8e2fbe131b53 | 106 | { |
roysandberg | 62:8e2fbe131b53 | 107 | ++PCInitCount ; |
roysandberg | 62:8e2fbe131b53 | 108 | lastWidth = width ; |
roysandberg | 62:8e2fbe131b53 | 109 | lastMI2 = 0 ; |
roysandberg | 62:8e2fbe131b53 | 110 | lastRC = 0 ; |
roysandberg | 62:8e2fbe131b53 | 111 | return ; |
roysandberg | 62:8e2fbe131b53 | 112 | } |
roysandberg | 62:8e2fbe131b53 | 113 | |
roysandberg | 62:8e2fbe131b53 | 114 | if(recentTypes[1] < MAXTYPES) |
roysandberg | 62:8e2fbe131b53 | 115 | { |
roysandberg | 62:8e2fbe131b53 | 116 | |
roysandberg | 62:8e2fbe131b53 | 117 | // Find first NN interval. |
roysandberg | 62:8e2fbe131b53 | 118 | for(i = 2; (i < 7) && (recentTypes[i] != recentTypes[i+1]); ++i) ; |
roysandberg | 62:8e2fbe131b53 | 119 | if(i == 7) normRR = 0 ; |
roysandberg | 62:8e2fbe131b53 | 120 | else normRR = recentRRs[i] ; |
roysandberg | 62:8e2fbe131b53 | 121 | |
roysandberg | 62:8e2fbe131b53 | 122 | // Shift the previous beat classifications to make room for the |
roysandberg | 62:8e2fbe131b53 | 123 | // new classification. |
roysandberg | 62:8e2fbe131b53 | 124 | for(i = pvcCount = 0; i < 8; ++i) |
roysandberg | 62:8e2fbe131b53 | 125 | if(PostClass[recentTypes[1]][i] == PVC) |
roysandberg | 62:8e2fbe131b53 | 126 | ++pvcCount ; |
roysandberg | 62:8e2fbe131b53 | 127 | |
roysandberg | 62:8e2fbe131b53 | 128 | for(i = 7; i > 0; --i) |
roysandberg | 62:8e2fbe131b53 | 129 | { |
roysandberg | 62:8e2fbe131b53 | 130 | PostClass[recentTypes[1]][i] = PostClass[recentTypes[1]][i-1] ; |
roysandberg | 62:8e2fbe131b53 | 131 | PCRhythm[recentTypes[1]][i] = PCRhythm[recentTypes[1]][i-1] ; |
roysandberg | 62:8e2fbe131b53 | 132 | } |
roysandberg | 62:8e2fbe131b53 | 133 | |
roysandberg | 62:8e2fbe131b53 | 134 | // If the beat is premature followed by a compensitory pause and the |
roysandberg | 62:8e2fbe131b53 | 135 | // previous and following beats are normal, post classify as |
roysandberg | 62:8e2fbe131b53 | 136 | // a PVC. |
roysandberg | 62:8e2fbe131b53 | 137 | |
roysandberg | 62:8e2fbe131b53 | 138 | if(((normRR-(normRR>>3)) >= recentRRs[1]) && ((recentRRs[0]-(recentRRs[0]>>3)) >= normRR)// && (lastMI2 > 3) |
roysandberg | 62:8e2fbe131b53 | 139 | && (recentTypes[0] == domType) && (recentTypes[2] == domType) |
roysandberg | 62:8e2fbe131b53 | 140 | && (recentTypes[1] != domType)) |
roysandberg | 62:8e2fbe131b53 | 141 | PostClass[recentTypes[1]][0] = PVC ; |
roysandberg | 62:8e2fbe131b53 | 142 | |
roysandberg | 62:8e2fbe131b53 | 143 | // If previous two were classified as PVCs, and this is at least slightly |
roysandberg | 62:8e2fbe131b53 | 144 | // premature, classify as a PVC. |
roysandberg | 62:8e2fbe131b53 | 145 | |
roysandberg | 62:8e2fbe131b53 | 146 | else if(((normRR-(normRR>>4)) > recentRRs[1]) && ((normRR+(normRR>>4)) < recentRRs[0]) && |
roysandberg | 62:8e2fbe131b53 | 147 | (((PostClass[recentTypes[1]][1] == PVC) && (PostClass[recentTypes[1]][2] == PVC)) || |
roysandberg | 62:8e2fbe131b53 | 148 | (pvcCount >= 6) ) && |
roysandberg | 62:8e2fbe131b53 | 149 | (recentTypes[0] == domType) && (recentTypes[2] == domType) && (recentTypes[1] != domType)) |
roysandberg | 62:8e2fbe131b53 | 150 | PostClass[recentTypes[1]][0] = PVC ; |
roysandberg | 62:8e2fbe131b53 | 151 | |
roysandberg | 62:8e2fbe131b53 | 152 | // If the previous and following beats are the dominant beat type, |
roysandberg | 62:8e2fbe131b53 | 153 | // and this beat is significantly different from the dominant, |
roysandberg | 62:8e2fbe131b53 | 154 | // call it a PVC. |
roysandberg | 62:8e2fbe131b53 | 155 | |
roysandberg | 62:8e2fbe131b53 | 156 | else if((recentTypes[0] == domType) && (recentTypes[2] == domType) && (lastMI2 > 2.5)) |
roysandberg | 62:8e2fbe131b53 | 157 | PostClass[recentTypes[1]][0] = PVC ; |
roysandberg | 62:8e2fbe131b53 | 158 | |
roysandberg | 62:8e2fbe131b53 | 159 | // Otherwise post classify this beat as UNKNOWN. |
roysandberg | 62:8e2fbe131b53 | 160 | |
roysandberg | 62:8e2fbe131b53 | 161 | else PostClass[recentTypes[1]][0] = UNKNOWN ; |
roysandberg | 62:8e2fbe131b53 | 162 | |
roysandberg | 62:8e2fbe131b53 | 163 | // If the beat is premature followed by a compensitory pause, post |
roysandberg | 62:8e2fbe131b53 | 164 | // classify the rhythm as PVC. |
roysandberg | 62:8e2fbe131b53 | 165 | |
roysandberg | 62:8e2fbe131b53 | 166 | if(((normRR-(normRR>>3)) > recentRRs[1]) && ((recentRRs[0]-(recentRRs[0]>>3)) > normRR)) |
roysandberg | 62:8e2fbe131b53 | 167 | PCRhythm[recentTypes[1]][0] = PVC ; |
roysandberg | 62:8e2fbe131b53 | 168 | |
roysandberg | 62:8e2fbe131b53 | 169 | // Otherwise, post classify the rhythm as the same as the |
roysandberg | 62:8e2fbe131b53 | 170 | // regular rhythm classification. |
roysandberg | 62:8e2fbe131b53 | 171 | |
roysandberg | 62:8e2fbe131b53 | 172 | else PCRhythm[recentTypes[1]][0] = lastRC ; |
roysandberg | 62:8e2fbe131b53 | 173 | } |
roysandberg | 62:8e2fbe131b53 | 174 | |
roysandberg | 62:8e2fbe131b53 | 175 | lastWidth = width ; |
roysandberg | 62:8e2fbe131b53 | 176 | lastMI2 = mi2 ; |
roysandberg | 62:8e2fbe131b53 | 177 | lastRC = rhythmClass ; |
roysandberg | 62:8e2fbe131b53 | 178 | } |
roysandberg | 62:8e2fbe131b53 | 179 | |
roysandberg | 62:8e2fbe131b53 | 180 | |
roysandberg | 62:8e2fbe131b53 | 181 | /************************************************************************* |
roysandberg | 62:8e2fbe131b53 | 182 | CheckPostClass checks to see if three of the last four or six of the |
roysandberg | 62:8e2fbe131b53 | 183 | last eight of a given beat type have been post classified as PVC. |
roysandberg | 62:8e2fbe131b53 | 184 | *************************************************************************/ |
roysandberg | 62:8e2fbe131b53 | 185 | |
roysandberg | 62:8e2fbe131b53 | 186 | int CheckPostClass(int type) |
roysandberg | 62:8e2fbe131b53 | 187 | { |
roysandberg | 62:8e2fbe131b53 | 188 | int i, pvcs4 = 0, pvcs8 ; |
roysandberg | 62:8e2fbe131b53 | 189 | |
roysandberg | 62:8e2fbe131b53 | 190 | if(type == MAXTYPES) |
roysandberg | 62:8e2fbe131b53 | 191 | return(UNKNOWN) ; |
roysandberg | 62:8e2fbe131b53 | 192 | |
roysandberg | 62:8e2fbe131b53 | 193 | for(i = 0; i < 4; ++i) |
roysandberg | 62:8e2fbe131b53 | 194 | if(PostClass[type][i] == PVC) |
roysandberg | 62:8e2fbe131b53 | 195 | ++pvcs4 ; |
roysandberg | 62:8e2fbe131b53 | 196 | for(pvcs8=pvcs4; i < 8; ++i) |
roysandberg | 62:8e2fbe131b53 | 197 | if(PostClass[type][i] == PVC) |
roysandberg | 62:8e2fbe131b53 | 198 | ++pvcs8 ; |
roysandberg | 62:8e2fbe131b53 | 199 | |
roysandberg | 62:8e2fbe131b53 | 200 | if((pvcs4 >= 3) || (pvcs8 >= 6)) |
roysandberg | 62:8e2fbe131b53 | 201 | return(PVC) ; |
roysandberg | 62:8e2fbe131b53 | 202 | else return(UNKNOWN) ; |
roysandberg | 62:8e2fbe131b53 | 203 | } |
roysandberg | 62:8e2fbe131b53 | 204 | |
roysandberg | 62:8e2fbe131b53 | 205 | /**************************************************************************** |
roysandberg | 62:8e2fbe131b53 | 206 | Check classification of previous beats' rhythms based on post beat |
roysandberg | 62:8e2fbe131b53 | 207 | classification. If 7 of 8 previous beats were classified as NORMAL |
roysandberg | 62:8e2fbe131b53 | 208 | (regular) classify the beat type as NORMAL (regular). |
roysandberg | 62:8e2fbe131b53 | 209 | Call it a PVC if 2 of the last 8 were regular. |
roysandberg | 62:8e2fbe131b53 | 210 | ****************************************************************************/ |
roysandberg | 62:8e2fbe131b53 | 211 | |
roysandberg | 62:8e2fbe131b53 | 212 | int CheckPCRhythm(int type) |
roysandberg | 62:8e2fbe131b53 | 213 | { |
roysandberg | 62:8e2fbe131b53 | 214 | int i, normCount, n ; |
roysandberg | 62:8e2fbe131b53 | 215 | |
roysandberg | 62:8e2fbe131b53 | 216 | |
roysandberg | 62:8e2fbe131b53 | 217 | if(type == MAXTYPES) |
roysandberg | 62:8e2fbe131b53 | 218 | return(UNKNOWN) ; |
roysandberg | 62:8e2fbe131b53 | 219 | |
roysandberg | 62:8e2fbe131b53 | 220 | if(GetBeatTypeCount(type) < 9) |
roysandberg | 62:8e2fbe131b53 | 221 | n = GetBeatTypeCount(type)-1 ; |
roysandberg | 62:8e2fbe131b53 | 222 | else n = 8 ; |
roysandberg | 62:8e2fbe131b53 | 223 | |
roysandberg | 62:8e2fbe131b53 | 224 | for(i = normCount = 0; i < n; ++i) |
roysandberg | 62:8e2fbe131b53 | 225 | if(PCRhythm[type][i] == NORMAL) |
roysandberg | 62:8e2fbe131b53 | 226 | ++normCount; |
roysandberg | 62:8e2fbe131b53 | 227 | if(normCount >= 7) |
roysandberg | 62:8e2fbe131b53 | 228 | return(NORMAL) ; |
roysandberg | 62:8e2fbe131b53 | 229 | if(((normCount == 0) && (n < 4)) || |
roysandberg | 62:8e2fbe131b53 | 230 | ((normCount <= 1) && (n >= 4) && (n < 7)) || |
roysandberg | 62:8e2fbe131b53 | 231 | ((normCount <= 2) && (n >= 7))) |
roysandberg | 62:8e2fbe131b53 | 232 | return(PVC) ; |
roysandberg | 62:8e2fbe131b53 | 233 | return(UNKNOWN) ; |
roysandberg | 62:8e2fbe131b53 | 234 | } |