Forum: FPGA, VHDL & Co. VHDL Xilin CORDIC atan Eingabeformat.


von Erik K. (Firma: miunske GmbH) (oleeiner)


Lesenswert?

Hallo,

ich möchte mit dem XILINX Cordic-Core einen Arcustangens berechen.

Meine Eingangswerte sind signed 32 bit Vektoren.

Laut Datenblatt sollen die Eingabewerte im Zweierkomplement dargestellt 
werden (2 Bit Integer+Vorzeichen, Restliche Bit für die Mantisse).

Nun stellt sich mir die Frage wie ich meine 32-bit Umformen muss um den 
Core nutzen zu können.

Datenblatt:
https://www.xilinx.com/support/documentation/ip_documentation/cordic_ds249.pdf

Grüße,
Erik

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


Lesenswert?

Erik K. schrieb:
> Meine Eingangswerte sind signed 32 bit Vektoren.
Und wie sind die skaliert?
Was ist 0x00000000 und was 0x7fffffff und was 0x80000000?

von Numerisch Konsistent (Gast)


Lesenswert?

Im Idealfall skalierst du deinen gültigen Zahlenbereich auf -1 .. 1 um 
den Quantisierungsfehler zu minimieren, praktischer ist aber wohl die 
nächsthöhere Zweierpotenz.

Die vollen 32 bit Eingangsgenauigkeit bekommst du leider nicht, da die 
Werte von +1.0 .. +1.9xx nicht zulässig sind.

von K. L. (Gast)


Lesenswert?

Das Thema hatte Ich auch mal. Bei dem Xilinx ATAN gibt es irgendein 
Problem.

Beitrag "Xilinx CORDIC Core - FixPoint manuell umwandeln"

von Erik K. (Firma: miunske GmbH) (oleeiner)


Lesenswert?

Hallo,

Lothar M. schrieb:
> Und wie sind die skaliert?
> Was ist 0x00000000 und was 0x7fffffff und was 0x80000000?


0x00000000 wird als 0 interpretiert
0x7fffffff als 2147483647
und 0x80000000 als -2147483647


Numerisch Konsistent schrieb:
> Im Idealfall skalierst du deinen gültigen Zahlenbereich auf -1 .. 1 um
> den Quantisierungsfehler zu minimieren, praktischer ist aber wohl die
> nächsthöhere Zweierpotenz.

Das heißt ich müsste meinen Zahlenbereich durch 2^30 dividieren?
Also müsste ich irgendwie einen fixe point Typ in vhdl definieren.
(Ich bin absoluter neuling in fixed point arithmethik und hab davon noch 
keine Ahnung)


Klaus L. schrieb:
> Das Thema hatte Ich auch mal. Bei dem Xilinx ATAN gibt es irgendein
> Problem.
>
> Beitrag "Xilinx CORDIC Core - FixPoint manuell umwandeln"

Den Thread habe ich auch schon gelesen, aber auch nicht daraus schlau 
geworden.



Ehrlich gesagt bin ich am Überlegen, ob ich das ganze einfach als Lookup 
Table implementiere.
Allerdings ist das bei 32 bit eine riesie Tabelle.

von Achim S. (Gast)


Lesenswert?

Erik K. schrieb:
> Ehrlich gesagt bin ich am Überlegen, ob ich das ganze einfach als Lookup
> Table implementiere.
> Allerdings ist das bei 32 bit eine riesie Tabelle.

das wäre in der Tat eine spaßige Lookup-Tabelle.

Erik K. schrieb:
> 0x00000000 wird als 0 interpretiert
> 0x7fffffff als 2147483647
> und 0x80000000 als -2147483647

Beim Zweierkomplement ist 0x8000... wohl -214748368 (letzte Stelle 8, 
nicht 7). Der Zahlenbereich für signed ist also ein ganz klein wenig 
asymmetrisch, was vielleicht auch mit ein Grund für deine 
Schwierigkeiten ist.

Binär betrachtet nutzt du bisher den Zahlenbereich

positivste Zahl: 01111...
negativste Zahl: 10000...

Wenn du den Wert vorzeichenrichtig eine Stelle nach rechts schiebst 
erhältst du

positivste Zahl: 00111...
negativste Zahl: 11000...


Der benötigte Zahlenbereich ist

positivste Zahl: 01000...
negativste Zahl: 11000...

Das ist fast der selbe Bereich, den du auch nach der simplen 
vorzeichenrichtigen Schieberei um 1 Bit erhältst. Nur der positive Wert 
unterscheidet sich um eine niederwertigste Stelle. Dezimal hast du nach 
der Schieberei also 0.999... statt der gewünschten 1.000..

Weniger Abweichung geht wohl nicht, weil du einen assymetrischen 
Zahlenbereich (-214748368..214748367) auf einen symmetrischen (-1..1) 
abbilden willst.

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


Lesenswert?

Erik K. schrieb:
> Das heißt ich müsste meinen Zahlenbereich durch 2^30 dividieren?
> Also müsste ich irgendwie einen fixe point Typ in vhdl definieren. (Ich
> bin absoluter neuling in fixed point arithmethik und hab davon noch
> keine Ahnung)
Nein, du musst nur Umdenken. Diese Dicvision muss in deinem Kopf 
stattfinden, das FPGA interpretiert das fast gleiche Bitmuster einfach 
anders.

