5 Replies - 1321 Views - Last Post: 27 July 2011 - 08:50 AM

#1 fido dido  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 16
  • Joined: 23-March 11

receiving data by bluetooth and analyzing it using code I wrote

Posted 25 July 2011 - 05:15 AM

I want to take the data recieved by mobile bluetooth bit by bitsave it in an array and then analyze it by this code
package ecganalysismodified;

public class BeatDetectionAndClassification implements FinalEcgConstanats{


private int[] ECGBuffer=new int[ECG_BUFFER_LENGTH];
private int ECGBufferIndex = 0 ;  // Circular data buffer.
private int[] BeatBuffer=new int[BEATLGTH] ;
private int[] BeatQue=new int[BEAT_QUE_LENGTH];
private int BeatQueCount = 0 ;  // Buffer of detection delays.
private int RRCount = 0 ;
private int InitBeatFlag = 1 ;
private int[] NoiseBuffer=new int[NB_LENGTH];private int NBPtr = 0 ;
private int NoiseEstimate ;
private double TH = .3125 ;
private int[] DDBuffer=new int[DER_DELAY];private int DDPtr ;	/* Buffer holding derivative data. */
private int Dly  = 0 ;
private int MEMMOVELEN =0;
private int[] BeatTemplates=new int[MAXTYPES*BEATLGTH] ;
private int[] BeatCounts=new int[MAXTYPES] ;
private int[] BeatWidths=new int[MAXTYPES] ;
private int[] BeatClassifications=new int[MAXTYPES] ;
private int[] BeatBegins=new int[MAXTYPES] ;
private int[] BeatEnds=new int[MAXTYPES] ;
private int[] BeatsSinceLastMatch=new int[MAXTYPES] ;
private int[] BeatAmps=new int[MAXTYPES] ;
private int[] BeatCenters=new int[MAXTYPES] ;
private double[] MIs=new double[MAXTYPES*8] ;

// Need access to these in postclas.cpp when beat types are combined
// and moved.
private int[] PostClass=new int[MAXTYPES*8] ;
private int[] PCRhythm=new int[MAXTYPES*8] ;

private int TypeCount = 0 ;


// Global variables.
private int[] RRBuffer=new int[RBB_LENGTH];
private int[] RRTypes=new int[RBB_LENGTH];
private int BeatCount = 0;
private int ClassifyState= LEARNING ;
private int BigeminyFlag ;
private int NewDom;
private int DomRhythm;
private int[] DMBeatTypes=new int[DM_BUFFER_LENGTH];
private int[] DMBeatClasses=new int[DM_BUFFER_LENGTH] ;
private int[] DMBeatRhythms=new int[DM_BUFFER_LENGTH] ;
private int[] DMNormCounts=new int[8];
private int[] DMBeatCounts=new int[8];private int DMIrregCount = 0 ;
private int PCInitCount;
private int DomType;
private int morphType;
private int[] RecentRRs=new int[8];
private int[] RecentTypes=new int[8] ;

int NoiseCheck(int datum, int delay, int RR, int beatBegin, int beatEnd)
	{
	int ptr, i;
	int ncStart, ncEnd, ncMax, ncMin ;
	double noiseIndex ;

	NoiseBuffer[NBPtr] = datum ;
	if(++NBPtr == NB_LENGTH) {
            NBPtr = 0;
        }

	// Check for noise in region that is 300 ms following
	// last R-wave and 250 ms preceding present R-wave.

	ncStart = delay+RR-beatEnd ;	// Calculate offset to end of previous beat.
	ncEnd = delay+beatBegin ;		// Calculate offset to beginning of this beat.
	if(ncStart > ncEnd + MS250) {
            ncStart = ncEnd + MS250;
        }


	// Estimate noise if delay indicates a beat has been detected,
	// the delay is not to long for the data buffer, and there is
	// some space between the end of the last beat and the beginning
	// of this beat.

	if((delay != 0) && (ncStart < NB_LENGTH) && (ncStart > ncEnd))
		{

		ptr = NBPtr - ncStart ;	// Find index to end of last beat in
		if(ptr < 0) {
                ptr += NB_LENGTH;
            }

		// Find the maximum and minimum values in the
		// isoelectric region between beats.

		ncMax = ncMin = NoiseBuffer[ptr] ;
		for(i = 0; i < ncStart-ncEnd; ++i)
			{
			if(NoiseBuffer[ptr] > ncMax) {
                    ncMax = NoiseBuffer[ptr];
                }
			else if(NoiseBuffer[ptr] < ncMin) {
                    ncMin = NoiseBuffer[ptr];
                }
			if(++ptr == NB_LENGTH) {
                    ptr = 0;
                }
			}

		// The noise index is the ratio of the signal variation
		// over the isoelectric window length, scaled by 10.

		noiseIndex = (ncMax-ncMin) ;
		noiseIndex /= (ncStart-ncEnd) ;
		NoiseEstimate = (int) (noiseIndex * 10) ;
		}
	else {
            NoiseEstimate = 0;
        }
	return(NoiseEstimate) ;
	}

int QRSFilter(int datum,int init)
	{
	int fdatum ;

	if(init!=0)
		{
		hpfilt( 0, 1 ) ;		// Initialize filters.
		lpfilt( 0, 1 ) ;
		mvwint( 0, 1 ) ;
		deriv1( 0, 1 ) ;
		deriv2( 0, 1 ) ;
		}

	fdatum = lpfilt( datum, 0 ) ;		// Low pass filter data.
	fdatum = hpfilt( fdatum, 0 ) ;	// High pass filter data.
	fdatum = deriv2( fdatum, 0 ) ;	// Take the derivative.
	fdatum = Math.abs(fdatum) ;				// Take the absolute value.
	fdatum = mvwint( fdatum, 0 ) ;	// Average over an 80 ms window .
	return(fdatum) ;
	}


/*************************************************************************
*  lpfilt() implements the digital filter represented by the difference
*  equation:
*
* 	y[n] = 2*y[n-1] - y[n-2] + x[n] - 2*x[t-24 ms] + x[t-48 ms]
*
*	Note that the filter delay is (LPBUFFER_LGTH/2)-1
*
**************************************************************************/

int lpfilt( int datum ,int init)
	{
	 long y1 = 0, y2 = 0 ;
	 int[] data=new int[LPBUFFER_LGTH];
	 int ptr = 0 ;
	long y0 ;
	int output, halfPtr ;
	if(init!=0)
		{
		for(ptr = 0; ptr < LPBUFFER_LGTH; ++ptr) {
                data[ptr] = 0;
            }
		y1 = y2 = 0 ;
		ptr = 0 ;
		}
	halfPtr = ptr-(LPBUFFER_LGTH/2) ;	// Use halfPtr to index
	if(halfPtr < 0) {
            halfPtr += LPBUFFER_LGTH;
        }
	y0 = (y1 << 1) - y2 + datum - (data[halfPtr] << 1) + data[ptr] ;
	y2 = y1;
	y1 = y0;
	output = (int) (y0 / ((LPBUFFER_LGTH * LPBUFFER_LGTH) / 4));
	data[ptr] = datum ;			// Stick most recent sample into
	if(++ptr == LPBUFFER_LGTH) {
            ptr = 0;
        }					// the buffer pointer.
	return(output) ;
	}


/******************************************************************************
*  hpfilt() implements the high pass filter represented by the following
*  difference equation:
*
*	y[n] = y[n-1] + x[n] - x[n-128 ms]
*	z[n] = x[n-64 ms] - y[n] ;
*
*  Filter delay is (HPBUFFER_LGTH-1)/2
******************************************************************************/

int hpfilt( int datum, int init )
	{
	long y=0 ;
	 int[] data=new int[HPBUFFER_LGTH];
         int ptr = 0 ;
	int z, halfPtr ;

	if(init!=0)
		{
		for(ptr = 0; ptr < HPBUFFER_LGTH; ++ptr) {
                data[ptr] = 0;
            }
		ptr = 0 ;
		y = 0 ;
		}

	y += datum - data[ptr];
	halfPtr = ptr-(HPBUFFER_LGTH/2) ;
	if(halfPtr < 0) {
            halfPtr += HPBUFFER_LGTH;
        }
	z = (int) (data[halfPtr] - (y / HPBUFFER_LGTH));

	data[ptr] = datum ;
	if(++ptr == HPBUFFER_LGTH) {
            ptr = 0;
        }

	return( z );
	}

/*****************************************************************************
*  deriv1 and deriv2 implement derivative approximations represented by
*  the difference equation:
*
*	y[n] = x[n] - x[n - 10ms]
*
*  Filter delay is DERIV_LENGTH/2
*****************************************************************************/

int deriv1(int x, int init)
	{
	 int[] derBuff=new int[DERIV_LENGTH];int derI = 0 ;
	int y ;

	if(init != 0)
		{
		for(derI = 0; derI < DERIV_LENGTH; ++derI) {
                derBuff[derI] = 0;
            }
		derI = 0 ;
		return(0) ;
		}

	y = x - derBuff[derI] ;
	derBuff[derI] = x ;
	if(++derI == DERIV_LENGTH) {
            derI = 0;
        }
	return(y) ;
	}

int deriv2(int x, int init)
	{
	 int[] derBuff=new int[DERIV_LENGTH];int derI = 0 ;
	int y ;

	if(init != 0)
		{
		for(derI = 0; derI < DERIV_LENGTH; ++derI) {
                derBuff[derI] = 0;
            }
		derI = 0 ;
		return(0) ;
		}

	y = x - derBuff[derI] ;
	derBuff[derI] = x ;
	if(++derI == DERIV_LENGTH) {
            derI = 0;
        }
	return(y) ;
	}




/*****************************************************************************
* mvwint() implements a moving window integrator.  Actually, mvwint() averages
* the signal values over the last WINDOW_WIDTH samples.
*****************************************************************************/

int mvwint(int datum, int init)
	{
	 long sum = 0 ;
	 int[] data=new int[WINDOW_WIDTH];
         int ptr = 0 ;
	int output;
	if(init!=0)
		{
		for(ptr = 0; ptr < WINDOW_WIDTH ; ++ptr) {
                data[ptr] = 0;
            }
		sum = 0 ;
		ptr = 0 ;
		}
	sum += datum ;
	sum -= data[ptr] ;
	data[ptr] = datum ;
	if(++ptr == WINDOW_WIDTH) {
            ptr = 0;
        }
	if((sum / WINDOW_WIDTH) > 32000) {
            output = 32000;
        }
	else {
            output = (int) (sum / WINDOW_WIDTH);
        }
	return(output) ;
	}


int QRSDet( int datum, int init )
	{
	 int det_thresh = 0, qpkcnt = 0 ;
	 int[] qrsbuf=new int[8], noise=new int[8], rrbuf=new int[8] ;
	 int[] rsetBuff=new int[8];
	 int rsetCount = 0 ;
	 int nmean = 0, qmean = 0, rrmean ;
	 int count = 0, sbpeak = 0, sbloc = 0, sbcount = MS1500 ;
	 int[] maxder=new int[1];int lastmax ;
	 int initBlank = 0, initMax  = 0;
	 int preBlankCnt = 0, tempPeak  = 0;

	int fdatum, QrsDelay = 0 ;
	int i, newPeak, aPeak ;

/*	Initialize all buffers to 0 on the first call.	*/

	if( init !=0)
		{
		for(i = 0; i < 8; ++i)
			{
			noise[i] = 0 ;	/* Initialize noise buffer */
			rrbuf[i] = MS1000 ;/* and R-to-R interval buffer. */
			}

		qpkcnt = maxder[0] = lastmax = count = sbpeak = 0 ;
		initBlank = initMax = preBlankCnt = DDPtr = 0 ;
		sbcount = MS1500 ;
		QRSFilter(0,1) ;	/* initialize filters. */
		Peak(0,1) ;
		}

	fdatum = QRSFilter(datum,0) ;	/* Filter data. */


	/* Wait until normal detector is ready before calling early detections. */

	aPeak = Peak(fdatum,0) ;
	if(aPeak < MIN_PEAK_AMP) {
            aPeak = 0;
        }

	// Hold any peak that is detected for 200 ms
	// in case a bigger one comes along.  There
	// can only be one QRS complex in any 200 ms window.

	newPeak = 0 ;
	if(aPeak!=0 &&( preBlankCnt==0))			// If there has been no peak for 200 ms
		{										// save this one and start counting.
		tempPeak = aPeak ;
		preBlankCnt = PRE_BLANK ;			// MS200
		}

	else if(aPeak==0 && preBlankCnt!=0)	// If we have held onto a peak for
		{										// 200 ms pass it on for evaluation.
		if(--preBlankCnt == 0) {
                newPeak = tempPeak;
            }
		}

	else if(aPeak!=0)							// If we were holding a peak, but
		{										// this ones bigger, save it and
		if(aPeak > tempPeak)				// start counting to 200 ms again.
			{
			tempPeak = aPeak ;
			preBlankCnt = PRE_BLANK ; // MS200
			}
		else if(--preBlankCnt == 0) {
                newPeak = tempPeak;
            }
		}

	/* Save derivative of raw signal for T-wave and baseline
	   shift discrimination. */

	DDBuffer[DDPtr] = deriv1( datum, 0 ) ;
	if(++DDPtr == DER_DELAY) {
            DDPtr = 0;
        }

	/* Initialize the qrs peak buffer with the first eight 	*/
	/* local maximum peaks detected.						*/

	if( qpkcnt < 8 )
		{
		++count ;
		if(newPeak > 0) {
                count = WINDOW_WIDTH;
            }
		if(++initBlank == MS1000)
			{
			initBlank = 0 ;
			qrsbuf[qpkcnt] = initMax ;
			initMax = 0 ;
			++qpkcnt ;
			if(qpkcnt == 8)
				{
				qmean = mean( qrsbuf, 8 ) ;
				nmean = 0 ;
				rrmean = MS1000 ;
				sbcount = MS1500+MS150 ;
				det_thresh = thresh(qmean,nmean) ;
				}
			}
		if( newPeak > initMax ) {
                initMax = newPeak;
            }
		}

	else	/* Else test for a qrs. */
		{
		++count ;
		if(newPeak > 0)
			{


			/* Check for maximum derivative and matching minima and maxima
			   for T-wave and baseline shift rejection.  Only consider this
			   peak if it doesn't seem to be a base line shift. */

			if(BLSCheck(DDBuffer, DDPtr, maxder)==0)
				{


				// Classify the beat as a QRS complex
				// if the peak is larger than the detection threshold.

				if(newPeak > det_thresh)
					{
					//memmove(qrsbuf[1], qrsbuf, getMEMMOVELEN()) ;
					qrsbuf[0] = newPeak ;
					qmean = mean(qrsbuf,8) ;
					det_thresh = thresh(qmean,nmean) ;
					//memmove(&rrbuf[1], rrbuf, getMEMMOVELEN()) ;
					rrbuf[0] = count - WINDOW_WIDTH ;
					rrmean = mean(rrbuf,8) ;
					sbcount = rrmean + (rrmean >> 1) + WINDOW_WIDTH ;
					count = WINDOW_WIDTH ;

					sbpeak = 0 ;

					lastmax = maxder[0] ;
					maxder[0] = 0 ;
					QrsDelay =  WINDOW_WIDTH + FILTER_DELAY ;
					initBlank = initMax = rsetCount = 0 ;
					}

				// If a peak isn't a QRS update noise buffer and estimate.
				// Store the peak for possible search back.


				else
					{
					//memmove(noise[1],noise, getMEMMOVELEN()) ;
					noise[0] = newPeak ;
					nmean = mean(noise,8) ;
					det_thresh = thresh(qmean,nmean) ;

					// Don't include early peaks (which might be T-waves)
					// in the search back process.  A T-wave can mask
					// a small following QRS.

					if((newPeak > sbpeak) && ((count-WINDOW_WIDTH) >= MS360))
						{
						sbpeak = newPeak ;
						sbloc = count  - WINDOW_WIDTH ;
						}
					}
				}
			}

		/* Test for search back condition.  If a QRS is found in  */
		/* search back update the QRS buffer and det_thresh.      */

		if((count > sbcount) && (sbpeak > (det_thresh >> 1)))
			{
			//memmove(qrsbuf[1],qrsbuf, getMEMMOVELEN()) ;
			qrsbuf[0] = sbpeak ;
			qmean = mean(qrsbuf,8) ;
			det_thresh = thresh(qmean,nmean) ;
			//memmove(&rrbuf[1],rrbuf, getMEMMOVELEN()) ;
			rrbuf[0] = sbloc ;
			rrmean = mean(rrbuf,8) ;
			sbcount = rrmean + (rrmean >> 1) + WINDOW_WIDTH ;
			QrsDelay = count -= sbloc ;
			QrsDelay += FILTER_DELAY ;
			sbpeak = 0 ;
			lastmax = maxder[0] ;
			maxder[0] = 0 ;

			initBlank = initMax = rsetCount = 0 ;
			}
		}

	// In the background estimate threshold to replace adaptive threshold
	// if eight seconds elapses without a QRS detection.

	if( qpkcnt == 8 )
		{
		if(++initBlank == MS1000)
			{
			initBlank = 0 ;
			rsetBuff[rsetCount] = initMax ;
			initMax = 0 ;
			++rsetCount ;

			// Reset threshold if it has been 8 seconds without
			// a detection.

			if(rsetCount == 8)
				{
				for(i = 0; i < 8; ++i)
					{
					qrsbuf[i] = rsetBuff[i] ;
					noise[i] = 0 ;
					}
				qmean = mean( rsetBuff, 8 ) ;
				nmean = 0 ;
				rrmean = MS1000 ;
				sbcount = MS1500+MS150 ;
				det_thresh = thresh(qmean,nmean) ;
				initBlank = initMax = rsetCount = 0 ;
				}
			}
		if( newPeak > initMax ) {
                initMax = newPeak;
            }
		}

	return(QrsDelay) ;}


/**************************************************************
* peak() takes a datum as input and returns a peak height
* when the signal returns to half its peak height, or
**************************************************************/

int Peak( int datum, int init )
	{
	 int max = 0, timeSinceMax = 0, lastDatum  = 0;
	int pk = 0 ;

	if(init!=0) {
            max = timeSinceMax = 0;
        }

	if(timeSinceMax > 0) {
            ++timeSinceMax;
        }

	if((datum > lastDatum) && (datum > max))
		{
		max = datum ;
		if(max > 2) {
                timeSinceMax = 1;
            }
		}

	else if(datum < (max >> 1))
		{
		pk = max ;
		max = 0 ;
		timeSinceMax = 0 ;
		Dly = 0 ;
		}

	else if(timeSinceMax > MS95)
		{
		pk = max ;
		max = 0 ;
		timeSinceMax = 0 ;
		Dly = 3 ;
		}
	lastDatum = datum ;
	return(pk) ;
	}

/********************************************************************
mean returns the mean of an array of integers.  It uses a slow
sort algorithm, but these arrays are small, so it hardly matters.
********************************************************************/

int mean(int[] array, int datnum)
	{
	long sum ;
	int i ;

	for(i = 0, sum = 0; i < datnum; ++i) {
            sum += array[i];
        }
	sum /= datnum ;
	return(int) (sum) ;
	}

/****************************************************************************
 thresh() calculates the detection threshold from the qrs mean and noise
 mean estimates.
****************************************************************************/

int thresh(int qmean, int nmean)
	{
	int thrsh, dmed ;
	double temp ;
	dmed = qmean - nmean ;
/*	thrsh = nmean + (dmed>>2) + (dmed>>3) + (dmed>>4); */
	temp = dmed ;
	temp *= TH ;
	dmed = (int) temp ;
	thrsh = nmean + dmed ; /* dmed * THRESHOLD */
	return(thrsh) ;
	}

/***********************************************************************
	BLSCheck() reviews data to see if a baseline shift has occurred.
	This is done by looking for both positive and negative slopes of
	roughly the same magnitude in a 220 ms window.
***********************************************************************/

int BLSCheck(int[] dBuf,int dbPtr,int[] maxder)
	{
	int max, min, maxt = 0, mint = 0, t, x ;
	max = min = 0 ;

	for(t = 0; t < MS220; ++t)
		{
		x = dBuf[dbPtr] ;
		if(x > max)
			{
			maxt = t ;
			max = x ;
			}
		else if(x < min)
			{
			mint = t ;
			min = x;
			}
		if(++dbPtr == DER_DELAY) {
                dbPtr = 0;
            }
		}

	maxder[0] = max ;
	min = -min ;

	/* Possible beat if a maximum and minimum pair are found
		where the interval between them is less than 150 ms. */

	if((max > (min>>3)) && (min > (max>>3)) &&
		(Math.abs(maxt - mint) < MS150)) {
            return 0;
        }

	else {
            return 1;
        }


}



/******************************************************************************
	ResetBDAC() resets static variables required for beat detection and
	classification.
*******************************************************************************/

void ResetBDAC()
	{
	int[] dummy=new int[1] ;
	QRSDet(0,1) ;	// Reset the qrs detector
	RRCount=0 ;
	Classify(BeatBuffer,0,0,dummy,dummy,1) ;
	InitBeatFlag=1 ;
        BeatQueCount=0 ;	// Flush the beat que.
	}
/**********************************************************************
 Resets post classifications for beats.
**********************************************************************/

void ResetPostClassify()
	{
	int i, j ;
	for(i = 0; i < MAXTYPES; ++i) {
            for (j = 0; j < 8; ++j) {
                PostClass[i*j] = 0;
                PCRhythm[i*j] = 0;
            }
        }
	PCInitCount = 0 ;
	}

/***********************************************************************
	Classify the previous beat type and rhythm type based on this beat
	and the preceding beat.  This classifier is more sensitive
	to detecting premature beats followed by compensitory pauses.
************************************************************************/

void PostClassify(int[] recentTypes, int domType, int[] recentRRs, int width, double mi2,
	int rhythmClass)
	{
	 int lastRC = 0, lastWidth ;
	 double lastMI2 = 0 ;
	int i, regCount, pvcCount, normRR  = 0;
	double mi3 ;

	// If the preceeding and following beats are the same type,
	// they are generally regular, and reasonably close in shape
	// to the dominant type, consider them to be dominant.

	if((recentTypes[0] == recentTypes[2]) && (recentTypes[0] != domType)
		&& (recentTypes[0] != recentTypes[1]))
		{
		mi3 = DomCompare(recentTypes[0],domType) ;
		for(i = regCount = 0; i < 8; ++i) {
                if (PCRhythm[recentTypes[0]*i] == NORMAL) {
                    ++regCount;
                }
            }
		if((mi3 < 2.0) && (regCount > 6)) {
                domType = recentTypes[0];
            }
		}

	// Don't do anything until four beats have gone by.

	if(PCInitCount < 3)
		{
		++PCInitCount ;
		lastWidth = width ;
		lastMI2 = 0 ;
		lastRC = 0 ;
		return ;
		}

	if(recentTypes[1] < MAXTYPES)
		{

		// Find first NN interval.
		for(i = 2; (i < 7) && (recentTypes[i] != recentTypes[i+1]); ++i) {
                if (i == 7) {
                    normRR = 0;
                } else {
                    normRR = recentRRs[i];
                }
            }

		// Shift the previous beat classifications to make room for the
		// new classification.
		for(i = pvcCount = 0; i < 8; ++i) {
                if (PostClass[recentTypes[1] * i] == PVC) {
                    ++pvcCount;
                }
            }

		for(i = 7; i > 0; --i)
			{
			PostClass[recentTypes[1]*i] = PostClass[recentTypes[1]*i-1] ;
			PCRhythm[recentTypes[1]*i] = PCRhythm[recentTypes[1]*i-1] ;
			}

		// If the beat is premature followed by a compensitory pause and the
		// previous and following beats are normal, post classify as
		// a PVC.

		if(((normRR-(normRR>>3)) >= recentRRs[1]) && ((recentRRs[0]-(recentRRs[0]>>3)) >= normRR)// && (lastMI2 > 3)
			&& (recentTypes[0] == domType) && (recentTypes[2] == domType)
				&& (recentTypes[1] != domType)) {
                PostClass[recentTypes[1] * 0] = PVC;
            }

		// If previous two were classified as PVCs, and this is at least slightly
		// premature, classify as a PVC.

		else if(((normRR-(normRR>>4)) > recentRRs[1]) && ((normRR+(normRR>>4)) < recentRRs[0]) &&
			(((PostClass[recentTypes[1]*1] == PVC) && (PostClass[recentTypes[1]*2] == PVC)) ||
				(pvcCount >= 6) ) &&
			(recentTypes[0] == domType) && (recentTypes[2] == domType) && (recentTypes[1] != domType)) {
                PostClass[recentTypes[1] * 0] = PVC;
            }

		// If the previous and following beats are the dominant beat type,
		// and this beat is significantly different from the dominant,
		// call it a PVC.

		else if((recentTypes[0] == domType) && (recentTypes[2] == domType) && (lastMI2 > 2.5)) {
                PostClass[recentTypes[1] * 0] = PVC;
            }

		// Otherwise post classify this beat as UNKNOWN.

		else {
                PostClass[recentTypes[1] * 0] = UNKNOWN;
            }

		// If the beat is premature followed by a compensitory pause, post
		// classify the rhythm as PVC.

		if(((normRR-(normRR>>3)) > recentRRs[1]) && ((recentRRs[0]-(recentRRs[0]>>3)) > normRR)) {
                PCRhythm[recentTypes[1] * 0] = PVC;
            }

		// Otherwise, post classify the rhythm as the same as the
		// regular rhythm classification.

		else {
                PCRhythm[recentTypes[1] * 0] = lastRC;
            }
		}

	lastWidth = width ;
	lastMI2 = mi2 ;
	lastRC = rhythmClass ;
	}


/*************************************************************************
	CheckPostClass checks to see if three of the last four or six of the
	last eight of a given beat type have been post classified as PVC.
*************************************************************************/

int CheckPostClass(int type)
	{
	int i, pvcs4 = 0, pvcs8 ;

	if(type == MAXTYPES) {
            return UNKNOWN;
        }

	for(i = 0; i < 4; ++i) {
            if (PostClass[type * i] == PVC) {
                ++pvcs4;
            }
        }
	for(pvcs8=pvcs4; i < 8; ++i) {
            if (PostClass[type * i] == PVC) {
                ++pvcs8;
            }
        }

	if((pvcs4 >= 3) || (pvcs8 >= 6)) {
            return PVC;
        }
	else {
            return UNKNOWN;
        }
	}

/****************************************************************************
	Check classification of previous beats' rhythms based on post beat
	classification.  If 7 of 8 previous beats were classified as NORMAL
	(regular) classify the beat type as NORMAL (regular).
	Call it a PVC if 2 of the last 8 were regular.
****************************************************************************/

int CheckPCRhythm(int type)
	{
	int i, normCount, n ;


	if(type == MAXTYPES) {
            return UNKNOWN;
        }

	if(GetBeatTypeCount(type) < 9) {
            n = GetBeatTypeCount(type) - 1;
        }
	else {
            n = 8;
        }

	for(i = normCount = 0; i < n; ++i) {
            if (PCRhythm[type*i] == NORMAL) {
                ++normCount;
            }
        }
	if(normCount >= 7) {
            return NORMAL;
        }
	if(((normCount == 0) && (n < 4)) ||
		((normCount <= 1) && (n >= 4) && (n < 7)) ||
		((normCount <= 2) && (n >= 7))) {
            return PVC;
        }
	return(UNKNOWN) ;
	}

/*****************************************************************************
Syntax:
	int BeatDetectAndClassify(int ecgSample, int *beatType, int *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;
        int[] rr =new int[1];
        int i, j ;
	int noiseEst = 0, beatBegin = 0, beatEnd  = 0;
	int domType ;
	int[] fidAdj=new int[1] ;
	int[] tempBeat=new int[(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 += 1 ;

	// 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 += 1 ;
		}

	// Return if no beat is ready for classification.

	if((BeatQue[0] < (BEATLGTH-FIDMARK)*(SAMPLE_RATE/BEAT_SAMPLE_RATE))
		|| (BeatQueCount == 0))
		{
            int NoiseCheck = NoiseCheck(ecgSample, 0, rr[0], beatBegin, beatEnd);


	// Update noise check buffer
		return 0 ;
		}

	// Otherwise classify the beat at the head of the que.

	rr[0] = 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[0],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 -= 1 ;


	// Skip the first beat.

	if(InitBeatFlag!=0)
		{
		InitBeatFlag=0 ;
		beatType[0] = 13 ;
		beatMatch[0] = 0 ;
		fidAdj[0]= 0 ;
		}

	// Classify all other beats.

	else
		{
		beatType[0] = Classify(BeatBuffer,rr[0],noiseEst,beatMatch,fidAdj,0) ;
		fidAdj[0] *= SAMPLE_RATE/BEAT_SAMPLE_RATE ;
      }

	// Ignore detection if the classifier decides that this
	// was the trailing edge of a PVC.

	if(beatType[0] == 100)
		{
		RRCount += rr[0] ;
		return(0) ;
		}

	// Limit the fiducial mark adjustment in case of problems with
	// beat onset and offset estimation.

	if(fidAdj[0] > MS80) {
            fidAdj[0] = MS80;
        }
	else if(fidAdj[0] < -MS80) {
            fidAdj[0] = -MS80;
        }

	return(detectDelay-fidAdj[0]) ;
	}

void DownSampleBeat(int[] beatOut, int[] beatIn)
	{
	int i ;

	for(i = 0; i < BEATLGTH; ++i) {
            beatOut[i] = (beatIn[i << 1] + beatIn[(i << 1) + 1]) >> 1;
        }
	}void ResetRhythmChk()
	{
	BeatCount = 0 ;
	ClassifyState = LEARNING ;
	}
        void ResetMatch()
	{
	int i, j ;
	TypeCount = 0 ;
	for(i = 0; i < MAXTYPES; ++i)
		{
		BeatCounts[i] = 0 ;
		BeatClassifications[i] = UNKNOWN ;
		for(j = 0; j < 8; ++j)
			{
			MIs[i*j] = 0 ;
			}
		}
	}

/**************************************************************************
	CompareBeats() takes two beat buffers and compares how well they match
	point-by-point.  Beat2 is shifted and scaled to produce the closest
	possible match.  The metric returned is the sum of the absolute
	differences between beats divided by the amplitude of the beats.  The
	shift used for the match is returned via the pointer *shiftAdj.
***************************************************************************/


double CompareBeats(int[] beat1, int[] beat2, int[] shiftAdj)
	{
	int i, max, min, magSum, shift ;
	long beatDiff , meanDiff  , minDiff  = 0, minShift  = 0;
	double metric, scaleFactor, tempD ;

	// Calculate the magnitude of each beat.

	max = min = beat1[MATCH_START] ;
	for(i = MATCH_START+1; i < MATCH_END; ++i) {
            if (beat1[i] > max) {
                max = beat1[i];
            } else if (beat1[i] < min) {
                min = beat1[i];
            }
        }

	magSum = max - min ;

	i = MATCH_START ;
	max = min = beat2[i] ;
	for(i = MATCH_START+1; i < MATCH_END; ++i) {
            if (beat2[i] > max) {
                max = beat2[i];
            } else if (beat2[i] < min) {
                min = beat2[i];
            }
        }

	// magSum += max - min ;
	scaleFactor = magSum ;
	scaleFactor /= max-min ;
	magSum *= 2 ;

	// Calculate the sum of the point-by-point
	// absolute differences for five possible shifts.

	for(shift = -MAX_SHIFT; shift <= MAX_SHIFT; ++shift)
		{
		for(i = FIDMARK-(MATCH_LENGTH>>1), meanDiff = 0;
			i < FIDMARK + (MATCH_LENGTH>>1); ++i)
			{
			tempD = beat2[i+shift] ;
			tempD *= scaleFactor ;
			meanDiff += beat1[i]- tempD ; // beat2[i+shift] ;
			}
		meanDiff /= MATCH_LENGTH ;

		for(i = FIDMARK-(MATCH_LENGTH>>1), beatDiff = 0;
			i < FIDMARK + (MATCH_LENGTH>>1); ++i)
			{
			tempD = beat2[i+shift] ;
			tempD *= scaleFactor ;
			beatDiff += Math.abs(beat1[i] - meanDiff- tempD) ; // beat2[i+shift]  ) ;
			}


		if(shift == -MAX_SHIFT)
			{
			minDiff = beatDiff ;
			minShift = -MAX_SHIFT ;
			}
		else if(beatDiff < minDiff)
			{
			minDiff = beatDiff ;
			minShift = shift ;
			}
		}

	metric = minDiff ;
	shiftAdj[0] = (int) minShift ;
	metric /= magSum ;

	// Metric scales inversely with match length.
	// algorithm was originally tuned with a match
	// length of 30.

	metric *= 30 ;
	metric /= MATCH_LENGTH ;
	return(metric) ;
	}

/***************************************************************************
	CompareBeats2 is nearly the same as CompareBeats above, but beat2 is
	not scaled before calculating the match metric.  The match metric is
	then the sum of the absolute differences divided by the average amplitude
	of the two beats.
****************************************************************************/

double CompareBeats2(int[] beat1, int[] beat2, int[] shiftAdj)
	{
	int i, max, min, shift ;
	int mag1, mag2 ;
	long beatDiff, meanDiff, minDiff = 0, minShift  = 0;
	double metric ;

	// Calculate the magnitude of each beat.

	max = min = beat1[MATCH_START] ;
	for(i = MATCH_START+1; i < MATCH_END; ++i) {
            if (beat1[i] > max) {
                max = beat1[i];
            } else if (beat1[i] < min) {
                min = beat1[i];
            }
        }

	mag1 = max - min ;

	i = MATCH_START ;
	max = min = beat2[i] ;
	for(i = MATCH_START+1; i < MATCH_END; ++i) {
            if (beat2[i] > max) {
                max = beat2[i];
            } else if (beat2[i] < min) {
                min = beat2[i];
            }
        }

	mag2 = max-min ;

	// Calculate the sum of the point-by-point
	// absolute differences for five possible shifts.

	for(shift = -MAX_SHIFT; shift <= MAX_SHIFT; ++shift)
		{
		for(i = FIDMARK-(MATCH_LENGTH>>1), meanDiff = 0;
			i < FIDMARK + (MATCH_LENGTH>>1); ++i) {
                meanDiff += beat1[i] - beat2[i + shift];
            }
		meanDiff /= MATCH_LENGTH ;

		for(i = FIDMARK-(MATCH_LENGTH>>1), beatDiff = 0;
			i < FIDMARK + (MATCH_LENGTH>>1); ++i) {
                beatDiff += Math.abs(beat1[i] - meanDiff - beat2[i + shift]);
            }

		if(shift == -MAX_SHIFT)
			{
			minDiff = beatDiff ;
			minShift = -MAX_SHIFT ;
			}
		else if(beatDiff < minDiff)
			{
			minDiff = beatDiff ;
			minShift = shift ;
			}
		}

	metric = minDiff ;
	shiftAdj[0] = (int) minShift ;
	metric /= (mag1+mag2) ;

	// Metric scales inversely with match length.
	// algorithm was originally tuned with a match
	// length of 30.

	metric *= 30 ;
	metric /= MATCH_LENGTH ;

	return(metric) ;
	}

/************************************************************************
UpdateBeat() averages a new beat into an average beat template by adding
1/8th of the new beat to 7/8ths of the average beat.
*************************************************************************/

void UpdateBeat(int[] aveBeat, int[] newBeat, int shift)
	{
	int i ;
	long tempLong ;

	for(i = 0; i < BEATLGTH; ++i)
		{
		if((i+shift >= 0) && (i+shift < BEATLGTH))
			{
			tempLong = aveBeat[i] ;
			tempLong *= 7 ;
			tempLong += newBeat[i+shift] ;
			tempLong >>= 3 ;
			aveBeat[i] = (int) tempLong ;
			}
		}
	}

/*******************************************************
	GetTypesCount returns the number of types that have
	been detected.
*******************************************************/

int GetTypesCount()
	{
	return(TypeCount) ;
	}

/********************************************************
	GetBeatTypeCount returns the number of beats of a
	a particular type have been detected.
********************************************************/

int GetBeatTypeCount(int type)
	{
	return(BeatCounts[type]) ;
	}

/*******************************************************
	GetBeatWidth returns the QRS width estimate for
	a given type of beat.
*******************************************************/
int GetBeatWidth(int type)
	{
	return(BeatWidths[type]) ;
	}

/*******************************************************
	GetBeatCenter returns the point between the onset and
	offset of a beat.
********************************************************/

int GetBeatCenter(int type)
	{
	return(BeatCenters[type]) ;
	}

/*******************************************************
	GetBeatClass returns the present classification for
	a given beat type (NORMAL, PVC, or UNKNOWN).
********************************************************/

int GetBeatClass(int type)
	{
	if(type == MAXTYPES) {
            return UNKNOWN;
        }
	return(BeatClassifications[type]) ;
	}

/******************************************************
	SetBeatClass sets up a beat classifation for a
	given type.
******************************************************/

void SetBeatClass(int type, int beatClass)
	{
	BeatClassifications[type] = beatClass ;
	}


/******************************************************************************
	NewBeatType starts a new beat type by storing the new beat and its
	features as the next available beat type.
******************************************************************************/

int NewBeatType(int[] newBeat )
	{
	int i;
        int[] onset=new int[1], offset=new int[1], isoLevel=new int[1], beatBegin=new int[1], beatEnd=new int[1] ;
	int mcType;
        int [] amp=new int[1] ;

	// Update count of beats since each template was matched.

	for(i = 0; i < TypeCount; ++i) {
            ++BeatsSinceLastMatch[i];
        }

	if(TypeCount < MAXTYPES)
		{
		for(i = 0; i < BEATLGTH; ++i) {
                BeatTemplates[TypeCount * i] = newBeat[i];
            }

		BeatCounts[TypeCount] = 1 ;
		BeatClassifications[TypeCount] = UNKNOWN ;
		AnalyzeBeat(BeatTemplates,onset,offset, isoLevel,
			beatBegin, beatEnd, amp) ;
		BeatWidths[TypeCount] = offset[0]-onset[0] ;
		BeatCenters[TypeCount] = (offset[0]+onset[0])/2 ;
		BeatBegins[TypeCount] = beatBegin[0] ;
		BeatEnds[TypeCount] = beatEnd[0] ;
		BeatAmps[TypeCount] = amp[0] ;

		BeatsSinceLastMatch[TypeCount] = 0 ;

		++TypeCount ;
		return(TypeCount-1) ;
		}

	// If we have used all the template space, replace the beat
	// that has occurred the fewest number of times.

	else
		{
		// Find the template with the fewest occurances,
		// that hasn't been matched in at least 500 beats.

		mcType = -1 ;

		if(mcType == -1)
			{
			mcType = 0 ;
			for(i = 1; i < MAXTYPES; ++i) {
                    if (BeatCounts[i] < BeatCounts[mcType]) {
                        mcType = i;
                    } else if (BeatCounts[i] == BeatCounts[mcType]) {
                        if (BeatsSinceLastMatch[i] > BeatsSinceLastMatch[mcType]) {
                            mcType = i;
                        }
                    }
                }
			}

		// Adjust dominant beat monitor data.

		AdjustDomData(mcType,MAXTYPES) ;

		// Substitute this beat.

		for(i = 0; i < BEATLGTH; ++i) {
                BeatTemplates[mcType * i] = newBeat[i];
            }

		BeatCounts[mcType] = 1 ;
		BeatClassifications[mcType] = UNKNOWN ;
		AnalyzeBeat(BeatTemplates,onset,offset, isoLevel,
			beatBegin, beatEnd, amp) ;
		BeatWidths[mcType] = offset[0]-onset[0] ;
		BeatCenters[mcType] = (offset[0]+onset[0])/2 ;
		BeatBegins[mcType] = beatBegin[0] ;
		BeatEnds[mcType] = beatEnd[0] ;
		BeatsSinceLastMatch[mcType] = 0 ;
      BeatAmps[mcType] = amp[0] ;
		return(mcType) ;
		}}


/***************************************************************************
	BestMorphMatch tests a new beat against all available beat types and
	returns (via pointers) the existing type that best matches, the match
	metric for that type, and the shift used for that match.
***************************************************************************/

void BestMorphMatch(int[] newBeat,int[] matchType,double[] matchIndex, double[] mi2,
	int[] shiftAdj)
	{
	int type, i, bestMatch = 0, nextBest = 0, minShift = 0, temp ;
	int[] bestShift2=new int[1], nextShift2=new int[1] ;
	double bestDiff2, nextDiff2;
	double beatDiff, minDiff = 0, nextDiff=10000 ;
int[] shift=new int[1];
	if(TypeCount == 0)
		{
		matchType[0] = 0 ;
		matchIndex[0] = 1000 ;		// Make sure there is no match so a new beat is
		shiftAdj[0] = 0 ;			// created.

		}

	// Compare the new beat to all type beat
	// types that have been saved.

	for(type = 0; type < TypeCount; ++type)
		{
		beatDiff = CompareBeats(BeatTemplates,newBeat,shift) ;
		if(type == 0)
			{
			bestMatch = 0 ;
			minDiff = beatDiff ;
			minShift = shift[0] ;
			}
		else if(beatDiff < minDiff)
			{
			nextBest = bestMatch ;
			nextDiff = minDiff ;
			bestMatch = type ;
			minDiff = beatDiff ;
			minShift = shift[0];
			}
		else if((TypeCount > 1) && (type == 1))
			{
			nextBest = type ;
			nextDiff = beatDiff ;
			}
		else if(beatDiff < nextDiff)
			{
			nextBest = type ;
			nextDiff = beatDiff ;
			}
		}

	// If this beat was close to two different
	// templates, see if the templates which template
	// is the best match when no scaling is used.
	// Then check whether the two close types can be combined.

	if((minDiff < MATCH_LIMIT) && (nextDiff < MATCH_LIMIT) && (TypeCount > 1))
		{
		// Compare without scaling.

		bestDiff2 = CompareBeats2(BeatTemplates,newBeat,bestShift2) ;
		nextDiff2 = CompareBeats2(BeatTemplates,newBeat,nextShift2) ;
		if(nextDiff2 < bestDiff2)
			{
			temp = bestMatch ;
			bestMatch = nextBest ;
			nextBest = temp ;
			temp = (int) minDiff ;
			minDiff = nextDiff ;
			nextDiff = temp ;
			minShift = nextShift2[1] ;
			mi2[0] = bestDiff2 ;
			}
		else {
                mi2[0] = nextDiff2;
            }

		beatDiff = CompareBeats(BeatTemplates,BeatTemplates,shift) ;

		if((beatDiff < COMBINE_LIMIT) &&
			((mi2[0] < 1.0) || (MinimumBeatVariation(nextBest)==0)))
			{

			// Combine beats into bestMatch

			if(bestMatch < nextBest)
				{
				for(i = 0; i < BEATLGTH; ++i)
					{
					if((i+shift[0] > 0) && (i + shift[0] < BEATLGTH))
						{
						BeatTemplates[bestMatch*i] += BeatTemplates[nextBest*i+shift[0]] ;
						BeatTemplates[bestMatch*i] >>= 1 ;
						}
					}

				if((BeatClassifications[bestMatch] == NORMAL) || (BeatClassifications[nextBest] == NORMAL)) {
                        BeatClassifications[bestMatch] = NORMAL;
                    }
				else if((BeatClassifications[bestMatch] == PVC) || (BeatClassifications[nextBest] == PVC)) {
                        BeatClassifications[bestMatch] = PVC;
                    }

				BeatCounts[bestMatch] += BeatCounts[nextBest] ;

				CombineDomData(nextBest,bestMatch) ;

				// Shift other templates over.

				for(type = nextBest; type < TypeCount-1; ++type) {
                        BeatCopy(type + 1, type);
                    }

				}

			// Otherwise combine beats it nextBest.

			else
				{
				for(i = 0; i < BEATLGTH; ++i)
					{
					BeatTemplates[nextBest*i] += BeatTemplates[bestMatch*i] ;
					BeatTemplates[nextBest*i] >>= 1 ;
					}

				if((BeatClassifications[bestMatch] == NORMAL) || (BeatClassifications[nextBest] == NORMAL)) {
                        BeatClassifications[nextBest] = NORMAL;
                    }
				else if((BeatClassifications[bestMatch] == PVC) || (BeatClassifications[nextBest] == PVC)) {
                        BeatClassifications[nextBest] = PVC;
                    }

				BeatCounts[nextBest] += BeatCounts[bestMatch] ;

				CombineDomData(bestMatch,nextBest) ;

				// Shift other templates over.

				for(type = bestMatch; type < TypeCount-1; ++type) {
                        BeatCopy(type + 1, type);
                    }


				bestMatch = nextBest ;
				}
			--TypeCount ;
			BeatClassifications[TypeCount] = UNKNOWN ;
			}
		}
	mi2[0] = CompareBeats2(BeatTemplates,newBeat,bestShift2) ;
	matchType[0] = bestMatch ;
	matchIndex[0] = minDiff ;
	shiftAdj[0] = minShift ;
	}

/***************************************************************************
	UpdateBeatType updates the beat template and features of a given beat type
	using a new beat.
***************************************************************************/

void UpdateBeatType(int matchType,int[] newBeat, double mi2,
	 int shiftAdj)
	{
	int i;
        int[] onset=new int[1];
        int[] offset=new int[1];
        int[] isoLevel=new int[1];int[] beatBegin=new int[1];int[] beatEnd=new int[1] ;
	int[] amp =new int[1];

	// Update beats since templates were matched.

	for(i = 0; i < TypeCount; ++i)
		{
		if(i != matchType) {
                ++BeatsSinceLastMatch[i];
            }
		else {
                BeatsSinceLastMatch[i] = 0;
            }
		}

	// If this is only the second beat, average it with the existing
	// template.

	if(BeatCounts[matchType] == 1) {
            for (i = 0; i < BEATLGTH; ++i) {
                if ((i + shiftAdj >= 0) && (i + shiftAdj < BEATLGTH)) {
                    BeatTemplates[matchType*i] = (BeatTemplates[matchType*i] + newBeat[i + shiftAdj]) >> 1;
                }
            }
        }

	// Otherwise do a normal update.

	else {
            UpdateBeat(BeatTemplates, newBeat, shiftAdj);
        }

	// Determine beat features for the new average beat.

	AnalyzeBeat(BeatTemplates,onset,offset,isoLevel,
		beatBegin, beatEnd, amp) ;

	BeatWidths[matchType] = offset[0]-onset[0] ;
	BeatCenters[matchType] = (offset[0]+onset[0])/2 ;
	BeatBegins[matchType] = beatBegin[0] ;
	BeatEnds[matchType] = beatEnd[0] ;
	BeatAmps[matchType] = amp[0] ;

	++BeatCounts[matchType] ;

	for(i = MAXPREV-1; i > 0; --i) {
            MIs[matchType * i] = MIs[matchType * i - 1];
        }
	MIs[matchType*0] = mi2 ;

	}


/****************************************************************************
	GetDominantType returns the NORMAL beat type that has occurred most
	frequently.
****************************************************************************/

int GetDominantType()
	{
	int maxCount = 0, maxType = -1 ;
	int type, totalCount ;

	for(type = 0; type < MAXTYPES; ++type)
		{
		if((BeatClassifications[type] == NORMAL) && (BeatCounts[type] > maxCount))
			{
			maxType = type ;
			maxCount = BeatCounts[type] ;
			}
		}

	// If no normals are found and at least 300 beats have occurred, just use
	// the most frequently occurring beat.

	if(maxType == -1)
		{
		for(type = 0, totalCount = 0; type < TypeCount; ++type) {
                totalCount += BeatCounts[type];
            }
		if(totalCount > 300) {
                for (type = 0; type < TypeCount; ++type) {
                    if (BeatCounts[type] > maxCount) {
                        maxType = type;
                        maxCount = BeatCounts[type];
                    }
                }
            }
		}

	return(maxType) ;
	}


/***********************************************************************
	ClearLastNewType removes the last new type that was initiated
************************************************************************/

void ClearLastNewType()
	{
	if(TypeCount != 0) {
            --TypeCount;
        }
	}

/****************************************************************
	GetBeatBegin returns the offset from the R-wave for the
	beginning of the beat (P-wave onset if a P-wave is found).
*****************************************************************/

int GetBeatBegin(int type)
	{
	return(BeatBegins[type]) ;
	}

/****************************************************************
	GetBeatEnd returns the offset from the R-wave for the end of
	a beat (T-wave offset).
*****************************************************************/

int GetBeatEnd(int type)
	{
	return(BeatEnds[type]) ;
	}

int GetBeatAmp(int type)
	{
	return(BeatAmps[type]) ;
	}


/************************************************************************
	DomCompare2 and DomCompare return similarity indexes between a given
	beat and the dominant normal type or a given type and the dominant
	normal type.
************************************************************************/

double DomCompare2(int[] newBeat, int domType)
	{
	int[] shift=new int[1] ;
	return(CompareBeats2(BeatTemplates,newBeat,shift)) ;
	}

double DomCompare(int newType, int domType)
	{
	int[] shift=new int[1] ;
	return(CompareBeats2(BeatTemplates,BeatTemplates,
		shift)) ;
	}

/*************************************************************************
BeatCopy copies beat data from a source beat to a destination beat.
*************************************************************************/

void BeatCopy(int srcBeat, int destBeat)
	{
	int i ;

	// Copy template.

	for(i = 0; i < BEATLGTH; ++i) {
            BeatTemplates[destBeat * i] = BeatTemplates[srcBeat * i];
        }

	// Move feature information.

	BeatCounts[destBeat] = BeatCounts[srcBeat] ;
	BeatWidths[destBeat] = BeatWidths[srcBeat] ;
	BeatCenters[destBeat] = BeatCenters[srcBeat] ;
	for(i = 0; i < MAXPREV; ++i)
		{
		PostClass[destBeat*i] = PostClass[srcBeat*i] ;
		PCRhythm[destBeat*i] = PCRhythm[srcBeat*i] ;
		}

	BeatClassifications[destBeat] = BeatClassifications[srcBeat] ;
	BeatBegins[destBeat] = BeatBegins[srcBeat] ;
	BeatEnds[destBeat] = BeatBegins[srcBeat] ;
	BeatsSinceLastMatch[destBeat] = BeatsSinceLastMatch[srcBeat];
	BeatAmps[destBeat] = BeatAmps[srcBeat] ;

	// Adjust data in dominant beat monitor.

	AdjustDomData(srcBeat,destBeat) ;
	}

/********************************************************************
	Minimum beat variation returns a 1 if the previous eight beats
	have all had similarity indexes less than 0.5.
*********************************************************************/

int MinimumBeatVariation(int type)
	{
	int i ;
	for(i = 0; i < MAXTYPES; ++i) {
            if (MIs[type * i] > 0.5) {
                i = MAXTYPES + 2;
            }
        }
	if(i == MAXTYPES) {
            return 1;
        }
	else {
            return 0;
        }
	}

/**********************************************************************
	WideBeatVariation returns true if the average similarity index
	for a given beat type to its template is greater than WIDE_VAR_LIMIT.
***********************************************************************/



int WideBeatVariation(int type)
	{
	int i, n ;
	double aveMI ;

	n = BeatCounts[type] ;
	if(n > 8) {
            n = 8;
        }

	for(i = 0, aveMI = 0; i <n; ++i) {
            aveMI += MIs[type * i];
        }

	aveMI /= n ;
	if(aveMI > WIDE_VAR_LIMIT) {
            return 1;
        }
	else {
            return 0;
        }
	}






/*****************************************************************************
	RhythmChk() takes an R-to-R interval as input and, based on previous R-to-R
	intervals, classifys the interval as NORMAL, PVC, or UNKNOWN.
******************************************************************************/

int RhythmChk(int rr)
	{
	int i, regular = 1 ;
	int NNEst = 0, NVEst  = 0;

	BigeminyFlag = 0 ;

	// Wait for at least 4 beats before classifying anything.

	if(BeatCount < 4)
		{
		if(++BeatCount == 4) {
                ClassifyState = READY;
            }
		}

	// Stick the new RR interval into the RR interval Buffer.

	for(i = RBB_LENGTH-1; i > 0; --i)
		{
		RRBuffer[i] = RRBuffer[i-1] ;
		RRTypes[i] = RRTypes[i-1] ;
		}

	RRBuffer[0] = rr ;

	if(ClassifyState == LEARNING)
		{
		RRTypes[0] = QQ ;
		return(UNKNOWN) ;
		}

	// If we couldn't tell what the last interval was...

	if(RRTypes[1] == QQ)
		{
		for(i = 0, regular = 1; i < 3; ++i) {
                if (RRMatch(RRBuffer[i], RRBuffer[i + 1]) == 0) {
                    regular = 0;
                }
            }

		// If this, and the last three intervals matched, classify
		// it as Normal-Normal.

		if(regular == 1)
			{
			RRTypes[0] = NN ;
			return(NORMAL) ;
			}

		// Check for bigeminy.
		// Call bigeminy if every other RR matches and
		// consecutive beats do not match.

		for(i = 0, regular = 1; i < 6; ++i) {
                if (RRMatch(RRBuffer[i], RRBuffer[i + 2]) == 0) {
                    regular = 0;
                }
            }
		for(i = 0; i < 6; ++i) {
                if (RRMatch(RRBuffer[i], RRBuffer[i + 1]) != 0) {
                    regular = 0;
                }
            }

		if(regular == 1)
			{
			BigeminyFlag = 1 ;
			if(RRBuffer[0] < RRBuffer[1])
				{
				RRTypes[0] = NV ;
				RRTypes[1] = VN ;
				return(PVC) ;
				}
			else
				{
				RRTypes[0] = VN ;
				RRTypes[1] = NV ;
				return(NORMAL) ;
				}
			}

		// Check for NNVNNNV pattern.

		if(RRShort(RRBuffer[0],RRBuffer[1])!=0 && RRMatch(RRBuffer[1],RRBuffer[2])!=0
			&& RRMatch(RRBuffer[2]*2,RRBuffer[3]+RRBuffer[4])!=0 &&
			RRMatch(RRBuffer[4],RRBuffer[0])!=0 && RRMatch(RRBuffer[5],RRBuffer[2])!=0)
			{
			RRTypes[0] = NV ;
			RRTypes[1] = NN ;
			return(PVC) ;
			}

		// If the interval is not part of a
		// bigeminal or regular pattern, give up.

		else
			{
			RRTypes[0] = QQ ;
			return(UNKNOWN) ;
			}
		}

	// If the previous two beats were normal...

	else if(RRTypes[1] == NN)
		{

		if(RRShort2(RRBuffer,RRTypes)!=0)
			{
			if(RRBuffer[1] < BRADY_LIMIT)
				{
				RRTypes[0] = NV ;
				return(PVC) ;
				}
			else {
                    RRTypes[0] = QQ;
                }
				return(UNKNOWN) ;
			}


		// If this interval matches the previous interval, then it
		// is regular.

		else if(RRMatch(RRBuffer[0],RRBuffer[1])!=0)
			{
			RRTypes[0] = NN ;
			return(NORMAL) ;
			}

		// If this interval is short..

		else if(RRShort(RRBuffer[0],RRBuffer[1])!=0)
			{

			// But matches the one before last and the one before
			// last was NN, this is a normal interval.

			if(RRMatch(RRBuffer[0],RRBuffer[2])!=0 && (RRTypes[2] == NN))
				{
				RRTypes[0] = NN ;
				return(NORMAL) ;
				}

			// If the rhythm wasn't bradycardia, call it a PVC.

			else if(RRBuffer[1] < BRADY_LIMIT)
				{
				RRTypes[0] = NV ;
				return(PVC) ;
				}

			// If the regular rhythm was bradycardia, don't assume that
			// it was a PVC.

			else
				{
				RRTypes[0] = QQ ;
				return(UNKNOWN) ;
				}
			}

		// If the interval isn't normal or short, then classify
		// it as normal but don't assume normal for future
		// rhythm classification.

		else
			{
			RRTypes[0] = QQ ;
			return(NORMAL) ;
			}
		}

	// If the previous beat was a PVC...

	else if(RRTypes[1] == NV)
		{

		if(RRShort2(RRBuffer,RRTypes)!=0)
			{
	/*		if(RRMatch2(RRBuffer[0],RRBuffer[1]))
				{
				RRTypes[0] = VV ;
				return(PVC) ;
				} */

			if(RRMatch(RRBuffer[0],RRBuffer[1])!=0)
				{
				RRTypes[0] = NN ;
				RRTypes[1] = NN ;
				return(NORMAL) ;
				}
			else if(RRBuffer[0] > RRBuffer[1])
				{
				RRTypes[0] = VN ;
				return(NORMAL) ;
				}
			else
				{
				RRTypes[0] = QQ ;
				return(UNKNOWN) ;
				}


			}

		// If this interval matches the previous premature
		// interval assume a ventricular couplet.

		else if(RRMatch(RRBuffer[0],RRBuffer[1])!=0)
			{
			RRTypes[0] = VV ;
			return(PVC) ;
			}

		// If this interval is larger than the previous
		// interval, assume that it is NORMAL.

		else if(RRBuffer[0] > RRBuffer[1])
			{
			RRTypes[0] = VN ;
			return(NORMAL) ;
			}

		// Otherwise don't make any assumputions about
		// what this interval represents.

		else
			{
			RRTypes[0] = QQ ;
			return(UNKNOWN) ;
         }
		}

	// If the previous beat followed a PVC or couplet etc...

	else if(RRTypes[1] == VN)
		{

		// Find the last NN interval.

		for(i = 2; (RRTypes[i] != NN) && (i < RBB_LENGTH); ++i) {
                if (i != RBB_LENGTH) {
                    NNEst = RRBuffer[i];
                    if (RRMatch(RRBuffer[0], NNEst) != 0) {
                        RRTypes[0] = NN;
                        return NORMAL;
                    }
                } else {
                    NNEst = 0;
                }
            }
		for(i = 2; (RRTypes[i] != NV) && (i < RBB_LENGTH); ++i) {
                if (i != RBB_LENGTH) {
                    NVEst = RRBuffer[i];
                } else {
                    NVEst = 0;
                }
            }
		if((NNEst == 0) && (NVEst != 0)) {
                NNEst = (RRBuffer[1] + NVEst) >> 1;
            }

		// NNEst is either the last NN interval or the average
		// of the most recent NV and VN intervals.

		// If the interval is closer to NN than NV, try
		// matching to NN.

		if(((NVEst != 0)==true) &&
			((Math.abs(NNEst - RRBuffer[0]) < Math.abs(NVEst - RRBuffer[0]))==true) &&
			RRMatch(NNEst,RRBuffer[0])!=0)
			{
			RRTypes[0] = NN ;
			return(NORMAL) ;
			}

		// If this interval is closer to NV than NN, try
		// matching to NV.

		else if(((NVEst != 0)==true) &&
			(((Math.abs(NNEst - RRBuffer[0]) > Math.abs(NVEst - RRBuffer[0])))==true) &&
			(RRMatch(NVEst,RRBuffer[0])!=0))
			{
			RRTypes[0] = NV ;
			return(PVC) ;
			}

		// If equally close, or we don't have an NN or NV in the buffer,
		// who knows what it is.

		else
			{
			RRTypes[0] = QQ ;
			return(UNKNOWN) ;
			}
		}

	// Otherwise the previous interval must have been a VV

	else
		{

		// Does this match previous VV.

		if(RRMatch(RRBuffer[0],RRBuffer[1])!=0)
			{
			RRTypes[0] = VV ;
			return(PVC) ;
			}

		// If this doesn't match a previous VV interval, assume
		// any new interval is recovery to Normal beat.

		else
			{
			if(RRShort(RRBuffer[0],RRBuffer[1])!=0)
				{
				RRTypes[0] = QQ ;
				return(UNKNOWN) ;
				}
			else
				{
				RRTypes[0] = VN ;
				return(NORMAL) ;
				}
			}
		}
	}


/***********************************************************************
	RRMatch() test whether two intervals are within 12.5% of their mean.
************************************************************************/

int RRMatch(int rr0,int rr1)
	{
	if(Math.abs(rr0-rr1) < ((rr0+rr1)>>3)) {
            return 1;
        }
	else {
            return 0;
        }
	}

/************************************************************************
	RRShort() tests whether an interval is less than 75% of the previous
	interval.
*************************************************************************/

int RRShort(int rr0, int rr1)
	{
	if(rr0 < rr1-(rr1>>2)) {
            return 1;
        }
	else {
            return 0;
        }
	}

/*************************************************************************
	IsBigeminy() allows external access to the bigeminy flag to check whether
	a bigeminal rhythm is in progress.
**************************************************************************/

int IsBigeminy()
	{
	return(BigeminyFlag) ;
	}

/**************************************************************************
 Check for short interval in very regular rhythm.
**************************************************************************/

int RRShort2(int[] rrIntervals, int[] rrTypes)
	{
	int rrMean = 0, i, nnCount ;

	for(i = 1, nnCount = 0; (i < 7) && (nnCount < 4); ++i) {
            if (rrTypes[i] == NN) {
                ++nnCount;
                rrMean += rrIntervals[i];
            }
        }

	// Return if there aren't at least 4 normal intervals.

	if(nnCount != 4) {
            return 0;
        }
	rrMean >>= 2 ;


	for(i = 1, nnCount = 0; (i < 7) && (nnCount < 4); ++i) {
            if (rrTypes[i] == NN) {
                if (Math.abs(rrMean - rrIntervals[i]) > (rrMean >> 4)) {
                    i = 10;
                }
            }
        }

	if((i < 9) && (rrIntervals[0] < (rrMean - (rrMean>>3)))) {
            return 1;
        }
	else {
            return 0;
        }
	}

int RRMatch2(int rr0,int rr1)
	{
	if(Math.abs(rr0-rr1) < ((rr0+rr1)>>4)) {
            return 1;
        }
	else {
            return 0;
        }
	}
int IsoCheck(int[] data, int isoLength)
	{
	int i, max, min ;

	for(i = 1, max=min = data[0]; i < isoLength; ++i)
		{
		if(data[i] > max) {
                max = data[i];
            }
		else if(data[i] < min) {
                min = data[i];
            }
		}

	if(max - min < ISO_LIMIT) {
            return 1;
        }
   return(0) ;
	}

/**********************************************************************
	AnalyzeBeat takes a beat buffer as input and returns (via pointers)
	estimates of the QRS onset, QRS offset, polarity, isoelectric level
	beat beginning (P-wave onset), and beat ending (T-wave offset).
	Analyze Beat assumes that the beat has been sampled at 100 Hz, is
	BEATLGTH long, and has an R-wave location of roughly FIDMARK.

	Note that beatBegin is the number of samples before FIDMARK that
	the beat begins and beatEnd is the number of samples after the
	FIDMARK that the beat ends.
************************************************************************/



void AnalyzeBeat(int[] beat, int[] onset, int[] offset, int[] isoLevel,
	int[] beatBegin, int[] beatEnd, int[] amp)
	{
	int maxSlope = 0, maxSlopeI, minSlope = 0, minSlopeI  ;
	int maxV, minV ;
	int isoStart = 0, isoEnd  = 0;
	int slope, i ;

	// Search back from the fiducial mark to find the isoelectric
	// region preceeding the QRS complex.

	for(i = FIDMARK-ISO_LENGTH2; (i > 0) && (IsoCheck(beat,ISO_LENGTH2) == 0); --i) {
            if (i == 0) {
                for (i = FIDMARK - ISO_LENGTH1; (i > 0) && (IsoCheck(beat, ISO_LENGTH1) == 0); --i) {
                    isoStart = i + (ISO_LENGTH1 - 1);
                }
            } else {
                isoStart = i + (ISO_LENGTH2 - 1);
            }
        }

	// Search forward from the R-wave to find an isoelectric region following
	// the QRS complex.

	for(i = FIDMARK; (i < BEATLGTH) && (IsoCheck(beat,ISO_LENGTH1) == 0); ++i) {
            isoEnd = i;
        }

	// Find the maximum and minimum slopes on the
	// QRS complex.

	i = FIDMARK-BEAT_MS150 ;
	maxSlope = maxSlope = beat[i] - beat[i-1] ;
	maxSlopeI = minSlopeI = i ;

	for(; i < FIDMARK+BEAT_MS150; ++i)
		{
		slope = beat[i] - beat[i-1] ;
		if(slope > maxSlope)
			{
			maxSlope = slope ;
			maxSlopeI = i ;
			}
		else if(slope < minSlope)
			{
			minSlope = slope ;
			minSlopeI = i ;
			}
		}

	// Use the smallest of max or min slope for search parameters.

	if(maxSlope > -minSlope) {
            maxSlope = -minSlope;
        }
	else {
            minSlope = -maxSlope;
        }

	if(maxSlopeI < minSlopeI)
		{

		// Search back from the maximum slope point for the QRS onset.

		for(i = maxSlopeI;
			(i > 0) && ((beat[i]-beat[i-1]) > (maxSlope >> 2)); --i) {
                onset[0] = i - 1;
            }

		// Check to see if this was just a brief inflection.

		for(; (i > onset[0]-INF_CHK_N) && ((beat[i]-beat[i-1]) <= (maxSlope >>2)); --i) {
                if (i > onset[0] - INF_CHK_N) {
                    for (; (i > 0) && ((beat[i] - beat[i - 1]) > (maxSlope >> 2)); --i) {
                        onset[0] = i - 1;
                    }
                }
            }
		i = onset[i++] ;

		// Check to see if a large negative slope follows an inflection.
		// If so, extend the onset a little more.

		for(;(i > onset[0]-INF_CHK_N) && ((beat[i-1]-beat[i]) < (maxSlope>>2)); --i) {
                if (i > onset[0] - INF_CHK_N) {
                    for (; (i > 0) && ((beat[i - 1] - beat[i]) > (maxSlope >> 2)); --i) {
                        onset[0] = i - 1;
                    }
                }
            }

		// Search forward from minimum slope point for QRS offset.

		for(i = minSlopeI;
			(i < BEATLGTH) && ((beat[i] - beat[i-1]) < (minSlope >>2)); ++i) {
                offset[0] = i;
            }

		// Make sure this wasn't just an inflection.

		for(; (i < offset[0]+INF_CHK_N) && ((beat[i]-beat[i-1]) >= (minSlope>>2)); ++i) {
                if (i < (offset[0] + INF_CHK_N)) {
                    for (; (i < BEATLGTH) && ((beat[i] - beat[i - 1]) < (minSlope >> 2)); ++i) {
                        offset[0] = i;
                    }
                }
            }
		i = offset[0] ;

		// Check to see if there is a significant upslope following
		// the end of the down slope.

		for(;(i < offset[0]+BEAT_MS40) && ((beat[i-1]-beat[i]) > (minSlope>>2)); ++i) {
                if (i < offset[0] + BEAT_MS40) {
                    for (; (i < BEATLGTH) && ((beat[i - 1] - beat[i]) < (minSlope >> 2)); ++i) {
                        offset[0] = i;
                    }
                    for (; (i < offset[0] + BEAT_MS60) && (beat[i] - beat[i - 1] > (minSlope >> 2)); ++i) {
                        if (i < offset[0] + BEAT_MS60) {
                            for (; (i < BEATLGTH) && (beat[i] - beat[i - 1] < (minSlope >> 2)); ++i) {
                                offset[0] = i;
                            }
                        }
                    }
                }
            }
		}

	else
		{

		// Search back from the minimum slope point for the QRS onset.

		for(i = minSlopeI;
			(i > 0) && ((beat[i]-beat[i-1]) < (minSlope >> 2)); --i) {
                onset[0] = i - 1;
            }

		// Check to see if this was just a brief inflection.

		for(; (i > onset[0]-INF_CHK_N) && ((beat[i]-beat[i-1]) >= (minSlope>>2)); --i) {
                if (i > onset[0] - INF_CHK_N) {
                    for (; (i > 0) && ((beat[i] - beat[i - 1]) < (minSlope >> 2)); --i) {
                        onset[0] = i - 1;
                    }
                }
            }
		i = onset[i++] ;

		// Check for significant positive slope after a turning point.

		for(;(i > onset[0]-INF_CHK_N) && ((beat[i-1]-beat[i]) > (minSlope>>2)); --i) {
                if (i > onset[0] - INF_CHK_N) {
                    for (; (i > 0) && ((beat[i - 1] - beat[i]) < (minSlope >> 2)); --i) {
                        onset[0] = i - 1;
                    }
                }
            }

		// Search forward from maximum slope point for QRS offset.

		for(i = maxSlopeI;
			(i < BEATLGTH) && ((beat[i] - beat[i-1]) > (maxSlope >>2)); ++i) {
                offset[0] = i;
            }

		// Check to see if this was just a brief inflection.

		for(; (i < offset[0]+INF_CHK_N) && ((beat[i] - beat[i-1]) <= (maxSlope >> 2)); ++i) {
                if ((i < offset[0] + INF_CHK_N) == true) {
                    for (; (i < BEATLGTH) && ((beat[i] - beat[i - 1]) > (maxSlope >> 2)); ++i) {
                        offset[0] = i;
                    }
                }
            }
		i = offset[0] ;

		// Check to see if there is a significant downslope following
		// the end of the up slope.

		for(;(i < offset[0]+BEAT_MS40) && ((beat[i-1]-beat[i]) < (maxSlope>>2)); ++i) {
                if (i < offset[0] + BEAT_MS40) {
                    for (; (i < BEATLGTH) && ((beat[i - 1] - beat[i]) > (maxSlope >> 2)); ++i) {
                        offset[0] = i;
                    }
                }
            }
		}

	// If the estimate of the beginning of the isoelectric level was
	// at the beginning of the beat, use the slope based QRS onset point
	// as the iso electric point.

	if((isoStart == ISO_LENGTH1-1)&& (onset[0] > isoStart)) {
            isoStart = onset[0];
        }

	// Otherwise, if the isoelectric start and the slope based points
	// are close, use the isoelectric start point.

	else if(onset[0]-isoStart < BEAT_MS50) {
            onset[0] = isoStart;
        }

	// If the isoelectric end and the slope based QRS offset are close
	// use the isoelectic based point.

	if(isoEnd - offset[0] < BEAT_MS50) {
            offset[0] = isoEnd;
        }

	isoLevel[0] = beat[isoStart] ;


	// Find the maximum and minimum values in the QRS.

	for(i = onset[0], maxV = minV = beat[onset[0]]; i < offset[0]; ++i) {
            if (beat[i] > maxV) {
                maxV = beat[i];
            } else if (beat[i] < minV) {
                minV = beat[i];
            }
        }

	// If the offset is significantly below the onset and the offset is
	// on a negative slope, add the next up slope to the width.

	if((beat[onset[0]]-beat[offset[0]] > ((maxV-minV)>>2)+((maxV-minV)>>3)))
		{

		// Find the maximum slope between the finish and the end of the buffer.

		for(i = maxSlopeI = offset[0], maxSlope = beat[offset[0]] - beat[offset[i--]];
			(i < offset[0]+BEAT_MS100) && (i < BEATLGTH); ++i)
			{
			slope = beat[i]-beat[i-1] ;
			if(slope > maxSlope)
				{
				maxSlope = slope ;
				maxSlopeI = i ;
				}
			}

		// Find the new offset.

		if(maxSlope > 0)
			{
			for(i = maxSlopeI;
				(i < BEATLGTH) && (beat[i]-beat[i-1] > (maxSlope>>1)); ++i) {
                    offset[0] = i;
                }
			}
		}

	// Determine beginning and ending of the beat.
	// Search for an isoelectric region that precedes the R-wave.
	// by at least 250 ms.

	for(i = FIDMARK-BEAT_MS250;
		(i >= BEAT_MS80) && (IsoCheck( beat,BEAT_MS80) == 0); --i) {
            beatBegin[0] = i;
        }

	// If there was an isoelectric section at 250 ms before the
	// R-wave, search forward for the isoelectric region closest
	// to the R-wave.  But leave at least 50 ms between beat begin
	// and onset, or else normal beat onset is within PVC QRS complexes.
	// that screws up noise estimation.

	if(beatBegin[0] == FIDMARK-BEAT_MS250)
		{
		for(; (i < onset[0]-BEAT_MS50) &&
			(IsoCheck(beat,BEAT_MS80) == 1); ++i) {
                beatBegin[0] = i - 1;
            }
		}

	// Rev 1.1
	else if(beatBegin[0] == BEAT_MS80 - 1)
		{
		for(; (i < onset[0]) && (IsoCheck(beat,BEAT_MS80) == 0); ++i) {
                if (i < onset[0]) {
                    for (; (i < onset[0]) && (IsoCheck(beat, BEAT_MS80) == 1); ++i) {
                        if (i < onset[0]) {
                            beatBegin[0] = i - 1;
                        }
                    }
                }
            }
		}

	// Search for the end of the beat as the first isoelectric
	// segment that follows the beat by at least 300 ms.

	for(i = FIDMARK+BEAT_MS300;
		(i < BEATLGTH) && (IsoCheck(beat,BEAT_MS80) == 0); ++i) {
	beatEnd[0] = i ;

	// If the signal was isoelectric at 300 ms. search backwards.
/*	if(*beatEnd == FIDMARK+30)
		{
		for(; (i > *offset) && (IsoCheck(&beat[i],8) != 0); --i) ;
		*beatEnd = i ;
		}
*/
	// Calculate beat amplitude.

	maxV=minV=beat[onset[0]] ;
	for(i = onset[0]; i < offset[0]; ++i) {
                if (beat[i] > maxV) {
                    maxV = beat[i];
                } else if (beat[i] < minV) {
                    minV = beat[i];
                }
            }
	amp[0] = maxV-minV ;

	}}

int Classify(int[] newBeat,int rr, int noiseLevel, int[] beatMatch, int[] fidAdj,
	int init)
	{
	int[] rhythmClass=new int[1];int beatClass, i, beatWidth, blShift ;
     int[] morphType=new int [1];
     int runCount = 0;
	double[] matchIndex=new double[1], domIndex=new double[1], mi2=new double[1] ;
	int[] shiftAdj=new int[1] ;
	int[] domType=new int[1], domWidth=new int[1], onset=new int[1], offset=new int[1], amp=new int[1] ;
	int[] beatBegin=new int[1], beatEnd=new int[1];int[] tempClass=new int[1] ;
	int[] hfNoise=new int[1], isoLevel=new int[1] ;
 int lastIsoLevel=0;
 int lastRhythmClass = UNKNOWN;
 int lastBeatWasNew = 0 ;

	// If initializing...

	if(init!=0)
		{
		ResetRhythmChk() ;
		ResetMatch() ;
		ResetPostClassify() ;
		runCount = 0 ;
		DomMonitor(0, 0, 0, 0, 1) ;
		return(0) ;
		}

	hfNoise[0] = HFNoiseCheck(newBeat) ;	// Check for muscle noise.
	rhythmClass[0] = RhythmChk(rr) ;			// Check the rhythm.

	// Estimate beat features.

	AnalyzeBeat(newBeat, onset, offset, isoLevel,
		beatBegin, beatEnd, amp) ;

	blShift = Math.abs(lastIsoLevel-isoLevel[0]) ;
	lastIsoLevel = isoLevel[0] ;

	// Make isoelectric level 0.

	for(i = 0; i < BEATLGTH; ++i) {
                newBeat[i] -= isoLevel[0];
            }

	// If there was a significant baseline shift since
	// the last beat and the last beat was a new type,
	// delete the new type because it might have resulted
	// from a baseline shift.

	if( (blShift > BL_SHIFT_LIMIT)
		&& (lastBeatWasNew == 1)
		&& (lastRhythmClass == NORMAL)
		&& (rhythmClass[0] == NORMAL) ) {
                ClearLastNewType();
            }

	lastBeatWasNew = 0 ;

	// Find the template that best matches this beat.

	BestMorphMatch(newBeat,morphType,matchIndex,mi2,shiftAdj) ;

	// Disregard noise if the match is good. (New)

	if(matchIndex[0] < MATCH_NOISE_THRESHOLD) {
                hfNoise[0] = noiseLevel = blShift = 0;
            }

	// Apply a stricter match limit to premature beats.

	if((matchIndex[0] < MATCH_LIMIT) && (rhythmClass[0] == PVC) &&
		MinimumBeatVariation(morphType[0])!=0 && (mi2[0] > PVC_MATCH_WITH_AMP_LIMIT))
		{
		setMorphType(NewBeatType(newBeat)) ;
		lastBeatWasNew = 1 ;
		}

	// Match if within standard match limits.

	else if((matchIndex[0] < MATCH_LIMIT) && (mi2[0] <= MATCH_WITH_AMP_LIMIT)) {
                UpdateBeatType(morphType[0], newBeat, mi2[0], shiftAdj[0]);
            }

	// If the beat isn't noisy but doesn't match, start a new beat.

	else if((blShift < BL_SHIFT_LIMIT) && (noiseLevel < NEW_TYPE_NOISE_THRESHOLD)
		&& (hfNoise[0] < NEW_TYPE_HF_NOISE_LIMIT))
		{
		setMorphType(NewBeatType(newBeat)) ;
		lastBeatWasNew = 1 ;
		}

	// Even if it is a noisy, start new beat if it was an irregular beat.

	else if((lastRhythmClass != NORMAL) || (rhythmClass[0] != NORMAL))
		{
		setMorphType(NewBeatType(newBeat)) ;
		lastBeatWasNew = 1 ;
		}

	// If its noisy and regular, don't waste space starting a new beat.

	else {
                morphType[0] = MAXTYPES;
            }

	// Update recent rr and type arrays.

	for(i = 7; i > 0; --i)
		{
		getRecentRRs()[i] = getRecentRRs()[i-1] ;
		getRecentTypes()[i] = getRecentTypes()[i-1] ;
		}
	getRecentRRs()[0] = rr ;
	RecentTypes[0] = morphType[0] ;

	lastRhythmClass = rhythmClass[0] ;
	lastIsoLevel = isoLevel[0] ;

	// Fetch beat features needed for classification.
	// Get features from average beat if it matched.

	if(morphType[0] != MAXTYPES)
		{
		beatClass = GetBeatClass(getMorphType()) ;
		beatWidth = GetBeatWidth(getMorphType()) ;
		fidAdj[0] = GetBeatCenter(getMorphType())-FIDMARK ;

		// If the width seems large and there have only been a few
		// beats of this type, use the actual beat for width
		// estimate.

		if((beatWidth > offset[0]-onset[0]) && (GetBeatTypeCount( morphType[0]) <= 4))
			{
			beatWidth = offset[0]-onset[0] ;
			fidAdj[0] = ((offset[0]+onset[0])/2)-FIDMARK ;
			}
		}

	// If this beat didn't match get beat features directly
	// from this beat.

	else
		{
		beatWidth = offset[0]-onset[0] ;
		beatClass = UNKNOWN ;
		fidAdj[0] = ((offset[0]+onset[0])/2)-FIDMARK ;
		}

	// Fetch dominant type beat features.

	DomType = domType[0] = DomMonitor( morphType[0],rhythmClass[0], beatWidth, rr, 0) ;
	domWidth[0] = GetBeatWidth(domType[0]) ;

	// Compare the beat type, or actual beat to the dominant beat.

	if((morphType[0] != domType[0]) && (morphType[0] != 8)) {
                domIndex[0] = DomCompare(morphType[0], domType[0]);
            }
	else if(morphType[0] == 8) {
                domIndex[0] = DomCompare2(newBeat, domType[0]);
            }
	else {
                domIndex = matchIndex;
            }

	// Update post classificaton of the previous beat.

	PostClassify(getRecentTypes(),domType[0], getRecentRRs(), beatWidth, domIndex[0], rhythmClass[0]) ;

	// Classify regardless of how the morphology
	// was previously classified.

	tempClass[0] = TempClass(rhythmClass[0],getMorphType(), beatWidth, domWidth[0], domType[0],
		hfNoise[0], noiseLevel, blShift, domIndex[0]) ;

	// If this morphology has not been classified yet, attempt to classify
	// it.

	if((beatClass == UNKNOWN) && (morphType[0] < MAXTYPES))
		{

		// Classify as normal if there are 6 in a row
		// or at least two in a row that meet rhythm
		// rules for normal.

		runCount = GetRunCount() ;

		// Classify a morphology as NORMAL if it is not too wide, and there
		// are three in a row.  The width criterion prevents ventricular beats
		// from being classified as normal during VTACH (MIT/BIH 205).

		if((runCount >= 3) && (domType[0] != -1) && (beatWidth < domWidth[0]+BEAT_MS20)) {
                    SetBeatClass(getMorphType(), NORMAL);
                }

		// If there is no dominant type established yet, classify any type
		// with six in a row as NORMAL.

		else if((runCount >= 6) && (domType[0] == -1)) {
                    SetBeatClass(getMorphType(), NORMAL);
                }

		// During bigeminy, classify the premature beats as ventricular if
		// they are not too narrow.

		else if(IsBigeminy() == 1)
			{
			if((rhythmClass[0] == PVC) && (beatWidth > BEAT_MS100)) {
                        SetBeatClass(getMorphType(), PVC);
                    }
			else if(rhythmClass[0] == NORMAL) {
                        SetBeatClass(getMorphType(), NORMAL);
                    }
			}
		}

	// Save morphology type of this beat for next classification.

	beatMatch[0] = getMorphType() ;

	beatClass = GetBeatClass(getMorphType()) ;

	// If the morphology has been previously classified.
	// use that classification.
  //	return(rhythmClass) ;

	if(beatClass != UNKNOWN) {
                return beatClass;
            }

	if(CheckPostClass(morphType[0]) == PVC) {
                return PVC;
            }

	// Otherwise use the temporary classification.

	return(tempClass[0]);
}
    
