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