PID Regler optimieren/einstellen PID_v1.h / Solar Eigenverbrauch

Hallo allerseits,
Ich möchte Mal in die Runde fragen, ob jemand einen Einfall zum optimalen einstellen des PID Regler im folgendem Fall hat:
Ich habe zum solaren Eigenverbrauch eine 6 kW Heizpatrone eingebunden, die über ein Energie Messgerät ab ca -400W Überschuss angesteuert wird.
Das Messgerät (Siemens Sentron) liefert die Daten über MOD Bus an den Arduino. Ich nutze die PID_v1.h Funktionen.
Das Ganze läuft Recht gut, aber halt nicht sehr optimal, was das Regelverhalten an geht.
anbei die relevanten Sketch Auszüge...
Nun ist es so, dass es mir noch nicht gelungen ist , ein zügiges ohne Überschwingen, ruhiges Regelverhalten hin zu bekommen. ( habe durch diverse Workarounds, die Effekte minimiert)
Die momentan im Sketch eingestellten Werte, schwingen zwar nicht, sind mir allerdings auch zu reaktionsträge.
Situationen wie das aufziehen einer Wolke oder das zuschalten eines Verbrauchers, ändern schnell mal den PV Überschuß von zB 5 kW auf 1,5 kW und umgekehrt ,dann sollte möglichst schnell die Ansteuerung des Heizstabs zurück gefahren oder wieder zu geschalten werden. Im moment benötigt das Nachführen der Regelung weinige Minuten. Wenn es schneller gehen soll fängt es an über zu schwingen und es kommt zum Netzbezug, was natürlich unbedingt vermieden werden soll.

In dem Zusammenhang gleich noch die Frage nach der PID Autotune Funktion. Weiß jemand wie man die verwendet.
Ich stellte mir das so vor, dass ich die Funktion einbinden , einige Zeit laufen lasse und mir dann die optimalen PID Werte ausgegeben werden. Kann man das so verwenden? Wenn ja, wie?
Wer weiß dazu was.
Ich bin gespannt auf Ideen aus der Community...

#include "U8glib.h"                                               //alles fürs Display
U8GLIB_SSD1306_128X64 u8g(U8G_I2C_OPT_NONE | U8G_I2C_OPT_DEV_0);  // I2C / TWI
//U8GLIB_SH1106_128X64 u8g(U8G_I2C_OPT_NO_ACK);	// Display which does not send ACK

#define WIZNET_W5100 1  // Ethernetshild bezeichnung

unsigned int param_value_int[7];
#include <Ethernet.h>
#include <PID_v1.h>
#include "ModbusTCP.h"
#include <avr/wdt.h>

//----------------------------------------------------------------------------
//#include <SPI.h>  // Not needed if device is I2C
#include <Wire.h>
// Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)

//------------------------------------------Thermometer------------------------------------------------------------------------------------------------------------------------------------------
#include <OneWire.h>
#include <DallasTemperature.h>
#define ONE_WIRE_BUS 11
#define TEMPERATURE_PRECISION 11
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);

//DeviceAddress Anlegefuehler;
DeviceAddress Anlegefuehler = { 0x28, 0x4f, 0xea, 0xf6, 0x04, 0x00, 0x00, 0xce };  //284FEAF6040000CE 284FEAF6040000CE
float Anlegefuehler_temp, Anlegefuehler_temp_old = 0;
int Notabkuehlung = 0;  // Wert wird mit 20C geladen wenn notaus durch überhitzung

//--------------Prototyp--------------------------------------------------------------------------------------------------------------------------------------------------------------
void Mbus();
void Display_();
void Leistungsstrg_PV();
void Ein_Ausgaenge();
void Temperatur();
void Pumpensteuerung();
void Timer(void);

//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

