Hallo Zusammen, ich interessiere mich zu Zeit für Audiokompression und arbeite deshalb gerade an einer Diskreten Cosinus Transformation auf einem FPGA System. Das Problem ist, dass die Transformation und Rücktransformation "eigentlich" funktioniert, nur dass bei einem Testsignal wie z.B einem Sinus die Nullstellen nach des rücktransformierten Signales gegen inf und -inf ausschlagen. Siehe Bild1. Was ich bereits überprüft habe und funktioniert: - Mein Design für die Kommunikation mit dem WM8731 - Das erzeugen der verschieden Cosinus Wellen in der DCT und iDCT - Die Übertragung der Transformationsdaten von der DCT zur iDCT Verwendet wird ein Altera DE2-115 FPGA Board. Die Hintransformation benutzt die DCT-II und die Rücktransformation die DCT-III. Die Audiodaten werden über den integrierten WM8731 Audiochip eingelesen und ausgegeben. Das Audiosignal wird mit 44.1kHz abgetastet mit einer Auflösung von 16 Bit. Die DCT verwendet N = 256 Elemente. Das Design ist komplett gepipelined und verwendet ein zwei Buffer System am Eingang der DCT, zwischen DCT und iDCT und am Ende der iDCT, sodass z.B eingehenden Audiodaten während der Berechnung der DCT nicht verloren gehen. Die Cosinus Funktion ist mit einer LUT implementiert. Um Komplexität zu vermeiden, bildet die LUT eine ganze Periode des Cosinus ab. die Länge der LUT ist 512 Elemente. Das Design verwendet Festkomma zur Darstellung Rationaler Zahlen. Die Bitbreite der Festkommasignale beträgt immer 18 Bit, da die DSP Multiplizierer im FPGA auf 18 Bit ausgelegt sind. Es werden immer die niederwertigsten Nachkommastellen abgeschnitten, um das 18 Bit Format beizubehalten. Der WM8731 benötigt einen Takt von 11.2896MHz und die DCT und iDCT wird mit einer Frequenz von 28MHz betrieben. Beide Clocks werden durch eine PLL erzeugt. Das beobachte verhalten tritt leider nicht in der Simulation auf. Das lässt, denke ich, eigentlich nur auf Timingprobleme schließen. Bild1: Die Abbildung zeigt die Rücktransformation eines Spektrums, dass mit einem Logic Analysier während des Betriebes vom FPGA gesammelt wurde und dann mit der Matlab idct() Funktion rücktransformiert wurde. Bild2: Das ist das Spektrum, welches während des Betriebes gesammelt wurde. Bild3: Die Abbildung zeigt das rücktransformierte Audiosignal mit einem Oszilloskop aufgenommen. Bild4: Auszug aus der Simulation. Die Ausschläge in Audio_out treten an den Grenzen des 256 Elemente Buffer der DCT auf und sind nicht das Problem, was ich versuche zu beheben. Die Werte in Bild1 und Bild2 sind nicht richtig Skaliert, weil diese Signale eigentlich im Festkommaformat sind, der Logic Analyser aber nur std_logic_vector kennt. Ich habe jetzt erst einmal noch nicht die VHDL Dateien angehangen. Falls es dazu Fragen oder Bedarf gibt, kann ich gerne Auszüge oder auch gleich die ganzen Dateien anbieten. Ich freue mich über jeden Impuls oder Tipp, was vielleicht die Ursache dieses Verhaltens sein könnte :) Viele Grüße und Danke im Voraus Anselm D.
Anselm D. schrieb: > ... Um Komplexität zu > vermeiden, bildet die LUT eine ganze Periode des Cosinus ab. die Länge > der LUT ist 512 Elemente. Skaliere deren Werte doch einmal. Nicht das die 1.0 da ueberlaeuft.
Anselm D. schrieb: > Ich habe jetzt erst einmal noch nicht die VHDL Dateien angehangen. Falls > es dazu Fragen oder Bedarf gibt, kann ich gerne Auszüge oder auch gleich > die ganzen Dateien anbieten. Her damit!
Anselm D. schrieb: > Die > Audiodaten werden über den integrierten WM8731 Audiochip eingelesen und > ausgegeben. Bist Du sicher, das das richtig funktioniert? Ich würde mal testweise einen Sägezahn bzw. ein Dreiecksignal ausgeben, um zu schauen, ob es dort an der 'Nullstelle' auch zu Problemen kommt. Außerdem würde ich empfehlen noch einen Debug-RAM anzuflanschen, um zu schauen ob die Daten der Berechnung plausibel sind.
Motopick schrieb: > Nicht das die 1.0 da ueberlaeuft. Die Werte der LUT und mein eingehendes Audiosignales speichere ich als sfixed(0 downto -17). Tatsächlich hatte ich das Problem, dass der synthetisierter rumgemeckert hat, weil er "1.0" nicht in diesem Format darstellen kann. Was ja auch Sinn macht wegen des asymmetrischen Zahlenraumes im 2er Komplement. Deshalb habe ich die "1.0" in der LUT durch "0.9999..." ersetzt. Analog dazu kann die "-1.0" ja in diesem Zahlenraum abgebildet werden und deshalb habe ich diese nicht mit "-0.9999..." angenähert.
Gustl B. schrieb: > Her damit! Hier einmal das archivierte Quartus Projekt und einmal die VHDL Dateien als ZIP. die Top Level Entity ist Audio_Visualizer_lite. Ein paar Anmerkungen zu dem Projekt: - Die Quartusversion ist 23.1std.0 Build 991 11/28/2023 Patches 0.02std SC Lite Edition. In der Version gab es einen Bug mit der Erzeugung von PLLs. Den Patch dazu hatte ich installiert. - Da ich nicht die Pro Version von Quartus habe, ist das ieee Fixpoint package nicht verfügbar. Deshalb verwende ich den Workaround dieses git Repositorys : https://github.com/LockBall/floatfixlib_VHDL1993 - Ich verwende zum speichern der Eingangsdaten, der Transformation und der Rücktransformation keine Signal Arrays sondern einen Double Buffer Dual Port RAM, da ich große Probleme mit langen Synthetisierzeiten hatte und da mir langsam der Platz auf dem FPGA ausgegangen ist. Diese Sachen konnte ich damit beheben. - der Dual Port RAM ist ein IP Core und verwendet kein Register am Ausgang und hat separate Clocks für Lesen und Schreiben. - Das Design beruht auf der Annahme, dass die Berechnung der DCT und iDCT sehr viel schneller ist, als das 256 neue Eingangsdaten gesammelt werden. Sobald die DCT oder iDCT mit der Berechnung fertig ist, warten diese darauf, dass der vorangehende Double Buffer RAM getauscht wird. Dieser wird immer getauscht, sobald 256 neue Daten geschrieben wurden. Außer der Double Buffer RAM am Ende der iDCT. Der wird immer getauscht, sobald 256 Daten gelesen wurden. - Die Anzahl der Bit vor und nach dem Komma jedes Signales der DCT und iDCT ist in dem Package "Custom_types.vhd" hinterlegt. Die Anzahl der Bit vor dem Komma ist genannt N und nach dem Komma ist genannt M. Vor den Konstanten ist der Rechenweg für dieses Signal beschrieben und wie ich auf die Anzahl der Bit vor dem Komma komme. - Durch die Pipeline sind die ganzen Rechenschritte etwas schleierhaft in der DCT oder iDCT. Falls das nicht verständlich ist, kann ich da gerne auch noch detailliert drauf eingehen.
Rick D. schrieb: > Ich würde mal testweise einen Sägezahn bzw. ein Dreiecksignal ausgeben, > um zu schauen, ob es dort an der 'Nullstelle' auch zu Problemen kommt. Hier sind einmal Aufnahmen mit Rechteck, Sägezahn, Dreieck und noch einmal Sinus als Eingangssignal. Was mir dabei auffällt ist, dass je nachdem ob das Signal gerade steigt oder fällt, diese Ausschläge in die selbe Richtung gehen. Also wenn das Signal gerade fällt, ist der Ausschlag ins Negative und wenn das Signal steigt, ist der Ausschlag ins Positive. Ich weiß noch nicht wie ein Debug Ram funktioniert aber ich werde mir das einmal anschauen :D
Ohne das ich jetzt in das Projekt hineingesehen haette, koenntest du dein Werk mit Signaltap an den kritischen Stellen "instrumentieren". Dazu muss man nicht die gesamte Signalbreite nehmen. In der Regel reichen die oberen 5 - 8 Bit aus, um Fehler in den Algorithmen zu erkennen. Und auch wenn der Synthesizer bei den "0.999..." nicht mehr mault, den in der LUT hinterlegten Wert noch einmal pruefen. Oder ihn gleich als Bitvektor hinschreiben. Es waere ja zu einfach gewesen, wenn das der Fehler gewesen waere. :) Viel Erfolg!
Anselm D. schrieb: > Deshalb habe ich die "1.0" in der LUT durch "0.9999..." ersetzt. Wie viele Neunen nach dem Komma genau? Eine Dezimalstelle entspricht gut 3,3 Bit. Setze doch einfach diese eine Zahl binär auf alles Eins bis auf das Vorzeichen (Name'left => '0', others => '1').
Da sind noch mehr "Grausamkeiten" drin, bspw. der Sinus wechselt schon mal die Richtung bevor er die Wendestellen erreicht. (siehe Anhang, aus Bild1.png durch Skalierung und Farbreduktion) Kan natürlich auch ein Problem der graphischen Darstellung sein, check mal die Roh-Werte. Eventuell dem Integer mehr Genauigkeit spendieren. Das Zahlenformat mal dahingehend überprüfen wie das Vorzeichenhandling bei der Null ist. Da scheint es eine Code für "+0" und einen für "-0" zu geben, es sollte aber nur einen geben. (kann aber auch ein Problem der graphischen Darstellung sein, welche Rohwerte stehen dort). Der Simulations-Auszug(?) (bild4.png) zeigt auch üble Artefakte nicht nur an den Nullstellen, vielleicht eher Runden statt abschneiden bei der Bitlängenreduktion ? also 001 -> 0 ... 001 -> 0 ; 010 -> 1 011 -> 1 ? BTW: Was ist der Unterschied zwischen den beiden Graphen in Bild4.png? Der obere sieht OK aus, der untere ist "grausam".
:
Bearbeitet durch User
Kay-Uwe R. schrieb: > Wie viele Neunen nach dem Komma genau? Den Wert, den ich benutzt hatte, war "0.999999999999". Mit der Umformung nach Festkomma in Signed 0 downto -17 ergab sich dann ein Wert von "0.999992370605469". Ich habe die Änderung mit "(Name'left => '0', others => '1')" einmal ausprobiert und das dann auch gleich für die "-1.0" angewandt. Die Lösung war es aber leider nicht :(. Ich werde die Änderung aber trotzdem beibehalten.
Bradward B. schrieb: > Eventuell dem Integer mehr Genauigkeit spendieren. Tatsächlich ist die Abbildung akkurat. Also es kommt wirklich zu diesen "kleinen Schwingungen" im Ausgangssignal. Ich ordne das aber dem zu, dass meine Buffer Größe für die DCT usw. nur 256 Elemente ist und dass ich nur maximal 18 Bit verwende und somit Ungenauigkeiten nicht so vermeiden sind. Ob diese Ungenauigkeiten auf der selben Größenordnung wie die theoretischen Ungenauigkeiten durch die begrenzte Bitbreite usw. sind, weiß ich nicht. Den größten Verlust von Genauigkeit habe ich bei der Summierung der Produkte von Eingangsdaten und des Cosinus. Das Produkt hat das Format Q1.17, also Signed 0 downto -17, und die Summe das Format Q9.9. Der Maximalwert für eine Summe liegt bei theoretisch ~255. Deshalb dieser große Sprung im Zahlenraum. Dieser Maximalwert würde natürlich bei "realen" Signalen so gut wie nie auftreten. Aber zur Sicherheit decke ich diesen Zahlenraum trotzdem ab. Ich probiere mal die Genauigkeit für die Summe zu erhöhen auf Q10.26. Bradward B. schrieb: > BTW: Was ist der Unterschied zwischen den beiden Graphen in Bild4.png? > Der obere sieht OK aus, der untere ist "grausam". Stimmt ich habe gar nicht die Simulation erklärt. Gezeigt ist nur das Eingangssignal und dann, nachdem dieses Hin- und dann wieder Zurücktransformiert wurde, das Ausgangssignal der iDCT. Die Rechenschritte der DCT und iDCT sind sehr schlecht gleichzeitig mit dem Eingangssignal darzustellen, da die Berechnungen mit 28MHz laufen und somit die Berechnung im Vergleich mit der Frequenz des Eingangssignales viel zu schnell ist. Ich kann gerne mal einen Ausschnitt der Simulation mit der Berechnung der DCT und iDCT zeigen. Die neue Abbildung der Simulation verwendet die resize() Funktion des Fixpoint Package, anstatt nur abzuschneiden. Dort wird, soweit ich das verstehe, auch gerundet. Ich hatte resize() bisher gemieden, da die Funktion in der Synthese eher Aufwendig ist. Ich denke, dass diese "Unschönheiten" im Ausgangssignal einfach nicht zu vermeiden sind bei einer begrenzten Buffer Größe und einer begrenzten Bitbreite.
Da die 'Störungen' auch bei Dreieck und Sägezahn zu erkennen sind, würde ich mir als erstes die DAC-Ansteuerung genauer anschauen. Möglicherweise ist der Algorithmus korrekt und du suchst an der falschen Stelle nach dem Fehler...
Moin, für mich sieht dein Eingangssignal um die Nullstelle (Bild 4) herum schon nicht ganz korrekt aus - es sieht etwas gestreckt aus, als würde die "Null" bspw. doppelt abgetastet. Du sagst, dass das simuliert ist. Welches Signal ist das genau? Simulierst du das interface zum ADC mit? Bist du sicher, dass das ADC-interface wirklich sauber implementiert ist - je nach genutztem Modus des Chips? Ist das interface auch sauber constrained? Hast du allgemein alles sauber constrained? Was sagt das tool bzgl. der timings? Ich habe dein Projekt nur kurz überflogen. Mir fallen aber weitere Dinge auf, die dein Problem möglicherweise nicht direkt lösen, aber nicht "gut" sind: - Du rechnest mit "mod 2*pi". Das würde ich definitiv anders lösen. Modulo ist nicht so einfach zu synthetisieren. Sagt dein timing report, dass das in einem Takt funktioniert? - Du erzeugst in der fabric ein Signal LRCLK und nutzt das als Takteingang. Das sollte man allgemein vermeiden.
Rick D. schrieb: > Möglicherweise ist der Algorithmus korrekt und du suchst an der falschen > Stelle nach dem Fehler... Mein Design für die Kommunikation mit dem WM8731 Audiochip verwendet für die Daten des DACs und ADCs jeweils einen std_logic_vector(15 downto 0). Ich habe einmal ein Design synthetisiert, bei dem die gesammelten Daten des ADCs wieder direkt als Eingangsdaten in den DAC geleitet werden. Anzumerken ist, dass die Kommunikation mit dem WM8731 seriell stattfindet. Der "beweis", dass das Design funktioniert, verbindet nicht einfach nur diese zwei seriellen Leitungen, sondern sammelt die (2 mal; linker und rechter Kanal) 16 Datenbit des ADCs in einem Std_logic_vector und gibt diese dann als Eingang für den DAC, wo sie dann wieder "in seriell" ausgegeben werden zum WM8731. Deshalb bin ich mir eigentlich so sicher, dass mein Design für die Kommunikation mit dem WM8731 ordentlich funktioniert. Hier noch die vier Signalformen ohne Transformation und ein Auszug aus dem RTL Viewer.
Hi, was sagt denn dein Synthesizer? Der muss doch Warnungen rauswerfen ohne Ende! Du hast in deinen Files für die DCT und iDCT viele, viele parallele Prozesse. Und du verwendest gleiche Signale in verschiedenen Prozessen. Immer wenn ich das gemacht habe, hat das nicht funktioniert. Wie machst du das denn, dass diese ganzen Prozesse sauber ineinander greifen? Poste doch bitte mal die Ergebnisse aus der Synthese mit allen Fehlern und Warnungen. Grüße, Jens
Anselm D. schrieb: > Der "Beweis", dass das Design funktioniert, verbindet nicht > einfach nur diese zwei seriellen Leitungen, sondern sammelt die (2 mal; > linker und rechter Kanal) 16 Datenbit des ADCs in einem Std_logic_vector > und gibt diese dann als Eingang für den DAC, wo sie dann wieder "in > seriell" ausgegeben werden zum WM8731. Habe ich Dich richtig verstanden: Du verwendest einen externen Signalgenerator und gibst dessen Signal auf den ADC-Eingang. Vom ADC-(FPGA-)Controller geht es dann zum DAC-(FPGA-)Controller. ADC und DAC sitzen vermutlich im selben Chip: https://www.mouser.com/datasheet/2/76/WM8731_v4.9-532414.pdf Dem entsprechend gibt es im FPGA auch nur ein Modul, welches mit dem Chip kommuniziert. Eigentlich hatte ich gemeint, das Du die Signale (Rampe, Dreieck, Rechteck, Sinus) im FPGA erzeugst (Stichwort: DDS) und dem DAC zur Ausgabe gibst. Das der Audiocontroller sein eigenes Format versteht, ist nahezu selbstverständlich, aber es ist möglich das Deine (gefilterten) Daten nicht im richtigen Format vorliegen. Deswegen der Test mit bekannten Daten.
Anselm D. schrieb: > Der "beweis", dass das Design funktioniert Das mag zeigen, dass der logische Teil funktioniert. Je nach interface sind aber auch weitere constraints notwendig. Das kann dann dazu führen, dass es von Synthese zu Synthese entweder funktioniert oder auch mal nicht. Insbesondere wenn ein Design größer wird und constraints nicht richtig gesetzt sind, kann es auf einmal failen. Demzufolge sieht das logisch zwar OK aus, beweist für mich aber erstmal nicht, dass das interface stets funktioniert. Ich sprach oben schon allgemein constraints an. Bei weiterem Reinschauen fällt mir nun auch bspw. Folgendes auf: In DCT_II wird dein double buffer genutzt. Der erzeugt auf der
1 | data_clk_in
|
das Signal
1 | got_swapped
|
. Dieses wird wieder in der DCT_II genutzt, aber in einer anderen clk domain. Das clock domain crossing ist hier nicht sauber. Des Weiteren ist die write clock deines double buffers in fabric erzeugt. Wie gesagt, das sollte man vermeiden.. Nimm eine saubere clock und arbeite mit clk_en. Deine reports müssen hier doch etwas ausspucken. Das sind schon einige Design-Fehler, die zu beheben sind. Ich würde mir an deiner Stelle nochmal deine ganze Struktur um die buffer anschauen und auch die möglichen clock domain crossings. Und schau in die reports!
Lars schrieb: > Du rechnest mit "mod 2*pi". Das würde ich definitiv anders lösen. > Modulo ist nicht so einfach zu synthetisieren. Sagt dein timing report, > dass das in einem Takt funktioniert? Du hast es auf den Punkt getroffen. Ich hatte in meinen anderen Projekten bisher nie Probleme mit Timing und deshalb kannte ich mich damit auch nicht aus. Und zwar wurden mir natürlich beim synthetisieren des Projektes die drei Slack Timings ausgegeben, es stellt sich aber heraus, dass diese nicht zutreffend waren, weil ich keine .sdc Datei hatte, in welcher die Timings der Clock angegeben waren. Danach hatte ich dann auch negative Stack Timings und der Timing Analyzer hat mir gesagt, dass diese aus dem Modulo Operator resultierten. Jetzt zum Lösungsansatz: Meine Cosinus LUT beruht darauf, dass ein Eingangswert mit der Periode von 0 bis 2*pi auf eine Periode von 0 bis 511 gestreckt wird. Um jetzt die 2*pi loszuwerden, strecke ich die Periode meines Eingangswertes auf 0 bis 8 (7.999...). Das verhindert zwar nicht, dass ich trotzdem meinen Eingangswert Modulo 8 nehmen muss, sorgt aber dafür dass die Berechnung sehr viel einfacher ist. Und zwar ist Modulo 8 natürlich einfach nur das Abschneiden ab dem 3. Bit aufwärts(angefangen beim 0. Bit zu zählen). Vielen Dank noch einmal für den Hinweis und entschuldige bitte, dass das Antworten so lange gedauert hat. Die Implementierung des neuen Cos und das herumspielen mit dem Timing Analyzer hat mich etwas beschäftigt gehalten :D
Anselm D. schrieb: > Ich hatte in meinen anderen Projekten bisher nie Probleme mit Timing und > deshalb kannte ich mich damit auch nicht aus. In der Simulation sollte das kein Thema sein, allerdings sehen Deine Kurven sehr danach aus, dass da schon funktionell irgendwelche Werte aus falschen Zeiten miteinander verrechnet werden. Außerdem könnte man sich mal die Fensterung ansehen: So wie das Signal in der einen Darstellung um die Nullpunkte herum aussieht, funktioniert entweder die Fensterung beim Diskretisieren nicht oder aber bei der Resynthese. Bei 256 Stellen muss das wesentlich glatter aussehen! Bei einer korrekten DFT und iDFT mit der Amplitude darf man optisch gar keine Artefakte in der Simulation sehen. P.S. Der eingeprägte "Audio IN" hat auch noch eine Macke! Da scheinen obere und untere Welle zusammengedrückt. Da ist gfs ein offset-Fehler. Schiebe mal ein Dreieck rein. Das ist meistens aufschlussreicher.
:
Bearbeitet durch User
Diese Spikes werden in einem späteren Schritt erst über Logikprüfung entfernt. Das liegt am Algorthmus, bzw. jener, der den Fehler nicht macht ist noch nicht frei durch abgelaufene Schutzrechte. Für die VTler: Über die Werte zwischen 1008...1023 sind geheime Informationen codiert. Anhand derer kann die Aufnahmequelle identifiziert werden. ;o)
Dieter D. schrieb: > Diese Spikes werden in einem späteren Schritt erst über Logikprüfung > entfernt. Das liegt am Algorthmus, bzw. jener, der den Fehler nicht > macht ist noch nicht frei durch abgelaufene Schutzrechte. Welche Schutzrechte bestehen im Bereich Audio hinsichtlich der DCT?
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.