Scientific validation: emitters/torchsig_fm¶
Verdict. Validated with documented limitations.
1. The component¶
TorchSigFMEmitter generates a clean complex-baseband waveform for analog frequency modulation (FM: a modulation scheme where information is encoded in the instantaneous frequency of a carrier, not its amplitude). The instantaneous frequency wanders around zero according to a band-limited Gaussian noise message; the output is exp(j·φ(t)), a unit-envelope complex tone (IQ signal: in-phase and quadrature components stacked as a (2, N) tensor).
Two class labels are supported: nbfm (NBFM: narrowband FM, used in channelised voice radio) and wbfm (WBFM: wideband FM, used in commercial broadcast). The labels are distinguished by per-label defaults and ceilings on the Carson 98%-containment bandwidth (Carson bandwidth: the spectral window that contains 98% of the signal’s average power, named after J. R. Carson’s 1922 rule), anchored on real-world channel standards.
Class signature¶
class TorchSigFMEmitter(BaseEmitter):
family: ClassVar[EmitterFamily] # EmitterFamily.COMMS
supported_classes: ClassVar[tuple[str, ...]] # ("nbfm", "wbfm")
def __init__(self) -> None: ...
def generate(
self,
*,
class_label: str, # "nbfm" or "wbfm"
sample_rate: float, # Hz; Nyquist rate for the complex-baseband record
duration_s: float, # seconds; record length
f_offset_hz: float, # Hz; digital baseband frequency shift
rng: torch.Generator, # seeded generator for reproducibility
device_id: str | None = None,
params: BaseModel | None = None, # TorchSigFMParams
) -> Signal: ...
Parameters¶
Name |
Type |
Units |
Default |
Purpose |
|---|---|---|---|---|
|
|
n/a |
required |
|
|
|
Hz |
required |
Complex-baseband Nyquist rate; must satisfy |
|
|
s |
required |
Record length; |
|
|
Hz |
required |
Baseband frequency shift applied as |
|
|
n/a |
required |
Seeded random generator; same seed produces identical IQ |
|
|
n/a |
|
Propagated to |
|
|
n/a |
|
Pydantic model with optional |
|
|
Hz |
label default |
Carson 98%-containment bandwidth; |
Per-label defaults and ceilings:
Label |
Default |
Ceiling |
Standard |
|---|---|---|---|
|
12,500 Hz |
25,000 Hz |
ETSI EN 300 086 land-mobile voice (12.5 / 20 / 25 kHz raster) |
|
150,000 Hz |
200,000 Hz |
FCC 47 CFR 73.317 commercial broadcast FM (200 kHz channel raster) |
Worked example¶
import torch
from rfgen.emitters import TorchSigFMEmitter, TorchSigFMParams
em = TorchSigFMEmitter()
g = torch.Generator()
g.manual_seed(42)
sig = em.generate(
class_label="wbfm",
sample_rate=2_000_000.0, # 2 MHz sample rate
duration_s=0.1, # 100 ms = 200,000 samples
f_offset_hz=0.0,
rng=g,
params=TorchSigFMParams(bandwidth_hz=200_000.0), # 200 kHz Carson bandwidth
)
print(sig.iq.shape) # torch.Size([2, 200000])
print(sig.iq.dtype) # torch.float32
print(sig.metadata.bandwidth_hz) # 200000.0
print(sig.metadata.class_taxonomy) # ('comms', 'fm', 'wbfm')
The emitter wraps torchsig.signals.builders.fm.fm_modulator. TorchSig internally draws a modulation index m ~ Uniform(1, 10), computes fdev = (bandwidth_hz/2) / (1 + 1/m) and fmax = fdev/m, then builds a Gaussian-noise message filtered to fmax and integrates the phase. The wrapper adds the Nyquist guard, per-label ceiling enforcement, and the f_offset_hz baseband shift.
2. What we validated¶
This validation establishes 7 load-bearing claims. Each is restated and supported by evidence in §3.
Output shape and metadata contract (§3.1): the emitter produces a
(2, N)float32 IQ tensor and correctSignalMetadata.Carson 98%-containment bandwidth (§3.2): the Carson bandwidth identity holds at algebraic precision; measured containment equals 1.0000 across all tested operating points.
Constant-envelope invariant (§3.3): FM is phase-only modulation;
|I + jQ|stays at unity for both WBFM and NBFM.WBFM fits the FCC 47 CFR 73.317 commercial broadcast mask (§3.4): at
bandwidth_hz = 200 kHz, full power fits inside the 200 kHz channel.NBFM and WBFM per-label defaults produce distinguishable IQ (§3.5): per-label bandwidth defaults route the two labels through different spectral regimes.
Baseband frequency shift is exact (§3.6):
f_offset_hzmigrates the spectral peak by the requested amount.Boundary and error enforcement (§3.7): per-label ceilings, Nyquist guards, and non-finite input rejection all raise the correct error types.
Limits and scope-bounded items appear in §4; full citations are in §5.
3. Evidence per claim¶
3.1 Output shape and metadata contract¶
The emitter returns a Signal whose iq field is a (2, N) torch.float32 tensor with N = round(sample_rate * duration_s). SignalMetadata carries the realised bandwidth, sample rate, carrier offset, class taxonomy, and generator name.
sig.iq.shape == (2, N)
sig.iq.dtype == torch.float32
sig.metadata.bandwidth_hz == bandwidth_hz (as resolved from params or label default)
sig.metadata.realized_carrier_hz == f_offset_hz
sig.metadata.class_taxonomy == ("comms", "fm", class_label)
sig.metadata.snr_db == float("inf") # clean baseband
Tests: test_iq_shape_dtype (3 (fs, dur_s, expected_n) parameter combinations), test_metadata_carries_request, test_family_and_supported_classes in tests/validation/emitters/torchsig_fm/test_experiment_contract.py. All pass.
3.2 Carson 98%-containment bandwidth¶
The claim. The bandwidth_hz parameter is the Carson 98%-containment bandwidth: the spectral window [-bandwidth_hz/2, +bandwidth_hz/2] that contains 98% (or more) of the signal’s average power. This is the standard definition from Haykin, Communication Systems, 5th ed., Ch. 5 (Carson’s rule: B_carson = 2·(fdev + fmax)).
Mathematical basis. TorchSig picks m ~ Uniform(1, 10) and sets fdev = (bandwidth_hz/2) / (1 + 1/m) and fmax = fdev/m. Then:
2·(fdev + fmax) = 2·fdev·(1 + 1/m) = 2·(bandwidth_hz/2 / (1 + 1/m))·(1 + 1/m) = bandwidth_hz
This is an algebraic identity that holds for every draw of m, not a statistical approximation. The iterative-design LPF (low-pass filter: a digital filter that passes frequencies below a cutoff and attenuates those above) inside TorchSig hard-band-limits the message to fmax, so all signal energy sits inside ±bandwidth_hz/2.
Measured result. Containment fraction = 1.0000 (±0.0001 Welch leakage floor) across four (label, bandwidth_hz) pairs: (wbfm, 200 kHz), (wbfm, 180 kHz), (nbfm, 12.5 kHz), (nbfm, 25 kHz).
Figure 1 shows the measured containment fraction across the full valid bandwidth sweep for both labels, confirming the Carson rule holds at every tested point with a margin of approximately 30 standard deviations above the 0.98 lower bound.

