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 internal Module state, shared by both nn.Module and ScriptModule.

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 channel impulse response on both polarization separately

__init__(impulse_response)

Initialize internal Module state, shared by both nn.Module and ScriptModule.

forward(tx_signal)

Define the computation performed at every call.

Should be overridden by all subclasses.

Note

Although the recipe for forward pass needs to be defined within this function, one should call the Module instance afterwards instead of this since the former takes care of running the registered hooks while the latter silently ignores them.

class mokka.channels.torch.FixedChannelDP(impulse_response)

Bases: Module

Apply a fixed channel impulse response on both polarization separately

__init__(impulse_response)

Initialize internal Module state, shared by both nn.Module and ScriptModule.

forward(tx_signal)

Define the computation performed at every call.

Should be overridden by all subclasses.

Note

Although the recipe for forward pass needs to be defined within this function, one should call the Module instance afterwards instead of this since the former takes care of running the registered hooks while the latter silently ignores them.

class mokka.channels.torch.FixedChannelSP(impulse_response)

Bases: Module

Apply a fixed channel impulse response for a single polarization

__init__(impulse_response)

Initialize internal Module state, shared by both nn.Module and ScriptModule.

forward(tx_signal)

Define the computation performed at every call.

Should be overridden by all subclasses.

Note

Although the recipe for forward pass needs to be defined within this function, one should call the Module instance afterwards instead of this since the former takes care of running the registered hooks while the latter silently ignores them.

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

__init__(rho)

Construct a PDL element which 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)

Define the computation performed at every call.

Should be overridden by all subclasses.

Note

Although the recipe for forward pass needs to be defined within this function, one should call the Module instance afterwards instead of this since the former takes care of running the registered hooks while the latter silently ignores them.

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
__init__(sigma_p, pmd_parameter, span_length, steps_per_span, method='static')

Initialize internal Module state, shared by both nn.Module and ScriptModule.

property a
forward(signal: Tensor)

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

Parameters:

signal

forward_dynamic(signal: Tensor)
forward_static(signal: Tensor)
step()
steps(k=1)
property theta
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 internal Module state, shared by both nn.Module and ScriptModule.

channel_transfer(length, pulse_shape=None)
forward(u)

Define the computation performed at every call.

Should be overridden by all subclasses.

Note

Although the recipe for forward pass needs to be defined within this function, one should call the Module instance afterwards instead of this since the former takes care of running the registered hooks while the latter silently ignores them.

forward_freq(u)
forward_time(u)
step()
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)
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]), 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]), 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 = 'elliptical'
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 = 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 = 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.