halfway merged and pulled?!

This commit is contained in:
Silas Labor Zizou
2025-12-15 15:41:02 +01:00
parent 7d0a634b87
commit b8cecae895
145 changed files with 19835 additions and 0 deletions

View File

@@ -0,0 +1,240 @@
classdef DP_Fiber
% Dual-Polarization fiber propagation (CNLSE / Manakov) class version
% Runs full setup + propagation inside process_ (no external loop).
properties (Access=public)
% ---- User options (public) ----
L % [km] fiber length
dz % [m] step size target (kept for compatibility; adaptive dz uses SS_* below)
lambda % [nm] reference wavelength
rng % RNG seed
gamma % [1/W/m] nonlinear coefficient
% Optional / advanced options (match legacy names where possible)
fa % [Hz] sampling frequency
X_alpha % [dB/100km] attenuation per 100 km (per-pol, used for X and Y)
X_beta % [1..4] dispersion coefficients vector for X (Y mirrors X)
D % [ps/(nm*km)]
Ds % [ps/(nm^2*km)] dispersion slope
Dpmd % [ps/sqrt(km)] PMD coefficient
beat_len % [m] beat length (for beta(1) if X_beta is zero)
corr_len % [m] correlation length (not directly used; kept for compatibility)
manakov % 1=Manakov (legacy behavior: manakov=eq-1)
SS_dphimax % [rad] max nonlinear phase per step (adaptive SSFM)
SS_dzmax % [m] max dz (adaptive SSFM)
SS_dzmin % [m] min dz (adaptive SSFM)
n_waveplates % number of PMD waveplates
% ---- Internal state (persistent between calls) ----
state % struct mirroring legacy 'state'
end
methods (Access=public)
function obj = DP_Fiber(options)
% Constructor copies fields from 'options' and sets defaults.
arguments
options.L
options.dz
options.lambda
options.rng = 0
options.gamma
% optional but recommended
options.fa
% legacy-compatible optional params
options.X_alpha = 4.605170185988092e-05 % dB/100km
options.X_beta = [0,0,-2.16826193914149e-26,3.56839456298263e-41]
options.D = 17 % ps/(nm*km)
options.Ds = 0.06 % ps/(nm^2*km)
options.Dpmd = 3 % ps/sqrt(km)
options.beat_len = 50 % m
options.corr_len = 50 % m (kept)
options.manakov = 0 % 1=Manakov
options.SS_dphimax = 5e-3 % rad
options.SS_dzmax = 2e4 % m
options.SS_dzmin = 100 % m
options.n_waveplates = 100
end
% Copy provided options into properties
fn = fieldnames(options);
for n = 1:numel(fn)
obj.(fn{n}) = options.(fn{n});
end
% Initialize empty state; will be built on first process_ call
obj.state = struct();
end
function signalclass_out = process(obj, signalclass_in)
% Public entry point: takes a signal class with .signal (2xN)
% and writes back the propagated signal.
signalclass_in.signal = obj.process_(signalclass_in.signal, signalclass_in.fs);
% logbook (kept as in new framework skeleton)
lbdesc = 'DP_Fiber propagation (CNLSE_plain)';
if ismethod(signalclass_in, 'logbookentry')
signalclass_in = signalclass_in.logbookentry(lbdesc);
end
signalclass_out = signalclass_in;
end
function signal_out = process_(obj, signal_in,fs)
% Core processing builds legacy 'state' and calls CNLSE_plain
% data_in: [2 x N] complex, dual-pol envelope
arguments (Input)
obj
signal_in
fs
end
% ---- Basic checks
if isempty(signal_in) || size(signal_in,2) ~= 2
error('DP_Fiber:Input','Expected data_in of size [2 x N].');
end
if isempty(fs)
error('DP_Fiber:Config','Sampling frequency options.fa is required.');
end
obj.fa = fs;
% ---- RNG (legacy behavior)
R = RandStream("twister","Seed",obj.rng);
% ---- (Re)build state if empty or size-dependent fields changed
need_rebuild = ~isfield(obj.state,'nt') || (obj.state.nt ~= size(signal_in,2));
if need_rebuild
% Constants
c0 = 299792458; % [m/s]
% Legacy state mapping
st = struct();
% High-level
st.L = obj.L * 1000; % [m] legacy expects meters
st.polNames = {'X','Y'};
st.dt = 1/obj.fa;
st.nt = max(size(signal_in));
st.omega = 2*pi*[(0:st.nt/2-1),(-st.nt/2:-1)]/(st.dt*st.nt);
st.lambda = obj.lambda * 1e-9; % [m]
st.D = obj.D * 1e-6; % ps/(nm*km) -> s/(nm*m)
st.Dpmd = obj.Dpmd * 1e-6; % ps/sqrt(km) -> s/sqrt(km)
st.Ds = obj.Ds * 1e3; % ps/(nm^2*km) -> s/(nm^2*m)
st.beat_len = obj.beat_len;
st.SS_dzmax = obj.SS_dzmax;
st.SS_dzmin = obj.SS_dzmin;
st.SS_dphimax= obj.SS_dphimax;
st.chi = 0; % legacy placeholders
st.psi = 0;
st.manakov = obj.manakov; % 1 if eq==2 (Manakov), 0 if eq==1 (CNLSE)
st.wave_plates = obj.n_waveplates;
% Alpha (same X/Y)
st.alpha.X = obj.X_alpha;
st.alpha_lin.X = st.alpha.X/10*log(10)/1000;
st.alpha.Y = st.alpha.X;
st.alpha_lin.Y = st.alpha_lin.X;
% Beta (dispersion) for X (Y mirrors X)
if ~any(obj.X_beta)
% Populate from (beat_len, D, Ds, lambda) like legacy
if obj.beat_len ~= 0
b1 = pi/obj.beat_len;
else
b1 = 0;
end
b2 = 0; % PMD freq term handled elsewhere in legacy
b3 = -(st.lambda.^2/(2*pi*c0))*st.D;
b4 = (st.lambda^2/(2*pi*c0))^2*st.Ds + (2/st.lambda)*(st.lambda.^2/(2*pi*c0)).^2*st.D;
st.beta.X = [b1, b2, b3, b4]; % keep 4 terms, legacy had 0 for beta0; b2 unused
% Note: legacy stored [b0,b1,b2,b3]? Here we mirror their usage.
% We follow their X_beta layout length=4.
else
st.beta.X = obj.X_beta;
end
st.beta.Y = st.beta.X;
% Gamma
st.gamma = obj.gamma;
% PMD / birefringence (legacy waveplate model)
st.corr_length = st.L / st.wave_plates;
% DGD formula (Agrawal 1.1.18)
st.dgd = st.Dpmd * sqrt(st.L/1000); % Dpmd in s/sqrt(km), L in m -> convert: sqrt(m/1000)
% For exact legacy match, they used: state.dgd = Dpmd * sqrt(L) wisth L in meters and Dpmd already scaled.
% Using their pattern:
st.dgd = obj.Dpmd*1e-6 * sqrt(st.L); % match old: state.Dpmd already 1e-6*ps/sqrt(km); they used sqrt(L) with L [m]
brf_multiplier = 1;
if st.Dpmd == 0
brf_multiplier = 0;
end
% Waveplate random parameters
st.pauli_mats.s0 = eye(2);
st.pauli_mats.s2 = [0 1; 1 0];
st.pauli_mats.s3i = [0 1; -1 0];
st.brf.theta = (R.rand(st.wave_plates,1)*pi - 0.5*pi) * brf_multiplier;
st.brf.epsilon = 0.5*asin(R.rand(st.wave_plates,1)*2-1) * brf_multiplier;
st.brf.stokes = NaN(st.wave_plates,3);
st.Ttest = zeros(1, st.wave_plates);
st.brf.matR = cell(st.wave_plates,1);
for n=1:st.wave_plates
matRth = cos(st.brf.theta(n)) * st.pauli_mats.s0 - sin(st.brf.theta(n)) * st.pauli_mats.s3i;
matRepsilon = complex(cos(st.brf.epsilon(n))*st.pauli_mats.s0, sin(st.brf.epsilon(n))*st.pauli_mats.s2);
matR = matRth * matRepsilon;
st.brf.matR{n} = matR;
u1 = matR(1,1);
u2 = matR(1,2);
st.Ttest(n) = abs(u1).^2 + abs(u2).^2;
st.brf.stokes(n,:) = [abs(u1).^2 - abs(u2).^2 , (u1) * conj(u2) + conj(u1) .* u2 , 1i*(u1) * conj(u2) - conj(u1) .* u2];
end
% Frequency-dependent PMD phase term (legacy form)
st.brf.db0 = (R.rand(st.wave_plates,1)*2*pi - pi) * brf_multiplier;
st.brf.db1 = sqrt(3*pi/8)*(st.dgd/obj.fa)/st.wave_plates .* st.omega;
st.brf.simdgd = 0;
% cumsum used in legacy only for debug; keep compatibility variable:
~cumsum(st.brf.db0); % no-op to mirror legacy path
% Bookkeeping
st.missing_dz = 0;
st.n_plates_done = 0;
st.test_plates = [];
st.test_plate_numbers = [];
st.lin_z_test = 0;
st.propagated_length = 0;
% Cache
obj.state = st;
end
% ---- Call the exact same CNLSE_plain as in the old framework
x_in = signal_in(:,1).';
y_in = signal_in(:,2).';
[x_out, y_out, obj.state] = CNLSE_plain(x_in, y_in, obj.state);
obj.state.propagated_length = obj.state.propagated_length + obj.state.L;
signal_out = [x_out; y_out].';
end
end
end

View File

@@ -0,0 +1,149 @@
classdef Optical_Demultiplex < handle
% Dual-Polarization optical demultiplexer
% - Input: total-field signal
% - Output: single-channel dual-pol signal objects in cell array
%
% Notes:
% Opt_sig_wdm_demux = Optical_Demultiplex("attenuation",0,"B",200e9,"filtype",1,"fs_out",Opt_sig_wdm_rx.fs/4,"fs_in",Opt_sig_wdm_rx.fs,"lambda_center",1310).process(Opt_sig_wdm_rx);
% Opt_sig_wdm_demux{1}.spectrum("fignum",1100,"displayname",'bla','normalizeTo0dB',0,'max_num_lines',4);
% Opt_sig_wdm_demux{2}.spectrum("fignum",1100,"displayname",'bla','normalizeTo0dB',0,'max_num_lines',4);
properties (Access=public)
fs_in % [Hz] (optional; inferred from data_in.fs if omitted)
fs_out % [Hz]
lambda_center % [nm] center wavelength of the WDM grid
wavelengthplan % [nm]
attenuation = 0 % [dB] insertion loss
filtype = 1 % 1=Gaussian, 2=Rectangle, 3=No filter
B = 200e9 % [Hz] 3 dB bandwidth (Gaussian) or width (Rect)
mgauss = 3 % Gaussian order (multiple of 1/2)
% Derived/utility
c = physconst('lightspeed') % [m/s]
end
methods (Access=public)
function obj = Optical_Demultiplex(options)
arguments
options.fs_in = []
options.fs_out
options.lambda_center
options.wavelengthplan
options.attenuation = 0
options.filtype = 1
options.B = 2.5e10
options.mgauss = 3
end
fn = fieldnames(options);
for n = 1:numel(fn)
try obj.(fn{n}) = options.(fn{n}); end
end
end
function signalclasses_out = process(obj, signalclass_in)
% ---- Infer wavelength: either given or from input total signal
if isempty(obj.wavelengthplan)
obj.wavelengthplan = signalclass_in.lambda; %meter
else
if all(500e-9 < obj.wavelengthplan) && all(obj.wavelengthplan < 1500e-9) %check if given in nm
obj.wavelengthplan = obj.wavelengthplan.*1e-9;
end
end
% ---- Infer input sampling rates
if isempty(obj.fs_in)
assert(isprop(signalclass_in,'fs') && ~isempty(signalclass_in.fs), ...
'Dual_Pol_Demultiplexer: data_in.fs missing and options.fs_in not provided.');
obj.fs_in = signalclass_in.fs;
end
% Runs demultiplexing in one go and appends a logbook entry.
[x_envelopes,y_envelopes] = obj.process_(signalclass_in.signal);
for n = 1:min(size(x_envelopes))
signalclasses_out{n} = signalclass_in;
signalclasses_out{n}.signal = [x_envelopes(:,n), y_envelopes(:,n)];
signalclasses_out{n} = signalclasses_out{n}.resample("fs_in",obj.fs_in,"fs_out",obj.fs_out);
signalclasses_out{n}.lambda = obj.wavelengthplan(n);
lbdesc = ['Opt. Demux ', num2str( obj.wavelengthplan(n)),' nm'];
signalclasses_out{n} = signalclasses_out{n}.logbookentry(lbdesc);
end
end
function [x_envelopes,y_envelopes] = process_(obj, signal_in)
% Core demux:
% - frequency translate target channel to baseband
% - apply optical filter H
% - resample to fs_out
arguments (Input)
obj
signal_in
end
w = obj.fs_out ./ obj.fs_in ;
blocklen_in = length(signal_in);
blocklen_out = w*blocklen_in;
att = 1/10^(obj.attenuation/10);
faxis=linspace( -obj.fs_in/2 , obj.fs_in/2 , blocklen_in+1 );
faxis=ifftshift(faxis(1:end-1));
switch obj.filtype
case 1
H=exp(-(faxis/obj.B).^(2*obj.mgauss)*log(2)*2^(2*obj.mgauss-1)).';
case 2
%all zero filter
H=zeros(1,length(faxis)).';
%set filter = 1 inside bandwidth -B/2 <-> B/2
H(abs(faxis)<=obj.B/2)=1;
case 3
H = 1;
end
f_mid = obj.c/(obj.lambda_center*1e-9); % center frequency of WDM grid [Hz]
f_channels = obj.c./(obj.wavelengthplan) ;
N = numel(f_channels);
df_T = f_mid - f_channels;
pha = mod(-2*pi*(0:blocklen_in-1).'.*df_T/obj.fs_in, 2*pi);
lo = cos(pha)+1i*sin(pha);
% x_envelopes = ifft(fft(att.*signal_in(:,1).*lo).*H);
% y_envelopes = ifft(fft(att.*signal_in(:,2).*lo).*H);
N = size(lo,1);
C = size(lo,2);
x_envelopes = zeros(N, C, 'like', signal_in);
y_envelopes = zeros(N, C, 'like', signal_in);
s1 = signal_in(:,1);
s2 = signal_in(:,2);
% Reusable work buffers (avoid reallocations)
wrk_time = zeros(N,1, 'like', signal_in);
wrk_freq = zeros(N,1, 'like', signal_in);
for c = 1:C
% ---- X branch ----
wrk_time(:) = att .* s1 .* lo(:,c); % N×1
wrk_freq(:) = fft(wrk_time); % N×1
wrk_freq(:) = wrk_freq .* H; % N×1
x_envelopes(:,c) = ifft(wrk_freq); % N×1
% ---- Y branch ----
wrk_time(:) = att .* s2 .* lo(:,c);
wrk_freq(:) = fft(wrk_time);
wrk_freq(:) = wrk_freq .* H;
y_envelopes(:,c) = ifft(wrk_freq);
end
end
end
end

View File

@@ -0,0 +1,171 @@
classdef Optical_Multiplex < handle
% Takes a cell array of signals
% returns a total field signal
% WDM spacing is given in wavelength plan OR via delta_F
% The grid is stored in the output signal -> the demux will ideally
% look this up and use this as the demux frequencies...
% signal_cell = {Opt_sig_1, Opt_sig_2};
% Opt_sig_wdm = Optical_Multiplex("fs_in",Opt_sig.fs,"fs_out",4*Opt_sig.fs,...
% "lambda_center",1310,"random_key",0,"filtype",1,"B",200e9,"delta_f",400e9).process(signal_cell);
properties(Access=public)
fs_in
fs_out
lambda_center
delta_f
random_key
attenuation
B
mgauss
filtype
c = physconst('lightspeed')
f_center
f_T
lambda_T
df_T
end
methods (Access=public)
function obj = Optical_Multiplex(options)
%NAME Construct an instance of this class
% Detailed explanation goes here
arguments
options.fs_in
options.fs_out
options.lambda_center
options.B = 200e9
options.mgauss = 3
options.filtype = 2
options.delta_f = 0
options.random_key
options.attenuation = 0;
end
%
fn = fieldnames(options);
for n = 1:numel(fn)
try
obj.(fn{n}) = options.(fn{n});
end
end
end
function signalclass_out = process(obj,signalclasses_in)
% actual processing of the signal (steps 1. - 3.)
signalclass_out = obj.process_(signalclasses_in);
% append to logbook
lbdesc = ['Opt. Mux. '];
signalclass_out = signalclass_out.logbookentry(lbdesc);
end
function data_out = process_(obj,data_in)
%METHOD1 Summary of this method goes here
% Detailed explanation goes here
arguments(Input)
obj
data_in cell
end
% assert(data_in{1}.fs == obj.fs_in,'Sampling rate');
att = 1/10^(obj.attenuation/10);
N = numel(data_in);
w = obj.fs_out/data_in{1}.fs;
blocklen_in = length(data_in{1});
blocklen_out = w*blocklen_in;
freqaxis = linspace(-obj.fs_out/2, obj.fs_out/2, blocklen_out+1);
obj.f_center = obj.c/(obj.lambda_center.*1e-9);
if obj.random_key ~= 0
res = freqaxis(2)-freqaxis(1);
R = RandStream("twister","Seed",obj.random_key);
laser_frequency_imperfection = res .* round(R.randn(N,1)*10); %in mutliples of the fft resolution, i.e. the distance between two freq. bins
else
laser_frequency_imperfection = zeros(blocklen_in,1);
end
obj.f_T = [];
obj.df_T = [];
polrots = [];
for o = 1:N
if obj.delta_f ~= 0
% user defined a channel spacing in GHz. Build plan
% left and right from zero
obj.df_T(o) = (-length(data_in)/2-0.5+o) .* obj.delta_f;
obj.df_T(o) = obj.df_T(o)+ laser_frequency_imperfection(o);
obj.f_T = [obj.f_T obj.f_center+obj.df_T(o)];
else
%center frequencies of channels
obj.f_T = [obj.f_T obj.c/(data_in{o}.lambda)];
obj.lambda_T = [obj.lambda_T data_in{o}.lambda];
%difference between mid frequency of MUX and channels
obj.df_T = [obj.df_T obj.f_center - obj.f_T(o)];
end
% adapt frequency shifts to match the FFT grid! Find nearest grid point
[glitch(o),pos] = min(abs( freqaxis-obj.df_T(o) ));
obj.df_T(o) = freqaxis(pos);
polrots = [polrots, data_in{o}.polrot];
end
obj.lambda_T = obj.c ./ (obj.f_center-obj.df_T);
obj.B = 200e9; %200GHz
faxis = linspace(-obj.fs_out/2,obj.fs_out/2, blocklen_out+1);%generates arow vector faxis of blocklen+1 points linearly spaced between and including -para.fs/2 and para.fs/2
faxis = ifftshift(faxis(1:end-1));
switch obj.filtype
case 1
H =exp(-(faxis/obj.B).^(2*obj.mgauss)*log(2)*2^(2*obj.mgauss-1)).';
case 2
H=zeros(length(faxis),1);
H(find(abs(faxis)<=obj.B/2))=1;
case 3
H = 1;
end
x_envelopes = NaN([blocklen_out N]);
y_envelopes = x_envelopes;
for o = 1:N
pha = mod(2*pi*(0:blocklen_out-1)*obj.df_T(o)/obj.fs_out,2*pi).';
lo = cos(pha)+1i*sin(pha);
data_in_resampled = data_in{o}.resample("fs_out",obj.fs_out);
res_env = ifft(fft(data_in_resampled.signal(:,1)).*H);
x_envelopes(:,o) = att.*res_env.*lo;
res_env = ifft(fft(data_in_resampled.signal(:,2)).*H);
y_envelopes(:,o) = att.*res_env.*lo;
end
data_out = data_in_resampled;
data_out.signal = [sum(x_envelopes,2), sum(y_envelopes,2)];
data_out.lambda = obj.lambda_T;
data_out.polrot = polrots;
end
end
methods (Access=private)
% Cant be seen from outside! So put all your functions here that can/
% shall not be called from outside
end
end

View File

@@ -0,0 +1,92 @@
classdef Polarization_Controller
%Input can be "normal" - output will be DP!
properties(Access=public)
mode
desired_angle
desired_power
rotation_angle
rotation_matrix
end
methods (Access=public)
function obj = Polarization_Controller(options)
%NAME Construct an instance of this class
% Detailed explanation goes here
arguments
options.mode polarization_control_mode = polarization_control_mode.rot_power
options.desired_angle
options.desired_power
end
%
fn = fieldnames(options);
for n = 1:numel(fn)
try
obj.(fn{n}) = options.(fn{n});
end
end
% do more stuff
end
function signalclass_out = process(obj,signalclass_in)
% actual processing of the signal (steps 1. - 3.)
[signalclass_in.signal,signalclass_in.polrot] = obj.process_(signalclass_in.signal,signalclass_in.polrot);
% append to logbook
lbdesc = ['Logbookentry'];
signalclass_in = signalclass_in.logbookentry(lbdesc);
% write to output
signalclass_out = signalclass_in;
end
function [data_out, polrot_out] = process_(obj,data_in,polrot_in)
% Rotate polarization of am opt signal
arguments(Input)
obj
data_in double
polrot_in double
end
if obj.mode ~= polarization_control_mode.deactivate
switch obj.mode
case polarization_control_mode.random
obj.rotation_angle = 2*pi*rand ;
case polarization_control_mode.rot_angle
obj.rotation_angle = obj.desired_angle*pi/180 ;
case polarization_control_mode.rot_power
obj.rotation_angle = -polrot_in + acos(sqrt(obj.desired_power/100)) ;
end
obj.rotation_matrix = [cos(obj.rotation_angle) -sin(obj.rotation_angle) ; sin(obj.rotation_angle) cos(obj.rotation_angle)].' ;
if min(size(data_in)) == 1
data_in = reshape(data_in,[],1);
data_in = [data_in, zeros(length(data_in),1)];
end
data_out = data_in * obj.rotation_matrix;
polrot_out = polrot_in + obj.rotation_angle ;
end
end
end
end

View File

@@ -0,0 +1,135 @@
function [opt_out_struct,state] = CNLSE(opt_in_struct,state)
% init transfer functions h.X and h.Y
h = struct('X',0,'Y',0);
state.common_beta=struct('X',0,'Y',0);
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% pre calculations
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% calculate transfer function and rotate coordines for both
% polarizations
for n=1:2
% get current polarization name and contrary one
curPol = state.polNames{n};
% extend linear transfer function depending on beta values for the
% current polarization
for n_beta = 1:length(state.beta.(curPol))
% h.(curPol) = h.(curPol) - 1j*state.beta.(curPol)(n_beta)*(state.omega).^(n_beta-1)/factorial(n_beta-1);
% if n_beta ~= 2
state.common_beta.(curPol) = state.common_beta.(curPol) + state.beta.(curPol)(n_beta) * (state.omega).^(n_beta-1) / factorial(n_beta-1);
% end
end
opt_out_struct.(curPol)=opt_in_struct.(curPol).envelope;
end
state.h=h;
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Splitstep method
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% state.SS_dzs = zeros(1,state.max_nonlin_its);
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Split Step Method
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% get nonlinear step size
[state.dz] = getNLstepsize(state,opt_out_struct);
state.n_step = 0;
state.z_prop = 0;
state.test_dz = [];
state.powers = [];
while state.z_prop < state.L
if state.z_prop + state.dz > state.L
state.dz = state.L - state.z_prop;
end
% lin conv
% opt_out_struct = [ opt_out_struct 0 0 0 0 0 ];
% opt_out_struct
%%%%%%%%%%%%%
% STEP
% update step number
state.n_step=state.n_step+1;
state.dzs(state.n_step)=state.dz;
% half linear step
[opt_out_struct,state] = lin_step(state,opt_out_struct,state.dz/2);
% complete nonlinear step
[opt_out_struct,state] = nl_step(state,opt_out_struct,state.dz);
% half linear step
[opt_out_struct,state] = lin_step(state,opt_out_struct,state.dz/2);
%%%%%%%%%%%%%
% prepare next STEP
% overlap(n_step+1,:) = opt_out_struct(M+1:end);
% opt_out_struct = opt_out_struct(1:M);
% get nonlinear step size
[state.dz] = getNLstepsize(state,opt_out_struct);
end
% figure(88);clf;subplot(2,1,1);stem(state.test_plates);subplot(2,1,1); hold all;stem(-1000*state.test_plate_numbers);subplot(2,1,2);stem(state.dzs)
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Post Calculations
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% opt_out_struct.X.envelope = ( cos(state.psi)*cos(state.chi) + 1j*sin(state.psi)*sin(state.chi))*opt_out_struct.X + ...
% (-sin(state.psi)*cos(state.chi) - 1j*cos(state.psi)*sin(state.chi))*opt_out_struct.Y;
%
buffer.X.envelope = opt_out_struct.X;
buffer.X.type = opt_in_struct.X.type;
buffer.X.wavelength = opt_in_struct.X.wavelength;
if isfield(buffer.X,'Nase')
buffer.X.Nase = opt_in_struct.X.Nase;
else
buffer.X.Nase = 0;
end
opt_out_struct.X =[];
opt_out_struct.X.envelope = buffer.X.envelope;
opt_out_struct.X.type = buffer.X.type;
opt_out_struct.X.wavelength = buffer.X.wavelength;
opt_out_struct.X.Nase = buffer.X.Nase;
%
% opt_out_struct.Y.envelope = ( sin(state.psi)*cos(state.chi) - 1j*cos(state.psi)*sin(state.chi))*opt_out_struct.X.envelope + ...
% ( cos(state.psi)*cos(state.chi) - 1j*sin(state.psi)*sin(state.chi))*opt_out_struct.Y;
%
buffer.Y.envelope = opt_out_struct.Y;
buffer.Y.type = opt_in_struct.Y.type;
buffer.Y.wavelength = opt_in_struct.Y.wavelength;
if isfield(buffer.Y,'Nase')
buffer.Y.Nase = opt_in_struct.Y.Nase;
else
buffer.Y.Nase = 0;
end
opt_out_struct.Y =[];
opt_out_struct.Y.envelope = buffer.Y.envelope;
opt_out_struct.Y.type = buffer.Y.type;
opt_out_struct.Y.wavelength = buffer.Y.wavelength;
opt_out_struct.Y.Nase = buffer.Y.Nase;
% figure(100+loop);plot([real(opt_out_struct.X.envelope);real(opt_out_struct.Y.envelope)].');
end

View File

@@ -0,0 +1,120 @@
function [opt_out_x,opt_out_y,state] = CNLSE_plain(opt_in_x,opt_in_y,state)
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% pre calculations
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
state.common_beta=struct('X',0,'Y',0);
for n=1:2
% get current polarization name and contrary one
curPol = state.polNames{n};
% extend linear transfer function depending on beta values for the current polarization
% Was ist der Sinn dieser komischen beta notation? zB. state.beta.X = [0.3142 0 -9.1105e-28 5.1068e-41]
for n_beta = 1:length(state.beta.(curPol))
state.common_beta.(curPol) = state.common_beta.(curPol) + state.beta.(curPol)(n_beta) * (state.omega).^(n_beta-1) / factorial(n_beta-1);
end
%opt_out_struct.(curPol)=opt_in_struct.(curPol).envelope;
end
beta_const = state.beta.('X')(1);
beta_1 = state.beta.('X')(2);
beta_2 = state.beta.('X')(3);
beta_3 = state.beta.('X')(4);
deltaomega = state.omega;
beta_x = beta_const + beta_1 * deltaomega + 1/2 * beta_2 * deltaomega.^2 + 1/6 *beta_3 * deltaomega.^3;
% opt_in_x = gpuArray(opt_in_x);
% opt_in_y = gpuArray(opt_in_y);
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Split Step Method
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% [opt_out_x,opt_out_y] = split_step_loop(state.L,opt_in_x,opt_in_y,state.gamma,state.SS_dzmin,state.SS_dzmax,state.SS_dphimax,state.alpha_lin,...
% state.lin_z_test,state.corr_length,state.n_plates_done,state.missing_dz,state.brf,state.common_beta,....
% state.chi,state.manakov,state.beat_len);
% [opt_out_x,opt_out_y] = split_step_loop_mex(state.L,opt_in_x,opt_in_y,state.gamma,state.SS_dzmin,state.SS_dzmax,state.SS_dphimax,state.alpha_lin,...
% state.lin_z_test,state.corr_length,state.n_plates_done,state.missing_dz,state.brf,state.common_beta,....
% state.chi,state.manakov,state.beat_len);
% get nonlinear step size
[state.dz] = getNLstepsize(opt_in_x,opt_in_y,state.gamma,state.SS_dzmin,state.SS_dzmax,state.SS_dphimax,state.alpha_lin);
%[state.dz] = getNLstepsize_original(state,opt_out_struct);
state.n_step = 0;
state.z_prop = 0;
state.test_dz = [];
state.powers = [];
tic
while state.z_prop < state.L
% reduce step length (dz) if we are to overshoot the fiber length
% (L) in the next step
if state.z_prop + state.dz > state.L
state.dz = state.L - state.z_prop;
end
% update step number (n)
state.n_step=state.n_step+1;
% append current step length to logbook (dzs)
state.dzs(state.n_step)=state.dz;
% half linear step
[opt_in_x,opt_in_y,state.z_prop,state.lin_z_test,...
state.corr_length,state.n_plates_done,state.missing_dz,state.n_step,...
state.test_plates,state.test_plate_numbers,state.brf,state.common_beta.X,...
state.common_beta.Y,state.alpha_lin.X,state.alpha_lin.X]...
= lin_step(...
opt_in_x,opt_in_y,state.z_prop,state.lin_z_test,...
state.dz/2,state.corr_length,state.n_plates_done,state.missing_dz,state.n_step,...
state.test_plates,state.test_plate_numbers,state.brf,state.common_beta.X,...
state.common_beta.Y,state.alpha_lin.X,state.alpha_lin.X);
% complete nonlinear step
[opt_in_x,opt_in_y] = nl_step(opt_in_x,opt_in_y, state.dz, state.gamma, state.chi, state.manakov, state.beat_len ,state.alpha_lin.X, state.alpha_lin.Y);
% half linear step
[opt_in_x,opt_in_y,state.z_prop,state.lin_z_test,...
state.corr_length,state.n_plates_done,state.missing_dz,state.n_step,...
state.test_plates,state.test_plate_numbers,state.brf,state.common_beta.X,...
state.common_beta.Y,state.alpha_lin.X,state.alpha_lin.X]...
= lin_step...
(opt_in_x,opt_in_y,state.z_prop,state.lin_z_test,...
state.dz/2,state.corr_length,state.n_plates_done,state.missing_dz,state.n_step,...
state.test_plates,state.test_plate_numbers,state.brf,state.common_beta.X,...
state.common_beta.Y,state.alpha_lin.X,state.alpha_lin.X);
% get nonlinear step size
[state.dz] = getNLstepsize(opt_in_x,opt_in_y,state.gamma,state.SS_dzmin,state.SS_dzmax,state.SS_dphimax,state.alpha_lin);
%[state.dz] = getNLstepsize_original(state,opt_out_struct);
end
toc
opt_out_x = (opt_in_x);
opt_out_y = (opt_in_y);
% opt_out_x = gather(opt_in_x);
% opt_out_y = gather(opt_in_y);
end

View File

@@ -0,0 +1,25 @@
function [rDZ] = getNLstepsize(ux,uy,gamma,dzmin,dzmax,dphimax,alpha_lin)
maxPow = max(gamma.*max(real(ux).^2+imag(ux).^2+real(uy).^2+imag(uy).^2));
Leff = dphimax/maxPow;
alpha_lin = max([alpha_lin.X alpha_lin.Y]);
nl_att_len_ratio = alpha_lin*Leff;
if nl_att_len_ratio >= 1
rDZ = dzmax;
else
if alpha_lin == 0
step = Leff;
else
%effective length?
step = -1/alpha_lin*log(1-nl_att_len_ratio);
end
rDZ = min([step dzmax]);
rDZ = max([rDZ dzmin]);
end
end

View File

@@ -0,0 +1,27 @@
function [rDZ] = getNLstepsize_original(state,aOpt)
ux = aOpt.X;
uy = aOpt.Y;
maxPow = max(state.gamma.*max(real(ux).^2+imag(ux).^2+real(uy).^2+imag(uy).^2));
Leff = state.SS_dphimax/maxPow;
alpha_lin = max([state.alpha_lin.X state.alpha_lin.Y]);
nl_att_len_ratio = alpha_lin*Leff;
if nl_att_len_ratio >= 1
rDZ = state.SS_dzmax;
else
if alpha_lin == 0
step = Leff;
else
%effective length?
step = -1/alpha_lin*log(1-nl_att_len_ratio);
end
rDZ = min([step state.SS_dzmax]);
rDZ = max([rDZ state.SS_dzmin]);
end
end

View File

@@ -0,0 +1,125 @@
%function [rOpt,state] = lin_step(state,aOpt,aStepSize)
function [rOpt_x,rOpt_y,z_prop,lin_z_test,...
corr_length,n_plates_done,missing_dz,n_step,test_plates,...
test_plate_numbers,brf,common_beta_x,common_beta_y,alpha_lin_x,alpha_lin_y]...
= lin_step(...
opt_x,opt_y,z_prop,lin_z_test,aStepSize,corr_length,...
n_plates_done,missing_dz,n_step,test_plates,test_plate_numbers,...
brf,common_beta_x,common_beta_y,alpha_lin_x,alpha_lin_y)
%%%%%% 1) Update and Check Distances etc. %%%%%%
% update propgated distance z_prop
z_prop = z_prop + aStepSize;
% calculate the number of plates needed for the so far propagated fiber length
n_plates = ceil(z_prop/corr_length);
% subtract the number of plates which were already processed
n_plates_left = n_plates - n_plates_done;
% compute last plate size ( if it fits, it should be 0)
if missing_dz > aStepSize
last_plate = aStepSize;
missing_dz = missing_dz-aStepSize;
plate_sizes = last_plate;
plate_numbers = n_plates;
else
last_plate = aStepSize - missing_dz - (n_plates_left-1)*corr_length;
if missing_dz == 0
missing_dz = [];
end
%build vector of plate lengths with missing plate part from prev.
%iterartion , then some normal plates and finally a fraction of a plate
%to fit into the step length
plate_sizes = [missing_dz corr_length*ones(1,n_plates_left-1) last_plate];
if n_plates_done == 0
plate_numbers =[(n_plates_done+1):(n_plates-1) n_plates];
else
plate_numbers = [n_plates_done (n_plates_done+1):(n_plates-1) n_plates]; % not wrking yet
end
%remember for next step
missing_dz = corr_length - last_plate;
end
plate_steps = repmat(n_step,1,length(plate_sizes));
%
%figure;stem(plate_sizes);
test_plates = [test_plates,plate_sizes];
test_plate_numbers = [test_plate_numbers, plate_numbers];
%%%%%% 2) Apply Waveplate Model %%%%%%
% transfer optical envelope to frequency domain for effective convolution with transfer function h
opt_x=fft(opt_x);
opt_y=fft(opt_y);
% db1 = gpuArray(brf.db1);
% db0 = gpuArray(brf.db0);
% common_beta_x = gpuArray(common_beta_x);
% common_beta_y = gpuArray(common_beta_y);
db1 = (brf.db1);
db0 = (brf.db0);
common_beta_x = (common_beta_x);
common_beta_y = (common_beta_y);
% process every waveplate with given sizes in plate_sizes
for n=1:length(plate_sizes)
dz = plate_sizes(n);
% figure(87);subplot(2,1,1);plot(real(x(900:1150)));subplot(2,1,2);plot(real(y(900:1150)));
% MOV1=[MOV1 getframe(87)];
% extract rotation matrix from pre calculated matrices
matR = brf.matR{plate_numbers(n)};
% transform to eigenvalue of of fiber segment
tOpt.X = conj(matR(1,1))*opt_x + conj(matR(2,1))*opt_y;
tOpt.Y = conj(matR(1,2))*opt_x + conj(matR(2,2))*opt_y;
% calculate statistical delta beta for pmd
delta_beta = 0.5*(db1+db0(n))/corr_length;
% build transfer function with delta beta
%common.beta = beta1+beta2*omega^2
%accumulate delta beta for log...
brf.simdgd = brf.simdgd + (db1(length(db1)/2+1)+db0(n))/corr_length;
h.X = exp(-1j*(common_beta_x-delta_beta)*dz);
h.Y = exp(-1j*(common_beta_y+delta_beta)*dz);
% delta_beta has to be added to the transfer function
% process with transfer function
tOpt.X = h.X.*tOpt.X ;
tOpt.Y = h.Y.*tOpt.Y ;
% rotate back
opt_x = matR(1,1)*tOpt.X + matR(1,2)*tOpt.Y;
opt_y = matR(2,1)*tOpt.X + matR(2,2)*tOpt.Y;
end
lin_z_test = lin_z_test + sum(plate_sizes,2);
%update the number of processed plates so far
n_plates_done = n_plates_done + n_plates_left;
% attanuate the signal each linear state with alpha
% ( 0.2dB = 4.6052e-05 )
rOpt_x=ifft(exp(-alpha_lin_x*aStepSize/2).*opt_x); % /2 not sure why (have to find it in formulas)
rOpt_y=ifft(exp(-alpha_lin_y*aStepSize/2).*opt_y); % but not relevant for now
end