    /**
     * @return the morphType
     */
   
    /**
     * @param morphType the morphType to set
     */
    public void setMorphType(int morphType) {
        this.morphType = morphType;
    }

    /**
     * @return the NewDom
     */
     public int getMorphType() {
        return morphType;
    }

    public int getNewDom() {
        return NewDom;
    }

    /**
     * @param NewDom the NewDom to set
     */
    public void setNewDom(int NewDom) {
        this.NewDom = NewDom;
    }

    /**
     * @return the DomRhythm
     */
    public int getDomRhythm() {
        return DomRhythm;
    }

    /**
     * @param DomRhythm the DomRhythm to set
     */
    public void setDomRhythm(int DomRhythm) {
        this.DomRhythm = DomRhythm;
    }

    /**
     * @return the DMBeatTypes
     */
    public int[] getDMBeatTypes() {
        return DMBeatTypes;
    }

    /**
     * @param DMBeatTypes the DMBeatTypes to set
     */
    public void setDMBeatTypes(int[] DMBeatTypes) {
        this.DMBeatTypes = DMBeatTypes;
    }

    /**
     * @return the DMBeatClasses
     */
    public int[] getDMBeatClasses() {
        return DMBeatClasses;
    }

    /**
     * @param DMBeatClasses the DMBeatClasses to set
     */
    public void setDMBeatClasses(int[] DMBeatClasses) {
        this.DMBeatClasses = DMBeatClasses;
    }

