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

📄 calcomp.cpp

📁 ADE7758校正程序,只需根据需要添加通信子程序
💻 CPP
字号:
#include "stdafx.h"
#include "math.h"
#include "calcomp.h"

// 四舍五入函数
inline static double round (double x)
{
	return floor(x+0.5);
}

// 取有效数字的函数,参数n为有效数字位数
static double dround (double x, int n)
{
	double z;
	int i;
	double y = pow(10.0,n-1);

	// 绝对值大于10的情况
	if (x>=10 || x<=-10)
	{
		z = x/10;
		i = 1;
		while (z>=10 || z<=-10)
		{
			z = z/10;
			i++;
		}
		z = round(z*y)/y;
		return z*pow(10.0,i);
	}
	// 绝对值小于1的情况
	if (x<1 && x>-1)
	{
		z = x*10;
		i = 1;
		while (z<1 && z>-1)
		{
			z = z*10;
			i++;
		}
		z = round(z*y)/y;
		return z/pow(10.0,i);
	}
	// 绝对值在1到10之间的情况
	return round(x*y)/y;
}

// ------------------------------------
// 校正各相电流和电压的偏移量
// ------------------------------------

// 函数ios_cal()校正各相电流
// 返回值为要写入寄存器的校正值

int ios_cal (
		double itest,	// itest表示标准电流值
		int itest_rms,	// itest_rms表示itest的测量值
		double imax_x,	// imax_x表示最大电流值的1/x
		int imax_x_rms	// imax_x_rms表示imax_x的测量值
	)
{
	double irmsos;
	if (itest_rms == 0 || imax_x_rms ==0)
		return 0;
	double itest2 = itest*itest;
	double imax_x2 = imax_x*imax_x;
	irmsos = (itest2*imax_x_rms*imax_x_rms-imax_x2*itest_rms*itest_rms)/(16384*(itest2-imax_x2));
	return (int) round(irmsos);
}

// 函数vos_cal()校正各相电压
// 返回值为要写入寄存器的校正值

int vos_cal (
		double vnom,	// vnom表示标准电压值
		int vnom_rms,	// vnom_rms表示vnom的测量值
		double vnom_x,	// vnom_x表示标准电压值的1/x
		int vnom_x_rms	// vnom_x_rms表示vnom_x的测量值
	)
{
	double vrmsos;
	if (vnom_rms == 0 || vnom_x_rms == 0)
		return 0;
    vrmsos = (vnom*vnom_x_rms-vnom_x*vnom_rms)/(64*(vnom_x-vnom));
	return (int) round(vrmsos);
}

// 函数cfref_comp()计算参考频率

double cfref_comp (
			double mc,
			double itest,
			double vnom,
			double pf	// 由于VAR时虽然功率因素是0,但是用的是sin进行计算,所以pf仍然为1
		)
{
	double cfref = mc*itest*vnom*pf/3600000.0;
	return dround(cfref,3);
}

// 函数cfnom_comp()估计没有设置CFDEN和CFNUM寄存器时的基准频率
double cfnom_comp (
			double itest,
			double vnom,
			double ifull,
			double vfull
		)
{
	double cfnom = 16000.0*itest*vnom/(ifull*vfull);
	return dround(cfnom,3);
}

// ------------------------------------
// 使用脉冲输出校正各相功率增益
// ------------------------------------

// 函数cfden_comp()计算预设置的ARCFDEN和VARCFDEN的值

int cfden_comp (
		double mc,		// 仪表的测量常数
		double itest,	// 测量电流
		double vnom,	// 测量电压
		double ifull,	// 最大电流
		double vfull	// 最大电压
	)
{
	double cfref,cfnom;
	// 计算CFref的值
	cfref = cfref_comp(mc,itest,vnom,1.0);
	// 计算xCFDEN值设置前的CF信号估计频率
	cfnom = cfnom_comp(itest,vnom,ifull,vfull);
	// 返回CFDEN的设置值
	return (int) round(cfnom/cfref);
}

// 函数gain_cal()对增益进行校正
// 返回增益寄存器的设置值

int gain_cal (
		double cf,		// 测量的cf信号频率
		double cfref,	// 参考cf信号频率
		double& gerr
	)
{
	double gain;
	if (fabs(cf)<1e-6)
	{
		gerr=0.0;
		return 0;
	}
	gerr = (cf-cfref)/cfref;
	gain = gerr/(-0.000244);
	return (int) round(gain);
}

