Werte glätten

McNugget

Level-1
Beiträge
220
Reaktionspunkte
10
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo allerseits.
Habe schon einiges hier im Forum gelesen und leider gesehen, dass ich letztes Wochenende in Bielefeld wohl gefehlt habe. :p
Hiermit melde ich mich mal mit einem ersten Thread und natürlich als Neuling in dem gesamten Programmierthema speziell in bezug auf ST mit einer dummen Frage.

Die Suche habe ich schon zu Rate gezogen, konnte aber bisher aus den gegebenen Antworten nichts passendes für mich triangulieren.. (liegt wohl an Unerfahrenheit)

Ich habe zwar Beispiele zum Glätten von Eingangswerten für AWL und SCL gesehen, konnte dies aber nicht in ST übertragen.

Wie sähe ein Codeschnipsel aus, mit dem ich einen WORD-Wert (von Busklemmen eines WAGO Feldbusknoten 750-841) der stark pendelt um Ausreisser bereinige und mit dem ich ein relativ sauberes gemitteltes Ausgangssignal erhalte?

Ich bin froh, dass es im Internet Foren dieser Art gibt.

Gruss

McNugget
 
OK.. Habe es mal versucht:
Läuft nicht.

Deklarationsteil:
FUNCTION_BLOCK FIlter_AI
VAR_INPUT
IN: WORD ;
END_VAR

VAR_OUTPUT
Durchschnitt: WORD;
END_VAR

VAR
Messwert:ARRAY[1..10 ] OF WORD;
I: INT;
Out: BOOL;
END_VAR

Anweisungsteil:
Durchschnitt:=0;

FOR i:=1 TO 10 DO
Durchschnitt := Durchschnitt + messwert;
END_FOR
Durchschnitt := Durchschnitt/10;


Der Eingang "IN" müsste doch irgendwo explizit einfliessen, oder?
Ausserdem setzt sich der Baustein doch immer wieder auf "0" zurück.

Wie gesagt: blutigster Anfänger in puncto Schleifen.

Gruss

McNugget
 
Ohne zu testen:
Code:
IF j > 10 THEN
    j := 1;
END_IF;

messwerte[j] := ExtMesswert;

durchschnitt := 0;
FOR i:=1 TO 10 DO
  durchschnitt := durchschnitt + messwerte[i];
END_FOR
durchschnitt := durchschnitt/10;
j := j + 1;

Man hat ein Array in dem die letzten 10 Messwerte gespeichert werden. Dieses Array wird dann wie von drfunfrock beschrieben aufaddiert und durch die Anzahl der Elemente dividiert was den Durchschnitt ergibt.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Vielen Dank Zotos,

ok, hier im Forum geht es etwas fixer zu.. Sehr cool. :D

Ich habe es so übernommen, aber nun passiert folgendes:

Das Array füllt sich in allen 10 Zeilenmit Werten zwischen 17000 und 17200, aber der errechnete Durchschnitt pendelt immer so um die 4000.

Da ist doch irgendwo noch der Wurm drin. oder habe ich irgendwas falsch übertragen?

Kann man den Wert Durchschnitt mit etwas anderem als einer 0 initialisieren?
Zum Beispiel einmalig der Aktualwert am Eingang?

Gruss

McNugget


PS: Zotos: Kann es sein, dass Du den Anhalter gelesen hast?
 
Zuletzt bearbeitet:
Das Beispiel von Zotos sieht für mich gut aus ... was mir nicht so gefällt ist das du in deinem Beispiel mit dem Variablentyp WORD arbeitest. Das könnte ggf. schon das Problem sein. Ansonsten stell doch einfach mal den Code deines Bausteins hier ein ...
 
Also ich würde das so machen:

Code:
durchschnitt:=(durchschnitt*10+messwert)/11;

ist etwas übersichtlicher und schneller.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo Larry,

die analoge Eingangsklemme liefert direkt ein Word. Ich möchte den Wert so früh wie möglich im System "beruhigen", bzw. glätten, und erst dann mit Typkonvertierungen beginnen, um eventuelle Rundungsfehler etc. möglichst zu minimieren.
Ist der Ansatz falsch?

Deklaration:
FUNCTION_BLOCK FIlter_AI
VAR_INPUT
IN: WORD ;
END_VAR

VAR_OUTPUT
Durchschnitt: WORD;
END_VAR

VAR
Messwerte:ARRAY[1..1000 ] OF WORD;
I: INT;
j: INT;
END_VAR


Anweisungsteil:

IF j > 10 THEN
j := 1;
END_IF;

messwerte[j] := IN;

durchschnitt := 0;
FOR i:=1 TO 10 DO
durchschnitt := durchschnitt + messwerte;
END_FOR
durchschnitt := durchschnitt/10;
j := j + 1;


Bin begeistert von der Anteilnahme. ;-)

Gruss

McNugget
 
Ich hatte ebenfalls vergessen, dass man natürlich nicht in eine Word-Var aufaddiert, weil es dann zu Überläufen kommt. Meine Var durchschnitt muss dann grösser als WORD sein. Nimm einfach UDINT.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Ok.. Habe ich gemacht, der Ausgabewert ist realistisch.
Aaaber: nun pendelt der Ausgabewert fast so schnell wie der Eingabewert, liegt wahrscheinlich daran, dass nur 10 Zyklen addiert werden und die Zykluszeit recht kurz ist (unter 15ms).
Kann ich das irgendwie schöner machen? Zyklenanzahl erhöhren wird wohl auch nicht endlos gehen, da ich dann ja auch irgendwann einen Überlauf produziere, oder?

