//------------------------------------------------------------------------------------ // CEMD.mqh // Version 2.01 // 2012, victorg // http://www.mql5.com //------------------------------------------------------------------------------------ #include //------------------------------------------------------------------------------------ // The Empirical Mode Decomposition (EMD). //------------------------------------------------------------------------------------ class CEMD:public CObject { public: int N; // Input and output data size int nIMF; // IMF counter double Mean; // Mean of input data private: int MaxIMF; // Maximum number of IMF int MaxIter; // Maximum number of iterations double Eps; // Accuracy comparison of floating-point numbers double Trs; // Threshold for calculating the zero crossings double Retr; // Number of successful retries double IMFResult[]; // Result double X[]; // X-coordinate for the TimeSeries. X[]=0,1,2,...,N-1. double Imf[]; // Temporary array to calculate the IMF double XMax[]; // x of local maxima double YMax[]; // y of local maxima double XMin[]; // x of local minima double YMin[]; // y of local minima double EnvUpp[]; // Upper envelope double EnvLow[]; // Lower envelope public: void CEMD(void); int CEMD::Decomp(double &y[]); // Decomposition void GetIMF(double &x[], int nn); // Returns the IMF with an index of nn private: int arrayprepare(void); int extrcounter(double &y[]); int extrema(double &y[],int &nmax,double &xmax[],double &ymax[], int &nmin,double &xmin[],double &ymin[],int &nzer); int SplineInterp(double &x[],double &y[],int n,double &x2[], double &y2[],int btype=0); }; //------------------------------------------------------------------------------------ // Constructor. //------------------------------------------------------------------------------------ void CEMD::CEMD(void) { MaxIMF=16; // The maximum number of IMF MaxIter=1000; // The maximum number of iterations Eps=8*DBL_EPSILON; // Accuracy comparison of floating-point numbers Trs=4*DBL_EPSILON; // Threshold for calculating the zero crossings Retr=7; // Number of successful retries } //------------------------------------------------------------------------------------ // Decomposition. //------------------------------------------------------------------------------------ int CEMD::Decomp(double &y[]) { int i,j,iter,nmax,nmin,nzer,pmin,pmax,pzer,count,valid; double a; N=ArraySize(y); if(N<6) { Print(__FUNCTION__,": Error! Insufficient length of the input data."); return(-1); } i=arrayprepare(); if(i<0){Print(__FUNCTION__,": Error! ArrayResize() error."); return(-2);} for(i=0;i XMin[],YMin[],XMax[],YMax[] valid=extrema(Imf,nmax,XMax,YMax,nmin,XMin,YMin,nzer); // ----- Stopping criterion if((nmax==pmax)&&(nmin==pmin)&&(nzer==pzer)&&(valid==1))count++; else {pmax=nmax; pmin=nmin; pzer=nzer; count=0;} if(count>=Retr)break; // End of loop // ----- Upper and Lower envelope if(nmax<2)for(i=0;i=MaxIter) Print(__FUNCTION__,": Warning! Reached the maximum number of iterations."); // ----- Check IMF j=extrcounter(Imf); // Counting of the extrema if(j<1)break; // If monotonic then the end of decomposition // ---------- Saving results if(ArrayResize(IMFResult,N*(nIMF+1))!=N*(nIMF+1)) // Resize for current IMF { Print(__FUNCTION__,": Error! ArrayResize() error."); return(-2); } for(i=0;i=MaxIMF) Print(__FUNCTION__,": Warning! Reached the maximum number of IMF."); return(0); } //------------------------------------------------------------------------------------ // Returns the IMF with an index of nn. // Input: // nn - IMF number: // nn=0; - Input data minus mean; // nn=1; - IMF number 1; // . . . // nn=nIMF-1; - IMF number nIMF-1; // nn=nIMF; - Residue of decomposition. // Output: // x[] - IMF number nn. //------------------------------------------------------------------------------------ void CEMD::GetIMF(double &x[], int nn) { int i,k; k=ArraySize(x); if(k>N)k=N; if(nn<0||nn>nIMF||nIMF==0)for(i=0;iDBL_MIN+Eps*MathMax(MathAbs(b),MathAbs(c))) // b != c { if(((b>c)&&(b>a))||((bTrs)&&(sig<1)){if(sig==-1)nzer++; sig=1; } if((y[i]<-Trs)&&(sig>-1)){if(sig==1)nzer++; sig=-1;} } nmax=0; nmin=0; ret=1; a=y[0]; b=y[1]; k=1; for(i=1;iDBL_MIN+Eps*MathMax(MathAbs(b),MathAbs(c))) // b != c { if((b>c)&&(b>a)) { xmax[nmax+2]=0.5*(k+i); d=0.5*(y[k]+y[i]); ymax[2+nmax++]=d; if(d<0)ret=0; } else if((b0)ret=0; } a=b; b=c; k=i+1; } } if(ret==1){k=nzer-nmax-nmin; if((k>1)&&(k<-1))ret=0;} //------------ extra boundary points nb=2; while(nmin<(nb+1)&&nmax<(nb+1))nb--; if(nb<2) { for(i=0;iymin[nb]) { if(2*xmax[nb]-xmin[2*nb-1]>0) { for(i=0;i0) { for(i=0;iymin[nmin]) { if(2*xmax[nmax]-xmin[nmin-nb+1]<(N-1)) { for(i=0;iArraySize(x)||n>ArraySize(y)||n2>ArraySize(y2)||n<2||n2<1) { Print(__FUNCTION__,": Error! Arguments has wrong size."); return(-1); } ArrayInitialize(y2,0); if(ArrayResize(a1,n)!=n) { Print(__FUNCTION__,": Error! ArrayResize() error."); return(-2); } if(ArrayResize(a2,n)!=n) { Print(__FUNCTION__,": Error! ArrayResize() error."); return(-2); } if(ArrayResize(a3,n)!=n) { Print(__FUNCTION__,": Error! ArrayResize() error."); return(-2); } if(ArrayResize(b,n)!=n) { Print(__FUNCTION__,": Error! ArrayResize() error."); return(-2); } if(ArrayResize(d,n)!=n) { Print(__FUNCTION__,": Error! ArrayResize() error."); return(-2); } for(i=1;i<=n-2;i++) { a1[i]=x[i+1]-x[i]; a2[i]=2*(x[i+1]-x[i-1]); a3[i]=x[i]-x[i-1]; b[i]=3*(y[i]-y[i-1])/(x[i]-x[i-1])*(x[i+1]-x[i])+3*(y[i+1]-y[i]) /(x[i+1]-x[i])*(x[i]-x[i-1]); } if(btype==1&&n==2) { d[0]=(y[1]-y[0])/(x[1]-x[0]); d[1]=d[0]; } else { if(btype==1) { a1[0]=0; a2[0]=1; a3[0]=1; b[0]=2*(y[1]-y[0])/(x[1]-x[0]); a1[n-1]=1; a2[n-1]=1; a3[n-1]=0; b[n-1]=2*(y[n-1]-y[n-2])/(x[n-1]-x[n-2]); } else { a1[0]=0; a2[0]=2; a3[0]=1; b[0]=3*(y[1]-y[0])/(x[1]-x[0]); a1[n-1]=1; a2[n-1]=2; a3[n-1]=0; b[n-1]=3*(y[n-1]-y[n-2])/(x[n-1]-x[n-2]); } for(i=1;i<=n-1;i++) { t=a1[i]/a2[i-1]; a2[i]=a2[i]-t*a3[i-1]; b[i]=b[i]-t*b[i-1]; } d[n-1]=b[n-1]/a2[n-1]; for(i=n-2;i>=0;i--)d[i]=(b[i]-a3[i]*d[i+1])/a2[i]; } c0=0; c1=0; c2=0; c3=0; a=0; bb=0; intervalindex=-1; pointindex=0; for(;;) { if(pointindex>=n2)break; t=x2[pointindex]; havetoadvance=false; if(intervalindex==-1)havetoadvance=true; else if(intervalindex=bb); if(havetoadvance) { intervalindex=intervalindex+1; a=x[intervalindex]; bb=x[intervalindex+1]; w=bb-a; w2=w*w; w3=w*w2; fa=y[intervalindex]; fb=y[intervalindex+1]; da=d[intervalindex]; db=d[intervalindex+1]; c0=fa; c1=da; c2=(3*(fb-fa)-2*da*w-db*w)/w2; c3=(2*(fa-fb)+da*w+db*w)/w3; continue; } t=t-a; y2[pointindex]=c0+t*(c1+t*(c2+t*c3)); pointindex=pointindex+1; } return(0); } //------------------------------------------------------------------------------------