Forum: FPGA, VHDL & Co. PID Regler durch VHDL


von Bit S. (amuniwien)


Lesenswert?

Hallo Alle,

der FPGA bekommt von einem Mikrocontroller die Reglerparameter und den 
Sollwert. Sollen alle Ein-und Ausgänge im Port (außer clock und reset) 
von std_logic_vector auf double oder signed geändert werden? Die 
restlichen Variablen sollten dann ebenfalls auf double gesetzt werden 
oder?
Und ist die Testbench eigentlich absolut notwendig? Ich habe es gerade 
mal so geschafft, den Design Code zusammenzubasteln und wollte direkt 
als nächstes die Synthese erstellen.

Vielen Vielen Dank im Vorraus und liebe Grüße !




Hier ist der Code:

•
1
library IEEE;
2
use IEEE.STD_LOGIC_1164.ALL;
3
use IEEE.std_logic_arith.all;
4
5
6
7
8
entity PID_Regler is
9
   generic(
10
    data_width: integer:= 14;
11
    intern_data_width: integer:= 28;
12
    TA: integer:=1 
13
     );
14
   port (
15
    w : in std_logic_vector(data_width-1 downto 0); --:= (others => '0');
16
    x : in std_logic_vector(data_width-1 downto 0); --:= (others => '0');
17
    y : out std_logic_vector(data_width-1 downto 0); --:= (others => '0');
18
    TP  : in std_logic_vector(intern_data_width-1 downto 0);
19
    TI  : in std_logic_vector(intern_data_width-1 downto 0);
20
    TD  : in std_logic_vector(intern_data_width-1 downto 0);
21
    clk_i : in  std_logic;
22
    rst_i : in  std_logic
23
);
24
end PID_Regler;
25
26
architecture Behavioral of PID_Regler is
27
28
signal e1 : std_logic_vector(data_width-1 downto 0) := (others => '0');
29
signal ealt : std_logic_vector(data_width-1 downto 0) := (others => '0');
30
signal e2 : std_logic_vector(data_width-1 downto 0) := (others => '0');
31
signal e3 : std_logic_vector(data_width-1 downto 0) := (others => '0');
32
33
begin
34
35
Regler1: process(clk_i, rst_i)
36
--rst_i wurde hinzugefügt
37
variable yp: std_logic_vector(intern_data_width-1 downto 0);
38
variable yi: std_logic_vector(intern_data_width-1 downto 0);
39
variable yi_alt: std_logic_vector(intern_data_width-1 downto 0);
40
variable yd: std_logic_vector(intern_data_width-1 downto 0); 
41
 
42
 begin
43
if (rst_i = '1') then  
44
      yp := (others => '0');
45
      yi := (others => '0');
46
      yi_alt:=(others => '0');
47
      yd := (others => '0');
48
      y <= (others => '0');
49
elsif (clk_i='1') then
50
      e1  <= std_logic_vector(signed(w) - signed(x));  
51
      yp := (signed(TP)*signed(e1));
52
      yi := yi_alt+(TI*e1*TA); -- yi_alt=yi
53
      yd := (TD*((e1-ealt)/TA)); -- ealt=e
54
      ealt <= e1;
55
      y <= (yp+yi+yd);
56
57
yi_alt := yi;
58
end if;
59
end process Regler1;
60
61
62
63
Regler2: process(clk_i, rst_i)
64
--rst_i wurde hinzugefügt
65
variable yp: std_logic_vector(intern_data_width-1 downto 0);
66
variable yi: std_logic_vector(intern_data_width-1 downto 0);
67
variable yi_alt: std_logic_vector(intern_data_width-1 downto 0);
68
variable yd: std_logic_vector(intern_data_width-1 downto 0); 
69
 
70
 begin
71
if (rst_i = '1') then  
72
      yp := (others => '0');
73
      yi := (others => '0');
74
      yd := (others => '0');
75
     ealt <= (others => '0');
76
      y <= (others => '0');
77
elsif (clk_i='1') then
78
      e2  <= std_logic_vector(signed(w) - signed(x));  
79
      yp := ((TP)*(e2));
80
      yi := ((yi_alt)+((TI)*(e2)*TA)); -- yi_alt=yi
81
      yd := ((TD)*(((e2)-(ealt))/TA)); -- ealt=e
82
      ealt <= e2;
83
      y <= ((yp)+(yi)+(yd));
84
85
yi_alt := yi;
86
end if;
87
end process Regler2;
88
89
90
Regler3: process(clk_i, rst_i)
91
--rst_i wurde hinzugefügt
92
variable yp: std_logic_vector(intern_data_width-1 downto 0);
93
variable yi: std_logic_vector(intern_data_width-1 downto 0);
94
variable yi_alt: std_logic_vector(intern_data_width-1 downto 0);
95
variable yd: std_logic_vector(intern_data_width-1 downto 0); 
96
 