Ausserdem habe ich in einem anderen Thread was davon gelesen, dass man die Werteveränderungen, die ein bestimmtes delta überschreiten, ausblenden kann.
Das wäre superedel.

Gruss

McNugget
 
Zuletzt bearbeitet:
also langsamer wird deine wertänderung, wenn du nur zu bestimmten zeiten einen neuen wert in dein fifo schreibst.

delta und grenzen sind ganz einfache grenzwertabragen, also

IF wert < grenzwert_max AND wert > grenzwert_min
THEN "wert verarbeiten"
ELSE "wert ignorieren"
 
Für einen schnellen Test bietet sich die Variante von repök an:

Code:
If messwert > LLim AND messwert < ULim THEN
   durchschnitt:=(durchschnitt*100+messwert)/101;
END_IF

LLim unteres Limit und ULim Oberes Limit. wenn der aktuelle Messwert ein "Ausreißer" ist wird mit dem alten Durchschnitt gearbeitet. Dies beinhaltet natürlich auch die Gefahr das man einen Sensor defekt nicht erkennt usw. das kann man dann aber auch mit einem Zähler abfangen.

Code:
If messwert > LLim AND messwert < ULim THEN
   durchschnitt:=(durchschnitt*100+messwert)/101;
   ErrorCount := 0;
ELSE
   ErrorCount := ErrorCount + 1;
END_IF

IF ErrorCount > 20 THEN
   (* Mach was! der Sensor ist kaputt!*);
END_IF
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Du kannst die Schleife sehr wohl recht heftig erhöhen, wenn die CPU das mitmacht. Das kannst du ja im Systemmanager sehen, wieviel CPU-Zeit verbraucht wird. Ich denke, eine Schleife bis 100 funktioniert auf einem X86-prozessor recht gut.
 
Sehr nette Anregungen.
Vielen Dank.

@vierlagig: habe jetzt einen Taktgeber davorgesetzt, und das Array auf 100 erhöht: ein schöner ruhiger Wert.
Zu der Grenzwertverletzung: Wäre das folgende sinnvoll?
IF wert > grenzwert_max AND wert > grenzwert_min
THEN "Return"
ELSE "arbeite die Schleife ab"

@Zotos: wenn der Sensor defekt ist, würde der Wert doch mit der Zeit gegen Null, bzw. gegen unendlich steigen, oder? (Gilt natürlich nur, wenn der Sensor definitiv einen Schluss oder einen Kabelbruch erlitten hat.)

Ich habe es bereits bei defekten Transmittern erlebt, dass die von 0-20 mA hoch und runter schwingen. Dazwischen immer mal wieder ein annehmbarer Wert. So ein Fehler liesse sich mit einem solchen array wahrscheinlich auch nnicht herausfinden.

Zudem hat Wago in seinen Klemmen im Datenwort zwei Statusbits, die auf Fühlerbruch hinweisen, aber dazu komme ich die Tage noch mal. Habe auch da noch dumme Fragen.

Vielen Dank schon mal für die Vielzahl an Antworten und Tipps.

Macht ja richtig Spass, so ein Feedback zu bekommen und so nett aufgenommen zu werden.

McNugget
 
Ich habe es bereits bei defekten Transmittern erlebt, dass die von 0-20 mA hoch und runter schwingen. Dazwischen immer mal wieder ein annehmbarer Wert. So ein Fehler liesse sich mit einem solchen array wahrscheinlich auch nnicht herausfinden.

Ich denke doch.
Du kannst doch in der Schleife genausogut wie du die Summenbildung für den Mittelwert machst auch nach groben Ausreissern gegenüber dem letzten erfassten Mittelwert suchen. Hast du solche erkannt, so kannst du z.B. daraus eine Fehlermeldung generieren oder/und sie bei der Mittelwertbildung ignorieren etc. - Im Prinzip ähnlich wie der Filter von Vierlagig.

Zu deiner Abtastrate:
Du könntest den FB auch zyklisch aufrufen und ihm als Parameter die OB1_Zykluszeit und ein gewünschtes Einlese-Intervall übergeben. Die Zykluszeit addierst du auf und führst den FB immer dann aus, wenn die aufaddierte Zeit > der Abtastrate ist.

Gruß
LL
 
Zuviel Werbung?
-> Hier kostenlos registrieren
@vierlagig: habe jetzt einen Taktgeber davorgesetzt, und das Array auf 100 erhöht: ein schöner ruhiger Wert.
Zu der Grenzwertverletzung: Wäre das folgende sinnvoll?
IF wert > grenzwert_max AND wert > grenzwert_min
THEN "Return"
ELSE "arbeite die Schleife ab"

eher:

IF wert > grenzwert_max OR wert < grenzwert_min
THEN "Return"
ELSE "arbeite die Schleife ab"
 
möchte nur darauf hinweisen das glätten normalerweise etwas anderes ist als durchschnitt.

der durchschnitt ist je nach anzahl der punkte auch relativ aufwendig.

besser geegnet sollte da eine tiefpassfunktion sein die den oberen frequenzbereich des signals abschneidet.

aber beide funktionen durchschnitt sowie tiefpass findest du auch im source code in der open source library von oscat unter www.oscat.de

der tiefpass heist dort FT_PT1
 
@hugo:

die mittelwertbildung zur quasi-glättung ist ein erprobtes und gängiges mittel. mir ist bis jetzt noch kein erfahrener programmierer untergekommen, der davon abstand nehmen würde. vorallem ist es schnell und einfach umgesetzt und darüber hinaus, richtig implentiert sehr flexibel.

sicher, es ist nicht die mathematisch korrekte variante, aber bei den meisten messwerten doch ausreichend.
 
Zurück
Oben