QT Interval Measurement: The PhysioNet/Computing in Cardiology Challenge 2006 1.0.0

File: <base>/sources/yuriy-chesnokov/lib.h (14,931 bytes)
/*

lib.h - ECG annotation library based on continuous (CWT) and fast (FWT) wavelet transforms.  
Copyright (C) 2006 YURIY V. CHESNOKOV

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.


You may contact the author by e-mail (chesnokov.yuriy@gmail.com or
chesnokov_yuriy@mail.ru) or postal mail (Unilever Centre for Molecular
Sciences Informatics, University Chemical Laboratory, Cambridge
University, Lensfield Road, Cambridge, CB2 1EW, UK)

*/






#pragma once


//////////////////////////////////////////////////////////////////////////////
typedef struct _datahdr
{
   char hdr[4];
   unsigned int size;
   float sr;
   unsigned char bits;
   unsigned char lead;
   unsigned short umv;
   unsigned short bline;
   unsigned char hh;
   unsigned char mm;
   unsigned char ss;
   char rsrv[19];
} DATAHDR, *PDATAHDR;

class Signal
{
   PDATAHDR phdr;                   //data header

   vector<DATAHDR> hdrs;           //arrays of headers
   vector<long double *> vdata;     //arrays of signals

    bool dat;                       //bin/txt file
    wchar_t fname[256];             //file name

   bool ReadDat();                  //read custom data file
   bool ReadTxt();                  //read text file data
   bool ReadMit();                  //read mit-bih dat file
   int parseHdr(FILE *fh);          //parse mit-bih header

   void getfname(wchar_t *path, wchar_t *name);
   void changeext(wchar_t *path, wchar_t *ext);
   int readline(FILE *f, char *buff);



  protected:
    long double *data,SR;
    int Lead,UmV,Bits,Len;
    int hh,mm,ss;               //start time of the record

      HANDLE fp, fpmap;
         LPVOID lpMap;

            FILE *in;
          float *lpf;
          short *lps;
 unsigned short *lpu;
           char *lpc;



  public:
           Signal();
          ~Signal();

  long double *ReadFile(wchar_t *name);
  long double *ReadFile(char *name);
          bool SaveFile(wchar_t *name, long double *buff, PDATAHDR hdr);
          bool SaveFile(char *name, long double *buff, PDATAHDR hdr);
          bool ToTxt(wchar_t *name, long double *buff, int size);
          bool GetInfo(wchar_t *name);
	  void CloseFile();

         int GetData(int index);
 long double *GetData(){ return data; };
         int GetLength(){ return Len; };
         int GetBits(){ return Bits; };
         int GetUmV(){ return UmV; };
         int GetLead(){ return Lead; };
         int GetLeadsNum(){return (int)vdata.size(); };
 long double GetSR(){ return SR; };
         int GetH(){ return hh; };
         int GetM(){ return mm; };
         int GetS(){ return ss; };

        void  mSecToTime(int , int &,int &,int &,int &);
        void  MinMax(long double *, int , long double &, long double &);

      //normalization
        void nMinMax(long double *buff, int len, long double a, long double b);
        void nMean(long double *buff, int len);
	void nZscore(long double *buff, int len);
       	void nSoftmax(long double *buff, int len);
       	void nEnergy(long double *buff, int len, int L=2);
        

  //math routines////////////////////////////////////////////////////////////
     long double log2(long double x){ return logl(x)/logl(2.0); };

            bool  AutoCov(long double *, int);
     long double  Disp(long double *, int);
     long double  Mean(long double *, int);

     long double  MINIMAX(long double *, int);
     long double  FIXTHRES(long double *, int);
     long double  SURE(long double *, int);
           void  Denoise(long double *mass, int size, int window, int type=0, bool soft=true);
            void  HardTH(long double *mass, int size, long double TH, long double l=0.0);
            void  SoftTH(long double *mass, int size, long double TH, long double l=0.0);

};
//----------------------------------------------------------------------------
/*////////info////////////////////////////////
 to OPEN file:
        long double *sig


          sig = s1->ReadFile("filename");              //error sig=0
         iSize = s1->GetLength();
            SR = s1->GetSR();
           UmV = s1->GetUmV();
          bits = s1->GetBits();


  to SAVE file:
     s1->SaveFile("fname", sig, SR,Len,Bits,Umv)


         s1->mSecToTime(msecs, &h,&m,&s,&ms)
         s1->MinMax(*buff, Len,&min,&max)
////////////////////////////////////////////*/
























/////////////////////////////////////////////////////////////////////////////////
typedef struct _cwthdr
{
   char hdr[4];
   float fmin;
   float fmax;
   float fstep;
   unsigned int size;
   float sr;
   unsigned char type;   //1-log; 0-norm scale

   char rsrv[15];
} CWTHDR, *PCWTHDR;

class CWT : public Signal
{  
     PCWTHDR phdr;

    long double fmin,fmax,fstep, w0;

