Scientific validation: TorchSig digital-constellation emitter

Validated with documented limitations.

1. The component

TorchSigCommsEmitter is a PyTorch-fronted generator that produces clean baseband in-phase/quadrature (IQ) tensors for 11 standard digital-modulation classes used in modulation-recognition training data. The in-phase (I) and quadrature (Q) channels are the real and imaginary parts of a complex-valued signal; together they form the two-channel representation (2, N) consumed by downstream models.

class TorchSigCommsEmitter(BaseEmitter):
    family: ClassVar[EmitterFamily] = EmitterFamily.COMMS
    supported_classes: ClassVar[tuple[str, ...]] = (
        "bpsk", "qpsk", "8psk", "16psk",
        "16qam", "32qam", "64qam", "256qam",
        "ook", "4ask", "8ask",
    )

    def __init__(self) -> None: ...

    def schema(self) -> type[BaseModel]: ...

    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: ...


class TorchSigCommsParams(BaseModel):
    bandwidth_hz: float = Field(default=200e3, gt=0)
    pulse_shape_name: str = Field(default="srrc")
    alpha_rolloff: float = Field(default=0.35, gt=0.0, lt=1.0)

Parameter

Type

Units

Default

Purpose

class_label

str

n/a

required

One of the 11 supported constellation labels. A constellation is the discrete set of complex points the modulator picks from to encode bits.

sample_rate

float

Hz

required

Samples per second on the output tensor. Must be finite and positive.

duration_s

float

s

required

Output duration. The total sample count is N = round(sample_rate * duration_s).

f_offset_hz

float

Hz

required

Baseband frequency shift in Hz. Mixes the signal up or down by this many Hz; real radio-frequency upconversion is a downstream step. May be negative or zero.

rng

torch.Generator

n/a

required

Seeds the NumPy random-number generator used to draw symbols. State advances on each call.

device_id

str or None

n/a

None

Optional metadata label echoed into Signal.metadata. Never affects IQ.

params.bandwidth_hz

float

Hz

200_000.0

Symbol-rate / 3 dB bandwidth. Default matches the GSM (Global System for Mobile Communications) cellular channel width of 200 kHz.

params.pulse_shape_name

str

n/a

"srrc"

Pulse shape applied to each symbol. "srrc" is the square-root raised-cosine filter, a finite-impulse-response (FIR) filter shaped so adjacent symbols cancel at sampling instants. "rectangular" is the boxcar alternative.

params.alpha_rolloff

float

n/a

0.35

Excess-bandwidth factor of the SRRC pulse, in (0, 1). Higher values give a wider but smoother spectrum. Default matches the DVB-S2 (Digital Video Broadcasting, Satellite, second generation) standard.

import torch
from rfgen.integrations.torchsig.emitters.torchsig_comms import TorchSigCommsEmitter

emitter = TorchSigCommsEmitter()
signal = emitter.generate(
    class_label="qpsk",
    sample_rate=1_000_000.0,   # 1 MHz
    duration_s=0.1,             # 0.1 s
    f_offset_hz=0.0,
    rng=torch.Generator().manual_seed(0),
)
# signal.iq has shape (2, 100_000) and dtype torch.float32:
# channel 0 is the in-phase (I) component, channel 1 is the quadrature (Q).
assert signal.iq.shape == (2, 100_000) and signal.iq.dtype == torch.float32

The taxonomy position is digital linear modulation at the modulation-order level: one label per constellation shape, with no protocol framing. The 11 supported labels span three constellation families: phase-shift keying (PSK, where bits are encoded by the phase of the carrier: BPSK / QPSK / 8PSK / 16PSK with 2 / 4 / 8 / 16 phases), quadrature amplitude modulation (QAM, where bits are encoded jointly by amplitude and phase: 16QAM / 32QAM / 64QAM / 256QAM with 16 / 32 / 64 / 256 points on a grid), and amplitude-shift keying (ASK, where bits are encoded by amplitude alone: OOK / 4ASK / 8ASK with 2 / 4 / 8 levels, where OOK is “on-off keying”, a two-level amplitude code). Sibling families (frequency-shift keying, orthogonal-frequency-division multiplexing without a separate symbol grid, analog amplitude and frequency modulation, chirp, tone) are exposed as separate emitter classes; this report covers only the constellation-based subset.

