Basierend auf meinem Heizungssteuerung-Thread habe ich mich gleich an den Quelltext des Bausteins ran gemacht...
Da ich (noch) kein php kann und mir die Befehle bzw. Logiken ein wenig zusammen gereimt habe kam nun folgender Code heraus:
Bitte prüfen und vielleicht kann der Code ja dann in den LBS eingepflegt werden... saegefisch
Da ich (noch) kein php kann und mir die Befehle bzw. Logiken ein wenig zusammen gereimt habe kam nun folgender Code heraus:
PHP-Code:
###[DEF]###
[name = PID-Regler V0.2]
[e#1 IMPORTANT = Soll]
[e#2 IMPORTANT = Ist]
[e#3 = Arbeitspunkt (y0) #init=0]
[e#4 = P-Glied #init=1]
[e#5 = I-Glied #init=1]
[e#6 = D-Glied #init=1]
[e#7 = Aktiv #init=1]
[e#8 IMPORTANT = P: Proportionalbeiwert (Kp) #init=2]
[e#9 IMPORTANT = I: Integrierzeit (Ti)(sec) #init=60]
[e#10 = max. Stellgröße #init=100]
[e#11 = min. Stellgröße #init=0]
[e#12 = Reset Summen]
[e#13 = pos./neg. Annäherung #init=0]
[a#1 = Soll (1:1)]
[a#2 = Ist (1:1)]
[a#3 = Zyklen]
[a#4 = Stellgröße]
[a#5 = Stellgröße (sbc)]
[a#6 = Stellgröße P-Teil]
[a#7 = Stellgröße I-Teil]
[a#8 = Stellgröße D-Teil]
[v#1 = 1 ] // Zyklen
[v#2 = 0 ] // Zeit
[v#3 = 0 ] // e sum (I-Glied)
[v#4 = 0 ] // e alt (D-Glied)
[v#5 = 0 ] // y alt (sendbychange)
// Grunddaten
[v#100 = 0.2 ] // Version
[v#101 = 19000113 ] // LBS
[v#102 = Heizung ] // eigens Log-File oder leer für TraceLog // in diesem LBS zZ kein Logging
[v#103 = 0 ] // LogLevel // in diesem LBS zZ kein Logging
[v#104 = ] // PreFix für FehlerLog // in diesem LBS zZ kein Logging
[v#105 = PID ] // MainTag für FehlerLog // in diesem LBS zZ kein Logging
[v#106 = 500 ] // Wartezeit(ms):Delay(statefull) oder usleep(EXEC) // hier scheint 2x pro Sekunde ein guter Wert
###[/DEF]###
###[HELP]###
PID-Regler V0.2
Reglerart: beliebige Kombination aus P-, I- und/oder D-Glied
$y = Kp*e + Ki e dt + Kd * de/dt mit Ki = Kp/Ti und Kd = Kp*Td
Fachliche Fragen zu PID? Wat issn dat? WWW fragen (Wikipedia, Hersteller z.B. Samson,..) :o)
Das P-Glied, I-Glied und D-Glied kann einzeln de/aktiviert werden, um auch P, PI, PD oder PID-Regelungen zu erreichen. Der LBS wurde bewusst generisch gehalten, die Nutzung ist nicht auf Temperaturen beschränkt, sondern kann prinzipiell für jede Regelgröße verwendet werden.
Es wurde vereinfachend die Zeitkomponente Td auf die Zeitkomponente Ti (Integrierzeit) gesetzt. Sollte dies nicht sinnvoll sein, so könnte man das noch ergänzen. Mir schien es hinreichend so. Bitte ggf. Rückmeldung an mich.
Ich hab kein Logging oder Fehlerhandling vorgesehen, es erschien mir hier nicht nötig. Die Analyse erfolgt am besten anhand der sich ergebenden Regelkurven oder mit Live-Werten im Logikeditor.
Habe ich eine Prüfung zur Fehlervermeidung vergessen? Bitte Rückmeldung an mich. Der Baustein sollte sparsam arbeiten, auch bei Einsatz mehrerer LBS für mehrerer Heizkreise. Sollte dies nicht zutreffen, bitte Rückmeldung an mich. Sonstige konstruktive Kritik. Her damit! :o) Wir haben ja von V0.1 bis V1.0 noch Luft...
Der Baustein wurde für den Gesamtkontext einer Heizungsregelung entwickelt. Für nähere Infos siehe Hilfe von LBS 19000115. Es gibt aber in Haus und Garten eine ganze Reihe anderer denkbarer Nutzungsmöglichkeiten.
Der Baustein wird gestoppt durch setzen von Aktiv = 0 oder Integrierzeit = 0. Dies sollte z.B. im Sommer zur Ressourcenschonung gemacht werden mit einem zentralen "Flag Heizperiode". Wenn der Baustein deaktiviert wurde, beginnt er bei erneuter Aktivierung ganz neu (Zyklen, Integralsumme,...).
Bei Bedarf kann man die Summen auch jederzeit zurück setzen (für D-Glied, aber insbesondere I-Glied)
Mit positiver bzw. negativer Annäherung ist gemeint, ob sich der Regler von unten (SOLL-Wert ist größer als IST-Wert, z.B. Heizen) oder von oben (SOLL-Wert ist kleiner als IST-Wert, z.B. Kühlen) annähert.
<hr />
<b><span style="text-decoration: underline;">Eingänge</span></b>
E1: SOLL-Wert (z.B: Temperatur).
E2: IST-Wert (z.B: Temperatur)
E3: Arbeitspunkt y0, d.h. Nullwertverschiebung von y. Dürfte meist mit 0 richtig sein
E4: P-Glied aktivieren für Stellwert-Berechnung?
E5: I-Glied aktivieren für Stellwert-Berechnung?
E6: D-Glied aktivieren für Stellwert-Berechnung?
E7: PID-Regler aktivieren/deaktivieren. Mit E7=0 wird der Baustein deaktiviert, d.h. der LBS wird gestoppt
E8: P: Proportionalbeiwert (Kp) für P-Glied, geht aber auch in I und D ein, daher stets versorgen!
E9: I: Integrierzeit (Ti)(sec) für I-Glied, d.h. in welchem Zeitintervall das Integral mit einem zusätzlichen Wert neu berechnet wird.
Der Wert entsprichte aber auch dem Neuberechnungsintervall aller Glieder, daher stets versorgen!
E10: max. Stellgröße zur oberen Begrenzung des Stellwerts (wenn > max, dann = max). 100 dürfte meist sinnvoll sein
E11: min. Stellgröße zur unteren Begrenzung des Stellwerts (wenn < min, dann = min). 0 dürfte meist sinnvoll sein (Visu, GA) oder ggf. -100 für weitere Berechnungen
E12: Zwischenzeitlicher Reset der Summen/gemerkten Werte durch senden einer 1
E13: positive oder negative Annäherung an den Sollwert, sprich von "oben" oder von "unten"
<b><span style="text-decoration: underline;">Ausgänge</span></b>
A1: durchgereichter SOLL-Wert (1:1) (Sieht schöner verkabelt aus im Logikeditor bei nachgelagerter Regelung)
A2: durchgereichter IST-Wert (1:1) (Sieht schöner verkabelt aus im Logikeditor bei nachgelagerter Regelung)
A3: Anzahl I-Zyklen seit letztem Aktivieren oder Reset
A4: berechnete Stellgröße
A4: berechnete Stellgröße (send-by-change)
A6: P-Teil der berechneten Stellgröße (eher informatorisch; roh, nicht begrenzt)
A7: I-Teil der berechneten Stellgröße (eher informatorisch; roh, nicht begrenzt)
A8: D-Teil der berechneten Stellgröße (eher informatorisch; roh, nicht begrenzt)
<hr />
<b><span style="text-decoration: underline;">Changelog</span></b>
0.2:
-Kühlfunktion integriert
0.1:
-initiale Version
###[/HELP]###
###[LBS]###
<?
function LB_LBSID($id) {
if ($E=logic_getInputs($id)) {
if ($E[12]['value']!=0&&$E[12]['refresh']!=0||$E[1]['refresh']!=0) {// Reset bei neuem SOLL-Wert oder angefordertem Reset
logic_setVar($id,3,($E[1]['value']-$E[2]['value'])); // V3: esum init: 0
logic_setVar($id,4,($E[1]['value']-$E[2]['value'])); // V4: ealt init: Regeldifferenz e = Soll-Ist
logic_setVar($id,1,1); // V1: Zyklus = 1
}
if ($E[7]['value']!=0&&$E[9]['value']!=0) { // LBS startet nur, wenn Aktiv = 1 UND Zeit nicht Null
if (logic_getState($id)==0) { // LBS läuft nicht?
logic_setState($id,1,logic_getVar($id,106),true); // LBS "starten"
$Zyk = 1;
logic_setVar($id,1,$Zyk); // V1: Zyklus = 1
logic_setVar($id,2,(getMicrotime()+$E[9]['value'])); // V2: Timestamp + E9
logic_setVar($id,3,($E[1]['value']-$E[2]['value'])); // V3: esum init: Regeldifferenz e = Soll-Ist (oder besser 0?)
logic_setVar($id,4,($E[1]['value']-$E[2]['value'])); // V4: ealt init: Regeldifferenz e = Soll-Ist
logic_setVar($id,5,0); // V5: y alt = 0
logic_setOutput($id,1,$E[1]['value']); // A1: Soll durchreichen (z.B: für nachgelagerten Heiz-LBS)
logic_setOutput($id,2,$E[2]['value']); // A2: Ist durchreichen (z.B: für nachgelagerten Heiz-LBS)
logic_setOutput($id,3,$Zyk); // A3: Zyklen ausgeben (nur informativ)
logic_setOutput($id,4,0); // A4: Stellgröße ausgeben
logic_setOutput($id,5,0); // A5: Stellgröße ausgeben
logic_setOutput($id,6,0); // A6: Stellgröße ausgeben
logic_setOutput($id,7,0); // A7: Stellgröße ausgeben
logic_setOutput($id,8,0); // A8: Stellgröße ausgeben
} else {
if (getMicrotime()>=logic_getVar($id,2)) { // Zeit abgelaufen
$Zyk = logic_getVar($id,1); // Zyklus aus V1 holen
$Zyk = $Zyk + 1; // Zyklus hochzählen
logic_setVar($id,1,$Zyk); // V1: Zyklus merken
logic_setVar($id,2,(getMicrotime()+$E[9]['value'])); // V2: Timestamp + E9 merken
$Soll = $E[1]['value']; // Sollwert
$Ist = $E[2]['value']; // Istwert
$y0 = $E[3]['value']; // Arbeitspunkt
// pos. oder neg. Annäherung
if ($E[13]['value']=0) {$d = $Soll-$Ist;} // Regeldifferenz (e) wenn Soll>Ist
if ($E[13]['value']=1) {$d = $Ist-$Soll;} // Regeldifferenz (e) wenn Soll<Ist
// P-Glied:
$Kp = $E[8]['value']; // Proportionalbeiwert (Kp) = Steigung | alt: "Proportionalbereich"/"P-Bereich" als Xp (in %) mit Kp=100%/Xp | große Kp: starker Eingriff, kleine Kp: Schwingungsneigung erhöht
$yP = $Kp * $d; // Stellgröße aus P-Glied
if ($Kp==0) { $Kp = 1; } // in der Folgeverarbeitung keine Null erlauben
// I-Glied:
$Ti = $E[9]['value']; // Zeitkonstante (Ti) = Abtastzeit = Integrierzeit
$Ki = $Kp / $Ti; // Integrierbeiwert Ki = Kp / Ti
$esum = logic_getVar($id,3) + $d; // esum = esum + e
logic_setVar($id,3,$esum); // V3: neues esum
$yI = $Ki * $Ti * $esum; // Stellgröße aus I-Glied
// D-Glied:
$Td = $Ti; // Vorhaltezeit (Td) --> vereinfacht: gleich Ti
$Kd = $Kp * $Td; // Differenzierbeiwert (Kd)
$ealt = logic_getVar($id,4); // vorheriges e aus V4 holen
$yD = $Kd * ($d -$ealt) / $Td; // Stellgröße aus D-Glied
logic_setVar($id,4,$d); // V4: aktuelles e für nächsten Zyklus merken
// Gesamt-Stellgröße
if ($E[4]['value']==0) { $yP = 0; } // P-Anteil aktivieren/nullen
if ($E[5]['value']==0) { $yI = 0; } // I-Anteil aktivieren/nullen
if ($E[6]['value']==0) { $yD = 0; } // D-Anteil aktivieren/nullen
$y = $yP + $yI + $yD + $y0; // Stellgröße (y) = P-Anteil + I-Anteil + D-Anteil + Arbeitspunkt y0
if ($y>$E[10]['value']) { $y = $E[10]['value']; } // Stellgröße begrenzen: max
if ($y<$E[11]['value']) { $y = $E[11]['value']; } // Stellgröße begrenzen: min
logic_setOutput($id,1,$Soll); // A1: Soll durchreichen (z.B: für nachgelagerten Heiz-LBS)
logic_setOutput($id,2,$Ist); // A2: Ist durchreichen (z.B: für nachgelagerten Heiz-LBS)
logic_setOutput($id,3,$Zyk); // A3: Zyklen ausgeben (nur informativ)
logic_setOutput($id,4,$y); // A4: Stellgröße ausgeben --> Hier ist das Gold! :o)
if (logic_getVar($id,5)!=$y) {
logic_setOutput($id,5,$y); // A5: Stellgröße ausgeben (sendbychange)
}
logic_setOutput($id,6,$yP); // A6: P-Teil ausgeben (nur informativ)
logic_setOutput($id,7,$yI); // A7: I-Teil ausgeben (nur informativ)
logic_setOutput($id,8,$yD); // A8: D-Teil ausgeben (nur informativ)
logic_setVar($id,5,$y); // V5: y merken für send-by-change
}
}
} else {
logic_setState($id,0); //LBS "stoppen"
}
}
}
?>
###[/LBS]###
###[EXEC]###
<?
?>
###[/EXEC]###
Bitte prüfen und vielleicht kann der Code ja dann in den LBS eingepflegt werden... saegefisch
Kommentar