Gleitende Mittelwertbildung

Beispiel FB:
Code:
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ß!
 
Zuletzt bearbeitet:
Meine Korrektur:

Beispiel FB:
Code:
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
 
Zuletzt bearbeitet:
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.

Code:
(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
 
Zuviel Werbung?
-> Hier kostenlos registrieren
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?
 
Zuletzt bearbeitet:
Code:
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
 
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:

Code:
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:

Code:
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
 

Anhänge

  • OB1.pdf
    7,7 KB · Aufrufe: 156
  • FC100.pdf
    6,4 KB · Aufrufe: 144
  • FC110.pdf
    7 KB · Aufrufe: 98
  • DB100.pdf
    4,4 KB · Aufrufe: 101
  • Fifo.zip
    33,5 KB · Aufrufe: 166
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!
 
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.

Code:
(alle Variablen als REAL angenommen)
L 1.0
L FAKTOR
-R
L ISTWERT
*R
L FAKTOR
L GLATTWERT // ALTWERT
*R
+R
T GLATTWERT // NEUWERT

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

Code:
(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
 
Zuviel Werbung?
-> Hier kostenlos registrieren
FB überarbeitet

Hey :D,

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 ^^

Code:
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
 

Anhänge

  • Mittelwertbildung.rar
    808 Bytes · Aufrufe: 65
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
 
Hey :D,

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:
Code:
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.
 
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. :p Ich hab das ganze ein Wenig missverstanden.
 
Zurück
Oben