Problem mit floating point Operationen

bone666

Level-1
Beiträge
72
Reaktionspunkte
4
Zuviel Werbung?
-> Hier kostenlos registrieren
Guten Tag,

ich versuche eigentlich nur aus 3 Wertpaaren den Leistungsfaktor, also lambda=|P|/S, mit einem FB zu berechnen. Jedoch schmiert mir bei der Ausführung das gesamte System ab. Nutze übrigens TC 3.1 auf einem C5210.

Nun zu meinem FB
Code:
FUNCTION_BLOCK FB_Power_Factor
VAR_INPUT
    fl32_P1     :REAL;
    fl32_P2     :REAL;
    fl32_P3     :REAL;
    
    fl32_S1     :REAL;
    fl32_S2     :REAL;
    fl32_S3     :REAL;
END_VAR
VAR_OUTPUT
    fl32_PF1     :REAL;
    fl32_PF2     :REAL;
    fl32_PF3     :REAL;
END_VAR
VAR
    dummy :ARRAY[1..3]OF REAL;
END_VAR
Code:
dummy[1]:=ABS(fl32_P1);
dummy[2]:=ABS(fl32_P2);
dummy[3]:=ABS(fl32_P3);

fl32_PF1:=(dummy[1]/fl32_S1);
fl32_PF2:=(dummy[2]/fl32_S2);
fl32_PF3:=(dummy[3]/fl32_S3);

Als Fehler erscheint daraufhin folgendes
fehler1.jpg
Außerdem kommt noch der Fehler "Ads-Error 0x12:port is disabled" dies hat jedoch damit zu tun, dass TwinCAT in den "Exceptionmode"(gelbes Symbol) wechselt.
Hat vielleicht jemand einen Tipp für mich?

MfG

Bone
 
Division durch Null mag kein Rechner. Ich würde da auch abschmieren.....

An den Fehlermeldungen könnte Beckhoff aber noch arbeiten. /0 Exceptions sollte man schon als Klartext erwarten können.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Ganz allgemein: Sobald etwas geteilt werden soll, dass ganze in eine IF-Anweisung packen, den Teiler mit Null vergleichen und sonst eine Fehlermeldung bringen. Direkt angewöhnen und nie vergessen.
 
Danke für die schnellen Antworten. Dachte mir schon so etwas. Jetzt muss ich mal gucken wo ich den Bock eingebaut habe -.-
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Teilen durch Null kann nur der Mensch

Echt jetzt? Gibt es unter Codesys wirklich keine andere Möglichkeit? Was bedeutet in diesem Fall "Abschmieren"?

Wenn man es nicht garantieren kann, dass da keine Null im Nenner steht, muss man schon das ganze vor der Division überprüfen. Das überlebt sonst kein mir bekanntes "RohProgramm" System.

Interessant wird es bei der SPS, was macht man denn im Fall des Falles! Ich habe schon etliche Programme als Revisor gesehen, die da keine Antwort für im Code haben.
 
Morgen allerseits

@ Onkel Dagobert: Abschmieren meint in meinem Fall, dass sich mein System aus dem Runmode in den Exceptionmode versetzt und ich neustarten muss.

Habe das Problem übrigens gefunden, habe falsche Variablen verknüpft, sodass ich dachte, dass eig. ein Wert >0 anliegen müsste, dem war jedoch nicht so.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Hi oliver,

was genau meinst du mit einer Überprüfungsfunktion?
Das Problem ist momentan, dass ich bis auf meinen IPC noch keine andere Hardware habe. Also alles nur "offline" teste. Wenn das System irgendwann mal von meinen Kommilitonen aufgebaut worden ist und alle Messungen richtig laufen, sollte es eig. nicht vorkommen, dass eine Leistung=0 ist, sodass auch nicht durch 0 geteilt wird.
 
Ein Steuerungsprogramm darf sich nicht darauf verlassen, daß ein Wert 0 "eigentlich nicht vorkommen" kann. Sowas muß mittels vorheriger Prüfung garantiert werden. Ein Steuerungsprogramm ist so schnell, daß alles was theoretisch vorkommen kann auch zur Lebenszeit des Programmierers mal vorkommt ;)

Harald
 
Die "Überprüfungsfunktion" von der Oliver spricht nennt sich "CheckFunctions". In V3 weiß ich nicht wie die da genau heißen. Bei V2 gibt es diese. Das kann man über die Hilfe rausfinden wie diese zu definieren sind.

Es handelt sich hierbei um Callbacks die implizit aufgerufen werden bei z.B. Division durch Null. Eine andere CheckFunction die es gibt wäre "CheckBounds" da kannst du sicherstellen, dass du bei einem indizierten Zugriff auf ein Array nicht ein Index angibst der nicht existiert.

Beispiel:

myArray : ARRAY [0..10] OF BOOL;

wenn du nun auf das Element myArray[11] zugreifst wird implizit die Funktion aufgerufen und du kannst die Grenzen prüfen ob diese verletzt wurden. Das Gibt's auch für Nulldivision CheckDivZero dann kannst du den Nenner auf 0 prüfen und dann z.B. eine 1 zurückgeben damit zumindest die PLC nicht mit Fehler stehen bleibt.

Aber Achtung: Die Checkfunktionen sind nur für die Entwicklungszeit gedacht. Bei Checkbounds kannst du dir vorstellen, dass diese sehr viel Performance benötigt. Muss ja bei jedem Zugriff auf jedes Arrayelement die Funktion als Callback durchlaufen werden. Wenn alles läuft habe ich die Funktionen immer wieder entfernt bevor die Anlage in Betrieb geht.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo Bone666,
was genau meinst du mit einer Überprüfungsfunktion?
im InfoSys findest Du hier alle Infos dazu:
http://127.0.0.1:47873/help/1-3392/...=de-de&topiclocale=DE-DE&topicversion=0&SQM=2

Du legst eine neue Überwachungs-POU an:
AddPOU.png

Die von TwinCAT vorgeschlagene Implementierung verhindert zunächst "nur", dass ein Divisor 0 sein kann indem die Funktion ihn auf 1 setzt.
TemplateCode.png

Diese Funktion kannst Du dann nach Deinen Wünschen noch erweitern (nur nicht den Deklarationsteil), z.B. kannst Du eine globale Variable anlegen und diese in der Funktion setzen um in Deinem Programm zu erkennen, dass eine Division durch 0 erfolgte und Dein Programm dann abbrechen. Allerdings ist mir, wo ich gerade so darüber nachdenke, nicht ganz klar, wo der Vorteil dieser Funktion liegt. Die Funktion macht wohl nur wirklich Sinn, wenn es nichts ausmacht, dass im Falle einer 0 durch 1 geteilt wird, bei allen anderen Fällen müsste man ja noch weiteren Aufwand treiben und da könnte man auch gleich noch eine If-Abfrage auf 0 mit einbauen. Oder wie sehen das die Experten hier?

Gruß

Oliver
 
Der Vorteil der Funktion wird wohl sein, das die CPU nicht in den Fehlerzustand geht und neu gestartet werden muss. Man kann also selber eine Fehlerreaktion erstellen, die im Einfachsten Fall das Ergebnis einfach verwirft oder meldet das mit dem Divisor was faul ist.
Oftmals kann es ja auch durch Rundungsfehler, unglücklichen Typenkonvertierungen oder Überläufen zu einer Division durch 0 kommen.

Die impliziten Funktionen laufen dann immer automatisch mit so wie ich das verstehe. D.h. sie werden bei jeder Division mit aufgerufen. Man muss also nicht selber jeden Divisor im Code überprüfen.
 
Zuletzt bearbeitet:
Hallo MasterOhh,
Der Vorteil der Funktion wird wohl sein, das die CPU nicht in den Fehlerzustand geht und neu gestartet werden muss.
das stimmt, aber das Ergebnis ist ja dann falsch und das Programm läuft fröhlich weiter, wenn ich also dann noch Abfragen in meinem Programm machen muss, ob die DivByZero Funktion zugeschlagen hat ist der Aufwand den ich dann noch treiben müsste für die Abfrage auf 0 vernachlässigbar und ich kann mir die Funktion eigentlich schenken.
Im Moment ist die Funktion, außer ein falsches Ergebnis spielt keine Rolle, für mich Spielerei, widersprecht mir falls ich mich irre.
 
Zuletzt bearbeitet:
Zuviel Werbung?
-> Hier kostenlos registrieren
Ich vermute mal, daß nicht nur 0.0 gefährlich ist. Es gibt doch bestimmt auch einen maximal zulässigen Wert für den Divisor. Man könnte/sollte einfach den Eingangswert auf einen Wert innerhalb zulässiger Grenzen limitieren, z.B. LIMIT(0.01, var, 1000.0)

Harald
 
Wenn man keine Lust hat, auf 0 zu prüfen, kann man auch noch dem Divisor eine Winzigkeit hinzuaddieren: x=Dividend/(Divisor+1.0e-19) oder 1.0e-29 oder was auch immer in der jeweiligen floating-point-Darstellung noch sicher eine von 0 verschiedene Zahl ist und andererseits den Wert nicht zu sehr verfälscht. Ermöglicht einerseits die exakt selben Programmschritte (ohne Abfrage/Sprünge/Verzweigungen) zu durchlaufen und andererseits geht das Ergebnis in die richtige Richtung (Richtung unendlich).
 
Wenn man keine Lust hat, auf 0 zu prüfen, ....

Genau das nicht! Es geht hier nicht um Lust sondern was macht man bei dem Fall null.

In der Regel ist da was schwer faul und die NichtPrüfung auf 0 ist "Augen zu und durch".

Das rächt sich in einer nicht Spielzeug Umgebung langfristig immer!

Also, wenn Nenner = null, dann eine angemessene Reaktion im ELSE Zweig!
 
Zurück
Oben