Channel-side impairments (multipath fading, additive noise, power-amplifier nonlinearity, in-phase / quadrature imbalance, oscillator phase noise, direct-current or DC offset) are out of scope and assigned to a separate channel layer. One documented edge case applies to the on-off-keying (OOK) constellation: its symbol map has non-zero population mean by design (1/sqrt(2) 0.707 after unit-root-mean-square normalisation), so the conditional zero-mean step is skipped for that class.

2. What we validated

This validation establishes 13 load-bearing claims. Each is restated and supported by evidence in §3.

  1. Shape and dtype contract (§3.1): the output is a (2, N) float32 tensor with N set by sample_rate and duration_s for every supported class label.

  2. Unit average power (§3.2): the symmetric constellations have unit average power and OOK has the expected half-duty-cycle power.

  3. Zero mean for symmetric classes, theoretical mean for OOK (§3.3): the population mean is zero for the symmetric classes and matches the OOK theoretical value.

  4. Determinism and RNG advancement (§3.4): a fixed torch.Generator seed reproduces bit-identical IQ, and consecutive calls advance the generator state.

  5. Bandwidth scaling tracks bandwidth_hz (§3.5): the empirical −3 dB spectral width scales linearly with the configured bandwidth_hz.

  6. alpha_rolloff controls transition-band steepness (§3.6): decreasing alpha_rolloff steepens the PSD transition band as predicted by the SRRC pulse-shape formula.

  7. SRRC -3 dB frequency matches Proakis-Salehi (§3.7): the measured one-sided -3 dB frequency matches the closed-form textbook prediction.

  8. Cross-class cumulant ordering follows Swami-Sadler (§3.8): waveform-level fourth-order cumulants preserve the literature-tabulated cross-class ordering.

  9. Cumulant attenuation is similar across the tested cohort (§3.9): the measured waveform-to-symbol ratios occupy a narrow range for the five tested constellations.

  10. f_offset_hz translates the spectral centroid (§3.10): the baseband frequency-shift identity translates the spectral centroid by the requested offset.

  11. Input-validation envelope (§3.11): the combined-occupancy guard and non-finite runtime inputs raise EmitterError before arithmetic; malformed parameter schemas raise Pydantic ValidationError during validation.

  12. Robustness at the operating-envelope boundary (§3.12): very short records and near-boundary configurations do not silently produce garbage.

  13. Statistical-estimator settings (§3.13): the PSD and cumulant estimator configurations are recorded exactly, and their observed results are checked against the tolerances documented in the evidence sections below.

Limits and scope-bounded items appear in §4; full citations are in §5.

3. Evidence per claim

3.1 Shape and dtype contract

The emitter must return a (2, N) float32 tensor with N = round(sample_rate * duration_s) for every supported class label. This is the structural contract every downstream consumer (the data-loader, the model input layer) depends on.

Measured at sample_rate = 1 MHz, duration_s = 0.1 s, N = 100000 across all 11 labels: shape (2, 100000), dtype torch.float32. Test: test_shape_and_dtype in tests/validation/emitters/torchsig_comms/test_experiment_contract.py.

3.2 Unit average power

For PSK (phase-shift keying), QAM (quadrature amplitude modulation), and ASK (amplitude-shift keying) constellations the symbol map is divided by the root-mean-square amplitude sqrt(mean(|map|^2)) before pulse shaping, so the mean instantaneous power E[I^2 + Q^2] is approximately 1. For OOK the half-duty-cycle structure gives a theoretical mean power of 0.5. Unit average power matters because every downstream signal-to-noise-ratio (SNR) calibration upstream of the channel layer assumes it.

Measured PSK / QAM / ASK power: 0.997. OOK power: 0.499. Test: test_power_normalisation in test_experiment_contract.py.

3.3 Zero mean for symmetric classes, theoretical mean for OOK

The 10 symmetric constellations (everything except OOK) have a population mean of zero by construction; finite-sample residuals are removed by a conditional mean-subtraction step. OOK retains its theoretical mean of 1/sqrt(2) 0.707 after unit-RMS (root-mean-square) normalisation. Zero mean for the symmetric classes matters because any residual DC bias would corrupt the IQ statistics a downstream classifier learns.

Measured for the 10 symmetric classes: |mean(I)| / max(|I|) < 3e-8. Measured for OOK at N = 200000: mean 0.683, deviating from theory by 0.024 and remaining within the test’s stated tolerance. Tests: test_symmetric_classes_zero_mean, test_B_ook_mean_is_near_theoretical, and test_ook_mean_is_near_theoretical_at_200k_samples in test_experiment_contract.py.

3.4 Determinism and RNG advancement

The same torch.Generator seed must reproduce bit-identical IQ; consecutive generate() calls on a shared generator must produce different IQ (so callers do not accidentally generate duplicate samples in a sweep). Determinism is the foundation for reproducible training-data generation.

Measured: pass for all 11 labels. Tests: test_seed_level_determinism in test_experiment_contract.py and test_consecutive_calls_advance_rng in test_robustness_silent_gaps.py.

3.5 Bandwidth scaling tracks bandwidth_hz

Doubling the requested bandwidth_hz should double the empirical −3 dB spectral width, with linear tracking inside the operating envelope. A downstream training pipeline will sweep bandwidth_hz to vary symbol rate; if the realised width did not track the requested value, the trained model would learn the wrong rate-to-bandwidth mapping.

Measured doubling ratios at B0 in {50, 100, 200} kHz: 1.93, 1.94, 2.00, all inside the tolerance band [1.7, 2.3]. Test: test_bandwidth_doubling in test_experiment_psd_bandwidth.py. Figure 1 (below) overlays the per-operating-point scipy.signal.welch PSDs (power spectral density estimated by averaging windowed periodograms; see §3.13 for the estimator’s settings).

Figure 1: empirical −3 dB spectral width at three operating points. Welch PSDs for  in {50, 100, 200} kHz; supports the bandwidth-scaling claim.

Figure 1 shows the three PSD curves shifting in proportion to the requested bandwidth, with -3 dB crossings at the predicted symbol-rate / 2 locations.

3.6 alpha_rolloff controls transition-band steepness

Smaller alpha_rolloff should produce a steeper SRRC transition between the passband and stopband; the closed-form prediction is that the -20 dB bandwidth scales with (1 + alpha), giving a ratio of about 1.81 between alpha = 0.99 and alpha = 0.10. This claim matters because a downstream classifier may treat alpha as a class-conditional feature; the empirical transition must follow the parameter monotonically.

Measured -20 dB bandwidth ratio alpha=0.99 / alpha=0.10: 1.72 (monotonic; the tolerance threshold for the assertion is > 1.3). Test: test_alpha_rolloff_controls_transition in test_experiment_psd_bandwidth.py. Figure 2 overlays Welch PSDs across the swept alpha values.

Figure 2: SRRC transition-band steepness vs . Welch PSDs at  from 0.10 to 0.99; supports the transition-steepness claim.

Figure 2 shows the PSDs steepening monotonically as alpha decreases, with the lowest-alpha curve having the narrowest passband-to-stopband transition.

3.7 SRRC -3 dB frequency matches Proakis-Salehi

For a square-root raised-cosine pulse at symbol rate f_sym, the one-sided -3 dB frequency of the resulting baseband PSD is f_sym / 2 (Proakis & Salehi 2008, §9.2). At bandwidth_hz = 200 kHz the prediction is 100 kHz. The closed-form prediction is the canonical anchor for SRRC fidelity.

Measured one-sided -3 dB frequency: 95.0 kHz. Relative error: -5.0%. Test: test_psd_3db_bandwidth in test_experiment_psd_bandwidth.py. Figure 3 overlays Welch PSDs for four constellations sharing the same SRRC shape, confirming the constellation-invariant spectral envelope.

Figure 3: Welch PSDs for BPSK, QPSK, 16QAM, and 64QAM at . All four share the same SRRC envelope; supports the SRRC -3 dB closed-form claim.

Figure 3 shows all four PSDs overlapping within the per-bin variance, agreeing with the SRRC closed form to within 5% in the -3 dB neighbourhood. The 5% contraction originates from the polyphase resampler inside TorchSig’s constellation_modulator at v2.1.1 (see §4).

3.8 Cross-class cumulant ordering follows Swami-Sadler

The fourth-order cumulant C42 (a kurtosis-like higher-order statistic that fingerprints constellation shape) takes characteristic absolute values per ideal constellation; Swami & Sadler 2000 tabulate the closed-form ordering BPSK > QPSK = 8PSK > 16QAM > 64QAM > 256QAM. Preserving this ordering on the waveform is the minimum bar for the emitter to be useful as training data for cumulant-feature-based classifiers.

In the tested N = 500000 cohort, the measured waveform values preserve the reference ordering across the six tested constellations; the smallest observed cross-class gap is 16QAM - 64QAM = 0.054. This is an observed separation for the tested cohort, not a general sampling-uncertainty bound. Test: test_K_cross_class_discriminability in test_experiment_cumulants.py. Figure 4 plots the per-class |C42| measurements next to the Swami-Sadler reference.

Figure 4: waveform-level |C42| (absolute fourth-order cumulant) for the six class labels named in the Swami-Sadler ordering (BPSK, QPSK, 8PSK, 16QAM, 64QAM, 256QAM). Two fills: blue = Swami-Sadler symbol-rate theory, red = measured waveform; the x-axis labels every class. Bars show the observed attenuation and preserved ordering in the tested cohort.

Figure 4 shows the measured waveform bars below the reference values, with the relative ordering preserved across every adjacent pair in the tested cohort.

3.9 Cumulant attenuation is similar across the tested cohort

Waveform-level |C42| measurements are lower than the symbol-level reference in the tested cohort. SRRC-filter inter-sample correlation is the documented mechanism under test: the oversampled waveform’s higher-order statistics are smoothed by the common pulse-shape FIR. The measurements below characterize this cohort; they do not prove a constellation-independent attenuation factor for untested configurations.

Measured per-class waveform-to-reference ratios at oversampling factor 5: QPSK 0.806, 16QAM 0.782, 64QAM 0.774, 256QAM 0.774, BPSK 0.818. Their descriptive coefficient of variation is 2.2% for these five measurements. Tests: test_F_cumulant_waveform_for_qpsk, test_F_cumulant_waveform_for_16qam, test_F_cumulant_waveform_for_64qam, test_F_cumulant_waveform_for_256qam, test_F_cumulant_waveform_for_bpsk in test_experiment_cumulants.py. Tests comparing the waveform-level |C42| directly against the symbol-level Swami-Sadler numbers are marked xfail(strict=True) with the inter-sample correlation cited as the cause.

The empirical constellation diagrams in Figure 5 corroborate the constellation-shape recovery: every label shows the expected point symmetry, ring structure, or on-axis ASK distribution.

Figure 5: empirical IQ-scatter constellation diagrams for all 11 supported labels. The discrete point clusters confirm the expected constellation shapes and support the per-class shape and cumulant-ordering claims.

Figure 5 shows clearly separated clusters at the expected positions for each constellation, with no degenerate collapses or missing points.

3.10 f_offset_hz translates the spectral centroid

The baseband frequency-shift identity iq_complex * exp(j * 2 * pi * f_offset_hz * t) (Oppenheim & Schafer 2010, §4.2) should translate the spectral centroid by exactly the requested f_offset_hz, and produce IQ measurably different from f_offset_hz = 0. The shift is the mechanism by which the channel layer composes multiple emitters at different carrier offsets onto a shared scene.

Measured spectral-centroid migration for a requested offset of 100 kHz: 99.4 kHz, within one Welch frequency-bin width. Test: test_f_offset_iq_is_upconverted in test_robustness_silent_gaps.py.

3.11 Input-validation envelope

Configurations that violate the complex-baseband Nyquist budget (the rfgen-specific combined spectral-extent guard bandwidth_hz * (1 + alpha) + 2 * |f_offset_hz| < sample_rate) must be rejected before any arithmetic, with a typed EmitterError carrying enough context for the caller to debug. Schema violations (non-positive bandwidth_hz, out-of-range alpha_rolloff, unsupported class_label, and extra fields) raise Pydantic ValidationError during parameter validation. Non-finite runtime inputs raise EmitterError before waveform arithmetic.

Measured: the combined-occupancy guard raises EmitterError at bandwidth_hz = 0.49 * sample_rate, alpha = 0.99, with a context dictionary naming bandwidth_hz, alpha_rolloff, f_offset_hz, sample_rate, occupied_bandwidth_hz, and shifted_extent_hz. All six NaN / +inf / -inf permutations of sample_rate, duration_s, and f_offset_hz raise EmitterError with a context dictionary naming the offending field. Schema bounds and extra-field rejection are enforced by Pydantic. Tests: test_combined_occupancy_guard and test_nan_inf_inputs_raise_emitter_error in test_robustness_envelope.py; test_alpha_schema_bounds and test_unsupported_class_label in test_experiment_contract.py. Figure 6 shows the well-formed PSD at both schema boundaries (alpha = 0.01 and alpha = 0.99), confirming the boundaries are reachable rather than degenerate.

Figure 6: Welch PSD at the two  schema boundaries (0.01 and 0.99). Both produce well-formed finite output and support the schema-envelope claim.

Figure 6 shows two finite, structurally sound PSDs spanning the schema-permitted alpha range. The narrowest-alpha curve has the steepest transition band and the widest-alpha curve has the smoothest skirt, as the SRRC closed form predicts.

3.12 Robustness at the operating-envelope boundary

Two boundary regimes are exercised to confirm the implementation does not silently produce garbage: very short records (n_samples < 64), and configurations adjacent to the combined-occupancy limit. Short records produce output dominated by the SRRC filter transient (documented in the module docstring; no exception is raised). Near-boundary configurations either pass without spectral folding or are rejected by the guard.

Tests: test_short_n1_output_is_zero_mean in test_robustness_pathological.py; test_combined_occupancy_passes and test_combined_occupancy_guard in test_robustness_envelope.py. Figures 7 and 8 visualise the two regimes.

Figure 7: IQ envelope and PSD for records shorter than 64 samples. Output is dominated by the SRRC filter transient and supports the short-record robustness claim.

Figure 7 shows the transient-dominated waveform and its broadband PSD for n_samples < 64, with finite values throughout and no exception raised.

Figure 8: Welch PSD near the combined-occupancy budget . The accepted configuration shows no spectral folding; the rejected configuration triggers the guard and supports the boundary-rejection claims.

Figure 8 shows a well-formed accepted PSD that uses nearly the full Nyquist budget, alongside the rejected-configuration result where the guard fires before any sample is computed.

3.13 Statistical-estimator settings

The two main estimators in the validation suite are Welch’s method for PSD and a plug-in sample-moment estimator for C42. Welch’s method (a PSD estimator that averages overlapping windowed periodograms) is invoked through scipy.signal.welch with nperseg = 4096, 50% overlap, and return_onesided = False. At sample_rate = 2 MHz, duration_s = 0.2 s (N = 400000), these are the exact settings exercised by the cited bandwidth tests. The measured crossings are evaluated against each test’s stated tolerance; this report does not assign an analytic uncertainty or coefficient of variation to those crossings.

The cumulant tests use N = 500000 and compare the observed class values and ordering directly with their checked assertions. The validation establishes the observed gaps for that tested cohort; it does not claim a numeric standard error or population-level statistical conclusion.

Sample-size choice: PSD-bandwidth tests use N = 400000, cumulant tests use N = 500000, and shape and determinism tests use N = 100000. Those sizes and the reported test tolerances define the verified configurations; no broader uncertainty guarantee is inferred from record length alone. Welch averaging is used for the stationary emitter outputs exercised here. This report does not prescribe an estimator for non-stationary signals.

4. Limits and what’s not validated