IPAddress ModbusDeviceIP(192, 168, 178, 12);    // Put IP Address of PLC here or slave , adresse von Modbus_modul
IPAddress moduleIPAddress(192, 168, 178, 11);  // (11)Assign Anything other than the PLC IP Address, adresse von Ethernetshild arduino
//IPAddress ModbusDeviceIP(192, 168, 178, 38);  // Put IP Address of PLC here or slave , adresse von Modbus_modul Wechselrichter MODBUS Addr1

byte mac[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };  // This is a generic MAC. In case your device has an specific MAC, please, use it;  ggf. mac adresse eingeben
                                                      // The IP address for the shield
byte netmask[] = {
  255, 255, 255, 0
};
byte gateway[] = {
  192, 168, 178, 1
};
byte dns[] = {
  192, 168, 178, 1
};



ModbusTCP node(1);  // Unit Identifier.

unsigned int data1;
unsigned int data2;

float Watt;

double Watt_eigenv_Ausgabe;

unsigned long dataNew;

int counter = 0;  // Seconds counter
unsigned long int currentTime, nextTime;

#define test_ausdruck 1  // zum aus ein schalten für testausdruck
#define REVERSE 1
#define DIRECT 0
#define P_ON_M 0
#define P_ON_E 1
double sollwert = -400;
//Define Variables we'll be connecting to
double Setpoint, Input, Output, Output_old;
//Define the aggressive and conservative Tuning Parameters
double aggKp = 0.5, aggKi = 0.08, aggKd = 0.001;      //letzte einstellungen: aggKp=0,5, aggKi=0.07, aggKd=0.001;
double consKp = 0.1, consKi = 0.03, consKd = 0.0001;  // werte ggf. 0.01;0.0005;0.0002 noch testen ??!
double downKp = 3.5, downKi = 0.05, downKd = 0.005;   // werte zum schnellen zurückfahren des Verbrauchers wenn Watt pos wird
//Specify the links and initial tuning parameters
PID myPID(&Input, &Output, &Setpoint, consKp, consKi, consKd, REVERSE);
double kW_Output_Heizung;
double Pump_Leist;
unsigned long WindowSize = 255;
const int HeizAnforderungEing = 7;                                 // Eing. 7 zur Heizung
const int Hauptschuetz = 5;                                        // Schaltet Leistung L1,2,3 auf Regler
const int Pumpe = 6;                                               //  für zusätzliche Zirkulationspumpe wird überanalog PIN & PWM angesteuert
double warten_Schuetz, warten_Temp, Abkuehlzeit, warten_Sollwert;  // für Zeiten
double Pumpenleistung = 130;                                       // für Analaogwert PWM
bool HeizAnforderung;
int display = 0;
int Watt_int;
int kW_Output_Heizung_int;
int Pump_Leist_int;
//bool Flag_Pumpe;   // Merker für diverse..........




