signalcalc.cpp

来自「常用算法与数据结构原代码」· C++ 代码 · 共 1,624 行 · 第 1/3 页

CPP
1,624
字号
// SignalCalc.cpp : Defines the initialization routines for the DLL.
//

#include "stdafx.h"
#include "SignalCalc.h"
#include <math.h>

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

#define PI 3.14159265
#define max_nscales 20
#define max_wlen 23
#define NODS 20

//
//	Note!
//
//		If this DLL is dynamically linked against the MFC
//		DLLs, any functions exported from this DLL which
//		call into MFC must have the AFX_MANAGE_STATE macro
//		added at the very beginning of the function.
//
//		For example:
//
//		extern "C" BOOL PASCAL EXPORT ExportedFunction()
//		{
//			AFX_MANAGE_STATE(AfxGetStaticModuleState());
//			// normal function body here
//		}
//
//		It is very important that this macro appear in each
//		function, prior to any calls into MFC.  This means that
//		it must appear as the first statement within the 
//		function, even before any object variable declarations
//		as their constructors may generate calls into the MFC
//		DLL.
//
//		Please see MFC Technical Notes 33 and 58 for additional
//		details.
//

/////////////////////////////////////////////////////////////////////////////
// CSignalCalcApp

BEGIN_MESSAGE_MAP(CSignalCalcApp, CWinApp)
	//{{AFX_MSG_MAP(CSignalCalcApp)
		// NOTE - the ClassWizard will add and remove mapping macros here.
		//    DO NOT EDIT what you see in these blocks of generated code!
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CSignalCalcApp construction

CSignalCalcApp::CSignalCalcApp()
{
	// TODO: add construction code here,
	// Place all significant initialization in InitInstance
}

/////////////////////////////////////////////////////////////////////////////
// The one and only CSignalCalcApp object

CSignalCalcApp theApp;

int CalculatePower(int N)
{
	int i,m;
	for(i=0;i<20;i++)
	{
		m=i+1;
		N/=2;
		if(N==1) break;
	}
	return m;
}


/*  NOTE: WINDOWFLAG=1     no window                       
          WINDOWFLAG=2     hanning window                  
	      WINDOWFLAG=3     hamming window                  
          WINDOWFLAG=4     blackman window                 */

void windowed( float *x, int n, int windowflag )
{   float  multiplier;
	int i;

	switch(windowflag)
	{   case 1:break;
		case 2:
			   for(i=0;i<n;i++)
			   {   multiplier=(float)(0.5*(1-cos(6.2831853*i/(n-1))));
				   x[i]=x[i]*multiplier;
			   }
			   break;
		case 3:
			   for(i=0;i<n;i++)
			   {   multiplier=(float)(0.54-0.46*cos(6.2831853*i/(n-1)));
				   x[i]=x[i]*multiplier;
			   }
			   break;
		case 4:
			   for(i=0;i<n;i++)
			   {   multiplier=(float)(0.42-0.5*cos(2*PI*i/(n-1))+0.08*cos(4*PI*i/(n-1)));
				   x[i]=x[i]*multiplier;
			   }
			   break;
	}
}

/////////////////峭度系数//////////////////////////////////////////////
extern "C" __declspec(dllexport)float kurtosis(float *x, int N)// 采用MATLAB中的峭度计算公式 smj 
{                                                    
    
	AFX_MANAGE_STATE(AfxGetStaticModuleState());
	float ans;
	float aver = 0.,sum1=0.,sum2=0.;
	for(int i=0;i<N;i++)
		aver += x[i];
	aver = aver/N;//样本序列均值aver

	for(i=0;i<N;i++)
    {   
	    ans=x[i]-aver;
		sum1+=ans*ans*ans*ans;
		sum2+=ans*ans;
    }

	return sum1*N/(sum2*sum2);//返回峭度系数值
}
///////////////////////////////////////////////////////////////////////

