Ich hatte die Tage etwas, ich sag mal, langeweile und hab mal mein altes
Regelungstechnikwissen ausgepackt und auf nem AVR (konkret: Atmega328P)
einen PID-Regler zusammen gestrickt.
Als Regelstrecke hab ich einen simplen Tiefpass mit 10kOhm und 100µF
aufgebaut, die von einer 8 Bit PWM gespeist wird.
Der Regler soll die PWM so regeln, dass sich die Ausgangsspannung des
TPs auf einen bestimmten Wert einstellen soll.
Das funktioniert auch Super, da kann ich nicht klagen (hab ein Bild und
die Messdaten hier mal angehangen).
Mir ist bewusst, da ich hier beim PID floats benutze, ist das nicht die
schnellste Implementierung. Ich hab mal mit Timer1 die Counts gezählt,
die die Funktion pid() benötigt und bekomme hier so rund 2500-2700
Counts. Da der AVR bei mir mit 8 MHz läuft bedeutet dies, dass die
Berechnung so rund 325µs dauert.
Die Frage, die sich mir nun noch stellt, und die ich bisher nicht
ermitteln konnte: Ist das für einen PID-Regler langsam, normal oder
schnell? Wie schnell sollte eine Berechnung der Werte erfolgen? Wie
schon gesagt, mir ist klar, dass es auch schneller geht, mir fehlt jetzt
nur das Gespür dafür, wie schnell meine Implementierung ist.
1
#include<stdlib.h>
2
#include<avr/io.h>
3
#include"uart.h"
4
5
6
#define SETVALUE 2.0
7
8
charvalueToPrint[6];
9
uint16_tadcValue;
10
volatileuint16_ti=0;
11
volatilefloatvoltage;
12
13
typedefstructPID_CONTROLLER{
14
floatkpFactor;
15
floatkiFactor;
16
floatkdFactor;
17
floattaFactor;
18
floatlastValue;
19
floaterror;
20
floatlastError;
21
floatpreLastError;
22
}pid_controller_t;
23
24
#define KP 8000.0
25
#define KI 2.0
26
#define KD 0.4
27
//Abtastzeit: ADC-Prescaler=64, 13 Zyklen für eine Wandlung und F_CPU = 8 MHz => ca 0.1 ms
Kommt drauf an, was du damit steuern möchtest.
Ich habe PID-Regler für Heizung und Kühlung. Dort brauchen Messwerte nur
alle paar Sekunden aufgenommen werden. Die Regelung arbeitet noch
langsamer.
Da könnte die CPU auch im KHz Bereich laufen.
Die Zykluszeit der Regelung (Regler+ Stellglied) sollte im Idealfall
viel schneller wie die Zeitkonstante der Strecke. Wenn das nicht mehr
der Fall ist muss man die analoge Naeherung verlassen und einen
digitalen Regler implementieren.
Die analoge Naeherung bedeutet der PID verhaelt sich intuitiv. Man kann
an den Parametern drehen zum optimieren.
Jetzt ist G. schrieb:> muss man die analoge Naeherung verlassen und einen> digitalen Regler implementieren.
Er hat bereits einen digitalen Regler, von einem analogen war nie die
Rede, oder was meinst Du damit?
M. K. schrieb:> Wie schnell sollte eine Berechnung der Werte erfolgen?
Nur Du kennst Deinen Regelkreis und weißt, wie schnell er sein muß.
Du hast nen Haufen Divisionen durch Konstanten drin, die kann man bequem
aus der Schleife herausziehen.
Jetzt ist G. schrieb:> Die Zykluszeit der Regelung (Regler+ Stellglied) sollte im Idealfall> viel schneller wie die Zeitkonstante der Strecke.
Das ist so nicht uneingeschränkt richtig. Je kleiner die Zykluszeit des
Reglers, desto kleiner (als Zahlenwert) werden deine Parameter, und
zumindest bei 8 Bit Systemen wo man float vereiden möchte kommst du da
ganz schnell an die Grenze für deine Festkommaarithmetik und die
Rundungsfehler erhöhen sich dann auch irgendwann bei float.
Jetzt ist G. schrieb:> Die analoge Naeherung bedeutet der PID verhaelt sich intuitiv.
Was bitte ist intuitiv? Bei einem digitalen PID hast du doch genauso
Parameter für den P, den I und den D Teil, das verhält sich nicht
grundlegend anders.
Bei so einfachen Strecken wie ein PT1 oder PT2 kann man dann auch mal
mit "einfachen" Optimierungsverfahren wie Ziegler Nichols, Chien &
Reswick, etc.
spielen.
Ich bin schon ewig aus dem Thema raus, aber wenn ich mich richtig
erinnere ist ein guter Wert für die Zykluszeit des Reglers 6-10 mal
schneller als die Haupt-zeitkonstante der Strecke. (Ohne Garantie)
Nachtrag:
Auf jeden Fall sollte man die Reger-Zykluszeit konstant machen
(Timergesteuert) und nicht von der Berechnungszeit abhängig lassen, denn
wenn aus welchen Gründen auch immer sich die Berechnungszeit und damit
die Zykluszeit verkleinert, dann erhöhen sich die effektiven Parameter
für den P, I und D Teil und vice versa.
Bernd K. schrieb:> Er hat bereits einen digitalen Regler, von einem analogen war nie die> Rede, oder was meinst Du damit?
Er meint, dass sich ein digital implementierter PID-Regler nur für kurze
Zykluszeiten (verglichen mit der Regelstrecke) auch so verhält, wie es
ein analoger PID-Regler in der Theorie täte.
Wenn der Regler zu langsam wird, gibt es seltsame Effekte, z.B. dass die
Parameter nicht mehr das erwartete Verhalten zeigen.
Peter D. schrieb:> M. K. schrieb:>> Wie schnell sollte eine Berechnung der Werte erfolgen?>> Nur Du kennst Deinen Regelkreis und weißt, wie schnell er sein muß.> Du hast nen Haufen Divisionen durch Konstanten drin, die kann man bequem> aus der Schleife herausziehen.
Hö? Wo hab ich das denn drin oder meinst du das vor dem Hintergrund,
dass ja KP, KD usw. alles Konstanten sind? Das ist zwar bei diesem
Beispiel richtig aber ich will ja ggf. später mal andere Werte benutzten
und ggf. auch mehr als nur einen Regler einsetzen mit unterschiedlichen
Werten. Daher müssen KP und Co als Variablen vorgesehen werden.
@all
Die Frage war nicht, wie schnell ist die Regelung sondern ob die
Berechnung der diskreten Stell-Werte denn für einen PID-Regler langsam,
normal oder schnell ist. Ich denke das geht hier ein wenig unter grade.
Mir ist natürlich schon klar, dass die Regelgeschwindigkeit am Ende auch
zu meiner Regel-Strecke passen muss.
Aber das ist ja gar nicht die Frage. Die Frage ist lediglich: Ist die
Berechnung der Stell-Werte besonders schnell, besonders langsam oder ist
das für einen digitalen Regler eine normale Geschwindigkeit. Hier fehlt
mir einfach das Gefühl dafür.
Ich hatte auch mal den PID aus der AVR221 benutzt, da werden die
Stell-Werte ca. 1000 Zyklen schneller berechnet was aber auch meine
Erwartungshaltung entsprach da diese PID mit Festkommaarithmetik rechnet
und das schon per se auf dem AVR schneller läuft als die
Gleitkommaarithmetik, die ich einsetze.
Bernd K. schrieb:> Jetzt ist G. schrieb:> muss man die analoge Naeherung verlassen und einen> digitalen Regler implementieren.>> Er hat bereits einen digitalen Regler, von einem analogen war nie die> Rede, oder was meinst Du damit?
Er meint die Reglerauslegung kann bei einer langsamen Strecke wie ein
Analog- (d.h zeitkontinuierlicher) Regler ausgelegt werden. Ist die
Strecke schnell, dann dann funktioniert das nicht mehr. Beispiel: Eine
Stromregelung, wo nach 4 Reglertakten der Sollwert erreicht ist. Wuerde
man den Regler zeitkontinuierlich auslegen, dann wuerde er
ueberschiessen, da beim Annaehern an den Sollwert der Ausgang nicht
rechtzeitig nachgeregelt (reduziert) wird. Die zeitdiskrete Auslegung
beruecksichtigt diese Zeiten, Stichwort Z-Transformation.
M. K. schrieb:> Die Frage war nicht, wie schnell ist die Regelung sondern ob die> Berechnung der diskreten Stell-Werte denn für einen PID-Regler langsam,> normal oder schnell ist. Ich denke das geht hier ein wenig unter grade.
Wenn deine Strecke schnell ist, musst du schnell nachfuehren. Deine
Abtastrate ist also immer von der Strecke abhaengig. Natuerlich darf die
Abtastrate auch beliebig hoeher sein, ist also nur eine untere Grenze.
M. K. schrieb:> Die Frage ist lediglich: Ist die> Berechnung der Stell-Werte besonders schnell, besonders langsam oder ist> das für einen digitalen Regler eine normale Geschwindigkeit.
Nochmal: "Normal" gibts nicht, ob es schnell genug oder zu langsam ist
hängt von der Regelstrecke ab.
Wenn Du eine Heizplatte regeln willst die 10 Minuten braucht bis sie
aufgeheizt ist würde wahrscheinlich ein Zyklus alle paar Sekunden
reichen, wenn Du die Fluglage eines 250g leichten Multikopters regeln
willst der in 2 Sekunden von 0 auf 150km/h kommt, in 200ms eine volle
Rolle macht und danach wieder wie angenagelt waagerecht in der Luft
stehen können soll wirst Du mehrere kHz brauchen.
Vieleicht solltest du die Kernfrage mal deutlicher machen:
M. K. schrieb:> Ich hab mal mit Timer1 die Counts gezählt,> die die Funktion pid() benötigt und bekomme hier so rund 2500-2700> Counts. Da der AVR bei mir mit 8 MHz läuft bedeutet dies, dass die> Berechnung so rund 325µs dauert.>> Die Frage, die sich mir nun noch stellt, und die ich bisher nicht> ermitteln konnte: Ist das für einen PID-Regler langsam, normal oder> schnell?
Nur was für eine Antwort erwartest du hier?
Um auf der sicheren Seite zu bleiben würde ich mit so einem Algorithmus
maximal Regler auslegen die nicht schneller sein müssen als 1ms
Zykluszeit (500µs wäre das absolute Maximum).
Siehe mein Beitrag oben zu konstanter Zykluszeit.
Hallo,
um kurz auf die Frage zurückzukommen:
M. K. schrieb:> Die Frage, die sich mir nun noch stellt, und die ich bisher nicht> ermitteln konnte: Ist das für einen PID-Regler langsam, normal oder> schnell? Wie schnell sollte eine Berechnung der Werte erfolgen? Wie> schon gesagt, mir ist klar, dass es auch schneller geht, mir fehlt jetzt> nur das Gespür dafür, wie schnell meine Implementierung ist
es kommt wie bereits gesagt auf die Anwendung an, ob man das als schnell
oder langsam betrachtet. Als Beispiel, bei einer Anwendung wie der
digitale Regelung eines Schaltnetzteils wäre das deutlich zu langsam,
dort soll oft (ideal) in jedem Schaltzyklus ein neuer Wert berechnet
werden bei 100kHz Schaltfrequenz heißt das <10us bleiben um die analogen
Werte einzulesen, Regler zu berechnen und das Ausgangssignal (PWM
Register) zu ändern. Dort wären bspw. Rechenzeiten von 1-3us angepeilt.
Wobei dann eine Realisierung nur dann mit float sinnvoll ist, wenn der
Prozessor FPU hat, ansonsten halt fixed-point-arithmetic.
Gruß Regler
M. K. schrieb:> Hö? Wo hab ich das denn drin oder meinst du das vor dem Hintergrund,> dass ja KP, KD usw. alles Konstanten sind? Das ist zwar bei diesem> Beispiel richtig aber ich will ja ggf. später mal andere Werte benutzten> und ggf. auch mehr als nur einen Regler einsetzen mit unterschiedlichen> Werten. Daher müssen KP und Co als Variablen vorgesehen werden.
Sie sind während der Regelschleife konstant.
Du mußt sie daher nur dann neu berechnen, wenn Du sie auch änderst.
Divisionen sind recht langsam. Daher lohnt es sich, sie aus der Schleife
heraus zu ziehen.
Peter D. schrieb:> Sie sind während der Regelschleife konstant.> Du mußt sie daher nur dann neu berechnen, wenn Du sie auch änderst.> Divisionen sind recht langsam. Daher lohnt es sich, sie aus der Schleife> heraus zu ziehen.
Ja, genau das ist ja auch die Idee der Variablen. Es soll ja flexibel
sein sodass ich die Parameter ändern kann. Eine Idee/Anwendung wäre ja
vielleicht, dass ein AVR drei unterschiedliche Strecken regeln soll.
Wenn man natürlich nur einen Regler auf eine konkrete Anwendung braucht
hast du sicher recht, dann kann man alle Konstanten vorher berechnen und
rausziehen um das System so noch schneller zu machen.
Udo S. schrieb:> Nur was für eine Antwort erwartest du hier?> ...
Es gibt halt verschiedenste Reglerimplementierungen und ich frage mich,
wie schnell ist meine Implementierung im Vergleich zu anderen. Ich
stimme dir da auch völlig zu: Meinen Regler würde ich hier auch nur bei
Systemen einsetzen, die 1ms oder langsamer sind. Die 500 us wären mir
schon zu kritisch.
Au weia schrieb:> Der Regler muß zur Strecke passen. Zu langsam ist genau so Mist wie zu> schnell....
Die Frage ist ja nicht, wie schnell der Regler an sich ist (das wird ja
durch die Parameter eingestellt) sondern wie schnell die Berechnung ist
;)
M. K. schrieb:> Eine Idee/Anwendung wäre ja> vielleicht, dass ein AVR drei unterschiedliche Strecken regeln soll.
Auch das ändert nichts daran, daß sie während der Regelung konstant
bleiben. Du brauchst ja eh 3 Structs dafür.
Man sollte immer alle unnötigen Berechnungswiederholungen aus Schleifen
heraus ziehen. Das erleichtert auch das Verständnis, was in der Schleife
wirklich passiert.
Der Compiler ist auch nicht dumm. Wenn er merkt, daß sich die Werte zur
Laufzeit nicht ändern, dann zieht er selber die Berechnungen raus und
führt sie schon zur Compilezeit aus.
Aber sobald Du die Werte zur Laufzeit änderst, bleiben die unnötigen
Wiederholungen in der Schleife drin und die Ausführungszeit kann sich
deutlich verlängern.
Dann weiß ich nicht, welche Konstanten du genau meinst bzw. ich wüsste
jetzt nicht so spontan welche Konstanten ich da raus ziehen kann/soll.
Kannst du das mal an einem Beispiel festmachen? Ich stelle mir das grade
so vor:
Ich versteh da grad nicht wie ich aus der Funktion pid() die
"Konstanten" rausziehen soll. Die sind doch vom jeweiligen Controller
abhängig, also Variable.
Peter D. schrieb:> M. K. schrieb:>> controller->kdFactor/controller->taFactor>> usw.
Achso meinst du das...ja, das macht Sinn. Hatte da grade nen Knoten im
Kopf.
Lehn den an die Tonne, der ist einer Heizung nicht gerecht.
Beim normalen PID uebernimmt der I Anteil den Waermeverlust, welcher mit
der Temperaturdifferenz nur Umgebung zunimmt. Dies loest man
sinnvollerweise mit einem Vorwaertspfad, der die statische
Waermeleistung uebernummt.
Also
Stellglied = (Tsoll-Tambient)x a1 + P x error + integrator
mit a1 einer proportionalitaetskonstante. Allenfalls kann dort auch eine
Tabelle stehen. Muss nich allzu genau sein. Es ist viel schneller als
den Integrator die Arbeit machen zu lassen.
Jetzt ist G. schrieb:> Lehn den an die Tonne, der ist einer Heizung nicht gerecht.> Beim normalen PID uebernimmt der I Anteil den Waermeverlust, welcher mit> der Temperaturdifferenz nur Umgebung zunimmt.
Es ging aber erstmal nur um einen "normalen" PID wie er im Buch steht.
Das Rausrechnen von irgendwelchen Dreckeffekten oder Nichtlinearitäten
hinter oder vor dem Regler von denen man das Glück hat sie mathematisch
halbwegs modellieren zu können damit der eigentliche Regler es leichter
hat ist dann erst das nächste Kapitel.
M. K. schrieb:> wie schnell ist meine Implementierung im Vergleich zu anderen.
habe deine pid() Funktion gerade mal in meinem STM32F407 reingeworfen,
0,54 µs braucht der für die Berechnung mit seiner FPU.
Johannes S. schrieb:> habe deine pid() Funktion gerade mal in meinem STM32F407 reingeworfen,> 0,54 µs braucht der für die Berechnung mit seiner FPU.
Interessant. Bei welcher Taktrate des STM denn? Hast du vielleicht auch
noch Vergleichswerte mit anderen PID-Implementierungen bei gleicher
Taktrate mit dem STM? Dank dir schonmal für den Test ;)
es ist das hier schon öfter erwähnte Board (die "Black" Variante, <10€):
http://wiki.stm32duino.com/index.php?title=STM32F407
CPU Takt ist 168 MHz und FPU aktiv.
https://www.st.com/en/microcontrollers/stm32f407ve.html
Das ist natürlich eine andere Kategorie als ein kleiner 8 Bitter, aber
einfach mal so als Hausnummer wieviel schneller die tatsächlich sind. Da
braucht man jedenfalls keine Angst mehr vor floats zu haben :)
Hier sieht man das alles nur in die FPU geschoben und verrechnet wird:
wichtig ist noch das man auch alles in float und nicht in double macht.
Beim AVR wird da nicht unterschieden, aber beim ARM ist eine Konstante
'0.8' ein double und dann werden die Berechnungen auch im ARM länger und
der Code wird grösser. Da muss man gut aufpassen wenn man Code von
Arduino Libs portiert.
Johannes S. schrieb:> Beim AVR wird da nicht unterschieden, aber beim ARM ist eine Konstante> '0.8' ein double und dann werden die Berechnungen auch im ARM länger und> der Code wird grösser. Da muss man gut aufpassen wenn man Code von> Arduino Libs portiert.
Oh ja, das kenn ich in ähnlicher Richtung. Bin schon gefragt worden,
warum ich bei der ein und anderen Stelle "nur" floats benutze und kein
double, wäre doch...µC war ein ATTiny85. Musste ich auch erstmal
aufklären, dass bei dem AVR kein Unterschied zwischen float und double
besteht und ichs nicht mag wenn man was vorgegaukelt bekommt, was nicht
drin steckt.
weil ich gerade dabei war habe ich die gleiche Routine nochmal auf zwei
anderen Boards laufen lassen.
1
STM32L031 @ 32 MHz (Cortex-M0+)
2
gcc 6.3.1 -Os: 38,6 µs
3
gcc 6.3.1 -O3: 39,5 µs
4
5
gcc 7.2.1 -Os: 39,3 µs
6
gcc 7.2.1 -O3: 39,8 µs
7
8
Keil: 24,3 µs
9
10
LPC1549 @ 72 MHz (Cortex-M3)
11
gcc 7.2.1 -0s: 19,3 µs
12
gcc 7.2.1 -O3: 9,5 µs
Auffällig ist die immer noch die stiefmütterliche Behandlung des
Cortex-M0. Optimierung Os und O3 bringt kaum einen Unterschied, O3 ist
hier sogar noch langsamer. Beim Cortex-M3 wird die Ausführung um Faktor
2 schneller bei O3, das sieht gut aus. Gegenüber dem M0 ist der M3
offensichtlich nur wegen dem doppelten Takt auch doppelt so schnell, das
der M3 ein Hardware Div kann scheint nix zu machen. Oder hatte der M0+
das auch? Weiss ich gerade nicht.
Die Keil Version ist mit dem mbed Online erstllt, der ist beim M0 immer
noch deutlich besser als der gcc.
Ist jetzt nicht ganz das PID Thema aber man sieht das die Compiler
Optimierung hier auch noch eine Menge ausmachen kann.
Die Testroutine ist die PID Funktion aus dem ersten Post die 1000x
aufgerufen wird und die Zeitdifferenz in µs Auflösung (mbed os Timer)
gemessen wird.
Ich hab jetzt heute noch mal ein wenig gespielt. Wie peda schon
empfohlen hat hab ich die konstanten Faktoren raus genommen und nebenbei
festgestellt, dass ich beim zweiten Summanden bei KI den Faktor TA
vergessen hatte, lehrbuchmäßig hätte das KI*TA sein müssen aber das TA
hatte ich vergessen.
However, durch das Rausziehen der Konstanten ist die Berechnung nochmal
rund 1000 Zyklen schneller geworden und braucht nun "nur" noch rund 1700
Zyklen.
Damit ich auf dem AVR auch noch einen konkreten Vergleich bekomme habe
ich den PID-Regler aus er Appnote AVR221 implementiert. Dieser braucht
etwa 1000 Zyklen, ist also erwartungsgemäß deutlich schneller.
Zu guter Letzt hatte ich dann mal meinen PID-Regler auf
Festkommaarithmetik umgebaut und war darüber überrascht: Mit
Festkommaarithmetik braucht meine PID-Lösung grad mal rund 320 Zyklen.
Das ist eine enorme Steigerung die ich in dieser Größenordnung nicht
erwartet hatte.
Allerdings ist die gewählte Teststrecke etwas ungünstig, bei der
Festkommaarithmetik ists nicht so einfach mal grob aus der Hüfte zu
schießen und hier passende Parameter zu finden, sodass es keinen Über-
bzw. allgemeine Schwinger gibt. Da werd ich mir dann erst bei einem
konkreten Problem mal Gedanken drüber machen.