Achim S. schrieb:
> Erik K. schrieb:
>> 0x00000000 wird als 0 interpretiert
>> 0x7fffffff als 2147483647
>> und 0x80000000 als -2147483647
Das ist vermutlich falsch. Du meinst sicher -2147483648. Rechne mal 
nach. Als Tipp: probiers mit weniger Bits wie z.B. 8, das gibt dann 
einen Wertebereich von -128..127

Erik K. schrieb:
> Ehrlich gesagt bin ich am Überlegen, ob ich das ganze einfach als Lookup
> Table implementiere. Allerdings ist das bei 32 bit eine riesie Tabelle.
Die bekommst du sowieso in keines der derzeit erhältlichen FPGAs, denn 
du bräuchtest dafür 32*2^32 Bits, also 137438953472 Bits oder eben 128 
Giga Bits...
Wir genau brauchst du das? Denn evtl. ginge es ja über eine kleine 
Tabelle mit linearer Interpolation.

EDIT: Pech, Zweiter, zu lange gebraucht... ;-)

: Bearbeitet durch Moderator
von Erik K. (Firma: miunske GmbH) (oleeiner)


Lesenswert?

Danke für eure Hilfe.

Ich habe es jetzt schon anders implementiert, so dass ich die Lösung mit 
dem XILINX CORE nicht mehr testen werde.

Für diejenigen die es interessiert:
Ich habe den Funktionswert des Arctan mit 1000 multipliziert (in dem 
Fall möglich, weil mein tatsächlicher Datenbereich die 32 bit nicht ganz 
ausschöpft) und habe dann einen Bereichsvergleich gemacht. Auflösung des 
ganzen ist dann 2,5 Grad.

Sieht dann so aus:
1
function  atan_e  (a : SIGNED) return SIGNED is
2
  begin
3
    
4
    if(a(31) = '1') then
5
      if(a > to_signed(0,32) and a <= to_signed(44,32)) then return to_signed(-1800,32);
6
      
7
      elsif(a > to_signed(44,32) and a <= to_signed(87,32)) then return to_signed(-1775,32);
8
9
      elsif(a > to_signed(87,32) and a <= to_signed(176,32)) then return to_signed(-1725,32);
10
11
      elsif(a > to_signed(176,32) and a <= to_signed(268,32)) then return to_signed(-1675,32);
12
13
      elsif(a > to_signed(268,32) and a <= to_signed(364,32)) then return to_signed(-1625,32);
14
15
      elsif(a > to_signed(364,32) and a <= to_signed(466,32)) then return to_signed(-1575,32);
16
17
      elsif(a > to_signed(466,32) and a <= to_signed(577,32)) then return to_signed(-1525,32);
18
19
      elsif(a > to_signed(577,32) and a <= to_signed(700,32)) then return to_signed(-1475,32);
20
21
      elsif(a > to_signed(700,32) and a <= to_signed(839,32)) then return to_signed(-1425,32);
22
23
      elsif(a > to_signed(839,32) and a < to_signed(1000,32)) then return to_signed(-1375,32);
24
      
25
      elsif(a = to_signed(1000,32)) then return to_signed(-1350,32);
26
27
28
......

Die Auflösung des arctan wäre nicht so wichtig gewesen, mir ging es nur 
um das Eingangsdatenformat.


Auf jeden Fall nochmals vielen Dank für eure Hilfe.

Grüße,
Erik

von Achim S. (Gast)


Lesenswert?

Erik K. schrieb:
> Die Auflösung des arctan wäre nicht so wichtig gewesen, mir ging es nur
> um das Eingangsdatenformat.

Wow. Und diese aufwändige und schlecht auflösende Lösung ist dir lieber, 
als eine einfache Zuweisung:

Würdest du den vollen Zahlenbereich nutzen, dann wäre es:
x(31) <= a(31);
x(30 downto 0) <= a(31 downto 1);

Wenn du nur einen Teil des Zahlenbereichst nutzt, dann müsstest du nur 
den Indexbereich von a anpassen.