View File

@@ -0,0 +1,106 @@
function [rOpt,state] = lin_step_original(state,aOpt,aStepSize)
% update propgated distance z_prop
state.z_prop = state.z_prop + aStepSize;
% if state.synchronous_plates % not waveplate model (just rotation with dz)
% state.plate_sizes = aStepSize;
%
% else
% calculate the number of plates needed for the so far propagated fiber
% length
state.n_plates = ceil(state.z_prop/state.corr_length);
% subtract the number of plates which were already be processed
state.n_plates_left = state.n_plates - state.n_plates_done;
% compute last plate size ( if it fits, it should be 0)
if state.missing_dz > aStepSize
state.last_plate = aStepSize;
state.missing_dz = state.missing_dz-aStepSize;
state.plate_sizes = state.last_plate;
state.plate_numbers = state.n_plates;
else
state.last_plate = aStepSize - state.missing_dz - (state.n_plates_left-1)*state.corr_length;
if state.missing_dz == 0
state.missing_dz = [];
end
state.plate_sizes = [state.missing_dz state.corr_length*ones(1,state.n_plates_left-1) state.last_plate];
if state.n_plates_done == 0
state.plate_numbers =[(state.n_plates_done+1):(state.n_plates-1) state.n_plates];
else
state.plate_numbers = [state.n_plates_done (state.n_plates_done+1):(state.n_plates-1) state.n_plates]; % not wrking yet
end
state.missing_dz = state.corr_length - state.last_plate;
end
state.plate_steps = repmat(state.n_step,1,length(state.plate_sizes));
% figure;stem(state.plate_sizes);
state.test_plates = [state.test_plates,state.plate_sizes];
state.test_plate_numbers = [state.test_plate_numbers, state.plate_numbers];
% end
% transfer optical envelope to frequency domain for effective
% convolution with transfer function h
aOpt.X=fft(aOpt.X);
aOpt.Y=fft(aOpt.Y);
% process every waveplate with given sizes in state.plate_sizes
for n=1:length(state.plate_sizes)
dz = state.plate_sizes(n);
% figure(87);subplot(2,1,1);plot(real(x(900:1150)));subplot(2,1,2);plot(real(y(900:1150)));
% state.MOV1=[state.MOV1 getframe(87)];
% extract rotation matrix from pre calculated matrices
matR = state.brf.matR{state.plate_numbers(n)};
% transform to eigenvalue of of fiber segment
tOpt.X = conj(matR(1,1))*aOpt.X + conj(matR(2,1))*aOpt.Y;
tOpt.Y = conj(matR(1,2))*aOpt.X + conj(matR(2,2))*aOpt.Y;
% calculate statistical delta beta for pmd
delta_beta = 0.5*(state.brf.db1+state.brf.db0(n))/state.corr_length;
% db1 = sqrt(3*pi/8)*(para.dgd/para.fa)/state.wave_plates.*state.omega;
% delta_beta = 0.5*(state.brf.db0(n))/state.corr_length;
% build transfer function with delta beta
% common.beta = beta1+beta2*omega^2
% delta beta
h.X = exp(-1j*(state.common_beta.X-delta_beta)*dz);
h.Y = exp(-1j*(state.common_beta.Y+delta_beta)*dz);
% delta_beta has to be added to the transfer function
% process with transfer function
tOpt.X = h.X.*tOpt.X ;
tOpt.Y = h.Y.*tOpt.Y ;
% rotate back
aOpt.X = matR(1,1)*tOpt.X + matR(1,2)*tOpt.Y;
aOpt.Y = matR(2,1)*tOpt.X + matR(2,2)*tOpt.Y;
end
state.lin_z_test = state.lin_z_test + sum(state.plate_sizes,2);
%update the number of processed plates so far
state.n_plates_done = state.n_plates_done + state.n_plates_left;
% attanuate the signal each linear state with alpha
% ( 0.2dB = 4.6052e-05 )
rOpt.X=ifft(exp(-state.alpha_lin.X*aStepSize/2).*aOpt.X); % /2 not sure why (have to find it in formulas)
rOpt.Y=ifft(exp(-state.alpha_lin.Y*aStepSize/2).*aOpt.Y); % but not relevant for now
end

View File

@@ -0,0 +1,39 @@
%function [rOpt,state] = nl_step(state,aOpt,aDz)
function [rOpt_x,rOpt_y] = nl_step(opt_x,opt_y, dz, gamma, chi, use_manakov, beatlength, alpha_lin_x, alpha_lin_y)
if ~use_manakov % CNLSE
rOpt_x = opt_x .* exp( (-1j*(1/3)*gamma*dz).* ...
( (2 + cos(2*chi)^2)*(abs(opt_x).^2) + ...
(2+2*sin(2*chi)^2)*(abs(opt_y).^2) ) );
rOpt_y = opt_y .* exp( (-1j*(1/3)*gamma*dz).* ...
( (2 + cos(2*chi)^2)*(abs(opt_y).^2) + ...
(2+2*sin(2*chi)^2)*(abs(opt_x).^2) ) );
% A_x = opt_x;
% A_y = opt_y;
%
% rOpt_x = 1i* gamma * (abs(A_x).^2 + (2/3 .* abs(A_y).^2) ) .* A_x + ((1i * gamma / 3) * conj(A_x).*(A_y.^2) * exp(-2i * dz * 2*pi / beatlength ));
% rOpt_y = 1i* gamma * (abs(A_y).^2 + (2/3 .* abs(A_x).^2) ) .* A_y + ((1i * gamma / 3) * conj(A_y).*(A_x.^2) * exp(-2i * dz * 2*pi / beatlength ));
else
% estimate effective length of dz (ref?)
if (alpha_lin_x == 0) && (alpha_lin_y == 0)
Leff = dz;
else
Leff = (1-exp(-alpha_lin_x*dz))/alpha_lin_x;
end
%compute power
power = real(opt_x).^2+imag(opt_x).^2+real(opt_y).^2+imag(opt_y).^2;
% power= abs(opt_x).^2+abs(opt_y).^2;
% powers = [powers;power];
Hnl = exp( -1j*8/9*gamma*power*Leff);
rOpt_x = opt_x .* Hnl;
rOpt_y = opt_y .* Hnl;
end
end

View File

@@ -0,0 +1,30 @@
function [rOpt,state] = nl_step(state,aOpt,aDz)
if ~state.manakov % CNLSE
rOpt.X = aOpt.X .* exp( (-1j*(1/3)*state.gamma*aDz).* ...
( (2 + cos(2*state.chi)^2)*(abs(aOpt.X).^2) + ...
(2+2*sin(2*state.chi)^2)*(abs(aOpt.Y).^2) ) );
rOpt.Y = aOpt.Y .* exp( (-1j*(1/3)*state.gamma*aDz).* ...
( (2 + cos(2*state.chi)^2)*(abs(aOpt.Y).^2) + ...
(2+2*sin(2*state.chi)^2)*(abs(aOpt.X).^2) ) );
else
% estimate effective length of dz (ref?)
if (state.alpha_lin.X == 0) && (state.alpha_lin.Y == 0)
Leff = aDz;
else
Leff = (1-exp(-state.alpha_lin.X*aDz))/state.alpha_lin.X;
end
%compute power
power = real(aOpt.X).^2+imag(aOpt.X).^2+real(aOpt.Y).^2+imag(aOpt.Y).^2;
% power= abs(aOpt.X).^2+abs(aOpt.Y).^2;
% state.powers = [state.powers;power];
Hnl = exp( -1j*8/9*state.gamma*power*Leff);
rOpt.X = aOpt.X .* Hnl;
rOpt.Y = aOpt.Y .* Hnl;
end
end

