Forum: Projekte & Code PID-Regler mit anti-Windup


von THM (Gast)


Lesenswert?

OK, wollte auch mal meinen Beitrag zum Thema PID-Regler leisten:
1
double PID_Berechnung (double x, double w)
2
{    
3
e = w - x;                // aktuelle Regelabweichung bestimmen
4
if ((y < 1023)&&(y > 0))  // bei Übersteuertem stellglied Integration einfrieren
5
  {                       // (Anti-Windup)
6
    esum = esum + e;      // Summe der Regelabweichung aktualisieren  
7
  }
8
y = (Kp*e)+(I*Ta*esum)+(D*((e-ealt))/Ta);  // Reglergleichung
9
ealt = e;                 // Regelabweichung für nächste Abtastung merken
10
if (y > 1023)             // Stellgröße auf 0..1023 begrenzen (10 bit PWM)
11
  {
12
    y = 1023;
13
  }
14
if (y < 1)
15
  {
16
    y = 0;
17
  }
18
return y;                 // Stellgröße zurückgeben
19
}
Das Ganze ist für einen mega32 @ 16Mhz geschrieben und getestet.
OK, über die vielen doubles kann man streiten, den µC interessiert's 
aber kaum, die Rechneleistung reicht locker dafür aus. Bei Messung einer 
Frequenz für den Istwert (z.B. Drehzahl) per Input-Capture muss zur 
Berechnung sowieso long int benutzt werden.

Die Variablen sind:
w => Sollwert (double)
x => Istwert (double)
e => Regelabweichung (double)
esum => Summe Regelabweichung für Integralanteil (double)
Kp => Proportionalanteil (double)
I => Integralantei (double)
D => Differentialanteil (double)
y => Stellgröße (double)

Für die Anti-Windup-Funktion wird bei übersteuertem Stellglied (hier <0 
und >1023) der Integralanteil eingefroren (=> esum nicht weiter 
aufintegriert). Dadurch wir ein extremer Überschwinger bei 
Wiedereintritt in den nicht übersteuerten Bereich des Stellgliedes 
vermieden.

Ich wollte das Teil etwas allgemein halten, so kann der Codeschnipsel 
für den jeweils benötigten Zweck angepasst werden.

:
von Thomas (Gast)


Lesenswert?

Ein paar Punkte:

- I*Ta sowie D/Ta sind Konstanten und brauchen nicht in Echtzeit 
gerechnet zu werden.

- Ich würde dazu wirklich kein double verwenden. Hast du mal die Anzahl 
der Taktzyklen ermittelt, die diese Methode benötigt? Interessant währe, 
was eine Integerversion dem gegenüber braucht.

- Den Anti-Windup kann man noch verbessern, indem man den I-Anteil auf 
den Wert begrenzt, der für eine bestimmte Strecke nötig ist um 
Steady-State Fehler völlig zu beseitigen. Weil sonst macht der nämlich 
nichts gutes.

- Den D-Anteil legt man (gerade bei digitalen Reglern) besser in die 
Rückkopplung. Damit änderst du nichts am dynamischen Verhalten des 
Systems, verhinderst aber den sog. Set-Point-Peak, der sonst immer 
entsteht, wenn sich der Sollwert schlagartig ändert (und das tut er in 
digitalen Systemen praktisch immer).

- Das ganze halte ich für ein heißes Thema für die Artikelsammlung, nach 
Regelalgorithmen wird ja hier schließlich häufiger gefragt.

von THM (Gast)


Lesenswert?

Sehe ich auch so, ich habe auch was gesucht und bin nicht richtig fündig 
geworden. Darum habe ich mich etwas eingehender damit beschäftigt.
Könntest du Codebeispiele für deine oben genannten Vorschläge posten?
Das mit den Konstanten ist richtig, werde meinen Code dementsprechend 
anpassen.
Wegen Taktzyklen habe ich noch nicht debuggt, aber ich messe und 
berechne zusätzlich die Frequenz (Istwert) per ICP und gebe alle 
Parameter zum Testen über fprintf auf UART aus. Ebenso wird ein LCD 2x16 
in 1/3s-Takt bedient. Also kann's so schlimm nicht sein ;)

Ta hatte ich oben vergessen, ist die Abtastrate, in meinem Fall 20ms per 
Output-Compare-INT.

DIe Variablen / Konstanten auf int zu ändern ist ja weniger das Problem. 
Je nach Anwendugsfall (Geschwindigkeit, Codegröße) eben.

von JÜrgen G. (Firma: 4CKnowLedge) (psicom) Benutzerseite


Lesenswert?

Thomas wrote:
> Ein paar Punkte:
>
> - I*Ta sowie D/Ta sind Konstanten und brauchen nicht in Echtzeit
> gerechnet zu werden.

Sehr guter Einwand...

> - Ich würde dazu wirklich kein double verwenden. Hast du mal die Anzahl
> der Taktzyklen ermittelt, die diese Methode benötigt? Interessant währe,
> was eine Integerversion dem gegenüber braucht.

Gibts in der Abteilung Elektronik und µC schon... kommt bald in die 
Codesammlung...
Zeitersparniss - sicher einiges!!!

> - Den Anti-Windup kann man noch verbessern, indem man den I-Anteil auf
> den Wert begrenzt, der für eine bestimmte Strecke nötig ist um
> Steady-State Fehler völlig zu beseitigen. Weil sonst macht der nämlich
> nichts gutes.

Stellt sich die Frage, ob man das als Parameter übergeben soll?! Nja... 
nichts gutes, is schon richtig nur muss man dafür die Strecke gut 
kennen!

> - Den D-Anteil legt man (gerade bei digitalen Reglern) besser in die
> Rückkopplung. Damit änderst du nichts am dynamischen Verhalten des
> Systems, verhinderst aber den sog. Set-Point-Peak, der sonst immer
> entsteht, wenn sich der Sollwert schlagartig ändert (und das tut er in
> digitalen Systemen praktisch immer).

Auch ein sehr berechtigter Einwand...

> - Das ganze halte ich für ein heißes Thema für die Artikelsammlung, nach
> Regelalgorithmen wird ja hier schließlich häufiger gefragt.

Das ist so seine Geschichte... weil extremst viel Entwicklungsaufwand 
dahinter steckt und jeder zumindest einmal einen PID-Regler selbst 
geproggt haben sollte und das ganze auch ein wenig verstehn - Stichwort: 
Wo drehe ich damit sich wo, was ändert...

von THM (Gast)


Lesenswert?

>ast du mal die Anzahl der Taktzyklen ermittelt, die diese Methode benötigt?

Taktzyklen nicht, aber ich hab's mal durch den Debugger laufen lassen:
knapp 50µs hat die komplette Funktion gebraucht.

von JÜrgen G. (Firma: 4CKnowLedge) (psicom) Benutzerseite


Lesenswert?

THM wrote:
>>ast du mal die Anzahl der Taktzyklen ermittelt, die diese Methode benötigt?
>
> Taktzyklen nicht, aber ich hab's mal durch den Debugger laufen lassen:
> knapp 50µs hat die komplette Funktion gebraucht.

In Integer od. in double?

von THM (Gast)


Lesenswert?

In double, so wie's oben im Posting ist.

von JÜrgen G. (Firma: 4CKnowLedge) (psicom) Benutzerseite


Lesenswert?

THM wrote:
> In double, so wie's oben im Posting ist.

Oh ok... hätt ich mir schlimmer vorgestellt...


Ich hätt schon angefangen zu coden... also Grundgerüst steht... jetzt 
muss ich mir mit den Datentypen noch was überlegen... kleine Hint's mit 
denen ich allgemein double umgehen kann...

Aber zuerst: betrinken ^^

Ich werd morgen mal eine Version reinstellen!

Schönen Abend noch!

von Andreas S. (andreas) (Admin) Benutzerseite


Lesenswert?

Thomas wrote:
> Ein paar Punkte:
>
> - I*Ta sowie D/Ta sind Konstanten und brauchen nicht in Echtzeit
> gerechnet zu werden.

Wenn I und D konstant sind sollte das der Compiler selbst merken und 
optimieren. Kann aber sein dass man "D/TA" explizit so hinschreiben 
muss, weil der Compiler das nicht von selbst umsortieren darf 
(geändertes Rundungsverhalten).

> - Ich würde dazu wirklich kein double verwenden. Hast du mal die Anzahl
> der Taktzyklen ermittelt, die diese Methode benötigt? Interessant währe,
> was eine Integerversion dem gegenüber braucht.

Wahrscheinlich ein hundertstel bis tausendstel der Rechenzeit. Aber ohne 
Not würde ich mir nicht die Arbeit machen das in Integer umzuschreiben. 
Ob der Prozessor z.B. bei einer Temperaturregelung 99% oder 99.99% der 
Zeit Däumchen dreht ist egal.

Die avr-libc kennt übrigens kein double, sondern rechnet alles mit 
normalem float.

> - Das ganze halte ich für ein heißes Thema für die Artikelsammlung, nach
> Regelalgorithmen wird ja hier schließlich häufiger gefragt.

Ja, wäre super wenn sich jemand die Mühe machen würde das in einem 
Artikel zusammenzufassen.

von Thomas (Gast)


Lesenswert?

"Wenn I und D konstant sind sollte das der Compiler selbst merken und 
optimieren."

Das ist richtig, aber wenn die Regelparameter zur Laufzeit angepasst 
werden sollen, reicht es diese Terme nur bei Änderungen neu zu 
berechnen. Vor allem entfällt dann die Division im Echtzeit-Task. OK, 
bei float bringt das wahrscheinlich auch nicht viel.

"Kann aber sein dass man "D/TA" explizit so hinschreiben muss, weil der 
Compiler das nicht von selbst umsortieren darf (geändertes 
Rundungsverhalten)."

Wie meinst du das? Wegen dem (e-ealt) dazwischen? Also, dass er in 
diesem Fall nicht optimiert?

"Wahrscheinlich ein hundertstel bis tausendstel der Rechenzeit. Aber 
ohne Not würde ich mir nicht die Arbeit machen das in Integer 
umzuschreiben. Ob der Prozessor z.B. bei einer Temperaturregelung 99% 
oder 99.99% der Zeit Däumchen dreht ist egal."

Da hast du wohl Recht, aber in den meisten Fällen braucht man das 
Ergebnis ja eh als Integer, hier z.B. für die PWM. Und wenn die Regelung 
nur ein kleiner Task eines großen Prozesses ist, ist man für jeden 
Geschwindigkeitsgewinn dankbar. Wobei sich irgendwann dann natürlich 
schon die Frage stellt, ob ein kleiner 8 Bitter für so etwas überhaupt 
noch die richtige Plattform ist. Zumal ja seit einiger Zeit auch die 
ARM7 stark in den Hobbybereich vordringen...
Es ist natürlich bequem direkt in Real-World-Values zu rechnen, gar 
keine Frage.

"Ja, wäre super wenn sich jemand die Mühe machen würde das in einem 
Artikel zusammenzufassen."

Zur Regelungstechnik könnte ich hier bestimmt einiges beitragen, leider 
bin ich beruflich zur Zeit so stark ausgelastet, dass ich nebenbei kaum 
noch den Kopf für so etwas frei bekomme.
NaJa, es werden auch wieder ruhigere Zeiten kommen...

von JÜrgen G. (Firma: 4CKnowLedge) (psicom) Benutzerseite


Lesenswert?

Entschuldigt mich, der Regelalgo braucht noch ne Weile... hab momentan 
andere Sachen vorschieben müssen!

von THM (Gast)


Lesenswert?

Da ich mir eine Blockspeicherheizung mit Solar- Elektrospeisung einbauen 
will und dafür mehrere Regler benötige, habe ich spaßeshalber mal 10 
PID-Regler auf einen µC gepackt:
1
double PID_Berechnung (double x, double w)
2
{    
3
e[i] = w - x;  // aktuelle Regelabweichung bestimmen
4
if ((y[i] < 1023)&&(y[i] > 0))  // bei Übersteuertem stellglied Integration einfrieren
5
  {        // (Anti-Windup)
6
    esum[i] = esum[i] + e[i];  // Summe der Regelabweichung aktualisieren  
7
  }
8
y[i] = (Kp[i]*e[i])+(I[i]*Ta*esum[i])+(D[i]*((e[i]-ealt[i]))/Ta); // Reglergleichung 
9
ealt[i] = e[i];  // Regelabweichung für nächste Abtastung merken
10
if (y[i] > 1023)// Stellgröße auf 0..1023 begrenzen (10 bit PWM)
11
  {
12
    y[i] = 1023;
13
  }
14
if (y[i] < 1)
15
  {
16
    y[i] = 0;
17
  }
18
return y[i];
19
}
20
21
//--------------------------------------------------------------------------------------
22
/*** Regelung *************************************************************************/
23
24
void Regeln (void)
25
{
26
i = 0;
27
Dummy = PID_Berechnung (5, 50);  // Regelparameter berechnen
28
i = 1;
29
Dummy = PID_Berechnung (5, 50);  // Regelparameter berechnen
30
i = 2;
31
Dummy = PID_Berechnung (5, 50);  // Regelparameter berechnen
32
i = 3;
33
Dummy = PID_Berechnung (5, 50);  // Regelparameter berechnen
34
i = 4;
35
Dummy = PID_Berechnung (5, 50);  // Regelparameter berechnen
36
i = 5;
37
Dummy = PID_Berechnung (5, 50);  // Regelparameter berechnen
38
i = 6;
39
Dummy = PID_Berechnung (5, 50);  // Regelparameter berechnen
40
i = 7;
41
Dummy = PID_Berechnung (5, 50);  // Regelparameter berechnen
42
i = 8;
43
Dummy = PID_Berechnung (5, 50);  // Regelparameter berechnen
44
i = 9;
45
OCR1B = PID_Berechnung (Frequenz, Sek_Soll);// Regelparameter berechnen
46
i = 0;
47
}

i => index des aktiven Reglers
Alle Regelparameter ausse x und w als Array[10] indiziert
Ta => 0.2s (Abtastrate)
Da meine Regelungen fast nur langsame Temperaturregelungen sind kann die 
Abtastrate getrost auf 1s oder größer gesetzt werden.

Durch aufruf von Regeln(); werden alle 10 Regler getaktet.

Bin mal auf die Regelalgo von  JÜrgen G. gespannt, wird dann auch 
implementiert. ;)

von JÜrgen G. (Firma: 4CKnowLedge) (psicom) Benutzerseite


Lesenswert?

THM wrote:

> Bin mal auf die Regelalgo von  JÜrgen G. gespannt, wird dann auch
> implementiert. ;)

Wie lang haste denn Zeit? Ich hab mein Mega32 Board bei einem Versuch 
mit der Teslaspule daneben gegrillt... jetzt kommen nächste Woche die 
Bauteile für ein neues! Aber mal so viel: Ich hab das ganze getrennt in 
einen Init Funktion die dann eine Struktur an den Regelalgo übergibt!
Damit lassen sich dann viele Regler mit verschiedenen 
Reglereinstellungen basteln xP

Tut mir Leid das es so lang dauert!

von THM (Gast)


Lesenswert?

@ JÜrgen G.:

Nur keine Hetze! Gut Ding will Weile haben! ;)

von JÜrgen G. (Firma: 4CKnowLedge) (psicom) Benutzerseite


Lesenswert?

THM wrote:
> @ JÜrgen G.:
>
> Nur keine Hetze! Gut Ding will Weile haben! ;)


Das schon... allerdings zu lange Zeit soll man sich auch nicht lassen... 
^^

Aber ich hab Erkenntnis bekommen: den µC nicht neben 50kV@800kHz liegen 
lassen xP

von JÜrgen G. (Firma: 4CKnowLedge) (psicom) Benutzerseite


Lesenswert?

So jetzt mal ohne Gewährleistung... Bis mein µC Brett wieder läuft ^^
Hab mal alles durch den Simulator vom AVRStudio gejagt...
1
void PID_Init(void);
2
int PID_Cyclic(int, int, PID_Einstellung*);
3
4
typedef struct
5
{
6
  int Ta;                      // Abtastzeit in ms
7
  int I;                      // Integralanteil
8
  int Kp;                      // Verstärkung
9
  int D;                      // Differenzieller Anteil
10
  int e;                      // Regelabweichung
11
  int esum;                    // Summe der Regelabweichungen
12
  int ealt;                    // Regelabweichung zum ZP z-1
13
  
14
}PID_Einstellung;                  // Struktur PID_Einstellungen erzeugen
15
16
17
PID_Einstellung Regler1;              // Variable Regler1, je nach Bedarf erweitern
18
19
20
void main(void)
21
{
22
  PID_Init();
23
  
24
  int Ausgang, w,x;  
25
  
26
  while(1)
27
  {
28
    Ausgang = PID_Cyclic(x,w,&Regler1);       // Parameter für Regler1 übergeben
29
  }
30
}
31
32
33
void PID_Init(void)                  // In der Init müssen die Reglereinstellungen gemacht werden
34
{
35
  Regler1.Ta=10;
36
  Regler1.I=100;
37
  Regler1.D=0;
38
  Regler1.Kp=1;
39
  Regler1.esum=0;  
40
  Regler1.e=0;                  // Für weiteren Regler einfach Neue Variable erstellen
41
  Regler1.ealt=0;                  // und hier Werte mit Regler2.xx=0 einstellen
42
}
43
44
45
int PID_Cyclic (int x, int w, PID_Einstellung* PID)
46
{    
47
  int y;
48
  PID->e = w - x;                                   // aktuelle Regelabweichung bestimmen
49
  if ((y < 1023)&&(y > 0))                      // bei Übersteuertem stellglied Integration einfrieren
50
   {                                           // (Anti-Windup)
51
        PID->esum = PID->esum + PID->e;                               // Summe der Regelabweichung aktualisieren  
52
    }
53
  y = (PID->Kp*PID->e)+(PID->I*PID->Ta*PID->esum)+(PID->D*((PID->e-PID->ealt))/PID->Ta);    // Reglergleichung
54
  PID->ealt = PID->e;                                     // Regelabweichung für nächste Abtastung merken
55
  if (y > 1023)                                 // Stellgröße auf 0..1023 begrenzen (10 bit PWM)
56
   {
57
      y = 1023;
58
    }
59
  if (y < 1)
60
    {
61
      y = 0;
62
    }
63
  return y;                                     // Stellgröße zurückgeben
64
}

Mit Optimizer: Die Konstanten des Regler werden nicht immer wieder neu 
berechnet...

von Thomas (Gast)


Lesenswert?

Ist es für einen "Universal-Eintrag" in der Codesammlung nicht sinnvoll, 
z.B. die Grenze von PID->esum zu überwachen?

Bei der Verwendung von Integers könnte es ja schon vorkommen dass der 
berechnete Wert über INT_MAX hinausgeht, falls die Reglerparameter 
enstprechend gewählt wurden sodass die Stellgröße noch nicht auf 
Anschlag ist.

von THM (Gast)


Lesenswert?

Die Überläufe sollten prinzipiell schon überwacht werden.
Durch die (wenn auch einfache) anti-Windup-Funktion sollte ein Überlauf 
von PID->esum eigentlich nicht vorkommen.
Falls doch wäre der Parameter für I extrem übredimensioniert. Also würde 
ich besser die Regelparameter begrenzen.

von JÜrgen G. (Firma: 4CKnowLedge) (psicom) Benutzerseite


Lesenswert?

In dem Fall von PID->esum, wird durch die Anti-Windup-Maßnahme eh 
begrenzt... was nicht nur den eher unkritischen Fall ausschließt das 
einfach der Wert über die Int-Grenzen läuft, sondern das Regelverhalten 
des Digital-Reglers um einiges verbessert!



THM wrote:
> Falls doch wäre der Parameter für I extrem übredimensioniert. Also würde
> ich besser die Regelparameter begrenzen.

Achja... Der I und D Anteil sind in ms anzugeben, falls nötig ist ein 
größerer Datentyp erforderlich!

und @THM: willst dich nicht mal registriern? ^^

von Thomas (Gast)


Lesenswert?

In der oben beschriebenen Variante wird der Anti-Windup auch nicht 
funktionieren, da y eine lokale Variable ist.
Sie müsste also noch der globalen Struktur hinzugefügt werden.

von THM (Gast)


Lesenswert?

@ JÜrgen G.:
>willst dich nicht mal registriern?
Bin ich schon, wechsle nur öfter den Rechner (Arbeitsplatz) und habe 
mein Login nicht mit (Faul!).
Werde mich aber bessern!

von Woifee (Gast)


Lesenswert?

ad JÜrgen G. (psicom) Datum: 18.11.2007 18:42

der so vorgestellte Algorithmus kann gar nicht richtig funktionieren 
(hättest du beim test mit dem board aber bemerkt).

Da y eine lokale Variable ist, ist die Zeile
     if ((y < 1023)&&(y > 0))
nutzlos bzw. die Entscheidung undefiniert, da y keinen zugewiesenen Wert 
hat (zufälliges Bitmuster)

Des weiteren würde bei der Berechnung über die Zeile
     y = 
(PID->Kp*PID->e)+(PID->I*PID->Ta*PID->esum)+(PID->D*((PID->e-PID->ealt)) 
/PID->Ta);     // Reglergleichung
schon bei kleinster Regelabweichung der gültige Zahlenbereich für int 
überlaufen ( I*Ta*esum wird sofort zu groß ).

Bei einer Implementierung muss man unbedingt auf die Datentypen achten,
und auch darauf, ob bei der Addition nicht ein 2er Komplement-Überlauf 
der signed integer auftritt.

Bin selbst gerade dabei, einen Regler in Assembler zu programmieren, der 
möglichst nur mit schneller Verschiebemathematik auskommen soll.

von JÜrgen G. (Firma: 4CKnowLedge) (psicom) Benutzerseite


Lesenswert?

1
void PID_Init(void);
2
void PID_Cyclic(int, int, PID_Einstellung*);
3
4
typedef struct
5
{
6
  int Ta;                      // Abtastzeit in ms
7
  int I;                      // Integralanteil
8
  int Kp;                      // Verstärkung
9
  int D;                      // Differenzieller Anteil
10
  int e;                      // Regelabweichung
11
  float esum;                    // Summe der Regelabweichungen
12
  int ealt;                    // Regelabweichung zum ZP z-1
13
  
14
}PID_Einstellung;                  // Struktur PID_Einstellungen erzeugen
15
16
17
PID_Einstellung Regler1;              // Variable Regler1, je nach Bedarf erweitern
18
19
20
void main(void)
21
{
22
  PID_Init();
23
  
24
  int Ausgang, w,x;  
25
  
26
  while(1)
27
  {
28
    Ausgang = PID_Cyclic(x,w,&Regler1);       // Parameter für Regler1 übergeben
29
  }
30
}
31
32
33
void PID_Init(void)                  // In der Init müssen die Reglereinstellungen gemacht werden
34
{
35
  Regler1.y=0;
36
  Regler1.Ta=10;
37
  Regler1.I=100;
38
  Regler1.D=0;
39
  Regler1.Kp=1;
40
  Regler1.esum=0;  
41
  Regler1.e=0;                  // Für weiteren Regler einfach Neue Variable erstellen
42
  Regler1.ealt=0;                  // und hier Werte mit Regler2.xx=0 einstellen
43
}
44
45
46
void PID_Cyclic (int x, int w, PID_Einstellung* PID)
47
{    
48
  PID->e = w - x;                                   // aktuelle Regelabweichung bestimmen
49
  if ((PID->y < 1023)&&(PID->y > 0))                      // bei Übersteuertem stellglied Integration einfrieren
50
   {                                           // (Anti-Windup)
51
        PID->esum = PID->esum + PID->e;                               // Summe der Regelabweichung aktualisieren  
52
    }
53
  PID->y = (PID->Kp*PID->e)+(PID->I*PID->Ta*PID->esum)+(PID->D*((PID->e-PID->ealt))/PID->Ta);    // Reglergleichung
54
  PID->ealt = PID->e;                                     // Regelabweichung für nächste Abtastung merken
55
  if (PID->y > 1023)                                 // Stellgröße auf 0..1023 begrenzen (10 bit PWM)
56
   {
57
      PID->y = 1023;
58
    }
59
  if (PID->y < 1)
60
    {
61
      PID->y = 0;
62
    }
63
                                    // Stellgröße zurückgeben
64
}


So, jetzt könnte man natürlich auch noch drüber streiten ob man x und w 
auch noch in die Struktur übernimmt od. nicht...

Jetzt ist der Zugriff auf den Ausgangswert über Regler1.y möglich!

von JÜrgen G. (Firma: 4CKnowLedge) (psicom) Benutzerseite


Lesenswert?

Wieso hab ich keine Berechtigungen meine eigenen Beiträge zu editieren?

Die Main muss dann dementsprechend anders aussehen:
1
void main(void)
2
{
3
  PID_Init();
4
  
5
  int Ausgang, w,x;  
6
  
7
  while(1)
8
  {
9
    PID_Cyclic(x,w,&Regler1);       // Parameter für Regler1 übergeben
10
  }
11
}

von JÜrgen G. (Firma: 4CKnowLedge) (psicom) Benutzerseite


Lesenswert?

1
void PID_Init(void);
2
void PID_Cyclic(int, int, PID_Einstellung*);
3
4
typedef struct
5
{
6
  int Ta;                      // Abtastzeit in ms
7
  int I;                      // Integralanteil
8
  int Kp;                      // Verstärkung
9
  int D;                      // Differenzieller Anteil
10
  int e;                      // Regelabweichung
11
  float esum;                    // Summe der Regelabweichungen
12
  int ealt;                    // Regelabweichung zum ZP z-1
13
  int y;
14
  
15
}PID_Einstellung;                  // Struktur PID_Einstellungen erzeugen
16
17
18
PID_Einstellung Regler1;              // Variable Regler1, je nach Bedarf erweitern
19
20
21
void main(void)
22
{
23
  PID_Init();
24
  
25
  int Ausgang, w,x;  
26
  
27
  while(1)
28
  {
29
    PID_Cyclic(x,w,&Regler1);       // Parameter für Regler1 übergeben
30
  }
31
}
32
33
34
void PID_Init(void)                  // In der Init müssen die Reglereinstellungen gemacht werden
35
{
36
  Regler1.y=0;
37
  Regler1.Ta=10;
38
  Regler1.I=100;
39
  Regler1.D=0;
40
  Regler1.Kp=1;
41
  Regler1.esum=0;  
42
  Regler1.e=0;                  // Für weiteren Regler einfach Neue Variable erstellen
43
  Regler1.ealt=0;                  // und hier Werte mit Regler2.xx=0 einstellen
44
}
45
46
47
void PID_Cyclic (int x, int w, PID_Einstellung* PID)
48
{    
49
  PID->e = w - x;                                   // aktuelle Regelabweichung bestimmen
50
  if ((PID->y < 1023)&&(PID->y > 0))                      // bei Übersteuertem stellglied Integration einfrieren
51
   {                                           // (Anti-Windup)
52
        PID->esum = PID->esum + PID->e;                               // Summe der Regelabweichung aktualisieren  
53
    }
54
  PID->y = (PID->Kp*PID->e)+(PID->I*PID->Ta*PID->esum)+(PID->D*((PID->e-PID->ealt))/PID->Ta);    // Reglergleichung
55
  PID->ealt = PID->e;                                     // Regelabweichung für nächste Abtastung merken
56
  if (PID->y > 1023)                                 // Stellgröße auf 0..1023 begrenzen (10 bit PWM)
57
   {
58
      PID->y = 1023;
59
    }
60
  if (PID->y < 1)
61
    {
62
      PID->y = 0;
63
    }
64
                                    // Stellgröße zurückgeben
65
}

von Team (Gast)


Lesenswert?

Also der schnelle Hack mit dem Float darf aber keiner sehen ;-)
War sowas auch in deiner Tesla-Anlage programmiert?

von JÜrgen G. (Firma: 4CKnowLedge) (psicom) Benutzerseite


Lesenswert?

Team wrote:
> Also der schnelle Hack mit dem Float darf aber keiner sehen ;-)
> War sowas auch in deiner Tesla-Anlage programmiert?

hab ich float geschrieben?


ach... tatsächlich... das tut natürlich der rechenzeit nicht gut... 
sollte eigentlich long int sein... also 32bit

nö meine teslaanlage ist mit solid state ansteuerung... allerdings ohne 
µC... aber meiner is zu weit in der nähe gelegen und hat was 
abbekommen...

von Hauke R. (lafkaschar) Benutzerseite


Lesenswert?

>zu weit in der nähe
Interessanter Ausdruck ;)

von Thilo M. (Gast)


Lesenswert?

@ JÜrgen G.:
habe meinen Login wiedergefunden ;)
War mal THM.

Sind long int, float und double beim AVR nicht alle 32 bit?

von JÜrgen G. (Firma: 4CKnowLedge) (psicom) Benutzerseite


Lesenswert?

Hauke Radtki wrote:
>>zu weit in der nähe
> Interessanter Ausdruck ;)

Bin Österreicher... mit Deutsch an sich haben wirs nicht so...

THM wrote:
> Sind long int, float und double beim AVR nicht alle 32 bit?

jup glaub schon... nur das float nachkommazahlen darstellt... und der 
AVR keine floatingpoint unit hat tut der sich ein wenig schwerer...

von Thilo M. (Gast)


Lesenswert?

OK, habe JÜrgen G's Version mal mit einer Ansprechschwelle ausgestattet. 
Diese ist für langsame Regelungen (Temperatur) um das Stellglied 
(Stellantrieb, z.B. Heizungsmischer) zu schonen, also möglichst wenig 
Aktivität (Steps). Diese Antriebe werden mit Impulsen verschiedener 
Länge und Häufigkeit (Freqenz) angesteuert.
Die Regelparameter müssen natürlich geändert werden, da Kp nun von der 
Ansprechschwelle abhängt.
1
typedef struct
2
{
3
  int Ta;                      // Abtastzeit in ms
4
  int I;                      // Integralanteil
5
  int Kp;                      // Verstärkung
6
  int D;                      // Differenzieller Anteil
7
  int e;                      // Regelabweichung
8
  float esum;                    // Summe der Regelabweichungen
9
  int ealt;                    // Regelabweichung zum ZP z-1
10
  int y;
11
  int AS;                     // Ansprechschwelle
12
}
13
14
void PID_Init(void)                  // In der Init müssen die Reglereinstellungen gemacht werden
15
{
16
  Regler1.AS=1;
17
  Regler1.y=0;
18
  Regler1.Ta=10;
19
  Regler1.I=100;
20
  Regler1.D=0;
21
  Regler1.Kp=1;
22
  Regler1.esum=0;  
23
  Regler1.e=0;                  // Für weiteren Regler einfach Neue Variable erstellen
24
  Regler1.ealt=0;                  // und hier Werte mit Regler2.xx=0 einstellen
25
}
26
27
// der Übersichtlichkeit halber nur diesen Ausschnitt
28
29
if ((PID->e >= AS)||((PID->e * (-1)) >= AS)) // Betrag der Differenz prüfen
30
{
31
  PID->y = (PID->Kp*PID->e)+(PID->I*PID->Ta*PID->esum)+(PID->D*((PID->e-PID->ealt))/PID->Ta);    // Reglergleichung
32
  PID->ealt = PID->e;                                     // Regelabweichung für nächste Abtastung merken
33
}

von Thilo M. (Gast)


Lesenswert?

Kleine Korrektur:
1
void PID_Cyclic (int x, int w, PID_Einstellung* PID)
2
{    
3
  PID->e = w - x;                                   // aktuelle Regelabweichung bestimmen
4
5
if ((PID->e >= AS)||(PID->e) >= (AS * (-1)))) // Betrag der Differenz prüfen
6
{
7
8
  if ((PID->y < 1023)&&(PID->y > 0))                      // bei Übersteuertem stellglied Integration einfrieren
9
   {                                           // (Anti-Windup)
10
        PID->esum = PID->esum + PID->e;                               // Summe der Regelabweichung aktualisieren  
11
    }
12
  PID->y = (PID->Kp*PID->e)+(PID->I*PID->Ta*PID->esum)+(PID->D*((PID->e-PID->ealt))/PID->Ta);    // Reglergleichung
13
  PID->ealt = PID->e;                                     // Regelabweichung für nächste Abtastung merken
14
15
}
16
17
  if (PID->y > 1023)                                 // Stellgröße auf 0..1023 begrenzen (10 bit PWM)
18
   {
19
      PID->y = 1023;
20
    }
