ECG-Kit 1.0
(9,942 bytes)
/* MEX-file for reading MIT format annotation for ECG Signals */
/* (c) Juan Pablo Martinez Cortes. University of Zaragoza.
e-mail: juanpabl@tsc1.cps.unizar.es */
/*
/ INCLUDE FILES
*/
#include "mex.h"
#include <stdio.h>
#include <string.h>
#ifdef HAVE_OCTAVE
#include <stdint.h>
#else
#include <tmwtypes.h>
#endif
void mexFunction(
int nlhs,
mxArray *plhs[],
int nrhs,
const mxArray *prhs[]
)
{
/* Variable definition*/
char *filename;
int32_T nsamp,dim;
int freq,buflen, A, II;
int32_T I;
double *timeabs, *time, *timedata;
int32_T timelim[2];
int32_T nbytes, nevents, i, pos,k;
int dims[2];
mxChar *anntyp;
mxChar *subtyp;
mxChar *chan, *num;
char **aux;
char *nullstring = "";
char *currauxfield;
unsigned char currnumfield, currchanfield, currsubtyp, data[2], skip[4];
const char* typecode = "NLRaVFJASEj/Q~ | sT*D\"=pB^t+u?!{}en xf()r";
const char* field_names[] ={"time","anntyp","subtyp","chan","num","aux"};
FILE *fid;
mxArray *outtime, *outsubtyp, *outanntyp, *outchan, *outnum, *outaux;
char finalflag=0;
mxChar *char_array;
/*---------------------------------------------------------------------*/
/*----------------------------------------------------------------------/
/ Check for proper number of arguments /
/----------------------------------------------------------------------*/
if ((nrhs < 1)||(nrhs>2))
{
mexErrMsgTxt ( "readannot: one or two input arguments required" );
}
if ( nlhs > 1 )
{
mexErrMsgTxt ( "readannot: none or one output argument required" );
}
if (!mxIsChar(prhs[0]))
mexErrMsgTxt("First argument must be a string.");
else if (!mxGetM(prhs[0]))
mexErrMsgTxt("First argument must be a string in a row vector.");
/* Get the length of the input string. */
buflen = mxGetN(prhs[0])+1;
/* Allocate memory for input filename */
filename = mxCalloc(buflen, sizeof(char));
/* Copy argument to variable */
mxGetString(prhs[0], filename, buflen);
/* Reading time of beginning and end */
if (nrhs>1)
{
if (!mxIsNumeric(prhs[1]))
mexErrMsgTxt("Second argument (optional) must be a numeric array.");
else if ((mxGetM(prhs[1])!=1)||(mxGetN(prhs[1])!=2))
mexErrMsgTxt("Third argument must be a 1x2 numerical array");
timeabs = mxGetPr(prhs[1]);
if (timeabs[1]<=timeabs[0])
mexErrMsgTxt("Bad time vector");
else
if (mxIsFinite(timeabs[1]))
{timelim[0]=(int32_T) timeabs[0];
timelim[1]=(int32_T) timeabs[1];}
else
{timelim[0]=(int32_T) timeabs[0];
timelim[1]=-1;}
}
else
{timelim[0]=1; timelim[1]=-1;} /* -1 means until the end */
/*printf (" timelim = %d %d\n",timelim[0],timelim[1]);*/
/*-----------------------------------------------------------------------------*/
/*------------------------- Reading and interpreting annotation data ----------*/
/*-----------------------------------------------------------------------------*/
if ((fid = fopen(filename, "rb"))==NULL)
mexErrMsgTxt("Unable to open annotation file");
/* Estimation of the number of annotationns */
fseek(fid, 0, SEEK_END);
nbytes = ftell(fid);
rewind(fid);
dim = nbytes / 2 ; /* The maximum number of posible events */
/**************** Reading of the two first bytes ************************/
fread(data,sizeof(char),2,fid);
if (ferror(fid)) mexErrMsgTxt("Error reading annotation file");
if( data[0] == 0 && data[1] == 0 )
{
fclose(fid);
/* Empty output */
plhs[0] = mxCreateNumericArray(0,0,mxDOUBLE_CLASS,mxREAL);
}
else
{
/* mexPrintf (" %d %d\n",data[0],data[1]); */
/*******************Memory Allocation ***************************/
time = (double*) mxCalloc(dim, sizeof(double));
anntyp = (mxChar*) mxCalloc(dim, sizeof(mxChar));
subtyp = (mxChar*) mxCalloc(dim, sizeof(mxChar));
chan = (mxChar*) mxCalloc(dim, sizeof(mxChar));
num = (mxChar*) mxCalloc(dim, sizeof(mxChar));
aux = (char**) mxCalloc(dim, sizeof(char*));
/***************** Variable Initialization**********************/
i=0; /* Current annotation number (index) */
pos = 0;
currnumfield = '0';
currchanfield = '0';
currsubtyp = '0';
currauxfield = nullstring;
if (timelim[1]== -1) finalflag =1;
while ((!feof(fid))&&(finalflag || (pos<timelim[1])))
{
A = data[0] + (((int) data[1])<<8); /* A = data[0] + data[1]*256 */
II = A & 0x03FF; /* in binary 0000001111111111 */
A = A>>10;
/* Special case. Initially A = 59 */
/* printf ("A = %d L = %d\n", A, II); */
if(A==59){
/* Skip samples */
while (A==59)
{
fread(skip,sizeof(char),4,fid);
if (ferror(fid)) mexErrMsgTxt("Error reading annotation file");
if (feof(fid)) mexErrMsgTxt("Unexpected EOF");
I = skip[2]+( (skip[3]+ ( (skip[0]+ ( ( (int32_T) skip[1] )<<8 ) )<<8 ) )<<8);
/*printf ("Skip = %d\n", I); */
pos += I;
fread(data,sizeof(char),2,fid);
if (ferror(fid)) mexErrMsgTxt("Error reading annotation file");
if (feof(fid)) mexErrMsgTxt("Unexpected EOF");
A = data[0] + (((int) data[1])<<8); /* A = data[0] + data[1]*256 */
II = A & 0x03FF; /* in binary 0000001111111111 */
A = A>>10;
}
continue;
}
else{
/* Annotations */
if(A)
anntyp[i] = typecode[A-1]; /*type of annotation*/
else if( A==0 && II == 0) /* eof */
break;
/* Reading next 2 bytes */
fread(data,sizeof(char),2,fid);
if (ferror(fid)) mexErrMsgTxt("Error reading annotation file");
if (feof(fid))
{
A = 0;
}
else
{
A = data[0] + (((int) data[1])<<8); /* A = data[0] + data[1]*256 */
I = A & 0x03FF; /* in binary 0000001111111111 */
A = A>>10;
}
while (A>=60){ /*while more information about i-th annotation*/
if (A==60) currnumfield = (char) '0'+I;
else if (A==61) currsubtyp = (char) '0'+I;
else if (A==62) currchanfield = (char) '0'+I;
else if (A==63)
{
if (I & 0x0001) I++;
currauxfield = (char*) mxCalloc(I+1, sizeof(char));
fread(currauxfield,sizeof(char),I,fid);
currauxfield[I]='\0'; /* Chain delimitator */
if (ferror(fid)) mexErrMsgTxt("Error reading annotation file");
if (feof(fid)) mexErrMsgTxt("Unexpected EOF");
aux;
}
fread(data,sizeof(char),2,fid);
if (ferror(fid)) mexErrMsgTxt("Error reading annotation file");
if (feof(fid)) {break; /* del? */}
A = data[0] + (((int) data[1])<<8); /* A = data[0] + data[1]*256 */
I = A & 0x03FF; /* in binary 0000001111111111 */
A = A>>10;
}
pos += II;
time[i]= (double) pos;
/*printf ("i = %d pos = %d time = %5.3f\n", i, pos, time[i]);*/
num[i]=currnumfield;
chan[i]=currchanfield;
aux[i]=currauxfield;
subtyp[i]=currsubtyp;
currsubtyp = '0';
currauxfield = nullstring;
i ++;
}
}
fclose(fid);
if ((!finalflag)&& (pos>timelim[1])) i--; /* Last event passes through final time */
/****** First event must be the first after timelim[0]*********/
k=0;
while (time[k]<timelim[0])
{
k++;
}
i-=k;
/* mexPrintf ("i = %d k = %d \n", i, k); */
/****************** Create struct ******************/
plhs[0] = mxCreateStructMatrix(1,1,6,field_names);
/****************** Fill the arrays for the fields ***/
dims[0]=i; dims[1]= 1;
/***** time field *****/
outtime = mxCreateNumericArray(2,dims,mxDOUBLE_CLASS,mxREAL);
timedata = (double*) mxGetData(outtime);
memcpy(timedata, &time[k], i*sizeof(double));
mxSetFieldByNumber(plhs[0], 0, 0, outtime);
/***** anntyp field ****/
outanntyp = mxCreateCharArray(2,dims);
char_array = (mxChar*) mxGetData(outanntyp);
memcpy(char_array, &anntyp[k], i*sizeof(mxChar));
/*printf(" %c %c ",char_array[45000],char_array[50000]);*/
mxSetFieldByNumber(plhs[0], 0, 1, outanntyp);
/***** subtyp field ****/
outsubtyp = mxCreateCharArray(2,dims);
char_array = (mxChar*) mxGetData(outsubtyp);
memcpy(char_array, &subtyp[k], i*sizeof(mxChar));
mxSetFieldByNumber(plhs[0], 0, 2, outsubtyp);
/***** chan field ****/
outchan = mxCreateCharArray(2,dims);
char_array = (mxChar*) mxGetData(outchan);
memcpy(char_array, &chan[k], i*sizeof(mxChar));
mxSetFieldByNumber(plhs[0], 0, 3, outchan);
/***** num field ****/
outnum = mxCreateCharArray(2,dims);
char_array = (mxChar*) mxGetData(outnum);
memcpy(char_array, &num[k], i*sizeof(mxChar));
mxSetFieldByNumber(plhs[0], 0, 4, outnum);
/***** aux field *****/
outaux=mxCreateCharMatrixFromStrings(i,(const char**) &aux[k]);
mxSetFieldByNumber(plhs[0], 0, 5, outaux);
/****************** Free Memory ******************/
mxFree(time);
mxFree(anntyp);
mxFree(subtyp);
mxFree(chan);
mxFree(num);
mxFree(aux);
}
}