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?
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?
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.
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?
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.
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?
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.
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?
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.
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
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.
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)
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. ?
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
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:
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.
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
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.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.