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
> 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 ;-)
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!
> 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.
@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
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
Ä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!
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...
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.
Mit dieser eben beschriebenen Methode kann man nicht nur ein Sinus oder
Cosinus erzuegen sondern jedes beliebige Muster. Du kann so z.B. eigene
Testsignale erzeugen
Asic-Mann schrieb:> Kann man als selbstidenten Algo fomrulieren in form eine Rekursion. Das> reicht meistens zeitlich für einige 100kHz - ganz ohne Tabelle.
Mit dem Cordic Algorithmus kommt man in höhere Frequenzen. Weit in die
Megaherzen. Das ist ganz ohne Tabelle.
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.
Solange man nur den Wert selber braucht und mit dem pipelining leben
kann, ist der CORDIC in der Tat besser. Es gibt aber Fälle, wo
dynammisch moduliert werden muss/soll und da ist die DDS-Methode besser.
Mit einer echten Tabelle kann man auch gut interpolieren, indem man die
Tabelle mehrfach abtastet. (dy und auch dt).
> Mit dem Cordic Algorithmus kommt man in höhere Frequenzen. Weit in die>Megaherzen.
Rene, wieso kommt man mit Berechnung höher, als mit Ablesen aus dem Ram?
Ranga Yogibaer schrieb:> Rene, wieso kommt man mit Berechnung höher, als mit Ablesen aus dem Ram?
Das wurde nicht behauptet... ;-)
Ein vorberechnetes RAM auszulesen dürfte ungeschlagen dei schnellste
Variante bleiben...
> 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.
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.
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.
Der NCO in Quartus braucht bei Deinen Angaben 1402 LEs ud mit 1 Bit mehr
1582 (32 Bit Phase, 17 Frequenzmodulation, 13 Bit Genauigkeit).
Er bringt bei 20kHz 80dB SNR laut Diagramm.
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.
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
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:
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?
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.
PS: Die LUT lasse ich mir uebrigens mit einem Perl-Script in der
gewuenschten Aufloesung und Tiefe generieren. Bin ja nicht bescheuert
und tippe das von Hand ein...
Andreas Fischer schrieb:> Arbeitet der Cordic-Core eigentlich auch nur über 90 Grad und spiegelt?
Ich denke, das machen alle Algorithmen so. Der Cordic liefert dazu noch
Sinus und Cosinus parallel frei Haus.
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?