Hallo zusammen,
sitze an meinem ersten grösseren VHDL-Audio-Projekt und habe nun
Probleme. Habe auch schon viel gelesen über FixedPoint und Multiplier
etc, trotzdem habe ich noch das ein oder andere Verständisproblem -
bitte um Hilfe zu folgenden Themen...
1) Q-Format:
ich möchte mein Audio-Input Signal simpel mit einem 4bit-Wert
1
0<Faktor<1
multiplizeiren, also leiser machen.
Den STD_LOGIC_VECTOR konvertiere ich in unsigned. Woher weiss der
Compiler denn nun, dass ich das Q-Format (also 1.3-Format) möchte und
nicht etwa das Signal mit 1111 = 15_dec multiplizieren möchte? Mir ist
die Existenz von dem Fixed-Package (sfixed, ufixed) bekannt, möchte es
aber gerne so machen und vorallem kappieren...
2) Truncate:
mein Ergebnis Vector soll ja wieder 24 Bit breit werden, von daher muss
ja das Produkt zurechtschneiden (oder runden, ich habe mich erstmal auf
schneiden festgelegt).
Meine recherchen sagen das MSB (Bit 47) ist überflüssiges VZ-Bit, fällt
also raus, dann sind die Signifikanten Bits 46-23 und die restlichen 23
(22 downto 0) fallen also raus... klingt gut, nur leider höre ich nichts
:-)! Wie muss ich das machen?
3) Simulation in iSIM:
wie Simuliere ich das ganze sinnvoll? Der Simulator kann ja nun mal
keine gebrochenen Zahlenwerte darstellen???
Vielen vielen Dank für die Hilfe...
und hier noch mein Code:
Wenn es bei so einfach Sachen schon hakt ....
Sieh Dir mal an, wiviele Bits Du bei einer unsigned-MUL und einer Signed
Mul wirklich jeweils bekommst und wie sich ein Wert im Ergenisvektor
abbildet. Dann siehst du auch, wo Du "schneiden" musst.
Runden hiese, zuvor noch rasch 0,5 addieren - so nebenbei.
Was Du aber vor allem wissen musst: wieviel bits musst du durchs
Gesamtsystem schleppen, um am Ende 24 bits zu haben.
Thorsten H. schrieb:> wie Simuliere ich das ganze sinnvoll? Der Simulator kann ja nun mal> keine gebrochenen Zahlenwerte darstellen???
Und leider auch keine Analogwerte (wie Modelsim)... :-(
> Meine recherchen sagen das MSB (Bit 47) ist überflüssiges VZ-Bit
Verwegene Annahme.
Wenn dein Eingangswort negativ ist, dann kann auch dein Ergebnis negativ
sein, und das erste Bit ist dann mitnichten "nur so ein Vorzeichen".
Sondern da steckt die Hälfte deiner Information drin...
> nur leider höre ich nichts
In welchem Wertebereich bewegt sich dein Eingangssignal?
Welchen Wert hat dein Vol_Faktor_Sig?
Korrekt: 0..15.
Das ist natürlich wenig, wenn du nach der Multiplikation die unteren
Bits alle wegschneidest. Denn: wo in den 48 Bits des Ergebnisses wird
sich das mit den 24 Bit am Eingang alles abspielen? Was gibt 24 Bit * 4
Bit?
Richtig: 28 Bits, das Ergebnis der Multiplikation wird sich dann also in
den Bits (23+7 downto 4) tummeln... :-o
Probiers mal so:
Vol_Faktor_Sig <= unsigned(Faktor & x"00000");
BTW:
Du brauchst hier eigentlich keinen Takt, die Berechnung ginge eigentlich
rein kombinatorisch. Oder willst du die Pipelinestufen im Multiplizierer
nutzen?
Schon vielen Dank für die Antworten!
@Berater: Manchmal scheitert es auch an vermeintlich einfachen Dingen,
trotzdem Danke für die Mühe.
@Lothar Miller: Vielen Dank für deine Ausführungen!
> In welchem Wertebereich bewegt sich dein Eingangssignal?> Welchen Wert hat dein Vol_Faktor_Sig?> Korrekt: 0..15.
ich nehme mal an 0...15, allerdings hätte ich gerne 0...1!
Das ist ja gerade mein Verständnisproblem bzgl 1.3-Format...
Die Schrittweite an sich, werd ich dann hinterher im Hörtest beurteilen
und bei Bedarf erweitern.
> Das ist natürlich wenig, wenn du nach der Multiplikation die unteren> Bits alle wegschneidest. Denn: wo in den 48 Bits des Ergebnisses wird> sich das mit den 24 Bit am Eingang alles abspielen? Was gibt 24 Bit * 4> Bit?> Richtig: 28 Bits, das Ergebnis der Multiplikation wird sich dann also in> den Bits (23+7 downto 4) tummeln... :-o>> Probiers mal so:> Vol_Faktor_Sig <= unsigned(Faktor & x"00000");
Logisch, Super es funktioniert!!!
Die Größe des Produktvektors (47 downto 0) kam in der Tat durch eine
dämliche Copy-Paste-Aktion aus einer anderen 24*24 bit Multiplikation
und dann habe ich schlicht nicht mehr darüber nachgedacht - vielen dank
für den Hinweis! Natürlich muss die Breite des Ergebnisvektors (27
downto 0) sein!
Das erklärt einiges...
>> BTW:> Du brauchst hier eigentlich keinen Takt, die Berechnung ginge eigentlich> rein kombinatorisch. Oder willst du die Pipelinestufen im Multiplizierer> nutzen?
gut zu wissen!
Bleibt also nurnoch die Frage mit dem verflixten Q-Format
(verständnishalber)?
Beste Grüße
Thorsten H. schrieb:> ich nehme mal an 0...15, allerdings hätte ich gerne 0...1!
1 wirst du nie schaffen, sondern immer 1 bit drunterbleiben.
Geh also einfach her und teile (für dich Gehirnintern) den Wert 0..15
mental durch 16. Das sind dann 1/16 = 0,625 bis 15/16 = 0,9375. Diese
Werte kannst du darstellen, 1,000 wirst du nicht schaffen.
Wenn du jetzt also (um bei handlichen Zahlen zu bleiben) 8 Bit mit 8 Bit
multiplizierst, dann ist dein Ergebnis 16 Bit. Wenn du jetzt mit 8 Bit
weiterarbeiten mußt, welche 8 Bit wirst du nehmen? Die oberen oder die
unteren 8 Bit? Klar: das was dich interessiert (dort wo die Musik
spielt), das findest du in den oberen 8 Bit.
Wenn du jetzt aber 8 Bit mit 4 Bit multiplizierst, dann ist dein
Ergebnis 12 Bit breit. Wenn du jetzt mit 8 Bit weiterarbeiten mußt,
welche 8 Bit wirst du nehmen? Die oberen oder die unteren 8 Bit? Klar:
das was dich interessiert (dort wo die Musik spielt), das findest du in
den oberen 8 Bit.
> Natürlich muss die Breite des Ergebnisvektors (27 downto 0) sein!
Aber nicht die deines Zwischenergebnisses!
Deine Multiplikation des Eingangswertes (24 Bit) mit 15 (=0,9375) ergibt
keine 48 Bit, sondern nur 24 + 4 Bit. Und deshalb dürftest du dann im
Ergebnis auch nur 4 Bits wegschneiden:
Out_L <= STD_LOGIC_VECTOR(Prod_L (27 downto 4));
Oder aber du mußt den Faktor soweit aufbohren, dass er wieder maximal
groß wird:
1111 ist bei 4-Bit die höchste Zahl (= 15/16 = 0,9375)
11111111111111111111111 bei 4 Bit (= 16777215/16777216 = 0,9999999404)
Beides entspricht der höchsten jeweils darstellbaren Zahl (0,9...), nur
bei mehr Bits wir es eben genauer (war ja eigentlich zu erwarten).
Da kann dir dann noch das Vorzeichen reinspucken, aber das kommt
später...
Und damit kommen wir zu meiner oben vorgeschlagene Lösung:
1111 & 00000000000000000000 (= 15728640/16777216 = 0,9375)
Erkennst du die Zahl?
Damit hast du 24 Bits und kannst wieder die "obere" Hälfte des
Ergebnisses verwenden.
Es ist nicht kompliziert, man muß es nur verstanden haben... ;-)
>Diese Werte kannst du darstellen, 1,000 wirst du nicht schaffen.
Deshalb multipliziert man auch nicht mit 0..15 sondern mit 1..16. Das
letzte 16.tel wird hernach aufaddiert. Soll die Volume auf null gehen
multipliziert man einen Faktor mit der bitgrösse = 4+4 und projiziert 17
Werte auf 16. Braucht man halt 2 Bit mehr (türkise Kurve).
Besser ist allerdings bei Audio und Loudness eh ein degressiver
Verstärkungsfaktor, oder ein progressiver, wenn man in db stimmen will.
Erstmal Wirklich vielen Dank euch beiden! Ihr bringt mirch der Sache
näher!
Lothar Miller schrieb:> 1 wirst du nie schaffen, sondern immer 1 bit drunterbleiben.> Geh also einfach her und teile (für dich Gehirnintern) den Wert 0..15> mental durch 16. Das sind dann 1/16 = 0,625 bis 15/16 = 0,9375. Diese> Werte kannst du darstellen, 1,000 wirst du nicht schaffen.
Ja soweit hab ichs kapiert denke ich. Der entscheidende Hinweis ist
vermutlich "Gehirnintern", was wohl heissen soll: deklariere ich ein
Signal als signed (oder unsigned), denke ich mir einfach dass mein
Signal von -0,999..+0,999 (bzw positiv) geht und der FPGA sieht aber
-8...+7 (2er Komplement). Was ist dann aber in dem Fall wenn ich
wirklich eine -8 möchte???
@Berater: meinst du vom Funktionsverlauf her mit "degressiv" vermutlich
einen logarithmischen Verlauf, der ja durch deine türkise Kurve
dargestellt ist, oder? Aber den Weg dahin hab ich leider nicht so
gecheckt (vol = 0 => projizieren?)
Grüße!
morgentau schrieb:> denke ich mir einfach dass mein Signal von -0,999..+0,999 (bzw positiv)
-1 .. +0,9999
> geht und der FPGA sieht aber -8...+7 (2er Komplement).
Ja. so ist das.
> Was ist dann aber in dem Fall wenn ich wirklich eine -8 möchte???
Gibts nicht im Wertebereich -1 ... +0.99999 :-o
Letztlich sieht eine -8 = "1000" binär genau gleich aus wie
eine -1 = "1000", und aufgrund des selben Bitmusters wird auch ein
DAC die selbe Spannung draus machen. Nur im Kopf kannst du da irgendwo
ein Komma reinsetzen:
0,9375 = "0,111"
7 = "0111,"
Bei den negativen Zahlen wirds ein wenig ungewohnter, aber es
funktioniert gleich:
-1 = "1,000"
-8 = "1000,"
Du siehst: das Bitmuster ist genau gleich, nur die Interpretation ist
anders.
@Thorsten: das oberste Bit kannst Du nur dann ignorieren, wenn auch dein
Verstärkungsfaktor ein Vorzeichen hat / hätte. Da er das sicher nicht
hat, ist die Überlegung hinfällig.
Schreibe Dir mal ein Excel und probiere die Maxwerte allesamt durch und
berechne die Bitbreiten und die nötigen Teiler, um das Ergebnis ja nach
jeder Operation wieder korrekt zu skalieren / zu interpretieren.
Also nochmal vielen Dank allezusammen!
Jetzt sitze ich beim nächsten (oder doch immernoch beim gleichen?)
Problem bzgl Kürzung des Ergebnisses (wie im ersten Post schon unter
Punkt 2) gefragt). In meinem Beispiel des ersten Postings oben hatte ich
ja einen unsigned * signed, nun aber zwei VZ-behaftete Zahlen...
Sowohl bei der Addition wie auch bei der Multiplikation von
1
signed
- Vektoren bekomme ich es trotz Bücherflut nicht auf die Kette :-(
Auch die Thread "rechnen in VHDL" sind leider nicht zu gebrauchen.
J.Reichardt in "VHDL-Synthese" (5.Auflage) schlägt folgendes vor:
Mein etwas vereinfachter Code macht folgendes :
SUM_Short<=STD_LOGIC_VECTOR(SUM(39downto16));-- 24 bit
was soviel heisst:
- durch "Prod_0(Prod_0'left) & ..." wird ein zusätzliches Bit
drangehängt was die Verkettung mit dem VZ-Bit ermöglicht.
- A und B bestehen nach der Konvertierung aus: VZ & (22 downto 0) = 24
Bit
- SUM ist ein Bit breiter gewählt als die eigentliche Summe aus den
Produkten und besteht aus: VZ & Sicherheitsbit & (38 downto 0) = 41 Bit
soweit alles klar....AABBBER:
jetzt soll mein Ergebnis am Port (SUM_Short) ja wieder 24 bit haben
wegen weiterer Nutzung in der Pipeline!
Wo schneide nun Information weg???? (letzte Zeile meines Beispiel-Codes)
In meinem Fall werden ja Addition und Multiplikation vermischt und ich
kann überhaupt nichtmehr nachvollziehen, wo der Fehler steckt, zumal
ich nicht weiss wie ich es simulieren soll?
Habe schon sämtliche abschneide Szenarien durchprobiert...
Bei Simulieren stimmt das Ergebnis SUM und PROD (Radix: "signed
Decimal"), allerdings "denke" ich mir ja ne Fixedpoint zahl.....Chaos!
Ich hoffe es kann jemand meine Problematik nachvollziehen und mir
zugestehen, dass es durchaus etwas kompliziert ist das Ganze ;-)...Wenn
mir das jemand plausibel darlegen könnte...ich wäre sehr
dankbar...merci!
Thorsten H. schrieb:> SUM ist ein Bit breiter gewählt als die eigentliche Summe aus den> Produkten
Weil jede Summe einen Überlauf in die nächste Stelle mit sich bringen
kann.
> VZ & Sicherheitsbit & (38 downto 0) = 41 Bit
Diese Darstellung ist falsch: das erste Bit ist nicht einfach so ein
Vorzeichenbit! Denn sonst würde ja das hier gelten:
dez binär (3 Bit)
1 = 001
-1 = 101
oder
3 = 011
-3 = 111
oder
0 = 000
-0 = 100
Du kannst nur sagen:
Wenn das vorderste Bit gesetzt ist, dann ist die Zahl immer negativ.
Thorsten H. schrieb:> Wo schneide nun Information weg???? (letzte Zeile meines Beispiel-Codes)
Du schneidest das erste Bit vorne weg (den Überlauf, denn darin darf
keine verarbeitbare Information stecken***), und den Rest (LSBs) hinten.
Dann bist du wieder schön im Bereich -1...0,9999. Probiers einfach
aus...
***Warum darfst du den Überlauf einfach abschneiden?
Die Summe darf gar nicht überlaufen.
Denn 0,6+0,6 gibt 1,2 und das passt nicht in deinen Wertebereich von
-1,0...0,9999 :-o