Vector Sink

Der Gegenpart zum Vector Source — sammelt einen Datenstrom vollständig als Python-Array, ohne eine GUI-Anzeige zu benötigen.

1. Beschreibung des Blocks

Der Vector Sink-Block (blocks.vector_sink_x) sammelt alle bei ihm ankommenden Samples in einem internen Puffer, statt sie darzustellen oder weiterzuleiten. Er hat keine grafische Oberfläche und keinen Ausgang — der Zugriff auf die gesammelten Werte erfolgt ausschließlich über seine Python-API, per data() für die Samples selbst und tags() für alle mitgelaufenen Stream-Tags.

Er ist damit das exakte Gegenstück zum Vector Source-Block: Wo Vector Source einen festen, bekannten Datensatz in den Flowgraph einspeist, sammelt Vector Sink das Ergebnis der Verarbeitung wieder ein — beide zusammen bilden den Standardaufbau für reproduzierbare, headless durchführbare Tests.

2. Technischer Einsatz

Vector Sink ist der zentrale Baustein der auf dieser Seite beschriebenen Testmethodik: Statt das Ergebnis eines Flowgraphs visuell an einem QT-GUI-Sink zu beurteilen, wird es bei Vector Sink als Python-Array abgegriffen und per assert gegen einen vorher berechneten Erwartungswert (Ground Truth) geprüft — vollständig automatisiert und ohne geöffnetes GUI-Fenster ausführbar.

Typischer Testaufbau: vector_source (Testsignal mit bekanntem Inhalt) → zu testender Block → vector_sink (Ergebnis einsammeln) → tb.run()assert auf snk.data(). Dieses Muster wird im BCD-Decoder-Test und im FSK/RTTY-Test durchgängig verwendet.

3. Parameter und Dimensionierung

Parameter Typ/Einheit Bedeutung Dimensionierungshinweis
type (Input Type) Enum Datentyp: Complex, Float, Int, Short, Byte muss zum Ausgangstyp des vorgeschalteten Blocks passen
vlen (Vector Length) Integer Anzahl Elemente pro Vektor-Sample Standard 1 (Skalarstrom)
reserve_items (Reserve memory for items) Integer Vorab reservierte Puffergröße reine Performance-Optimierung gegen wiederholtes Reallozieren bei großen Captures — kein hartes Limit, siehe unten
Verifiziert (GNU Radio 3.10.12.0, tatsächlich ausgeführt): Um zu prüfen, ob reserve_items tatsächlich nur ein Performance-Hinweis oder doch eine harte Kapazitätsgrenze ist, wurde bewusst mehr hineingeschickt, als reserviert wurde:
from gnuradio import gr, blocks

tb = gr.top_block()
data = list(range(2000))                              # 2000 Samples ...
src = blocks.vector_source_f([float(x) for x in data], False)
snk = blocks.vector_sink_f(1, 100)                     # ... aber nur reserve_items=100
tb.connect(src, snk)
tb.run()

print("captured length:", len(snk.data()))
from gnuradio import gr, blocks

tb = gr.top_block()
data = list(range(2000))                              # 2000 Samples ...
src = blocks.vector_source_f([float(x) for x in data], False)
snk = blocks.vector_sink_f(1, 100)                     # ... aber nur reserve_items=100
tb.connect(src, snk)
tb.run()

print("captured length:", len(snk.data()))

Ausgabe:

captured length: 2000
captured length: 2000

Warum dieser Test: Wäre reserve_items eine harte Grenze, würde der Vector Sink entweder abstürzen oder die Aufnahme bei 100 Samples abschneiden. Da tatsächlich alle 2000 Samples ankommen, ist bestätigt: Der Parameter reserviert nur vorab Speicher zur Vermeidung wiederholter Reallokation — der Puffer wächst bei Bedarf automatisch darüber hinaus, ohne Datenverlust.

4. Ein- und Ausgänge

Ein-/Ausgang Typ
Eingang Complex, Float, Int, Short oder Byte (je nach type)
Ausgang keiner

5. Weitere wichtige Aspekte

Zugriff auf die gesammelten Daten: Nach tb.run() liefert snk.data() alle empfangenen Samples als Python-Liste (bei Complex als complex-Werte, ansonsten als float/int). snk.tags() liefert zusätzlich alle mitgelaufenen Stream-Tags mit ihrer jeweiligen Sample-Position — wichtig, um z. B. beim BCD-Decoder-Test geprüfte Bit-Tags exakt zu lokalisieren.

Verifiziert (GNU Radio 3.10.12.0, tatsächlich ausgeführt): Mit dem einfachstmöglichen Datensatz (vier unterscheidbare, aufsteigende Werte) lässt sich am direktesten prüfen, ob Reihenfolge und Werte beim Durchlauf erhalten bleiben:
from gnuradio import gr, blocks

tb = gr.top_block()
src = blocks.vector_source_f([1.0, 2.0, 3.0, 4.0], False)
snk = blocks.vector_sink_f()
tb.connect(src, snk)
tb.run()

print("data():", snk.data())
from gnuradio import gr, blocks

tb = gr.top_block()
src = blocks.vector_source_f([1.0, 2.0, 3.0, 4.0], False)
snk = blocks.vector_sink_f()
tb.connect(src, snk)
tb.run()

print("data():", snk.data())

Ausgabe:

data(): [1.0, 2.0, 3.0, 4.0]
data(): [1.0, 2.0, 3.0, 4.0]

Warum diese Werte: Vier unterschiedliche, streng aufsteigende Zahlen wurden bewusst gewählt, weil damit sowohl eine Vertauschung der Reihenfolge als auch ein Verlust einzelner Samples sofort auffallen würde — ein Testdatensatz aus lauter gleichen Werten (z. B. Nullen) hätte einen solchen Fehler nicht sichtbar gemacht. Ausgabe und Eingabe sind identisch: keine Reihenfolgeänderung, kein Sample-Verlust.

Kein Ersatz für eine Anzeige während der Entwicklung: Vector Sink liefert kein visuelles Feedback — für die interaktive Fehlersuche im laufenden Betrieb ist zunächst weiterhin ein QT GUI Time Sink sinnvoller; Vector Sink kommt typischerweise erst zum Einsatz, wenn ein Testfall bereits feststeht und automatisiert wiederholbar sein soll.