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

View File

@@ -0,0 +1,351 @@
classdef FFE_DCremoval_adaptive_mu < handle
% Implementation of plain and simple FFE.
% 1) Training mode (stable performance when you use NLMS)
% 2) Decision directed mode
% Eq = FFE("epochs_tr",5,"epochs_dd",5,"len_tr",4096*2,"mu_dd",1e-4,"mu_tr",0,"order",25,"sps",2,"decide",0);
properties
sps % usually 2
order
e
e_tr
error
len_tr
mu_tr
epochs_tr
mu_dd
epochs_dd
mu_dc
dc_buffer_len
adaptive_mu_mode
ffe_buffer_len
smoothing_buffer_length
smoothing_buffer_update
constellation
decide
end
methods
function obj = FFE_DCremoval_adaptive_mu(options)
arguments(Input)
options.sps = 2;
options.order = 15;
options.len_tr = 4096;
options.mu_tr = 0;
options.epochs_tr = 5;
options.mu_dd = 1e-5;
options.epochs_dd = 5;
options.mu_dc = 0.05;
options.dc_buffer_len = 1;
options.ffe_buffer_len = 1;
options.adaptive_mu_mode = 1;
options.smoothing_buffer_length = 0;
options.smoothing_buffer_update = 0;
options.decide = false;
end
assert(options.dc_buffer_len>0);
fn = fieldnames(options);
for n = 1:numel(fn)
obj.(fn{n}) = options.(fn{n});
end
obj.e = zeros(obj.order,1);
obj.error = 0;
obj.dc_buffer_len = floor(obj.dc_buffer_len);
end
function [X,Noi] = process(obj, X, D)
% actual processing of the signal (steps 1. - 3.)
% 1 normalize RMS
X = X.normalize("mode","rms");
obj.constellation = unique(D.signal);
% if obj.smoothing_buffer_length > 0
% % Apply A1 filter smoothing
% % Calculate the moving sum with the window size N1
% moving_sum = movsum(X.signal, [obj.smoothing_buffer_length,0]);
%
% % Initialize the output smoothed signal
% X.signal = X.signal - (1 / obj.smoothing_buffer_length) * moving_sum;
% end
% Training Mode
training = 1;
obj.equalize(X.signal, D.signal,obj.mu_tr,obj.epochs_tr,obj.len_tr,training);
obj.e_tr = obj.e;
% Decision Directed Mode
N = X.length;
training = 0;
[signal,decision]=obj.equalize(X.signal, D.signal,obj.mu_dd,obj.epochs_dd,N,training);
% Output Signal
if obj.decide
X.signal = decision;
else
X.signal = signal;
end
X.fs = D.fs; %change sampling frequency of outgoing signal from fdac e.g. 2 sps to symbol spaced = fsym
lbdesc = [num2str(obj.order),' tap FFE'];
X = X.logbookentry(lbdesc); % append to logbook
Noi = X - D;
end
function [y,d_hat] = equalize(obj, x, d, mu_lms, epochs, N, training)
% Equalize with adaptive DC-removal, VSS, and parallel-buffered DC updates
% Added: FFE gradient buffering in DD mode (error buffer) with update every obj.dc_buffer_len symbols
arguments
obj
x
d
mu_lms % LMS step-size (or 0 for NLMS)
epochs % number of training/DD epochs
N % number of samples to process
training % boolean flag: true->training mode, false->DD mode
end
if isempty(obj.e)
obj.e = zeros(obj.order,1);
end
% Zero-padding for filter memory
x = [zeros(floor(obj.order/2),1); x; zeros(obj.order,1)];
% Initialize storage
numSymbols = ceil(N/obj.sps);
y = zeros(numSymbols,1);
d_hat = zeros(numSymbols,1);
err = NaN(numSymbols,numel(obj.constellation));
e_dc_save= zeros(numSymbols,1);
% DC-adaptation parameters
P_err = 0; % running error power
alpha = 0.98; % forgetting factor for error power
err_prev = 0; % previous error sample for VSS correlation
gamma_dc = 1e-6; % meta step-size for DC VSS
mu_min = 1e-6; % lower bound for mu_dc
mu_max = 3e-1; % upper bound for mu_dc
% DC removal buffer
L = obj.dc_buffer_len; % buffer length
e_dc_buf = NaN(L,1);
e_dc_est = 0;
% FFE gradient buffer (DD mode only)
L_grad = obj.ffe_buffer_len; % buffer length
if ~training
% each column holds one past gradient of length obj.order
grad_buf = NaN(obj.order, L_grad);
end
smth_buffer = zeros(1, obj.smoothing_buffer_length);
smth_mean = 0;
% Main loop
for epoch = 1:epochs
s = 0;
for sample = 1:obj.sps:N
s = s + 1;
if obj.smoothing_buffer_length > 0
smth_buffer = circshift(smth_buffer,1,2);
smth_buffer(1) = x(sample);
if mod(s, obj.smoothing_buffer_update) == 0
smth_mean = mean(smth_buffer);
end
x(sample:sample+obj.sps-1) = x(sample:sample+obj.sps-1)-smth_mean;
end
U = x(obj.order+sample-1:-1:sample);
%-- 1) filter output with DC correction
y(s) = e_dc_est + obj.e.'*U;
%-- 2) decision
if training
[~, idx] = min(abs(d(s) - obj.constellation));
else
[~, idx] = min(abs(y(s) - obj.constellation));
end
d_hat(s) = obj.constellation(idx);
%-- 3) error
e_val = y(s) - d_hat(s);
if epoch == epochs
err(s,idx) = e_val;
true_err(s,idx) = y(s) - d(s);
end
%-- 4) tap-weight update: training immediate, DD buffered
if training
% immediate update (LMS or NLMS)
if mu_lms ~= 0
obj.e = obj.e - mu_lms * e_val * U;
else
normU = (U.'*U) + eps;
obj.e = obj.e - e_val * U / normU;
end
else
if 0
% buffer gradient
if mu_lms ~= 0
grad = e_val * U;
else
normU = (U.'*U) + eps;
grad = e_val * U / normU;
end
% shift and insert
grad_buf = circshift(grad_buf, 1, 2);
grad_buf(:,1) = grad;
% update once every L symbols
if mod(s, L_grad) == 0
avg_grad = mean(grad_buf, 2, 'omitnan');
if mu_lms ~= 0
obj.e = obj.e - mu_lms * avg_grad;
else
obj.e = obj.e - avg_grad;
end
end
end
end
%-- 5) DC adaptation
if obj.mu_dc ~= 0
if obj.adaptive_mu_mode
% VSS for mu_dc
delta_mu = gamma_dc * e_val * err_prev * (U.'*U);
obj.mu_dc = min(max(obj.mu_dc + delta_mu, mu_min), mu_max);
err_prev = e_val;
% DC buffer update & periodic estimate
P_err = alpha*P_err + (1-alpha)*e_val^2;
mu_dc_norm = obj.mu_dc / (P_err + eps);
else
% DC buffer update & periodic estimate
% P_err = alpha*P_err + (1-alpha)*e_val^2;
% mu_dc_norm = obj.mu_dc / (P_err + eps);
mu_dc_norm = obj.mu_dc;
end
e_dc_buf = circshift(e_dc_buf, 1);
e_dc_buf(1) = e_dc_est - mu_dc_norm * e_val;
if mod(s, L) == 0
e_dc_est = median(e_dc_buf, 'omitnan');
end
P_err_save(s) = P_err;
% Pcorr_save(s) = e_val * err_prev;
Ucorr_save(s) = (U.'*U);
mu_dc_save(s) = mu_dc_norm;
e_dc_save(s) = e_dc_est;
end
% store instantaneous squared error
obj.error(epoch, s) = e_val^2;
end
end
% Optional plotting in DD mode (uncomment if needed)
if 0%~training
constellation = unique(d);
lvlcol = cbrewer2('Paired', numel(constellation)*2);
lvlcol = lvlcol(2:2:end, :);
true_err(true_err==0) = NaN;
true_errmoverr = movsum(true_err, 4096, 'omitnan');
true_errmoverr = true_errmoverr./rms(true_errmoverr);
moverr = movsum(err, [100,100], 'omitnan');
moverr = moverr./rms(moverr);
figure(500); clf
hold on
% 1st subplot: true_errmoverr
% subplot(2,2,1); hold on
% for k = 1:4
% scatter(1:numSymbols, true_errmoverr(:,k), 1, lvlcol(k,:), '.');
% end
% scatter(1:numSymbols, Ucorr_save./rms(Ucorr_save), 1, lvlcol(1,:), '.','DisplayName','Ucorr_save');
% scatter(1:numSymbols, Pcorr_save./rms(Pcorr_save), 1, lvlcol(1,:), '.','DisplayName','P_corr');
% scatter(1:numSymbols, P_err_save, 1, lvlcol(1,:), '.','DisplayName','P_err');
% scatter(1:numSymbols, mu_dc_save, 1, lvlcol(2,:), '.','DisplayName','adapted value of $\mu_{DC}$');
% scatter(1:numSymbols, sum(moverr,2,'omitnan'), 1, lvlcol(1,:), '.','DisplayName','Mov Error $\hat{d}$ - x over all levels');
scatter(1:numSymbols, sum(e_dc_save,2,'omitnan'), 1, lvlcol(2,:), '.','DisplayName','Est. Error that is subtracted');
title('Moving Sum Error');
hold off
legend
% 2nd subplot: moverr
subplot(2,2,2); hold on
for k = 1:4
scatter(1:numSymbols, moverr(:,k), 1, lvlcol(k,:), '.');
end
title('Moving Sum Error');
hold off
legend
% 3rd subplot: err
subplot(2,2,3); hold on
for k = 1:4
scatter(1:numSymbols, err(:,k), 1, lvlcol(k,:), '.');
end
title('Error');
hold off
legend
% 4th subplot: err + obj.constellation'
subplot(2,2,4); hold on
for k = 1:4
scatter(1:numSymbols, err(:,k) + obj.constellation(k), 1, lvlcol(k,:), '.');
end
yline(obj.constellation, '--k');
title('Error + Constellation');
hold off
legend
sgtitle('Error Analysis Subplots');
end
end
end
end

View File

@@ -0,0 +1,240 @@
classdef FFE_DCremoval_level < handle
% Implementation of plain and simple FFE.
% 1) Training mode (stable performance when you use NLMS)
% 2) Decision directed mode
% Eq = FFE("epochs_tr",5,"epochs_dd",5,"len_tr",4096*2,"mu_dd",1e-4,"mu_tr",0,"order",25,"sps",2,"decide",0);
properties
sps % usually 2
order
e
error
len_tr
mu_tr
epochs_tr
mu_dd
epochs_dd
mu_dc
dc_buffer_len
constellation
decide
KF_meas_noise = 0;
KF_process_noise = 0;
KF_state_cov = 0;
end
methods
function obj = FFE_DCremoval_level(options)
arguments(Input)
options.sps = 2;
options.order = 15;
options.len_tr = 4096;
options.mu_tr = 0;
options.epochs_tr = 5;
options.mu_dd = 1e-5;
options.epochs_dd = 5;
options.mu_dc = 0.05;
options.dc_buffer_len = 1;
options.decide = false;
end
assert(options.dc_buffer_len>0);
fn = fieldnames(options);
for n = 1:numel(fn)
obj.(fn{n}) = options.(fn{n});
end
obj.e = zeros(obj.order,1);
obj.error = 0;
obj.dc_buffer_len = floor(obj.dc_buffer_len);
end
function [X,Noi] = process(obj, X, D)
% actual processing of the signal (steps 1. - 3.)
% 1 normalize RMS
X = X.normalize("mode","rms");
obj.constellation = unique(D.signal);
% Training Mode
training = 1;
obj.equalize(X.signal, D.signal,obj.mu_tr,obj.epochs_tr,obj.len_tr,training);
% Decision Directed Mode
N = X.length;
training = 0;
[signal,decision]=obj.equalize(X.signal, D.signal,obj.mu_dd,obj.epochs_dd,N,training);
% Output Signal
if obj.decide
X.signal = decision;
else
X.signal = signal;
end
X.fs = D.fs; %change sampling frequency of outgoing signal from fdac e.g. 2 sps to symbol spaced = fsym
lbdesc = [num2str(obj.order),' tap FFE'];
X = X.logbookentry(lbdesc); % append to logbook
Noi = X - D;
end
function [y, d_hat, logs] = equalize(obj, x, d, mu_lms, epochs, N, training)
% Equalize with Kalman-based DC removal; training epochs estimate KF noise parameters
arguments
obj
x
d
mu_lms % LMS step-size (or 0 for NLMS)
epochs % number of training or DD epochs
N % number of samples to process
training % true => training mode (tap-training + noise estimation)
end
% Zero-pad for filter memory
x = [zeros(floor(obj.order/2),1); x; zeros(obj.order,1)];
numSym = ceil(N/obj.sps);
% Pre-allocate outputs
y = zeros(numSym,1);
d_hat = zeros(numSym,1);
% --- Training: estimate noise stats and train taps ---
if training
% Pre-allocate error accumulator
totalTrain = epochs * numSym;
trainErrs = zeros(totalTrain,1);
te_idx = 0;
for ep = 1:epochs
s = 0;
for n = 1:obj.sps:N
s = s + 1;
U = x(obj.order + n - 1 : -1 : n);
% Equalizer output (no DC correction yet)
y(s) = obj.e.' * U;
% Decision based on known symbol
[~, idx] = min(abs(d(s) - obj.constellation));
d_hat(s) = obj.constellation(idx);
% Instantaneous error
e_n = y(s) - d_hat(s);
% Collect error for noise estimation
te_idx = te_idx + 1;
trainErrs(te_idx) = e_n;
% Tap-weight update (LMS or NLMS)
if mu_lms ~= 0
obj.e = obj.e - mu_lms * e_n * U;
else
normU = (U.'*U) + eps;
obj.e = obj.e - e_n * U / normU;
end
end
end
% Estimate measurement noise R and process noise Q
R_est = var(trainErrs(1:te_idx));
Q_est = 1e-3 * R_est; % Q/R ratio = 1e-3 (tune as needed)
% Store into object for DD pass
obj.KF_meas_noise = R_est;
obj.KF_process_noise = Q_est;
obj.KF_state_cov = 5*R_est; % or 5*R_est for a more eager start
% No Kalman in training; return
logs = struct();
return;
end
% --- Decision-Directed with Kalman DC tracking ---
% Initialize Kalman state
x_est = 0;
P = obj.KF_state_cov; % initial P (tune in obj; e.g. 1)
% Logging containers
logs.y_raw = zeros(numSym,1);
logs.y_corr = zeros(numSym,1);
logs.err = zeros(numSym,1);
logs.K_gain = zeros(numSym,1);
logs.x_est = zeros(numSym,1);
logs.P = zeros(numSym,1);
logs.normU = zeros(numSym,1);
logs.tap_norm = zeros(numSym,1);
for ep = 1:epochs
s = 0;
for n = 1:obj.sps:N
s = s + 1;
U = x(obj.order + n - 1 : -1 : n);
% 1) Kalman prediction
P = P + obj.KF_process_noise;
x_prior = x_est;
% 2) raw equalizer output
y_raw = obj.e.' * U;
logs.y_raw(s) = y_raw;
% 3) DC-corrected output
y_corr = y_raw + x_prior;
y(s) = y_corr;
logs.y_corr(s) = y_corr;
% 4) decision-directed symbol
[~, idx] = min(abs(y_corr - obj.constellation));
d_hat(s) = obj.constellation(idx);
% 5) error
e_n = y_corr - d_hat(s);
logs.err(s) = e_n;
% 6) tap-weight update (LMS/NLMS)
if mu_lms ~= 0
obj.e = obj.e - mu_lms * e_n * U;
else
normU = U.' * U + eps;
logs.normU(s) = normU;
obj.e = obj.e - e_n * U / normU;
end
logs.tap_norm(s) = norm(obj.e);
% 7) Kalman update
K_gain = P / (P + obj.KF_meas_noise);
x_est = x_prior + K_gain * (e_n - x_prior);
P = (1 - K_gain) * P;
% 8) log Kalman state
logs.K_gain(s) = K_gain;
logs.x_est(s) = x_est;
logs.P(s) = P;
end
end
end
end
end

View File

