Das wird dir höchstwahrscheinlich nicht viel bringen, kommt darauf an
was für Eingangs- und Ausgangssignale du hast. PWM? Analog? Wieviel bit?
AD/DA-Wandler per I²c, SPI, Parallel?
Mit der Berechnung der Stellgröße könnte ich aushelfen, den Rest musst
du schon selbstanpassen.
In diesem Fall mit Resourcen 'geaast' (double-Variablen), Abtastung alle
20ms
if(y>1023)// Stellgröße auf 0..1023 begrenzen (10 bit PWM)
6
{
7
y=1023;
8
}
9
if(y<1)
10
{
11
y=0;
12
}
13
ealt2=ealt;// Regelabweichungs-Historie zuweisen
14
ealt=e;
15
yalt=y;// Stellgrößen-Historie zuweisen
16
17
returny;// Stellgröße zurückgeben
18
}
e => Regelabweichung
w => Sollwert
x => Istwert
y => Stellgröße
Kp => Proportionalverstärkung
I => Integralverstärkung
D => Differentialverstärkung
Der Schnipsel ist für die Ausgabe über 10-bit-PWM geschrieben und
funktioniert prima.
Wo ist denn beim D-Anteil die Differenz?
Es sollte m.E. heissen
ealt2 = e - ealt; // Differenz der Regelabweichungen
Sonst wird der D-Anteil ja nicht 0 bei konstantem e.
EDIT
Und beim Integral ist ja eine Aufsummierung der delta e notwendig.
ealt und ealt2 werden mit den jeweiligen Differential- und
Integralverstärkungen multipliziert, das Ganze bezieht sich jeweils nur
auf die letzten zwei Messwerte.
Der D-Anteil ist auch niemals 0, nur wenn die Regelabweichung über
längere Zeit genau null ist.
D*ealt2 wird niemals null, nur wenn der Sollwert null ist. Wie soll denn
ein Motor/Lüfter/Pumpe o.Ä. laufen, wenn keine Ansteuerung erfolgt? Eine
gewisse Stellgröße braucht jedes Stellglied, um einen Sollwert zu
halten.
Die Stellgröße y setzt sich ja aus den drei Anteilen zusammen.
Danke für den Quellenhinweis, nur tauchen die dort genannten
Rechenschritte
esum = esum + e
y = Kp * e + Ki Ta esum + Kd * (e – ealt)/Ta
ealt = e
nur bruchstückhaft und verstümmelt in dem Programm im ersten Post auf.
EDIT
Ich meinte natürlich im ersten Antwortpost.
Also vor geraumer Zeit habe ich hier ein wenig dazu erklärt. Habe die
Beiträge oben kurz überflogen. Ich glaube auch, dass der Quelltext oben
nicht ganz richtig ist. Also hier ersteinmal für die Interessierten...
Beitrag "Re: PID- Regler"
Ich denke, wenn man das Thema PID Regler nicht gerafft hat, sollte man's
eh seinlassen. Und wenn man's gerafft hat, sind die paar Zeilen in ein
paar Minuten geschrieben.
Und ich denke, dass jeder einen PID-Regler einsetzen kann, ganz gleich
ob er ihn verstanden hat oder nicht. Ist wie beim Autofahren, das kann
auch jeder...
ealt=e;// Regelabweichung für nächste Abtastung merken
7
if(y>1023)// Stellgröße auf 0..1023 begrenzen (10 bit PWM)
8
{
9
y=1023;
10
}
11
if(y<1)
12
{
13
y=0;
14
}
15
returny;// Stellgröße zurückgeben
16
}
mit
Ta = 0.02 (20ms)
Kp = 18
I = 16
D = 0.05
regelt mein Lüfter sauber, schnell und ruhig, ohne großes Zappeln der
Stellgröße.
Ich bitte um Korrektur, falls ich auf die Schnelle was vergessen habe!
Also wieso der Double Datentyp?
Braucht meiner Meinung nach einfach zu viel Rechenleistung!! Da ist man
mit Int auch leicht bedient!
Ausserdem würde ich für den I-Anteil eine Anti-Windup Maßnahme setzen!
Für die Regelung einer Lüfterdrehzahl kann man auf den D-Anteil locker
verzichten, das brauchts nur bei dynamischen Vorgängen wie Positions-
oder Lageregelung mit Motoren.
@ JÜrgen G.:
Stimmt schon mit den doubles. Habe ich von oben übernommen, da es nicht
auf die Rechenleistung ankommt (16MHz, mega32) kann ich die schon
nehmen. Bei int muss man die Überläufe abfangen (vermeiden), da kommt
dann auch noch Rechenleistung dazu.
Was meinst du mit Anti-Windup-Maßnahme? Kannst du das Beispiel damit
ausstatten?
@ Dieter Werner:
Haste Recht. Ich habe grade einen Lüfter mit Reflexkoppler da gehabt,
darum habe ich den benutzt. Den D-Anteil kann man problemlos weglassen.
Anti Windup meint eigentlich nur den I-Anteil "einfrieren" wenn er über
die Aussteuerungsgrenzen des Reglers kommt.
Ich hab mir die Website durchgelesen -> kommt auf AWR hin!
Das Problem ohne AWR: Der I-Anteil integriert immer weiter auf, auch
wenn der Regler auf Anschlag steht, bis das der Datentyp erschöpft ist.
Wenn jetzt allerdings eine Änderung im System ist, muss der ganze
I-Anteil wieder runter gerackert werden, bis das er überhaupt mal zu
Aussteuerungsgrenze kommt und dann erst für den Ausgang wirksam zu
sinken beginnt...
http://virtual.cvut.cz/dynlabmodules/ihtml/dynlabmodules/syscontrol/img1963.gif
kleine Demonstration was ohne WindUp-Maßnahme sein kann.
Bei dem obigen Source wurde zwar der gesamte Ausgang begrenzt allerdings
der I-Anteil nicht "vereist" ^^
Meine Meinung wär ja sowieso die einzelnen Elemente einzeln zu errechnen
und dann zu addieren! So kann man sich die Einzelnen Begrenzungen besser
ansehen & Maßnahmen setzen!
Ich such ma Quellcode... Vllt liegt irgendwo einer rum...
EDIT:
http://www.mstarlabs.com/apeng/techniques/pidsoftw.html
Hier ist der Algo in eine Klasse gepackt... ein wenig umschreiben und
dann geht...
esum+=e;// Summe der Regelabweichung aktualisieren
9
}
10
11
prop=(Kp*e);// Proportional Faktor
12
integ=(I*Ta*esum);// Integraler Anteil
13
diff=(D*((e-ealt))/Ta);// Differenzieller Anteil
14
ealt=e;// Regelabweichung für nächste Abtastung merken
15
y=prop+integ+diff;// Ausgangsstellgröße
16
17
if(y>1023)// Stellgröße auf 0..1023 begrenzen(10 bitPWM)
18
{
19
y=1023;
20
}
21
if(y<1)
22
{
23
y=0;
24
}
25
returny;// unsigned int weil y nur zwischen 0 und 1023
26
}
So falls Fehler drinne sind melden ^^
Habs nur ein wenig leichter gemacht... In Bezug auf Aufteilung... Vllt
optimier ich den Code auch noch ein wenig...
EDIT:
@THM: Wenn du wie e Begrenzung durch y machst, kann der I-Anteil nicht
wirken, während der D-Anteil voll aufdreht... Deswegen NUR das integral
begrenzen ^^
Ich habe bei übersteuertem Stellglied nur esum eingefroren. Dadurch kann
nicht mehr integriert werden. Die anderen Parameter bleiben davon
unberührt.
Ich hab's auf meiner Hardware laufen, der Unterschied zu vorher ist
Welten besser! :)
THM wrote:
> Ich hab's auf meiner Hardware laufen, der Unterschied zu vorher ist> Welten besser! :)
Immer gern xP
WENN REGELEN dann RICHTIG ^_^
So aber nun zur Optimierung... Die Datentypen gefallen mir nicht
wirklich... Ich hab doch nur einen 10bit AD-Wandler also zurück zu
signed INT (16bit)
>Die Datentypen gefallen mir nicht
Jo, mir auch nicht! ;) Das kommt als nächstes.
Zur Visualisierung mal den Unterschied des Regelverhaltens.
In diesem Bild OHNE anti-Windup.
Grün => Stellgröße
Rot => Sollwert (70 Hz)
Weiß => Istwert
Der Lüfter gibt eine Frequenz von 0 bis max 140 Hz zurück
Achso, zur Erklärung:
Ich ahbe den Lüfter für ca. 2s angehalten und wieder losgelassen. Im
Bild mit anti-Windup sieht man, dass der 1. Überschwinger deutlich
kleiner ist. Ohne Anti-Windup wird er umso größer, je länger ich den
Lüfter anhalte.
Sven wrote:
>> (unsigned int) y = prop + integ + diff; // Ausgangsstellgröße>> Sorry, müsste das nicht>> y = (unsigned int)(prop + integ + diff);>> heissen ?>> Ich lerne gerne dazu....>> Gruß Sven
sorry... stimmt... wollen ja ANSI C proggen... geht nur in C++ !!!
@THM: Das stimmt schon so... Ich muss ja das ganze "Spektrum" vom
I-Anteil ausnützen können... und ich fange mit 0 an -> also integ<=0
Ich probiere nicht aus, weil ich keinen µC grad bei der Hand hab -> muss
ja so auch gehn ^^
>Ich probiere nicht aus, weil ich keinen µC grad bei der Hand hab
Aber ich! :)
Mit größer-gleich geht's nicht. Mit größer schon.
Das Problem ist, wie erkenne ich ob der Ausgang übersteuert ist (z.B.
1028) oder ob er bei genau 1023 ist. Das geht nur, wenn ich ein Bit
abziehe. Darum der 'größer', bzw. 'kleiner'-Verleich anstatt >=, bzw <=.
Wie iniitierst du denn das ganze?
integ muss 0 gesetzt werden sonst nimmt das einen bullsh** an...
Also es muss bei 0 genauso funktionieren deshalb ja integ<=0
Ja, also probiern hat seinen Wert ^^
Bin nich zuhause - also µC-los heul
>Wie iniitierst du denn das ganze?
Kp = 18;
I = 12;
D = 0;
w = 50;
Den ganzen Rest mit 0.
Also esum ist ja das Element, das integriert wird. Wenn ich dieses
einfriere, also den Wert bei überschreiten der Übersteuergrenze (0 und
1023) halte (nicht 0 setzen!), dann bleibt esum außerhalb der
Übersteuergrenzen auf einem konstanten Wert und der Regler 'fängt' sich
bei Rückkehr in den Regelbereich an dem Punkt wieder, an dem das
Stellglied übersteuert wurde. Von dort arbeitet er wieder korrekt.
Wenn du integ auf 0 setzt fängt das ganze furchtbar an zu schwingen,
sobald einmal die Übersteuergrenze überschritten war.
Ok schon gesehen ^^
Von Thomas sind dort auch ein paar SEHR interessante Aspekte bezüglich
Optimierung gekommen...
Vllt teilen wir das ganze in PID_init und in PID_cyclic od. so... Damit
man sich dann wirklich keine Sorgen machen muss und sonst noch was "dazu
pfuschen"...