Skip to main content

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.

  • POWER and POWER_KW: The electrical power is first calculated in W (watts) and separately in kW (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 integrators integrate() separately via the min() and max() 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: The timer() 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 the buffer() function, values from the energy meters are transferred to a circular buffer of length 8. Whenever a positive edge is received with the newDay signal, the values in the circular buffer are shifted one position to the right, and the current value WAUF_KWH or WABG_KWH is 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 _weekDay for the current UTC time _now. This is an integer value in the range [0..6][0 .. 6], starting with 0 for Sunday.

  • The previous day of the week _yesterday is determined using a modulo operation within the same range.

  • The memory _memECLatch continuously 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 _memStart with 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 as Consume_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.