@@ -0,0 +1,233 @@
classdef FFE_MLSE < handle
% Implementation of plain and simple FFE.
% 1) Training mode (stable performance when you use NLMS)
% 2) Decision directed mode
%LMS: mu in order of 0.0001 for acceptable convergence speed
%NLMS: mu in order of 0.01 for acceptable convergence speed
%RLS: mu is lambda -> 0.99 -> 1 (has a strong dependency on this! use a loop to find out best values)
% FFE("epochs_tr",5,"epochs_dd",2,"len_tr",2^13,"mu_dd",mu_dd,"mu_tr",mu_tr,"order",25,"sps",2,"decide",0, "adaption",adaption_method(adaption),"dd_mode",use_dd_mode);
properties
sps % usually 2
order
e
e_tr
error
len_tr
mu_tr
epochs_tr
dd_mode % 1 or 0 to set DD-mode on or off
mu_dd %weight update in dd mode
epochs_dd
constellation
L %viterbi memory length
alpha
DIR
DIR_flip
trellis_states
traceback_depth
end
methods
function obj = FFE_MLSE(options)
arguments(Input)
options.sps = 2;
options.order = 15;
options.len_tr = 4096;
options.mu_tr = 0;
options.epochs_tr = 5;
options.dd_mode = 1;
options.mu_dd = 1e-5;
options.epochs_dd = 5;
options.traceback_depth = 1024;
options.L = 1
end
fn = fieldnames(options);
for n = 1:numel(fn)
obj.(fn{n}) = options.(fn{n});
end
obj.e = zeros(obj.order,1);
obj.error = 0;
end
function [X,X_viterbi] = process(obj, X, D)
% actual processing of the signal (steps 1. - 3.)
% 1 normalize RMS
X = X.normalize("mode","rms");
obj.constellation = unique(D.signal);
if length(X)/length(D) ~= obj.sps
warning('Signal length does not fit to reference!');
end
% Training Mode
n = obj.len_tr;
training = 1;
obj.equalize(X.signal, D.signal,obj.mu_tr,obj.epochs_dd,n,training);
obj.e_tr = obj.e;
% Decision Directed Mode
n = X.length;
training = 0;
[y,y_vit]=obj.equalize(X.signal, D.signal,obj.mu_dd,obj.epochs_dd,n,training);
X_viterbi = X;
X.signal = y;
X.fs = D.fs; %change sampling frequency of outgoing signal from fdac e.g. 2 sps to symbol spaced = fsym
lbdesc = [num2str(obj.order),' tap FFE'];
X = X.logbookentry(lbdesc); % append to logbook
X_viterbi.signal = y_vit;
X_viterbi.fs = D.fs; %change sampling frequency of outgoing signal from fdac e.g. 2 sps to symbol spaced = fsym
lbdesc = [num2str(obj.order),'order FFE + PF + Viterbi'];
X_viterbi = X_viterbi.logbookentry(lbdesc); % append to logbook
end
function [y,y_vit] = equalize(obj,x,d,mu,epochs,N,training)
% ==============================================================
% FFE + Whitening + Viterbi Equalizer (reference implementation)
% ==============================================================
% --- Input padding and preallocation
x = [zeros(floor(obj.order/2),1); x; zeros(obj.order,1)];
N_ = N / obj.sps;
y = zeros(N_,1);
y_white = zeros(N_,1);
for epoch = 1:epochs
% ==============================================================
% INITIALIZATION (only before final epoch and detection mode)
% ==============================================================
if epoch == epochs && ~training
% --- Parameters
S = numel(unique(d));
L = obj.L;
nStates = S^L;
nFeasible = S^(L-1)*S;
% --- Trellis setup
obj.DIR = arburg(y-d, L);
obj.DIR_flip = flip(obj.DIR);
obj.trellis_states = reshape(unique(d),1,[]);
pre_comb_mat = repmat(obj.trellis_states, L, 1);
pre_comb_cell = mat2cell(pre_comb_mat, ones(1,L), size(pre_comb_mat,2));
combs = fliplr(combvec(pre_comb_cell{:}).');
first_sym = combs(:,1);
last_sym = combs(:,end);
nStates = size(combs,1);
noise_free_received = inf(nStates,nStates);
valid = false(nStates);
for from = 1:nStates
for to = 1:nStates
if all(combs(to,2:end) == combs(from,1:end-1))
noise_free_received(to,from) = ...
dot(combs(to,:), obj.DIR_flip(end:-1:2)) + last_sym(from)*obj.DIR_flip(1);
valid(to,from) = true;
end
end
end
nf_vec = noise_free_received(valid);
[valid_to, valid_from] = find(valid);
from_per_to = arrayfun(@(to)find(valid(to,:)), 1:nStates, 'UniformOutput', false);
% --- Noise stats
y_ideal = conv(d(:), obj.DIR(:), "same");
sigma2 = mean(abs(y - y_ideal).^2);
inv2s2 = 1/(2*sigma2);
% --- Vector initialization
bm_vec = zeros(1,nFeasible);
pm = zeros(nStates,1);
pm_next = zeros(nStates,1);
bm_fw = zeros(nStates,nStates,length(y));
zi = zeros(max(numel(obj.DIR)-1,0),1);
end
% ==============================================================
% RUNTIME LOOP (FFE update + Viterbi detection in last epoch)
% ==============================================================
symbol = 0;
for sample = 1:obj.sps:N
symbol = symbol + 1;
% --- FFE output
U = x(obj.order+sample-1:-1:sample);
y(symbol,1) = obj.e.' * U;
% --- Decision
if training
d_hat(symbol,1) = d(symbol);
else
[~,symbol_idx] = min(abs(y(symbol) - obj.constellation));
d_hat(symbol,1) = obj.constellation(symbol_idx);
end
% --- LMS weight update
err(symbol) = d_hat(symbol) - y(symbol);
obj.e = obj.e + mu * (err(symbol) * U);
% --- Whitening + Viterbi (final epoch only)
if epoch == epochs && ~training
[y_white(symbol), zi] = filter(obj.DIR,1,y(symbol), zi);
if symbol == 1
pm = -inf(nStates,nStates);
pm(:,1:nStates) = 0;
else
bm_vec = -(y_white(symbol) - nf_vec).^2 * inv2s2;
bm_mat = -inf(nStates,nStates);
bm_mat(valid) = bm_vec;
pm_new = pm + bm_mat;
[pm_survive(:,symbol), pm_survivor_fw_idx(:,symbol)] = max(pm_new,[],2);
pm = repmat(pm_survive(:,symbol).', nStates,1);
end
% --- Traceback
if mod(symbol,obj.traceback_depth) == 0
[~,viterbi_path(symbol)] = max(pm_survive(:,symbol));
for n = symbol:-1:symbol-obj.traceback_depth+2
viterbi_path(n-1) = pm_survivor_fw_idx(viterbi_path(n),n);
end
end
end
end
% --- Final reconstruction
if epoch == epochs && ~training
y_vit = first_sym(viterbi_path);
end
end
end
end
end

View File

@@ -0,0 +1,355 @@
classdef ML_MLSE < handle
% ---------------------------------------------------------------------
% W. Lanneer and Y. Lefevre,
% Machine Learning-Based Pre-Equalizers for Maximum Likelihood
% Sequence Estimation in High-Speed PONs, EUSIPCO 2023
% ---------------------------------------------------------------------
% This implementation reproduces the closed-loop ML-based
% pre-equalizer training for MLSE, supporting both training and
% detection (decision-directed) modes.
% ---------------------------------------------------------------------
properties
sps
order
e
e_tr
error
len_tr
mu_tr
epochs_tr
dd_mode
mu_dd
epochs_dd
adaptive_mu
constellation
L
alpha
DIR
DIR_flip
trellis_states
traceback_depth
delta
% Internal variables
S
Nf
nStates
nFeasible
combs
first_sym
last_sym
valid
valid_to_idx
valid_from_idx
w
% Fast lookup
nSym
key_table
trans_index
true_to_state_idx
% Debug metrics
ber = []
ce = ones(1,1)
end
methods
function obj = ML_MLSE(options)
arguments(Input)
options.sps = 2;
options.order = 15;
options.len_tr = 4096;
options.mu_tr = 0.001;
options.epochs_tr = 5;
options.dd_mode = 1;
options.mu_dd = 1e-5;
options.epochs_dd = 5;
options.adaptive_mu = 1;
options.delta = 0;
options.traceback_depth = 1024;
options.L = 1;
end
fn = fieldnames(options);
for n = 1:numel(fn)
obj.(fn{n}) = options.(fn{n});
end
obj.e = zeros(obj.order,1);
obj.error = 0;
end
% ==============================================================
% PROCESS
% ==============================================================
function [X,X_viterbi] = process(obj, X, D)
% Normalize input RMS
X = X.normalize("mode","rms");
obj.constellation = sort(unique(D.signal),'ascend');
obj.nSym = numel(obj.constellation);
if length(X)/length(D) ~= obj.sps
warning('Signal length does not fit to reference!');
end
% --- Parameters
obj.S = obj.nSym;
obj.Nf = obj.order * obj.sps;
obj.nStates = obj.S^obj.L;
obj.nFeasible = obj.nStates * obj.S;
% --- Trellis mapping
obj.trellis_states = reshape(obj.constellation,1,[]);
pre_comb_mat = repmat(obj.trellis_states, obj.L, 1);
pre_comb_cell = mat2cell(pre_comb_mat, ones(1,obj.L), size(pre_comb_mat,2));
obj.combs = fliplr(combvec(pre_comb_cell{:}).');
obj.first_sym = obj.combs(:,1);
obj.last_sym = obj.combs(:,end);
obj.nStates = size(obj.combs,1);
% --- Valid transitions
obj.valid = false(obj.nStates);
for from = 1:obj.nStates
for to = 1:obj.nStates
if all(obj.combs(to,2:end) == obj.combs(from,1:end-1))
obj.valid(to,from) = true;
end
end
end
[obj.valid_to_idx,obj.valid_from_idx] = find(obj.valid);
% --- Initialize weights
if isempty(obj.w) || any(size(obj.w) ~= [obj.Nf+1,obj.nFeasible])
obj.w = randn(obj.Nf+1,obj.nFeasible);
end
% --- Fast lookup tables
[~, sym_idx_mat] = ismember(obj.combs, obj.constellation);
key_vals = 1 + sum((sym_idx_mat - 1) .* (obj.nSym .^ (0:obj.L-1)), 2);
max_key = obj.nSym^obj.L;
obj.key_table = zeros(max_key,1,'uint32');
obj.key_table(key_vals) = 1:obj.nStates;
obj.trans_index = sparse(obj.nStates,obj.nStates);
for i = 1:length(obj.valid_from_idx)
f = obj.valid_from_idx(i);
t = obj.valid_to_idx(i);
obj.trans_index(t,f) = i;
end
% ==============================================================
% TRAINING
% ==============================================================
fprintf('\n--- Training mode ---\n');
obj.equalize(X.signal, D.signal, obj.mu_tr, obj.epochs_tr, obj.len_tr, true);
obj.e_tr = obj.e;
% ==============================================================
% DECISION-DIRECTED / TESTING
% ==============================================================
fprintf('--- Decision-directed / detection mode ---\n');
[y, y_vit] = obj.equalize(X.signal, D.signal, obj.mu_dd, obj.epochs_dd, X.length, false);
X_viterbi = X;
X.signal = y;
X_viterbi.signal = y_vit;
end
% ==============================================================
% EQUALIZE
% ==============================================================
function [y,y_ref] = equalize(obj,x,d,mu,epochs,N,training)
debug = 0;
showPlots = 0;
y = zeros(N,1);
nSymbols = ceil(N/obj.sps);
for epoch = 1:epochs
pm = zeros(obj.nStates,1);
pred = zeros(nSymbols,obj.nStates,'uint32');
pm_sto = nan(obj.nStates,nSymbols,'like',pm);
CE_accum = 0;
start_sample = 1;
end_sample = N;
start_symbol = 1 + floor((start_sample - 1)/obj.sps);
% --- initialize true state
if numel(d) >= obj.L && start_symbol >= obj.L
init_seq = d(start_symbol-obj.L+1:start_symbol);
key_init = obj.seq2key(init_seq);
true_to_state_idx = obj.key_table(key_init);
if true_to_state_idx==0, true_to_state_idx=1; end
else
true_to_state_idx = uint32(1);
end
for sample = start_sample:obj.sps:end_sample
symbol = (sample - start_sample)/obj.sps + 1;
sym_idx = start_symbol + (symbol - 1);
% --- Observation window (with delta)
i1 = sample - obj.Nf + 1 + obj.delta;
i2 = sample + obj.delta;
buf = x(max(1,i1):min(length(x),i2));
padL = max(0,1 - i1);
padR = max(0,i2 - length(x));
yk = [zeros(padL,1); buf(:); zeros(padR,1)];
yk = [yk;1];
% --- Branch metrics
c_hat = (yk.' * obj.w).';
pm = pm - min(pm);
v_tilde = pm(obj.valid_from_idx) + c_hat;
% --- allocate once
if epoch==1 && symbol==1
obj.true_to_state_idx = ones(ceil(N/obj.sps),1,'uint32');
end
% --- previous "to" becomes "from"
if symbol>1
true_from_state_idx = obj.true_to_state_idx(symbol-1);
else
true_from_state_idx = 1;
end
% --- compute or reuse "to" state
if epoch==1
if sym_idx>=obj.L
key_to = obj.seq2key(d(sym_idx-obj.L+1:sym_idx));
state_idx = obj.key_table(key_to);
if state_idx==0
state_idx = true_from_state_idx;
end
obj.true_to_state_idx(symbol) = state_idx;
else
obj.true_to_state_idx(symbol) = true_from_state_idx;
end
end
true_to_state_idx = obj.true_to_state_idx(symbol);
% --- fast Dirac creation
dirac = zeros(obj.nFeasible,1);
trans_idx = obj.trans_index(true_to_state_idx,true_from_state_idx);
if trans_idx~=0
dirac(trans_idx)=1;
end
% ===================================================================
% TRAINING MODE (weight update)
% ===================================================================
if training
% --- Softmax and CE
v_shift = -(v_tilde - min(v_tilde));
v_shift = min(v_shift,100);
expv = exp(v_shift);
p = expv./(sum(expv)+eps);
CE_symbol(symbol) = -log(p(dirac==1)+eps);
% --- CE smoothing and adaptive μ
if sym_idx>obj.L
CE_smooth(symbol)=0.01*CE_symbol(symbol)+0.99*CE_symbol(symbol-1);
else
CE_smooth(symbol)=CE_symbol(symbol);
end
CE_accum=CE_accum+CE_symbol(symbol);
% --- Gradient update
dmp=(dirac-p)';
dL_Dw=(yk).*dmp;
if sym_idx>=obj.L
if obj.adaptive_mu
mu_eff=CE_smooth(symbol);
mu_eff=max(min(mu_eff,0.2),1e-4);
else
mu_eff=mu;
end
obj.w=obj.w - mu_eff.*dL_Dw;
end
end
% ===================================================================
% DECODING MODE (Viterbi only)
% ===================================================================
% Compare-Select (always executed)
vmat=inf(obj.nStates,obj.nStates);
vmat(obj.valid)=v_tilde;
[pm_next,pred(symbol,:)]=min(vmat,[],2);
pm_next=pm_next-min(pm_next);
pm=pm_next;
pm_sto(:,symbol)=pm;
end
% --- Traceback
[~,s_end]=min(pm);
vpath=zeros(symbol,1,'uint32');
vpath(symbol)=s_end;
for n=symbol:-1:2
vpath(n-1)=pred(n,vpath(n));
end
y_ref=d(start_symbol:end);
y=obj.first_sym(vpath);
% --- BER/CE reporting and plots
if training
err=sum(y~=y_ref(1:length(y)));
ser=err/length(y);
try
ref_bits=PAMmapper(obj.S,0).demap(y_ref(1:length(y)));
eq_bits=PAMmapper(obj.S,0).demap(y);
[~,~,ber,~]=calc_ber(ref_bits,eq_bits,"skip_front",10,"skip_end",10,"returnErrorLocation",1);
fprintf('Epoch %d - BER: %.2e\n',epoch,ber);
obj.ber(epoch)=ber;
catch
fprintf('Epoch %d - SER: %.2e\n',epoch,ser);
obj.ber(epoch)=ser;
end
obj.ce(epoch)=CE_accum/symbol;
if debug && mod(epoch,10)==1 && showPlots
figure(10);clf
subplot(3,2,1:2);
imagesc(obj.w);axis xy;colorbar;title('Filter W');
subplot(3,2,3);
vtilde_mat=NaN(obj.nStates,obj.nStates);
vtilde_mat(obj.valid)=v_tilde;
imagesc(vtilde_mat);axis xy;colorbar;title('Path Metrics (v\_tilde)');
subplot(3,2,4);
plot(1:symbol,pm_sto);title('Path Metric Evolution');
subplot(3,2,5);hold on;
scatter(1:symbol,CE_symbol,1,'.');
scatter(1:symbol,CE_smooth,1,'.');
title('Cross Entropy');
subplot(3,2,6);hold on;
yyaxis left
scatter(1:length(obj.ce),obj.ce,10,'s','filled');
ylabel('Cross Entropy');
yyaxis right
scatter(1:length(obj.ber),obj.ber,10,'d','filled');
set(gca,'YScale','log');
ylabel('BER (log)');
xlabel('Epoch');grid on;
title('Convergence');
drawnow;
end
end
end
end
% ==============================================================
% Helper: Sequence key (always scalar)
% ==============================================================
function key = seq2key(obj, seq)
[~, idx] = ismember(flip(seq), obj.constellation);
pow = (obj.nSym .^ (0:obj.L-1)).';
key = 1 + sum((idx(:) - 1) .* pow);
end
end
end

View File

@@ -0,0 +1,152 @@
classdef MLSE_new < handle
%MLSE: BCJRbased softoutput for PAMM sequence estimation & GMI
properties
M % PAM order (e.g. 4)
DIR % channel impulse response
trellis_states % PAM constellation levels (e.g. [-3 -1 1 3])
end
methods
function obj = MLSE_new(opts)
arguments
opts.M double = 4;
opts.DIR double = 1;
opts.trellis_states double = [-3 -1 1 3];
end
obj.M = opts.M;
obj.DIR = opts.DIR;
obj.trellis_states = opts.trellis_states;
end
function [hd_out, LLR, NGMI] = process(obj, signalclass,ref_symbolclass)
% rx, tx: column vectors of equalized and reference symbols
data_in = signalclass.signal;
shape_in = size(data_in);
data_ref = ref_symbolclass.signal;
[data_out_hd,LLR,GMI] = obj.bcjr_soft(data_in,data_ref);
try
data_out_hd = reshape(data_out_hd,shape_in(1),shape_in(2));
catch
warning('output reshaping failed after MLSE');
end
signalclass_hd = signalclass;
signalclass_hd.signal = data_out_hd;
[hd_out, LLR, NGMI] = obj.bcjr_soft(rx, tx);
end
end
methods (Access=private)
function [hd_sym, LLR, NGMI] = bcjr_soft(obj, y, x)
%--- build trellis states & branch outputs ---
DIR = flip(obj.DIR(:));
S = combvec(obj.trellis_states, obj.trellis_states)';
prev = S(:,1); cur = S(:,2);
branch_out = prev*DIR(1) + cur*DIR(2); % for 2tap
N = numel(y);
M = obj.M;
m = log2(M);
%--- forward/backward metrics (maxlog) ---
nStates = numel(obj.trellis_states);
alpha = -inf(nStates,N);
beta = -inf(nStates,N);
bm_fw = zeros(nStates,nStates,N);
% branch metrics
sigma2 = var(y - x);
inv2sigma2 = 1/(2*sigma2);
for n=1:N
bm = -((y(n)-branch_out).^2)* inv2sigma2;
bm = reshape(bm, nStates, nStates);
bm_fw(:,:,n) = bm;
end
% forward
alpha(:,1) = max(bm_fw(:,:,1),[],2);
for n=2:N
mat = alpha(:,n-1) + bm_fw(:,:,n);
alpha(:,n) = max(mat,[],2);
end
% backward
beta(:,N) = 0;
for n=N-1:-1:1
mat = beta(:,n+1).' + bm_fw(:,:,n+1);
beta(:,n) = max(mat,[],2);
end
% Precompute the zeroth forward metric
alpha0 = zeros(nStates,1);
LLP = -inf(nStates,nStates,N);
for n = 1:N
% Select the correct previous alpha column
if n == 1
a_prev = alpha0;
else
a_prev = alpha(:,n-1);
end
% Combine α, branch metric, and β
mat = a_prev + bm_fw(:,:,n) + beta(:,n).';
LLP(:,:,n) = mat;
end
%--- compute LLRs symbolwise via logsumexp over branches ---
levels = obj.trellis_states;
bit_map = PAMmapper(M,0).demap(levels');
LLR = zeros(N,m);
for n=1:N
% sum branch posteriors per symbol
llp_n = LLP(:,:,n);
logZ = logsumexp(llp_n(:));
post = exp(llp_n - logZ);
% aggregate per symbol index
Psym = zeros(M,1);
for i=1:nStates
for j=1:nStates
% branch (i->j) emits symbol 'cur(j)'
idx = find(levels==cur(j));
Psym(idx) = Psym(idx) + post(i,j);
end
end
% bitLLR from symbol posterior
for k=1:m
idx1 = bit_map(:,k)==1;
idx0 = ~idx1;
P1 = sum(Psym(idx1));
P0 = sum(Psym(idx0));
LLR(n,k) = log(P1/P0);
end
end
%--- hard decisions ---
[~,symIdx] = max(LLR,[],2);
hd_sym = levels(symIdx);
%--- GMI via Alvarado Eq.(30) ---
tx_bits = PAMmapper(M,0).demap(x);
MI = zeros(1,m);
for k=1:m
r0 = LLR(tx_bits(:,k)==0,k);
r1 = LLR(tx_bits(:,k)==1,k);
I0 = mean(log2(1+exp(-r0)));
I1 = mean(log2(1+exp(+r1)));
MI(k) = 1 - 0.5*(I0+I1);
end
GMI = sum(MI);
NGMI = GMI/m;
end
end
end
function s = logsumexp(a)
m = max(a(:));
s = m + log(sum(exp(a-m), 'all'));
end

View File

@@ -0,0 +1,68 @@
classdef Equalizerstruct
% Equalizerstruct - Class to store and manage equalizer structure data
properties
eq_id (1,1) double {mustBeNumeric} = NaN
equalizer_structure equalizer_structure = equalizer_structure.ffe
eq
mlse
comment char = string.empty() % Changed to string with proper empty initialization
hash char = string.empty() % Changed to string with proper empty initialization
end
methods
function obj = Equalizerstruct(varargin)
% Constructor method for Equalizerstruct
% Can be called empty or with name-value pairs
if nargin > 0
for i = 1:2:nargin
if isprop(obj, varargin{i})
obj.(varargin{i}) = varargin{i+1};
else
error('Property %s does not exist in Equalizerstruct', varargin{i});
end
end
end
end
function s = toStruct(obj)
% Convert the object to a struct
s = struct();
props = properties(obj);
for i = 1:length(props)
s.(props{i}) = obj.(props{i});
end
end
function str = toString(obj)
% Convert the object to a formatted string
s = obj.toStruct();
str = sprintf('Equalizerstruct:\n');
fields = fieldnames(s);
for i = 1:length(fields)
val = s.(fields{i});
if isempty(val)
str = sprintf('%s%s: []\n', str, fields{i});
elseif isnumeric(val) && length(val) > 1
str = sprintf('%s%s: [%s]\n', str, fields{i}, num2str(val'));
else
str = sprintf('%s%s: %s\n', str, fields{i}, string(val));
end
end
end
end
methods (Static)
function obj = fromStruct(s)
% Create an Equalizerstruct object from a struct
obj = Equalizerstruct();
fields = fieldnames(s);
for i = 1:length(fields)
if isprop(obj, fields{i})
obj.(fields{i}) = s.(fields{i});
end
end
end
end
end

View File

@@ -0,0 +1,147 @@
classdef Metricstruct
% ResultData - Class to store and manage metric data from signal processing results
properties
result_id (1,1) double {mustBeNumeric} = NaN
run_id (1,1) double {mustBeNumeric} = NaN
eqParam_id (1,1) double {mustBeNumeric} = NaN
date_of_processing (1,1) datetime = datetime('now')
numBits (1,1) double {mustBeInteger, mustBeNonnegative} = 0
BER (1,1) double {mustBeNumeric, mustBeNonnegative, mustBeLessThanOrEqual(BER,1)} = 0
numBitErr (1,1) double {mustBeInteger, mustBeNonnegative} = 0
BER_precoded (1,1) double {mustBeNumeric, mustBeNonnegative, mustBeLessThanOrEqual(BER_precoded,1)} = 0
numBitErr_precoded (1,1) double {mustBeInteger, mustBeNonnegative} = 0
SNR (1,1) double {mustBeNumeric} = NaN
SNR_level (:,1) double {mustBeNumeric} = []
STD (1,1) double {mustBeNumeric} = NaN
STD_level (:,1) double = []
STDrx (1,1) double {mustBeNumeric} = NaN
STDrx_level (:,1) double = []
EVM (1,1) double {mustBeNumeric} = NaN
EVM_level (:,1) double {mustBeNumeric} = []
GMI (1,1) double {mustBeNumeric} = NaN
AIR (1,1) double {mustBeNumeric} = NaN
Alpha (:,1) double {mustBeNumeric} = NaN
MLSE_dir (:,1) double {mustBeNumeric} = []
end
methods
function obj = Metricstruct(varargin)
% Constructor method for ResultData
% Can be called empty or with name-value pairs
% Process name-value pairs if provided
if nargin > 0
for i = 1:2:nargin
if isprop(obj, varargin{i})
obj.(varargin{i}) = varargin{i+1};
else
error('Property %s does not exist in ResultData', varargin{i});
end
end
end
end
function s = toStruct(obj)
% Convert the object to a struct
s = struct();
props = properties(obj);
for i = 1:length(props)
s.(props{i}) = obj.(props{i});
end
end
function str = toString(obj)
% Convert the object to a formatted string
s = obj.toStruct();
str = sprintf('ResultData:\n');
fields = fieldnames(s);
for i = 1:length(fields)
val = s.(fields{i});
if isempty(val)
str = sprintf('%s%s: []\n', str, fields{i});
elseif isnumeric(val) && length(val) > 1
str = sprintf('%s%s: [%s]\n', str, fields{i}, num2str(val'));
else
str = sprintf('%s%s: %s\n', str, fields{i}, string(val));
end
end
end
function print(obj,options)
% Print method to display key metrics in a formatted way
arguments
obj
options.description = '';
end
% Define the width for formatting
nameWidth = 15; % Width for parameter names
valueWidth = 12; % Width for values
% Print header
fprintf('\n%s\n', repmat('=', 1, nameWidth + valueWidth));
fprintf([char(options.description),' Results \n']);
fprintf('%s\n', repmat('=', 1, nameWidth + valueWidth));
% Function to format numbers with appropriate precision
function str = formatNumber(value)
if isnan(value)
str = 'N/A';
elseif abs(value) < 0.1 && value ~= 0
str = sprintf('%.2e', value);
else
str = sprintf('%.4f', value);
end
end
% Print each metric
% BER metrics
fprintf('%-*s: %*s\n', nameWidth, 'BER', valueWidth, formatNumber(obj.BER));
fprintf('%-*s: %*s\n', nameWidth, 'BER (precoded)', valueWidth, formatNumber(obj.BER_precoded));
% SNR
fprintf('%-*s: %*s\n', nameWidth, 'SNR', valueWidth, formatNumber(obj.SNR));
% Information rates
fprintf('%-*s: %*s\n', nameWidth, 'GMI', valueWidth, formatNumber(obj.GMI));
fprintf('%-*s: %*s GBd \n', nameWidth, 'AIR', valueWidth, formatNumber(obj.AIR.*1e-9));
% Alpha (if it's not empty, show first few values)
if ~isempty(obj.Alpha)
if length(obj.Alpha) <= 3
alphaStr = sprintf('%.4f ', obj.Alpha);
else
alphaStr = sprintf('%.4f %.4f %.4f...', obj.Alpha(1:3));
end
fprintf('%-*s: %s\n', nameWidth, 'Alpha', alphaStr);
else
fprintf('%-*s: %*s\n', nameWidth, 'Alpha', valueWidth, '[]');
end
% Print footer
fprintf('%s\n', repmat('=', 1, nameWidth + valueWidth));
end
end
methods (Static)
function obj = fromStruct(s)
% Create a ResultData object from a struct
obj = Metricstruct();
fields = fieldnames(s);
for i = 1:length(fields)
if isprop(obj, fields{i})
obj.(fields{i}) = s.(fields{i});
end
end
end
end
end

View File

@@ -0,0 +1,169 @@
% QueryFilter - Class for building SQL WHERE conditions for database queries.
%
% Usage:
% qf = QueryFilter();
% qf.where('Runs', 'fiber_length', SqlOperator.GREATER_THAN, 5);
% qf.where('Runs', 'bitrate', SqlOperator.IN, [224, 336, 448]);
% qf.where('Runs', 'is_mpi', SqlOperator.EQUALS, 0);
%
% % Convert to struct for use in DBHandler or other query functions:
% filterStruct = qf.toStruct();
%
% % Display current filters:
% disp(qf);
classdef QueryFilter < handle
properties (Access = private)
filters struct = struct()
end
methods
function obj = QueryFilter(oldFormat)
% Constructor - optionally convert from old filter format
if nargin > 0 && isstruct(oldFormat)
tableNames = fieldnames(oldFormat);
for t = 1:length(tableNames)
tableName = tableNames{t};
if isstruct(oldFormat.(tableName))
fields = fieldnames(oldFormat.(tableName));
for f = 1:length(fields)
fieldName = fields{f};
value = oldFormat.(tableName).(fieldName);
if ~isempty(value)
obj.where(tableName, fieldName, value);
end
end
end
end
end
end
function where(obj, tableName, fieldName, operator, value)
% Add a WHERE condition to the query
%
% Inputs:
% tableName - Name of the database table (char)
% fieldName - Name of the field/column (char)
% operator - SqlOperator enum or value if using EQUALS
% value - Value to filter by
%
% Example:
% filter.where('Runs', 'fiber_length', SqlOperator.GREATER_THAN, 5)
arguments
obj
tableName char
fieldName char
operator SqlOperator
value = []
end
% Handle case where operator is the value (using default EQUALS)
if nargin < 5
value = operator;
operator = SqlOperator.EQUALS;
end
% Validate operator type
if ~isa(operator, 'SqlOperator')
error('Operator must be a SqlOperator enumeration');
end
% Validate value based on operator
obj.validateValue(operator, value);
% Create filter
filter = SqlFilter(value, operator.toSqlString());
% Add to filters
if ~isfield(obj.filters, tableName)
obj.filters.(tableName) = struct();
end
obj.filters.(tableName).(fieldName) = filter;
end
function s = toStruct(obj)
% Convert filters to struct format for database query
s = obj.filters;
end
function display(obj)
% Custom display of filter conditions
fprintf('QueryFilter with conditions:\n');
if isempty(fieldnames(obj.filters))
fprintf(' No filters set\n');
return;
end
tables = fieldnames(obj.filters);
for t = 1:length(tables)
tableName = tables{t};
if ~isempty(fieldnames(obj.filters.(tableName)))
fprintf('\nTable: %s\n', tableName);
fields = fieldnames(obj.filters.(tableName));
for f = 1:length(fields)
fieldName = fields{f};
filter = obj.filters.(tableName).(fieldName);
if isnumeric(filter.value)
if length(filter.value) > 1
valueStr = ['[', num2str(filter.value), ']'];
else
valueStr = num2str(filter.value);
end
elseif isempty(filter.value)
valueStr = 'empty';
else
valueStr = char(filter.value);
end
fprintf(' %s %s %s\n', fieldName, filter.operator, valueStr);
end
end
end
end
function clear(obj, tableName)
% Clear all filters or filters for a specific table
if nargin < 2
obj.filters = struct();
else
if isfield(obj.filters, tableName)
obj.filters = rmfield(obj.filters, tableName);
end
end
end
function remove(obj, tableName, fieldName)
% Remove a specific filter
if isfield(obj.filters, tableName) && ...
isfield(obj.filters.(tableName), fieldName)
obj.filters.(tableName) = rmfield(obj.filters.(tableName), fieldName);
end
end
end
methods (Access = private)
function validateValue(~, operator, value)
% Validate value based on operator type
switch operator
case SqlOperator.BETWEEN
if ~isnumeric(value) || length(value) ~= 2
error('BETWEEN operator requires array of 2 numbers');
end
case SqlOperator.IN
if ~isnumeric(value) || isempty(value)
error('IN operator requires non-empty array');
end
case SqlOperator.LIKE
if ~ischar(value) && ~isstring(value)
error('LIKE operator requires string value');
end
otherwise
% For other operators, just ensure value is not empty
if isempty(value)
error('Value cannot be empty');
end
end
end
end
end

View File

@@ -0,0 +1,22 @@
% SqlFilter - Internal class for holding a value and SQL operator for a filter condition.
%
% Usage:
% f = SqlFilter(10, SqlOperator.GREATER_THAN.toSqlString());
% % f.value == 10, f.operator == '>'
classdef SqlFilter
properties
value
operator char = '='
end
methods
function obj = SqlFilter(value, operator)
obj.value = value;
if nargin > 1
obj.operator = operator;
end
end
end
end

View File

@@ -0,0 +1,48 @@
% SqlOperator - Enumeration of supported SQL operators for query building.
%
% Usage:
% op = SqlOperator.GREATER_THAN;
% opStr = op.toSqlString(); % returns '>'
%
% Supported operators:
% EQUALS, GREATER_THAN, LESS_THAN, GREATER_EQUAL, LESS_EQUAL,
% NOT_EQUAL, IN, BETWEEN, LIKE
classdef SqlOperator < uint32
enumeration
EQUALS (1) % ==
GREATER_THAN (2) % >
LESS_THAN (3) % <
GREATER_EQUAL (4) % >=
LESS_EQUAL (5) % <=
NOT_EQUAL (6) % !=
IN (7) % IN
BETWEEN (8) % BETWEEN
LIKE (9) % LIKE
end
methods
function op = toSqlString(obj)
switch obj
case SqlOperator.EQUALS
op = '=';
case SqlOperator.GREATER_THAN
op = '>';
case SqlOperator.LESS_THAN
op = '<';
case SqlOperator.GREATER_EQUAL
op = '>=';
case SqlOperator.LESS_EQUAL
op = '<=';
case SqlOperator.NOT_EQUAL
op = '!=';
case SqlOperator.IN
op = 'IN';
case SqlOperator.BETWEEN
op = 'BETWEEN';
case SqlOperator.LIKE
op = 'LIKE';
end
end
end
end

View File

@@ -0,0 +1,32 @@
function cleanedTable = cleanUpTable(inputTable)
% Converts string numbers to numeric, 'NaN' to NaN, and tries to convert date strings to datetime.
cleanedTable = inputTable;
varNames = cleanedTable.Properties.VariableNames;
for i = 1:numel(varNames)
col = cleanedTable.(varNames{i});
if iscell(col)
numericCol = str2double(col);
if all(isnan(numericCol) == strcmpi(col, 'NaN') | cellfun(@isempty, col))
cleanedTable.(varNames{i}) = numericCol;
else
try
cleanedTable.(varNames{i}) = datetime(col, 'InputFormat', 'yyyy-MM-dd HH:mm:ss.SSSSSS');
catch
cleanedTable.(varNames{i}) = string(col);
end
end
elseif isstring(col)
numericCol = str2double(col);
if all(isnan(numericCol) == strcmpi(col, "NaN"))
cleanedTable.(varNames{i}) = numericCol;
else
try
cleanedTable.(varNames{i}) = datetime(col, 'InputFormat', 'yyyy-MM-dd HH:mm:ss');
catch
end
end
end
end
end

View File

@@ -0,0 +1,53 @@
function resultTable = groupIt(fixedVars, dataTable, aggregationFunction)
% groupIt Groups data in a table based on fixedVars and applies aggregationFunction to numeric data.
%
% resultTable = groupIt(fixedVars, dataTable, aggregationFunction)
%
% Inputs:
% fixedVars - Cell array of variable names to group by
% dataTable - Input MATLAB table
% aggregationFunction - Function handle (e.g., @mean, @min, @max)
%
% Output:
% resultTable - Grouped and aggregated table
[G, groupKeys] = findgroups(dataTable(:, fixedVars));
varNames = dataTable.Properties.VariableNames;
nVars = numel(varNames);
aggData = cell(height(groupKeys), nVars);
groupCount = zeros(height(groupKeys), 1);
for i = 1:height(groupKeys)
idx = (G == i);
groupCount(i) = sum(idx);
for j = 1:nVars
colData = dataTable.(varNames{j});
if isnumeric(colData)
if any(idx)
aggData{i, j} = aggregationFunction(colData(idx));
else
aggData{i, j} = NaN;
end
else
if iscell(colData)
nonEmptyIdx = find(idx & ~cellfun(@isempty, colData), 1);
if ~isempty(nonEmptyIdx)
aggData{i, j} = colData{nonEmptyIdx};
else
aggData{i, j} = [];
end
else
nonEmptyIdx = find(idx, 1);
if ~isempty(nonEmptyIdx)
aggData{i, j} = colData(nonEmptyIdx);
else
aggData{i, j} = [];
end
end
end
end
end
resultTable = cell2table(aggData, 'VariableNames', varNames);
resultTable.nRows = groupCount;
end

View File

@@ -0,0 +1,61 @@
function [cleanedTable, outliersTable] = removeGroupOutliers(dataTable, fixedVars, y_var)
% removeGroupOutliers removes outliers in y_var within each group defined by fixedVars.
%
% [cleanedTable, outliersTable] = removeGroupOutliers(dataTable, fixedVars, y_var)
%
% Inputs:
% dataTable - Input MATLAB table
% fixedVars - Cell array of variable names to group by
% y_var - Name of the variable to check for outliers (string or char)
%
% Outputs:
% cleanedTable - Table with outliers removed
% outliersTable - Table of removed outlier rows
[G, groupKeys] = findgroups(dataTable(:, fixedVars));
keepIdx = true(height(dataTable), 1);
outlierRecords = [];
for groupIdx = 1:height(groupKeys)
groupRows = (G == groupIdx);
y_values = dataTable.(y_var)(groupRows);
% Skip groups with fewer than 3 points
if sum(groupRows) < 3
continue;
end
% Detect outliers in log10 space (robust for BER, etc.)
y_log = log10(y_values);
outlierMask = isoutlier(y_log, 'quartiles', 1);
if any(outlierMask)
groupData = dataTable(groupRows, :);
outlierGroupTable = groupData(outlierMask, :);
% Optionally, add group key values for traceability
for k = 1:numel(fixedVars)
outlierGroupTable.(['Group_', fixedVars{k}]) = repmat(groupKeys{groupIdx, k}, height(outlierGroupTable), 1);
end
outlierRecords = [outlierRecords; outlierGroupTable]; %#ok<AGROW>
end
% Mark outliers for removal
groupRowIdx = find(groupRows);
keepIdx(groupRowIdx(outlierMask)) = false;
end
cleanedTable = dataTable(keepIdx, :);
if isempty(outlierRecords)
outliersTable = table();
else
outliersTable = outlierRecords;
end
nRemoved = sum(~keepIdx);
nTotalOriginal = height(dataTable);
fprintf('Removed %d outliers from the data table (%.2f%% of total %d entries).\n', ...
nRemoved, 100*nRemoved/nTotalOriginal, nTotalOriginal);
end

146
Classes/GifWriter.m Normal file
View File

@@ -0,0 +1,146 @@
classdef GifWriter < handle
%GIFWRITER Simple class to create GIFs from figures (parallel-safe)
%
% Example:
% g = GifWriter('Name','mySim','Parallel',true);
% parfor i = 1:10
% plot(rand(10,1));
% g.addFrame(1,i);
% end
% g.compile(1);
properties
Name (1,:) char = 'default' % GIF base name
DelayTime (1,1) double = 0.1 % Frame delay in seconds
Parallel (1,1) logical = false % Enable parallel-safe mode
BaseDir (1,:) char % Base directory for temp frames
OutputDir (1,:) char % Final GIF output directory
end
methods
%% Constructor
function obj = GifWriter(varargin)
% Parse name/value pairs
p = inputParser;
addParameter(p, 'Name', 'default', @ischar);
addParameter(p, 'DelayTime', 0.1, @isnumeric);
addParameter(p, 'Parallel', false, @islogical);
addParameter(p, 'OutputDir', fullfile(pwd, 'gif_output'), @ischar);
parse(p, varargin{:});
obj.Name = p.Results.Name;
obj.DelayTime = p.Results.DelayTime;
obj.Parallel = p.Results.Parallel;
obj.OutputDir = p.Results.OutputDir;
obj.BaseDir = fullfile(obj.OutputDir, 'tmp', obj.Name);
if ~exist(obj.BaseDir, 'dir'), mkdir(obj.BaseDir); end
if ~exist(obj.OutputDir, 'dir'), mkdir(obj.OutputDir); end
end
%%
function addFrame(obj, figInput, pos)
%ADDFRAME Add a figure frame to the GIF (supports parallel mode)
%
% Usage:
% obj.addFrame(figHandle)
% obj.addFrame(figNum)
% obj.addFrame(figHandle, pos) % parallel mode
% obj.addFrame(figNum, pos)
%
% In parallel mode, 'pos' must be a unique integer (loop index).
if nargin < 3, pos = []; end
% --- Resolve figure handle ---
if isnumeric(figInput)
% User passed a figure number
if ~ishandle(figInput)
warning('GifWriter:addFrame', 'Figure %d not found.', figInput);
return;
end
figHandle = figure(figInput);
elseif isa(figInput, 'matlab.ui.Figure')
figHandle = figInput;
else
error('GifWriter:addFrame:InvalidInput', ...
'Input must be a figure handle or figure number.');
end
% --- Parallel-safe frame writing ---
if obj.Parallel
if isempty(pos)
error('GifWriter:ParallelMode', ...
'In parallel mode, provide a unique ''pos'' identifier.');
end
% Directory for this figure number
frameDir = fullfile(obj.BaseDir, sprintf('fig_%d', figHandle.Number));
if ~exist(frameDir, 'dir')
mkdir(frameDir);
end
% File path for this frame
frameFile = fullfile(frameDir, sprintf('frame_%05d.png', pos));
% Export to PNG (headless-safe)
exportgraphics(figHandle, frameFile, 'Resolution', 150);
else
% --- Serial mode: append directly to GIF ---
gifFile = fullfile(obj.OutputDir, ...
sprintf('%s_fig_%d.gif', obj.Name, figHandle.Number));
% Export frame temporarily
tmpFile = [tempname, '.png'];
exportgraphics(figHandle, tmpFile, 'Resolution', 150);
img = imread(tmpFile);
delete(tmpFile);
% Append to GIF
[A, map] = rgb2ind(img, 256);
if ~isfile(gifFile)
imwrite(A, map, gifFile, 'gif', ...
'LoopCount', Inf, 'DelayTime', obj.DelayTime);
else
imwrite(A, map, gifFile, 'gif', ...
'WriteMode', 'append', 'DelayTime', obj.DelayTime);
end
end
end
%% Compile all PNGs into a GIF (and clean up)
function compile(obj, fignum)
figDir = fullfile(obj.BaseDir, sprintf('fig_%d', fignum));
gifFile = fullfile(obj.OutputDir, sprintf('%s_fig_%d.gif', obj.Name, fignum));
frames = dir(fullfile(figDir, 'frame_*.png'));
if isempty(frames)
warning('GifWriter:NoFrames', 'No frames found for figure %d.', fignum);
return;
end
% Sort by frame name
[~, idx] = sort({frames.name});
frames = frames(idx);
% Combine into a GIF
for i = 1:numel(frames)
img = imread(fullfile(frames(i).folder, frames(i).name));
[A, map] = rgb2ind(img, 256);
if i == 1
imwrite(A, map, gifFile, 'gif', ...
'LoopCount', Inf, 'DelayTime', obj.DelayTime);
else
imwrite(A, map, gifFile, 'gif', ...
'WriteMode', 'append', 'DelayTime', obj.DelayTime);
end
end
% Clean up temporary frames
rmdir(figDir, 's');
end
end
end

View File

@@ -0,0 +1,7 @@
classdef Parameter < StorageParameter
methods
function obj = Parameter(varargin)
obj@StorageParameter(varargin{:});
end
end
end

View File

@@ -0,0 +1,40 @@
params = struct;
params.sir = [20:2:36];
params.laser_linewidth = [1e5 1e6 10e6];
params.pn_key = [1:3];
params.vp = [0.25,0.5,0.75,1];
params.vb = [1:0.1:1.8];
params.rop = -5:0;
wh = DataStorage(params);
wh.addStorage("ber");
wh.addStorage("rop_save");
wh.addStorage("cspr");
wh.addStorage("mod_out_pow");
cnt = 1;
for sir = params.sir
for lw = params.laser_linewidth
for pnk = params.pn_key
for vp = params.vp
for vb = params.vb
for rop = params.rop
current_ber = randn;
wh.addValueToStorage(current_ber,'ber',sir,lw,pnk,vp,vb,rop);
wh.addValueToStorage(-10,'rop_save',sir,lw,pnk,vp,vb,rop);
wh.addValueToStorage(10,'cspr',sir,lw,pnk,vp,vb,rop);
wh.addValueToStorage(-6,'mod_out_pow',sir,lw,pnk,vp,vb,rop);
end
end
end
end
end
end
wh.getStoValue('ber',20,1e5,2,0.25,1.1,-3)
wh.showInfo

View File

@@ -0,0 +1,251 @@
% Script, that shows the data management routine :-)
loadExistingWareHouse = 0;
if loadExistingWareHouse
[file, path] = uigetfile();
wh = load([path filesep file]);
wh = wh.wh;
wh.showInfo;
else
% 1) Define all your parameters, best practice directly constructs a
% structure
params = struct;
params.l = [2,10];
params.dispersion = [0];
params.sgm = [0];
% params.pol = ["YXYXYXYX","YXXYYXXY","YYYYYYYY"];
params.pol = ["alternated","paired","copolarized"];
params.p_in = [3];
params.p_out = [-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2];
params.pmd = [0.1];
params.gamma = [0.0023];
params.realization = [1:20];
params.numchannels = [16];
params.center_wavelength = floor([getSweepWavelengths(35, 50e9, 1310)] .* 1000) ./ 1000 ;
params.center_wavelength = [1285 1287 1290 1292 1295];
params.center_wavelength = 1310;
params.channelspacing = [400e9];
params.random_zdw = [0];
%wh = warehouse :-)
wh = DataStorage(params);
wh.showInfo;
wh.addStorage("ber");
wh.addStorage("totalBer");
end
%2) Simulate a bunch of data - TO BE IMPLEMENTED HERE - for now use scripts
%from Sebastian
%3) Once the simulation folder is around, specifiy path and analyze dirs
path = uigetdir('C:\Users\Silas\Documents\MATLAB\Raw_Cluster_Simulations');
allMat = getAllFilesInFolder(path,'.mat');
allErr = getAllFilesInFolder(path,'.err');
%allMat = dir([path filesep '*.mat']);
%allErr = dir([path filesep '*.err']);
if numel(allMat) == 0
warning('You defined an empty folder. Could not locate any .mat file.')
else
fprintf('%-20s', 'Err Files:'); fprintf('%-12s', num2str(numel(allErr))); fprintf('\n');
fprintf('%-20s', 'Mat Files:'); fprintf('%-12s', num2str(numel(allMat))); fprintf('\n');
fprintf('%-20s', 'Missing Mat Files:'); fprintf('%-12s', num2str(numel(allErr)-numel(allMat))); fprintf('\n');
end
%4) Now load that data
f = waitbar(0,'Please wait...');
cnt = 0;
for num = 1:numel(allMat)
fileName = allMat(num).name;
fileFolder = allMat(num).path;
fileExt = allMat(num).ext;
%
matFile = load([fileFolder filesep fileName fileExt]);
matFile = matFile.loop_data;
% ____________________________________
% FIND THE DATAPOINT CURRENTLY LOADED
zdw = 1310;
channelplan = "symmetric";
channelspacing = str2double(strrep(regexp(fileName,'(_chsp)+([\d]*)','match'),'_chsp','')).*1e9;
numchannels = str2double(strrep(regexp(fileName,'(ch)+(_)+([\d]*)','match'),'ch_',''));
center_wavelength = str2double(insertAfter(strrep(regexp(fileName,'(lambda)+([\d]*)','match'),'lambda',''),4,'.'));
center_wavelength = floor(center_wavelength * 1000) / 1000;
if center_wavelength == 2192
continue
end
center_wavelength = 1310;
random_zdw = str2double(strrep(regexp(fileName,'(rzwd)+([\d])','match'),'rzwd',''));
l = str2double(strrep(regexp(fileName,'([L])+(_)+([\d]*)','match'),'L_',''));
d = str2double(strrep(regexp(fileName,'([D])+(_)+([\d]*)','match'),'D_',''));
if d == 0
sgm = false;
else
sgm = true;
end
if numel(regexp(fileName,'(YYYY)','match')) > 1
pol = "copolarized";
elseif numel(regexp(fileName,'(YXXY)','match')) > 1
pol = "paired";
elseif numel(regexp(fileName,'(YXYX)','match')) > 1
pol = "alternated";
else
pol = "copolarized";
end
p_in = str2double(strrep(regexp(fileName,'(pow_)+([-,\d]{1})','match'),'pow_',''));
pmd = 0.1;
gamma = 0.0023;
realiz = str2double(strrep(regexp(fileName,'(r)+([-,\d]{1,3})','match'),'r',''));
% ____________________________________
% Get the information you want from current file
rop=[];
ber = [];
for pow = 2:12
module_number = '';
for p = 1:11 %11 because there are 11 ROP branches in model
% get ROP
if p == 1
p_out = matFile.dp_optatten_para.atten;
else
p_out = matFile.("dp_optatten__"+(p)+"_para").atten;
end
p_out = round(p_out-10*log10(numel(matFile.config.parameters.common.wavelengthPlan)));
for c = 1:numel(matFile.config.parameters.common.wavelengthPlan)
ber(c) = matFile.("prms_compare_wdm__"+(p+1)+"_out"){1,c}.ber;
end
totalBer = matFile.("prms_compare_wdm__"+(p+1)+"_out"){1,end}.totalBer;
if totalBer > 0.2 && channelspacing == 400e9 && pol == "alternated"
disp("stopping here");
pause;
end
% ____________________________________
% Add value to warehouse at the correct position
wh.addValueToStorage(ber,'ber',l,d,sgm,pol,p_in,p_out,pmd,gamma,realiz,numchannels, center_wavelength,channelspacing,random_zdw);
wh.getStoValue('ber',l,d,sgm,pol,p_in,p_out,pmd,gamma,realiz,numchannels, center_wavelength,channelspacing,random_zdw);
wh.addValueToStorage(totalBer,'totalBer',l,d,sgm,pol,p_in,p_out,pmd,gamma,realiz,numchannels,center_wavelength,channelspacing,random_zdw);
end
end
waitbar(num/numel(allMat),f,'Loading your data');
end
close(f)
% 4) Hey! the warehouse is here and (hopefully) filled with data :-)
% Create a save dialog
defaultDir = 'C:\Users\Silas\Documents\MATLAB\Raw_Cluster_Simulations\';
defaultExt = '*.mat';
[filename, pathname] = uiputfile(fullfile(defaultDir, defaultExt),'', 'wh.mat');
% Check if the user pressed Cancel
if isequal(filename, 0) || isequal(pathname, 0)
disp('Save operation canceled.');
else
% Save the variable to the selected file
save(fullfile(pathname, filename), 'wh');
disp(['Variable "wh" saved to: ', fullfile(pathname, filename)]);
end
function matFileStructArray = getAllFilesInFolder(folderPath,extension)
% Get a list of all files in the current folder
currentFolderFiles = dir(fullfile(folderPath, '*'));
% Exclude '.' and '..' directories
currentFolderFiles = currentFolderFiles(~ismember({currentFolderFiles.name}, {'.', '..'}));
% Initialize the structure array for .mat files
matFileStructArray = struct('path', {}, 'name', {}, 'ext', {});
% Loop over each file in the current folder
for i = 1:length(currentFolderFiles)
currentFile = currentFolderFiles(i);
% Check if the current item is a file and has a .mat extension
if ~currentFile.isdir && endsWith(currentFile.name, extension, 'IgnoreCase', true)
% If it's a .mat file, add it to the structure array
[matFileStructArray(end + 1).path,matFileStructArray(end+1).name, matFileStructArray(end+1).ext] = fileparts(fullfile(folderPath, currentFile.name));
elseif currentFile.isdir
% If it's a directory, recursively call the function
subfolderPath = fullfile(folderPath, currentFile.name);
subfolderMatFiles = getAllFilesInFolder(subfolderPath,extension);
% Add .mat files from the subfolder to the structure array
matFileStructArray = [matFileStructArray, subfolderMatFiles];
end
end
end

View File

@@ -0,0 +1,250 @@
% Script, that shows the data management routine :-)
loadExistingWareHouse = 0;
if loadExistingWareHouse
[file, path] = uigetfile();
wh = load([path filesep file]);
wh = wh.wh;
wh.showInfo;
else
% 1) Define all your parameters, best practice directly constructs a
% structure
params = struct;
params.l = [2, 10];
params.dispersion = [0, 3];
params.sgm = [0, 1];
% params.pol = ["YXYXYXYX","YXXYYXXY","YYYYYYYY"];
params.pol = ["alternated","paired","copolarized"];
params.p_in = [3];
params.p_out = [-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2];
params.pmd = [0.1];
params.gamma = [0.0023];
params.realization = [1:20];
params.numchannels = [1,2,4,8,16];
params.center_wavelength = floor([getSweepWavelengths(35, 50e9, 1310)] .* 1000) ./ 1000 ;
params.center_wavelength = [1285 1287 1290 1292 1295];
params.center_wavelength = 1310;
params.channelspacing = [400e9];
params.random_zdw = [0,1];
%wh = warehouse :-)
wh = DataStorage(params);
wh.showInfo;
wh.addStorage("ber");
wh.addStorage("totalBer");
end
%2) Simulate a bunch of data - TO BE IMPLEMENTED HERE - for now use scripts
%from Sebastian
%3) Once the simulation folder is around, specifiy path and analyze dirs
path = uigetdir('C:\Users\Silas\Documents\MATLAB\Raw_Cluster_Simulations');
allMat = getAllFilesInFolder(path,'.mat');
allErr = getAllFilesInFolder(path,'.err');
%allMat = dir([path filesep '*.mat']);
%allErr = dir([path filesep '*.err']);
if numel(allMat) == 0
warning('You defined an empty folder. Could not locate any .mat file.')
else
fprintf('%-20s', 'Err Files:'); fprintf('%-12s', num2str(numel(allErr))); fprintf('\n');
fprintf('%-20s', 'Mat Files:'); fprintf('%-12s', num2str(numel(allMat))); fprintf('\n');
fprintf('%-20s', 'Missing Mat Files:'); fprintf('%-12s', num2str(numel(allErr)-numel(allMat))); fprintf('\n');
end
%4) Now load that data
f = waitbar(0,'Please wait...');
cnt = 0;
for num = 1:numel(allMat)
fileName = allMat(num).name;
fileFolder = allMat(num).path;
fileExt = allMat(num).ext;
%
matFile = load([fileFolder filesep fileName fileExt]);
matFile = matFile.loop_data;
% ____________________________________
% FIND THE DATAPOINT CURRENTLY LOADED
zdw = 1310;
channelplan = "symmetric";
channelspacing = str2double(strrep(regexp(fileName,'(_chsp)+([\d]*)','match'),'_chsp','')).*1e9;
numchannels = str2double(strrep(regexp(fileName,'(ch)+(_)+([\d]*)','match'),'ch_',''));
center_wavelength = str2double(insertAfter(strrep(regexp(fileName,'(lambda)+([\d]*)','match'),'lambda',''),4,'.'));
center_wavelength = floor(center_wavelength * 1000) / 1000;
if center_wavelength == 2192
continue
end
center_wavelength = 1310;
random_zdw = str2double(strrep(regexp(fileName,'(rzwd)+([\d])','match'),'rzwd',''));
l = str2double(strrep(regexp(fileName,'([L])+(_)+([\d]*)','match'),'L_',''));
d = str2double(strrep(regexp(fileName,'([D])+(_)+([\d]*)','match'),'D_',''));
if d == 0
sgm = false;
else
sgm = true;
end
if numel(regexp(fileName,'(YYYY)','match')) > 1
pol = "copolarized";
elseif numel(regexp(fileName,'(YXXY)','match')) > 1
pol = "paired";
elseif numel(regexp(fileName,'(YXYX)','match')) > 1
pol = "alternated";
else
pol = "copolarized";
end
p_in = str2double(strrep(regexp(fileName,'(pow_)+([-,\d]{1})','match'),'pow_',''));
pmd = 0.1;
gamma = 0.0023;
realiz = str2double(strrep(regexp(fileName,'(r)+([-,\d]{1,3})','match'),'r',''));
% ____________________________________
% Get the information you want from current file
rop=[];
ber = [];
for pow = 2:12
module_number = '';
for p = 1:11 %11 because there are 11 ROP branches in model
% get ROP
if p == 1
p_out = matFile.dp_optatten_para.atten;
else
p_out = matFile.("dp_optatten__"+(p)+"_para").atten;
end
p_out = round(p_out-10*log10(numel(matFile.config.parameters.common.wavelengthPlan)));
for c = 1:numel(matFile.config.parameters.common.wavelengthPlan)
ber(c) = matFile.("prms_compare_wdm__"+(p+1)+"_out"){1,c}.ber;
end
totalBer = matFile.("prms_compare_wdm__"+(p+1)+"_out"){1,end}.totalBer;
if totalBer > 0.2 && channelspacing == 400e9 && pol == "alternated"
disp("stopping here");
pause;
end
% ____________________________________
% Add value to warehouse at the correct position
wh.addValueToStorage(ber,'ber',l,d,sgm,pol,p_in,p_out,pmd,gamma,realiz,numchannels, center_wavelength,channelspacing,random_zdw);
wh.getStoValue('ber',l,d,sgm,pol,p_in,p_out,pmd,gamma,realiz,numchannels, center_wavelength,channelspacing,random_zdw);
wh.addValueToStorage(totalBer,'totalBer',l,d,sgm,pol,p_in,p_out,pmd,gamma,realiz,numchannels,center_wavelength,channelspacing,random_zdw);
end
end
waitbar(num/numel(allMat),f,'Loading your data');
end
close(f)
% 4) Hey! the warehouse is here and (hopefully) filled with data :-)
% Create a save dialog
defaultDir = 'C:\Users\Silas\Documents\MATLAB\Raw_Cluster_Simulations\';
defaultExt = '*.mat';
[filename, pathname] = uiputfile(fullfile(defaultDir, defaultExt),'', 'wh.mat');
% Check if the user pressed Cancel
if isequal(filename, 0) || isequal(pathname, 0)
disp('Save operation canceled.');
else
% Save the variable to the selected file
save(fullfile(pathname, filename), 'wh');
disp(['Variable "wh" saved to: ', fullfile(pathname, filename)]);
end
function matFileStructArray = getAllFilesInFolder(folderPath,extension)
% Get a list of all files in the current folder
currentFolderFiles = dir(fullfile(folderPath, '*'));
% Exclude '.' and '..' directories
currentFolderFiles = currentFolderFiles(~ismember({currentFolderFiles.name}, {'.', '..'}));
% Initialize the structure array for .mat files
matFileStructArray = struct('path', {}, 'name', {}, 'ext', {});
% Loop over each file in the current folder
for i = 1:length(currentFolderFiles)
currentFile = currentFolderFiles(i);
% Check if the current item is a file and has a .mat extension
if ~currentFile.isdir && endsWith(currentFile.name, extension, 'IgnoreCase', true)
% If it's a .mat file, add it to the structure array
[matFileStructArray(end + 1).path,matFileStructArray(end+1).name, matFileStructArray(end+1).ext] = fileparts(fullfile(folderPath, currentFile.name));
elseif currentFile.isdir
% If it's a directory, recursively call the function
subfolderPath = fullfile(folderPath, currentFile.name);
subfolderMatFiles = getAllFilesInFolder(subfolderPath,extension);
% Add .mat files from the subfolder to the structure array
matFileStructArray = [matFileStructArray, subfolderMatFiles];
end
end
end