void setup() {
  wdt_disable();  // WD vorsichtshalber ausschalten um zugriff aufrecht zu erhalten

  Serial.begin(9600);  // Monitorübertragung funktioniert nicht mehr bei höherer Baud Rate ---bei dearf nochmal austesten
  delay(1000);

  //------------------------------Ein/Ausgänge---------------------------------------------------------
  pinMode(HeizAnforderungEing, INPUT);  // Wenn Heizung Wärme benötigt und drei Wege auf "Nachheizung" steht; Puldown an Klemme
  pinMode(Hauptschuetz, OUTPUT);
  pinMode(Pumpe, OUTPUT);
  TCCR3B = TCCR3B & 0b11111000 | 0x02;  // PIN 3 PWM 3,9 kHz                 Takte für Analogausgänge geändert
  TCCR4B = TCCR4B & 0b11111000 | 0x05;  // PIN 6 auf 30 Hz zur PWM für Pumpe
  /*//TCCR4B = TCCR4B & B11111000 | 0x01;    // set timer 4 divisor to     1 for PWM frequency of 31372.55 Hz
//TCCR4B = TCCR4B & B11111000 | 0x02;    // set timer 4 divisor to     8 for PWM frequency of  3921.16 Hz
  TCCR4B = TCCR4B & B11111000 | 0x03;    // set timer 4 divisor to    64 for PWM frequency of   490.20 Hz
//TCCR4B = TCCR4B & B11111000 | 0x04;    // set timer 4 divisor to   256 for PWM frequency of   122.55 Hz
//TCCR4B = TCCR4B & B11111000 | 0x05;    // set timer 4 divisor to  1024 for PWM frequency of    30.64 Hz*/
  //-------------------------------Temperatursensor---------------------------------------------------------------------------------------------------------------------
  sensors.begin();

  Serial.print("Locating Temperatu_devices...");
  Serial.print("Found -->");
  Serial.print(sensors.getDeviceCount(), DEC);
  Serial.println(" devices.");
  if (!sensors.getAddress(Anlegefuehler, 0)) Serial.println("Unable to find address for Device -- Anlegefühler");

  sensors.setResolution(Anlegefuehler, TEMPERATURE_PRECISION);

  //------------------PID setup------------------------------------------------------------------------------------------------------------------------------
  //initialize the variables we're linked to

  myPID.SetSampleTime(50);
  ;  // 50 ms  hat sich im Test bewährt
  myPID.SetOutputLimits(0, WindowSize);
  //turn the PID on
  myPID.SetMode(AUTOMATIC);
  //-----------------------------------------------------------------------------------------------------------------------------------------------------------


  pinMode(4, OUTPUT);
  digitalWrite(4, HIGH);  // To disable slave select for SD card; depricated.

  warten_Schuetz = millis();  // Zeit erstmalig laden
  warten_Sollwert = (millis());

  //Ethernet.begin(mac, moduleIPAddress);       // Starts the Ethernet card
  Ethernet.begin(mac, moduleIPAddress, dns, gateway, netmask);
  node.setServerIPAddress(ModbusDeviceIP);
  delay(1000);  // To provide sufficient time to initialize.
  //----------------------------------------------------------------------------------------------------------------------------------

  HeizAnforderung = digitalRead(HeizAnforderungEing);


  //----------Versionsanzeige-----------------------------
  Serial.print("Vers_Eigenverbr_300823 ");
  Serial.println("");

  delay(5000);


  wdt_enable(WDTO_8S); /* läd WD mit der Zeit 8s...weitere Zeiten   16 ms 	WDTO_15MS
32 ms 	WDTO_30MS
64 ms 	WDTO_60MS
0,125 s 	WDTO_120MS
0,25 s 	WDTO_250MS
0,5 s 	WDTO_500MS
1,0s 	WDTO_1S
2,0 s 	WDTO_2S
4,0 s 	WDTO_4S
8,0 s 	WDTO_8S*/
}

//----setup Ende-------------------------------------------------------------------------------------------------------------------------------------------------




//----------------------------------------------------------------------------------------------------------------------------------------------------------
void loop() {



  Mbus();  //
  Ein_Ausgaenge();
  Temperatur();

  if (millis() - warten_Sollwert >= 60000) {

    Leistungsstrg_PV();
  }

  if (Watt > 100) {
    warten_Sollwert = (millis());  // zu Timer neu stellen wenn Wert mal Positiv zB. 100 Watt war
    myPID.SetMode(0);              // PID einmal aus / ein schalten zur neu initialisierung
    myPID.SetMode(AUTOMATIC);
  }
  Pumpensteuerung();






#if test_ausdruck

  //Test_Prog();
  Serial.print("Test_Prog-->");
  Serial.println(Watt);

#endif

  node.clearResponseBuffer();
  //-------------------------------------------------- Display-------------

  u8g.firstPage();
  do {
    Display_();
  } while (u8g.nextPage());
  
  //---------------------------------------------------

  wdt_reset();  // Watchdog zurück setzen damit er nicht auslöst
}