Figure 2 shows the average Welch PSD (power spectral density: signal energy plotted against frequency) for WBFM and NBFM at their respective default bandwidths, confirming the two labels produce distinct emission widths.

Tests: test_carson_98_percent_containment (4 parametrized cases), test_carson_holds_across_bandwidth_sweep (6 cases across both labels), test_carson_holds_across_sample_rate_sweep (4 sample rates) in tests/validation/emitters/torchsig_fm/test_empirical_known_results.py and test_robustness_envelope.py.
Note on -3 dB bandwidth. A reader expecting bandwidth_hz to equal the -3 dB bandwidth will be surprised. For m ~ Uniform(1, 10) the -3 dB point sits near fmax = bandwidth_hz / (2·(m+1)), approximately an order of magnitude below bandwidth_hz. The Carson 98%-containment interpretation is the one this parameter controls; the module docstring states this explicitly.
3.3 Constant-envelope invariant¶
The claim. FM is phase-only modulation: s(t) = exp(j·φ(t)), which has |s(t)| = 1 at every sample by construction. The wrapper deliberately does NOT subtract the empirical complex-baseband mean (unlike the digital-comms wrapper). For narrow bandwidths the phase trajectory walks slowly enough that the empirical mean magnitude can reach ~0.4 over short records; subtracting it would collapse the unit envelope into a ~30%-RMS (root-mean-square: the quadratic average of a signal’s amplitude) amplitude variation, converting a textbook constant-envelope FM signal into an AM-contaminated artefact.
Measured result. Envelope mean = 1.000, std < 0.005 for WBFM at 200 kHz bandwidth; envelope mean = 1.000, std < 0.05 for NBFM at 12.5 kHz bandwidth (float32 cast introduces small rounding ripple at narrow bandwidths).
Figure 3 shows the IQ envelope over time for both WBFM and NBFM realisations, confirming the unit-envelope property holds for both labels.

