Your First Scene¶
Build a multi-emitter wideband scene end to end: pick emitters, pick a channel, set scene density, write joint labels, optionally annotate.
Warning
Pre-implementation. Commands and configs below are the target v0.5+ surface.
The scenario¶
Three coexisting emitters in a 100 MHz scene centered near the 2.4 GHz industrial, scientific, and medical (ISM) band:
Wi-Fi 11g orthogonal frequency-division multiplexing (OFDM) 20 MHz burst at 2.452 GHz
Bluetooth Low Energy (BLE) advertising Gaussian frequency-shift keying (GFSK) 1 Mbit/s frame at 2.402 GHz (advertising channel 37)
Barker-13 radar pulse train at 2.485 GHz, 1 ms pulse repetition interval (PRI)
The first emitter is a Wi-Fi burst, the second is a short Bluetooth advertising frame, and the third is a pulsed radar waveform whose pulses repeat every 1 ms.
Channel: tapped-delay-line C (TDL-C), the 3GPP urban non-line-of-sight (NLoS) profile, with 300 ns delay spread and 30 Hz Doppler. Delay spread controls multipath timing, Doppler controls motion-related frequency shift, and the scene has one receiver (RX). The run writes the full label suite plus caption and scene-report annotations.
The config¶
Read the YAML in two passes: first load reusable preset files, then override the few fields this example needs.
The config is composed by Hydra from named pieces under configs/<group>/. The defaults: list loads one published YAML per config group (emitter_zoo, channel, scene, label, annotator, storage), and the trailing _self_ entry tells Hydra to merge this file’s top-level keys after the defaults so they override specific fields. The emitter_zoo: block lower in the file therefore extends the named preset rather than redefining it; only the keys that appear here are overridden, and the rest of the preset stays as published. See Hydra’s defaults list for the full merge semantics.
# my_first_scene.yaml
defaults:
- /emitter_zoo: heterogeneous_24ghz # configs/emitter_zoo/heterogeneous_24ghz.yaml
- /channel: sionna_phy_tdl_c # configs/channel/sionna_phy_tdl_c.yaml
- /scene: dense # configs/scene/dense.yaml
- /label: joint # configs/label/joint.yaml
- /annotator: caption_and_scene_report # configs/annotator/caption_and_scene_report.yaml
- /storage: zarr_local # configs/storage/zarr_local.yaml
- _self_ # apply this file's top-level keys after the defaults
run:
num_samples: 1000
shard_size: 100
seed: 42
storage:
path: ./out/first-scene
scene:
sample_rate_hz: 2.0e8
bandwidth_hz: 1.0e8
center_hz: 2.45e9
duration_s: 0.1
density:
mode: fixed
min_emitters: 3
max_emitters: 3
emitter_zoo: # overrides specific fields of the heterogeneous_24ghz preset above
families:
- family: comms
classes: [wifi.11g.ofdm-20mhz]
weight: 1.0
- family: iot
classes: [ble.gfsk.1m.adv]
weight: 1.0
- family: radar
classes: [pulsed.barker.b13]
weight: 1.0
params:
pri_us: 1000
pulse_width_us: 13
num_pulses: 100
This example captures 0.1 seconds per record at 200 MHz sample rate, keeps 100 MHz of bandwidth centered at 2.45 GHz, and fixes the scene at exactly three emitters.
Selected preset |
Meaning |
|---|---|
|
Emitter-zoo preset with Wi-Fi, Bluetooth, radar, and other 2.4 GHz family options. |
|
Channel preset using Sionna PHY’s TDL-C non-line-of-sight profile. |
|
Scene preset for drawing several emitters in one bandwidth window. |
|
Label preset that writes one coordinated label set across modalities. |
|
Annotator preset that asks for a short caption and a structured scene report. |
|
Storage preset that writes the canonical local Zarr store plus shard mirrors. |
The heterogeneous_24ghz preset is one of the published emitter_zoo config-group YAMLs; its full set of families and classes lives at configs/emitter_zoo/heterogeneous_24ghz.yaml. See the EmitterZooConfig schema for the structure each emitter_zoo YAML follows, and Scenario Presets for the larger top-level presets such as dense_urban_2_4ghz (dense 2.4 GHz urban ISM scene) and contested_ew_lband (electronic-warfare L-band scene). A top-level scenario preset composes an emitter_zoo group together with channel, scene, label, annotator, storage, and orchestration groups in one preset file.
Generate¶
rfgen generate --config-name my_first_scene
Output:
Note
Illustrative. Specific values below (config hash, byte counts, percentile SNRs, audit metrics, sample IDs) show the target output shape, not measured behavior. Numbers will be regenerated from real runs once the v0 implementation lands.
Resolved config (sha256:<digest>):
...
Generating 1000 samples in 10 shards (locally, 8 workers) ...
[████████████████████████] 1000/1000 [<elapsed>]
Cross-modality consistency: <pct> (<count>/1000)
Statistics audit: PASS
density: 3.0 emitters/scene (target: 3.0)
SNR p10/p50/p90: <value> / <value> / <value> dB
delay-spread RMS: <value> ns (target: <target> ns)
Wrote ./out/first-scene/
manifest.json <size>
samples.zarr/ <size> (1000 samples, complex64 IQ + bbox + seg)
shards/ <size> (10 WebDataset tars)
stats.json <size>
Read this output as a quick health report. Signal-to-noise ratio (SNR) percentiles summarize received signal quality, IQ means complex in-phase / quadrature samples, bbox means time-frequency bounding boxes, seg means segmentation masks, and WebDataset tars are training shards mirrored from the canonical store.
Inspect¶
rfgen inspect ./out/first-scene sample --random --n 1
{
"sample_id": "f9a3b7c2-...",
"scene": {
"bandwidth_hz": 1.0e8,
"num_emitters": 3,
...
},
"bbox": [
{
"class_name": "comms.wifi.11g.ofdm-20mhz",
"abs": {"start_sample": 1840000, "stop_sample": 2080000,
"low_freq_hz": 2.442e9, "high_freq_hz": 2.462e9},
"yolo": {"cx": 0.098, "cy": 0.56, "w": 0.012, "h": 0.20}
},
{
"class_name": "iot.ble.gfsk.1m.adv",
"abs": {"start_sample": 8400000, "stop_sample": 8476000, ...},
...
},
{
"class_name": "radar.pulsed.barker.b13.pri-1ms",
"abs": {"start_sample": 0, "stop_sample": 20000000, ...},
...
}
],
"text": {
"caption": "Three coexisting emitters in 100 MHz around 2.45 GHz: a Wi-Fi 11g OFDM burst at channel 9, a BLE advertising frame on channel 37, and a Barker-13 radar pulse train at 2.485 GHz with 1 ms PRI.",
"scene_report": "..."
}
}
In the label output, abs gives absolute sample and hertz coordinates. yolo gives normalized center, width, and height coordinates for detector training. Generated annotations may use the domain vocabulary configured by the annotation template, such as OFDM or PRI.
Visualize¶
import matplotlib.pyplot as plt
import numpy as np
from rfgen.storage import open_store
from rfgen.viz import spectrogram, overlay_bboxes
with open_store("./out/first-scene") as store:
sample = store.read_random(seed=0)
# Convert complex IQ samples into a time-frequency image.
spec = spectrogram(sample.iq, n_fft=1024, hop=256)
fig, ax = plt.subplots(figsize=(12, 6))
ax.imshow(spec, aspect="auto", origin="lower", cmap="viridis")
# Overlay ground-truth emitter boxes on the spectrogram.
overlay_bboxes(ax, sample.bboxes, sample.scene)
ax.set_title(sample.text["caption"])
plt.show()
You should see three rectangles annotating the three emitters in the spectrogram, with the caption rendered at the top.
What’s next¶
Generate the full dense_urban_2_4ghz preset (1M samples) on Spark.
How NVIDIA Sionna’s modules (RT, PHY) map to the framework’s layers.
Write your own BaseEmitter for an unsupported waveform.
Add reasoning chains or contrastive pairs to an existing dataset.