N'Abend,
ich hab mir einen PID-Regler programmiert, der eine Temperaturregelung
(Kühlung per Peltier) eines isolierten Flüssigkeitsbehälters realisieren
soll.
Ja, Wikipedia und andere Literatur zum Try&Error-Einstellen der
Parameter ist mir geläufig. Nein, in diesem Falle nicht anwendbar, denn
die Regelung ist _träge_ (20°C->4°C dauern knapp 2 Stunden). Ich
möchte nicht 30 Minuten davorsitzen, um zu schauen, ob die Schwingung
jetzt aufgehört hat.
Der Regler bekommt einen je UINT16 als Meßgröße (DS18S22), Stellgröße
(AVR-OCR1A-PWM-Peltier) und Sollgröße (über GUI einstellbar). Dabei
werden Meß- und Sollgröße als Fix-Kommawert mit zwei Nachkommastellen
behandelt (00400 ^= 4,00°C).
Die Abtastrate beträgt 244 (16MHz/0xFFFF) Hz und ist sehr konstant, da
sie über die TOVR-ISR des Timers1 realisiert wird.
Code der ISR:
1 | ISR(TIMER1_OVF_vect) {
|
2 | double e, y;
|
3 | static double eAlt=0, eSum=0;
|
4 | long tmp;
|
5 |
|
6 | e = currentCoolerTargetTemperature; // globales u_int16
|
7 | e -= ((struct ds18b20)*temperatureSensorColdSide).temperature; // globales u_int16
|
8 | eSum += e;
|
9 | // Begrenzen des I-Anteils...
|
10 | if (eSum>5) eSum = 5;
|
11 | if (eSum<-5) eSum = -5;
|
12 | y=(0.1 * e) + (0.5 * eSum) + 5 * (e-eAlt);
|
13 | // Begrenzen des Ausgangssignals...
|
14 | if (y>1000) y=1000;
|
15 | if (y<-1000) y=-1000;
|
16 | eAlt = e;
|
17 | tmp = ceil((float)OCR1A - y);
|
18 | if (tmp > 65535) tmp = 65535;
|
19 | if (tmp < 0) tmp = 0;
|
20 | OCR1A = (unsigned int) tmp;
|
21 | }
|
Mit den Parametern wie oben im C-Code verhält sich das Teil wie ne
schlechte Zweipunktregelung. Kann mir nun jemand eine Methode nennen,
wie ich die Parameter berechnen kann, so dass der Regelkreis möglichst
stabil bleibt? Oder mich in die richtige Richtung weisen, was ich denn
messen muss, um welchen Parameter wie zu berechnen. Danke.