Hallo zusammen,
da ich mich erst seit kurzem mit FPGAs beschäftige, konnte ich bisher
nur wenig Erfahrung sammeln.
Ich möchte ein 12 Bit breites Dreieck Signal auf ein IIR Filter 2.
Ordnung geben und mir das Ausgangssignal mit Signal Tap anzeigen lassen.
Die Koeffizienten des Filters sind bekannt. Eine Excel Tabelle stellt
das Ausgangssignal mithilfe der Rekursionsformel dar(s. exc.jpg). Signal
Tap zeigt aber nicht das erhoffte Ergebnis an (s. sigtap.jpg).
Das Dreieck Signal generiere ich mit einem einfachen Counter der von 0
bis 2^11 und wieder runter zählt. Der Code zum Filter:
Für die Implementierung habe ich mich an der transponierten Form eines
FIR Filters orientiert. Der Code des FIR Filter und des IIR Filter sind
im Anhang.
Woran liegt es, dass ich am Ausgang kein sinusförmiges Signal ähnlich zu
Excel erhalte?
Vielen Dank vorab.
Hab das jetzt nicht simuliert, aber vielleicht schneidest du die
interessanten Bits ab?
12 Bit Daten, 16 Bit Koeffizienten, das macht schon mal grob 28 Bits.
Ich würde da nicht die 12 LSBs sondern die 12 MSBs ausgeben.
Gustl B. schrieb:> sondern die 12 MSBs ausgeben
hab ich getan, sieht nun nicht mehr nur nach Rauschen aus aber ist
leider immer noch nicht sinusförmig. Irgendwelche weiteren Ideen?
Stimmen den meine Berechnungen der Signale überhaupt, ich denke schon?
Ich weiß echt nicht mehr weiter..
Deine Berechnungen sind schwer nachzuvollziehen denn statt Rechnungen
hast du Bilder angehängt. Wie wäre es mit Quelltext des FIR oder der
Excel Datei?
Jedenfalls hat dein FIR nur 4 Koeffizienten. Das ist sehr wenig. Oder
genauer: Wenn dein Sägezahn eine sehr niedrige Frequenz hat, also viele
Abtastwerte/Periode, dann wirst du daraus mit diesen wenigen FIR
Koeffizienten keinen Sinus bekommen. Denn dein FIR betrachtet immer nur
4 aufeinanderfolgende Abtastwerte.
Probier erst einmal einfachere Filter:
Multiplikation mit 0.5
Verzögerung um 1 Takt
einfaches IIR Filter erster Ordnung yk=0.9*y(k-1)+xk
Einfaches FIR Filter yk=0.5xk+0.5x(k-1)
usw.
Damit tastest Du Dich langsam an dein Filter heran.
Warum SignalTAP? Ich würde sowas als erstem im Simulator prüfen.
Dort sieht man, das erstmal nix so richtig losgeht, weil x als inout
deklariert ist und keinen Startwert hat. Nach kleineren Korrekturen kann
man die erste Messung nachvollziehen.
Wowa schrieb:> Stimmen den meine Berechnungen der Signale überhaupt, ich denke schon?
Wahrscheinlich nicht. Jetzt ist es hilfreich ein Modell zu haben
(Matlab, Python, etc.) wo es korrekte Werte gibt und man sieht, an
welchen Stellen da was überläuft.
Das direkt in Hardware zu debuggen ist viel zu aufwändig.
Gustl B. schrieb:> Jedenfalls hat dein FIR nur 4 Koeffizienten. Das ist sehr wenig.
Er hat ja IIR statt FIR, da geht das schon, bringt aber andere
Fallstricke mit.
Duke
Wowa schrieb:> sieht nun nicht mehr nur nach Rauschen aus aber ist> leider immer noch nicht sinusförmig.
Wenn du einen Sinus mit nur 1 Bit Auflösung zeichnest, sieht er deinem
aktuellen Ergebnis schon ähnlich.
Wowa schrieb:> Irgendwelche weiteren Ideen?
Wenn xk(11 downto 0) dir nur Überläufe anzeigt und xk(27 downto 16)
einem Sinus nahekommt, der mit nur 1 Bit Auflösung dargestellt wird,
dann könntest du es auch mal mit etwas "dazwischen" versuchen. Z.B.
xk(17 downto 6) oder xk(16 downto 5).
Ist natürlich nur Rumgestochere in der Hoffnung, dass die Koeffizienten
im Prinzip stimmen und du per Zufall die "richtigen" Bits deines
Ergebnisses findest. Sinnvoller wäre, da planmäßig ranzugehen.
Duke Scarring schrieb:> Jetzt ist es hilfreich ein Modell zu haben> (Matlab, Python, etc.) wo es korrekte Werte gibt und man sieht, an> welchen Stellen da was überläuft.Wowa schrieb:> Eine Excel Tabelle stellt> das Ausgangssignal mithilfe der Rekursionsformel dar(s. exc.jpg).
Zumindest ein Schritt in die richtige Richtung. Wie sieht es aus, wenn
du in deiner Excel-Berechnung eine Ganzzahlenrechnung erzwingst und die
Wertebereiche der Ergebnisse jeweils an das anpasst, was du in VHDL
implementiert hast?
Er hat auch einen FIR im Anhang. Sein IIR funktioniert. Aber er skaliert
falsch. Da sollte er das x anders skalieren mit mehr oder weniger Bits
und den Ausgang statt inout anders zuweisen.
Weil das x ja rückkoppelt braucht das vielleicht mehr Bits als dein
Ausgang.
Gustl schrieb:> Er hat auch einen FIR im Anhang.
Hmm. Aber jpg nimmt mein Simulator nicht ;-)
> Sein IIR funktioniert.
Naja. Bei der 'Normalskalierung' (11 downto 0) fängt das Ding heftig an
zu eskalieren, sobald der Eingangswert über 150 geht.
Solange der Eingangswerte zwischen -150 und 150 bleibt, kommt einfach 0
raus.
Ja, das kann ein Skalierungsproblem sein.
Duke
Kann es sein, dass dein xk signal zu klein ist?
Das wilde herumzappeln von deinem Signal könnte ein Überlaufproblem
sein.
Ich würde die Signale für deine Zwischenergebnisse ein bisschen größer
machen (Guardbits) und danach wieder dahin skalieren, wie du es
brauchst.
Mach doch die Signale einfach mal auf 32bit. Im Simulator hast du da
keinen großen Unterschied.
Dann schaust du dir an was da raus kommt (auch die Zwischenergebnisse)
und schaust, dass da nichts überläuft.
Grüße, Jens
Duke Scarring schrieb:> Er hat ja IIR statt FIR, da geht das schon, bringt aber andere> Fallstricke mit.
NeeNee, dass ist durchaus ein FIR, oder sollte es wohl zumindest werden,
weil er die Summe der koeffizientengewichteten Eingänge bildet.
Nur vergisst er, die Summe zwischenzuspeichern und die einmal
beschriebenen Signale wieder zu löschen (wenn es ein serielles Filter
werden soll) ...
.. respektive sie alternativ zubelassen, den entsprechenden Zeitebenen
zuzuordnen, damit die pipeline zeit- und werterichtig funktioniert (wenn
es ein gepipelinetes Filter werden soll).
Im Fall 1 braucht es einen inneren Zähler, der alles resettet und aus
den Einzelwerten sukzessive die Summe aufbaut, im Fall 2 mehr Signale,
um alle Zeitebenen abzubilden und die benötigte Raute aufzuspannen.
Da für die richtige und effiziente Konstruktion des Falls 2 selbst
MATLAB zu doof ist (man schaue sich mal an, was der HDL-Coder da so
hinzaubert) würde ich vorschlagen, Fall 1 zu fokussieren und es zu
machen, wie in C - dann eben mit 1/n Abtastrate.
Wenn man jetzt mal Code und Bild vergleicht, sieht man, dass das auch
fpr den angestrebten Filter so niemals stimmen kann:
Entweder summiert man das analog zu 1 alles sequenziell mit einmal
gesetzten Variablen und taktet viel und hoch genug, um fertig zu werden,
bevor man einen neuen Wert ein wirft (was es wohl werden sollte) oder
man baut auch hier eine gepipte Raute drum herum, muss dann aber genau
schauen, dass es mit den zeitlich duplizierten pipe-Stufen passt.
Um das zu bauen, was im Bild vorgeschlagen ist und Fall 1 zu fahren,
müsste man das Timing rund um die Berechnung kapseln. Und skaliert
werden muss es auch, weil die Koeffizienten sicher nicht zwischen 0 und
1 liegen. Das muss der Skalierungsfaktor nach jeder MUL raus und dann
hat er wahrscheinlich wieder ein System-Timing problem. Um das wiederum
zu lösen, würde ich vorschlagen, es mit Signalen zu formulieren und das
Timing dem Tool zu überlassen, oder super langsam zu takten (so habe ich
das bei meinen 64-Stimmen-Synths gemacht, bei denen das FPGA nur mit nur
mit 64x48kHz getaktet wurde). Dann hat man quasi einen kombinatorischen
Filter, der nur ein Synchregister nutzt. ES braucht dann aber für JEDE
der mathematischen Variablen ein solches!
Jürgen S. schrieb:> Wenn man jetzt mal Code und Bild vergleicht, sieht man, dass das auch> fpr den angestrebten Filter so niemals stimmen kann:Wowa schrieb:> Der Code des FIR Filter und des IIR Filter sind> im Anhang.
Der TO hat hier versucht zwei unterschiedliche Varianten zu bauen. Die
sind also ganz bewusst verschieden. Das eine soll ein IIR werden, das
andere ein FIR.
Gustl B. schrieb:> Das eine soll ein IIR werden, das> andere ein FIR.
War ja nur einer, mehrerer Vorschläge. Das Gesagte hinsichtlich der
Speicherung der Zwischenwerte gilt ohnehin für beide Varianten und
Filterformen. Das ist nämlich das eigentliche Grundproblem des Codes:
Man sieht dass der Entwickler aus der C-Ecke kommt und vergisst, dass
alles, was im FPGA formuliert ist, zu jedem Zeitpunkt abgearbeitet wird.
Diese stückweise Addition, die gemacht wird (ungeachtet des Umstands
dass sie nicht richtig gemacht wird) klappt SO grundsätzlich nicht, weil
schon im nächsten Takt die Signale neu gefüllt werden und zwar mit
Ergebnissen, die sich über mehrere Zeiten ziehen und damit nicht
zusammen passen. Entweder nutzt man das als pipe und baut es in die eine
Richtung aus oder man nutzt es als loop und baut es zurück - also
aktualisiert nur alle n -System-Takte, damit es zum Dateneingangstakt
passt.
Vielen Dank für Eure Hilfe!
Ich habe den Quelltext noch ein wenig weiter angepasst und zusätzlich
eine Sättigungsarithmetik eingefügt. Mein Prof. und ich sind mit dem
Ergebnis nun zufrieden.
Grüße
Gustl B. schrieb:> Testbench und Filter sind im Anhang.
Gustl, dir ist aber schon klar, dass man SO! kleine Werte von b nicht
mit 16 Bit codieren kann? Das gibt enorme fortgesetzte Rundungsfehler.
Und das gewünschte Durchdividieren mittels einfachem Abschneiden der
unteren Bits ohne jegliche Rundungsbehandlung ist ein weiterer Punkt,
der einen massiven Fehler generiert. So hat dieser Filter ordentlich
(unnötiges) digitales Rauschen, das besonders bei kleiner werdenden
Werte voll einschlägt.
Wowa schrieb:> Mein Prof. und ich sind mit dem> Ergebnis nun zufrieden.
Interessant! Dein Professor soll sich mal den Fall ansehen, bei dem der
Überlauf entsteht: Deine Limitierungsfunktion greift einen Takt zu spät
und versagt damit, weil die zeitgleich stattfindene Rechnung der
Folgezeitebene für das nächste Sample schon mit dem übergelaufenen Wert
weiter läuft und je nach Aussteuerung damit zu einem Fehler führt.
Umsetzungstechnisch sollte man das im gleichen Takt machen, also
außerhalb eines Taktes hinschreiben oder den Überlauffall vorausrechnend
formulieren: (if wert+zuwachs >= Maximum ...)
Schaltungstechnisch müsste man es für alle anderen Variablen auch tun-
insbesondere, wenn man den Fall um einen Takt verschleppt und sich der
übergroße Wert in die nächste Rechnung weiterschleppt
Funktionstechnisch wäre hingegen anzustreben, den Fall abzufangen und
die Filterauflösung so zu bemessen, dass es keine Limitierung gibt und
der headroom reicht. Nur dann funktioniert der Filter nämlich richtig.
Frage: Hat euch euer Professor mal erklärt, wie man die minimale
digitale Auflösung eines quasianalogen Wertes berechnet? Welche Fälle es
da gibt, welche Kriterien wirken? Wie sich die Fehler durch Kummulation
in einer Formel erhöhen und wie groß damit jeder einzelne sein darf?
Jürgen S. schrieb:> Gustl, dir ist aber schon klar, dass man SO! kleine Werte von b nicht> mit 16 Bit codieren kann?
Klar geht das.
Jürgen S. schrieb:> Das gibt enorme fortgesetzte Rundungsfehler.>> Und das gewünschte Durchdividieren mittels einfachem Abschneiden der> unteren Bits ohne jegliche Rundungsbehandlung ist ein weiterer Punkt,> der einen massiven Fehler generiert. So hat dieser Filter ordentlich> (unnötiges) digitales Rauschen, das besonders bei kleiner werdenden> Werte voll einschlägt.
Stand nicht in den Anforderungen des TO und ich habe da auch nicht drauf
geachtet.
Wie würdest du das denn in VHDL hinschreiben? Dann könnte man mal beide
Lösungen simulieren und eine SINAD berechnen.
Jürgen S. schrieb:> Frage: [..]
Nein. Das Modul hat mit Implementierung in FPGAs kaum was zu tun, es
befasst sich im wesentlichen mit Digitalfilter, deren Berechnungen,
Übertragungsfunktionen, Sprungantworten usw., also einfacheren Dingen
als die Implementierung.
Die Aufgabe ein solches Filter zu implementieren war nur dazu da, einen
kleinen Einblick in FPGAs zu geben und Quartus kennenzulernen.
Gustl B. schrieb:> Klar geht das.
Naja, man kriegt gerade eine Auflösung von 2 Stellen, nämlich 16,0 mit
einem Fehler von bis zu 0,5/16 = 3% für einen Real-Wert, der auf 6-7
Stellen angegeben war. Natürlich funktioniert der Filter schon
irgendwie, aber wir wissen doch, dass die Koeffizienten schon recht
genau sein müssen, soll die Grenzfrequenz gut getroffen werden.
Gustl B. schrieb:> Stand nicht in den Anforderungen des TO
Hätte der Prof aber machen können, oder noch besser der TO selber, finde
ich, denn Rundung gehört eigentlich immer zu allen mathematischen
Berechnungen.
> und ich habe da auch nicht drauf geachtet.
hm ...
> Wie würdest du das denn in VHDL hinschreiben?
Kommt auf das Signal an und dessen physikalische Bedeutung, Spektrum und
Darstellung. Im einfachsten Fall addiert man 0,5 vor dem Abschneiden, um
die harte mathematische Rundung zu vollziehen. D.h. bei einem
Abschneiden von 4 Bits ("/16") einfach vorher 8 addieren. Bei "signed"
muss man etwas aufpassen und/oder wenn man die Gaussklammer-Rundung
(nicht) braucht. Einfacher zu formulieren ist es in VHDL mit rescale.
Möchte/Muss man statistisch runden, addiert man entweder brute force
jeden zweiten Takt eine 1 bzw eine 0, oder (die etwas schlauere Methode)
anhand des zu erwartenden Endwertes die 1 mit dem korrelierten
statistischen Verhältnis (z.B. 40% / 60%) oder (die schlaueste Methode)
man addiert ein optimiertes Rauschen. Je nach Abtastrate hat das dann
eine entsprechende Zahl von Werten / damit eine Grund + Oberwelle(n).
Bei Datenströmen mit z.b. 8-facher Abtastrate gegenüber der Nutzwelle
kann man wenigstens 4 Rauschwerte - meistens 8 Rauschwerte addieren. Das
filtert sich dann später zu Null, wenn man es richtig macht. Das
einfache 1er togglen ist quasi ein Rechteckrauschen mit halber Amplitude
und der Grundwelle bei Nyquist - jedenfalls wenn die Rechnung
kontinuierlich ist.
Für Audio, wo man das Nutzspektrum kennt und der Filter tief eingreift,
kann man z.B. auch bei nur 48kHz ein Rauschen mit 12kHz einspeisen.
Ein Kompromiss zwischen statistischem- und statischem Runden ist ein
Rauschen von 0,5 und ein offset von 0.25. Braucht dann 4 Bit mehr
Auflösung in der gesamten Rechenkette:
Ergebnis18Bit <= IrgendwasmitNBit(N-1 downto N-18);
Zwischenwert18Bit <= Ergebnis18Bit + 1 + togglenoisebit & '0';
Ergebnis16Bit = Ergebnis18Bit (17 downto 2);
... und bevor jetzt jemand sagt:
"Na dann rechne ich doch gleich mit 18Bit":
1) Irgendwann muss man die Rechung runterskalieren, weil die Werte sonst
falsch wachsen und es nicht mehr stimmt und kurz vor dem Abschneiden ist
dert beste Punkt
2) Die Fragestellung bleibt und bezieht sich dann auf die Rundung zwei
Bits weiter unten.
In der Messtechnik, wo man mit z.B. der 10-fachen Abtastrate arbeitet,
ist es besonders einfach, weil man ein sauber getrimmtes Rauschen
addieren kann. Dieses ersetzt - wenn es richtig gemacht wird - mehrere
Bits an zusätzlicher Auflösung, die man alternativ spendieren müsste.
Wowa schrieb:> Das Modul hat mit Implementierung in FPGAs kaum was zu tun, es> befasst sich im wesentlichen mit Digitalfilter, deren Berechnungen,> Übertragungsfunktionen, Sprungantworten usw., also einfacheren Dingen> als die Implementierung.
Das Skalieren und (damit) Runden von Werten bei der Nutzung von
Ganzzahldarstellung in digitalen Systemen ist aber ebenfalls gänzlich
losgelöst vom Thema FPGA oder VHDL. Das muss in DSPs genau so gemacht
werden. Das ist eigentlich Grundlagenwissen, das man in eben jenen
Vorlesungen erlernen sollte. In welchem Semester bist du?
Bei uns war das schon im ersten Semester Messtechnik das Thema.
Angefangen von der Fehlerrechnung (die wir schon im Abi hatten) hin zur
Fehlerrückfortpflanzung, also dem Rücktreiben des Zielfehlers auf die
Eingangsdarstellung kommt man dahin, wie genau man Messen muss
(physikalische Genauigkeit) und um wieviel höher an welcher Stelle die
digitale Auflösung sein muss.
Willst du z.B. ein zu regelndes Signal auf 1% genau stellen und hast
(wie man es meistens hat) einen Komparator drin, der ja subtrahiert,
dann tauchen unterwegs oft Anforderungen an die Genauigkeit auf, die
höher sind, als 1:100 und die bilden sich in dem maximalen Rauschen ab,
dass das analoge Signal innen haben darf und macht implizite Vorgaben
für die digitale Auflösung, wenn man es diskret abbilden will. Ganz nach
vorne kommt man dann zu einer Messgenauigkeit der Eingangssignale und
des gestellten Signals, dessen maximalen Fehler, Genauigkeit von Gebern
und eben Analog-Digitalwandlern.
Spätestens in der Regelungstechnik (3.Semester bei uns) muss das
komplett da sein, sonst kann man nix bauen und nix entwerfen. Nicht in
analog auf dem Steckbrett, nicht in Spice und schon gar nicht in
Software (wo es mehr Randbedingungen hat).