📄 calcomp.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 + -