Evtl. braucht es noch ein Typcast, um aus dem signed einen 
std_logic_vector zu machen (so ungefähr in der Art std_logic_vector(a(31 
donwnto 1))

Aber das wäre auch schon alles.

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


Lesenswert?

Erik K. schrieb:
> Sieht dann so aus:
Wenn schon, dann hätte ich "a" in einen Integer gewandelt, dann fallen 
wenigstens die vielen Vergleiche kompakt und leserlich aus.

Und dazu noch den kleinen Programmiertrick,dass alles, was schon 
abgefragt wurde nicht mehr abgefragt werden muss. Um mal deinen Code 
anzupassen:
1
    if(a(31) = '1') then
2
      if(a > to_signed(0,32) and a <= to_signed(44,32)) then return to_signed(-1800,32);
3
      
4
      elsif(a <= to_signed( 87,32)) then return to_signed(-1775,32); -- größer all 44 ist er eh' schon, sonst wäre er nicht hierher gekommen...
5
      elsif(a <= to_signed(176,32)) then return to_signed(-1725,32);
6
      elsif(a <= to_signed(268,32)) then return to_signed(-1675,32);
7
      :
8
      :      
9
      elsif(a = to_signed(1000,32)) then return to_signed(-1350,32); -- für diesen einmaligen kleinen Sonderfall (Wahrschielichkeit 0,1%) eine extra Condition?
10
.....
Und was passiert eigentlich, wenn a = 0 ist?

Wenn so eine krude Auflösung reicht, dann hätte ich da doch die 
Tabellenlösung mit der linearen Interpolation genommen...

: Bearbeitet durch Moderator
von J. S. (engineer) Benutzerseite


Lesenswert?

Erik K. schrieb:
> Das heißt ich müsste meinen Zahlenbereich durch 2^30 dividieren?

Nein, Du musst Den Zahlenbereich des Winkels entsprechend skalieren und 
interpretieren. Der Xilinx-Core muss natürlich entsprechend parametriert 
werden, d.h. bei ATAN muss man sich entscheiden, welchen Winkel man 
verwendet. Es gibt z.B. die Option den Core das flippen der 4 Quadranten 
machen zu lassen oder es selber zu tun. Richtig ausrechnen, kann der ja 
nur -90 Grad bis 90 Grad jeweils abzüglich eines infinitisimalen 
epsilon. Die Sonderfälle Y=unendlich und x=0 kann man auch gerne selber 
abfangen.

von T.U.Darmstadt (Gast)


Lesenswert?

Ich habe den Core gerade mit MATLAB-Simulink in Verwendung. Dort kann 
man die Skalierung einstellen. Geht von -0.9999 ... +0.9999. Ich habe 
den zum Ausprobieren auf binär gestellt und bekomme auch seltsame Werte. 
Sind im Negativen nur halb so groß, wie im Positiven.

von Weltbester FPGA-Pongo (Gast)


Lesenswert?

Thomas U. schrieb:
> Ich habe den Core gerade mit MATLAB-Simulink in Verwendung. Dort kann
> man die Skalierung einstellen. Geht von -0.9999 ... +0.9999. Ich habe
> den zum Ausprobieren auf binär gestellt und bekomme auch seltsame Werte.
> Sind im Negativen nur halb so groß, wie im Positiven.

Beispiel?

Der CORDIC vom X sollte sich nicht anders verhalten, als gewöhnlich. 
Ansonsten wird ATAN hier gerade intensivst erörtert:

www.mikrocontroller.net/topic/480840

Hier hat jemand eine Lösung gepostet, auf 51 Bits genau:
Die wäre mal gegen das Xilinx-Format gegenzutesten.

Beitrag "Atan function implementation"

von Christoph Z. (christophz)


Lesenswert?

Erik K. schrieb:
> Ich habe den Funktionswert des Arctan mit 1000 multipliziert (in dem
> Fall möglich, weil mein tatsächlicher Datenbereich die 32 bit nicht ganz
> ausschöpft)

Dann hatte dein Funktionswert schlicht und einfach zu viele Bits 
genutzt. Ein signed ist 32 bit breit, wenn kein Wertbereich angegeben 
wird.

Signale etc. werden IMMER mit Werbereich deklariert (Alle coding 
guidelines die ich kenne wollen das auch so). Das spart 1. Ressourcen, 
2. es zeigt, dass sich der Entwickler Gedanken darüber gemacht hat, wie 
viel es denn wirklich braucht.

Erik K. schrieb:
> a > to_signed(0,32)

Damit es auch wiederverwendbar ist mit anderen Wertbereichen:
1
a > to_signed(0,a'length)

von J. S. (engineer) Benutzerseite


Angehängte Dateien:

Lesenswert?

Thomas U. schrieb:
> Ich habe
> den zum Ausprobieren auf binär gestellt und bekomme auch seltsame Werte.
Das könnte wie schon gesagt an dem Umklappen in einen andere Quadraten 
liegen.

Christoph Z. schrieb:
> Erik K. schrieb:
>> Ich habe den Funktionswert des Arctan mit 1000 multipliziert (in dem
>> Fall möglich, weil mein tatsächlicher Datenbereich die 32 bit nicht ganz
>> ausschöpft)
>
> Dann hatte dein Funktionswert schlicht und einfach zu viele Bits
> genutzt.
Das sollte sich leicht testen / limitieren lassen.

Anbei ein Bild einer Echtzeitberechnung mehrerer ATANs über 
Xilinx-CORDIC, um von der Position von X und Y auf den Winkel zu 
schließen und die Ersatzbilder für Iris und Pupille zu bilden. Lief äuf 
auf einem Spartan 6 (Trenz Carrier Board mit VGA Ausgabe) - geht 
inzwischen auch auf HDMI.

von J. S. (engineer) Benutzerseite


Lesenswert?

Das hier war damals übrigens der Ansatz und die Grundlage für den 
Augenhintergrund:
Beitrag "Re: Rechenfehler grafisch angezeigt"

Und hier das Video dazu:
https://youtu.be/F8HvA-YQ8is

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.