Example 1 - Power Calculation, Energy Meter, Daily Values
Example 1a - Power Calculation
Task:
The electrical power of a device is to be calculated from measured voltage (LINEVOLT_1, LINEVOLT_2 in volts) and current signals (LINECURRENT in amperes). The voltage is measured redundantly, whereby one measurement point may be switched off. The output should be in the unit "kW". Determine the energy consumed and energy supplied in "kWh".
Solution:
// Constants for unit conversion
uConv_Ws2kWh = 1e-3 / 3600; // Ws -> kWh
LINEVOLT = max(LINEVOLT_1, LINEVOLT_2); // V
POWER = LINEVOLT * LINECURRENT; // W
POWER_KW = POWER / 1000.0; // kW
WAUF_KWH = integrate(max(POWER, 0.0), {storage: 'sto_WAUF'}) * uConv_Ws2kWh; // kWh
WABG_KWH = -integrate(min(POWER, 0.0), {storage: 'sto_WABG'}) * uConv_Ws2kWh; // kWh
Functions Used
Explanation:
-
uConv_Ws2kWh: First, a factor for converting units from Ws to kWh is defined. This improves the readability of the following code. Such definitions are conveniently placed centrally at the beginning of the formula set. -
LINEVOLT: The maximum of the two measured line voltages is taken. If one fails and becomes 0.0, the other still provides a plausible value. -
POWERandPOWER_KW: The electrical power is first calculated in W (watts) and separately inkW(kilowatts). This separation is necessary because the subsequent integral function should always be fed with SI base units from the "MKS" system, in this case power in W. -
WAUF_KWH, WABG_KWH: The calculated power is fed to the two integratorsintegrate()separately via themin()andmax()functions based on its sign and thus the direction of power flow. Both integrators store their current count (in SI base units!) in the specified memory locations. Through integration, the dimension of time is added to the integrand as s (second). The integrated value thus has the energy unit "Ws" (watt-second). This is converted to kWh (kilowatt-hour) using the scaling factor calculated above. -
If, at a later stage, the units of the measurement signals to be integrated (kV, kA, mA) or of the integrated value (kJ, MWh, etc.) change, the value stored in the integrator can easily continue to be used, provided it is in SI base units. In that case, only an easily understandable, traceable scaling of the input or output variable is necessary, but no permanent rescaling of the value stored in the integrator or a forced restart resulting from it.
Example 1b - Daily Updated Intermediate Values
Task:
The calculation should now be expanded to output daily meter readings at the end of the operating day, consumption for the last 7 days, and current consumption for the current day.
Solution:
In addition to the formula text from Example 1a):
#timezone Europe/Berlin
newDay = timer({ minute: 15, hour: 3, useTZ: true }); // Reference time, shift change
_hist_WAUF_KWH = buffer(WAUF_KWH, newDay, {size:8, storage:'sto_h_WAUF'});
WEEK_WAUF_KWH = _hist_WAUF_KWH[0] - _hist_WAUF_KWH[7];
YDAY_WAUF_KWH = _hist_WAUF_KWH[0] - _hist_WAUF_KWH[1];
TDAY_WAUF_KWH = WAUF_KWH - _hist_WAUF_KWH[0];
_hist_WABG_KWH = buffer(WABG_KWH, newDay, {size:8, storage:'sto_h_WABG'});
WEEK_WABG_KWH = _hist_WABG_KWH[0] - _hist_WABG_KWH[7];
YDAY_WABG_KWH = _hist_WABG_KWH[0] - _hist_WABG_KWH[1];
TDAY_WABG_KWH = WABG_KWH - _hist_WABG_KWH[0];
Functions Used
Explanation:
-
Variables for internal use are marked with an
_as the first character. This improves readability. -
newDay: Thetimer()function generates a pulse signal that, with the given configuration, produces a short pulse every morning at 3:15 local time in "Berlin." This pulse is used to save the meter readings. -
_hist_WAUF_KWH, _hist_WAUF_KWH: Using thebuffer()function, values from the energy meters are transferred to a circular buffer of length 8. Whenever a positive edge is received with thenewDaysignal, the values in the circular buffer are shifted one position to the right, and the current valueWAUF_KWHorWABG_KWHis stored at position [0]. These buffers also save their contents to a persistent location so that calculations can continue with the previously recorded meter readings after a reboot. -
WEEK_*: The energy consumption for the last 7 days is calculated as the difference between the value recorded last night and the value from 8 nights prior [7]. -
YDAY_*: The energy consumption for the last day (yesterday) is calculated as the difference between the value recorded last night [0] and the value recorded the night before last [1]. -
TDAY_*: The energy consumption for the current day (today) is the difference between the absolute value and the value stored last night.
Since the stored historical values change only once a day, data transfer to the cloud or to OSF files is highly efficient.
Example 1c - Consumption Values for Weekdays or Months
Task:
Example 1b) requires that the smartCORE be permanently online and able to generate trigger pulses. Starting with catalog version 13, the memory() function can be used to work around this issue.
Solution:
In addition to the formula text from Example 1a):
_now = time();
_dateVec = decodeTime(_now);
_weekDay = int(_dateVec[7]); // 0..6, starting on Sunday
_yesterday = (_weekDay + 6) % 7;
_memECLatch = memory( false, _weekDay, WAUF_KWH
, {mode: latch, size:7
, storage: memECLatch_kWh});
_memStart = memory( false, _weekDay, _memECLatch[_yesterday]
, {mode: latch, size:7
, storage: memStart_kWh});
Consumption = _memECLatch - _memStart;
Consume_Sun = Consumption[0];
Consume_Mon = Consumption[1];
...
Consume_Sat = Consumption[6];
Functions used:
Explanation:
-
First, the
decodeTime()function is used to obtain the weekday_weekDayfor the current UTC time_now. This is an integer value in the range , starting with 0 for Sunday. -
The previous day of the week
_yesterdayis determined using a modulo operation within the same range. -
The memory
_memECLatchcontinuously stores the current meter reading at the memory location indexed by_weekDay(= element of the vector). For this purpose, it is initialized with 7 memory slots and persistent storage in latch mode. For each day of the week, the most recent meter reading for that day is thus always stored. For this, the control input control is always false.
In principle, the daily consumption is calculated as the difference between the meter readings from the previous day. However, if the difference were calculated immediately, the value for the 6th day prior (i.e., Thursday if the current day is Wednesday) would be incorrect. After all, the final value from Wednesday (one week ago) is constantly being overwritten.
-
Therefore, a second memory
_memStartwith the same structure always holds the values from the previous day_memECLatch[_yesterday]as the starting value for the current day. -
The difference between the two vectors (memories) yields the daily consumption by day of the week as the vector
Consumption, or broken down by day of the week asConsume_Sun,Consume_Mon, etc.
An advantage over the method of using pulses from the trigger() function to advance a buffer() ring buffer is that the device does not need to be powered on at the trigger time. Condition in this case: at least one calculation on the previous day.