Forum: FPGA, VHDL & Co. Formel in VHDL beschreiben/rechnen


von Calc (Gast)


Angehängte Dateien:

Lesenswert?

Hallo zusammen,

ich habe einen Sensor, dessen 1bit Dateneingang ich seriell eintakte. Je 
nachdem, ob der Eingang 1 oder 0 ist, werden verschiedene Summen A1/A2 
und B1/B2 gebildet, die positiv, aber auch negativ sein können. Diese 
sollen dann in der folgenden Formel verrechnet werden (siehe Bild, 
leider weiß ich nicht, wie man den Formeleditor hier bedient). Das 
Ergebnis soll 16bit haben.

Ich habe versucht die Formel so umzuformen, dass möglichst viele 2er 
Potenzen vorhanden sind. Dennoch bin ich nun mit meinem Latein am Ende.

Den Ausdruck in der eckigen Klammer würde ich mithilfe von Variablen in 
einem Prozess berechnen.
- Dazu habe ich die 16bit Werte A1/A2 und B1/B2 um ein 17. Bit 
erweitert, für das "Vorzeichen" (16 DOWNTO 0)
- Die Summe beider Werte A1/A2 und B1/B2 muss ich ja nochmal um ein Bit 
erweitern. (17 DOWNTO 0)
- Um die *2 hinzubekommen, habe ich zusätzlich zum Additionsbit noch ein 
weiteres Bit hinzugefügt (19 DOWNTO 0).
1
   SIGNAL s_a1 : signed (16 DOWNTO 0);
2
   SIGNAL s_a2 : signed (16 DOWNTO 0);
3
   SIGNAL s_b1 : signed (16 DOWNTO 0);
4
   SIGNAL s_b2 : signed (16 DOWNTO 0);
5
...
6
7
  calc : PROCESS (CLK, NRES)
8
    variable v_a_block    : signed(17 DOWNTO 0);
9
    variable v_b_block    : signed(17 DOWNTO 0);
10
    variable v_sum           : signed(19 DOWNTO 0);
11
    variable v_shift           : signed(35 DOWNTO 0);
12
    variable v_ergebnis : signed(35 DOWNTO 0);
13
  BEGIN
14
    IF (NRES = '0') THEN
15
       s_sensor_vaue <= (OTHERS => '0');
16
    ----- FALLING EGDE!!! ------
17
    ELSIF falling_edge(CLK) THEN
18
        v_a_block   := s_a1 + s_a2;
19
        v_b_block   := s_b1 + s_b2;
20
        v_sum        := ('0' & v_a_block) + (v_b_block & '0'); 
21
    END IF;
22
  END PROCESS calc;
In v_sum sollte nun die eckige Klammer stehen.

Nun kommt die Formel aus der analogen Welt, so dass das 1/2^16 sich 
nicht so einfach abbilfen lässt. Das ist ja ein extrem kleiner Wert, so 
dass ich den mit x Stellen nach dem Komma darstellen muss, um dann die 
v_sum damit zu multiplizieren.

2^16 wäre ja eine einfach shift Operation. Damit mir aber keine 
Informationen verloren gehen, muss ich den Vektor entsprechend 
erweitern.
1
v_shift := "0000000000000000" & v_sum;
Dann müsste ich das einfach von 2^15 abziehen, erweitert um die 
Nachkommastellen.
1
v_ergebnis := x"800000000" - v_shift;

- Ist mein Gedankenansatz so korrekt?
- Wie kann ich aber nun mit der 2^16-1 umgehen, was ja an sich keine 
Shiftoperation mehr ist?
- Habe ich den signed Typ korrekt verwendet?
- Sind meine Gedanken zu den Vorzeichenbits und die ständigen 
Bit-Erweiterungen  incl. der Nachkommastellen korrekt?
- Wo muss ich nun aus v_ergebnis "herausschneiden"?

Ich muss nochmal die Theorie zu dieser Formel erfragen, der Kommilitone 
ist leider gerade im Urlaub, so dass ich erstmal nur stupide rechnen 
kann, ohne zu wissen, was genau ich da rechne. Es müsste eine Art 
Mittelwertbildung sein.

Vielen Dank! :)

von Vancouver (Gast)


Lesenswert?

Ich würde das ganze erstmal mit 2^16-1 durchmultiplizieren und dann den 
rechten Teil der Gleichung mit genügender Bitbreite rechnen (sieht nach 
32bit aus). Am Schluss multiplizierst Du das Ergbnis mit der 
vorberechneten Konstanten 1/(2^16-1). Damit bekommst Du die 
Rundungsfehler erst ganz am Schluss rein. Um eine Multiplikation kommst 
Du nicht herum, wenn des wirklich 2^16-1 sein muss, aber 
Konstantenmultiplier sind  nicht so wild. Geht es um einen FPGA? Um 
welchen?
Wegen der größeren Bitbreiten wäre es sinnvoll, das ganze zu pipelinen. 
Und numeric_std hat Funktionen zum resizen von Bitvektoren, siehe hier: 
http://www.synthworks.com/papers/vhdl_math_tricks_mapld_2003.pdf.

Ich kann so keinen Fehler erkenennen, aber der Simulator in meinem Kopf 
ist etwas unzuverlässig :-)

Wenn möglich, solltest Du einen synchronen Reset verwenden statt einen 
asynchronen, aber das hat auf die Arithemtik keine Auswirkungen.

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


Lesenswert?

Calc schrieb:
> leider weiß ich nicht, wie man den Formeleditor hier bedient
Stichwort: LaTeX

> Diese sollen dann in der folgenden Formel verrechnet werden
Ich glaube fast, die "-1" ist falsch, die erinnert mich sehr an die 
Berechnung der Spannung aus einem ADC-Wert. Und dort werden dann auch 
die Formeln mit 255, 1023, 2047, 4095... gern genommen, sind aber 
falsch.

Was soll mit dieser Formel erreicht werden?

von Calc (Gast)


Lesenswert?

Hallo,

Vancouver schrieb:
> Am Schluss multiplizierst Du das Ergbnis mit der
> vorberechneten Konstanten 1/(2^16-1).
Mit einer vorgerechneten Kontante multiplizieren ist eine gute Idee!

Vancouver schrieb:
> siehe hier:
> http://www.synthworks.com/papers/vhdl_math_tricks_mapld_2003.pdf.
Vielen Dank für den Link. Nicht viel neues dabei, wenn man das hier 
bereits kennt:
http://www.lothar-miller.de/s9y/categories/16-Numeric_Std
Aber doch nochmal eine gute Übersicht....

Lothar M. schrieb:
> Was soll mit dieser Formel erreicht werden?
Der Ausgabewert bzw. der Wert eines Sensors, basierend auf den aus dem 
Eingangssignal gebildeten Summen. Das Eingangssignal wird wohl durch die 
Messgröße beeinflusst. Je nach Messgröße vergrößern oder verkleinern 
sich die Summen und am Ende findet eine Art Mittelwertbildung statt, 
denn es werden zwei "Messungen" gemittelt.
Ich habe noch keine Infos, auf welcher Basis diese Formel entstanden 
ist. Ich habe nur die Aufgabe bekommen, das in Hardware zu rechnen. Dann 
hat sich der Kommilitone in den Ski-Urlaub verabschiedet.

Lothar M. schrieb:
> Ich glaube fast, die "-1" ist falsch, die erinnert mich sehr an die
> Berechnung der Spannung aus einem ADC-Wert. Und dort werden dann auch
> die Formeln mit 255, 1023, 2047, 4095... gern genommen, sind aber
> falsch.
Das kann ich dem Kollegen nochmal als Hinweis geben, vielleicht 
vereinfacht sich dadurch alles etwas, sollte er diesen Fehler gemacht 
haben.

Vielen Dank!

von Vancouver (Gast)


Lesenswert?

Calc schrieb:
> Vielen Dank für den Link. Nicht viel neues dabei, wenn man das hier
> bereits kennt:

War der falsche Link, sorry. Ich meinte das Fixedpoint-Package 
http://www.vhdl.org/fphdl/Fixed_ug.pdf,falls Du das verwenden willst. 
Aber ich weiß nicht ob sich das lohnt für die eine Multiplikation.

von Vancouver (Gast)


Lesenswert?

Nochmal der korrekte Link:
http://www.vhdl.org/fphdl/Fixed_ug.pdf

von Burkhard K. (buks)


Lesenswert?

Bist Du sicher, dass die Formel in der zitieren Form stimmt?

Kleine Überschlagsrechnung: wenn Deine A0/A1 und B0/B1 Werte ohne 
Vorzeichen 16 Bit Breite haben, dann kann deren Summe maximal auf 
(unsigned) 65535*6 (=393210) anwachsen, dieser Wert passt in 19 Bit. 
Wenn Du dieses Zwischenergebnis durch (2^16 -1, d.h. 16 Bit) teilst, 
bleiben 3 MSB übrig - die von einem 15 bit Wert (32768) abgezogen bzw. 
dazu (negativer Wert) addiert werden sollen!???

Das Ergebnis wäre ein 3-Bit Rauschen auf einem 15-Bit Offset. Scheint 
mir so keinen Sinn zu ergeben.

: Bearbeitet durch User
von Bego (Gast)


Lesenswert?

Ich möchte wetten, dass der Nenner sich komplett über den Term 
erstrecken sollte. So ist das Murks. Und das was Lothar andeutet, könnte 
auch noch Thema sein.

von Calc (Gast)


Lesenswert?

Ich habe nochmal die Unterlagen durchgeschaut.

s_a1 wird pro Schritt immer +1 oder -1 gerechnet.
s_a2 wird immer s_a1 + s_a2 gerechnet.

Es werden maximal 2^16 Schritte gerechnet.

s_a1 hat also maximal 17 bit (65536), mit Vorzeichen also 18 bit = 17 
DOWNTO 0.
s_a2 hat also maximal 31 bit (2147450880), mit Vorzeichen als 32 bit = 
31 DOWNTO 0

Wenn ich beide Summen nun zusammen addieren will.
Das Bit 17 und das Bit 31 sind ja jeweils die Vorzeichenbits.

Muss ich dann also alles so rechnen, damit ich die Vorzeichen korrekt 
verrechne?
1
v_a_block := s_a1(17) & "00000000000000" & s_a1(16 DOWNTO 0)  + s_a2;

Vielen Dank!

von Michael W. (Gast)


Lesenswert?

Calc schrieb:
> v_a_block := s_a1(17) & "00000000000000" & s_a1(16 DOWNTO 0)  + s_a2;

gibt für mich keinen sinn

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


Lesenswert?

Calc schrieb:
> damit ich die Vorzeichen korrekt verrechne?
Das sa(17) ist nicht DAS VorzeichenBIT.

Calc schrieb:
> Das Bit 17 und das Bit 31 sind ja jeweils die Vorzeichenbits.
Solche einzelnen(!) Vorzeichenbits gibt es nicht in der allgemein 
verwendeten Zweierkomplementdarstellung. Das hatten wir doch vor kurzem 
schon mal...

Ah, ja, hier im Beitrag "signed Vektoren unterschiedlicher Breite korrekt addieren". Erinnerst 
du dich? Was hast du da nicht verstanden?

Wenn du es dir unbedingt selber machen willst, dann muss es für eine 
korrekte Vorzeichenerweiterung so aussehen:
1
v_a_block := s_a1(17) & s_a1(17) & s_a1(17) & s_a1(17) & s_a1(17) & s_a1(17) & s_a1(17) & s_a1(17) & s_a1(17) & s_a1(17) & s_a1(17) & s_a1(17) & s_a1(17) & s_a1(17) & s_a1(17) &  s_a1(16 DOWNTO 0) + s_a2;

Ich würde da aber eher resize() nehmen oder zusammen mit der numeric_std 
gleich so schreiben:
1
v_a_block := s_a1 + s_a2;

: Bearbeitet durch Moderator
von Markus F. (mfro)


Lesenswert?

Ich habe jetzt auf die Schnelle nicht gefunden, welches FPGA benutzt 
wird.

Es macht aber sicher Sinn, auch mal die Nase ins Handbuch zu stecken, ob 
spezielle Hardware für die Multiplikation zur Verfügung steht und wie 
man die Synthese dazu bringt, die auch zu benutzen.

17 Bit breite Vektoren beispielsweise werden wahrscheinlich eher nicht 
unterstützt...

: Bearbeitet durch User
von Mike (Gast)


Lesenswert?

Markus F. schrieb:
> Ich habe jetzt auf die Schnelle nicht gefunden, welches FPGA benutzt
> wird.
>
> Es macht aber sicher Sinn, auch mal die Nase ins Handbuch zu stecken, ob
> spezielle Hardware für die Multiplikation zur Verfügung steht und wie
> man die Synthese dazu bringt, die auch zu benutzen.
>
> 17 Bit breite Vektoren beispielsweise werden wahrscheinlich eher nicht
> unterstützt...

Oh doch, das funktioniert ganz gut. Quartus z.B. verwendet bei 
Multiplikationen automatisch die passende Hardware (in Grenzen). Ein 
Blick ins Handbuch bzw. eigene Experimente schaden aber auf keinen Fall. 
Zumindest wenn man die Hardware optimal ausnutzen will. Signed-Zahlen im 
Format 1+17 Bit wären z.B. optimal für Altera FPGAs: dort werden dann 
z.B. 9 Bit Multiplikatoren kaskadiert.

Auf jeden Fall sollte das gründlich simuliert werden. Bei neueren 
Versionen von Modelsim ist es sehr hilfreich wenn man sich für die 
Anzeige der Festkommazahlen einen passenden benutzerdefinierten "Global 
Signal Radix" definiert.

Allerdings scheint die Formel fehlerhaft zu sein. Wenn das Endergebnis 
16 Bit haben soll ist eine Division durch 2^16-1 ziemlich sinnfrei...

von uwe (Gast)


Lesenswert?

> Wenn das Endergebnis 16 Bit haben soll ist eine Division durch 2^16-1
> ziemlich sinnfrei...
Sein Kollege scheint wohl durch 2^(16-1) Teilen zu wollen um ne Zahl 
zwischen -1 und +1 zubekommen, was natürlich vollkommen sinnfrei ist, 
denn man kann die Zahl ja einfach genauso interpretieren ohne durch 
irgendetwas zu Teilen (Fixedpoint interpretiert).

von J. S. (engineer) Benutzerseite


Lesenswert?

Das Ganze scheint mir in der Tat mehr ein mathematisches 
Verständnisproblem zu sein, als eines von VHDL.

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.