Emitters¶
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 emitter backends have been scientifically validated against published references. See the per-backend reports:
TorchSig comms backend: validated with documented limitations.
TorchSig FSK backend: validated.
TorchSig OFDM backend: validated with documented limitations.
TorchSig AM backend: validated with documented limitations.
TorchSig FM backend: validated with documented limitations.
TorchSig chirp backend: validated with documented limitations.
TorchSig tone backend: validated with documented limitations.
Chirp radar backend: 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.
An emitter creates the clean signal a transmitter would have produced before the scene places it in time, frequency, and space. The signal is complex baseband in-phase/quadrature (IQ): samples are centered at zero hertz in the emitter’s own frame, while carrier placement stays in metadata for later scene and channel stages.
Everything downstream should be able to consume that output without knowing whether the source was LoRa (a low-power chirp-spread-spectrum radio family), frequency-modulated continuous-wave (FMCW) radar, Long-Term Evolution (LTE) cellular, a TorchSig benchmark modulation, or captured playback from recorded IQ.
rfgen delegates waveform synthesis to mature libraries instead of inventing
radio-frequency (RF) generators. The per-family backend choices are grounded in
Library Landscape:
TorchSig signals and Sig53 for RF machine-learning benchmark modulations,
Sionna physical-layer (PHY) primitives and 3rd Generation Partnership Project
(3GPP) TS 38.211 for 5G New Radio (NR), srsRAN 4G for LTE, gr-lora_sdr for
LoRa, RadarSimPy / SciPy chirp / Richards for radar, and SigMF for captured
IQ playback.
The emitter contract is intentionally small: implement the waveform source, publish the supported labels and parameter schema, and return a Signal with SignalMetadata. Scenes, channels, labels, and storage handle placement, propagation, supervision, and persistence.
Minimal worked example¶
import torch
from rfgen.emitters import LoRaEmitter
emitter = LoRaEmitter()
signal = emitter.generate(
# LoRa chirp spread spectrum, spreading factor 7, 125 kHz bandwidth,
# coding rate 4/5. See Signal Catalog for the label taxonomy.
class_label="iot.lora.css.sf7.bw125.cr-4-5",
sample_rate=1_000_000,
duration_s=0.020,
f_offset_hz=0.0,
rng=torch.Generator().manual_seed(0),
)
assert signal.metadata.family == "lora"
assert signal.metadata.bandwidth_hz == 125_000.0
assert signal.metadata.snr_db == float("inf") # clean baseband; channel adds noise
For the browsable list of supported families with parameter ranges and example configs, see Signal Catalog.
Adjacent Concepts¶
Two emitter topics are important enough to have their own pages. Keeping them separate prevents this page from becoming a dependency catalog or a validation report.
Sub-concept |
What it covers |
See |
|---|---|---|
Library landscape |
Which mature tool or implementation strategy backs each family, and where optional dependencies are isolated. |
|
Coverage |
What the catalog covers in practice, how coverage is measured, and where validation data is required. |
A reader writing a new emitter or scoping a sim2real study will want both. A reader trying to understand the emitter contract (this page) does not.
What an emitter does¶
An emitter (BaseEmitter subclass) returns a Signal wrapping the clean IQ and its SignalMetadata.
The metadata record stamps three things:
Identity:
family,class_name,class_taxonomy,generator_name, and (when supplied)device_id. Tells downstream what was emitted, which implementation produced it, and which virtual TX device it belongs to.Time-frequency extent:
sample_rate_hz,bandwidth_hz,duration_samples. Tells downstream how the IQ sits on the time and frequency axes in the emitter’s own frame.Clean-noise state:
snr_db = +inf. Emitters never add propagation, receiver, or thermal noise; the channel layer is what makes SNR finite.
Source: the proposed BaseEmitter contract and Reference / Contract Tests require emitter outputs to be baseband, metadata-bearing, deterministic, and clean; Concepts / Channels owns propagation, RX capture, RX hardware, and receiver noise.
Channels, the scene composer, and the labeler fill in the rest of the record: scene-relative placement, channel realizations, receiver outputs, and derived annotations. Full field-by-field reference belongs on the SignalMetadata API page.
The emitter also honors the RNG contract: random payloads, jitter, burst timing, and protocol choices are drawn from the supplied generator. Re-running the same emitter with the same resolved configuration, seed, dependency versions, and device determinism settings should reproduce the same clean IQ. Full normative contract on the BaseEmitter API page.
What an emitter does not do¶
Center-frequency placement in a wideband scene → handled by the scene composer.
Channel propagation (reflections from multiple paths, signal weakening with distance, motion-related Doppler shifts, receive (RX) capture, and RX hardware effects including low-noise amplifier (LNA) thermal noise) → handled by channels.
Time placement in a scene → scene composer.
Label generation → the label layer reads
component_signalsafter the scene composer assembles the scene.
The emitter is a pure waveform source. Everything that depends on receiver geometry, propagation, or downstream supervision lives elsewhere.
Two cross-layer subtleties matter:
Emitters own waveform-intrinsic frequency behavior. Frequency-sweeping families such as LoRa chirp spread spectrum (CSS) and FMCW radar must not be reduced to “generate at direct current (DC), then blindly frequency-shift later” if that would break the waveform structure. The vocabulary for emitter-relative and scene-relative frequency lives in Coordinate Systems.
Emitters can carry a
device_id, which identifies transmitter hardware. The impairment math runs in the channel layer, but the identity travels with the emitted signal so scenes, channels, and labels can agree on the same virtual radio. See TX Impairments.
Source: gr-lora_sdr is the planned LoRa reference backend for chirp spread spectrum waveforms; SciPy documents frequency-swept chirps in scipy.signal.chirp, and Richards, Fundamentals of Radar Signal Processing, 2nd ed., is the cited radar waveform reference in Library Landscape. The RF-frame handoff is defined in Coordinate Systems § Frame Transitions.
Adding a custom emitter¶
This section is a contract sketch for readers who need to recognize the shape of an emitter plugin. Step-by-step implementation instructions belong in How-to / Add a custom emitter.
Subclass BaseEmitter, implement the waveform generation and schema methods, and register the family:
from rfgen.emitters.base import BaseEmitter
from rfgen.core.registry import register_emitter
from rfgen.core.types import Signal, SignalMetadata
from rfgen.enums import EmitterFamily
@register_emitter(family=EmitterFamily.COMMS)
class MyRadioEmitter(BaseEmitter):
family = EmitterFamily.COMMS
supported_classes = ("mode_a", "mode_b")
def generate(self, *, class_label, sample_rate, duration_s, f_offset_hz,
rng, device_id=None, params=None):
# synthesize IQ at baseband, apply f_offset_hz internally if needed
...
return Signal(iq=iq, metadata=SignalMetadata(...))
def schema(self):
return MyRadioParams # Pydantic validation model for emitter parameters
The contract reference is on the emitters API page, and LoRaEmitter is the canonical worked example.
See Also¶
Library Landscape for which backend powers each family and the license boundaries.
Coverage for the spectrum-coverage map and validation methodology.
Reference /
rfgen.emittersfull API for BaseEmitter, LoRaEmitter, TorchSigCommsEmitter, and the rest of the catalog.Signal Catalog browsable index of supported families with parameter ranges and example configs.
How-to / Add a custom emitter step-by-step for shipping a new family.
Concepts / Scenes how emitters are placed in time and frequency.
Background / Design Decisions § ABC Pluggability for the rationale behind subclass-only extensibility and the registry-driven backend selection that emitter plugins use.
Concepts / Channels propagation, RX-capture, and RX-hardware transformations applied after emission.
Concepts / TX Impairments for how
device_idis reused across layers.Concepts / Labels how supervision is derived from the emitted signals plus the assembled scene.
Why ABC instead of duck-typed callables
The base class gives every emitter the same lifecycle: validate parameters, generate clean IQ, check metadata invariants, and expose a schema. That keeps family-specific synthesis local while scenes, channels, labels, and storage depend on one stable interface.
Why stateless?
Workers can instantiate emitters freely per shard, sample, or test without
reset logic. State that should persist across samples, such as per-device
fingerprint parameters, is keyed by device_id outside the emitter instance.
What we deliberately do not model
Receiver-side hardware effects, including low-noise amplifier (LNA) noise and analog-to-digital converter (ADC) quantization; those live in the channel layer, after propagation.
Protocol-stack-level effects (medium access, retransmissions, carrier sensing) are outside scope; we model PHY only.
Power-amplifier modeling beyond Rapp / Saleh: fine for fingerprinting, coarse for power-amp characterization research.
Cellular base-station scheduling: LTE/NR emitters produce single-cell downlink (DL) waveforms; multi-cell coordination is left to scene composition.
Source: RX capture and RX hardware define LNA noise and ADC as channel transformations; TX impairments cites the Rapp and Saleh PA models used by the proposed PA slot; Background / Sionna stack records that Sionna PHY targets NR physical-layer primitives, while heterogeneous multi-emitter scene composition remains an rfgen responsibility.