RX Capture¶
Note
Layer 3 shipped, Pass-1. The Layer 3 implementation (emitters,
device-fingerprint, tx-impairments, propagation, rx-frontend) landed
on branch rfgen-impl-2026-06-25-105955 (PR #94). The class names,
Pydantic schemas, and Transformation enum members referenced below
match the shipped surface; Pass-1 stubs (GNU Radio OOT emitters,
cellular emitters, Sionna propagation backends) construct cleanly and
raise an EmitterError or ChannelError tagged with
stage="pass1_stub" until backend wiring lands. See
Reference / rfgen.emitters and
Reference / rfgen.channels for the shipped
class roster.
Scientific validation
The RX capture transformations have been scientifically validated against published references. See the per-component reports:
RX mixer, IF filter, resampler: validated with documented limitations.
RX LNA noise, ADC quantization, AGC: validated with documented limitations.
Each report covers construct validity, mathematical correctness against cited equations, empirical comparison to published reference numbers, literature grounding, experimental methodology, operating envelope, and documented limitations.
Receiver capture, abbreviated RX capture, is Group 3 of the four-group channel pipeline. It is where propagated per-emitter components become one receiver-local IQ buffer: select only components inside the receiver’s tuned band, shift each selected component into the receiver frequency frame, filter and resample to the receiver rate, sum the selected components, then inject low-noise amplifier (LNA) thermal noise.
In this page, R_emitter is the emitter component’s native sample rate and R_rx is the receiver’s configured sample rate. Baseband IQ means complex-valued in-phase/quadrature samples whose zero-frequency bin is a reference point rather than the physical carrier itself. In-band means the component’s occupied frequency interval intersects the receiver’s capture interval.
Overview¶
Name |
ABC |
Default backend |
|
|---|---|---|---|
Mix to RX frame |
|
Shift each component by |
|
IF / bandpass filter |
|
Limit the component to |
|
Resample to |
|
Polyphase rational resampler from |
|
LNA noise injection |
|
Additive complex Gaussian noise with power |
The numbering continues from Group 2: T1-T5 are TX impairments, T6 is channel propagation, and these four RX-capture transformations are T7-T10. See Channels overview for the full T1-T14 map.
Note
Sum step. Between BaseResampler and BaseLNANoise, the composer sums the in-band emitter components into one buffer at R_rx. The sum is an operational step rather than a Transformation; it has no plugin slot and cannot be replaced by a user implementation.
The Sum Point¶
The sum at the head of RX capture, after resampling, is the only place in the pipeline where emitter components are combined. Before this point, each component travels independently through TX impairments and channel propagation. After this point, there is a single composite IQ at each receiver.
The sum is composer-driven: it is not a plugin slot and cannot be replaced by a user implementation. The composer adds all resampled in-band components element-wise at R_rx.
Band-Overlap Predicate¶
Only emitters whose signal band overlaps the receiver’s capture band contribute to the sum. The default predicate is an interval intersection:
emitter_low_hz = emitter.realized_carrier_hz - emitter_signal_bw / 2
emitter_high_hz = emitter.realized_carrier_hz + emitter_signal_bw / 2
rx_low_hz = rx.center_freq_hz - rx.bandwidth_hz / 2
rx_high_hz = rx.center_freq_hz + rx.bandwidth_hz / 2
overlaps = emitter_low_hz < rx_high_hz and rx_low_hz < emitter_high_hz
When emitter signal bandwidth is not tracked separately, the backend may use this center-frequency approximation:
|emitter.realized_carrier_hz - rx.center_freq_hz| < rx.bandwidth_hz / 2
Emitters that fail this predicate are dropped from that receiver’s component list before the RX mixer. They contribute nothing to that receiver’s IQ or labels, and the current shipped path does not persist a drop-reason audit field in scene metadata.
Sample Rate and Carrier Frame¶
Input to RX mixer: baseband IQ per emitter, at
R_emitter, with zero frequency mapped toemitter.realized_carrier_hz.After RX mixer: IQ shifted by
emitter.realized_carrier_hz - rx.center_freq_hz, still atR_emitter.After IF filter: bandlimited to
rx.bandwidth_hz, still atR_emitter.After resampler: resampled to
R_rx.After sum: composite IQ at
R_rx, in the receiver’s frequency frame. Direct current (DC), frequency zero in the baseband representation, maps torx.center_freq_hz.After LNA noise: composite IQ with LNA noise added, at
R_rx.
RX hardware receives the output of LNA noise injection and operates entirely at R_rx.
Mix to RX Frame¶
The RX mixer shifts each in-band component from the emitter’s carrier frequency to the receiver’s frequency frame by applying the complex rotation:
where \(\Delta f = f_\text{emitter,carrier} - f_\text{rx,center}\).
Here n is an integer sample index and n / R_emitter is elapsed time in seconds for that component.
A component whose realized_carrier_hz equals rx.center_freq_hz passes through the RX mixer unchanged. A component offset by 1 MHz appears at 1 MHz within the baseband frame after mixing.
Source: GNU Radio’s Frequency Xlating FIR Filter documents the same receiver-side pattern: frequency translation, filtering, and optional decimation in one channel-selection block. The explicit complex-rotation equation is part of rfgen’s proposed BaseRXMixer contract and is cross-linked from Coordinate Systems.
IF/Bandpass Filter¶
The intermediate-frequency (IF) filter applies a bandpass, or equivalently low-pass after mixing, filter to limit the component to rx.bandwidth_hz. The default implementation uses a linear-phase polyphase FIR filter: linear phase keeps a constant group delay, polyphase is the efficient multi-rate filter structure, and the transition band is chosen so frequencies outside the kept band do not fold back during resampling. Filter order and window type are configurable.
Source: GNU Radio’s Frequency Xlating FIR Filter grounds the paired frequency-translation plus FIR channel-selection model. SciPy’s signal.resample_poly documents the upsample, FIR low-pass, downsample pattern used by the default anti-aliasing path.
Resample to R_rx¶
The resampler converts from R_emitter to R_rx using a polyphase rational resampler. Each emitter component may have a different R_emitter; the resampler handles each independently before the sum. After resampling, all in-band components share R_rx and can be added element-wise.
Source: SciPy’s signal.resample_poly is the implementation reference for polyphase FIR resampling. Crochiere and Rabiner’s Multirate Digital Signal Processing is the textbook grounding for rational-rate conversion.
LNA Noise Injection¶
The LNA noise transformation adds thermal noise representing the receiver low-noise amplifier’s contribution. The Johnson-Nyquist formula gives the thermal-noise floor for a resistor over a bandwidth:
where \(k\) is Boltzmann’s constant, \(T_0 = 290\,\text{K}\) (IEEE reference temperature), \(B = R_\text{rx}\) for the complex-baseband convention used here, and \(NF_\text{dB}\) is the receiver noise figure. In this convention, the sampled complex IQ buffer spans a two-sided baseband interval whose total bandwidth equals the sample rate.
LNA noise runs after the sum so that one noise realization is injected per receiver, not per component. This correctly models the physical situation: the LNA is at the receiver input and sees the composite RF signal.
Source: Nyquist’s thermal-noise derivation (DOI 10.1103/PhysRev.32.110) grounds the Johnson-Nyquist kTB term, and Friis’ receiver-noise paper (DOI 10.1109/JRPROC.1944.232049) grounds noise figure. IEEE Std 145-2013 gives the \(T_0 = 290\) K reference temperature. The rfgen equation is collected with the Friis cascade model in Reference / RF frontend models.
Per-Receiver Parameters¶
RX capture runs once per receiver. Each receiver carries its own center_freq_hz, bandwidth_hz, sample_rate_hz, and noise_figure_db when those fields are set. When ReceiverConfig.center_freq_hz, bandwidth_hz, or sample_rate_hz is omitted, the composer falls back to scene_cfg.center_hz, scene_cfg.bandwidth_hz, or scene_cfg.sample_rate_hz before building ChannelRxParams. The scene-level Group.RX_CAPTURE and Group.RX_HARDWARE stages then run once on that receiver’s summed buffer.
Minimal Example¶
RX capture and RX hardware chain for one receiver. The 5 dB LNA noise figure and 30.72 Msps sample rate are representative example values; exact values come from the receiver model or scenario config.
from rfgen.channel_pipeline import ChannelPipeline
from rfgen.config import ReceiverConfig
from rfgen.rx_frontend import (
LeesonRXPhaseNoise,
LinearADCQuantizer,
LinearAGC,
LinearLNANoise,
LinearRXMixer,
ScipyFIRIFFilter,
ScipyPolyResampler,
TorchSigRXIQImbalance,
)
rx_chain = ChannelPipeline([
# RX capture
LinearRXMixer(),
ScipyFIRIFFilter(cutoff_norm=0.4, num_taps=65, gain=1.0),
ScipyPolyResampler(up=1, down=1),
# The composer inserts the sum between resampling and LNA noise.
LinearLNANoise(noise_figure_db=5.0),
# RX hardware
LinearADCQuantizer(enob_bits=10),
LeesonRXPhaseNoise(),
TorchSigRXIQImbalance(),
LinearAGC(),
])
rx_cfg = ReceiverConfig(
rx_id="rx0",
center_freq_hz=3.5e9,
bandwidth_hz=20e6,
sample_rate_hz=30.72e6,
)
The pipeline above is supplied at the scene level; ReceiverConfig carries only the per-receiver RF and geometry parameters. See Channels overview for the full pipeline including the pre-sum chain.
See Also¶
Channels overview: semantic channel groups and the sum-point location.
Channel propagation: propagation that produces the per-component inputs to RX capture.
RX hardware: ADC and RX hardware effects that follow RX capture.
Reference /
rfgen.channels: full ABC contracts for BaseRXMixer, BaseIFFilter, BaseResampler, and BaseLNANoise.Reference / RF frontend models: full receiver-chain derivations (Friis cascade, noise figure, kT0B identity).
Reference / Noise floor table: kT0B values per bandwidth and noise figure used to validate LNA noise.
Background / Design Decisions § Channel pipeline for the rationale behind the post-sum chain and why thermal noise enters at LNA noise inside
Group.RX_CAPTURErather than as a standalone AWGN stage.
References¶
The RX mixer, IF filter, and resampler use frequency-translation, FIR channel-selection, and polyphase-resampling identities; LNA noise is the Johnson-Nyquist thermal-noise floor scaled by receiver noise figure. The math is collected in Reference / RF frontend models and Reference / Noise floor table; the citations below duplicate the inline sources.
GNU Radio. Frequency Xlating FIR Filter. https://wiki.gnuradio.org/index.php/Frequency_Xlating_FIR_Filter (frequency translation plus FIR channel selection)
SciPy.
scipy.signal.resample_poly. https://docs.scipy.org/doc/scipy/reference/generated/scipy.signal.resample_poly.html (polyphase FIR upsample, filter, downsample behavior)Crochiere, R. E. and Rabiner, L. R. Multirate Digital Signal Processing, Prentice Hall, 1983. (polyphase rational resampler)
Vaidyanathan, P. P. Multirate Systems and Filter Banks, Prentice Hall, 1993. (polyphase FIR and filter-bank design)
Friis, H. T. Noise Figures of Radio Receivers, Proc. IRE, 1944. https://doi.org/10.1109/JRPROC.1944.232049 (LNA noise figure, cascade noise factor)
Nyquist, H. Thermal Agitation of Electric Charge in Conductors, Phys. Rev., 1928. https://doi.org/10.1103/PhysRev.32.110 (kT0B Johnson-Nyquist floor)
IEEE Std 145-2013 IEEE Standard for Definitions of Terms for Antennas. https://doi.org/10.1109/IEEESTD.2014.6758443 (reference temperature \(T_0 = 290\) K)