Spartan 3E - Sinusgenerator - Amplitude verändern

Gast #2372609
Lesenswert?

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
Gast #2372624
Lesenswert?

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
Gast #2372655
Lesenswert?

Ä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?
Gast #2372784
Lesenswert?

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.
Gast #2372806
Lesenswert?

Ü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
Gast #2372910
Lesenswert?

:-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?
#2372995
Lesenswert?

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
#2373037
Lesenswert?

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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren