Das Blockschaltbild der HBF-Kaskade
In der ersten Annäherung bekommen wir einen Datenstrom von Samples vom ADC im 1 MHz Takt und liefern Samples mit 1 MHz durch 256. Dafür brauchen wir mindestens einen Speicher für Daten und Koeffizienten, einen MAC (z.B. DSP48E1 bei Xilinx) und eine etwas komplexe Ablaufsteuerung, die das ganze organisiert.
Erst mal müssen wir uns überlegen was wir für einen Speicher brauchen. Die erste Randbedinung ist die Geschwindigkeit für den Datenzugriff. Die Eingangsdaten kommen mit 1 MHz bei einem Verarbeitungstakt von 100 MHz (es geht auch mit 200, aber gehen wir es gemütlich an). Die erste Stufe des HBFs wird also nur alle 200 Takte aktiviert (es wird ja nur jeder zweite Wert berechnet). Für die Berechnung werden 4 Koeffizienten und neun Daten gelesen und ein Wert geschrieben. Damit wären 14 der 200 Takte belegt. Die nächste Stufe wird nur alle 400 Takte benötig u.s.w. so dass durch die ersten 6 Stufen vielleicht 26 der 200 Takte belegt sind, also 13 %, die letzten beiden HBF haben mehr Koeffizienten, aber da haben wir noch reichlich Luft.
Die zweite Rahmenbedingung ist der Speicherbedarf. Wir brauchen zyklischen Speicherzugriff für die Eingangsdaten, die Basisadresse muss also ein vielfaches des 2X Datenspeichers sein. Die Filterlänge der ersten Stufen ist 15, da wäre mit 32 als Puffergröße also ausreichend Luft. Die Stufe 7 hat 23 Koeffizienten und kommt auch mit 32 aus. Einzig Stufe 8 mit 67 Koeffizienten braucht mit 128 Werten richtig Platz. Dazu kommen die Koeffizienten mit 4 für die ersten 6 Stufen, die aber nur ein mal vorhanden sein müssen, 6 Koeffizienten für Stufe 7 und 17 für Stufe 8. Insgesamt brauchen wir also mindestens 128 + 7 * 32 + 17 + 7 + 4 = 380, also 512. Das heißt auch hier kommen wir mit einem normalen Blockram von 16/18 kBit aus, selbst wenn wir auf höhere Bitbreiten für Daten oder Koeffizienten gehen wollen.
Da wir mit Initialisierung nur 5 MAC-Operationen pro Filterung brauchen ist dieser deutlich weniger belegt als das RAM, hier haben wir also kein Problem mit dieser Ressource auszukommen.
Jetzt kommt es zum Eingemachten. Der Ablaufsteuerung. Wir benötigen Kontrolle über die verschiedenen Zeiger (Schreib-/Lesezeiger) und Zähler (wie viele Daten in einem Teilvektor gültig sind). Das könnte man in einer Ablaufsteuerung hinbekommen, aber ich will da auf eine alte Tradition zurückgreifen. Der Mikroprogrammierung. Das wird bestimmt lustig.
Das Signal kommt von links und wird im RAM gepuffert. Die Ablaufsteuerung kümmert sich um die korrekte Adressierung des DPRAMs, taktet die Notwendigen Daten in die Übergaberegister des MAC und steuert diesen über seine Control-Leitungen.
Die Zwischenergebnisse der Berechnungen werden wieder unter Kontrolle der Ablaufsteuerung in das RAM geschrieben und das Endergebnis direkt ausgegeben (dazu wird natürlich auch ein Clock-Enable erzeugt, welches hier nicht eingezeichnet wurde).
Bereich | Startadresse | Größe (Worte) | Endadresse | Bemerkung |
---|---|---|---|---|
Stufe 8 | 0x0000 | 128 | 0x007F | |
Stufe 7 | 0x0080 | 32 | 0x009F | |
Stufe 6 | 0x00A0 | 32 | 0x00BF | |
Stufe 5 | 0x00C0 | 32 | 0x00DF | |
Stufe 4 | 0x00E0 | 32 | 0x00FF | |
Stufe 3 | 0x0100 | 32 | 0x011F | |
Stufe 2 | 0x0120 | 32 | 0x013F | |
Stufe 1 | 0x0140 | 32 | 0x015F | |
Coeff 8 | 0x0160 | 32 | 0x017F | |
Coeff 7 | 0x0180 | 8 | 0x0187 | |
Coeff 6 | 0x0188 | 4 | 0x018B | |
Coeff 5 | 0x018C | 4 | 0x018F | |
Coeff 4 | 0x0190 | 4 | 0x0193 | |
Coeff 3 | 0x0194 | 4 | 0x0197 | |
Coeff 2 | 0x0198 | 4 | 0x019B | |
Coeff 1 | 0x019C | 4 | 0x019F | |
Alignment | 0x01A0 | 352 | 0x02FF | Padding auf 512-128 |
Param 8 | 0x0300 | 8 | 0x0307 | |
Param 7 | 0x0308 | 8 | 0x030F | |
Param 6 | 0x0310 | 8 | 0x0317 | |
Param 5 | 0x0318 | 8 | 0x031F | |
Param 4 | 0x0320 | 8 | 0x0327 | |
Param 3 | 0x0328 | 8 | 0x032F | |
Param 2 | 0x0330 | 8 | 0x0337 | |
Param 1 | 0x0338 | 8 | 0x033F | |
Reserved | 0x0340 | 448 | 0x04FF | Restlicher Speicher |