3-phase PV router
Loading...
Searching...
No Matches
processing.cpp
Go to the documentation of this file.
1
11
12#include <Arduino.h>
13
14#include "config.h"
15#include "calibration.h"
16#include "dualtariff.h"
17#include "processing.h"
18#include "utils_pins.h"
19#include "shared_var.h"
20
21// Define operating limits for the LP filters which identify DC offset in the voltage
22// sample streams. By limiting the output range, these filters always should start up
23// correctly.
24constexpr int32_t l_DCoffset_V_min{ (512L - 100L) * 256L };
25constexpr int32_t l_DCoffset_V_max{ (512L + 100L) * 256L };
26constexpr int16_t i_DCoffset_I_nom{ 512L };
27
29
35constexpr float f_offsetOfEnergyThresholdsInAFmode{ 0.1F };
36
38
39bool b_diversionStarted{ false };
40
53
54constexpr float f_lowerThreshold_default{ initThreshold(true) };
55constexpr float f_upperThreshold_default{ initThreshold(false) };
56
57float f_energyInBucket_main{ 0.0F };
60
61// for improved control of multiple loads
62bool b_recentTransition{ false };
63uint8_t postTransitionCount{ 0 };
64constexpr uint8_t POST_TRANSITION_MAX_COUNT{ 3 };
65// constexpr uint8_t POST_TRANSITION_MAX_COUNT{50}; /**< for testing only */
67
68int32_t l_sumP[NO_OF_PHASES]{};
73
76
78
80
81// For an enhanced polarity detection mechanism, which includes a persistence check
85
88
90
91uint8_t perSecondCounter{ 0 };
92
93bool beyondStartUpPeriod{ false };
94
111template< size_t N >
112constexpr void initializeArray(int32_t (&array)[N], int32_t value)
113{
114 for (size_t i = 0; i < N; ++i)
115 {
116 array[i] = value;
117 }
118}
119
134constexpr uint16_t getOutputPins()
135{
136 uint16_t output_pins{ 0 };
137
138 for (const auto &loadPin : physicalLoadPin)
139 {
140 if (bit_read(output_pins, loadPin))
141 return 0;
142
143 bit_set(output_pins, loadPin);
144 }
145
146 if constexpr (WATCHDOG_PIN_PRESENT)
147 {
148 if (bit_read(output_pins, watchDogPin))
149 return 0;
150
151 bit_set(output_pins, watchDogPin);
152 }
153
154 if constexpr (RELAY_DIVERSION)
155 {
156 for (uint8_t idx = 0; idx < relays.size(); ++idx)
157 {
158 const auto relayPin = relays.get_relay(idx).get_pin();
159
160 if (bit_read(output_pins, relayPin))
161 return 0;
162
163 bit_set(output_pins, relayPin);
164 }
165 }
166
167 return output_pins;
168}
169
185constexpr uint16_t getInputPins()
186{
187 uint16_t input_pins{ 0 };
188
189 if constexpr (DUAL_TARIFF)
190 {
191 if (bit_read(input_pins, dualTariffPin))
192 return 0;
193
194 bit_set(input_pins, dualTariffPin);
195 }
196
197 if constexpr (DIVERSION_PIN_PRESENT)
198 {
199 if (bit_read(input_pins, diversionPin))
200 return 0;
201
202 bit_set(input_pins, diversionPin);
203 }
204
205 if constexpr (PRIORITY_ROTATION == RotationModes::PIN)
206 {
207 if (bit_read(input_pins, rotationPin))
208 return 0;
209
210 bit_set(input_pins, rotationPin);
211 }
212
213 if constexpr (OVERRIDE_PIN_PRESENT)
214 {
215 // Add all configured override pins
216 for (uint8_t i = 0; i < overridePins.size(); ++i)
217 {
218 const uint8_t pin = overridePins.getPin(i);
219 if (bit_read(input_pins, pin))
220 return 0;
221
222 bit_set(input_pins, pin);
223 }
224 }
225
226 return input_pins;
227}
228
243{
244 initializeArray(l_DCoffset_V, 512L * 256L); // nominal mid-point value of ADC @ x256 scale
245
246 setPinsAsOutput(getOutputPins()); // set the output pins as OUTPUT
247 setPinsAsInputPullup(getInputPins()); // set the input pins as INPUT_PULLUP
248
249 uint8_t i{ NO_OF_DUMPLOADS };
250 do
251 {
252 --i;
255 } while (i);
256
257 // First stop the ADC
258 bit_clear(ADCSRA, ADEN);
259
260 // Activate free-running mode
261 ADCSRB = 0x00;
262
263 // Set up the ADC to be free-running
264 bit_set(ADCSRA, ADPS0); // Set the ADC's clock to system clock / 128
265 bit_set(ADCSRA, ADPS1);
266 bit_set(ADCSRA, ADPS2);
267
268 bit_set(ADCSRA, ADATE); // set the Auto Trigger Enable bit in the ADCSRA register. Because
269 // bits ADTS0-2 have not been set (i.e. they are all zero), the
270 // ADC's trigger source is set to "free running mode".
271
272 bit_set(ADCSRA, ADIE); // set the ADC interrupt enable bit. When this bit is written
273 // to one and the I-bit in SREG is set, the
274 // ADC Conversion Complete Interrupt is activated.
275
276 bit_set(ADCSRA, ADEN); // Enable the ADC
277
278 bit_set(ADCSRA, ADSC); // start ADC manually first time
279
280 sei(); // Enable Global Interrupts
281}
282
299{
300 uint16_t pinsON{ 0 };
301 uint16_t pinsOFF{ 0 };
302
303 uint8_t i{ NO_OF_DUMPLOADS };
304
305 do
306 {
307 --i;
308 // update the local load's state.
310 {
311 // setPinOFF(physicalLoadPin[i]);
312 pinsOFF |= bit(physicalLoadPin[i]);
313 }
314 else
315 {
316 ++countLoadON[i];
317 // setPinON(physicalLoadPin[i]);
318 pinsON |= bit(physicalLoadPin[i]);
319 }
320 } while (i);
321
322 // Apply override bitmask directly to pinsON
323 pinsON |= Shared::overrideBitmask;
324
325 setPinsOFF(pinsOFF);
326 setPinsON(pinsON);
327}
328
354{
355 if constexpr (PRIORITY_ROTATION != RotationModes::OFF)
356 {
358 {
359 uint8_t i{ NO_OF_DUMPLOADS - 1 };
360 const auto temp{ loadPrioritiesAndState[i] };
361 do
362 {
364 --i;
365 } while (i);
366 loadPrioritiesAndState[0] = temp;
367
369 }
370 }
371
372 const bool bDiversionEnabled{ Shared::b_diversionEnabled };
373 uint8_t idx{ NO_OF_DUMPLOADS };
374 do
375 {
376 --idx;
377 const auto iLoad{ loadPrioritiesAndState[idx] & loadStateMask };
378 const bool bOverrideActive = Shared::overrideBitmask & (1U << physicalLoadPin[iLoad]);
379 physicalLoadState[iLoad] = bDiversionEnabled && (bOverrideActive || (loadPrioritiesAndState[idx] & loadStateOnBit)) ? LoadStates::LOAD_ON : LoadStates::LOAD_OFF;
380 } while (idx);
381}
382
400void processPolarity(const uint8_t phase, const int16_t rawSample)
401{
402 // remove DC offset from each raw voltage sample by subtracting the accurate value
403 // as determined by its associated LP filter.
404 l_sampleVminusDC[phase] = (static_cast< int32_t >(rawSample) << 8) - l_DCoffset_V[phase];
406}
407
425void processCurrentRawSample(const uint8_t phase, const int16_t rawSample)
426{
427 // extra items for an LPF to improve the processing of data samples from CT1
428 static int32_t lpf_long[NO_OF_PHASES]{}; // new LPF, for offsetting the behaviour of CTx as a HPF
429
430 // remove most of the DC offset from the current sample (the precise value does not matter)
431 int32_t sampleIminusDC = (static_cast< int32_t >(rawSample - i_DCoffset_I_nom)) << 8;
432
433 // extra filtering to offset the HPF effect of CTx
434 const int32_t last_lpf_long{ lpf_long[phase] };
435 lpf_long[phase] += alpha * (sampleIminusDC - last_lpf_long);
436 sampleIminusDC += (lpf_gain * lpf_long[phase]);
437
438 // calculate the "real power" in this sample pair and add to the accumulated sum
439 const int32_t filtV_div4 = l_sampleVminusDC[phase] >> 2; // reduce to 16-bits (now x64, or 2^6)
440 const int32_t filtI_div4 = sampleIminusDC >> 2; // reduce to 16-bits (now x64, or 2^6)
441 int32_t instP = filtV_div4 * filtI_div4; // 32-bits (now x4096, or 2^12)
442 instP >>= 12; // scaling is now x1, as for Mk2 (V_ADC x I_ADC)
443
444 l_sumP[phase] += instP; // cumulative power, scaling as for Mk2 (V_ADC x I_ADC)
445 l_sumP_atSupplyPoint[phase] += instP; // cumulative power, scaling as for Mk2 (V_ADC x I_ADC)
446}
447
464void confirmPolarity(const uint8_t phase)
465{
466 static uint8_t count[NO_OF_PHASES]{};
467
469 {
470 count[phase] = 0;
471 return;
472 }
473
474 if (++count[phase] > PERSISTENCE_FOR_POLARITY_CHANGE)
475 {
476 count[phase] = 0;
478 }
479}
480
498void processVoltage(const uint8_t phase)
499{
500 // for the Vrms calculation (for datalogging only)
501 const int32_t filtV_div4{ l_sampleVminusDC[phase] >> 2 }; // reduce to 16-bits (now x64, or 2^6)
502 int32_t inst_Vsquared{ filtV_div4 * filtV_div4 }; // 32-bits (now x4096, or 2^12)
503
504 if constexpr (DATALOG_PERIOD_IN_SECONDS > 10)
505 {
506 inst_Vsquared >>= 16; // scaling is now x1/16 (V_ADC x I_ADC)
507 }
508 else
509 {
510 inst_Vsquared >>= 12; // scaling is now x1 (V_ADC x I_ADC)
511 }
512
513 l_sum_Vsquared[phase] += inst_Vsquared; // cumulative V^2 (V_ADC x I_ADC)
514 //
515 // store items for use during next loop
516 l_cumVdeltasThisCycle[phase] += l_sampleVminusDC[phase]; // for use with LP filter
517 polarityConfirmedOfLastSampleV[phase] = polarityConfirmed[phase]; // for identification of half cycle boundaries
518 ++n_samplesDuringThisMainsCycle[phase]; // for real power calculations
519}
520
537void processStartUp(const uint8_t phase)
538{
539 // wait until the DC-blocking filters have had time to settle
540 if (millis() <= (initialDelay + startUpPeriod))
541 {
542 return; // still settling, do nothing
543 }
544
545 // the DC-blocking filters have had time to settle
546 beyondStartUpPeriod = true;
547 l_sumP[phase] = 0;
548 l_sumP_atSupplyPoint[phase] = 0;
551
553 // can't say "Go!" here 'cos we're in an ISR!
554}
555
570{
571 bool bOK_toAddLoad{ true };
572 const auto tempLoad{ nextLogicalLoadToBeAdded() };
573
574 if (tempLoad == NO_OF_DUMPLOADS)
575 {
576 return;
577 }
578
579 // a load which is now OFF has been identified for potentially being switched ON
581 {
582 // During the post-transition period, any increase in the energy level is noted.
584
585 // the energy thresholds must remain within range
587 {
589 }
590
591 // Only the active load may be switched during this period. All other loads must
592 // wait until the recent transition has had sufficient opportunity to take effect.
593 bOK_toAddLoad = (tempLoad == activeLoad);
594 }
595
596 if (bOK_toAddLoad)
597 {
599 activeLoad = tempLoad;
601 b_recentTransition = true;
602 }
603}
604
619{
620 bool bOK_toRemoveLoad{ true };
621 const auto tempLoad{ nextLogicalLoadToBeRemoved() };
622
623 if (tempLoad == NO_OF_DUMPLOADS)
624 {
625 return;
626 }
627
628 // a load which is now ON has been identified for potentially being switched OFF
630 {
631 // During the post-transition period, any decrease in the energy level is noted.
633
634 // the energy thresholds must remain within range
636 {
638 }
639
640 // Only the active load may be switched during this period. All other loads must
641 // wait until the recent transition has had sufficient opportunity to take effect.
642 bOK_toRemoveLoad = (tempLoad == activeLoad);
643 }
644
645 if (bOK_toRemoveLoad)
646 {
648 activeLoad = tempLoad;
650 b_recentTransition = true;
651 }
652}
653
670{
671 // Restrictions apply for the period immediately after a load has been switched.
672 // Here the b_recentTransition flag is checked and updated as necessary.
673 // if (b_recentTransition)
674 // b_recentTransition = (++postTransitionCount < POST_TRANSITION_MAX_COUNT);
675 // for optimization, the next line is equivalent to the two lines above
677
679 {
680 // the energy state is in the upper half of the working range
681 f_lowerEnergyThreshold = f_lowerThreshold_default; // reset the "opposite" threshold
683 {
684 // Because the energy level is high, some action may be required
686 }
687 }
688 else
689 {
690 // the energy state is in the lower half of the working range
691 f_upperEnergyThreshold = f_upperThreshold_default; // reset the "opposite" threshold
693 {
694 // Because the energy level is low, some action may be required
696 }
697 }
698
699 updatePhysicalLoadStates(); // allows the logical-to-physical mapping to be changed
700
701 updatePortsStates(); // update the control ports for each of the physical loads
702
704 {
706 }
707 else
708 {
710 }
711
712 // Now that the energy-related decisions have been taken, min and max limits can now
713 // be applied to the level of the energy bucket. This is to ensure correct operation
714 // when conditions change, i.e. when import changes to export, and vice versa.
715 //
717 {
719 }
720 else if (f_energyInBucket_main < 0)
721 {
723 }
724}
725
741void processMinusHalfCycle(const uint8_t phase)
742{
743 // This is a convenient point to update the Low Pass Filter for removing the DC
744 // component from the phase that is being processed.
745 // The portion which is fed back into the integrator is approximately one percent
746 // of the average offset of all the SampleVs in the previous mains cycle.
747 //
748 l_DCoffset_V[phase] += (l_cumVdeltasThisCycle[phase] >> 12);
749 l_cumVdeltasThisCycle[phase] = 0;
750
751 // To ensure that this LP filter will always start up correctly when 240V AC is
752 // available, its output value needs to be prevented from drifting beyond the likely range
753 // of the voltage signal.
754 //
755 if (l_DCoffset_V[phase] < l_DCoffset_V_min)
756 {
758 }
759 else if (l_DCoffset_V[phase] > l_DCoffset_V_max)
760 {
762 }
763}
764
778{
779 for (uint8_t index = 0; index < NO_OF_DUMPLOADS; ++index)
780 {
781 if (0x00 == (loadPrioritiesAndState[index] & loadStateOnBit))
782 {
783 return (index);
784 }
785 }
786
787 return (NO_OF_DUMPLOADS);
788}
789
803{
804 uint8_t index{ NO_OF_DUMPLOADS };
805 do
806 {
808 {
809 return (index);
810 }
811 } while (index);
812
813 return (NO_OF_DUMPLOADS);
814}
815
832void processLatestContribution(const uint8_t phase)
833{
834 // for efficiency, the energy scale is Joules * SUPPLY_FREQUENCY
835 // add the latest energy contribution to the main energy accumulator
837
838 // apply any adjustment that is required.
839 if (0 == phase)
840 {
841 // If diversion hasn't started yet, use start threshold, otherwise use regular offset
843 {
845
846 // Check if we've exceeded the threshold to start diversion
848 {
849 b_diversionStarted = true;
850 // Once started, we divert all surplus according to the configured fixed offset
851 }
852 }
853 else
854 {
855 // When diversion is already started, apply normal export offset if configured
856 // Comment or remove this if you want to divert ALL surplus once started
858 }
859
861 {
863
865 {
867 // Reset diversion state if we've had no diversion for a full second
868 b_diversionStarted = false;
869 }
870 else
872 }
873
874 Shared::b_newMainsCycle = true; // a 50 Hz 'tick' for use by the main code
875 }
876 // Applying max and min limits to the main accumulator's level
877 // is deferred until after the energy related decisions have been taken
878 //
879}
880
896{
898 {
899 return; // data logging period not yet reached
900 }
901
903
904 uint8_t phase{ NO_OF_PHASES };
905 do
906 {
907 --phase;
909 l_sumP_atSupplyPoint[phase] = 0;
910
912 l_sum_Vsquared[phase] = 0;
913 } while (phase);
914
915 uint8_t i{ NO_OF_DUMPLOADS };
916 do
917 {
918 --i;
920 countLoadON[i] = 0;
921 } while (i);
922
926
929
930 // signal the main processor that logging data are available
931 // we skip the period from start to running stable
933}
934
952void processPlusHalfCycle(const uint8_t phase)
953{
954 processLatestContribution(phase); // runs at 6.6 ms intervals
955
956 // A performance check to monitor and display the minimum number of sets of
957 // ADC samples per mains cycle, the expected number being 20ms / (104us * 6) = 32.05
958 //
959 if (0 == phase)
960 {
962 {
964 }
965
967 }
968
969 l_sumP[phase] = 0;
971}
972
990void processRawSamples(const uint8_t phase)
991{
992 // The raw V and I samples are processed in "phase pairs"
993 const auto &lastPolarity{ polarityConfirmedOfLastSampleV[phase] };
994
996 {
997 // the polarity of this sample is positive
998 if (Polarities::POSITIVE != lastPolarity)
999 {
1000 // This is the start of a new +ve half cycle, for this phase, just after the zero-crossing point.
1002 {
1003 processPlusHalfCycle(phase);
1004 }
1005 else
1006 {
1007 processStartUp(phase);
1008 }
1009 }
1010
1011 // still processing samples where the voltage is POSITIVE ...
1012 // check to see whether the trigger device can now be reliably armed
1013 if ((0 == phase) && beyondStartUpPeriod && (2 == n_samplesDuringThisMainsCycle[0])) // lower value for larger sample set
1014 {
1015 // This code is executed once per 20mS, shortly after the start of each new mains cycle on phase 0.
1017 }
1018 }
1019 else
1020 {
1021 // the polarity of this sample is negative
1022 if (Polarities::NEGATIVE != lastPolarity)
1023 {
1024 // This is the start of a new -ve half cycle (just after the zero-crossing point)
1025 processMinusHalfCycle(phase);
1026 }
1027 }
1028}
1029
1047void processVoltageRawSample(const uint8_t phase, const int16_t rawSample)
1048{
1049 processPolarity(phase, rawSample);
1050 confirmPolarity(phase);
1051
1052 processRawSamples(phase); // deals with aspects that only occur at particular stages of each mains cycle
1053
1054 processVoltage(phase);
1055
1056 if (phase == 0)
1057 {
1059 }
1060}
1061
1076{
1077 // display relevant settings for selected output mode
1078 DBUG(F("Output mode: "));
1080 {
1081 DBUGLN(F("normal"));
1082 }
1083 else
1084 {
1085 DBUGLN(F("anti-flicker"));
1086 DBUG(F("\toffsetOfEnergyThresholds = "));
1088 }
1089 DBUG(F("\tf_capacityOfEnergyBucket_main = "));
1091 DBUG(F("\tf_lowerEnergyThreshold = "));
1093 DBUG(F("\tf_upperEnergyThreshold = "));
1095}
1096
1127ISR(ADC_vect)
1128{
1129 static uint8_t sample_index{ 0 };
1130 int16_t rawSample;
1131
1132 switch (sample_index)
1133 {
1134 case 0:
1135 rawSample = ADC; // store the ADC value (this one is for Voltage L1)
1136 ADMUX = bit(REFS0) + sensorV[1]; // the conversion for I1 is already under way
1137 ++sample_index; // increment the control flag
1138 //
1139 processVoltageRawSample(0, rawSample);
1140 break;
1141 case 1:
1142 rawSample = ADC; // store the ADC value (this one is for Current L1)
1143 ADMUX = bit(REFS0) + sensorI[1]; // the conversion for V2 is already under way
1144 ++sample_index; // increment the control flag
1145 //
1146 processCurrentRawSample(0, rawSample);
1147 break;
1148 case 2:
1149 rawSample = ADC; // store the ADC value (this one is for Voltage L2)
1150 ADMUX = bit(REFS0) + sensorV[2]; // the conversion for I2 is already under way
1151 ++sample_index; // increment the control flag
1152 //
1153 processVoltageRawSample(1, rawSample);
1154 break;
1155 case 3:
1156 rawSample = ADC; // store the ADC value (this one is for Current L2)
1157 ADMUX = bit(REFS0) + sensorI[2]; // the conversion for V3 is already under way
1158 ++sample_index; // increment the control flag
1159 //
1160 processCurrentRawSample(1, rawSample);
1161 break;
1162 case 4:
1163 rawSample = ADC; // store the ADC value (this one is for Voltage L3)
1164 ADMUX = bit(REFS0) + sensorV[0]; // the conversion for I3 is already under way
1165 ++sample_index; // increment the control flag
1166 //
1167 processVoltageRawSample(2, rawSample);
1168 break;
1169 case 5:
1170 rawSample = ADC; // store the ADC value (this one is for Current L3)
1171 ADMUX = bit(REFS0) + sensorI[0]; // the conversion for V1 is already under way
1172 sample_index = 0; // reset the control flag
1173 //
1174 processCurrentRawSample(2, rawSample);
1175 break;
1176 default:
1177 sample_index = 0; // to prevent lockup (should never get here)
1178 }
1179} // end of ISR
Calibration values definition.
constexpr float alpha
Definition calibration.h:54
constexpr float lpf_gain
Definition calibration.h:53
constexpr float f_powerCal[NO_OF_PHASES]
Definition calibration.h:34
Standard three-phase PVRouter setup with 2 dump loads.
constexpr uint8_t loadPrioritiesAtStartup[NO_OF_DUMPLOADS]
Definition config.h:93
constexpr bool RELAY_DIVERSION
Definition config.h:51
constexpr bool OVERRIDE_PIN_PRESENT
Definition config.h:48
constexpr uint8_t dualTariffPin
Definition config.h:96
constexpr RelayEngine relays
Definition config.h:126
constexpr uint8_t physicalLoadPin[NO_OF_DUMPLOADS]
Definition config.h:92
constexpr bool DUAL_TARIFF
Definition config.h:52
constexpr uint8_t diversionPin
Definition config.h:97
constexpr OverridePins overridePins
Definition config.h:143
constexpr uint8_t NO_OF_DUMPLOADS
Definition config.h:42
constexpr bool WATCHDOG_PIN_PRESENT
Definition config.h:50
constexpr bool DIVERSION_PIN_PRESENT
Definition config.h:46
constexpr uint8_t rotationPin
Definition config.h:98
constexpr uint8_t watchDogPin
Definition config.h:99
constexpr int16_t REQUIRED_EXPORT_IN_WATTS
constexpr uint32_t WORKING_ZONE_IN_JOULES
constexpr conditional< DATALOG_PERIOD_IN_SECONDS *SUPPLY_FREQUENCY >=UINT8_MAX, uint16_t, uint8_t >::type DATALOG_PERIOD_IN_MAINS_CYCLES
constexpr uint8_t DATALOG_PERIOD_IN_SECONDS
constexpr uint8_t NO_OF_PHASES
constexpr uint8_t SUPPLY_FREQUENCY
constexpr int16_t DIVERSION_START_THRESHOLD_WATTS
#define DBUGLN(...)
Definition debug.h:97
#define DBUG(...)
Definition debug.h:96
Classes/types needed for dual-tariff support.
uint8_t i
constexpr uint16_t getInputPins()
Retrieves the input pins configuration.
constexpr void initializeArray(int32_t(&array)[N], int32_t value)
Initializes all elements of a given array to a specified value.
constexpr uint16_t getOutputPins()
Retrieves the output pins configuration.
void initializeProcessing()
Initializes the processing engine, including ports, load states, and ADC setup.
ISR(ADC_vect)
Interrupt Service Routine - Interrupt-Driven Analog Conversion.
void updatePhysicalLoadStates()
Updates the physical load states based on logical load priorities and states.
void processLatestContribution(const uint8_t phase)
Process the latest contribution after each phase-specific new cycle.
void updatePortsStates()
Updates the control ports for each of the physical loads.
void processStartUp(const uint8_t phase)
Processes the startup period for the router.
void processStartNewCycle()
Processes the start of a new mains cycle on phase 0.
void processMinusHalfCycle(const uint8_t phase)
Processes the start of a new negative half cycle for the specified phase.
void processVoltageRawSample(const uint8_t phase, const int16_t rawSample)
Processes the current voltage raw sample for the specified phase.
void proceedLowEnergyLevel()
Handles the case when the energy level is low, potentially removing a load.
void processPolarity(const uint8_t phase, const int16_t rawSample)
Processes the polarity of the current voltage sample for a specific phase.
void processRawSamples(const uint8_t phase)
Processes raw voltage and current samples for the specified phase.
uint8_t nextLogicalLoadToBeAdded()
Retrieve the next logical load that could be added.
void processPlusHalfCycle(const uint8_t phase)
Process the start of a new positive half cycle for the specified phase.
void processDataLogging()
Process data logging at the end of each logging period.
uint8_t nextLogicalLoadToBeRemoved()
Retrieve the next logical load that could be removed (in reverse order).
void confirmPolarity(const uint8_t phase)
Confirms the polarity of the current voltage sample for a specific phase.
void processVoltage(const uint8_t phase)
Processes the current voltage sample for the specified phase.
void proceedHighEnergyLevel()
Handles the case when the energy level is high, potentially adding a load.
void processCurrentRawSample(const uint8_t phase, const int16_t rawSample)
Processes the current raw sample for the specified phase.
volatile int32_t copyOf_sum_Vsquared[NO_OF_PHASES]
Definition shared_var.h:22
volatile uint16_t overrideBitmask
Definition shared_var.h:14
volatile float copyOf_energyInBucket_main
Definition shared_var.h:23
volatile bool b_datalogEventPending
Definition shared_var.h:10
volatile bool b_reOrderLoads
Definition shared_var.h:12
volatile uint16_t copyOf_sampleSetsDuringThisDatalogPeriod
Definition shared_var.h:25
volatile int32_t copyOf_sumP_atSupplyPoint[NO_OF_PHASES]
Definition shared_var.h:21
volatile uint8_t copyOf_lowestNoOfSampleSetsPerMainsCycle
Definition shared_var.h:24
volatile uint16_t copyOf_countLoadON[NO_OF_DUMPLOADS]
Definition shared_var.h:26
volatile uint16_t absenceOfDivertedEnergyCountInSeconds
Definition shared_var.h:16
volatile bool b_newMainsCycle
Definition shared_var.h:11
volatile bool b_diversionEnabled
Definition shared_var.h:13
Polarities polarityConfirmedOfLastSampleV[NO_OF_PHASES]
uint8_t n_lowestNoOfSampleSetsPerMainsCycle
float f_energyInBucket_main
constexpr OutputModes outputMode
constexpr int16_t i_DCoffset_I_nom
uint32_t absenceOfDivertedEnergyCountInMC
constexpr int32_t l_DCoffset_V_min
constexpr int32_t l_DCoffset_V_max
float f_upperEnergyThreshold
uint16_t countLoadON[NO_OF_DUMPLOADS]
constexpr float f_offsetOfEnergyThresholdsInAFmode
bool b_diversionStarted
remove_cv< remove_reference< decltype(DATALOG_PERIOD_IN_MAINS_CYCLES)>::type >::type n_cycleCountForDatalogging
constexpr uint8_t POST_TRANSITION_MAX_COUNT
constexpr auto initThreshold(const bool lower)
set default threshold at compile time so the variable can be read-only
constexpr float f_capacityOfEnergyBucket_main
LoadStates physicalLoadState[NO_OF_DUMPLOADS]
int32_t l_sum_Vsquared[NO_OF_PHASES]
int32_t l_sumP[NO_OF_PHASES]
Polarities polarityConfirmed[NO_OF_PHASES]
bool b_recentTransition
uint8_t n_samplesDuringThisMainsCycle[NO_OF_PHASES]
constexpr float f_lowerThreshold_default
void printParamsForSelectedOutputMode()
Print the settings used for the selected output mode.
constexpr float f_midPointOfEnergyBucket_main
bool beyondStartUpPeriod
int32_t l_cumVdeltasThisCycle[NO_OF_PHASES]
int32_t l_sampleVminusDC[NO_OF_PHASES]
Polarities polarityOfMostRecentSampleV[NO_OF_PHASES]
uint16_t i_sampleSetsDuringThisDatalogPeriod
constexpr float f_upperThreshold_default
float f_lowerEnergyThreshold
int32_t l_DCoffset_V[NO_OF_PHASES]
int32_t l_sumP_atSupplyPoint[NO_OF_PHASES]
uint8_t activeLoad
uint8_t perSecondCounter
uint8_t postTransitionCount
Public functions/variables of processing engine.
constexpr uint16_t startUpPeriod
Definition processing.h:27
constexpr uint8_t PERSISTENCE_FOR_POLARITY_CHANGE
Definition processing.h:24
uint8_t loadPrioritiesAndState[NO_OF_DUMPLOADS]
Definition processing.h:22
constexpr uint8_t sensorV[NO_OF_PHASES]
Definition processing.h:18
constexpr uint8_t sensorI[NO_OF_PHASES]
Definition processing.h:19
constexpr uint16_t initialDelay
Definition processing.h:26
Polarities
Definition types.h:35
@ NEGATIVE
Definition types.h:36
@ POSITIVE
Definition types.h:37
constexpr uint8_t loadStateMask
Definition types.h:55
constexpr uint8_t loadStateOnBit
Definition types.h:56
LoadStates
Definition types.h:49
@ LOAD_OFF
Definition types.h:50
@ LOAD_ON
Definition types.h:51
OutputModes
Definition types.h:42
@ ANTI_FLICKER
Definition types.h:43
Some utility functions for pins manipulation.
constexpr void bit_set(T &_dest, const uint8_t bit)
Set the specified bit to 1.
Definition utils_pins.h:54
void setPinsOFF(uint16_t pins)
Set the Pins state to OFF.
Definition utils_pins.h:181
constexpr uint8_t bit_read(const T &_src, const uint8_t bit)
Read the specified bit.
Definition utils_pins.h:67
void setPinsAsInputPullup(uint16_t pins)
Set the pins as INPUT_PULLUP.
Definition utils_pins.h:226
void setPinsAsOutput(uint16_t pins)
Set the pins as OUTPUT.
Definition utils_pins.h:215
void setPinsON(uint16_t pins)
Set the Pins state to ON.
Definition utils_pins.h:149
constexpr uint8_t bit_clear(T &_dest, const uint8_t bit)
Clear the specified bit.
Definition utils_pins.h:80