// 快速傅立叶变换
// xr--输入序列的实部;xi--输入序列的虚部;
// m--序列长度N取2的对数,即 ;
// inv--0为正变换,1为反变换;
extern "C" __declspec(dllexport) void fft(float *xr,float *xi,int m,int inv)
{
   AFX_MANAGE_STATE(AfxGetStaticModuleState());
   float ur,ui,wr,wi,tr,ti,tmr,tmi;
   int n,l,i,j,le,le1,ip,nv1,nv2,k;
   n=(int)pow(2.0,(double)m);
   //calculate fft
   for(l=1;l<=m;l++)  
   { 
	   le=(int)pow(2.0,(m+1-l));
       le1=le/2;
       ur=1.0f;
       ui=0.0f;
       wr=(float)cos(PI/le1);
       if(inv==0)
         wi=-(float)sin(PI/le1);
       else
         wi=(float)sin(PI/le1);
       for(j=0;j<le1;j++)
	   { 
		   for(i=j;i<n;i+=le)
		   { 
			   ip=i+le1;
	           tmr=xr[i]-xr[ip];
	           tmi=xi[i]-xi[ip];
	           xr[i]=xr[i]+xr[ip];
	           xi[i]=xi[i]+xi[ip];
               xr[ip]=tmr*ur-tmi*ui;
	           xi[ip]=tmr*ui+tmi*ur;
		   }
           if((j+1)==le/4)   //to enhance precision
		   { 
			   if(inv==0)
			   { 
				   ur=0.0f;
	               ui=-1.0f;
			   }
	           else
			   {
			      ur=0.0f;
	              ui=1.0f;
			   }
		   }
           else
		   {  
			   tr=ur*wr-ui*wi;
	           ui=ur*wi+ui*wr;
	           ur=tr;
		   }
	   }
   }
// reverse order
   nv2=n/2;
   nv1=n-1;
   j=0;
   for(i=0;i<nv1;i++)
   { if(i<j)
     {  tr=xr[j];
        ti=xi[j];
        xr[j]=xr[i];
        xi[j]=xi[i];
        xr[i]=tr;
        xi[i]=ti;
     }
     k=nv2;
     while(k<=j)
     { j-=k;
       k=k/2;
     }
     j+=k;
   }
   if(inv==1)
   {  for(i=0;i<=n-1;i++)
      {  xr[i]=xr[i]/n;
         xi[i]=xi[i]/n;
      }
   }
}