View File

@@ -0,0 +1,415 @@
%automate plots
[file, path] = uigetfile("C:\Users\Silas\Documents\MATLAB\Datensätze\Raw_Cluster_Simulations\session_februar_24\wh_mi_nacht.mat");
wh = load([path filesep file]);
wh = wh.wh;
% fields = fieldnames(wh.parameter);
% for k = 1:numel(fields)
% oldParam = wh.parameter.(fields{k});
% % copy over the properties to your new class
% wh.parameter.(fields{k}) = StorageParameter(...
% oldParam.Name, oldParam.values);
% end
%
plotJob = struct();
width = 350;
height = 200;
plotJob.Position = [100 100 width 100+height];
cols = cbrewer2("paired",12);
plotJob.color = cols(1,:);
plotJob.l = 10;
plotJob.ch = 16;
plotJob.d = 0;
plotJob.sgm = 0;
plotJob.pol = "copolarized";
plotJob.p_in = 3;
plotJob.gamma = 0.0023;
plotJob.pmd = 0.1;
plotJob.channelspacing = 400e9;
plotJob.randzdw = 1;
plotJob.plot_ber_curve = 0;
plotJob.plot_3dber_curve = 0;
plotJob.plot_violin = 1;
plotJob.plot_wavelength_sweep = 0;
plotJob.plot_wavelength_sweep_failure_rate = 0;
plotJob.dataStatArg = 'Lineplot with quartiles';
plotJob.plotTypeArg = 'Lines';
plotJob.displayname = 'a';
plotJob.title = 'title';
plotJob.figName = '16 Chann';
plotJob.xAxisLabel = 'ROP per Channel in dBm';
plotJob.yAxisLabel = 'BER';
%%
% createbercurves(wh,plotJob)
P = [3];
for i = 1:2
plotJob.p_in = P(i);
createviolinplots(wh,plotJob);
end
% createsweepplots(wh,plotJob);
%% 1
function createbercurves(wh,plotJob)
width = 1650;
height = 400;
s = 100;
e = 100;
cols = cbrewer2("paired",12);
numRows = 2;
numCols = 4;
plotJob.figName = '16 Chann_200G';
plotJob.channelspacing = 400e9;
plotJob.ch = 16;
Len = [2,2,2,2,10,10,10,10];
Pol = ["copolarized","alternated","paired","copolarized","copolarized","alternated","paired","copolarized"];
Title = ["Co Polarized","Alternating Pol. Interl.","Paired Pol. Interl.","Link Segmentation",];
D = [0,0,0,3,0,0,0,3];
Sgm = [0,0,0,1,0,0,0,1];
colidx = [4,8,6];
P_launch = [3,6];
fig = figure('Name',plotJob.figName);
fig.Position = plotJob.Position;
fig.Units = "centimeters";
fig.Position = [0 0 18 7];
t = tiledlayout(numRows,numCols,'TileSpacing','compact','Padding','compact');
for idx = 1:(numRows * numCols)
% Create subplot
% sp = subplot(numRows, numCols, idx);
nexttile;
plotJob.l = Len(idx);
plotJob.pol = Pol(idx);
plotJob.d = D(idx);
plotJob.sgm = Sgm(idx);
plotJob.randzdw = 1;
for i = 1:length(P_launch)
plotJob.p_in = P_launch(i);
plotJob.color = cols(colidx(i),:);
hold on
plotCurve(wh, plotJob);
end
%
if idx ~= 1 && idx ~= 5 % For example, hide y-axis for subplot 1
set(gca, 'YTickLabel',[]); % Hide y-axis ticks and labels
set(gca,'YGrid','on');
set(gca, 'YLabel', []);
end
if idx ~= 5 && idx ~= 6 && idx ~= 7 && idx ~= 8
set(gca, 'XLabel', []);
set(gca, 'XTickLabel', []);
end
grid on
g = gca;
pos = g.Position;
if idx <= 4
title(Title(idx),'FontSize',8);
% a = annotation('textbox', pos-[0.0020 -0.1434 0.0947 0.3121], 'String', "FEC: 3.8e-3","LineStyle","none","FontSize",8,'LineWidth',0.1,'Interpreter','latex',"FontUnits","points",'Vert','middle','FitBoxToText','on');
% a = annotation('textbox', pos, 'String', "2 km","LineStyle","none","FontSize",8,'LineWidth',0.1,'Interpreter','latex',"FontUnits","points",'Vert','bottom','FitBoxToText','on');
else
% a = annotation('textbox', pos, 'String', "FEC: 3.8e-3","LineStyle","none","FontSize",8,'LineWidth',0.1,'Interpreter','latex',"FontUnits","points",'Vert','middle','FitBoxToText','on');
% a = annotation('textbox', pos, 'String', "10 km","LineStyle","none","FontSize",8,'LineWidth',0.1,'Interpreter','latex',"FontUnits","points",'Vert','bottom','FitBoxToText','on');
end
end
% Create textbox
annotation(fig,'textbox',...
[0.0696078431372547 0.246851385390432 0.0656862745098043 0.0453400503778337],...
'String','10 km',...
'LineStyle','none',...
'Interpreter','latex',...
'FontSize',8,...
'FitBoxToText','off');
% Create textbox
annotation(fig,'textbox',...
[0.288235294117647 0.239294710327459 0.0656862745098043 0.0453400503778338],...
'String','10 km',...
'LineStyle','none',...
'Interpreter','latex',...
'FontSize',8,...
'FitBoxToText','off');
% Create textbox
annotation(fig,'textbox',...
[0.516666666666666 0.241813602015117 0.0656862745098042 0.0453400503778338],...
'String','10 km',...
'LineStyle','none',...
'Interpreter','latex',...
'FontSize',8,...
'FitBoxToText','off');
% Create textbox
annotation(fig,'textbox',...
[0.742156862745097 0.236775818639802 0.0656862745098042 0.0453400503778339],...
'String','10 km',...
'LineStyle','none',...
'Interpreter','latex',...
'FontSize',8,...
'FitBoxToText','off');
% Create textbox
annotation(fig,'textbox',...
[0.071996471804854 0.578899159967702 0.0656862745098039 0.0453400503778341],...
'String',{'2 km'},...
'LineStyle','none',...
'Interpreter','latex',...
'FontSize',8,...
'FitBoxToText','off');
% Create textbox
annotation(fig,'textbox',...
[0.29596893566113 0.576253721089996 0.0656862745098041 0.0453400503778341],...
'String',{'2 km'},...
'LineStyle','none',...
'Interpreter','latex',...
'FontSize',8,...
'FitBoxToText','off');
% Create textbox
annotation(fig,'textbox',...
[0.524883914268912 0.580785315705112 0.0656862745098041 0.0453400503778341],...
'String',{'2 km'},...
'LineStyle','none',...
'Interpreter','latex',...
'FontSize',8,...
'FitBoxToText','off');
% Create textbox
annotation(fig,'textbox',...
[0.753758338909501 0.581291504465311 0.0656862745098037 0.0453400503778341],...
'String',{'2 km'},...
'LineStyle','none',...
'Interpreter','latex',...
'FontSize',8,...
'FitBoxToText','off');
a=sgtitle(['N=',num2str(plotJob.ch),'; $\Delta f_{\mathrm{ch}}$= ',num2str(plotJob.channelspacing*1e-9),' GHz'],'FontSIze',10);
a.Interpreter = "latex";
lgd = legend('$P_{\mathrm{in}}=0$ dBm','$P_{\mathrm{in}}=3$ dBm','$P_{\mathrm{in}}=6$ dBm','Interpreter','latex');
lgd.NumColumns = 3;
lgd.Layout.Tile = 'south';
copygraphics(t,'BackgroundColor','none');
end
%% 2
function createviolinplots(wh,plotJob)
width = 350;
height = 200;
s = 100;
e = 100;
cols = cbrewer2("paired",12);
numRows = 1;
numCols = 4;
plotJob.ch = 16;
plotJob.randzdw = 1;
Pol = ["copolarized","copolarized","alternated","paired",];
Title = ["Co Pol.","Link Segmentation","Paired Pol. Interl.","Alternating Pol. Interl."];
D = [0,3,0,0];
Sgm = [0,1,0,0];
colidx = [4];
Len = plotJob.l;
fig = findall(groot, 'Type', 'figure', 'Name', plotJob.figName);
if isvalid(fig)
figure(fig)
% fig = get(fig);
AxesMain = fig.CurrentAxes;
hold on
% t = tiledlayout(1,4,'TileSpacing','compact','Padding','compact');
else
fig = figure('name',char(plotJob.figName));
AxesMain = gca;
hold on; grid on;
% t = tiledlayout(1,4,'TileSpacing','compact','Padding','compact');
end
for idx = 1:(numRows * numCols)
% Create subplot
subplot(numRows, numCols, idx);
plotJob.pol = Pol(idx);
plotJob.d = D(idx);
plotJob.sgm = Sgm(idx);
for i = 1
plotJob.color = cols(colidx(i),:);
plotJob.l = Len(i);
hold on
plotViolin(wh, plotJob);
end
if idx ~= 1 % For example, hide y-axis for subplot 1
%set(gca, 'YTickLabel',[]); % Hide y-axis ticks and labels
set(gca, 'YGrid','on');
set(gca, 'YLabel', []);
end
if idx <= 4
title(Title(idx));
end
end
% Create textbox
annotation(fig,'textbox',...
[0.300019607843137 0.816120906801009 0.108803921568628 0.0906801007556676],...
'String','$P_{\mathrm{in}}=3$ dBm',...
'LineStyle','none',...
'Interpreter','latex',...
'FontSize',8,...
'FitBoxToText','off');
% Create textbox
annotation(fig,'textbox',...
[0.530411764705882 0.81612090680101 0.108803921568628 0.0906801007556676],...
'String','$P_{\mathrm{in}}=3$ dBm',...
'LineStyle','none',...
'Interpreter','latex',...
'FontSize',8,...
'FitBoxToText','off');
% Create textbox
annotation(fig,'textbox',...
[0.755901960784313 0.816120906801011 0.108803921568628 0.0906801007556676],...
'String','$P_{\mathrm{in}}=3$ dBm',...
'LineStyle','none',...
'Interpreter','latex',...
'FontSize',8,...
'FitBoxToText','off');
% Create textbox
annotation(fig,'textbox',...
[0.0696274509803918 0.584382871536529 0.108803921568628 0.0906801007556676],...
'String','$P_{\mathrm{in}}=3$ dBm',...
'LineStyle','none',...
'Interpreter','latex',...
'FontSize',8,...
'FitBoxToText','off');
% lgd = legend('$P_{\mathrm{in}}=0$ dBm','$P_{\mathrm{in}}=3$ dBm','$P_{\mathrm{in}}=6$ dBm','Interpreter','latex');
% lgd.NumColumns = 3;
% lgd.Layout.Tile = 'south';
end
%% 3
function createsweepplots(wh,plotJob)
width = 650;
height = 200;
s = 100;
e = 100;
plotJob.Position = [0 0 width e+height];
cols = cbrewer2("paired",12);
numRows = 1;
numCols = 4;
plotJob.channelspacing = 200e9;
plotJob.ch = 16;
plotJob.randzdw = 1;
plotJob.l = 10;
plotJob.p_in = 3;
Pol = ["copolarized","alternated","paired","copolarized"];
Title = ["Co Polarized","Alternating Pol. Interl.","Paired Pol. Interl.","Link Segmentation",];
D = [0,0,0,3];
Sgm = [0,0,0,1];
Channelspacing = [200e9, 200e9];
PlotTypeArg = ["--","-"];
colidx = [6,8,2,4];
Len = [2,10];
plotJob.figName = [num2str(plotJob.ch),num2str(plotJob.channelspacing*1e-9),num2str(plotJob.p_in),'...'];
plotJob.figName = "10km 400ghz";
fig = findall(groot, 'Type', 'figure', 'Name', plotJob.figName);
if isvalid(fig)
figure(fig)
fig = get(fig);
AxesMain = fig.CurrentAxes;
hold on
else
fig = figure('name',char(plotJob.figName));
AxesMain = gca;
hold on
end
fig.Position = plotJob.Position;
fig.Units = "centimeters";
fig.Position = [0 0 18 7];
for j = 1
plotJob.channelspacing = Channelspacing(j);
plotJob.plotTypeArg = PlotTypeArg(j);
for idx = 1:4
plotJob.color = cols(colidx(idx),:);
plotJob.pol = Pol(idx);
plotJob.d = D(idx);
plotJob.sgm = Sgm(idx);
plotJob.displayname = [char(plotJob.pol)];
hold on
plotBerVsZdwFailureRate(wh, plotJob);
end
end
legend('Location', 'southoutside', 'Orientation', 'horizontal');
%plot channel positions
hold on
chpos = calcWavelengthPlan(plotJob.ch, plotJob.channelspacing, 1310);
xline(chpos,'LineWidth',2,'Alpha',0.4,'HandleVisibility','off');
chpos = calcWavelengthPlan(plotJob.ch, plotJob.channelspacing, chpos(4));
xline(chpos,'LineWidth',2,'LineStyle','--','Alpha',0.1,'HandleVisibility','off');
title(['N=',num2str(plotJob.ch),' $\Delta f_{\mathrm{ch}}$= ',num2str(plotJob.channelspacing*1e-9),' GHz'],'FontSize',10,'Interpreter','latex');
end