    /**
     * @return the DMBeatRhythms
     */
    public int[] getDMBeatRhythms() {
        return DMBeatRhythms;
    }

    /**
     * @param DMBeatRhythms the DMBeatRhythms to set
     */
    public void setDMBeatRhythms(int[] DMBeatRhythms) {
        this.DMBeatRhythms = DMBeatRhythms;
    }

    /**
     * @return the DMNormCounts
     */
    public int[] getDMNormCounts() {
        return DMNormCounts;
    }

    /**
     * @param DMNormCounts the DMNormCounts to set
     */
    public void setDMNormCounts(int[] DMNormCounts) {
        this.DMNormCounts = DMNormCounts;
    }

    /**
     * @return the DMBeatCounts
     */
    public int[] getDMBeatCounts() {
        return DMBeatCounts;
    }

    /**
     * @param DMBeatCounts the DMBeatCounts to set
     */
    public void setDMBeatCounts(int[] DMBeatCounts) {
        this.DMBeatCounts = DMBeatCounts;
    }

    /**
     * @return the DMIrregCount
     */
    public int getDMIrregCount() {
        return DMIrregCount;
    }

    /**
     * @param DMIrregCount the DMIrregCount to set
     */
    public void setDMIrregCount(int DMIrregCount) {
        this.DMIrregCount = DMIrregCount;
    }
 public int[] getPostClass() {
        return PostClass;
    }

