*******************************************************************************/
#include <wfdb/ecgcodes.h>
#include <stdlib.h>
#include <stdio.h>
#include "qrsdet.h"
#include "bdac.h"
#include "match.h"
#include "rythmchk.h"
#include "analbeat.h"
#include "postclas.h"
// Detection Rule Parameters.
#define MATCH_LIMIT 1.3
#define MATCH_WITH_AMP_LIMIT 2.5
#define PVC_MATCH_WITH_AMP_LIMIT 0.9
#define BL_SHIFT_LIMIT 100
#define NEW_TYPE_NOISE_THRESHOLD 18
#define NEW_TYPE_HF_NOISE_LIMIT 75
#define MATCH_NOISE_THRESHOLD 0.7
/
#define R2_DI_THRESHOLD 1.0
#define R3_WIDTH_THRESHOLD BEAT_MS90
#define R7_DI_THRESHOLD 1.2
#define R8_DI_THRESHOLD 1.5
#define R9_DI_THRESHOLD 2.0
#define R10_BC_LIM 3
#define R10_DI_THRESHOLD 2.5
#define R11_MIN_WIDTH BEAT_MS110
#define R11_WIDTH_BREAK BEAT_MS140
#define R11_WIDTH_DIFF1 BEAT_MS40
#define R11_WIDTH_DIFF2 BEAT_MS60
#define R11_HF_THRESHOLD 45
#define R11_MA_THRESHOLD 14
#define R15_DI_THRESHOLD 3.5
#define R15_WIDTH_THRESHOLD BEAT_MS100
#define R16_WIDTH_THRESHOLD BEAT_MS100
#define R17_WIDTH_DELTA BEAT_MS20
#define R18_DI_THRESHOLD 1.5
#define R19_HF_THRESHOLD 75
#define DM_BUFFER_LENGTH 180
#define IRREG_RR_LIMIT 60
// Local prototypes.
int HFNoiseCheck(int *beat) ;
int TempClass(int rhythmClass, int morphType, int beatWidth, int domWidth,
int domType, int hfNoise, int noiseLevel, int blShift, double domIndex) ;
int DomMonitor(int morphType, int rhythmClass, int beatWidth, int rr, int reset) ;
int GetDomRhythm(void) ;
int GetRunCount(void) ;
int DomType ;
int RecentRRs[8], RecentTypes[8] ;
int Classify(int *newBeat,int rr, int noiseLevel, int *beatMatch, int *fidAdj,
int init)
{
int rhythmClass, beatClass, i, beatWidth, blShift ;
static int morphType, runCount = 0 ;
double matchIndex, domIndex, mi2 ;
int shiftAdj ;
int domType, domWidth, onset, offset, amp ;
int beatBegin, beatEnd, tempClass ;
int hfNoise, isoLevel ;
static int lastIsoLevel=0, lastRhythmClass = UNKNOWN, lastBeatWasNew = 0 ;
if(init)
{
ResetRhythmChk() ;
ResetMatch() ;
ResetPostClassify() ;
runCount = 0 ;
DomMonitor(0, 0, 0, 0, 1) ;
return(0) ;
}
hfNoise = HFNoiseCheck(newBeat) ;
rhythmClass = RhythmChk(rr) ;
AnalyzeBeat(newBeat, &onset, &offset, &isoLevel,
&beatBegin, &beatEnd, &) ;
blShift = abs(lastIsoLevel-isoLevel) ;
lastIsoLevel = isoLevel ;
for(i = 0; i < BEATLGTH; ++i)
newBeat[i] -= isoLevel ;
if( (blShift > BL_SHIFT_LIMIT)
&& (lastBeatWasNew == 1)
&& (lastRhythmClass == NORMAL)
&& (rhythmClass == NORMAL) )
ClearLastNewType() ;
lastBeatWasNew = 0 ;
BestMorphMatch(newBeat,&morphType,&matchIndex,&mi2,&shiftAdj) ;
if(matchIndex < MATCH_NOISE_THRESHOLD)
hfNoise = noiseLevel = blShift = 0 ;
if((matchIndex < MATCH_LIMIT) && (rhythmClass == PVC) &&
MinimumBeatVariation(morphType) && (mi2 > PVC_MATCH_WITH_AMP_LIMIT))
{
morphType = NewBeatType(newBeat) ;
lastBeatWasNew = 1 ;
}
else if((matchIndex < MATCH_LIMIT) && (mi2 <= MATCH_WITH_AMP_LIMIT))
UpdateBeatType(morphType,newBeat,mi2,shiftAdj) ;
else if((blShift < BL_SHIFT_LIMIT) && (noiseLevel < NEW_TYPE_NOISE_THRESHOLD)
&& (hfNoise < NEW_TYPE_HF_NOISE_LIMIT))
{
morphType = NewBeatType(newBeat) ;
lastBeatWasNew = 1 ;
}
else if((lastRhythmClass != NORMAL) || (rhythmClass != NORMAL))
{
morphType = NewBeatType(newBeat) ;
lastBeatWasNew = 1 ;
}
else morphType = MAXTYPES ;
for(i = 7; i > 0; --i)
{
RecentRRs[i] = RecentRRs[i-1] ;
RecentTypes[i] = RecentTypes[i-1] ;
}
RecentRRs[0] = rr ;
RecentTypes[0] = morphType ;
lastRhythmClass = rhythmClass ;
lastIsoLevel = isoLevel ;
if(morphType != MAXTYPES)
{
beatClass = GetBeatClass(morphType) ;
beatWidth = GetBeatWidth(morphType) ;
*fidAdj = GetBeatCenter(morphType)-FIDMARK ;
if((beatWidth > offset-onset) && (GetBeatTypeCount(morphType) <= 4))
{
beatWidth = offset-onset ;
*fidAdj = ((offset+onset)/2)-FIDMARK ;
}
}
else
{
beatWidth = offset-onset ;
beatClass = UNKNOWN ;
*fidAdj = ((offset+onset)/2)-FIDMARK ;
}
DomType = domType = DomMonitor(morphType, rhythmClass, beatWidth, rr, 0) ;
domWidth = GetBeatWidth(domType) ;
if((morphType != domType) && (morphType != 8))
domIndex = DomCompare(morphType,domType) ;
else if(morphType == 8)
domIndex = DomCompare2(newBeat,domType) ;
else domIndex = matchIndex ;
PostClassify(RecentTypes, domType, RecentRRs, beatWidth, domIndex, rhythmClass) ;
tempClass = TempClass(rhythmClass, morphType, beatWidth, domWidth,
domType, hfNoise, noiseLevel, blShift, domIndex) ;
if((beatClass == UNKNOWN) && (morphType < MAXTYPES))
{
runCount = GetRunCount() ;
if((runCount >= 3) && (domType != -1) && (beatWidth < domWidth+BEAT_MS20))
SetBeatClass(morphType,NORMAL) ;
else if((runCount >= 6) && (domType == -1))
SetBeatClass(morphType,NORMAL) ;
else if(IsBigeminy() == 1)
{
if((rhythmClass == PVC) && (beatWidth > BEAT_MS100))
SetBeatClass(morphType,PVC) ;
else if(rhythmClass == NORMAL)
SetBeatClass(morphType,NORMAL) ;
}
}
*beatMatch = morphType ;
beatClass = GetBeatClass(morphType) ;
if(beatClass != UNKNOWN)
return(beatClass) ;
if(CheckPostClass(morphType) == PVC)
return(PVC) ;
return(tempClass) ;
}
#define AVELENGTH BEAT_MS50
int HFNoiseCheck(int *beat)
{
int maxNoiseAve = 0, i ;
int sum=0, aveBuff[AVELENGTH], avePtr = 0 ;
int qrsMax = 0, qrsMin = 0 ;
for(i = FIDMARK-BEAT_MS70; i < FIDMARK+BEAT_MS80; ++i)
if(beat[i] > qrsMax)
qrsMax = beat[i] ;
else if(beat[i] < qrsMin)
qrsMin = beat[i] ;
for(i = 0; i < AVELENGTH; ++i)
aveBuff[i] = 0 ;
for(i = FIDMARK-BEAT_MS280; i < FIDMARK+BEAT_MS280; ++i)
{
sum -= aveBuff[avePtr] ;
aveBuff[avePtr] = abs(beat[i] - (beat[i-BEAT_MS10]<<1) + beat[i-2*BEAT_MS10]) ;
sum += aveBuff[avePtr] ;
if(++avePtr == AVELENGTH)
avePtr = 0 ;
if((i < (FIDMARK - BEAT_MS50)) || (i > (FIDMARK + BEAT_MS110)))
if(sum > maxNoiseAve)
maxNoiseAve = sum ;
}
if((qrsMax - qrsMin)>=4)
return((maxNoiseAve * (50/AVELENGTH))/((qrsMax-qrsMin)>>2)) ;
else return(0) ;
}
int TempClass(int rhythmClass, int morphType,
int beatWidth, int domWidth, int domType,
int hfNoise, int noiseLevel, int blShift, double domIndex)
{
if(domType < 0)
return(UNKNOWN) ;
if(MinimumBeatVariation(domType) && (rhythmClass == PVC)
&& (domIndex > R2_DI_THRESHOLD) && (GetDomRhythm() == 1))
return(PVC) ;
if(beatWidth < R3_WIDTH_THRESHOLD)
return(NORMAL) ;
if((morphType == MAXTYPES) && (rhythmClass != PVC)) // == UNKNOWN
return(NORMAL) ;
if((GetTypesCount() == MAXTYPES) && (GetBeatTypeCount(morphType)==1)
&& (rhythmClass == UNKNOWN))
return(NORMAL) ;
if((domIndex < R7_DI_THRESHOLD) && (rhythmClass == NORMAL))
return(NORMAL) ;
if((domIndex < R8_DI_THRESHOLD) && (CheckPCRhythm(morphType) == NORMAL))
return(NORMAL) ;
if((domIndex < R9_DI_THRESHOLD) && (rhythmClass != PVC) && WideBeatVariation(domType))
return(NORMAL) ;
if((domIndex > R10_DI_THRESHOLD)
&& (GetBeatTypeCount(morphType) >= R10_BC_LIM) &&
(CheckPCRhythm(morphType) == PVC) && (GetDomRhythm() == 1))
return(PVC) ;
if( (beatWidth >= R11_MIN_WIDTH) &&
(((beatWidth - domWidth >= R11_WIDTH_DIFF1) && (domWidth < R11_WIDTH_BREAK)) ||
(beatWidth - domWidth >= R11_WIDTH_DIFF2)) &&
(hfNoise < R11_HF_THRESHOLD) && (noiseLevel < R11_MA_THRESHOLD) && (blShift < BL_SHIFT_LIMIT) &&
(morphType < MAXTYPES) && (GetBeatTypeCount(morphType) > R11_BC_LIM)) // Rev 1.1
return(PVC) ;
if((rhythmClass == PVC) && (GetDomRhythm() == 1))
return(PVC) ;
if((rhythmClass == NORMAL) && (GetDomRhythm() == 1))
return(NORMAL) ;
if((beatWidth > domWidth) && (domIndex > R15_DI_THRESHOLD) &&
(beatWidth >= R15_WIDTH_THRESHOLD))
return(PVC) ;