DC Blocker
Ein rechnerisch günstiger Filter zur Entfernung des Gleichanteils (DC-Offsets) aus einem Signal — mit engerer Kerbe um 0 Hz als ein äquivalenter FIR-Filter.
1. Beschreibung des Blocks
Der DC Blocker-Block (filter.dc_blocker_ff / filter.dc_blocker_cc) entfernt den Gleichanteil (DC-Offset, 0 Hz) aus einem Signal. Anders als ein klassischer FIR-Hochpass erreicht er eine deutlich engere Sperrkerbe um 0 Hz bei geringerer Gruppenlaufzeit — auf Basis einer rekursiven Verzögerungsleitung (Delay Line) statt eines FIR-Filterentwurfs. Das zugrunde liegende Verfahren stammt aus R. Yates, „DC Blocker Algorithms", IEEE Signal Processing Magazine, März 2008.

Der Block existiert in zwei Varianten (per Type-Parameter wählbar): Complex->Complex für IQ-Signale und Float->Float für reelle Signale. Beide arbeiten nach demselben Prinzip, nur auf unterschiedlichen Datentypen.
from gnuradio import gr, blocks, filter as gr_filter
import numpy as np
samp_rate, freq, n = 48000, 1000, 4000
t = np.arange(n) / samp_rate
dc_offset = 0.7
sig = dc_offset + 0.5 * np.sin(2*np.pi*freq*t) # 0,7 Gleichanteil + 1-kHz-Sinus, Amplitude 0,5
tb = gr.top_block()
src = blocks.vector_source_f(sig.tolist(), False)
dcb = gr_filter.dc_blocker_ff(32, True) # length=32, long_form=True
snk = blocks.vector_sink_f()
tb.connect(src, dcb, snk)
tb.run()
out = np.array(snk.data())
delay = dcb.group_delay()
steady = out[delay + 500:] # Einschwingphase nach der Gruppenlaufzeit überspringen
print("input mean (DC-Anteil):", round(float(np.mean(sig)), 4))
print("output mean nach Einschwingen:", round(float(np.mean(steady)), 4))
print("output amplitude (Peak):", round(float(np.max(np.abs(steady))), 4))
from gnuradio import gr, blocks, filter as gr_filter
import numpy as np
samp_rate, freq, n = 48000, 1000, 4000
t = np.arange(n) / samp_rate
dc_offset = 0.7
sig = dc_offset + 0.5 * np.sin(2*np.pi*freq*t) # 0,7 Gleichanteil + 1-kHz-Sinus, Amplitude 0,5
tb = gr.top_block()
src = blocks.vector_source_f(sig.tolist(), False)
dcb = gr_filter.dc_blocker_ff(32, True) # length=32, long_form=True
snk = blocks.vector_sink_f()
tb.connect(src, dcb, snk)
tb.run()
out = np.array(snk.data())
delay = dcb.group_delay()
steady = out[delay + 500:] # Einschwingphase nach der Gruppenlaufzeit überspringen
print("input mean (DC-Anteil):", round(float(np.mean(sig)), 4))
print("output mean nach Einschwingen:", round(float(np.mean(steady)), 4))
print("output amplitude (Peak):", round(float(np.max(np.abs(steady))), 4))
Ausgabe:
input mean (DC-Anteil): 0.7014
output mean nach Einschwingen: -0.0019
output amplitude (Peak): 0.4854
input mean (DC-Anteil): 0.7014
output mean nach Einschwingen: -0.0019
output amplitude (Peak): 0.4854
Warum diese Werte: Der Eingang hat exakt 0,70 Gleichanteil, der Ausgang nach dem Einschwingen praktisch 0 (−0,0019) — der DC Blocker hat den Gleichanteil also nahezu vollständig entfernt. Gleichzeitig bleibt die Sinusamplitude mit 0,485 nahe am ursprünglichen Wert von 0,5 erhalten (die kleine Abweichung stammt aus der endlichen Fensterlänge der Mittelwertbildung, nicht aus einer Dämpfung durch den Filter). Die ersten delay + 500 Samples werden bewusst verworfen, weil der Filter erst nach seiner Gruppenlaufzeit eingeschwungen ist — würde man von Sample 0 an mitteln, wäre der Übergangsvorgang mit im Ergebnis und würde den gemessenen Mittelwert verfälschen.
2. Technischer Einsatz
Der DC Blocker wird eingesetzt, wenn ein Signal einen unerwünschten Gleichanteil trägt, der die nachfolgende Verarbeitung stört — etwa nach einem AM-Envelope-Detector (der Betrag eines Signals ist grundsätzlich nie negativ und hat daher immer einen positiven Gleichanteil), nach einem ADC mit leichtem Offset-Fehler, oder als Vorstufe vor einer AGC-Regelung, die sonst fälschlich auf den DC-Anteil statt auf die eigentliche Signalamplitude reagieren würde.
3. Parameter und Dimensionierung
| Parameter | Typ/Einheit | Bedeutung | Dimensionierungshinweis |
|---|---|---|---|
type (Type) |
Enum | Complex->Complex oder Float->Float | muss zum Datentyp der angeschlossenen Blöcke passen |
length (Length, $D$) |
Integer | Länge der internen Verzögerungsleitung | Standard 32; größere Werte verengen die Sperrkerbe um 0 Hz, erhöhen aber die Gruppenlaufzeit |
long_form (Long Form) |
Bool | Long Form (glatterer Frequenzgang) oder Short Form (kürzere Verzögerung, rechnerisch günstiger) | Standard „True"; „False" nur bei knappem Rechenbudget oder wenn die zusätzliche Verzögerung nicht tolerierbar ist |
from gnuradio import filter as gr_filter
for D, form in [(32, True), (32, False)]:
blk = gr_filter.dc_blocker_ff(D, form)
print(f"length={D}, long_form={form}: group_delay() = {blk.group_delay()}")
from gnuradio import filter as gr_filter
for D, form in [(32, True), (32, False)]:
blk = gr_filter.dc_blocker_ff(D, form)
print(f"length={D}, long_form={form}: group_delay() = {blk.group_delay()}")
Ausgabe:
length=32, long_form=True: group_delay() = 62
length=32, long_form=False: group_delay() = 31
length=32, long_form=True: group_delay() = 62
length=32, long_form=False: group_delay() = 31
Warum diese Werte: $2 \cdot 32 - 2 = 62$ und $32 - 1 = 31$ — die von group_delay() tatsächlich gemeldete Verzögerung stimmt exakt mit den Formeln überein. length=32 wurde gewählt, weil es der Default-Wert des Blocks ist (siehe Parametertabelle) und damit der Wert, den man in der Praxis am häufigsten unverändert übernimmt.
4. Ein- und Ausgänge
| Ein-/Ausgang | Typ (je nach type) |
|---|---|
| Eingang | Complex oder Float |
| Ausgang | Complex oder Float (identisch zum Eingang) |
Der Datentyp von Ein- und Ausgang ist immer identisch — es findet keine Typkonvertierung statt.
5. Weitere wichtige Aspekte
Gruppenlaufzeit einplanen: Da der DC Blocker eine reale Verzögerung von $2D-2$ (Long Form) bzw. $D-1$ (Short Form) Samples einführt, muss diese bei zeitkritischer Weiterverarbeitung (z. B. Bit-Slicing oder Symbol-Timing) berücksichtigt werden — ähnlich wie die Filterverzögerung bei den FIR-Filter-Blöcken, die im FSK/RTTY-Test real gemessen und kompensiert wurde.
Kein Ersatz für einen echten Hochpass: Der DC Blocker unterdrückt gezielt den Bereich sehr nahe 0 Hz, verhält sich aber außerhalb dieser engen Kerbe nahezu wie ein Durchlassfilter — für eine breitbandige Unterdrückung niederfrequenter Störanteile ist ein dimensionierter Hochpassfilter die richtige Wahl.
Hochpassfilter (Grundlagen)
Mathematischer Hintergrund und wann ein echter Hochpass statt eines DC Blockers benötigt wird.
Hochpass-Filter-Blöcke
Der FIR-basierte Hochpass als Alternative für breitbandige Tiefenunterdrückung.
FSK/RTTY-Strecke (DDK9)
Ein Beispiel, in dem Filterverzögerungen real gemessen und in der Bit-Slicing-Stufe kompensiert wurden.