📄 calibration.c
字号:
//**************************************************************************
// This program extracts the pulse from a reference meter and use this to calculate
// the calibration the meter.
// This program also stores the calibrated values in flash
// A 32 bit threshold called E_accum_threshold and A 32 bit energy register call E_accum
// is used
// A 32 bit counter call E_accum_count shows the amount of counts of the E_accum
// exceeding E_accum_threshold
// Add a new flag called energy tick.
//
// Vincent Chan
// Texas Instruments Hong Kong Ltd
// Date Comments
// =====================
// 01/10/15 Code Starts, need to add more variables to the channel parameters long array
// 01/10/5 module more or less working.
// 01/10/23 phase compensation and pulse compensation now working. Pulse compensation
// has been tested with a reference meter.
// 01/11/27 Now the reference pulse comes into P1.1/TA0 so use CCR0 for reference pulse
//**************************************************************************
#include "emeter_3phase.h"
#include "math.h"
//--------------------------------------------------------------------------
unsigned int local_pulse_count,ref_pulse_count;
unsigned int local_last_capture,ref_last_capture;
unsigned long local_total_time,ref_total_time;
extern long FLASH_INFO_E_accum_threshold;
extern long logged_shifted_p_accum,shift_p_accum;
extern int logged_shifted_p_count,shifted_p_count;
extern int sinne_1,sinne_2;
extern int samples_read_index,samples_write_index,shifted_samples_read_index;
extern double chan1_ratio;
extern int chan1_int_params[17];
extern int FLASH_INFO_average_temperature,FLASH_INFO_average_VeREF_range;
extern int average_temperature,average_VeREF_range;
extern int instant_temperature,instant_VeREF_PLUS,instant_VeREF_MINUS;
void calibrate_starts(int* int_params, long* long_params)
{
int* chan_int_params;
long* chan_long_params;
long l_word;
float* f_ptr;
int i;
float ratio,param1,param2;
chan_long_params=long_params;
chan_int_params=int_params;
//setup and enable TIMER_A for channel 1 calibrating
//setup TAR_A to use 32768 as master clock
//CCR2 as capture mode
//TACCTL1=CAP+CCIS0+CM1; //
//TACCTL1=CAP+CM_1;
//TACCTL0=CAP+CCIS0+CM_1;
//TACTL=TACLR+MC_2+TASSEL_1+ID1+ID0;
// start TIMER_A continous mode, ACLK as input clock
// DIV by 16 to give 8 seconds maximum duration
//wait for the first 6 pulses to let self settle, then start real calibration
local_last_capture=0;
ref_last_capture=0;
ref_total_time=0;
local_total_time=0;
local_pulse_count=16;
ref_pulse_count=16;
do
{
if((TACCTL0&CCIFG)&&(ref_pulse_count))
//reference meter pulse received
//only deal with it when pulse_count>0
{
TACCTL0&=~CCIFG; //reset flag
i=TACCR0-ref_last_capture; //work out delta
ref_last_capture=TACCR0; //store last value
if(ref_pulse_count<=10)
ref_total_time+=i; //only accum. after 6 pulses
DISPLAY(i,0);
DISPLAY_1DIGIT(ref_pulse_count,5); //display number of pulses captured
DISPLAY_1DIGIT(10,6); //display A for ref pulse
--ref_pulse_count;
}
// if((TACCTL0&CCIFG)&&(local_pulse_count)) //local pulse received
// {
// TACCTL0&=~CCIFG; //reset flag
// i=TACCR0-local_last_capture;
// local_last_capture=TACCR0;
if((int_params[channel_status]&E_TICK)&&(local_pulse_count))
{
int_params[channel_status]&=~E_TICK;
i=int_params[ENERGY_PERIOD];
if(local_pulse_count<=10)
local_total_time+=i;
DISPLAY(i,0);
DISPLAY_1DIGIT(local_pulse_count,5); //display number of pulses captured
DISPLAY_1DIGIT(11,6); //display B for localpulse
--local_pulse_count;
}
average_temperature=(average_temperature+instant_temperature)/2;
average_VeREF_range=(average_VeREF_range+(instant_VeREF_PLUS-instant_VeREF_MINUS))/2;
}while((local_pulse_count!=0)||(ref_pulse_count!=0));
//calculate the ratio between the reference pulse and generated pulse length
//Threshold = old Threshold * ref_time/local_time
//If reference meter pulse is quicker, then ref_total_time<local_total_time, we then
// want to decrease the threshold to make the local pulse faster. Hence
// Threshold * ref_time/local_time
ratio = (float) long_params[E_accum_threshold];
param1 = (float) local_total_time;
param2 = (float) ref_total_time;
ratio = ratio * param2/param1;
long_params[E_accum_threshold] = (long) ratio;
//*****************************************************
// Use the pulse period to calculate displayed power
// then the scale factor
//*****************************************************
#if 1
l_word=0;
for(i=0;i<8;i++)
{
while(!(int_params[channel_status]&NEW_P_LOG));
l_word+=long_params[logged_P_accum]/int_params[logged_P_count];
int_params[channel_status]&=~NEW_P_LOG;
DISPLAY(i,0);
}
l_word=l_word/8; //this is the average power by averageing
f_ptr= (float*) &long_params[POWER_SCALE_FACTOR];
DISPLAY(power_conversion(l_word,*f_ptr),0);
param1=(float)l_word;
//since float and long has the same number of words
//use a long array element to store a float
//reading/(32768/8) = time,
//power = 3600/(reading/4096) =3600*4096/reading;
//power to 0.1 Watt = 36000*4096/reading;
param2=(float) 36000*4096;
//work out the channel power
param2=param2/(float) int_params[ENERGY_PERIOD];
//channel_power=averaged_power*power_scale_factor
//power_scale_factor=channel_power/averaged_power
param2=param2/param1;
//store results
f_ptr = (float*) & long_params[POWER_SCALE_FACTOR];
*f_ptr = param2;
#endif
TACCTL0&=~CCIFG;
while(!(TACCTL0&CCIFG));
TACCTL0&=~CCIFG;
while(!(TACCTL0&CCIFG));
long_params[E_accum] = 0;
DISPLAY_1DIGIT(0x10,5); //0x10 equivalent to 0
DISPLAY_1DIGIT(0x10,6);
//Disable TIMER_A and comparator
//TACTL=0;
//store results in parameters in flash
}
void sync_with_reference(void)
{
_DINT();
//setup and enable TIMER_A for channel 1 calibrating
//setup TAR_A to use 32768 as master clock
//CCR2 as capture mode
//TACCTL1=CAP+CCIS0+CM1; //enables interrupt at CCR2 capture
//use comparator output as input
//use negative edge as input
//TACCTL1=CAP+CM_1;
//TACCTL0=CAP+CCIS0+CM_1;
//TACTL=TACLR+MC_2+TASSEL_1+ID1+ID0;
//wait for pulses from reference meter
TACCTL0&=~CCIFG;
while(!(TACCTL0&CCIFG));
TACCTL0&=~CCIFG;
while(!(TACCTL0&CCIFG));
//TACTL=0;
_EINT();
}
int calibrate_CT(int* int_params, long* long_params)
{
long total_power,shifted_total_power;
int i,j,k;
double phase_shift,ratio;
float* f_ptr;
_EINT();
k=0,j=0;
do //make this stable
{
if(int_params[channel_status]&(NEW_P_LOG+NEW_I_LOG+NEW_V_LOG))
{
//this flags indicates an X number of cycles of voltage signals as been
// added, the sum is divided by the number of samples to extract the
// DC bias level
if(int_params[channel_status]&NEW_V_LOG)
{
i=long_params[logged_V_accum]/int_params[logged_V_count];
int_params[V_bias]=(i+int_params[V_bias])/2;
int_params[channel_status]&=~NEW_V_LOG;
//DISPLAY(int_params[V_bias],0);
}
//this flags indicates an X number of cycles of current signals as been
// added, the sum is divided by the number of samples to extract the
// DC bias level
if(int_params[channel_status]&NEW_I_LOG)
{
i=long_params[logged_I_accum]/int_params[logged_I_count];
int_params[I_bias]=(int_params[I_bias]+i)/2;
int_params[channel_status]&=~NEW_I_LOG;
//DISPLAY(int_params[I_bias],0);
}
if(int_params[channel_status]&NEW_P_LOG)
{
total_power+=long_params[logged_P_accum]/int_params[logged_P_count];
shifted_total_power+=long_params[logged_PS_P_accum]/int_params[logged_PS_P_count];
int_params[channel_status]&=~NEW_P_LOG;
if(++j>=8)
{
total_power/=8;
shifted_total_power/=8;
ratio= (double) shifted_total_power/total_power;
f_ptr= (float*) &long_params[POWER_SCALE_FACTOR];
// DISPLAY(power_conversion(shifted_total_power,*f_ptr),0);
DISPLAY(power_conversion(total_power,*f_ptr),0);
DISPLAY_1DIGIT(k,5);
total_power=0;
shifted_total_power=0;
j=0;
k++;
}
average_temperature=(average_temperature+instant_temperature)/2;
average_VeREF_range=(average_VeREF_range+(instant_VeREF_PLUS-instant_VeREF_MINUS))/2;
}
}
// }while(k<10);
}while(k<5);
//each sample = (50/3276.8)*360 = 5.4931640625 degree or 0.09587379924285 rad
//each CT compensation step = 0.08583068847656 degree 0.00149802811317 rad
//This calculate the phase_shift based on the ratio between non shifted power and
phase_shift =calc_phase_shift(ratio);
phase_shift = phase_shift/(0.00149802811317); // divide by CT compensation step to get index
phase_shift += 0.5; // will convert result to integer only so need to
// do fractional adjustment
return((int) phase_shift);
}
// This rouine returns a phase shift in radians
// It uses the ratio between the power with an artificial current phase shift of 60.4 degree,
// and the power without this shift
// If p is the phase shift of the CT. Then the ratio can be expressed as:
// cos(60.4+p)/cos(p)=ratio
// cos(60.4)-sin(60.4)sin(p)/cos(p)=ratio
// sin(p)/cos(p)=[cos(60.4)-ratio]/sin(60.4)]
// Let's say [cos(60.4)-ratio]/sin(60.4)] = Q
// p = arc_cos[ square_root(1/(Q^2+1))]
// p is in radians.
// This equation does not detect sign of the shift which needs to be additionally worked out
double calc_phase_shift(double ratio)
{
double result;
int sign;
if(ratio>0.4935653955488) sign=1;
else sign=0; //delay by 11*5.49 degree
result=(0.4935653955488-ratio)/0.8697086870423; //= (cos(60.4)-ratio)/sin(60.4)
result= result*result+1;
result=1/result;
result=sqrt(result);
result =acos(result);
if(sign) return (-result);
else return(result); // each step = [(50/3276.8)2*PI]/64
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -