comnum.blocks#

The blocks of the registry of declarative links as classes, for comnum.Chain.

One class per entry of comnum.spec_blocks(), named in CamelCase (awgn_ebn0 → AwgnEbn0), with the parameters of the block as keyword arguments and its documentation as docstring. A parameter given as comnum.var("name") takes the value of the grid variable name; a parameter left out takes the default of the block (the specification lists the parameters given only). needs and gives are the facts of the frame a block reads and adds (see comnum.spec_check_link()).

This file is generated by tools/gen_blocks.py from the registry of the extension: do not edit it (python tools/gen_blocks.py regenerates it, --check verifies it); at import, a warning names the blocks that differ from the extension.

Example

>>> from comnum import blocks as B
>>> B.AwgnEbn0(ebn0_db=10).spec()
{'type': 'awgn_ebn0', 'ebn0_db': 10}
>>> B.AwgnEbn0.needs, B.AwgnEbn0.gives
(('samples', 'constellation'), ('noise',))

Classes

AdaptiveEqualizer(*[, algorithm, n_taps, ...])

Adaptive FIR equaliser, output at 1 sample per symbol; the n × n butterfly over the polarisations or antennas.

Adc(*, bits[, full_scale, loading, enob, ...])

Analogue-to-digital converter: front-end bandwidth, clock jitter, ENOB noise and uniform quantisation with clipping.

Awgn(*, snr_db[, reference, bandwidth_hz])

Add white Gaussian noise for an SNR in a bandwidth.

AwgnEbn0(*, ebn0_db)

Add white Gaussian noise for an E_b/N_0 (matched-filter definition).

Bps(*[, n, b])

Blind phase search, unwrapped with a period of π/2, and correction.

Capture(*, file[, channel, datatype, fs, ...])

A measured recording as the source: one segment per trial, the reference sequence not yet aligned.

Cdc(*[, fiber, length_km])

Chromatic-dispersion compensation in the frequency domain.

Cdl(*[, profile, delay_spread_s, n_rx, ...])

Clustered delay line of 3GPP TR 38.901 between uniform linear arrays (one tap per cluster, random ray phases and coupling); records the taps for a genie-aided receiver.

CeOfdmRx(*[, n_subcarriers, oversampling, ...])

CE-OFDM receiver back to the symbols: the arctangent phase demodulator, the linear and enhanced receivers of Ahmed and Zeidler (2015) or GAMP (López Morales et al. 2022); records ser_theory and ber_theory when esn0_db is given.

CeOfdmTx(*[, n_subcarriers, oversampling, n_cp])

Constant-envelope OFDM modulator (Thompson et al. 2008): K symbols per block on the bins 1..K of an N = 2J(K + 1) DFT, exp(j2πh x).

Cfo(*[, offset_hz, omega_rad, centred])

Carrier frequency offset.

Classify(*[, candidates, method])

Blind modulation classification at one sample per symbol, by fourth-order cumulants or by likelihood; records class (the index of the decided candidate), correct (1 if it is the transmitted alphabet) and snr_m2m4_db (M2M4 for the decided alphabet).

ClockOffset(*, ppm)

Sampling clock offset: the samples at m (1 + ζ) T (cubic interpolation).

CpmRx(*[, h, pulse, length, bt, sps, ...])

CPM detector (maximum-likelihood sequence detection over the phase trellis, or one-symbol differential detection) back to the symbols.

CpmTx(*[, h, pulse, length, bt, sps, precode])

Continuous-phase modulator of the symbols of a real constellation (CPFSK, MSK, GMSK, raised-cosine CPM): a unit-envelope signal at sps samples per symbol.

Dac(*, bits[, full_scale, loading, bandwidth_hz])

Digital-to-analogue converter: uniform quantisation with clipping and output bandwidth.

Dbp(*[, fiber, steps_per_span, ...])

Digital back-propagation by the split-step method.

Ddpll(*[, kv, tau1_s, tau2_s])

Decision-directed phase-locked loop.

Decimate(*[, sps_out, method, offset])

Reduce the samples per symbol.

Demap(*[, max_log])

Bit LLRs of the received symbols, with the noise variance of every symbol (from the receiver, or the noise block).

Dump(*[, dir, trials, datatype])

Save the samples at this point of the link for the first trials (by index) of every condition, as SigMF recordings <dir>/<campaign>/<condition>/<label>_<trial>.sigmf-meta and -data (one per stream, suffixed _s<stream> after the first).

Dvbs2Rx(*[, modulation, rate, frame, ...])

DVB-S2 receiver of frame-aligned PLFRAMEs: descrambling, demapping, decoding.

Dvbs2Tx(*[, modulation, rate, frame, ...])

DVB-S2 transmitter: BBFRAME, BCH and LDPC, bit interleaving, mapping, PL framing.

Edfa(*, gain_db[, nf_db, fc_hz])

Erbium-doped fibre amplifier with ASE.

FecDecode(*, code[, interleave, seed])

Deinterleave and decode the LLRs into the information bits.

FecEncode(*, code[, blocks, interleave, seed])

Draw the information bits of the coded blocks and encode them (the first block of a coded link).

Fiber(*[, fiber, length_km, compensate_loss])

Linear fibre (loss and dispersion, OptiCommPy linearFiberChannel).

Fir(*, h[, alignment])

Linear channel with complex taps.

Foe(*[, m, refined])

Frequency-offset estimation by the M-th power and correction; records foe_hz.

FrameSync(*[, start, length, max_delay, ...])

Delay and rotation on known symbols, output aligned on the transmitted symbols; records delay and quality.

Gardner(*[, kp, ki, nyquist])

Gardner clock recovery at 2 samples per symbol.

Manakov(*[, fiber, step_rule, ...])

Dual-polarisation nonlinear propagation over the link (Manakov equation, split step with the phase at the middle of the step or OptiCommPy's trapezoidal one), EDFAs with ASE.

ManakovDbp(*[, fiber, steps_per_span, ...])

Dual-polarisation digital back-propagation of the link (Manakov equation, coefficients negated).

Map(*[, constellation, symbol_rate])

Map the coded bits on a constellation (Gray labels, the last symbol padded with random bits).

MatchedFilter(*[, kind, rolloff, n_taps])

Filter with a receive pulse at the current samples per symbol.

MimoRx(*[, detector, k, iterations, llr])

Detect a single-carrier link over flat fading with the known channel; output the symbols and their noise variances.

MimoTx(*[, n_tx, scheme])

Spread the symbols over n_tx antennas: spatial multiplexing (power 1/n_tx per antenna) or Alamouti's code.

NoiseEstimate(*[, mode])

Declare the receiver's posterior: the noise variance of the aligned samples; records sigma2.

Normalize(*[, power_dbm])

Scale the samples to a mean power.

OfdmRx(*[, estimation, detector, k, ...])

Demodulate the OFDM grids, estimate the channel and detect every data resource element; output the symbols and their noise variances.

OfdmTx(*[, n_fft, n_subcarriers, n_cp, ...])

Map every antenna's symbols on resource grids with pilots and OFDM-modulate them (power K/(LN) per sample).

PasDecode(*[, constellation, mb_lambda, n, ...])

PAS receiver: bit LLRs with the amplitude priors, LDPC decoding, dematching (the parameters of pas_encode).

PasEncode(*[, constellation, mb_lambda, n, ...])

Probabilistic amplitude shaping: CCDM-shaped amplitudes, an LDPC code whose parity bits are the signs, square QAM (the first block of a link).

PhaseNoise(*[, linewidth_hz, sigma_rad, origin])

Wiener phase noise.

Pmd(*[, mean_dgd_ps, sections, theta_deg])

Random rotation of the polarisations and polarisation-mode dispersion of a dual-polarisation signal, a new realisation every trial.

Probe(*[, metrics, skip_start, skip_end, scale])

Measure metrics at this point of the link; reported as <label>.<metric> (label: probe by default).

PulseShape(*[, kind, rolloff, n_taps, sps])

Upsample and filter with a transmit pulse, then normalise to unit power.

Rayleigh(*[, n_rx, coherence_samples, ...])

Flat fading y = H x on every antenna; records the channel for a genie-aided receiver.

ReferenceSync(*[, window, start, symmetry])

Align the periodic reference of a capture on the received symbols (circular correlation); records offset and quality.

Resample(*[, sps])

Band-limited resampling of the block (FFT) to a number of samples per symbol.

RxIq(*, t)

Receiver IQ imbalance [Re y; Im y] = T [Re x; Im x].

Source(*[, constellation, n_symbols, ...])

Draw the bits and symbols of a block (Gray labels of OptiCommPy).

Ssfm(*[, fiber, step_km, steps_per_span, ...])

Split-step Fourier propagation over the link, one polarisation.

Tdl(*[, profile, delay_spread_s, ...])

Tapped-delay-line multipath fading with Clarke/Jakes Doppler; records the taps for a genie-aided receiver.

TxIq(*, beta)

Transmitter IQ imbalance y = x + β x*.

Viterbi(*[, n, m])

Viterbi–Viterbi phase estimation and correction.

WdmRx(*[, sps])

Bring the channel under test to baseband and keep its band (ideal low-pass by resampling).

WdmTx(*[, n_channels, spacing_hz, sps, ...])

WDM transmitter: the channel under test and independently modulated neighbours on the grid of OptiCommPy's simpleWDMTx.

class comnum.blocks.AdaptiveEqualizer(*, algorithm: str | list | Var = 'cma', n_taps: int | Var = 15, mu: float | list | Var = 0.001, passes: int | Var = 1, update_rule: str | Var | None = None, kikuchi: int | Var | None = None)#

Adaptive FIR equaliser, output at 1 sample per symbol; the n × n butterfly over the polarisations or antennas.

Needs: samples, constellation. Gives: nothing.

Parameters:
  • algorithm (str | list) – cma, rde, nlms, dd-lms, or a schedule [[algorithm, symbols], …]; default cma

  • n_taps (int) – taps; default 15

  • mu (float | list) – step size, or one per stage of the schedule (the last one holds for the following stages); default 1e-3

  • passes (int) – passes over the block; default 1

  • update_rule (str) – the update rule of every stage instead of that of its algorithm: sign for the sign-error update; one of lms, nlms, sign; default none

  • kikuchi (int) – 2 × 2: Kikuchi’s initialisation against the singularity, output 0 alone during this number of symbols, then output 1 as its unitary complement; records correlation and singular; default none

gives = ()#
needs = ('samples', 'constellation')#
param_names = ('algorithm', 'n_taps', 'mu', 'passes', 'update_rule', 'kikuchi')#
class comnum.blocks.Adc(*, bits: int | Var, full_scale: float | Var | None = None, loading: float | Var | None = None, enob: float | Var | None = None, jitter_s: float | Var = 0.0, bandwidth_hz: float | Var | None = None)#

Analogue-to-digital converter: front-end bandwidth, clock jitter, ENOB noise and uniform quantisation with clipping.

Needs: samples. Gives: nothing.

Parameters:
  • bits (int) – resolution N (1 to 24) [bits]; required

  • full_scale (float) – full scale A of each dimension (levels ±(A - Δ/2), Δ = 2A/2^N); default loading × RMS

  • loading (float) – full scale in RMS values of one dimension of the samples (an automatic gain control); default optimal for a Gaussian input

  • enob (float) – effective number of bits (≤ bits); default bits

  • jitter_s (float) – RMS sampling-clock jitter [s]; default 0.0

  • bandwidth_hz (float) – 3 dB bandwidth of the front end (Gaussian) [Hz]; default unlimited

gives = ()#
needs = ('samples',)#
param_names = ('bits', 'full_scale', 'loading', 'enob', 'jitter_s', 'bandwidth_hz')#
class comnum.blocks.Awgn(*, snr_db: float | Var, reference: str | Var = 'signal', bandwidth_hz: float | Var | None = None)#

Add white Gaussian noise for an SNR in a bandwidth.

Needs: samples. Gives: noise.

Parameters:
  • snr_db (float) – signal-to-noise ratio [dB]; required

  • reference (str) – signal: measured power (OptiCommPy); unit: E_s = 1 whatever the samples, σ² = 10^(-SNR/10) per symbol; one of signal, unit; default signal

  • bandwidth_hz (float) – noise bandwidth B: σ² = (f_s/B) P / SNR [Hz]; default symbol rate

gives = ('noise',)#
needs = ('samples',)#
param_names = ('snr_db', 'reference', 'bandwidth_hz')#
class comnum.blocks.AwgnEbn0(*, ebn0_db: float | Var)#

Add white Gaussian noise for an E_b/N_0 (matched-filter definition).

Needs: samples, constellation. Gives: noise.

Parameters:

ebn0_db (float) – E_b/N_0 [dB]; required

gives = ('noise',)#
needs = ('samples', 'constellation')#
param_names = ('ebn0_db',)#
class comnum.blocks.Bps(*, n: int | Var = 35, b: int | Var = 64)#

Blind phase search, unwrapped with a period of π/2, and correction.

Needs: samples, constellation. Gives: nothing.

Parameters:
  • n (int) – half window [symbols]; default 35

  • b (int) – test phases; default 64

gives = ()#
needs = ('samples', 'constellation')#
param_names = ('n', 'b')#
class comnum.blocks.Capture(*, file: str | Var, channel: int | Var = 0, datatype: str | Var | None = None, fs: float | Var | None = None, symbol_rate: float | Var, constellation: str | dict | Var = '16-QAM', reference: str | Var, segment: int | Var | None = None, offset: str | int | Var = 'random')#

A measured recording as the source: one segment per trial, the reference sequence not yet aligned.

Needs: nothing. Gives: bits, symbols, constellation, samples, capture.

Parameters:
  • file (str) – SigMF (.sigmf-meta/.sigmf-data or a .sigmf archive), NPY (.npy) or raw samples, relative to the specification; required

  • channel (int) – the channel of a multi-channel SigMF recording; default 0

  • datatype (str) – data type of a raw file: cf32_le, ci16_le, cf64_le, ci8, cu8, …; default none

  • fs (float) – sampling rate; required when the file does not record it [Hz]; default from file

  • symbol_rate (float) – symbol rate [Bd]; required

  • constellation (str | dict) – the transmitted constellation; keys kind, m; default 16-QAM

  • reference (str) – one period of the transmitted symbols (.npy complex) or indices (.npy or text integers); required

  • segment (int) – samples per trial; default whole file

  • offset (str | int) – first sample of a segment: random (drawn per trial) or an integer; default random

gives = ('bits', 'symbols', 'constellation', 'samples', 'capture')#
needs = ()#
param_names = ('file', 'channel', 'datatype', 'fs', 'symbol_rate', 'constellation', 'reference', 'segment', 'offset')#
class comnum.blocks.Cdc(*, fiber: dict | Var | None = None, length_km: float | Var | None = None)#

Chromatic-dispersion compensation in the frequency domain.

Needs: samples. Gives: nothing.

Parameters:
  • fiber (dict) – fibre parameters, merged over the fiber of the specification (see FiberParams); its raman mapping adds Raman pumps and ISRS; keys alpha_db_km, d_ps_nm_km, gamma_w_km, span_km, n_spans, fc_hz, nf_db, slope_ps_nm2_km, raman; default spec fiber

  • length_km (float) – compensated length [km]; default total

gives = ()#
needs = ('samples',)#
param_names = ('fiber', 'length_km')#
class comnum.blocks.Cdl(*, profile: str | Var = 'CDL-A', delay_spread_s: float | Var = 1e-07, n_rx: int | Var = 1, spacing_wavelengths: float | Var = 0.5, velocity_mps: float | Var = 0.0, fc_hz: float | Var = 3500000000.0)#

Clustered delay line of 3GPP TR 38.901 between uniform linear arrays (one tap per cluster, random ray phases and coupling); records the taps for a genie-aided receiver.

Needs: samples. Gives: csi.

Parameters:
  • profile (str) – the profile of TR 38.901 Tables 7.7.1-1 to 7.7.1-5 (A, B, C: NLOS; D, E: LOS); one of CDL-A, CDL-B, CDL-C, CDL-D, CDL-E; default CDL-A

  • delay_spread_s (float) – desired RMS delay spread (TR 38.901 §7.7.3) [s]; default 100e-9

  • n_rx (int) – receive antennas, a vertical uniform linear array; default 1

  • spacing_wavelengths (float) – element spacing of both arrays [wavelengths]; default 0.5

  • velocity_mps (float) – speed of the receiver along the array axis; 0 for a channel constant over the trial [m/s]; default 0.0

  • fc_hz (float) – carrier frequency (the wavelength of the Doppler shifts) [Hz]; default 3.5e9

gives = ('csi',)#
needs = ('samples',)#
param_names = ('profile', 'delay_spread_s', 'n_rx', 'spacing_wavelengths', 'velocity_mps', 'fc_hz')#
class comnum.blocks.CeOfdmRx(*, n_subcarriers: int | Var = 64, oversampling: int | Var = 4, h: float | Var, n_cp: int | Var = 0, unwrap: str | Var | None = None, receiver: str | Var = 'arctangent', esn0_db: float | Var | None = None)#

CE-OFDM receiver back to the symbols: the arctangent phase demodulator, the linear and enhanced receivers of Ahmed and Zeidler (2015) or GAMP (López Morales et al. 2022); records ser_theory and ber_theory when esn0_db is given.

Needs: samples, constellation. Gives: nothing.

Parameters:
  • n_subcarriers (int) – data subcarriers K (as the modulator); default 64

  • oversampling (int) – oversampling factor J (as the modulator); default 4

  • h (float) – modulation index (as the modulator); required

  • n_cp (int) – cyclic prefix (as the modulator) [samples]; default 0

  • unwrap (str) – none (principal phase) or stream (unwrapped along the stream, the phase unwrapper of the paper); one of none, stream; default none

  • receiver (str) – arctangent (phase demodulator), linear (Im r) or enhanced (Im r (2 - Re r)) of Ahmed and Zeidler 2015, or gamp (near-optimum message passing, needs esn0_db); one of arctangent, linear, enhanced, gamp; default arctangent

  • esn0_db (float) – E_s/N_0 of the channel per data symbol: records ser_theory and ber_theory (the linear regime for arctangent and gamp, where it is the optimum asymptotic rate of QPSK; Bussgang’s analysis for linear and enhanced), and sets the noise variance of gamp [dB]; default none

gives = ()#
needs = ('samples', 'constellation')#
param_names = ('n_subcarriers', 'oversampling', 'h', 'n_cp', 'unwrap', 'receiver', 'esn0_db')#
class comnum.blocks.CeOfdmTx(*, n_subcarriers: int | Var = 64, oversampling: int | Var = 4, h: float | Var, n_cp: int | Var = 0)#

Constant-envelope OFDM modulator (Thompson et al. 2008): K symbols per block on the bins 1..K of an N = 2J(K + 1) DFT, exp(j2πh x).

Needs: samples. Gives: nothing.

Parameters:
  • n_subcarriers (int) – data subcarriers K per block; default 64

  • oversampling (int) – oversampling factor J; default 4

  • h (float) – modulation index (phase standard deviation 2πh); required

  • n_cp (int) – cyclic prefix [samples]; default 0

gives = ()#
needs = ('samples',)#
param_names = ('n_subcarriers', 'oversampling', 'h', 'n_cp')#
class comnum.blocks.Cfo(*, offset_hz: float | Var | None = None, omega_rad: float | Var | None = None, centred: bool | Var = False)#

Carrier frequency offset.

Needs: samples. Gives: nothing.

Parameters:
  • offset_hz (float) – offset [Hz]; default none

  • omega_rad (float) – offset per sample, instead of offset_hz [rad/sample]; default none

  • centred (bool) – phase zero at the middle of the block, e^{jω(n - N/2)}, instead of the first sample; default false

gives = ()#
needs = ('samples',)#
param_names = ('offset_hz', 'omega_rad', 'centred')#
class comnum.blocks.Classify(*, candidates: list | Var | None = None, method: str | Var = 'ml')#

Blind modulation classification at one sample per symbol, by fourth-order cumulants or by likelihood; records class (the index of the decided candidate), correct (1 if it is the transmitted alphabet) and snr_m2m4_db (M2M4 for the decided alphabet).

Needs: samples. Gives: nothing.

Parameters:
  • candidates (list) – the candidate alphabets; default [BPSK, QPSK, 8-PSK, 16-QAM, 64-QAM]

  • method (str) – cumulants (Swami & Sadler 2000, normalised by the received power: for high SNR) or ml (likelihood, the scale and the noise estimated by M2M4 under every candidate); one of cumulants, ml; default ml

gives = ()#
needs = ('samples',)#
param_names = ('candidates', 'method')#
class comnum.blocks.ClockOffset(*, ppm: float | Var)#

Sampling clock offset: the samples at m (1 + ζ) T (cubic interpolation).

Needs: samples. Gives: nothing.

Parameters:

ppm (float) – the relative offset ζ = (T’ - T)/T of the sampling period of the receiver, positive for a slower clock [ppm]; required

gives = ()#
needs = ('samples',)#
param_names = ('ppm',)#
class comnum.blocks.CpmRx(*, h: str | Var = '1/2', pulse: str | Var = 'rec', length: int | Var = 1, bt: float | Var = 0.3, sps: int | Var = 4, detector: str | Var = 'ml', rx_bt: float | Var | None = None, precode: bool | Var = False)#

CPM detector (maximum-likelihood sequence detection over the phase trellis, or one-symbol differential detection) back to the symbols.

Needs: samples, constellation. Gives: nothing.

Parameters:
  • h (str) – as cpm_tx; default 1/2

  • pulse (str) – as cpm_tx; one of rec, rc, gmsk; default rec

  • length (int) – as cpm_tx; default 1

  • bt (float) – as cpm_tx; default 0.3

  • sps (int) – as cpm_tx; default 4

  • detector (str) – ml (Viterbi over the phase trellis, coherent) or differential (sign of the one-symbol phase increment, after a Gaussian low-pass of rx_bt); one of ml, differential; default ml

  • rx_bt (float) – bandwidth–time product of the receive low-pass of the differential detector (none: no filter); default none

  • precode (bool) – as cpm_tx (with the ml detector); default false

gives = ()#
needs = ('samples', 'constellation')#
param_names = ('h', 'pulse', 'length', 'bt', 'sps', 'detector', 'rx_bt', 'precode')#
class comnum.blocks.CpmTx(*, h: str | Var = '1/2', pulse: str | Var = 'rec', length: int | Var = 1, bt: float | Var = 0.3, sps: int | Var = 4, precode: bool | Var = False)#

Continuous-phase modulator of the symbols of a real constellation (CPFSK, MSK, GMSK, raised-cosine CPM): a unit-envelope signal at sps samples per symbol.

Needs: samples, constellation. Gives: nothing.

Parameters:
  • h (str) – modulation index p/q, as a fraction (1/2 with a rectangular pulse of length 1 is MSK); default 1/2

  • pulse (str) – frequency pulse: rectangular (1REC is CPFSK), raised cosine, or Gaussian (GMSK, with bt); one of rec, rc, gmsk; default rec

  • length (int) – length L of the pulse in symbols; default 1

  • bt (float) – bandwidth–time product of the Gaussian pulse; default 0.3

  • sps (int) – samples per symbol; default 4

  • precode (bool) – MSK precoding (binary, h 1/2, rec, length 1): the bits are the boundary signs of the equivalent OQPSK signal, and cpm_rx reads them from the phase states of the ML path, with the BER of BPSK; default false

gives = ()#
needs = ('samples', 'constellation')#
param_names = ('h', 'pulse', 'length', 'bt', 'sps', 'precode')#
class comnum.blocks.Dac(*, bits: int | Var, full_scale: float | Var | None = None, loading: float | Var | None = None, bandwidth_hz: float | Var | None = None)#

Digital-to-analogue converter: uniform quantisation with clipping and output bandwidth.

Needs: samples. Gives: nothing.

Parameters:
  • bits (int) – resolution N (1 to 24) [bits]; required

  • full_scale (float) – full scale A of each dimension; default loading × RMS

  • loading (float) – full scale in RMS values of one dimension of the samples; default optimal for a Gaussian input

  • bandwidth_hz (float) – 3 dB bandwidth of the output (Gaussian) [Hz]; default unlimited

gives = ()#
needs = ('samples',)#
param_names = ('bits', 'full_scale', 'loading', 'bandwidth_hz')#
class comnum.blocks.Dbp(*, fiber: dict | Var | None = None, steps_per_span: int | Var = 1, step_distribution: str | Var = 'uniform', step_factor: float | Var = 0.4, nonlinear_length: str | Var = 'effective', amplification: str | Var = 'edfa', nonlinear: bool | Var = True, nonlinear_scale: float | Var = 1.0)#

Digital back-propagation by the split-step method.

Needs: samples. Gives: nothing.

Parameters:
  • fiber (dict) – fibre parameters, merged over the fiber of the specification (see FiberParams); its raman mapping adds Raman pumps and ISRS; keys alpha_db_km, d_ps_nm_km, gamma_w_km, span_km, n_spans, fc_hz, nf_db, slope_ps_nm2_km, raman; default spec fiber

  • steps_per_span (int) – symmetric steps per span; default 1

  • step_distribution (str) – the steps of a span: equal, logarithmic (Bosco et al. 2000: every step carries the same integrated power of the forward span; better with 2 to 8 steps per span, worse with many), or modified logarithmic (Zhang et al. 2013: the attenuation times step_factor); one of uniform, logarithmic, modified_logarithmic; default uniform

  • step_factor (float) – the adjusting factor of the modified logarithmic steps (0.4 recommended by Zhang et al. 2013); default 0.4

  • nonlinear_length (str) – the nonlinear length of a coarse step: its effective length (the power integrated over the step) or the step itself (the midpoint rule of Häger & Pfister 2021); one of effective, step; default effective

  • amplification (str) – the amplification of the forward link; one of edfa, ideal, none; default edfa

  • nonlinear (bool) – false: linear back-propagation (dispersion compensation and loss); default true

  • nonlinear_scale (float) – ξ: multiplies the nonlinear phase (optimised DBP with few steps, Ip & Kahn 2008); default 1.0

gives = ()#
needs = ('samples',)#
param_names = ('fiber', 'steps_per_span', 'step_distribution', 'step_factor', 'nonlinear_length', 'amplification', 'nonlinear', 'nonlinear_scale')#
class comnum.blocks.Ddpll(*, kv: float | Var = 0.1, tau1_s: float | Var | None = None, tau2_s: float | Var | None = None)#

Decision-directed phase-locked loop.

Needs: samples, constellation. Gives: nothing.

Parameters:
  • kv (float) – VCO gain; default 0.1

  • tau1_s (float) – loop-filter time constant [s]; default 1/(2π 10 MHz)

  • tau2_s (float) – loop-filter time constant [s]; default 1/(2π 10 MHz)

gives = ()#
needs = ('samples', 'constellation')#
param_names = ('kv', 'tau1_s', 'tau2_s')#
class comnum.blocks.Decimate(*, sps_out: int | Var = 1, method: str | Var = 'max_variance', offset: int | Var = 0)#

Reduce the samples per symbol.

Needs: samples. Gives: nothing.

Parameters:
  • sps_out (int) – output samples per symbol; default 1

  • method (str) – max_variance (OptiCommPy decimate) or offset; one of max_variance, offset; default max_variance

  • offset (int) – sampling phase of the offset method; default 0

gives = ()#
needs = ('samples',)#
param_names = ('sps_out', 'method', 'offset')#
class comnum.blocks.Demap(*, max_log: bool | Var = False)#

Bit LLRs of the received symbols, with the noise variance of every symbol (from the receiver, or the noise block).

Needs: samples, symbols, constellation, noise. Gives: llr.

Parameters:

max_log (bool) – max-log approximation instead of the exact LLRs; default false

gives = ('llr',)#
needs = ('samples', 'symbols', 'constellation', 'noise')#
param_names = ('max_log',)#
class comnum.blocks.Dump(*, dir: str | Var = 'results/signals', trials: int | Var = 1, datatype: str | Var = 'cf64')#

Save the samples at this point of the link for the first trials (by index) of every condition, as SigMF recordings <dir>/<campaign>/<condition>/<label>_<trial>.sigmf-meta and -data (one per stream, suffixed _s<stream> after the first).

Needs: samples. Gives: nothing.

Parameters:
  • dir (str) – directory of the recordings (relative to the working directory); default results/signals

  • trials (int) – trials saved per condition: those of index 0 to trials - 1, whatever the order the threads run them in; default 1

  • datatype (str) – sample format of the SigMF data file; one of cf32, cf64, ci16; default cf64

gives = ()#
needs = ('samples',)#
param_names = ('dir', 'trials', 'datatype')#
class comnum.blocks.Dvbs2Rx(*, modulation: str | Var = 'QPSK', rate: str | Var = '1/2', frame: str | Var = 'normal', pilots: bool | Var = True, scrambling_code: int | Var = 0, frames: int | Var = 1, symbol_rate: float | Var = 1.0, iterations: int | Var = 50, max_log: bool | Var = False)#

DVB-S2 receiver of frame-aligned PLFRAMEs: descrambling, demapping, decoding.

Needs: samples, noise. Gives: decoded.

Parameters:
  • modulation (str) – modulation; one of QPSK, 8PSK, 16APSK, 32APSK; default QPSK

  • rate (str) – code rate (Table 12); one of 1/4, 1/3, 2/5, 1/2, 3/5, 2/3, 3/4, 4/5, 5/6, 8/9, 9/10; default 1/2

  • frame (str) – FECFRAME of 64 800 bits (normal) or 16 200 bits (short); one of normal, short, 64800, 16200; default normal

  • pilots (bool) – pilot blocks of 36 symbols every 16 slots; default true

  • scrambling_code (int) – number n of the Gold scrambling sequence; default 0

  • frames (int) – PLFRAMEs per trial (dvbs2_tx; the receiver reads it from the frame); default 1

  • symbol_rate (float) – symbol rate [Bd]; default 1.0

  • iterations (int) – LDPC iterations (sum-product, layered); default 50

  • max_log (bool) – max-log demapping instead of the exact LLRs; default false

gives = ('decoded',)#
needs = ('samples', 'noise')#
param_names = ('modulation', 'rate', 'frame', 'pilots', 'scrambling_code', 'frames', 'symbol_rate', 'iterations', 'max_log')#
class comnum.blocks.Dvbs2Tx(*, modulation: str | Var = 'QPSK', rate: str | Var = '1/2', frame: str | Var = 'normal', pilots: bool | Var = True, scrambling_code: int | Var = 0, frames: int | Var = 1, symbol_rate: float | Var = 1.0, iterations: int | Var = 50, max_log: bool | Var = False)#

DVB-S2 transmitter: BBFRAME, BCH and LDPC, bit interleaving, mapping, PL framing.

Needs: nothing. Gives: samples, payload.

Parameters:
  • modulation (str) – modulation; one of QPSK, 8PSK, 16APSK, 32APSK; default QPSK

  • rate (str) – code rate (Table 12); one of 1/4, 1/3, 2/5, 1/2, 3/5, 2/3, 3/4, 4/5, 5/6, 8/9, 9/10; default 1/2

  • frame (str) – FECFRAME of 64 800 bits (normal) or 16 200 bits (short); one of normal, short, 64800, 16200; default normal

  • pilots (bool) – pilot blocks of 36 symbols every 16 slots; default true

  • scrambling_code (int) – number n of the Gold scrambling sequence; default 0

  • frames (int) – PLFRAMEs per trial (dvbs2_tx; the receiver reads it from the frame); default 1

  • symbol_rate (float) – symbol rate [Bd]; default 1.0

  • iterations (int) – LDPC iterations (sum-product, layered); default 50

  • max_log (bool) – max-log demapping instead of the exact LLRs; default false

gives = ('samples', 'payload')#
needs = ()#
param_names = ('modulation', 'rate', 'frame', 'pilots', 'scrambling_code', 'frames', 'symbol_rate', 'iterations', 'max_log')#
class comnum.blocks.Edfa(*, gain_db: float | Var, nf_db: float | Var = 4.5, fc_hz: float | Var = 193100000000000.0)#

Erbium-doped fibre amplifier with ASE.

Needs: samples. Gives: nothing.

Parameters:
  • gain_db (float) – gain [dB]; required

  • nf_db (float) – noise figure [dB]; default 4.5

  • fc_hz (float) – carrier frequency [Hz]; default 193.1e12

gives = ()#
needs = ('samples',)#
param_names = ('gain_db', 'nf_db', 'fc_hz')#
class comnum.blocks.FecDecode(*, code: dict | Var, interleave: bool | Var = False, seed: int | Var = 0)#

Deinterleave and decode the LLRs into the information bits.

Needs: llr. Gives: decoded.

Parameters:
  • code (dict) – the code of fec_encode, with the decoder settings; required

  • interleave (bool) – random bit interleaver over the coded bits of the trial (BICM), the same in fec_encode and fec_decode; default false

  • seed (int) – seed of the interleaver; default 0

gives = ('decoded',)#
needs = ('llr',)#
param_names = ('code', 'interleave', 'seed')#
class comnum.blocks.FecEncode(*, code: dict | Var, blocks: int | Var = 1, interleave: bool | Var = False, seed: int | Var = 0)#

Draw the information bits of the coded blocks and encode them (the first block of a coded link).

Needs: nothing. Gives: bits, payload.

Parameters:
  • code (dict) – the code: {type: conv|rs|turbo|ldpc|polar, …} and its parameters; required

  • blocks (int) – codewords per trial; default 1

  • interleave (bool) – random bit interleaver over the coded bits of the trial (BICM), the same in fec_encode and fec_decode; default false

  • seed (int) – seed of the interleaver; default 0

gives = ('bits', 'payload')#
needs = ()#
param_names = ('code', 'blocks', 'interleave', 'seed')#
class comnum.blocks.Fiber(*, fiber: dict | Var | None = None, length_km: float | Var | None = None, compensate_loss: bool | Var = True)#

Linear fibre (loss and dispersion, OptiCommPy linearFiberChannel).

Needs: samples. Gives: nothing.

Parameters:
  • fiber (dict) – fibre parameters, merged over the fiber of the specification (see FiberParams); its raman mapping adds Raman pumps and ISRS; keys alpha_db_km, d_ps_nm_km, gamma_w_km, span_km, n_spans, fc_hz, nf_db, slope_ps_nm2_km, raman; default spec fiber

  • length_km (float) – length; the whole link by default [km]; default total

  • compensate_loss (bool) – restore the power with an ideal gain e^(αL/2); default true

gives = ()#
needs = ('samples',)#
param_names = ('fiber', 'length_km', 'compensate_loss')#
class comnum.blocks.Fir(*, h: list | Var, alignment: str | Var = 'causal')#

Linear channel with complex taps.

Needs: samples. Gives: nothing.

Parameters:
  • h (list) – taps, [[re, im], …] or real numbers; required

  • alignment (str) – causal: y[n] = Σ h[k] x[n-k], the delay of the taps kept; centred: the taps centred on the samples (OptiCommPy firFilter); one of causal, centred, centered; default causal

gives = ()#
needs = ('samples',)#
param_names = ('h', 'alignment')#
class comnum.blocks.Foe(*, m: int | Var = 4, refined: bool | Var = True)#

Frequency-offset estimation by the M-th power and correction; records foe_hz.

Needs: samples. Gives: nothing.

Parameters:
  • m (int) – rotational symmetry; default 4

  • refined (bool) – refine the periodogram peak between the bins; default true

gives = ()#
needs = ('samples',)#
param_names = ('m', 'refined')#
class comnum.blocks.FrameSync(*, start: int | Var = 0, length: int | Var = 512, max_delay: int | Var = 64, symmetry: int | Var = 4, exclude: bool | Var = True)#

Delay and rotation on known symbols, output aligned on the transmitted symbols; records delay and quality.

Needs: samples, symbols. Gives: nothing.

Parameters:
  • start (int) – first known symbol; default 0

  • length (int) – number of known symbols; default 512

  • max_delay (int) – largest delay searched [symbols]; default 64

  • symmetry (int) – rotational symmetry of the constellation; 0 removes the exact phase; default 4

  • exclude (bool) – exclude the known symbols from the metrics; default true

gives = ()#
needs = ('samples', 'symbols')#
param_names = ('start', 'length', 'max_delay', 'symmetry', 'exclude')#
class comnum.blocks.Gardner(*, kp: float | Var = 0.001, ki: float | Var = 1e-06, nyquist: bool | Var = True)#

Gardner clock recovery at 2 samples per symbol.

Needs: samples. Gives: nothing.

Parameters:
  • kp (float) – proportional gain; default 1e-3

  • ki (float) – integral gain; default 1e-6

  • nyquist (bool) – detector for Nyquist pulses; default true

gives = ()#
needs = ('samples',)#
param_names = ('kp', 'ki', 'nyquist')#
class comnum.blocks.Manakov(*, fiber: dict | Var | None = None, step_rule: str | Var = 'fwm', steps_per_span: int | Var = 100, fwm_phase_rad: float | Var = 20.0, bandwidth_hz: float | Var | None = None, max_nl_phase_rad: float | Var = 0.02, step_km: float | Var | None = None, nonlinear_step: str | Var = 'midpoint', check_sampling: bool | Var = True, max_iterations: int | Var = 10, tolerance: float | Var = 1e-05, amplification: str | Var = 'edfa', noise: bool | Var = True)#

Dual-polarisation nonlinear propagation over the link (Manakov equation, split step with the phase at the middle of the step or OptiCommPy’s trapezoidal one), EDFAs with ASE.

Needs: samples. Gives: nothing.

Parameters:
  • fiber (dict) – fibre parameters, merged over the fiber of the specification (see FiberParams); its raman mapping adds Raman pumps and ISRS; keys alpha_db_km, d_ps_nm_km, gamma_w_km, span_km, n_spans, fc_hz, nf_db, slope_ps_nm2_km, raman; default spec fiber

  • step_rule (str) – the steps: the four-wave-mixing phase of Musetti et al. 2018 (power independent), OptiCommPy’s nonlinear phase per step, or steps_per_span logarithmic steps (Bosco et al. 2000); one of fwm, nonlinear_phase, logarithmic; default fwm

  • steps_per_span (int) – logarithmic steps per span (step_rule logarithmic); default 100

  • fwm_phase_rad (float) – four-wave-mixing phase across the bandwidth in the first step of a span (step_rule fwm) [rad]; default 20.0

  • bandwidth_hz (float) – signal bandwidth of the rule fwm (measured on the launched field if absent) [Hz]; default none

  • max_nl_phase_rad (float) – largest nonlinear phase rotation per step (step_rule nonlinear_phase) [rad]; default 2e-2

  • step_km (float) – a fixed step instead of the adaptive one [km]; default none

  • nonlinear_step (str) – the nonlinear phase of a step: the power at its middle (the scalar solver) or the trapezoidal mean of the power at its ends (OptiCommPy, iterated; less accurate in WDM); one of midpoint, trapezoidal; default midpoint

  • check_sampling (bool) – refuse a signal whose sampling rate or block cannot hold the four-wave mixing and the walk-off of the link (Musetti et al. 2018, Appendix B); default true

  • max_iterations (int) – trapezoidal iterations per step at most; default 10

  • tolerance (float) – convergence tolerance of the iterations; default 1e-5

  • amplification (str) – edfa (gain αL, ASE), ideal (noiseless gain) or none; with fiber.raman, the amplifier restores every frequency; one of edfa, ideal, none; default edfa

  • noise (bool) – draw the ASE of the EDFAs and the spontaneous Raman noise; default true

gives = ()#
needs = ('samples',)#
param_names = ('fiber', 'step_rule', 'steps_per_span', 'fwm_phase_rad', 'bandwidth_hz', 'max_nl_phase_rad', 'step_km', 'nonlinear_step', 'check_sampling', 'max_iterations', 'tolerance', 'amplification', 'noise')#
class comnum.blocks.ManakovDbp(*, fiber: dict | Var | None = None, steps_per_span: int | Var = 1, nonlinear_scale: float | Var = 1.0, amplification: str | Var = 'edfa')#

Dual-polarisation digital back-propagation of the link (Manakov equation, coefficients negated).

Needs: samples. Gives: nothing.

Parameters:
  • fiber (dict) – fibre parameters, merged over the fiber of the specification (see FiberParams); its raman mapping adds Raman pumps and ISRS; keys alpha_db_km, d_ps_nm_km, gamma_w_km, span_km, n_spans, fc_hz, nf_db, slope_ps_nm2_km, raman; default spec fiber

  • steps_per_span (int) – symmetric steps per span; default 1

  • nonlinear_scale (float) – ξ: multiplies the nonlinear phase (0: dispersion compensation only); default 1.0

  • amplification (str) – the amplification of the forward link; one of edfa, ideal, none; default edfa

gives = ()#
needs = ('samples',)#
param_names = ('fiber', 'steps_per_span', 'nonlinear_scale', 'amplification')#
class comnum.blocks.Map(*, constellation: str | dict | Var = 'QPSK', symbol_rate: float | Var = 1.0)#

Map the coded bits on a constellation (Gray labels, the last symbol padded with random bits).

Needs: bits. Gives: symbols, constellation, samples.

Parameters:
  • constellation (str | dict) – the constellation, as for source; keys kind, m; default QPSK

  • symbol_rate (float) – symbol rate [Bd]; default 1.0

gives = ('symbols', 'constellation', 'samples')#
needs = ('bits',)#
param_names = ('constellation', 'symbol_rate')#
class comnum.blocks.MatchedFilter(*, kind: str | Var = 'rrc', rolloff: float | Var = 0.1, n_taps: int | Var = 1025)#

Filter with a receive pulse at the current samples per symbol.

Needs: samples. Gives: nothing.

Parameters:
  • kind (str) – the pulse; one of rect, nrz, rc, rrc, rz; default rrc

  • rolloff (float) – roll-off of rc and rrc; default 0.1

  • n_taps (int) – taps of rc and rrc (odd: on the sampling instants); default 1025

gives = ()#
needs = ('samples',)#
param_names = ('kind', 'rolloff', 'n_taps')#
class comnum.blocks.MimoRx(*, detector: str | Var = 'mmse', k: int | Var = 8, iterations: int | Var = 10, llr: bool | Var = False)#

Detect a single-carrier link over flat fading with the known channel; output the symbols and their noise variances.

Needs: samples, constellation, csi. Gives: noise, llr.

Parameters:
  • detector (str) – mr (matched filter), zf, mmse, sic (MMSE-SIC), zf_sic (ZF-SIC), ml, sphere, kbest, amp (LAMA) or oamp (OAMP-LMMSE); one of mr, zf, mmse, sic, zf_sic, ml, sphere, kbest, amp, oamp; default mmse

  • k (int) – paths of kbest; default 8

  • iterations (int) – iterations of amp and oamp; default 10

  • llr (bool) – also compute the bit LLRs with the detector (mr, zf, mmse, ml, kbest, amp, oamp); default false

gives = ('noise', 'llr')#
needs = ('samples', 'constellation', 'csi')#
param_names = ('detector', 'k', 'iterations', 'llr')#
class comnum.blocks.MimoTx(*, n_tx: int | Var = 2, scheme: str | Var = 'spatial')#

Spread the symbols over n_tx antennas: spatial multiplexing (power 1/n_tx per antenna) or Alamouti’s code.

Needs: samples. Gives: nothing.

Parameters:
  • n_tx (int) – transmit antennas; default 2

  • scheme (str) – spatial (V-BLAST, symbol i on antenna i mod n_tx) or alamouti (n_tx = 2); one of spatial, alamouti; default spatial

gives = ()#
needs = ('samples',)#
param_names = ('n_tx', 'scheme')#
class comnum.blocks.NoiseEstimate(*, mode: str | Var = 'decisions')#

Declare the receiver’s posterior: the noise variance of the aligned samples; records sigma2.

Needs: samples, symbols, constellation. Gives: noise.

Parameters:

mode (str) – decisions (blind, around the nearest points) or known (around the transmitted symbols); one of decisions, known; default decisions

gives = ('noise',)#
needs = ('samples', 'symbols', 'constellation')#
param_names = ('mode',)#
class comnum.blocks.Normalize(*, power_dbm: float | Var | None = None)#

Scale the samples to a mean power.

Needs: samples. Gives: nothing.

Parameters:

power_dbm (float) – mean power [dBm]; default unit power

gives = ()#
needs = ('samples',)#
param_names = ('power_dbm',)#
class comnum.blocks.OfdmRx(*, estimation: str | Var = 'perfect', detector: str | Var = 'mmse', k: int | Var = 8, iterations: int | Var = 10, llr: bool | Var = False)#

Demodulate the OFDM grids, estimate the channel and detect every data resource element; output the symbols and their noise variances.

Needs: samples, constellation, ofdm. Gives: noise, llr.

Parameters:
  • estimation (str) – perfect (the channel of the channel block), ls (linear interpolation) or lmmse (uniform delay profile over the prefix); one of perfect, ls, lmmse; default perfect

  • detector (str) – mr (matched filter), zf, mmse, sic (MMSE-SIC), zf_sic (ZF-SIC), ml, sphere, kbest, amp (LAMA) or oamp (OAMP-LMMSE); one of mr, zf, mmse, sic, zf_sic, ml, sphere, kbest, amp, oamp; default mmse

  • k (int) – paths of kbest; default 8

  • iterations (int) – iterations of amp and oamp; default 10

  • llr (bool) – also compute the bit LLRs with the detector (mr, zf, mmse, ml, kbest, amp, oamp); default false

gives = ('noise', 'llr')#
needs = ('samples', 'constellation', 'ofdm')#
param_names = ('estimation', 'detector', 'k', 'iterations', 'llr')#
class comnum.blocks.OfdmTx(*, n_fft: int | Var = 256, n_subcarriers: int | Var = 200, n_cp: int | Var = 16, oversampling: int | Var = 1, dc_null: bool | Var = False, n_symbols: int | Var = 14, pilots: str | dict | Var | None = None, subcarrier_spacing_hz: float | Var = 15000.0, seed: int | Var = 0)#

Map every antenna’s symbols on resource grids with pilots and OFDM-modulate them (power K/(LN) per sample).

Needs: samples. Gives: ofdm.

Parameters:
  • n_fft (int) – subcarrier grid N; default 256

  • n_subcarriers (int) – active subcarriers K; default 200

  • n_cp (int) – cyclic prefix (Nyquist-rate samples) [samples]; default 16

  • oversampling (int) – oversampling L; default 1

  • dc_null (bool) – leave the DC subcarrier empty; default false

  • n_symbols (int) – OFDM symbols per grid; default 14

  • pilots (str | dict) – pattern block {period}, comb {spacing}, lattice {freq, time} or none; with several antennas the pilots of a symbol are dealt to the antennas in turn; keys pattern, period, spacing, freq, time; default {pattern: lattice, freq: 3, time: 4}

  • subcarrier_spacing_hz (float) – subcarrier spacing Δf [Hz]; default 15e3

  • seed (int) – seed of the pilot symbols; default 0

gives = ('ofdm',)#
needs = ('samples',)#
param_names = ('n_fft', 'n_subcarriers', 'n_cp', 'oversampling', 'dc_null', 'n_symbols', 'pilots', 'subcarrier_spacing_hz', 'seed')#
class comnum.blocks.PasDecode(*, constellation: str | dict | Var = '64-QAM', mb_lambda: float | Var = 1.0, n: int | Var = 1536, k: int | Var | None = None, var_degree: int | Var = 3, seed: int | Var = 1, rule: str | Var = 'sum_product', alpha: float | Var = 0.8, layered: bool | Var = True, iterations: int | Var = 50, blocks: int | Var = 1, symbol_rate: float | Var = 1.0)#

PAS receiver: bit LLRs with the amplitude priors, LDPC decoding, dematching (the parameters of pas_encode).

Needs: samples, symbols, noise. Gives: decoded.

Parameters:
  • constellation (str | dict) – a square QAM: 2^m-PAM per dimension; keys kind, m; default 64-QAM

  • mb_lambda (float) – Maxwell-Boltzmann amplitudes p(a) ∝ exp(-λ x²) on the unit-energy uniform QAM (0: uniform); default 1.0

  • n (int) – length of the LDPC codeword, a multiple of 2m [bits]; default 1536

  • k (int) – information bits of the code; above n(m-1)/m the signs also carry data (γ > 0) [bits]; default n(m-1)/m

  • var_degree (int) – variable-node degree of the PEG code; default 3

  • seed (int) – seed of the PEG construction; default 1

  • rule (str) – check-node rule; one of sum_product, min_sum, normalized_min_sum, offset_min_sum; default sum_product

  • alpha (float) – scale or offset of min-sum; default 0.8

  • layered (bool) – layered schedule; default true

  • iterations (int) – decoding iterations at most; default 50

  • blocks (int) – codewords per trial (pas_encode); default 1

  • symbol_rate (float) – symbol rate (pas_encode) [Bd]; default 1.0

gives = ('decoded',)#
needs = ('samples', 'symbols', 'noise')#
param_names = ('constellation', 'mb_lambda', 'n', 'k', 'var_degree', 'seed', 'rule', 'alpha', 'layered', 'iterations', 'blocks', 'symbol_rate')#
class comnum.blocks.PasEncode(*, constellation: str | dict | Var = '64-QAM', mb_lambda: float | Var = 1.0, n: int | Var = 1536, k: int | Var | None = None, var_degree: int | Var = 3, seed: int | Var = 1, rule: str | Var = 'sum_product', alpha: float | Var = 0.8, layered: bool | Var = True, iterations: int | Var = 50, blocks: int | Var = 1, symbol_rate: float | Var = 1.0)#

Probabilistic amplitude shaping: CCDM-shaped amplitudes, an LDPC code whose parity bits are the signs, square QAM (the first block of a link).

Needs: nothing. Gives: bits, symbols, constellation, samples, payload.

Parameters:
  • constellation (str | dict) – a square QAM: 2^m-PAM per dimension; keys kind, m; default 64-QAM

  • mb_lambda (float) – Maxwell-Boltzmann amplitudes p(a) ∝ exp(-λ x²) on the unit-energy uniform QAM (0: uniform); default 1.0

  • n (int) – length of the LDPC codeword, a multiple of 2m [bits]; default 1536

  • k (int) – information bits of the code; above n(m-1)/m the signs also carry data (γ > 0) [bits]; default n(m-1)/m

  • var_degree (int) – variable-node degree of the PEG code; default 3

  • seed (int) – seed of the PEG construction; default 1

  • rule (str) – check-node rule; one of sum_product, min_sum, normalized_min_sum, offset_min_sum; default sum_product

  • alpha (float) – scale or offset of min-sum; default 0.8

  • layered (bool) – layered schedule; default true

  • iterations (int) – decoding iterations at most; default 50

  • blocks (int) – codewords per trial (pas_encode); default 1

  • symbol_rate (float) – symbol rate (pas_encode) [Bd]; default 1.0

gives = ('bits', 'symbols', 'constellation', 'samples', 'payload')#
needs = ()#
param_names = ('constellation', 'mb_lambda', 'n', 'k', 'var_degree', 'seed', 'rule', 'alpha', 'layered', 'iterations', 'blocks', 'symbol_rate')#
class comnum.blocks.PhaseNoise(*, linewidth_hz: float | Var | None = None, sigma_rad: float | Var | None = None, origin: str | Var = 'zero')#

Wiener phase noise.

Needs: samples. Gives: nothing.

Parameters:
  • linewidth_hz (float) – laser linewidth, increments of variance 2πΔν/f_s [Hz]; default none

  • sigma_rad (float) – increment standard deviation per sample, instead of the linewidth [rad]; default none

  • origin (str) – zero: φ[0] = 0, the first sample is not rotated (OptiCommPy); step: φ[0] = Δ[0], the first sample is rotated too; one of zero, step; default zero

gives = ()#
needs = ('samples',)#
param_names = ('linewidth_hz', 'sigma_rad', 'origin')#
class comnum.blocks.Pmd(*, mean_dgd_ps: float | Var = 0.0, sections: int | Var = 20, theta_deg: float | Var | None = None)#

Random rotation of the polarisations and polarisation-mode dispersion of a dual-polarisation signal, a new realisation every trial.

Needs: samples. Gives: nothing.

Parameters:
  • mean_dgd_ps (float) – mean differential group delay of the link; 0 for a rotation only [ps]; default 0.0

  • sections (int) – birefringent sections of the coarse-step model; default 20

  • theta_deg (float) – a fixed real rotation by this angle instead, without DGD [deg]; default none

gives = ()#
needs = ('samples',)#
param_names = ('mean_dgd_ps', 'sections', 'theta_deg')#
class comnum.blocks.Probe(*, metrics: list | Var | None = None, skip_start: int | Var = 0, skip_end: int | Var = 0, scale: str | Var = 'power')#

Measure metrics at this point of the link; reported as <label>.<metric> (label: probe by default).

Needs: samples. Gives: nothing.

Parameters:
  • metrics (list) – the metrics of the specifications (on symbols aligned at 1 sample per symbol), and power_dbm and papr_db anywhere; default [snr_db]

  • skip_start (int) – symbols left out at the start of every polarisation (the edges of the filters) [symbols]; default 0

  • skip_end (int) – symbols left out at the end of every polarisation [symbols]; default 0

  • scale (str) – scaling before the decisions: power (blind), ls (least-squares complex gain, genie-aided) or none; one of power, ls, none; default power

gives = ()#
needs = ('samples',)#
param_names = ('metrics', 'skip_start', 'skip_end', 'scale')#
class comnum.blocks.PulseShape(*, kind: str | Var = 'rrc', rolloff: float | Var = 0.1, n_taps: int | Var = 1025, sps: int | Var = 2)#

Upsample and filter with a transmit pulse, then normalise to unit power.

Needs: samples. Gives: nothing.

Parameters:
  • kind (str) – the pulse; one of rect, nrz, rc, rrc, rz; default rrc

  • rolloff (float) – roll-off of rc and rrc; default 0.1

  • n_taps (int) – taps of rc and rrc (odd: on the sampling instants); default 1025

  • sps (int) – samples per symbol; default 2

gives = ()#
needs = ('samples',)#
param_names = ('kind', 'rolloff', 'n_taps', 'sps')#
class comnum.blocks.Rayleigh(*, n_rx: int | Var = 1, coherence_samples: int | Var = 0, k_factor: float | Var = 0.0, rx_correlation: float | Var = 0.0, tx_correlation: float | Var = 0.0)#

Flat fading y = H x on every antenna; records the channel for a genie-aided receiver.

Needs: samples. Gives: csi.

Parameters:
  • n_rx (int) – receive antennas; default 1

  • coherence_samples (int) – samples per channel matrix (0: one matrix per trial, 1: fast fading) [samples]; default 0

  • k_factor (float) – Rician factor K (linear), 0 for Rayleigh fading; default 0.0

  • rx_correlation (float) – exponential correlation ρ of the receive antennas; default 0.0

  • tx_correlation (float) – exponential correlation ρ of the transmit antennas; default 0.0

gives = ('csi',)#
needs = ('samples',)#
param_names = ('n_rx', 'coherence_samples', 'k_factor', 'rx_correlation', 'tx_correlation')#
class comnum.blocks.ReferenceSync(*, window: int | Var = 4096, start: int | Var | None = None, symmetry: int | Var = 4)#

Align the periodic reference of a capture on the received symbols (circular correlation); records offset and quality.

Needs: samples, constellation, capture. Gives: bits, symbols.

Parameters:
  • window (int) – symbols of the correlation (at most one period); default 4096

  • start (int) – first symbol of the window, or middle; default middle

  • symmetry (int) – rotational symmetry of the constellation; 0 removes the exact phase; default 4

gives = ('bits', 'symbols')#
needs = ('samples', 'constellation', 'capture')#
param_names = ('window', 'start', 'symmetry')#
class comnum.blocks.Resample(*, sps: float | Var = 2.0)#

Band-limited resampling of the block (FFT) to a number of samples per symbol.

Needs: samples. Gives: nothing.

Parameters:

sps (float) – output samples per symbol; default 2.0

gives = ()#
needs = ('samples',)#
param_names = ('sps',)#
class comnum.blocks.RxIq(*, t: list | Var)#

Receiver IQ imbalance [Re y; Im y] = T [Re x; Im x].

Needs: samples. Gives: nothing.

Parameters:

t (list) – row-major real 2×2 matrix [t00, t01, t10, t11]; required

gives = ()#
needs = ('samples',)#
param_names = ('t',)#
class comnum.blocks.Source(*, constellation: str | dict | Var = '16-QAM', n_symbols: int | Var = 4096, symbol_rate: float | Var = 1.0, mb_lambda: float | Var | None = None, pols: int | Var = 1)#

Draw the bits and symbols of a block (Gray labels of OptiCommPy).

Needs: nothing. Gives: bits, symbols, constellation, samples.

Parameters:
  • constellation (str | dict) – 16-QAM, QPSK, 8-PSK, 4-PAM, OOK, {kind, m}, or gaussian (circular Gaussian symbols, no decisions); unit energy; keys kind, m; default 16-QAM

  • n_symbols (int) – symbols per trial; default 4096

  • symbol_rate (float) – symbol rate; 1 keeps a normalised time axis [Bd]; default 1.0

  • mb_lambda (float) – Maxwell-Boltzmann shaping p(x) ∝ exp(-λ|x|²); default none

  • pols (int) – polarisations: 2 draws independent symbols for x and y (dual-polarisation optics); default 1

gives = ('bits', 'symbols', 'constellation', 'samples')#
needs = ()#
param_names = ('constellation', 'n_symbols', 'symbol_rate', 'mb_lambda', 'pols')#
class comnum.blocks.Ssfm(*, fiber: dict | Var | None = None, step_km: float | Var = 1.0, steps_per_span: int | Var | None = None, amplification: str | Var = 'edfa', noise: bool | Var = True, precision: str | Var = 'f64', check_sampling: bool | Var = True)#

Split-step Fourier propagation over the link, one polarisation.

Needs: samples. Gives: nothing.

Parameters:
  • fiber (dict) – fibre parameters, merged over the fiber of the specification (see FiberParams); its raman mapping adds Raman pumps and ISRS; keys alpha_db_km, d_ps_nm_km, gamma_w_km, span_km, n_spans, fc_hz, nf_db, slope_ps_nm2_km, raman; default spec fiber

  • step_km (float) – step [km]; default 1.0

  • steps_per_span (int) – this number of logarithmic steps per span instead of step_km (Bosco et al. 2000, eq. (6): every step carries the same integrated power, short at the start of the span; double precision); default none

  • amplification (str) – edfa (gain αL, ASE), ideal (noiseless gain) or none; with fiber.raman, the amplifier restores every frequency; one of edfa, ideal, none; default edfa

  • noise (bool) – draw the ASE of the EDFAs and the spontaneous Raman noise; default true

  • precision (str) – f64, or f32 (about twice as fast, relative error about 1e-6 √steps; not with Raman); one of f64, f32; default f64

  • check_sampling (bool) – refuse a signal whose sampling rate or block cannot hold the four-wave mixing and the walk-off of the link (Musetti et al. 2018, Appendix B); default true

gives = ()#
needs = ('samples',)#
param_names = ('fiber', 'step_km', 'steps_per_span', 'amplification', 'noise', 'precision', 'check_sampling')#
class comnum.blocks.Tdl(*, profile: str | dict | Var = 'EPA', delay_spread_s: float | Var = 1e-07, doppler_hz: float | Var = 0.0, n_rx: int | Var = 1)#

Tapped-delay-line multipath fading with Clarke/Jakes Doppler; records the taps for a genie-aided receiver.

Needs: samples. Gives: csi.

Parameters:
  • profile (str | dict) – EPA, EVA, ETU (3GPP TS 36.101), pedestrian_a, pedestrian_b, vehicular_a, vehicular_b (ITU-R M.1225, Tables 4 and 5), TDLA30, TDLB100, TDLC300, TDLD30 (3GPP TS 38.101-4, Annex B.2.1), TDL-A to TDL-E (3GPP TR 38.901, Tables 7.7.2-1 to 7.7.2-5, scaled to delay_spread_s), or {rms_delay_s, resolution_s} (exponential); keys rms_delay_s, resolution_s; default EPA

  • delay_spread_s (float) – RMS delay spread of TDL-A to TDL-E (TR 38.901 §7.7.3); the other profiles ignore it [s]; default 100e-9

  • doppler_hz (float) – maximum Doppler shift; 0 for a channel constant over the trial [Hz]; default 0.0

  • n_rx (int) – receive antennas; default 1

gives = ('csi',)#
needs = ('samples',)#
param_names = ('profile', 'delay_spread_s', 'doppler_hz', 'n_rx')#
class comnum.blocks.TxIq(*, beta: list | Var)#

Transmitter IQ imbalance y = x + β x*.

Needs: samples. Gives: nothing.

Parameters:

beta (list) – [re, im] of β; required

gives = ()#
needs = ('samples',)#
param_names = ('beta',)#
class comnum.blocks.Viterbi(*, n: int | Var = 35, m: int | Var = 4)#

Viterbi–Viterbi phase estimation and correction.

Needs: samples. Gives: nothing.

Parameters:
  • n (int) – window [symbols]; default 35

  • m (int) – power; default 4

gives = ()#
needs = ('samples',)#
param_names = ('n', 'm')#
class comnum.blocks.WdmRx(*, sps: int | Var = 2)#

Bring the channel under test to baseband and keep its band (ideal low-pass by resampling).

Needs: samples, wdm. Gives: nothing.

Parameters:

sps (int) – output samples per symbol; default 2

gives = ()#
needs = ('samples', 'wdm')#
param_names = ('sps',)#
class comnum.blocks.WdmTx(*, n_channels: int | Var = 5, spacing_hz: float | Var = 50000000000.0, sps: int | Var = 8, power_dbm: float | list | Var = 0.0, kind: str | Var = 'rrc', rolloff: float | Var = 0.1, n_taps: int | Var = 1025, linewidth_hz: float | Var = 0.0, channel: int | Var | None = None, mzm_scale: float | Var | None = None)#

WDM transmitter: the channel under test and independently modulated neighbours on the grid of OptiCommPy’s simpleWDMTx.

Needs: samples. Gives: wdm.

Parameters:
  • n_channels (int) – channels N; the grid is (k - ⌊N/2⌋) Δf, shifted by Δf/2 when N is even; default 5

  • spacing_hz (float) – grid spacing Δf [Hz]; default 50e9

  • sps (int) – samples per symbol of the multiplex (the sampling rate must cover the band); default 8

  • power_dbm (float | list) – launch power per channel, both polarisations; a list gives one per channel [dBm]; default 0.0

  • kind (str) – the pulse; one of rect, nrz, rc, rrc, rz; default rrc

  • rolloff (float) – roll-off of rc and rrc; default 0.1

  • n_taps (int) – taps of rc and rrc (odd: on the sampling instants); default 1025

  • linewidth_hz (float) – linewidth of the transmit lasers [Hz]; default 0.0

  • channel (int) – index of the channel under test (⌊N/2⌋ by default); default centre

  • mzm_scale (float) – drive the IQ modulator of OptiCommPy at this peak amplitude V/V_π (none: a linear modulator); default none

gives = ('wdm',)#
needs = ('samples',)#
param_names = ('n_channels', 'spacing_hz', 'sps', 'power_dbm', 'kind', 'rolloff', 'n_taps', 'linewidth_hz', 'channel', 'mzm_scale')#