rfgen.domains¶
The domain nursery: emitter recipes that encode a standard rather than a mechanism. A module belongs here when it is specific to one domain – communications or radar – and nothing outside that domain has asked for it. The moment a second domain wants a mechanism, that mechanism moves out to the stage package that owns it, which is what keeps this package a nursery rather than a second home for shared code.
The modulation machinery these recipes build on is domain-neutral and lives in
rfgen.waveforms, together with the
BaseEmitter contract every recipe here
subclasses, the pool factory, and the built-in selector inventory that lists
every emitter selector in one table.
Package |
What it ships |
|---|---|
|
Cellular (LTE, 5G NR PUSCH), LoRa, ADS-B, the gr-OOT links (BLE, Wi-Fi, ZigBee), and the five drone links |
|
The deterministic chirp emitter, whose parameters are radar concepts rather than communications ones |
Nothing in this package is imported eagerly by rfgen: a recipe that needs an
optional extra raises BackendUnavailableError
when it is instantiated, never at import time.
rfgen.domains.radar.chirp_emitter¶
ChirpRadarEmitter (from rfgen.domains.radar.chirp_emitter import ChirpRadarEmitter, ChirpRadarParams)
synthesizes a deterministic linear-FM pulse train and is always available;
SciPy is a runtime dependency rather than an extra. It is documented with the
rest of the emitter catalog on the Waveforms page, and its
scientific validation report is
Chirp radar backend.
Do not confuse it with the TorchSig chirp adapter
(rfgen.integrations.torchsig.emitters.torchsig_chirp), which is a randomized
augmentation source rather than a deterministic radar waveform.
rfgen.domains.comms¶
The communications recipes: the LoRa dual backend, the 5G NR PUSCH emitter, and the five drone links. Each subsection below documents one family and names the module to import it from.
LoRa: dual backend¶
The LoRa family ships two backends behind one shared schema. Both accept ("lora",) as their only class label and share LoRaParams for the per-emission parameters; selection happens at scene-config time via the LoRaBackend enum ("gr-lora-sdr" or "lora-phy").
LoRaSdrEmitter is the default, backed by
gr-lora_sdr(GNU Radio OOT; typically installed via conda or a system package manager, not PyPI). Behindrfgen[lora-sdr].LoRaPHYEmitter is the pure-Python fallback, backed by the
loraphylibrary. Behindrfgen[lora-phy].
Both subclass an internal _LoRaBase ABC that fixes family = EmitterFamily.IOT and supported_classes = ("lora",); per-emission knobs (spreading_factor, bandwidth_hz, coding_rate, payload_bytes) live in the shared LoRaParams model.
Because the public class label is the single value "lora", the scene composer
treats LoRa as one family with backend-selectable internals.
NRPuschEmitter¶
Import with from rfgen.domains.comms.cellular import NRPuschEmitter, NRPuschParams.
Wraps sionna.phy.nr.PUSCHTransmitter/PUSCHConfig directly: frequency-domain
resource mapping, DMRS (pilot) insertion, transport-block encoding (LDPC +
rate matching), scrambling, and OFDM modulation are all performed by
PUSCHTransmitter. This is 3GPP-conformant by delegation: rfgen does not
re-verify or re-implement 3GPP conformance itself, but inherits it from
Sionna’s independent TS 38.211/TS 38.212 implementation. See the
Signal Atlas comms-v1 Phase-2 physics validation
for the evidence (a real DMRS at OFDM symbol index 2, a real sized transport
block).
NRPuschParams:
Field |
Type |
Default |
Constraint |
|---|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
When set, |
|
|
|
|
Not every (n_rb, mcs) pair is a constructible NR transport block: Sionna’s
LDPC base-graph selection (3GPP TS38212) rejects some combinations near the
BG1/BG2 code-rate crossover. NRPuschEmitter.generate() catches Sionna’s
ValueError in both cases and re-raises EmitterError
with the offending parameters attached; when occupied_bandwidth_hz is set,
a bounded ±8-RB search finds the nearest constructible neighbor before
raising. signal.metadata.extras records nr_pusch_n_rb, nr_pusch_mcs,
nr_pusch_subcarrier_spacing_hz, nr_pusch_tb_size_bits (the real,
achieved transport-block size in bits), nr_pusch_num_slots_generated,
nr_pusch_native_sample_rate_hz, nr_pusch_channel_n_rb,
nr_pusch_allocation_fraction, nr_pusch_allocated_n_rb, and, when
occupied_bandwidth_hz is set, nr_pusch_occupied_bandwidth_bounds_hz.
Requested duration versus slot duration. generate() transmits as many
consecutive Sionna slots as needed to cover duration_s, then resamples and
trims or zero-pads the concatenated waveform to exactly
round(sample_rate * duration_s) samples. When a caller’s fixed generation
window is shorter than one full NR slot (which lasts 1 / (2 ** numerology)
milliseconds; longer at 15 kHz, shorter at 240 kHz), the returned record can
end mid-slot, potentially cutting off part or all of the single-symbol DMRS
this section describes as real and standards-conformant. This is a
window-length-versus-slot-duration interaction of the caller’s own
generation configuration, not a property of NRPuschEmitter itself; request
a duration_s covering at least one full slot
(resource_grid.ofdm_symbol_duration * resource_grid.num_ofdm_symbols,
both read from the constructed PUSCHTransmitter.resource_grid) when the
downstream use of a record depends on an intact DMRS.
Drone signal emitters¶
The drone EmitterFamily members. Each is synthesized clean-room from a
published specification (never from copyleft reference code) and is pure
NumPy/torch, so no optional extra is required. They were added to support the
use_cases/signal-atlas/cuas-v1 counter-UAS dataset, but are core mechanism
(no dataset-specific values) per the Core/Defaults/Use-case placement rule;
their measured-vs-published fidelity evidence, real-capture comparison, and
scope-bounded limitations live in the cuas-v1 emitter reports and retained
pre-graph-migration composition report
(use_cases/signal-atlas/cuas-v1/docs/report/cuas-v1-validation.pdf and
use_cases/signal-atlas/cuas-v1/docs/validation/), not duplicated here. The
composition report is prominently marked historical because its former
thermal-noise graph does not validate the current aggregate-AWGN track.
DroneIdEmitter (from rfgen.domains.comms.drone_id import DroneIdEmitter, DroneIdParams)
synthesizes one DJI DroneID broadcast frame: an LTE-derived OFDM grid (15 kHz
subcarrier spacing, 1024-point FFT, 601 occupied subcarriers with a nulled DC),
two Zadoff-Chu synchronization symbols (roots 600 and 147), and QPSK data
subcarriers carrying a representative (non-decodable) payload. frame_variant
selects the 9-symbol or 8-symbol frame layout.
FhssRcLinkEmitter (from rfgen.domains.comms.drone_fhss_rc import FhssRcLinkEmitter, FhssRcLinkParams)
synthesizes a frequency-hopping RC control-link burst sequence from
register-verified presets (protocol: frsky_d8, frsky_d16, dsmx,
afhds2a), each self-mixed onto its hop channel within the requested
bandwidth.
AnalogFpvVideoEmitter (from rfgen.domains.comms.drone_fpv_video import AnalogFpvVideoEmitter, AnalogFpvVideoParams)
frequency-modulates a synthetic composite-video baseband (video_standard:
ntsc or pal) with the ITU-R BT.470-7 color subcarrier and line rate.
RemoteIdEmitter (from rfgen.domains.comms.drone_remote_id import RemoteIdEmitter, RemoteIdParams)
synthesizes an ASTM F3411 Remote ID broadcast over its Bluetooth Low Energy
advertising transport only (GFSK bursts on the three advertising channels);
Wi-Fi/NaN Remote ID is not modeled.
OcuSyncSurrogateEmitter (from rfgen.domains.comms.drone_ocusync_surrogate import OcuSyncSurrogateEmitter, OcuSyncSurrogateParams)
synthesizes a duty-cycled wideband OFDM burst (bandwidth_mode_hz: 10 or
20 MHz) as an explicitly non-protocol-faithful surrogate for DJI’s
proprietary, encrypted OcuSync link; metadata.extras records
protocol_faithful: False.