Averaging Sampled Data

Averaging Sampled Data
none 0.0 0
  • HMI Model: cMT-FHDX820
  • EasyBuilder Pro Version:6.08.01.614

I have data samples that I am taking at 1 minute intervals over 24 hours. This represents a percentage of speed / uptime. Is there an easy way to calculate an average of these 1440 samples to display on a dashboard?

Hi @jjansen,

I would recommend that you use a macro to calculate this average, here is an example that may be suitable for this application:

  1. Within the “Project” tab click “Macro”:

  2. Within the following menu, click “New”:

  3. Follow the instructions within this post to implement a GetData() command and pull the sampled data into the macro:
    Note: In this example I’m retrieving data from LW-59. You may need a variable to hold the total sum and average and a variable to count the number of samples. The data type I am reading this example is a short, but please configure the data type of the variable used within GetData() such that it matches the type sampled.
    image

  4. Store the total count within HMI memory, in this example I am storing the count within LW-1000:
    Note: Information related to the SetData() command can be found within the post mentioned above as well.
    image

  5. Add the current data to a running total and save this data within HMI memory as well:
    image

  6. Calculate the average and set this within HMI memory:

  7. Enable periodical execution and run this macro every one minute:
    image

  8. Click “Save & Compile” when finished:
    image

Here is a link to a demo project: Link

My concern is that I have 1440 samples, each representing 1 minute of data. Wouldn’t I have to have 1440 GetData() calls to read in the values?

@jjansen,

Is each sample obtained from a different register or tag within the external device or is this data read into the same register at one minute intervals?

A single register at intervals. The plan was to use the Data Sampling under Data/History to keep 24 hours worth, and hopefully summarize it from in there. Ultimately there are 35 production lines to do all of this with.

@jjansen,

If it is only a single register, then you can develop a solution using the example mentioned above. The GetData() will occur at 1 minute intervals due to periodical execution. It will retain a running total and average based on the current sample count. I would recommend that you reset the total and count registers daily to ensure that these values remain within a valid range.

I need to do a rolling average of the last 24 hours. Can I pull data from the Data Sampling like a FIFO so as I add the latest minute, I can remove the minute from 24 hours ago?

Or some way to maintain a FIFO that doesn’t involve 1440 GetData() and SetData() commands?

@jjansen,

Can you please advise the data type of the data you would like to average? I will try to give you an example of a queue as defined within our macro shortly.

I will be using integer data. Updates come in at 60 second intervals, and I plan to keep 24 hours (1440 samples) as a “Last 24 hours” display in a rolling queue.

FWIW: I have found a way and decided to use Codesys for this instead, as I have easier access to arrays. Thanks for the help!

Hi @jjansen,

Thank you for the update, if you have time it would be great if you can post the solution you’ve developed or a brief description of it on our forum for anyone else that might have this question. Have a great day!

FUNCTION_BLOCK UpTimeCalc
VAR_INPUT
running : BOOL;
END_VAR
VAR_OUTPUT
runSeconds : WORD;
avg24H : REAL;
END_VAR
VAR
snapshot : BOOL;
active : ARRAY[0…60] OF BOOL;
history24H : ARRAY[0…1440] OF BYTE;
secondCount : INT;
calcAvg : DWORD;
i : INT;
END_VAR


// Function is called every 1 second
secondCount := secondCount + 1;

// Once per minute, reset the second counter and set the snapshot bit for 1 scan
IF (secondCount = 60) THEN
secondCount := 0;
snapshot := TRUE;
ELSE
snapshot :=FALSE;
END_IF

// Active array tracks each seconds status
active[secondCount] := running;

// Generate a rolling average for the current minute
calcAvg := 0;
FOR i := 0 TO 59 DO
IF(active[i] = TRUE) THEN
calcAvg := calcAvg + 1;
END_IF
END_FOR

// Set the runSecond output for display
runSeconds := DWORD_TO_WORD(calcAvg);

// Each minute, recalculate the 24 hour rolling average
IF(snapshot = TRUE) THEN
calcAvg := 0;
FOR i:= 0 TO 1439 DO
history24H[i] := history24H[i+1];
calcAvg := calcAvg + history24H[i];
END_FOR
history24H[1440] := WORD_TO_BYTE(runSeconds);
calcAvg := calcAvg + runSeconds;
avg24H := 100.0*(DWORD_TO_REAL(calcAvg) / 86400); // 86,400 seconds in 24 hours. X100 to get a percentage
END_IF