97
 begin
98
if (rst_i = '1') then  
99
      yp := (others => '0');
100
      yi := (others => '0');
101
      yd := (others => '0');
102
      y <= (others => '0');
103
elsif(clk_i='1') then
104
      e3  <= std_logic_vector(signed(w) - signed(x));  
105
      yp := ((TP)*e3);
106
      yi := ((yi_alt)+((TI)*(e3)*TA)); -- yi_alt=yi
107
      yd := ((TD)*(((e3)-(ealt))/TA)); -- ealt=e
108
      ealt <= (e3);
109
      y <= ((yp)+(yi)+(yd));
110
111
yi_alt := yi;
112
end if;
113
end process Regler3;
114
end Behavioral;
115
116


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


Lesenswert?

Mueid S. schrieb:
> Und ist die Testbench eigentlich absolut notwendig?
Nein. Eine Testbench ist einfach nur der "Debugger" der Hardware. Wenn 
du deine Software ohne Debugger zum Laufen bekommst, dann brauchst du 
für die Hardware auch keinen Simulator.

> Ich habe es gerade
> mal so geschafft, den Design Code zusammenzubasteln und wollte direkt
> als nächstes die Synthese erstellen.
Und, läuft alles wie es soll?

Mueid S. schrieb:
> y <= ((yp)+(yi)+(yd));
Ohne auf Einzelheiten in deinem Code einzugehen: ist diese Berechnung 
Vorzeichenbehaftet oder nicht?
Oder anders: man rechnet nicht mit uneingeschränkten Datentypen. Nimm 
die numeric_std und passende Datentypen...
http://www.lothar-miller.de/s9y/categories/16-Numeric_Std

Und das mit dem "double" als Datentyp kannst du für die Synthese schnell 
vergessen. Denn auf dem FPGA sind alle Zahlen irgendwelche Bitmuster. 
Und welches Bitmuster hat ein "double"? Dazu musst du die IEEE 754 
konsultieren.

: Bearbeitet durch Moderator
von hannes (Gast)


Lesenswert?

> Und ist die Testbench eigentlich absolut notwendig?
Fuer dich ja, wenn ich mir deinen Code so anschaue.

Siehe:
1
      yd := (others => '0');
2
      y <= (others => '0');
3
elsif(clk_i='1') then
4
      e3  <= std_logic_vector(signed(w) - signed(x));  
5
      yp := ((TP)*e3);
6
      yi := ((yi_alt)+((TI)*(e3)*TA)); -- yi_alt=yi

da sollte wohl ein rising_edge(clk_i) stehen.


hannes

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


Lesenswert?

hannes schrieb:
> wenn ich mir deinen Code so anschaue.
Dazu noch ein Tipp: verwende keine speichernden Variablen (yi_alt). Du 
biegst dir damit selber das Bein ab...

Siehe dazu den Beitrag "Variable vs Signal"
Oder andersrum: wer Variablen kennt nimmt Signale.

: Bearbeitet durch Moderator
von Thomas R. (Firma: abaxor engineering) (abaxor)


Lesenswert?

Hallo Mueid,

wie hoch ist dein Takt?


Tom

von Bit S. (amuniwien)


Lesenswert?

Lothar M. schrieb:
>> Ich habe es gerade
>> mal so geschafft, den Design Code zusammenzubasteln und wollte direkt
>> als nächstes die Synthese erstellen.
> Und, läuft alles wie es soll?

Ich weiß es leider nicht. Kann ich das überprüfen, ohne extra eine 
Testbech zu schreiben?

>> y <= ((yp)+(yi)+(yd));
>Ohne auf Einzelheiten in deinem Code einzugehen: ist diese Berechnung
Vorzeichenbehaftet oder nicht?

Nein. Die Werte sind immer positiv.

An double habe ich gedacht, weil die Werte, die von Microcontroller in 
den Fpga reingehen, double Werte sind. Oder muss ich die double Werte in 
binär Werte konvertieren bzw. kann ich einfach mit den double Werten 
weiterrechnen?

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


Lesenswert?

Mueid S. schrieb:
> Ich weiß es leider nicht. Kann ich das überprüfen, ohne extra eine
> Testbech zu schreiben?
Wenns auf der Hardware läuft ist es ok.
Wenn nicht: schreib eine Testbench. Das ist ja keine Raketentechnik, 
sondern hier sogar super einfach: du brauchst ja nur ein paar statiche 
Eingangswerte und ein paar Sprünge im Sollwert. Das ist in 15 min. 
erledigt...

