Hallo Joachim,
ich benutze zwar nicht Helmuts super-duper Kontroller, sondern „nur“ den seriellen Adapter mit Bascom Code (vielen Dank Helmut) aber das funktioniert auch wunderbar.
Ich experimentiere seit etwa 6 Wochen mit verschiedenen Reglertypen und Parametern und bin bisher zu folgendem Ergebniss gekommen:
-
Im Prinzip reicht der P-Regler. Er ist mit dem entsprechenden Kp schnell und präzise, hat aber eine kleine WAF Besonderheit: Bei Erreichen der Solltemperatur ist das Ventil zu und der Heizkörper wird kalt. Nun noch ein bischen Fremdwärme durch Sonne oder Fernseher/Beamer und er bleibt kalt. Und 21° mit kalter Heizung fühlen sich kälter an, als 21° mit warmer Heizung.
-
Den PID Regler habe ich sofort wieder verworfen, da der D-Anteil bei mir extrem viele und merkwürdige Ventilbewegungen verursacht hat - vielleicht waren aber auch nur mein Parameter murks.
-
Der gute Kompromiss ist für mich der PI-Regler. Ich stoppe das Integrieren aber nicht nur bei geschlossenem Ventil, sondern auch bei voll geöffnetem Ventil. Da ich viele Räume mit Fenstern nach Süden und Südwesten habe, begrenze ich esum auf einen Max und Min Wert, damit die Heizung bei Fremdwärme nicht allzu träge reagiert.
-
Ein normaler Thermostat hat eine Regelautonomie von 2K, d.h. 1K unter Solltemperatur ist er auf und 1K über Solltemperatur zu. Mit der Formel für den P-Regler ergibt das ein Kp von 50. Die besseren Thermostate liegen bei 1K, was einem Kp von 100 entspricht.
-
Meine Stellmotoren gehen bei y=0 in eine 5% Frostschutzstellung, daher ist mein kleinster Wert für y nicht 0 sondern 1.
-
Ich bin schon seit Jahren dabei, meinen Altbau Stück für Stück auf den energetisch neusten Stand zu bringen und habe einen bunten Mischmasch von Räumen mit guter und weniger guter Isolierung, alten und neuen Fenstern. Dementsprechend reagieren die Räume auch unterschiedlich, wenn überall die gleichen Reglerparameter verwendet werden. Ich habe deshalb mein Reglerscript so angepasst, dass es jeden Morgen mit offenen Ventilen ohne Regelung startet, die Verzugszeit und Ausgleichszeit beim Aufheizen bestimmt und daraus die Parameter Kp und Ki berechnet, dann umschaltet auf einen P-Regler mit festen Parametern, der die Ventile langsam zufährt und anschließend auf den PI-Regler schaltet, wenn der P-Regler die Ventile zu weit schließen würde. Das klingt vielleicht oversized, aber das direkte Umschalten von der Parameterbestimmung mit offenen Ventilen auf den PI-Regler hatte zur Folge, dass die Brennerregelung die Heizung erstmal abgeschaltet hat, wenn alle Ventile mehr oder weniger zeitgleich von 100% auf 20-30% runtergefahren wurden. Das spielt jetzt keine Rolle mehr, aber bei Temperaturen um und unter Null wirds dann wieder etwas kälter in der Wohnung.
$Status = GetValueString(56027 /*[Wetter\Heizung]*/);
$Parameterbestimmung = GetValueString(38608 /*[Wohnzimmer\Heizung\Parameterbestimmung]*/);
$Wochentag = date ("w");
$Uhrzeit = date("H:i");
$Zeitstring = GetValueString(39161 /*[Zeit\Datum/Zeit]*/);
$Solltemperatur = GetValueFloat(38985 /*[Wohnzimmer\Heizung\Solltemperatur]*/);
$Isttemperatur = GetvalueFloat(50695 /*[Wohnzimmer\S 2001-ID Wohnzimmer\Temperatur]*/);
$Starttemperatur = GetValueFloat(29142 /*[Wohnzimmer\Heizung\Starttemperatur]*/);
$Tu = GetValueFloat(13052 /*[Wohnzimmer\Heizung\Tu - Verzugszeit]*/);
$Tg = GetValueFloat(20705 /*[Wohnzimmer\Heizung\Tg - Ausgleichszeit]*/);
$Kp = GetValueFloat(18350 /*[Wohnzimmer\Heizung\Kp - Proportionalbeiwert]*/);
$Ki = GetValueFloat(43863 /*[Wohnzimmer\Heizung\Ki - Integralbeiwert]*/);
$esum = GetValueFloat(34279 /*[Wohnzimmer\Heizung\esum - Integralanteil]*/);
$ealt = GetValueFloat(22624 /*[Wohnzimmer\Heizung\ealt]*/);
$y = GetValueFloat(15174 /*[Wohnzimmer\Heizung\Ventilposition]*/);
$Zieltemperatur = GetValueFloat(14264 /*[Wohnzimmer\Heizung\Zieltemperatur]*/);
$Pp = 0;
$Py = 0;
$Regelungsart = GetValueString(37358 /*[Wohnzimmer\Heizung\Regelungsart]*/);
// wöchentliche Entkalkungsfahrt Stellmotor 1
If ($Wochentag == 6 AND $Uhrzeit == '06:00') { // Samstag Morgen 6:00
$str=chr(5).chr(255).chr(13); // Befehl(Entkalkungsfahrt Motor 1).Daten(nach Fahrt voll öffnen).chr(13) ist CR als Abschluß der Sequence
COMPort_SendText (38228 /*[Serial Port]*/ ,$str);
SetValueString(15479 /*[Wohnzimmer\Heizung\Letzte Entkalkungsfahrt]*/, $Zeitstring);
};
// Berechnung Parameter des Tages
If (($Wochentag >= 1 AND $Wochentag <= 5) AND // Montag und Freitag
$Status == 'Heizbetrieb' AND
$Uhrzeit == '05:40') { // Start Heizbetrieb
SetValueString(38608 /*[Wohnzimmer\Heizung\Parameterbestimmung]*/, 'aktiv'); // Parameterbestimmung aktivieren, Regelung ausschalten
SetValueFloat(29142 /*[Wohnzimmer\Heizung\Starttemperatur]*/, $Isttemperatur); // Startwert für Parameter setzen
$str=chr(1).chr(255).chr(13); //Befehl(Motor 1).voll öffnen.chr(13) ist CR als Abschluß der Sequence
COMPort_SendText (38228 /*[Serial Port]*/ , $str);
SetValueFloat(13052 /*[Wohnzimmer\Heizung\Tu - Verzugszeit]*/, 0); // alle nötigen Parameter erstmal auf Null
SetValueFloat(20705 /*[Wohnzimmer\Heizung\Tg - Ausgleichszeit]*/, 0);
SetValueFloat(34279 /*[Wohnzimmer\Heizung\esum - Integralanteil]*/, 0);
SetValueFloat(22624 /*[Wohnzimmer\Heizung\ealt]*/, 0);
SetValueFloat(14264 /*[Wohnzimmer\Heizung\Zieltemperatur]*/, 0);
SetValueString(37358 /*[Wohnzimmer\Heizung\Regelungsart]*/, 'Aufheizen');
return;
};
If (($Wochentag < 1 OR $Wochentag > 5) AND // Sonntag und Samstag
$Status == 'Heizbetrieb' AND
$Uhrzeit == '06:30') { // Start Heizbetrieb
SetValueString(38608 /*[Wohnzimmer\Heizung\Parameterbestimmung]*/, 'aktiv'); // Parameterbestimmung aktivieren, Regelung ausschalten
SetValueFloat(29142 /*[Wohnzimmer\Heizung\Starttemperatur]*/, $Isttemperatur); // Startwert für Parameter setzen
$str=chr(1).chr(255).chr(13); //Befehl(Motor 1).voll öffnen.chr(13) ist CR als Abschluß der Sequence
COMPort_SendText (38228 /*[Serial Port]*/ , $str);
SetValueFloat(13052 /*[Wohnzimmer\Heizung\Tu - Verzugszeit]*/, 0); // alle nötigen Parameter erstmal auf Null
SetValueFloat(20705 /*[Wohnzimmer\Heizung\Tg - Ausgleichszeit]*/, 0);
SetValueFloat(34279 /*[Wohnzimmer\Heizung\esum - Integralanteil]*/, 0);
SetValueFloat(22624 /*[Wohnzimmer\Heizung\ealt]*/, 0);
SetValueFloat(14264 /*[Wohnzimmer\Heizung\Zieltemperatur]*/, 0);
SetValueString(37358 /*[Wohnzimmer\Heizung\Regelungsart]*/, 'Aufheizen');
return;
};
If ($Status == 'Heizbetrieb' AND
($Isttemperatur - $Starttemperatur) >= 0.1 AND // Bedingung Verzugszeit
$Tu == 0 AND
$Parameterbestimmung == 'aktiv') {
$updatezeit = IPS_GetVariable(38608 /*[Wohnzimmer\Heizung\Parameterbestimmung]*/);
$updatezeit = $updatezeit['VariableUpdated']; // holen der Startzeit Heizbetrieb
$Tu = round((time() - $updatezeit) / 60); // Berechnung Verzugszeit
SetValueFloat(13052 /*[Wohnzimmer\Heizung\Tu - Verzugszeit]*/, $Tu);
};
If ($Status == 'Heizbetrieb' AND
$Tg == 0 AND
$Parameterbestimmung == 'aktiv' AND
$Zieltemperatur == 0) {
$Zieltemperatur = $Starttemperatur + (0.63 * ($Solltemperatur-$Starttemperatur));// Berechnung Zieltemperatur für Ausgleichszeit
If ($Zieltemperatur >= $Solltemperatur ) {$Zieltemperatur = $Solltemperatur;}; // größer als Solltemperatur geht nicht
SetValueFloat(14264 /*[Wohnzimmer\Heizung\Zieltemperatur]*/, $Zieltemperatur);
};
If ($Status == 'Heizbetrieb' AND
$Isttemperatur >= $Zieltemperatur AND // Bedingung Ausgleichszeit
$Tg == 0 AND
$Parameterbestimmung == 'aktiv') {
$updatezeit = IPS_GetVariable(13052 /*[Wohnzimmer\Heizung\Tu - Verzugszeit]*/);
$updatezeit = $updatezeit['VariableUpdated']; // Beginn Ausgleichzeit ist Ende Verzugszeit
$Tg = round((time() - $updatezeit) / 60); // Berechnung Ausgleichszeit
SetValueFloat(20705 /*[Wohnzimmer\Heizung\Tg - Ausgleichszeit]*/, $Tg);
$Kp = 0.35 * 100/($Solltemperatur - $Starttemperatur)* $Tg / $Tu; // Berechnung Proportionalbeiwert
If ($Kp <= 50 ) {$Kp = 50;}; // Minimum für Kp
SetValueFloat(18350 /*[Wohnzimmer\Heizung\Kp - Proportionalbeiwert]*/, $Kp); // nach Chien/Hrones/Reswick ohne Überschwingen
$Ki = $Kp / (1.2 * $Tg); // Berechnung Integralbeiwert
If ($Ki >= 3 ) {$Ki = 3;}; // Maximum für Ki
SetValueFloat(43863 /*[Wohnzimmer\Heizung\Ki - Integralbeiwert]*/, $Ki);
SetValueString(38608 /*[Wohnzimmer\Heizung\Parameterbestimmung]*/, 'fertig'); // Abschluß Parameterbestimmung, Aktivierung der Regelung
SetValueString(37358 /*[Wohnzimmer\Heizung\Regelungsart]*/, 'Übergang - P-Regler');
};
// Regelung
If ($Parameterbestimmung == 'fertig' AND $Status == 'Heizbetrieb') {
$e = $Solltemperatur - $Isttemperatur; // Regelabweichung
SetValueFloat(31526 /*[Wohnzimmer\Heizung\e - Regelabweichung]*/, $e);
If ( $y > 1 AND $y < 100 ) { // Anti Wind Up Hold
$esum = $esum + $e; // Integration I-Anteil
If ($esum <= -35 ) {$esum = -35;}; // Untere Begrenzung I-Anteil
If ($esum >= 35 ) {$esum = 35;}; // Obere Begrenzung I-Anteil
SetValueFloat(34279 /*[Wohnzimmer\Heizung\esum - Integralanteil]*/, $esum);
};
$p = $Kp * $e; // Proportionalanteil PI-Regler
SetValueFloat(54772 /*[Wohnzimmer\Heizung\p - Proportionalanteil]*/, $p);
$Pp = 100 * $e; // Proportionalanteil P-Regler mit Kp=100 für Übergang
$i = $Ki * 2 * $esum; // Integralanteil PI-Regler
SetValueFloat(30501 /*[Wohnzimmer\Heizung\i - Integralanteil]*/, $i);
$y = $p + $i; // Stellgröße in % PI-Regler
$Py = $Pp; // Stellgröße P-Regler Übergang
SetValueFloat(36158 /*[Wohnzimmer\Heizung\Stellgröße]*/, $y);
SetValueFloat(22624 /*[Wohnzimmer\Heizung\ealt]*/, $e);
If ($Py > $y AND $Regelungsart == 'Übergang - P-Regler') {$y = $Py;} // P-Regler macht langsamer 'zu', Heizung arbeitet kontinuierlicher
elseif ($Py <= $y AND $Regelungsart == 'Übergang - P-Regler') {SetValueString(37358 /*[Wohnzimmer\Heizung\Regelungsart]*/, 'PI-Regler');}; // bei gleicher Stellgröße Umschalten auf PI-Regler
If ($y <= 0 ) {$y = 1;}; // untere Begrenzung Stellgröße - y=0 heißt Frostschutz 5%
If ($y > 100 ) {$y = 100;}; // obere Begrenzung Stellgröße
SetValueFloat(15174 /*[Wohnzimmer\Heizung\Ventilposition]*/, $y);
$Ventilposition = (round($y * 2.55)); // Prozentwerte in 0-255 umrechnen
$str=chr(1).chr($Ventilposition).chr(13); // Befehl(Motor 1).Daten.chr(13) ist CR als Abschluß der Sequence
COMPort_SendText (38228 /*[Serial Port]*/ , $str);
};
// Anregungen/Todo:
// - Meßwerte über mehrere Intervalle mitteln
// - dynamic anti wind up probieren
// PI-Regler reicht
// D-Anteil des PID-Reglers führt zu viel zu großen und unnützen Ventilbewegungen bei Temperaturänderung
Man kann das bestimmt auch eleganter programmieren, aber ich bin leider nicht der PHP-Profi.
Ach so, der FHT8i ist gerade für 10€ im Angebot.
Viele Grüße
Stephan