View File

@@ -0,0 +1,137 @@
% Select dataset
[file, path] = uigetfile("C:\Users\Silas\Documents\MATLAB\Datensätze\Raw_Cluster_Simulations\session_februar_24\wh_mi_nacht.mat");
wh = load(fullfile(path, file));
wh = wh.wh;
%% --- Plot Settings ---
cols = cbrewer2("Paired", 12);
plotJob = struct();
plotJob.Position = [100 100 600 400];
plotJob.channelspacing = 400e9;
plotJob.ch = 16;
plotJob.d = 0;
plotJob.sgm = 0;
plotJob.gamma = 0.0023;
plotJob.pmd = 0.1;
plotJob.randzdw = 1;
plotJob.plot_ber_curve = 1;
plotJob.xAxisLabel = 'ROP per $\lambda$ [dBm]';
plotJob.yAxisLabel = 'BER';
plotJob.figName = 'avg BER_vs_Plaunch_combined';
plotJob.dataStatArg = 'Lineplot with quartiles';%'All Channels; mean(PMD Realizations)';Lineplot with quartiles
plotJob.plotTypeArg = 'Lines';
plotJob.displayname = 'bla';
% --- Parameter combinations ---
Len = [2, 10];
Pol = ["copolarized", "copolarized", "alternated", "paired"];
Title = ["CoPol","LS", "API", "PPI"];
D = [0, 3, 0, 0];
Sgm = [0, 1, 0, 0];
% Pol = ["copolarized", "copolarized"];
% Title = ["CoPol","LS"];
% D = [0, 3];
% Sgm = [0, 1];
colidx = [6,4,2,2]; % color indices for different schemes
P_launch = [0,3,6]; % input power sweep
%% --- Create Figure ---
fig = findall(groot, 'Type', 'figure', 'Name', plotJob.figName);
if isvalid(fig)
figure(fig)
% fig = get(fig);
AxesMain = fig.CurrentAxes;
hold on
% t = tiledlayout(1,4,'TileSpacing','compact','Padding','compact');
else
fig = figure('name',char(plotJob.figName));
AxesMain = gca;
hold on; grid on;
% t = tiledlayout(1,4,'TileSpacing','compact','Padding','compact');
end
dsa = ["AVG"];
for d = 1
plotJob.dataStatArg = dsa(d);
cnt = 1;
for l = 1:numel(Len)
subplot(1,2,cnt);
cnt = cnt+1;
for s = 1:length(P_launch)
for p = 1:numel(Title)
plotJob.l = Len(l);
plotJob.pol = Pol(p);
plotJob.d = D(p);
plotJob.sgm = Sgm(p);
% color + style per length
baseColor = cols(colidx(p), :);
if s == 1
plotJob.linestyle = '-';
elseif s == 2
plotJob.linestyle = '--';
else
plotJob.linestyle = ':';
end
if p == 1
% plotJob.linestyle = '-';
plotJob.markerstyle = 'o';
plotJob.markersize = 2;
elseif p == 2
% plotJob.linestyle = ':';
plotJob.markerstyle = 'square';
plotJob.markersize = 2;
elseif p == 3
% plotJob.linestyle = '-';
plotJob.markerstyle = 'x';
plotJob.markersize = 6;
else
% plotJob.linestyle = '-';
plotJob.markerstyle = 'diamond';
plotJob.markersize = 2;
end
% if d == 1
% plotJob.linestyle = '-';
% else
% plotJob.linestyle = ':';
% plotJob.markerstyle = 'none';
% end
plotJob.p_in = P_launch(s);
plotJob.displayname = sprintf('%s',Title(p));
plotJob.color = baseColor;% * (1 - 0.15*(p-1)); % slight shade for powers
plotCurve(wh, plotJob);
% h = findobj(gca,'Type','Line','-not','Tag','FEC');
% set(h(p),'DisplayName',sprintf('%s (%.0f km, %.0f dBm)',Title(p),Len(l),P_launch(s)));
% title(sprintf('%d km; %d Channels, \Delta f = %.0f GHz', ...
% plotJob.l, plotJob.ch, plotJob.channelspacing*1e-9));
end
end
end
end
set(gca, 'YScale', 'log');
xlabel(plotJob.xAxisLabel);
ylabel(plotJob.yAxisLabel);
% legend('Interpreter','latex','NumColumns',2,'Location','southoutside');
grid on; box on;
copygraphics(fig, 'BackgroundColor','none');

View File

@@ -0,0 +1,83 @@
%automate plots
[file, path] = uigetfile("C:\Users\Silas\Documents\MATLAB\Datensätze\Raw_Cluster_Simulations\");
wh = load([path filesep file]);
wh = wh.wh;
plotJob = struct();
width = 350;
height = 200;
plotJob.Position = [100 100 width 100+height];
cols = cbrewer2("paired",12);
plotJob.color = cols(1,:);
plotJob.l = 1;
plotJob.ch = 1;
plotJob.sgm = 1;
plotJob.pol = "copolarized";
plotJob.p_in = 3;
plotJob.gamma = 0.0023;
plotJob.pmd = 0.1;
plotJob.channelspacing = 400e9;
plotJob.randzdw = 0;
plotJob.plot_ber_curve = 1;
plotJob.plot_3dber_curve = 0;
plotJob.plot_violin = 0;
plotJob.plot_wavelength_sweep = 0;
plotJob.plot_wavelength_sweep_failure_rate = 0;
plotJob.dataStatArg = 'Lineplot with quartiles';
plotJob.plotTypeArg = 'Lines';
plotJob.displayname = 'a';
plotJob.title = 'title';
plotJob.figName = '1 Chann__';
plotJob.xAxisLabel = 'ROP per Channel in dBm';
plotJob.yAxisLabel = 'BER';
plotJob.d = 0;
xAxis = wh.parameter.p_out.values;
D = wh.parameter.dispersion.values;
figure()
ber_ = [];
for d_ = 0:39
if d_ == 0
plotJob.sgm = 0;
ber_(d_+1,:) = wh.getStoValue('ber',plotJob.l,d_,plotJob.sgm,string(plotJob.pol),plotJob.p_in,xAxis,plotJob.pmd,plotJob.gamma,1,plotJob.ch,1310,plotJob.channelspacing,plotJob.randzdw)';
else
plotJob.sgm = 1;
ber_(d_+1,:) = wh.getStoValue('ber',plotJob.l,d_,plotJob.sgm,string(plotJob.pol),plotJob.p_in,xAxis,plotJob.pmd,plotJob.gamma,1,plotJob.ch,1310,plotJob.channelspacing,plotJob.randzdw)';
end
hold on
plot(xAxis,ber_(d_+1,:))
set(gca,'yscale','log');
end
yline(3.8e-3);
hdfec = 3.8e-3.*ones(size(xAxis));
for i = 1:size(ber_,1)
ber_series = ber_(i,:);
a = InterX([hdfec(:)';xAxis],[ber_series;xAxis]);
cross(i) = a(2);
end
col = cbrewer2('Paired',8);
figure()
plot(D,cross,'Marker','o','MarkerSize',5,'MarkerEdgeColor',[1,1,1],'MarkerFaceColor',col(2,:),'Color',col(1,:),'LineWidth',1);
grid minor
xlabel('Accumulated Dispersion')
ylabel('Required ROP to reach FEC limit in dB')
line([D(16),D(16)],[-10,cross(16)],'linestyle','--')
line([0,D(16)],[cross(16),cross(16)],'linestyle','--')
line([D(29),D(29)],[-10,cross(29)],'linestyle','--')
line([0,D(29)],[cross(29),cross(29)],'linestyle','--')

View File

@@ -0,0 +1,52 @@
wh = load("C:\Users\Silas\Documents\MATLAB\Datensätze\Raw_Cluster_Simulations\session_dispersion_validation\wh_with_variation.mat");
wh = wh.wh;
lambda = 1295;
figure(3)
plot(xAxis,getber(wh,lambda),'DisplayName',['w:', num2str(lambda), 'variation']);
yline(3.8e-3,'HandleVisibility','off');
legend
set(gca,'yscale','log');
grid(gca,'on');
grid(gca,'minor');
grid minor
fontsize(gca,8,"points")
fig.Units = "centimeters";
fig.Position = [2 2 8.5 7];
set(gca,'TickLabelInterpreter','latex')
ylim([1e-5,0.5]);
xlim([min(xAxis),-3]);
wh = load("C:\Users\Silas\Documents\MATLAB\Datensätze\Raw_Cluster_Simulations\session_dispersion_validation\wh_no_variation.mat");
wh = wh.wh;
figure(3)
hold on
plot(xAxis,getber(wh,lambda),'DisplayName',['w:', num2str(lambda), 'no variation']);
yline(3.8e-3,'HandleVisibility','off');
legend
set(gca,'yscale','log');
grid(gca,'on');
grid(gca,'minor');
grid minor
fontsize(gca,8,"points")
fig.Units = "centimeters";
fig.Position = [2 2 8.5 7];
set(gca,'TickLabelInterpreter','latex')
ylim([1e-5,0.5]);
xlim([min(xAxis),-3]);
function ber = getber(wh,lambda)
realization = wh.parameter.realization.values(1:end);
xAxis = wh.parameter.p_out.values;
ber = [];
for xl = 1:numel(xAxis)
p_out = xAxis(xl);
temp = wh.getStoValue('ber',10,0,0,"copolarized",3,p_out,0.1,0.0023,realization,1,lambda,400e9,1);
ber(xl) = mean(temp,'all');
end
end

View File

@@ -0,0 +1,61 @@
function generatePlots(wh,plotJob)
% 0) Test for valid query:
p_out = wh.parameter.p_out.values(1);
realization = 9;
if 1 %~isempty(wh.getStoValue('ber',plotJob.l,plotJob.d,plotJob.sgm,string(plotJob.pol),plotJob.p_in,p_out,plotJob.pmd,plotJob.gamma,realization,plotJob.ch,1310))
% test violin
baseName = plotJob.figName;
width = 350;
height = 200;
s = 100;
e = 100;
if plotJob.plot_ber_curve
plotJob.Position = [100 100 width e+height];
plotJob.figName = [baseName, ' zdwvsber'];
plotCurve(wh, plotJob);
end
if plotJob.plot_3dber_curve
plotJob.Position = [100 100 width e+height];
plotJob.figName = [baseName, ' zdwvsber'];
plot3dCurve(wh, plotJob);
end
if plotJob.plot_wavelength_sweep
plotJob.Position = [100 100 width e+height];
plotJob.figName = [baseName, ' zdwvsber'];
plotBerVsZDW(wh, plotJob);
end
if plotJob.plot_wavelength_sweep_failure_rate
plotJob.Position = [100 100 width e+height];
plotJob.figName = [baseName, ' zdwvsber'];
plotBerVsZdwFailureRate(wh, plotJob);
end
if plotJob.plot_violin
plotJob.Position = [s+width 100 width e+height];
plotJob.figName = [baseName, ' violin'];
plotViolin(wh, plotJob);
end
if 0
%2) plotHistogram
plotJob.Position = [s+2*width 100 width e+height];
plotJob.figName = [baseName, ' FEC crossing'];
plotHistogram(wh,plotJob)
end
else
warndlg('The requested Datapoint is not available... This can occur for some edgecase constellations... ')
end
end

View File

@@ -0,0 +1,248 @@
function plotCurve(wh,plotJob)
%PLOTCURVE Summary of this function goes here
% Detailed explanation goes here
fig = findall(groot, 'Type', 'figure', 'Name', plotJob.figName);
if isvalid(fig)
figure(fig)
fig = get(fig);
AxesMain = fig.CurrentAxes;
hold on
else
fig = figure('name',char(plotJob.figName));
AxesMain = gca;
hold on
end
col = plotJob.color;
% we want to fetch all realizations
if plotJob.pmd == 0
realization = 499;
% realization = 0:7;
else
realization = wh.parameter.realization.values(1:end);
end
realization = wh.parameter.realization.values(1:end);
% get all xAxis values
xAxis = wh.parameter.p_out.values;
% Fetch Data from Warehouse
for xl = 1:numel(xAxis)
p_out = xAxis(xl);
if string(plotJob.dataStatArg) == "Worst"
temp = wh.getStoValue('ber',plotJob.l,plotJob.d,plotJob.sgm,string(plotJob.pol),plotJob.p_in,p_out,plotJob.pmd,plotJob.gamma,realization,plotJob.ch,1310,plotJob.channelspacing,plotJob.randzdw);
temp = removeZeros(temp);
ber(xl) = max(temp,[],'all');
linew = 1.0;
markersz = 3;
linestyle = '-';
elseif string(plotJob.dataStatArg) == "AVG"
temp = wh.getStoValue('ber',plotJob.l,plotJob.d,plotJob.sgm,string(plotJob.pol),plotJob.p_in,p_out,plotJob.pmd,plotJob.gamma,realization,plotJob.ch,1310,plotJob.channelspacing,plotJob.randzdw);
temp = removeZeros(temp);
ber(xl) = mean(temp,'all');
linew = 1.0;
markersz = 3;
linestyle = '-';
elseif string(plotJob.dataStatArg) == "Best"
temp = wh.getStoValue('ber',plotJob.l,plotJob.d,plotJob.sgm,string(plotJob.pol),plotJob.p_in,p_out,plotJob.pmd,plotJob.gamma,realization,plotJob.ch,1310,plotJob.channelspacing,plotJob.randzdw);
temp = removeZeros(temp);
ber(xl) = min(temp,[],'all');
linew = 1.0;
markersz = 3;
linestyle = '-';
elseif string(plotJob.dataStatArg) == "All Channels; mean(PMD Realizations)"
temp = wh.getStoValue('ber',plotJob.l,plotJob.d,plotJob.sgm,string(plotJob.pol),plotJob.p_in,p_out,plotJob.pmd,plotJob.gamma,realization,plotJob.ch,1310,plotJob.channelspacing,plotJob.randzdw);
temp = removeZeros(temp);
ber(:,xl) = mean(temp,1,"omitnan").';
linew = 1;
markersz = 3;
linestyle = '--';
elseif string(plotJob.dataStatArg) == "Lineplot with quartiles"
temp = wh.getStoValue('ber',plotJob.l,plotJob.d,plotJob.sgm,string(plotJob.pol),plotJob.p_in,p_out,plotJob.pmd,plotJob.gamma,realization,plotJob.ch,1310,plotJob.channelspacing,plotJob.randzdw);
temp = removeZeros(temp);
ber(xl) = mean(temp,"all","omitnan").';
upperq(xl) = quantile(temp,0.9,"all");
lowerq(xl) = quantile(temp,0.1,"all");
if lowerq(xl) == 0
lowerq(xl) = lowerq(xl-1);
end
% upperq(xl) = 0.5*std(tmp,1,'all','omitnan');
% lowerq(xl) = 0.5*std(tmp,1,'all','omitnan');
% upperq(xl) = max(dataNoNans);
% lowerq(xl) = min(dataNoNans);
% upperq(xl) = mean(tmp,"all","omitnan") + 1.96 * (std(tmp,1,'all','omitnan')/sqrt(numel(tmp)));
% lowerq(xl) = mean(tmp,"all","omitnan") - 1.96 * (std(tmp,1,'all','omitnan')/sqrt(numel(tmp)));
linew = 1;
markersz = 1;
linestyle = '-';
elseif string(plotJob.dataStatArg) == "All Channels ;All PMD Realizations"
tmp = reshape(wh.getStoValue('ber',plotJob.l,plotJob.d,plotJob.sgm,string(plotJob.pol),plotJob.p_in,p_out,plotJob.pmd,plotJob.gamma,realization,plotJob.ch,1310,plotJob.channelspacing,plotJob.randzdw).',[],1);
ber(1:size(tmp,1),xl) = tmp;
linew = 0.3;
markersz = 2;
linestyle = ':';
end
end
xAxis = xAxis;
% Plot Data
if string(plotJob.plotTypeArg) == "Scatter"
for rlz = 1:size(ber,1)
if rlz < size(ber,1)
scatter(xAxis,ber(rlz,:),markersz,'MarkerEdgeColor',col,'MarkerFaceColor',col,'Parent', AxesMain(1),'HandleVisibility','off');
else
scatter(xAxis,ber(rlz,:),markersz,'MarkerEdgeColor',col,'MarkerFaceColor',col,'Parent', AxesMain(1),'DisplayName',[plotJob.dataStatArg,' Ch.: ', plotJob.displayname]);
end
end
elseif string(plotJob.plotTypeArg) == "Lines"
% if ~anynan(ber)
% [xAxis,ber] = interpCurve(xAxis, ber);
% end
for rlz = 1:size(ber,1)
%
if (string(plotJob.dataStatArg) == "All Channels ;All PMD Realizations")||(string(plotJob.dataStatArg) == "All Channels; mean(PMD Realizations)")
ch = mod(rlz,plotJob.ch);
if ch == 0; ch = plotJob.ch; end
else
ch = plotJob.dataStatArg;
end
if rlz <= size(ber,1)
s = plot3(xAxis,repmat(ch,1,numel(xAxis)),ber(rlz,:),linestyle,'Marker',"o",'MarkerSize',markersz,'MarkerFaceColor',plotJob.color,'LineWidth',linew,'Color',col,'Parent', AxesMain,'HandleVisibility','off');
s.DataTipTemplate.Interpreter = "latex";
s.DataTipTemplate.DataTipRows(1).Label = "Ch: ";
s.DataTipTemplate.DataTipRows(1).Value = repmat(ch,size(ber));
s.DataTipTemplate.DataTipRows(1);
s.DataTipTemplate.DataTipRows(2) = [];
else
if string(plotJob.dataStatArg) == "Lineplot with quartiles"
[hl,hp] = boundedline(xAxis,ber(rlz,:),([(ber(rlz,:)-lowerq(rlz,:));upperq(rlz,:)-ber(rlz,:)]'),'-*', 'alpha','Color',col,'transparency', 0.2);
hp.LineWidth = 1.2;
ho = outlinebounds(hl,hp);
set(ho, 'linestyle', ':', 'color', col);
else
s = plot(xAxis,ber(rlz,:),linestyle,'Marker',"o",'MarkerFaceColor',col,'MarkerSize',markersz,'LineWidth',linew,'Color',col,'Parent', AxesMain,'DisplayName',[plotJob.displayname]);
s.DataTipTemplate.Interpreter = "latex";
s.DataTipTemplate.DataTipRows(1).Label = "Ch: ";
s.DataTipTemplate.DataTipRows(1).Value = repmat(string(ch),size(ber));
s.DataTipTemplate.DataTipRows(1)
s.DataTipTemplate.DataTipRows(2) = [];
end
end
end
end
% Draw FEC Threshold Line
%get x data of first children:
%get all linear Values
if 0
linear = wh.getStoValue('ber',plotJob.l,plotJob.d,plotJob.sgm,string(plotJob.pol),plotJob.p_in,wh.parameter.p_out.values,0,0,499,"symmetric");
linear = mean(linear,2);
lincurve = findall(AxesMain, 'Type', 'line','DisplayName','Linear Baseline');
%
if isempty(lincurve)
xdata = AxesMain.Children(1).XData;
hdfec = 3.8e-3.*ones(size(xdata));
plot(xdata,linear,'-','Marker',"o",'MarkerSize',3,'LineWidth',4,'Color',[0.6400 0.6400 0.6400],'MarkerFaceColor',[0.6400 0.6400 0.6400],'Parent', AxesMain,'DisplayName','Linear Baseline');
%h = get(gca,'Children');
%set(gca,'Children',[h(2) h(1)])
end
end
feccurve = findall(AxesMain, 'Type', 'line','DisplayName','FEC $3.8*10^{-3}$');
%
if isempty(feccurve)
xdata = xAxis;
hdfec = 3.8e-3.*ones(size(xdata));
for ch = 1:plotJob.ch
plot3(xdata,repmat(ch,1,numel(xAxis)),hdfec,':','MarkerSize',4,'Color','black','MarkerFaceColor','black','LineWidth',0.5,'Parent', AxesMain,'DisplayName','FEC $3.8*10^{-3}$','HandleVisibility','off');
end
%h = get(gca,'Children');
%set(gca,'Children',[h(2) h(1)])
end
% Figure Settings
%title(AxesMain,plotJob.title,"Interpreter","none");
xlabel(AxesMain,plotJob.xAxisLabel,"Interpreter","none");
ylabel(AxesMain,plotJob.yAxisLabel,"Interpreter","none");
set(AxesMain,'zscale','log');
grid(AxesMain,'on');
grid(AxesMain,'minor');
grid minor
view(AxesMain,[42.0619302949062 23.4176470588235]);
%legend(AxesMain);
fontsize(AxesMain,8,"points")
fontname(AxesMain,"Arial")
fig.Position = plotJob.Position;
fig.Units = "centimeters";
fig.Position = [2 2 8.5 7];
set(AxesMain,'TickLabelInterpreter','none')
set(AxesMain.Legend,'Interpreter','none')
% set(gcf,'Units','centimeters')
% set(gcf,'Position',[2 2 9 4.5])
zlim([1e-4,0.3]);
xlim([min(xAxis),-3]);
annotation('textbox', [0.125, 0.32, 0.1, 0.1], 'String', "FEC 3.8e-3","LineStyle","none","FontSize",8,"FontUnits","points")
hold off
end
function vec = removeZeros(vec)
% Find rows that contain only zeros
rows_to_remove = all(vec == 0, 2);
% Remove rows with only zeros
vec(rows_to_remove, :) = [];
end

View File

@@ -0,0 +1,300 @@
function plotBerVsZDW(wh,plotJob)
fig = findall(groot, 'Type', 'figure', 'Name', plotJob.figName);
if isvalid(fig)
figure(fig)
fig = get(fig);
AxesMain = fig.CurrentAxes;
hold on
else
fig = figure('name',char(plotJob.figName));
AxesMain = gca;
hold on
end
col = plotJob.color;
% we want to fetch all realizations
realization = wh.parameter.realization.values(1:end);
% get all xAxis values
xAxis = wh.parameter.p_out.values;
% get all center wavelengths
wavelengths = wh.parameter.center_wavelength.values;
% totber = NaN(numel(realization),1,numel(xAxis),numel(wavelengths));
% ber = zeros(numel(realization),plotJob.ch,numel(xAxis),numel(wavelengths));
%get BER values for query
for w = 2:numel(wavelengths)
for xl = 1:numel(xAxis)
c_wavelen = wavelengths(w);
p_out = xAxis(xl);
% dim1 : realiz; dim2: channels, dim3: rop, dim4, c_wavelength
temp = removeZeros(wh.getStoValue('ber',plotJob.l,plotJob.d,plotJob.sgm,string(plotJob.pol),plotJob.p_in,p_out,plotJob.pmd,plotJob.gamma,realization,plotJob.ch,c_wavelen,plotJob.channelspacing,plotJob.randzdw));
ber(1:size(temp,1),:,xl,w) = temp;
end
end
hdfec = 3.8e-3.*ones(size(xAxis));
zdw_ = [];
zdw_chann = [];
zdw_tot = [];
cf_tot = [];
cf_ = [];
S = [];
Stot = [];
S_chann = [];
cf_chann = [];
cnt = 0;
%get fec thresholds
%linear = squeeze(linear);
for c_wavelen = 1:size(ber,4)
for realiz = 1:size(ber,1)
for chann = 1:size(ber,2)
%finde Schnittpunkt zwischen FEC und BER Kurve
temp_ber = squeeze(ber(realiz,chann,:,c_wavelen)).';
if ~all(temp_ber == 0)
%nur wenn nicht alles nullen sind
crossing_ch = InterX([hdfec;xAxis],[temp_ber;xAxis]);
else
continue
end
%Req. FEC Ergebnis einsortieren
if ~isempty(crossing_ch)
if crossing_ch(2) == 0
print("d")
end
S(realiz,chann,c_wavelen) = crossing_ch(2);
else
S(realiz,chann,c_wavelen) = -1;
cnt = cnt +1;
end
end
end
end
temp_max = -inf;
for i = 1:plotJob.ch
hold on
%S:: 1.dim: realiz; 2.dim: channel; 3.dim: center wavelength
%squeeze a channel:
temp_data = squeeze(S(:,i,:));
%remove realizations that have no entry (only zero)
temp_data = removeZeros(temp_data);
%replace zeros with NAN (e.g. for the wavelengths that have missing realizations)
temp_data(temp_data==0) = NaN;
%plot required ROP for channel and all realizations that cross the
%FEC limit
scatter(wavelengths,temp_data ,5,plotJob.color,'Marker','.');
% %plot mean per channel
% temp_mean = mean(temp_data,'omitnan');
% hold on
% plot(wavelengths,temp_mean,'Marker','*');
%get max overall value
temp_max = max(temp_max,max(temp_data));
end
%plot mean overall
mean_overall = squeeze(mean(S,2));
mean_overall(mean_overall==0) = NaN;
%mean_overall(mean_overall==-1) = NaN;
mean_overall=mean(mean_overall,1,'omitnan');
plot(wavelengths,mean_overall,'Color',plotJob.color);
%plot max overall
scatter(wavelengths,temp_max ,35,plotJob.color,'Marker','v');
%plot channel positions
hold on
chpos = calcWavelengthPlan(plotJob.ch, 400e9, 1310);
xline(chpos,'LineWidth',2,'Alpha',0.2);
chpos = calcWavelengthPlan(plotJob.ch, 400e9, chpos(4));
xline(chpos,'LineWidth',2,'Alpha',0.2);
fig.Position = plotJob.Position;
ylabel('Penalty in dB');
xlabel('Wavelength in nm');
xlim([min(wavelengths),max(wavelengths) ]);
grid minor;
set(gca, 'color', 'none');
legend = [];
fontsize(AxesMain,8,"points")
fig.Position = plotJob.Position;
fig.Units = "centimeters";
fig.Position = [2 2 8.5 7];
set(AxesMain,'TickLabelInterpreter','latex')
set(AxesMain.Legend,'Interpreter','latex')
%
%
%
%
%
% distinct_cf = unique(cf_chann);
%
% for i = 1:length(distinct_cf)
% indices = find(cf_chann==distinct_cf(i));
% cf(i) = distinct_cf(i);
% worst_fec_cross(i) = max(S_chann(indices));
% avg_fec_cross(i) = mean(S_chann(indices));
% end
%
% avg_fec_cross = smooth(avg_fec_cross,5);
%
% figure(224)
% hold on
% scatter(cf_,S,10.*abs(S-mean(S)).*ones(size(S)),'DisplayName',['AVG'],'MarkerEdgeColor',col,'MarkerFaceColor',col,'Marker','.');
% hold on
% scatter(cf(2:end),worst_fec_cross(2:end),15,'DisplayName',['Worst'],'MarkerEdgeColor',col,'MarkerFaceColor',col,'Marker','.','HandleVisibility','off');
% plot(cf(2:end),avg_fec_cross(2:end),'DisplayName',['AVG'],'LineWidth',1,'LineStyle','-','Color',col,'Marker','none','MarkerFaceColor',col,'MarkerSize',2);
% plot(cf(2:end),worst_fec_cross(2:end),'DisplayName',['AVG'],'LineWidth',0.5,'LineStyle','-','Color',col,'Marker','none','MarkerFaceColor',col,'MarkerSize',2);
% ghzgrid = hz2nm(nm2hz(1310)+[0:1:20].*400e9);
% set(gca,'xtick',sort(ghzgrid))
% xlim([min(cf(cf~=0)), 1310.1]);
%
%
% % With matlab internal errorbar function...
% figure(221)
% %plot(cf,avg_fec_cross,'DisplayName',['AVG'],'LineWidth',1,'Color',col,'Marker','none','MarkerFaceColor',col,'MarkerSize',2);
% hold on
% %plot(cf_tot,min(S_chann(1:length(cf_tot),:),[],2),'DisplayName',['AVG'],'LineWidth',1,'LineStyle',':','Color',col,'Marker','^','MarkerFaceColor',col,'MarkerSize',2);
% plot(cf,worst_fec_cross,'DisplayName',['AVG'],'LineWidth',2,'LineStyle','-','Color',col,'Marker','none','MarkerFaceColor',col,'MarkerSize',2);
% ghzgrid = hz2nm(nm2hz(1310)+[0:1:20].*400e9);
% set(gca,'xtick',sort(ghzgrid))
% xlim([1302, 1310.1]);
% xline(ghzgrid,'LineStyle',':','Color',[.7 .7 .7]);
%with
% Stot = movmean(Stot,5);
% figure(222)
% [hl,hp] = boundedline(cf_tot,Stot,[(Stot'-min(S_chann(1:length(cf_tot),:),[],2)),(max(S_chann(1:length(cf_tot),:),[],2)-Stot')], 'alpha','Color',col,'transparency', 0.05);
% ho = outlinebounds(hl,hp);
% set(ho, 'linestyle', ':', 'color', col, 'marker', '.','linewidth',0.5);
% hold on
%
% ghzgrid = hz2nm(nm2hz(1310)+[0:1:12].*400e9);
% xline(ghzgrid);
%plot the total ber
% %figure(22);
% hold on;
% b= movmean(Stot,3);
% plot(AxesMain,cf_tot,b,'LineWidth',2,'DisplayName',[plotJob.dataStatArg,' Ch.: ', plotJob.displayname],'Color',col,'Marker','o');
% hold on
%scatter(AxesMain,zdw_,S,'Marker','+','MarkerEdgeColor',col,'MarkerFaceAlpha',0.4,'MarkerEdgeAlpha',0.4,'LineWidth',0.5,'Parent', AxesMain(1),'DisplayName',[plotJob.dataStatArg,' Ch.: ', plotJob.displayname]);
%ylim(AxesMain,[-9.3 -7]);
% for i = 1:numel(chp)
% hold on
% xline(AxesMain,chp(i),'Color',colr(i,:),'DisplayName',['CH: ', num2str(i)],'LineWidth',1.5);
% hold off
% end
%
% a = movmean(sortrows([zdw_; S]'),10,'Endpoints','discard');
%
% sorted = sortrows([zdw_; S]');
% figure(2)
% scatter(sorted(:,1),sorted(:,2))
%
% ber_sorted = sort(S);
% mean(ber_sorted);
% std(ber_sorted);
% z1 = [];
% penalty = mean(ber_sorted):0.01:mean(ber_sorted)+2;
% for i = 1:length(penalty)
% l = penalty(i);
% if i == 1
% z1 = [z1 sum(ber_sorted(1,:)<l ) / length(ber_sorted) ];
% else
% z1 = [z1 sum(ber_sorted(1,:)<l & ber_sorted(1,:)>l-0.01) / length(ber_sorted) ];
% end
%
% end
%
% penalty_higherthan = 0.5;
% probability = sum(z1(find(penalty>mean(ber_sorted)+penalty_higherthan)));
% disp(['A penalty of more than 1dB has a probability of: ', num2str(probability)]);
% %
% stem(AxesMain,penalty,z1,"filled",'Marker','o','MarkerSize',2,'Color',col);
%
%
% [f1,x1]=ecdf(S(end,:));
% %figure(23);plot(AxesMain,x1,f1,'r','LineWidth',3, 'Color',col);
%
% %plot(AxesMain,a(:,1),a(:,2),'Color',col+1,'Parent', AxesMain(1));
%
% % histogram(AxesMain,S,1000,'EdgeColor','none','FaceAlpha',0.4);
%
%
%
% %
% %scatter(AxesMain,zdw_,S,'Marker','+','MarkerEdgeColor',col,'MarkerFaceAlpha',0.4,'MarkerEdgeAlpha',0.4,'LineWidth',0.5,'Parent', AxesMain(1),'DisplayName',[plotJob.dataStatArg,' Ch.: ', plotJob.displayname]);
% hold on
% %scatter(AxesMain,zdw_chann(:,1),mean(S_chann,2),'Marker','diamond','MarkerEdgeColor',col,'MarkerFaceAlpha',0.6,'LineWidth',7,'MarkerFaceColor',col,'Parent', AxesMain(1),'DisplayName',[plotJob.dataStatArg,' Ch.: ', plotJob.displayname]);
% hold off
% %
% % for rlz = 1:size(S,2)
% % zdwval = zdw_(rlz);
% % feccrossing = S(rlz);
% % scatter(AxesMain,zdwval,feccrossing,10,'MarkerEdgeColor',col,'MarkerFaceColor',col,'Parent', AxesMain(1),'DisplayName',[plotJob.dataStatArg,' Ch.: ', plotJob.displayname]);
% % end
%
% xline([1302.03471732576,1304.30061112288,1306.57440520904,1308.85614097425,1311.14586009814,1313.44360455251,1315.74941660391,1318.06333881618]);
end
function vec = removeZeros(vec)
% Find rows that contain only zeros
rows_to_remove = all(vec == 0, 2);
% Remove rows with only zeros
vec(rows_to_remove, :) = [];
end

View File

@@ -0,0 +1,157 @@
function plotBerVsZdwFailureRate(wh,plotJob)
fig = findall(groot, 'Type', 'figure', 'Name', plotJob.figName);
if isvalid(fig)
figure(fig)
fig = get(fig);
AxesMain = fig.CurrentAxes;
hold on
else
fig = figure('name',char(plotJob.figName));
AxesMain = gca;
hold on
end
col = plotJob.color;
% we want to fetch all realizations
realization = wh.parameter.realization.values(1:end);
% get all xAxis values
xAxis = wh.parameter.p_out.values;
% get all center wavelengths
wavelengths = wh.parameter.center_wavelength.values;
%wavelengths = wavelengths(2:end);
% totber = NaN(numel(realization),1,numel(xAxis),numel(wavelengths));
% ber = zeros(numel(realization),plotJob.ch,numel(xAxis),numel(wavelengths));
%get BER values for query
for w = 1:numel(wavelengths)
for xl = 1:numel(xAxis)
c_wavelen = wavelengths(w);
p_out = xAxis(xl);
% dim1 : realiz; dim2: channels, dim3: rop, dim4, c_wavelength
temp = removeZeros(wh.getStoValue('ber',plotJob.l,plotJob.d,plotJob.sgm,string(plotJob.pol),plotJob.p_in,p_out,plotJob.pmd,plotJob.gamma,realization,plotJob.ch,c_wavelen,plotJob.channelspacing,plotJob.randzdw));
ber(1:size(temp,1),:,xl,w) = temp;
end
end
hdfec = 3.8e-3.*ones(size(xAxis));
zdw_ = [];
zdw_chann = [];
zdw_tot = [];
cf_tot = [];
cf_ = [];
S = [];
Stot = [];
S_chann = [];
cf_chann = [];
cnt = 0;
%get fec thresholds
%linear = squeeze(linear);
for c_wavelen = 1:size(ber,4)
for realiz = 1:size(ber,1)
for chann = 1:size(ber,2)
%finde Schnittpunkt zwischen FEC und BER Kurve
temp_ber = squeeze(ber(realiz,chann,:,c_wavelen)).';
if ~all(temp_ber == 0)
%nur wenn nicht alles nullen sind
crossing_ch = InterX([hdfec;xAxis],[temp_ber;xAxis]);
else
continue
end
%Req. FEC Ergebnis einsortieren
if ~isempty(crossing_ch)
if crossing_ch(2) == 0
print("d")
end
S(realiz,chann,c_wavelen) = crossing_ch(2);
else
S(realiz,chann,c_wavelen) = -1;
cnt = cnt +1;
end
end
end
end
temp_max = -inf;
sum_FEC_not_crossed=[];
sum_FEC_crossed=[];
threshold = plotJob.p_in - 10;
for i = 1:plotJob.ch
hold on
%S:: 1.dim: realiz; 2.dim: channel; 3.dim: center wavelength
%squeeze a channel:
temp_data = squeeze(S(:,i,:));
%remove realizations that have no entry (only zero)
temp_data = removeZeros(temp_data);
%replace zeros with NAN (e.g. for the wavelengths that have missing realizations)
temp_data(temp_data==0) = NaN;
%for current channel
FEC_crossed = temp_data < threshold & ~isnan(temp_data);
FEC_not_crossed = temp_data >= threshold & ~isnan(temp_data);
%sum over channels for overall picture
sum_FEC_not_crossed(i,:) = sum(FEC_not_crossed);
sum_FEC_crossed(i,:) = sum(FEC_crossed);
failure_rate_channelwise(i,:) = sum_FEC_not_crossed(i,:)./ ( sum_FEC_crossed(i,:) + sum_FEC_not_crossed(i,:));
end
failure_rate_total = sum(sum_FEC_not_crossed,1) ./ ( sum(sum_FEC_crossed,1) + sum(sum_FEC_not_crossed,1) );
% plot failure rate (nbetween 0 and 1)
plot(wavelengths,failure_rate_total,'Color',plotJob.color,'LineWidth',1,'LineStyle',plotJob.plotTypeArg,'Marker','x','MarkerSize',5,'MarkerFaceColor',plotJob.color,'DisplayName',plotJob.displayname);
%plot max overall
%scatter(wavelengths,failure_rate_channelwise ,35,plotJob.color,'Marker','.');
ylabel('Failure Rate of Link');
xlabel('Wavelength in nm');
xlim([min(wavelengths),max(wavelengths) ]);
ylim([0,1]);
grid minor;
set(gca, 'color', 'none');
legend = [];
% fontsize(AxesMain,8,"points")
fig.Position = plotJob.Position;
fig.Units = "centimeters";
fig.Position = [0 0 12 5 7];
try
set(AxesMain,'TickLabelInterpreter','latex')
set(AxesMain.Legend,'Interpreter','latex')
end
end
function vec = removeZeros(vec)
% Find rows that contain only zeros
rows_to_remove = all(vec == 0, 2);
% Remove rows with only zeros
vec(rows_to_remove, :) = [];
end

View File

@@ -0,0 +1,51 @@
function plotChannelSpacingAna(wh,plotJob)
xAxis = wh.parameter.p_out.values;
realization = wh.parameter.realization.values(1:end);
channelsp = wh.parameter.channelspacing.values(1:end);
channelsp = [200 400].*1e9;
for ch = 1:2
channspacing = channelsp(ch);
for xl = 1:numel(xAxis)
p_out = xAxis(xl);
curber = wh.getStoValue('ber',plotJob.l,plotJob.d,plotJob.sgm,string(plotJob.pol),plotJob.p_in,p_out,plotJob.pmd,plotJob.gamma,realization,plotJob.numchannels,channspacing);
curzdw = wh.getStoValue('zdw',plotJob.l,plotJob.d,plotJob.sgm,string(plotJob.pol),plotJob.p_in,p_out,plotJob.pmd,plotJob.gamma,realization,plotJob.numchannels,channspacing);
ber(1:size(curber,1),1:size(curber,2),xl) = curber;
zdw(1:size(curber,1),1,xl) = curzdw;
end
ber = squeeze(mean(ber,1));
zdw = squeeze(mean(zdw,1));
hdfec = 3.8e-3.*ones(size(xAxis));
S = [];
wavelength={};
zdw_ = [];
zdw_chann = [];
zdw_tot = [];
S = [];
S_chann = [];
wl = round([1302.03471732576,1304.30061112288,1306.57440520904,1308.85614097425,1311.14586009814,1313.44360455251,1315.74941660391,1318.06333881618],2);
wl = 1:16;
wl = [1.2930 1.2953 1.2975 1.2998 1.3020 1.3043 1.3066 1.3089 1.3111 1.3134 1.3157 1.3181 1.3204 1.3227 1.3251 1.3274];
a = InterX([hdfec(:)';xAxis],[mean(ber,1);xAxis]);
if ~isempty(a)
s(ch) = a(2);
else
s(ch) = NaN;
end
end
figure(2224)
hold on
plot(channelsp,s,'LineWidth',1,'Color',plotJob.color,'Marker','o');

View File

@@ -0,0 +1,294 @@
function plotCurve(wh,plotJob)
%PLOTCURVE Summary of this function goes here
% Detailed explanation goes here
fig = findall(groot, 'Type', 'figure', 'Name', plotJob.figName);
if isvalid(fig)
figure(fig)
% fig = get(fig);
AxesMain = fig.CurrentAxes;
hold on
else
fig = figure('name',char(plotJob.figName));
AxesMain = gca;
hold on
end
col = plotJob.color;
% we want to fetch all realizations
if plotJob.pmd == 0
realization = 499;
% realization = 0:7;
else
realization = wh.parameter.realization.values(1:end);
end
realization = wh.parameter.realization.values(1:end);
% get all xAxis values
xAxis = wh.parameter.p_out.values;
markerstyle = 'o';
linestyle = '-';
% Fetch Data from Warehouse
for xl = 1:numel(xAxis)
p_out = xAxis(xl);
if string(plotJob.dataStatArg) == "Worst"
temp = wh.getStoValue('ber',plotJob.l,plotJob.d,plotJob.sgm,string(plotJob.pol),plotJob.p_in,p_out,plotJob.pmd,plotJob.gamma,realization,plotJob.ch,1310,plotJob.channelspacing,plotJob.randzdw);
temp = removeZeros(temp);
ber(xl) = quantile(temp,0.9,"all");
% ber(xl) = max(temp,[],'all');
linew = 1.0;
markersz = plotJob.markersize;
markerstyle = plotJob.markerstyle;
linestyle = plotJob.linestyle;
elseif string(plotJob.dataStatArg) == "AVG"
temp = wh.getStoValue('ber',plotJob.l,plotJob.d,plotJob.sgm,string(plotJob.pol),plotJob.p_in,p_out,plotJob.pmd,plotJob.gamma,realization,plotJob.ch,1310,plotJob.channelspacing,plotJob.randzdw);
temp = removeZeros(temp);
ber(xl) = mean(temp,'all');
linew = 1.0;
markersz = plotJob.markersize;
markerstyle = plotJob.markerstyle;
linestyle = plotJob.linestyle;
elseif string(plotJob.dataStatArg) == "Best"
temp = wh.getStoValue('ber',plotJob.l,plotJob.d,plotJob.sgm,string(plotJob.pol),plotJob.p_in,p_out,plotJob.pmd,plotJob.gamma,realization,plotJob.ch,1310,plotJob.channelspacing,plotJob.randzdw);
temp = removeZeros(temp);
ber(xl) = min(temp,[],'all');
linew = 1.0;
markersz = plotJob.markersize;
markerstyle = plotJob.markerstyle;
linestyle = plotJob.linestyle;
elseif string(plotJob.dataStatArg) == "All Channels; mean(PMD Realizations)"
temp = wh.getStoValue('ber',plotJob.l,plotJob.d,plotJob.sgm,string(plotJob.pol),plotJob.p_in,p_out,plotJob.pmd,plotJob.gamma,realization,plotJob.ch,1310,plotJob.channelspacing,plotJob.randzdw);
temp = removeZeros(temp);
ber(:,xl) = mean(temp,1,"omitnan").';
linew = 1;
markersz = 1;
markerstyle = plotJob.markerstyle;
linestyle = plotJob.linestyle;
elseif string(plotJob.dataStatArg) == "Lineplot with quartiles"
temp = wh.getStoValue('ber',plotJob.l,plotJob.d,plotJob.sgm,string(plotJob.pol),plotJob.p_in,p_out,plotJob.pmd,plotJob.gamma,realization,plotJob.ch,1310,plotJob.channelspacing,plotJob.randzdw);
temp = removeZeros(temp);
ber(xl) = mean(temp,"all","omitnan").';
upperq(xl) = quantile(temp,0.99,"all");
lowerq(xl) = quantile(temp,0.04,"all");
% upperq(xl) = 0.5*std(tmp,1,'all','omitnan');
% lowerq(xl) = 0.5*std(tmp,1,'all','omitnan');
upperq(xl) = max(temp(:));
lowerq(xl) = min(temp(:));
if lowerq(xl) == 0
lowerq(xl) = 1e-8;
end
% upperq(xl) = mean(tmp,"all","omitnan") + 1.96 * (std(tmp,1,'all','omitnan')/sqrt(numel(tmp)));
% lowerq(xl) = mean(tmp,"all","omitnan") - 1.96 * (std(tmp,1,'all','omitnan')/sqrt(numel(tmp)));
linew = 1;
markersz = 1;
linestyle = '-';
elseif string(plotJob.dataStatArg) == "All Channels ;All PMD Realizations"
raw_fetch = wh.getStoValue('ber',plotJob.l,plotJob.d,plotJob.sgm,string(plotJob.pol),plotJob.p_in,p_out,plotJob.pmd,plotJob.gamma,realization,plotJob.ch,1310,plotJob.channelspacing,plotJob.randzdw).';
tmp = reshape(raw_fetch,[],1);
ber(1:size(tmp,1),xl) = tmp;
ber_per_chann(:,:,xl) = raw_fetch;
linew = 0.3;
markersz = 2;
linestyle = ':';
end
end
%routine to remove total outliers (here those wehere the rop curve has a mean BER greater than 0.1)
% ber_per_chann_clean = NaN(size(ber_per_chann));
% for ch = 1:size(ber_per_chann,1)
% bla = squeeze(ber_per_chann(ch,:,:));
% ber_per_chann(ch,find(mean(bla,2)>0.25),:) = NaN;
% cleaned = rmoutliers(bla,"mean",'ThresholdFactor',2);
%
% ber_per_chann_clean(ch,1:size(cleaned,1),1:size(cleaned,2)) = cleaned;
%
% end
%
% ber = [];
% for rop = 1:size(ber_per_chann,3)
% temp = squeeze(ber_per_chann_clean(:,:,rop));
% ber(rop) = mean(temp,"all","omitnan").';
% upperq(rop) = quantile(temp,0.9,"all");
% lowerq(rop) = quantile(temp,0.1,"all");
% end
xAxis = xAxis;
% Plot Data
if string(plotJob.plotTypeArg) == "Scatter"
for rlz = 1:size(ber,1)
if rlz < size(ber,1)
scatter(xAxis,ber(rlz,:),markersz,'MarkerEdgeColor',col,'MarkerFaceColor',col,'Parent', AxesMain(1),'HandleVisibility','off');
else
scatter(xAxis,ber(rlz,:),markersz,'MarkerEdgeColor',col,'MarkerFaceColor',col,'Parent', AxesMain(1),'DisplayName',[plotJob.dataStatArg,' Ch.: ', plotJob.displayname]);
end
end
elseif string(plotJob.plotTypeArg) == "Lines"
% if ~anynan(ber)
% [xAxis,ber] = interpCurve(xAxis, ber);
% end
cols = cbrewer2('RdBu',size(ber,1));
for rlz = 1:size(ber,1)
%
if (string(plotJob.dataStatArg) == "All Channels ;All PMD Realizations")||(string(plotJob.dataStatArg) == "All Channels; mean(PMD Realizations)")
ch = mod(rlz,plotJob.ch);
if ch == 0; ch = plotJob.ch; end
else
ch = plotJob.dataStatArg;
end
if rlz < size(ber,1)
col = cols(rlz,:);
s = plot(xAxis,ber(rlz,:),linestyle,'Marker',"none",'MarkerSize',markersz,'LineWidth',linew,'Color',col,'Parent', AxesMain,'HandleVisibility','off');
s.DataTipTemplate.Interpreter = "latex";
s.DataTipTemplate.DataTipRows(1).Label = "Ch: ";
s.DataTipTemplate.DataTipRows(1).Value = repmat(ch,size(ber));
s.DataTipTemplate.DataTipRows(1);
s.DataTipTemplate.DataTipRows(2) = [];
else
if string(plotJob.dataStatArg) == "Lineplot with quartiles"
[hl,hp] = boundedline(xAxis,ber(rlz,:),([(ber(rlz,:)-lowerq(rlz,:));upperq(rlz,:)-ber(rlz,:)]'),'-o','alpha','Color',col,'transparency', 0.06,'linewidth',0.7);
hl.MarkerFaceColor = col;
hl.MarkerSize = 2;
set(hp,'HandleVisibility','off');
%hp.LineWidth = 1.2;
ho = outlinebounds(hl,hp);
set(ho, 'linestyle', ':', 'color', col,'Linewidth',0.6);
set(ho,'HandleVisibility','off');
% errorbar(xAxis,ber(rlz,:),ber(rlz,:)-lowerq(rlz,:),upperq(rlz,:)-ber(rlz,:),'-o','Color',col,'linewidth',0.7);
else
s = plot(xAxis,ber(rlz,:),linestyle,'Marker',markerstyle,'MarkerFaceColor',col,'MarkerSize',markersz,'LineWidth',linew,'Color',col,'Parent', AxesMain,'DisplayName',[plotJob.displayname]);
s.DataTipTemplate.Interpreter = "latex";
s.DataTipTemplate.DataTipRows(1).Label = "Ch: ";
s.DataTipTemplate.DataTipRows(1).Value = repmat(string(ch),size(ber));
s.DataTipTemplate.DataTipRows(1)
s.DataTipTemplate.DataTipRows(2) = [];
end
end
end
end
% Draw FEC Threshold Line
%get x data of first children:
%get all linear Values
if 0
linear = wh.getStoValue('ber',plotJob.l,plotJob.d,plotJob.sgm,string(plotJob.pol),plotJob.p_in,wh.parameter.p_out.values,0,0,499,"symmetric");
linear = mean(linear,2);
lincurve = findall(AxesMain, 'Type', 'line','DisplayName','Linear Baseline');
%
if isempty(lincurve)
xdata = AxesMain.Children(1).XData;
hdfec = 3.8e-3.*ones(size(xdata));
plot(xdata,linear,'-','Marker',"o",'MarkerSize',3,'LineWidth',4,'Color',[0.6400 0.6400 0.6400],'MarkerFaceColor',[0.6400 0.6400 0.6400],'Parent', AxesMain,'DisplayName','Linear Baseline');
%h = get(gca,'Children');
%set(gca,'Children',[h(2) h(1)])
end
end
feccurve = findall(AxesMain, 'Type', 'line','DisplayName','FEC $3.8*10^{-3}$');
%
if isempty(feccurve)
xdata = AxesMain.Children(1).XData;
hdfec = 3.8e-3.*ones(size(xdata));
plot(xdata,hdfec,'--','MarkerSize',4,'Color','black','MarkerFaceColor','black','LineWidth',1,'Parent', AxesMain,'DisplayName','FEC $3.8*10^{-3}$','HandleVisibility','off');
%h = get(gca,'Children');
%set(gca,'Children',[h(2) h(1)])
end
% Figure Settings
%title(AxesMain,plotJob.title,"Interpreter","none");
xlabel(AxesMain,plotJob.xAxisLabel,"Interpreter","latex");
ylabel(AxesMain,plotJob.yAxisLabel,"Interpreter","latex");
set(AxesMain,'yscale','log');
grid(AxesMain,'on');
grid(AxesMain,'minor');
grid minor
%legend(AxesMain);
fontsize(AxesMain,8,"points")
% fontname(AxesMain,"Arial")
% fig.Position = plotJob.Position;
% fig.Units = "centimeters";
% fig.Position = [2 2 8.5 7];
set(AxesMain,'TickLabelInterpreter','latex')
set(AxesMain.Legend,'Interpreter','latex')
% set(gcf,'Units','centimeters')
% set(gcf,'Position',[2 2 9 4.5])
ylim([1e-5,0.3]);
xlim([-10,-4]);
% annotation('textbox', [0.125, 0.32, 0.1, 0.1], 'String', "FEC 3.8e-3","LineStyle","none","FontSize",8,"FontUnits","points")
hold off
end
function vec = removeZeros(vec)
% Find rows that contain only zeros
rows_to_remove = all(vec == 0, 2);
% Remove rows with only zeros
vec(rows_to_remove, :) = [];
end

View File

@@ -0,0 +1,151 @@
function plotHistogram(wh,plotJob)
fig = findall(groot, 'Type', 'figure', 'Name', plotJob.figName);
if isvalid(fig)
figure(fig)
fig = get(fig);
AxesMain = fig.CurrentAxes;
hold on
else
fig = figure('name',char(plotJob.figName));
AxesMain = gca;
hold on
end
col = plotJob.color;
% we want to fetch all realizations
realization = wh.parameter.realization.values(1:end);
% get all xAxis values
xAxis = wh.parameter.p_out.values;
% Fetch Data from Warehouse
for xl = 1:numel(xAxis)
p_out = xAxis(xl);
if string(plotJob.dataStatArg) == "Worst"
ber(xl) = max(wh.getStoValue('ber',plotJob.l,plotJob.d,plotJob.sgm,string(plotJob.pol),plotJob.p_in,p_out,plotJob.pmd,plotJob.gamma,realization,string(plotJob.channelplan),string(plotJob.dsp)),[],'all');
linew = 2.0;
markersz = 3;
linestyle = '-';
elseif string(plotJob.dataStatArg) == "AVG"
ber(xl) = mean(wh.getStoValue('ber',plotJob.l,plotJob.d,plotJob.sgm,string(plotJob.pol),plotJob.p_in,p_out,plotJob.pmd,plotJob.gamma,realization,string(plotJob.channelplan),string(plotJob.dsp)),'all');
linew = 2.0;
markersz = 3;
linestyle = ':';
elseif string(plotJob.dataStatArg) == "Best"
ber(xl) = min(wh.getStoValue('ber',plotJob.l,plotJob.d,plotJob.sgm,string(plotJob.pol),plotJob.p_in,p_out,plotJob.pmd,plotJob.gamma,realization,string(plotJob.channelplan),string(plotJob.dsp)),[],'all');
linew = 2.0;
markersz = 3;
linestyle = ':';
elseif string(plotJob.dataStatArg) == "All Channels; mean(PMD Realizations)"
tmp = wh.getStoValue('ber',plotJob.l,plotJob.d,plotJob.sgm,string(plotJob.pol),plotJob.p_in,p_out,plotJob.pmd,plotJob.gamma,realization,string(plotJob.channelplan),string(plotJob.dsp));
if numel(tmp(tmp==0)) ~= 0
disp('Removed all zero values!');
tmp(tmp==0) = NaN;
end
ber(:,xl) = mean(tmp,1,"omitnan").';
linew = 0.7;
markersz = 2;
linestyle = '-';
elseif string(plotJob.dataStatArg) == "All Channels ;All PMD Realizations"
tmp = reshape(wh.getStoValue('ber',plotJob.l,plotJob.d,plotJob.sgm,string(plotJob.pol),plotJob.p_in,p_out,plotJob.pmd,plotJob.gamma,realization,string(plotJob.channelplan),string(plotJob.dsp)).',[],1);
ber(1:size(tmp,1),xl) = tmp;
linew = 0.3;
markersz = 2;
linestyle = ':';
end
end
disp('Removed all zero values!');
ber(ber==0) = NaN;
if ~anynan(ber)
[xAxis,ber] = interpCurve(xAxis, ber);
end
% plot FEC Crossing as histogram
hdfec = 3.8e-3.*ones(size(xAxis));
S = [];
for i = 1:size(ber,1)
a = InterX([hdfec;xAxis],[ber(i,:);xAxis]);
if ~isempty(a)
S(:,i) = a;
end
end
%% SUB 1
AxesMain = subplot(2,1,1);
hold on
if ~isempty(S)
histogram(S(end,:),300,'Normalization','probability','FaceColor',col,'EdgeColor',col,'Parent',AxesMain,'DisplayName',[plotJob.dataStatArg,' Ch.: ', plotJob.displayname],'FaceAlpha',0.4,'EdgeAlpha',0.4);
end
xlim([-3 ,9 ]);
ylim([0 .10]);
% Figure Settings
title(AxesMain,['$P_{in}:$ ',num2str(plotJob.p_in-9), 'dBm; L : ', num2str(plotJob.l),'Km'],'Interpreter','latex');
xlabel(AxesMain,plotJob.xAxisLabel,'Interpreter','latex');
ylabel('PDF')
grid(AxesMain,'on');
grid(AxesMain,'minor');
%legend(AxesMain,'Interpreter','latex');
fontsize(AxesMain,24,"pixels")
hold off
%% SUB 2
AxesMain = subplot(2,1,2);
if ~isempty(S)
hold on
[f1,x1]=ecdf(S(end,:));
plot(x1,f1,'r','LineWidth',3, 'Color',col,'DisplayName',[plotJob.dataStatArg,' Ch.: ', plotJob.displayname]);
end
xlim([-3 ,9 ]);
ylim([0 1]);
% Figure Settings
title(AxesMain,['$P_{in}:$ ',num2str(plotJob.p_in-9), 'dBm; L : ', num2str(plotJob.l),'Km'],'Interpreter','latex');
xlabel(AxesMain,plotJob.xAxisLabel,'Interpreter','latex');
ylabel('CDF')
grid(AxesMain,'on');
grid(AxesMain,'minor');
fontsize(AxesMain,24,"pixels")
%legend(AxesMain,'Interpreter','latex');
fig.Position = plotJob.Position;
hold off
end

View File

@@ -0,0 +1,206 @@
function plotViolin(wh,plotJob)
fig = findall(groot, 'Type', 'figure', 'Name', plotJob.figName);
if isvalid(fig)
figure(fig)
fig = get(fig);
AxesMain = fig.CurrentAxes;
hold on
else
fig = figure('name',char(plotJob.figName));
AxesMain = gca;
hold on
end
%% Violin
col = plotJob.color;
% we want to fetch all realizations
if plotJob.pmd == 0
realization = 1;
else
realization = wh.parameter.realization.values(1:end);
end
%realization = 0:8;
% get all xAxis values
xAxis = wh.parameter.p_out.values;
% ber = NaN(500,16,10);
% zdw = NaN(500,1,10);
%get BER values for query
for xl = 1:numel(xAxis)
p_out = xAxis(xl);
curber = wh.getStoValue('ber',plotJob.l,plotJob.d,plotJob.sgm,string(plotJob.pol),plotJob.p_in,p_out,plotJob.pmd,plotJob.gamma,realization,plotJob.ch,1310,plotJob.channelspacing,plotJob.randzdw);
curber= removeZeros(curber);
ber(1:size(curber,1),1:size(curber,2),xl) = curber;
end
% to remove outliers set the percentile range
% a = squeeze(mean(ber,2));
% out = isoutlier(mean(a,2),"percentiles",[0 100]);
% ber = ber(~out,:,:);
% disp(sum(out));
hdfec = 3.8e-3.*ones(size(xAxis));
S = [];
wavelength={};
S = [];
S_chann = [];
wl = calcWavelengthPlan(plotJob.ch,plotJob.channelspacing,1310);
%get fec thresholds
% [C,ia,ib] =intersect(linx,xAxis);
% linear = squeeze(linear);
%ber(ber==0) = NaN;
S_chann_no_crossing = zeros(1,plotJob.ch);
for chann = 1:size(ber,2)
for realiz = 1:size(ber,1)
ber_series = squeeze(ber(realiz,chann,:)).';
if mean(ber_series) > 0.1
continue
end
a = InterX([hdfec(:)';xAxis],[ber_series;xAxis]);
if ~isempty(a)
S_chann(realiz,chann) = a(2);
% if a(2) > -7 && string(plotJob.pol) == "copolarized"
% continue
% end
S(end+1) = a(2);
wavelength{end+1} = num2str(wl(chann));
else
S(end+1) = 0;
wavelength{end+1} = num2str(wl(chann));
S_chann_no_crossing(realiz,chann) = 1;
S_chann(realiz,chann) = -1;
end
end
end
threshold = -6;
FEC_crossed = sum(S_chann < threshold & ~isnan(S_chann),1);
FEC_not_crossed = sum(S_chann >= threshold & ~isnan(S_chann),1);
failure_rate = FEC_not_crossed ./ (FEC_crossed + FEC_not_crossed) ;
S_chann(S_chann==0) = NaN;
total_avg = mean(S_chann,"all","omitnan");
%figure(2024)
%C = flip(cbrewer2('Spectral',8));
if numel(S) <= numel(wl)
vs = scatter(1:numel(S),S,50,'o','MarkerEdgeColor','black','MarkerFaceColor',plotJob.color,'LineWidth',1,'HandleVisibility','off');
%vs = scatter(1,mean(S),50,'o','MarkerEdgeColor','black','MarkerFaceColor',plotJob.color,'LineWidth',1);
else
vs = violinplot(S,wavelength,...
'ViolinColor',plotJob.color,...
'ViolinAlpha',0.1,...
'MarkerSize',1,...
'ShowMedian',false,...
'EdgeColor',plotJob.color,...
'ShowWhiskers',false,...
'ShowData',false,...
'ShowBox',false,...
'Bandwidth',0.051 ...
);
hold on
partly_failed = boolean(ceil(failure_rate));
avg = mean(S_chann,1,"omitnan");
notfailed = ~partly_failed .* avg;
notfailed(notfailed==0) = NaN;
scatter(1:size(S_chann,2),notfailed,10,'Marker','x','MarkerEdgeColor','black','MarkerFaceColor',plotJob.color,'LineWidth',0.5,'HandleVisibility','off');
hold on
partly_failed = partly_failed.*avg;
partly_failed(partly_failed==0) = NaN;
s=scatter(1:numel(failure_rate),partly_failed,10,'Marker','x','LineWidth',0.5,'HandleVisibility','off','MarkerEdgeColor','red');
s.DataTipTemplate.Interpreter = "latex";
s.DataTipTemplate.DataTipRows(1).Label = "Fail Rate: ";
s.DataTipTemplate.DataTipRows(1).Value = failure_rate;
s.DataTipTemplate.DataTipRows(2) = [];
hold off
end
% ax = gca;
% ax.XTicks
hold on
yline(total_avg,'LineWidth',1,'LineStyle','--','DisplayName','System Avg.')
fig.Position = plotJob.Position;
xticklabels(1:16);
ylabel('Penalty in dB');
xlabel('Channel Number');
ylim([-9.3,-3]);
xlim([0,plotJob.ch+1]);
% grid minor;
set(gca, 'color', 'none');
legend = [];
fontsize(AxesMain,8,"points")
fig.Position = plotJob.Position;
fig.Units = "centimeters";
fig.Position = [2 2 8.5 7];
set(AxesMain,'TickLabelInterpreter','latex')
set(AxesMain.Legend,'Interpreter','latex')
if 0
ber_sorted = sort(S);
z1 = [];
penalty = mean(ber_sorted):0.01:mean(ber_sorted)+2;
for i = 1:length(penalty)
l = penalty(i);
if i == 1
z1 = [z1 sum(ber_sorted(1,:)<l ) / length(ber_sorted) ];
else
z1 = [z1 sum(ber_sorted(1,:)<l & ber_sorted(1,:)>l-0.01) / length(ber_sorted) ];
end
end
penalty_higherthan = 0.5;
probability = sum(z1(find(penalty>mean(ber_sorted)+penalty_higherthan)));
disp(['A penalty of more than 0.5 dB has a probability of: ', num2str(probability)]);
end
end
function vec = removeZeros(vec)
% Find rows that contain only zeros
rows_to_remove = all(vec == 0, 2);
% Remove rows with only zeros
vec(rows_to_remove, :) = [];
end

View File

@@ -0,0 +1,58 @@
%automate plots
% [file, path] = uigetfile("C:\Users\Silas\Documents\MATLAB\Raw_Cluster_Simulations\session_januar24\wh_complete_at_1310.mat");
% wh = load([path filesep file]);
% wh = wh.wh;
plotJob = struct();
plotJob.l = 10;
plotJob.ch = 16;
plotJob.d = 3;
plotJob.sgm = 1;
plotJob.pol = "copolarized";
plotJob.p_in = 3;
plotJob.gamma = 0.0023;
plotJob.pmd = 0.1;
plotJob.channelspacing = 400e9;
plotJob.randzdw = 0;
ber_per_chann = [];
% get all xAxis values
xAxis = wh.parameter.p_out.values;
realization = wh.parameter.realization.values(1:end);
% Fetch Data from Warehouse
for xl = 1:numel(xAxis)
p_out = xAxis(xl);
raw_fetch = wh.getStoValue('ber',plotJob.l,plotJob.d,plotJob.sgm,string(plotJob.pol),plotJob.p_in,p_out,plotJob.pmd,plotJob.gamma,realization,plotJob.ch,1310,plotJob.channelspacing,plotJob.randzdw).';
ber_per_chann(:,:,xl) = raw_fetch;
end
%%
figure(2023);
for ch = [1,floor(plotJob.ch/2),ceil(plotJob.ch/2)+1,plotJob.ch] %1:15:size(ber_per_chann,1)
for p = 5%1:size(ber_per_chann,3)
% Extract data for the current row
row_data = squeeze(ber_per_chann(ch,:,p));
[f, xi] = ksdensity(row_data);
% Identify the peak point
[max_density, max_index] = max(f);
peak_x = xi(max_index);
end
% Create a histogram plot for the current row with a unique color
plot(xi, f, 'LineWidth', 2, 'DisplayName', ['Ch. ', num2str(ch)],'LineStyle','--');
%histogram(row_data,100, 'DisplayName', ['Channel ', num2str(ch)], 'EdgeColor', 'none');
hold on; % Hold the plot for the next iteration
text(peak_x, max_density, ['Ch ', num2str(ch)], 'VerticalAlignment', 'bottom', 'HorizontalAlignment', 'left');
end
legend show
%%