#if test_ausdruck

Serial.print("Messung_Watt ");
Serial.println(Watt);
Serial.print(",");
#endif

Setpoint = sollwert;

#if test_ausdruck

Serial.print("Setpoint ");
Serial.println(Setpoint);
Serial.print(",");
#endif

double gap = abs(Watt - Setpoint); //Abweichung vom Einstellwert zB -400 W

#if test_ausdruck

Serial.print("gap--> ");
Serial.println(gap);
Serial.print(",");
#endif

if (gap < 200)

{ //we're close to setpoint, use conservative tuning parameters
myPID.SetTunings(consKp, consKi, consKd);
} else {
//we're far from setpoint, use aggressive tuning parameters
myPID.SetTunings(aggKp, aggKi, aggKd, P_ON_E); // P_ON_M soll das Überschwingen verhindern----testen; weitere Test mit P_ON_E...
}

if (Watt > 0) {

myPID.SetMode(0);  // PID einmal aus / ein schalten zur neu initialisierung
myPID.SetMode(AUTOMATIC);
myPID.SetTunings(downKp, downKi, downKd);

}

/*#if test_ausdruck

Serial.print("PID_Input ");
Serial.println(Input);
Serial.print(",");
#endif */

Setpoint = map((Setpoint), 0, -6000, 0, 255); // scaliert 0-6000 watt auf 0-255 digits und //damit im PID Regler POS Werte verarbeitet werden
Input = map((Watt), 0, -6000, 0, 255);

myPID.Compute();

Watt_eigenv_Ausgabe = Output; //
//
kW_Output_Heizung = map(Output, 0, 255, 0, 6000); // scaliert 0-255 watt auf 0-6000 für die Anzeige;

/*#if test_ausdruck

Serial.print("PID_Output ");
Serial.println(Output);
Serial.print(",");
#endif */
#if test_ausdruck
Serial.print("kW_Output_Heizung 0-6000 ");
Serial.println(kW_Output_Heizung);
Serial.print(",");
#endif

/#if test_ausdruck
Serial.print("Watt_eigenv_Ausgabe 0-255 ");
Serial.println(Watt_eigenv_Ausgabe);
Serial.print(",");
#endif
/

analogWrite(3, Watt_eigenv_Ausgabe); // hier wird der Ausgangswert zur Ansteuerung 0-10 V geschrieben
}

Hallo,
du solltest den Code in codetags stellen
zu Deinem Problemchen.
ich muss da noch mal nachfragen
die Wassertemperatur wird nicht damit geregelt , es geht lediglich darum die Überschüssige Solarenergie an den Heizstab zu bringen. ?

ich würde das ganz ohne Regler machen , das ist doch ein Stellbetrieb.

erkläre mal ein bisschen wie der Regelkreis aufgebaut ist. Was ist der Sollwert , was der Istwert.

Hallo Rentner,

was das Hochladen des Codes betrifft, kenne ich mich bei dem Handling hier im Forum nicht so aus...
Benutze so ein Forum zum ersten Mal.

Zum Programm:

der Solarüberschuss wird gemessen und alles was mehr als 400 W ist, geht über ein Leistungssteller der mit 0-10V angesteuert wird in einen Heizstab. 0 V = 0W bis 10V = 6000W.
Die 0-10V werden über die PWM aus dem Arduino durch eine Zusatzschaltung PWM zu 0-10V erzeugt. Die Regelung führt also immer die zu verbrauchende Leistung nach. Deshalb PID...
Die Temperaturmessung die man sehen kann dient nur zur Sicherheitsüberwachung und zur Drehzahlsteuerung der Pumpe.
Weil die Heizpatrone nicht dierekt im Speicher eingebaut werden konnte, ist sie in einem seperaten Gefäß ( etwas dickeres Rohr) neben dem Speicher platziert. Das erwärmte Wasser wird dann in den Speicher gefördert. Weil bei der Leistung das Wasser rasch heiß wird, hier die Überwachungen und zusätzlich begrenzug durch Thermosicherung mit Hautschütz. ( falls ich doch mal ein Bug drin habe, gibts wenigstens keine Dampfschläge).
Wie gesagt, die Regelung funktioniert schon recht gut, jetzt ca. 3 Monate, allerdings mit einer Trägheit von Minuten.
Ideal wären wenige Sekunden in der Nachführung ohne Schwingen.
Ich habe unzählige PI (D) Werte / Kombinationen schon durchprobiert. Auch mit der Samplingzeit hab ich rum gespielt. Letztendlich sind es ungefähr immer wieder die Werte die im Setup zu sehen sind. Ich habe auch die Erfahrung gemacht, dass wenn man die PID Funktionen im Schwingungsfall mal aus schaltet ( deaktiviert) und wieder ein schaltet wie beim Setup, dass dann eine Beruhigung ein tritt.
Das sind aber alles Workarounds die nich notwendikg sein dürften.

Hallo,

von Arbeit her weiß ich das es nicht den einen Parametersatz PID gibt der alles abdeckt. Bei uns wird bspw. ein Druck geregelt mit verschiedenen Zielwerten und mit verschiedenen Gasflußmengen. Im Grunde gibt es für fast jeden Druck Zielwert einen PID Parametersatz. Und sogar noch jeweils einen weiteren womit zwischen wenig Gasfluss und viel Gasfluss unterschieden wird. Die Anlagensoftware wählt dann den passenden aus. Wenn sich der Zieldruck ändert reagiert die "Drosselklappe" zügig um in der Nähe vom Zielwert dank optimierter PID wieder sanft einzuregeln und ein Überschwingen zu vermeiden. Überschwingen kann man im Grunde nie vermeiden wenn die Regelung bzw. Annäherung nicht unendlich dauern soll aber man kann sie abschwächen bis zur Perfektion.

Auf Dein Problem übertragen würde ich für verschiedene Leistungswerte verschiedene PIDs erstellen.

Vielleicht kannst du dir auch einen kleinen Simulator schreiben und guckst dir das auf dem analogen Monitor an. Bevor du jedesmal deine Heizung bzw. PV quälst.

Zur PID Lib kann ich nichts sagen.

Wenn I und D 1.0 ist, schwingt der Zielwert je nach P. Ist P zu klein kommt die Regelung erst gar zum Zielwert. Sollte aber nicht zu groß sein, denn I kommt noch dazu. I sorgt für die Annäherungsgeschwindigkeit und für das dämpfen der Einregelung. I unter 1 wird hektischer bzw. nähert sich der aktuelle Druck schneller an den Zielwert an. I größer 1 wird alles langsamer. D wird meistens nicht benötigt, kann bei 1.0 bleiben. Das ist eher Feintuning.
Wildes probieren hilft auch nicht.
Alles auf 1.0 setzen.
P ändern das man mit der Schwingung um den Zielwert einigermaßen zu frieden ist. Dann I sachte mit 2. Kommastelle ändern. Dann sollte man eine Änderung in der Annäherung an den Zielwert sehen. I wirkt nur und umso stärker je weiter weg der aktuelle Wert vom Zielwert ist. Ist der aktuelle Wert nahe Zielwert wirkt quasi nur noch P.
Voraussetzung ist noch das der Istwert, die Eingangsgröße, schnell genug im Lesen reagiert und dennoch genügend gefiltert ist. Sonst spielt die Regelung Amok obwohl sich real nichts geändert hat.
Am Ende ist PID Einstellung immer probieren.
PS: Die Werte um 1.0 sind bei uns auf Arbeit. Die Größenordnungen weichen in der PID Lib hier ab. Also wenn die PID Lib genauso arbeitet was ich kenne und P bspw. 100 ist dann I in Einerschritten ändern. Fürs rantasten kann man Zehnerschritte nehmen.

Ich verstehe immer noch nicht, was genau du regelns willst.

der Solarüberschuss wird gemessen und alles was mehr als 400 W ist, geht über ein Leistungssteller der mit 0-10V angesteuert wird in einen Heizstab.

Das klingt für mich nach einer einfachen, direkten Steuerung:
Pout = Psolar - 400W

Wenn du die Kennlinie deinen Leistungsstellers kennst, kannst du das direkt ansteuern. Den Ansatz mit einem Regler halte ich - vorausgesetzt, ich habe es richtig verstanden - für falsch.

Hallo,
Ok soweit verstanden. Dennoch ist meiner Meinung kein Regler nötig.

Du hast mir die Frage nach Sollwert und Istwert für den Regler leider nicht beantwortet.

Das was an Überschuss vorhanden ist kann doch 1:1 in den Heizstab. Da gibt es doch nichts zu regeln. Wenn die max Temperatur erreicht ist schaltest du ab.

Der Sollwert des Leistungsstellers ergibt die Leistung für den Heizstab. OK da wird die Spannung verstellt und nicht die Leistung. Da ergibt sich dann eine quadratische Kennlinie, aber die kann man ermitteln bzw berechnen.

So wie ich das jetzt verstanden habe nutzt du den Regler letztlich ja nur um die Leistungskurve des Heizstabs zu regeln.

Problem bei einem Regler ist letztlich der I Anteil weil er eben integriert über die Zeit. Ohne bleibt eine Regeldifferenz bestehen. Der D Anteil ist für Störgrößen das sind deine Wolken.

Dein Ansatz zum schnellen runterfahren geht ja schon in die Richtung zwei oder mehrere unterschiedliche Parameter zu verwenden. Allerdings wird das immer komplizierter diese zu ermitteln.

Wenn die Regelstrecke letztlich nur aus Leistungssteller und Heizstab besteht ist die ja eigendlich ziemlich schnell. In sofern verstehe ich deine langsame Regelzeit nicht so ganz.

Hallo,

das was du in der Formel schreibst ist ja der P Anteil der Regelung.

Also nach Deinem Vorschlag würde zB: Psol ( 2,4 kW) - ( 2,4-0,4) also 2 kW( Regelabweichung) = 0,4 ( gewünschter Sollwert) ergeben. Leistungssteller wird für 2kW angesteuert. Bei der nächsten Datenübertragung wäre dann Soll = Ist Wert, ( kein Solarüberschuss mehr vorhanden) , alles wie gewünscht und der Leistungsteller regelt wieder runter. Nun Steigt die Störgröße wieder usw. Es wäre damit ein ständiges An/ Aus des zusätzlichen Verbrauchers.

Deshalb eben auch der I Anteil des Reglers. Der die Regelabweichungen aufsummiert und so nachführt dass möglichst immer Resteinspeisung von 0,4 kW bleiben.

Wie gesagt: funktioniert im Prinzip würde aber gerne schneller und präziser nachführen lassen.

Hallo,
Danke für deine ausführlichen Überlegungen
Ich werde wohl noch einiges in dieser Richtung ausprobieren.

Sollwert ist = Setpoint = 400 Watt Überschuss ins Netz ( siehe auch Setup im Sketch)

Istwert ist= Watt ( Messung vom Energiemeter über MOD Bus)

also, alles was mehr an Leistung vorhanden ist geht in der Tat 1:1 in den Heizstab.

allerdings ändert sich wie beschrieben der Istwert stetig ( Sonne, Wolken andere Verbraucher im Haus)

naja, die Regelzeit ist schon die Schnellste die die Funktion her gibt 50 ms , diese hat sich auch von allen Zeiten bewährt.

Aber ihr könnt mir glauben, dass ich viel Kombinationen von P ; I; und manchmal auch D Werten mit großen und kleinen Werten probiert habe.

Die im Setup zu sehen sind haben sich nun erstmal bewährt.

Weiß niemand was über die AutoPID Library.

Ich hatte die Hoffnung dass diese mir irgendwie nach einiger Zeit ausspuckt.

Sorry, das verstehe ich nicht.
So wie ich das verstanden habe, misst du die Ausgangsleistung deines Solarmoduls.
Davon gehen 400W weg (in die Akkuladung?), und der Rest soll zum Heizen verwendet werden. Dann ist die gemessene Ausgangsleistung unabhäng von der Heizlast und ändert sich nicht (es sei denn, das Wetter ändert sich)

Falls nicht, solltest du vielleicht mal deine komplette Anlage skizzieren.

Warum regelst du nicht auf 0 W Differenz?

Hallo,
das glaube ich Dir gerne. Ich gehe jetzt mal davon aus das Du das systematisch gemäß der gängigen Vorgehensweise in der Regelungstechnik gemacht hast. :wink:
Deine Regelstrecke hab ich nun verstanden, ist schon so wie ich mir das gedacht habe. Der Regelkreis besteht aus Regler und Spannungssteller für den Heizstab. Der Istwert ist ein Leistungsmesser der die aktuelle Einspeisung/Bezug hinter Deinem Zähler mit Vorzeichen misst. Damit ist die Strecke eigentlich recht einfach und schnell. Und du nutzt den Regler eigentlich nur dazu den unlinearen Zusammenhang zwischen P und U in den Griff zu bekommen. Noch mal zu dem Spannungssteller , das ist nicht irgendeine Rampenfunktion mit drin, so das die Spannung langsam an einer Rampe hoch und runter gefahren wird. Sowas wird bei Motoren gerne verwendet.

Kritisch sehe ich eventuell noch die Messrate für den Istwert, das ist eine Totzeit, da ist für Regelkreise ziemlich böse. ich gehe mal davon aus das die maximal im 1s Bereich liegt. Schneller kann Dein Regelkreis ja nie werden. Zudem muss ja erst mal ein Messwert von z.B 500W vorhanden sein damit der Regler überhaupt den Heizstab einschalten kann. Das Ergebnis siehst Du dann eventuell erst 2-3 Messwerte später.

Bei meiner PV Anlage 9,25KWp und 9KWh Speicher dauert es auch in der Regel mehrere Sekunden bei einem Lastsprung bist der Wechselrichter wieder die optimale Aufteilung Netz Aku eingestellt hat. Auch da kommt es regelmäßig dazu das erst mal was aus dem Netz gezogen wird, das können auch schon mal 2000W sein , das sind dann aber in einer Sekunde auch nur 0,5Wh.

Zum Thema automatische Ermittlung der Reglerparameter. Ich hab während meiner beruflichen Praxis hunderte von Reglkreisen in Betrieb genommen. Heizung, Hydraulik, Drehzahl, Druck. ich hab das immer manuell gemacht. Einzige Ausnahme war in den letzten Jahren die Einstellung von Frequenzumrichtern/ Servoregler für Antriebe die im Vectorbetrieb liefen. Und das war recht zuverlässig wenn man die richtigen Motorkenndaten eingegeben hat. (Spannung , Strom, Leistung, Drehzah, cosfi usw) . Es mussten also ein paar Kenndaten der Stecke bekannt sein damit das zuverlässig klappt.

In der Regel läuft das immer so ab das mehrmals Sollwertsprünge gemacht werden. Aus dem Verhalten des Istwertes werden dann nacheinander die Regler Parameter bestimmt. Auch dabei wird "probiert" und eventuell ein Schritt zurück gegangen. Ähnlich wie bei einer manuellen Optimierung. Für den Arduino Regler hab ich die Auto Funtion bisher nicht genutzt. Machen kannst Du das sicher nur bei ganz konstanter Sonneneinstrahlung von der PV Anlage.

Ich denke ja immer noch der Regler ist nicht nötig. Du musst nur einmal die Kennlinie für z.B 10 Sollwerte ermitteln . Die trägst Du in z.B Excel ein erstellst eine Grafik U auf der Y Achse P auf der X Achse also U(P) . Dann kannst Du Dir von Excell eine Näherungsformel anzeigen lassen, die Du im Arduino verwendest. Damit berechnest Du die Spannung die nötig ist um das gewünschte P einzustellen. Das machst Du zyklisch mit jedem neuen Messwert. Das ist so eine Art geführter Stellbetrieb.Du ziehst von Deinem Messwert die gewünschten 400W ab der Rest soll an den Heizstab. P umrechnen auf U , die Formel hast Du ja aus Excel bekommen.

Heinz

Hallo Heinz (Rentner)
erstmal möchte ich mich bedanken, dass Du Dir soviel Zeit genommen hast, Dich mit meinem Thema auseinander zu setzen.
Ja, das Problem mit der Tot-Zeit wegen der MOD BUS Übertragung habe ich auch schon betrachtet.
Das kann ich natürlich nicht beeinflussen. Ich werde vermutlich deinen letzten Vorschlag mit der Messreihe weiter verfolgen und ggf. auf die PID Funktionen verzichten.
Dann kann ich auch besser nachvollziehen was passiert.
Wie der Batteriespeicher reagiert habe ich auch bei mir beobachtet. Dass dieser auch eine gewisse Regeldifferenz an Tag legt. Aber immerhin reagiert er im sekunden bereich 15-30s. Was meine Schaltung leider noch nicht macht.
Der Batteriespeicher mag tacktende Verbraucher im Haushalt wie Bügeleisen und Mikrowellen überhaupt nicht. Dass konnte man alles schon beobachten wenn man ab und zu mal auf das Display vom Sentron schaut.
Auf jedem Fall erstmal vielen Dank für Deine Gedanken und ich werde mich ggf. nochmal melden wenn ich irgend welche Erfolge verkünden kann.

Norman

Hallo allerseits,

wen es interessiert, hier meine Lösung für das geschilderte Problem, dank Eurer vielen Anregungen.
Ich habe es Händisch ohne die PID Library gemacht...`

double gap = (Watt - Setpoint);  //Abweichung vom Einstellwert zB -400 W

 if (Watt != Watt_alt) {  // erst durchlaufen wenn neue Werte anliegen

    if ((abs(gap) > 50))                                 // ist die Abweichung größer +- 50 --> durch abs = immer Posit
    {  Output = Output + gap * -(aggKp);  // aggKp nicht größer als 1 werden lassen; mit neg vorzeichen damit Ausgang positiv angesteuert wird
                                         // Output ändert sich nur bei einer Abweichung im    Bereich +- 50
    }
  }
  if (Output <= 0) Output = 0;
  if (Output >= 6000) Output = 6000;  // zur Sicherheit Werte begrenzen

Also, damit wird der Ausgang schnell und ohne großes Überschwingen nachgestellt.
Die Var aggKp ist noch aus dem alten Programm über geblieben und hat den wert von ca. 0.1.
Sonst ist es doch öfter übers "Ziel" hinaus geschossen. Nun pendelt sich der Setpoint schnell bei +- 50 Watt ein, also -350 bis -450Watt.
Das Problem ist wirklich die Tot- Zeit zwischen Heizstab nachstellen, Messen, MOD Bus und Übertragen des neuen Wertes. In der Zeit hat der Controler schon eineige Zyklen hinter sich. Deshalb auch noch die erste If Abfrage nach einem neuen Messwert.

Jedenfalls ist das Erggebnis zufriedenstellender als vorher:)

Gruß
Norman

Schau dir mal https://www.arduino.cc/reference/de/language/functions/math/constrain/ an.

Output  = constrain(Output , 0, 6000);