# Gleitende Mittelwertbildung



## SPS_NEU (17 September 2009)

Hallo,

ich lese mit der SPS Senorwerte ein. Diese möchte ichg gern glätten. Gibt es da eine Möglichkeit. Evtl. gleitende Mittelwertbildung?


----------



## Mike369 (17 September 2009)

ja ließt du 1 oder 0 ?? oder was anderes


----------



## SPS_NEU (17 September 2009)

analoge Stromwerte 4..20mA in REAL


----------



## Günni1977 (17 September 2009)

ja das geht. warum auch nicht...


----------



## Andreas- (17 September 2009)

Beispiel FB:

```
AUF DB_Nummer    // IN DB: DB Adresse, wo die Messungen gespeichert
L Byte_ANF_ADDR // IN INT: Anfangsaddresse der Messungen
SLW 3
L DW#16#84000000
UD
LAR1
LAR2
L Messwert // IN INT Dein Messwert
T W[AR1,P#0.0]
L AnzahlMessungen // IN DINT: Anzahl der Messungen, die du machen willst
Mess: T Temp_Anzahl // Temp DINT
TAR1
L P#2.0
+D
LAR1
L Messwert
T W[AR1,P#0.0]
L Temp_Anzahl
LOOP Mess

L W[AR2,P#0.0]
T Zwischenergebnis // TEMP DINT
L AnzahlMessungen
Me01: T Temp_Anzahl
TAR2
L P#2.0
+D
LAR2
L Zwischenergebnis
L W[AR2,P#0.0]
+D
T Zwischenergebnis
L Temp_Anzahl
LOOP Me01

L Zwischenergebnis
L AnzahlMessungen
/D
T Mittelwert // OUT DINT: Ausgang Mittelwert deiner Messungen
```
Achte darauf, dass du den DB zuerst anlegen musst, und ihm pro Messwert genug Platz reservierst. (1 Messwert = WORD)
Den Realwert wandelst du mit FC105 in INT um.
Müsste so funktionieren, hab es allerdings nicht getestet. Sag bitte bescheid, obs überhaupt funktioniert.

Gruß!


----------



## Andreas- (17 September 2009)

Sorry, mir ist aufgefallen, dass das so nicht funktioniert 

Ich up gleich die Korrektur ^^​


----------



## Andreas- (17 September 2009)

Meine Korrektur: 

Beispiel FB:

```
AUF DB_Nummer    // IN DB: DB Adresse, wo die Messungen gespeichert
U Messunglaeuft // Statisch BOOL
SPB m003
SET
= Messunglaeuft
L Byte_ANF_ADDR // IN INT: Anfangsaddresse der Messungen
SLW 3
L DW#16#84000000
UD
LAR1
LAR2
T Anfang // Statisch DWORD
T Adresse // Statisch DWORD
L Messwert // IN INT Dein Messwert
T W[AR1,P#0.0]
L AnzahlMessungen // IN DINT: Anzahl der Messungen, die du machen willst
T Anzahl // Statisch DINT
BEA

m003: NOP 0
L Adresse
LAR1

Mess: NOP 0
U Gespeichert
SPBN m001
T Anzahl
CLR
= Gespeichert
BEA
m001: NOP 0
TAR1
L P#2.0
+D
LAR1
T Adresse
L Messwert
T W[AR1,P#0.0]
S Gespeichert // Statisch BOOL
L Temp_Anzahl
LOOP Mess

CLR 
= Gespeichert

L Anfang
LAR2
L W[AR2,P#0.0]
T Zwischenergebnis // TEMP DINT
L AnzahlMessungen
Me01: T Temp_Anzahl
TAR2
L P#2.0
+D
LAR2
L Zwischenergebnis
L W[AR2,P#0.0]
+D
T Zwischenergebnis
L Temp_Anzahl
LOOP Me01

L Zwischenergebnis
L AnzahlMessungen
/D
T Mittelwert // OUT DINT: Ausgang Mittelwert deiner Messungen

CLR
= Messunglaeuft
```
Hab leider grad keine Zeit das zu testen. Ich machs etwas später daheim. Falls du es aber schon vormit testet, so gib mir bitte Auskunft darüber.

Bis dann


----------



## Dumbledore (17 September 2009)

SPS_NEU schrieb:


> analoge Stromwerte 4..20mA in REAL


 
wenn es sich um eine reine Glättung (ohne genaue mathematische Vorgaben dazu) handeln soll dann kann man sehr einfach ein PT1-Glied programmieren. Ich benutze dazu gerne die Formel NEUWERT = FAKTOR * ALTWERT + (1-FAKTOR) * ISTWERT. Der FAKTOR ist z.B. 0,9 (nach Bedarf anpassen). Berechnung unbedingt in REAL ausführen und auf gültige Ziffern achten, falls FAKTOR sehr nahe an 1 oder 0 liegen sollte.


```
(alle Variablen als REAL angenommen)
L 1.0
L FAKTOR
-R
L ISTWERT
*R
L FAKTOR
L GLATTWERT // ALTWERT
*R
+R
T GLATTWERT // NEUWERT
```
 
Wenn man diese Berechnung z.B. in OB35 ausführt (also mit konstanten Abtastzeiten) dann kann man die Glättung (also T1) sogar berechnen falls nötig.

Gruß Michael aka Dumbledore


----------



## SPS_NEU (17 September 2009)

Also ich habe jetzt mal deine Variante Dumbledore getestet. Das Signal verändert sich zwar, aber wird nicht richtig geglättet. Ich arbeitet mit werten um 30 (REAL). Wie ist es dabei güntig den Faktor anzupassen?

@-Andreas:  Leider komme ich mit deinem Programm nicht ganz mit. Ich möchte den Mittelwert aus ca. 10 Messungen gleitend bilden. Kann man das so vereinfachen, dass ein REAL Wert gegeben wird und und zweiter gemittelter als REAL rauskommt?


----------



## wwwandy (17 September 2009)

```
FUNCTION_BLOCK FB 1874
TITLE =
//1.4.2009 aw: Einfacher MTA Filter
VERSION : 0.1


VAR_INPUT
  IN : REAL ;    
  CNT : INT ;    
END_VAR
VAR_OUTPUT
  OUT : REAL ;    
END_VAR
VAR
  buffer : ARRAY  [0 .. 99 ] OF REAL ;    
  pos : INT ;    
  sum : REAL ;    
END_VAR
VAR_TEMP
  i : INT ;    
  tmp : REAL ;    
END_VAR
BEGIN
NETWORK
TITLE =
//IF CNT>100 THEN CNT:=100; END_IF;//Index auf maximale Bufferlänge begrenzen
//             
//out:=out-buffer[pos]+IN/CNT;
//buffer[pos]:=IN/CNT;
//pos:=pos+1;
//IF pos=CNT THEN pos:=0; END_IF;
      L     #CNT; //Anzahl der Werte für den Mittelwert lesen
      L     100; //ggf. auf Länge von buffer (0..99)=100 begrenzen
      >I    ; 
      SPBN  ngr; 
      T     #CNT; 
ngr:  L     #IN; //Eingang durch Anzahl Werte dividieren
      L     #CNT; 
      ITD   ; 
      DTR   ; 
      /R    ; 
      T     #tmp; //tmp=IN/CNT

      L     #pos; 
      SLD   5; 
      LAR1  ; 
      L     DID [AR1,P#10.0]; 
      L     #OUT; 
      TAK   ; 
      -R    ; 
      L     #tmp; 
      T     DID [AR1,P#10.0]; 
      +R    ; 
      T     #OUT; 

      L     #pos; //pos um 1 erhöhen
      INC   1; 
      T     #pos; 
      L     #CNT; //Wenn pos=cnt dann pos=0
      ==I   ; 
      SPBN  ng; 
      L     0; 
      T     #pos; 
ng:   NOP   0; //Bausteinende

END_FUNCTION_BLOCK
```


----------



## Kai (17 September 2009)

SPS_NEU schrieb:


> Ich lese mit der SPS Sensorwerte ein. Diese möchte ich gern glätten. Gibt es da eine Möglichkeit. Evtl. gleitende Mittelwertbildung?


 
In dem folgenden Programmbeispiel werden die letzten 10 Messwerte in einem FIFO-Speicher gespeichert:


```
FUNCTION FC 100 : VOID
TITLE =FIFO
AUTHOR : KAI
FAMILY : SPSFORUM
NAME : FIFO
VERSION : 1.0
 
VAR_INPUT
  DB_Werte : BLOCK_DB ; 
  Anzahl_Werte : INT ; 
  Wert : REAL ; 
END_VAR
VAR_TEMP
  DB_Register : WORD ; 
  AR1_Register : DWORD ; 
  Zwischenwert : REAL ; 
  Schleife : INT ; 
END_VAR
BEGIN
NETWORK
TITLE =Register sichern
 
      L     DBNO; // DB-Register
      T     #DB_Register; 
 
      TAR1  ; // AR1-Register
      T     #AR1_Register; 
 
NETWORK
TITLE =FIFO
 
      AUF   #DB_Werte; // DB-Werte
 
      L     #Wert; // Wert
      T     #Zwischenwert; // Zwischenwert
 
      L     P#0.0; 
      LAR1  ; 
 
      L     #Anzahl_Werte; // Anzahl Werte
M01:  T     #Schleife; 
 
      L     DBD [AR1,P#0.0]; // Wert
      L     #Zwischenwert; // Zwischenwert
      T     DBD [AR1,P#0.0]; // Zwischenwert -> Wert   
      TAK   ; 
      T     #Zwischenwert; // Wert -> Zwischenwert
 
      L     P#4.0; 
      +AR1  ; 
 
      L     #Schleife; 
      LOOP  M01; 
 
NETWORK
TITLE =Register wiederherstellen
 
      AUF   DB [#DB_Register]; // DB-Register
 
      L     #AR1_Register; // AR1-Register
      LAR1  ; 
 
END_FUNCTION
```
 
Aus den gespeicherten Messwerten wird dann ein Mittelwert gebildet:


```
FUNCTION FC 110 : VOID
TITLE =Mittelwert
AUTHOR : KAI
FAMILY : SPSFORUM
NAME : FIFO
VERSION : 1.0
 
VAR_INPUT
  DB_Werte : BLOCK_DB ; 
  Anzahl_Werte : INT ; 
END_VAR
VAR_OUTPUT
  Mittelwert : REAL ; 
END_VAR
VAR_TEMP
  DB_Register : WORD ; 
  AR1_Register : DWORD ; 
  Zwischenwert : REAL ; 
  Zaehler : REAL ; 
  Schleife : INT ; 
END_VAR
BEGIN
NETWORK
TITLE =Register sichern
 
      L     DBNO; // DB-Register
      T     #DB_Register; 
 
      TAR1  ; // AR1-Register
      T     #AR1_Register; 
 
NETWORK
TITLE =Mittelwert
//Mittelwert
//
//M = LM + ((Z - LM) / N) = LM + Z / N - LM / N
//
//M  = Mittelwert
//LM = Letzter Mittelwert
//Z  = Wert
//N  = Anzahl Werte
//   
 
      AUF   #DB_Werte; // DB-Werte
 
      L     0.000000e+000; 
      T     #Zwischenwert; // M Mittelwert
 
      L     1.000000e+000; 
      T     #Zaehler; // N Anzahl Werte
 
      L     P#0.0; 
      LAR1  ; 
 
      L     #Anzahl_Werte; // Anzahl Werte
M01:  T     #Schleife; 
 
      L     DBD [AR1,P#0.0]; // Z Wert
      L     #Zwischenwert; // LM Letzter Mittelwert
      -R    ; 
      L     #Zaehler; // N Anzahl Werte
      /R    ; 
      L     #Zwischenwert; // LM Letzter Mittelwert
      +R    ; 
      T     #Zwischenwert; // M Mittelwert
 
      L     #Zaehler; // N Anzahl Werte
      L     1.000000e+000; 
      +R    ; 
      T     #Zaehler; // N Anzahl Werte
 
      L     P#4.0; 
      +AR1  ; 
 
      L     #Schleife; 
      LOOP  M01; 
 
      L     #Zwischenwert; // M Mittelwert
      T     #Mittelwert; // Mittelwert
 
NETWORK
TITLE =Register wiederherstellen
 
      AUF   DB [#DB_Register]; // DB-Register
 
      L     #AR1_Register; // AR1-Register
      LAR1  ; 
 
END_FUNCTION
```
 
Gruß Kai


----------



## Kai (17 September 2009)

Und noch zwei Bilder aus der Simulation mit PLCSIM.

Gruß Kai


----------



## Ralle (17 September 2009)

SPS_NEU schrieb:


> Also ich habe jetzt mal deine Variante Dumbledore getestet. Das Signal verändert sich zwar, aber wird nicht richtig geglättet. Ich arbeitet mit werten um 30 (REAL). Wie ist es dabei güntig den Faktor anzupassen?



Für die einfache Glättung eines Signals ist Dumledores Weg sicher die einfachste, schnellste und immer noch hinreichend genau. Beim Faktor 0,9 gehen neue Werte zu 1/10-tel in den alten Wert ein. Wenn du es noch "glatter willst" mußt du den Faktor mehr an die 1 annähern, aber denke daran, damit werden Wertänderungen auch immer langsamer in den Gesamtwert eingehen!


----------



## Kai (17 September 2009)

Dumbledore schrieb:


> wenn es sich um eine reine Glättung (ohne genaue mathematische Vorgaben dazu) handeln soll dann kann man sehr einfach ein PT1-Glied programmieren. Ich benutze dazu gerne die Formel NEUWERT = FAKTOR * ALTWERT + (1-FAKTOR) * ISTWERT. Der FAKTOR ist z.B. 0,9 (nach Bedarf anpassen). Berechnung unbedingt in REAL ausführen und auf gültige Ziffern achten, falls FAKTOR sehr nahe an 1 oder 0 liegen sollte.
> 
> 
> ```
> ...


 
Der Programmcode von Dumbledore ist nicht ganz richtig, nachfolgend der korrigierte Programmcode:


```
(alle Variablen als REAL angenommen)
L 1.0
L FAKTOR
-R
L ISTWERT
*R
[COLOR=red]T ZWISCHENWERT_1[/COLOR]
 
L FAKTOR
L GLATTWERT // ALTWERT
*R
[COLOR=red]T ZWISCHENWERT_2[/COLOR]
 
[COLOR=red]L ZWISCHENWERT_1[/COLOR]
[COLOR=red]L ZWISCHENWERT_2[/COLOR]
+R
T GLATTWERT // NEUWERT
```
 
Gruß Kai


----------



## Andreas- (18 September 2009)

*FB überarbeitet*

Hey ,

also ich habe meinen Baustein noch mal überarbeitet und getestet. Er funktioniert prima. Der Messwert wird als Real eingelesen. Ändert sich der Messwert, so wird ein Messzyklus gespeichert. Die Anzahl der Messzyklen wird als INT von 1 - 99 vorgegeben. Nach den Messzyklen wird aus den Messwerten der Mittelwert errechnet und als Real wieder ausgegeben.

Anbei die AWL-Quelle.

Grüße ^^


```
FUNCTION_BLOCK FB 37
TITLE =Mittelwertbildung nach vorgebaren Messzyklen 
//Messwert in REAL
//Mit jeder Änderung des Messwertes wird dieser gespeichert und nach der 
//vorgegebenen Anzahl der Mittelwert errechnet und ausgegeben.
VERSION : 0.1


VAR_INPUT
  Messwert : REAL ;    
  Messcyc_Anz : INT ;    
END_VAR
VAR_OUTPUT
  Mittelwert : REAL ;    
