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:
@@ -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
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user