# new module for "moving average"

**URL:** <https://oscat.discourse.group/t/new-module-for-moving-average/2285>\
**Category:** Modulentwicklung / Module Development\
**Created:** [9. April 2018 um 15:20 UTC](https://oscat.discourse.group/t/new-module-for-moving-average/2285 "2018-04-09T15:20:01Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![elconfa](https://avatars.discourse-cdn.com/v4/letter/e/da6949/32.png) [@elconfa](https://oscat.discourse.group/u/elconfa)\
**Post date:** [9. April 2018 um 15:20 UTC](https://oscat.discourse.group/t/new-module-for-moving-average/2285/1 "2018-04-09T15:20:01Z")

</div>

this is my code, may be someone need it, or you are able to make it better  
Thanks  
Massimo

FUNCTION\_BLOCK FB\_MovingAverage  
VAR\_INPUT  
IN : REAL;  
N\_Cicli : INT;  
t\_Pausa\_1 : DINT;  
t\_Pausa\_2 : DINT;  
END\_VAR  
VAR\_OUTPUT  
Media : REAL;  
END\_VAR  
VAR  
Valore : ARRAY [0..999] OF REAL;  
x, x1, x2: INT;  
SCHEDULER\_1: OSCAT\_BASIC.SCHEDULER;  
A, B, C, D: REAL;  
E: BOOL;  
END\_VAR

SCHEDULER\_1(  
E0:= TRUE,  
E1:= TRUE,  
T0:= DINT\_TO\_TIME(t\_Pausa\_1),  
T1:= DINT\_TO\_TIME(t\_Pausa\_2));

IF SCHEDULER\_1.Q0 THEN  
A := A + IN;  
B := B + 1;  
END\_IF

IF SCHEDULER\_1.Q1 THEN //MEDIA DELLE LETTURE BREVI  
C := A / B;  
A := 0;  
B := 0;  
D := 0;  
E := TRUE;  
END\_IF

IF E THEN  
FOR x := 1 TO (N\_Cicli-1) DO  
x1 := N\_Cicli - x;  
x2 := N\_Cicli - x - 1;  
Valore[x1] := Valore[x2];  
END\_FOR  
Valore[0] := C;  
FOR x := 0 TO (N\_Cicli-1) DO  
D := D + Valore;  
END\_FOR  
E := FALSE;  
Media := D / N\_Cicli; //MEDIA TRASCINATA  
END\_IF

---

<div class="post-metadata">

**Author:** ![mattsches](https://avatars.discourse-cdn.com/v4/letter/m/d78d45/32.png) [@mattsches](https://oscat.discourse.group/u/mattsches)\
**Post date:** [12. April 2018 um 13:01 UTC](https://oscat.discourse.group/t/new-module-for-moving-average/2285/2 "2018-04-12T13:01:28Z")

</div>

I don’t know if you are aware of the FILTER\_MAV\_W function block in OSCAT\_Basic which does a moving average, although for WORD variables. I needed that for REALs, too, so I modified it and fixed the buffer initialization at the same time. Might be interesting for you, since it seems considerably more compact than your code. If you really need a calculation with 1000 values (which seems a lot to me), you can easily change the size of the “buffer” array.

```auto

FUNCTION_BLOCK FILTER_MAV_R
VAR_INPUT
	X : REAL;
	N : UINT;
	RST : BOOL := FALSE;
END_VAR
VAR_OUTPUT
	Y : REAL;
END_VAR
VAR
	init: BOOL := FALSE;
	buffer : ARRAY[0..31] OF REAL;
	i: INT;
	sum : REAL;
END_VAR
VAR_TEMP
	tmp : INT;
END_VAR

(* limit N to size of buffer *)
N := MIN(N, SIZEOF(buffer)/4);

(* startup initialisation *)
IF NOT init OR rst OR N = 0 THEN
	init := TRUE;
	FOR i := 0 TO UINT_TO_INT(N)-1 DO
		buffer[i] := X;
	END_FOR;
	sum := X * N;
	Y := X;
ELSE
	i := INC1(i, UINT_TO_INT(N));
	sum := sum + X - buffer[i];
	Y := sum / N;
	buffer[i] := X;
END_IF;

```

---

<div class="post-metadata">

**Author:** ![elconfa](https://avatars.discourse-cdn.com/v4/letter/e/da6949/32.png) [@elconfa](https://oscat.discourse.group/u/elconfa)\
**Post date:** [12. April 2018 um 15:09 UTC](https://oscat.discourse.group/t/new-module-for-moving-average/2285/3 "2018-04-12T15:09:03Z")

</div>

:-[  
I have to thankyou! I did not seen that function and your help is very appreciated. I just made a little change because after changing the N variable, I need to send a reset signal for a Plc cycle or the result is wrong.

(\* limit N to size of buffer \*)  
N := MIN(N, SIZEOF(buffer)/4);

A\_TRIG\_N(IN:= UINT\_TO\_REAL(N), RES:= 0.5, Q=\> rst, D=\> );

(\* startup initialisation \*)  
IF NOT init OR rst OR N = 0 THEN  
init := TRUE;  
FOR i := 0 TO UINT\_TO\_INT(N)-1 DO  
buffer[i] := X;  
END\_FOR;  
sum := X \* N;  
Y := X;  
ELSE  
i := INC1(i, UINT\_TO\_INT(N));  
sum := sum + X - buffer[i];  
Y := sum / N;  
buffer[i] := X;  
END\_IF;

---

<div class="post-metadata">

**Author:** ![mattsches](https://avatars.discourse-cdn.com/v4/letter/m/d78d45/32.png) [@mattsches](https://oscat.discourse.group/u/mattsches)\
**Post date:** [13. April 2018 um 10:35 UTC](https://oscat.discourse.group/t/new-module-for-moving-average/2285/4 "2018-04-13T10:35:40Z")

</div>

Provided that you need to change N during runtime, yes, the buffer initialization makes sense. I’d prefer a leaner approach for detecting changes on N, without the A\_TRIG\_N instance call. But that’s just my personal taste.

```auto

(* limit N to size of buffer *)
N := MIN(N, SIZEOF(buffer)/4);

(* startup initialisation *)
IF NOT init OR rst OR N = 0 OR N <> N_old THEN
   init := TRUE;
   FOR i := 0 TO UINT_TO_INT(N)-1 DO
      buffer := X;
   END_FOR;
   sum := X * N;
   Y := X;
ELSE
   i := INC1(i, UINT_TO_INT(N));
   sum := sum + X - buffer;
   Y := sum / N;
   buffer := X;
END_IF;

N_old := N;

```

With N\_old being an FB internal variable, of course.

---

<div class="post-metadata">

**Author:** ![system](https://global.discourse-cdn.com/free1/uploads/oscat/original/1X/2efdfb9c592ff9a666c94dff124ee84fa863dae5.jpeg) [@system](https://oscat.discourse.group/u/system)\
**Post date:** [13. November 2018 um 09:06 UTC](https://oscat.discourse.group/t/new-module-for-moving-average/2285/5 "2018-11-13T09:06:25Z")

</div>

We are delighted to be part of providing good information for you.
