📄 emeter-background.c
字号:
+ phase->V_history[(phase->V_history_index - phase->current.in_phase_phase_correction_step[use_stage]) & V_HISTORY_MASK];
#else
corrected = phase->V_history[(phase->V_history_index - phase->current.in_phase_phase_correction_step[use_stage]) & V_HISTORY_MASK];
#endif
#else
corrected = V_sample;
#endif
accum48(phase->current.P_accum[use_stage], imul16(corrected, I_live_sample));
#if defined(REACTIVE_POWER_BY_QUADRATURE_SUPPORT)
corrected = (Q1_15_mul(phase->V_history[(phase->V_history_index - phase->current.quadrature_phase_correction_step - 1) & V_HISTORY_MASK], phase->current.quadrature_fir_beta) >> 1)
+ (phase->V_history[(phase->V_history_index - phase->current.quadrature_phase_correction_step) & V_HISTORY_MASK] >> 1);
accum48(phase->current.P_reactive_accum[use_stage], imul16(corrected, I_live_sample));
#endif
}
++phase->current.sample_count;
#if defined(SINGLE_PHASE) && defined(NEUTRAL_MONITOR_SUPPORT)
I_neutral_sample = phase->neutral.I_history[0][0];
phase->neutral.I_history[0][0] = phase->neutral.I_history[0][1];
corrected = adc_buffer[++adc_ptr];
if ((corrected >= ADC_MAX || corrected <= ADC_MIN) && phase->neutral.I_endstops)
phase->neutral.I_endstops--;
#if defined(__MSP430_HAS_SD16_3__)
phase->neutral.I_history[0][1] = corrected;
#else
//phase->neutral.I_history[0][1] = corrected - adc_buffer[++adc_ptr];
phase->neutral.I_history0[0][1] = corrected;
#endif
I_neutral_sample = dc_filter(&phase->neutral.I_dc_estimate, I_neutral_sample);
#if defined(IRMS_SUPPORT) || defined(POWER_FACTOR_SUPPORT)
accum48(phase->neutral.I_sq_accum[0], imul16(I_neutral_sample, I_neutral_sample));
#endif
if (operating_mode == OPERATING_MODE_NORMAL)
{
#if defined(PHASE_CORRECTION_SUPPORT)
#if defined(__MSP430_HAS_ADC12__) || defined(__MSP430_HAS_ADC10__)
corrected = Q1_15_mulq(phase->V_history[(phase->V_history_index - phase->neutral.in_phase_phase_correction_step - 1) & V_HISTORY_MASK], phase->neutral.in_phase_fir_beta)
+ phase->V_history[(phase->V_history_index - phase->neutral.in_phase_phase_correction_step) & V_HISTORY_MASK];
#else
corrected = phase->V_history[(phase->V_history_index - phase->neutral.in_phase_phase_correction_step) & V_HISTORY_MASK];
#endif
#else
corrected = V_sample;
#endif
accum48(phase->neutral.P_accum[0], imul16(corrected, I_neutral_sample));
#if defined(REACTIVE_POWER_BY_QUADRATURE_SUPPORT)
corrected = (Q1_15_mulq(phase->V_history[(phase->V_history_index - phase->neutral.quadrature_phase_correction_step - 1) & V_HISTORY_MASK], phase->neutral.quadrature_fir_beta) >> 1)
+ (phase->V_history[(phase->V_history_index - phase->neutral.quadrature_phase_correction_step) & V_HISTORY_MASK] >> 1);
accum48(phase->neutral.P_reactive_accum[0], imul16(corrected, I_neutral_sample));
#endif
}
++phase->neutral.sample_count[0];
#endif
#if defined(REACTIVE_POWER_BY_QUADRATURE_SUPPORT) || defined(PHASE_CORRECTION_SUPPORT)
phase->V_history_index = (phase->V_history_index + 1) & V_HISTORY_MASK;
#endif
++phase->sample_count;
#if defined(PER_PHASE_ENERGY_SUPPORT)
/* We now play the last measurement interval's power level, evaluated
in the foreground, through this measurement interval. In this way
we can evenly pace the pulsing of the LED. The only error produced
by this is the ambiguity in the number of samples per measurement.
This should not exceed 1 or 2 in over 4000. */
#if defined(LIMP_MODE_SUPPORT)
if (operating_mode == OPERATING_MODE_NORMAL)
{
#endif
#if defined(INHIBIT_NEGATIVE_PHASE_POWER_ACCUMULATION)
if (phase->power > 0 && (phase->power_counter += phase->power) >= PHASE_ENERGY_PULSE_THRESHOLD)
#else
if ((phase->power_counter += phase->power) >= PHASE_ENERGY_PULSE_THRESHOLD)
#endif
{
phase->power_counter -= PHASE_ENERGY_PULSE_THRESHOLD;
++phase->consumed_energy;
/* Ideally we want to log the energy each kWh unit, but doing
it with a mask here is good enough and faster. */
if ((phase->consumed_energy & 0x3FF) == 0)
phase->status |= ENERGY_LOGABLE;
/* Pulse the LED. Long pulses may not be reliable, as at full
power we may be pulsing several times per second. People may
check the meter's calibration with an instrument that counts
the pulsing rate, so it is important the pulses are clear,
distinct, and exactly at the rate of one per
1/ENERGY_PULSES_PER_KW_HOUR kW/h. */
#if !defined(SINGLE_PHASE)
switch (j)
{
case 0:
set_phase_1_energy_pulse_indicator();
break;
case 1:
set_phase_2_energy_pulse_indicator();
break;
case 2:
set_phase_3_energy_pulse_indicator();
break;
}
#else
set_energy_pulse_indicator();
#endif
phase->energy_pulse_remaining_time = ENERGY_PULSE_DURATION;
}
if (phase->energy_pulse_remaining_time && --phase->energy_pulse_remaining_time == 0)
{
#if !defined(SINGLE_PHASE)
switch (j)
{
case 0:
clr_phase_1_energy_pulse_indicator();
break;
case 1:
clr_phase_2_energy_pulse_indicator();
break;
case 2:
clr_phase_3_energy_pulse_indicator();
break;
}
#else
clr_energy_pulse_indicator();
#endif
}
#if defined(LIMP_MODE_SUPPORT)
}
else
{
if ((phase->power_counter += LIMP_SAMPLING_RATIO*phase->power) >= PHASE_ENERGY_PULSE_THRESHOLD)
{
phase->power_counter -= PHASE_ENERGY_PULSE_THRESHOLD;
++phase->consumed_energy;
if ((phase->consumed_energy & 0x3FF) == 0)
phase->status |= ENERGY_LOGABLE;
#if !defined(SINGLE_PHASE)
switch (j)
{
case 0:
set_phase_1_energy_pulse_indicator();
break;
case 1:
set_phase_2_energy_pulse_indicator();
break;
case 2:
set_phase_3_energy_pulse_indicator();
break;
}
#else
set_energy_pulse_indicator();
#endif
phase->energy_pulse_remaining_time = ENERGY_PULSE_DURATION;
}
if (phase->energy_pulse_remaining_time && (phase->energy_pulse_remaining_time -= LIMP_SAMPLING_RATIO) == 0)
{
#if !defined(SINGLE_PHASE)
switch (j)
{
case 0:
clr_phase_1_energy_pulse_indicator();
break;
case 1:
clr_phase_2_energy_pulse_indicator();
break;
case 2:
clr_phase_3_energy_pulse_indicator();
break;
}
#else
clr_energy_pulse_indicator();
#endif
}
}
#endif
#endif
/* Do the power cycle start detection */
/* There is no hysteresis used here, but since the signal is
changing rapidly at the zero crossings, and is always of
large amplitude, miscounting cycles due to general noise
should not occur. Spikes are another matter. A large spike
could cause the power cycles to be miscounted, but does not
matter very much. The cycle counting is not critical to power
or energy measurement. */
#if defined(MAINS_FREQUENCY_SUPPORT)
#if defined(LIMP_MODE_SUPPORT)
if (operating_mode == OPERATING_MODE_LIMP)
phase->cycle_sample_count += LIMP_SAMPLING_RATIO*256;
else
#endif
phase->cycle_sample_count += 256;
#endif
if (abs(V_sample - phase->last_V_sample) <= phase->since_last*4000)
{
/* This doesn't look like a spike - do mains cycle detection, and
estimate the precise mains period */
if (V_sample < 0)
{
/* Log the sign of the signal */
phase->status &= ~V_POS;
phase->since_last = 0;
phase->last_V_sample = V_sample;
}
else
{
if (!(phase->status & V_POS))
{
#if defined(MAINS_FREQUENCY_SUPPORT)
/* Apply limits to the sample count, to avoid spikes or dying power lines disturbing the
frequency reading too much */
/* The mains should be <40Hz or >70Hz to fail this test! */
if (256*SAMPLES_PER_10_SECONDS/700 <= phase->cycle_sample_count && phase->cycle_sample_count <= 256*SAMPLES_PER_10_SECONDS/400)
{
/* A mains frequency measurement procedure based on interpolating zero crossings,
to get a fast update rate for step changes in the mains frequency */
/* Interpolate the zero crossing by successive approx. */
z = V_sample - phase->last_V_sample;
x = 0;
y = 0;
for (k = 0; k < 8; k++)
{
y <<= 1;
z >>= 1;
x += z;
if (x > V_sample)
x -= z;
else
y |= 1;
}
/* Now we need to allow for skipped samples, due to spike detection */
z = y;
while (phase->since_last > 1)
{
z += y;
phase->since_last--;
}
/* z is now the fraction of a sample interval between the zero
crossing and the current sample, in units of 1/256 of a sample */
/* A lightly damped filter should now be enough to remove noise and get a
stable value for the frequency */
phase->mains_period += ((int32_t) (phase->cycle_sample_count - z) << 12) - (phase->mains_period >> 4);
/* Start the next cycle with the residual fraction of a sample */
phase->cycle_sample_count = z;
}
else
{
phase->cycle_sample_count = 0;
}
#endif
}
/* Log the sign of the signal */
phase->status |= V_POS;
phase->since_last = 0;
phase->last_V_sample = V_sample;
#if defined(POWER_FACTOR_SUPPORT)
/* Determine whether the current leads or lags, in a noise tolerant manner.
Testing 50 cycles means we will respond in about one second to a genuine
swap between lead and lag. Since that is also about the length of our
measurement blocks, this seems a sensible response time. */
if (I_live_sample < V_sample)
{
if (phase->current.leading > -50)
phase->current.leading--;
}
else
{
if (phase->current.leading < 50)
phase->current.leading++;
}
#if defined(SINGLE_PHASE) && defined(NEUTRAL_MONITOR_SUPPORT)
if (I_neutral_sample < V_sample)
{
if (phase->neutral.leading > -50)
phase->neutral.leading--;
}
else
{
if (phase->neutral.leading < 50)
phase->neutral.leading++;
}
#endif
#endif
/* See if a sufficiently long measurement interval has been
recorded, and catch the start of the next cycle. We do not
really care how many cycles there are, as long as the block
is a reasonable length. Setting a minimum of 1 second is
better than counting cycles, as it is not affected by noise
spikes. Synchronising to a whole number of cycles reduces
block to block jitter, though it doesn't affect the long
term accuracy of the measurements. */
if (phase->sample_count >= samples_per_second)
{
#if defined(SINGLE_PHASE)
log_parameters();
#else
log_parameters(phase);
#endif
#if defined(__MSP430__)
/* The foreground may be conserving power (e.g. in limp mode), so we
need to kick it. */
_BIC_SR_IRQ(LPM0_bits);
#else
/* When run as a host program there is no RTC, but we still need to
kick the foreground somehow. */
meter_status |= TICKER;
#endif
}
}
}
phase->since_last++;
if (phase->sample_count >= samples_per_second + 200)
{
/* We don't seem to be detecting the end of a mains cycle, so force
the end of processing block condition. */
#if defined(SINGLE_PHASE)
log_parameters();
#else
log_parameters(phase);
#endif
#if defined(__MSP430__)
/* The foreground may be conserving power (e.g. in limp mode), so we
need to kick it. */
_BIC_SR_IRQ(LPM0_bits);
#else
/* When run as a host program there is no RTC, but we still need to
kick the foreground somehow. */
meter_status |= TICKER;
#endif
}
#if defined(MAINS_FREQUENCY_SUPPORT)
/* Monitor the cycles and frequency of the current sensors, as limp
mode is based on these. */
#if defined(LIMP_MODE_SUPPORT)
if (operating_mode == OPERATING_MODE_LIMP)
phase->current.cycle_sample_count += 256*LIMP_SAMPLING_RATIO;
else
#endif
phase->current.cycle_sample_count += 256;
#endif
if (I_live_sample < 0)
{
/* Log the sign of the signal */
phase->status &= ~I_POS;
}
else
{
if (!(phase->status & I_POS))
{
/* A negative to positive transition has occurred. Trust it
blindly as a genuine zero crossing/start of cycle, even
though it might really be due to a noise spike. */
#if defined(MAINS_FREQUENCY_SUPPORT)
if (SAMPLES_PER_10_SECONDS/700 <= phase->current.cycle_sample_count && phase->current.cycle_sample_count <= SAMPLES_PER_10_SECONDS/400)
phase->current.mains_period += ((int32_t) phase->current.cycle_sample_count << 16) - (phase->current.mains_period >> 8);
phase->current.cycle_sample_count = 0;
#endif
}
/* Log the sign of the signal */
phase->status |= I_POS;
}
#if defined(SINGLE_PHASE) && defined(NEUTRAL_MONITOR_SUPPORT)
#if defined(MAINS_FREQUENCY_SUPPORT)
#if defined(LIMP_MODE_SUPPORT)
if (operating_mode == OPERATING_MODE_LIMP)
phase->neutral.cycle_sample_count += LIMP_SAMPLING_RATIO;
else
#endif
phase->neutral.cycle_sample_count++;
#endif
if (I_neutral_sample < 0)
{
/* Log the sign of the signal */
phase->status &= ~I_NEUTRAL_POS;
}
else
{
if (!(phase->status & I_NEUTRAL_POS))
{
/* A negative to positive transition has occurred. Trust it
blindly as a genuine zero crossing/start of cycle, even
though it might really be due to a noise spike. */
#if defined(MAINS_FREQUENCY_SUPPORT)
if (SAMPLES_PER_10_SECONDS/700 <= phase->neutral.cycle_sample_count && phase->neutral.cycle_sample_count <= SAMPLES_PER_10_SECONDS/400)
phase->neutral.mains_period += ((int32_t) phase->neutral.cycle_sample_count << 16) - (phase->neutral.mains_period >> 8);
phase->neutral.cycle_sample_count = 0;
#endif
}
/* Log the sign of the signal */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -