Hallo allerseits,
Ich hab mal ein kleines Problem. Ich habe eine Aufgabe bekommen, einen
PID Regler in VHDL zu programmieren, das eine kommende Amplitude sowohl
eine Eigenfrequenz eines Systems regelt. Kann mir einer ne Idee geben
wie ich so ein Problem angehe, was sollte ich bei der Programmierung
beachten.
Wäre sehr dankbar für euere Hilfe.
MfG
Hallo,
Also, ich muss einen generischen Digitalen regler programmieren, die
Eigenfrequenz und Amplitude sind unabhängig voneinander, und können
entweder vorgegeben werden oder werden von einem System in den Regler
eingeschleust. Für den Amplitudenregler wird eine Aplituden Rampe
eingeschleust und fürden EF-Regler eine Impedance Phase Ramp.
ich weiß es gibt zwei Methoden einen Regler zu entwerfen, 1. man
entwirft analog einen und diskretisiert ihn oder man entwirft gleich
einen diskreten Regler. Danke.
Hi,
vielleicht hilft dir diese Arbeit. Sie beschreibt wie du mit Hilfe von
Matlab/Simulink einen Regler entwirfst und dann in VHDL exportieren
kannst.
Ansonsten schlage ich vor du gehst nach deiner zweiten Methode vor. Am
besten fängst du mit einem einfachen P-Regler an. Der läst sich ganz
einfach implementieren.
Hallo,
danke für deine Hilfe, hilft mir wirklich sehr, hatte auch schon daran
gedacht, erst in matlab zu programmieren und dnn in HDl umzuwandeln, da
geht es einfacher, frag mich aber trotzdem wie ich direkt in VHDL
implementieren soll.
Hab nun einen dieskreten PID Regler aufgestellt, was ist nun der nächste
Schritt, wie beginne ich mit der Programmierung in VHDL.Danke.
MfG
hallo,
vielen dank, diese seite kenne ich bereits, hab meine anfänglichen
versuche unternommen um einen pid regler zu programmien, wie siehts aus,
ist es einigermaßen in Ordnung.Danke.
Hi,
ich finde das sieht fürs erste mal ganz gut aus. Was noch fehlt (glaub
ich) ist sowas wie "if(rising_edge(clk_i))". Ansonsten führt er den
Process auch bei fallender Flanke aus oder macht sogar was ganz
undefiniertes.
Was mir noch aufgefallen ist: Du hast bei
1
yi:=(yi_alt+(k_i*e*T));
kein T definiert. Und du brauchst das auch nicht wirklich. Deine Zeit
ist ja in clk_i mit enthalten und dass der Process mit jedem Zeittakt
neu ausgeführt wird. Das gleiche gilt auch für yd.
Falls dein Problem nur simuliert werden soll, kannst du es so lassen.
Ansonsten würde ich die Variablen durch Signale ersetzen. Bei diesen
verschachtelten Anweisungen bekommst du sonst sicher Probleme mit der
Laufzeit bzw. maximalen Taktrate.
Signale generieren dir eine Pipeline wodurch das Resultat zwar um einen
Takt verzögert am Ausgang erscheint, du allerdings den Systemtakt stark
erhöhen kannst. Das wiederum kann der Bandbreite des Reglers nur
dienlich sein.
Btw.: Die Divisionsoperation ist nicht so einfach zu synthetisieren. Das
wird dir jedes Tool um die Ohren hauen. Ich persönlich löse soetwas gern
durch Multiplikation mit dem Reziprokwert aus einem ROM. Das geht
schnell und braucht nicht viel Ressourcen. Dafür ist man aber auf eine
max. Anzahl von Werte für T beschränkt.
Sagen wir, du möchtest mit Werten von 1-500 dividieren. Also nimmst du
ein BlockRAM und hinterlegst an den Adressen 1-500 die entsprechenden
(vorberechneten) Reziprokwerte. Jetzt "wählst" du dir den gewünschten
Divisor durch anlegen der entsprechenden Adresse (also dem
Divisionswert) an den RAM. Im nächsten Takt liegt der Reziprokwert am
Ausgang des BlockRAMs und wird einem Multiplizierer zugeführt. Schwupps,
Division erledigt.
Nachteil dieser Methode: Bei zu geringer Bitbreite des Divisors wird die
Genauigkeit schlechter.
Hallo,
Ich hab die Variable yp durch signal ersetzt, gibt dann fehlermeldung
Signal "yp" cannot be target of variable assignment statement.
Signal declaration 'yp' not allowed in this region
dieser Code fonktioniert einwandfrei mit variable bei dem Obigen hatte
ich paar Fehler drin:
>Ich persönlich löse soetwas gern>durch Multiplikation mit dem Reziprokwert aus einem ROM.
Ja, habe ich auch immer gemacht. Bei höheren Genauigkeiten ist das aber
untauglich. Es ist zweckmäßiger, die Division auf Binärteilung zu
normieren und entsprechend zu multiplizieren, also die Restrechung zu
skalieren.
>Also nimmst du ein BlockRAM und hinterlegst an den Adressen 1-500> die entsprechenden (vorberechneten) Reziprokwerte.
Ja ist klar. Ein Blockram mit 512 Speicherzellen. In diese Architektur
bekommt man aber auch ohne große Schwierigkeiten die Terme für eine
binäre Division hinein.
>Nachteil dieser Methode: Bei zu geringer Bitbreite des Divisors wird die>Genauigkeit schlechter.
Genau. Denn wenn man genauer werden will, muss man manuell dividieren,
also den Rest nochmal prozessieren. Das sind dann 2x(2+1) Takt = 6 Takte
+ handling drum herum.
Ein Core im Cyclone 2 macht das auch in 8-10 Takten voll gepipelined.
Der nutzt dazu die sog. Softmultiplier, die er ins RAM stopft. Und er
ist zudem auch noch "restwertfähig".
Als Beispiel habe ich eine Division über 20bit/10 Bit mit nochmaliger
Restwertberechung Rest*10Bit/10Bit und bekomme ein 20Bit breites Ergbnis
nach nur 20 Takten. Die Rechenpipeline ist so aufgezogen, daß alle
Divisionen (durchaus ähnlich einem Regler mit " /T") einzeln vorliegen.
Dann packt der Core 8 Kanäle und hat einen Durchsatz von 1/(80 clks) je
Kanal -> 1 MHz. (immer noch "analog klein" gegen das Wandlereinlesen und
-auslese z.B.).
Hallo,
Habs soweit einen konkreten PID regler aufgestellt, nun will ich ihn
soweit erweitern, die eigentliche Aufgabe ist ja, dass der Regler extern
Werte in Form Amplitude und Frequenz einer Spannung abbekommt, die
werden dann durch einen A/D Wandler umgewandelt, die Auflösung des A/D
wandlers ist 14 bit groß, das heißt doch, dasss ich mein w (Sollwert)
und x(Istwert)
als std_logic_vector (13 downto 0) deklarieren muss.
Anschließend wird wieder D/A umgewandelt und die Daten an ein System
gesendet.
Nochwas, die PID Anteile sind nicht konkret festgelegt, sondern sollen
in ein Register festgelegt werden wobei die dann abgerufen werden, dass
ist für mich der schwierige Teil.
Also muss ich doch alle signal und variablen usw. als std_logic_vector
deklarieren oder.
So sieht mein gedankengang aus, hoffe ihr könnt mir weiterhelfen.Danke.
Ali schrieb:> use ieee.math_real.all;
Wofür?
> Also muss ich doch alle signal und variablen usw. als std_logic_vector> deklarieren oder.
Wenn ich eine rechenlastige Aufgabe habe, dann werden die Signale an den
Ports als std_logic_vector übergeben und in meinem Modul
schnellstmöglich nach signed oder unsigned oder integer gewandelt. Es
ist unsinnig, mit nackten Vektoren zu rechnen. Denn was gibt z.B. "111"
+ "111"?
Der Profi schrieb:> Ein Core im Cyclone 2 macht das auch in 8-10 Takten voll gepipelined.> Der nutzt dazu die sog. Softmultiplier, die er ins RAM stopft. Und er> ist zudem auch noch "restwertfähig".
Ich habe auch nie davon abgeraten einen IP-Core zu nutzen. Was du unter
"restwertfähig" verstehst würde mich brennend interessieren. Die von mir
vorgeschlagene Variante braucht keinen expliziten Rest, da das Ergebnis
automatisch zu einer Festkommazahl mit x Nachkommastellen wird.
Der Profi schrieb:> Ja ist klar. Ein Blockram mit 512 Speicherzellen.
Was willst du mir damit sagen? Also mehrere RAM-Blöcke zu verknoten, um
512 32-Bit Werte zu speichern, sollte doch kein Problem darstellen.
@Ali
std_logic_vector ist die richtige Wahl. Für mathematische Operationen
bieten sich aber auch unsinged/signed aus ieee.numeric_std an.
Geschmacksache ...
Mit was ist das FPGA denn verbunden? Mikrocontroller oder PC? Dann würde
ich auf I2C oder RS-232 zurückgreifen, um die Parameter zu übertragen.
Dafür gibt es genügend Cores, etwa bei opencores.org
Hallo,
danke für deine Antwort, es ist mit einem Microcontroller verbunden,
aber die Daten können über eine RS232 Schnittstelle auch mit dem
computer verbunden werden, und über diese Schnittstelle kann man auf die
Register zugreifen. Hauptsächlich werden die Parameter mit RS232
übetragen.
opencores.org: was genau enthält diese website, was ist für mich
brauchbar, hab diese seite noch nie besucht.
Danke.
Die Umwandlung ist so i.O. wenn e,w und x vom Type std_logic_vector
sind.
Auf opencores.org gibt es verschiedenste IP-Cores. So z.B.
http://opencores.org/project,mmuart ... eine RS-232 UART für die
Verbindung von FPGA und PC/Mikrocontroller. Erspart einen die Arbeit das
Rad neu zu erfinden :)
Sinnvoll wäre es mit Sicherheit wenn Du die gesamte Rechnung über signed
laufen lässt. Dafür kannst du bei der Signaldefinition anstatt
std_logic_vector(x downto 0) -> signed(x downto 0) schreiben. Allerdings
müssen k_(p|i|d) über einen Cast zu signed konvertiert werden.
Hallo,
da bin ich wieder,
ich muss die Einstellungen für den P- I- und D-Anteil in einem Register
ablegen wie genau realisiere ich das.Danke.
Hab mein Code soweit umgeändert: