Hallo, Ich habe für einen Spartan 3E einen Sinus Generator implementiert. Über USB kann die Sinuskurve im Block RAM des FPGA abgelegt werden. Über einen DAC wird der Sinus dann Ausgegeben. Die Abtastfrequenz ist einstellbar. Nun möchte ich nicht immer bei einer Amplitudenänderung die Sinuskurve neu über den PC berechnen und in den Block RAM laden. Hierzu möchte ich einen normierten Sinus im Block RAM ablegen und über den PC nur den Multiplikator einstellen. Um Rundungsfehler zu vermeiden Multipliziere ich erst mit dem Multiplikator um anschließend per Division auf den Richtigen Wert zu skalieren. Es wird also auf eine feste Divison durch 1000 oder ähnliches hinauslaufen. Der Multiplikator lässt sich leicht mit dem Core Generator von Xilinix erstellen. Dieser Multipliziert zwei 16 Bit Werte in einem Takt. Mein Problem ist jetzt das die Division 30 Takte benötigt. Für meine Anwendung ist das viel zu langsam. Gibt es eine andere möglichkeit die Divison durchzuführen. Oder gibt es vielleicht noch einen besseren Ansatz das ganze umzusetzen? Gruß Jörn
Jörn schrieb: > Es wird also auf eine feste Divison durch 1000 oder ähnliches > hinauslaufen. > > Der Multiplikator lässt sich leicht mit dem Core Generator von Xilinix > erstellen. Dieser Multipliziert zwei 16 Bit Werte in einem Takt. > > Mein Problem ist jetzt das die Division 30 Takte benötigt. Für meine > Anwendung ist das viel zu langsam. > > Gibt es eine andere möglichkeit die Divison durchzuführen. Oder gibt es > vielleicht noch einen besseren Ansatz das ganze umzusetzen? Jepp. Mach eine Division mit 1024. Die braucht gar keinen Takt ;-) Duke
Also eine Verschiebung um 10 Bits nach rechts. ;-)
Ähm, also irgendwie kann ich gerade nicht folgen.... Angenommen ich möchte 5000 auf 5 skalieren... 5000 / 1000 = 5 Binär wäre das dann 5000: 000100111 0001000 5 : 000000000 0000101 Wie soll ich das durch eine Bitverschiebung erreichen?
Deshalb sollst du auch 1024 (Binärzahl) und nicht 1000 (Dezimalzahl) als Divisor nehmen ;)
Vielleicht stell ich mich gerade auch einfach nur ziemlich dumm an, aber ich kann mir gerade absolut nicht vorstellen wie ich das umsetzen soll. Der Mit dem Core Generator erstellte Dividirer braucht ja egal mit welchem Dividenden seine 30 Takte.. Ein kurzer VHDL schnipsel würde mir bestimmt schon auf die Sprünge helfen.
Überleg Dir das Ganze mal an einer Division mit 2, 4, 8 ...
1 | signal s : unsigned(23 downto 0); |
2 | signal s_div_1024 : unsigned(13 downto 0); |
3 | |
4 | begin
|
5 | |
6 | ...
|
7 | s_div_1024 <= s(23 downto 10); |
8 | ...
|
Duke
Duke Scarring schrieb: > Überleg Dir das Ganze mal an einer Division mit 2, 4, 8 ... Aber der Mensch hat nun mal 10 Finger... ;-)
:-D Na toll, dann hab ich das ja doch richtig verstanden, genau den Ansatz habe ich auch schon ausprobiert Aber angenommen meine Zahl ist 8765 und möchte diese durch 100 teilen.... dann funktioniert das ganze nicht mehr.... oder?
Lothar Miller schrieb: > Aber der Mensch hat nun mal 10 Finger... ;-) Aber 2 Füße und deshalb kann er auch binär ;) schau hier : http://www.youtube.com/user/AlgoRythmics HG
Jörn schrieb: > Aber angenommen meine Zahl ist 8765 und möchte diese durch 100 > teilen.... > dann funktioniert das ganze nicht mehr.... oder? Doch: s=Sinusample g=Gain r=Resultat r=s*g / 2^x also s und g sind als Binärzahlen gespeichert in deinem FPGA. Zb. sind sie beide 16 Bit breit, dann ergibt sich t=s*g t = 32Bit breit, da s,g jeweils 16 Bit muß t minimal 32Bit breiter Vektor sein. r = t / 2^16, da t = 32Bit und r wieder 16 Bit breite haben soll. Fertig. Umgeschrieben sähe es so aus: r = s * (g / 2^16) Dein Gain g kannst du also als eine zahl zwischen 1 bis 1/2^16 betrachten. Ist g also 0xFFFF dann hast du die höchste Verstärkung, bei 0 kommt hinten auch immer 0 raus. Möchtest du also 0.5 Gain haben steht in g = 2^8-1 drinnen da 0.5 = 2^8/2^16-1 ist. Ergo: wenn du dein Gain Register befüllst dann weist du das dieses Register einen Wertebereich von (0 bis 2^x-1)/2^x hat. Möchtest du Gain = 0.1 setzen dann gilt g = 0.1 * 2^16, x = 16 Bits, so einfach ist das. Mit anderen Worten: alles in deinem FPGA sind Binärzahlen zur basis 2. Du möchtest mit Zahlen zur Basis 10 einstellen können. Um keine umständlichen Deziemalen Berechnungen durchführen zu müssen entscheidest du dich alle Berechnungen zur Basis 2 durchzuführen. Das bedeutet du musst deine Dezimalen Konfigurationen wie den Gain vorher von Dezimal nach Binär umrechnen. Das ist alles. Arbeite dich in Zahlendarstellung=Potenzschreibweise, in 5. Klasse gelernt ?, und Festpunktarithmetik ein. >8765 und möchte diese durch 100 87.65 = 8765 / 100 = 8765 * (0.01 * 2^x) / 2^x (0.01 * 2^x) ist das Gain Register im FPGA und ausrechnen tust du 0.01 * 2^x nicht im FPGA sondern extern in deiner Steuersoftware. Schaue dir die Formel genau an und du wirst sehen das sich die beiden 2^x streichen lassen. Aber für deine Berechnungen bedeutet diese Expansion der dezimalen Formel das du nun keine Berechnugen wie Divisionen mit dezimalen Zahlen durchführst sondern mit binären Zahlen und so auf langwierige Divisonen verzichten kannst weil dein Divisor eine zahl zur Basis 2 ist. Gruß Hagen
auf einem FPGA mit 2^x zu dividieren bedeutet nichts anders als die x untersten Bits eines Vektors zu ignorieren bzw. bestensfalls noch eine Rundung mit Hilfe dieser x untersten Bits.
Der nächste Tipp ist die Einführung eines Offsets um alle Berechnung ganzzahlig ohen Vorzeichen machen zu können. Also deine Sinus tabelle enthält normalerweise zb. Werte zwischen -+2^(x-1), sie sind also mit Vorzeichen gespeichert. Sagen wir mal 8Bit pro Sinuswert ergibt Wertebereich -128 bis +127. Wie fürhen einen Offset von +128 ein. Unsere Sinustabelle enthält nun Werte zwischen 0 bis 255 ohne Vorzeichen. Alle Berechungen werden nun ohne Vorzeihen und als ganzzahlen durchgeführt. Erst ganzs am Ende wird der DAC Wert wieder mit -Offset korregiert falls das überhaupt notwendig ist. So, finally hast du 1.) alles Wichtige auf binäre vorzeichenlose Berechnungen umgestellt 2.) dadurch die Möglichkeit eröffnet mit Festpunkzahlen zu arbeiten (hier 0.xyz) 3.) alle Divsionen durch Multiplikationen mit dem Reziproken ausgetauscht, statt also x / y rechnest du x * (1/y) wobei 1/y offline extern berechnet werden kann. 4.) alle verbleibenden Divisonen so umgewandelt das der Divisior immer eine Potenz zur Basis 2 ist 5.) dadurch diese Divisonen als Performancebremse komplett entfernt Gruß hagen PS: den Offset von +128 kannst du so sehen wie im Analogbereich der virtuelle Nullpunkt der Schaltung.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.