END_VAR
VAR
  Messwert_ALT : REAL ;    
  Messunglaeuft : BOOL ;    
  Gespeichert : BOOL ;    
  T_Anzahl : INT ;    
  Speicheraddresse : DWORD ;    
  Anfangsaddresse : DWORD ;    
  Zwischenergebnis : ARRAY  [1 .. 99 ] OF REAL ;    
  T_Mittelwert : REAL ;    
END_VAR
BEGIN
NETWORK
TITLE =

      L     #Messwert; 
      L     #Messwert_ALT; 
      ==R   ; 
      SPB   ENDE; 

      U     #Messunglaeuft; 
      SPB   strt; 
      SET   ; 
      =     #Messunglaeuft; 
      L     L#26; 
      SLD   3; 
      T     #Speicheraddresse; 
      T     #Anfangsaddresse; 
      L     #Messcyc_Anz; 
      L     1; 
      -I    ; 
      L     99; 
      >I    ; 
      SPBN  anza; 
      T     #T_Anzahl; 
      SPA   ENDE; 
anza: TAK   ; 
      T     #T_Anzahl; 
      SPA   ENDE; 

strt: L     #Speicheraddresse; 
      LAR1  ; 
Mess: NOP   0; 

      U     #Gespeichert; 
      SPBN  wetr; 
      CLR   ; 
      =     #Gespeichert; 
      SPA   ENDE; 