// 函数whlsb_comp()计算功率寄存器的Wh/LSB

double whlsb_comp (
			double mc,		// 测量参数
			int cfden,		// CFDEN的值
			int cfnum,		// CFNUM的值
			int wdiv		// WDIV的值
		)
{
	return (250.0*cfnum*wdiv)/(mc*cfden);
}

// ------------------------------------
// 使用线累加模式校正各相功率增益
// ------------------------------------

// 函数actime_comp()计算能量累加时间

double actime_comp (
			int linecyc,	// 半线周期数
			int freq,		// 频率
			int nphase		// 选择的相数
		)
{
	return 0.5*linecyc/(freq*nphase);
}

// 函数gain_cal2()使用线累加模式校正增益

int gain_cal2 (
		double mc,		// 测量常数
		double itest,
		double vnom,
		double actime,
		int	power,		// 寄存器中读取的能量值
		int div,		// xDIV寄存器中的值
		double& whlsb	// Wh/LSB,VA/LSB,VARh/LSB的值
	)
{
	double gain;

	if (power==0)
	{
		whlsb=0.0;
		return 0;
	}
	whlsb = itest*vnom*actime/(3600*power);
	gain = 16.384*mc*whlsb*div;
	return (int) round(gain);
}

// ------------------------------------
// 使用脉冲输出校正各相相位
// ------------------------------------

// 函数phase_cal()校正相位

int phase_cal (
		int freq,
		double cf,		// 实测频率
		double cfref,
		double& pherr
	)
{
//	double pherr;
	double phcal;
	if (fabs(cf)<1e-6)
	{
		pherr=0.0;
		return 0;
	}

//	double cfref;
//	cfref = cfref_comp(mc,itest,vnom,0.5);	// 计算参考频率
	pherr = asin((cfref-cf)/(cfref*sqrt(3)))/asin(1)*90;  // 计算相位误差,用角度表示
	pherr = dround(pherr,3);
	if (pherr<0.0)
		phcal = freq/(-1440.0*pherr);
	else
		phcal = freq/(-720.0*pherr);

	return (int) round(phcal);
}

// ------------------------------------
// 使用线累加模式校正相位
// ------------------------------------

// 函数phase_cal2()用线累加模式校正相位

int phase_cal2(
		int power1,		// PF=1时的功率
		int power5,		// PF=0.5时的功率
		int freq,
		double& pherr
	)
{
	double phcal;
	
	if (power1 == 0 || power5 == 0)
	{
		pherr = 0.0;
		return 0;
	}
	pherr = asin((power1-2.0*power5)/(power1*sqrt(3)))/asin(1)*90;

	if (pherr<0.0)
		phcal = freq/(-1440.0*pherr);
	else
		phcal = freq/(-720.0*pherr);

	return (int) round(phcal);
}

// ------------------------------------
// 使用脉冲输出模式校正各相偏移
// ------------------------------------

// 函数offset_cal()校正偏移

int offset_cal(
		double clkin,
		double cf,
		double cfref,
		int cfden,
		int cfnum,
		int	freq,
		int fvar,		// fvar为1说明是对VAR进行偏移校正
		double& oserr
	)
{
	double q;
	double oscal;
	if (fabs(cf)<1e-6)
	{
		oserr = 0.0;
		return 0;
	}
	q = clkin/536870912.0;	// clkin/(1024*1024*512)
	if (fvar==1)
		q = q*1616.0/freq;
	
	oserr = (cf-cfref)/cfref;
	oscal = -oserr*cfref*16.0*cfden/(q*cfnum);
	return (int) round(oscal);
}

// ------------------------------------
// 使用线累加模式校正各相偏移
// ------------------------------------

// 函数offset_cal2()使用线累加模式校正偏移

int offset_cal2 (
		double clkin,
		double imin,	// 最小电流
		double itest,	// 测试电流
		int pmin,	// 最小功率
		int ptest,	// 测试功率
		double actime
	)
{
	double oscal;
	if (pmin == 0 || ptest == 0)
		return 0;

	oscal = 4*536870912.0/(actime*clkin)*(pmin*itest-ptest*imin)/(imin-itest);
	return (int) round(oscal);
}

⌨️ 快捷键说明

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