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 ;-)
Mit Cordic den Sinus berechnen - oder ist das zu langsam? http://www.xilinx.com/bvdocs/ipcenter/data_sheet/cordic.pdf
ups 2^12, sorry hab mich vertippt, und die anzahl wurd mir so vorgegeben benutzt wird von altera das Board Stratix II EP2S60F1020C4
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!
> 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
Kann man als selbstidenten Algo fomrulieren in form eine Rekursion. Das reicht meistens zeitlich für einige 100kHz - ganz ohne Tabelle.
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...
Wie genau ist der Cordic-Algorithmus? Kann man sich das aussuchen?
> 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
Na dann werde ich das mal erledigen. Wenn ich den Core freigeben habe, kannst du ja "approved by Horst" drunterstempeln :-)
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
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...
ahh, edit: Die LUT speichert nur 90Grad ab, also ist die Aufloesung in etwa 0,35Grad/4 also damit <0,1Grad...
Arbeitet der Cordic-Core eigentlich auch nur über 90 Grad und spiegelt?
Andreas Fischer schrieb: > Arbeitet der Cordic-Core eigentlich auch nur über 90 Grad und spiegelt? ja
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?
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.
:
Bearbeitet durch Moderator
Das Thema "Sinustabelle in FPGA" hatten wir ja eigentlich schon zur Genüge durchgekaut :-) Beitrag "Simpler VCO in VHDL" Beitrag "Universell programmierbarer DDS-Funktionsgenerator" Beitrag "Frequenzgenerator in VHDL" Beitrag "Frequenz DDFS" Beitrag "DDS bis 100Mhz, Probleme mim Ausgangssignal" Beitrag "Sinusgenerator für FPGA gesucht" Beitrag "DDS Interpolation" Beitrag "Wellenform synthetisieren" Beitrag "DDS Grundlagenfrage" Beitrag "Sinus über DDS erzeugen" Beitrag "Sinuserzeugung in VHDL" Beitrag "DDS erster Versuch" Beitrag "FIR-, IIR-Filter in VHDL umsetzen" Beitrag "Sinustabelle mit 2 Geschwindigkeiten" Beitrag "DDS - was, wenn f > f/2" Beitrag "FPGA als digitaler Oszillator?" Beitrag "Sinus per DDS, warum 2. Harmonische?" Aber irgendwie wird das Thema immer wieder ausgebuddelt....
Jürgen S. schrieb: > schon zur Genüge durchgekaut Yeah, hübsche (An-)Sammlung... ;-)
:
Bearbeitet durch Moderator
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.