21
  if (PID->y < 1)
22
    {
23
      PID->y = 0;
24
    }
25
                                    // Stellgröße zurückgeben
26
}

Sonst summiert sich esum bis zum Überlauf auf.

von Thilo M. (Gast)


Lesenswert?

Ich warzus schnell:
1
void PID_Cyclic (int x, int w, PID_Einstellung* PID)
2
{    
3
  PID->e = w - x;                                   // aktuelle Regelabweichung bestimmen
4
5
if ((PID->e >= AS)||(PID->e) <= (AS * (-1)))) // Betrag der Differenz prüfen
6
{
7
8
  if ((PID->y < 1023)&&(PID->y > 0))                      // bei Übersteuertem stellglied Integration einfrieren
9
   {                                           // (Anti-Windup)
10
        PID->esum = PID->esum + PID->e;                               // Summe der Regelabweichung aktualisieren  
11
    }
12
  PID->y = (PID->Kp*PID->e)+(PID->I*PID->Ta*PID->esum)+(PID->D*((PID->e-PID->ealt))/PID->Ta);    // Reglergleichung
13
  PID->ealt = PID->e;                                     // Regelabweichung für nächste Abtastung merken
14
15
}
16
17
  if (PID->y > 1023)                                 // Stellgröße auf 0..1023 begrenzen (10 bit PWM)
18
   {
19
      PID->y = 1023;
20
    }
21
  if (PID->y < 1)
22
    {
23
      PID->y = 0;
24
    }
25
                                    // Stellgröße zurückgeben
26
}

von JÜrgen G. (Firma: 4CKnowLedge) (psicom) Benutzerseite


Lesenswert?

Und Thilo, wie gehts den Lüftern mit der neuen Version des Reglers?

Das mit der Ansprechschwelle find ich keine blöde Idee... nur wie wirkt 
sich das ganze auf die Regelcharakteristik aus?

von Thilo M. (Gast)


Lesenswert?

Der Lüfter läuft auch mit der neuen Version prima.
Nur ist hier die Ansprechschwelle weniger von Nöten. Die ist mehr für 
langsame Regelungen mit Stellantrieb (Getriebemotor) gedacht. Der nutzt 
sonst durch das ständige Regeln sehr schnell ab.

Die Regelcharakteristik ändert sich natürlich grundlegend, da die 
Verstärkung (Kp) bei Überschreiten der Ansprechschwelle viel stärker zum 
Eingriff kommt. Ist aber alles handhabbar und reine Einstellungssache.
Den D-Anteil kann man bei langsamen Regelungen sowieso weglassen.

von Martin (Gast)


Lesenswert?

Hallo

Wieso ist esum vom Typ float? ein int-typ wäre doch schöner - oder 
nicht?

Grüsse

Martin

von Thilo M. (Gast)


Lesenswert?

esum müsste ein long int sein, da es sich ja aufsummiert könnte bei 16 
bit (ADC) die int - Grenze schnell überschritten werden. Ob ich jetzt 
double, float oder long int habe ist beim AVR egal, sind jedesmal 32 
bit. Lediglich die Rechenzeit könnte sich minimal unterscheiden.
Bei langsamen Regelungen - wie ich sie habe - ist das aber zweitrangig.

von Martin (Gast)


Lesenswert?

Hallo

Vielen Dank für die Info. Ich fragte deshalb, weil sich das ungünstig 
auf die Programmgrösse und die Programmgeschwindigkeit auswirken könnte.

Der C-Compiler von Microchip würde z.B. die floating-point library 
einbindene (unnötiger Verbrauch von Speicher) und die Gleichung zum Teil 
in floats berechnen (Geschwindigkeitsverlust).

Beste Grüsse

Martin

von JÜrgen G. (Firma: 4CKnowLedge) (psicom) Benutzerseite


Lesenswert?

Thilo M. wrote:
> Ob ich jetzt double, float oder long int habe ist beim AVR egal, sind
> jedesmal 32 bit. Lediglich die Rechenzeit könnte sich minimal unterscheiden.

Jup, weils mich interessiert hat, hab ich jetzt nachgeforscht... Ich hab 
leider keine Codegrößenangaben od. exakte Rechenwerte weil der 
PID-Regler möglich auf jedem µC laufen sollte!

Long Int hat 32-bit
float hat 32-bit

Das einzige was die beiden unterscheidet ist die Darstellungsweise:

Int ist allerdings in 2er komplement und float ist in matrisse und 
exponent aufgeteilt, was ein rechnen mit long int, der einfachheit 
halber schneller macht! CPU's von PC's haben allerdings eine eigene 
floatingpoint unit drinnen, die nur für solche zahlen die eben aus 
matrisse und exponent bestehen gemacht ist und diese ebenfalls mit einem 
rechentakt abarbeiten können!

Faktum: PID->esum ist LONG INT

von Thilo M. (Gast)


Lesenswert?

>Faktum: PID->esum ist LONG INT

Macht Sinn! ;)

von JÜrgen G. (Firma: 4CKnowLedge) (psicom) Benutzerseite


Lesenswert?

@Thilo:

Wie wärs als nächstes mit etwas weniger C programmierung und ein wenig 
mehr Regelungstechnik? Fuzzy-Control? xP

von Thilo M. (Gast)


Lesenswert?

Klingt verlockend!
Nur muss ich das Ganze mal in Hardware verwirklichen, sprich meine 
Heizungsanlage aufrüsten. Dann kann ich das Teil in der Praxis Testen. 
Also ADC, evtl. DAC, SSR zur Mischersteuerung (Stellantriebe) und PT100 
Temperaturmessung sind als Einzelkomponenten getestet und werden jetzt 
'verheiratet'.
Dann gilt meine Aufmerksamkeit wieder der Regelungstechnik. ;)

von JÜrgen G. (Firma: 4CKnowLedge) (psicom) Benutzerseite


Lesenswert?

Thilo M. wrote:
> Nur muss ich das Ganze mal in Hardware verwirklichen, sprich meine
> Heizungsanlage aufrüsten. Dann kann ich das Teil in der Praxis Testen.
> Also ADC, evtl. DAC, SSR zur Mischersteuerung (Stellantriebe) und PT100
> Temperaturmessung sind als Einzelkomponenten getestet und werden jetzt
> 'verheiratet'.

Es gibt immer was zu tun xP

von Zumax (Gast)


Lesenswert?

Hallo zusammen, zwar ist der Thread schon etwas älter, jedoch denk ich 
das es trotzdem noch passendürfte.

Ich bin vor kurzem auf den oben aufgeführten C-Code des PID Reglers 
gestoßen und wollte ihn natürlich sofot mal testen, jedoch bekomm ich 
mit diesem Regler so konfiguriert wie oben beschrieben egal was ich für 
Soll und ISTwerte eintrage, immer als Stellgröße (y) 1023 raus bei 
positivem e ( ISTwert- Sollwert) und y=0 bei negativem e....

wenn ich jetzt z.B. als sollwert 600 und als istwert 400 eintrage
kommt als y immer 0 raus... vertausche ich diese zwei werte, kommt als y 
immer 1023 raus...

versteh nicht so ganz was ich falsch mache...

vielleicht weiß jemand Rat...

lg Thomas

von Karl H. (kbuchegg)


Lesenswert?

Zumax schrieb:

> versteh nicht so ganz was ich falsch mache...

Die Frage ist immer, was passiert bei einem Stellwert.
Wenn der Stellwert positiv ist und der Regelkreis so reagiert, dass 
dadurch die Istgröße abnimmt, dann passt ja alles. (bzw. umgekehrt)


Bsp. y sei ein Wasserventil
     0 bedeutet     ... komplett offen
     1023 bedeutet  ... komplett zu


Du gibst jetzt vor, dass die Durchflussmenge 600 l/min betragen soll.
Gemessen werden 400 l/min. Als Folge davon erredchnet der PID Regler 
einen y-Wert von 0. Also: Ventil volle Pulle auf.
Was in dem Fall ja auch Sinn ergibt.

von Zumax (Gast)


Lesenswert?

Vielen Dank Karl heinz Buchegger, für die absolut rasche Antwort,

soweit versteh ich das nun schon, da ja wie im Beispiel erklärt die 
Wassermenge erhöht werden muss wird das Ventil erst mal voll aufgedreht, 
damit erstmal mehr fließt, jedoch möchte ich den Fluß ja auf 600 l/min 
begrenzen und nicht mit 1023 l/min fahren, muss ich die Funktion im 
zweiten Durchlauf nachdem y=0 oder y=1023 nun erneut aufrufen und zwar 
nun mit dem istWert 1023 bzw 0 und dem Sollwert von 600?? Also die 
Funktion einfach nochmal bzw so lange aufrufen bis sich der Wert 
einpendelt??? Jedoch mit dem neu berechneten ISTWERT aber natürlich dem 
selben gewünschten SOLLWERT.
 Wenn dem so wäre, könnte ich ja nie sagen wie oft ich die Funktion 
aufrufen muss bis sich der Wert denn nun endlich schön eingependelt hat? 
dachte die Funktion macht dies schon automatisch, also die 
einpendelung..

Ich hoffe mal ich konnte das irgendwie halbwegs verständlich ausdrücken?

LG Thomas

von KNOC (Gast)


Lesenswert?

Hallo

Am 3.11.2007 wurde von JÜrgen G. geschrieben:

> - Den D-Anteil legt man (gerade bei digitalen Reglern) besser in die
> Rückkopplung. Damit änderst du nichts am dynamischen Verhalten des
> Systems, verhinderst aber den sog. Set-Point-Peak, der sonst immer
> entsteht, wenn sich der Sollwert schlagartig ändert (und das tut er in
> digitalen Systemen praktisch immer).

Mich würde das mit dem D-Anteil in der Rückkopplung genauer 
interessieren.
Wie muss da die Software dazu aussehen.

Danke,

von JÜrgen G. (Firma: 4CKnowLedge) (psicom) Benutzerseite


Lesenswert?

Das habe nicht ich geschrieben, aber ich kann mich wieder mal 
reinlesen... ich hab momentan mit Reglern soviel wie nichts zu tun...

von Stefan (Gast)


Lesenswert?

>Mich würde das mit dem D-Anteil in der Rückkopplung genauer
>interessieren.
Das würde mich auch mal interessieren. Hab schon danach geschaut aber 
nix darüber gefunden. Bin zwar keine Regelungstechnik-Guru, habe aber 
schon mit Reglern zu tun gehabt, aber das ist mir (wissentlich) noch 
nicht über den Weg gelaufen.
Das Einzige was ich mal versucht habe, ist ein PT1-Messglied in der 
Rückführung wegen der großen Verzögerung zu "kompensieren", was dann 
letzendes in einer "nicht-kausalen" PD-Rückkopplungskorrektur geendet 
hat, die nur Müll produzierte... hab's dann aber auch nicht 
weiterverfolgt...

von Patrick D. (oldbug) Benutzerseite


Lesenswert?

Zumax schrieb:
> [...]
>  Wenn dem so wäre, könnte ich ja nie sagen wie oft ich die Funktion
> aufrufen muss bis sich der Wert denn nun endlich schön eingependelt hat?
> dachte die Funktion macht dies schon automatisch, also die
> einpendelung..
>

...ist das mittlerweile klar geworden?

von hacker (Gast)


Lesenswert?

Hallo,

das mit dem D-Anteil in der Rückkopplung, der anscheinend bei digitalen 
Regelungen wichtig ist, würde mich auch brennend interessieren.

Entwerfe momentan ein Regler für eine Hydralik und da wäre es 
interessant, ob ich das mit einbeziehen muss.

Grüße,
hacker

von Peter B. (basejump)


Angehängte Dateien:

Lesenswert?

Hallo, ich hab mal eine Frage bezüglich der Parameter.

@ Thilo M.
Ich nutze die Standardwerte.

Wie kann ich die Überschwinger kompensieren?
Gibt es da eine Faustformel nach der man die Werte wählen kann?

Wenn ich den I Anteil auf null setze (ist doch dann nur noch ein 
PD-Regler) ändert sich nichts großartig.

(Die gelben Peaks sind nur Darstellungsfehler.)

von Thilo M. (Gast)


Lesenswert?

Nimm bei dieser schnell reagierenden Regelung mal den D-Anteil 'raus.
Dann mit P und I-Anteil experimentieren. Ich denke mal, die 
Überschwinger kommen vom D-Anteil.

von Peter B. (basejump)


Angehängte Dateien:

Lesenswert?

@ Thilo
Hat ein Weilchen gedauert, aber jetzt funktioniert es.

Hab etwas an den Werten gespielt und bei einem sehr niedrigen I-Anteil 
die besten Ergebnisse, ohne I -Anteil ist die Regelung nicht so schön 
schnell.

Vorher hatte ich auch eine 8 Bit PWM, das war bestimmt das größte 
Problem.
Jetzt ist es eine 14 Bit PWM.
(eigentlich nur eine aufgebohrte 8 Bit, der Wert springt also immer 
zwischen zwei Werten)

Die restlichen hochfrequenten Rippel bekomme ich mit einem LC-Tiefpass 
weg.

mfg Peter

von Thilo M. (Gast)


Lesenswert?

Freut mich dass es läuft! ;-)

von Hugo B. (stinkywinky)


Lesenswert?

Zurück zur Frage:
"das mit dem D-Anteil in der Rückkopplung..."

Da bei einem normalen PID-Regler der D-Anteil aus (Soll-Ist)*D berechnet 
wird, hat eine Änderung am Sollwert zwangsläufig eine sprunghafte 
Änderung am D-Anteil zur Folge.
Nicht jedoch, wenn man Ist*D vom Stellwert subtrahiert.

Diagramm:
http://i.cmpnet.com/embedded/gifs/2000/0010/0010feat3fig1.gif

Artikel in englisch:
http://www.embedded.com/2000/0010/0010feat3.htm

von Andreas (Gast)


Lesenswert?

Kann jemand bitte noch mal seinen aktuellen Source-Code für den PID 
Regler senden?
Gibt es eigentlich schon einen WIKI-Arikel zu PID-Reglern auf 
mikrocontroller.net?

von Thilo M. (Gast)


Lesenswert?

Bitteschön:
1
/**** Regler **************************************************/
2
3
double PID_Berechnung (double x, double w)
4
{    
5
e =w-x;                    // aktuelle Regelabweichung bestimmen
6
//--------------------------------------------------------------------------------------------------
7
  if ((e >= AS)||(e <= (AS*(-1))))        // Betrag der Differenz prüfen
8
  {
9
//--------------------------------------------------------------------------------------------------
10
  if ((y < 1023)&&(y > 0))            // bei Übersteuertem stellglied Integration einfrieren
11
    {                      // (Anti-Windup)
12
      esum = esum + e;            // Summe der Regelabweichung aktualisieren  
13
    }
14
//--------------------------------------------------------------------------------------------------   
15
    y = (Kp*e)+(I*Ta*esum)+(D*((e-ealt))/Ta);  // Reglergleichung 
16
                          // (I-Anteil bei der Initialisierung mit Abtastrate verrechnet)
17
    ealt = e;                  // Regelabweichung für nächste Abtastung merken
18
  }
19
//--------------------------------------------------------------------------------------------------
20
  if (y > 1023)                  // Stellgröße auf 0..1023 begrenzen (10 bit PWM)
21
    {
22
      y = 1023;
23
    }
24
  if (y < 1)
25
    {
26
      y = 0;
27
    }
28
//--------------------------------------------------------------------------------------------------
29
  return y;
30
}

e => Regelabweichung
w => Sollwert
x => Istwert
AS => Ansprechschwelle (Totband um den Sollwert)

von Julian W. (julian-w) Benutzerseite


Lesenswert?

@Peter Bandhauer:
Mit welchem Programm hasst du denn die schönen Graphen erstellt?
Sind das simulierte Werte oder sind die aus einer realen Messung 
entstanden?

von basejump (Gast)


Lesenswert?

Das sind reale Werte von einem StepUp Wandler.

Beim ersten Bild: Eingangs-Strom/Spannung , Ausgangs-Strom/Spannung und 
der aktuelle PWM-Wert.

Beim zweiten Bild ohne Strommessung, also Uin. Uout, PWM.
- mit 470 Ohm: von 9V -> 7V -> 10V

Jetzt habe ich noch 115 Ohm parallel geschaltet um zu testen wie weit 
die Spannung einbricht bei Lastwechsel.
10V @ 470 Ohm =>  21.3mA
10V @  92 Ohm => 108.7mA

Es fließt jetzt 5 mal so viel Strom und die Spannung bricht bis auf 9V 
ein.

Danach probiere ich noch 11V -> 12V -> 9V -> 6V  -> 12V
Man sieht schön wie sich der PWM-Wert (grau) verhält, die Kurve sieht 
optimal aus.
Ich habe dahinter ein LC Tiefpass, es kommen also keine Peaks am Ausgang 
an.

Ich habe in Java nur die Linienn in ein Panel gezeichnet und ein paar 
Slider um U-Soll und die P,I,D Werte an den Controller zu übertragen.

von Alex97 (Gast)


Lesenswert?

Hi,
ich hätte hier mal eine Frage zur Anti-WindUp-Maßnahme:
1
if ((y < 1023)&&(y > 0))            
2
    {                      
3
      esum = esum + e;            
4
    }
5
//...
6
//------------------------------
7
if (y > 1023)  
8
    {
9
      y = 1023;
10
    }
11
  if (y < 1)
12
    {
13
      y = 0;
14
    }
Kann es sein, dass diese nie ausgeführt wird?

Die Abfrage überprüft ob y größer oder kleiner als die Grenze ist.
Also ob y=1024 bis + unendlich oder -1 bis - unendlich ist?!
Aber durch die Begrenzung am Ende wird y mit minimal 0 oder maximal 1023 
überschrieben und kann demnach nie kleiner 0 oder größer 1023 sein 
oder?!

Also müsste die Abfrage für WindUp eigentlich so lauten:
1
if (y<=1023) && (y>=0)
2
{...}

Ich steh hier geraude auf dem Schlauch und hoffe Ihr könnt mir 
weiterhelfen.

von LinuxMint_User (Gast)


Lesenswert?

Alex97 schrieb:
> if (y<=1023) && (y>=0)

In dem Fall ist alles okay, er muss keinen Fehler abfangen ... also ist 
die Abfrage dann so wie du es geschrieben hast sinnlos.

von Horst H. (horha)


Lesenswert?

Hallo,

@Alex97:
Beim Anti-Windup geht es doch darum, das bei Vollaussteuerung der 
Stellgröße Y eine weitere Aufsummierung der Abweichung esum verhindert 
werden soll.
Wenn man nämlich länger im Bereich der Vollaussteuerung ist, wird der 
I-Anteil ständig weiter steigen und diese Summe muss später wieder 
abgebaut "werden", was nur geht, wenn die Regelabweichung e entsprechend 
lang negativ ist, was man ja nicht will.

Die Vollaussteuerung ist hier 0 oder 1023 für die 10-Bit PWM.
( Man hätte es vielleicht auf den Bereich [0..1] umrechnen können, das 
wäre anschaulicher, aber nicht praktischer. )
> if (y<=1023) && (y>=0)
führt aber dazu, dass immer aufsummiert wird, denn Y kann nur aus dem 
Bereich 0..1023 sein.
Dann ist der Anti-Windup Effekt weg.

Apropos Anti-Windup:
http://de.wikipedia.org/wiki/Regler suche Wind-Up-Effekt:
/Dem tritt man mit der Begrenzung des I-Anteils auf die 
Stellgrößen-Grenzen entgegen (Anti-Windup)./
Wenn ich das richtig lese, würde dort nicht
1
if ((y < 1023)&&(y > 0))            
2
    {                      
3
      esum = esum + e;            
4
    }
sondern dies ausgeführt:
1
// maximale Summe bei der alleine der Integralteil für Y= Y_max sorgt
2
esum_max = Y_max/(I*Ta ) // hier 1023
3
esum_min = Y_min/(I*Ta )   // hier 0
4
...
5
esum = esum + e;  
6
if (esum < esum_min) 
7
  { esum = esum_min;}
8
if (esum>esum_max)
9
    {esum =esum_max;}

von Sed (Gast)


Lesenswert?

Horst Hahn schrieb:
> // maximale Summe bei der alleine der Integralteil für Y= Y_max sorgt
>
> esum_max = Y_max/(I*Ta ) // hier 1023
>
> esum_min = Y_min/(I*Ta )   // hier 0
>
> esum = esum + e;
>
> if (esum < esum_min)
>
>   { esum = esum_min;}
>
> if (esum>esum_max)
>
>     {esum =esum_max;}
>
>
Hallo Horst,
ich programmiert derzeit eine digitale PID Regler und habe auch riesige 
problem mit der Anti windup. frühe habe wie die ander gemacht;
if ((y < 1023)&&(y > 0))
    {
      esum = esum + e;
    }
hat nie funktioniert.  nach ein paar Tage Recherche habe ich wie du 
umgestellt. es klappt ein bisschen aber nicht ganz und ich weiß nicht 
warum.
beim start des systems ist bei mir y schon initialisiert auf den soll 
oder einen wert nahe den soll. ich rechne e=x-w  und es kommt sofort e 
negativ, was normal ist. Nach dem ersten Durchlauf ist e negativ bzw. 
esum
entspricht diesem Fall bei dir

if (esum < esum_min)
>
>   { esum = esum_min;}

z.B meine ymax=1000
           ymin=800.

soll ich esum_min auf 0 oder 800 begrenzenn oder wie ?  oder hat es mit 
negative Werte zu tun? wie kann man das proble lösen

danke
Sed



> Beitrag melden | Bearbeiten | Löschen |

von Horst H. (horha)


Lesenswert?

Hallo,

hast Du Deine Regelstrecke mit den "richtigen" Werten für K_I,K_P und 
K_D bestückt?
http://de.wikipedia.org/wiki/Faustformelverfahren_(Automatisierungstechnik)
Anti Wind-up erstmal weglassen.
Taste Dich doch zuerst mit K_i = K_D = 0 an den passenden K_p(P) Wert.
Zitat:
P   K_p = 1/K_s \cdot T/T_t
PI   K_p = 0.9/K_s \cdot T/T_t, T_n = 3.33 \cdot T_t
PID   K_p = 1.2/K_s \cdot T/T_t, T_n = 2 \cdot T_t, T_v = 0.5 \cdot T_t
/Zitat

Oder stelle, falls möglich, als Wunschwert 0,5 des Bereiches ein und 
drehe K_p(Test) von 0 langsam solange hoch, bis es schwingt dann ist 
K_p(P) = 0,5*K_p(Test).

Dann K_p(PI) auf 0,9*K_p(P) und passenden K_i(PI) suchen
Dann K_p(PID) wieder auf 1,2* K_p(P) und K_i(PID) auf 2/3*K_i(PI) und 
K_d bestimmen.

Lange Rede, wenig Sinn, ich schätze Dein K_i ist zu groß.

HALT :
Du solltest, wenn Du den Sollwert vorgibst "esum" so berechnen, das er 
diesem entspricht.
Denn man muss sich klar machen, dass bei einem PI(D)- Regler im 
störungsfreiem, eingeregeltem Zustand des Reglers ist e=ealt = 0.
Also nur der I-Anteil bestimmt die Stellgröße Y.
1
 y = (Kp*e)+(I*Ta*esum)+(D*((e-ealt))/Ta);  // Reglergleichung
wird zu
1
 y = 0+(I*Ta*esum)+0;  // Reglergleichung
also müßtest Du zu Beginn
esum = Y(geschätzt)/(I*Ta); setzen.

Y_min,max bleiben gleich, sodass der komplette Stellgrößenbereich auch 
genutzt werden kann.
Aber warum gibst Du Y(w) schon vor?
Der Regler sollte doch, wenn die Regelabweichung sehr gross ist, auch 
mit Y_max oder Y_min möglichst schnell den neuen Zustand erreichen 
können und nicht nur mit einem kleineren Wert.


P.S.
1
if ((y < 1023)&&(y > 0))  // bei Übersteuertem stellglied Integration einfrieren

Halte ich für einleuchtender, dass das schneller einschwingt.
Das müsste man mal testen.
Aber ich bin der Meinung, das es so sicherer ist,esum anschaulicher 
durch y_i ersetzt und innen y_i zu begrenzen.
Das könnte Dir auch aufzeigen, das bei Dir der I-Anteil zu groß war, 
oder die Berechung von e falsch skalierte.
Deshalb alles auf 0..1 rechnen.
1
[c]const
2
  double y_min = 0;
3
  double y_max = 1023;//(10 bit PWM)
4
  double x_min =0;
5
  double x_max =255; //z.B 8_Bit ADC 
6
  double Ta = ???;
7
  double Kp = ????;
8
  double Ki = ????*Ta;
9
  double Kd = ????/Ta;
10
  
11
// w und x so umrechnen das sie aus dem Bereich 0..1  sind
12
//Spannung von 0..12 wird eben 0..100% von 12 Volt
13
double PID_Berechnung (double x, double w)
14
{    
15
e = w - x;                // aktuelle Regelabweichung bestimmen
16
if ((y < 1)&&(y > 0))  // bei Übersteuertem stellglied Integration einfrieren
17
  {                       // (Anti-Windup)
18
    y_i = y_i + Ki*e;   // Summe der Regelabweichung aktualisieren  
19
  }
20
y = Kp*e+Y_i+ kd*(e-ealt);  // Reglergleichung
21
ealt = e;                 // Regelabweichung für nächste Abtastung merken
22
if (y > 1)            // Stellgröße auf y_min..y_max begrenzen (10 bit PWM)
23
  {
24
    y = 1;
25
  }
26
if (y < 0)
27
  {
28
    y = 0;
29
  }
30
return y;                 // Stellgröße zurückgeben aus 0..1
31
32
....
33
//IstWert,SollWert  aus [0..1] 
34
Stellgröße= PID_Berechnung (IstWert,SollWert)*(y_max-y_min)+y_min;
35
36
}

von Pboy (Gast)


Lesenswert?

Wow ...

Da wollte ich nur einen Lüfter auf Drehzahl halten, laß was von PID, und 
dann dieser ganze Stoff hier kopf qualm.

Jungs (Mädels ;)) - Ihr seid meine Götter !!
Werde mal schauen, ob ich Eure Informationen in einen (halbwegs) 
lauffähigen Basic-Code (wie man so lesen kann, recht lahmer µC) 
umgesetzt bekomme.

Ich erhoffe mir, daß ich mit Euren Code-Beispielen mein Ziel erreiche - 
suchte nach 'Pseudo Code'/'Pseudo Basic'.

Werde mich, nach Hilfe schreiend g (stellt Euch ein schreiendes Pla 
.... äh, Kleinkind gg vor) bestimmt noch Mal an Euch wenden.

Super, daß es Leuz wie Euch gibt

MtR (mit tierischem Respekt)
Pboy

von Fohnbit (Gast)


Lesenswert?

Hallo,

welche Werte sollte man für eine Stellgröße-Ausgabe für eine Heizung 
machen?
Und in welchen Zyklus soll berechnet werden?

Vor allem Fussbodenheizungen und Wandkollektoren kommen immer zum 
Einsatz.

Der PID Regler soll das Ventil regeln, welches am Heizkörper montiert 
ist.
Ich hab mal etwas getestet, aber er gibt anfangs (wenn Ist 2° unter 
Soll) 3% aus und dann kontinuirlich 100%
Auch wenn die Ist weit über der Soll liegt.

Für Hilfe wäre ich dankbar,

Fohnbit

von Horst H. (horha)


Lesenswert?

Hallo,

Fußbodenheizung ist doch viel zu träge, als dass dort P-Regler, 
geschweige denn PID Regler Sinn machen.
Ich schätze/rate mal die Zeitkonstante.
Das Badezimmer hat 11 qm.
8,5 qm sind beheizt. Der Zementestrich ist 7 cm stark+ 1 cm Fliesen also 
0,08 m.
Das ganze wiegt wohl 8,5*0,08*1900 ~ 1300 kg.
http://www.schweizer-fn.de/stoff/wkapazitaet/v2_wkapazitaet_baustoffe.htm
Spezifische Wärmekapazität = 1 Kj/kgK
Also muss man 1300 KJ an Wärmeenergie in den Heizestrich einbringen, 
damit dieser sich bequemt, 1 Grad wärmer zu werden.
Jetzt brauche ich bei -14 Grad aussen im Bad maximal 720 Watt ( mit 
allen Aufschlägen für Lüftung/Wärmebrücken..).
Entsprechend ist der maximale Durchfluss eingestellt.
Die Aufheizzeit für 1 Grad ohne Wärmeabgabe wäre schon 1300 [KJ/K] / 720 
[W=J/s] /1 [K] = 1805 [s] = 30 min
Jetzt sind noch Wände (37 qm )und Decke( Ok.Abgehängt. Rigips mit 
Schalldämmung obenauf )  im Bad die auch Wärme aufnehmen. Also dauert es 
noch länger.Denn die müssen ja um 0.5 Grad wärmer werden.(1 Grad auf der 
Innenseite und 0 auf der Aussenseite)
Also c~880 J/kgK und rho etwa 1600 kg/cbm und 17,5 cm stark 
(KS-Vollstein)
ergibt: 880*37*1600*0,175 J/K = 9000 Kj/K bei 0,5 Grad eben 4500 KJ
Also um die Wände aufzuheizen auch eine ewige Zeit von fast 60 min.
Wenn man das vereinfacht abschnittweise betrachtet wird erst der Boden 
warm und dann die Wände.Nach 1,5 Stunden merkt man was.

Das lohnt sich eine PID Regelung nicht. Die Aussentemperatutren ändern 
sich ja schneller ;-)

Die Raumthermostate haben eine Hysterese/Schaltabstand zwischen ein und 
aus von 0,5 Grad.
Die Schaltventile/Stellantriebe bewegen sich in 3min Sekunden von auf 
nach zu, das ist doch schnell genug.

von Thilo M. (Gast)


Lesenswert?

Horst Hahn schrieb:
> Das lohnt sich eine PID Regelung nicht. Die Aussentemperatutren ändern
>
> sich ja schneller ;-)

So ist es.
Und es gilt zu beachten, dass die Stellzeit des Ventils einen I-Anteil 
darstellt. Folglich braucht man einen Dreipunkt-Schrittregler für so ein 
träges System mit Stellantrieb, um einen PI-Regler zu realisieren 
(I-Anteil kann zusätzlich zu dem des Stellantriebes addiert werden, 
falls nötig).

In meinen Heizkreisreglern ist die Außentemperatur stark (3 Minuten) 
gedämpft, der Regler macht Impulse zwischen 0.8s und 4s, Pausen- und 
Impulslänge hängen von der Regelabweichung und der Verstärkung ab.
Eine Ansprechschwelle von mindestens +/- 0.5°C um den Sollwert macht das 
System ruhiger (weniger Regelsteps).

von Horst H. (horha)


Lesenswert?

Hallo,

und durch diese Impulse wird aus dem Auf/Zu-Stellantrieb ein 
kontinuirlicher?
Das sieht man man sicher am Durchflußmesser.
Das eigentliche Problem was ich dann hätte, wäre die Überlagerung der 
Heizkurve.
Ich müsste ja dann jede Vor und Rücklauftemperatur messen, um mit der 
Raum- und Außentemperatur zusammen den optimalen Durchfluß einzustellen.

Momentan habe ich nur die Heizkurve eingestellt und die alle Ventile 
voll auf.
Ausser bei starken Temperaturwechseln funktioniert das sehr gut ( dann 
habe ich plötzlich 21.0/ 19,5 statt 20.3 ) , vielleicht auch deshalb, 
weil die Südseite bis Anfang März völlig verschattet und die Sonne in 
der Heizperiode kaum eine Rolle spielt und natürlich die enormen 
Wandmassen.
Ein Bekannter mit Euromac?-Haus (Styropor Schalensteine mit Beton 
verfüllt ) hat alle Wandinnenseiten 50 mm Styropor mit Gipskarton 
verkleidet, der bekommt seine Fussbodenheizung nicht in den Griff.Wenn 
ein paar Leute kommen wird es direkt warm.
Er braucht für sein komplettes Haus 100 W/K , wie soll man das noch 
regeln, wenn pro Person 100 W hinzukommen, die sich meistens in der 
Küche aufhalten?

von Thilo M. (Gast)


Lesenswert?

Horst Hahn schrieb:
> Ich müsste ja dann jede Vor und Rücklauftemperatur messen, um mit der
> Raum- und Außentemperatur zusammen den optimalen Durchfluß einzustellen.

