mokka.channels

Module with channel model implementations.

Channels sub-module implemented within the PyTorch framework.

class mokka.channels.torch.ComplexAWGN(N_0=None)

Bases: Module

Complex AWGN channel defined with zero mean and variance N_0.

This converts to a setting of stddev sqrt(N_0/2) for real and imaginary parts of the distribution.

__init__(N_0=None)

Construct ComplexAWGN.

forward(x, N_0=None)

Apply Gaussian noise to a signal.

Parameters:
  • x – input signal to apply noise to.

  • N_0 – noise variance

Returns:

input signal distorted with AWGN

class mokka.channels.torch.DPImpairments(samp_rate, tau_cd, tau_pmd, phi_IQ, theta, rho=0)

Bases: Module

Apply a list of impairments experienced for dual pol. transmission.

This includes residual chromatic dispersion, polarization mode dispersion, polarization rotation and IQ shift

__init__(samp_rate, tau_cd, tau_pmd, phi_IQ, theta, rho=0)

Initialize py:class:DPImpairments.

Parameters:
  • samp_rate – sampling rate of the input signal

  • tau_cd – Residual chromatic dispersion coefficient tau_{cd}

  • tau_pmd – Residual polarization-mode dispersion coefficient tau_{pmd}

  • phi_IQ – Phase rotation phi_{IQ}

  • theta – Polarization angle theta

  • rho – Polarization angle rho

forward(signal)

Apply DPImpairment to a dual polarization signal.

Parameters:

signal – Must be a 2xN complex-valued PyTorch tensor

class mokka.channels.torch.EDFAAmpDualPol(span_length: int, amp_gain: str, alphaa_db: Float[Tensor, '1'], alphab_db: Float[Tensor, '1'], amp_noise: bool, noise_figure: Float[Tensor, '1'], optical_carrier_frequency: float, bw: float, P_input_lin: float, padding: int)

Bases: Module

Implement Gaussian noise EDFA model for dual polarization fiberoptical simulation.

Parameters:
  • span_length – span_length

  • amp_gain – Which amplification gain model to use either ‘alpha_equalization’, ‘equal_power’

  • alphaa_db – power loss coeficient [dB/km] for eigenstate a

  • alphab_db – power loss coeficient [dB/km] for eigenstate b

  • amp_noise – Consider amplification noise

  • noise_figure – Amplifier noise figure in dB

  • optical_carrier_frequency – Optical carrier frequency (for PSD) [GHz]

  • bw – Bandwidth of baseband signal (for PSD)

  • P_input_lin – Input power

  • padding – Number of samples to ignore in the beginning and end

P_input_lin: float
__init__(span_length: int, amp_gain: str, alphaa_db: Float[Tensor, '1'], alphab_db: Float[Tensor, '1'], amp_noise: bool, noise_figure: Float[Tensor, '1'], optical_carrier_frequency: float, bw: float, P_input_lin: float, padding: int) None

Method generated by attrs for class EDFAAmpDualPol.

alphaa_db: Float[Tensor, '1']
alphaa_lin: Float[Tensor, '1']
alphab_db: Float[Tensor, '1']
alphab_lin: Float[Tensor, '1']
amp_gain: str
amp_noise: bool
bw: float
forward(u1, u2, segment)

Amplify the signal according to the selected method after each span.

attention: the noise depends on the amplification. if \(\alpha = 0\), no noise is added.

Parameters

u1array_like

co-polarized signal before the amplifier

u2array_like

cross-polarized signal before the amplifier

segment: array_like

segment number

Returns

signal : signal after the amplifier

noise_figure: Float[Tensor, '1']
optical_carrier_frequency: float
padding: int
span_length: int
class mokka.channels.torch.EDFAAmpSinglePol(span_length: int, amp_gain: str, alpha_db: Float[Tensor, '1'], amp_noise: bool, noise_figure: Float[Tensor, '1'], optical_carrier_frequency: float, bw: float, P_input_lin: float, padding: int)

Bases: Module

Gaussian noise model of an EDFA for single polarization fiberoptics.

Parameters:
  • span_length – span_length [km]

  • amp_gain – Either ‘alpha_equalization’ or ‘equal_power’

  • alpha_db – Attenuation of the fiber [dB/km]

  • amp_noise – Consider amplification noise [bool]

  • amp_gain – Which amplification gain model to use either ‘alpha_equalization’, ‘equal_power’

  • optical_carrier_frequency – Optical carrier frequency (for PSD) [GHz]

  • bw – Occupied bandwidth (for PSD) [Hz]

  • P_input_lin – Input power [W]

  • padding – Number of samples to ignore in the beginning and end

P_input_lin: float
__init__(span_length: int, amp_gain: str, alpha_db: Float[Tensor, '1'], amp_noise: bool, noise_figure: Float[Tensor, '1'], optical_carrier_frequency: float, bw: float, P_input_lin: float, padding: int) None

Method generated by attrs for class EDFAAmpSinglePol.

alpha_db: Float[Tensor, '1']
alpha_lin: Float[Tensor, '1']
amp_gain: str
amp_noise: bool
bw: float
forward(signal, segment)

Amplify the signal according to the selected method after each span.

Attention: the noise depends on the amplification. if \(\alpha = 0\), no noise is added.

Parameters

signalarray_like

signal before the amplifier

segment: array_like

segment number

Returns

signal : signal after the amplifier

noise_figure: Float[Tensor, '1']
optical_carrier_frequency: float
padding: int
span_length: int
class mokka.channels.torch.FixedArbitraryChannelDP(impulse_response)

Bases: Module

Apply a fixed 2x2 channel impulse response to a dual polarization signal.

This class only implements a time-invariant dual-polarization channel.

__init__(impulse_response)

Initialize FixedArbitraryChannelDP.

Parameters:

impulse_response – arbitrary 2x2 impulse response.

forward(tx_signal)

Apply arbitrary dual polarization channel to tx_signal.

class mokka.channels.torch.FixedChannelDP(impulse_response)

Bases: Module

Apply a fixed channel impulse response on both polarization separately.

__init__(impulse_response)

Initialize FixedChannelDP.

Parameters:

impulse_response – single polarization impulse response

forward(tx_signal)

Apply static dual polarization signal to tx_signal.

Parameters:

tx_signal – dual polarization input signal

class mokka.channels.torch.FixedChannelSP(impulse_response)

Bases: Module

Apply a fixed channel impulse response to a single polarization input signal.

This class only implements a time-invariant single-polarization channel.

__init__(impulse_response)

Initialize FixedChannelSP.

Parameters:

impulse_response – 1xN vector of complex time-domain samples of the impulse response

forward(tx_signal)

Apply fixed single-polarization channel on tx_signal.

Parameters:

tx_signal – Single polarization complex signal vector

class mokka.channels.torch.OpticalNoise(dt: float, optical_carrier_wavelength: float, wavelength_bandwidth: float, OSNR: float)

Bases: Module

Zero mean additive Gaussian noise based on given OSNR defined over certain wavelength.

Parameters:
  • dt – Time step

  • optical_carrier_wavelength – Wavelength of optical carrier in nm

  • wavelength_bandwidth – Bandwidth in nm for which OSNR is given

  • OSNR – Optical SNR in dB

OSNR: float
__init__(dt: float, optical_carrier_wavelength: float, wavelength_bandwidth: float, OSNR: float) None

Method generated by attrs for class OpticalNoise.

dt: float
forward(signal)

Apply optical noise realization on signal.

Parameters:

signal – input signal

Returns:

noise impaired signal

optical_carrier_wavelength: float
wavelength_bandwidth: float
class mokka.channels.torch.PDLElement(rho)

Bases: Module

Simulate PDL in optical channels.

This class applies PDL which is randomly rotated w.r.t to the input signal.

__init__(rho)

Construct a PDL element.

It exhibits a differential linear attenuation of rho. To get the attenuation matrix Gamma we first set attenuation of one polarization to sqrt(1+rho) and the other to sqrt(1-rho) and then rotate the matrix with a random rotation matrix uniform in Stokes space.

Parameters:

rho – PDL in linear units

forward(signal)

Apply time-invariant PDL by mutiplying input signal and Jones matrix.

class mokka.channels.torch.PMDElement(sigma_p, pmd_parameter, span_length, steps_per_span, method='static')

Bases: Module

Static and dynamic PMD Element according to Czegledi (2016).

Note: for SSFM only static PMD is correct

property J

Calculate the Jones matrix of the rotation portion.

__init__(sigma_p, pmd_parameter, span_length, steps_per_span, method='static')

Initialize PMDElement.

Parameters:
  • sigma_p – Variance of time-varying Wiener process

  • pmd_parameter – Calculate second moment of the DGD based on the PMD parameter

  • span_length – Length of each span of optical fiber

  • steps_per_span – Simulation steps per span

  • method – Either “static” or “dynamic” - sets the mode to either time-varying or fixed in time

property a

Calculate and return parameters a.

forward(signal: Tensor)

Process a dual polarization signal and apply PMD with a random walk to it.

Parameters:

signal

forward_dynamic(signal: Tensor)

Apply the time-varying PMD simulation to the input signal.

forward_static(signal: Tensor)

Apply the static PMD simulation to the input signal.

step()

Perform one time-step for the time-varying simulation and return J_k1.

steps(k=1)

Perform k time-varying steps and return the Jones matrices.

property theta

Calculate theta as norm of vector alpha.

class mokka.channels.torch.PMDPDLChannel(L, num_steps, pmd_parameter, pmd_correlation_length, f_samp, pmd_sigma=0.0, num_pdl_elements=0, pdl_max=0.8, pdl_min=0.1, method='freq')

Bases: Module

Optical channel with only PMD and PDL impairments.

__init__(L, num_steps, pmd_parameter, pmd_correlation_length, f_samp, pmd_sigma=0.0, num_pdl_elements=0, pdl_max=0.8, pdl_min=0.1, method='freq')

Initialize PMDPDLChannel.

Parameters:
  • L

  • num_steps

  • pmd_parameter

  • pmd_correlation_length

  • f_samp

  • pmd_sigma

  • num_pdl_elements

  • pdl_max

  • pdl_min

  • method

channel_transfer(length, pulse_shape=None)

Compute the 2x2 channel transfer function.

Parameters:
  • length – One-sided length of the desired impulse response

  • pulse_shape – Shaping to apply to the window function

forward(u)

Apply Channel to input signal.

Parameters:

u – Dual-polarization complex input signal

forward_freq(u)

Apply channel in frequency domain.

Parameters:

u – Dual-polarization complex input signal

forward_time(u)

Apply channel in time domain.

Parameters:

u – Dual-polarization complex input signal

step()

Propagate the PMD Elements in time.

Only relevant for time-variant PMD.

class mokka.channels.torch.PhasenoiseWiener(start_phase_width=6.283185307179586, start_phase_init=0)

Bases: Module

Wiener phase noise channel.

Forward call takes N0 for AWGN and sigma_phi for Wiener phase noise.

Parameters:
  • start_phase_width – upper bound for initialization with a uniform distribution.

  • start_phase_init – initial phase value at the start of the generation for each noise sequence.

__init__(start_phase_width=6.283185307179586, start_phase_init=0)

Construct PhasenoiseWiener.

apply(x, sigma_phi=None)

Apply only Wiener phase noise.

Parameters

x: array_like

Input data

sigma_phi: float

phase noise variance

forward(x, N0=None, sigma_phi=None)

Apply Wiener phase noise to a complex signal.

Parameters:
  • x – ipnut signal to apply noise to

  • N0 – noise variance for Gaussian noise

  • sigma_phi – standard deviation of Wiener phase noise process

Returns:

noise impaired signal

sample_noise(x, sigma_phi=None)

Sample one realization of phase noise.

Parameters

x: array_like