    /**
     * @param PostClass the PostClass to set
     */
    public void setPostClass(int[] PostClass) {
        this.PostClass = PostClass;
    }

    /**
     * @return the BeatBegins
     */
    public int[] getBeatBegins() {
        return BeatBegins;
    }

    /**
     * @param BeatBegins the BeatBegins to set
     */
    public void setBeatBegins(int[] BeatBegins) {
        this.BeatBegins = BeatBegins;
    }

    /**
     * @return the BeatsSinceLastMatch
     */
    public int[] getBeatsSinceLastMatch() {
        return BeatsSinceLastMatch;
    }

    /**
     * @param BeatsSinceLastMatch the BeatsSinceLastMatch to set
     */
    public void setBeatsSinceLastMatch(int[] BeatsSinceLastMatch) {
        this.BeatsSinceLastMatch = BeatsSinceLastMatch;
    }

    /**
     * @return the BeatEnds
     */
    public int[] getBeatEnds() {
        return BeatEnds;
    }

    /**
     * @param BeatEnds the BeatEnds to set
     */
    public void setBeatEnds(int[] BeatEnds) {
        this.BeatEnds = BeatEnds;
    }

    /**
     * @return the BeatAmps
     */
    public int[] getBeatAmps() {
        return BeatAmps;
    }

    /**
     * @param BeatAmps the BeatAmps to set
     */
    public void setBeatAmps(int[] BeatAmps) {
        this.BeatAmps = BeatAmps;
    }

    /**
     * @return the BeatCenters
     */
    public int[] getBeatCenters() {
        return BeatCenters;
    }

    /**
     * @param BeatCenters the BeatCenters to set
     */
    public void setBeatCenters(int[] BeatCenters) {
        this.BeatCenters = BeatCenters;
    }

    /**
     * @return the MIs
     */
    public double[] getMIs() {
        return MIs;
    }

    /**
     * @param MIs the MIs to set
     */
    public void setMIs(double[] MIs) {
        this.MIs = MIs;
    }

int HFNoiseCheck(int[] beat)
	{
	int maxNoiseAve = 0, i ;
	int sum=0;
        int[] aveBuff=new int[AVELENGTH];
        int avePtr = 0 ;
	int qrsMax = 0;int qrsMin = 0 ;

	// Determine the QRS amplitude.

	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] =Math.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;
        }
	}

/************************************************************************
*  TempClass() classifies beats based on their beat features, relative
*  to the features of the dominant beat and the present noise level.
*************************************************************************/

int TempClass(int rhythmClass, int morphType,
	int beatWidth, int domWidth, int domType,
	int hfNoise, int noiseLevel, int blShift, double domIndex)
	{

	// Rule 1:  If no dominant type has been detected classify all
	// beats as UNKNOWN.

	if(domType < 0) {
            return UNKNOWN;
        }

	// Rule 2:  If the dominant rhythm is normal, the dominant
	// beat type doesn't vary much, this beat is premature
	// and looks sufficiently different than the dominant beat
	// classify as PVC.

	if(MinimumBeatVariation(domType)!=0 && (rhythmClass == PVC)
		&& (domIndex > R2_DI_THRESHOLD) && (GetDomRhythm() == 1)) {
            return PVC;
        }

	// Rule 3:  If the beat is sufficiently narrow, classify as normal.

	if(beatWidth < R3_WIDTH_THRESHOLD) {
            return NORMAL;
        }

	// Rule 5:  If the beat cannot be matched to any previously
	// detected morphology and it is not premature, consider it normal
	// (probably noisy).

	if((morphType == MAXTYPES) && (rhythmClass != PVC)) {
            return NORMAL;
        }

	// Rule 6:  If the maximum number of beat types have been stored,
	// this beat is not regular or premature and only one
	// beat of this morphology has been seen, call it normal (probably
	// noisy).

	if((GetTypesCount() == MAXTYPES) && (GetBeatTypeCount(morphType)==1)
			 && (rhythmClass == UNKNOWN)) {
            return NORMAL;
        }

	// Rule 7:  If this beat looks like the dominant beat and the
	// rhythm is regular, call it normal.

	if((domIndex < R7_DI_THRESHOLD) && (rhythmClass == NORMAL)) {
            return NORMAL;
        }

	// Rule 8:  If post classification rhythm is normal for this
	// type and its shape is close to the dominant shape, classify
	// as normal.

	if((domIndex < R8_DI_THRESHOLD) && (CheckPCRhythm(morphType) == NORMAL)) {
            return NORMAL;
        }

	// Rule 9:  If the beat is not premature, it looks similar to the dominant
	// beat type, and the dominant beat type is variable (noisy), classify as
	// normal.

	if((domIndex < R9_DI_THRESHOLD) && (rhythmClass != PVC)==true && WideBeatVariation(domType)!=0) {
            return NORMAL;
        }

	// Rule 10:  If this beat is significantly different from the dominant beat
	// there have previously been matching beats, the post rhythm classification
	// of this type is PVC, and the dominant rhythm is regular, classify as PVC.

	if((domIndex > R10_DI_THRESHOLD)
		&& (GetBeatTypeCount(morphType) >= R10_BC_LIM) &&
		(CheckPCRhythm(morphType) == PVC) && (GetDomRhythm() == 1)) {
            return PVC;
        }

	// Rule 11: if the beat is wide, wider than the dominant beat, doesn't
	// appear to be noisy, and matches a previous type, classify it as
	// a 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)) {
            return PVC;
        }

	// Rule 12:  If the dominant rhythm is regular and this beat is premature
	// then classify as PVC.

	if((rhythmClass == PVC) && (GetDomRhythm() == 1)) {
            return PVC;
        }

	// Rule 14:  If the beat is regular and the dominant rhythm is regular
	// call the beat normal.

	if((rhythmClass == NORMAL) && (GetDomRhythm() == 1)) {
            return NORMAL;
        }

	// By this point, we know that rhythm will not help us, so we
	// have to classify based on width and similarity to the dominant
	// beat type.

	// Rule 15: If the beat is wider than normal, wide on an
	// absolute scale, and significantly different from the
	// dominant beat, call it a PVC.

	if((beatWidth > domWidth) && (domIndex > R15_DI_THRESHOLD) &&
		(beatWidth >= R15_WIDTH_THRESHOLD)) {
            return PVC;
        }

	// Rule 16:  If the beat is sufficiently narrow, call it normal.

	if(beatWidth < R16_WIDTH_THRESHOLD) {
            return NORMAL;
        }

	// Rule 17:  If the beat isn't much wider than the dominant beat
	// call it normal.

	if(beatWidth < domWidth + R17_WIDTH_DELTA) {
            return NORMAL;
        }

	// If the beat is noisy but reasonably close to dominant,
	// call it normal.

	// Rule 18:  If the beat is similar to the dominant beat, call it normal.

	if(domIndex < R18_DI_THRESHOLD) {
            return NORMAL;
        }

	// If it's noisy don't trust the width.

	// Rule 19:  If the beat is noisy, we can't trust our width estimate
	// and we have no useful rhythm information, so guess normal.

	if(hfNoise > R19_HF_THRESHOLD) {
            return NORMAL;
        }

	// Rule 20:  By this point, we have no rhythm information, the beat
	// isn't particularly narrow, the beat isn't particulary similar to
	// the dominant beat, so guess a PVC.

	return(PVC) ;

	}
int DomMonitor(int morphType, int rhythmClass, int beatWidth, int rr, int reset)
	{
 int brIndex = 0 ;
	int i, oldType, runCount, dom, max ;

	// Fetch the type of the beat before the last beat.

	i = brIndex - 2 ;
	if(i < 0) {
            i += DM_BUFFER_LENGTH;
        }
	oldType = DMBeatTypes[i] ;

	// If reset flag is set, reset beat type counts and
	// beat information buffers.

	if(reset != 0)
		{
		for(i = 0; i < DM_BUFFER_LENGTH; ++i)
			{
			DMBeatTypes[i] = -1 ;
			DMBeatClasses[i] = 0 ;
			}

		for(i = 0; i < 8; ++i)
			{
			DMNormCounts[i] = 0 ;
			DMBeatCounts[i] = 0 ;
			}
		DMIrregCount = 0 ;
		return(0) ;
		}

	// Once we have wrapped around, subtract old beat types from
	// the beat counts.

	if((DMBeatTypes[brIndex] != -1) && (DMBeatTypes[brIndex] != MAXTYPES))
		{
		--DMBeatCounts[DMBeatTypes[brIndex]] ;
		DMNormCounts[DMBeatTypes[brIndex]] -= DMBeatClasses[brIndex] ;
		if(DMBeatRhythms[brIndex] == UNKNOWN) {
                --DMIrregCount;
            }
		}

	// If this is a morphology that has been detected before, decide
	// (for the purposes of selecting the dominant normal beattype)
	// whether it is normal or not and update the approporiate counts.

	if(morphType != 8)
		{

		// Update the buffers of previous beats and increment the
		// count for this beat type.

		DMBeatTypes[brIndex] = morphType ;
		++DMBeatCounts[morphType] ;
		DMBeatRhythms[brIndex] = rhythmClass ;

		// If the rhythm appears regular, update the regular rhythm
		// count.

		if(rhythmClass == UNKNOWN) {
                ++DMIrregCount;
            }

		// Check to see how many beats of this type have occurred in
		// a row (stop counting at six).

		i = brIndex - 1 ;
		if(i < 0) {
                i += DM_BUFFER_LENGTH;
            }
		for(runCount = 0; (DMBeatTypes[i] == morphType) && (runCount < 6); ++runCount) {
                if (--i < 0) {
                    i += DM_BUFFER_LENGTH;
                }
            }

		// If the rhythm is regular, the beat width is less than 130 ms, and
		// there have been at least two in a row, consider the beat to be
		// normal.

		if((rhythmClass == NORMAL) && (beatWidth < BEAT_MS130) && (runCount >= 1))
			{
			DMBeatClasses[brIndex] = 1 ;
			++DMNormCounts[morphType] ;
			}

		// If the last beat was within the normal P-R interval for this beat,
		// and the one before that was this beat type, assume the last beat
		// was noise and this beat is normal.

		else if(rr < ((FIDMARK-GetBeatBegin(morphType))*SAMPLE_RATE/BEAT_SAMPLE_RATE)
			&& (oldType == morphType))
			{
			DMBeatClasses[brIndex] = 1 ;
			++DMNormCounts[morphType] ;
			}

		// Otherwise assume that this is not a normal beat.

		else {
                DMBeatClasses[brIndex] = 0;
            }
		}

	// If the beat does not match any of the beat types, store
	// an indication that the beat does not match.

	else
		{
		DMBeatClasses[brIndex] = 0 ;
		DMBeatTypes[brIndex] = -1 ;
		}

	// Increment the index to the beginning of the circular buffers.

	if(++brIndex == DM_BUFFER_LENGTH) {
            brIndex = 0;
        }

	// Determine which beat type has the most beats that seem
	// normal.

	dom = 0 ;
	for(i = 1; i < 8; ++i) {
            if (DMNormCounts[i] > DMNormCounts[dom]) {
                dom = i;
            }
        }

	max = 0 ;
	for(i = 1; i < 8; ++i) {
            if (DMBeatCounts[i] > DMBeatCounts[max]) {
                max = i;
            }
        }

	// If there are no normal looking beats, fall back on which beat
	// has occurred most frequently since classification began.

	if((DMNormCounts[dom] == 0) || (DMBeatCounts[max]/DMBeatCounts[dom] >= 2)) {
            dom = GetDominantType();
        }

	// If at least half of the most frequently occuring normal
	// type do not seem normal, fall back on choosing the most frequently
	// occurring type since classification began.

	else if(DMBeatCounts[dom]/DMNormCounts[dom] >= 2) {
            dom = GetDominantType();
        }

	// If there is any beat type that has been classfied as normal,
	// but at least 10 don't seem normal, reclassify it to UNKNOWN.

	for(i = 0; i < 8; ++i) {
            if ((DMBeatCounts[i] > 10) && (DMNormCounts[i] == 0) && (i != dom) && (GetBeatClass(i) == NORMAL)) {
                SetBeatClass(i, UNKNOWN);
            }
        }

	// Save the dominant type in a global variable so that it is
	// accessable for debugging.

	NewDom = dom ;
	return(dom) ;
	}

