Also known as: DSP block, GNU Radio block, signal processing block
A signal-processing block is a self-contained DSP unit with typed input and output
signatures and a work() method the runtime calls to turn input samples into output
samples.1 It is the node in a flowgraph: one block does one
job — a filter, a resampler, a demodulator, a decoder — and exposes just enough interface for
a scheduler to hand it buffers of samples and collect the
results. Blocks are the reusable Lego bricks of block-based SDR: wire different ones together
and you get a different radio.
How it works
Every block declares two things up front and implements one behaviour:
- Input signature — how many input ports it has and the item size on each (complex 8-byte IQ, 4-byte float, 1-byte packed bits, a custom struct).
- Output signature — the same for its outputs. A source has zero inputs; a sink has zero outputs.
- A work function — the code the runtime calls with pointers to a chunk of available input
and space for output. In GNU Radio, a sync block (one output item per input item)
implements
work(); a general block with a different or data-dependent rate implementsgeneral_work()plus aforecast()that tells the scheduler how many input items it needs to produce a given number of outputs.
The block returns how many output items it actually produced, and the runtime advances the stream pointers accordingly. This contract — here is your input, here is your output space, tell me how much you consumed and produced — is what lets the scheduler manage buffering, back-pressure, and rate changes without the block author having to know anything about the blocks around it.
In practice
Rate relationships classify the common block types:
- Sync block — 1:1. A per-sample gain, an FM discriminator, an AGC.
- Decimator — N:1. Consumes N inputs per output; the front of a channelizer.
- Interpolator — 1:N. Upsampling before pulse shaping.
- General block — arbitrary or data-dependent rate. A packet framer that emits a burst
only when a valid frame is found uses
general_work()andforecast().
Blocks can also carry stream tags — metadata pinned to a sample index — and message ports for asynchronous control, so a block is not limited to pushing samples: it can annotate the stream or exchange out-of-band messages. Custom blocks that ship outside the core tree live in an out-of-tree module, and a group of blocks can be bundled as a hierarchical block that itself looks like one block.
Relevance to SDR
The block is the unit of reuse in SDR software. Because its interface is narrow and typed, a filter written once works in any flowgraph that feeds it the right item type, and you can unit test a block by feeding known input and asserting on the output — no radio hardware required. This is why GNU Radio ships hundreds of stock blocks and why a large fraction of SDR development is really “write one new block and drop it into an existing chain.”
When you build SDR software, the discipline the block interface enforces — one job, explicit input/output types, no assumptions about neighbours — is worth adopting even without a formal block runtime. GopherTrunk is written in pure Go and does not use GNU Radio, but its decode chain is factored the same way: the down-converter, demodulator, symbol slicer, and framer are each independent stages with clear input and output types, which is exactly what makes them individually testable against captured IQ files. The naming differs; the “one block, one job, typed I/O” principle is identical.
Sources
-
Blocks Coding Guide — GNU Radio Wiki, on io signatures, sync blocks, general blocks, work()/general_work(), and forecast(). ↩