Figure 4 shows the instantaneous frequency trajectory (how fast the signal’s frequency is changing at each moment) for both labels, confirming the deviation stays within the Carson half-bandwidth.

Tests: test_envelope_approximately_unit_wbfm, test_envelope_approximately_unit_nbfm, test_constant_envelope_holds in tests/validation/emitters/torchsig_fm/test_empirical_known_results.py.
3.4 WBFM fits the FCC 47 CFR 73.317 broadcast mask¶
The claim. At bandwidth_hz = 200 kHz the emitter produces a WBFM signal whose full power lies inside the FCC 47 CFR 73.317 commercial broadcast channel (±100 kHz around the carrier). The FCC requires ≥99% in-channel power at 200 kHz channel spacing.
Measured result. Power fraction inside ±100 kHz = 1.0000 (measured at 2 MHz sample rate, 0.1 s capture, Welch nperseg = 16384). The fraction exceeds the FCC 99% requirement by a large margin because TorchSig’s iterative-design LPF hard-limits the message; there is negligible spectral leakage beyond the Carson boundary.
Tests: test_wbfm_200khz_channel_fits_fcc_mask in tests/validation/emitters/torchsig_fm/test_empirical_known_results.py.
Out-of-band floor. Beyond twice the Carson half-bandwidth, the average PSD is below -50 dB relative to the in-band peak. Test: test_oob_floor_below_minus_50_db.
3.5 NBFM and WBFM per-label defaults produce distinguishable IQ¶
The claim. Calling the emitter with class_label = "nbfm" (no explicit bandwidth_hz) routes through the ETSI EN 300 086 default of 12.5 kHz; calling with class_label = "wbfm" routes through the FCC 47 CFR 73.317 default of 150 kHz. The two labels cannot silently produce the same IQ under any seed.
Figure 5 shows the realised bandwidth_hz from SignalMetadata across 10 seeds for both labels, confirming the defaults are constant and differ by a factor of 12.

Tested. test_nbfm_wbfm_default_bandwidth_differs in tests/validation/emitters/torchsig_fm/test_experiment_contract.py confirms both the bit-difference and the metadata bandwidth values.
3.6 Baseband frequency shift is exact¶
The claim. Setting f_offset_hz = f applies the complex multiply iq * exp(j·2π·f·t), which shifts the baseband spectrum by exactly f Hz without distorting the waveform.
Measured result. At f_offset_hz = 200 kHz, the spectral peak migrates from 0 to 200 kHz within ±30 kHz tolerance (approximately half the empirical -3 dB bandwidth of the FM waveform at bandwidth_hz = 100 kHz).
Figure 6 shows the Welch PSD before and after the frequency shift for three offset values, confirming the spectral envelope translates cleanly.