View File

@@ -0,0 +1,93 @@
function [opt_x,opt_y] = split_step_loop(L,opt_x,opt_y,gamma,SS_dzmin,SS_dzmax,SS_dphimax,alpha_lin,...
lin_z_test,corr_length,n_plates_done,missing_dz,brf,common_beta,...
chi,manakov,beat_len)
%SPLIT_STEP_LOOP Summary of this function goes here
% Detailed explanation goes here
%Optical Input
% opt_x;
% opt_y;
%
% %required for loop condition
% z_prop = 0;
% L;
%
% %required for NLstepsize
% gamma;
% SS_dzmin;
% SS_dzmax;
% SS_dphimax;
% alpha_lin;
%
% %required for lin_step
% z_prop;
% lin_z_test;
% corr_length;
% n_plates_done;
% missing_dz;
% n_step = 0;
% brf;
% common_beta.X;
% common_beta.Y;
% alpha_lin.X;
% alpha_lin.X;
%
% %required fr nonlin step
% chi;
% manakov;
% beat_len ;
% alpha_lin.X;
% alpha_lin.Y;
% get nonlinear step size
[dz] = getNLstepsize(opt_x,opt_y,gamma,SS_dzmin,SS_dzmax,SS_dphimax,alpha_lin);
n_step = 0;
z_prop = 0;
while z_prop < L
% reduce step length (dz) if we are to overshoot the fiber length
% (L) in the next step
if z_prop + dz > L
dz = L - z_prop;
end
% update step number (n)
n_step=n_step+1;
% half linear step
[opt_x,opt_y,z_prop,lin_z_test,...
corr_length,n_plates_done,missing_dz,n_step,...
brf,common_beta.X,...
common_beta.Y,alpha_lin.X,alpha_lin.X]...
= lin_step(...
opt_x,opt_y,z_prop,lin_z_test,...
dz/2,corr_length,n_plates_done,missing_dz,n_step,...
brf,common_beta.X,...
common_beta.Y,alpha_lin.X,alpha_lin.X);
% complete nonlinear step
[opt_x,opt_y] = nl_step(opt_x,opt_y, dz, gamma, chi, manakov, beat_len ,alpha_lin.X, alpha_lin.Y);
% half linear step
[opt_x,opt_y,z_prop,lin_z_test,...
corr_length,n_plates_done,missing_dz,n_step,...
brf,common_beta.X,...
common_beta.Y,alpha_lin.X,alpha_lin.X]...
= lin_step...
(opt_x,opt_y,z_prop,lin_z_test,...
dz/2,corr_length,n_plates_done,missing_dz,n_step,...
brf,common_beta.X,...
common_beta.Y,alpha_lin.X,alpha_lin.X);
% get nonlinear step size
[dz] = getNLstepsize(opt_x,opt_y,gamma,SS_dzmin,SS_dzmax,SS_dphimax,alpha_lin);
end
end