📄 calphased.c
字号:
#if ADC_COMPENSATION
// calculate temperature compensation for the meter
// This calculates the IC's adjustment, but probably needs
// the adjustments for the current sensors, as well
static void compensation (void)
{
int32x_t tppmc1, tppmc2;
int32x_t a, b;
int32x_t tn;
#if 1 == ENHANCED_TRIM
// These 51 bytes are dynamically allocated, so it doesn't waste RAM.
int8x_t trimbga, trimbgb, trimm;
int32x_t c, d;
// temporary values correspond to letters in the design-spreadsheet.
int32x_t td, tf, th, tj, tl;
#endif
// set temp_nom for calibration; note that the calibration
// is with the temperature compensation on.
temp_nom = temp_raw;
tn = temp_nom;
tppmc1 = 0; // the linear parts per million per degree C
tppmc2 = 0; // the quadratic parts per million per degree C
// code to add other components' temperature compensations
// to PPMC and PPMC2 goes here. tn is the calibration temperature.
// calculate and add in the IC's temperature compensation
#if 1 == ENHANCED_TRIM // compensate H-version (high-precision) parts
// read a trim value
trimbgb = Read_Trim (_TRIMBGB); // -128..127
// if the chip has not been trimmed
if (trimbgb == 0)
{
#endif // ENHANCED_TRIM.
// Set untrimmed defaults for temperature compensations.
a = -668; // -6.68 * (ppm/c) * 1000
b = -341000; // -0.341 * (ppm/c^2) * 1000000
#if 1 == ENHANCED_TRIM
}
else
{ // Chip is trimmed, so calculate the..
// ..temperature compensations, per the spreadsheet.
// Constants are not abstracted because they are used only here..
trimm = Read_Trim (_TRIMM); // -4..3
trimbga = Read_Trim (_TRIMBGA); // -128..127
#if M6520
// c = [(temp_nom/2427.249249) - (bga * 500) - 370000]/900
// 2427.249249 = (2^16)/(2^3)
tn = (tn + 256L) / 512L; // tn = tn / 2^9
td = ((tn * 27L) + 64L) / 128L;
th = ((int32_t)trimbga) * -500L;
tj = th - 370000L;
tf = td + tj;
c = (tf + 5L)/9L;
#elif TRACE11
// c = [(temp_nom/4.74074) - (bga * 500) - 370000]/900
// 4.74074 = 128/27
td = ((tn * 27L) + 64L) / 128L;
th = ((int32_t)trimbga) * -500L;
tj = th - 370000L;
tf = td + tj;
c = (tf + 5L)/9L;
#elif TRACE13
// Calculate c = [(temp_nom/2) - (bga * 500) - 370000]/900
td = tn / 2L;
th = ((int32_t)trimbga) * -500L;
tj = th - 370000L;
tf = td + tj;
c = (tf + 5L)/9L;
#else
#error unknown configuration
#endif
// Calculate d = (bgb /10) - [(m + 0.5)*0.14]
td = ((int32_t)trimbgb) * 100L;
th = (((int32_t)trimm) * 100L) + 50L;
tj = ((th * 14L) + 5L) / 10L;
d = td - tj;
// a = (-0.28c+33)d+0.33c+7.9
// calculate a
td = -28L * c;
tf = (td + (330000L + 5L)) / 10L;
th = ((tf * d) + 5000L) / 10000L;
tl = ((33L * c) + 50L) / 100L;
tn = tl + 790L;
a = th + tn;
// b = (-0.0002c+0.02)d-0.46
// Calculate b
td = -2L * c;
tf = td + 20000L;
th = ((tf * d) + 500L) / 1000L;
b = th - 460000L;
} // end else chip has a trim
#endif // ENHANCED_TRIM.
tppmc1 += ((22463L * a) + 50000L) / 100000L; // a * 2.4632
tppmc2 += ((1150L * b) + 500000L) / 1000000L; // b * 1150.1
ppmc1 = tppmc1;
ppmc2 = tppmc2;
}
#endif // compensation
// Adjust each element.
static void cal_end (void)
{
uint8_t element_index;
for (element_index = 0; element_index < ELEMENTS; ++element_index)
{
// Adjust the gains and phase of each element.
adjust_element (element_index);
}
}
// Adjust the gains and phase of an element.
// The assumed test signal is an AC signal with no phase offset between
// voltage and current.
// This calculates a rotating and scaling linear transform in polar
// coordinates to adjust the CE. The transform is an ideal solution,
// with no approximations beyond those in the data sheet.
static void adjust_element (uint8_t element_index)
{
const struct Element_t *pel; // pointer to an element
float WhI; // ideal watt-hours
float VI; // ideal volts
float fT; // temporary float
float WhM; // Watt hours measured
float VARhM; // VAR hours measured
float VAhM; // Volt-amps measured
float VM; // Volts measured
float Vgn; // Corrective gain of the voltage, 1=unity
// locate the Element's structure:
pel = &element_array[element_index];
// get measured Wh and VARh
WhM = s2f (pel->pwh); // s2f() converts 64-bit numbers to floats
#if VAR_ELEMENT
VARhM = s2f (pel->pvarh);
#else
VARhM = 0.0;
#endif
// Calculate volt-amps as measured
// VA is the radius of the circle.
#if VAR_ELEMENT
VAhM = sqrt( (WhM * WhM) + (VARhM * VARhM) );
#else
VAhM = WhM; // save the space
#endif
// Calibration equations begin here
// Find the tangent of the corrective phase angle
#if VAR_ELEMENT
// prevent divide by zero
if (WhM > -1.0e-17 && WhM < 1.0e-17)
WhM = 1.0e-17;
fT = -VARhM / WhM; // the tangent of the corrective phase angle
// Calculate the phase correction for the CE
// The phase correction is limited to +/- seven degrees
// tan(7 degrees) equals 0.12278
fT = max( -0.12278, min( 0.12278, fT ));
#if FREQUENCY
// if the line frequency is being measured, adapt to it
if (freq > (long)(55. / 0.587e-6)) // if the frequency > 55 Hz
{
// 60Hz calculation
fT = (0.02229 * fT)/(0.1487 - (0.0131 * fT));
}
else
{
// 50Hz calculation
fT = (0.0155 * fT)/(0.1241 - (0.009695 * fT));
}
#else
// if the line frequency isn't being measured
#if LINE_FREQ == 60 // define the line frequency in options.h
// 60Hz calculation
fT = (0.02229 * fT)/(0.1487 - (0.0131 * fT));
#elif LINE_FREQ == 50
// 50Hz calculation
fT = (0.0155 * fT)/(0.1241 - (0.009695 * fT));
#else
#error unknown line frequency
#endif
#endif
memset_ce (pel->pphase_adj, lroundf(fT));
#else // if no VARhs measured, no phase adjustment can be set.
memset_ce (pel->pphase_adj, 0L); // save the space
#endif
// convert measurements to watt-hours
// Note that this, like all numbers from the data sheet, assumes
// 2520.615 samples/sec, and an accumulation interval of 2520 samples.
if (Scal == 0)
Scal = 1;
#if M6520 || TRACE11
// 6.6952e-13 is from the 6511 or 6520 data sheets, divided by 100
// to compensate for the LSB of Vmax and Imax.
// Vmax is the PCB's designed maximum voltage in 0.1V.
// Imax is the PCB's designed maximum voltage in 0.1A.
// 3600.879 is the number of accumulation intervals per hour at 2520
// samples per accumulation interval. Samples are at 32768/13 Hz.
// cai is the measured count of accumulation intervals
VAhM = (VAhM * 6.6952e-15 * (float)Vmax * (float)Imax * 3600.879)/((float)cai);
// convert to volts; 4.9e-6 is sqrt(6.6952e-13*3600), from data sheet
VM = sqrt((float)(*(pel->pvsqsum))) * 4.90945e-6 * (float)Vmax;
#elif TRACE13
// 9.4045e-13 is from the 6513 or 6530 data sheets.
// Vmax is the PCB's designed maximum voltage in 0.1V.
// Imax is the PCB's designed maximum voltage in 0.1A.
// 3600.879 is the number of accumulation intervals per hour at 2520
// samples per accumulation interval. Samples are at 32768/13 Hz.
// cai is the measured count of accumulation intervals
VAhM = (VAhM * 9.4045e-15 * (float)Vmax * (float)Imax * 3600.879)/((float)cai);
// convert to volts; 5.82e-6 is sqrt(9.4045e-13*3600), from data sheet
VM = sqrt((float)(*(pel->pvsqsum))) * 5.81861e-6 * (float)Vmax;
#else
#error unknown device
#endif
// find the ideal values
// The ideal Vrms and Irms are stored in Totals.Parms
// in units of 0.1V and 0.1A respectively. Parameters_T is loaded
// from a table ri_Parms[] in defaults.c at power-up.
WhI = ((float)Vcal * (float)Ical) / (100.0); // ideal watt-hours
VI = ((float)(Vcal)) / (10.0); // ideal volts
// The voltage of the test signal has no harmonics or delay. (Ideally...)
Vgn = VI/VM; // calculate voltage gain, 1 = unity
fT = 16384. * Vgn; // convert to CE's LSBs for gain
fT = max(-32767., min(32767., fT)); // keep within limits
memset_ce (pel->pcal_v, lroundf(fT)); // correctly round and store
// Ign, the current gain, needs scaling to eliminate power errors,
// and rotation to eliminate phase error.
// Let Phi be the phase adjust angle.
// An Ign for a sinusoid test signal, rotating and scaling in the
// complex plane, multiplies one column of a rotational matrix, the
// real (geometrically horizontal) column, by the linear adjustment, so:
// Ign = (WhI * cos(Phi))/(WhM * Vgn)) + (VARhI * sin(Phi))/(VARhM * Vgn)
// But, the test signal's VARhI = 0, so that term is negligible.
// Further, cos(Phi) = WhM/VAhM; Substituting, we get the inscrutable:
fT = WhI/(VAhM * Vgn); // current gain, 1 = unity
fT = 16384. * fT; // convert to CE's LSBs for gain
fT = max(-32767., min(32767., fT)); // keep within limits
memset_ce (pel->pcal_i, lroundf(fT)); // correctly round and store
}
#endif // CAL_PHASE
/***************************************************************************
* History:
* $Log: calphased.c,v $
* Revision 1.11 2006/10/13 00:51:09 tvander
* Removed compile options for 6530, 6515;
* renamed 6511 and 6513 to trace11 and trace13;
* Binary verified unchanged from previous version.
*
* Revision 1.10 2006/09/09 01:12:57 gmikef
* *** empty log message ***
*
* Revision 1.9 2006/08/18 23:23:27 tvander
* Added calibration.c back to build in order to cope with differential meter
* equations, which it can calibrate, while caphased.c cannot.
*
* Revision 1.8 2006/07/10 23:21:36 tvander
* cal_restore() used to restore apulser and apulsew, which could sometimes cause spurious pulses on start-up. Now it restores them, but clears the CE registers before resuming.
*
* Revision 1.7 2006/06/14 02:40:25 tvander
* Can be compiled without an EEPROM
*
* Revision 1.6 2006/06/06 03:58:18 tvander
* Modified so that the save and restore functions are independent of the
* autocal functions.
*
* Revision 1.5 2006/05/25 03:29:29 tvander
* Renamed net-metering variables, so switch of nonvolatile has no conflicts.
* Calibration loader integrated.
*
* Revision 1.4 2006/05/18 23:18:50 tvander
* 16K and 32K
* First cut at new requirements.
* 32K 6521 is grossly tested.
* All others have a clean compile with C51 8.02
*
* Revision 1.3 2006/04/25 01:09:54 tvander
* Integrated improved RTC. Compensates for time off, has default constant
* compensation. Computes true hours of operation.
*
* Revision 1.2 2006/04/14 20:20:17 tvander
* Integrated, debugged on 6513
*
* Revision 1.1 2006/04/12 00:26:26 tvander
* Math is right for current and voltage gains. Phase number is right for my test signal, i.e. zero phase. Needs testing on a real meter.
*
* Revision 1.27 2006/02/08 03:43:24 tvander
* Made "import" the default power measurement mode, rather than net-metering
*
* Revision 1.26 2006/01/26 01:07:15 tvander
* Debugged calibration. It actually calibrates correctly.
*
* Revision 1.25 2006/01/25 01:04:23 tvander
* Calibration compiles but does not calibrate
*
* Revision 1.24 2006/01/11 00:50:57 gmikef
* *** empty log message ***
*
* Revision 1.22 2006/01/10 04:04:06 gmikef
* Added PDATA support for CE Outputs.
*
* Revision 1.21 2006/01/04 04:47:51 gmikef
* Switched RMS and VA calculations to use floating point. (and Calibration).
*
* Revision 1.19 2005/12/09 20:01:48 tvander
* Clean build
*
* Revision 1.18 2005/12/09 19:42:09 tvander
* Calibration save and restore now work in flash, and save and restore temp_nom
* in the 6520's temp_raw value for the CE variables.
*
* Revision 1.17 2005/12/07 02:30:46 tvander
* Added SO command.
* Fixed uninitialized variable in tempoerature compensation of calibration.
* Added xtal_freq to 6521 options, and alternative brownout baud rate
* to reg652x.h
* Rolled date.
*
* Revision 1.16 2005/12/07 01:43:51 tvander
* tn in temperature compensation was not being initialized.
*
* Revision 1.15 2005/10/31 17:38:03 tvander
* Includes improved EEPROM code with uwire.
* Clean build, all build trees (Thank-you, Mike!)
*
* Revision 1.14 2005/10/15 02:18:08 tvander
* Improved so compensation and extended trim can be separate options.
* Also improved the flash version to save a nominal temperature.
*
* Revision 1.13 2005/10/06 23:36:08 tvander
* Fixed calibration for 6520-- the nominal temperature is shifted left by
* 9 bits.
*
* Revision 1.12 2005/10/06 23:01:36 tvander
* Fixed I-147, default temperature compensation.
*
* Revision 1.11 2005/09/22 23:45:13 tvander
* Clean build all models and unit tests, updated copyright to be fore Teridian
*
* Revision 1.10 2005/08/30 18:14:24 gmikef
* *** empty log message ***
*
* Revision 1.9 2005/08/20 01:32:47 gmikef
* *** empty log message ***
*
* Revision 1.8 2005/08/19 01:04:43 gmikef
* *** empty log message ***
*
* Revision 1.7 2005/08/12 21:54:55 tvander
* Calibration compiles with the EEPROM option.
*
* Revision 1.6 2005/08/12 06:00:27 gmikef
* Added MPU temperature compensation for GAIN_ADJ.
* Added changes to support new CE 6521 code.
*
* Revision 1.5 2005/08/10 02:00:29 gmikef
* *** empty log message ***
*
* Revision 1.4 2005/07/14 20:15:50 tvander
* ce code concentrated in ce.c
* ce interface concentrated in ce652x.c, .h
* Fixed 0-length read or write using flag protocol.
* display.c is out of the build
* kwh_initialize now reads the LRC.
*
* Revision 1.3 2005/06/16 18:58:43 tvander
* Updates the debug values
*
* Revision 1.2 2005/06/10 22:57:07 tvander
* Uses macros to reset watchdog and clear IE and RTC interrupts
* Includes 6515 improvements in register defs.
*
* Revision 1.1 2005/05/13 00:34:46 tvander
* 6511/32k works
* Integrated and debugged self-calibration.
* The build has one unused segment, and no other errors or warnings.
* default LCD and pulse displays appear OK.
* EEPROM, software timers and hardware timers are all integrated.
*
* Revision 1.3 2005/04/30 02:12:43 gmikef
* *** empty log message ***
*
*
* Revision 1.2 2005/04/27 23:40:48 gmikef
* Some MATH rountines now use 'idata'.
* Added MATH_FAST flag to 'options.h".
* Changed "6521B.Uv2" to max optimization.
*
* Copyright (C) 2005 Teridian Semiconductor Corp. All Rights Reserved. *
* this program is fully protected by the United States copyright *
* laws and is the property of Teridian Semiconductor Corporation. *
***************************************************************************/
#endif /* calibration.c */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -