Forum: FPGA, VHDL & Co. DDS Compiler - Phase nur bis 16 Bit?


von Michael W. (Gast)


Lesenswert?

Ich werd' noch mal blöde mit dem Xilinx:

Gerade auf die Schnelle versucht, eine Sinustabell mit dem DDS-Compiler 
zu erzeugen, die mit uc-programmierten Frequenzen läuft und 
festgestellt, dass die nur bis 16 bit Phasenauflösung geht. Gibt es das?

von Achim S. (Gast)


Lesenswert?

Markus W. schrieb:
> Gerade auf die Schnelle versucht, eine Sinustabell mit dem DDS-Compiler
> zu erzeugen, die mit uc-programmierten Frequenzen läuft und
> festgestellt, dass die nur bis 16 bit Phasenauflösung geht. Gibt es das?

Du meinst der Phasenakkumulator schafft nur 16 Bit Auflösung? Das fände 
ich sehr  seltsam.

Oder meinst du, dass die Sinustabelle "nur" 2^16 Einträge schafft? Das 
könnte schon sein, schließlich ist der Speicherplatz in deinem FPGA 
begrenzt.

Welches FPGA nutzt du denn, wieviel Speicherressourcen hat das?

von Michael W. (Gast)


Angehängte Dateien:

Lesenswert?

Genannt ist nur die Phase. Kann sein es ist die LUT-Adress-Breite, keine 
Ahnung. Chip ist Kintex, Platz sollte rechnerisch für 20 solche Tabellen 
sein.

von Achim S. (Gast)


Lesenswert?

Markus W. schrieb:
> Genannt ist nur die Phase. Kann sein es ist die LUT-Adress-Breite, keine
> Ahnung.

Ja, es ist die LUT-Adressbreite. Wenn du oben statt "LUT-Only" eine 
andere Option wählst siehst du, dass der Phasenakkumulator wesentlich 
breiter sein könnte. Und tatsächlich definiert ja zunächst mal der 
Phasenakkumulator die Phasenauflösung der DDS, nicht die Größe der 
Sinustabelle.

Bei der Sinustabelle wird tatsächlich auf eine Adressbreite von 16 Bit 
begrenzt. Das hat vielleicht auch was mit der Spannungsauflösung zu tun 
(in deinem Bild der "Output Width"). Der DDS-Compiler will vielleicht 
nicht beliebig viel Speicherplatz für die Sinustabelle verwenden, wenn 
in der Tabelle in benachbarten Stellen dann ohnehin jeweils lauter 
identische Werte stehen würden.

Findet sich denn im Datenblatt des DDS-Compilers nichts dazu?

von my2ct (Gast)


Lesenswert?

Markus W. schrieb:
> Gerade auf die Schnelle versucht, ...

Markus W. schrieb:
> Genannt ist nur die Phase. Kann sein es ist die LUT-Adress-Breite, keine
> Ahnung.

Dann solltest du vielleicht erstmal letzteres Ändern.
Nimm dir etwas Zeit und arbeite dich etwas in die Funktionsweise eines 
DDS ein, statt blind auf irgendwelchen Tools rumzuklicken.

von Michael W. (Gast)


Lesenswert?

Achim S. schrieb:
> Bei der Sinustabelle wird tatsächlich auf eine Adressbreite von 16 Bit
> begrenzt. Das hat vielleicht auch was mit der Spannungsauflösung zu tun
> (in deinem Bild der "Output Width").
Leider nein, auch wenn ich auf 20 bit und mehr aufziehe, ergibt sich 
keine andere Konfigurationsoption. Die "Rasterung", was immer das sein 
soll, schränkt sogar auf 4 Bits ein. Auch andere Optionen ändern das 
nicht.

> Der DDS-Compiler will vielleicht
> nicht beliebig viel Speicherplatz für die Sinustabelle verwenden,
Es steht genug RAM zur Verfügung.

> wenn in der Tabelle in benachbarten Stellen dann ohnehin jeweils lauter
> identische Werte stehen würden.
Das wäre nicht der Fall, da die 24 Bit diese Auflösung hergeben. Lässt 
sich ja ausprobieren. Die Werte ändern sich von Phasenwert zu Phasenwert


Achim S. schrieb:
> Und tatsächlich definiert ja zunächst mal der
> Phasenakkumulator die Phasenauflösung der DDS, nicht die Größe der
> Sinustabelle.
Dann würde auch eine 10 Bit DDS dasselbe ausgeben, wie eine 20 Bit DDS? 
Hauptsache der Phasenvektor ist gross genug?


my2ct schrieb:
> Dann solltest du vielleicht erstmal letzteres Ändern.
Kann ich nicht. Ich benötige die Auflösung.

> Nimm dir etwas Zeit und arbeite dich etwas in die Funktionsweise eines
> DDS ein
Ich kenne DDS sehr genau und habe auch den Core immer mal wieder 
verwendet.

Ich sehe nur, dass er scheinbar nur noch AXI kann, statt auch das 
frühere Interface. Da gab es diese Einschränkung nicht. Hängt es gfs 
damit zusammen, dass die AXI-Phase nut 16 Bit kann?

von Achim S. (Gast)


Lesenswert?

Markus W. schrieb:
> Ich sehe nur, dass er scheinbar nur noch AXI kann, statt auch das
> frühere Interface. Da gab es diese Einschränkung nicht.

habe es eben mit der ISE 14.7 ausprobiert. Da kann die Phasenbreite zwar 
bis 26 Bit eingestellt werden (was beim aktuellen DDS-Compiler 
wahrscheinlich immer noch geht), aber die Adressbreite für die 
Sinustabelle geht auch bei dieser ziemlich uralten ISE nur maximal bis 
16 Bit. War also auch früher schon genau so.

Dafür werden im Datenblatt dann verschiedene Methoden genannt, wie man 
die daraus evtl. entstehenden Signalverfälschungen reduzieren kann 
(Phase Dither, ...)

Markus W. schrieb:
> my2ct schrieb:
>> Dann solltest du vielleicht erstmal letzteres Ändern.
> Kann ich nicht. Ich benötige die Auflösung.

Na ja.

Es geht dir also einfach darum, einen möglichst großen Speicher im FPGA 
mit einer Sinustabelle vorzubelegen? Wenn dir der DDS-Compiler dabei 
nicht weit genug geht, dann kannst du ja selbst einen entsprechend 
großen Block-RAM instanziieren und die Sinuswerte über ein 
Koeffizientenfile vorbelegen. Um Sinus-Werte zu berechnen brauchst du ja 
nicht zwingend den DDS-Compiler, das kannst du auch unabhängig von 
Xilinx z.B. per Excel erledigen.

Wenn der Router es dann noch schafft, alle Ram-Blöcke wie von dir 
gewünscht zu verdrahten, hast du die benötigte Auflösung deines 
Problems.

von my2ct (Gast)


Lesenswert?

Markus W. schrieb:
> my2ct schrieb:
>> Dann solltest du vielleicht erstmal letzteres Ändern.
> Kann ich nicht. Ich benötige die Auflösung.

Für die Phase des DDS oder für den Analogwert bei Ausgabe der 
Sinuskurve?

von J. S. (engineer) Benutzerseite


Lesenswert?

Achim S. schrieb:
> einen großen Block-RAM instanziieren und die Sinuswerte über ein
> Koeffizientenfile vorbelegen. Um Sinus-Werte zu berechnen brauchst du ja
> nicht zwingend den DDS-Compiler, das kannst du auch unabhängig von
> Xilinx z.B. per Excel erledigen.

Exakt. Mache ich schon immer so. Der DDS-Compiler scheint auch so seine 
Eigenheiten zu haben, bzw. die Firma Xilinx hat ein eigenes Verständnis, 
wie Sinuswerte auszusehen haben, damit man sie sequenziell ausgeben 
kann. Ich habe vor etwa 10 Jahren dazu schon einen Artikel gepostet, in 
welchem ich auf die Unterschiede hingewiesen habe. Es scheint sich um 
Rundungsfehler zu handeln, bzw. ich runde anders, als Xilinx es tut. 
Mein Phasenoffset ist auch ein anderer und orientiert sich an dem 
Prinzip, dass ein Phasenwert X immer die Mitte eines Phasenbereiches 
abdeckt, also die 0 repräsentiert den Bereich von 0 bis 1,  die 1 den 
von 1 bis 2. Damit ist der richtige Sinuswert Y der des Wertes X in der 
Mitte, also z.B. 0.5, 1.5 etc. Der erledigt das Problem eines impliziten 
Offsets und einer möglichen Änderung des Verhaltens wenn der Vektor mal 
aufgebohrt wird. Auch sind die Sinuswellen unterschiedlicher Auflösungen 
so immer auf derselben Phasenlage. Siehe auch meine Ausführungen im 
Artikel
Digitale Sinusfunktion.

Der Nachteil einer selbst erzeugten Tabelle ist leider die extreme 
Synthesezeit bei langen Tabellen, wenn man es nicht im BRAM, sondern 
unter z.B. Mitbenutzung von LUTRAM bauen will. Ich erlebe das auch 
gerade wieder bei meinen fest verbauten Wellenformen. Die haben z.B. 20 
Bit-Phasen und synthetisieren ewig. Ich will die aber in LUT haben, 
damit sie klein bleiben. Typisch lassen sich die Umfänge ja stark 
reduzieren, wenn die Logik optimiert wird.

Wenn es nur ein Sinus sein soll, dann tut gfs auch der CORDIC. Der hat 
dann eben wieder Latenzen und den Nachteil, dass man nur binäre 
Auflösungen erzeugen kann.

von Gerhard H. (ghf)


Lesenswert?

Ich habe in 2010 eine Sinustabelle in reinem VHDL nach

<  https://opencores.org/projects/sincos      >

hochgeladen. Die hat keine künstlichen Beschränkungen.
Wenn du das RAM /ROM hast, dann bekommt er es voll.
Das Testbett enthält als Beispiel einen DDS.
Reines portables VHDL, kein ise/vivado/matlab, was auch immer.

Es werden alle möglichen Symmetrien ausgenutzt und man
bekommt Sinus & Cosinus gleichzeitig ohne Mehraufwand.
(Na ja, ein paar Pipelineregister).

Die Anzahl der Pipelinestufen kann man einstellen von 0
(rein kombinatorisch) bis 10, WIMRE. Die werden halbwegs
sinnvoll an den richtigen Stellen eingefügt, weil der
Register-balancer zumindest damals bei der ISE nicht
viel getaugt hat.

Bei der Compilation wird gecheckt, dass alle Werte
korrekt bis zum letzten Bit gerundet sind; das heisst
der Fehler ist max. ein halbes Bit.

Die einzigen Beschwerden die bisher gekommen sind,
waren dass Leute es nicht geschafft haben ihren
Modelsim auf ps einzustellen.

Wenn man z.B. wirklich niedriges Phasenrauschen
braucht, dann muss man eben den Speicher opfern.

Wenn man Phasen/Frequenzmodulation/sweeps machen will,
dann bekommt man beim Cordic Latenz-Probleme.

Die Sinustabelle ist dieses Jahr bisher 139 mal runter-
geladen worden. Meist in Clustern. Ich vermute,
immer dann, wenn passende Hausaufgaben verteilt werden. :-)

Gruß, Gerhard

: Bearbeitet durch User
von Michael W. (Gast)


Lesenswert?

Klingt nicht schlecht, die hatte ich auch schon gefunden. Nur hat mich 
das "Development status:Beta" abgeschreckt. Auch ist OC nicht die 
präferrierte Quelle für Sourcen wegen der Rechtesituation dort. Wir 
hatten schon echten Ärger mit Kunden und Kundeskunden, weil OC-SW 
verwendet wurde. Wird in Aufträgen auch regelmäßig ausgeschlossen.

von Gerhard H. (ghf)


Lesenswert?

BSD ist doch letztlich "Mach damit was du willst, aber lass mich in
Ruhe und behaupte nicht, es wäre von dir."
Entgegenkommender kann man kaum sein.

Ja, ich wollte eigentlich noch erweitern auf BCD, damit man aus einer
100 MHz clock auch EXAKT und phasenstarr 0.999 MHz machen kann, aber
wenn nie eine Rückmeldung kommt, ausser wenn jemand Probleme mit
seinen Werkzeugen hat, dann verschwindet der Antrieb recht schnell.

Gruß, Gerhard

(BCD gestrichen, auf stable gesetzt)

von Michael W. (Gast)


Lesenswert?

Habe es mal versucht, zu analysieren und zu implementieren. Scheitere 
aber an diese float_fixed_lib. Ist die aus dem Xilinx_Lib pool zu 
ziehen?

Mit float möchte ich eigentlich nicht arbeiten.

Ich finde mich auch ehrlich gesagt nicht zurecht. Sind erstaunlich viele 
files. Welche brauche ich davon denn?

Ich erkenne auch nicht, wo ich die Bitbreiten einstellen soll. Ich hätte 
jetzt sowas wie generic erwartet.

?

von Gerhard H. (ghf)


Lesenswert?

Ah, Sonntag morgen um 00:45....

Float ist ein ganz normaler VHDL-Datentyp, und der wird nur
zur Compilationszeit auf deinem PC benutzt. Im FPGA landet
keinerlei Gleitkomma-Arithmetik. Die Funktion init_sintabxxxx()
macht zwar intern jede Menge Gleitkomma-Turnerei, aber was
sie letztendlich abliefert ist nur ein ROM-Image, mit dem man
ein konstantes Dingens vom Typ sintab initialisieren kann.
Und sie ist beim Compilieren geschwätzig.

VHDL ist eine Simulationssprache, von der ein Teil
synthetisierbar ist. VHDL kann alles was C oder Pascal
können. Die libraries sind halt beschissen (textio etc)
und es macht eher weniger Spaß. Das kotzt einen spätestens
an, wenn man aus Vorschriftswut kein wirkliches Äquivalent
zu printf() mit variabler Parameterzahl bekommt.

Die Vektor-Breiten ergeben sich automatisch daraus, was du
"von oberhalb" anschliesst. Da ist nix zu tun. Du musst es
nur im Context compilieren.

Wenn Du einen Bus mit 20 Bit Breite an den Ausgang anschliesst,
dann liefert die Tabelle eben 20 Bit. Du brauchst nicht sagen,
übrigens, wir brauchen 20 Bit. Das kann man schon an den
Attributen des Ausgangsbusses sehen. Es wird einfach das 'length
oder 'high-Attribut der angeschlossenen Busse benutzt.
Das passt dann von selbst.

Aaargh, ich hatte > 8 Jahre keinen Grund mehr, mir das anzuschauen.
Ich bemühe mich, mehr in analoge Raumfahrtelektronik abzudriften.
Aber auch da poppt schon mal ein Steinzeit-Virtex hoch, das
nach einer triple module redundancy library fragt.

Gute Nacht für heute!

Gerhard

: Bearbeitet durch User
von Michael W. (Gast)


Angehängte Dateien:

Lesenswert?

Danke für die Ausführungen. Ist plausibel. Allerdings kriege ich es 
nicht ins Laufen:

Alles importiert, ein Untermodul wurde nicht gefunden.

Verweise intern von work (obsolet) auf xil_defaultlib umgestellt (was 
normal klappt), nichts geht mehr:

von Michael W. (Gast)


Lesenswert?

push

von J. S. (engineer) Benutzerseite


Angehängte Dateien:

Lesenswert?

Braucht es das wirklich so genau? Mit einer Tabelle, die 16 Bit Phase 
hat und sowohl SIN als auch COS enthält, kann man durch direktes 
rechnerisches Interpolieren deutlich erhöhte Auflösungen erzielen, als 
es scheint, in man einfach 2 Punkte ausliest und eine Kurve darüberlegt 
(bis zu 4 Randbedingungen). Heutige Microprozessoren sind rechenstark 
genug, um das zu leisten. Selbst im FPGA mache ich keine Sinustabellen 
mehr, die größer sind. Im Gegenteil: Ich habe schon mit WaveTables 
gearbeitet, die nur 12 Bit Phase hatten und die haben ja noch Oberwellen 
drin.

Ein einfacher Sinus mit 11Bit Auflösung für die volle 4/4-Phase und nur 
9 Bit Amplitude, unter Aufspaltung in 5 Phasen- und 6 Restbits bringt 
selbst bei linearer Interpolation nur 0,6% Abweichung, wenn man es 
richtig macht.
(effektiv eine Altera-freundliche Tabelle mit (16 9 Bit-Werten, 
inklusive Offsettrickserei 8 Stützwerte!). Unter Ausnutzung eines 
kompletten Block-RAMs mit voller Symmetrienutzung (11 Bit für die 
1/4-Phase und 6 Bit für den Steigungskoeffizienten) sind es es nochmal 
einen Faktor 10 besser.

Erhöht man die Amplitudenauflösung auf quasi artefaktfrei, ab z.B. 4 
Bits mehr, reduziert sich der Fehler auf etwa die Hälfte, was aber nicht 
wirklich besser ist, weil dann je nach erzeugter Frequenz die Werte in 
den Tälern rhythmisch getroffen werden und sich der Fehler spektral 
schlechter verteilt.

Noch besser wird es mit quadratischer Interpolation über 3 Punkte, 
besser aber gleich 4 mit der doppelten RAM-Größe. Das ist im ersten 
Schritt sogar effektiver, als die doppelte RAM-Größe in die Amplituden- 
oder Phasenauflösung zu investieren.

Erst, wenn man das hat, lohnen mehr Bits in den Tabellen. Das scheint 
vielen nicht so recht klar zu sein. Hatte schon mehrere erstaunte 
Kunden, die trotz gut aufgelöster Sinus-Tabellen in ihren Generatoren 
sehr mäßige Ergebnisse hatten im Vergleich zu meinen spezialisierten 
MINI-Cores.
Wenn ich mir den Resourcenbedarf so ansehe, den der XI-Core da 
erfordert, steht das in keinem Verhältnis zum Ergebnis.

Ist aber heute Designstrategie: Hauptsache schnell fertig, rein damit 
und zufrieden sein. Chipfläche kostet ja nichts.

von Gerhard H. (ghf)


Lesenswert?

In James A. Crawford's Synthesizer Design Handbook, Artech House

< 
https://www.amazon.de/Frequency-Synthesizer-Handbook-Microwave-Hardcover-ebook/dp/B006TWYZ5Y/ref=sr_1_fkmr0_1?__mk_de_DE=%C3%85M%C3%85%C5%BD%C3%95%C3%91&keywords=James+A.+Crawford%27s+Synthesizer+Desihn+Handbook%2C+Artech+House&qid=1576525910&sr=8-1-fkmr0 
>

sind einige Techniken zur Reduktion der Tabellengröße aufgeführt.
Das reicht von etwas Interpolation über Sunderland's Zerlegung
des ROMs in 2 kleinere bis zum Dithering, um die entstehenden
spurs glattzurubbeln.
Die Reduktion kann bis 1:50 gehen, WIMRE.
Das geht so über 30 Seiten; wenn ich das scanne, dann bekomme
ich wohl Ärger.

Ich werde mich im Januar noch mal mit dem Opencores-Block befassen,
jetzt ist Meilenstein-Rallye.

Gruß, Gerhard

: Bearbeitet durch User
von Michael W. (Gast)


Lesenswert?

Gerhard H. schrieb:
> Sunderland's Zerlegung

Danke für den Hinweis! Ich konnte über go...le einen Ausschnitt dieses 
Buches finden und stieß dort auf eine Tabelle, wie man Sunderland 
erzeugen können soll. Leider ist mir nicht so ganz klar, wie das gemeint 
ist, denn der Text ist äußerst knapp. Ich finde es aber interessant und 
habe einen thread dazu aufgemacht. Ich poste es im DSP-Forum, weil es 
sich wohl am Besten für Software-Lösungen eigenen dürfte:

Beitrag "Bildung und Nutzung von Sunderland Tabellen für Sinus"

Ich habe auch heute nochmal gesucht und finde im Grunde immer wieder 
dieselbe Tabelle auf die alle Bezug nehmen.

Die Kernfrage wäre, ob sich das skalieren ließe, als z.B. von 12 auf 24 
Bit Eingangsbreite und ob (die wichtige Frage) sich damit die Auflösung 
auch verbessert - nicht dass der Fehler relativ gleich bleibt.

von J. S. (engineer) Benutzerseite


Lesenswert?

Gerhard H. schrieb:
> Sunderland's Zerlegung des ROMs
Die Methode sollte sich IMHO in der Gesamtschau bei der Qualität 
heutiger Synthesewerkzeuge und Hardware erledigt haben. Das gilt 
insbesondere für Tabellen in FPGAs, die in LUTs abgebildet sind. 
Aufgrund der geringen BIT-Zahl kommt man da nicht mehr so gut bei raus, 
sobald die erforderliche Bit-Breite mehr, als 2 LUT-Breiten sind. Eine 
Abbildung im Block-RAM ist zielführender, weil schneller addressierbar 
und am Ende kleiner und stromsparender, weil der Adress-MUX schon hart 
implementiert ist. Und wenn man ein BRAM hat, sind 10kb-20kb das minimal 
verfügbare.

Beitrag "Re: Bildung und Nutzung von Sunderland Tabellen für Sinus"

Für etwas rechenschwache Systeme wie NIOS oder MicroBlaze, die in sehr 
kleinen FPGAs gebaut werden sollen, welche kaum BRAM haben, aber dennoch 
hohe Durchsätze produzieren sollen, könnte das noch ein Thema sein.


Gerhard H. schrieb:
> bis zum Dithering, um die entstehenden
> spurs glattzurubbeln.

Mit dithering ist diesbezüglich aber nicht viel zu wollen. Das taugt 
mehr, um die Auflösung in Y und X zu tunneln und so richtig wirkt das 
dann, wenn derselbe Y-Wert oder Werte mit Bezug zueinender infolge 
starrer Frequenz mehrfach ausgelesen werden. Das ist aber nur bei tiefen 
Frequenzen der Fall / wirklich hilfreich.

Dithering behebt auch keine Interpolationsfehler und die sind bei der 
Diskussion hier der Hauptfokus, denke ich. Um bei dem Thema DDS mit 
groben Interpolationen klarzukommen, gibt es 3 Hauptstrategien:

1) Anpassung der Tabellenlänge, weg von binären Längen hin zu einer 
Länge, welche entweder perfekt zur Zielfrequenz passt oder insofern dazu 
passt, dass bei hohen Frequenzen nur gut filterbare Frequenzen entstehen 
und nicht etwas tieffrequente Schwebungen.

2) Einteilung der Vektorunterteilung so, dass die Knicke so liegen, dass 
ganzzahlige Vielfache der Grundwelle entstehen, also anhand der Phase 
und nicht anhand der Amplitude. Bei meinem abschnittsweise definierten 
Sinus verfahre ich so. Das produziert harmonische Oberwellen, die 
passen.

3) Postfilterung unter Nutzung einer TAP-Zahl die zur Tabellenlänge 
komplementär ist, also die Artefakte, die durch das Springen des 
Phasenvektors entstehen, optimal filtert und nicht etwa interferiert, 
was ich auch schon gesehen habe. Gerade schnell und damit einfache 
FIR-Filter haben die unangenehme Eigenschaft, Oberwellen durchzulassen, 
die nicht gut in die Filterlänge passen. Da sowohl Filterlänge, als auch 
Tabellenlänge oft Binärwerte sind, haben beide genau an derselben 
Stelle, also für die selben Frequenzen Stärken und für andere Schwächen.

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
Noch kein Account? Hier anmelden.