int GetNewDominantType()
	{
	return(NewDom) ;
	}

int GetDomRhythm()
	{
	if(DMIrregCount > IRREG_RR_LIMIT) {
            return 0;
        }
	else {
            return 1;
        }
	}


void AdjustDomData(int oldType, int newType)
	{
	int i ;

	for(i = 0; i < DM_BUFFER_LENGTH; ++i)
		{
		if(DMBeatTypes[i] == oldType) {
                DMBeatTypes[i] = newType;
            }
		}

	if(newType != MAXTYPES)
		{
		DMNormCounts[newType] = DMNormCounts[oldType] ;
		DMBeatCounts[newType] = DMBeatCounts[oldType] ;
		}

	DMNormCounts[oldType] = DMBeatCounts[oldType] = 0 ;

	}

void CombineDomData(int oldType, int newType)
	{
	int i ;

	for(i = 0; i < DM_BUFFER_LENGTH; ++i)
		{
		if(DMBeatTypes[i] == oldType) {
                DMBeatTypes[i] = newType;
            }
		}

	if(newType != MAXTYPES)
		{
		DMNormCounts[newType] += DMNormCounts[oldType] ;
		DMBeatCounts[newType] += DMBeatCounts[oldType] ;
		}

	DMNormCounts[oldType] = DMBeatCounts[oldType] = 0 ;

	}

