⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 calculate2.c

📁 这是一个采用快速傅立叶算法计算电能量的例程
💻 C
📖 第 1 页 / 共 2 页
字号:
/*******************************电量的计算与管理********************************/
/*****由定时器4形成间隔为20ms的中断,在中断中指定数组,在主程序中计算***********/

#include <sfr16_lb.h>
#include <math.h>
#include <ExternDef.h>
#define _CALCULATE_DATA_
#include <variable.h>
#include <GMUDef.h>
#include <adf.h>

bit symbol_diandu1;//有功电度净值的正负:正为0负为1
bit symbol_diandu2;//无功电度净值的正负:正为0负为1
bit permit_diandu_flag;
unsigned int permit_diandu_num;


//变量定义
bit bIntPer20ms;				//程序开始,闭锁周期计算一段时间,以保证采样数据稳定后再开始计算,此标志置1时才允许计算
bit bInt20ms;					//发生20ms中断的标志.在20ms中断中计算电流与电压矢量,供显示主程序计算用.
xdata unsigned char SmpCount;	//采样中断的采样点号,在0-240之间。采样队列也有240大小。
xdata unsigned char OldSmpPtr;	//在周期采样处理中需要用到的采样数组的起始计算点号。

//计算中使用的新变量列表

xdata float fCalValWh0,fCalValWh1;			//计算正、反向有功电度的累积计算结果
xdata float fCalValvar0,fCalValvar1;		//计算正、反向有功电度的累积计算结果
xdata float fCalValVA;                      //计算视在电度的累积计算结果

xdata float VectorR[12];						//实时记录每通道电压电流的矢量:实部;按顺序依次是:Ua,Ia,Ub,Ib,Uc,Ic
xdata float VectorX[12];						//实时记录每通道电压电流的矢量:虚部;按顺序依次是:Ua,Ia,Ub,Ib,Uc,Ic

xdata float fCalP[4],fCalQ[4],fCalS[4];				//记录各个通道的计算功率:浮点数类型

//以下变量在DFT中使用的中间变量,部分完成参数传递。在其他地方禁止使用,  
//此部分参数应采用其内部RAM数据,以提高程序的处理速度。	
idata union {
  long dlong;
  int dint[2];
  char dchr[4];
  } DFTTmpData;
idata int DFTTmp1,DFTTmp2;
idata int DFTTmpR1,DFTTmpR2;
idata int DFTTmpX1,DFTTmpX2;
//int TmpR0,TmpX0;
idata int * DFTDataAddr;           /*DFT变换中有效数据的地址指针*/


extern xdata unsigned int lcd_num;    
extern xdata unsigned char RamFlag;
extern bit ram_select_flag;

//函数原型说明
void calculate(void);
void AlertHandle(void);
void NVRAM_write_byte (unsigned char data_out, unsigned int address); //写NVRAM
unsigned char NVRAM_read_byte (unsigned int address); //读NVRAM  

//继电器操作函数
void Relay_Action(unsigned char n);
void Relay_UnAction(unsigned char n);            

//以下为初始化存储的变量,仅作为测试用,以后删除



/*24点采样的快速傅立叶变换:输入为准备进行DFT变换的通道数据的首地址。存放在DFTDataAddr指针开始的连续24个数据中。
                         输出是变化后的复数结果,存放在变量DFTTmp1(实部)和DFTTmp2(虚部)中。  */
/*在通道处理时已经保证:每次进行傅氏变换,数据不会越出每一个采样的数据段,因此,在本函数的处理中不考虑采样数据越界的情况,以提高数据处理的速度    */
/*在WAVE环境下仿真12MHz标准51芯片,程序的执行时间是:1851us*/
/*使用的变量列表:
			union {long dlong;int dint[2]; char dchr[4];} DFTTmpData;    数据转换用
			int DFTTmp1,DFTTmp2;							同系数采样点合并用
			int DFTTmpR1,DFTTmpR2;						第一、二组参数的实数部分
			int DFTTmpX1,DFTTmpX2;						第一、二组参数的虚数部分
			int xdata * data DFTDataAddr;          DFT变换中有效数据的地址指针										*/
