Forum: FPGA, VHDL & Co. Problem mit PID Regler


von Dennis L. (eslon)


Lesenswert?

Hab versucht einen PID-Regler in VHDL zu basteln, als Vorlage diente ein 
Mathlab Block Diagramm.
Die jeweiligen Anteile sollen durch vorgegebene Werte für Kp, Ki, Kc 
festgelegt werden. Da jetzt mein Problem, ich kann ja nicht mit 0.5 oder 
0.1 rechnen. Wie kann ich das umgehen, bzw. zum Laufen bekommen ?

Hab gedacht man könnte real benutzen, geht aber wohl nicht -.-

1
          Kp : real   := 0.5;        -- P-Anteil
2
          Ki : real   := 0.1;       -- I-Anteil
3
          Kd : integer:= 0;         -- D-Anteil
4
          Kc : real  := 0.1      -- I-Korrektur
5
6
...
7
8
-- P-Anteil
9
    yp <= std_logic_vector(Kp * signed(e));
10
-- I-Anteil  
11
    yi <= std_logic_vector((Ki * signed(yp_alt)) + signed(yi_alt) + signed(aw)); 
12
-- D-Anteil    
13
    yd <= std_logic_vector(Kd *(signed(yd_alt) - signed(yp_alt)));
14
-- Ausgang vor Korrektur
15
    y_o <= std_logic_vector(signed(yp)+signed(yi)+signed(yd));
16
--Begrenzung
17
    y_m <= resize(y_o, 16);
18
-- Korrektur
19
    aw <= std_logic_vector(Kc * (signed(y_m) - signed(y_o)));

von Duke Scarring (Gast)


Lesenswert?

Dennis Lindner schrieb:
> Hab versucht einen PID-Regler in VHDL zu basteln,
Zur Simulation oder zur Synthese?

Duke

von Dennis L. (eslon)


Lesenswert?

Erstmal zur Simulation, sollte aber auch Synthese tauglich werden.

von Thomas R. (Firma: abaxor engineering) (abaxor)


Lesenswert?

Dennis Lindner schrieb:
> Da jetzt mein Problem, ich kann ja nicht mit 0.5 oder
> 0.1 rechnen. Wie kann ich das umgehen, bzw. zum Laufen bekommen ?


In VHDL-2008 gibt es auch Festkomma-Zahlen, also sfixed und ufixed. Die 
können auch kleiner 1 sein.

Falls du mit signed auskommen willst, musst du deine k-Faktor mit 2**n 
multiplizieren und zum Schluss von deiner Stellgröße n-Bit weglassen.

Tom

von Dennis L. (eslon)


Lesenswert?

Thomas Reinemann schrieb:
>
> In VHDL-2008 gibt es auch Festkomma-Zahlen, also sfixed und ufixed. Die
> können auch kleiner 1 sein.
>
> Falls du mit signed auskommen willst, musst du deine k-Faktor mit 2**n
> multiplizieren und zum Schluss von deiner Stellgröße n-Bit weglassen.

Wenn ich jedoch mein Faktor, der 0.1 ist mit 2**n multipliziere, dann 
komm ich ja auch nicht auf einen Integer Wert ohne zu runden. ?_?

von Thomas R. (Firma: abaxor engineering) (abaxor)


Lesenswert?

Dennis Lindner schrieb:
> Wenn ich jedoch mein Faktor, der 0.1 ist mit 2**n multipliziere, dann
> komm ich ja auch nicht auf einen Integer Wert ohne zu runden. ?_?

Willkommen in der Welt der binären Arithmetik.

Auf

http://www.h-schmidt.net/FloatApplet/IEEE754de.html

kannst du dir Single Gleitkommazahlen zusammen klicken, versuche mal 
eine 0.1 hinzubekommen?

Selbst dein vor dir stehender PC kann es nicht. Du kannst die 
Rundungsfehler nur minimieren.

Unabhängig davon, woher weißt du, dass du einen Reglerkoeffizienten von 
0.1 brauchst? Ich gehe mal davon aus, dass du den willkürlich festgelegt 
hast. Früher hat man Reglerkoeffizienten mit einem Poti eingestellt, 
alleine dessen Temperaturdrift war größer als der Rundungsfehler in 
binärer Arithmetik. Und der Rundungsfehler ist bekannt und konstant.

Tom

von Dennis L. (eslon)


Lesenswert?

Also wenn ich das Richtig verstanden habe, dann multipliziere ich meine 
faktoren mit 2**n, dann hab ich ein integer, notfalls gerunden, und dann 
rechne ich mit dem integer und dividiere dann am ente wieder mit 2**n ?

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Dennis Lindner schrieb:
> Also wenn ich das Richtig verstanden habe, dann multipliziere ich meine
> faktoren mit 2**n, dann hab ich ein integer, notfalls gerunden, und dann
> rechne ich mit dem integer und dividiere dann am ente wieder mit 2**n ?
Im Großen und Ganzen: Ja.
Oder du machst es wie so, dass du deinen Integer-Zahlenbereich statt auf 
-214783648..+214783647 (= -2^31--.2^31-1) als  -1..+0,99999999 
definierst.

Dann ist 10000000_00000000_00000000_00000000 = -1
und      00000000_00000000_00000000_00000000 = 0
und      01111111_11111111_11111111_11111111 = +0,99999999953

Und du bleibst auch bei Multiplikationen immer im definierten Bereich, 
denn -0,5*-0,5 = +0,25...  ;-)

von Thomas R. (Firma: abaxor engineering) (abaxor)


Lesenswert?

So ist es. Mit der Wahl von n kannst du den Rundungsfehler beeinflussen. 
je größer n umso kleiner der Rundungsfehler. Je nach FPGA können die 
Multiplizierer 18 oder 25 Bit Faktoren verarbeiten. Da ist dann die 
Grenze. Da dein AD und DA Wandler aber sicher nicht mehr als 16 Bit 
haben, reicht das aber auch aus.

Achso, 0.1 kann man doch mit einer Gleitkommazahl in einfacher 
Genauigkeit darstellen. Dazu braucht man aber alle 23 Bit der Mantisse.

Tom

von Dennis L. (eslon)


Lesenswert?

Danke erstmal, jetzt bekomm ich beim compilieren eine fehlermeldung mit 
der ich nichts anfangen kann.

Error (10511): VHDL Qualified Expression error at pid3.vhd(79): RESIZE 
type specified in Qualified Expression must match std_logic_vector type 
that is implied for expression by context

Die entsprechende Zeile dazu:
1
y_m <= resize(y_o, 16);

Damit wollte ich das signal y_m (18bit) auf 16 bit kürzen, das soll für 
ein antiwindup am ende des reglers sein.

von Thomas R. (Firma: abaxor engineering) (abaxor)


Lesenswert?

Dennis Lindner schrieb:
> Die entsprechende Zeile dazu:y_m <= resize(y_o, 16);
>
> Damit wollte ich das signal y_m (18bit) auf 16 bit kürzen, das soll für
> ein antiwindup am ende des reglers sein.

Der Quellcode wäre schon gut.

Woher soll resize wissen, wo die Bits weg sollen?