wetr: NOP   0; 
      L     #Messwert; 
      L     #Messwert_ALT; 
      +R    ; 
      L     2.000000e+000; 
      /R    ; 
      T     DID [AR1,P#0.0]; 
      SET   ; 
      =     #Gespeichert; 
      L     #Speicheraddresse; 
      L     P#4.0; 
      +D    ; 
      T     #Speicheraddresse; 
      L     #T_Anzahl; 
      DEC   1; 
      T     #T_Anzahl; 
      L     0; 
      ==I   ; 
      SPBN  Mess; 

      L     #Anfangsaddresse; 
      LAR1  ; 
      L     DID [AR1,P#0.0]; 
      L     DID [AR1,P#4.0]; 
      +R    ; 
      L     2.000000e+000; 
      /R    ; 
      T     #T_Mittelwert; 
      L     0.000000e+000; 
      T     DID [AR1,P#0.0]; 
      T     DID [AR1,P#4.0]; 
      TAR1  ; 
      L     P#8.0; 
      +D    ; 
      LAR1  ; 
      L     #T_Anzahl; 
      L     2; 
      -I    ; 
Mitt: T     #T_Anzahl; 
      L     #T_Mittelwert; 
      L     DID [AR1,P#0.0]; 
      +R    ; 
      L     2.000000e+000; 
      /R    ; 
      T     #T_Mittelwert; 
      L     0.000000e+000; 
      T     DID [AR1,P#0.0]; 
      TAR1  ; 
      L     P#4.0; 
      +D    ; 
      LAR1  ; 
      L     #T_Anzahl; 
      LOOP  Mitt; 

      CLR   ; 
      =     #Messunglaeuft; 

      L     #T_Mittelwert; 
      T     #Mittelwert; 

      L     0.000000e+000; 
      T     #T_Mittelwert; 

ENDE: NOP   0; 
      L     #Messwert; 
      T     #Messwert_ALT; 

END_FUNCTION_BLOCK
```


----------



## MDL (18 September 2009)

Hallo,
von Siemens gibts dafür bereits einen "fertigen" Fb, sehr einfach/effektiv.
(in der Bibliothek von Modular PID enthalten...FB9...LAG1ST: first-order lag element (Verzögerungsglied 1. Ordnung)
Bausteinbeschreibung :
Der Baustein glättet die Eingangsgröße nach der Verzögerung 1. Ordnung. Die Verzögerungszeit ist parametrierbar.
MFG


----------



## Andreas- (18 September 2009)

Naja, dann wars für mich halt ne effektive Übung ^_^!

BB


----------



## SPS_NEU (18 September 2009)

Vielen Dank euch allen. Ich werde mal die Varianten durch probieren. Ist dieser FB9 standartmäßig vorhanden?


----------



## Thomas_v2.1 (18 September 2009)

Andreas- schrieb:


> Hey ,
> 
> also ich habe meinen Baustein noch mal überarbeitet und getestet. Er funktioniert prima. Der Messwert wird als Real eingelesen. Ändert sich der Messwert, so wird ein Messzyklus gespeichert. Die Anzahl der Messzyklen wird als INT von 1 - 99 vorgegeben. Nach den Messzyklen wird aus den Messwerten der Mittelwert errechnet und als Real wieder ausgegeben.



Dein Programm hat mit den Thema "gleitender Mittelwert" nur nichts zu tun.
Das Programm erzeugt einen Mittelwert aus einer unbestimmten Anzahl von Werten. Unbestimmt darum, weil das Programm wenn sich der Messwert nicht ändert, den Wert einfach nicht für die Berechung heranzieht.

Zur Glättung eines Messwertes taugen diese Array-Lösungen, bei denen nach einer bestimmten Anzahl von Werten aus diesen ein Mittelwert berechnet wird, auch nicht.

Wenn z.B. pro Sekunde 100 Messwerte ins Array geschrieben werden und der daraus berechnete Mittelwert ausgegeben wird, würde sich eine Störfrequenz (z.B. Rechtecksignal) von 0,5 Hz voll auf den Ausgang durchschlagen, wenn das Sampling-Fenster genau auf eine Periode fällt.

 Beispiel:

```
Signal:
100|      |------|      |------|
   |      |      |      |      |
 0 |------|      |------|      |

Sampling:
Zyklus       1       2
          A      E
                 A      E
```
Wenn man bei A beginnt in den Array zu schreiben und bei E aufhört, kommt im Messzyklus 1 als Mittelwert 100 heraus. Im nächsten Mess-Zyklus 2 dann 0 usw.
Eine Filtercharakteristik mit Grenzfrequenzen kann man für soetwas zumindest nicht bestimmen.


----------



## Andreas- (18 September 2009)

Thomas_v2.1 schrieb:


> Dein Programm hat mit den Thema "gleitender Mittelwert" nur nichts zu tun.
> Das Programm erzeugt einen Mittelwert aus einer unbestimmten Anzahl von Werten. Unbestimmt darum, weil das Programm wenn sich der Messwert nicht ändert, den Wert einfach nicht für die Berechung heranzieht.



Danke, das du mich aufgeklärt hast.   Ich hab das ganze ein Wenig missverstanden.


----------



## borromeus (18 September 2009)

Dumbledore schrieb:


> wenn es sich um eine reine Glättung (ohne genaue mathematische Vorgaben dazu) handeln soll dann kann man sehr einfach ein PT1-Glied programmieren. Ich benutze dazu gerne die Formel NEUWERT = FAKTOR * ALTWERT + (1-FAKTOR) * ISTWERT. Der FAKTOR ist z.B. 0,9 (nach Bedarf anpassen). Berechnung unbedingt in REAL ausführen und auf gültige Ziffern achten, falls FAKTOR sehr nahe an 1 oder 0 liegen sollte.


 
Also ich verwende auch immer ein PT1- Glied, gleich aus der PCS7-Bibliothek, da kann man T1 auch einstellen- ich kenne keine Messung, die ich damit nicht in den Griff bekommen hätte.


----------



## wwwandy (18 September 2009)

Was mir an den ganzen Postings fehlt:

MTA darf man nicht mit PT1 verwechseln, auch wenn beide Tiefpasscharakteristik haben. MTA hat N Nullstellen im Frequenzgang, PT1 KEINE. Wenn du Rauschen unbekannten Spektrums minimieren willst, empfehle ich dir ein PT1, wenn du die Nullstellen als Notch-Filter ausnutzen willst einen MTA.

Anmerkungen zu meinem MTA Programm weiter oben: Dieser verwendet einen Trick, nämlich wird die Summe über N Elemente nicht jedesmal neu berechnet. Somit ist es unerheblich ob du MTA über 5 oder 100 machst.Siehst du daran, dass es keine Schleifen gibt.

Gruß Andy


----------