void Fast_DFT(void)
{
/*以下是用于傅立叶分解用的系数组,在程序中将他们已经分解处理。
  ConvCos[]={1024,989,886,724,512,265,0,-266,-512,-725,-887,-990,-1024,-990,-887,-725,-513,-266,-1,265,511,724,886,989};
  ConvSin[]={0,265,511,724,886,989,1024,989,886,724,512,265,0,-266,-512,-725,-887,-990,-1024,-990,-887,-725,-513,-266};
  由于按照DFT变换,有以下计算:
  Rx =989*{f(1)-f(11)-f(13)+f(23)}+866*{f(2)-f(10)-f(14)+f(22)}+724*{f(3)-f(9)-f(15)+f(21)}+512*{f(4)-f(8)-f(16)+f(20)}+265*{f(5)-f(7)-f(17)+f(19)}+1024*{f(0)-f(12)};
  Img=265*{f(1)+f(11)-f(13)-f(23)}+512*{f(2)+f(10)-f(14)-f(22)}+724*{f(3)+f(9)-f(15)-f(21)}+886*{f(4)+f(8)-f(16)-f(20)}+989*{f(5)+f(7)-f(17)-f(19)}+1024*{f(6)-f(18)};
  设:Tmp00 = f(0)-f(12) ;
      Tmp01 = f(1)-f(13) ;  Tmp02 = f(11)-f(23);
      Tmp11 = f(2)-f(14) ;  Tmp12 = f(10)-f(22);
      Tmp21 = f(3)-f(15) ;  Tmp22 = f( 9)-f(21);
      Tmp31 = f(4)-f(16) ;  Tmp32 = f( 8)-f(20);
      Tmp41 = f(5)-f(17) ;  Tmp42 = f( 7)-f(19);
      Tmp51 = f(6)-f(18);
      Rx =989*(Tmp01-Tmp02)+886*(Tmp11-Tmp12)+724*(Tmp21-Tmp22)+512*(Tmp31-Tmp32)+265*(Tmp41-Tmp42)+1024*Tmp00;
      Img=265*(Tmp01+Tmp02)+512*(Tmp11+Tmp12)+724*(Tmp21+Tmp22)+886*(Tmp31+Tmp32)+989*(Tmp41+Tmp42)+1024*Tmp51;				*/
      
  /*==  Rx:989*{f(1)-f(11)-f(13)+f(23)};   Img:{f(1)+f(11)-f(13)-f(23)}  ====================================*/
  DFTTmp1=*(DFTDataAddr+ 1)-*(DFTDataAddr+13);
  DFTTmp2=*(DFTDataAddr+11)-*(DFTDataAddr+23);

  DFTTmpData.dlong=990*((long)(DFTTmp1-DFTTmp2));
  DFTTmpData.dchr[3]=DFTTmpData.dchr[2];
  DFTTmpData.dchr[2]=DFTTmpData.dchr[1];
  DFTTmpR1  = DFTTmpData.dint[1]>>1;

  DFTTmpData.dlong=266*((long)(DFTTmp1+DFTTmp2));
  DFTTmpData.dchr[3]=DFTTmpData.dchr[2];
  DFTTmpData.dchr[2]=DFTTmpData.dchr[1];
  DFTTmpX1  = DFTTmpData.dint[1]>>1;

  /*==  Rx: 724*{f(3)-f(9)-f(15)+f(21)};  Img:724*{f(3)+f(9)-f(15)-f(21)}  ====================================*/
  DFTTmp1=*(DFTDataAddr+ 3)-*(DFTDataAddr+15);
  DFTTmp2=*(DFTDataAddr+ 9)-*(DFTDataAddr+21);

  DFTTmpData.dlong=725*(long)(DFTTmp1-DFTTmp2);
  DFTTmpData.dchr[3]=DFTTmpData.dchr[2];
  DFTTmpData.dchr[2]=DFTTmpData.dchr[1];
  DFTTmpR1 += DFTTmpData.dint[1]>>1;

  DFTTmpData.dlong=725*(long)(DFTTmp1+DFTTmp2);
  DFTTmpData.dchr[3]=DFTTmpData.dchr[2];
  DFTTmpData.dchr[2]=DFTTmpData.dchr[1];
  DFTTmpX1 += DFTTmpData.dint[1]>>1;

  /*==  Rx :265*{f(5)-f(7)-f(17)+f(19)};  Img:989*{f(5)+f(7)-f(17)-f(19)};  ====================================*/
  DFTTmp1=*(DFTDataAddr+ 5)-*(DFTDataAddr+17);
  DFTTmp2=*(DFTDataAddr+ 7)-*(DFTDataAddr+19);

  DFTTmpData.dlong=266*(long)(DFTTmp1-DFTTmp2);
  DFTTmpData.dchr[3]=DFTTmpData.dchr[2];
  DFTTmpData.dchr[2]=DFTTmpData.dchr[1];
  DFTTmpR1 += DFTTmpData.dint[1]>>1;

  DFTTmpData.dlong=990*(long)(DFTTmp1+DFTTmp2);
  DFTTmpData.dchr[3]=DFTTmpData.dchr[2];
  DFTTmpData.dchr[2]=DFTTmpData.dchr[1];
  DFTTmpX1 += DFTTmpData.dint[1]>>1;

  /*==  Rx :886*{f(2)-f(10)-f(14)+f(22)};  Img:512*{f(2)+f(10)-f(14)-f(22)};  ====================================*/
  DFTTmp1=*(DFTDataAddr+ 2)-*(DFTDataAddr+14);
  DFTTmp2=*(DFTDataAddr+10)-*(DFTDataAddr+22);

  DFTTmpData.dlong=886*(long)(DFTTmp1-DFTTmp2);
  DFTTmpData.dchr[3]=DFTTmpData.dchr[2];
  DFTTmpData.dchr[2]=DFTTmpData.dchr[1];
  DFTTmpR2  = DFTTmpData.dint[1]>>1;

  DFTTmpX2=DFTTmp1+DFTTmp2;
  /*DFTTmpData.dlong=512*(long)DFTTmpX2;DFTTmpData.dchr[3]=DFTTmpData.dchr[2];DFTTmpData.dchr[2]=DFTTmpData.dchr[1];DFTTmpX2  = DFTTmpData.dint[1]/2;  */

  /*==  Rx :512*{f(4)-f(8)-f(16)+f(20)};  Img:886*{f(4)+f(8)-f(16)-f(20)};  ====================================*/
  DFTTmp1=*(DFTDataAddr+ 4)-*(DFTDataAddr+16);
  DFTTmp2=*(DFTDataAddr+ 8)-*(DFTDataAddr+20);
  /*DFTTmpData.dlong=512*(long)DFTTmpR4;DFTTmpData.dchr[3]=DFTTmpData.dchr[2];DFTTmpData.dchr[2]=DFTTmpData.dchr[1];DFTTmpR2 += DFTTmpData.dint[1]/2;  */
  DFTTmpR2 += (DFTTmp1-DFTTmp2);

  DFTTmpData.dlong=886*(long)(DFTTmp1+DFTTmp2);
  DFTTmpData.dchr[3]=DFTTmpData.dchr[2];
  DFTTmpData.dchr[2]=DFTTmpData.dchr[1];
  DFTTmpX2 += DFTTmpData.dint[1]>>1;

  /*==  Rx :1024*{f(0)-f(12)};    Img:1024*{f(6)-f(18)};  =======================================================*/
  DFTTmp2=*DFTDataAddr-*(DFTDataAddr+12);
  /*DFTTmpData.dlong=1024*(long)DFTTmp2;  DFTTmpData.dchr[3]=DFTTmpData.dchr[2];  DFTTmpData.dchr[2]=DFTTmpData.dchr[1];  DFTTmpR2 += DFTTmpData.dint[1]/2;  */
  DFTTmp2 +=DFTTmp2;
  DFTTmpR2 += DFTTmp2;

  DFTTmp1=*(DFTDataAddr+ 6)-*(DFTDataAddr+18);
  /*DFTTmpData.dlong=1024*(long)DFTTmp1;DFTTmpData.dchr[3]=DFTTmpData.dchr[2];DFTTmpData.dchr[2]=DFTTmpData.dchr[1];DFTTmpX2 += DFTTmpData.dint[1]/2;  */
  DFTTmp1 += DFTTmp1;
  DFTTmpX2 += DFTTmp1;

  DFTTmp1 = (DFTTmpR1>>1) + (DFTTmpR2>>1);
  DFTTmp2 = (DFTTmpX1>>1) + (DFTTmpX2>>1);
}

