# Mittelwert Bildung - CoDeSys 2



## DachBahn (30 September 2015)

Hallo da draußen,
ich haben einen Messwert, der sehr schwank.
Nun möchte ich, diesen Wert eine Stunde lang, mit einem Intervall von 2 Sekunden, mitteln.
Wie bekomme ich das mit CoDeSys 2 am besten hin ???

Danke für die Hilfe


----------



## Morymmus (30 September 2015)

guten Morgen,

ich verstehe die Aufgabenstellung so, das Du eine Anzeige von Messwerten realisieren möchtest, die 1h Historie bereithält. Abtastrate der gemittelten Messwerte soll 2s sein?

Also für die Messwerterfassung einen Task anlegen, der mit einem definierten Intervall den Eingang erfasst (z.B. 500ms)
Mit einer Schleife die Werte in Variablen "wegschreiben"
Wenn Schleife einmal "rum" ist (in meinem Fall nach 4 gespeicherten Werten) die Mittelwertbildung triggern (Summe der Messwerte/Anzahl der Messwerte)
Den so erhaltenen Wert in ein Array wegschreiben und Array-Pointer auf nächste Adresse setzen.
Wenn das Array nun 60 Einträge umfasst hast du 1h Historie.

Ich hoffe das hilft schonmal als Denkanstoß ;-)

Gruß


Christian


----------



## Guga (30 September 2015)

Stichwort fliessender Gleitpunkt! 

Die Mathematik sagt für einen fliessenden Gleitpunkt (Arrays, das kostet bei vielen Stützpunkten viel Rechenleistung).
x: aktueller Messpunkt
x_fl: Fliessender Gleitpunkt
x_fl_old: Fliessender Gleitpunkt beim letzten (zeitlich äquidistanter) Aufruf
n: Anzahl der Stützstellen und somit zeitliche Fenster


x_fl := (x +  (n-1)*xfl_old)/n ;


----------



## Morymmus (30 September 2015)

Ja, guter Einwand - diese Lösung gibt aber (erstmal) nur den aktuellen fließenden Gleitpunkt zurück - eine History müsste man dann immer noch "dazubasteln" ;-)

Auch die Rechenleistung ist ein berechtigter Einwand, da uns aber keine Informationen vorliegen über die verwendete Hardware bzw. die weiteren Aufgaben der SPS hielt ich es als denkanstoß für legitim.


Warten wir mal ab, was der Themenstarter dazu sagt bzw. ob wir seine Aufgabenstellung getroffen haben... 

gesendet von meinem Moto G mit Tapatalk


----------



## shrimps (30 September 2015)

Hi,
da ich etwas ähnliches benötigte, habe ich mein Beispiel mal hier gepostet.
Ist als mögliche Basis ggf. erweiterbar.
Jedoch, wie die vorhergehenden Schreiber schon sagten, es ist ggf. sehr Resourcenintensiv:
alle 2 s für eine h = 60/2 * 60 = 1800 Werte um eine h rollierend zu behalten...

Vile Erfolg
Shrimps

```
FUNCTION_BLOCK _fbAVG_INT16
VAR_INPUT
    iSignal    : INT;    (* Eingangswert *)
    tZeit    : TIME := t#8s;    (* Abtastzeit gesamt *)
END_VAR
VAR_OUTPUT
    iAVG    : INT;    (* Der Mittelwert *)
END_VAR
VAR
    Timer     : TON;    (* Timer *)
    tTakt    : TIME;    (* 1/16 von tZeit *)
    iData     : ARRAY [0..15] OF INT;    (* Die Daten *)
    Summe    : DINT;    (* Summenzaehler *)
    Index    : INT;    (* Index für Array *)
    init    : BOOL := TRUE;    (* Start *)
END_VAR
(* FB ermittelt einen gleitenden Mittelwert aus *)
(* 16 Integerwerten welche in einem vorgebbaren *)
(* Zeitinterval als FIFO gespeichert werden *)
IF init THEN
    FOR Index := 0 TO 15 DO
        iData[Index] := iSignal;
    END_FOR
    init := FALSE;
    iAVG := iSignal;
END_IF

tTakt := tZeit / 16;

Timer(IN := NOT Timer.Q, PT := tTakt);

IF Timer.Q THEN
    Summe := 0;
    FOR Index := 15 TO 1 BY -1  DO
        iData[Index] := iData[Index - 1];
        Summe := Summe + iData[Index];
    END_FOR
    iData[0] := iSignal;
    Summe := Summe + iSignal;
    iAVG := DINT_TO_INT(summe / 16);
END_IF
```


----------



## Caroli (1 Oktober 2015)

Nach der obigen Formel würde das fertige Programm dann so aussehen:

PROGRAM MAIN
VAR
	x:REAL;(*aktueller Messpunkt*)
	x_fl:REAL;(*Fließender Gleitpunkt*)
	n:INT:=1;
	ton1: TON;
	rBuffer:ARRAY[0..1800]OF REAL;(*x_fl_old Fließender Gleitpunkt beim letzten Aufruf*)
	n1: INT;
END_VAR

ton1(pt:=t#2s, in:=NOT ton1.Q);
IF ton1.Q THEN
	rBuffer[n]:=x_fl;
	IF n<>0 THEN (*div 0 verhindern*)x_fl:=(x+(n-1)*rBuffer[n])/n;END_IF
	n:=n+1;
	IF n>1800 THEN
		n:=1800;
		rBuffer[0]:=rBuffer[1800];
		FOR n1:=1800 TO 1 BY -1  DO
			rBuffer[n1]:=rBuffer[n1-1];
		END_FOR
	END_IF
END_IF


----------



## b4w3f (2 Oktober 2015)

Mit folgendem Baustein hab ich das in meinem Projekt gelöst. Da kann man einfach den aktuellen Messwert reinwerfen, den Mittelwert ausgeben sobald ausreichend Messwerte eingegangen sind. i Gibt die Anzahl der Durchläufe zurück. Bei mir wurde jeder Zyklus gemessen. Das müsste man dann noch anpassen.

```
FUNCTION_BLOCK
VAR_INPUT	fActWert: REAL;
	fAnzahlWerte: REAL;
	xEnable: BOOL;
END_VAR
VAR_OUTPUT
	fMEANOK: REAL;
	bDone: BOOL;
END_VAR
VAR
	fMEAN: REAL;
	i: INT;
	EnableTrig: R_TRIG;
	fweight: REAL;
END_VAR
```


```
bDone:=FALSE;
fMEAN:=(1.0 - fweight) * fMEAN + fweight * fActWert;		//Gleitende Mittelwertbildung


EnableTrig(CLK:=xEnable);


IF EnableTrig.Q THEN
	i:=0;
	fMEAN:=0;
	fweight:= 1.0 / fAnzahlWerte;
END_IF


i:=i+1;


IF xEnable AND i> fAnzahlWerte THEN
	bDone:=TRUE;
	fMEANOK:=fMEAN;
END_IF
```


----------

