📄 emeter-foreground.c
字号:
{
P1OUT &= ~BIT4;
if ((j & 0x80))
P1OUT |= BIT7;
else
P1OUT &= ~BIT7;
P1OUT |= BIT4;
j <<= 1;
}
/* Clock the data into the output register */
P1OUT &= ~BIT6;
P1OUT |= BIT6;
}
#endif
#if defined(SINGLE_PHASE) && defined(NEUTRAL_MONITOR_SUPPORT) && defined(POWER_BALANCE_DETECTION_SUPPORT)
static long int test_phase_balance(long int live_signal, long int neutral_signal, int threshold)
{
int permitted_imbalance_fraction;
/* This may be testing between two currents, or between two powers. I normal mode it
is testing between two power readings. In limp mode it is testing between two
current readings. */
/* See which one is bigger, with some tolerance built in. If the signal measured
from the neutral is more than 6.25% or 12.5% (options) different from the signal
measured from the live there is something wrong (maybe fraudulent tampering, or
just something faulty). In this case we use the current measured from the
channel with the higher signal. When the channel is reasonably balanced, we use
the signal from the live lead. If neither signal is above the threshold we use
a more relaxed measure of imbalance (say 25% or even 50%), to allow for the lower
accuracy of these small signals (remember, we need the test to work well under
transient conditions, so the threshold needs to be far more relaxed than the
basic measurement accuracy would indicate). Assessments are persistence checked
to avoid transient conditions causing a false change of imbalance status. */
if (live_signal <= threshold && neutral_signal <= threshold)
permitted_imbalance_fraction = RELAXED_IMBALANCE_FRACTION;
else
permitted_imbalance_fraction = PERMITTED_IMBALANCE_FRACTION;
/* We have a signal strong enough for proper assessment. */
if ((phase->status & PHASE_UNBALANCED))
{
/* We are looking for the restoration of balance between the
live and neutral. */
if ((live_signal - (live_signal >> permitted_imbalance_fraction)) < neutral_signal
&&
neutral_signal < (live_signal + (live_signal >> permitted_imbalance_fraction)))
{
/* Things might be balanced, but persistence check to be sure. */
if (--current_unbalanced <= -PHASE_UNBALANCED_PERSISTENCE_CHECK)
{
/* Things look genuinely balanced. */
phase->status &= ~(PHASE_UNBALANCED | CURRENT_FROM_NEUTRAL);
current_unbalanced = 0;
}
}
else
{
current_unbalanced = 0;
/* The imbalanced might have swapped around - check. */
/* Here we just choose the greater signal each block, as we have
already confirmed (i.e. debounced) the imbalance condition. */
if (neutral_signal > live_signal)
phase->status |= CURRENT_FROM_NEUTRAL;
else
phase->status &= ~CURRENT_FROM_NEUTRAL;
}
}
else
{
/* We are looking for the live and neutral becoming unbalanced. */
if ((live_signal - (live_signal >> permitted_imbalance_fraction)) > neutral_signal
||
neutral_signal > (live_signal + (live_signal >> permitted_imbalance_fraction)))
{
/* Things might be unbalanced, but persistence check to be sure. */
if (++current_unbalanced >= PHASE_UNBALANCED_PERSISTENCE_CHECK)
{
/* Things look genuinely unbalanced. */
current_unbalanced = 0;
phase->status |= PHASE_UNBALANCED;
if (neutral_signal > live_signal)
phase->status |= CURRENT_FROM_NEUTRAL;
else
phase->status &= ~CURRENT_FROM_NEUTRAL;
}
}
else
{
current_unbalanced = 0;
}
}
/* Clear the unbalanced detection, so we don't display unbalanced. This should eliminate
flashing of the LED if the are transient conditions causing false indications of
imbalance. */
if (live_signal <= threshold && neutral_signal <= threshold)
phase->status &= ~PHASE_UNBALANCED;
if ((phase->status & CURRENT_FROM_NEUTRAL))
return neutral_signal;
return live_signal;
}
#endif
#if defined(MAINS_FREQUENCY_SUPPORT)
#if defined(SINGLE_PHASE)
int frequency(void)
#else
int frequency(struct phase_parms_s *phase)
#endif
{
long int x;
int step;
int offset;
/* Calculate the mains frequency in 1/100Hz increments, based on the mains
period assessment from the background activity. */
#if defined(LIMP_MODE_SUPPORT)
if (operating_mode == OPERATING_MODE_LIMP)
{
/* In limp mode there is no voltage waveform, so we get the frequency from
the current in the active lead. This may fail to measure frequency
correctly for very low currents, and very distorted current waveforms. */
#if defined(SINGLE_PHASE) && defined(NEUTRAL_MONITOR_SUPPORT)
if ((phase->status & CURRENT_FROM_NEUTRAL))
x = phase->neutral.mains_period;
else
#endif
x = phase->current.mains_period;
}
else
{
#endif
/* Normally we get the mains frequency from the voltage. Voltage is always
present, and is not subject to the same level of distortion as the current
waveform with difficult loads. */
/* Offset by half a sample period, as the FIR table gives delays between - and + 1/2 sample */
x = (phase->mains_period >> 18) - 128;
/* We have a whole cycle period, but we want the delay for 90 degrees, so we shift 2 for that.
We have estimated the period in 1/256 sample steps, but the FIR table is in 1/128th sample
steps. We shift 1 more for that. */
step = (x >> 8) + 1;
offset = 127 - ((x >> 1) & 0x7F);
#if REACTIVE_POWER_BY_QUADRATURE_SUPPORT
phase->current.quadrature_fir_beta = fir_coeffs[offset][0];
phase->current.quadrature_fir_gain = fir_coeffs[offset][1];
phase->current.quadrature_phase_correction_step = step + phase->current.in_phase_phase_correction_step[0];
#if defined(SINGLE_PHASE) && defined(NEUTRAL_MONITOR_SUPPORT)
phase->neutral.quadrature_fir_beta = fir_coeffs[offset][0];
phase->neutral.quadrature_fir_gain = fir_coeffs[offset][1];
phase->neutral.quadrature_phase_correction_step = step + phase->neutral.in_phase_phase_correction_step[0];
#endif
#endif
x = phase->mains_period;
#if defined(LIMP_MODE_SUPPORT)
}
#endif
x = (int32_t) SAMPLES_PER_10_SECONDS*256L*10L/(x >> 16);
return x;
}
#endif
#if defined(VRMS_SUPPORT)
#if defined(SINGLE_PHASE)
long int voltage(void)
#else
long int voltage(struct phase_parms_s *phase, struct phase_nv_parms_s const *phase_nv)
#endif
{
int i;
long int x;
/* Calculate the RMS voltage in 10mV increments. Return -1 for overrange
(i.e. ADC clip). */
if ((phase->status & V_OVERRANGE))
return -1;
x = div_sh48(phase->V_sq_accum_logged, 26 - 2*ADC_BITS, phase->sample_count_logged);
#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;
return x;
}
#endif
#if defined(IRMS_SUPPORT)
#if defined(SINGLE_PHASE)
long int current(void)
#else
long int current(struct phase_parms_s *phase, struct phase_nv_parms_s const *phase_nv, int ph)
#endif
{
#if defined(DYNAMIC_PHASE_CORRECTION_SUPPORT)
int i;
int j;
long int z;
int gain;
#endif
long int x;
#if defined(SINGLE_PHASE) && defined(NEUTRAL_MONITOR_SUPPORT)
long int y;
#endif
/* 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. */
/* We always have to work out the properly scaled current from both leads, in
order to work out the FIR coeffs for the next block. */
#if defined(SINGLE_PHASE) && defined(NEUTRAL_MONITOR_SUPPORT)
if ((phase->status & I_NEUTRAL_OVERRANGE))
{
y = -1;
#if defined(PRECALCULATED_PARAMETER_SUPPORT)
phase->neutral.I_rms = y;
#endif
#if defined(DYNAMIC_PHASE_CORRECTION_SUPPORT)
/* Use the last step in the phase shift table (i.e. the 55A and up step) */
i = 6 + 50 + 20;
j = 0;
#endif
}
else
{
#if ADC_BITS == 16
y = div48(phase->neutral.I_sq_accum_logged[0], phase->sample_count_logged);
#else
y = div_sh48(phase->neutral.I_sq_accum_logged[0], 32 - 2*ADC_BITS, phase->sample_count_logged);
#endif
y = isqrt32(y) - nv_parms.seg_a.s.neutral.ac_offset;
#if defined(LIMP_MODE_SUPPORT)
if (operating_mode == OPERATING_MODE_LIMP)
y = (y >> 12)*nv_parms.seg_a.s.neutral.I_rms_limp_scale_factor;
else
#endif
y = (y >> 12)*nv_parms.seg_a.s.neutral.I_rms_scale_factor;
y >>= 14;
#if defined(PRECALCULATED_PARAMETER_SUPPORT)
phase->neutral.I_rms = y;
#endif
#if defined(DYNAMIC_PHASE_CORRECTION_SUPPORT)
if (y < 0)
{
/* This should not happen, but just in case... */
i = 0;
j = 0;
}
else if (y < 5000)
{
/* 0.1A steps up to 5A */
i = y/100;
j = y%100;
}
else if (y < 25000)
{
/* 1A steps up to 25A */
i = (y - 5000)/1000 + 50;
j = (y%1000)/10;
}
else if (y < 55000)
{
/* 5A steps up to 60A */
i = (y - 25000)/5000 + 50 + 20;
j = (y%5000)/50;
}
else
{
/* Stick at the 55A position */
i = 6 + 50 + 20;
j = 0;
}
#endif
}
#if defined(DYNAMIC_PHASE_CORRECTION_SUPPORT)
gain = (uint8_t) phase_corrections[i][NEUTRAL_CURRENT_CHANNEL][1];
j = ((phase_corrections[i + 1][NEUTRAL_CURRENT_CHANNEL][0] - phase_corrections[i][NEUTRAL_CURRENT_CHANNEL][0])*j)/100;
i = nv_parms.seg_a.s.neutral.phase_correction + phase_corrections[i][NEUTRAL_CURRENT_CHANNEL][0] + j;
/* Adjust the phase shift to allow for the current mains frequency. This is just a linear
approximation, but should be good enough over the frequency ranges we must cover. */
if (frequency_phase_factor[NEUTRAL_CURRENT_CHANNEL])
{
/* The frequency correction is phase-shift dependant, and is proportional to the square of
the phase-shift. */
z = i*i;
z *= ((int) phase->frequency - MAINS_NOMINAL_FREQUENCY*100);
//z = z*frequency_phase_factor[NEUTRAL_CURRENT_CHANNEL];
z >>= 16;
/* 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->neutral.in_phase_phase_correction_step[0] = 2 + (i >> 8);
i &= 0xFF;
#if defined(__MSP430_HAS_ADC12__) || defined(__MSP430_HAS_ADC10__)
i >>= 1;
phase->neutral.in_phase_fir_beta[0] = fir_coeffs[i][0];
phase->neutral.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->neutral.sd16_preloaded_offset != i)
{
SD16PRE_NEUTRAL = phase->neutral.sd16_preloaded_offset - i;
phase->neutral.sd16_preloaded_offset = i;
}
#endif
#endif
#endif
if ((phase->status & I_OVERRANGE))
{
x = -1;
#if defined(PRECALCULATED_PARAMETER_SUPPORT)
phase->current.I_rms = x;
#endif
#if defined(DYNAMIC_PHASE_CORRECTION_SUPPORT)
/* Use the last step in the table (i.e. the 55A and up step) */
i = 6 + 50 + 20;
j = 0;
#endif
}
else
{
#if ADC_BITS == 16
x = div48(phase->current.I_sq_accum_logged[0], phase->sample_count_logged);
#else
x = div_sh48(phase->current.I_sq_accum_logged[0], 32 - 2*ADC_BITS, phase->sample_count_logged);
#endif
x = isqrt32(x) - phase_nv->current.ac_offset;
#if defined(LIMP_MODE_SUPPORT)
if (operating_mode == OPERATING_MODE_LIMP)
x = (x >> 12)*phase_nv->current.I_rms_limp_scale_factor[0];
else
#endif
x = (x >> 12)*phase_nv->current.I_rms_scale_factor[0];
x >>= 14;
#if defined(PRECALCULATED_PARAMETER_SUPPORT)
phase->current.I_rms = x;
#endif
#if defined(DYNAMIC_PHASE_CORRECTION_SUPPORT)
if (x < 0)
{
/* This should not happen, but just in case... */
i = 0;
j = 0;
}
else if (x < 5000)
{
/* 0.1A steps up to 5A */
i = x/100;
j = x%100;
}
else if (x < 25000)
{
/* 1A steps up to 25A */
i = (x - 5000)/1000 + 50;
j = (x%1000)/10;
}
else if (x < 55000)
{
/* 5A steps up to 60A */
i = (x - 25000)/5000 + 50 + 20;
j = (x%5000)/50;
}
else
{
/* Stick at the 55A position */
i = 6 + 50 + 20;
j = 0;
}
#endif
}
#if defined(DYNAMIC_PHASE_CORRECTION_SUPPORT)
#if !defined(SINGLE_PHASE)
gain = (uint8_t) phase_corrections[i][ph][1];
j = ((phase_corrections[i + 1][ph][0] - phase_corrections[i][ph][0])*j)/100;
i = phase_nv->current.phase_correction + phase_corrections[i][ph][0] + j;
#else
gain = (uint8_t) phase_corrections[i][0][1];
j = ((phase_corrections[i + 1][0][0] - phase_corrections[i][0][0])*j)/100;
i = phase_nv->current.phase_correction + phase_corrections[i][0][0] + j;
#endif
/* Adjust the phase shift to allow for the current mains frequency. This is just a linear
approximation, but should be good enough over the frequency ranges we must cover. */
#if defined(SINGLE_PHASE)
if (frequency_phase_factor[0])
#else
if (frequency_phase_factor[ph])
#endif
{
/* The frequency correction is phase-shift dependant, and is proportional to the square of
the phase-shift. */
z = i*i;
z *= ((int) phase->frequency - MAINS_NOMINAL_FREQUENCY*100);
//z = z*frequency_phase_factor[ph];
z >>= 16;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -