Many changes here and there. I lost track... :-(

Current work is on MLSE and SD Decoding etc. MLSE is currently not 100% working, the scalings are maybe off?!
This commit is contained in:
Silas Oettinghaus
2025-08-11 07:42:04 +02:00
parent 09d9e5011c
commit 5dbc48abc0
37 changed files with 1506 additions and 570 deletions

View File

@@ -1,189 +1,171 @@
classdef Fiber
%FIBER Summary of this class goes here
% Detailed explanation goes here
% Fiber: Simulate optical fiber signal propagation using
% the split-step Fourier method (SSFM).
properties
% Simulation sampling frequency [Hz]
fsimu
% Fiber length [m]
fiber_length
% Attenuation coefficient [dB/km]
alpha
% Dispersion parameter D [s/m^2]
D
% Dispersion slope [s/m^3]
Dslope
% Reference wavelength [m]
lambda0
% Nonlinear coefficient [1/(W·m)]
gamma
% Maximum allowed nonlinear phase change per step [rad]
dphimax
% Derived parameters:
% Second-order dispersion coefficient β2 [s^2/m]
b2
% Third-order dispersion coefficient β3 [s^3/m]
b3
% Linear attenuation constant [1/m]
alpha_lin
% Frequency-domain linear operator per unit length
linstep
end
methods
function obj = Fiber(options)
%FIBER Construct an instance of this class
% Detailed explanation goes here
% Constructor: initialize fiber physical and simulation parameters.
arguments
options.fsimu
options.fiber_length = 0
options.alpha = 0.2
options.D = 17
options.Dslope = 0.06
options.lambda0 = 1550
options.gamma = 0
options.dphimax = 5e-3
options.fsimu % Sampling frequency [Hz]
options.fiber_length = 0 % Fiber length [km]
options.alpha = 0.2 % Attenuation [dB/km]
options.D = 17 % Dispersion D parameter [ps/(nm·km)]
options.Dslope = 0.06 % Dispersion slope [ps/(nm^2·km)]
options.lambda0 = 1550 % Reference wavelength [nm]
options.gamma = 0 % Nonlinear coefficient [1/(W·km)]
options.dphimax = 5e-3 % Max phase step [rad]
end
obj.fsimu = options.fsimu;
obj.fiber_length = options.fiber_length*1000; %km
obj.alpha = options.alpha;
obj.D = options.D*1e-6;
obj.Dslope = options.Dslope*1e3;
obj.lambda0 = options.lambda0*1e-9;
obj.gamma = options.gamma;
obj.dphimax = options.dphimax;
% Assign inputs to object properties, converting units to SI.
obj.fsimu = options.fsimu;
obj.fiber_length = options.fiber_length * 1e3; % km m
obj.alpha = options.alpha;
obj.D = options.D * 1e-6; % ps/(nm·km) s/(m·m)
obj.Dslope = options.Dslope * 1e3; % ps/(nm^2·km) s/m^2
obj.lambda0 = options.lambda0 * 1e-9; % nm m
obj.gamma = options.gamma; % 1/(W·km) (assumed 1/(W·m) internally)
obj.dphimax = options.dphimax;
end
function signalclass_out = process(obj,signalclass_in)
function signalclass_out = process(obj, signalclass_in)
% process: Apply fiber propagation to input signal class.
% Calls the internal SSFM routine and logs the operation.
% actual processing of the signal (steps 1. - 3.)
signalclass_in = obj.process_(signalclass_in);
% Run internal split-step propagation
signalclass = obj.process_(signalclass_in);
% append to logbook
lbdesc = 'Fiber ';
signalclass_in = signalclass_in.logbookentry(lbdesc);
% write to output
signalclass_out = signalclass_in;
% Add entry to logbook for tracking
signalclass = signalclass.logbookentry('Fiber ');
% Return processed signal class
signalclass_out = signalclass;
end
function opt_sig = process_(obj,opt_sig)
%METHOD1 Summary of this method goes here
% Detailed explanation goes here
function opt_sig = process_(obj, opt_sig)
% process_: Internal routine for one-step fiber propagation.
% Computes linear and (optionally) nonlinear effects.
signal = opt_sig.signal;
% Extract time-domain field and wavelength
signal = opt_sig.signal;
lambda_signal = opt_sig.lambda;
obj.D = obj.D + (lambda_signal-obj.lambda0)*obj.Dslope;
obj.b2 = -obj.D*lambda_signal^2/(2*pi*Constant.LightSpeed);
obj.b3 = ((lambda_signal.^2/(2*pi*Constant.LightSpeed)).^2*obj.Dslope);
obj.alpha_lin = obj.alpha/10*log(10)/1000;
% Update dispersion parameter D for current wavelength
obj.D = obj.D + (lambda_signal - obj.lambda0) * obj.Dslope;
% Compute dispersion coefficients (β2, β3)
obj.b2 = -obj.D * lambda_signal^2 / (2 * pi * Constant.LightSpeed);
obj.b3 = (lambda_signal^2 / (2 * pi * Constant.LightSpeed))^2 * obj.Dslope;
% Convert attenuation from dB/km to linear 1/m
obj.alpha_lin = obj.alpha / 10 * log(10) / 1e3;
% Build frequency axis for FFT operations
N = length(signal);
faxis = linspace(-obj.fsimu/2,obj.fsimu/2,N+1);
faxis = ifftshift(faxis(:,1:end-1));
faxis = faxis';
obj.linstep = -obj.alpha_lin/2 - 2*1j*pi^2*obj.b2*faxis.^2 - 4/3*1j*pi^3*obj.b3*faxis.^3;
faxis = linspace(-obj.fsimu/2, obj.fsimu/2, N+1);
faxis = faxis(1:end-1); % drop redundant endpoint
faxis = ifftshift(faxis)'; % center zero frequency
if 0
H = exp((obj.linstep)*obj.fiber_length);
figure(222)
hold on
plot(faxis.*1e-9,abs(real(Y)),'LineStyle','-','DisplayName','Abs(real) part of complex TF');
xlabel("Frequency in GHz")
ylabel("$ R|(H(\omega, L))|$")
end
% Define linear operator per meter in frequency domain
obj.linstep = -obj.alpha_lin/2 ... % half-step loss
- 1j*2*pi^2*obj.b2 .* faxis.^2 ... % second-order dispersion
- 1j*(4/3)*pi^3*obj.b3 .* faxis.^3; % third-order dispersion
% Choose linear-only or nonlinear SSFM based on gamma
if obj.gamma ~= 0
% Full adaptive SSFM with nonlinear Schrödinger solver
opt_out = obj.NLSE(signal);
else
opt_out = ifft( fft(signal) .* exp(obj.linstep*obj.fiber_length) ); % only one linear step
% Single-step linear propagation in frequency domain
opt_out = ifft( fft(signal) .* exp(obj.linstep * obj.fiber_length) );
end
%TODO: attenuate nase ...
% Update output field in signal class
opt_sig.signal = opt_out;
end
function [yout] = NLSE(obj, xin)
maxPow = obj.gamma.*max(abs(xin).^2);
Leff = obj.dphimax / maxPow ;
dz = Leff;
function yout = NLSE(obj, xin)
% NLSE: Solve nonlinear Schrödinger equation by adaptive split-step
% xin: input time-domain field
% Returns yout: output time-domain field after propagation
% Initial estimate of effective length per step
maxPow = obj.gamma * max(abs(xin).^2);
Leff = obj.dphimax / maxPow;
dz = Leff;
z_prop = 0;
yout = fft(xin);
yout = ((yout).*exp(obj.linstep*dz/2));
% Apply initial half-step linear operator
yout = fft(xin) .* exp(obj.linstep * dz/2);
% Loop until full fiber length is reached
while true
% Inverse FFT to time domain for nonlinear phase shift
yout = ifft(yout);
Leff = dz;
% Nonlinear phase rotation per segment
power = abs(yout).^2;
Hnl = exp( -1j*obj.gamma*power*Leff);
yout = yout .* Hnl;
Hnl = exp(-1j * obj.gamma * power * dz);
yout = yout .* Hnl;
% Accumulate propagation distance
z_prop = z_prop + dz;
maxPow = obj.gamma*max(abs(yout).^2);
Leff = obj.dphimax/maxPow;
dz_new = Leff;
% Compute adaptive step for next interval
maxPow = obj.gamma * max(abs(yout).^2);
dz_new = obj.dphimax / maxPow;
% If remaining length shorter than new step, finish loop
if z_prop + dz_new > obj.fiber_length
dz_new = obj.fiber_length - z_prop;
break
break;
end
yout = fft(yout);
yout = ((yout).*exp(obj.linstep*(dz/2+dz_new/2)));
dz = dz_new;
% Half-step linear operator bridging segments
yout = fft(yout) .* exp(obj.linstep * ((dz/2) + (dz_new/2)));
dz = dz_new;
end
yout = fft(yout);
yout = ((yout).*exp(obj.linstep*(dz/2+dz_new/2)));
% Final propagation segment: combine half-steps and nonlinear
yout = fft(yout) .* exp(obj.linstep * ((dz/2) + (dz_new/2)));
yout = ifft(yout);
Leff = dz;
% Last nonlinear phase shift
power = abs(yout).^2;
Hnl = exp(-1j * obj.gamma * power * dz_new);
yout = yout .* Hnl;
Hnl = exp( -1j*obj.gamma*power*Leff);
yout = yout .* Hnl;
yout = fft(yout);
yout = ((yout).*exp(obj.linstep*(dz/2)));
% Final half-step linear operator to complete SSFM
yout = fft(yout) .* exp(obj.linstep * (dz_new/2));
yout = ifft(yout);
end
end
end