📄 emeter-foreground.c
字号:
/* Half bit round */
z++;
i -= z;
}
#if defined(__MSP430_HAS_ADC12__) || defined(__MSP430_HAS_ADC10__)
/* We use a +/- 0.5 sample FIR interpolator to perform the phase correction. We use a set
of coefficients from a table of 128 spread evenly across the +/- 0.5 sample range.
We need to get the phase shift into range, and end up with an FIR table entry in the
range 0 (-0.5 samples) to 127 (+0.5 samples), and the number of whole sample steps
to use inconjunction with it. */
i += 128;
#endif
gain = 32767 - (gain << 2);
/* Update the whole group quickly, so the interrupt routine uses a consistent pair of
step and beta values. */
phase->current.in_phase_phase_correction_step[0] = 2 + (i >> 8);
i &= 0xFF;
#if defined(__MSP430_HAS_ADC12__) || defined(__MSP430_HAS_ADC10__)
i >>= 1;
phase->current.in_phase_fir_beta[0] = fir_coeffs[i][0];
phase->current.in_phase_fir_gain[0] = Q1_15_mul(gain, fir_coeffs[i][1]);
#elif defined(__MSP430_HAS_SD16_3__)
if (operating_mode == OPERATING_MODE_NORMAL && phase->current.sd16_preloaded_offset != i)
{
SD16PRE_LIVE = phase->current.sd16_preloaded_offset - i;
phase->current.sd16_preloaded_offset = i;
}
#endif
#endif
#if defined(LIMP_MODE_SUPPORT)
if (operating_mode == OPERATING_MODE_LIMP)
{
/* We need to work out for ourselves which is the relevant current
to use. */
#if defined(SINGLE_PHASE) && defined(NEUTRAL_MONITOR_SUPPORT) && POWER_BALANCE_DETECTION_SUPPORT
x = test_phase_balance(x, y, PHASE_UNBALANCED_THRESHOLD_CURRENT);
/* In limp mode we have no way to determine if the phase is reversed,
so just say it is not. */
phase->status &= ~PHASE_REVERSED;
#endif
}
else
#endif
{
/* The power calculation has provided us which is the appropriate
current to use. */
#if defined(SINGLE_PHASE) && defined(NEUTRAL_MONITOR_SUPPORT)
if ((phase->status & CURRENT_FROM_NEUTRAL))
x = y;
#endif
}
return x;
}
#endif
#if !defined(SINGLE_PHASE) && defined(NEUTRAL_MONITOR_SUPPORT) && defined(IRMS_SUPPORT)
long int neutral_current(void)
{
long int x;
/* Calculate the RMS current in 1mA increments. Return -1 for overrange
(i.e. ADC clip). A side effect of this routine is it updates the dynamic
phase correction settings, based on the newly calculated current. */
if ((neutral.status & I_OVERRANGE))
{
x = -1;
}
else
{
#if ADC_BITS == 16
x = div48(neutral.I_sq_accum_logged[0], neutral.sample_count_logged);
#else
x = div_sh48(neutral.I_sq_accum_logged[0], 32 - 2*ADC_BITS, neutral.sample_count_logged);
#endif
x = isqrt32(x);
#if defined(LIMP_MODE_SUPPORT)
if (operating_mode == OPERATING_MODE_LIMP)
x = (x >> 12)*nv_parms.seg_a.s.neutral.I_rms_limp_scale_factor;
else
#endif
x = (x >> 12)*nv_parms.seg_a.s.neutral.I_rms_scale_factor;
x >>= 14;
}
return x;
}
#endif
long int fredx;
long int fredy;
#if defined(SINGLE_PHASE)
long int power(void)
#else
long int power(struct phase_parms_s *phase, struct phase_nv_parms_s const *phase_nv)
#endif
{
long int x;
long int y;
int i;
#if defined(PHASE_REVERSED_DETECTION_SUPPORT)
int reversed;
#endif
/* We can only do real power assessment in full operating mode. */
/* If we have neutral monitoring for a single phase meter, we need to measure
both power levels, and decide between them. Issues to be assessed here are
whether one or both leads show reverse power, and whether the power levels
are balanced. */
#if defined(PHASE_REVERSED_DETECTION_SUPPORT)
/* If we find a negative power level we may be genuinely feeding power to the grid,
or we may be seeing a tamper condition. This is application dependant. */
reversed = FALSE;
#endif
x = div_sh48(phase->current.P_accum_logged[0], 27 - 2*ADC_BITS, phase->sample_count_logged);
i = phase_nv->current.P_scale_factor[0];
#if defined(PHASE_CORRECTION_SUPPORT) && (defined(__MSP430_HAS_ADC12__) || defined(__MSP430_HAS_ADC10__))
i = Q1_15_mul(i, phase->current.in_phase_fir_gain[0]);
#endif
fredx = mul48(x, i);
x = fredx;
#if GAIN_STAGES > 1
y = div_sh48(phase->current.P_accum_logged[1], 27 - 2*ADC_BITS, phase->sample_count_logged);
i = phase_nv->current.P_scale_factor[1];
#if defined(PHASE_CORRECTION_SUPPORT) && (defined(__MSP430_HAS_ADC12__) || defined(__MSP430_HAS_ADC10__))
i = Q1_15_mul(i, phase->current.in_phase_fir_gain[1]);
#endif
fredy = mul48(y, i);
x += fredy;
#endif
#if defined(PRECALCULATED_PARAMETER_SUPPORT)
phase->current.power = x;
#endif
#if defined(PHASE_REVERSED_DETECTION_SUPPORT)
if (x < 0)
{
#if defined(PHASE_REVERSED_IS_TAMPERING)
x = -x;
#endif
phase->status |= I_REVERSED;
if (x > PHASE_REVERSED_THRESHOLD_POWER)
reversed = TRUE;
}
else
{
phase->status &= ~I_REVERSED;
}
#endif
#if defined(SINGLE_PHASE) && defined(NEUTRAL_MONITOR_SUPPORT)
y = div_sh48(phase->neutral.P_accum_logged[0], 27 - 2*ADC_BITS, phase->sample_count_logged[0]);
i = nv_parms.seg_a.s.neutral.P_scale_factor[0];
#if defined(PHASE_CORRECTION_SUPPORT) && (defined(__MSP430_HAS_ADC12__) || defined(__MSP430_HAS_ADC10__))
i = Q1_15_mul(i, phase->neutral.in_phase_fir_gain[0]);
#endif
y = mul48(y, i);
#if defined(PRECALCULATED_PARAMETER_SUPPORT)
phase->neutral.power = y;
#endif
#if defined(PHASE_REVERSED_DETECTION_SUPPORT)
if (y < 0)
{
#if defined(PHASE_REVERSED_IS_TAMPERING)
y = -y;
#endif
phase->status |= I_NEUTRAL_REVERSED;
if (y > PHASE_REVERSED_THRESHOLD_POWER)
reversed = TRUE;
}
else
{
phase->status &= ~I_NEUTRAL_REVERSED;
}
#endif
#if defined(POWER_BALANCE_DETECTION_SUPPORT)
#if defined(SINGLE_PHASE)
x = test_phase_balance(x, y, PHASE_UNBALANCED_THRESHOLD_POWER);
#else
x = test_phase_balance(phase, x, y, PHASE_UNBALANCED_THRESHOLD_POWER);
#endif
if ((phase->status & PHASE_UNBALANCED))
{
/* When the phase is unbalanced we only look for reversed current in the
lead with the higher current. If we do not impose this restriction, coupling
through a parasitic CT power supply transformer can cause the reverse condition
to be raised incorrectly. If there is no parasitic supply this test is probably
a waste of time. */
if ((phase->status & CURRENT_FROM_NEUTRAL))
reversed = phase->status & I_NEUTRAL_REVERSED;
else
reversed = phase->status & I_REVERSED;
}
#endif
#endif
#if defined(PHASE_REVERSED_DETECTION_SUPPORT)
if ((phase->status & PHASE_REVERSED))
{
if (!reversed)
{
if (--current_reversed <= -PHASE_REVERSED_PERSISTENCE_CHECK)
{
phase->status &= ~PHASE_REVERSED;
current_reversed = 0;
}
}
else
{
current_reversed = 0;
}
}
else
{
if (reversed)
{
if (++current_reversed >= PHASE_REVERSED_PERSISTENCE_CHECK)
{
phase->status |= PHASE_REVERSED;
current_reversed = 0;
}
}
else
{
current_reversed = 0;
}
}
#endif
return x;
}
#if REACTIVE_POWER_SUPPORT
#if defined(SINGLE_PHASE)
int32_t reactive_power(void)
#else
int32_t reactive_power(struct phase_parms_s *phase, struct phase_nv_parms_s const *phase_nv)
#endif
{
int32_t x;
int16_t i;
/* We can only do real power assessment in full operating mode. */
#if defined(SINGLE_PHASE) && defined(NEUTRAL_MONITOR_SUPPORT)
/* If we have neutral monitoring for a single phase meter, we need to use whichever
channel has been selected by the anti-tamper validation scheme. */
if ((phase->status & CURRENT_FROM_NEUTRAL))
{
x = div_sh48(phase->neutral.P_reactive_accum_logged[0], 28 - 2*ADC_BITS, phase->sample_count_logged[0]);
i = nv_parms.seg_a.s.neutral.P_scale_factor[0];
#if REACTIVE_POWER_BY_QUADRATURE_SUPPORT
i <<= 1;
i = Q1_15_mul(i, phase->neutral.quadrature_fir_gain);
#endif
}
else
{
#endif
x = div_sh48(phase->current.P_reactive_accum_logged[0], 28 - 2*ADC_BITS, phase->sample_count_logged[0]);
i = phase_nv->current.P_scale_factor[0];
#if REACTIVE_POWER_BY_QUADRATURE_SUPPORT
i <<= 1;
i = Q1_15_mul(i, phase->current.quadrature_fir_gain);
#endif
#if defined(SINGLE_PHASE) && defined(NEUTRAL_MONITOR_SUPPORT)
}
#endif
x = mul48(x, i);
#if PHASE_REVERSED_DETECTION_SUPPORT
if (x < 0)
{
#if PHASE_REVERSED_IS_TAMPERING
x =- x;
#endif
}
#endif
return x;
}
#endif
#if defined(VA_POWER_SUPPORT)
#if defined(SINGLE_PHASE)
int32_t VA_power(void)
#else
int32_t VA_power(struct phase_parms_s *phase, struct phase_nv_parms_s const *phase_nv)
#endif
{
#if REACTIVE_POWER_BY_QUADRATURE_SUPPORT
int32_t p;
int32_t x;
int shift;
/* Calculate apparent (VA) power in 0.01W increments */
p = labs(phase->power);
x = labs(phase->reactive_power);
/* Justify for optimal accuracy */
shift = 0;
while ((p & 0xFFFF8000) || (x & 0xFFFF8000))
{
shift++;
p >>= 1;
x >>= 1;
}
x = isqrt32(p*p + x*x);
x >>= (16 - shift);
#else
int16_t i;
int32_t x;
int32_t y;
/* Calculate VA power in 0.01W increments */
#if defined(SD16CCTL0_)
x = div_sh48(phase->V_sq_accum_logged, -6, phase->sample_count_logged[0]);
#else
x = div_sh48(phase->V_sq_accum_logged, 2, phase->sample_count_logged[0]);
#endif
#if defined(LIMP_MODE_SUPPORT)
if (operating_mode == OPERATING_MODE_LIMP)
i = phase_nv->V_rms_limp_scale_factor;
else
#endif
i = phase_nv->V_rms_scale_factor;
x = isqrt32(x);
x = (x >> 12)*i;
x >>= 14;
#if defined(SINGLE_PHASE) && defined(NEUTRAL_MONITOR_SUPPORT)
if ((phase->status & CURRENT_FROM_NEUTRAL))
{
#if defined(SD16CCTL0_)
y = div48(phase->neutral.I_sq_accum_logged[0], phase->sample_count_logged[0]);
#else
y = div_sh48(phase->neutral.I_sq_accum_logged[0], 8, phase->sample_count_logged[0]);
#endif
y = isqrt32(y);
#if defined(LIMP_MODE_SUPPORT)
if (operating_mode == OPERATING_MODE_LIMP)
y = (y >> 12)*nv_parms.s.neutral.I_rms_limp_scale_factor[0];
else
#endif
y = (y >> 12)*nv_parms.s.neutral.I_rms_scale_factor[0];
y >>= 14;
}
else
{
#endif
#if defined(SD16CCTL0_)
y = div48(phase->current.I_sq_accum_logged[0], phase->sample_count_logged[0]);
#else
y = div_sh48(phase->current.I_sq_accum_logged[0], 8, phase->sample_count_logged[0]);
#endif
y = isqrt32(y);
#if defined(LIMP_MODE_SUPPORT)
if (operating_mode == OPERATING_MODE_LIMP)
y = (y >> 12)*phase_nv->current.I_rms_limp_scale_factor[0];
else
#endif
y = (y >> 12)*phase_nv->current.I_rms_scale_factor[0];
y >>= 14;
#if defined(SINGLE_PHASE) && defined(NEUTRAL_MONITOR_SUPPORT)
}
#endif
x *= y;
x /= 1000;
#endif
return x;
}
#endif
#if defined(POWER_FACTOR_SUPPORT)
#if defined(SINGLE_PHASE)
int power_factor(void)
#else
int power_factor(struct phase_parms_s *phase, struct phase_nv_parms_s const *phase_nv)
#endif
{
long int p;
long int x;
p = labs(phase->power);
x = labs(phase->VA_power);
if (p && x)
{
/* Justify for optimal accuracy */
while ((p & 0x40000000) == 0 && (x & 0x40000000) == 0)
{
p <<= 1;
x <<= 1;
}
x >>= 16;
p /= x;
p *= 10000;
p >>= 16;
/* Don't let a little imprecision cause strange answers */
if (p > 10000)
p = 10000;
}
else
{
p = 0;
}
/* Use a negative PF to indicate an inductive load */
#if defined(SINGLE_PHASE) && defined(NEUTRAL_MONITOR_SUPPORT)
if ((phase->status & CURRENT_FROM_NEUTRAL))
{
if (phase->neutral.leading < 0)
p = -p;
}
else
#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -