Nachdem der FIR Filter funktioniert
(Beitrag "Re: Ausgangssignal eines FPGA basierten Tiefpasses"), stoße ich beim
IIR Filter verständnismäßig an meine Grenzen. Also grundsätzlich ist ja
erstmal der Unterschied eines IIR zu einem FIR der, dass der IIR
instabil werden kann und keine konstante Gruppenlaufzeit aufweist. Und
natürlich unterscheiden sich auch die Strukturen. Für eine spätere
Kaskadierung möchte ich einen IIR Filter in Direktform II 2. Ordnung
implementieren. Ich orientiere mich dabei an dem Aufbau, der sich im
Anhang befindet. Da ich die Filterkoeffizienten mit Matlabs Filter
Designer berechne, erhalte ich noch einen zusätzlichen Gain nach dem
Input x(k). Ich erhalte die Daten wie im oben genannten Thread von einem
ADC und gebe diese an einen DAC weiter. Ich erhalte 13Bit signed als
Input und möchte 12 Bit an den DA Wandler ausgeben. Mein erstes
Testsignal ist ein Sinus mit 200Hz und überlagertem 12,5kHz. Die
Erwartung ist, dass der Filter die 12,5kHz herausfiltert(siehe
Amplitudengang im Anhang). Das Protokoll zwischen ADC,Filter und DAC
funktioniert. Das konnte ich bereits prüfen.
Jedoch habe ich vor Allem Verständnisprobleme, was die Anzahl der Bits
angeht und dessen Rundung.
Input: 1.12 Fixed Point, Output: 12Bit für DA Wandler. Koeffizienten:
2.14 Fixed Point. Sample Rate: 50kHz
In VHDL berechne ich quasi jeden Rechenschritt sequentiell, da der
Filter mit sehr hohem Takt läuft und gleichzeitige Multiplikationen zu
Timingproblemen führten. In dem 3. Anhang befindet sich nochmal das Bild
der Struktur mit einer roten Nummerierung, welche Rechenoperationen ich
in welcher Reihenfolge ausführe.
Es befinden sich noch Input und der fehlerhafte Output im Anhang. Der
Input ist mit einem Offset von 1,65V versehen, da der AD Wandler nur im
positiven Spannungsbereich von 0 - 3,3V arbeitet.
Ich habe versucht, Bitzahl der Zwischenergebnisse nachzuvollziehen.
Eigentlich müsste ja die maximale Bitzahl in meinem Beispiel 45 Bit
betragen. Am Input habe ich 13 Bit, diese werden mit dem von 16 Bit
multipliziert. Somit kommt eine 29 Bit Zahl heraus. Diese 29 Bit werden
dann noch einmal mit 16 Bit (b0) multipliziert. Somit kommt eine 45 Bit
Zahl heraus.
Also bei Multiplikation von 1.12fixed Point * 2.14 fixed Point * 2.14
fixed Point sollte das eine 5.40 fixed Point zahl ergeben. Diese muss
ich dann ganz am Ende Runden auf das Ergebnis. Zudem habe ich noch die
Summe der Zwischenergebnisse nach der Multiplikationen mit den beiden
Polstellen links gerundet, um diese wiederum mit input*gain verrechnen
zu können.
Nun der VHDL Code des Filters:
Ich würde das auf jeden Fall vorher am PC simulieren oder sogar in einer
Programmiersprache deiner Wahl schreiben und solange testen bis das
Filter filtert.
Mit welchem Systemtakt läuft denn dein FPGA?
Da du alles sequentiell rechnest musst du innerhalb einer Sampleperiode
die komplette Berechnung des Rückkopplungspfades erledigt haben.
Fischl schrieb:> Mit welchem Systemtakt läuft denn dein FPGA?> Da du alles sequentiell rechnest musst du innerhalb einer Sampleperiode> die komplette Berechnung des Rückkopplungspfades erledigt haben.
Genau, das ist mir klar. Der Filtertakt ist mit 125MHz (habe einfach das
Maximum genommen) viel höher, als der Sampletakt. Dieser beträgt 50kHz.
Ich habe gerade noch herausfinden können, dass ein Fehler in der
Benutzung der auf dem Board befindlichen Multiplizierer liegen könnte,
da diese eine maximale Bitbreite von 25x18 pro Multiplikation haben.
Eventuell muss ich meine Koeffizienten mit einer kleineren Auflösung
arbeiten lassen.
Alex K. schrieb:> Koeffizienten:> 2.14 Fixed Point.
Ist sichergestellt, dass diese Wortbreite ausreicht? Nicht dass ich mich
wirklich auskenne, ich weiss nur aus der Literatur, dass Overflow zu
Oszillationen führen kann.
Burkhard schrieb:> Ist sichergestellt, dass diese Wortbreite ausreicht? Nicht dass ich mich> wirklich auskenne, ich weiss nur aus der Literatur, dass Overflow zu> Oszillationen führen kann.
Ja, die Auflösung genügt. Ein Overflow wird auch im Falle der
Multiplikation dadurch vermieden, dass die Wortbreite des Ergebnisses
breiter wird.
Allerdings könnte ich mal checken, ob keine Summation einen Overflow
verursacht.
Andreas schrieb:> Ansonsten würde ich das Teil in einer BiquadForm aufbauen und noch jeder> Multiplikation ein resize machen, um die Datenbreite in den> Delayelementen z-1 u. z-2 zu begrenzen. Das Package sfixed wäre bestimmt> auch ganz hilfreich.
An sich implementiere ich doch eine Biquad Struktur, wenn ich das
richtig verstanden habe. Letztendlich arbeite ich dann mit N Direktform
II Filtern 2. Ordnung in Reihe, mit N = Filterordnung. Mich stört halt
auch der Gain, den Matlab mit ausgibt. In keinem Buch wird so ein
vorgeschalteter Gain erwähnt.
Andreas schrieb:> Da hatte ich vor einiger Zeit mal einen Sinus-Sweep Generator in VHDL> geschrieben, dieser liegt hier:
Werde ich mir mal ansehen, dankeschön!
Andreas schrieb:> Das Package sfixed wäre bestimmt> auch ganz hilfreich.
Werde ich mir ebenfalls ansehen
Als kurzes Update: Ich bin jetzt (glaube ich) etwas weiter gekommen. Der
Output hat jetzt zumindest mal die richtige Frequenz von 200Hz,
allerdings stimmen die Werte halt so gar nicht.
Ich denke mal, dass ich die Rundungen falsch durchführe. Da knie ich
mich jetzt nochmal hinter
Andreas schrieb:> Ich hatte damals eine DF2 Transponiert genommen, da ich da das> Eingangssignal direkt mit den bn Koeffis multiplizieren kann und die> Rückkopplung immer in dein Z-Element geht.
Könnte ich auch mal ausprobieren, danke für den Hinweis!
Also ich bekomme jetzt ein einigermaßen passendes Ausgangssignal. Der
Fehler lag scheinbar in der Rundung des Outputs. Allerdings erhalte ich
jetzt von Vivado die Meldung, dass ich jetzt die Timingspezifikationen
nicht einhalte. Dennoch kann ich die Schaltung in das FPGA
implementieren und es läuft.... Eigentlich dürften die Timing
requirements doch gerade eingehalten werden, weil ich alles sequentiell
mache. Das verstehe ich nicht ganz.
Alex K. schrieb:> Allerdings erhalte ich> jetzt von Vivado die Meldung, dass ich jetzt die Timingspezifikationen> nicht einhalte.
I.d.R. steht doch im detailierten timing report, an welcher Stelle das
Timing nicht passt. Kannst Du die Stelle mal raussuchen?
Duke
Ich würde dir ohnehin empfehlen erst an den Stellen zu runden, an denen
es auch wirklich nötig ist. Das bedeutet vor jeder Multiplikation und am
Ausgang deines Filters. Sinnvoller ist es demnach das Signal first_delay
und second_delay zu runden, anstelle der Ausgangssignale a1_mult und
a2_mult von der Multiplikation.
Ebenfalls ist Runden durch simples Abschneiden der LSBs die denkbar
schlechteste Möglichkeit. Benutze lieber eine Rundung wie "Round half to
even". Gerade IIR Filter sind eben sehr empfindlich auf solche
Quantisierungseffekte.
Duke Scarring schrieb:> I.d.R. steht doch im detailierten timing report, an welcher Stelle das> Timing nicht passt. Kannst Du die Stelle mal raussuchen?>> Duke
Hat sich jetzt(vorerst) erledigt, indem ich eine DFI Struktur
implementiert habe.
Fischl schrieb:> Ich würde dir ohnehin empfehlen erst an den Stellen zu runden, an denen> es auch wirklich nötig ist. Das bedeutet vor jeder Multiplikation und am> Ausgang deines Filters. Sinnvoller ist es demnach das Signal first_delay> und second_delay zu runden, anstelle der Ausgangssignale a1_mult und> a2_mult von der Multiplikation.>> Ebenfalls ist Runden durch simples Abschneiden der LSBs die denkbar> schlechteste Möglichkeit. Benutze lieber eine Rundung wie "Round half to> even". Gerade IIR Filter sind eben sehr empfindlich auf solche> Quantisierungseffekte.
Wegen Zeitdruck habe ich es erstmal mit der schlechtesten Methode
versucht. Eine Frage noch zum runden vor Multiplikationen: Würdest Du
dann first delay wieder auf die 13 Bit herunterrunden, die das
Eingangssignal hat?
Danke euch für eure Verbesserungsvorschläge
Alex K. schrieb:> Wegen Zeitdruck habe ich es erstmal mit der schlechtesten Methode> versucht. Eine Frage noch zum runden vor Multiplikationen: Würdest Du> dann first delay wieder auf die 13 Bit herunterrunden, die das> Eingangssignal hat?
first_delay und second_delay musst du letztendlich auf die Wortbreite
deiner Multiplizierer runden. Deine Koeffizienten haben 16bit
Wortbreite, also nehme ich mal an, dass die Signaleingänge deines
Multiplizierers auf 16bit beschränkt sind.
Um die Quantisierungseffekte auf ein Minimum zu reduzieren, rundest am
Knotenpunkt vor b0 auf 16bit im Format Q1.15. Somit hast du für alle
Multiplikationen die richtige Wortbreite. y[k] wird dann auf 12bit
gerundet, wie du es schon implementiert hast.
Die Additionen können dann immer mit voller Wortbreite rechnen.
Zur Rundung:
Das Abschneiden der MSBs ist dabei nur zulässig, wenn du sicherstellst,
dass dein Wertebreich von
niemals überschritten wird. Nur dann kannst du immer auf das Format
Q1.15 und am Ausgang auf Q1.11 runden.
Sollte dies nicht sichergestellt sein, kannst du das Signal entweder
clippen, oder den Gain deines Eingangssignals soweit verringern, dass
kein Überlauf mehr vorkommen kann.
Alex K. schrieb:> Fischl schrieb:>> Ich würde dir ohnehin empfehlen erst an den Stellen zu runden, an denen>> es auch wirklich nötig ist. Das bedeutet vor jeder Multiplikation und am>> Ausgang deines Filters. Sinnvoller ist es demnach das Signal first_delay>> und second_delay zu runden, anstelle der Ausgangssignale a1_mult und>> a2_mult von der Multiplikation.
Ich habs jetzt so gemacht und tatsächlich ist die Amplitude wesentlich
genauer
Ich habe nun versucht, drei dieser Filter hintereinanderzuschalten, um
damit einen Filter 6. Ordnung mit Bandpassverhalten zu erzeugen. Hier
hänge ich jetzt gerade noch. Vom Prinzip her sollte das aber eigentlich
richtig sein. Ich kaskadiere die drei Filter 2. Ordnung. Wenn der erste
Filter ein Ergebnis errechnet hat, gibt er dieses an den 2. weiter
etc... Mein nächster Versuch wird es sein, das "Round half up" zu
implementieren. Vielleicht liegt dort ja bereits eine Fehlerquelle
Ich habe bei solchen Aufgaben immer eine parallele Implementierung in
einer Hochspache (z.B. Python). Damit kann man schön an den Parametern
drehen und hat auch gleich eine Referenz, für das, was aus der
HDL-Simulation rauskommen sollte.
Wenn es dann in der Hardware immer noch nicht richtig geht (z.B. wegen
Übersteuerung), werden die problematischen Werte gesampelt und der
jeweiligen Simulation zugeführt.
Duke
Duke Scarring schrieb:> für das, was aus der> HDL-Simulation rauskommen sollte.
Was spricht gegen eine Implementierung in VHDL, Erzeugung des Designs
und Ausprobieren des "Herumschraubens"?
In dem Fall die Parameter des Filters?
Klaus E. schrieb:> Duke Scarring schrieb:>> für das, was aus der>> HDL-Simulation rauskommen sollte.>> Was spricht gegen eine Implementierung in VHDL, Erzeugung des Designs> und Ausprobieren des "Herumschraubens"?>> In dem Fall die Parameter des Filters?
Das Anpassen der Filterparameter mag noch gehen. Viele andere Sachen
gehen mit Hochsprachen schneller umzusetzen.
Duke