/***********************************************************************
	GetRunCount() checks how many of the present beat type have occurred
	in a row.
***********************************************************************/

int GetRunCount()
	{
	int i ;
	for(i = 1; (i < 8) && (getRecentTypes()[0] == getRecentTypes()[i]); ++i)

        {}
            return i;
	}

    /**
     * @return the MEMMOVELEN
     */
    public int getMEMMOVELEN() {
        return MEMMOVELEN;
    }

    /**
     * @param MEMMOVELEN the MEMMOVELEN to set
     */
    public void setMEMMOVELEN(int MEMMOVELEN) {
        this.MEMMOVELEN = MEMMOVELEN;
    }

    /**
     * @return the RecentRRs
     */
    public int[] getRecentRRs() {
        return RecentRRs;
    }

    /**
     * @param RecentRRs the RecentRRs to set
     */
    public void setRecentRRs(int[] RecentRRs) {
        this.RecentRRs = RecentRRs;
    }

    /**
     * @return the RecentTypes
     */
    public int[] getRecentTypes() {
        return RecentTypes;
    }

    /**
     * @param RecentTypes the RecentTypes to set
     */
    public void setRecentTypes(int[] RecentTypes) {
        this.RecentTypes = RecentTypes;
    }



}

    /**
     * @return the PostClass
     */




Is This A Good Question/Topic? 0
  • +

Replies To: receiving data by bluetooth and analyzing it using code I wrote

#2 CasiOo  Icon User is offline

  • D.I.C Lover
  • member icon

Reputation: 1428
  • View blog
  • Posts: 3,171
  • Joined: 05-April 11

Re: receiving data by bluetooth and analyzing it using code I wrote

Posted 25 July 2011 - 05:25 AM

You want some links to get started or what exactly do you need?

Hopefully you don't want us to go through 3576 lines of code :D
Was This Post Helpful? 0
  • +
  • -

#3 fido dido  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 16
  • Joined: 23-March 11

Re: receiving data by bluetooth and analyzing it using code I wrote

Posted 25 July 2011 - 05:40 AM

View PostCasiOo, on 25 July 2011 - 05:25 AM, said:

You want some links to get started or what exactly do you need?

Hopefully you don't want us to go through 3576 lines of code :D


no don't worry, all what I need is to know how to recieve from bluetooth and save the received in an array , I know how to program with java but J2ME is very new to me so I need good guidance
THanks
Was This Post Helpful? 0
  • +
  • -

#4 pbl  Icon User is offline

  • There is nothing you can't do with a JTable
  • member icon

Reputation: 8347
  • View blog
  • Posts: 31,913
  • Joined: 06-March 08

Re: receiving data by bluetooth and analyzing it using code I wrote

Posted 26 July 2011 - 09:53 PM

As CasiOo mentioned still 3576 lines of code. Can you narrow down your problem ?
Was This Post Helpful? 0
  • +
  • -

#5 macosxnerd101  Icon User is online

  • Self-Trained Economist
  • member icon




Reputation: 10816
  • View blog
  • Posts: 40,316
  • Joined: 27-December 08

Re: receiving data by bluetooth and analyzing it using code I wrote

Posted 26 July 2011 - 10:00 PM

Moved to Mobile Development.

The Oracle tutorial is a good place to start.
Was This Post Helpful? 2
  • +
  • -

#6 fido dido  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 16
  • Joined: 23-March 11

Re: receiving data by bluetooth and analyzing it using code I wrote

Posted 27 July 2011 - 08:50 AM

hi every body thanks for replying, please Ignore the code ,my problem is not in that code .
All what I want to know is how data is sent by bluetooth to mobile and how is it recieved and stored to be able to pass this data into the code written above,as I said before mobile application is new to me so I need links or tutorials about J2ME & bluetooth if possible to show me the difference between java and J2ME also to tell me how to deal with bluetooth ,thanks in advance.
Was This Post Helpful? 0
  • +
  • -

Page 1 of 1