IQ layout policy

RFGen uses one layout while composing scenes and a separate native layout when it persists a Signal Dataset record.

Layouts by boundary

Boundary

Shape

dtype

axes

Worker-local, one receiver

(2, N)

PyTorch float32

I/Q channel, time

Worker-local, joint receivers

(num_rx, 2, N)

PyTorch float32

receiver, I/Q channel, time

Native record, per receiver field

(N,)

NumPy complex64

time

The projection that produced a capture owns the conversion from paired real-valued I/Q channels to complex native fields. A record ID covers the resulting field bytes and semantic axes.

Receiver projection

One sample publishes one record, whatever the receiver count. There is no per-receiver fan-out and no configuration knob that selects one. Each receiver is a named subtree of that record, so a two-receiver scene stores

projections/<projection_id>/receivers/rx0/iq
projections/<projection_id>/receivers/rx1/iq

each a complex64 array of shape (N,). A consumer that wants one training example per receiver selects the subtree at read time.

Segmentation is stored once per record and gains a leading receiver axis when the scene has more than one receiver:

Case

Persisted dtype and shape

Single receiver, single-label

int16 (F, T)

Single receiver, multi-label

uint8 (C, F, T)

Multiple receivers, single-label

int16 (num_rx, F, T)

Multiple receivers, multi-label

uint8 (num_rx, C, F, T)

Bounding boxes are declared once per record, in the shared receiver-baseband frame. A scene whose receivers do not share a center frequency is refused with a LabelError naming “heterogeneous receiver center frequencies”, so a published record always has one unambiguous receiver frame.

SigMF calibration input

SigMF is a calibration capture input rather than a generation store. The calibration reader converts capture samples to the worker-local paired-I/Q representation before comparison.

Dataset sizing

For an uncompressed IQ field, approximate payload bytes as:

bytes = records × receivers_per_record × samples × 8

complex64 occupies eight bytes per sample. Add segmentation, other fields, metadata, and container overhead separately. Compression ratios depend on the signal and store implementation; do not use a fixed ratio for capacity planning.