Forum: FPGA, VHDL & Co. Cyclone EP4CE115 DCT Ausschläge bei Nullstellen von Sinus


von Anselm D. (skeracrow)


Angehängte Dateien:

Lesenswert?

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.

von Motopick (motopick)


Lesenswert?

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.

von Gustl B. (-gb-)


Lesenswert?

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!

von Rick D. (rickdangerus)


Lesenswert?

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.

von Anselm D. (skeracrow)


Lesenswert?

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.

von Anselm D. (skeracrow)


Angehängte Dateien:

Lesenswert?

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.

von Anselm D. (skeracrow)


Angehängte Dateien:

Lesenswert?

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

von Motopick (motopick)


Lesenswert?

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!

von Kay-Uwe R. (dfias)


Lesenswert?

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').

von Bradward B. (Firma: Starfleet) (ltjg_boimler)


Angehängte Dateien:

Lesenswert?

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
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.