     int cwtSize,type,cwIndex;
     long double *csig;                //pointer to original signal
     long double *cwtBuff;             //buffer with spectra
     long double *ReW,*ImW;            //Re,Im parts of wavelet
       bool prec;
      int precision;

      bool mirror;   //mirror boundary extension
      long double lval,rval;   //left/right value for signal ext at boundaries

      long double cWave(int, long double);


  public:
          CWT();
         ~CWT();

        float * CWTCreateFileHeader(wchar_t *, PCWTHDR, int, long double);
        float * CWTReadFile(wchar_t *);
  long double   HzToScale(long double, long double, int, long double w=5);
         void   ConvertName(wchar_t *, int, long double);

          void  InitCWT(int, int, long double w=5, long double sr=0);
          void  CloseCWT();
  long double * CWTrans(long double *buff, long double freq, bool mr=true, long double lv=0, long double rv=0);

      long double GetFmin(){return fmin;};
      long double GetFmax(){return fmax;};
      long double GetFstep(){return fstep;};
              int GetType(){return type;};
              int GetFreqRange();
};
/*//////////////////////////////////////////////
    CWT cwt;

     cwt->ReadFile(L"filename");

      cwt.InitCWT(size, wletindex, w0, SR);
       *buff = cwt.CWT(sig, freq);
      cwt.loseCWT();

//////////////////////////////////////////////*/










/////////////////////////////////////////////////////////////
typedef struct _fwthdr
{
   char hdr[4];
   unsigned int size;
   float sr;
   unsigned char bits;
   unsigned char lead;
   unsigned short umv;

   char wlet[8];
   unsigned short J;

   char rsrv[14];
} FWTHDR, *PFWTHDR;

class FWT : public Signal
{
    PFWTHDR phdr;
    char fname[256];

    long double *tH, *tG;     //analysis filters
    long double *H, *G;       //synth filters
    int thL, tgL, hL, gL;     //filters lenghts
    int thZ, tgZ, hZ, gZ;     //filter centers

     int J;                //scales
     int *Jnumbs;          //hi values per scale
     int sigLen;           //signal len
     int size;             //divided signal size


   //filters inits
    FILE *filter;
    long double *loadfilter(int &L, int &Z);

   //spectra
     long double *fwtBuff;     //buffer with fwt spectra
     long double *tempBuff;    //temporary
     long double *hi,*lo;      //pointers to tempBuff
     int hiNum, loNum;         //number of lo and hi coeffs

     

     void fwtHiLoTrans();
     void fwtHiLoSynth();

   public:
       FWT();
       ~FWT();

      bool InitFWT(wchar_t *fltname, long double *sig, int len);
      void CloseFWT();

      void fwtTrans(int scales);                      //wavelet transform
      void fwtSynth(int scales);                      //wavelet synthesis


  long double *getSpec(){ return fwtBuff; };
         int getSpecSize(){ return size; };
         int getJ() {return J;};
       char *getFltName(){ return fname; };


      int *GetJnumbs(int j, int len);
      void HiLoNumbs(int j, int len, int &hinum, int &lonum);

      bool  fwtSaveFile(wchar_t *name, long double *hipass, long double *lopass, PFWTHDR hdr);
      bool  fwtReadFile(wchar_t *name, char *appdir=0);

};







////////////////////////////////////////////////////////////////////////////////
#define qNORM 0
#define qNOISE 1

typedef struct _annrec
{
   unsigned int pos;    //offset
   unsigned int type;   //beat type
   unsigned int aux;    //index to aux array
} ANNREC, *PANNREC;

typedef struct _annhdr
{
   int minbpm;
   int maxbpm;
   long double minUmV;  //min R,S amplitude
   long double minQRS;  //min QRS duration  
   long double maxQRS;  //max QRS duration
   long double minPQ;
   long double maxPQ;
   long double minQT;
   long double maxQT;
   long double pFreq;   //p wave freq for CWT
   long double tFreq;   //t wave freq for CWT
} ANNHDR, *PANNHDR;

class Annotation : public Signal
{
     ANNHDR ahdr;             //annotation ECG params

     int **ANN, annNum;           //annotation after getPTU (RR's + PT)
     int **qrsANN, qrsNum;        //annotation after getQRS (RR's+MAnoise)  +ECT after getECT()
      vector <int> MA;       //MA noise
     int auxNum;
     char **AUX;


    bool chkNoise(long double *mass, int window);        //check for noise in window len
    bool flt30Hz(long double *mass, int len, long double sr, wchar_t *fltdir, int stype);    //0-30Hz removal

     void findRS(long double *mass, int len, int &R, int &S, long double err=0.0);  //find RS or QR  
     int findr(long double *mass, int len, long double err=0.0);  //find small r in PQ-S
     int findq(long double *mass, int len, long double err=0.0);  //find small q in PQ-R
     int finds(long double *mass, int len, long double err=0.0);  //find small s in R-Jpnt
     int findTmax(long double *mass, int len); 


   public:
       Annotation(PANNHDR p=0);
       ~Annotation();


   int **GetQRS(long double *mass, int len, long double sr, wchar_t *fltdir=0, int stype=qNORM);     //get RR's classification
    void GetECT(int **ann, int qrsnum, long double sr);                                              //classify ectopic beats
   int **GetPTU(long double *mass, int len, long double sr, wchar_t *fltdir, int **ann, int qrsnum);
     int GetQRSnum(){ return qrsNum; };
     int GetANNnum(){ return annNum; };

     void AddANN(int add);    //add if annotated within fromX-toX  


     bool  SaveANN(wchar_t *, int **, int);
     //bool  ReadANN(wchar_t *);
      int ** GetANNdata(){return ANN;};
      int ** GetQRSdata(){return qrsANN;};
      char ** GetAUXdata(){return AUX;};

     PANNHDR GetANNhdr(){return &ahdr;}; 

     bool GetRRseq(int **ann, int nums, long double sr, vector<long double> *RR, vector<int> *RRpos);
     bool SaveRRseq(wchar_t *, int **, int, long double, int);
     bool SaveRRnseq(wchar_t *, int **, int, long double, int);
     bool SaveQTseq(wchar_t *, int **, int, long double, int);
     bool SavePQseq(wchar_t *, int **, int, long double, int);
     bool SavePPseq(wchar_t *, int **, int, long double, int);
};

/*                   0           1             2
    int **ANN [x][samples][annotation type][aux data index]

    wchar_t *dir = "c:\\dir_for_fwt_filters\\filters";
    long double *sig;   //signal massive
    long double SR;     //sampling rate of the signal
    int size;   //size of the signal

    Annotation ann;

     int **qrsAnn;  //qrs annotation massive
     qrsAnn = ann.GetQRS(sig,size,SR,dir);       //get QRS complexes
     //qrsAnn = ann->GetQRS(psig,size,SR,umess,qNOISE);    //get QRS complexes if signal is quite noisy

     int **ANN; //QRS + PT annotation
     if(qrsAnn)
     {
        ann.GetECT(qrsAnn,ann->GetQRSnum(),SR);     //label Ectopic beats
        ANN = ann.GetPTU(sig,size,SR,dir,qrsAnn,ann.GetQRSnum());   //find P,T waves
     }
*/



  //annotation codes types
      /*
         skip=59
         num=60
         sub=61
         chn=62
         aux=63

      char anncodes [51][10] =  {"notQRS", "N",       "LBBB",    "RBBB",     "ABERR", "PVC",
                                 "FUSION", "NPC",     "APC",     "SVPB",     "VESC",  "NESC",
                                 "PACE",   "UNKNOWN", "NOISE",   "q",        "ARFCT", "Q",
                                 "STCH",   "TCH",     "SYSTOLE", "DIASTOLE", "NOTE",  "MEASURE",
                                 "P",      "BBB",     "PACESP",  "T",        "RTM",   "U",
                                 "LEARN",  "FLWAV",   "VFON",    "VFOFF",    "AESC",  "SVESC",
                                 "LINK",   "NAPC",    "PFUSE",   "(",        ")",     "RONT",

          //user defined beats//
                                 "(p",     "p)",      "(t",      "t)",       "ECT",
                                 "r",      "R",       "s",       "S"};

                     /*
                        [16] - ARFCT
                        [15] - q
                        [17] - Q
                        [24] - P
                        [27] - T 
                        [39, 40] - '(' QRS ')'  PQ, J point
                        42 - (p Pwave onset
                        43 - p) Pwave offset
                        44 - (t Twave onset
                        45 - t) Twave offset
                        46 - ect Ectopic of any origin beat
                        47 - r
                        48 - R
                        49 - s
                        50 - S
                                                     */





     



class ECGDenoise : public FWT
{
     wchar_t fltdir[256];             //filters dir

     long double *ecgBuff;            //pointer to [original sig]
     long double *tempBuff;           //[SRadd][original sig][SRadd]

     //void  Denoise(long double *, int);


   public:
       ECGDenoise();
       ~ECGDenoise();

       void  InitDenoise(wchar_t *fltdir, long double *data, int size, long double sr, bool mirror=true);
       void  CloseDenoise();

       bool LFDenoise();         //baseline wander removal
       bool HFDenoise();         //hf denoising
       bool LFHFDenoise();       //baseline and hf denoising

};

/*
    wchar_t *dir = "c:\\dir_for_fwt_filters\\filters";
    long double *sig;   //signal massive
    long double SR;     //sampling rate of the signal
    int size;   //size of the signal

     ECGDenoise enoise;

      enoise.InitDenoise(dir, sig,size,SR);
      enoise.LFDenoise();     //baseline wander removal
      //or  enoise.HFDenoise();    //high frequency noise removal
      //or  enoise.LFHFDenoise();  //both noises removal
      enoise.CloseDenoise();

*/