Forum: FPGA, VHDL & Co. Dreieck Signal auf IIR Filter geben, Ausgang Signal Tap


von Wowa (Gast)


Angehängte Dateien:

Lesenswert?

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:
1
library ieee;
2
use ieee.std_logic_1164.all;
3
use ieee.numeric_std.all;
4
5
entity filter is
6
  generic
7
  (  -- Q = 14
8
    b0 : signed(15 downto 0) := to_signed(16,16);     -- b0 = 0,00094469  -> b0*2^14 = 16
9
    b1 : signed(15 downto 0) := to_signed(31,16);     -- b1 = 0,00188940  -> b1*2^14 = 31
10
    b2 : signed(15 downto 0) := to_signed(62,16);     -- b2 = b0
11
    a1 : signed(15 downto 0) := to_signed(-31313,16);  -- a1 = -1,91120934 -> a1*2^14 = -31313
12
    a2 : signed(15 downto 0) := to_signed(15426,16)    -- a2 = 0,91498813  -> a2*2^14 = 15426
13
  );
14
  port
15
  (
16
    clk : in std_logic;
17
    n_reset : in std_logic;
18
    --clk_en : in std_logic;
19
    u : in signed(11 downto 0); -- Eingang
20
    x : inout signed(11 downto 0) -- inout, da x rückgekoppelt wird?
21
  );
22
23
end entity;
24
25
architecture rtl of filter is
26
signal xa, xb : signed(27 downto 0); -- analog zu Bild transposed_df.jpg
27
begin
28
process (clk)
29
  variable xk : signed(27 downto 0);
30
  begin
31
    if rising_edge(clk) then
32
      if n_reset = '0' then
33
        xa <= (others => '0');
34
        xb <= (others => '0');
35
        xk := to_signed(0,28);
36
      else
37
        -- Rekursionsformel: x = b0*u + b1*u + b2*u - a1*x - a2*x
38
        xa <= b2*u - a2*x;
39
        xb <= xa + b1*u - a1*x;
40
        
41
        xk := xb + b0*u;
42
        x <= xk(11 downto 0);
43
      end if;
44
    end if;
45
  end process;
46
end rtl;

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.

von Gustl B. (-gb-)


Lesenswert?

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.

von Wowa (Gast)


Angehängte Dateien:

Lesenswert?

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

von Gustl B. (-gb-)


Lesenswert?

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.

von ossi (Gast)


Lesenswert?

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.

von Duke Scarring (Gast)


Angehängte Dateien:

Lesenswert?

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

von Achim S. (Gast)


Lesenswert?

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?

von Gustl (Gast)


Lesenswert?

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.

von Duke Scarring (Gast)


Angehängte Dateien:

Lesenswert?

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

von Jens (Gast)


Lesenswert?

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

von J. S. (engineer) Benutzerseite


Lesenswert?

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!

: Bearbeitet durch User
von Gustl B. (-gb-)


Lesenswert?

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.

von J. S. (engineer) Benutzerseite


Lesenswert?

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.

von Gustl B. (-gb-)


Lesenswert?

Exakt! Wobei ich finde dass der IIR bis auf die Skalierung funktionieren 
sollte.

von Gustl B. (-gb-)


Angehängte Dateien:

Lesenswert?

So, also der IIR filtert mit kleinen Anpassungen wunderbar. Testbench 
und Filter sind im Anhang.

von Wowa (Gast)


Angehängte Dateien:

Lesenswert?

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

von J. S. (engineer) Benutzerseite


Lesenswert?

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?

von Gustl B. (-gb-)


Lesenswert?

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.

von Wowa (Gast)


Lesenswert?

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.

von J. S. (engineer) Benutzerseite


Lesenswert?

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.

von J. S. (engineer) Benutzerseite


Lesenswert?

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

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.