rfgen.waveforms¶
The domain-neutral half of the emitter catalog: the waveform-generator contract, the pool factory, and the modulation families that are defined by signal structure rather than by a standard. Protocol recipes – cellular, LoRa, ADS-B, the gr-OOT links and the drone links – live under rfgen.domains, and the selector inventory below covers both. Every concrete class subclasses BaseEmitter and produces a baseband SignalMetadata-tagged IQ tensor. TorchSig-backed emitters are optional adapters under rfgen.integrations.torchsig.emitters; they are selected explicitly in EmitterFamilyConfig.selector, rather than imported by the core package.
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.
Signal Atlas comms-v1 Phase-2 RF physics: validates
NRPuschEmitter,ConformantOFDMEmitter, andFECConstellationEmitter(this section), plus the three new Sionna-backed propagation channels, with one fix applied and 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.
Module summary¶
import torch
from rfgen.domains.radar.chirp_emitter import ChirpRadarEmitter, ChirpRadarParams
emitter = ChirpRadarEmitter() # always available (scipy is a runtime dep)
signal = emitter.generate(
class_label="lfm_chirp",
sample_rate=10_000_000,
duration_s=0.001,
f_offset_hz=0.0,
rng=torch.Generator().manual_seed(0),
# `bandwidth_hz` defaults to 10 MHz, which is this call's whole sample
# rate; the emitter requires it strictly below Nyquist, so the default
# cannot be used at this rate and the parameters are passed explicitly.
params=ChirpRadarParams(bandwidth_hz=2_000_000),
)
Every emitter has the same surface (the generate keyword-only signature, the family and supported_classes ClassVars, schema() returning a Pydantic model). What differs is the synthesis math, the parameter schema, and the dependency tier.
Choosing a record length for shaped waveforms¶
When generating a shaped digital waveform, request at least 64 IQ samples so
the record contains more than filter startup and the reported occupied-bandwidth
interval is useful. A one-sample record intentionally reports no interval;
records from 2 through 63 samples still return the standard numerical estimate,
but it is too low-resolution for waveform or occupancy analysis. Their metadata
therefore retains that numerical occupied-bandwidth estimate and additionally sets
occupied_interval_analysis_status="short_record" and
occupied_interval_minimum_recommended_samples=64.
For the target-constellation, APSK, and generic OQPSK emitters, choose
bandwidth_hz >= sample_rate_hz / max(N, 64), where N is the rounded
requested record length. This keeps the resampling ratio bounded while
preserving the explicit one-sample occupancy outcome. These are
generation-envelope requirements, not claims about a transmitter or protocol
rate.
Discovering the rfgen.emitters entry-point group does NOT force-import Sionna, srsRAN, RadarSimPy, gr-lora_sdr, or any other optional dependency; missing-extra emitters raise BackendUnavailableError only when the class is actually instantiated. (rfgen.emitters is an entry-point group name, not an importable module.)
Class index¶
Class |
Family |
|
Backend / extra |
Notes |
|---|---|---|---|---|
abstract |
abstract |
abc |
ABC; subclass to add a custom emitter |
|
|
|
|
1090 MHz Mode-S; stub ( |
|
|
|
pure NumPy/torch (always available) |
Analog FM FPV video envelope; fully implemented |
|
|
|
GNU Radio OOT; |
BLE; stub |
|
|
|
|
LFM chirp; fully implemented |
|
|
12 |
|
Standards-shaped OFDM; fully implemented, explicitly uncoded (real resource grid and pilot pattern, no transport-block encoding) |
|
|
|
pure NumPy/torch (always available) |
DJI DroneID broadcast frame; fully implemented, clean-room from published specs |
|
|
|
|
FEC-coded QAM; fully implemented (real Sionna encoder per family, TorchSig pulse shaping) |
|
|
|
pure NumPy/torch (always available) |
Frequency-hopping RC control link; fully implemented, register-verified presets |
|
|
|
srsRAN over ZMQ; |
LTE; stub |
|
|
|
|
LoRa fallback backend; stub |
|
|
|
|
Default LoRa backend; stub |
|
|
|
|
5G NR PUSCH; fully implemented (delegates to |
|
|
|
pure NumPy/torch (always available) |
Labeled non-protocol-faithful OcuSync detection surrogate; fully implemented |
|
|
|
SigMF reference reader; |
Gated raw CF32/CF64 capture replay. It is not an accepted-current generator or validation source until a supplied local consumer/schema fixture qualifies the adapter. |
|
|
|
pure NumPy/torch (always available) |
ASTM F3411 Remote ID over BLE advertising; fully implemented, BLE-transport only |
|
|
|
TorchSig signal builders |
|
Optional adapters; import from |
|
|
GNU Radio OOT; |
802.11g/n; stub |
|
|
|
GNU Radio OOT; |
802.15.4 OQPSK; stub |
Each emitter ships a matching *Params Pydantic v2 model (e.g. ChirpRadarParams, LoRaParams, LTEParams) returned from schema(). Import it from the emitter’s own module — rfgen.domains.radar.chirp_emitter, rfgen.domains.comms.lora, and so on, as each class section below states. There is no rfgen.emitters module to import from.
Built-in selector inventory¶
This is the complete current set of 26 built-in rfgen.emitters entry-point
selectors, discovered through
importlib.metadata.entry_points,
and their exact supported_classes strings. It is the reference for checking
whether an exact native class exists; a listed stub declares a class contract
but raises its documented backend or implementation error when used.
Selector |
Emitter |
Exact |
|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
zigbee_oqpsk is a protocol-specific IEEE 802.15.4 Zigbee waveform class. It
does not provide the standalone, protocol-neutral exact class oqpsk. The
generic oqpsk source is instead a bounded augmentation primitive.
For the conceptual map of supported families and cataloged availability boundaries (GSM, captured playback, NR downlink, and extended radar waveforms), see Signal Catalog. For synthesis algorithms, see Reference / Algorithms.
Waveform sources for bounded augmentation¶
Use these optional sources from the Emitter concept when an augmentation experiment needs a specific clean-baseband geometry or modulation primitive. They feed the ordinary emitter-to-scene-to-channel pipeline; they do not define a corpus projection and they do not replay a capture.
All four implement the keyword-only BaseEmitter.generate() signature:
generate(*, class_label, sample_rate, duration_s, f_offset_hz, rng, device_id=None, params=None) -> Signal.
sample_rate is finite and positive in Hz, duration_s must round to at least
one sample, and f_offset_hz must be finite and fit the source’s complex
baseband budget. The output is float32 IQ shaped
(2, round(sample_rate * duration_s)), with clean snr_db=+inf and its
measured 99%-power occupied interval in metadata. The requested
bandwidth_hz is not reported as the measured interval. Invalid labels,
coordinates, record lengths, parameter models, or resampling requests raise
EmitterError; backend construction fails with an EmitterError whose context
identifies the missing torchsig extra. Install rfgen[torchsig] before
instantiating any source in this section.
All shaped sources accept short records, but at least 64 samples is the
practical minimum for waveform or occupancy analysis. A one-sample record has
no occupied interval (occupied_interval_reason="insufficient_samples"), and
records of 2–63 samples carry occupied_interval_analysis_status="short_record".
For the target-constellation, APSK, and OQPSK sources, use
bandwidth_hz >= sample_rate / max(N, 64), where N is the rounded output
length.
TorchSigTargetConstellationEmitter¶
Import the canonical optional adapter with
from rfgen.integrations.torchsig.emitters.torchsig_target_constellations import TorchSigTargetConstellationEmitter, TorchSigTargetConstellationParams.
rfgen.integrations.torchsig.emitters.torchsig_target_constellations is a convenience facade for the
same two names. The source accepts only 32psk and 128qam_cross; those are
TorchSig geometry identifiers.
TorchSigTargetConstellationParams is the TorchSigCommsParams model:
bandwidth_hz: float = 200000.0 (> 0), pulse_shape_name: str = "srrc", and
alpha_rolloff: float = 0.35 (strictly between 0 and 1). It delegates
constellation synthesis, pulse shaping, and resampling to TorchSig, preserves
the common output contract above, and uses the supplied torch.Generator for
repeatable generation. It establishes only the listed finite geometries; it
does not establish a protocol bit order, pulse shape, physical sample rate, or
corpus equivalence.
APSKEmitter¶
Import with from rfgen.waveforms.apsk import APSKEmitter, APSKParams. Its
accepted labels are 16apsk, 32apsk, 64apsk, and 128apsk.
APSKParams has bandwidth_hz: float = 200000.0 (> 0) and
alpha_rolloff: float = 0.35 (strictly between 0 and 1); extra fields are
rejected. The emitter uses fixed selected DVB-S2/S2X ring geometry, then
TorchSig pulse shaping and resampling. Metadata includes
target_geometry="ETSI_DVB_S2_S2X" in addition to the common fields. It is
not a DVB FECFRAME generator, complete MODCOD configuration, or receiver test
vector.
OQPSKEmitter¶
Import with from rfgen.waveforms.oqpsk import OQPSKEmitter, OQPSKParams.
It accepts only the lowercase API label oqpsk.
OQPSKParams has bandwidth_hz: float = 200000.0 (> 0) and rejects extra
fields. The emitter generates generic half-sine-shaped OQPSK, delays Q by half
of its four-sample native symbol, normalizes output power, then resamples with
TorchSig. Its metadata records the native samples per symbol, Q delay,
half-sine pulse shape, and power-normalization scale. This is a modulation
primitive, not IEEE 802.15.4 packet or DSSS synthesis.
ConformantOFDMEmitter¶
Import with from rfgen.waveforms.ofdm_conformant import ConformantOFDMEmitter, ConformantOFDMParams.
Builds a genuine OFDM resource grid via sionna.phy.ofdm.ResourceGrid (14
OFDM symbols, 15 kHz subcarrier spacing, 3GPP numerology 0), inserts a real
orthogonal pilot pattern through sionna.phy.ofdm.KroneckerPilotPattern, and
maps uncoded bits to QPSK via sionna.phy.mapping.Mapper. It is distinct
from TorchSigOFDMEmitter’s waveform-envelope OFDM (no pilots, no resource
grid, no guard carriers): its "nr-grid-<N>rb" class labels have zero string
overlap with TorchSigOFDMEmitter’s "ofdm-<subcarrier_count>" labels.
Conformance is scoped, not full. This emitter is standards-shaped, not
fully 3GPP-conformant: the resource grid and pilot pattern sit at correct
3GPP numerology, but data is explicitly uncoded (no transport-block
encoding, scrambling, or rate matching), and its full-band Kronecker pilot
pattern is standards-plausible rather than a specific named 3GPP DMRS comb
pattern. See the
Phase-2 physics validation
for the evidence. signal.metadata.extras carries no code-rate or
transport-block-size key, confirming the uncoded claim structurally, not
only in prose.
class_label selects a resource-block allocation, encoded as
"nr-grid-<N>rb" for N in {1, 2, 3, 4, 5, 6, 8, 10, 12, 16, 20, 25} (one
resource block is 12 subcarriers, 3GPP TS38211 section 4.4.4.1).
ConformantOFDMParams:
Field |
Type |
Default |
Constraint |
|---|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
When set, |
signal.metadata.extras records ofdm_conformant_n_rb,
ofdm_conformant_fft_size, ofdm_conformant_cyclic_prefix_length,
ofdm_conformant_pilot_spacing_symbols, ofdm_conformant_num_slots_generated,
and ofdm_conformant_class_label_n_rb. Sionna construction failures (an
invalid fft_size/cyclic_prefix_length/pilot_spacing_symbols
combination) raise EmitterError.
FECConstellationEmitter¶
Import with from rfgen.waveforms.fec_constellation import FECConstellationEmitter, FECConstellationParams, FECFamily.
A single-carrier, pulse-shaped, FEC-coded bit stream: no resource grid or
pilots (unlike ConformantOFDMEmitter). FECFamily names the four
supported code families, all genuinely encoded by a real Sionna encoder:
ldpc (sionna.phy.fec.ldpc.LDPC5GEncoder), polar
(sionna.phy.fec.polar.Polar5GEncoder), turbo
(sionna.phy.fec.turbo.TurboEncoder), and convolutional
(sionna.phy.fec.conv.ConvEncoder). Coded bits are mapped to QAM with
sionna.phy.mapping.Mapper, then pulse-shaped and resampled with the same
TorchSig SRRC taps and polyphase resampler
APSKEmitter uses (rfgen[torchsig]
required in addition to rfgen[sionna]). See the
Phase-2 physics validation
for a real encode-map-AWGN-demap-decode round trip confirming genuine bit
recovery for all four families.
FECConstellationParams:
Field |
Type |
Default |
Constraint |
|---|---|---|---|
|
|
|
When set, must equal |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
A requested code_rate below a family’s real achievable floor is silently
floor-clamped, never rejected: generate() reports the ACHIEVED rate
(computed from the real constructed encoder’s k / n) under
extras["fec_constellation_code_rate"], keeping the caller’s original
request separately under extras["fec_constellation_requested_code_rate"]
for traceability. extras also carries fec_constellation_family,
fec_constellation_order, fec_constellation_k, fec_constellation_n,
fec_constellation_num_blocks_generated, and (for Turbo/convolutional)
fec_constellation_design_rate.
Amendment-4 bandwidth sizing: resource_blocks_for_bandwidth¶
NRPuschParams.occupied_bandwidth_hz and
ConformantOFDMParams.occupied_bandwidth_hz are both implemented on top of
one shared, pure-arithmetic helper in rfgen.waveforms._resource_grid (no
backend calls; 3GPP TS38211 section 4.4.4.1’s “one resource block is 12
subcarriers” is the only fact it encodes):
def resource_blocks_for_bandwidth(
occupied_bandwidth_hz: float,
*,
subcarrier_spacing_hz: float,
n_rb_min: int,
n_rb_max: int,
) -> int: ...
Rounds occupied_bandwidth_hz / (12 * subcarrier_spacing_hz) to the nearest
whole resource-block count, clamped to [n_rb_min, n_rb_max]. Raises
ValueError if occupied_bandwidth_hz is non-positive, non-finite, or
outside [n_rb_min, n_rb_max] * 12 * subcarrier_spacing_hz (each caller
re-raises this as EmitterError). Each emitter exposes its own physical
bounds through a matching helper: nr_pusch_occupied_bandwidth_bounds_hz(subcarrier_spacing_hz)
and conformant_ofdm_occupied_bandwidth_bounds_hz(fft_size=4096, *, cyclic_prefix_length=0),
both returning (min_hz, max_hz). These are the same bounds the
signal-atlas-comms-v1 use case’s own sampler-level bandwidth constraint
reads to exclude a below-floor bandwidth-ladder rung rather than let an
emitter silently realize an oversized channel; see
Amendment-4 bandwidth-to-resource-block mapping is physically sound
for the full evidence.
class rfgen.waveforms.base.BaseEmitter¶
Produces IQ for one emitter on a shared time/frequency grid. Stateless across calls; all randomness comes from the supplied rng.
from abc import ABC, abstractmethod
from typing import ClassVar
import torch
from pydantic import BaseModel
class BaseEmitter(ABC):
"""One emitter family. Implementations are stateless; call producing IQ."""
family: ClassVar[EmitterFamily]
supported_classes: ClassVar[tuple[str, ...]]
@abstractmethod
def generate(
self,
*,
class_label: str,
sample_rate: float,
duration_s: float,
f_offset_hz: float,
rng: torch.Generator,
device_id: str | None = None,
params: BaseModel | None = None,
) -> Signal: ...
@abstractmethod
def schema(self) -> type[BaseModel]: ...
Contract¶
Output IQ shape MUST be
(2, int(round(sample_rate * duration_s))).Output IQ MUST be at baseband. A direct caller may supply
f_offset_hzfor an emitter-specific native/provisional offset, subject to that emitter’s contract. The scene composer instead invokes every emitter withf_offset_hz=0.0, applies its own scene-relative placement shift after TX impairments and resampling, and stamps the final absolute carrier on the placed component. Intrinsic sweeps such as LoRa CSS and FMCW retain their slope under that whole-waveform placement shift.Returned
Signal.metadataMUST be self-consistent:start_samplewithin[0, int(sample_rate * duration_s)), frequency-extent fields within[-sample_rate/2, +sample_rate/2].Implementations MUST consume randomness only from
rngfor determinism under shard re-runs.paramsis a backend-specific Pydantic model (e.g.ChirpRadarParams); callers validate it against the emitter’sschema()before calling.device_id, when set, is used by the fingerprint module to pick a deterministic CFO/IQ-imb/phase-noise profile per virtual device.
Class attributes¶
Attribute |
Type |
Description |
|---|---|---|
|
|
Top-level family tag, copied into every emitted |
|
|
Whitelist of |
BaseEmitter.__init_subclass__ validates concrete subclasses at import time:
they must declare an EmitterFamily family and a non-empty tuple of non-empty
string supported_classes. The emitter-pool factory additionally verifies that
the configured selector resolves to a class, belongs to the configured family,
and supports every requested class label before generation starts.
Method: generate¶
Abstract method on BaseEmitter. Produces one emitter’s IQ plus its ground-truth metadata. See the full normative contract above.
Method: schema¶
Abstract method on BaseEmitter. Returns the Pydantic v2 model describing valid params for this emitter, used by the config validator and programmatic consumers.
Why stateless?
Local runs may instantiate emitters repeatedly; statelessness avoids reset
coupling. State that should persist across emitters (per-device fingerprint
parameters) lives in rfgen.calibration.fingerprint.DeviceRegistry, keyed by
device_id.
Why does BaseEmitter.generate() still accept f_offset_hz?
The direct-emitter API supports native/provisional offsets where an emitter’s own contract needs one. That does not make the emitter the owner of final scene placement: the shipped scene composer calls it with zero and performs the scene-relative whole-waveform shift itself. Intrinsic sweeps retain their modulation slope under this shift; the composer then records the final absolute carrier on the placed component.
Class-reference anchors¶
The catalog rows above each follow the same template as ChirpRadarEmitter (the fully implemented reference example). Emitter availability and any backend limitations are documented in each class section; TorchSig adapters remain optional and are selected explicitly.
The anchor labels below give every shipped class a stable cross-reference target so concept pages, glossary entries, and how-to guides can use {ref} links per the STYLE.md code-span linking rule.
Per-protocol algorithm references:
PlaybackSigMFEmitter: Emitter / Capture Replay. This adapter remains gated, not accepted-current: a supplied local consumer/schema fixture must qualify it before it is used as a data source or validation input. Its
PlaybackSigMFParams.source_uriis supplied at call time; the capture must includecore:datatype,core:sample_rate,core:license,rfgen:collection_authority, and a commoncore:frequencyon every capture segment. The replay records the source-native capture SHA-256, source URI, declared licence, declared collection authority, native sample rate, frequency, and shared occupied-bandwidth result inSignalMetadata.extras; CF64 samples are canonically converted to rfgen float32 IQ after hashing. RFGen validates the specified metadata and technical constraints, but the caller or external package must assess licence, collection authority, and intended use.TorchSig*Emitterfamily: TorchSig v2.1.x signal-builder docs upstream; no per-protocol page because the math lives upstream.DroneIdEmitter, FhssRcLinkEmitter, AnalogFpvVideoEmitter, RemoteIdEmitter, OcuSyncSurrogateEmitter: see the Drone signal emitters section above; per-emitter fidelity evidence is in the
use_cases/signal-atlas/cuas-v1technical-validation report, not a core algorithms page.
Compatibility anchors¶
The anchors below preserve inbound links for names that are not exported classes. The class index states each supported replacement or availability boundary.
Waveform evidence primitive¶
rfgen.evidence.waveform.estimate_occupied_bandwidth is the shared
measurement used by raw capture replay and later waveform owners. It accepts
complex (N,) samples or float IQ shaped (2, N) and returns the narrowest
99%-power interval measured with scipy.signal.welch: Hann window,
nperseg=min(4096,N), 50% overlap, constant detrending, density scaling, and
two-sided frequencies. The returned OccupiedBandwidth contains low_hz,
high_hz, method, and a one-bin confidence_tolerance_hz; for N < 2 it
returns None, which capture replay records as
occupied_interval_reason="insufficient_samples". The companion
measure_occupied_bandwidth exposes this as an explicit
OccupiedBandwidthMeasurement, so any waveform owner can emit either the
interval or a null/reason pair. Its defined null reasons are
insufficient_samples, zero_power, dc_removed_by_policy (constant
detrending removed a nonzero DC-only record), numerical_overflow (the
finite-input PSD calculation overflowed), and crosses_nyquist.
seed_1337_waveform_fixture is the pinned
(2, 4096) float32 fixture; the contract test verifies its C-order IQ-byte
SHA-256 before validating estimator behavior.
rfgen.evidence.waveform API¶
def estimate_occupied_bandwidth(
iq: torch.Tensor | np.ndarray, *, sample_rate_hz: float
) -> OccupiedBandwidth | None: ...
def measure_occupied_bandwidth(
iq: torch.Tensor | np.ndarray, *, sample_rate_hz: float
) -> OccupiedBandwidthMeasurement: ...
Both functions accept complex samples shaped (N,) or real I/Q samples shaped
(2, N). sample_rate_hz is a finite positive value in Hz. The convenience
function returns an interval or None; use measure_occupied_bandwidth when
the caller must retain why no linear interval is representable.
Type or function |
Primary behavior |
|---|---|
|
Immutable measured interval in Hz relative to baseband; |
|
Immutable interval-or-reason result. Exactly one field is set; |
|
Returns the interval only, or |
|
Returns the complete outcome and one of |
|
Returns the pinned |
|
Returns the SHA-256 of C-order float32 |
estimate_occupied_bandwidth and measure_occupied_bandwidth raise
ValueError for a non-positive/non-finite sample rate, non-numeric I/Q, or
non-finite samples. They do not synthesize a signal or validate a waveform
against a regulatory measurement procedure.
PlaybackSigMFEmitter API¶
class PlaybackSigMFParams(BaseModel):
source_uri: str
class PlaybackSigMFEmitter(BaseEmitter):
def __init__(self, *, source_uri: str | None = None) -> None: ...
def schema(self) -> type[PlaybackSigMFParams]: ...
def generate(
self, *, class_label: str, sample_rate: float, duration_s: float,
f_offset_hz: float, rng: torch.Generator, device_id: str | None = None,
params: PlaybackSigMFParams | BaseModel | Mapping[str, object] | None = None,
) -> Signal: ...
def load_sigmf_capture(source_uri: str) -> SigMFCapture: ...
PlaybackSigMFEmitter replays a complete local cf32_le or cf64_le capture
through the SigMF reference reader. The adapter is gated: do not use it as
an accepted-current generation or validation source until a supplied local
consumer/schema fixture qualifies it. Its source_uri may be supplied to the
constructor or per call through the frozen PlaybackSigMFParams; per-call
parameters take precedence.
generate requires class_label="capture_replay", a positive sample_rate
that exactly matches the capture, and f_offset_hz=0.0. duration_s and rng
exist for the shared emitter interface but do not alter raw replay; output
length is the capture’s native sample count. The returned Signal carries
float32 I/Q, capture provenance, and the shared occupied-bandwidth outcome.
It raises BackendUnavailableError when rfgen[sigmf] is unavailable and
EmitterError for a missing URI, invalid metadata, unsupported samples,
non-stationary capture frequency, non-finite/out-of-range I/Q, or a requested
transform.
load_sigmf_capture returns the immutable SigMFCapture record with I/Q,
sample rate, capture frequency, native-byte SHA-256, source URI, licence, and
collection authority. It has the same reader and metadata error behavior as
the emitter, without constructing a Signal.
# This is a call-shape example, not a qualified capture-validation workflow.
params = PlaybackSigMFParams(source_uri="/captures/example.sigmf-meta")
emitter = PlaybackSigMFEmitter()
signal = emitter.generate(
class_label="capture_replay",
sample_rate=2_000_000.0,
duration_s=0.0,
f_offset_hz=0.0,
rng=torch.Generator().manual_seed(0),
params=params,
)
The URI in the example must name a local capture with the required metadata and sample rate. RFGen does not verify that its declared licence or collection authority permits the intended use; the caller or external package must assess those questions. Because this adapter is gated, the example does not qualify a capture for generation or validation.
The Signal Catalog distinguishes current registered selectors from runnable implementations.