> Nein. Die Werte sind immer positiv.
Warum schreibst du dann " signed(w) - signed(x)"?

> Oder muss ich die double Werte in binär Werte konvertieren
Ich würde einfach mal sagen: Ja, tu das.

> kann ich einfach mit den double Werten weiterrechnen?
Nein "einfach" im Sinne von "schnell und ressourcenschonend" geht das 
nicht. Und "einfach" im Sinne von "dann muss ich nichts Denken" geht es 
auch nicht...

Mueid S. schrieb:
> wollte direkt als nächstes die Synthese erstellen.
Und was sagt der Synthesizer?

von Bit S. (amuniwien)


Lesenswert?

Thomas R. schrieb:

> wie hoch ist dein Takt?
>
> Tom

Die Abtastrate für das Signal oder die Taktfrequenz der Clock? Also die 
Abtastrate wird auf jeden Fall kleiner als die Integrierzeit, genau habe 
ich sie allerdings nicht festgelegt. Die Taktfrequenz habe ich noch 
nicht genau definiert. Ich weiß auch nicht nach welchen Kriterien ich 
sie festlegen soll.

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


Lesenswert?

Mueid S. schrieb:
> Thomas R. schrieb:
>
>> wie hoch ist dein Takt?
>>
>> Tom
>
> Die Abtastrate für das Signal oder die Taktfrequenz der Clock? Also die
> Abtastrate wird auf jeden Fall kleiner als die Integrierzeit, genau habe
> ich sie allerdings nicht festgelegt. Die Taktfrequenz habe ich noch
> nicht genau definiert. Ich weiß auch nicht nach welchen Kriterien ich
> sie festlegen soll.

Genau darauf wollte ich hinaus. Denn in deinem Beispiel durchläufst du 
mit jedem Takt eine Berechnung. D.h. im PID-Regler ist deine 
Abtastfrequenz gleich der Taktfrequenz. Da die Taktfrequenz 
üblicherweise ein paar MHz ist wäre das auch deine Abtastfrequenz. Du 
brauchst noch ein Signal DataValid, dass dir sagt, jetzt kommt ein neues 
Sample. Dann darfst du nur einen einzigen Reglerdurchlauf machen, sonst 
ist dein I- und D-Anteil falsch.

Tom

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


Lesenswert?

Mueid S. schrieb:
> Die Taktfrequenz habe ich noch nicht genau definiert.
> Ich weiß auch nicht nach welchen Kriterien ich sie festlegen soll.
Nach dem, was auf dem Quarz neben dem FPGA steht. Der Rest geht über 
Clock-Enables...

von Bit S. (amuniwien)


Lesenswert?

Thomas R. schrieb:
> Du
> brauchst noch ein Signal DataValid, dass dir sagt, jetzt kommt ein neues
> Sample.

Ich hab das nicht ganz verstanden. Soll ich das als zusätzliche If 
Bedingung einfügen? Ich dachte dafür ist das Clock Signal da. Nämlich 
anzugeben, dass jetzt eine neue Berechnung kommt.

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


Lesenswert?

Mueid S. schrieb:
> Ich dachte dafür ist das Clock Signal da. Nämlich anzugeben, dass jetzt
> eine neue Berechnung kommt.
Dann muss der Takt aber zum Regler passen...

Der Takt in einem FPGA ist dazu da, irgendwelche Flipflops dazu zu 
bewegen, die Daten am Eingang zu speichern und am Ausgang 
bereitzustellen. Deshalb ist dieser FPGA-Takt erst mal komplett 
unabhängig vom Filtertakt/Reglertakt. Denn wenn der Regler z.B. mit 1ms 
Zyklus laufen soll, dann muss ein FPGA mit 100 MHz Taktfrequenz genau 
100000 Takte lang nichts tun, und dann wieder 1x den Regler berechnen.

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


Lesenswert?

Mueid S. schrieb:
> Thomas R. schrieb:
>> Du
>> brauchst noch ein Signal DataValid, dass dir sagt, jetzt kommt ein neues
>> Sample.
>
> Ich hab das nicht ganz verstanden. Soll ich das als zusätzliche If
> Bedingung einfügen? Ich dachte dafür ist das Clock Signal da. Nämlich
> anzugeben, dass jetzt eine neue Berechnung kommt.

Nein, dein Takt kommt von einem Quarz üblicherweise mit einigen 10 MHz. 
Der kann völlig unabhängig von deiner Samplingfrequenz sein. Es ist 
sogar besser, wenn er Takt deutlich höher als die Samplingfrequenz ist.

Bei dem was du vorhast, könnte dein Takt auch unterschiedliche 
Frequenzen haben. Das ist etwas, was man nicht in einem FPGA haben will.

Tom

: Bearbeitet durch User
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.