Input data

sigma_phi: float

phase noise variance

class mokka.channels.torch.PolyPhaseChannelizer(coeff, n_down)

Bases: Module

Perform poly-phase channelization with variable filter coefficients.

__init__(coeff, n_down)

Init PolyPhaseChannelizer.

forward(signal)

Apply poly-phase channelization on a wideband signal.

mokka.channels.torch.ProakisChannel(variant, sps=1)

Return impulse response for channels defined in [0].

Parameters:
  • variant – Either “a”, “b”, “c” or “a_complex”. In the literature all channels are real-valued. The complex channel “a_complex” is an extension of the “a” channel by applying a phase rotation of the given samples.

  • sps – samples-per-symbol choosing an integer value greater than 1 will add sps-1 zeros in-between the channel given channel taps. No band-limiting filter is applied subsequently.

[0] Proakis, John G., and Masoud Salehi. Digital communications. McGraw-hill, 2008.

class mokka.channels.torch.RamanAmpDualPol(amp_gain: str, alphaa_db: Float[Tensor, '1'], alphab_db: Float[Tensor, '1'], amp_noise: bool, noise_figure: Float[Tensor, '1'], optical_carrier_frequency: float, bw: float, P_input_lin: float, padding: int)

Bases: Module

Implement a Gaussian model of the Raman dual polarization amp.

Parameters:
  • amp_gain – Which amplification gain model to use either ‘alpha_equalization’, ‘equal_power’

  • alphaa_db – power loss coeficient [dB/km] for eigenstate a

  • alphab_db – power loss coeficient [dB/km] for eigenstate b

  • noise_figure – Amplifier noise figure in dB

  • optical_carrier_frequency – Optical carrier frequency (for PSD) [GHz]

  • bw – Bandwidth of baseband signal (for PSD)

  • P_input_lin – Input power

  • padding – Number of samples to ignore in the beginning and end

P_input_lin: float
__init__(amp_gain: str, alphaa_db: Float[Tensor, '1'], alphab_db: Float[Tensor, '1'], amp_noise: bool, noise_figure: Float[Tensor, '1'], optical_carrier_frequency: float, bw: float, P_input_lin: float, padding: int) None

Method generated by attrs for class RamanAmpDualPol.

alphaa_db: Float[Tensor, '1']
alphaa_lin: Float[Tensor, '1']
alphab_db: Float[Tensor, '1']
alphab_lin: Float[Tensor, '1']
amp_gain: str
amp_noise: bool
bw: float
forward(u1, u2, dz)

Amplify the signal according to the selected method after each span.

Attention: the noise depends on the amplification. if \(\alpha = 0\), no noise is added Parameters ———- signal : signal before the amplifier dz : step-size Returns ——- signal : signal after the amplifier

noise_figure: Float[Tensor, '1']
optical_carrier_frequency: float
padding: int
class mokka.channels.torch.ResidualPhaseNoise

Bases: Module

Residual phase noise implementation.

This implements residual phase noise modeled with a zero mean phase noise process.

__init__()

Construct ResidualPhaseNoise.

forward(x, RPN)

Apply residual phase noise to signal.

Parameters:
  • x – complex input signal

  • RPN – phase noise variance per input symbol

Returns:

x with phase noise

class mokka.channels.torch.SSFMPropagationDualPol(dt: Float[Tensor, '1'], dz: Float[Tensor, '1'], alphaa_db: Float[Tensor, '1'], alphab_db: Float[Tensor, '1'], betapa: Float[Tensor, '...'], betapb: Float[Tensor, '...'], gamma: Float[Tensor, '1'], length_span: Float[Tensor, '1'], num_span: Integer, delta_G: Float = 0.001, maxiter: Integer = 4, alphaa_pdl_lin: Float[Tensor, '1'] = tensor(0.), alphab_pdl_lin: Float[Tensor, '1'] = tensor(0.), psp: Float[Tensor, '2'] = tensor([0, 0]), solution_method: str = 'elliptical', amp: RamanAmpDualPol | EDFAAmpDualPol | None = None, solver_method: str = 'localerror', pmd_simulation: Bool = False, pmd_sigma: Float[Tensor, '1'] = tensor(0.), pmd_correlation_length: Float[Tensor, '1'] = tensor(0.1000), pmd_parameter: Float[Tensor, '1'] = tensor(0.), pdl_simulation: Bool = False, pdl_min: float = 0.07, pdl_max: float = 0.17)

