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

📄 calphased.c

📁 TDK 6521 SOC 芯片 DEMO程序
💻 C
📖 第 1 页 / 共 2 页
字号:
#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 + -