Naja, an einer modernen Heizung musst du normalerweise gar nicht am 
Thermostatventil eingreifen. Wenn der hydraulische Abgleich (jeder 
Heizkörper im Durchfluss so eingestellt, dass auch ohne 
Thermostatventilkopf der Rücklauf nicht wärmer als der Rücklauf +1..2°C 
wird) ordentlich gemacht ist, kann mit dem Heikreisvorlaufmischer (an 
der Heizung) mittels Außentemperaturkennlinie der gesamte Vorlauf 
geregelt werden. Dann braucht's nur eine Regelung.

Horst Hahn schrieb:
> Ein Bekannter mit Euromac?-Haus (Styropor Schalensteine mit Beton
> verfüllt ) hat alle Wandinnenseiten 50 mm Styropor mit Gipskarton
> verkleidet, der bekommt seine Fussbodenheizung nicht in den Griff.Wenn
> ein paar Leute kommen wird es direkt warm.

Naja, Styropor ist suboptimal als Dämmung, weil nicht diffusionsoffen. 
Heute nach EnEV auch als Dämmung nicht mehr erlaubt.

Wenn die Fußbodenheizung sich nicht regeln lässt gibt es mehrere Gründe.
Zum Einen kann sie überdimensioniert sein, oder die einzelnen Schleifen 
schlecht oder gar nicht hydraulisch abgeglichen.
Zum Anderen kann die Heizung zu heißes Wasser zum Vorlauf bringen, der 
Effekt ist dann, dass das Stellglied in einem extrem ungünstigen Bereich 
regeln soll (Zu / fast Zu).
Darum ist ein Pufferspeicher, der nicht höher als 40°C aufgeladen wird 
für eine Fußbodenheizung ideal. Ein Öl/Gasbrenner, der vllt. noch 
überdimensioniert ist, läuft extrem unwirtschaftlich (ständig an-aus) 
und die Regelung kriegt das heiße Wasser im Zulauf nicht in den Griff.

Horst Hahn schrieb:
> Er braucht für sein komplettes Haus 100 W/K , wie soll man das noch
> regeln, wenn pro Person 100 W hinzukommen, die sich meistens in der
> Küche aufhalten?

Ein solches Haus braucht eine kontrollierte Wohnraumlüftung, sonst 
kriegt man da weder die Temperatur noch den Schimmel in den Griff.

von Wladimir N. (Firma: electronick.de) (wnickel)


Lesenswert?

Hallo.

Der oben beschriebene Regler funktioniert sehr schön, sobald man ihn mit 
vernünftigen Werten für P, I und D versorgt. Diese werte sind in dem 
vorliegenden Fall aber nur Bits, virtuell. Wie komme ich jetz zu 
SI-Einheiten?

Ich will einen universellen, flexiblen Regler bauen, der die Werte Kp, 
Tv und Tn von außen (UART) bekommt. Gewünscht ist, dass ich bei einer 
unbekannten Strecke das 2. Verfahren von Ziegler und Nichols anwenden 
kann. Also I und D auf 0, P hochdrehen bis es schwingt, Periode messen 
und aus der Periode Tn und Tv einstellen (Kp = 0.6 * Kpkrit, Tn = 0.5 * 
Tkrit, Tv = 0,125 * Tkrit).

Meine Überlegungen vorab:
1. Die Samplingrate muss genau sein und in die Formel eingehen (ist hier 
bereits).
2. Tn (was hier I entspricht) muss unter den Bruchstrich, wie in der 
normalen PID-Regler-Formel. Also höhere Werte für Tn sollen den I-Anteil 
des Reglers kleiner werden lassen.

Dan würde die Formel so aussehen:
y = (Kp*e)+((Ta*esum)/I)+(D*((e-ealt))/Ta);

Was meint Ihr dazu?

von tetst (Gast)


Lesenswert?

Die Regler-Parameter sind Faktoren und haben mit dem SI nichts zu tun.
Wenn du deinen Regler mit Floating Point betreibst, kannst du in Grenzen 
der Auflösung dieses Typs deine Größen als SI benutzen und musst dann 
beim Einlesen und Ausgeben entsprechend umrechnen.

von Michael Knight (Gast)


Lesenswert?

Ich habe da mal eine kleine Frage zur Implementierung des Totbandes und 
der Ansprechschwelle.
Weiter oben in den Beispielen ist diese Funktion immer vor der 
eigentlichen Berechnung gemacht worden. Nun ist es ja so das bei Reglern 
allgemein und vor allem mit I und D Anteil die Intervalle der 
Reglerfunktionsaufrufe sehr genau eingehalten werden sollten. Durch die 
Implementierung der Ansprechschwelle vor dem Regelalgorithmus ist dies 
jedoch nicht mehr gegeben, was die Regelqualität negativ beeinflusst. 
Weiterhin wird der Regler innerhalb des Totbandes komplett deaktiviert.
Ich würde die Schwellbegrenzung eher nach der Berechnung machen.
Was meint ihr dazu oder seh ich da jetzt was grundlegendes falsch?

von Thilo M. (Gast)


Lesenswert?

Michael Knight schrieb:
> Nun ist es ja so das bei Reglern
> allgemein und vor allem mit I und D Anteil die Intervalle der
> Reglerfunktionsaufrufe sehr genau eingehalten werden sollten.

Das stimmt, der Intervall sollte interruptgesteuert aufgerufen werden, 
damit die zeitlichen Abläufe stimmen.

> Durch die
> Implementierung der Ansprechschwelle vor dem Regelalgorithmus ist dies
> jedoch nicht mehr gegeben, was die Regelqualität negativ beeinflusst.

Da der Regler innerhalb des Totbandes deaktiviert ist, findet keine 
Regelaktivität statt. Also muss auch der Intervall nicht stattfinden.
Die Ansprechschwelle dient zum Ein- bzw. Ausschalten des Reglers. Die 
Größe der Ansprechschwelle beeinflusst selbstverständlich den P-, I- und 
D-Anteil, da bei überschreiten der Ansprechschwelle die Regelabweichung 
von der Größe der Ansprechschwelle abhängt.

von Gunnar (Gast)


Lesenswert?

Hallo Thomas,

du hast geschrieben (2. Eintrag), dass man den D-Anteil lieber in die 
Ausgangsrückführung steckt um den großen Sprung der Regelgröe zu 
vermeiden. Braucht man dann bei diesem Verfahren also kein 
Verzögerungsglied mehr?
Grüße, Gunnar

von kwasposer k. (kwasposer_k)


Lesenswert?

Hallo Thomas,

du hast geschrieben (2. Eintrag), dass man den D-Anteil lieber in die
Ausgangsrückführung steckt um den großen Sprung der Regelgröe zu
vermeiden. Braucht man dann bei diesem Verfahren also kein
Verzögerungsglied mehr?
Grüße, Gunnar

von Tanja (Gast)


Lesenswert?

Hallo Leute!

Das Thema scheint zwar tot zu sein, aber ich versuche es dennoch mal.
Ich bin ganz neu hier und hab direkt eine Frage.
Ich muss für die Hochschule einen PI-Regler in C schreiben. Das Ziel ist 
es einen Spannung zu Regeln und zwar darf dieser nicht mehr als 2,5V 
betragen.
ICh habe den Code von Thilo M. benutzt, hab mein PWM Signal konfiguriert 
usw. aber die myAVR Workpad Sofware wirf jede menge Fehler.
Ich hab schon mal uC programmiert, leider ist das aber etwas her und 
mein C ist estwas eingerostet... Ich hoffe ihr erschlagt mich nicht 
gleich... =)
Also hier erstmal der Code (hab den D-Anteil raukommentiert, da ich nur 
einen PI-Regler benötige):

//----------------------------------------------------------------------
// Titel     : C Grundgerüst für das myAVR-Board
//----------------------------------------------------------------------
// Funktion  : ...
// Schaltung : ...
//----------------------------------------------------------------------
// Prozessor : ...
// Takt     : 3.6864 MHz
// Sprache   : C
// Datum     : ...
// Version   : ...
// Autor     : ...
//----------------------------------------------------------------------
#define   F_CPU 3686400  // Taktferquenz des myAVR-Boards
#include  <avr\io.h>    // AVR Register und Konstantendefinitionen
#include   <stdint.h>

typedef struct
{
  int Ta;                      // Abtastzeit in ms
  int I;                      // Integralanteil
  int Kp;                      // Verstärkung
//  int D;                      // Differenzieller Anteil
  int e;                      // Regelabweichung
  float esum;                    // Summe der Regelabweichungen
  int ealt;                    // Regelabweichung zum ZP z-1
  int y;
  int AS;                     // Ansprechschwelle
}

void main(void)
{
  PID_Init();

  int Ausgang, w,x;

  timer_init();

    OCR1A = 0x0000;

  while(1)
  {
    PID_Cyclic(x,w,&Regler1);       // Parameter für Regler1 übergeben
  }
}

//---------------------------------------------------------------------- 
-----
void timer_init(void)
{
  DDRB = (1 << PB1 );
  TCCR1A = (1<<COM1A1) | (1<<WGM11)| (1<<WGM10);
  TCCR1B = (1<<WGM13) | (1<<WGM12) | (1<<CS10);
//    ICR1 = 0x0003;
}

//---------------------------------------------------------------------- 
-----
void PID_Init(void)                  // In der Init müssen die 
Reglereinstellungen gemacht werden
{
  Regler1.AS=1;
  Regler1.y=0;
  Regler1.Ta=10;
  Regler1.I=100;
//  Regler1.D=0;
  Regler1.Kp=1;
  Regler1.esum=0;
  Regler1.e=0;                  // Für weiteren Regler einfach Neue 
Variable erstellen
  Regler1.ealt=0;                  // und hier Werte mit Regler2.xx=0 
einstellen
}

//---------------------------------------------------------------------- 
-----
double PID_Berechnung (double x, double w)
{
e =w-x;                    // aktuelle Regelabweichung bestimmen
  if ((e >= AS)||(e <= (AS*(-1))))        // Betrag der Differenz prüfen
  {
  if ((y < 1023)&&(y > 0))            // bei Übersteuertem stellglied 
Integration einfrieren
    {                      // (Anti-Windup)
      esum = esum + e;            // Summe der Regelabweichung 
aktualisieren
    }
    y = (Kp*e)+(I*Ta*esum); //+(D*((e-ealt))/Ta);  // Reglergleichung
                          // (I-Anteil bei der Initialisierung mit 
Abtastrate verrechnet)
    ealt = e;                  // Regelabweichung für nächste Abtastung 
merken
  }
  if (y > 1023)                  // Stellgröße auf 0..1023 begrenzen (10 
bit PWM)
    {
      y = 1023;
    }
  if (y < 1)
    {
      y = 0;
    }
  return y;
}



Und das sind die dazugehörigen Fehlermeldungen....:

piRegler.cc:31  31: error: new types may not be defined in a return type
 31: note: (perhaps a semicolon is missing after the definition of '')
 31: error: two or more data types in declaration of 'main'
 31: error: invalid function declaration
piRegler.cc  In function 'void PID_Init()':
piRegler.cc:59  59: error: 'Regler1' was not declared in this scope
piRegler.cc  In function 'double PID_Berechnung(double, double)':
piRegler.cc:73  73: error: 'e' was not declared in this scope
piRegler.cc:74  74: error: 'AS' was not declared in this scope
piRegler.cc:76  76: error: 'y' was not declared in this scope
piRegler.cc:78  78: error: 'esum' was not declared in this scope
piRegler.cc:80  80: error: 'y' was not declared in this scope
 80: error: 'Kp' was not declared in this scope
 80: error: 'I' was not declared in this scope
 80: error: 'Ta' was not declared in this scope
 80: error: 'esum' was not declared in this scope
piRegler.cc:82  82: error: 'ealt' was not declared in this scope
piRegler.cc:84  84: error: 'y' was not declared in this scope
piRegler.cc:88  88: error: 'y' was not declared in this scope
piRegler.cc:92  92: error: 'y' was not declared in this scope


Danke schon mal viel mals für eure Hilfe!

Liebe Grüße
Tanja

von Jan D. (nbg)


Lesenswert?

Du hast deinem typedef keinen Namen gegeben, versuch es mal so:
1
typedef struct
2
{
3
  int Ta;                      // Abtastzeit in ms
4
  int I;                      // Integralanteil
5
  int Kp;                      // Verstärkung
6
//  int D;                      // Differenzieller Anteil
7
  int e;                      // Regelabweichung
8
  float esum;                    // Summe der Regelabweichungen
9
  int ealt;                    // Regelabweichung zum ZP z-1
10
  int y;
11
  int AS;                     // Ansprechschwelle
12
} PI_Regler_t;
13
14
PI_Regler_t Regler1;
15
16
void main(void) ...

Jan

von Tanja (Gast)


Lesenswert?

Hallo Jan!

Danke für die schnelle Antwort! Dadurch sind ein paar Fehlermeldungen 
weniger geworden! Dennoch sind immernoch haufenweise "'xyz' was not 
declared in this scope" errors da...
Also der hat mit diesem Teil noch Probleme:


int main()
{
  PID_Init();

  int Ausgang, w,x;

  timer_init();

  OCR1A = 0x0000;

  while(1)
  {
    //******Hier gibts Probleme******
    PID_Cyclic(x,w,&Regler1);       // Parameter für Regler1 übergeben
  }
}


//*******Er kennt die ganzen Variablen nicht, obwohl die doch in Regler1 
definiert wurden, allerdings kommt der wohl gar nicht dahin, da der 
schon Probleme mit "PID_Cyclic(x,w,&Regler1);" hat....

double PID_Berechnung (double x, double w)
{
e = w - x;                    // aktuelle Regelabweichung bestimmen
  if ((e >= AS)||(e <= (AS*(-1))))        // Betrag der Differenz prüfen
  {
  if ((y < 1023)&&(y > 0))            // bei Übersteuertem stellglied 
Integration einfrieren
    {                      // (Anti-Windup)
      esum = esum + e;            // Summe der Regelabweichung 
aktualisieren
    }
    y = (Kp*e)+(I*Ta*esum); //+(D*((e-ealt))/Ta);  // Reglergleichung
                          // (I-Anteil bei der Initialisierung mit 
Abtastrate verrechnet)
    ealt = e;                  // Regelabweichung für nächste Abtastung 
merken
  }
  if (y > 1023)                  // Stellgröße auf 0..1023 begrenzen (10 
bit PWM)
    {
      y = 1023;
    }
  if (y < 1)
    {
      y = 0;
    }
  return y;
}


Die Fehlermeldungen sind nun so:

piRegler.cc  In function 'int main()':
piRegler.cc:71  71: error: 'PID_Cyclic' was not declared in this scope
piRegler.cc  In function 'double PID_Berechnung(double, double)':
piRegler.cc:77  77: error: 'e' was not declared in this scope
piRegler.cc:78  78: error: 'AS' was not declared in this scope
piRegler.cc:80  80: error: 'y' was not declared in this scope
piRegler.cc:82  82: error: 'esum' was not declared in this scope
piRegler.cc:84  84: error: 'y' was not declared in this scope
 84: error: 'Kp' was not declared in this scope
 84: error: 'I' was not declared in this scope
 84: error: 'Ta' was not declared in this scope
 84: error: 'esum' was not declared in this scope
piRegler.cc:86  86: error: 'ealt' was not declared in this scope
piRegler.cc:88  88: error: 'y' was not declared in this scope
piRegler.cc:92  92: error: 'y' was not declared in this scope
piRegler.cc:96  96: error: 'y' was not declared in this scope


Danke nochmals für jegliche Hilfe!

Liebe Grüße
Tanja

von Udo S. (urschmitt)


Lesenswert?

Also wenn ich mir das so anschaue, dann würde ich mal sagen:
Deine C Kenntnisse sind nicht eingerostet, denn nichts kann nicht 
rosten.

Sorry aber programmieren heisst nicht irgendwo Code abschreiben und das 
Ergebnis incl. Compilerfehler sich in einem Forum lauffähig machen 
lassen.
Auch nicht zu Guttenbergs Zeiten.

meine Meinung!

von Jan D. (nbg)


Lesenswert?

Tag,

das Problem ist das du keine Funktion mit dem Namen PID_Cyclic() hast. 
Deine nennt sich PID_Berechnung(). Du kannst deine Funktion einfach 
durch die PID_Cyclic() aus diesem Beitrag ersetzen: 
Beitrag "Re: PID-Regler mit anti-Windup"

Da musst du noch im Funktionskopf "PID_Einstellung*" durch 
"PI_Regler_t*" ersetzen.

Jan

von Tanja (Gast)


Lesenswert?

Zur Kenntniss genommen Herr Udo Schmitt.
Wenn Sie mir nicht helfen okay.

Kann mir sonst jemand vll weiterhelfen?

Liebe Grüße
Tanja

von Tanja (Gast)


Lesenswert?

Hallo Jan!

Danke dir, werds probieren und dann bescheid sagen!

Liebe Grüße
Tanja

von Tanja (Gast)


Lesenswert?

Also, letzte Fehlermeldung:

piRegler.cc:63  63: error: 'AS' was not declared in this scope

Dabei hab ich doch schon AS in der PID_Init() deklariert...

Liebe Grüße
Tanja

von Jan D. (nbg)


Lesenswert?

Muss heißen "PID->AS"

von Tanja (Gast)


Lesenswert?

if ((PID -> e >= AS) || (PID -> e) <= (AS * (-1)))

Ähm das versteh ich grad nicht so richtig... Ich verwende die 
Ansprechwelle ja nur da in der if-Abfrage. Muss ich die davor noch wie 
aktuelle Regelabweichung (PID -> e = w - x;) bestimmen?

Vielen vielen Dank nochmals Jan!

Liebe Grüße
Tanja

von Udo S. (urschmitt)


Lesenswert?


von Frank B. (f-baer)


Lesenswert?

Vielleicht ist das nur ein Denkfehler, aber:
1
if ((y < 1)&&(y > 0))  // bei Übersteuertem stellglied Integration einfrieren
2
  {                       // (Anti-Windup)
3
    esum = esum + Ki*e;   // Summe der Regelabweichung aktualisieren  
4
  }

Das ist für Ant-Windup ganz nett, sorgt aber dafür, dass der Regler sich 
nicht beruhigt. Im Endeffekt vergrößert das den Fehler, den das I-Glied 
doch gerade ausgleichen soll.
Für negative y muss meiner Meinung nach daher trotzdem eine Addition 
durchgeführt werden. Sonst läuft der Regler weg, weil esum zwangsläufig 
groß wird.

Beispiel:

Soll: 5000
Ist: 2000

e=3000, esum=3000.

Nächster Schritt:
e=1000, esum=4000.

soweit so klar, bei e=0 nehmen wir esum=5500 an.
Jetzt kommt folgendes Problem: Der Regler erreicht Soll und esum wird 
nicht abgebaut. Sobald ein Schwinger nach unten kommt, hämmert der 
Regler den vollen I-Anteil auf das Stellglied, die Strecke beginnt zu 
schwingen. Und noch dazu ist esum jetzt noch etwas größer. Nach einigen 
Schwingern ist esum bei 100000 angekommen und findet damit immernoch 
kein Ende.
Der Regler wird mit zunehmender Zeit immer instabiler, weil sich das 
normale Einschwingen zu Beginn des Regelvorganges zu einem heftigen 
Überschwingen mausert.
Sollte sich der Regler mit der Zeit, zum Beispiel durch geänderte 
Sollvorgaben wider Erwarten dennoch stabilisieren, wird eine erhebliche 
Sollwertabweichung vorliegen, weil e groß bleibt.
Demzufolge muss(!) eine negative Regelabweichung (also Ist>Soll) von 
esum abgezogen werden.

Zusammengefasst: e muss trotz gesättigtem Stellglied kleiner werden 
können.
Ich konnte diese Effekte alle nachweisen und frage mich ehrlich gesagt, 
wie eure Regler mit diesem Algorithmus stabil sein können. Der Fehler 
zieht sich ja durch jedes Posting hier.
Die Bedingung fürs Anti-Windup muss jedenfalls lauten:
1
if ((y < 1)&&(esum > 0))
2
   esum+=e;

Die Prüfung auf esum ist notwendig, weil sonst esum tief ins negative 
abdriften kann und damit wieder Windup (Wind-Down) auftritt. Damit wird 
der Reglerausgang dann auch wirklich zu Null, wenn keine 
Sollwertabweichung mehr vorhanden ist. Das ist mit den vorher gezeigten 
Algorithmen nicht stabil möglich, weil die Drift des Reglers 
positiv-lastig ist.

Korrigiert mich, wenn ich damit total falsch liege.

von Davis (Gast)


Lesenswert?

> Die Bedingung fürs Anti-Windup muss jedenfalls lauten:

> if ((y < 1)&&(esum > 0))
   esum+=e;
>

So steht es auch im Orginalbeitrag:
1
 esum = esum + e;      // Summe der Regelabweichung aktualisieren

von Frank B. (f-baer)


Lesenswert?

Davis schrieb:
>> Die Bedingung fürs Anti-Windup muss jedenfalls lauten:
>
>> if ((y < 1)&&(esum > 0))
>    esum+=e;
>>
>
> So steht es auch im Orginalbeitrag:
>
>
1
>  esum = esum + e;      // Summe der Regelabweichung aktualisieren
2
>

Bitte lesen!
Es geht um die Bedingung für die Summation, nicht um die Summation 
selbst.
Im Originalbeitrag steht
1
 if(y>1023 && y<0)
und das sorgt dafür, dass der Regler aufschwingt.

von Martin Klein (Gast)


Lesenswert?

Ich kann die Ausführungen von Frank leider nicht nachvollziehen.

>Nach einigen Schwingern ist esum bei 100000 angekommen und findet damit immernoch 
>kein Ende.
Wenn dein esum 100000 erreichen kann ist dein I möglicherweise bei 0,01 
eingestellt, was ein durchaus normaler Wert sein kann. Bei einem I von 
0,01 könnte esum aber maximal 1023/0,01=102300 erreichen da es 
anschließend in der Reglergleichung zu einem Y von 1023 wird.

>...nehmen wir esum=5500 an. Jetzt kommt folgendes Problem: Der Regler erreicht
>Soll und esum wird nicht abgebaut.
Richtig das ist der Plan. Bei Ist=Soll muss der Integralanteil die 
Störgröße ausgleichen weil der Proportionalanteil per Definition 0 ist.

>Sobald ein Schwinger nach unten kommt, hämmert der Regler den vollen I-Anteil
>auf das Stellglied, die Strecke beginnt zu schwingen.
Ein esum von 5500 wird in der Reglergleichung nun mit I multipliziert zu 
55. Bei einem Bereich von 0-1023 hämmert da nix, um bei deinen Worten zu 
bleiben denn das I-Anteil wirkt ja schon die ganze Zeit auf den 
Reglerausgang.

>Die Prüfung auf esum ist notwendig, weil sonst esum tief ins negative
>abdriften kann und damit wieder Windup (Wind-Down) auftritt.
Warum willst du keinen Negativen Integralanteil? Der Proportional und 
der Differentialanteil können auch negativ werden.

>Demzufolge muss(!) eine negative Regelabweichung (also Ist>Soll) von
>esum abgezogen werden.
Richtig, deshalb müsste die Prüfung auf (esum>0) auch falsch sein.

>Damit wird der Reglerausgang dann auch wirklich zu Null, wenn keine
>Sollwertabweichung mehr vorhanden ist.
Wie Bitte? Das ist normalerweise nicht die Aufgabe eines stetigen 
Reglers, kommt aber vor wenn die Störgröße 0 wird und führt 
Beispielsweise bei einem Computernetzteil ohne Last zu einer netten 
Rauchwolke :)

Letzen Endes wird esum doch durch die Prüfung der Regelgrenzen und der 
Sollwertabweichung begrenzt. Ist der Reglerausgang bei 0 oder der x <= w 
wird esum nicht mehr kleiner. Ist der Reglerausgang bei 1023 oder der x 
=> w wird esum nicht mehr größer. Reglerschwingungen werden 
normalerweise nur durch falsche Parameter verursacht. Ein reiner 
I-Regler ohne Proportionalanteil schwingt Prinzipbedingt immer.

Möglicherweise liegst du Richtig und alle anderen liegen Falsch oder du 
hast dein Problem nicht verständlich machen können. Nimm einfach die 
anti-Windup Prüfung raus und führe "esum = esum + e" ungeprüft aus, wenn 
dein Regler immer noch Aufschwingt liegt es an den Parametern. 
Anti-Windup soll aussergewöhnliche Betriebszustände und nicht Schwingen 
des Reglers kompensieren. Deshalb ist es bei vernünftigen Parametern und 
normalen Betriebszustand nicht notwendig.

von Frank B. (f-baer)


Lesenswert?

Hallo Martin,
danke für deine Anmerkungen

Martin Klein schrieb:
>>Sobald ein Schwinger nach unten kommt, hämmert der Regler den vollen I-Anteil
>>auf das Stellglied, die Strecke beginnt zu schwingen.
> Ein esum von 5500 wird in der Reglergleichung nun mit I multipliziert zu
> 55. Bei einem Bereich von 0-1023 hämmert da nix, um bei deinen Worten zu
> bleiben denn das I-Anteil wirkt ja schon die ganze Zeit auf den
> Reglerausgang.

Hier liegt doch genau das Problem. Egal, wie klein der I-Parameter ist, 
er wird massiv aufschwingen:
Wir nehmen an: esum=5500, I=0,01. Jetzt kommt ein Schwinger unter den 
Sollwert.
Danach ist esum=5600. Soweit noch kein Problem. Nach 100 
Sollwertunterschreitungen ist esum dann aber bei 15500 angekommen. Nach 
einigen 100 Sollwertunterschreitungen bei angenommen 102300. Und jetzt 
siehst du vielleicht das Problem: Der I-Anteil steuert jetzt den Ausgang 
schon alleine komplett aus. Damit ergibt sich massives Überschwingen. 
Mit jeder neuen Sollwertunterschreitung ergibt sich eine größere 
Korrektur, weil esum immer größer wird. Deswegen schwingt der Regler 
immer weiter auf.
Bei einer Sollwertüberschreitung muss aber esum wieder abgebaut werden 
können, eben um bei der nächsten Unterschreitung wieder auf die reale 
Störgröße reagieren zu können.


>>Die Prüfung auf esum ist notwendig, weil sonst esum tief ins negative
>>abdriften kann und damit wieder Windup (Wind-Down) auftritt.
> Warum willst du keinen Negativen Integralanteil? Der Proportional und
> der Differentialanteil können auch negativ werden.

Klar können sie das. Aber bei der Summierung der Regelabweichungen 
erreicht esum schnell große Werte im Negativen, was dann das selbe 
Problem darstellt. Bis das wieder ausgeglichen ist, ist mir meine 
Regelgröße schon weit weggelaufen. Im schlimmsten Fall geht esum bei 
einer Sollwertänderung nach unten gegen -2e9 (int32 angenommen). Damit 
schwingt der Regler massiv nach unten, bis der I-Anteil wieder 
ausgeglichen ist.

>>Demzufolge muss(!) eine negative Regelabweichung (also Ist>Soll) von
>>esum abgezogen werden.
> Richtig, deshalb müsste die Prüfung auf (esum>0) auch falsch sein.

Jain. Die Prüfung auf >0 sollte besser auf einen negativen Wert lauten. 
Die Prüfung auf 0 ist mehr oder weniger willkürlich (und sorgt 
ihrerseits wieder für eine kleine Regelabweichung), wichtig ist, dass 
esum eine untere Grenze braucht. Man könnte hier auch -1000 ansetzen. 
Das würde den Regler nicht beeinflussen. Setzt man diese Begrenzung 
nicht, nutzt der Regler den kompletten Wertebereich und wird bei einem 
Überlauf sogar zur absoluten Katastrophe. Denn dann wird esum von -2e9 
zu +2e9. Dass der Regler damit unabhängig vom Wert des I-Anteils 
komplett aussteuert, sollte klar sein.

>>Damit wird der Reglerausgang dann auch wirklich zu Null, wenn keine
>>Sollwertabweichung mehr vorhanden ist.
> Wie Bitte? Das ist normalerweise nicht die Aufgabe eines stetigen
> Reglers, kommt aber vor wenn die Störgröße 0 wird und führt
> Beispielsweise bei einem Computernetzteil ohne Last zu einer netten
> Rauchwolke :)

Stell dir das ganze einfach mal für eine Lageregelung vor. Dafür lassen 
wir den D-Anteil aussen vor. Ist die Position erreicht, muss der Motor 
nur noch entgegen wirkende Kräfte ausgleichen. Sind keine Gegenkräfte 
(=Störgrößen) vorhanden, weil der Motor bspw. in der Horizontalen 
arbeitet, dann muss der Reglerausgang zu 0 werden. Während der Motor 
fährt, sind aber sehr wohl bspw. durch schwingende Lasten oder die 
Trägheit der Anordnung Störgrößen vorhanden. Ohne meine Korrektur würde 
der Motor nie zum Stillstand kommen.

> Letzen Endes wird esum doch durch die Prüfung der Regelgrenzen und der
> Sollwertabweichung begrenzt. Ist der Reglerausgang bei 0 oder der x <= w
> wird esum nicht mehr kleiner. Ist der Reglerausgang bei 1023 oder der x
> => w wird esum nicht mehr größer. Reglerschwingungen werden
> normalerweise nur durch falsche Parameter verursacht. Ein reiner
> I-Regler ohne Proportionalanteil schwingt Prinzipbedingt immer.

Das ist genau der Punkt: esum wird nie kleiner. esum kann nur kleiner 
werden, wenn ein negatives e auftritt. Dieses negative e sorgt aber 
dafür, dass y außerhalb der Aussteuergrenzen liegt, denn y wird dadurch 
ebenfalls negativ. Und ein negatives y sorgt dafür, dass (esum+=e) nicht 
berechnet wird.

> Möglicherweise liegst du Richtig und alle anderen liegen Falsch oder du
> hast dein Problem nicht verständlich machen können. Nimm einfach die
> anti-Windup Prüfung raus und führe "esum = esum + e" ungeprüft aus, wenn
> dein Regler immer noch Aufschwingt liegt es an den Parametern.
> Anti-Windup soll aussergewöhnliche Betriebszustände und nicht Schwingen
> des Reglers kompensieren. Deshalb ist es bei vernünftigen Parametern und
> normalen Betriebszustand nicht notwendig.

Was heisst "normaler Betriebszustand"? Ein erlaubter, d.h. normaler 
Betriebszustand kann auch sein, dass im Betrieb die Sollwertvorgabe 
geändert wird. Dann greift Anti-Windup genauso. Nur dass eben ohne meine 
Korrekturen überhaupt keine Regelcharakteristik mehr erkennbar ist, weil 
der Regler extrem langsam wird.

Vielleicht habe ich hier wirklich einen massiven Denkfehler, oder ich 
drücke mich nur nicht allzu verständlich aus, ich will das nicht 
ausschliessen. Aber deine Argumentation überzeugt mich nicht ;-)

von tobi (Gast)


Lesenswert?

Noch ein Fall bei dem die Anti-windup versagen wird: Sollwertänderung 
nach unten.

Bsp: eingeschwungen soll=100 -> p-anteil =0 i-anteil>55 >Y=55
soll neu 50
p-ant <0 Y angenommen <0 --> i-anteil bleibt konstant, dh der  Anteil 
wird nicht angepasst und treibt dann dominant / zu kräftig wenn das 
System nahe an denn Sollwert driftet


Ich hab Antiwindup bei her Temp/Ofen Steuerung vom P-anteil abhängig 
gemacht. Ist der alleine schon an der Stellgliedgrenze (100% oder 0%) 
wird der I Anteil eingefroren, mit der Ausnahme das der I-anteil 
betragsmäßig immer kleiner werden darf. Geht bei mir gut

von Falk B. (falk)


Lesenswert?

Seeing is believing. Pack doch einfach den Code in ein einfaches 
Testprogramm (Testbench) und simulier das. Dann sieht man, was passiert. 
Kann auch jeder selbst nachvollziehen.

von klaus (Gast)


Lesenswert?

die Ansprechschwelle AS
if ((e >= AS)||(e <= (AS*(-1))))

was genau soll die eigentlich bewirken?
bzw. wozu genau brauch ich die eigentlich? Kann ich die nicht einfach 
weg lassen?

von Falk B. (falk)


