Cellular Emitter Algorithms¶
5G NR, LTE, and GSM waveform synthesis paths.
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.
8. Cellular¶
8.1 5G NR PUSCH via sionna.phy.nr¶
def generate_nr_pusch(*, class_label, sample_rate, duration_s, params, rng):
"""
class_label: "cellular.nr.pusch.bw-{5,10,20,40,100}mhz.scs-{15,30,60}khz"
params:
scs_khz: int
bandwidth_mhz: int
modulation: "QPSK" | "16-QAM" | "64-QAM" | "256-QAM"
num_layers: int
"""
import sionna.phy.nr as nr # lazy import
carrier = nr.CarrierConfig(
n_size_grid=_rb_count(params["bandwidth_mhz"], params["scs_khz"]),
subcarrier_spacing=params["scs_khz"],
)
pusch_config = nr.PUSCHConfig(carrier_config=carrier)
pusch_config.tb.mcs_table = _mcs_table(params["modulation"])
pusch_config.num_layers = params["num_layers"]
transmitter = nr.PUSCHTransmitter(
pusch_config,
return_bits=True,
output_domain="time",
)
iq_native, bits = transmitter(batch_size=_slot_count(duration_s, params["scs_khz"]))
iq_native = torch.from_numpy(iq_native.numpy()).to(torch.complex64)
iq = _resample(iq_native, native_rate=_nr_sample_rate(carrier), target_rate=sample_rate)
return Signal(iq=iq, metadata=SignalMetadata(bandwidth_hz=params["bandwidth_mhz"] * 1e6, ...))
This sketch is intentionally PUSCH-only. PDSCH, SSB, PRACH, CSI-RS, and NR test-model emitters are not part of the blueprint until the implementation pass verifies an upstream transmitter block or selects another mature backend.
8.2 LTE via srsRAN_4G ZMQ¶
srsRAN_4G is AGPL-3.0; not bundled. The user opts in via Hydra config and provides the binary on $PATH.
def generate_lte(*, class_label, sample_rate, duration_s, params, rng):
"""
class_label: "cellular.lte.fdd.bw-{1.4,3,5,10,15,20}mhz"
params:
bandwidth_mhz: float
cell_id: int
pdsch_payload: "random" | bytes
"""
bw_to_rb = {1.4: 6, 3: 15, 5: 25, 10: 50, 15: 75, 20: 100}
n_rb = bw_to_rb[params["bandwidth_mhz"]]
# Spawn srsenb subprocess writing IQ to a ZMQ socket; we read from the socket.
handle = _spawn_srsran(
config_template="lte_dl.conf.j2",
n_prb=n_rb,
cell_id=params["cell_id"],
zmq_tx_port=_pick_free_port(),
seed=int(rng.initial_seed()),
)
iq_native = _read_zmq_for(duration_s + 0.1, handle) # buffer extra
handle.terminate()
iq = _resample(iq_native, native_rate=30.72e6, target_rate=sample_rate)
iq = _trim_or_pad(iq, target_len=int(round(sample_rate * duration_s)))
return Signal(iq=iq, metadata=SignalMetadata(bandwidth_hz=params["bandwidth_mhz"] * 1e6, ...))
Verification. Round-trip a known transport block through srsRAN_4G TX + a separate srsRAN_4G or open-source LTE RX.
8.3 GSM GMSK¶
Pure-NumPy GMSK at 270.833 kbit/s (legacy completeness only).
def generate_gsm(*, class_label, sample_rate, duration_s, params, rng):
"""class_label = "cellular.gsm.gmsk-200khz" """
bit_rate = 270833.0
bt = 0.3 # GSM uses BT = 0.3
bw = 200e3
bits = _gsm_burst_bitstream(rng) # normal burst: 3 tail + 58 data + 26 training + 58 data + 3 tail + 8.25 guard
return _gmsk_modulate(bits, bit_rate, bt, sample_rate, duration_s)
GMSK reuses the BLE GFSK algorithm (§4) with BT = 0.3, h = 0.5.
See Also¶
Emitter Algorithms: overview and cross-family invariants.
Signal Catalog: browsable family list with parameter ranges.
References¶
The 5G NR PUSCH waveform is generated by sionna.phy.nr (Sionna’s standards-grade NR transmitter); the LTE path is generated by srsRAN_4G (open-source LTE stack); the GSM GMSK path follows the public 3GPP specs. The framework does not re-implement any of these waveform chains.
3GPP TS 38.211, NR; Physical channels and modulation (Release 18). 3rd Generation Partnership Project, 2024. (PUSCH subcarrier spacing, n_size_grid, OFDM numerology used by
sionna.phy.nr)3GPP TS 38.212, NR; Multiplexing and channel coding (Release 18). 3GPP, 2024. (Transport block MCS table referenced by
pusch_config.tb.mcs_table)3GPP TS 38.214, NR; Physical layer procedures for data (Release 18). 3GPP, 2024. (PUSCH MCS-to-modulation mapping for QPSK / 16-QAM / 64-QAM / 256-QAM)
3GPP TS 36.211, E-UTRA; Physical channels and modulation (Release 17). 3GPP, 2023. (LTE PRB count vs. channel bandwidth; 30.72 MHz native sample rate at 20 MHz)
3GPP TS 45.004, GSM/EDGE; Modulation. 3GPP, 2020. (GSM GMSK at 270.833 kbit/s, BT = 0.3 Gaussian filter, h = 0.5 modulation index)
3GPP TS 45.002, GSM/EDGE; Multiplexing and multiple access on the radio path. 3GPP, 2020. (Normal burst structure: 3 + 58 + 26 + 58 + 3 + 8.25 guard symbols)
Hoydis, J. et al. Sionna: An Open-Source Library for Next-Generation Physical Layer Research, NVIDIA, 2022. https://nvlabs.github.io/sionna/. (
sionna.phy.nrPUSCHTransmitter API and validation against 3GPP test models)srsRAN Project. srsRAN_4G: Open-source 4G/5G software radio suite. https://github.com/srsran/srsRAN_4G. (AGPL-3.0 LTE stack used for the LTE path)