Rolling Average Calculation

From Cassandra

Jump to: navigation, search

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
Personal tools