Bei dieser Frage geht es um die Implementierung eines IIR-Filters in einem FPGA mit DSP-Slices mit sehr spezifischen Kriterien.
Nehmen wir an, Sie erstellen einen Filter ohne Vorwärtsabgriffe und nur 1 Rückwärtsabgriff mit dieser Gleichung:
(siehe Bild)
Nehmen Sie als Beispiel das DSP48A1-Slice von Xilinx - die meisten harten IP-DSP-Slices sind ähnlich.
Nehmen wir an, Sie haben analoge Daten, die mit 1 Abtastwert pro Takt eingehen. Ich möchte einen IIR-Filter entwerfen, der synchron mit dem Sample-Clock läuft.
Das Problem ist, dass Sie nicht multiplizieren UND zum selben Zyklus hinzufügen können, um das DSP-Slice mit der maximalen Rate auszuführen. Sie müssen ein Pipeline-Register zwischen diesen Komponenten haben.
Wenn Sie also pro Takt 1 neues Sample haben, müssen Sie 1 Ausgang pro Takt erzeugen. Sie benötigen jedoch die vorherigen 2 Takte, bevor Sie eine neue in diesem Design erstellen können.
Die naheliegende Lösung besteht darin, die Daten entweder mit doppelter Taktrate zu verarbeiten oder das Pipeline-Register zu deaktivieren, damit Sie im selben Zyklus multiplizieren und addieren können.
Wenn Sie beispielsweise mit der maximalen Taktrate des DSP-Slice mit vollständiger Pipeline abtasten, ist leider keine dieser Lösungen möglich. Gibt es eine andere Möglichkeit, dies zu bauen?
(Bonuspunkte, wenn Sie einen IIR-Filter entwerfen können, der mit einer beliebigen Anzahl von DSP-Slices mit der Hälfte der Abtastrate arbeitet)
Das Ziel wäre, einen Kompensationsfilter für einen 1-GSPS-ADC in einem Xilinx Artix-FPGA auszuführen. Ihre DSP-Slices können bei voller Pipeline etwas mehr als 500 MHz laufen. Wenn es eine Lösung für 1 Probe pro Uhr gibt, möchte ich versuchen, die Lösung für 2 Proben pro Uhr zu skalieren. Mit einem FIR-Filter ist das alles sehr einfach.
Antworten:
Ich habe noch nicht mit IIR-Filtern gearbeitet, aber wenn Sie nur die angegebene Gleichung berechnen müssen
Einmal pro CPU-Zyklus können Sie Pipelining verwenden.
In einem Zyklus führen Sie die Multiplikation durch und in einem Zyklus müssen Sie die Summierung für jede Eingangsabtastung durchführen. Das bedeutet, dass Ihr FPGA in der Lage sein muss, die Multiplikation in einem Zyklus durchzuführen, wenn es mit der angegebenen Abtastrate getaktet wird! Dann müssen Sie nur noch die Multiplikation des aktuellen Samples UND die Summierung des Multiplikationsergebnisses des letzten Samples parallel durchführen. Dies führt zu einer konstanten Verarbeitungsverzögerung von 2 Zyklen.
Ok, schauen wir uns die Formel an und entwerfen eine Pipeline:
Ihr Pipeline-Code könnte folgendermaßen aussehen:
Beachten Sie, dass alle drei Befehle parallel ausgeführt werden müssen und dass "Ausgabe" in der zweiten Zeile daher die Ausgabe aus dem letzten Taktzyklus verwendet!
Ich habe nicht viel mit Verilog gearbeitet, daher ist die Syntax dieses Codes höchstwahrscheinlich falsch (z. B. fehlende Bitbreite der Eingangs- / Ausgangssignale; Ausführungssyntax für die Multiplikation). Sie sollten jedoch auf die Idee kommen:
PS: Vielleicht könnte ein erfahrener Verilog-Programmierer diesen Code bearbeiten und diesen Kommentar und den Kommentar über dem Code anschließend entfernen. Vielen Dank!
PPS: Wenn Ihr Faktor "b1" eine feste Konstante ist, können Sie das Design möglicherweise optimieren, indem Sie einen speziellen Multiplikator implementieren, der nur eine Skalareingabe verwendet und nur "Zeiten b1" berechnet.
Antwort auf: "Leider entspricht dies tatsächlich y [n] = y [n-2] * b1 + x [n]. Dies liegt an der zusätzlichen Pipeline-Stufe." als Kommentar zur alten Version der Antwort
Ja, das war eigentlich richtig für die folgende alte (INCORRECT !!!) Version:
Ich habe diesen Fehler jetzt hoffentlich behoben, indem ich auch die Eingabewerte in einem zweiten Register verzögert habe:
Um sicherzustellen, dass es diesmal richtig funktioniert, schauen wir uns an, was in den ersten Zyklen passiert. Beachten Sie, dass die ersten beiden Zyklen mehr oder weniger (definierten) Müll produzieren, da keine vorherigen Ausgabewerte (z. B. y [-1] == ??) verfügbar sind. Das Register y wird mit 0 initialisiert, was der Annahme von y [-1] == 0 entspricht.
Erster Zyklus (n = 0):
Zweiter Zyklus (n = 1):
Dritter Zyklus (n = 2):
Vierter Zyklus (n = 3):
Wir können sehen, dass wir beginnend mit cylce n = 2 die folgende Ausgabe erhalten:
das ist äquivalent zu
Wie oben erwähnt, führen wir eine zusätzliche Verzögerung von l = 1 Zyklen ein. Das bedeutet, dass Ihre Ausgabe y [n] um die Verzögerung l = 1 verzögert ist. Das heißt, die Ausgabedaten sind äquivalent, werden jedoch um einen "Index" verzögert. Um es klarer zu machen: Die Ausgangsdaten verzögern sich um 2 Zyklen, da ein (normaler) Taktzyklus benötigt wird und 1 zusätzlicher (Verzögerung l = 1) Taktzyklus für die Zwischenstufe hinzugefügt wird.
Hier ist eine Skizze, um grafisch darzustellen, wie die Daten fließen:
PS: Danke, dass Sie sich meinen Code genau angesehen haben. Also habe ich auch etwas gelernt! ;-) Lass mich wissen, ob diese Version korrekt ist oder ob du weitere Probleme siehst.
quelle
y[n+l] = y[n-1] * b + x[n]
einen festen Wert für die Verzögerung hat,l
der umgeschrieben werden kann,y[n] = y[n-1-l] * b + x[n-l]
und für l = 1 ist diesy[n] = y[n-2] * b + x[n-1]
.y[n+l] = x[n] * b0 + x[n-1] * b1 - y[n-1] * a1 - y[n-2] * a2
=>y[n] = x[n-l]*b0 + x[n-1-l] * b1 - y[n-1-l] * a1 - y[n-2-l]*a2
. Angenommen, Sie können alle drei Multiplikationen parallel durchführen (1. Stufe / 1 Zyklus) und müssen die beiden addieren, um die Produkte zu addieren. Sie benötigen 2 Zyklen (1 Zyklus: Add / Sub, erste zwei Produktergebnisse, 1 Zyklus: Add / Sub Als Ergebnis dieser beiden Add / Subs) benötigen Sie 2 zusätzliche Zyklen. Also l = (3-1) = 2 gibt diry[n]=x[n-2]*b0+x[n-1-2]*b1-y[n-1-2]*a1-y[n-2-2]*a2
=>y[n]=x[n-2]*b0+x[n-3]*b1-y[n-3]*a1-y[n-4]*a2
Ja, Sie können mit der Abtastfrequenz takten.
Eine Lösung für dieses Problem besteht darin, den ursprünglichen Ausdruck so zu bearbeiten, dass Pipeline-Register eingefügt werden können, während die gewünschte Ausgabesequenz beibehalten wird.
Gegeben: y [n] = y [n-1] * b1 + x [n];
Dies kann manipuliert werden in: y [n] = y [n-2] * b1 * b1 + x [n-1] * b1 + x [n].
Um zu überprüfen, ob dies dieselbe Sequenz ist, betrachten Sie, was mit den ersten mehreren Abtastwerten x [0], x [1], x [2] usw. passiert, wobei vor x [0] alle x, y-Abtastwerte Null waren.
Für den ursprünglichen Ausdruck lautet die Sequenz:
Es ist klar, dass es notwendig ist, dass b1 <1 ist, sonst wächst dies ungebunden.
Betrachten Sie nun den manipulierten Ausdruck:
Dies ist die gleiche Reihenfolge.
Eine Hardwarelösung in Grundelementen der Xilinx-Bibliothek würde zwei DSP48E in Kaskade benötigen. In Abbildung 1-1 in UG193 v3.6 finden Sie die folgenden Port- und Registernamen. Das erste Grundelement multipliziert mit b1 und addiert einen Takt später; Die zweite wird mit b1 * b1 multipliziert und eine Uhr später addiert. Für diese Logik gibt es eine Pipeline-Latenz von 4 Takten.
- DSP48E # 1
a_port1: = b1; - konstanter Koeffizient, setze AREG = 1
b_port1: = x; - setze Attribut BREG = 1
c_port1: = x; - CREG = 1 setzen
- intern in DSP48E # 1
reg_a1 <= a_port1;
reg_b1 <= b_port1;
reg_c1 <= c_port1;
reg_m1 <= reg_a1 * reg_b1;
reg_p1 <= reg_m1 + reg_c1; - Ausgabe des 1. DSP48E
- Ende von DSP48E # 1
- DSP48E # 2
a_port2: = reg_p2; - setze Attribut AREG = 0
b_port2: = b1 * b1; - konstant, setze BREG = 1
c_port2: = reg_p1; - CREG = 1 setzen
- intern in DSP48E # 2
reg_b2 <= b_port2;
reg_c2 <= c_port2;
reg_m2 <= a_port2 * reg_b2;
reg_p2 <= reg_m2 + reg_c2;
- Ende von DSP48E # 2
Die Sequenz bei reg_p1:
x [0],
x [1] + x [0] * b1,
x [2] + x [1] * b1,
x [3] + x [2] * b1,
usw.
Die Sequenz bei reg_p2 ist das gewünschte Ergebnis. Innerhalb des 2. DSP48E hat das Register reg_m2 eine Sequenz:
x [0] * b1 * b1,
x [1] * b1 * b1 + x [0] * b1 * b1 * b1,
x [2] * b1 * b1 + x [1] * b1 * b1 * b1 + x [0] * b1 * b1 * b1 * b1
Dieses Ergebnis hat eine schöne Eleganz. Es ist klar, dass der DSP48E nicht im selben Takt multipliziert und addiert, aber genau das erfordert die Differenzgleichung. Die manipulierte Differenzgleichung ermöglicht es uns, die M- und P-Register im DSP48E zu tolerieren und mit voller Geschwindigkeit zu takten.
quelle