Bases: Module

Coupled NLS fibre propagation (with SSFM).

This class is adapted from Code written by Dominik Rimpf published under the MIT license [https://gitlab.com/domrim/bachelorarbeit-code]

This class solves the coupled nonlinear Schrodinger equation for pulse propagation in an optical fiber using the split-step Fourier method. The implementation and name are based on https://photonics.umd.edu/software/ssprop/vector-version/

Parameters:
  • dt – time step between samples (sample time)

  • dz – propagation stepsize (delta z) of SSFM (segment length)

  • alphaa_db – power loss coeficient [dB/km] for eigenstate a

  • alphab_db – power loss coeficient [dB/km] for eigenstate b

  • betapa – dispersion polynomial coefficient vector for eigenstate a

  • betapb – dispersion polynomial coefficient vector for eigenstate b

  • gamma – nonlinearity coefficient

  • length_span – Length of span between amplifiers

  • num_span – Number of spans where num_span * length_span is full fiber channel length

  • delta_G – Goal local error (optional) (default 1e-3)

  • maxiter – Number of step-size iterations (optional) (default 4)

  • psp – Principal eigenstate of the fiber specified as a 2-vector containing the angles Psi and Chi (optional) (default [0,0])

  • solution_method – String that specifies which method to use when performing the split-step calculations. Supported methods elliptical and circular (optional) (default elliptical)

__init__(dt: Float[Tensor, '1'], dz: Float[Tensor, '1'], alphaa_db: Float[Tensor, '1'], alphab_db: Float[Tensor, '1'], betapa: Float[Tensor, '...'], betapb: Float[Tensor, '...'], gamma: Float[Tensor, '1'], length_span: Float[Tensor, '1'], num_span: Integer, delta_G: Float = 0.001, maxiter: Integer = 4, alphaa_pdl_lin: Float[Tensor, '1'] = tensor(0.), alphab_pdl_lin: Float[Tensor, '1'] = tensor(0.), psp: Float[Tensor, '2'] = tensor([0, 0]), solution_method: str = 'elliptical', amp: RamanAmpDualPol | EDFAAmpDualPol | None = None, solver_method: str = 'localerror', pmd_simulation: Bool = False, pmd_sigma: Float[Tensor, '1'] = tensor(0.), pmd_correlation_length: Float[Tensor, '1'] = tensor(0.1000), pmd_parameter: Float[Tensor, '1'] = tensor(0.), pdl_simulation: Bool = False, pdl_min: float = 0.07, pdl_max: float = 0.17) None

Method generated by attrs for class SSFMPropagationDualPol.

alphaa_db: Float[Tensor, '1']
alphaa_lin: Float[Tensor, '1']
alphaa_pdl_lin: Float[Tensor, '1']
alphab_db: Float[Tensor, '1']
alphab_lin: Float[Tensor, '1']
alphab_pdl_lin: Float[Tensor, '1']
amp: RamanAmpDualPol | EDFAAmpDualPol | None
betapa: Float[Tensor, '...']
betapb: Float[Tensor, '...']
calculate_basis(w)

Calculate basis functions for linear step.

If any of the parameters alpha or beta change, this function needs to be executed again to recalculate parameters

delta_G: Float
dt: Float[Tensor, '1']
dz: Float[Tensor, '1']
forward(ux, uy)

Compute the progpagation for the dual polarization signal through the fiber optical channel.

Parameters:
  • ux – input signal in x-polarization.

  • uy – input signal in y-polarization.

Returns:

signal at the end of the fiber

gamma: Float[Tensor, '1']
get_operators(dz)

Obtain linear operators for given step length.

length_span: Float[Tensor, '1']
maxiter: Integer
num_span: Integer
pdl_max: float
pdl_min: float
pdl_simulation: Bool
pmd_correlation_length: Float[Tensor, '1']
pmd_parameter: Float[Tensor, '1']
pmd_sigma: Float[Tensor, '1']
pmd_simulation: Bool
psp: Float[Tensor, '2']
solution_method: str
solver_method: str
class mokka.channels.torch.SSFMPropagationSinglePol(dt: tensor, dz: tensor, alphadb: tensor, betap: tensor, gamma: tensor, length_span: tensor, num_span: tensor, delta_G: tensor = 0.001, maxiter: tensor = 4, amp: object = None, solver_method: str = 'localerror')

Bases: Module

Non-linear fibre propagation (with SSFM).

This class is adapted from Code written by Dominik Rimpf published under the MIT license [https://gitlab.com/domrim/bachelorarbeit-code]

This class solves the nonlinear Schrodinger equation for pulse propagation in an optical fiber using the split-step Fourier method. The actual implementation is the local error method Sec II.E of Optimization of the Split-Step Fourier Method in Modeling Optical-Fiber Communications Systems https://doi.org/10.1109/JLT.2003.808628

Parameters:
  • dt – time step between samples (sample time)

  • dz – propagation stepsize (delta z) of SSFM (segment length)

  • alphadb – power loss coeficient [dB/km]

  • beta2 – dispersion polynomial coefficient

  • gamma – nonlinearity coefficient

  • length_span – Length of span between amplifiers

  • num_span – Number of spans where num_span * length_span is full fiber channel length

  • delta_G – Goal local error

  • maxiter – Number of step-size iterations

__init__(dt: tensor, dz: tensor, alphadb: tensor, betap: tensor, gamma: tensor, length_span: tensor, num_span: tensor, delta_G: tensor = 0.001, maxiter: tensor = 4, amp: object = None, solver_method: str = 'localerror') None

Method generated by attrs for class SSFMPropagationSinglePol.

alphadb: tensor
alphalin: tensor
amp: object
betap: tensor
delta_G: tensor
dt: tensor
dz: tensor
forward(u)

Compute the propagation through the configured fiber-optical channel.

Parameters:

u0 – input signal (array)

Returns:

array signal at the end of the fiber

gamma: tensor
get_operators(dz)

Calculate linear operators for given step length.

length_span: tensor
maxiter: tensor
num_span: tensor
solver_method: str
mokka.channels.torch.SSFM_halfstep_end(signal, linear_op)

Calculate the final halfstep of the single polarization SSFM.

mokka.channels.torch.SSFM_step(signal, linear_op, nonlinear_op)

Calculate single polarization SSFM step.

class mokka.channels.torch.WDMDemux(n_channels, spacing, sym_rate, sim_rate, used_channels, method='classical')

Bases: Module

WDM Demuxing for a configurable number of channels and system parameters.

__init__(n_channels, spacing, sym_rate, sim_rate, used_channels, method='classical')

Initialize WDMDemux.

classical_demux(signal)

Perform WDM Demuxing for each channel individually.

forward(signal)

WDM Demux the wide-band signal.

polyphase_demux(signal)

Peform WDM Demuxing with the Polyphase Channelizer method.

class mokka.channels.torch.WDMMux(n_channels, spacing, samp_rate, sim_rate)

Bases: Module

Perform configurable muxing of baseband channels to simulate WDM.

__init__(n_channels, spacing, samp_rate, sim_rate)

Initialize WDMMux.

forward(signals)

Modulate the signals on WDM channels in the digital baseband.

mokka.channels.torch.symmetrical_SSFM_step(signal, half_linear_op, nonlinear_op)

Calculate symmetrical single polarization SSFM step.

mokka.channels.torch.symmetrical_SSPROPV_step(u1, u2, h11, h12, h21, h22, NOP)

Calculate symmetrical dual polarization SSFM step.