y_m <= y_o (y_m'high downto y_m'high - y_o'high);

Tom

von Dennis L. (eslon)


Angehängte Dateien:

Lesenswert?

Jetzt fällt mir erst auf, dass es wohl nicht so einfach funktioniert, da 
ich ja mit signed arbeite und wenn man da einfach nur die stellen kürzt, 
dann kommt ggf. einfach mal -1 raus.

Nun bin ich total verwirrt und nichtmehr sicher wie ich das mit den 
werten nun machen soll -.-

Hab den Quellcode mal angehängt

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Dennis Lindner schrieb:
> ich ja mit signed arbeite und wenn man da einfach nur die stellen kürzt,
> dann kommt ggf. einfach mal -1 raus.
Sag ich doch: du mußt deinen Zahlenbereich anders definieren, und am 
unscheinbaren, unwichtigen hinteren Ende (LSB) abschneiden.

von Dennis L. (eslon)


Lesenswert?

Wie kann ich denn meinen Zahlenbereich definieren?

Naja am ausgang also y soll ja maximal den wert 1 haben bei einer breite 
von 16 bit, durch die addition vorher könnte ja ein größerer wert 
entstehen und den will ich begrenzen und die differenz dann rückführen.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

BTW:
1
  Signal  yp    :  STD_LOGIC_VECTOR (data_width-1 downto 0) := (others => '0');
2
  Signal  yi    :  STD_LOGIC_VECTOR (data_width-1 downto 0) := (others => '0');
3
:
4
:
5
    yi <= std_logic_vector(((KiM * signed(yp_alt)) / MKi) + signed(yi_alt) + signed(aw));
Warum nimmst du nicht gleich passende Datentypen und rechnest mit 
signed?
1
  Signal  yp    :  signed (data_width-1 downto 0) := (others => '0');
2
  Signal  yi    :  signed (data_width-1 downto 0) := (others => '0');
3
:
4
:
5
    yi <= (KiM * yp_alt) / MKi + yi_alt + aw;

Dennis Lindner schrieb:
> Naja am ausgang also y soll ja maximal den wert 1 haben bei einer breite
> von 16 bit, durch die addition vorher könnte ja ein größerer wert
> entstehen und den will ich begrenzen und die differenz dann rückführen.
Das ist stupide Rechentechnik: du addierst die beiden Zahlen und wenn 
ein Übertrag ins nächste Bit passiert, dann sättigst du den Wert auf 1.

von Thomas R. (Firma: abaxor engineering) (abaxor)


Lesenswert?

Dennis Lindner schrieb:
> Hab den Quellcode mal angehängt

Den hab ich mir mal angesehen. Zwei Fragen habe ich

1. Wie hoch ist die Samplingfrequenz?
2. Wie hoch ist die Taktfrequenz?

Tom

von Dennis L. (eslon)


Lesenswert?

Vielen Dank für die Hilfe.

Jetzt hab ich noch ne Frage zu ModelSim, kann ich mir mein 
Ausgangssignal, also y irgendwie als Pegel darstellen lassen, dort 
sollte dann ja ein Anstieg zu sehen sein, momentan seh ich nur die 16 
bits und dort kann man zwar erahnen, dass der wert weiter ansteigt, aber 
gibt es noch eine variante das besser auszugeben?

von Dennis L. (eslon)


Lesenswert?

Thomas Reinemann schrieb:

> Den hab ich mir mal angesehen. Zwei Fragen habe ich
>
> 1. Wie hoch ist die Samplingfrequenz?
> 2. Wie hoch ist die Taktfrequenz?
>
> Tom


Bin gerade etwas verwirrt, welche Frequenzen du genau meinst.

Also dem Regler hab ich jetzt erstmal ein Takt von 5 MHz gegeben, wird 
aber sicher noch weiter runter gehen, weil mein ADC nicht alle 200 ns 
neue Werte liefert.

Desweiteren musste ich noch was ändern am Code, weil sonst Fehler in der 
Simulation aufgetreten sind.

Deshalb jetzt so:
1
yp <= resize((KpM * e) / MKp, 16);

Sonst haben die Größen nicht gepasst.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Dennis Lindner schrieb:
> dass der wert weiter ansteigt, aber
> gibt es noch eine variante das besser auszugeben?
Du kannst deine Werte im Modelsim auch Analog anzeigen, so wie ich das 
hier gemacht habe:
http://www.lothar-miller.de/s9y/archives/57-Sinusausgabe-mit-PWM.html

Ein Rechtsklick an der richtigen Stelle hilft dir weiter...

von Thomas R. (Firma: abaxor engineering) (abaxor)


Lesenswert?

Dennis Lindner schrieb:
> Bin gerade etwas verwirrt, welche Frequenzen du genau meinst.
>

> Also dem Regler hab ich jetzt erstmal ein Takt von 5 MHz gegeben, wird
> aber sicher noch weiter runter gehen, weil mein ADC nicht alle 200 ns
> neue Werte liefert.

Aus der Samplingfrequnez des ADC ergibt sich eine Frequenz, mit der der 
Regler die Stellgröße berechnet. Normalerweise startet man den Regler 
einmal für jedes neue Sample. Dann hast du aber bei deinem von dir 
programmierten Regler eine Totzeit von drei Samplen

1. Takt Berechnung der drei Anteile P, I und D des Reglers
2. Takt Summierung der drei Anteile
3. Takt Korrektur und Ausgabe

Das ist nicht der Sinn eines Reglers im FPGA. Du kannst auch nicht 
einfach den Regler dreimal auf ein Sample loslassen, weil
1. du dreimal integrierst
2. der D Anteil zwei mal Null ist

Grundsätzlich ist dein yi falsch, da in die Berechnung von yi(k) bei dir 
yi(k-2) eingeht. Denn yi(k) = f[yi_alt(k-1)] und yi_alt=f[yi(k-1)].

Du musst dir eine FSM schreiben, die mit dem Mehrfachen deiner 
Samplingfrequenz läuft. Diese FSM wird mit jedem neuen Sample einmal 
gestartet und arbeitet alle Rechenschritte ab, bevor das nächste Sample 
da ist.

z.B. so

Zustand 0
auf Sample warten

Zustand 1
Regelabweichung berechnen

Zustand 2
yp, yi, yd und aw berechnen

Zustand 3
yo berechnen

Zustand 4
ym ausgeben
und nach Zustand0 zurück

Tom

von Duke Scarring (Gast)


Angehängte Dateien:

Lesenswert?

Dennis Lindner schrieb:
> momentan seh ich nur die 16
> bits und dort kann man zwar erahnen, dass der wert weiter ansteigt, aber
> gibt es noch eine variante das besser auszugeben?
Vielleicht hilft Dir: RMT -> Format -> Analog

Duke

von Dennis L. (eslon)


Lesenswert?

Thomas Reinemann schrieb:
>
> Grundsätzlich ist dein yi falsch, da in die Berechnung von yi(k) bei dir
> yi(k-2) eingeht. Denn yi(k) = f[yi_alt(k-1)] und yi_alt=f[yi(k-1)].
>

Ich habe so aus einem Block Diagramm von Matlab übernommen, da wird für 
die Berechnung yp mit delay genommen, also yp(k-1) und am ende wird 
dieser wert dann zusammen mit dem vorherigen addiert.

Danke für den Tip mit der FSM

von Dennis L. (eslon)


Lesenswert?

Wie kann ich denn eine Begrenzung erreichen?

Mein Problem:

maximalwert für y = 0111_1111_1111_1111

Durch die Addition passiert es aber, dass y = 1000_0100_0001_0100
was ja einem Wert nahe dem Minimum entspricht.
Wie kann ich das abfangen oder verhindern??

von Dennis L. (eslon)


Lesenswert?

Hab meine Frage selbst beantwortet, dafür war das Antiwindup ja auch 
gedacht, man sollte es nur richtig einbauen ;)

Werd mal versuchen das Ganze nun noch in eine FSM zu verpacken.

Schönes Wochenende

von Dennis L. (eslon)


Lesenswert?

Thomas Reinemann schrieb:
> Du musst dir eine FSM schreiben, die mit dem Mehrfachen deiner
>
> Samplingfrequenz läuft. Diese FSM wird mit jedem neuen Sample einmal
>
> gestartet und arbeitet alle Rechenschritte ab, bevor das nächste Sample
>
> da ist.


Wie kann ich das denn am besten steuern, mit dem Sample?

Hatte erst gedacht, ich frage ab, ob sich ein Eingangswert ändert, aber 
es kann ja auch sein, dass diese sich nicht ändern.

Mir fehlt jetzt gerade eine passende Idee wie ich das mache.

von Thomas R. (Firma: abaxor engineering) (abaxor)


Lesenswert?

Dennis Lindner schrieb:
> Wie kann ich das denn am besten steuern, mit dem Sample?

Du legst eine Samplingrate fest. Mit der liest du den ADC aus und 
startest den Regler.

Tom

von Dennis L. (eslon)


Lesenswert?

Mein Problem ist da nur, dass ich die Samplerate im ADC noch nicht 
festgelegt habe.
Mache ich das über ein extra taktsignal? wenn ja, ich bekomm meinen 
internen Takt, 80MHz nicht auf einen passenden Wert, ich würde gerne von 
1-250 kHz variieren können.
Wenn ich die Samplerate hätte wär es natürlich kein Problem diese auch 
im PID Regler zu nutzen.

von Duke Scarring (Gast)


Lesenswert?

Dennis Lindner schrieb:
> Mein Problem ist da nur, dass ich die Samplerate im ADC noch nicht
> festgelegt habe.
Dann mach das doch mal.

> Mache ich das über ein extra taktsignal?
Das hängt von Deinem ADC und dessen Ansteuerung ab.

> wenn ja, ich bekomm meinen
> internen Takt, 80MHz nicht auf einen passenden Wert, ich würde gerne von
> 1-250 kHz variieren können.
Dann leg doch das ganz erstmal auf 250 kHz aus. Da hättest Du 320 Takte 
Zeit bis zum nächsten Sample (bei 80 MHz FPGA-Takt).

Duke

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.