Sinustabelle in fpga initialisieren

Gast #1026293
Lesenswert?

hallo

für mein projekt soll ich einen NCO (numerical controlled oscillator) 
realisieren, dazu benötige ich eine sinustabelle. wie ich sie realisiere 
und so ist klar, das problem ist, ich darf die sinustabelle im fpga 
nicht erst errechnen, sondern sie soll zu beginn schon vorhanden sein.
da sie aber ne größe von 2^16 addressen hat, kann ich die tabelle nicht 
per hand reinschreiben. welche möglichkeiten gibt es denn noch. habe es 
mit ner externen textdatei versucht, wo ich später herausgelesen hab, 
das man die datei erst über fpga schreiben muss, bevor man sie einlesen 
kann.

dann gibt es noch die .mfc-datei, wenn ich mich täusche ist diese auch 
nicht für reine vhdl-programmierung geeignet und dsp-programmierung ist 
nicht erlaubt.

einzige alternative die ich sonst noch kenn, das ich mir den rom mit der 
tabelle beschreibe und dann immer darauf zugreife
Moderator (Firma: Titel) Persönliche Seite #1026311
Lesenswert?

> da sie aber ne größe von 2^16 addressen hat
Wozu brauchst du eine Sinustabelle mit 65536 Werten?
Mal abgesehen davon, dass übliche FPGAs intern gar keine so großen 
Speicher (64kByte) haben, könntest du damit einen Sinus auf 
360°/(65536*4)=0,0014° auflösen (mal 4 weil du ja nur 1/4 eines Sinus 
ablegen mußt, die anderen 3 Quadranten lassen sich dann leicht 
berechnen).

Das ist schon extrem genau ;-)

Ich würde behaupten, das brauchst du nicht. Mach doch eine kleine 
Tabelle und interpoliere zwischen den Stützpunkten. Das wäre m.E. der 
bessere Weg.

Konkret zu deiner Frage:
Welchen FPGA-Hersteller willst du einsetzen?

> einzige alternative die ich sonst noch kenn,
> das ich mir den rom mit der
> tabelle beschreibe und dann immer darauf zugreife
Dann kannst du (zumindest bei Xilinx-Config-Proms) aber nur gaaaanz 
niedrige Frequenzen erzeugen, die sind nämlich seriell ;-)
Gast #1026484
Lesenswert?

Ich hab vor kurzem mit dem selbem Problem gekämpft. Eine Sinustabelle 
kannst du ganz einfach durch den Kompiler erzeugen. Beispiel:
1
type VEKTOR is array (0 to 255) of integer;
2
signal SINUS: VEKTOR; 
3
signal COSINUS: VEKTOR;
4

5

6
     
7
build_tab: for k in 0 to 255 GENERATE
8
            CONSTANT x: REAL := SIN(real(2) * MATH_PI * real(k)* real(1)/real(255)) * real(255)*0.5 ;
9
             CONSTANT y: REAL := COS(real(2) * MATH_PI * real(k)* real(1)/real(255)) * real(255)*0.5 ;
10
            begin
11
                SINUS(k) <= integer(x);
12
                COSINUS(k) <= integer(y);
13
            end generate build_tab;

Eine Tabelle für 2^16 Bit Auflösung wird aber unwahrscheinlich groß und 
deine Entwicklungsumgebung braucht viiieeel Zeit um das alles zu 
erstellen.
Wenn es wirklich mit einer Tabelle gemacht werden soll, wäre es besser 
eine kleine Tabelle zu erstellen und dann zwischen den werte 
interpolieren.

Besser ist der Cordic algorithmus. Ich habe mich da auch erst vor 
gescheut weil es unheimlich kompliziert aussieht. Aber im eigentlich ist 
der Algorithmus ganz einfach und Logisch aufgebaut. Ich empfehle wir das 
Buch Digital Signal Processing with Field Programmable Gate Arrays. Da 
ist der Algorithmus sehr gut erklärt und sogar ein Beispiel Code dabei, 
ganz einfach zu verstehen!
Gast #1026580
Lesenswert?

> welche möglichkeiten gibt es denn noch.

Ein C-, Java-, oder sonstwie Programm, welches in einer Schleife die 
Sinuswerte errechnet und eine VHDL-Datei für ein ROM generiert. Schon 
zigmal gemacht, aber versuch es erstmal als Übung - es ist ganz 
nützlich, mit solchen Codegeneratoren Erfahrung zu haben.
Gast #1026604
Lesenswert?

@michi, danke für den tip

der war sehr nützlich, und da die tabelle ja beim compilieren erstellt 
wird, werd ich das wohl auch im projekt verwenden dürfen

die kompilierzeit beträgt bei mir 5min und speicher geht übrigens auch 
kaum verloren bin bei 6% also noch viel platz


auch der buchtip ist sehr nützlich weil ich auch noch nen digitalen 
filter realisieren soll und ich mir die nützlichen seiten auf google 
book anschauen kann
Gast #1029476
Lesenswert?

Hallo Michi,
was sollen die real(255)*0.5 in deinem Code:

build_tab: for k in 0 to 255 GENERATE
            CONSTANT x: REAL := SIN(real(2)  MATH_PI  real(k)* 
real(1)/real(255)) * real(255)*0.5 ;
             CONSTANT y: REAL := COS(real(2)  MATH_PI  real(k)* 
real(1)/real(255)) * real(255)*0.5 ;
            begin
                SINUS(k) <= integer(x);
                COSINUS(k) <= integer(y);
            end generate build_tab;

Erzeugt Sinus im Sinus, da mit halber Frequenz.

Wenn du einen reinen Sinus wünschst, einfach weglassen:
CONSTANT x: REAL := SIN(real(2)  MATH_PI  real(k)* real(1)/real(255));

Mfg
Gast #2024769
Lesenswert?

Äh what?