Lesenswert?

@ klaus (Gast)

>die Ansprechschwelle AS
>if ((e >= AS)||(e <= (AS*(-1))))

>was genau soll die eigentlich bewirken?

Dass der Regler nur für Abweichungen >= +/- AS aktiv wird. Bei kleineren 
Abweichungen reagiert er nicht. Das KANN bei bestimmten Problemen 
vorteilhaft sein, bei anderen aber genaus das Gegenteil bewirken 
(Totbereich ohne Wirkung).

>bzw. wozu genau brauch ich die eigentlich? Kann ich die nicht einfach
>weg lassen?

Kann man.

von Frank B. (f-baer)


Lesenswert?

Ich habe den Algorithmus nochmal etwas überarbeitet, hier jetzt mit 
funktionierendem Anti-Wind-Up und Anti-Wind-Down.
Mein vorher angebrachter Vorschlag hatte noch ein paar unschöne 
Kleinigkeiten zu bieten, die jetzt auch raus sind.
1
/* Regelalgorithmus */
2
  e = Soll - Ist);    // Soll - Ist
3
  if(e < PWM_Aufloesung)    //Anti-Wind-Up
4
    esum += e;
5
  if(esum<0) esum=0;    // Anti-Wind-Down

Ich betreibe den Regler ohne D-Anteil. Man kann jetzt darüber streiten, 
ob man esum auf einen negativen Wert begrenzt, bei dem dann der I- den 
P-Anteil aufheben würden, in dem Fall -(PWM-Auflösung/KI). Das kommt auf 
die jeweilige Anwendung an.
In dieser Version wirkt der I- nur im Bereich rund um den Sollwert und 
beim Hochregeln.

Zur Erklärung:
Ich betreibe damit eine Heizungsregelung. Da ich also nicht gezielt 
abkühlen kann, ist die Regelcharakteristik beim Abkühlen egal. Das 
Anti-Wind-Down ist dafür zwingend erforderlich, da ein Abkühlen mehrere 
Minuten dauern kann. Damit sich in der Zwischenzeit esum nicht Richtung 
minus unendlich verabschiedet, muss diese Bedingung her.

von Falk B. (falk)


Lesenswert?

@ Frank Bär (f-baer)

>/* Regelalgorithmus */
>  e = Soll - Ist);    // Soll - Ist

So ein Kommentar ist überflüssig, die Klammer am Ende ein Fehler.
Code abgetippt?

>  if(e < PWM_Aufloesung)    //Anti-Wind-Up

Was hat die PWM AUFLÖSUNG damit zu tun? Meinst du nicht eher den PWM 
Maximalwert? Ausserdem ist das nicht korrekt, denn die Stellgröße wird 
ja berechnet, indem noch I*Ta multipliziert werden.

>y = (Kp*e)+(I*Ta*esum); //+(D*((e-ealt))/Ta);  // Reglergleichung
>                          // (I-Anteil bei der Initialisierung mit

>    esum += e;
>  if(esum<0) esum=0;    // Anti-Wind-Down

Naja, gilt aber nur hier, wo die Stellgrößer von 0-X im positiven 
Bereich ist. Es gibt durchaus auch Fälle, wo negativ Stellgrößen 
sinnvoll sind.

>Ich betreibe den Regler ohne D-Anteil. Man kann jetzt darüber streiten,
>ob man esum auf einen negativen Wert begrenzt, bei dem dann der I- den
>P-Anteil aufheben würden, in dem Fall -(PWM-Auflösung/KI). Das kommt auf
>die jeweilige Anwendung an.

Ist sowas real denkbar? Dann müsste ja der I-Anteil eine SEHR kurze 
Zeitkonstante haben, da er ja nach einem Überschwingen sehr schnell ins 
Negative gehen müsste. Sowas ist praktisch SEHR selten, dann sowas ist 
meist tierisch instabil.

Die Appnote von Atmel ist hier besser, weil der allgemeine Fall 
dargestellt wird, konfigurierbar nach Bedarf.

http://www.atmel.com/Images/doc2558.pdf
http://www.atmel.com/Images/AVR221.zip

von Frank B. (f-baer)


Lesenswert?

Ach Falk...

Falk Brunner schrieb:
> @ Frank Bär (f-baer)
>
>>/* Regelalgorithmus */
>>  e = Soll - Ist);    // Soll - Ist
>
> So ein Kommentar ist überflüssig, die Klammer am Ende ein Fehler.
> Code abgetippt?

Nein, es ist ein klassischer Tippfehler. Der Kommentar steht da, weil in 
meinem Code die Variablen selbstverständlich nicht "Soll" und "Ist" 
heissen. Das hätte ich dir eigentlich zugetraut, selbst zu erkennen.
Die Klammer ist bei der Ersetzung verlustig gegangen...

>>  if(e < PWM_Aufloesung)    //Anti-Wind-Up
>
> Was hat die PWM AUFLÖSUNG damit zu tun? Meinst du nicht eher den PWM
> Maximalwert? Ausserdem ist das nicht korrekt, denn die Stellgröße wird
> ja berechnet, indem noch I*Ta multipliziert werden.

Muss ich mir nochmal ansehen.

>>y = (Kp*e)+(I*Ta*esum); //+(D*((e-ealt))/Ta);  // Reglergleichung
>>                          // (I-Anteil bei der Initialisierung mit
>
>>    esum += e;
>>  if(esum<0) esum=0;    // Anti-Wind-Down
>
> Naja, gilt aber nur hier, wo die Stellgrößer von 0-X im positiven
> Bereich ist. Es gibt durchaus auch Fälle, wo negativ Stellgrößen
> sinnvoll sind.

Meine Güte... aber doch nicht in einem System, in dem das Stellglied auf 
positive Stellgrößen beschränkt ist... Ich glaube, du hast das Prinzip 
von Anti-Wind-Up nicht verstanden. Nochmal: Es geht nicht um den 
Regelalgorithmus an sich, sondern eigentlich nur um Anti-Wind-Up und 
Anti-Wind-Down.

>>Ich betreibe den Regler ohne D-Anteil. Man kann jetzt darüber streiten,
>>ob man esum auf einen negativen Wert begrenzt, bei dem dann der I- den
>>P-Anteil aufheben würden, in dem Fall -(PWM-Auflösung/KI). Das kommt auf
>>die jeweilige Anwendung an.
>
> Ist sowas real denkbar? Dann müsste ja der I-Anteil eine SEHR kurze
> Zeitkonstante haben, da er ja nach einem Überschwingen sehr schnell ins
> Negative gehen müsste. Sowas ist praktisch SEHR selten, dann sowas ist
> meist tierisch instabil.

Du missverstehst gewaltig: Wenn e negativ werden kann, dann ergibt sich 
auch eine negative Stellgröße. Wenn der Regler das abbilden kann, dann 
gibt es keinen Grund, e auf positive Werte zu begrenzen.
Und davon abgesehen: Manchmal will man vielleicht einfach, dass der 
I-Anteil den P-Anteil kompensieren kann. Was weiß ich. Das war ein 
Vorschlag um die Sache etwas allgemeiner zu fassen. In meiner Anwendung 
ist es nicht notwendig.

> Die Appnote von Atmel ist hier besser, weil der allgemeine Fall
> dargestellt wird, konfigurierbar nach Bedarf.
>
> http://www.atmel.com/Images/doc2558.pdf
> http://www.atmel.com/Images/AVR221.zip

Wozu diskutieren wir dann hier? Mal ehrlich: Ich habe mich beim 
Reglerdesign in diesem Thread etwas belesen. Dann habe ich einen Bug im 
Regler gefunden. Jetzt dokumentiere ich, wie der behoben werden könnte. 
Wo ist dein Problem? Warum postest du nicht einfach gleich eingangs die 
Appnote und allen ist "geholfen"?

von Frank B. (f-baer)


Lesenswert?

Falk Brunner schrieb:
> Die Appnote von Atmel ist hier besser, weil der allgemeine Fall
> dargestellt wird, konfigurierbar nach Bedarf.
>
> http://www.atmel.com/Images/doc2558.pdf
> http://www.atmel.com/Images/AVR221.zip

Dafür ist leider der Code strukturell eine mittlere Katastrophe. 
Abgesehen davon ist der Regler im Bezug auf Rechenzeit und Codegröße 
deutlich schlechter als die Implementation hier im Thread.

von IchBinIch (Gast)


Lesenswert?

Hallo allerseits

Ich knüpf hier mal an... Ich möchte ebenfalls einen PI Regler mit 
anti-Windup implementieren. Ich hab jedoch einen anderen Ansatz gewählt.

Ich hab mir gedacht ich transformier meinen kontinuierlichen PI Regler 
(ganz nach Schulbuch) mit Tustin s = 2(z-1)/(Ta(z+1)) in den Z-Bereich
-->


Und von dort dann in den Zeitbereich (ich hab hier die Konstanten der 
Einfachheit halber zusammengefasst)


Das lässt sich so ganz einfach implementieren
e=w-x;
u=A*u_old+B*(e-e_old);
u_old=u;
e_old=e;


Meine Frage: Wie integrier ich hier das anti-Windup?
Was ist der Unterschied zwischen meiner Lösung und dem Beispiel vom 
Anfang?


Würd mich freuen, wenn mir jemand weiterhelfen kann.

von avr (Gast)


Lesenswert?

Frank Bär schrieb:
> Abgesehen davon ist der Regler im Bezug auf Rechenzeit und Codegröße
> deutlich schlechter als die Implementation hier im Thread.

Das glaub ich nicht. Schließlich verbraucht allein die Nutzung von 
double ein paar Kilobyte. Der Code von Atmel nutzt keine 
Fließkommazahlen. Daher sollte er schneller und kleiner sein.

von Peter K. (Gast)


Lesenswert?

IchBinIch schrieb:
> Meine Frage: Wie integrier ich hier das anti-Windup?
> Was ist der Unterschied zwischen meiner Lösung und dem Beispiel vom
> Anfang?

Das Anti-Windup mathematisch zu integrieren ist etwas schwierig da es 
sich dabei um eine nichtlineare und unstetige Funktion handelt.

Mathematisch verwendest du da einmal einen PI-Regler und wenn die 
Stellgröße in der Begrenzung ist, also größer als ein bestimmter wert, 
machst du aus deinem PI-Regler eine Art P-Regler, bedeutet du nimmst 
zwar deinen I-Anteil immer noch mit in die Gleichung integrierst aber 
nicht mehr auf.

Soweit mir bekannt ist wird Anti_Windup auch nur bei digitalen Reglern 
eingesetzt und ist nur mehr oder weniger eine absicherung für den 
Worst-Case denn generell sollten bei "kontinuierlichen" Reglern wie P, 
PI oder PID Reglern keine Unstetigkeiten (Stellgrößenbegrenzung) 
auftreten. Treten sie doch auf ist entweder die Regelung falsch 
dimensioniert oder die Aktoren sind falsch dimensioniert

von Ellen Moore (Gast)


Lesenswert?

Peter Kremsner schrieb:
> Soweit mir bekannt ist wird Anti_Windup auch nur bei digitalen Reglern
> eingesetzt und ist nur mehr oder weniger eine absicherung für den
> Worst-Case denn generell sollten bei "kontinuierlichen" Reglern wie P,
> PI oder PID Reglern keine Unstetigkeiten (Stellgrößenbegrenzung)
> auftreten. Treten sie doch auf ist entweder die Regelung falsch
> dimensioniert oder die Aktoren sind falsch dimensioniert

Absolut korrekt ... richtig dimensioniert funktioniert dieser Regler 
sehr gut (PI-Regler-Teil, der D-Regler-Teil wurde bei meiner Anwendung 
nicht betrachtet). Das betrift im Übrigen auch die Größe des Wind-Ups 
und die zeitliche Abtastung. Das lässt sich mathematisch als auch in 
Testversuchen zeigen.

Eng wirds mit 8-bit Prozessioren und int16_t. Man muss sher genau 
schauen, dass es nicht zum Überlauf kommt. Ich empfehle dann die Prüfung 
von esum.

von Ulrich (Gast)


Lesenswert?

@IchBinIch:
Der Gezeigte PI-regler ist einfach die Geschwindigkeitsform. Die gibt es 
erweitert um einen zusätzlichen Term (mit dem Fehler aus 2 Schritten 
zurück) auch als PID-Regler.

In dieser Form macht man Antiwindup ganz einfach indem man u in der 
Größe Begrenzt bevor man sich den Wert als u_old merkt. Da es so einfach 
ist, fällt es manchmal nicht auf, das überhaupt ein Anti-Windup schon da 
ist. Allerdings wird es damit schwieriger eine andere Anti Windup 
Strategie zu implementieren.

von Richard (nbger)


Lesenswert?

Hallo zusammen,

macht es Sinn, einen so alten Thread nochmal "aufzuwärmen"? Ich hoffe 
schon!

Ich wollte endlich mal etwas über Regler lernen (insbesondere PID) und 
hab dafür viel gegoogled. Der Thread hier hat mir eigentlich am meisten 
geholfen, daß ganze zu verstehen, insbesonder konnte ich dank des 
Sourcecodes alles auch selbst ausprobieren.

Dabei ist mir auch aufgefallen, daß das Anti-Winding nur teilweise 
funktioniert.
Wir betrachten ja hier eine Temperatur-Regelung!
Nach meinen Beobachtungen funktioniert es gut beim Aufheizen, aber nicht 
beim Abkühlen (also Sollwert < Istwert). Das liegt meiner Meinung aber 
an den Gegebenheiten der physikalischen Vorgänge.
Das Heizen machen wir aktiv, den Heizverlauf können wir deswegen regeln.
Das Abkühlen hängt NUR von den Gegebenheiten ab (Zimmer, Ofen, 
Wärmeverlust über die Zeit).
Der Regler, so wie er programmiert ist, weiß davon aber nichts. Deswegen 
summiert sich bei einem Sollwert > Istwert ein riesiges esum auf. Das 
wird dann zum Problem, wenn die Temperatur aufgrund der Abkühlung den 
Sollwert erreicht und dann unterschreitet. Durch das riesige esum dauert 
es ewig, bis der Regler mal wieder zum Heizen anfängt.

Ich habe das ganze in einer Simulation nachprogrammiert und ein 
einfaches Modell für einen Ofen gemacht. Damit lassen sich Effekte ganz 
gut nachvollziehen. Ich bereite das Ganze gerade etwas auf und werde 
dann Screenshots zur Verfügung stellen.

Grüße NBGer

von Ernst O. (ernstj)


Lesenswert?

Richard Rauch schrieb:
> Das Heizen machen wir aktiv, den Heizverlauf können wir deswegen regeln.
> Das Abkühlen hängt NUR von den Gegebenheiten ab (Zimmer, Ofen,
> Wärmeverlust über die Zeit).
> Der Regler, so wie er programmiert ist, weiß davon aber nichts. Deswegen
> summiert sich bei einem Sollwert > Istwert ein riesiges esum auf. Das
> wird dann zum Problem, wenn die Temperatur aufgrund der Abkühlung den
> Sollwert erreicht und dann unterschreitet. Durch das riesige esum dauert
> es ewig, bis der Regler mal wieder zum Heizen anfängt.

Ich hätte jetzt erwartet, dass esum beim abkühlen negativ ist...  und 
dass negative Werte von esum ignoriert werden., wenn es keine aktive 
Kühlung gibt.

von Peter K. (Gast)


Lesenswert?

Hallo Richard,

der Anti Windup in dem Code tut genau das was er soll, nähmlich die 
Integration stoppen solange die Stellgröße an der Endbeschränkung ist, 
also in deinem Fall solange der Heizkörper voll an ist.

Das kann beim Einschalten sein wenn der P-Anteil alleine bereits die 
Stellgröße übersteuert aber auch dann der Fall sein wenn P und I Anteil 
gemeinsam übersteueren.

So wie du die Sache schilderst hört es sich nach einem falsch 
Dimensionierten Regler mit zu hohem I Anteil an, das bedeutet der 
Integrator Integriert viel zu schnell auf und ist daher Instabiel und 
gegen Instabilität des gesammt Systems kann der Anti Windup auch nichts 
machen.

