Hallo zusammen,
Bei einem PI Regler bereitet mir der I Anteil scheinbar durch die
Skalierung Schwierigkeiten. Der Code ist im Q15 Format, jede Größe damit
um 32768 skaliert.Die P und I Koeffizienten werden auf einen Wert
kleiner 1 normiert und anschließend nach Q15 umgewandelt.
Das Problem tritt immer bei dem Anti Windup (Abfrage auf 512) auf. Die
Variable x_integral für den I-Anteil wird schon im ersten Durchgang zu
groß, das es durch den Anti-Windup begrenzt wird. Selbst bei kleinen
Fehlern.Eigentlich kann das Problem nur in der Skalierung liegen (das
gleiche mit floating point funktioniert einwandrei). Aber ich finde den
Fehler einfach nicht.
Chris schrieb:> Eigentlich kann das Problem nur in der Skalierung liegen (das> gleiche mit floating point funktioniert einwandrei). Aber ich finde den> Fehler einfach nicht.> #define KI 2.75> #define KI_NORM (KI / 64.f)> #define KI_Q15 Q15(KI_NORM*32768)
Das ist doppelt gemoppelt. Q15(x) rechnet schon x*32768. Bei deinem
Macro rechnest du x*32768*32768. Ergo. K.I.S.S.
außerdem würde ich auch x_integral als IQ15 nutzen, denn damit hat man
mehr Auflösung. Die verschecnkst du, wenn du x nur als Int mit dem
kleinen Zahlenbereich von -515 - 512 nutzt. Das Zurückwandeln von IQ15
nach Int macht man erst, wenn ein Hardwareregister, z.B. einer PWM
geschrieben wird.
Klaus W. schrieb:> Was ist e und was ist error?
Wahrscheinlich hat der OP nicht den Orignalquelltext kopiert sondern aus
dem Gedächtnis hingeschrieben, und dabei neue Fehler eingebaut! So macht
man es NICHT!
Falk B. schrieb:> Klaus W. schrieb:>> Was ist e und was ist error?>> Wahrscheinlich hat der OP nicht den Orignalquelltext kopiert sondern aus> dem Gedächtnis hingeschrieben, und dabei neue Fehler eingebaut! So macht> man es NICHT!
Ja richtig. Sorry dafür.
->
#define KI_Q15 Q15(KI_NORM)//*32768
und e = error
Chris schrieb:> Ja richtig. Sorry dafür.> ->> #define KI_Q15 Q15(KI_NORM)//*32768
Immer noch Unsinn. Bring mal bissel Ruhe und Ordnung in dein Denken.
Q15 IST die Normierung! Da normiert man vorher nichts!
> und e = errorhttps://www.mikrocontroller.net/articles/Netiquette#%C3%84u%C3%9Fere_Form
"Quelltext nie abtippen, sonder immer das direkt kopierte Original
posten, anderenfalls schleichen sich neue Fehler ein oder die
existierenden werden nicht abgeschrieben."
Bei TI wird das Thema der Festkommazahlen so gehandhabt, wenn gleich das
immer 32 Bit sind. Hier mal für 16 Bit.
Die Typdefinitioen ist nützlich, weil sie zeigt, welches Format die
Variabeln haben, auch wenn es nut ein anderer Name für int ist!
Das Makro ermöglicht eine einfache Handhabung von Fließkommazahlen im
Quelltext.
1
typdefintiq15_t;
2
#define _IQ15(x) (int)((x)*32768.0)
3
#define IQ152INT(x) ((int)(x)>>15)
4
#define SCALE_USOLL 543.3L // 500V = 100% = ADC Maximum, Skalierungsfaktor immer als Fließkomma angeben, sonst stimmt die Rechnung nicht
5
6
iq15_tki,kp,kd,prop,integral,diff,e,out;
7
iq15_tusoll,uist;
8
9
10
kp=_IQ15(1.0);
11
ki=_IQ15(2.5);
12
kd=_IQ15(0);
13
usoll=(455.6/SCALE_USOLL);
14
15
// PID Regler
16
// alles mit Festkommarechung
17
voidPID(void){
18
uist=ADC_WERT<<3;// 12 Bit ADC auf IQ15 konvertiert
19
e=usoll-uist;// Regelabweichung
20
// cast nötig, um Überlauf zu vermeiden, anschließend wieder auf IQ15
Falk B. schrieb:> Chris schrieb:>> Ja richtig. Sorry dafür.>> ->>> #define KI_Q15 Q15(KI_NORM)//*32768>> Immer noch Unsinn. Bring mal bissel Ruhe und Ordnung in dein Denken.> Q15 IST die Normierung! Da normiert man vorher nichts!>>> und e = error>> https://www.mikrocontroller.net/articles/Netiquette#%C3%84u%C3%9Fere_Form>> "Quelltext nie abtippen, sonder immer das direkt kopierte Original> posten, anderenfalls schleichen sich neue Fehler ein oder die> existierenden werden nicht abgeschrieben."
Es wird hier auf einen Bereich kleiner 1 normiert(Q15!). Dann nach Q15
gewandelt. Das passt schon so.
Gruß
Chris
Falk B. schrieb:> Bei TI wird das Thema der Festkommazahlen so gehandhabt, wenn gleich das> immer 32 Bit sind. Hier mal für 16 Bit.> Die Typdefinitioen ist nützlich, weil sie zeigt, welches Format die> Variabeln haben, auch wenn es nut ein anderer Name für int ist!> Das Makro ermöglicht eine einfache Handhabung von Fließkommazahlen im> Quelltext.
Danke Falk. Schönes Beispiel.
Aber kurze Frage dazu: Sollten die Koeffizienten nicht auf einen Wert
kleiner 1 gebracht werden?
Chris schrieb:> Danke Falk. Schönes Beispiel.> Aber kurze Frage dazu: Sollten die Koeffizienten nicht auf einen Wert> kleiner 1 gebracht werden?
Kann man machen, muss man nicht. Ach so, wenn man nur IQ15 mit 16 Bit
darunter hat, dann schon ;-) (ich war in Gedanken bei 32 Bit bei TI)
Klopp dieses Q15 in die Tonne. Das Einzige, was ich davon verstehe ist,
dass es nur 15bit plus Vorzeichen bringt. Mach's Einfacher mit signed 32
bit. Die Werte skalieren kannst du dir sparen, das bringt wenig.
Gleich mit vernuneftigen ADC Werten loslegen
Mein Regelungsalgorithmus rechnet in ADC Einheiten. Der Sollwert ist als
ADC Wert gegeben (zB 25173 falls 16bit), und der Regelfehler = ADC Soll
- ADC ist wird auf Null geregelt. Die Rechnungen laufen in Signed 32bit.
Purzel H. schrieb:> Klopp dieses Q15 in die Tonne. Das Einzige, was ich davon verstehe ist,> dass es nur 15bit plus Vorzeichen bringt. Mach's Einfacher mit signed 32> bit. Die Werte skalieren kannst du dir sparen, das bringt wenig.> Gleich mit vernuneftigen ADC Werten loslegen
Jaja, nix verstanden aber groß rumlabern. BRAVO!
Beitrag "Re: PID Regler in Q15 Format"
Naja, das Beispiel war halt mal schnell hingeschrieben, sind natülich
ein paar Fehler drin. Wenn man IQ15 mit 16 Bit darstellt, müssen
natürlich alle Zahlen <1 sein. Man muss auch genügend Spielraum für die
Begrenzung des I-Anteils lassen, denn vor der Begrenzung darf durch die
Integration kein Überlauf auftreten. 0.5 klingt brauchbar. Ggf. muss man
vorher den Fehler schon begrenzen.
Ich hab mal die Doku von TI zum Thema IQ Mathematik angehängt, da kann
man sich was abschauen und kopieren. Das ist ein pragmatischer Ansatz.
Für einfache Regler sind 16 Bit OK (8-10 Bit ADC, DAC und PWM), wenn es
besser, genauer und mit weniger Stress laufen soll, nimmt man besser
IQ24 mit 32 Bit.
Danke. Das PDF ist wirklich brauchbar.
Man sieht häufig, auch auf 16Bit DSP's(uC) explizite Castings bei
Multiplikationen,Additionen... .
(siehe Falks Beispiel: integral += ((int32t)ki*e)>>15;)
Mir ist schon klar warum, aber was bedeutet das für die Effizienz der
Berechnung? Was macht der Compiler damit? Ich vermute, dieser emuliert
32Bit, was bedeuten würde, das die Laufzeit einbricht. Bin mir aber
nicht sicher. Wenn man gezwungen ist, auf 16Bit Breite zu arbeiten, wie
effizient ist das ganze dann noch, wenn man Overflows zu 100% vermeiden
möchte?
Gruß
Chris
Das kann man nicht pauschal sagen.
Um das zu beantworten, müsste man genau betrachten wo man im konkreten
Programm welche Wertebereiche hat.
Eingebaute Tests würden ja auch wieder Zeit kosten...
Entweder arbeitet man sich Stück für Stück manuell durch, oder man
instrumentiert Code (ggf. mit Echtdaten auf einem stärkeren Rechner) und
schaut, wieweit die Zahlenbereiche genutzt werden und wie weit man vom
Überlauf entfernt bleibt.
In der Produktionsversion könnte man die Instrumentierung ja wieder
entfernen.
Chris schrieb:> Man sieht häufig, auch auf 16Bit DSP's(uC) explizite Castings bei> Multiplikationen,Additionen... .> (siehe Falks Beispiel: integral += ((int32t)ki*e)>>15;)> Mir ist schon klar warum, aber was bedeutet das für die Effizienz der> Berechnung? Was macht der Compiler damit? Ich vermute, dieser emuliert> 32Bit, was bedeuten würde,
Was heißt denn emuliert? Er führt die Rechung mit 32 Bit Integern durch.
> das die Laufzeit einbricht.
Nun übertreib mal nicht. Der Witz von Festkommaarithmetik ist, daß
die meisten Rechungen eben mit Integern laufen, was auf praktisch allen
CPUs recht schnell geht. Fließkomma wird weitestgehend vermieden,
bestenfalls beim Normieren und Denormieren wird das gebraucht.
> Bin mir aber> nicht sicher. Wenn man gezwungen ist, auf 16Bit Breite zu arbeiten,
Ist man das? Wo denn? Auch 8 Bitter können 32 Bit Rechnungen.
> wie> effizient ist das ganze dann noch, wenn man Overflows zu 100% vermeiden> möchte?
Es ist vor allem aufwändiger, diese durch Zwischenrechnungen und
Skalierungen abzufangen. Das ist vor allem Programmier- und Testaufwand,
weniger Rechnenaufwand für die CPU. Die 16 Bit IQ15 Zahlen brauchen halt
den halben Speicher wie die 32 Bit Versionen. Die wenigen Rechnungen,
die halt mit 32 Bit gemacht werden müssen, sind für den Programmierer
"unsichtbar" und kosten die CPU auch wenig Zeit.
Bei einem 16Bit DSP oder Prozessor haben alle Register nur 16 Bit zur
Verfügung. Man kann zwar mit 32 Bit Variablen rechnen oder eben explizit
casten, aber das wird wahrscheinlich doch nicht so effizient sein als
mit der von der Architektur vorgebener Bandbreite an Bits.Oder habe ich
einen Denkfehler?