void IntPer20ms(void)		//每20毫秒响应的一次中断,作为周期量计算的定时器
{
xdata float fTmpR1,fTmpX1,fTmpR2,fTmpX2;
xdata float fValR1,fValX1;

    if(bIntPer20ms==FALSE) return;	
	            //在程序刚开始时需要闭锁一段时间,使采样数据满足至少一个周期的有效队列后,本程序才开始计算
  				//一旦在突变量检测中发现监控对象出现故障,本程序也终止计算。
  				//此变量在程序初始化时清零,在每周期采样中满足要求时置位。
	 
	if(bInt20ms==TRUE){
       
	   bInt20ms=FALSE;
	    //以下完成A相电压、电流的DFT分解,在两表法时接Uab,Ia;在三表法时接Ua,Ia    

       DFTDataAddr=Chan_Ua;
       DFTDataAddr=DFTDataAddr+ OldSmpPtr;
       Fast_DFT();            
       
       fTmpR2=(float)DFTTmp2;
       fTmpX2=(float)DFTTmp1;//刘兵加
       
       fValR1 = fSetK[0] * fTmpR2 ;		//完成其幅值与相位的校正:实部,A相电压是参考相没有角度的校正
       fValX1 = fSetK[0] * fTmpX2 ;		//完成其幅值与相位的校正:虚部,A相电压是参考相没有角度的校正
       
       VectorR[0] = fValR1;
       VectorX[0] = fValX1;

       DFTDataAddr=Chan_Ia;
       DFTDataAddr=DFTDataAddr+ OldSmpPtr;
       Fast_DFT();            

       fTmpR2=(float)DFTTmp2;
       fTmpX2=(float)DFTTmp1;//刘兵加
       //,A相电流及后续电量需要进行角度的校正
       fTmpR1 = fSetK[1] * ( fTmpR2 * fSetArjR[1] - fTmpX2 * fSetArjX[1] );		//完成其幅值与相位的校正:实部
       fTmpX1 = fSetK[1] * ( fTmpX2 * fSetArjR[1] + fTmpR2 * fSetArjX[1] );		//完成其幅值与相位的校正:虚部
       
       VectorR[1] = fTmpR1;
       VectorX[1] = fTmpX1;

	   //A相有功功率和无功功率的计算
	   fCalP[0]= (fValR1 * fTmpR1 + fValX1 * fTmpX1);
	   fCalQ[0]= (fValX1 * fTmpR1 - fValR1 * fTmpX1);				//记录各个通道的计算功率:浮点数类型
    
       //以下完成C相电压、电流的DFT分解,在两表法时接Ucb,Ic;在三表法时接Uc,Ic    
       DFTDataAddr=Chan_Uc;
       DFTDataAddr=DFTDataAddr+ OldSmpPtr;
       Fast_DFT();            

       fTmpR2=(float)DFTTmp2;
       fTmpX2=(float)DFTTmp1;//刘兵加
       
       //,C相电压通道的角度与幅值校正
       fValR1 = fSetK[4] * ( fTmpR2 * fSetArjR[4] - fTmpX2 * fSetArjX[4] );		//完成其幅值与相位的校正:实部
       fValX1 = fSetK[4] * ( fTmpX2 * fSetArjR[4] + fTmpR2 * fSetArjX[4] );		//完成其幅值与相位的校正:虚部
       
	   VectorR[4] = fValR1;
       VectorX[4] = fValX1;

       DFTDataAddr=Chan_Ic;
       DFTDataAddr=DFTDataAddr+ OldSmpPtr;
       Fast_DFT();            

       fTmpR2=(float)DFTTmp2;
       fTmpX2=(float)DFTTmp1;//刘兵加
       
       //,C相电流角度的校正
       fTmpR1 = fSetK[5] * ( fTmpR2 * fSetArjR[5] - fTmpX2 * fSetArjX[5] );		//完成其幅值与相位的校正:实部
       fTmpX1 = fSetK[5] * ( fTmpX2 * fSetArjR[5] + fTmpR2 * fSetArjX[5] );		//完成其幅值与相位的校正:虚部
       
       VectorR[5] = fTmpR1;
       VectorX[5] = fTmpX1;

	   //C相有功功率和无功功率的计算
	   fCalP[2]= (fValR1 * fTmpR1 + fValX1 * fTmpX1) ;
	   fCalQ[2]= (fValX1 * fTmpR1 - fValR1 * fTmpX1) ;				//记录各个通道的计算功率:浮点数类型

       if(bMeter3!=0){		//装置采用三表法接线,此处需要计算Ub,Ib的大小.
    	  //以下完成B相电压、电流的DFT分解,在两表法时不接c;在三表法时接Ub,Ib    
    	  DFTDataAddr=Chan_Ub;
    	  DFTDataAddr=DFTDataAddr+ OldSmpPtr;
    	  Fast_DFT();          


       	  fTmpR2=(float)DFTTmp2;
          fTmpX2=(float)DFTTmp1;//刘兵加
       
          //,B相电压通道的角度与幅值校正
          fValR1 = fSetK[2] * ( fTmpR2 * fSetArjR[2] - fTmpX2 * fSetArjX[2] );		//完成其幅值与相位的校正:实部
          fValX1 = fSetK[2] * ( fTmpX2 * fSetArjR[2] + fTmpR2 * fSetArjX[2] );		//完成其幅值与相位的校正:虚部
       
          VectorR[2] = fValR1;
          VectorX[2] = fValX1;
    	
    	  DFTDataAddr=Chan_Ib;
    	  DFTDataAddr=DFTDataAddr+ OldSmpPtr;
    	  Fast_DFT();          

          fTmpR2=(float)DFTTmp2;
          fTmpX2=(float)DFTTmp1;//刘兵加
       
          //B相电流及后续电量需要进行角度的校正
          fTmpR1 = fSetK[3] * ( fTmpR2 * fSetArjR[3] - fTmpX2 * fSetArjX[3] );		//完成其幅值与相位的校正:实部
          fTmpX1 = fSetK[3] * ( fTmpX2 * fSetArjR[3] + fTmpR2 * fSetArjX[3] );		//完成其幅值与相位的校正:虚部
       
          VectorR[3] = fTmpR1;
          VectorX[3] = fTmpX1;
       
	      fCalP[1]= (fValR1 * fTmpR1 + fValX1 * fTmpX1);

⌨️ 快捷键说明

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