Tests: test_f_offset_shifts_spectrum in tests/validation/emitters/torchsig_fm/test_experiment_contract.py.
Determinism. Same seed produces bit-identical IQ; different seeds produce different IQ. Tests: test_same_seed_same_iq, test_different_seed_different_iq.
3.7 Boundary and error enforcement¶
The emitter enforces all boundary conditions before calling TorchSig, so every error surfaces as a typed rfgen exception rather than a raw backend error.
Boundary |
Expected error |
Test |
|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
Non-finite |
|
|
|
|
|
TorchSig backend absent |
|
|
Unsupported |
|
|
All tests in tests/validation/emitters/torchsig_fm/test_robustness_envelope.py and test_experiment_contract.py pass.
4. Limits and what’s not validated¶
No audio source. The message is white Gaussian noise band-limited to fmax. Real FM transmissions carry voice, music, or signalling tones with distinctive spectral and temporal structure absent here.
No pre-emphasis. Real FM broadcast applies 75 µs (US) or 50 µs (Europe) pre-emphasis (a high-frequency boost applied to the audio before modulation) before modulation. The emitter omits this because pre-emphasis is part of an audio pipeline outside the framework’s scope.
No stereo pilot or sub-carriers. Commercial FM stereo (19 kHz pilot, 38 kHz L-R subcarrier) and RDS (57 kHz subcarrier) are not present. These belong to a higher-layer broadcast emitter.
No CTCSS sub-audible tones. Narrowband FM voice channels use CTCSS (Continuous Tone-Coded Squelch System: a sub-audible tone that activates a receiver’s squelch circuit) for squelch control. Out of scope at the modulation-class abstraction level.
No transmitter impairments. No PA (power amplifier) nonlinearity, IQ imbalance, oscillator phase noise, or carrier-frequency drift. These are deferred to the channel-pipeline layer per the rfgen architecture.
No frame structure. Continuous modulation only; no PTT (push-to-talk) on/off envelope, no preamble, no inter-burst silence.
Modulation index not user-controllable. m ~ Uniform(1, 10) is drawn per call inside TorchSig and cannot be fixed. Standards typically pin m (e.g. broadcast FM has effective m in [1, 5] depending on programme content; GSM uses m = 0.5). Exposing m would require patching TorchSig or switching to its lower-level signal-generator API.
No upper bound on n_samples. Very large sample_rate * duration_s products can exhaust memory. Resource caps belong in the pipeline-configuration layer.
5. References¶
5.1 Published works¶
Citation |
Role |
|---|---|
J. R. Carson, “Notes on the Theory of Modulation,” Proc. IRE, vol. 10, no. 1, pp. 57–64, Feb. 1922 |
Original derivation of Carson’s rule; the |
S. Haykin, Communication Systems, 5th ed., Wiley, 2009, Ch. 5 |
Canonical FM textbook covering Carson’s rule, Bessel sidebands, NBFM vs. WBFM, and pre-emphasis; cited in the module docstring |
L. W. Couch, Digital and Analog Communication Systems, 8th ed., Pearson, 2013, eq. 5-94 |
Carson’s rule restatement and modulation index definition |
FCC 47 CFR §73.317, FM transmission system requirements (current) |
US commercial FM mask: 75 kHz peak deviation, 15 kHz audio bandwidth, 200 kHz channel raster; anchors the |
ETSI EN 300 086, Land Mobile Service; Radio equipment with an internal or external RF connector intended primarily for analogue speech |
NBFM channel raster 12.5 / 20 / 25 kHz; anchors the |
ITU-R BS.450-3, Transmission standards for FM sound broadcasting at VHF (2001) |
International FM broadcast values match the FCC mask numerically |
M. Boegner, J. West, et al., “Large Scale Radio Frequency Signal Classification,” arXiv:2207.09918 (2022), doi:10.48550/arXiv.2207.09918 |
TorchSig library and dataset citation |
5.2 Libraries¶
PyPI distribution |
Installed version |
Documentation |
Role in this validation |
|---|---|---|---|
|
2.1.1 |
Provides |
|
|
2.12.1 |
|
|
|
1.18.0 |
|
|
|
2.4.6 |
Complex arithmetic, |
|
|
3.11.0 |
Figure generation in |