/////////////////////////////////////////////
void fht2t( float *x, int n, int m  )
{  int i,j,k,n1,n2,n4,l1,l2,l3,l4;
   float xt,ophase1,ophase2,ss,cc,w,a;
   // digit reverse counter,use radar algorithm
   j=0;
   for(i=0;i<n-1;i++)
   {  if(i<j)
	  {  xt=x[i]; x[i]=x[j]; x[j]=xt; }
	  k=n>>1;                         //k=n/2
	  while(k<=j)
	  {  j-=k;
		 k=k>>1;                      //k=k/2
	  }
	  j=j+k;
   }
   //Hartley transform
   for( i=0;i<n;i+=2)
   {  xt=x[i];
	  x[i]=xt+x[i+1];
	  x[i+1]=xt-x[i+1];
   }
   n2=1;
   for( k=1;k<m;k++ )
   {  n4=n2;
	  n2=n4<<1;          //n2=n4*2
	  n1=n2<<1;         //n1=n2*2
	  w=(float)(6.2831853/n1);
	  for( j=0;j<n;j+=n1 )
	  {  l2=j+n2;
		 l3=j+n4;
		 l4=l2+n4;  //j=0;l2=n/2,l3=n/4,l4=3*n/4
		 xt=x[j];
		 x[j]=xt+x[l2];
		 x[l2]=xt-x[l2];
		 xt=x[l3];
		 x[l3]=xt+x[l4];
		 x[l4]=xt-x[l4];
		 a=w;
		 for( i=1; i<n4;i++ )
		 {  l1=j+i;
			l2=l1+n2;
			l3=j+n2-i;
			l4=l3+n2;  //l1=k,l2=n/2+k,l3=n/2-k,l4=n-k
			ss=(float)sin(a);
			cc=(float)cos(a);
			ophase1=x[l2]*cc+x[l4]*ss;
			ophase2=x[l2]*ss-x[l4]*cc;
			xt=x[l1];
			x[l1]=xt+ophase1;
			x[l2]=xt-ophase1;
			xt=x[l3];
			x[l3]=xt+ophase2;
			x[l4]=xt-ophase2;
			a+=w;
		 }
	  }
   }
}
////////////////////////////////////////////////////////////////
/*  NOTE: outport order:                                       */
/*        {Re[0],Re[1],...Re[N/2],Im[N/2-1],Im[N/2-2]...Im[1]  */
/////////////////////////////////////////////////////////////////
extern "C" __declspec(dllexport)void efft( float *x, int n, int windowflag )
{  
    AFX_MANAGE_STATE(AfxGetStaticModuleState());
	float xt;
    int i,m;
    m=CalculatePower(n);
    windowed( x, n, windowflag);
    fht2t( x, n, m );
    for(i=1;i<n/2;i++)
    {   xt=x[i];
	    x[i]=(xt+x[n-i])/2;
	    x[n-i]=-(xt-x[n-i])/2;
    }
}
//////////////////////校正的频谱计算/////////////////////////////////////////
// x--输入实序列,输出的前N/2+1项为校正后的幅值谱(bRectify=FALSE则不校正);
// N--序列长度;
// samplefrequence--采样频率;
// windowflag--加窗类型,1为矩形窗,2为汉宁窗,3为海明窗,4为布莱克曼窗;
// spectrumpeaknumber--需校正的幅值谱数目;
extern "C" __declspec(dllexport) void amendfft( float *x,int N,float samplefrequence,	
				int windowflag,BOOL bRectify,int spectrumpeaknumber)
{   
	AFX_MANAGE_STATE(AfxGetStaticModuleState());
	int i,j,k = 0, l;
	float max,amplititude,phase,frequence,kt,aver=0.0f;
	float *save, *y;
    HANDLE hFloatsave,hFloaty;
	float ophase1,ophase2,dk;
	max=0.0f;
	hFloaty=(HANDLE)GlobalAlloc(GMEM_MOVEABLE|GMEM_ZEROINIT,N*sizeof(float));
	y=(float *)GlobalLock(hFloaty);

	//原始数据去均值2001/03/06
    for(i=0;i<N;i++)
		aver+=x[i];
	aver=aver/N;
	for(i=0;i<N;i++)
		x[i]-=aver;

	if(windowflag>2)
	{   hFloatsave=(HANDLE)GlobalAlloc(GMEM_MOVEABLE,N*sizeof(float));
	    save=(float  *)GlobalLock(hFloatsave);
	    for(i=0;i<N/2;i++)
		   save[i]=x[i];
		for(i=N/2;i<N;i++)
		   save[i]=0.0;
		efft(save,N,0);//not add window
	}
	efft(x,N,windowflag);

	y[0]=(float)(2*fabs(x[0])/N);  //除N是为了使幅值与时域相等  smj 下同
	y[N/2]=(float)(2*fabs(x[N/2])/N);

	if(windowflag==2 && bRectify==0)//  WINDOWFLAG=2 为 hanning window,note by smj
	{
		kt=0.0;
		for(i=0;i<N;i++)
			kt+=(float)(0.5*(1.0+cos(2*PI*i/N)));// 1/kt为函数窗的能量放大因子
		for(i=1;i<N/2;i++)
			y[i]=(float)(2*sqrt(x[i]*x[i]+x[N-i]*x[N-i])/kt/N);
	}
	else
	{
		for( i=1;i<N/2;i++)
			y[i]=(float)(2*sqrt(x[i]*x[i]+x[N-i]*x[N-i])/N);//please note x/N
	}
	
	float maxoftotal=0.1;					// Modified by XFY, 12/12/1999
	short lastposiofmax=0;					// Modified by XFY, 12/12/1999
	for(i=0;i<spectrumpeaknumber;i++)
	{
		max =(float)( y[0]+1.0e-6);					// Modified by XFY, 12/12/1999
		for(j=0;j<=N/2;j++)					// Modified by XFY, 12/12/1999
		{
			if(max<y[j])
			{  max=y[j]; k=j;}
		}
		if(k==0)	k=1;
		if(i==0)							// Modified by XFY, 12/12/1999
			maxoftotal = (float)(y[k]+1.0e-6);
		
		//if(bRectify)			// Original
		if(bRectify && (k-lastposiofmax) > 2 && y[k]>maxoftotal*0.1+1.0e-6)	//Modified by XFY 12/12/1999
		{	
			switch(windowflag)
			{  case 1:
					  if(k<3||k>N/2-4)
						 break;
					  if(y[k+1]>=y[k-1])
						  dk=y[k+1]/(y[k]+y[k+1]); //dk 为频率校正公式 note by smj
					  else dk=-y[k-1]/(y[k]+y[k-1]);//参阅论文《频谱分析的校正方法》
					  amplititude=(float)(PI*dk*y[k]/sin(PI*dk));
					  frequence=(float)(samplefrequence*(k+dk)/N);
					  if(fabs(x[k])<=1e-6)
						 phase=(float)(PI/2);
					  else phase=(float)(atan(x[N-k]/x[k]));
					  if( x[k]<0.0 )
						 phase=phase+(float)PI;
					  if(x[k]>0.0 && x[N-k]<0.0)
						 phase=phase+(float)(2*PI);
					  phase=phase-(float)(dk*PI);
					 // phase=phase+(float)(dk*PI);
					  y[N-11*i-1]=amplititude;//校正幅值;smj
					  y[N-11*i-2]=frequence;
					  y[N-11*i-3]=phase;
					  break;
			   case 2:
					  if(k<3||k>N/2-4)
						 break;
					  if(y[k+1]>=y[k-1])
						 dk=(2*y[k+1]-y[k])/(y[k+1]+y[k]);
					  else  dk=(y[k]-2*y[k-1])/(y[k]+y[k-1]);
					  amplititude=(float)(PI*dk*y[k]*2*(1-dk*dk)/sin(PI*dk));
					  frequence=samplefrequence*(k+dk)/N; //here I recommend dk, fre ammend is canceled.
					  //frequence=samplefrequence*k/N;
					  if(fabs(x[k])<1e-6)
						 phase=(float)PI/2;
					  else phase=(float)atan(x[N-k]/x[k]);
					  
        			  if( x[k]<-0.1 )
						 phase=phase+(float)PI;
					  
					  if(x[k]>0.0 && x[N-k]<0.0)//smj recorrect 12/25/2000
					 // if(phase<-1.0e-005)
						 phase=phase+(float)(2*PI);
					  phase=phase-(float)(dk*PI);
					 // phase=phase+(float)(dk*PI);
					  y[N-11*i-1]=amplititude;
					  y[N-11*i-2]=frequence;
					  y[N-11*i-3]=phase;
					  break;
			   case 3:
			   case 4:
					  if(k<0||k>N/2-4)
						 break;
					  if(fabs(x[k])<1e-6)
						ophase1=(float)PI/2;
					  else ophase1=(float)atan(x[N-k]/x[k]);
					  if(x[k]<0.0)
						ophase1=ophase1+(float)PI;
					  if( x[k]>0.0 && x[N-k]<0.0 )
						ophase1=ophase1+(float)(2*PI);
					  if(fabs(save[k])<1e-6)
						ophase2=(float)(PI/2);
					  else  ophase2=(float)atan(save[N-k]/save[k]);
					  if(save[k]<0.0)
						ophase2=ophase2+(float)PI;
					  if( save[k]>0.0 && save[N-k]<0.0 )
						ophase2=ophase2+(float)(2*PI);
					  dk=(float)(2*(ophase1-ophase2)/PI);
					  phase=ophase1-(float)(PI*dk*(N-1)/N);
					  if(windowflag==3)
						amplititude=(float)(y[k]*PI/(dk*sin(PI*dk)*(0.54/(dk*dk)+0.46/(1-dk*dk))));
					  else
						amplititude=(float)(y[k]*PI/(dk*sin(PI*dk)*(0.42/(dk*dk)+0.5/(1-dk*dk)-0.08/(4-dk*dk))));
					  frequence=samplefrequence*(k+dk)/N;
					  y[N-11*i-1]=amplititude;
					  y[N-11*i-2]=frequence;
					  y[N-11*i-3]=phase;
					  break;
			}
		}
		else
		{
			y[N-11*i-1]=y[k];
			y[N-11*i-2]=samplefrequence*k/N;

			if(fabs(x[k])<1e-6)
				phase=(float)PI/2;
			else
				phase=(float)atan(x[N-k]/x[k]);
			if( x[k]<0.0 )
				phase=phase+(float)PI;
			if(x[k]>0.0 && x[N-k]<0.0)
				phase=phase+(float)(2*PI);

			y[N-11*i-3]=phase;

		}

		y[N-11*i-4]=(float)k;
		if(k>=3 && k<=N/2-4)	
		{  for(j=k-2;j<=k+2;j++)		//Modified by XFY, 16/12/1999
		   {  l=j-k+3;
			  y[N-11*i-5-l]=y[j];
			  y[j]=0.0;					
		   }
		}
		else
		{  y[N-11*i-5]=y[k];
		   if(k<3 && k!=0) 				//Modified by XFY, 12/12/1999
		   {	for(j=0;j<=k+2;j++)
					y[j]=0.0;					
		   }
           else
		   {   for(j=k-2;j<=N/2;j++)
					y[j]=0.0;					
		   }
		}

	lastposiofmax = k;			// Modified by XFY, 12/12/1999
	}

	for(i=0;i<spectrumpeaknumber;i++)
	{  k=(int)y[N-11*i-4];
	   if(k>=3 && k<=N/2-4)
	   {  for(l=-2;l<=2;l++)   //此处应为-2~+2  ???????smj修改  4/23/2000
		         y[k+l]=y[N-i*11-(l+8)];
		  y[k]=y[N-11*i-1];  //amplititude has been amended
	   }
	   else
	   {
		  y[k]=y[N-11*i-5];
		  //y[N-11*i-5]=y[N-11*i-5]*kt;
	   }

	}

	for(i=0;i<N;i++)
	   x[i]=y[i];

	//获取校正峰值,modified by XFY, 19/12/1999
	for(i=0;i<spectrumpeaknumber;i++)
	{   
		x[int(y[N-11*i-4])] = y[N-11*i-1];
//		if(g_bSimulate && i==2 && windowflag>1) 
//			x[int(y[N-11*i-4])] = y[N-11*i-1]*2;
	}
	GlobalUnlock(hFloaty);
	GlobalFree(hFloaty);
	
	if(windowflag>2)
	{  GlobalUnlock(hFloatsave);
	   GlobalFree(hFloatsave);
	}
}

//////////趋势图用数据/////////////////////////////////////
// 趋势频谱提取
// x--输入实序列;
// n--序列长度;
// samplefrequence--采样频率;
// rpm--转速。
extern "C" __declspec(dllexport)void amendfft1( float *x, int n, float samplefrequence,float rpm )
{                           
	AFX_MANAGE_STATE(AfxGetStaticModuleState());
	
	int i,j,k,mm,position;
	float max,phase[513];
	float dk,aver=0.0;

		//原始数据去均值2001/04/09  
    for(i=0;i<n;i++)
		aver+=x[i];
	aver=aver/n;
	for(i=0;i<n;i++)
		x[i]-=aver;
	
//	m = int (log(float(n))/log(2.0));

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?