Die Temperatur eines Raumes verhält sich ja normalerweise anähernd wie 
ein Integrator, ich schalte die Heizung ein und die Temperatur steigt 
(idealerweise) konstant mit einer Zeitkonstante an.
Mathematisch gesehen hast du daher eine Phasenverschiebung von 90° 
hängts du da jetzt den PID-Regler dazu erzeugt dir der I-Anteil eine 
zusätzliche Phasenverschiebung von 90° das führt dann dazu dass die 
Regelung instabil ist wenn die Phasenverschiebung bei der 0-dB linie im 
Bodediagramm >=180° ist.

Du musst den Regler so Auslegen dass der Knick des PI-Reglers vor der 
+10dB linie ist damit dein Regelkreis stabil ist.

Versuche einfach mal den I-Anteil weg zu lassen wenn deine Regelung 
nicht so genau sein muss, ohne I-Anteil sollte deine Strecke nicht 
instabil werden.

ernst oellers schrieb:
> Ich hätte jetzt erwartet, dass esum beim abkühlen negativ ist...  und
> dass negative Werte von esum ignoriert werden., wenn es keine aktive
> Kühlung gibt.

sollte man nicht machen wenn man esum oder sonst einen wert auf ein 
Intervall begrenzt ist das nichtlineares Verhalten und das macht jeden 
noch so gut ausgelegten Regler mehr oder weniger zunichte.

Das Anti-Windup selbst ist bereits ein nichtlinearer eingriff in den 
Regler wesswegen bei einem gut Dimensionierten Regelkreis das 
Anti-Windup nicht eingreifen sollte.
Desweiteren sollte man einem Regler nie oder nur selten einen Sprung 
aufschalten, weil man dadurch ja fast instabilität oder überschwingen 
herausfordert, kommt in dem fall auf den Regler an, besser ist es immer 
auch einen Vorfilter zu verwenden damit der Sollwert nicht springen kann

von Richard (nbger)


Lesenswert?

ok, das probier ich mal aus...

ich hab im Moment gar keine echte Anwendung dafür, vielleicht ist auch 
mein Modell zur Simulation (Ofen, Raum,...) falsch.

Ich hab das Modell folgendermaßen aufgebaut:
1. die Temperatur des Ofens passt sich über die Zeit an die 
Außentemperatur an. Je kleiner die Differenz, um so langsamer ist die 
Anpassung (das ist auch die einzige Möglichkeit der Abkühlung!)

2. ein Heizelement kann über PWM angesteuert werden und den Ofen heizen.
Der Ofen passt sich (ähnlich wie bei der Außentemperatur, aber 
schneller) der Temperatur des Heizelementes an

3. Auch die Temperatur des Heizelementes passt sich an die Temperatur 
des Ofens entsprechend an (wird durch Abgabe von Wärme abgekühlt). Dies 
wirkt vor allem, wenn das Element nicht heizt.

In C sieht das so aus:
1
static void th_SimuHeatingDevice(CYG_ADDRESS data)
2
{
3
  diag_printf("Thread Heating Device Started\n");
4
5
6
   float diff;
7
   float temp;
8
9
   float temp_heater = HeatingDevice.temp;
10
11
   for (;;) // Thread endless loop
12
   {
13
      CYG_INSTRUMENT_USER(10,(int)(temp_heater),0);
14
15
      // temperature adjustment to ambient temperature
16
      temp = HeatingDevice.temp;
17
      diff = temp-HeatingDevice.ambient_temp;
18
      temp = temp - ( diff / 50.0);
19
20
      // temperature of heating
21
      diff = temp_heater - temp;
22
      temp_heater = temp_heater - (diff / 10.0);
23
24
      diff = 1000.0 - temp_heater;
25
      temp_heater = temp_heater +  ( diff * HeatingDevice.pwm_heating / 100.0 / 10.0 );
26
27
      diff = temp_heater - temp;
28
      temp = temp + ( diff / 10.0 );
29
30
      HeatingDevice.temp = temp;
31
      cyg_thread_delay(100);
32
33
   }
34
}

Das ganze läuft übrigens unter einem Echtzeit-OS (eCos), wird aber zum 
Rumspielen auf dem PC mit einem ARM-Simulator emuliert.

von Peter K. (Gast)


Lesenswert?

Das Model sollte so passen.

Versuch es aber eine stufe einfacher, mach deinen Ofen nicht träge als 
die Temperatur des ofens ist immer gleich der des Heizelements und dein 
Heizelement verhätl sich auch nicht träge.

Versuche nur die Lufttemperatur des Raumes zu modelieren, also dein Raum 
folgt der Temperatur des Ofens nur langsam auch wenn sich dieser 
Sprungartig erwärmen kann.

Ist bei einer echten Heizung auch so der Ofen bzw das Heizelement 
erwärmt sich so schnell im verhältnis zum Raum dass die geschwindigkeit 
mit der sich das Heizelement erwärmt vernachlässigbar ist.

Wenn du jetzt jedoch in deinem Beispiel nicht von einem Heitkörtper 
sondern von einem Backofen sprichst, ist dein Raum der Backraum des 
Ofenens, und der ofen von dem ich rede das Heizelement ^^

Peter Kremsner schrieb:
> Die Temperatur eines Raumes verhält sich ja normalerweise anähernd wie
> ein Integrator

Da hab ich mich verschrieben, die Temperatur verhält sich natürlich 
anähernd wie ein PT1.
der kern der aussage bleibt aber gleich bei einem PT1 ist es so dass es 
sich überhalb der knickfrequenz anähernd wie ein Integrator verhält.

von Richard (nbger)


Lesenswert?

hmm...ich wollte es etwas realistischer machen, deswegen hat das 
Heizelement einen eigenen Temperaturverlauf

Nehmen wir mal an, es wäre anstatt einem Ofen ein Raum mit einem 
Heizkörper:

- Der Raum selbst (ungeheizt) kühlt mit der Zeit ab und nähert sich der 
Außentemperatur z.B. 0 ° an. (je nach Dämmung langsame Zeitkonstante). 
Also ohne Heizen würde es vielleicht nach ein paar Tagen innen auch fast 
0 ° haben.

- Der Heizkörper ist das Heizelement und kann viel wärmer als der Raum 
werden (z.b. 60 °)

- Der Raum wird durch den Heizkörper geheizt (schnelle Zeitkonstante), 
der Heizkörper kühlt dadurch aber ab

- Die Regelung soll jetzt eigentlich das Thermostat-Ventil simulieren, 
welches den Raum auf Soll-Temperatur hält. (z.B. 22 ° )

Mir geht es dabei nicht wirklich um eine Raum-Regelung. Auch ein 
schlechter Regler wird wahrscheinlich irgendwann in etwa die 
Soll-Temperatur einstellen. Ich möchte eher etwas über Regelung lernen 
und beschäftige mich damit, wie der Regler arbeitet.

von Richard (nbger)


Angehängte Dateien:

Lesenswert?

also, ich hab mal ein paar Screenshots gemacht.

Allerdings kann ich momentan das ursprüngliche Problem nicht mehr 
nachstellen. Der Regler arbeitet einwandfrei, sowohl beim Hochheizen, 
als auch beim Runterkühlen.

Trotzdem mal 2 Screenshots.

1. Verlauf beim Hochheizen von 20 ° auf 500 °
2. Verlauf beim Setzen einer neuen Solltemp. 100 ° (also von 500->100)

Erklärung zum Oszi-Schrieb:

User1 : Solltemperatur Vorgabe
User2 : Ist-Temperatur Verlauf
User3 : PID->y ; also der Vorgabewert für den PWM
User4 : PID->esum
User10: Temperaturverlauf des Heizelements

von Peter K. (Gast)


Lesenswert?

Richard Rauch schrieb:
> Der Raum wird durch den Heizkörper geheizt (schnelle Zeitkonstante),
> der Heizkörper kühlt dadurch aber ab

der Heizkörper kühlt nur dann ab wenn er durch die PWM weniger Leistung 
bekommt. Die Temperatur des Heizers ist im stationären Fall immer 
Wärmeübergangskoeffizient (°C/W) * Leistung. Der 
Wärmeübergangskoeffizient ergibt sich bei einem Heizkörper aus fläche 
und Oberflächenbeschaffenheit, den wert °C/W findet man typischerweise 
bei der Angabe der Kühlkörper für Transistoren kann hier aber auch 
verwendet werden.

Naja eine schlechte Regelung kann instabil sein, das bedeutet der Regler 
wird nie die 22°C erreichen.
Wenn der Regler an der stabilitätsgrenze ist schwingt die Temperatur 
immer um die 22°C, wird sie aber nie erreichen. Bei Instabilität wird 
der Raum der theorie nach auf einen Bereich von -unendlich bis 
+unendlich grad geheizt und erreicht auch nie 22°C

Im Regelfall spricht man von einem schlechten Regler dann wenn der 
Regelkreis stabil ist aber einfach nur extrem langsam oder einfach 
extrem lange nachschwingt.

Zum Thema Regelungstechnik kann ich dir das Buch Regelungstechnik von 
Haager empfehlen ist ziemlich verständlich erklärt, wenn du aber wissen 
willst wie so eine Regelung im detail funktioniert wirst du um so Sachen 
wie Laplace-Transformation, Bode-Diagramm und Stabilitätskriterien nicht 
drum herum kommen.

So ein Regler ist eben ein pures Mathematisches Konstrukt.
Im Allgemeinen kann man aber sagen der Regler hat einen P Anteil, der 
Verstärkt einfach nur den unterschied zwischen soll und ist wert
Der Integralanteil summiert den Unterschied bei jedem aufruf der 
Reglerfunktion auf
und der Differentialanteil Verstärkt einfach die Änderung im Unterschied 
zwischen soll und ist, am ende werden diese einzelnen Anteile summiert 
und das ist dein PID-Regler

Der PID-Regler steuert jetzt dein Stellglied, also bie dir den Heizer so 
an dass die Temperatur(Ist_Wert) möglichst schnell den Sollwert 
erreicht, dabei ist es aber wichtig wie deine Regelstrecke(der Raum) 
beschaffen ist ansonsten kann es passieren dass der Regler sehr lange 
zum erreichen der Solltemperatur braucht oder dass er sie gar nicht 
erreichen kann, weil er selbst dass Stellglied so steuert dass die 
Regelstrecke immer das macht was der Regler eigentlich nicht möchte.

Es ist also für den Regler essentiel das zu kennen was er Regeln möchte, 
ich kann einen Regler für ein Walzwerk nicht in eine Temperaturregelung 
einsetzen oder Umgekehrt, es gibt aber bestimmte einstellverfahren für 
Regler:
http://de.wikipedia.org/wiki/Faustformelverfahren_%28Automatisierungstechnik%29

Oder wenn man die Regelstrecke als mathematisches Model hat kann man den 
Regler auch nach gewissen Formeln einstellen:
http://de.wikipedia.org/wiki/Betragsoptimum
http://de.wikipedia.org/wiki/Symmetrisches_Optimum

leider sind die beiden Wikiartikeln ziemlich spärlich, aber die Begriffe 
stimmen zumindest.

von Richard (nbger)


Lesenswert?

spannend!
naja, ich bin nicht so ganz das Mathe-Genie, von daher tue ich mich 
etwas schwer mit den mathematischen Grundlagen und Formeln.
wofür die P, I  und D - Anteile sind, hab ich aber inzwischen 
einigermaßen begriffen.

da werde ich mal weiter damit rumspielen und das unterschiedliche 
Verhalten bei unterschiedlichen Paramtern ausprobieren.

was mir noch nicht ganz klar ist, wie bringe ich unterschiedliches 
Zeitverhalten in den Regler rein? Es ist ja ein riesen Unterschied, ob 
ich eine träge Temperatur oder eine schnell reagierende Drehzahl eines 
Motors regeln will.

Meine Vorgehensweise zum Ausprobieren inklusive Screenshots und 
Sourcecode habe ich übrigens hier abgelegt:
http://tiprom.itrgmbh.com/projects/itr-products-ecos-toolchain/wiki/ECos-PID-sample

: Bearbeitet durch User
von Peter K. (Gast)


Lesenswert?

Richard Rauch schrieb:
> was mir noch nicht ganz klar ist, wie bringe ich unterschiedliches
> Zeitverhalten in den Regler rein? Es ist ja ein riesen Unterschied, ob
> ich eine träge Temperatur oder eine schnell reagierende Drehzahl eines
> Motors regeln will.

Nunja die Mathematische Form eines Digitalen PID-Reglers wird durch eine 
sogenannte Differenzengleichung dargestellt, die ist für den PID-Regler:

Wenn du dir den PID Algorithmus anschaust kannst du die 
Differnzengleichung auch im Programm sehen, die Summe ist dort jedoch 
durch esum ersetzt und
 ist durch ealt ersetzt

Die Abtastzeitkonstante kommt daher dass dein Regler ja digital ist und 
den Ist-Wert ja nur in bestimmten Zeitabständen aufnimmt.

der Integrierbeiwert gibt jetzt an wie schnell der Integrator 
integrieren soll, je größer der Wert desto schneller ist der Integrator 
man kann den Integrierbeiwert auch durch die Integrationszeitkonstante 
ersetzen

das selbe gilt für den Differenzierbeiwert
durch diese beiden Konstanten bringst du das Zeitverhalten in den 
PID-Regler
wie diese auszulegen sind kommt drauf an welche Eigenschaften deine 
Regelung haben soll, soll sie gut und schnell der Stellgröße folgen, 
oder soll sie gut Störungen kompensieren können, wie viel Prozent darf 
die Stellgröße maximal über den Sollwert überschwingen usw.
Daher werden diese Zeitkonstanten entweder durch ein 
Faustformelverfahren oder aber im Bode-Diagramm bzw durch Rechnungen im 
Laplace-Bereich bestimmt, Rechnungen sind in diesem Fall ein muss wenn 
es um sehr gute Regelungen geht, die Faustformeln eignen sich nur für 
Regler die hald funktionieren sollen, bei denen die Spezifikationen aber 
eher locker sind.

von Richard (nbger)


Lesenswert?

Hallo Peter,

vielen Dank. So eine gute Erklärung habe ich bisher noch nicht gefunden.
Vor allem die Darstellung der Zusammenhänge zwischen der mathematischen 
Formel und der realen Implementierung ist sehr hilfreich.

Übrigens....mit der Implementierungs-Variante hier aus dem Thread, alles 
mit Integer-Arithmetik zu machen (wegen Performance) bin ich überhaupt 
nicht zurecht gekommen.
Therme waren immer sehr schnell 0 (wegen Abrundung!). Der Regler hat 
dann nie den Sollwert erreicht. Außerdem funktioniert es bei mir am 
Besten mit einem Integrierbeiwert von 0,1.
Im Falle von Integer hätte ich nur die Möglichkeit 0 oder 1.

von Peter K. (Gast)


Lesenswert?

Reglerimplementierungen mit Integern werden normal so gelöst, dass du 
jeden Parameter(Alle Beiwerte Plus soll und Istwert) den du in den 
Regler eingibst mit einem Faktor zb 100 Multiplizierst, der 
Integrierbeiwert wird dann bei dir zB von 0.1 zu 10 du musst dir dann 
hald nur merken dass die Stellgröße die dein Regler ausgibt 100* die 
Tatsächliche Stellgröße ist, die kannst du jetzt durch 100 dividieren, 
das sollte aber in Gleitkomma arithmetik passieren, oder du weist 
aufgrund deiner Regelstrecke dass du den Faktor 100 sowieso benötigst, 
beispielsweise bei einer PWM für die Prozent dutycycle, es macht da 
eigentlich wenig sinn, die Reglerstellgröße durch 100 zu dividieren und 
den wert den du dann erhältst mit 100 zu multiplizieren um von % auf 
einen Integer zu kommen.

Andererseits kannst du diesen Faktor auch in deine Strecke 
miteinbeziehen, du kannst sagen, mein Regler gibt wirklich meine 
Stellgröße aus, aber in meinem Model ist der Proportionalanteil meiner 
Strecke mit 100 multipliziert.

 Atmel hat das mal in einem Application Note beschrieben

http://www.atmel.com/webdoc/atmel.docs/atmel.docs.33085.19841.html

dort gibts das PDF plus c-Code
in dem haben sie den PID Algorithmus auch noch ein bisschen angepasst 
indem sie für d-Anteil nicht die Differenz der Regelabweichungen 
verwenden sondern die differenz der Ist-Werte, das führt dazu, dass der 
Reglerausgang nicht springt wenn sich der Sollwert sprungartig ändert.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.