freq_xlating_fir_filter

Eines der Block-Tests-Unterverzeichnisse (siehe ../README.md
für die Übersicht). Testet Freq Xlating FIR Filter (Variante ccf:
komplexer Ein-/Ausgang, reelle Taps) — den Block, der Frequenzverschiebung,
Tiefpassfilterung und Dezimierung in einem einzigen, optimierten Schritt
kombiniert (siehe Einsatz im USB-Empfänger).

Testaufbau

test_freq_xlating_fir_filter.py erzeugt ein synthetisches IQ-Signal mit
drei Tönen (1 MHz Abtastrate):

Ton Frequenz Rolle
Zielton +100 kHz soll nach der Verschiebung bei 0 Hz landen
Störer 1 −300 kHz soll unterdrückt werden
Störer 2 +350 kHz soll unterdrückt werden

plus komplexes weißes Rauschen. Der Block wird mit center_freq=100 kHz
(verschiebt den Zielton exakt auf 0 Hz), decim=10 (Ausgangsrate
100 kHz) und einem Tiefpass (Grenzfrequenz 40 kHz, Übergangsbreite
10 kHz, Hamming-Fenster) konfiguriert.

Ausführen

python3 test_freq_xlating_fir_filter.py
python3 test_freq_xlating_fir_filter.py
Verifiziert (GNU Radio 3.10.12.0, tatsächlich ausgeführt):
=== Block-Parameter (Freq Xlating FIR Filter, Variante ccf) ===
center_freq (Frequenzverschiebung): +100.0 kHz
decim (Dezimierungsfaktor): 10
Eingangs-Abtastrate: 1.000 MHz
Ausgangs-Abtastrate: 100.0 kHz
Tiefpass-Grenzfrequenz: 40.0 kHz
Uebergangsbreite: 10.0 kHz
Fenster: Hamming
Anzahl Filter-Taps: 241
Gruppenlaufzeit (Taps // 2): 120 Samples bei 1.000 MHz = 120.00 us
relative_rate() (GNU-Radio-intern): 0.1000 (erwartet 1/10 = 0.1000)
Eingangs-Samples: 200000, Ausgangs-Samples: 20000 (erwartet ca. 20000)

=== Messung: Unterdrueckung der Stoerer ===
Zielton vorher (bei 100 kHz): 62.8 dB
Zielton nachher (bei 0 Hz): 63.3 dB
Stoerer 1 vorher (bei -300 kHz): 61.3 dB
(Stoerer liegen nach der Dezimierung ausserhalb des Ausgangsbands - vom Filter samt Alias-Schutz entfernt, siehe PNG.)
=== Block-Parameter (Freq Xlating FIR Filter, Variante ccf) ===
center_freq (Frequenzverschiebung): +100.0 kHz
decim (Dezimierungsfaktor): 10
Eingangs-Abtastrate: 1.000 MHz
Ausgangs-Abtastrate: 100.0 kHz
Tiefpass-Grenzfrequenz: 40.0 kHz
Uebergangsbreite: 10.0 kHz
Fenster: Hamming
Anzahl Filter-Taps: 241
Gruppenlaufzeit (Taps // 2): 120 Samples bei 1.000 MHz = 120.00 us
relative_rate() (GNU-Radio-intern): 0.1000 (erwartet 1/10 = 0.1000)
Eingangs-Samples: 200000, Ausgangs-Samples: 20000 (erwartet ca. 20000)

=== Messung: Unterdrueckung der Stoerer ===
Zielton vorher (bei 100 kHz): 62.8 dB
Zielton nachher (bei 0 Hz): 63.3 dB
Stoerer 1 vorher (bei -300 kHz): 61.3 dB
(Stoerer liegen nach der Dezimierung ausserhalb des Ausgangsbands - vom Filter samt Alias-Schutz entfernt, siehe PNG.)

Spektrum vor und nach dem Freq Xlating FIR Filter

Einordnung des Ergebnisses

Oben das Eingangsspektrum (drei deutliche Peaks über dem Rauschteppich),
unten das Ausgangsspektrum: Der Zielton sitzt exakt bei 0 Hz, beide
Störer sind komplett verschwunden — sie lägen nach der Verschiebung bei
−400 kHz bzw. +250 kHz, weit außerhalb sowohl des Filterdurchlassbereichs
als auch der Nyquist-Grenze der dezimierten 100-kHz-Ausgangsrate (±50 kHz).
Der Block erledigt Tuning, Anti-Alias-Filterung vor der Dezimierung und die
Dezimierung selbst in einem Durchgang.

Der Rauschteppich im Ausgangsspektrum ist keine flache Linie, sondern steigt zur Mitte hin leicht an ("Huckel"-Form um den 63-dB-Zielton). Das ist kein Filterfehler, sondern spektrales Leckage der Fensterfunktion (Blackman-Harris) bei der FFT-Analyse: Ein derart starker, schmalbandiger Ton hinterlässt auch mit gutem Fenster einen sichtbaren Leckage-"Skirt" in benachbarten Bins. Kontrollmessung ohne Ton (nur Rauschen durch denselben Filter): Rauschteppich flach bei ca. −16 dB im Durchlassbereich, Abfall auf ca. −45 dB im Sperrbereich — der eigentliche Frequenzgang des Filters ist also einwandfrei flach, nur die Analyse-Darstellung neben dem starken Ton täuscht das optisch an.

Was die einzelnen Parameter bedeuten

Parameter Bedeutung
center_freq Frequenz, die auf 0 Hz gemischt wird — bestimmt die Empfangs-/Sendefrequenz
decim Dezimierungsfaktor; Ausgangsrate = Eingangsrate / decim
taps Tiefpass-Filterkoeffizienten (hier via firdes.low_pass erzeugt) — legen Durchlassbereich, Übergangsbreite und Anzahl der Taps fest
relative_rate() GNU-Radio-interne Kenngröße, die das Verhältnis Ausgangs- zu Eingangsrate bestätigt (hier 0,1 = 1/decim)
Gruppenlaufzeit len(taps) // 2 Samples — Verzögerung, die der Filter dem Signal aufprägt (symmetrisches FIR-Filter)