Ankündigung

Einklappen
Keine Ankündigung bisher.

LBS 19000113 - PID-Regler (generisch)

Einklappen
X
 
  • Filter
  • Zeit
  • Anzeigen
Alles löschen
neue Beiträge

    LBS 19000113 - PID-Regler (generisch)

    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:

    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
    Zuletzt geändert von JonDonSponky; 20.07.2017, 06:48.
    Grüße Tobi


    #2
    Hi
    ich hatte das problem auch - und hab es "elegant" umgangen: für´s kühlen rechne ich die Temperaturen *-1 - somit wird aus Soll 25 grad und ist 30 Grad ein
    soll -25 und ist -30 grad... und der regler regelt schön von -30 "hoch" auf -25.
    Funktioniert bei der derzeitigen Hitzewelle ganz gut :-)

    Gruß
    Thorsten

    Kommentar


      #3
      Guten Abend miteinander!

      Nach einem Sommer, wo ich noch meinem alten HomeServer vertraute, hab ich mich nun wieder an den Regler ran gemacht um ihm auch das "Kühlen" zu lehren

      Herausgekommen ist folgender Code, der sich bei meinen aktuellen Simulationen als funktionstüchtig erwiesen hat:
      PHP-Code:
      ###[DEF]###
      [name        =    PID-Regler ]

      [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.3 ]              // Version
      [v#101 = 19000113 ]            // LBS
      [v#102 = PID-Regler ]        // eigens Log-File oder leer für TraceLog                 // in diesem LBS zZ kein Logging
      [v#103 = 5 ]                // LogLevel (dieser LBS: -): 0-none,1-emerg,2-alert,3-crit,4-err,5-warning,6-notice,7-info,8-debug
      [v#104 = 0 ]                   // One log file per LBS instance                        // in diesem LBS zZ kein Logging
      [v#105 = 1 ]                   // log ID in each log entry                                // 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

      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 <i>positiver</i> bzw. <i>negativer</i> 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) an den Sollwert annähern soll.
      <hr>
      <b><u>Eingänge</u></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: Annäherung an den Sollwert von "unten" (positive Annäherung z.B. Heizen) bzw. "oben" (negative Annäherung z.B. Kühlen)

      <b><u>Ausgänge</u></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><u>Changelog</u></b>
      V0.1: initiale Version
      V0.2: Vorbereitung für CustomLog (Update technisch NICHT erforderlich!)
      V0.3: Einbau von #E13 für eine positive bzw. negative Annäherung an den Sollwert (Heizen/Kühlen)
      ###[/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

                          // Regeldifferenz
                          if ($E[13]['value']==1) {$d = $Ist-$Soll; }                // Regeldifferenz (e) wenn Soll<Ist
                          else {$d = $Soll-$Ist; }                                // 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"

              }

          }

      }

      function LB_LBSID_writelog($id, $priority = 8, $msg, $var = NULL )
      {
          $logLevel = getLogicElementVar($id, 103);
          if (is_int($priority) && $priority <= $logLevel && $priority > 0) {
              $logLevelNames = array('0-none','1-emerg','2-alert','3-crit','4-err','5-warning','6-notice','7-info','8-debug');
              $logLevelTxt = str_pad($logLevelNames[$priority], 7) . "|" . $logLevel;
              $version = getLogicElementVar($id, 100);
              $lbsNo = getLogicElementVar($id, 101);
              $logName = getLogicElementVar($id, 102);
              $logName = preg_replace('/ /', '_', $logName);
              if (logic_getVar($id, 104) == 1) $logName .= "-$id";    // jede Instanz eigenes Log
              strpos($_SERVER['SCRIPT_NAME'], $lbsNo) ? $scriptname = 'EXE' . $lbsNo : $scriptname = 'LBS' . $lbsNo;
              if ($logLevel > 7) $scriptname .= " [v$version]";        // Versionsnummer nur bei hohen LogLevel
              if ($msg != '') {
                  if (logic_getVar($id, 105) == 1) $msg .= " ($id)";        // Nachricht mit Instanz
                  writeToCustomLog($logName, $logLevelTxt, $scriptname . ":\t" . $msg);
              }
              if (isset($var)) {
                  if (logic_getVar($id, 105) == 1) $pre = "ARRAY/OBJECT($id):"; else $pre = '';        // Nachricht mit Instanz
                  writeToCustomLog($logName, $logLevelTxt, $scriptname . ":\t" . $pre . json_encode($var));
              }
          }
      }

      ?>
      ###[/LBS]###


      ###[EXEC]###
      <?
      ?>
      ###[/EXEC]###

      Bitte gerne gegen testen!
      Zuletzt geändert von JonDonSponky; 30.11.2017, 09:31.
      Grüße Tobi

      Kommentar


        #4
        Hallo Tobi,
        ich hab den Baustein genau wie Thorsten zur Kühlung in Verwendung. Allerdings hab ich den Reset bei Änderung des Sollwerts entfernt. Für mich macht das keinen Sinn da von vorne zu starten.
        Du hast doch den P und D Anteil, um auf eine Sollwertänderung im Rahmen der Regelung passend zu reagieren.
        VG, Christoph

        Kommentar


          #5
          Hi Christoph

          vielleicht hab ich mir falsch ausgedrückt. Ich möchte mit dem gleichen Baustein Heizen und Kühlen!

          Hintergrund ist der, dass meine Wärmepumpe eben eine Heiz- und Kühlfunktion hat und ich somit im Winter heizen und im Sommer kühlen will. Dazu benötige ich eben im Baustein ein KO, dass die Richtung der Annäherung an den Sollwert ändert. Klar kann ich das auch über Wenn-Dann-, Gatter-, Mathe-Logiken auch realisieren, aber das macht doch die Logikseite unnötig komplex.

          Aktuell sieht meine Test-Logikseite für einen Heizkreis so aus:
          Unbenannt.JPG

          Wenn ich alle meine Heizkreise in der Art realisiere, bleibt das meiner Meinung nach sehr übersichtlich und ich verstehe auch in ein paar Jahren noch wie die Logik abläuft.

          Das einzige Problem was ich gerade noch am lösen bin, ist der Wind-UP-Effekt, aber den versuche ich in den kommenden Tagen in den Baustein noch rein zu packen.

          Grüße zurück, Tobi
          Grüße Tobi

          Kommentar


            #6
            HI Christoph, hi Tobi, hi Thorsten

            ich bin dankbar für Eure Weiterenteicklung. Über die Weihnachtszeit werde ich sicher die Zeit finden, Eure Erkenntnisse in den PID einfließen zu lassen und eine neu e "offizielle" Version zu machen.

            * Kühl-Option. Damals bei der Entwicklung nahm ich Thorstens Sicht selber als hinreichend an - aber mittlerweile scheint mir eine andere Lösung tatsächlich auch sinnvoller.
            * Reset bei neuem Sollwert per EIngangsschalter wählbar

            Viele Grüße,
            Carsten

            Kommentar


              #7
              ach sorry, hab gar nicht gemerkt, dass der TE gar nicht der LBS-Ersteller ist
              dann warte ich mal auf das Update des LBS, Anti-wind-up klingt gut.

              ach ja, eine Kleinigkeit fällt mir gerade noch ein: wenn ein neuer Ist- oder Sollwert am Eingang eintrifft dauert es immer eine Weile, bis der am Ausgang wieder raus kommt, obwohl er eigentlich direkt durchgereicht werden sollte (lt. Beschreibung). Vielleicht könnte man den direkt durchreichen. Wie genau das funktioniert hab ich mir nicht angesehen (kann kein php) und eigentlich störts mich auch nicht
              VG
              Zuletzt geändert von Sonnengruesser; 01.12.2017, 15:27.

              Kommentar


                #8
                Servus zusammen!

                Hab nun auch den Wind-Up-Effekt in den Griff bekommen.

                saegefisch: Wenn du meine aktuellen Baustein haben willst (oder auch gerne weitere Tester), ich habe ihn mal im in den Download-Bereich gestellt: LBS 19001341

                Ich deaktivieren ihn natürlich wieder, sobald Carsten seinen aktualisiert hat.

                Schönen Abend noch!
                Zuletzt geändert von JonDonSponky; 04.12.2017, 19:16.
                Grüße Tobi

                Kommentar


                  #9
                  Hab mir den "Test-LBS" mal gezogen. Und gleich die erste Frage: beim zusätzlichen Eingang "Kühlen/Heizen", was ist 0 und was 1?
                  Edit: OK, rausgefunden: 0=Heizen, 1=Kühlen, alles andere ist undefiniert
                  Zuletzt geändert von Sonnengruesser; 05.12.2017, 19:08.

                  Kommentar


                    #10
                    Zitat von Sonnengruesser Beitrag anzeigen
                    ...was ist 0 und was 1?
                    Guter Verbesserungsvorschlag! Bau ich gleich in die Hilfe mit ein.

                    Hab noch ein Problem festgestellt und zwar wenn man Edomi neu startet, "überschlägt" sich der Baustein erst mal, wenn er den ersten IST-Wert vom KNX-Bus bekommt. Ich vermute er errechnet dann die "Regelabweichung" von 0 zu aktuellem IST-Wert und kommt somit auf eine riesige Spreizung --> große Reglerstellung...

                    Wenn man den Baustein einmal kurz OFF setzt und wieder startet, funktioniert alles wieder schön brav.

                    Muss mal schauen, wie ich das noch behoben bekomme (für Lösungsvorschläge bin ich gerne offen!).
                    Grüße Tobi

                    Kommentar


                      #11
                      Berechnung erst starten, wenn beide Werte vorhanden sind...

                      Kommentar


                        #12
                        Habe wieder einen neue Version hochgeladen. Habe jetzt das Problem mit dem "Edomi-Neustart" gelöst.

                        Des weiteren habe ich noch "Faktoren" für die Glieder integriert, sodass man seinen Regler noch ein wenig mehr individualisieren kann. Spricht statt nur den P-, I- und D-Teil an/aus zu schalten, kann man ihm auch noch eine Wertigkeit geben.
                        Grüße Tobi

                        Kommentar


                          #13
                          Und erneut aktualisiert auf V0.6, da mir beim Testen aufgefallen ist, dass durch das Nullstellen des I-Anteil Fehlermeldungen entstehen...

                          Aber mal eine ganz andere Frage und zwar welche LBS die Edomi-User hier benutzen um ihre Heizungen zu steuern (also Fußbodenheizung bzw. Radiatoren, etc.). Irgendwie kommt es mir so vor, als würden nur wir vier (Carsten, Thorsten, Christoph und meinereiner) den Baustein nutzen...

                          Und wenn ihn noch jemand nutzt, mich würden seine Einstellungen speziell bei einer Fußbodenheizung interessieren.
                          Zuletzt geändert von JonDonSponky; 08.12.2017, 20:55.
                          Grüße Tobi

                          Kommentar


                            #14
                            Wieso benutzt ihr nicht die Regler von den Aktoren? Den aktor kann man sich damit doch nicht sparen?

                            Kommentar


                              #15
                              meine Aktoren bringen keine Logik mit...aber klart, die meisten AKtoren haben Logik.

                              Grundsätzlich kann man mit dem generischen PID-Regler aber allerleri Regeln. Ist halt generisch...darum habe ich ihn auch vom Rest getrennt konzipiert.

                              Kommentar

                              Lädt...
                              X