I've got some basic filter code setup (but not yet tested).
Dependencies: BLE_API Queue mbed nRF51822
Fork of BLE_HeartRate by
Diff: bdac.cpp
- Revision:
- 62:8e2fbe131b53
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bdac.cpp Sun Jun 28 03:06:00 2015 +0000 @@ -0,0 +1,268 @@ +/***************************************************************************** +FILE: bdac.cpp +AUTHOR: Patrick S. Hamilton +REVISED: 5/13/2002 + ___________________________________________________________________________ + +bdac.cpp: Beat Detection And Classification +Copywrite (C) 2001 Patrick S. Hamilton + +This file is free software; you can redistribute it and/or modify it under +the terms of the GNU Library General Public License as published by the Free +Software Foundation; either version 2 of the License, or (at your option) any +later version. + +This software is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A +PARTICULAR PURPOSE. See the GNU Library General Public License for more +details. + +You should have received a copy of the GNU Library General Public License along +with this library; if not, write to the Free Software Foundation, Inc., 59 +Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +You may contact the author by e-mail (pat@eplimited.edu) or postal mail +(Patrick Hamilton, E.P. Limited, 35 Medford St., Suite 204 Somerville, +MA 02143 USA). For updates to this software, please visit our website +(http://www.eplimited.com). + __________________________________________________________________________ + +bdac.cpp contains functions for handling Beat Detection And Classification. +The primary function calls a qrs detector. When a beat is detected it waits +until a sufficient number of samples from the beat have occurred. When the +beat is ready, BeatDetectAndClassify passes the beat and the timing +information on to the functions that actually classify the beat. + +Functions in bdac.cpp require functions in the following files: + qrsfilt.cpp + qrsdet.cpp + classify.cpp + rythmchk.cpp + noisechk.cpp + analbeat.cpp + match.cpp + postclas.cpp + + __________________________________________________________________________ + + Revisions: + 5/13/02: + Encapsulated down sampling from input stream to beat template in + the function DownSampleBeat. + + Constants related to time are derived from SAMPLE_RATE in qrsdet + and BEAT_SAMPLE_RATE in bcac.h. + +*******************************************************************************/ +#include "qrsdet.h" // For base SAMPLE_RATE +#include "bdac.h" + +#define ECG_BUFFER_LENGTH 1000 // Should be long enough for a beat + // plus extra space to accommodate + // the maximum detection delay. +#define BEAT_QUE_LENGTH 10 // Length of que for beats awaiting + // classification. Because of + // detection delays, Multiple beats + // can occur before there is enough data + // to classify the first beat in the que. + +// Internal function prototypes. + +void DownSampleBeat(int *beatOut, int *beatIn) ; + +// External function prototypes. + +int QRSDet( int datum, int init ) ; +int NoiseCheck(int datum, int delay, int RR, int beatBegin, int beatEnd) ; +int Classify(int *newBeat,int rr, int noiseLevel, int *beatMatch, int *fidAdj, int init) ; +int GetDominantType(void) ; +int GetBeatEnd(int type) ; +int GetBeatBegin(int type) ; +int gcd(int x, int y) ; + +// Global Variables + +int ECGBuffer[ECG_BUFFER_LENGTH], ECGBufferIndex = 0 ; // Circular data buffer. +int BeatBuffer[BEATLGTH] ; +int BeatQue[BEAT_QUE_LENGTH], BeatQueCount = 0 ; // Buffer of detection delays. +int RRCount = 0 ; +int InitBeatFlag = 1 ; + +/****************************************************************************** + ResetBDAC() resets static variables required for beat detection and + classification. +*******************************************************************************/ + +void ResetBDAC(void) + { + int dummy ; + QRSDet(0,1) ; // Reset the qrs detector + RRCount = 0 ; + Classify(BeatBuffer,0,0,&dummy,&dummy,1) ; + InitBeatFlag = 1 ; + BeatQueCount = 0 ; // Flush the beat que. + } + +/***************************************************************************** +Syntax: + int BeatDetectAndClassify(int ecgSample, int *beatType, *beatMatch) ; + +Description: + BeatDetectAndClassify() implements a beat detector and classifier. + ECG samples are passed into BeatDetectAndClassify() one sample at a + time. BeatDetectAndClassify has been designed for a sample rate of + 200 Hz. When a beat has been detected and classified the detection + delay is returned and the beat classification is returned through the + pointer *beatType. For use in debugging, the number of the template + that the beat was matched to is returned in via *beatMatch. + +Returns + BeatDetectAndClassify() returns 0 if no new beat has been detected and + classified. If a beat has been classified, BeatDetectAndClassify returns + the number of samples since the approximate location of the R-wave. + +****************************************************************************/ + +int BeatDetectAndClassify(int ecgSample, int *beatType, int *beatMatch) + { + int detectDelay, rr, i, j ; + int noiseEst = 0, beatBegin, beatEnd ; + int domType ; + int fidAdj ; + int tempBeat[(SAMPLE_RATE/BEAT_SAMPLE_RATE)*BEATLGTH] ; + + // Store new sample in the circular buffer. + + ECGBuffer[ECGBufferIndex] = ecgSample ; + if(++ECGBufferIndex == ECG_BUFFER_LENGTH) + ECGBufferIndex = 0 ; + + // Increment RRInterval count. + + ++RRCount ; + + // Increment detection delays for any beats in the que. + + for(i = 0; i < BeatQueCount; ++i) + ++BeatQue[i] ; + + // Run the sample through the QRS detector. + + detectDelay = QRSDet(ecgSample,0) ; + if(detectDelay != 0) + { + BeatQue[BeatQueCount] = detectDelay ; + ++BeatQueCount ; + } + + // Return if no beat is ready for classification. + + if((BeatQue[0] < (BEATLGTH-FIDMARK)*(SAMPLE_RATE/BEAT_SAMPLE_RATE)) + || (BeatQueCount == 0)) + { + NoiseCheck(ecgSample,0,rr, beatBegin, beatEnd) ; // Update noise check buffer + return 0 ; + } + + // Otherwise classify the beat at the head of the que. + + rr = RRCount - BeatQue[0] ; // Calculate the R-to-R interval + detectDelay = RRCount = BeatQue[0] ; + + // Estimate low frequency noise in the beat. + // Might want to move this into classify(). + + domType = GetDominantType() ; + if(domType == -1) + { + beatBegin = MS250 ; + beatEnd = MS300 ; + } + else + { + beatBegin = (SAMPLE_RATE/BEAT_SAMPLE_RATE)*(FIDMARK-GetBeatBegin(domType)) ; + beatEnd = (SAMPLE_RATE/BEAT_SAMPLE_RATE)*(GetBeatEnd(domType)-FIDMARK) ; + } + noiseEst = NoiseCheck(ecgSample,detectDelay,rr,beatBegin,beatEnd) ; + + // Copy the beat from the circular buffer to the beat buffer + // and reduce the sample rate by averageing pairs of data + // points. + + j = ECGBufferIndex - detectDelay - (SAMPLE_RATE/BEAT_SAMPLE_RATE)*FIDMARK ; + if(j < 0) j += ECG_BUFFER_LENGTH ; + + for(i = 0; i < (SAMPLE_RATE/BEAT_SAMPLE_RATE)*BEATLGTH; ++i) + { + tempBeat[i] = ECGBuffer[j] ; + if(++j == ECG_BUFFER_LENGTH) + j = 0 ; + } + + DownSampleBeat(BeatBuffer,tempBeat) ; + + // Update the QUE. + + for(i = 0; i < BeatQueCount-1; ++i) + BeatQue[i] = BeatQue[i+1] ; + --BeatQueCount ; + + + // Skip the first beat. + + if(InitBeatFlag) + { + InitBeatFlag = 0 ; + *beatType = 13 ; + *beatMatch = 0 ; + fidAdj = 0 ; + } + + // Classify all other beats. + + else + { + *beatType = Classify(BeatBuffer,rr,noiseEst,beatMatch,&fidAdj,0) ; + fidAdj *= SAMPLE_RATE/BEAT_SAMPLE_RATE ; + } + + // Ignore detection if the classifier decides that this + // was the trailing edge of a PVC. + + if(*beatType == 100) + { + RRCount += rr ; + return(0) ; + } + + // Limit the fiducial mark adjustment in case of problems with + // beat onset and offset estimation. + + if(fidAdj > MS80) + fidAdj = MS80 ; + else if(fidAdj < -MS80) + fidAdj = -MS80 ; + + return(detectDelay-fidAdj) ; + } + +void DownSampleBeat(int *beatOut, int *beatIn) + { + int i ; + + for(i = 0; i < BEATLGTH; ++i) + beatOut[i] = (beatIn[i<<2]+ + beatIn[(i<<2)+1]+ + beatIn[(i<<2)+2]+ + beatIn[(i<<2)+3] + )>>2 ; + } + + +void DownSampleBeatOld(int *beatOut, int *beatIn) + { + int i ; + + for(i = 0; i < BEATLGTH; ++i) + beatOut[i] = (beatIn[i<<1]+beatIn[(i<<1)+1])>>1 ; + }