*255*0.5 würde ich glatt für ne Bereichsanpassung halten...
sin x -> [0°, 360°[
sin y -> [0 ... 1]

nach der Anpassung
sin x -> [0°, 360°[
sin y -> [0 ... 255/2]

*255 für Bytegröße, *0.5 wegen halber Amplitude (halber Bereich für 
positive Amp. und die andere Hälfte in den negativen Bereich)

wenn man mit Integergenauigkeit arbeitet muss man halt
* (2^32-1) * 0.5 rechnen, damit man die 32 Bit ausnutzt!
Moderator (Firma: Titel) Persönliche Seite #2024813
Lesenswert?

SagINet schrieb:
> 20.01.2011 10:41
>       Äh what?
Würde ich nach 1 1/2 Jahren auch fragen...

> *255 für Bytegröße, *0.5 wegen halber Amplitude
Richtig. Und daher ist der Kommentar falsch:
>> Erzeugt Sinus im Sinus, da mit halber Frequenz.
>> Wenn du einen reinen Sinus wünschst, einfach weglassen:
>> CONSTANT x: REAL := SIN(real(2)*MATH_PI*real(k)*real(1)/real(255));
Was da wegulassen wäre ist nämlich das real(2) im Sinus... :-o

SagINet schrieb:
> wenn man mit Integergenauigkeit arbeitet
Wird dort aber nirgends getan, die CONSTANT x ist REAL.
Allerdings wird dann durch das *0.5 dem Array SINUS() Werte im Bereich 
von -127 bis +127 zugewiesen...
Gast #2025257
Lesenswert?

Also 4096 Werte a 16Bit sind 65536Bit. Dies sollte kein Problem 
darstellen die Daten in einem RAM abzulegen.

Ich mache es wie folgt (bei Xilinx):

1. Ich erstelle mit Excel die Sinustabelle dies ist schnell gemacht.
2. Speicher dann die Tabelle als txt-Datei ab.
3. Bei Xilinx gibt es ein Tool mit dem man BlockRams oder ROM mit Werten 
vorbelegen kann. Ich Öffne also das Programm lade das Text-File und 
erzeuge dann das File für die BlockRam vorbelegung.

4. Anschließen erzeuge ich mit dem IP-Core Wizard einen BlockRAM mit der 
richtigen größe. Beim Wizard kann man dann einstellen ob alle Zellen mit 
einer Konstanten vorbelegt sein sollen oder ob man ein 
Initialisierung-File verwenden möchte. Ich wähle natürlich das 
Initialisierungs-File aus und erzeuge somit den vorinitialisierten Block 
RAM.

5. Somit steht in der 0. BlockRam Adresse der 1. Sinuswert in der 2. 
Adresse der 2. Sinuswert usw.
Gast #2027403
Lesenswert?

Entweder mit der Sinusfunktion aus math_real eine Tabelle generieren 
oder eben CORDIC. Für kleine Sinustabellen (so 1 KB) würde ich eine 
Tabelle verwenden, darüber CORDIC.

Der Cordic Algorithmus läuft pipelined je nach Wortlänge mit über 200 
MHz am Stratix II C4. Selbst seriell sollten mit 15 Stufen solltest du 
noch etwa 10 Mio Sinusberechnungen/s durchführen können.
Gast #2125618
Lesenswert?

> Ein vorberechnetes RAM auszulesen, dürfte ... die schnellste
> Variante bleiben...
Das wollte ich aber auch gesagt haben. Wobei: Grosse Tabellen belegen 
zuviel Blockram. Muss man raus ins DDR, wird es auch langsamer wegen der 
Latenz.
(Firma: www.dossmatik.de) #2133137
Lesenswert?

Hotte schrieb:
> Wie genau ist der Cordic-Algorithmus? Kann man sich das aussuchen?

Der Cordic-Algorithmus ist ein Näherungeverfahren. Je mehr Stufen 
einbaut um so genauer wird er. Der Algorithmus konverigert sehr schnell. 
Bereits bei geringen Iterationanzahlen ist der Fehler sehr gering.


http://www.mathworks.com/help/toolbox/fixedpoint/ref/cordiccos.html


>Rene, wieso kommt man mit Berechnung höher, als mit Ablesen aus dem Ram?
Höher habe ich nicht gesagt doch die Ausgabe mit 100Msamples/s ist kein 
Problem. Es geht auch höher, doch das habe ich noch nicht gebraucht.
Gast #2134224
Lesenswert?

Nach dieser Grafik von Mathworks beträgt der maximale absolute Fehler 
auch bei einer Iterationstiefe von 10 immerhin noch 0,005! Die Frage 
ist, wie dort der zugehörige Endwert aussieht. Selbst bei 1.0 wären das 
maximal 1:200, also nicht einmal 8 Bit Genauigkeit. Da braucht man aber 
keinen 12-bit Cordic.

Für eine Audiosignalerzeugung oder "analoge" IQ-Demodulation reicht das 
bei Weitem nicht.

Interessieren würden mich mal der Platzbedarf und der 
Rechenzeitbedarf(Latenz) für eine echtes Äquivalent einer Tabelle von: 
12 Bit Amplitude und 16 Bit Phase. Die bräuchte ich nämlich für eine 
DDS.
Gast #2137870
Lesenswert?

Ich habe eine Sinus/Cosinus-Funktion unter

http://opencores.org/project,sincos

abgelegt. Sie benutzt ROMs, weil der Cordic für meine Zwecke (digitale
PLLs) zu viel Totzeit erzeugt. Die Anzahl der Pipelinestufen kann man 
frei
wählen (in 0...10). Für den rein kombinatorischen Fall erzeugt XST viele
kleine distributed RAMs und keine Blockrams, was die generierte Hardware
natürlich ziemlich aufbläht.

Es wird nur 1/4 Welle abgespeichert, der Rest wird gespiegelt.
Sinus & Cosinus gleichzeitig brauchen nicht mehr Speicher als Sinus 
allein.
Das ist praktisch für I/Q-Verarbeitung.

Geschwindigkeit ist 230 MHz in Spartan-6 ohne Klimmzüge mit hinreichend
vielen Pipelinestufen.

Reines, portables VHDL ohne Xilinx, Matlab oder sonstwelchen Bezug.


Gruß, Gerhard




Aus der description:
Sine and cosine table that can be synthesized. Pure VHDL, no other tools 
or
silicon vendor macros. Pipeline delay can be selected from combinatorial
to 10 stages at compile time via a generic.

Phase input and sin/cos output widths are automatically determined by 
the
connected bus. 16 bit phase/18 bit amplitude runs at 230 MHz in 
Spartan6-3
without any optimization efforts. (Just setting 250 MHz as the goal)

Also features a programmable pipeline register entity for most basic 
VHDL types.
Pipeline delay can be set from 0 to MAXINT clocks

Also a library for conversion between reals and integer/fractional 
signed and unsigned.

The test bed can log the generated sinewaves to a file for inspection 
with matlab.
Gast #2137999
Lesenswert?

Compiliert, synthetisiert und simuliert jedenfalls ok. Und Matlab hat an 
den erzeugten Sinuswellen auch nix auszusetzen. Für die Doku will ich 
das noch durch den Video-DAC des SP605-Boards jagen ("Hardware-proved"). 
Leider schon wieder ein neuer DAC-Typ.

Rückmeldungen bekommt man auch bei 350 Downloads nicht, weder pos. noch 
neg.

Gerhard
Gast #2302170
Lesenswert?

Gerhard Hoffmann schrieb:
> Für die Doku will ich
> das noch durch den Video-DAC des SP605-Boards jagen ("Hardware-proved").
> Leider schon wieder ein neuer DAC-Typ.
Verstehe ich das richtig: Du willst einen (analogen) Farbkanal verwenden 
um Dein Signal auszugeben?

Um den Analogteil des Chrontel (SP605 u.ä.) zu aktivieren verwende ich 
folgende Initialisierung:
1
    // input data format (idf)
2
    // idf 0 - 24 bit color depht
3
    // dvi output / rgb bypass (vga output)
4
    // chrontel_address = 0x76; // 7 bit
5
    // dvi_address      = 0x50; // 7 bit -> display
6
    // apbvga delivers 640x480@60Hz
7
    // xclk with 1X pixel rate
8
    // reg  freq  <= 65 MHz   > 65 MHz
9
    // 0x33 tpcp    0x08        0x06
10
    // 0x34 tpd     0x16        0x26
11
    // 0x36 tpf     0x60        0xa0
12

13
    // adjust xclk and data
14
    chrontel_reg_write( 0x1d, 0x45); // input clock register, xcmd[3..0]=5
15
    
16
    // enable sync out and bypass
17
    chrontel_reg_write( 0x21, 0x09); // dac control register, sync, dacg[1..0], dacbp
18

19
    // values for lower 65 MHz according to table above
20
    chrontel_reg_write( 0x33, 0x08); // dvi pll charge pump control register,  dvid[2..0], dvii, tppsd[1..0], tcpcp
21
    chrontel_reg_write( 0x34, 0x16); // dvi pll divider register, tpffd[1..0], tpfbd[3..0]
22
    chrontel_reg_write( 0x36, 0x60); // dvi pll filter register, tplpf[3..0]
23
    
24
    // c0 = DVI, 00 = VGA only
25
    chrontel_reg_write( 0x49, 0xc0); // power management register, dvip, dvil, dacpd[2..0], fpd

Duke
Gast #2303733
Lesenswert?

Het mal jemand einen Vergleich gemacht, wie sich CORDIC und Tabelle 
gegeneinander verhalten?

Also, welche CORDIC Auflösung entspricht welcher Tabellengröße?

Zumindest in der Softwareentwicklung kommt man schnell von Tabellen weg. 
Wie ist das bei FGPAs?
Gast #2304029
Lesenswert?

Jo, bin da auch gerade dran...

Also, ein lummeliger Spartan3 schafft die CORDIC Umrechnung von Winkel 
nach Sinus/Cosinus nicht mit 100MHz (landet so ca. bei 75MHz, Winkel ist 
15bit, Sinus/Cosinus sind 16bit Werte). Ich habe das ganze mit 
Register-Balancing probiert (2 Clock cycle fuer die Berechnungen, hat 
nicht funktioniert) und bin dann auf 'multi-cycle' gegangen (da tut das 
ganze natuerlich, da effektiv mit 50MHz betrieben). Ist aber ziemlich 
'nasty'...

Eine LUT mit 1024x15bit plus angeschlossenem Multiplier (fuer die 
Verstaerkung) macht locker 100MHz (pipelined), ich kann also meinen 
Winkel mit einer Genauigkeit von 360Grad/1024 ~ 0,35Grad machen. Das 
reicht mir und deshalb nehme ich die LUT, zumal genuegend RAMs und 
Multiplier verfuegbar sind auf dem Chip.
Gast #5204682
Lesenswert?

Michi schrieb:
> Ich hab vor kurzem mit dem selbem Problem gekämpft. Eine
> Sinustabelle
> kannst du ganz einfach durch den Kompiler erzeugen. Beispiel:type VEKTOR
> is array (0 to 255) of integer;
> signal SINUS: VEKTOR;
> signal COSINUS: VEKTOR;
>
>
> build_tab: for k in 0 to 255 GENERATE
>             CONSTANT x: REAL := SIN(real(2)  MATH_PI  real(k)*
> real(1)/real(255)) * real(255)*0.5 ;
>              CONSTANT y: REAL := COS(real(2)  MATH_PI  real(k)*
> real(1)/real(255)) * real(255)*0.5 ;
>             begin
>                 SINUS(k) <= integer(x);
>                 COSINUS(k) <= integer(y);
>             end generate build_tab;
>
> Eine Tabelle für 2^16 Bit Auflösung wird aber unwahrscheinlich groß und
> deine Entwicklungsumgebung braucht viiieeel Zeit um das alles zu
> erstellen.
> Wenn es wirklich mit einer Tabelle gemacht werden soll, wäre es besser
> eine kleine Tabelle zu erstellen und dann zwischen den werte
> interpolieren.
>
> Besser ist der Cordic algorithmus. Ich habe mich da auch erst vor
> gescheut weil es unheimlich kompliziert aussieht. Aber im eigentlich ist
> der Algorithmus ganz einfach und Logisch aufgebaut. Ich empfehle wir das
> Buch Digital Signal Processing with Field Programmable Gate Arrays. Da
> ist der Algorithmus sehr gut erklärt und sogar ein Beispiel Code dabei,
> ganz einfach zu verstehen!

Hallo,

wenn ich diese Möglichkeit ausprobiere bekomme ich bei Quartus Prime die 
Meldung, dass keine Division und Multiplikation von Realzahlen möglich 
ist.


Error (10327): VHDL error at fft.vhd(162): can't determine definition of 
operator ""/"" -- found 0 possible definitions
Error (10327): VHDL error at fft.vhd(162): can't determine definition of 
operator ""*"" -- found 0 possible definitions

Eingebunden habe ich die folgenden Bibliotheken:

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.math_real.all;

Ich habe nun mal in die math_real reingeschaut und gesehen, dass hier 
auch keine Multiplikation oder Division definiert ist. Gibt es hierfür 
einen andere Bibliothek, welche ich einbinden muss?
Moderator (Firma: Titel) Persönliche Seite #5204878
Lesenswert?

toko schrieb:
> Gibt es hierfür einen andere Bibliothek, welche ich einbinden muss?
real und integer kann VHDL von sich aus. Sowas z.B.:
1
library IEEE;
2
use IEEE.std_logic_1164.all;
3
:
4
    signal i : integer;
5
    signal r : real := 0.5*2345.7/987;
6
:
7
:
8
    i <= integer(r*1.5678);
9
:
Nur für Sinus und Cosinus brauchst du die math_real.
Persönliche Seite #5206228
Lesenswert?

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