Forum: Mikrocontroller und Digitale Elektronik PID Regler in Q15 Format


von Chris (Gast)


Lesenswert?

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.
1
#define KI 2.75
2
#define KI_NORM (KI / 64.f)
3
#define KI_Q15 Q15(KI_NORM*32768) 
4
5
Ki = KI_Q15;
6
7
e = ref - meas;
8
9
x_integral = x_integral + ((Ki * error) >> 15);
10
11
//wind up
12
13
if(x_integral >512) 
14
//32768/64
15
   x_integral = 512;
16
17
else if(x_integral < -512)
18
   x_integral = -512;
19
20
x_prop = ((x_prop * error) >> 15);
21
22
out = x_prop  + x_integral;
23
24
out = (out *64);

Danke fuer eure Hilfe.

(Mod: [c] Token eingefügt)

: Bearbeitet durch Moderator
von Falk B. (falk)


Lesenswert?

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.

: Bearbeitet durch User
von Klaus W. (mfgkw)


Lesenswert?

Was ist e und was ist error?

Ich glaube aus dem Wenigen kann man nicht viel erraten..

von Falk B. (falk)


Lesenswert?

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!

von Chris (Gast)


Lesenswert?

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

von Falk B. (falk)


Lesenswert?

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."

von Falk B. (falk)


Lesenswert?

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
typdef int iq15_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_t ki, kp, kd, prop, integral, diff, e, out;
7
iq15_t usoll, 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
void PID(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 
21
  skalieren
22
  integral += ((int32t)ki*e)>>15;
23
  if (integral > IQ15(10)) {
24
    integral = IQ15(10);
25
  } else if (integral < IQ15(-10)) {
26
    integral = IQ15(-10);
27
  }
28
29
  prop = e * kp;
30
  diff = e * kd;
31
  out = prop + integral + diff;
32
  // Stellgröße denormieren
33
  // 8 Bit PWM, also nur 15-8=7 Bits schieben
34
  PWM_REG = out>>7;
35
}
36
37
// denormierte Ausgabe zur Anzeige
38
// benutzt Fließkomma
39
u_real = IQ152INT(uist*SCALE_USOLL);

: Bearbeitet durch User
von Chris (Gast)


Lesenswert?

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

von Chris (Gast)


Lesenswert?

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?

von Falk B. (falk)


Lesenswert?

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)

von Purzel H. (hacky)


Lesenswert?

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

von Purzel H. (hacky)


Lesenswert?

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.

: Bearbeitet durch User
von Falk B. (falk)


Lesenswert?

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!

von Falk B. (falk)


Angehängte Dateien:

Lesenswert?

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.

von Chris (Gast)


Lesenswert?

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

von Klaus W. (mfgkw)


Lesenswert?

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.

von Falk B. (falk)


Lesenswert?

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.

von Chris (Gast)


Lesenswert?

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?

von Klaus W. (mfgkw)


Lesenswert?

Ist schon richtig.

Aber wenn 16*16bit nicht in 16 bit passen, bis man es wieder zurecht 
schiebt, muß es halt sein.

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.