Rolling Average Calculation
From Cassandra
The following code performs a rolling average calculation. The average is initiaized to the first value read from the input, and then it goes from there.
The NUM_SAMPLES constant determines the number of "buckets" to use for calculating the rolling average, and the SAMPLE_PERIOD is the interval between samples (should be some multiple of the parent IND block's PERIOD). Therefore, your rolling average interval is NUM_SAMPLES * SAMPLE_PERIOD seconds. In this example, it is a 1-hour rolling average of 1-minute samples.
Enjoy - c²
INDEPENDENT_SEQUENCE
{******************************************************
**
** Rolling Average Calculation (IND block version)
**
** Calculate rolling average over a time period
** equal to NUM_SAMPLES * SAMPLE_PERIOD secs.
** Here we use a ring buffer to hold the samples.
** We initialize by filling the ring buffer with the
** first reading and get a starting "average" value =
** that reading. We then start a loop, getting the
** input value, poking it in the ring buffer after
** saving the value in that ring buffer location.
** We then calculate the sum of the ring buffer values
** by adding the new value to the sum and subtracting
** the saved old value, and get the average by dividing
** that sum by the number of samples (size of ring
** buffer. Finally we wait one sample interval, and
** lather rinse repeat.
******************************************************}
CONSTANTS
NUM_SAMPLES = 60;
SAMPLE_PERIOD = 60; { secs; IND block period should
be an integer multiple of this }
VARIABLES
ring_buf : R[NUM_SAMPLES];
i : I;
USER_LABELS
input : RI0001; { Live input value }
roll_avg : RO0001; { Calculated rolling average }
roll_sum : RO0002; { Sum of input values over
averaging period }
st_inp : RO0003; { Stored input value }
rb_oldest : RO0004; { Saved ring buf value @ ptr loc }
rb_ptr : IO0001; { Ring buffer index pointer }
STATEMENTS
{ Initialize ring buffer }
ring_buf := SET_ARRAY(input);
rb_ptr := 1;
{ Starting "rolling sum" }
roll_sum := ring_buf[1] * NUM_SAMPLES;
{ Wait until next scan before starting main loop }
WAIT 1.0;
{ Main loop }
<<loop_lbl>>
{ Get input, save old value at current ring buffer
pointer location, and save input value. Store to
an output for troubleshooting.
}
st_inp := input;
rb_oldest := ring_buf[rb_ptr];
ring_buf[rb_ptr] := st_inp;
{ Calculate rolling sum and average }
roll_sum := roll_sum + ring_buf[rb_ptr] -
rb_oldest;
roll_avg := roll_sum / NUM_SAMPLES;
{ Move ring buf pointer to next slot }
IF rb_ptr < NUM_SAMPLES THEN
rb_ptr := rb_ptr + 1;
ELSE
rb_ptr := 1;
ENDIF;
{ Wait until next calculation cycle }
WAIT SAMPLE_PERIOD;
GOTO loop_lbl;
ENDSEQUENCE
