I've got some basic filter code setup (but not yet tested).
Dependencies: BLE_API Queue mbed nRF51822
Fork of BLE_HeartRate by
analbeat.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: analbeat.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 | analbeat.cpp: Analyze 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 | This file contains functions for determining the QRS onset, QRS offset, |
roysandberg | 62:8e2fbe131b53 | 31 | beat onset, beat offset, polarity, and isoelectric level for a beat. |
roysandberg | 62:8e2fbe131b53 | 32 | |
roysandberg | 62:8e2fbe131b53 | 33 | Revisions: |
roysandberg | 62:8e2fbe131b53 | 34 | 4/16: Modified to prevent isoStart from being set to less than ISO_LENGTH1-1 |
roysandberg | 62:8e2fbe131b53 | 35 | 5/13/2002: Time related constants are tied to BEAT_SAMPLE_RATE in bdac.h. |
roysandberg | 62:8e2fbe131b53 | 36 | |
roysandberg | 62:8e2fbe131b53 | 37 | *****************************************************************************/ |
roysandberg | 62:8e2fbe131b53 | 38 | #include <mbed.h> |
roysandberg | 62:8e2fbe131b53 | 39 | #include "bdac.h" |
roysandberg | 62:8e2fbe131b53 | 40 | //#include <stdio.h> |
roysandberg | 62:8e2fbe131b53 | 41 | //#include <stdlib.h> |
roysandberg | 62:8e2fbe131b53 | 42 | |
roysandberg | 62:8e2fbe131b53 | 43 | #define ISO_LENGTH1 BEAT_MS50 |
roysandberg | 62:8e2fbe131b53 | 44 | #define ISO_LENGTH2 BEAT_MS80 |
roysandberg | 62:8e2fbe131b53 | 45 | #define ISO_LIMIT 20 |
roysandberg | 62:8e2fbe131b53 | 46 | |
roysandberg | 62:8e2fbe131b53 | 47 | // Local prototypes. |
roysandberg | 62:8e2fbe131b53 | 48 | |
roysandberg | 62:8e2fbe131b53 | 49 | int IsoCheck(int *data, int isoLength); |
roysandberg | 62:8e2fbe131b53 | 50 | |
roysandberg | 62:8e2fbe131b53 | 51 | /**************************************************************** |
roysandberg | 62:8e2fbe131b53 | 52 | IsoCheck determines whether the amplitudes of a run |
roysandberg | 62:8e2fbe131b53 | 53 | of data fall within a sufficiently small amplitude that |
roysandberg | 62:8e2fbe131b53 | 54 | the run can be considered isoelectric. |
roysandberg | 62:8e2fbe131b53 | 55 | *****************************************************************/ |
roysandberg | 62:8e2fbe131b53 | 56 | |
roysandberg | 62:8e2fbe131b53 | 57 | int IsoCheck(int *data, int isoLength) |
roysandberg | 62:8e2fbe131b53 | 58 | { |
roysandberg | 62:8e2fbe131b53 | 59 | int i, max, min ; |
roysandberg | 62:8e2fbe131b53 | 60 | |
roysandberg | 62:8e2fbe131b53 | 61 | for(i = 1, max=min = data[0]; i < isoLength; ++i) |
roysandberg | 62:8e2fbe131b53 | 62 | { |
roysandberg | 62:8e2fbe131b53 | 63 | if(data[i] > max) |
roysandberg | 62:8e2fbe131b53 | 64 | max = data[i] ; |
roysandberg | 62:8e2fbe131b53 | 65 | else if(data[i] < min) |
roysandberg | 62:8e2fbe131b53 | 66 | min = data[i] ; |
roysandberg | 62:8e2fbe131b53 | 67 | } |
roysandberg | 62:8e2fbe131b53 | 68 | |
roysandberg | 62:8e2fbe131b53 | 69 | if(max - min < ISO_LIMIT) |
roysandberg | 62:8e2fbe131b53 | 70 | return(1) ; |
roysandberg | 62:8e2fbe131b53 | 71 | return(0) ; |
roysandberg | 62:8e2fbe131b53 | 72 | } |
roysandberg | 62:8e2fbe131b53 | 73 | |
roysandberg | 62:8e2fbe131b53 | 74 | /********************************************************************** |
roysandberg | 62:8e2fbe131b53 | 75 | AnalyzeBeat takes a beat buffer as input and returns (via pointers) |
roysandberg | 62:8e2fbe131b53 | 76 | estimates of the QRS onset, QRS offset, polarity, isoelectric level |
roysandberg | 62:8e2fbe131b53 | 77 | beat beginning (P-wave onset), and beat ending (T-wave offset). |
roysandberg | 62:8e2fbe131b53 | 78 | Analyze Beat assumes that the beat has been sampled at 100 Hz, is |
roysandberg | 62:8e2fbe131b53 | 79 | BEATLGTH long, and has an R-wave location of roughly FIDMARK. |
roysandberg | 62:8e2fbe131b53 | 80 | |
roysandberg | 62:8e2fbe131b53 | 81 | Note that beatBegin is the number of samples before FIDMARK that |
roysandberg | 62:8e2fbe131b53 | 82 | the beat begins and beatEnd is the number of samples after the |
roysandberg | 62:8e2fbe131b53 | 83 | FIDMARK that the beat ends. |
roysandberg | 62:8e2fbe131b53 | 84 | ************************************************************************/ |
roysandberg | 62:8e2fbe131b53 | 85 | |
roysandberg | 62:8e2fbe131b53 | 86 | #define INF_CHK_N BEAT_MS40 |
roysandberg | 62:8e2fbe131b53 | 87 | |
roysandberg | 62:8e2fbe131b53 | 88 | void AnalyzeBeat(int *beat, int *onset, int *offset, int *isoLevel, |
roysandberg | 62:8e2fbe131b53 | 89 | int *beatBegin, int *beatEnd, int *amp) |
roysandberg | 62:8e2fbe131b53 | 90 | { |
roysandberg | 62:8e2fbe131b53 | 91 | int maxSlope = 0, maxSlopeI, minSlope = 0, minSlopeI ; |
roysandberg | 62:8e2fbe131b53 | 92 | int maxV, minV ; |
roysandberg | 62:8e2fbe131b53 | 93 | int isoStart, isoEnd ; |
roysandberg | 62:8e2fbe131b53 | 94 | int slope, i ; |
roysandberg | 62:8e2fbe131b53 | 95 | |
roysandberg | 62:8e2fbe131b53 | 96 | // Search back from the fiducial mark to find the isoelectric |
roysandberg | 62:8e2fbe131b53 | 97 | // region preceeding the QRS complex. |
roysandberg | 62:8e2fbe131b53 | 98 | |
roysandberg | 62:8e2fbe131b53 | 99 | for(i = FIDMARK-ISO_LENGTH2; (i > 0) && (IsoCheck(&beat[i],ISO_LENGTH2) == 0); --i) ; |
roysandberg | 62:8e2fbe131b53 | 100 | |
roysandberg | 62:8e2fbe131b53 | 101 | // If the first search didn't turn up any isoelectric region, look for |
roysandberg | 62:8e2fbe131b53 | 102 | // a shorter isoelectric region. |
roysandberg | 62:8e2fbe131b53 | 103 | |
roysandberg | 62:8e2fbe131b53 | 104 | if(i == 0) |
roysandberg | 62:8e2fbe131b53 | 105 | { |
roysandberg | 62:8e2fbe131b53 | 106 | for(i = FIDMARK-ISO_LENGTH1; (i > 0) && (IsoCheck(&beat[i],ISO_LENGTH1) == 0); --i) ; |
roysandberg | 62:8e2fbe131b53 | 107 | isoStart = i + (ISO_LENGTH1 - 1) ; |
roysandberg | 62:8e2fbe131b53 | 108 | } |
roysandberg | 62:8e2fbe131b53 | 109 | else isoStart = i + (ISO_LENGTH2 - 1) ; |
roysandberg | 62:8e2fbe131b53 | 110 | |
roysandberg | 62:8e2fbe131b53 | 111 | // Search forward from the R-wave to find an isoelectric region following |
roysandberg | 62:8e2fbe131b53 | 112 | // the QRS complex. |
roysandberg | 62:8e2fbe131b53 | 113 | |
roysandberg | 62:8e2fbe131b53 | 114 | for(i = FIDMARK; (i < BEATLGTH) && (IsoCheck(&beat[i],ISO_LENGTH1) == 0); ++i) ; |
roysandberg | 62:8e2fbe131b53 | 115 | isoEnd = i ; |
roysandberg | 62:8e2fbe131b53 | 116 | |
roysandberg | 62:8e2fbe131b53 | 117 | // Find the maximum and minimum slopes on the |
roysandberg | 62:8e2fbe131b53 | 118 | // QRS complex. |
roysandberg | 62:8e2fbe131b53 | 119 | |
roysandberg | 62:8e2fbe131b53 | 120 | i = FIDMARK-BEAT_MS150 ; |
roysandberg | 62:8e2fbe131b53 | 121 | maxSlope = maxSlope = beat[i] - beat[i-1] ; |
roysandberg | 62:8e2fbe131b53 | 122 | maxSlopeI = minSlopeI = i ; |
roysandberg | 62:8e2fbe131b53 | 123 | |
roysandberg | 62:8e2fbe131b53 | 124 | for(; i < FIDMARK+BEAT_MS150; ++i) |
roysandberg | 62:8e2fbe131b53 | 125 | { |
roysandberg | 62:8e2fbe131b53 | 126 | slope = beat[i] - beat[i-1] ; |
roysandberg | 62:8e2fbe131b53 | 127 | if(slope > maxSlope) |
roysandberg | 62:8e2fbe131b53 | 128 | { |
roysandberg | 62:8e2fbe131b53 | 129 | maxSlope = slope ; |
roysandberg | 62:8e2fbe131b53 | 130 | maxSlopeI = i ; |
roysandberg | 62:8e2fbe131b53 | 131 | } |
roysandberg | 62:8e2fbe131b53 | 132 | else if(slope < minSlope) |
roysandberg | 62:8e2fbe131b53 | 133 | { |
roysandberg | 62:8e2fbe131b53 | 134 | minSlope = slope ; |
roysandberg | 62:8e2fbe131b53 | 135 | minSlopeI = i ; |
roysandberg | 62:8e2fbe131b53 | 136 | } |
roysandberg | 62:8e2fbe131b53 | 137 | } |
roysandberg | 62:8e2fbe131b53 | 138 | |
roysandberg | 62:8e2fbe131b53 | 139 | // Use the smallest of max or min slope for search parameters. |
roysandberg | 62:8e2fbe131b53 | 140 | |
roysandberg | 62:8e2fbe131b53 | 141 | if(maxSlope > -minSlope) |
roysandberg | 62:8e2fbe131b53 | 142 | maxSlope = -minSlope ; |
roysandberg | 62:8e2fbe131b53 | 143 | else minSlope = -maxSlope ; |
roysandberg | 62:8e2fbe131b53 | 144 | |
roysandberg | 62:8e2fbe131b53 | 145 | if(maxSlopeI < minSlopeI) |
roysandberg | 62:8e2fbe131b53 | 146 | { |
roysandberg | 62:8e2fbe131b53 | 147 | |
roysandberg | 62:8e2fbe131b53 | 148 | // Search back from the maximum slope point for the QRS onset. |
roysandberg | 62:8e2fbe131b53 | 149 | |
roysandberg | 62:8e2fbe131b53 | 150 | for(i = maxSlopeI; |
roysandberg | 62:8e2fbe131b53 | 151 | (i > 0) && ((beat[i]-beat[i-1]) > (maxSlope >> 2)); --i) ; |
roysandberg | 62:8e2fbe131b53 | 152 | *onset = i-1 ; |
roysandberg | 62:8e2fbe131b53 | 153 | |
roysandberg | 62:8e2fbe131b53 | 154 | // Check to see if this was just a brief inflection. |
roysandberg | 62:8e2fbe131b53 | 155 | |
roysandberg | 62:8e2fbe131b53 | 156 | for(; (i > *onset-INF_CHK_N) && ((beat[i]-beat[i-1]) <= (maxSlope >>2)); --i) ; |
roysandberg | 62:8e2fbe131b53 | 157 | if(i > *onset-INF_CHK_N) |
roysandberg | 62:8e2fbe131b53 | 158 | { |
roysandberg | 62:8e2fbe131b53 | 159 | for(;(i > 0) && ((beat[i]-beat[i-1]) > (maxSlope >> 2)); --i) ; |
roysandberg | 62:8e2fbe131b53 | 160 | *onset = i-1 ; |
roysandberg | 62:8e2fbe131b53 | 161 | } |
roysandberg | 62:8e2fbe131b53 | 162 | i = *onset+1 ; |
roysandberg | 62:8e2fbe131b53 | 163 | |
roysandberg | 62:8e2fbe131b53 | 164 | // Check to see if a large negative slope follows an inflection. |
roysandberg | 62:8e2fbe131b53 | 165 | // If so, extend the onset a little more. |
roysandberg | 62:8e2fbe131b53 | 166 | |
roysandberg | 62:8e2fbe131b53 | 167 | for(;(i > *onset-INF_CHK_N) && ((beat[i-1]-beat[i]) < (maxSlope>>2)); --i); |
roysandberg | 62:8e2fbe131b53 | 168 | if(i > *onset-INF_CHK_N) |
roysandberg | 62:8e2fbe131b53 | 169 | { |
roysandberg | 62:8e2fbe131b53 | 170 | for(; (i > 0) && ((beat[i-1]-beat[i]) > (maxSlope>>2)); --i) ; |
roysandberg | 62:8e2fbe131b53 | 171 | *onset = i-1 ; |
roysandberg | 62:8e2fbe131b53 | 172 | } |
roysandberg | 62:8e2fbe131b53 | 173 | |
roysandberg | 62:8e2fbe131b53 | 174 | // Search forward from minimum slope point for QRS offset. |
roysandberg | 62:8e2fbe131b53 | 175 | |
roysandberg | 62:8e2fbe131b53 | 176 | for(i = minSlopeI; |
roysandberg | 62:8e2fbe131b53 | 177 | (i < BEATLGTH) && ((beat[i] - beat[i-1]) < (minSlope >>2)); ++i); |
roysandberg | 62:8e2fbe131b53 | 178 | *offset = i ; |
roysandberg | 62:8e2fbe131b53 | 179 | |
roysandberg | 62:8e2fbe131b53 | 180 | // Make sure this wasn't just an inflection. |
roysandberg | 62:8e2fbe131b53 | 181 | |
roysandberg | 62:8e2fbe131b53 | 182 | for(; (i < *offset+INF_CHK_N) && ((beat[i]-beat[i-1]) >= (minSlope>>2)); ++i) ; |
roysandberg | 62:8e2fbe131b53 | 183 | if(i < *offset+INF_CHK_N) |
roysandberg | 62:8e2fbe131b53 | 184 | { |
roysandberg | 62:8e2fbe131b53 | 185 | for(;(i < BEATLGTH) && ((beat[i]-beat[i-1]) < (minSlope >>2)); ++i) ; |
roysandberg | 62:8e2fbe131b53 | 186 | *offset = i ; |
roysandberg | 62:8e2fbe131b53 | 187 | } |
roysandberg | 62:8e2fbe131b53 | 188 | i = *offset ; |
roysandberg | 62:8e2fbe131b53 | 189 | |
roysandberg | 62:8e2fbe131b53 | 190 | // Check to see if there is a significant upslope following |
roysandberg | 62:8e2fbe131b53 | 191 | // the end of the down slope. |
roysandberg | 62:8e2fbe131b53 | 192 | |
roysandberg | 62:8e2fbe131b53 | 193 | for(;(i < *offset+BEAT_MS40) && ((beat[i-1]-beat[i]) > (minSlope>>2)); ++i); |
roysandberg | 62:8e2fbe131b53 | 194 | if(i < *offset+BEAT_MS40) |
roysandberg | 62:8e2fbe131b53 | 195 | { |
roysandberg | 62:8e2fbe131b53 | 196 | for(; (i < BEATLGTH) && ((beat[i-1]-beat[i]) < (minSlope>>2)); ++i) ; |
roysandberg | 62:8e2fbe131b53 | 197 | *offset = i ; |
roysandberg | 62:8e2fbe131b53 | 198 | |
roysandberg | 62:8e2fbe131b53 | 199 | // One more search motivated by PVC shape in 123. |
roysandberg | 62:8e2fbe131b53 | 200 | |
roysandberg | 62:8e2fbe131b53 | 201 | for(; (i < *offset+BEAT_MS60) && (beat[i]-beat[i-1] > (minSlope>>2)); ++i) ; |
roysandberg | 62:8e2fbe131b53 | 202 | if(i < *offset + BEAT_MS60) |
roysandberg | 62:8e2fbe131b53 | 203 | { |
roysandberg | 62:8e2fbe131b53 | 204 | for(;(i < BEATLGTH) && (beat[i]-beat[i-1] < (minSlope>>2)); ++i) ; |
roysandberg | 62:8e2fbe131b53 | 205 | *offset = i ; |
roysandberg | 62:8e2fbe131b53 | 206 | } |
roysandberg | 62:8e2fbe131b53 | 207 | } |
roysandberg | 62:8e2fbe131b53 | 208 | } |
roysandberg | 62:8e2fbe131b53 | 209 | |
roysandberg | 62:8e2fbe131b53 | 210 | else |
roysandberg | 62:8e2fbe131b53 | 211 | { |
roysandberg | 62:8e2fbe131b53 | 212 | |
roysandberg | 62:8e2fbe131b53 | 213 | // Search back from the minimum slope point for the QRS onset. |
roysandberg | 62:8e2fbe131b53 | 214 | |
roysandberg | 62:8e2fbe131b53 | 215 | for(i = minSlopeI; |
roysandberg | 62:8e2fbe131b53 | 216 | (i > 0) && ((beat[i]-beat[i-1]) < (minSlope >> 2)); --i) ; |
roysandberg | 62:8e2fbe131b53 | 217 | *onset = i-1 ; |
roysandberg | 62:8e2fbe131b53 | 218 | |
roysandberg | 62:8e2fbe131b53 | 219 | // Check to see if this was just a brief inflection. |
roysandberg | 62:8e2fbe131b53 | 220 | |
roysandberg | 62:8e2fbe131b53 | 221 | for(; (i > *onset-INF_CHK_N) && ((beat[i]-beat[i-1]) >= (minSlope>>2)); --i) ; |
roysandberg | 62:8e2fbe131b53 | 222 | if(i > *onset-INF_CHK_N) |
roysandberg | 62:8e2fbe131b53 | 223 | { |
roysandberg | 62:8e2fbe131b53 | 224 | for(; (i > 0) && ((beat[i]-beat[i-1]) < (minSlope>>2));--i) ; |
roysandberg | 62:8e2fbe131b53 | 225 | *onset = i-1 ; |
roysandberg | 62:8e2fbe131b53 | 226 | } |
roysandberg | 62:8e2fbe131b53 | 227 | i = *onset+1 ; |
roysandberg | 62:8e2fbe131b53 | 228 | |
roysandberg | 62:8e2fbe131b53 | 229 | // Check for significant positive slope after a turning point. |
roysandberg | 62:8e2fbe131b53 | 230 | |
roysandberg | 62:8e2fbe131b53 | 231 | for(;(i > *onset-INF_CHK_N) && ((beat[i-1]-beat[i]) > (minSlope>>2)); --i); |
roysandberg | 62:8e2fbe131b53 | 232 | if(i > *onset-INF_CHK_N) |
roysandberg | 62:8e2fbe131b53 | 233 | { |
roysandberg | 62:8e2fbe131b53 | 234 | for(; (i > 0) && ((beat[i-1]-beat[i]) < (minSlope>>2)); --i) ; |
roysandberg | 62:8e2fbe131b53 | 235 | *onset = i-1 ; |
roysandberg | 62:8e2fbe131b53 | 236 | } |
roysandberg | 62:8e2fbe131b53 | 237 | |
roysandberg | 62:8e2fbe131b53 | 238 | // Search forward from maximum slope point for QRS offset. |
roysandberg | 62:8e2fbe131b53 | 239 | |
roysandberg | 62:8e2fbe131b53 | 240 | for(i = maxSlopeI; |
roysandberg | 62:8e2fbe131b53 | 241 | (i < BEATLGTH) && ((beat[i] - beat[i-1]) > (maxSlope >>2)); ++i) ; |
roysandberg | 62:8e2fbe131b53 | 242 | *offset = i ; |
roysandberg | 62:8e2fbe131b53 | 243 | |
roysandberg | 62:8e2fbe131b53 | 244 | // Check to see if this was just a brief inflection. |
roysandberg | 62:8e2fbe131b53 | 245 | |
roysandberg | 62:8e2fbe131b53 | 246 | for(; (i < *offset+INF_CHK_N) && ((beat[i] - beat[i-1]) <= (maxSlope >> 2)); ++i) ; |
roysandberg | 62:8e2fbe131b53 | 247 | if(i < *offset+INF_CHK_N) |
roysandberg | 62:8e2fbe131b53 | 248 | { |
roysandberg | 62:8e2fbe131b53 | 249 | for(;(i < BEATLGTH) && ((beat[i] - beat[i-1]) > (maxSlope >>2)); ++i) ; |
roysandberg | 62:8e2fbe131b53 | 250 | *offset = i ; |
roysandberg | 62:8e2fbe131b53 | 251 | } |
roysandberg | 62:8e2fbe131b53 | 252 | i = *offset ; |
roysandberg | 62:8e2fbe131b53 | 253 | |
roysandberg | 62:8e2fbe131b53 | 254 | // Check to see if there is a significant downslope following |
roysandberg | 62:8e2fbe131b53 | 255 | // the end of the up slope. |
roysandberg | 62:8e2fbe131b53 | 256 | |
roysandberg | 62:8e2fbe131b53 | 257 | for(;(i < *offset+BEAT_MS40) && ((beat[i-1]-beat[i]) < (maxSlope>>2)); ++i); |
roysandberg | 62:8e2fbe131b53 | 258 | if(i < *offset+BEAT_MS40) |
roysandberg | 62:8e2fbe131b53 | 259 | { |
roysandberg | 62:8e2fbe131b53 | 260 | for(; (i < BEATLGTH) && ((beat[i-1]-beat[i]) > (maxSlope>>2)); ++i) ; |
roysandberg | 62:8e2fbe131b53 | 261 | *offset = i ; |
roysandberg | 62:8e2fbe131b53 | 262 | } |
roysandberg | 62:8e2fbe131b53 | 263 | } |
roysandberg | 62:8e2fbe131b53 | 264 | |
roysandberg | 62:8e2fbe131b53 | 265 | // If the estimate of the beginning of the isoelectric level was |
roysandberg | 62:8e2fbe131b53 | 266 | // at the beginning of the beat, use the slope based QRS onset point |
roysandberg | 62:8e2fbe131b53 | 267 | // as the iso electric point. |
roysandberg | 62:8e2fbe131b53 | 268 | |
roysandberg | 62:8e2fbe131b53 | 269 | if((isoStart == ISO_LENGTH1-1)&& (*onset > isoStart)) // ** 4/19 ** |
roysandberg | 62:8e2fbe131b53 | 270 | isoStart = *onset ; |
roysandberg | 62:8e2fbe131b53 | 271 | |
roysandberg | 62:8e2fbe131b53 | 272 | // Otherwise, if the isoelectric start and the slope based points |
roysandberg | 62:8e2fbe131b53 | 273 | // are close, use the isoelectric start point. |
roysandberg | 62:8e2fbe131b53 | 274 | |
roysandberg | 62:8e2fbe131b53 | 275 | else if(*onset-isoStart < BEAT_MS50) |
roysandberg | 62:8e2fbe131b53 | 276 | *onset = isoStart ; |
roysandberg | 62:8e2fbe131b53 | 277 | |
roysandberg | 62:8e2fbe131b53 | 278 | // If the isoelectric end and the slope based QRS offset are close |
roysandberg | 62:8e2fbe131b53 | 279 | // use the isoelectic based point. |
roysandberg | 62:8e2fbe131b53 | 280 | |
roysandberg | 62:8e2fbe131b53 | 281 | if(isoEnd - *offset < BEAT_MS50) |
roysandberg | 62:8e2fbe131b53 | 282 | *offset = isoEnd ; |
roysandberg | 62:8e2fbe131b53 | 283 | |
roysandberg | 62:8e2fbe131b53 | 284 | *isoLevel = beat[isoStart] ; |
roysandberg | 62:8e2fbe131b53 | 285 | |
roysandberg | 62:8e2fbe131b53 | 286 | |
roysandberg | 62:8e2fbe131b53 | 287 | // Find the maximum and minimum values in the QRS. |
roysandberg | 62:8e2fbe131b53 | 288 | |
roysandberg | 62:8e2fbe131b53 | 289 | for(i = *onset, maxV = minV = beat[*onset]; i < *offset; ++i) |
roysandberg | 62:8e2fbe131b53 | 290 | if(beat[i] > maxV) |
roysandberg | 62:8e2fbe131b53 | 291 | maxV = beat[i] ; |
roysandberg | 62:8e2fbe131b53 | 292 | else if(beat[i] < minV) |
roysandberg | 62:8e2fbe131b53 | 293 | minV = beat[i] ; |
roysandberg | 62:8e2fbe131b53 | 294 | |
roysandberg | 62:8e2fbe131b53 | 295 | // If the offset is significantly below the onset and the offset is |
roysandberg | 62:8e2fbe131b53 | 296 | // on a negative slope, add the next up slope to the width. |
roysandberg | 62:8e2fbe131b53 | 297 | |
roysandberg | 62:8e2fbe131b53 | 298 | if((beat[*onset]-beat[*offset] > ((maxV-minV)>>2)+((maxV-minV)>>3))) |
roysandberg | 62:8e2fbe131b53 | 299 | { |
roysandberg | 62:8e2fbe131b53 | 300 | |
roysandberg | 62:8e2fbe131b53 | 301 | // Find the maximum slope between the finish and the end of the buffer. |
roysandberg | 62:8e2fbe131b53 | 302 | |
roysandberg | 62:8e2fbe131b53 | 303 | for(i = maxSlopeI = *offset, maxSlope = beat[*offset] - beat[*offset-1]; |
roysandberg | 62:8e2fbe131b53 | 304 | (i < *offset+BEAT_MS100) && (i < BEATLGTH); ++i) |
roysandberg | 62:8e2fbe131b53 | 305 | { |
roysandberg | 62:8e2fbe131b53 | 306 | slope = beat[i]-beat[i-1] ; |
roysandberg | 62:8e2fbe131b53 | 307 | if(slope > maxSlope) |
roysandberg | 62:8e2fbe131b53 | 308 | { |
roysandberg | 62:8e2fbe131b53 | 309 | maxSlope = slope ; |
roysandberg | 62:8e2fbe131b53 | 310 | maxSlopeI = i ; |
roysandberg | 62:8e2fbe131b53 | 311 | } |
roysandberg | 62:8e2fbe131b53 | 312 | } |
roysandberg | 62:8e2fbe131b53 | 313 | |
roysandberg | 62:8e2fbe131b53 | 314 | // Find the new offset. |
roysandberg | 62:8e2fbe131b53 | 315 | |
roysandberg | 62:8e2fbe131b53 | 316 | if(maxSlope > 0) |
roysandberg | 62:8e2fbe131b53 | 317 | { |
roysandberg | 62:8e2fbe131b53 | 318 | for(i = maxSlopeI; |
roysandberg | 62:8e2fbe131b53 | 319 | (i < BEATLGTH) && (beat[i]-beat[i-1] > (maxSlope>>1)); ++i) ; |
roysandberg | 62:8e2fbe131b53 | 320 | *offset = i ; |
roysandberg | 62:8e2fbe131b53 | 321 | } |
roysandberg | 62:8e2fbe131b53 | 322 | } |
roysandberg | 62:8e2fbe131b53 | 323 | |
roysandberg | 62:8e2fbe131b53 | 324 | // Determine beginning and ending of the beat. |
roysandberg | 62:8e2fbe131b53 | 325 | // Search for an isoelectric region that precedes the R-wave. |
roysandberg | 62:8e2fbe131b53 | 326 | // by at least 250 ms. |
roysandberg | 62:8e2fbe131b53 | 327 | |
roysandberg | 62:8e2fbe131b53 | 328 | for(i = FIDMARK-BEAT_MS250; |
roysandberg | 62:8e2fbe131b53 | 329 | (i >= BEAT_MS80) && (IsoCheck(&beat[i-BEAT_MS80],BEAT_MS80) == 0); --i) ; |
roysandberg | 62:8e2fbe131b53 | 330 | *beatBegin = i ; |
roysandberg | 62:8e2fbe131b53 | 331 | |
roysandberg | 62:8e2fbe131b53 | 332 | // If there was an isoelectric section at 250 ms before the |
roysandberg | 62:8e2fbe131b53 | 333 | // R-wave, search forward for the isoelectric region closest |
roysandberg | 62:8e2fbe131b53 | 334 | // to the R-wave. But leave at least 50 ms between beat begin |
roysandberg | 62:8e2fbe131b53 | 335 | // and onset, or else normal beat onset is within PVC QRS complexes. |
roysandberg | 62:8e2fbe131b53 | 336 | // that screws up noise estimation. |
roysandberg | 62:8e2fbe131b53 | 337 | |
roysandberg | 62:8e2fbe131b53 | 338 | if(*beatBegin == FIDMARK-BEAT_MS250) |
roysandberg | 62:8e2fbe131b53 | 339 | { |
roysandberg | 62:8e2fbe131b53 | 340 | for(; (i < *onset-BEAT_MS50) && |
roysandberg | 62:8e2fbe131b53 | 341 | (IsoCheck(&beat[i-BEAT_MS80],BEAT_MS80) == 1); ++i) ; |
roysandberg | 62:8e2fbe131b53 | 342 | *beatBegin = i-1 ; |
roysandberg | 62:8e2fbe131b53 | 343 | } |
roysandberg | 62:8e2fbe131b53 | 344 | |
roysandberg | 62:8e2fbe131b53 | 345 | // Rev 1.1 |
roysandberg | 62:8e2fbe131b53 | 346 | else if(*beatBegin == BEAT_MS80 - 1) |
roysandberg | 62:8e2fbe131b53 | 347 | { |
roysandberg | 62:8e2fbe131b53 | 348 | for(; (i < *onset) && (IsoCheck(&beat[i-BEAT_MS80],BEAT_MS80) == 0); ++i); |
roysandberg | 62:8e2fbe131b53 | 349 | if(i < *onset) |
roysandberg | 62:8e2fbe131b53 | 350 | { |
roysandberg | 62:8e2fbe131b53 | 351 | for(; (i < *onset) && (IsoCheck(&beat[i-BEAT_MS80],BEAT_MS80) == 1); ++i) ; |
roysandberg | 62:8e2fbe131b53 | 352 | if(i < *onset) |
roysandberg | 62:8e2fbe131b53 | 353 | *beatBegin = i-1 ; |
roysandberg | 62:8e2fbe131b53 | 354 | } |
roysandberg | 62:8e2fbe131b53 | 355 | } |
roysandberg | 62:8e2fbe131b53 | 356 | |
roysandberg | 62:8e2fbe131b53 | 357 | // Search for the end of the beat as the first isoelectric |
roysandberg | 62:8e2fbe131b53 | 358 | // segment that follows the beat by at least 300 ms. |
roysandberg | 62:8e2fbe131b53 | 359 | |
roysandberg | 62:8e2fbe131b53 | 360 | for(i = FIDMARK+BEAT_MS300; |
roysandberg | 62:8e2fbe131b53 | 361 | (i < BEATLGTH) && (IsoCheck(&beat[i],BEAT_MS80) == 0); ++i) ; |
roysandberg | 62:8e2fbe131b53 | 362 | *beatEnd = i ; |
roysandberg | 62:8e2fbe131b53 | 363 | |
roysandberg | 62:8e2fbe131b53 | 364 | // If the signal was isoelectric at 300 ms. search backwards. |
roysandberg | 62:8e2fbe131b53 | 365 | /* if(*beatEnd == FIDMARK+30) |
roysandberg | 62:8e2fbe131b53 | 366 | { |
roysandberg | 62:8e2fbe131b53 | 367 | for(; (i > *offset) && (IsoCheck(&beat[i],8) != 0); --i) ; |
roysandberg | 62:8e2fbe131b53 | 368 | *beatEnd = i ; |
roysandberg | 62:8e2fbe131b53 | 369 | } |
roysandberg | 62:8e2fbe131b53 | 370 | */ |
roysandberg | 62:8e2fbe131b53 | 371 | // Calculate beat amplitude. |
roysandberg | 62:8e2fbe131b53 | 372 | |
roysandberg | 62:8e2fbe131b53 | 373 | maxV=minV=beat[*onset] ; |
roysandberg | 62:8e2fbe131b53 | 374 | for(i = *onset; i < *offset; ++i) |
roysandberg | 62:8e2fbe131b53 | 375 | if(beat[i] > maxV) |
roysandberg | 62:8e2fbe131b53 | 376 | maxV = beat[i] ; |
roysandberg | 62:8e2fbe131b53 | 377 | else if(beat[i] < minV) |
roysandberg | 62:8e2fbe131b53 | 378 | minV = beat[i] ; |
roysandberg | 62:8e2fbe131b53 | 379 | *amp = maxV-minV ; |
roysandberg | 62:8e2fbe131b53 | 380 | |
roysandberg | 62:8e2fbe131b53 | 381 | } |
roysandberg | 62:8e2fbe131b53 | 382 | |
roysandberg | 62:8e2fbe131b53 | 383 | |
roysandberg | 62:8e2fbe131b53 | 384 |