Step 7 Wert "Null" bei PT1 Glied nicht gültig

Beiträge
2.643
Reaktionspunkte
774
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo zusammen,

Ich hab mir ein PT1 Glied programmiert und stelle fest das der Wert Null nicht gültig ist.
Das ist wenn Mann die mathematische Formel anschaut auch kein Wunder.

Die Eingangssignalen des PT1 Glieds gehen bei mir vom Minus bis Plus Werten.
Im Moment hab ich mir so geholfen.

Code:
 FUNCTION_BLOCK "PT1"
VERSION : '0.1'
AUTHOR : 'v.Berkel'
   VAR_INPUT 
      IN_REAL : Real;   // IN REAL
      Time_0_100 : Real;   // Zeit von 0 bis 100% AUSGANG zu EINGANG
      OB_Zyklus_mS : Real;   // OB Zykluszeit in mS
   END_VAR
   VAR_OUTPUT 
      OUT_REAL : Real;   // OUT REAL
   END_VAR
   VAR 
      Cache_Berechnung : Real;   // Cache_Berechnung
      Cache_IN : REAL;
   END_VAR
BEGIN
// Cache IN darf nicht null werden
IF  IN_REAL<=0.001 AND IN_REAL >=-0.001 THEN
    Cache_IN := 0.001;
ELSE
    Cache_IN := IN_REAL;
END_IF;
// PT1 Berechnung
    OUT_REAL:=(( Cache_IN-Cache_Berechnung)/((Time_0_100*100.0)/OB_Zyklus_mS))+Cache_Berechnung;
    Cache_Berechnung := OUT_REAL;
END_FUNCTION_BLOCK

In Prinzip sein Zwischenspeicher nicht auf Null gehen lassen.
Jetzt ist das Glied nicht mehr Lückenlos. Das ist auch nicht so schlimm.
Mir ist trotzdem die frage gekommen ob ich das schöner umsetzen kann.

Ich hab schon die Berechnung in diese variant gemacht.
Code:
  IF IN_REAL <> 0.0 THEN
    OUT_REAL:=((IN_REAL-Cache_Berechnung)/((Time_0_100*100.0)/OB_Zyklus_mS))+Cache_Berechnung;
    Cache_Berechnung := OUT_REAL;
    ELSE
    OUT_REAL := IN_REAL;
    END_IF;

Dan bekomme ich aber Sprüngen wenn das Signal von z.b. eine Hohe Wert direkt Null wird.

Bei der beispielvarianten von Siemens sehe ich das die einfach ein Bit setzen das sagt " not valid"

Mache ich jetzt Erbsezählerei oder ist meine erste Umsetzung o.k.?

Bin gespannt auf euer Meinung.

Bram
 
Hab das jetzt nicht genau angeschaut, aber wenn hier irgendwo durch 0 dividiert wird, dann geht das eben nicht.

Vor der Division einen Vergleich: R=0, dann R=0,0000001 oder so ähnlich, dann verhinderst du dass wirklich durch 0 dividiert wird und dein tatsächlicher Fehler wird in der Praxis wohl nicht auffallen.

Alternative: wenn der Wert 0 wird einfach die Berechnung überspringen und das dann richtige Ausgeben, so kommt es auch zu keiner Division durch 0.
 
Hab das jetzt nicht genau angeschaut, aber wenn hier irgendwo durch 0 dividiert wird, dann geht das eben nicht.

Vor der Division einen Vergleich: R=0, dann R=0,0000001 oder so ähnlich, dann verhinderst du dass wirklich durch 0 dividiert wird und dein tatsächlicher Fehler wird in der Praxis wohl nicht auffallen.

Alternative: wenn der Wert 0 wird einfach die Berechnung überspringen und das dann richtige Ausgeben, so kommt es auch zu keiner Division durch 0.

Die variante mit der vergleicher hab ich umgesetzt.
Eigentlich mit gute ergebnisse.

Bram
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Das Problem ist das der Ausgangswert weit ins minus rutscht bei in ist 0.0 und damit unbrauchbar ist für weitere verarbeitung.

Bram

Naja, das mit dem Minus stimmt nicht ganz.
Eigentlich wird das Real Format versaut wenn der IN_REAL Null wird.
Sprich, mit diese Code.

Code:
 OUT_REAL:=(( IN_REAL-Cache_Berechnung)/((Time_0_100*100.0)/OB_Zyklus_mS))+Cache_Berechnung;
    Cache_Berechnung := OUT_REAL;



Screenshot.jpg

Bram
 
Zuletzt bearbeitet:
Hmm, verstehe eigentlich immer noch nicht, wo Dein Problem liegt.

trotzdem hier mal mein Code für nen "richtiges" PT1:

Code:
VAR_INPUT
    Takt_10Hz :BOOL :=FALSE; //Taktmerker 10Hz
    INfVal  :REAL :=0.0;     //IN - value
    INfKP   :REAL :=1.0;     //IN - proportional coefficient
    INfT1   :REAL :=1.0;     //IN - time constant
    
END_VAR
VAR_IN_OUT
END_VAR
VAR_OUTPUT
    QfVal   :REAL :=0.0;  //Ausgangswert
END_VAR
VAR
    
    QfValTmp : REAL;
// TAGS for Edge detect
    Takt_OLD : BOOL := FALSE;
END_VAR
VAR_TEMP
END_VAR
BEGIN;
    
// PT1 Calculation =====================================================
    IF Takt_10Hz AND NOT Takt_OLD THEN
        // PT1 Calculation IN1 =========================================
        QfValTmp := QfValTmp + (0.1 / INfT1 * ((INfKP * INfVal) - QfValTmp));
    END_IF;
    QfVal := QfValTmp;
    
// Set Tags for edge detect =====================================
    Takt_OLD := Takt_10Hz;
    
END_FUNCTION_BLOCK

an Takt_10Hz kommt der 10Hz Taktmerker dran.

Gruß.
 
Hallo Ducati,

Ich hab gerade dein Baustein in der SPS geprüft. Was mir auffällt ist das auchdiese Baustein sich "Verschluckt" beim Eingangswert = Null
Die PT1 Charakteristik ist der gleiche wie mein eigenes.

Ich will eigentlich das wenn der IN_REAL Null wird, der Ausgangswert auch Null ist.
Hab es auch nahezu hinbekommen durch ein Vergleichung ein zu bauen.

Das Problem ist wenn der Wert " Versaut " ist ich diese nicht als prozesswert eines Regler anbieten kann.

Bram
 
Was verstehst Du unter "versaut" ?

in Deinem Screenshot ist der Out_Real -5.79*10^-37 also fast 0.0 (-0.00000000000000000000000000000000000005794449).

oder was meinst Du?

Gruß.

Mmmm, du hast recht.

ich glaube das mir das Darstellungsformat mir verwirrt hat.

ich hab mal ein einfache P-Regler gemacht und sehe das mit Fest und PT1 Werte der Ausgang in Ordnung ist.
Dann kann ich mir das vergleichen auch sparen :grin:

Bram
 
Hmm, verstehe eigentlich immer noch nicht, wo Dein Problem liegt.

trotzdem hier mal mein Code für nen "richtiges" PT1:

QUOTE]

und hier meinen ;-)

FUNCTION_BLOCK "PT1"

NAME:'PT1'

VERSION:'2.0'
// Typical-Attribute
KNOW_HOW_PROTECT
VAR_INPUT
X : REAL; // Eingang
K : REAL := 1.0; // Übertragungskonstante
T : REAL := 1.0; // Zeitkonstante; Angabe in s
Ta : REAL:= 0.1; // Abtastzeit; Angabe in s
Track : BOOL;
XN : REAL;
END_VAR
VAR_OUTPUT
Y : REAL; // Ausgang

END_VAR
VAR_TEMP
Tx : REAL; // temporäre Variablen

END_VAR
VAR
bsT, bsTa : REAL;
Yn : REAL :=0; // Altwert
X_ini : BOOL := false;
END_VAR


//*******************************************************
// Zeitdiskretes PT1 Glied
//*******************************************************



IF Ta <= 0.0 THEN
// Anweisungsteil_IF
bsTa := 0.1; //default
ELSE
bsTa := Ta;
;
END_IF;

IF T < bsTa THEN
// Anweisungsteil_IF
bsT := bsTa; //default
ELSE
bsT := T;
;
END_IF;




Tx := bsT/bsTa;
Yn :=X*K/Tx+(1 - 1/Tx)*Yn;

IF Track THEN
Yn := XN;
END_IF;

Y := Yn;
IF NOT OK THEN
Yn :=0;
Y := 0;
X_ini := true;
OK := true;
END_IF;

;
END_FUNCTION_BLOCK
 
Zurück
Oben