The following items bound the scope of the validation. Each carries a one-sentence technical rationale.

  • No transmitter impairments. Power-amplifier AM-AM compression and AM-PM phase distortion (the gain and phase changes a real amplifier introduces near saturation), in-phase / quadrature gain and phase imbalance, oscillator phase noise, and local-oscillator DC offset are all absent. The synthesised waveform is the idealised transmitter-side baseband signal. A classifier trained on this emitter alone, without a realistic channel and hardware-impairment layer, will be brittle to real captures. Out of scope: impairments are the channel layer’s responsibility in the rfgen architecture.

  • No protocol framing. Real transmissions have preambles, sync words, headers, payloads, cyclic-redundancy-check fields, and inter-burst guard intervals. The emitter produces a continuous stationary burst of modulated symbols. Out of scope for a per-class waveform generator.

  • Non-Gray-coded bit mapping. TorchSig’s constellation maps use natural-binary indexing rather than Gray coding, a bit assignment where adjacent constellation points differ in only one bit. Adjacent 8PSK index neighbours can differ by up to 3 bits. The physical waveform shape is unaffected; only the bit-to-symbol interpretation differs. Inherited from the upstream library.

  • 32QAM is a 4 by 8 rectangular grid, not the cross-shape used in DVB-T2. TorchSig defines the 32qam label as a rectangular 4 x 8 grid; the cross-shape variant is available in TorchSig as 32qam_cross but is not exposed by this emitter. Documented in the module docstring.

  • Symbol rate not exposed as a first-class parameter. TorchSigCommsParams exposes bandwidth_hz rather than symbol_rate or samples_per_symbol. A consumer who wants to sweep symbol rate at fixed pulse-shape rolloff must back-compute the bandwidth. The signal-catalog example configurations advertise symbol_rate as a knob; aligning the schema and the catalog is a public-surface change outside this validation’s scope.

  • n_samples < 64 not hard-rejected. Short records produce output dominated by the SRRC pulse transient. A runtime warning or hard raise would break legitimate single-sample-probe tests. The minimum recommended value is documented in the module docstring and in the generate() parameter docstring.

  • 5% PSD-width contraction and −18.8 dB measured stopband floor. Both deviations from the ideal SRRC response originate from the polyphase resampler inside constellation_modulator. They are retained as measured upstream-library behavior; this report does not compare them with a transmitter standard or claim spectral-mask compliance.

  • No upper bound on n_samples at the emitter layer. Resource-limit policy belongs to the pipeline configuration layer, not to a single emitter.

  • Mean-subtraction rather than an IIR DC-blocker. The zero-mean adjustment for symmetric classes removes the O(1 / sqrt(N)) finite-sample residual via plain mean subtraction. An infinite-impulse-response (IIR) DC-blocker (a one-pole high-pass filter often used to strip residual DC) has a phase response and filter-state question that would change the public behaviour; outside this component’s scope.

The executable validation suite is at tests/validation/emitters/torchsig_comms/, totalling 151 passing tests with 3 expected-failures across seven files, and runs in about 12 seconds on a developer workstation.

5. References

Published works

Citation

Identifier

Role

J. G. Proakis and M. Salehi, Digital Communications, 5th ed., McGraw-Hill, 2008, §9.2

ISBN 978-0072957167

Canonical SRRC pulse formula; matched-filter and Nyquist-criterion derivation; closed-form -3 dB frequency

A. V. Oppenheim and R. W. Schafer, Discrete-Time Signal Processing, 3rd ed., Pearson, 2010, §4.2

ISBN 978-0131988422

Complex-baseband frequency-shift identity

A. Swami and B. M. Sadler, “Hierarchical digital modulation classification using cumulants,” IEEE Transactions on Communications, vol. 48, no. 3, pp. 416 to 429, March 2000

doi:10.1109/26.837045

Closed-form symbol-level &#124;C42&#124; values for the constellation ordering

L. Boegner et al., “Large Scale Radio Frequency Signal Classification,” 2022

arXiv:2207.09918, doi:10.48550/arXiv.2207.09918

TorchSig library citation

ETSI EN 302 307-1 v1.4.1 (2014), §5.4

ETSI EN 302 307-1

DVB-S2 SRRC rolloff values including the default alpha = 0.35

ETSI TS 145 005 v15.4.0 (2019), §2

ETSI TS 145 005

GSM channel raster of 200 kHz used as the default bandwidth_hz

Libraries

Installed versions read via importlib.metadata.version at the time the validation suite ran. The PyPI distribution name is the string passed to pip install; the documentation URL is the library’s primary docs entry point.

Library

PyPI distribution

Installed version

Documentation

Role in validation

TorchSig

torchsig

2.1.1

v2.1.1 constellation builder source

Wrapped backend providing constellation_modulator for constellation symbol generation, SRRC tap computation, and polyphase resampling

PyTorch

torch

2.12.1

https://pytorch.org/docs/stable/

Tensor primitives, torch.Generator for deterministic seeding, and the public IQ output type torch.float32 tensor

NumPy

numpy

2.4.6

numpy statistics reference

Frequency-shift arithmetic, sample-moment estimators in the cumulant tests, and array primitives

SciPy

scipy

1.18.0

scipy.signal.welch

PSD estimator used in the bandwidth and SRRC-shape tests

Pydantic

pydantic

2.13.4

https://docs.pydantic.dev/latest/

Schema validation for TorchSigCommsParams; raises ValidationError on out-of-bounds or extra fields in the input-validation tests

Matplotlib

matplotlib

3.11.0

https://matplotlib.org/stable/

Renders the eight embedded figures (PSDs, constellation scatter plots, cumulant bars)