halfway merged and pulled?!
This commit is contained in:
240
Classes/02_optical/DP_Fiber.m
Normal file
240
Classes/02_optical/DP_Fiber.m
Normal 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
|
||||||
149
Classes/02_optical/Optical_Demultiplex.m
Normal file
149
Classes/02_optical/Optical_Demultiplex.m
Normal 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
|
||||||
|
|
||||||
171
Classes/02_optical/Optical_Multiplex.m
Normal file
171
Classes/02_optical/Optical_Multiplex.m
Normal 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
|
||||||
92
Classes/02_optical/Polarization_Controller.m
Normal file
92
Classes/02_optical/Polarization_Controller.m
Normal 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
|
||||||
135
Classes/02_optical/dp_fiber_lib/CNLSE.m
Normal file
135
Classes/02_optical/dp_fiber_lib/CNLSE.m
Normal 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
|
||||||
120
Classes/02_optical/dp_fiber_lib/CNLSE_plain.m
Normal file
120
Classes/02_optical/dp_fiber_lib/CNLSE_plain.m
Normal 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
|
||||||
25
Classes/02_optical/dp_fiber_lib/getNLstepsize.m
Normal file
25
Classes/02_optical/dp_fiber_lib/getNLstepsize.m
Normal 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
|
||||||
27
Classes/02_optical/dp_fiber_lib/getNLstepsize_original.m
Normal file
27
Classes/02_optical/dp_fiber_lib/getNLstepsize_original.m
Normal 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
|
||||||
125
Classes/02_optical/dp_fiber_lib/lin_step.m
Normal file
125
Classes/02_optical/dp_fiber_lib/lin_step.m
Normal 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
|
||||||
106
Classes/02_optical/dp_fiber_lib/lin_step_original.m
Normal file
106
Classes/02_optical/dp_fiber_lib/lin_step_original.m
Normal 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
|
||||||
39
Classes/02_optical/dp_fiber_lib/nl_step.m
Normal file
39
Classes/02_optical/dp_fiber_lib/nl_step.m
Normal 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
|
||||||
30
Classes/02_optical/dp_fiber_lib/nl_step_original.m
Normal file
30
Classes/02_optical/dp_fiber_lib/nl_step_original.m
Normal 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
|
||||||
93
Classes/02_optical/dp_fiber_lib/split_step_loop.m
Normal file
93
Classes/02_optical/dp_fiber_lib/split_step_loop.m
Normal 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
|
||||||
|
|
||||||
351
Classes/04_DSP/Equalizer/FFE_DCremoval_adaptive_mu.m
Normal file
351
Classes/04_DSP/Equalizer/FFE_DCremoval_adaptive_mu.m
Normal 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
|
||||||
|
|
||||||
240
Classes/04_DSP/Equalizer/FFE_DCremoval_level.m
Normal file
240
Classes/04_DSP/Equalizer/FFE_DCremoval_level.m
Normal 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
|
||||||
|
|
||||||
233
Classes/04_DSP/Equalizer/FFE_MLSE.m
Normal file
233
Classes/04_DSP/Equalizer/FFE_MLSE.m
Normal 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
|
||||||
355
Classes/04_DSP/Equalizer/ML_MLSE.m
Normal file
355
Classes/04_DSP/Equalizer/ML_MLSE.m
Normal 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
|
||||||
152
Classes/04_DSP/Sequence Detection/MLSE_new.m
Normal file
152
Classes/04_DSP/Sequence Detection/MLSE_new.m
Normal file
@@ -0,0 +1,152 @@
|
|||||||
|
classdef MLSE_new < handle
|
||||||
|
%MLSE: BCJR‐based soft‐output for PAM‐M 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 2‐tap
|
||||||
|
|
||||||
|
N = numel(y);
|
||||||
|
M = obj.M;
|
||||||
|
m = log2(M);
|
||||||
|
|
||||||
|
%--- forward/backward metrics (max‐log) ---
|
||||||
|
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 “zero‐th” 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 symbol‐wise via log‐sum‐exp 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
|
||||||
|
% bit‐LLR 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
|
||||||
68
Classes/DataBaseHandler/Equalizerstruct.m
Normal file
68
Classes/DataBaseHandler/Equalizerstruct.m
Normal 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
|
||||||
147
Classes/DataBaseHandler/Metricstruct.m
Normal file
147
Classes/DataBaseHandler/Metricstruct.m
Normal 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
|
||||||
169
Classes/DataBaseHandler/QueryFilter.m
Normal file
169
Classes/DataBaseHandler/QueryFilter.m
Normal 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
|
||||||
22
Classes/DataBaseHandler/SqlFilter.m
Normal file
22
Classes/DataBaseHandler/SqlFilter.m
Normal 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
|
||||||
48
Classes/DataBaseHandler/SqlOperator.m
Normal file
48
Classes/DataBaseHandler/SqlOperator.m
Normal 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
|
||||||
32
Classes/DataBaseHandler/related functions/cleanUpTable.m
Normal file
32
Classes/DataBaseHandler/related functions/cleanUpTable.m
Normal 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
|
||||||
53
Classes/DataBaseHandler/related functions/groupIt.m
Normal file
53
Classes/DataBaseHandler/related functions/groupIt.m
Normal 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
|
||||||
@@ -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
146
Classes/GifWriter.m
Normal 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
|
||||||
7
Classes/Warehouse_class/classes/Parameter.m
Normal file
7
Classes/Warehouse_class/classes/Parameter.m
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
classdef Parameter < StorageParameter
|
||||||
|
methods
|
||||||
|
function obj = Parameter(varargin)
|
||||||
|
obj@StorageParameter(varargin{:});
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
40
Classes/Warehouse_class/classes/minimal_example.m
Normal file
40
Classes/Warehouse_class/classes/minimal_example.m
Normal 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
|
||||||
@@ -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
|
||||||
|
|
||||||
|
|
||||||
@@ -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
|
||||||
|
|
||||||
|
|
||||||
@@ -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
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -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');
|
||||||
@@ -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','--')
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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');
|
||||||
|
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
|
|
||||||
|
%%
|
||||||
9
Datatypes/adaption_method.m
Normal file
9
Datatypes/adaption_method.m
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
classdef adaption_method < int32
|
||||||
|
|
||||||
|
enumeration
|
||||||
|
lms (1)
|
||||||
|
nlms (2)
|
||||||
|
rls (3)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
10
Datatypes/polarization_control_mode.m
Normal file
10
Datatypes/polarization_control_mode.m
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
classdef polarization_control_mode < int32
|
||||||
|
|
||||||
|
enumeration
|
||||||
|
random (1)
|
||||||
|
rot_angle (2)
|
||||||
|
rot_power (3)
|
||||||
|
deactivate (4)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
8
Datatypes/processingMode.m
Normal file
8
Datatypes/processingMode.m
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
|
||||||
|
classdef processingMode < int32
|
||||||
|
enumeration
|
||||||
|
serial (1)
|
||||||
|
parallel (2)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
316
Functions/EQ_structures/dsp_runid.m
Normal file
316
Functions/EQ_structures/dsp_runid.m
Normal file
@@ -0,0 +1,316 @@
|
|||||||
|
function [output] = dsp_runid(run_id, options)
|
||||||
|
|
||||||
|
arguments
|
||||||
|
run_id
|
||||||
|
options.append_to_db = 0;
|
||||||
|
options.max_occurences = 4;
|
||||||
|
options.parameters = struct();
|
||||||
|
options.database_type
|
||||||
|
options.dataBase
|
||||||
|
options.load_file_path = struct();
|
||||||
|
options.storage_path
|
||||||
|
options.mode
|
||||||
|
end
|
||||||
|
|
||||||
|
try
|
||||||
|
% Initialize output structures
|
||||||
|
output.ffe_package = {};
|
||||||
|
output.mlse_package = {};
|
||||||
|
output.vnle_package = {};
|
||||||
|
output.dbtgt_package = {};
|
||||||
|
output.dbenc_package = {};
|
||||||
|
output.mlmlse_package = {};
|
||||||
|
|
||||||
|
if options.mode == "load_run_id" || options.append_to_db
|
||||||
|
% Initialize database connection
|
||||||
|
database = DBHandler("dataBase", [options.dataBase], "type", options.database_type );
|
||||||
|
|
||||||
|
if 0
|
||||||
|
% 2. Check if an equalizer configuration with the same hash exists
|
||||||
|
queryStr = sprintf('SELECT COUNT(DISTINCT eq_id) AS unique_eq_count, COUNT(*) AS entries_for_run FROM `Results` WHERE run_id = %d', run_id);
|
||||||
|
existing_results = database.fetch(queryStr);
|
||||||
|
|
||||||
|
if existing_results.unique_eq_count >= 6
|
||||||
|
if (existing_results.entries_for_run / existing_results.unique_eq_count) > 5
|
||||||
|
return
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
if options.mode == "load_run_id"
|
||||||
|
|
||||||
|
dataTable = queryRunid(run_id, database);
|
||||||
|
fsym = dataTable.symbolrate;
|
||||||
|
M = double(dataTable.pam_level);
|
||||||
|
duob_mode = db_mode(strrep(dataTable.db_mode,'"',''));
|
||||||
|
|
||||||
|
% if database.checkIfRunExists('Results','run_id',run_id)
|
||||||
|
% disp(['Already got at least one reulst for run id: ',num2str(run_id),' '])
|
||||||
|
% return
|
||||||
|
% end
|
||||||
|
|
||||||
|
% Load and Sync signal data from DB
|
||||||
|
[Tx_bits, Symbols, Scpe_cell, ~] = loadAndSyncSignalDataFromDb(dataTable, options);
|
||||||
|
|
||||||
|
elseif options.mode == "load_files"
|
||||||
|
|
||||||
|
Tx_bits = load(options.load_file_path.tx_bits_path);
|
||||||
|
Symbols = load(options.load_file_path.tx_symbols_path);
|
||||||
|
Scpe_sig_raw = load(options.load_file_path.rx_raw_path);
|
||||||
|
|
||||||
|
Tx_bits = Tx_bits.Bits;
|
||||||
|
Symbols = Symbols.Symbols;
|
||||||
|
Scpe_sig_raw = Scpe_sig_raw.Scpe_sig_raw;
|
||||||
|
|
||||||
|
fsym = Symbols.fs;
|
||||||
|
M = Symbols.logbook.ModifierCopy{1}.M;
|
||||||
|
duob_mode = Symbols.logbook.ModifierCopy{1}.duobinary_mode;
|
||||||
|
|
||||||
|
Scpe_sig_resampled = Scpe_sig_raw.resample("fs_in", Scpe_sig_raw.fs, "fs_out", 2*fsym);
|
||||||
|
[~, Scpe_cell, ~, found_sync] = Scpe_sig_resampled.tsynch("reference", Symbols, "fs_ref", fsym, "debug_plots", 1);
|
||||||
|
|
||||||
|
else
|
||||||
|
|
||||||
|
% Run quick Simulation
|
||||||
|
tx_simulation;
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
% Handle Settings and argument replacement
|
||||||
|
|
||||||
|
len_tr = 4096*2;
|
||||||
|
|
||||||
|
ffe_order = [50, 5, 5];
|
||||||
|
dfe_order = [0, 0, 0];
|
||||||
|
pf_ncoeffs = 1;
|
||||||
|
mu_ffe = [0.0001, 0.0008, 0.001];
|
||||||
|
mu_dfe = 0.0004;
|
||||||
|
mu_dc = 0.005;
|
||||||
|
dc_buffer_len = 1;
|
||||||
|
|
||||||
|
mu_tr = 0;
|
||||||
|
mu_dd = 0.05;
|
||||||
|
adaption= 1;
|
||||||
|
use_dd_mode = 1;
|
||||||
|
|
||||||
|
use_ffe = 0;
|
||||||
|
use_dfe = 0;
|
||||||
|
use_vnle_mlse = 0;
|
||||||
|
use_dbtgt = 0;
|
||||||
|
use_dbenc = 0;
|
||||||
|
use_ml_mlse = 1;
|
||||||
|
|
||||||
|
addProcessingResultToDatabase = 0;
|
||||||
|
|
||||||
|
% Overwrite default parameters if given in options.parameters
|
||||||
|
paramStruct = options.parameters;
|
||||||
|
if ~isempty(paramStruct)
|
||||||
|
paramNames = fieldnames(paramStruct);
|
||||||
|
for i = 1:numel(paramNames)
|
||||||
|
thisName = paramNames{i};
|
||||||
|
thisValue = paramStruct.(thisName);
|
||||||
|
eval([thisName ' = thisValue;']);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
% Configure equalizers
|
||||||
|
|
||||||
|
options.max_occurences = min(options.max_occurences,length(Scpe_cell));
|
||||||
|
for r = 1:options.max_occurences
|
||||||
|
|
||||||
|
%FFE
|
||||||
|
% eq_dfe = 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);
|
||||||
|
|
||||||
|
|
||||||
|
%
|
||||||
|
pf_ = Postfilter("ncoeff",pf_ncoeffs,"useBurg",1);
|
||||||
|
% mlse_ = MLSE_viterbi("duobinary_output",0,'M',M,'trellis_states',PAMmapper(M,0).levels);
|
||||||
|
mlse_ = MLSE("duobinary_output",0,'M',M,'trellis_states',PAMmapper(M,0).levels);
|
||||||
|
|
||||||
|
eq_post = FFE("epochs_tr",5,"epochs_dd",5,"len_tr",4096*2,"mu_dd",1e-4,"mu_tr",0,"order",2001,"sps",1,"decide",0,"adaption_technique","lms");
|
||||||
|
eq_post = 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);
|
||||||
|
% Duobinary signaling (db encoded)
|
||||||
|
mlse_db_enc = MLSE("DIR", [1,1], "duobinary_output", 0, "M", M, "trellis_states", PAMmapper(M,0).levels);
|
||||||
|
eq_db_enc = EQ("Ne", ffe_order, "Nb", dfe_order, "training_length", len_tr, ...
|
||||||
|
"training_loops", 5, "dd_loops", 5, "K", 2, "DCmu", mu_dc, ...
|
||||||
|
"DDmu", [mu_ffe mu_dfe], "DFEmu", 0.005, "FFEmu", 0, "plotfinal", 0, "ideal_dfe", 1);
|
||||||
|
|
||||||
|
% Preprocess signal
|
||||||
|
Scpe_sig = preprocessSignal(Scpe_cell{r}, Symbols, fsym);
|
||||||
|
|
||||||
|
Scpe_sig.spectrum("fignum",200,"normalizeTo0dB",1,"displayname",'Rx','addDCoffset',-6);
|
||||||
|
|
||||||
|
Scpe_sig.spectrum("fignum",201,"normalizeTo0dB",0,"displayname",'Rx');
|
||||||
|
|
||||||
|
ylim([-30,3]);
|
||||||
|
xlim([-5,100]);
|
||||||
|
% Scpe_sig.spectrum("fignum",22233,"normalizeTo0dB",0,"displayname",'Rx');
|
||||||
|
% Scpe_sig.eye(fsym,M,"fignum",1024);
|
||||||
|
|
||||||
|
if duob_mode ~= db_mode.db_encoded
|
||||||
|
|
||||||
|
if use_ffe
|
||||||
|
|
||||||
|
ffe_order = [50, 0, 0];
|
||||||
|
eq_dfe = EQ("Ne",ffe_order,"Nb",[0,0,0],"training_length",len_tr,"training_loops",5,"dd_loops",5,"K",2,"DCmu",mu_dc,"DDmu",[mu_ffe mu_dfe],"DFEmu",0.005,"FFEmu",0,"plotfinal",0,"ideal_dfe",0);
|
||||||
|
|
||||||
|
ffe_results = ffe(eq_dfe,M,Scpe_sig,Symbols,Tx_bits,...
|
||||||
|
"precode_mode",duob_mode,...
|
||||||
|
'showAnalysis',0,...
|
||||||
|
"postFFE",[],...
|
||||||
|
"eth_style_symbol_mapping",0);
|
||||||
|
|
||||||
|
output.ffe_package{r} = ffe_results;
|
||||||
|
|
||||||
|
ffe_results.metrics.print;
|
||||||
|
ffe_results.config.equalizer_structure = "ffe";
|
||||||
|
|
||||||
|
if options.append_to_db
|
||||||
|
database.addProcessingResult(run_id, ffe_results.metrics, ffe_results.config);
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
if use_dfe
|
||||||
|
|
||||||
|
ffe_order = [50, 5, 5];
|
||||||
|
eq_dfe = EQ("Ne",ffe_order,"Nb",[2,0,0],"training_length",len_tr,"training_loops",5,"dd_loops",5,"K",2,"DCmu",mu_dc,"DDmu",[mu_ffe mu_dfe],"DFEmu",0.005,"FFEmu",0,"plotfinal",0,"ideal_dfe",0);
|
||||||
|
|
||||||
|
dfe_results = ffe(eq_dfe,M,Scpe_sig,Symbols,Tx_bits,...
|
||||||
|
"precode_mode",duob_mode,...
|
||||||
|
'showAnalysis',0,...
|
||||||
|
"postFFE",[],...
|
||||||
|
"eth_style_symbol_mapping",0);
|
||||||
|
|
||||||
|
output.ffe_package{r} = dfe_results;
|
||||||
|
dfe_results.config.equalizer_structure = "dfe";
|
||||||
|
|
||||||
|
dfe_results.metrics.print;
|
||||||
|
|
||||||
|
if options.append_to_db
|
||||||
|
database.addProcessingResult(run_id, dfe_results.metrics, dfe_results.config);
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
if use_vnle_mlse
|
||||||
|
|
||||||
|
pf_ncoeffs = 1;
|
||||||
|
ffe_order = [50, 5, 5];
|
||||||
|
eq_ = EQ("Ne",ffe_order,"Nb",dfe_order,"training_length",len_tr,"training_loops",5,"dd_loops",5,"K",2,"DCmu",mu_dc,"DDmu",[mu_ffe mu_dfe],"DFEmu",0.005,"FFEmu",0,"plotfinal",0,"ideal_dfe",0);
|
||||||
|
% eq_ = VNLE("epochs_tr",5,"epochs_dd",5,"len_tr",4096*2,"mu_dd",[0.0004 0.0005 0.0006],"mu_tr",0.0004,"order",[50,5,5],"sps",2,"decide",0);
|
||||||
|
pf_ = Postfilter("ncoeff",pf_ncoeffs,"useBurg",1);
|
||||||
|
|
||||||
|
useviterbi = 0;
|
||||||
|
if useviterbi
|
||||||
|
mlse_ = MLSE_viterbi("duobinary_output",0,'M',M,'trellis_states',PAMmapper(M,0).levels);
|
||||||
|
else
|
||||||
|
|
||||||
|
if duob_mode == db_mode.no_db && M == 6 %only for PAM-6 and no duobinary precoding, otherwise leads to false sequence estimation
|
||||||
|
trellexlusion = 1;
|
||||||
|
else
|
||||||
|
trellexlusion = 0;
|
||||||
|
end
|
||||||
|
|
||||||
|
%state_mode 3 -> stat lvl; state_mode 2 -> use target lvls
|
||||||
|
%scale_mode 2 -> mmse adaption
|
||||||
|
|
||||||
|
mlse_ = MLSE("duobinary_output",0,'M',M,'trellis_states',PAMmapper(M,0).levels,'scale_mode',2,'trellis_exclusion',trellexlusion,'trellis_state_mode',2);
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
[ffe_results, mlse_results] = vnle_postfilter_mlse(eq_, pf_, mlse_, M, Scpe_sig, Symbols, Tx_bits, ...
|
||||||
|
"precode_mode", duob_mode,...
|
||||||
|
'showAnalysis', 0, ...
|
||||||
|
"postFFE", [],...
|
||||||
|
"eth_style_symbol_mapping", 0);
|
||||||
|
|
||||||
|
ffe_results.metrics.print;
|
||||||
|
ffe_results.config.equalizer_structure = "vnle";
|
||||||
|
mlse_results.metrics.print;
|
||||||
|
|
||||||
|
output.mlse_package{r} = mlse_results;
|
||||||
|
output.vnle_package{r} = ffe_results;
|
||||||
|
|
||||||
|
if options.append_to_db
|
||||||
|
database.addProcessingResult(run_id, mlse_results.metrics, mlse_results.config);
|
||||||
|
database.addProcessingResult(run_id, ffe_results.metrics, ffe_results.config);
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
if use_ml_mlse
|
||||||
|
|
||||||
|
%ML-based MLSE (L=2)
|
||||||
|
mu_ml = 0.01; training_epochs = 100;
|
||||||
|
ml_mlse_equalizer = ML_MLSE("epochs_tr",training_epochs,"epochs_dd",1, ...
|
||||||
|
"len_tr",length(Scpe_sig),"mu_dd",mu_ml,"mu_tr",mu_ml,"order",11,"sps",2, ...
|
||||||
|
"traceback_depth",128,"L",1,"delta",4,"adaptive_mu",0);
|
||||||
|
|
||||||
|
[ml_mlse_results] = ml_mlse(ml_mlse_equalizer, M, Scpe_sig, Symbols, Tx_bits,"precode_mode",duob_mode);
|
||||||
|
output.mlmlse_package{r} = ml_mlse_results;
|
||||||
|
|
||||||
|
if options.append_to_db
|
||||||
|
database.addProcessingResult(run_id, ml_mlse_results.metrics, ml_mlse_results.config);
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
if use_dbtgt
|
||||||
|
|
||||||
|
useviterbi = 0;
|
||||||
|
if useviterbi
|
||||||
|
mlse_db_ = MLSE_viterbi("duobinary_output",0,'M',M,'trellis_states',PAMmapper(M,0).levels);
|
||||||
|
else
|
||||||
|
if duob_mode == db_mode.no_db && M == 6 %only for PAM-6 and no duobinary precoding, otherwise leads to false sequence estimation
|
||||||
|
trellexlusion = 1;
|
||||||
|
else
|
||||||
|
trellexlusion = 0;
|
||||||
|
end
|
||||||
|
mlse_db_ = MLSE("DIR",[1,1],"duobinary_output",0,"M",M,"trellis_states",PAMmapper(M,0).levels,'scale_mode',2,'trellis_exclusion',trellexlusion,'trellis_state_mode',3);
|
||||||
|
end
|
||||||
|
ffe_order = [50, 5, 5];
|
||||||
|
eq_ = EQ("Ne",ffe_order,"Nb",dfe_order,"training_length",len_tr,"training_loops",5,"dd_loops",5,"K",2,"DCmu",mu_dc,"DDmu",[mu_ffe mu_dfe],"DFEmu",0.005,"FFEmu",0,"plotfinal",0,"ideal_dfe",1);
|
||||||
|
|
||||||
|
dbt_results = duobinary_target(eq_, mlse_db_, M, Scpe_sig, Symbols, Tx_bits, ...
|
||||||
|
"precode_mode", duob_mode, ...
|
||||||
|
'showAnalysis', 0,...
|
||||||
|
"postFFE", []);
|
||||||
|
|
||||||
|
dbt_results.metrics.print;
|
||||||
|
|
||||||
|
output.dbtgt_package{r} = dbt_results;
|
||||||
|
|
||||||
|
if options.append_to_db
|
||||||
|
database.addProcessingResult(run_id, dbt_results.metrics, dbt_results.config);
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if duob_mode == db_mode.db_encoded
|
||||||
|
|
||||||
|
mlse_db_enc = MLSE_viterbi("duobinary_output",0,'M',M,'trellis_states',PAMmapper(M,0).levels);
|
||||||
|
mlse_db_enc = MLSE("DIR", [1,1], "duobinary_output", 0, "M", M, "trellis_states", PAMmapper(M,0).levels);
|
||||||
|
|
||||||
|
db_results = duobinary_signaling(eq_db_enc, mlse_db_enc, M, Scpe_sig, Symbols, Tx_bits, "precode_mode",duob_mode, "showAnalysis",0,"postFFE",[]);
|
||||||
|
output.dbenc_package{r} = db_results;
|
||||||
|
if options.append_to_db
|
||||||
|
database.addProcessingResult(run_id, db_results.metrics, db_results.config);
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
catch ME
|
||||||
|
save('workerError.mat','ME');
|
||||||
|
rethrow(ME);
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
end
|
||||||
192
Functions/EQ_structures/ffe.m
Normal file
192
Functions/EQ_structures/ffe.m
Normal file
@@ -0,0 +1,192 @@
|
|||||||
|
function [ffe_results] = ffe(eq_, M, rx_signal, tx_symbols, tx_bits, options)
|
||||||
|
% FFE Processes signals through FFE equalizer
|
||||||
|
%
|
||||||
|
% Inputs:
|
||||||
|
% eq_ - Equalizer object
|
||||||
|
% M - Modulation order
|
||||||
|
% rx_signal - Received signal
|
||||||
|
% tx_symbols - Transmitted symbols
|
||||||
|
% tx_bits - Transmitted bits
|
||||||
|
% options - Optional parameters
|
||||||
|
%
|
||||||
|
% Outputs:
|
||||||
|
% ffe_results - Results from FFE processing
|
||||||
|
|
||||||
|
arguments
|
||||||
|
eq_
|
||||||
|
M
|
||||||
|
rx_signal
|
||||||
|
tx_symbols
|
||||||
|
tx_bits
|
||||||
|
options.precode_mode db_mode
|
||||||
|
options.showAnalysis = 0;
|
||||||
|
options.eth_style_symbol_mapping = 0;
|
||||||
|
options.postFFE = [];
|
||||||
|
options.database = [];
|
||||||
|
end
|
||||||
|
|
||||||
|
%% Process signals through equalizer
|
||||||
|
% FFE or VNLE
|
||||||
|
[eq_signal_sd, eq_noise] = eq_.process(rx_signal, tx_symbols);
|
||||||
|
|
||||||
|
% Apply post-FFE if provided
|
||||||
|
if ~isempty(options.postFFE)
|
||||||
|
tic
|
||||||
|
[eq_signal_sd, eq_noise] = options.postFFE.process(eq_signal_sd, tx_symbols);
|
||||||
|
toc
|
||||||
|
end
|
||||||
|
|
||||||
|
try
|
||||||
|
ch_coefficients = arburg(eq_noise.signal,1);
|
||||||
|
channel_alpha = ch_coefficients(2);
|
||||||
|
end
|
||||||
|
|
||||||
|
% Hard decision on FFE output
|
||||||
|
eq_signal_hd = PAMmapper(M, 0).quantize(eq_signal_sd);
|
||||||
|
|
||||||
|
%% Calculate BER based on precoding mode
|
||||||
|
[bits, errors, ber, error_pos, errors_precoded, ber_precoded] = calculateBER(eq_signal_hd, tx_symbols, tx_bits, options.precode_mode, M, options.eth_style_symbol_mapping);
|
||||||
|
|
||||||
|
%% Calculate performance metrics
|
||||||
|
[snr, snr_lvl] = calc_snr(tx_symbols.signal, eq_noise.signal);
|
||||||
|
% [gmi] = calc_air(eq_signal_sd, tx_symbols, "skip_front", 10000, "skip_end", 10000);
|
||||||
|
[gmi] = calc_ngmi(eq_signal_sd,tx_symbols);
|
||||||
|
gmi = max(gmi,0);
|
||||||
|
|
||||||
|
air = tx_symbols.fs .* floor(log2(double(M))*10)/10 .* gmi ./ log2(double(M));
|
||||||
|
[evm_total, evm_lvl] = calc_evm(eq_signal_sd, tx_symbols);
|
||||||
|
[std_total, std_lvl] = calc_std(eq_signal_sd, tx_symbols);
|
||||||
|
[std_rxraw_total, std_rxraw_lvl] = calc_std(rx_signal.resample("fs_out", tx_symbols.fs), tx_symbols);
|
||||||
|
|
||||||
|
%% Display analysis if requested
|
||||||
|
if options.showAnalysis
|
||||||
|
displayAnalysis(eq_noise, eq_signal_sd, rx_signal, eq_, tx_symbols, M, options.postFFE);
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
%% Prepare output structure
|
||||||
|
% Determine postFFE order
|
||||||
|
if ~isempty(options.postFFE)
|
||||||
|
npostFFE = options.postFFE.order;
|
||||||
|
else
|
||||||
|
npostFFE = 0;
|
||||||
|
end
|
||||||
|
|
||||||
|
% Create FFE results structure
|
||||||
|
ffe_results = struct();
|
||||||
|
try
|
||||||
|
eq_.e = [];
|
||||||
|
eq_.e2 = [];
|
||||||
|
eq_.e3 = [];
|
||||||
|
eq_.b = [];
|
||||||
|
eq_.b2 = [];
|
||||||
|
eq_.b3 = [];
|
||||||
|
end
|
||||||
|
|
||||||
|
ffe_results.config = Equalizerstruct();
|
||||||
|
ffe_results.config.eq = jsonencode(eq_);
|
||||||
|
ffe_results.config.equalizer_structure = int32(equalizer_structure.ffe);
|
||||||
|
ffe_results.config.comment = 'function: ffe';
|
||||||
|
|
||||||
|
ffe_results.metrics = Metricstruct;
|
||||||
|
ffe_results.metrics.result_id = NaN;
|
||||||
|
ffe_results.metrics.run_id = NaN;
|
||||||
|
ffe_results.metrics.eqParam_id = NaN;
|
||||||
|
ffe_results.metrics.date_of_processing = datetime('now');
|
||||||
|
ffe_results.metrics.BER = ber;
|
||||||
|
ffe_results.metrics.numBits = bits;
|
||||||
|
ffe_results.metrics.numBitErr = errors;
|
||||||
|
ffe_results.metrics.BER_precoded = ber_precoded;
|
||||||
|
ffe_results.metrics.numBitErr_precoded = errors_precoded;
|
||||||
|
ffe_results.metrics.SNR = snr;
|
||||||
|
ffe_results.metrics.SNR_level = snr_lvl;
|
||||||
|
ffe_results.metrics.STD = std_total;
|
||||||
|
ffe_results.metrics.STD_level = std_lvl;
|
||||||
|
ffe_results.metrics.STDrx = std_rxraw_total;
|
||||||
|
ffe_results.metrics.STDrx_level = std_rxraw_lvl;
|
||||||
|
ffe_results.metrics.GMI = gmi;
|
||||||
|
ffe_results.metrics.AIR = air;
|
||||||
|
ffe_results.metrics.EVM = evm_total;
|
||||||
|
ffe_results.metrics.EVM_level = evm_lvl;
|
||||||
|
ffe_results.metrics.Alpha = channel_alpha;
|
||||||
|
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
%% Helper Functions
|
||||||
|
function [bits, errors, ber, error_pos, errors_precoded, ber_precoded] = calculateBER(eq_signal_hd, tx_symbols, tx_bits, precode_mode, M, eth_style)
|
||||||
|
% Calculate BER based on precoding mode
|
||||||
|
mapper = PAMmapper(M, 0, "eth_style", eth_style);
|
||||||
|
|
||||||
|
switch precode_mode
|
||||||
|
case db_mode.no_db
|
||||||
|
% TX Data is not precoded
|
||||||
|
% A) Emulate diff precoding
|
||||||
|
eq_signal_hd_precoded = Duobinary().encode(eq_signal_hd, "M", M);
|
||||||
|
eq_signal_hd_precoded = Duobinary().decode(eq_signal_hd_precoded, "M", M);
|
||||||
|
|
||||||
|
tx_symbols_precoded = Duobinary().encode(tx_symbols);
|
||||||
|
tx_symbols_precoded = Duobinary().decode(tx_symbols_precoded);
|
||||||
|
|
||||||
|
tx_bits_precoded = mapper.demap(tx_symbols_precoded);
|
||||||
|
|
||||||
|
rx_bits = mapper.demap(eq_signal_hd_precoded);
|
||||||
|
[~, errors_precoded, ber_precoded, ~] = calc_ber(rx_bits.signal, tx_bits_precoded.signal, "skip_front", 30000, "skip_end", 150, "returnErrorLocation", 1);
|
||||||
|
|
||||||
|
% B) Just determine BER
|
||||||
|
rx_bits = mapper.demap(eq_signal_hd);
|
||||||
|
[bits, errors, ber, error_pos] = calc_ber(rx_bits.signal, tx_bits.signal, "skip_front", 30000, "skip_end", 150, "returnErrorLocation", 1);
|
||||||
|
|
||||||
|
case db_mode.db_precoded
|
||||||
|
% Data is precoded on TX side
|
||||||
|
% A) Decode at Rx if no DB targeting was applied
|
||||||
|
eq_signal_hd_decoded = Duobinary().encode(eq_signal_hd, "M", M);
|
||||||
|
eq_signal_hd_decoded = Duobinary().decode(eq_signal_hd_decoded, "M", M);
|
||||||
|
rx_bits_decoded = mapper.demap(eq_signal_hd_decoded);
|
||||||
|
[~, errors_precoded, ber_precoded, ~] = calc_ber(rx_bits_decoded.signal, tx_bits.signal, "skip_front", 30000, "skip_end", 150, "returnErrorLocation", 1);
|
||||||
|
|
||||||
|
% B) Omit the Coding by comparing with demapped TX symbol sequence
|
||||||
|
tx_bits_demapped = mapper.demap(tx_symbols);
|
||||||
|
rx_bits = mapper.demap(eq_signal_hd);
|
||||||
|
[bits, errors, ber, error_pos] = calc_ber(rx_bits.signal, tx_bits_demapped.signal, "skip_front", 30000, "skip_end", 150, "returnErrorLocation", 1);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function displayAnalysis(eq_noise, eq_signal_sd, rx_signal, eq_, tx_symbols, M, postFFE)
|
||||||
|
% Display analysis plots and metrics
|
||||||
|
|
||||||
|
% Initialize figure handles
|
||||||
|
% Corrected line - added tx_symbols as second positional argument
|
||||||
|
showLevelScatter(rx_signal.resample("fs_out", tx_symbols.fs), tx_symbols, "fignum", 100);
|
||||||
|
|
||||||
|
warning off
|
||||||
|
showLevelScatter(eq_signal_sd, tx_symbols, "fignum", 101);
|
||||||
|
figure(gcf);hold on; plot(((1:length(eq_noise.signal)) / eq_noise.fs) * 1e6,movmean(eq_noise.signal,2000,1), 'LineWidth',3,'Color','black')
|
||||||
|
warning on
|
||||||
|
|
||||||
|
showLevelHistogram(eq_signal_sd, tx_symbols, "fignum", 102);
|
||||||
|
|
||||||
|
showEQNoisePSD(eq_noise, "fignum", 103, "displayname", 'Residual Noise after FFE');
|
||||||
|
|
||||||
|
% Figure 2: Post-FFE coefficients (if available)
|
||||||
|
if ~isempty(postFFE)
|
||||||
|
showEQcoefficients('n1', postFFE.e, "displayname", 'Coefficients', 'fignum', 104);
|
||||||
|
end
|
||||||
|
|
||||||
|
try
|
||||||
|
figure(339);
|
||||||
|
showEQfilter(eq_.e_tr, eq_signal_sd.fs.*2,"displayname",'training','fignum',339);
|
||||||
|
showEQfilter(eq_.e, eq_signal_sd.fs.*2,"displayname",'dec. directed','fignum',339);
|
||||||
|
legend on
|
||||||
|
end
|
||||||
|
|
||||||
|
try
|
||||||
|
figure(240); hold on; plot(pow2db(movmean(eq_.debug_struct.error_tr',100)));ylim([-30,3]);title('error training');
|
||||||
|
|
||||||
|
figure(241); hold on; plot(pow2db(movmean(eq_.debug_struct.update_tr',100)));title('update step training');
|
||||||
|
|
||||||
|
figure(242); hold on; plot(pow2db(movmean(eq_.debug_struct.update',1000)));title('update step dd');
|
||||||
|
end
|
||||||
|
% eq_signal_sd.eye(eq_signal_sd.fs,M,"displayname",'Eye','fignum',105);
|
||||||
|
|
||||||
|
end
|
||||||
140
Functions/EQ_structures/ml_mlse.m
Normal file
140
Functions/EQ_structures/ml_mlse.m
Normal file
@@ -0,0 +1,140 @@
|
|||||||
|
function [ml_mlse_results] = ml_mlse(eq_, M, rx_signal, tx_symbols, tx_bits, options)
|
||||||
|
%
|
||||||
|
%
|
||||||
|
% Inputs:
|
||||||
|
% eq_ - Equalizer object
|
||||||
|
% M - Modulation order
|
||||||
|
% rx_signal - Received signal
|
||||||
|
% tx_symbols - Transmitted symbols
|
||||||
|
% tx_bits - Transmitted bits
|
||||||
|
% options - Optional parameters
|
||||||
|
%
|
||||||
|
% Outputs:
|
||||||
|
% ffe_results - Results from FFE processing
|
||||||
|
|
||||||
|
arguments
|
||||||
|
eq_
|
||||||
|
M
|
||||||
|
rx_signal
|
||||||
|
tx_symbols
|
||||||
|
tx_bits
|
||||||
|
options.precode_mode db_mode
|
||||||
|
options.eth_style_symbol_mapping = 0;
|
||||||
|
options.postFFE = [];
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
%% Process signals through equalizer
|
||||||
|
|
||||||
|
[eq_signal_hd,y_ref] = eq_.process(rx_signal,tx_symbols);
|
||||||
|
|
||||||
|
%% Calculate BER based on precoding mode
|
||||||
|
[bits, errors, ber, error_pos, errors_precoded, ber_precoded] = calculateBER(eq_signal_hd, tx_symbols, tx_bits, options.precode_mode, M, options.eth_style_symbol_mapping);
|
||||||
|
|
||||||
|
|
||||||
|
% Create FFE results structure
|
||||||
|
ml_mlse_results = struct();
|
||||||
|
try
|
||||||
|
eq_.e = [];
|
||||||
|
eq_.e2 = [];
|
||||||
|
eq_.e3 = [];
|
||||||
|
eq_.b = [];
|
||||||
|
eq_.b2 = [];
|
||||||
|
eq_.b3 = [];
|
||||||
|
end
|
||||||
|
|
||||||
|
ml_mlse_results.config = Equalizerstruct();
|
||||||
|
|
||||||
|
eq_small = strip_eq(eq_, 10);
|
||||||
|
json_str = jsonencode(eq_small);
|
||||||
|
|
||||||
|
ml_mlse_results.config.eq = jsonencode(eq_);
|
||||||
|
ml_mlse_results.config.equalizer_structure = int32(equalizer_structure.ml_mlse);
|
||||||
|
ml_mlse_results.config.comment = 'function: ML-based MLSE';
|
||||||
|
|
||||||
|
ml_mlse_results.metrics = Metricstruct;
|
||||||
|
% ml_mlse_results.metrics.result_id = NaN;
|
||||||
|
% ml_mlse_results.metrics.run_id = NaN;
|
||||||
|
% ml_mlse_results.metrics.eqParam_id = NaN;
|
||||||
|
ml_mlse_results.metrics.date_of_processing = datetime('now');
|
||||||
|
ml_mlse_results.metrics.BER = ber;
|
||||||
|
ml_mlse_results.metrics.numBits = bits;
|
||||||
|
ml_mlse_results.metrics.numBitErr = errors;
|
||||||
|
ml_mlse_results.metrics.BER_precoded = ber_precoded;
|
||||||
|
ml_mlse_results.metrics.numBitErr_precoded = errors_precoded;
|
||||||
|
% ml_mlse_results.metrics.SNR = NaN;
|
||||||
|
% ml_mlse_results.metrics.SNR_level = NaN;
|
||||||
|
% ml_mlse_results.metrics.STD = NaN;
|
||||||
|
% ml_mlse_results.metrics.STD_level = NaN;
|
||||||
|
% ml_mlse_results.metrics.STDrx = NaN;
|
||||||
|
% ml_mlse_results.metrics.STDrx_level = NaN;
|
||||||
|
% ml_mlse_results.metrics.GMI = NaN;
|
||||||
|
% ml_mlse_results.metrics.AIR = NaN;
|
||||||
|
% ml_mlse_results.metrics.EVM = NaN;
|
||||||
|
% ml_mlse_results.metrics.EVM_level = NaN;
|
||||||
|
% ml_mlse_results.metrics.Alpha = NaN;
|
||||||
|
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
%% Helper Functions
|
||||||
|
function [bits, errors, ber, error_pos, errors_precoded, ber_precoded] = calculateBER(eq_signal_hd, tx_symbols, tx_bits, precode_mode, M, eth_style)
|
||||||
|
% Calculate BER based on precoding mode
|
||||||
|
mapper = PAMmapper(M, 0, "eth_style", eth_style);
|
||||||
|
|
||||||
|
switch precode_mode
|
||||||
|
case db_mode.no_db
|
||||||
|
% TX Data is not precoded
|
||||||
|
% A) Emulate diff precoding
|
||||||
|
eq_signal_hd_precoded = Duobinary().encode(eq_signal_hd, "M", M);
|
||||||
|
eq_signal_hd_precoded = Duobinary().decode(eq_signal_hd_precoded, "M", M);
|
||||||
|
|
||||||
|
tx_symbols_precoded = Duobinary().encode(tx_symbols);
|
||||||
|
tx_symbols_precoded = Duobinary().decode(tx_symbols_precoded);
|
||||||
|
|
||||||
|
tx_bits_precoded = mapper.demap(tx_symbols_precoded);
|
||||||
|
|
||||||
|
rx_bits = mapper.demap(eq_signal_hd_precoded);
|
||||||
|
[~, errors_precoded, ber_precoded, ~] = calc_ber(rx_bits.signal, tx_bits_precoded.signal, "skip_front", 30000, "skip_end", 150, "returnErrorLocation", 1);
|
||||||
|
|
||||||
|
% B) Just determine BER
|
||||||
|
rx_bits = mapper.demap(eq_signal_hd);
|
||||||
|
[bits, errors, ber, error_pos] = calc_ber(rx_bits.signal, tx_bits.signal, "skip_front", 30000, "skip_end", 150, "returnErrorLocation", 1);
|
||||||
|
|
||||||
|
case db_mode.db_precoded
|
||||||
|
% Data is precoded on TX side
|
||||||
|
% A) Decode at Rx if no DB targeting was applied
|
||||||
|
eq_signal_hd_decoded = Duobinary().encode(eq_signal_hd, "M", M);
|
||||||
|
eq_signal_hd_decoded = Duobinary().decode(eq_signal_hd_decoded, "M", M);
|
||||||
|
rx_bits_decoded = mapper.demap(eq_signal_hd_decoded);
|
||||||
|
[~, errors_precoded, ber_precoded, ~] = calc_ber(rx_bits_decoded.signal, tx_bits.signal, "skip_front", 30000, "skip_end", 150, "returnErrorLocation", 1);
|
||||||
|
|
||||||
|
% B) Omit the Coding by comparing with demapped TX symbol sequence
|
||||||
|
tx_bits_demapped = mapper.demap(tx_symbols);
|
||||||
|
rx_bits = mapper.demap(eq_signal_hd);
|
||||||
|
[bits, errors, ber, error_pos] = calc_ber(rx_bits.signal, tx_bits_demapped.signal, "skip_front", 30000, "skip_end", 150, "returnErrorLocation", 1);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function eq_out = strip_eq(eq_, max_elems)
|
||||||
|
% strip_eq removes all large fields from the ML_MLSE object
|
||||||
|
% eq_out = strip_eq(eq_, max_elems)
|
||||||
|
% max_elems ... maximum number of elements to keep (default = 10)
|
||||||
|
|
||||||
|
if nargin < 2
|
||||||
|
max_elems = 10; % default threshold
|
||||||
|
end
|
||||||
|
|
||||||
|
props = properties(eq_);
|
||||||
|
for i = 1:numel(props)
|
||||||
|
val = eq_.(props{i});
|
||||||
|
if ~isempty(val)
|
||||||
|
% Count total number of elements
|
||||||
|
if numel(val) > max_elems
|
||||||
|
eq_.(props{i}) = [];
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
eq_out = eq_;
|
||||||
|
end
|
||||||
85
Functions/EQ_visuals/show2Dconstellation.m
Normal file
85
Functions/EQ_visuals/show2Dconstellation.m
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
function [symbols_for_lvl,avg_for_lvl] = show2Dconstellation(eq_signal,ref_symbols,options)
|
||||||
|
arguments
|
||||||
|
eq_signal
|
||||||
|
ref_symbols
|
||||||
|
options.fignum (1,1) double = NaN % Default to NaN if not provided
|
||||||
|
options.displayname (1,:) char = '' % Default to an empty string if not provided
|
||||||
|
end
|
||||||
|
|
||||||
|
plot_shit = 1;
|
||||||
|
|
||||||
|
if isa(eq_signal,'Signal')
|
||||||
|
eq_signal = eq_signal.signal;
|
||||||
|
end
|
||||||
|
if isa(ref_symbols,'Signal')
|
||||||
|
ref_symbols = ref_symbols.signal;
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
if plot_shit
|
||||||
|
% Determine the figure number to use or create a new figure
|
||||||
|
if isnan(options.fignum)
|
||||||
|
fig = figure; % Create a new figure and get its handle
|
||||||
|
else
|
||||||
|
fig = figure(options.fignum); % Use the specified figure number
|
||||||
|
clf;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
rx_symbols = eq_signal; %./ rms(eq_signal);
|
||||||
|
correct_symbols = ref_symbols;
|
||||||
|
|
||||||
|
col = cbrewer2('Paired',numel(unique(correct_symbols))*2);
|
||||||
|
ccnt = -1;
|
||||||
|
|
||||||
|
levels = unique(correct_symbols);
|
||||||
|
M = numel(levels);
|
||||||
|
symbols_for_lvl = NaN(numel(levels),length(correct_symbols));
|
||||||
|
start = 1;
|
||||||
|
ende = length(correct_symbols);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
for l = 1:numel(levels)
|
||||||
|
ccnt = ccnt+2;
|
||||||
|
|
||||||
|
level_amplitude = levels(l);
|
||||||
|
|
||||||
|
symbols_for_lvl(l,correct_symbols==level_amplitude) = rx_symbols(correct_symbols==level_amplitude);
|
||||||
|
|
||||||
|
statistical_mean(l) = mean(symbols_for_lvl(l,:),'omitnan');
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
tx_even = correct_symbols(1:2:end);
|
||||||
|
tx_odd = correct_symbols(2:2:end);
|
||||||
|
|
||||||
|
rx_even = rx_symbols(1:2:end);
|
||||||
|
rx_odd = rx_symbols(2:2:end);
|
||||||
|
|
||||||
|
D_even = tx_even - rx_even;
|
||||||
|
D_odd = tx_odd - rx_odd;
|
||||||
|
|
||||||
|
D = sqrt(D_even.^2 + D_odd.^2);
|
||||||
|
|
||||||
|
[X,Y] = meshgrid(levels, levels);
|
||||||
|
[X_,Y_] = meshgrid(statistical_mean, statistical_mean);
|
||||||
|
|
||||||
|
hold on;
|
||||||
|
scatter(rx_even,rx_odd,5*ones(1,length(D)),D,'.','DisplayName',['Even/Odd PAM-',num2str(M)],'MarkerEdgeColor',col(2,:));
|
||||||
|
% colormap(gca,flip(cbrewer2('Spectral',100)))
|
||||||
|
colormap(gca,'hsv');
|
||||||
|
scatter(X_(:), Y_(:), 2, 'x', 'LineWidth', 10, 'MarkerEdgeColor', col(6,:),'DisplayName','Statistical Rx Levels');
|
||||||
|
scatter(X(:), Y(:), 2, 'x', 'LineWidth', 10, 'MarkerEdgeColor', col(4,:),'DisplayName','Tx Levels');
|
||||||
|
xlim([floor(min(X_(:)))-1, ceil(max(X_(:)))+1]);
|
||||||
|
ylim([floor(min(Y_(:)))-1, ceil(max(Y_(:)))+1]);
|
||||||
|
|
||||||
|
yticks((levels(1:end-1) + levels(2:end)) / 2);
|
||||||
|
xticks((levels(1:end-1) + levels(2:end)) / 2);
|
||||||
|
legend
|
||||||
|
xlabel('even symbols');
|
||||||
|
ylabel('odd symbols');
|
||||||
|
axis equal; grid on;
|
||||||
|
end
|
||||||
114
Functions/Job_Processing/loadAndSyncSignalDataFromDb.m
Normal file
114
Functions/Job_Processing/loadAndSyncSignalDataFromDb.m
Normal file
@@ -0,0 +1,114 @@
|
|||||||
|
function [Bits, Symbols, Scpe_cell, found_sync] = loadAndSyncSignalDataFromDb(dataTable, options)
|
||||||
|
% LOADSIGNALDATA Loads and synchronizes signal data from storage
|
||||||
|
%
|
||||||
|
% Inputs:d
|
||||||
|
% dataTable - Table with file paths and configuration
|
||||||
|
% options - Struct with storage_path and max_occurences
|
||||||
|
%
|
||||||
|
% Outputs:
|
||||||
|
% Symbols_mapped - Mapped symbols from bits
|
||||||
|
% Symbols - Original symbols
|
||||||
|
% Scpe_cell - Cell array of synchronized signals
|
||||||
|
% found_sync - Boolean indicating if synchronization was successful
|
||||||
|
|
||||||
|
found_sync = 0;
|
||||||
|
tempLocalStorage = 1;
|
||||||
|
|
||||||
|
% Define the fixed storage directory relative to the user's MATLAB preferences directory
|
||||||
|
storage_dir = fullfile(prefdir, 'temp_sync_data');
|
||||||
|
|
||||||
|
% Part A: Check and load from local storage if available-
|
||||||
|
if tempLocalStorage == 1
|
||||||
|
local_filename = fullfile(storage_dir, sprintf('sync_data_run_%s.mat', num2str(dataTable.run_id)));
|
||||||
|
if exist(local_filename, 'file')
|
||||||
|
% Load from local storage and return
|
||||||
|
try
|
||||||
|
load(local_filename, 'Bits', 'Symbols', 'Scpe_cell');
|
||||||
|
found_sync = 1;
|
||||||
|
return
|
||||||
|
catch
|
||||||
|
delete(local_filename);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
% If not locally saved, load from storage
|
||||||
|
if ~found_sync
|
||||||
|
% Load transmitted bits
|
||||||
|
Bits = load(fullfile([options.storage_path, char(dataTable.tx_bits_path)]));
|
||||||
|
Bits = Bits.Bits;
|
||||||
|
|
||||||
|
% Map bits to symbols
|
||||||
|
M = double(dataTable.pam_level);
|
||||||
|
fsym = dataTable.symbolrate;
|
||||||
|
Symbols_mapped = PAMmapper(M,0).map(Bits);
|
||||||
|
Symbols_mapped.fs = fsym;
|
||||||
|
|
||||||
|
% Load original symbols
|
||||||
|
Symbols = load(fullfile([options.storage_path, char(dataTable.tx_symbols_path)]));
|
||||||
|
Symbols = Symbols.Symbols;
|
||||||
|
|
||||||
|
found_sync = 0;
|
||||||
|
Scpe_cell = {};
|
||||||
|
|
||||||
|
% Try to load pre-synchronized data
|
||||||
|
try
|
||||||
|
Scpe_load = load(fullfile([options.storage_path, char(dataTable.rx_sync_path)]));
|
||||||
|
Scpe_cell = Scpe_load.S;
|
||||||
|
[~,~,~,found_sync] = Scpe_cell{2}.tsynch("reference", Symbols, "fs_ref", fsym, "debug_plots", 1);
|
||||||
|
catch
|
||||||
|
% Continue to next method if this fails
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
% If not found, try with raw data
|
||||||
|
if ~found_sync
|
||||||
|
try
|
||||||
|
Scpe_sig_raw = load([options.storage_path, char(dataTable.rx_raw_path(1))]);
|
||||||
|
Scpe_sig_raw = Scpe_sig_raw.Scpe_sig_raw;
|
||||||
|
Scpe_sig_resampled = Scpe_sig_raw.resample("fs_in", Scpe_sig_raw.fs, "fs_out", 2*fsym);
|
||||||
|
[~, Scpe_cell, ~, found_sync] = Scpe_sig_resampled.tsynch("reference", Symbols, "fs_ref", fsym, "debug_plots", 1);
|
||||||
|
catch
|
||||||
|
% Continue to next method if this fails
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
% Last attempt with mapped symbols
|
||||||
|
if ~found_sync && exist('Scpe_sig_raw', 'var')
|
||||||
|
if length(Symbols_mapped.signal) ~= sum(Symbols_mapped.signal == Symbols.signal)
|
||||||
|
[~, Scpe_cell, ~, found_sync] = Scpe_sig_raw.tsynch("reference", Symbols_mapped, "fs_ref", fsym, "debug_plots", 0);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
% Part B: Save to local storage if data was loaded and synced
|
||||||
|
if tempLocalStorage == 1 && found_sync
|
||||||
|
% Create directory if it doesn't exist
|
||||||
|
if ~exist(storage_dir, 'dir')
|
||||||
|
mkdir(storage_dir);
|
||||||
|
end
|
||||||
|
|
||||||
|
% local_filename = fullfile(storage_dir, sprintf('sync_data_run_%s.mat', num2str(dataTable.run_id)));
|
||||||
|
|
||||||
|
% List existing files and remove oldest if more than N
|
||||||
|
max_local_files = 10; % Store up to N files
|
||||||
|
files = dir(fullfile(storage_dir, 'sync_data_run_*.mat'));
|
||||||
|
if length(files) >= max_local_files
|
||||||
|
% Sort by date
|
||||||
|
[~, idx] = sort([files.datenum]);
|
||||||
|
% Delete oldest file
|
||||||
|
delete(fullfile(storage_dir, files(idx(1)).name));
|
||||||
|
end
|
||||||
|
|
||||||
|
% Save current data
|
||||||
|
save(local_filename, 'Bits', 'Symbols', 'Scpe_cell');
|
||||||
|
end
|
||||||
|
|
||||||
|
% Limit number of occurrences
|
||||||
|
if found_sync
|
||||||
|
record_realizations = min(options.max_occurences, length(Scpe_cell));
|
||||||
|
Scpe_cell = Scpe_cell(1:record_realizations);
|
||||||
|
else
|
||||||
|
warning('Could not synchronize the received signal with the stored symbols!');
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
32
Functions/Job_Processing/preprocessSignal.m
Normal file
32
Functions/Job_Processing/preprocessSignal.m
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
function Scpe_sig = preprocessSignal(Scpe_sig, Symbols, fsym)
|
||||||
|
% PREPROCESSSIGNAL Performs standard preprocessing on a signal
|
||||||
|
%
|
||||||
|
% Inputs:
|
||||||
|
% Scpe_sig - Input signal
|
||||||
|
% Symbols - Reference symbols for synchronization
|
||||||
|
% fsym - Symbol frequency
|
||||||
|
%
|
||||||
|
% Outputs:
|
||||||
|
% Scpe_sig - Preprocessed signal
|
||||||
|
|
||||||
|
% Resample to 2x symbol rate
|
||||||
|
Scpe_sig = Scpe_sig.resample("fs_out", 2*fsym);
|
||||||
|
|
||||||
|
% Synchronize with reference
|
||||||
|
[Scpe_sig, ~] = Scpe_sig.tsynch("reference", Symbols, "fs_ref", fsym, "debug_plots", 0);
|
||||||
|
|
||||||
|
% Apply Gaussian filter
|
||||||
|
if 1
|
||||||
|
Scpe_sig = Filter('filtdegree', 8, "f_cutoff", Symbols.fs.*0.52, ...
|
||||||
|
"fs", Scpe_sig.fs, "filterType", filtertypes.gaussian, ...
|
||||||
|
"active", true).process(Scpe_sig);
|
||||||
|
else
|
||||||
|
Scpe_sig = Filter('filtdegree', 4, "f_cutoff", Symbols.fs.*0.6, ...
|
||||||
|
"fs", Scpe_sig.fs, "filterType", filtertypes.gaussian, ...
|
||||||
|
"active", true).process(Scpe_sig);
|
||||||
|
end
|
||||||
|
|
||||||
|
%Remove DC offset
|
||||||
|
Scpe_sig = Scpe_sig - mean(Scpe_sig.signal);
|
||||||
|
|
||||||
|
end
|
||||||
47
Functions/Job_Processing/printResults.m
Normal file
47
Functions/Job_Processing/printResults.m
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
function printResults(run_id, M, Symbols, vnle_pf_package, dbtgt_package, occ)
|
||||||
|
% PRINTRESULTS Prints formatted results from equalization
|
||||||
|
%
|
||||||
|
% Inputs:
|
||||||
|
% run_id - Run identifier
|
||||||
|
% M - PAM level
|
||||||
|
% Symbols - Symbol data with fs property
|
||||||
|
% vnle_pf_package - VNLE+PF results package
|
||||||
|
% dbtgt_package - DB target results package (optional)
|
||||||
|
% occ - Occurrence index
|
||||||
|
|
||||||
|
% Print header
|
||||||
|
fprintf("==== EQUALIZATION RUN-ID %d | PAM-%d | %.2f GBd ====\n\n", run_id, M, Symbols.fs.*1e-9);
|
||||||
|
|
||||||
|
% VNLE Results
|
||||||
|
if ~isempty(vnle_pf_package)
|
||||||
|
vnle_result = vnle_pf_package{occ}.resultsVNLE;
|
||||||
|
mlse_result = vnle_pf_package{occ}.resultsMLSE;
|
||||||
|
|
||||||
|
fprintf(">> VNLE Results:\n");
|
||||||
|
fprintf(" BER: %.2e\n", vnle_result.BER);
|
||||||
|
fprintf(" BER (pre-code): %.2e\n", vnle_result.BER_precoded);
|
||||||
|
fprintf(" SNR: %.2f dB\n", vnle_result.SNR);
|
||||||
|
fprintf(" GMI: %.4f\n", vnle_result.GMI);
|
||||||
|
fprintf(" Linerate: %.2f Gbps\n", Symbols.fs .* floor(log2(M)*10)/10 .*1e-9);
|
||||||
|
fprintf(" AIR: %.2f Gbps\n", vnle_result.AIR.*1e-9);
|
||||||
|
fprintf("\n");
|
||||||
|
|
||||||
|
% MLSE Results
|
||||||
|
fprintf(">> MLSE Results:\n");
|
||||||
|
fprintf(" BER: %.2e\n", mlse_result.BER);
|
||||||
|
fprintf(" BER (pre-code): %.2e\n", mlse_result.BER_precoded);
|
||||||
|
fprintf(" Channel Alpha: %.2f\n", mlse_result.Alpha);
|
||||||
|
fprintf("\n");
|
||||||
|
end
|
||||||
|
|
||||||
|
% DB Target Results
|
||||||
|
if ~isempty(dbtgt_package)
|
||||||
|
dbtgt = dbtgt_package{occ}.resultsDBtgt;
|
||||||
|
fprintf(">> DB Target Results:\n");
|
||||||
|
fprintf(" BER: %.2e\n", dbtgt.BER);
|
||||||
|
fprintf(" BER (pre-code): %.2e\n", dbtgt.BER_precoded);
|
||||||
|
fprintf("\n");
|
||||||
|
end
|
||||||
|
|
||||||
|
fprintf("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \n\n");
|
||||||
|
end
|
||||||
11
Functions/Job_Processing/queryRunid.m
Normal file
11
Functions/Job_Processing/queryRunid.m
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
function dataTable = queryRunid(run_id, database)
|
||||||
|
|
||||||
|
% Query database for run configuration
|
||||||
|
filterParams = database.tables;
|
||||||
|
filterParams.Runs = struct('run_id', run_id);
|
||||||
|
|
||||||
|
[dataTable, ~] = database.queryDB(filterParams, database.getTableFieldNames('Runs'));
|
||||||
|
[~, uniqueIdx] = unique(dataTable.run_id); % Get unique run_id indices
|
||||||
|
dataTable = dataTable(uniqueIdx, :); % Extract unique configurations for each run_id
|
||||||
|
|
||||||
|
end
|
||||||
235
Functions/Job_Processing/submitJobs.m
Normal file
235
Functions/Job_Processing/submitJobs.m
Normal file
@@ -0,0 +1,235 @@
|
|||||||
|
function [results, wh] = submitJobs(run_ids, dsp_options, submit_mode, submit_options)
|
||||||
|
% SUBMITJOBS Submits dsp_runid jobs for processing (parallel or serial)
|
||||||
|
%
|
||||||
|
% [results, wh] = submitJobs(run_ids, dsp_options, submit_mode, submit_options)
|
||||||
|
%
|
||||||
|
% run_ids : scalar or vector of run IDs
|
||||||
|
% dsp_options : struct of dsp_runid name/value options
|
||||||
|
% submit_mode : processingMode.parallel or .serial
|
||||||
|
% submit_options : struct with fields
|
||||||
|
% .waitbar (logical)
|
||||||
|
% .wh (DataStorage object)
|
||||||
|
%
|
||||||
|
% results : cell(nJobsPerRunId, nRunIds)
|
||||||
|
% wh : updated DataStorage
|
||||||
|
|
||||||
|
arguments
|
||||||
|
run_ids int32 = 0
|
||||||
|
dsp_options struct = struct()
|
||||||
|
submit_mode processingMode = processingMode.serial
|
||||||
|
submit_options.waitbar (1,1) logical = true
|
||||||
|
submit_options.wh = DataStorage(struct())
|
||||||
|
end
|
||||||
|
|
||||||
|
% Normalize
|
||||||
|
run_ids = run_ids(:)';
|
||||||
|
nRunIds = numel(run_ids);
|
||||||
|
nJobsPerRunId = submit_options.wh.getLastLinIndice();
|
||||||
|
totalJobs = nRunIds * nJobsPerRunId;
|
||||||
|
|
||||||
|
% Preallocate
|
||||||
|
results = cell(nJobsPerRunId, nRunIds);
|
||||||
|
futures = parallel.FevalFuture.empty(totalJobs,0);
|
||||||
|
jobIndices = zeros(totalJobs,2);
|
||||||
|
|
||||||
|
% Optional waitbar
|
||||||
|
if submit_options.waitbar
|
||||||
|
h = waitbar(0, 'Processing Jobs...');
|
||||||
|
cleanupObj = onCleanup(@() delete(h));
|
||||||
|
end
|
||||||
|
|
||||||
|
switch submit_mode
|
||||||
|
case processingMode.parallel
|
||||||
|
%—– SET UP POOL & QUEUE —–
|
||||||
|
p = setupParallelPool(11, 300); % 10 workers, 300s idle timeout
|
||||||
|
|
||||||
|
% === submit all futures ===
|
||||||
|
jobCounter = 0;
|
||||||
|
for r = 1:nRunIds
|
||||||
|
for k = 1:nJobsPerRunId
|
||||||
|
jobCounter = jobCounter + 1;
|
||||||
|
jobIndices(jobCounter,:) = [r,k];
|
||||||
|
|
||||||
|
opt = buildOptionalVars(k, submit_options.wh);
|
||||||
|
futures(jobCounter) = parfeval( ...
|
||||||
|
p, @dsp_runid, 1, ...
|
||||||
|
run_ids(r), ...
|
||||||
|
"database_type", dsp_options.database_type, ...
|
||||||
|
"dataBase", dsp_options.dataBase, ...
|
||||||
|
"append_to_db", dsp_options.append_to_db, ...
|
||||||
|
"load_file_path", dsp_options.load_file_path, ...
|
||||||
|
"max_occurences", dsp_options.max_occurences, ...
|
||||||
|
"storage_path", dsp_options.storage_path, ...
|
||||||
|
"mode", dsp_options.mode, ...
|
||||||
|
"parameters", opt ...
|
||||||
|
);
|
||||||
|
|
||||||
|
fprintf('[RunID %d, Job %d] Submitted to pool.\n', run_ids(r), k);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
%—– W A I T B A R U P D A T E —–
|
||||||
|
if submit_options.waitbar
|
||||||
|
futureArray = futures;
|
||||||
|
updateWB = @() waitbar( ...
|
||||||
|
sum(arrayfun(@(f) strcmp(f.State,'finished'), futureArray))/totalJobs, ...
|
||||||
|
h, sprintf('Completed %d/%d jobs', ...
|
||||||
|
sum(arrayfun(@(f) strcmp(f.State,'finished'), futureArray)), totalJobs) ...
|
||||||
|
);
|
||||||
|
afterEach(futureArray, updateWB, 0);
|
||||||
|
end
|
||||||
|
|
||||||
|
% —– before the loop —–
|
||||||
|
% Keep track of which futures we've already handled:
|
||||||
|
consumedIdx = false(totalJobs,1);
|
||||||
|
|
||||||
|
% —– fetch in completion order, handling successes and errors —–
|
||||||
|
for n = 1:totalJobs
|
||||||
|
try
|
||||||
|
% This returns the value AND the linear index in 'futures'
|
||||||
|
[idx, val] = fetchNext(futures);
|
||||||
|
|
||||||
|
duration = futures(idx).RunningDuration;
|
||||||
|
startDT = futures(idx).StartDateTime;
|
||||||
|
finishDT = futures(idx).FinishDateTime;
|
||||||
|
duration = finishDT - startDT;
|
||||||
|
|
||||||
|
% Mark it consumed
|
||||||
|
consumedIdx(idx) = true;
|
||||||
|
|
||||||
|
% Map back to (r,k) and store
|
||||||
|
r = jobIndices(idx,1);
|
||||||
|
k = jobIndices(idx,2);
|
||||||
|
|
||||||
|
fprintf('[%s] JobID %d/%d (%.1f%%) — %s — RunID %d — Subjob %d — fetched.\n', ...
|
||||||
|
datestr(now,'yyyy-mm-dd HH:MM:SS'), ...
|
||||||
|
r, totalJobs, 100*n/totalJobs,char(duration), ...
|
||||||
|
run_ids(r), k);
|
||||||
|
|
||||||
|
% Update waitbar
|
||||||
|
if submit_options.waitbar
|
||||||
|
waitbar(n/totalJobs, h, ...
|
||||||
|
sprintf('Fetched %d/%d (%.1f% Percent)', n, totalJobs, 100*n/totalJobs));
|
||||||
|
drawnow; % force the GUI to refresh
|
||||||
|
end
|
||||||
|
|
||||||
|
storeResult(val, k, submit_options.wh);
|
||||||
|
results{k,r} = val;
|
||||||
|
|
||||||
|
catch fetchErr
|
||||||
|
% fetchNext has already set Read=true on the errored future.
|
||||||
|
% Find the one Read==true that we have _not_ yet consumed.
|
||||||
|
readMask = arrayfun(@(f) f.Read, futures);
|
||||||
|
idxErr = find(readMask & ~consumedIdx', 1);
|
||||||
|
consumedIdx(idxErr) = true;
|
||||||
|
|
||||||
|
% Pull the _real_ exception out of the future object
|
||||||
|
errInfo = futures(idxErr).Error;
|
||||||
|
if iscell(errInfo)
|
||||||
|
origME = errInfo{1};
|
||||||
|
else
|
||||||
|
origME = errInfo;
|
||||||
|
end
|
||||||
|
|
||||||
|
% Map back to (r,k) and log
|
||||||
|
r = jobIndices(idxErr,1);
|
||||||
|
k = jobIndices(idxErr,2);
|
||||||
|
handleError(origME, k, run_ids(r));
|
||||||
|
results{k,r} = origME;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
case processingMode.serial
|
||||||
|
%—– SERIAL EXECUTION —–
|
||||||
|
jobCounter = 0;
|
||||||
|
for r = 1:nRunIds
|
||||||
|
for k = 1:nJobsPerRunId
|
||||||
|
jobCounter = jobCounter + 1;
|
||||||
|
optionalVars = buildOptionalVars(k, submit_options.wh);
|
||||||
|
try
|
||||||
|
fprintf('[RunID %d, Job %d] Running in linear mode...\n', run_ids(r), k);
|
||||||
|
val = dsp_runid( run_ids(r), ...
|
||||||
|
"database_type", dsp_options.database_type, ...
|
||||||
|
"dataBase", dsp_options.dataBase, ...
|
||||||
|
"append_to_db", dsp_options.append_to_db, ...
|
||||||
|
"load_file_path", dsp_options.load_file_path, ...
|
||||||
|
"max_occurences", dsp_options.max_occurences, ...
|
||||||
|
"storage_path", dsp_options.storage_path, ...
|
||||||
|
"mode", dsp_options.mode, ...
|
||||||
|
"parameters", optionalVars );
|
||||||
|
|
||||||
|
fprintf('[RunID %d, Job %d] Completed successfully.\n', run_ids(r), k);
|
||||||
|
storeResult(val, k, submit_options.wh);
|
||||||
|
results{k,r} = val;
|
||||||
|
|
||||||
|
catch ME
|
||||||
|
handleError(ME, k, run_ids(r));
|
||||||
|
results{k,r} = ME;
|
||||||
|
end
|
||||||
|
|
||||||
|
if submit_options.waitbar
|
||||||
|
waitbar(jobCounter/totalJobs, h, ...
|
||||||
|
sprintf('Completed %d/%d jobs', jobCounter, totalJobs));
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
otherwise
|
||||||
|
error('Unknown submit_mode "%s".', string(submit_mode))
|
||||||
|
end
|
||||||
|
|
||||||
|
wh = submit_options.wh;
|
||||||
|
|
||||||
|
%% Local helpers %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
||||||
|
function handleError(ME, jobIndex, run_id)
|
||||||
|
fprintf('[RunID %d, Job %d] ERROR [%s]: %s\n', run_id, jobIndex, ...
|
||||||
|
ME.identifier, ME.message);
|
||||||
|
for st = ME.stack'
|
||||||
|
fprintf(' %s:%d (%s)\n', st.file, st.line, st.name);
|
||||||
|
end
|
||||||
|
fprintf('Full report:\n%s\n', getReport(ME,'extended'));
|
||||||
|
end
|
||||||
|
|
||||||
|
function optionalVars = buildOptionalVars(jobIndex, wh)
|
||||||
|
optionalVars = struct();
|
||||||
|
if ~isempty(wh.getDimension())
|
||||||
|
[vals, names] = wh.getPhysIndicesByLinIndex(jobIndex);
|
||||||
|
for pi = 1:numel(names)
|
||||||
|
optionalVars.(names{pi}) = vals{pi};
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function storeResult(val, jobIndex, wh)
|
||||||
|
if ~isempty(wh)
|
||||||
|
wh.addValueToStorageByLinIdx(val.ffe_package, 'ffe_package', jobIndex);
|
||||||
|
wh.addValueToStorageByLinIdx(val.mlse_package, 'mlse_package', jobIndex);
|
||||||
|
wh.addValueToStorageByLinIdx(val.vnle_package, 'vnle_package', jobIndex);
|
||||||
|
wh.addValueToStorageByLinIdx(val.dbtgt_package,'dbtgt_package',jobIndex);
|
||||||
|
wh.addValueToStorageByLinIdx(val.dbenc_package,'dbenc_package',jobIndex);
|
||||||
|
wh.addValueToStorageByLinIdx(val.mlmlse_package,'mlmlse_package',jobIndex);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
function p = setupParallelPool(numWorkers, idleTimeout)
|
||||||
|
% Ensure a pool exists at the right size & timeout
|
||||||
|
p = gcp('nocreate');
|
||||||
|
if isempty(p) || p.NumWorkers~=numWorkers
|
||||||
|
if ~isempty(p)
|
||||||
|
delete(p);
|
||||||
|
end
|
||||||
|
p = parpool('local', numWorkers, 'IdleTimeout', idleTimeout);
|
||||||
|
end
|
||||||
|
|
||||||
|
% Cancel anything left in the pool's default queue
|
||||||
|
q = p.FevalQueue;
|
||||||
|
if ~isempty(q.QueuedFutures) || ~isempty(q.RunningFutures)
|
||||||
|
cancelAll(q);
|
||||||
|
fprintf('Canceled %d unfetched jobs from old queue.\n', ...
|
||||||
|
numel(q.QueuedFutures)+numel(q.RunningFutures));
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
end
|
||||||
158
Functions/Metrics/calc_gmi_bitwise.m
Normal file
158
Functions/Metrics/calc_gmi_bitwise.m
Normal file
@@ -0,0 +1,158 @@
|
|||||||
|
function [GMI,NGMI] = calc_gmi_bitwise(test_signal,reference_signal,options)
|
||||||
|
% https://cioffi-group.stanford.edu/doc/book/AppendixG.pdf
|
||||||
|
% Supports PAM2/4/8 (per-symbol) and PAM6 (pairwise: 5 bits per 2 symbols)
|
||||||
|
|
||||||
|
arguments(Input)
|
||||||
|
test_signal
|
||||||
|
reference_signal
|
||||||
|
options.skip_front (1,1) double = 0
|
||||||
|
options.skip_end (1,1) double = 0
|
||||||
|
options.returnErrorLocation (1,1) double = 0 %#ok<NASGU>
|
||||||
|
end
|
||||||
|
|
||||||
|
options.skip_end = abs(options.skip_end);
|
||||||
|
options.skip_front = abs(options.skip_front);
|
||||||
|
assert((options.skip_end+options.skip_front) < numel(test_signal), ...
|
||||||
|
"You can not skip more samples than overall length.");
|
||||||
|
|
||||||
|
if isa(reference_signal,'Signal'); reference_signal = reference_signal.signal; end
|
||||||
|
if isa(test_signal,'Signal'); test_signal = test_signal.signal; end
|
||||||
|
|
||||||
|
% TRIM
|
||||||
|
[test_signal,reference_signal] = trimseq(test_signal,reference_signal,options.skip_front,options.skip_end);
|
||||||
|
|
||||||
|
% Common precompute
|
||||||
|
N = length(test_signal);
|
||||||
|
M = numel(unique(reference_signal));
|
||||||
|
noise = test_signal - reference_signal;
|
||||||
|
sigma2 = var(noise); % real AWGN variance
|
||||||
|
|
||||||
|
% --- Constellation (levels observed)
|
||||||
|
constellation = unique(reference_signal);
|
||||||
|
M = numel(constellation);
|
||||||
|
|
||||||
|
% --- Empirical P_X (uniform is fine too; keep your original behavior)
|
||||||
|
N = numel(reference_signal);
|
||||||
|
counts = arrayfun(@(c) sum(reference_signal==c), constellation);
|
||||||
|
priors = counts / N;
|
||||||
|
|
||||||
|
% ----- PAM6: 5 bits mapped to 2 consecutive symbols (36 transitions) -----
|
||||||
|
if M == 6
|
||||||
|
% Pair the stream (drop last if odd)
|
||||||
|
numPairs = floor(N/2);
|
||||||
|
if numPairs == 0, GMI = 0; NGMI = 0; return; end
|
||||||
|
|
||||||
|
y1 = test_signal(1:2:2*numPairs);
|
||||||
|
y2 = test_signal(2:2:2*numPairs);
|
||||||
|
|
||||||
|
% Use the same level order as PAMmapper to be consistent with labeling
|
||||||
|
levels = constellation;%PAMmapper(6,0,"eth_style",0).levels; % 1x6 (actual amplitudes used)
|
||||||
|
% Build all 36 transitions (i,j)
|
||||||
|
[S1,S2] = ndgrid(levels, levels); % 6x6
|
||||||
|
trans_pairs = [S1(:), S2(:)]; % 36x2
|
||||||
|
|
||||||
|
% 5-bit labels for each transition (ETH style).
|
||||||
|
% NOTE: keep the normalization you use with your PAMmapper (often /sqrt(10)).
|
||||||
|
bits72 = PAMmapper(6,0,"eth_style",0).demap( reshape(trans_pairs.',[],1) );
|
||||||
|
pairBits = reshape(bits72.', 5, []).'; % 36 x 5
|
||||||
|
|
||||||
|
% Transmitted 5-bit labels for each observed pair (from the reference)
|
||||||
|
tx_bits_pair = PAMmapper(6,0,"eth_style",0).demap( reshape(reference_signal(1:2* numPairs).',[],1) );
|
||||||
|
tx_bits_pair = reshape(tx_bits_pair.', 5, []).'; % numPairs x 5
|
||||||
|
|
||||||
|
% Precompute symbol log-priors (uniform => constant; included for shaped inputs)
|
||||||
|
logP = log(priors);
|
||||||
|
|
||||||
|
% Precompute masks for bit=0 / bit=1 in the 6x6 grid
|
||||||
|
mask1 = false(6,6,5);
|
||||||
|
mask0 = false(6,6,5);
|
||||||
|
for b = 1:5
|
||||||
|
tmp = false(6,6);
|
||||||
|
tmp(:) = pairBits(:,b)==1;
|
||||||
|
mask1(:,:,b) = tmp;
|
||||||
|
tmp = false(6,6);
|
||||||
|
tmp(:) = pairBits(:,b)==0;
|
||||||
|
mask0(:,:,b) = tmp;
|
||||||
|
end
|
||||||
|
|
||||||
|
% Exact LLRs via log-sum-exp over the 6x6 grid
|
||||||
|
LLR = zeros(numPairs,5);
|
||||||
|
cst = -0.5*log(2*pi*sigma2); % cancels in LLR but harmless
|
||||||
|
for k = 1:numPairs
|
||||||
|
li = cst - ((y1(k) - levels).^2)/(2*sigma2) + logP; % 1x6
|
||||||
|
lj = cst - ((y2(k) - levels).^2)/(2*sigma2) + logP; % 1x6
|
||||||
|
logW = li(:) + lj(:).'; % 6x6 (adds logP twice)
|
||||||
|
|
||||||
|
for b = 1:5
|
||||||
|
L1 = logsumexp(logW(mask1(:,:,b)));
|
||||||
|
L0 = logsumexp(logW(mask0(:,:,b)));
|
||||||
|
LLR(k,b) = L1 - L0; % natural-log LLR
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
% Bit-wise MI using consistency relation
|
||||||
|
MI_bits = zeros(1,5);
|
||||||
|
for b = 1:5
|
||||||
|
idx0 = (tx_bits_pair(:,b)==0);
|
||||||
|
idx1 = ~idx0;
|
||||||
|
r0 = LLR(idx0,b);
|
||||||
|
r1 = LLR(idx1,b);
|
||||||
|
I0 = mean( log2(1 + exp( r0)) ); % natural LLR inside exp()
|
||||||
|
I1 = mean( log2(1 + exp(-r1)) );
|
||||||
|
MI_bits(b) = 1 - 0.5*(I0 + I1);
|
||||||
|
end
|
||||||
|
|
||||||
|
% Per-symbol outputs (5 bits per 2 symbols)
|
||||||
|
GMI = sum(MI_bits)/2;
|
||||||
|
NGMI = GMI / 2.5;
|
||||||
|
|
||||||
|
% ----- Generic PAM2/4/8…: per-symbol, Gray bits directly on symbols -----
|
||||||
|
else
|
||||||
|
nBits = log2(M);
|
||||||
|
levels = PAMmapper(M,0).levels' / PAMmapper(M,0).scaling; % match PAMmapper ordering
|
||||||
|
grayBits= PAMmapper(M,0).showBitMapping; % M x nBits
|
||||||
|
|
||||||
|
% Allocate
|
||||||
|
LLR = zeros(N, nBits);
|
||||||
|
|
||||||
|
for n = 1:N
|
||||||
|
y = test_signal(n);
|
||||||
|
ll_table = -((y - levels).^2)/(2*sigma2) + log(priors); % 1xM (log-domain)
|
||||||
|
for b = 1:nBits
|
||||||
|
idx0 = grayBits(:,b)==0;
|
||||||
|
idx1 = ~idx0;
|
||||||
|
L0 = logsumexp(ll_table(idx0));
|
||||||
|
L1 = logsumexp(ll_table(idx1));
|
||||||
|
LLR(n,b) = L1 - L0; % natural-log LLR
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
tx_bits = PAMmapper(M,0,"eth_style",0).demap(reference_signal);
|
||||||
|
|
||||||
|
% Bit-wise MI
|
||||||
|
MI_bits = zeros(1,nBits);
|
||||||
|
for b = 1:nBits
|
||||||
|
r0 = LLR(tx_bits(:,b)==0,b);
|
||||||
|
r1 = LLR(tx_bits(:,b)==1,b);
|
||||||
|
I0 = mean( log2(1 + exp( r0)) );
|
||||||
|
I1 = mean( log2(1 + exp(-r1)) );
|
||||||
|
MI_bits(b) = 1 - 0.5*(I0 + I1);
|
||||||
|
end
|
||||||
|
|
||||||
|
GMI = sum(MI_bits); % bits / symbol
|
||||||
|
NGMI = GMI / nBits;
|
||||||
|
end
|
||||||
|
|
||||||
|
% ===== Helpers =====
|
||||||
|
function s = logsumexp(a)
|
||||||
|
if isempty(a), s = -inf; return; end
|
||||||
|
m = max(a(:));
|
||||||
|
s = m + log(sum(exp(a(:) - m)));
|
||||||
|
end
|
||||||
|
|
||||||
|
function [data_,reference_] = trimseq(data,reference,skipstart,skip_end)
|
||||||
|
data_ = data(skipstart+1:end-skip_end,:);
|
||||||
|
delta = numel(reference) - numel(data_);
|
||||||
|
reference_ = reference(skipstart+1:end-(skip_end+delta),:);
|
||||||
|
end
|
||||||
|
end
|
||||||
31
Functions/Metrics/count_error_bursts.m
Normal file
31
Functions/Metrics/count_error_bursts.m
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
function burst_count = count_error_bursts(err_pos, max_burst_length)
|
||||||
|
% err_pos: Vector of error positions
|
||||||
|
% max_burst_length: Maximum length for which bursts are counted (e.g., 10)
|
||||||
|
|
||||||
|
% Sort the error positions to ensure they're in increasing order
|
||||||
|
err_pos = sort(err_pos);
|
||||||
|
|
||||||
|
% Initialize burst_count array to hold the counts for each burst length
|
||||||
|
burst_count = zeros(1, max_burst_length);
|
||||||
|
|
||||||
|
% Find the differences between consecutive error positions
|
||||||
|
diffs = diff(err_pos);
|
||||||
|
|
||||||
|
% Find the start of the bursts (where the difference is greater than 1)
|
||||||
|
burst_starts = [1, find(diffs > 1) + 1]; % Starts at index 1 and after gaps
|
||||||
|
burst_ends = [find(diffs > 1), length(err_pos)]; % Ends where gaps are
|
||||||
|
|
||||||
|
% Loop over the bursts
|
||||||
|
for b = 1:length(burst_starts)
|
||||||
|
burst_length = burst_ends(b) - burst_starts(b) + 1;
|
||||||
|
|
||||||
|
% Check if the burst length exceeds any of the thresholds
|
||||||
|
for i = 1:max_burst_length
|
||||||
|
if burst_length == i
|
||||||
|
burst_count(i) = burst_count(i) + 1;
|
||||||
|
else
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
27
Functions/Theory/CCDM/ccdm_gpt_example.m
Normal file
27
Functions/Theory/CCDM/ccdm_gpt_example.m
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
%% Target source entropy for PS-PAM8
|
||||||
|
clear; clc;
|
||||||
|
|
||||||
|
M = 8;
|
||||||
|
a = -(M-1):2:(M-1); % PAM-8 amplitude levels: [-7 -5 -3 -1 1 3 5 7]
|
||||||
|
H_target = 2.79; % desired entropy [bits/symbol]
|
||||||
|
|
||||||
|
% Objective: find nu such that H(PA) = H_target
|
||||||
|
f = @(nu) entropy_MB(a,nu) - H_target;
|
||||||
|
nu_opt = fzero(f, [0, 2]); % search ν in reasonable range
|
||||||
|
|
||||||
|
% Compute final distribution
|
||||||
|
P = exp(-nu_opt*a.^2);
|
||||||
|
P = P/sum(P);
|
||||||
|
H = -sum(P .* log2(P));
|
||||||
|
|
||||||
|
fprintf('Shaping parameter ν = %.4f\n', nu_opt);
|
||||||
|
fprintf('Entropy H(A) = %.3f bits/symbol\n', H);
|
||||||
|
disp('Probability vector (P_A):');
|
||||||
|
disp(P.');
|
||||||
|
|
||||||
|
%% Helper: entropy function
|
||||||
|
function H = entropy_MB(a,nu)
|
||||||
|
P = exp(-nu*a.^2);
|
||||||
|
P = P/sum(P);
|
||||||
|
H = -sum(P .* log2(P));
|
||||||
|
end
|
||||||
64
Functions/Theory/analyze_moving_average_filter.m
Normal file
64
Functions/Theory/analyze_moving_average_filter.m
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
% Parameters
|
||||||
|
N_values = [10 100 1000 4096]; % Different filter lengths to analyze
|
||||||
|
fs = 112e9;
|
||||||
|
|
||||||
|
% Create figure
|
||||||
|
figure;
|
||||||
|
|
||||||
|
% Plot frequency responses
|
||||||
|
subplot(211)
|
||||||
|
hold on
|
||||||
|
grid on
|
||||||
|
ylabel('Magnitude (dB)')
|
||||||
|
title('Frequency Response')
|
||||||
|
yline(-3,'--r')
|
||||||
|
ylim([-40 5])
|
||||||
|
|
||||||
|
subplot(212)
|
||||||
|
hold on
|
||||||
|
grid on
|
||||||
|
xlabel('Frequency (GHz)')
|
||||||
|
ylabel('Phase (rad)')
|
||||||
|
title('Phase Response')
|
||||||
|
|
||||||
|
% Color map for different lines
|
||||||
|
colors = cbrewer2('Set1',length(N_values));
|
||||||
|
|
||||||
|
% Loop through different filter lengths
|
||||||
|
for i = 1:length(N_values)
|
||||||
|
N = N_values(i);
|
||||||
|
|
||||||
|
% Filter coefficients
|
||||||
|
b = ones(1,N)/N;
|
||||||
|
a = 1;
|
||||||
|
|
||||||
|
% Frequency response
|
||||||
|
[h,w] = freqz(b,a,4096*8);
|
||||||
|
freq = (w/(2*pi))*fs;
|
||||||
|
h_db = 20*log10(abs(h));
|
||||||
|
|
||||||
|
% Plot magnitude response
|
||||||
|
subplot(211)
|
||||||
|
plot(freq/1e9, h_db, 'Color', colors(i,:), 'DisplayName', sprintf('N=%d', N),'LineWidth',0.1)
|
||||||
|
|
||||||
|
% Plot phase response
|
||||||
|
subplot(212)
|
||||||
|
plot(freq/1e9, unwrap(angle(h)), 'Color', colors(i,:), 'DisplayName', sprintf('N=%d', N),'LineWidth',0.1)
|
||||||
|
|
||||||
|
% Find -3dB frequency
|
||||||
|
cutoff_idx = find(h_db <= -3, 1);
|
||||||
|
f_cutoff = freq(cutoff_idx)/1e9;
|
||||||
|
fprintf('N=%d: Cutoff frequency (-3dB point): %.2f GHz\n', N, f_cutoff)
|
||||||
|
end
|
||||||
|
|
||||||
|
% Add legend and adjust axes
|
||||||
|
subplot(211)
|
||||||
|
legend('show')
|
||||||
|
xlim([0 16]) % Adjust x-axis limit to better see the differences
|
||||||
|
|
||||||
|
subplot(212)
|
||||||
|
legend('show')
|
||||||
|
xlim([0 16]) % Adjust x-axis limit to better see the differences
|
||||||
|
|
||||||
|
% Analytical approximation
|
||||||
|
f_3db_approx = 0.443 * fs./N_values ./ 1e9;
|
||||||
89
Functions/Theory/dispersion_10km.m
Normal file
89
Functions/Theory/dispersion_10km.m
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
%% ============================================================
|
||||||
|
% IM/DD Fading Notch – λ_null vs. Bandwidth (Fixed 10 km)
|
||||||
|
% ============================================================
|
||||||
|
|
||||||
|
clear; clc;
|
||||||
|
|
||||||
|
%% Fiber and dispersion parameters
|
||||||
|
lambda0 = 1310e-9; % Zero-dispersion wavelength [m]
|
||||||
|
S0 = 0.09; % Dispersion slope at ZDW [ps/(nm²·km)]
|
||||||
|
L = 10e3; % Fiber length [m]
|
||||||
|
c = physconst('lightspeed');
|
||||||
|
|
||||||
|
%% Frequency sweep (defines the desired first-fading notch)
|
||||||
|
f_targets = linspace(40e9, 150e9, 200); % [Hz]
|
||||||
|
f_GHz = f_targets / 1e9;
|
||||||
|
|
||||||
|
%% Compute wavelength λ_null for each target f_null
|
||||||
|
[lambda_vec, Dacc_vec] = lambda_for_first_null_full(f_targets, L, lambda0, S0);
|
||||||
|
lambda_nm = lambda_vec * 1e9; % Convert to nm
|
||||||
|
Dacc = Dacc_vec; % [ps/nm]
|
||||||
|
|
||||||
|
%% ------------------------------------------------------------
|
||||||
|
% Plot λ_null vs. f_null for 10 km fiber
|
||||||
|
% ------------------------------------------------------------
|
||||||
|
cols = cbrewer2('Paired',10);
|
||||||
|
figure('Color','w'); hold on;
|
||||||
|
|
||||||
|
hLine = plot(lambda_nm, f_GHz, ...
|
||||||
|
'LineWidth', 2, ...
|
||||||
|
'DisplayName', sprintf('L = %.1f km', L/1000), ...
|
||||||
|
'Color', cols(2,:));
|
||||||
|
|
||||||
|
xlabel('Wavelength λ [nm]');
|
||||||
|
ylabel('First fading notch f_{null} [GHz]');
|
||||||
|
title('IM/DD Fading Notch Position vs. Wavelength');
|
||||||
|
grid on; box on;
|
||||||
|
|
||||||
|
lim = (lambda0.*1e9) - [8, 40];
|
||||||
|
xlim([lim(2) lim(1)]);
|
||||||
|
yticks([56,75,90,112]);
|
||||||
|
|
||||||
|
%% ------------------------------------------------------------
|
||||||
|
% Custom DataTip Template
|
||||||
|
% ------------------------------------------------------------
|
||||||
|
% Add accumulated dispersion value to the DataTip
|
||||||
|
hLine.DataTipTemplate.DataTipRows(1).Label = 'λ [nm]';
|
||||||
|
hLine.DataTipTemplate.DataTipRows(2).Label = 'f_{null} [GHz]';
|
||||||
|
|
||||||
|
% Create a new row for Dacc
|
||||||
|
dRow = dataTipTextRow('D_{acc} [ps/nm]', Dacc);
|
||||||
|
hLine.DataTipTemplate.DataTipRows(end+1) = dRow;
|
||||||
|
|
||||||
|
%% ------------------------------------------------------------
|
||||||
|
% Helper function: lambda_for_first_null_full
|
||||||
|
% ------------------------------------------------------------
|
||||||
|
function [lambda_vec, Dacc_vec] = lambda_for_first_null_full(f_target, L, lambda0, S0)
|
||||||
|
c = physconst('lightspeed');
|
||||||
|
S0_si = S0 * 1e3; % ps/(nm²·km) -> s/(m³)
|
||||||
|
|
||||||
|
lambda_min = 1260e-9;
|
||||||
|
lambda_max = 1360e-9;
|
||||||
|
|
||||||
|
f_target = f_target(:);
|
||||||
|
N = numel(f_target);
|
||||||
|
|
||||||
|
lambda_vec = zeros(N,1);
|
||||||
|
Dacc_vec = zeros(N,1);
|
||||||
|
|
||||||
|
for k = 1:N
|
||||||
|
RHS = c * 0.5 / (f_target(k)^2 * L);
|
||||||
|
|
||||||
|
fun = @(lambda) -(S0_si/4).*(lambda - (lambda0^4)./(lambda.^3)).*lambda.^2 - RHS;
|
||||||
|
|
||||||
|
try
|
||||||
|
lambda_sol = fzero(fun, [lambda_min, lambda0 * 0.999]);
|
||||||
|
catch
|
||||||
|
lambda_sol = lambda_min;
|
||||||
|
end
|
||||||
|
|
||||||
|
lambda_sol = min(max(lambda_sol, lambda_min), lambda_max);
|
||||||
|
lambda_vec(k) = lambda_sol;
|
||||||
|
|
||||||
|
D_lambda = (S0_si/4) * (lambda_sol - (lambda0^4)/(lambda_sol^3)) / 1e-6; % ps/(nm·km)
|
||||||
|
Dacc_val = D_lambda * (L/1000); % ps/nm
|
||||||
|
Dacc_val = min(max(Dacc_val, -100), 100);
|
||||||
|
|
||||||
|
Dacc_vec(k) = Dacc_val;
|
||||||
|
end
|
||||||
|
end
|
||||||
55
Functions/Theory/dispersion_contour.m
Normal file
55
Functions/Theory/dispersion_contour.m
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
% Gitter für lambda0 und S0
|
||||||
|
lambda0_vec = linspace(1260,1360,200);
|
||||||
|
S0_vec = linspace(0.06,0.1,200);
|
||||||
|
[Lambda0, S0] = meshgrid(lambda0_vec, S0_vec);
|
||||||
|
|
||||||
|
% Festen Betriebsparameter
|
||||||
|
lambda = 1293; % nm
|
||||||
|
L = 1; % km
|
||||||
|
|
||||||
|
% Dispersion berechnen (lineare Näherung)
|
||||||
|
D = S0 .* ( lambda - Lambda0 ) * L;
|
||||||
|
% D = (S0./4) .* ( lambda - (Lambda0.^4)./(lambda^3) ) * L;
|
||||||
|
|
||||||
|
%% 2D-Konturplot nur mit Linien und Text
|
||||||
|
figure('Color','w');
|
||||||
|
hold on
|
||||||
|
|
||||||
|
% Konturlinien
|
||||||
|
numLevels = 10;
|
||||||
|
levels = linspace(min(D(:)), max(D(:)), numLevels);
|
||||||
|
[C,h] = contour(S0, Lambda0, D, levels, ...
|
||||||
|
'LineWidth',1.5, ...
|
||||||
|
'ShowText','on', ...
|
||||||
|
'LabelFormat','%0.1f');
|
||||||
|
|
||||||
|
% cbrewer2-Colormap für die Linien
|
||||||
|
cmap = cbrewer2('div','RdYlGn', numLevels);
|
||||||
|
colormap(cmap);
|
||||||
|
|
||||||
|
% Achsenlinien
|
||||||
|
% yline(1310, '--k','ZDW_{mean}','LabelVerticalAlignment','top','LabelHorizontalAlignment','center');
|
||||||
|
x0 = 0.09;
|
||||||
|
% xline(x0, '--k','S_{0}','LabelHorizontalAlignment','left');
|
||||||
|
|
||||||
|
% Gaussian auf der x-Linie (S0 = 0.09)
|
||||||
|
mu_zwd = 1310; % nm
|
||||||
|
sigma_zwd = 2; % nm
|
||||||
|
zwd_vals = linspace(min(lambda0_vec), max(lambda0_vec), 500);
|
||||||
|
% PDF berechnen
|
||||||
|
gauss_pdf = (1/(sigma_zwd*sqrt(2*pi))) * exp(-0.5*((zwd_vals-mu_zwd)/sigma_zwd).^2);
|
||||||
|
% Normieren und auf eine sichtbare Breite skalieren
|
||||||
|
scale = 0.005; % passt die Maximal-Auslenkung in x-Richtung an
|
||||||
|
x_gauss = x0 + (gauss_pdf/max(gauss_pdf)) * scale;
|
||||||
|
|
||||||
|
% Plot
|
||||||
|
% plot(x_gauss, zwd_vals, 'LineWidth',2);
|
||||||
|
|
||||||
|
% Achsenbeschriftung & Titel
|
||||||
|
% Achsenbeschriftung & Titel
|
||||||
|
xlabel('S0 [ps / nm2 km]', 'FontSize', 12);
|
||||||
|
ylabel('ZDW [nm]', 'FontSize', 12);
|
||||||
|
title (sprintf('Dispersion: %d km; %d nm', L, lambda), 'FontSize', 14);
|
||||||
|
|
||||||
|
grid on
|
||||||
|
hold off
|
||||||
146
Functions/Theory/dispersion_contour_bandwidth_lambda.m
Normal file
146
Functions/Theory/dispersion_contour_bandwidth_lambda.m
Normal file
@@ -0,0 +1,146 @@
|
|||||||
|
%% ------------------------------------------------------------
|
||||||
|
% Contour plot: λ_null as function of bandwidth (f_target) and reach (L)
|
||||||
|
% ------------------------------------------------------------
|
||||||
|
|
||||||
|
% Parameters
|
||||||
|
lambda0 = 1310e-9; % [m]
|
||||||
|
S0 = 0.08; % [ps/(nm²·km)]
|
||||||
|
c = physconst('lightspeed');
|
||||||
|
|
||||||
|
% Sweep dimensions
|
||||||
|
f_targets = linspace(50e9, 120e9, 100); % [Hz] (x-axis)
|
||||||
|
L_values = linspace(0.5e3, 10e3, 100); % [m] (y-axis)
|
||||||
|
|
||||||
|
lambda_surface = zeros(numel(L_values), numel(f_targets));
|
||||||
|
Dacc_surface = zeros(numel(L_values), numel(f_targets));
|
||||||
|
|
||||||
|
% Outer loop over fiber length (since L must be scalar)
|
||||||
|
for iL = 1:numel(L_values)
|
||||||
|
L = L_values(iL);
|
||||||
|
[lambda_vec, Dacc_vec] = lambda_for_first_null_full(f_targets, L, lambda0, S0);
|
||||||
|
lambda_vec = 2*abs(lambda0 - lambda_vec);
|
||||||
|
|
||||||
|
if 0
|
||||||
|
fprintf('\n- %d km ------------------------------------\n',L);
|
||||||
|
fprintf(' f_null [GHz] lambda [nm] Dacc [ps/nm]\n');
|
||||||
|
fprintf('----------------------------------------------\n');
|
||||||
|
fprintf('%10.1f %8.2f %+8.3f\n',[f_targets(:)/1e9, lambda_vec(:)*1e9, Dacc_vec(:)].');
|
||||||
|
fprintf('----------------------------------------------\n\n');
|
||||||
|
end
|
||||||
|
|
||||||
|
lambda_surface(iL, :) = lambda_vec; % λ for each f_target
|
||||||
|
Dacc_surface(iL, :) = Dacc_vec; % corresponding accumulated dispersion
|
||||||
|
end
|
||||||
|
|
||||||
|
% Convert for plotting
|
||||||
|
lambda_surface_nm = lambda_surface * 1e9; % [nm]
|
||||||
|
L_km = L_values / 1000; % [km]
|
||||||
|
f_GHz = f_targets / 1e9; % [GHz]
|
||||||
|
|
||||||
|
%% Contour plot
|
||||||
|
figure('Color','w');
|
||||||
|
|
||||||
|
% Define wavelength contour levels [nm]
|
||||||
|
lambda_levels = [1260:10:1290, 1290:5:1300, 1300:2.5:1310];
|
||||||
|
lambda_levels = [100:-20:50, 50:-10:30,30:-5:0];
|
||||||
|
|
||||||
|
% Contour plot
|
||||||
|
contour(f_GHz, L_km, lambda_surface_nm, lambda_levels, ...
|
||||||
|
'LineWidth', 1.5, ...
|
||||||
|
'ShowText', 'on', ...
|
||||||
|
'LabelFormat', '%.0f nm');
|
||||||
|
|
||||||
|
% Colormap and colorbar
|
||||||
|
colormap((cbrewer2('RdYlGn',100)));
|
||||||
|
colorbar;
|
||||||
|
clim([0 100]);
|
||||||
|
|
||||||
|
% Axis formatting
|
||||||
|
xlabel('Signal Bandwidth [GHz]');
|
||||||
|
ylabel('Fiber length [km]');
|
||||||
|
legend('$\Delta \lambda$')
|
||||||
|
|
||||||
|
% X-axis ticks at 56 : 16 : 150 GHz
|
||||||
|
xticks(56:8:150);
|
||||||
|
|
||||||
|
grid on; box on;
|
||||||
|
|
||||||
|
|
||||||
|
%% Optional: overlay accumulated-dispersion contours
|
||||||
|
if 0
|
||||||
|
hold on;
|
||||||
|
[CS, h] = contour(f_GHz, L_km, Dacc_surface, 10, 'k--', 'LineWidth', 0.8);
|
||||||
|
clabel(CS, h, 'Color','k', 'FontSize',8);
|
||||||
|
end
|
||||||
|
|
||||||
|
function [lambda_vec, Dacc_vec] = lambda_for_first_null_full(f_target, L, lambda0, S0)
|
||||||
|
% lambda_for_first_null_full (stable, single-branch + validity checks)
|
||||||
|
% --------------------------------------------------------------------
|
||||||
|
% Computes the wavelength(s) at which the first IM/DD fading null
|
||||||
|
% occurs at frequency/ies f_target using the full dispersion model:
|
||||||
|
%
|
||||||
|
% D(lambda) = (S0/4)*(lambda - lambda0^4 / lambda^3)
|
||||||
|
%
|
||||||
|
% Restricted to the NORMAL-dispersion branch (λ < λ0),
|
||||||
|
% and valid only in the O-band (1260–1360 nm).
|
||||||
|
%
|
||||||
|
% Inputs:
|
||||||
|
% f_target - scalar or vector of target null frequencies [Hz]
|
||||||
|
% L - fiber length [m]
|
||||||
|
% lambda0 - zero-dispersion wavelength (ZDW) [m]
|
||||||
|
% S0 - dispersion slope at ZDW [ps/(nm²·km)]
|
||||||
|
%
|
||||||
|
% Outputs:
|
||||||
|
% lambda_vec - wavelength(s) [m] where first null occurs (clamped to O-band)
|
||||||
|
% Dacc_vec - accumulated dispersion(s) [ps/nm] (NaN if out of valid range)
|
||||||
|
% --------------------------------------------------------------------
|
||||||
|
|
||||||
|
c = physconst('lightspeed');
|
||||||
|
S0_si = S0 * 1e3; % ps/(nm²·km) -> s/(m³)
|
||||||
|
|
||||||
|
% Define O-band boundaries (in meters)
|
||||||
|
lambda_min = 1255e-9;
|
||||||
|
lambda_max = 1361e-9;
|
||||||
|
|
||||||
|
% Force column vector
|
||||||
|
f_target = f_target(:);
|
||||||
|
N = numel(f_target);
|
||||||
|
|
||||||
|
lambda_vec = NaN(N,1);
|
||||||
|
Dacc_vec = NaN(N,1);
|
||||||
|
|
||||||
|
for k = 1:N
|
||||||
|
RHS = c * 0.5 / (f_target(k)^2 * L);
|
||||||
|
|
||||||
|
% Normal-dispersion branch (λ < λ0)
|
||||||
|
fun = @(lambda) -(S0_si/4).*(lambda - (lambda0^4)./(lambda.^3)).*lambda.^2 - RHS;
|
||||||
|
|
||||||
|
% Limit the search to [λ_min, λ0)
|
||||||
|
try
|
||||||
|
lambda_sol = fzero(fun, [lambda_min, lambda0 * 0.999]);
|
||||||
|
catch
|
||||||
|
% If the zero is not within bounds, skip this point
|
||||||
|
lambda_sol = NaN;
|
||||||
|
end
|
||||||
|
|
||||||
|
% Validate solution
|
||||||
|
if isnan(lambda_sol) || lambda_sol < lambda_min || lambda_sol > lambda_max
|
||||||
|
lambda_vec(k) = NaN;
|
||||||
|
Dacc_vec(k) = NaN;
|
||||||
|
continue
|
||||||
|
end
|
||||||
|
|
||||||
|
% Compute D(lambda) and accumulated dispersion
|
||||||
|
D_lambda = (S0_si/4) * (lambda_sol - (lambda0^4)/(lambda_sol^3)) / 1e-6; % ps/(nm·km)
|
||||||
|
Dacc_val = D_lambda * (L/1000); % ps/nm
|
||||||
|
|
||||||
|
% Sanity bound on dispersion (avoid unphysical > ±100 ps/nm)
|
||||||
|
if abs(Dacc_val) > 100
|
||||||
|
lambda_vec(k) = NaN;
|
||||||
|
Dacc_vec(k) = NaN;
|
||||||
|
else
|
||||||
|
lambda_vec(k) = lambda_sol;
|
||||||
|
Dacc_vec(k) = Dacc_val;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
38
Functions/Theory/dispersion_first_notch_10km.m
Normal file
38
Functions/Theory/dispersion_first_notch_10km.m
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
%% ------------------------------------------------------------
|
||||||
|
% Plot: Maximum usable IM/DD bandwidth vs wavelength
|
||||||
|
% ------------------------------------------------------------
|
||||||
|
|
||||||
|
% Fiber and dispersion parameters
|
||||||
|
lambda0 = 1310e-9; % [m]
|
||||||
|
S0 = 0.08; % [ps/(nm²·km)]
|
||||||
|
L = 10000; % [m]
|
||||||
|
c = physconst('lightspeed');
|
||||||
|
|
||||||
|
% Wavelength range around ZDW
|
||||||
|
lambda_vec = linspace(1250e-9, 1350e-9, 200); % [m]
|
||||||
|
|
||||||
|
% Compute D(lambda) using full model
|
||||||
|
lambda_nm = lambda_vec * 1e9;
|
||||||
|
lambda0_nm = lambda0 * 1e9;
|
||||||
|
D_lambda = (S0/4) .* (lambda_nm - (lambda0_nm.^4) ./ (lambda_nm.^3)); % [ps/(nm·km)]
|
||||||
|
|
||||||
|
% Convert D to [s/m²]
|
||||||
|
D_si = D_lambda * 1e-6;
|
||||||
|
|
||||||
|
% Compute first null frequency (f₀) for each wavelength
|
||||||
|
f_null = sqrt(c*(0.5) ./ (abs(D_si).*lambda_vec.^2*L)); % [Hz]
|
||||||
|
|
||||||
|
% Plot
|
||||||
|
figure('Color','w');
|
||||||
|
plot(lambda_vec*1e9, f_null/1e9, 'LineWidth', 1.6);
|
||||||
|
grid on; box on;
|
||||||
|
xlabel('Wavelength [nm]');
|
||||||
|
ylabel('First Fading Null Frequency [GHz]');
|
||||||
|
title(sprintf('IM/DD Bandwidth Limit vs. Wavelength (L = %.1f km)', L/1000));
|
||||||
|
|
||||||
|
% Highlight useful bandwidth thresholds
|
||||||
|
yline(25, '--', '25 GHz','Color',[0.4 0.4 0.4],'LabelHorizontalAlignment','left');
|
||||||
|
yline(50, '--', '50 GHz','Color',[0.2 0.6 0.2],'LabelHorizontalAlignment','left');
|
||||||
|
yline(100,'--', '100 GHz','Color',[0.6 0.2 0.2],'LabelHorizontalAlignment','left');
|
||||||
|
|
||||||
|
legend('First fading notch (f_{null})','Location','best');
|
||||||
165
Functions/Theory/dispersion_power_fading.m
Normal file
165
Functions/Theory/dispersion_power_fading.m
Normal file
@@ -0,0 +1,165 @@
|
|||||||
|
%% Chromatic Dispersion Power Fading Demonstration
|
||||||
|
% ------------------------------------------------------------
|
||||||
|
% This script computes and visualizes power fading after
|
||||||
|
% photodiode detection caused by chromatic dispersion in IM/DD links.
|
||||||
|
%
|
||||||
|
% It also determines the wavelength λ that produces the first
|
||||||
|
% fading null at a specified RF frequency f_target using the
|
||||||
|
% full physical dispersion model:
|
||||||
|
%
|
||||||
|
% D(λ) = (S0/4) * (λ - λ0^4 / λ^3)
|
||||||
|
%
|
||||||
|
% and compares the analytic null frequency with simulation.
|
||||||
|
% ------------------------------------------------------------
|
||||||
|
|
||||||
|
% clear; close all; clc;
|
||||||
|
|
||||||
|
%% Fiber and wavelength parameters
|
||||||
|
lambda0 = 1310e-9; % Zero-dispersion wavelength (ZDW) [m]
|
||||||
|
S0 = 0.08; % Dispersion slope at ZDW [ps/(nm^2·km)]
|
||||||
|
L = 10000; % Fiber length [m]
|
||||||
|
alpha_dB = 0; % Attenuation [dB/m] (ignored here)
|
||||||
|
|
||||||
|
%% Target null frequency
|
||||||
|
f_targets = linspace(55e9,58e9,10);
|
||||||
|
f_targets = 56e9;
|
||||||
|
% f_targets = 80e9;
|
||||||
|
% Compute wavelength that gives the first null at f_target
|
||||||
|
[lambda_vec, Dacc_vec] = lambda_for_first_null_full(f_targets, L, lambda0, S0);
|
||||||
|
% lambda_vec = 1293e-9;
|
||||||
|
|
||||||
|
|
||||||
|
fprintf('\n----------------------------------------------\n');
|
||||||
|
fprintf(' f_null [GHz] lambda [nm] Dacc [ps/nm]\n');
|
||||||
|
fprintf('----------------------------------------------\n');
|
||||||
|
fprintf('%10.1f %8.2f %+8.3f\n',[f_targets(:)/1e9, lambda_vec(:)*1e9, Dacc_vec(:)].');
|
||||||
|
fprintf('----------------------------------------------\n\n');
|
||||||
|
|
||||||
|
%% Frequency grid
|
||||||
|
f_simu = 500e9; % Simulation bandwidth [Hz]
|
||||||
|
N_freq = 500000;
|
||||||
|
faxis = linspace(-f_simu/2, f_simu/2, N_freq);
|
||||||
|
|
||||||
|
%% Derived fiber parameters
|
||||||
|
c = physconst('lightspeed');
|
||||||
|
S0_si = S0 * 1e3; % ps/(nm²·km) -> s/m³
|
||||||
|
|
||||||
|
% Convert wavelengths to nm for the D(lambda) model
|
||||||
|
lambda_nm = lambda_vec(end) * 1e9;
|
||||||
|
lambda0_nm = lambda0 * 1e9;
|
||||||
|
|
||||||
|
% Dispersion parameter [ps/(nm·km)]
|
||||||
|
D_lambda = (S0/4) * (lambda_nm - (lambda0_nm^4)/(lambda_nm^3));
|
||||||
|
|
||||||
|
% Convert to [s/m²]
|
||||||
|
D_si = D_lambda * 1e-6;
|
||||||
|
|
||||||
|
% β2 in [s²/m]
|
||||||
|
b2 = -D_si * lambda_vec(end)^2 / (2*pi*c);
|
||||||
|
|
||||||
|
%% IM/DD intensity response (simulation)
|
||||||
|
phi = 2*pi^2*b2*faxis.^2*L;
|
||||||
|
H_field_pos = exp(-1j*phi); % +f sideband
|
||||||
|
H_field_neg = exp(+1j*phi); % -f sideband
|
||||||
|
H_intensity = 0.5 * (H_field_pos + H_field_neg); % PD beating term
|
||||||
|
H_sim = abs(H_intensity);
|
||||||
|
|
||||||
|
%% Theoretical analytical IM/DD response
|
||||||
|
phi = 2*pi^2 * abs(b2) * faxis.^2 * L;
|
||||||
|
H_theoretical = abs(cos(phi));
|
||||||
|
|
||||||
|
%% Analytic first null (for verification)
|
||||||
|
f_null_analytic = sqrt(c*(0.5)/(abs(D_si)*lambda_vec(end)^2*L));
|
||||||
|
fprintf('Analytic first null from D,λ,L: %.2f GHz\n\n', f_null_analytic/1e9);
|
||||||
|
|
||||||
|
%% Plot
|
||||||
|
cols = linspecer(5);
|
||||||
|
figure('Color','w'); hold on; grid on; box on;
|
||||||
|
plot(faxis*1e-9, 10*log10(H_sim), 'DisplayName','$|H_{sim}|$ (IM/DD simulation)','Color',cols(1,:));
|
||||||
|
plot(faxis*1e-9, 10*log10(H_theoretical), 'DisplayName','|cos($\phi$)| (theory)','Color',cols(2,:),'LineStyle','--');
|
||||||
|
xline(f_targets(end)/1e9,'k:','LineWidth',1.2,'DisplayName','Target null (56 GHz)');
|
||||||
|
xline(f_null_analytic/1e9,'Color',[0.2 0.6 0.2],'LineStyle','-.','LineWidth',1.2,'DisplayName','Analytic null');
|
||||||
|
xlabel('Frequency [GHz]');
|
||||||
|
ylabel('Magnitude [dB]');
|
||||||
|
title(sprintf('Power Fading for %.2f nm, L = %.1f km',lambda_nm,L/1000));
|
||||||
|
legend('Location','best'); ylim([-30 0]);
|
||||||
|
|
||||||
|
%% Plot Bandwidth vs Lambda max
|
||||||
|
|
||||||
|
figure();
|
||||||
|
hold on;
|
||||||
|
plot(lambda_vec.*1e6,f_targets.*1e-9)
|
||||||
|
xlabel('wavelength');
|
||||||
|
ylabel('max. Bandwidth')
|
||||||
|
|
||||||
|
function [lambda_vec, Dacc_vec] = lambda_for_first_null_full(f_target, L, lambda0, S0)
|
||||||
|
% lambda_for_first_null_full (stable, single-branch + validity checks)
|
||||||
|
% --------------------------------------------------------------------
|
||||||
|
% Computes the wavelength(s) at which the first IM/DD fading null
|
||||||
|
% occurs at frequency/ies f_target using the full dispersion model:
|
||||||
|
%
|
||||||
|
% D(lambda) = (S0/4)*(lambda - lambda0^4 / lambda^3)
|
||||||
|
%
|
||||||
|
% Restricted to the NORMAL-dispersion branch (λ < λ0),
|
||||||
|
% and valid only in the O-band (1260–1360 nm).
|
||||||
|
%
|
||||||
|
% Inputs:
|
||||||
|
% f_target - scalar or vector of target null frequencies [Hz]
|
||||||
|
% L - fiber length [m]
|
||||||
|
% lambda0 - zero-dispersion wavelength (ZDW) [m]
|
||||||
|
% S0 - dispersion slope at ZDW [ps/(nm²·km)]
|
||||||
|
%
|
||||||
|
% Outputs:
|
||||||
|
% lambda_vec - wavelength(s) [m] where first null occurs (clamped to O-band)
|
||||||
|
% Dacc_vec - accumulated dispersion(s) [ps/nm] (NaN if out of valid range)
|
||||||
|
% --------------------------------------------------------------------
|
||||||
|
|
||||||
|
c = physconst('lightspeed');
|
||||||
|
S0_si = S0 * 1e3; % ps/(nm²·km) -> s/(m³)
|
||||||
|
|
||||||
|
% Define O-band boundaries (in meters)
|
||||||
|
lambda_min = 1255e-9;
|
||||||
|
lambda_max = 1361e-9;
|
||||||
|
|
||||||
|
% Force column vector
|
||||||
|
f_target = f_target(:);
|
||||||
|
N = numel(f_target);
|
||||||
|
|
||||||
|
lambda_vec = NaN(N,1);
|
||||||
|
Dacc_vec = NaN(N,1);
|
||||||
|
|
||||||
|
for k = 1:N
|
||||||
|
RHS = c * 0.5 / (f_target(k)^2 * L);
|
||||||
|
|
||||||
|
% Normal-dispersion branch (λ < λ0)
|
||||||
|
fun = @(lambda) -(S0_si/4).*(lambda - (lambda0^4)./(lambda.^3)).*lambda.^2 - RHS;
|
||||||
|
|
||||||
|
% Limit the search to [λ_min, λ0)
|
||||||
|
try
|
||||||
|
lambda_sol = fzero(fun, [lambda_min, lambda0 * 0.999]);
|
||||||
|
catch
|
||||||
|
% If the zero is not within bounds, skip this point
|
||||||
|
lambda_sol = NaN;
|
||||||
|
end
|
||||||
|
|
||||||
|
% Validate solution
|
||||||
|
if isnan(lambda_sol) || lambda_sol < lambda_min || lambda_sol > lambda_max
|
||||||
|
lambda_vec(k) = NaN;
|
||||||
|
Dacc_vec(k) = NaN;
|
||||||
|
continue
|
||||||
|
end
|
||||||
|
|
||||||
|
% Compute D(lambda) and accumulated dispersion
|
||||||
|
D_lambda = (S0_si/4) * (lambda_sol - (lambda0^4)/(lambda_sol^3)) / 1e-6; % ps/(nm·km)
|
||||||
|
Dacc_val = D_lambda * (L/1000); % ps/nm
|
||||||
|
|
||||||
|
% Sanity bound on dispersion (avoid unphysical > ±100 ps/nm)
|
||||||
|
if abs(Dacc_val) > 100
|
||||||
|
lambda_vec(k) = NaN;
|
||||||
|
Dacc_vec(k) = NaN;
|
||||||
|
else
|
||||||
|
lambda_vec(k) = lambda_sol;
|
||||||
|
Dacc_vec(k) = Dacc_val;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
32
Functions/Theory/dispersion_wavelength_notch.m
Normal file
32
Functions/Theory/dispersion_wavelength_notch.m
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
%% Dependency f_null vs Delta_lambda
|
||||||
|
lambda0 = 1310e-9;
|
||||||
|
S0 = 0.09; % ps/(nm²·km)
|
||||||
|
L = 10e3; % m
|
||||||
|
c = physconst('lightspeed');
|
||||||
|
|
||||||
|
% Convert slope to SI
|
||||||
|
S0_si = S0 * 1e3; % s/m³
|
||||||
|
|
||||||
|
Delta_lambda = linspace(5e-9, 80e-9, 300); % [m] detuning
|
||||||
|
f_null_2 = sqrt( c * 0.5 ./ (S0_si .* abs(Delta_lambda) .* lambda0.^2 .* L) );
|
||||||
|
L = 2e3; % m
|
||||||
|
f_null_10 = sqrt( c * 0.5 ./ (S0_si .* abs(Delta_lambda) .* lambda0.^2 .* L) );
|
||||||
|
|
||||||
|
cols = cbrewer2('Paired',10);
|
||||||
|
figure('Color','w');hold on
|
||||||
|
cnt = 2;
|
||||||
|
for L = 10%[2,5,10]
|
||||||
|
f_null_10 = sqrt( c * 0.5 ./ (S0_si .* abs(Delta_lambda) .* lambda0.^2 .* L*1e3) );
|
||||||
|
plot(1310-Delta_lambda*1e9, f_null_10/1e9, 'LineWidth',2,'DisplayName',sprintf('%d km',L),'Color',cols(cnt,:));
|
||||||
|
cnt = cnt+2;
|
||||||
|
end
|
||||||
|
yticks([56,75,90,112])
|
||||||
|
tickse = 1310-[7.5, 12, 17, 31.5];
|
||||||
|
xticks(flip(tickse));
|
||||||
|
|
||||||
|
xlabel('$\Delta \lambda$ from ZDW [nm]');
|
||||||
|
ylabel('$F_{null}$ [GHz]');
|
||||||
|
grid on; box on;
|
||||||
|
lim=1310-[5,35];
|
||||||
|
xlim([lim(2) lim(1)]);
|
||||||
|
ylim([40,130])
|
||||||
111
Functions/Theory/dispersion_wdm.m
Normal file
111
Functions/Theory/dispersion_wdm.m
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
%% ============================================================
|
||||||
|
% IM/DD Fading Notch Design Map
|
||||||
|
% Shows λ_null vs. bandwidth (f_target) and fiber length (L)
|
||||||
|
% ============================================================
|
||||||
|
|
||||||
|
clear; close all; clc;
|
||||||
|
|
||||||
|
%% Parameters
|
||||||
|
lambda0 = 1310e-9; % Zero-dispersion wavelength [m]
|
||||||
|
S0 = 0.08; % Dispersion slope at ZDW [ps/(nm²·km)]
|
||||||
|
c = physconst('lightspeed');
|
||||||
|
|
||||||
|
% Frequency and length sweep
|
||||||
|
f_targets = linspace(20e9, 140e9, 80); % [Hz] → x-axis
|
||||||
|
L_values = linspace(0.5e3, 12e3, 80); % [m] → y-axis
|
||||||
|
|
||||||
|
% Preallocate result matrices
|
||||||
|
lambda_surface = zeros(numel(L_values), numel(f_targets));
|
||||||
|
Dacc_surface = zeros(numel(L_values), numel(f_targets));
|
||||||
|
|
||||||
|
%% Compute λ_null and Dacc for each (f_target, L)
|
||||||
|
for iL = 1:numel(L_values)
|
||||||
|
L = L_values(iL);
|
||||||
|
[lambda_vec, Dacc_vec] = lambda_for_first_null_full(f_targets, L, lambda0, S0);
|
||||||
|
lambda_surface(iL, :) = lambda_vec; % [m]
|
||||||
|
Dacc_surface(iL, :) = Dacc_vec; % [ps/nm]
|
||||||
|
end
|
||||||
|
|
||||||
|
%% Convert to display units
|
||||||
|
lambda_surface_nm = lambda_surface * 1e9; % [nm]
|
||||||
|
L_km = L_values / 1000; % [km]
|
||||||
|
f_GHz = f_targets / 1e9; % [GHz]
|
||||||
|
|
||||||
|
%% ------------------------------------------------------------
|
||||||
|
% Contour plot (λ_null as function of f_null and L)
|
||||||
|
% ------------------------------------------------------------
|
||||||
|
figure('Color','w');
|
||||||
|
|
||||||
|
% Define wavelength contour levels [nm]
|
||||||
|
lambda_levels = [1260:10:1290, 1290:5:1300, 1300:2:1310];
|
||||||
|
|
||||||
|
contourf(f_GHz, L_km, lambda_surface_nm, lambda_levels, ...
|
||||||
|
'LineWidth', 1.5, ...
|
||||||
|
'ShowText', 'on', ...
|
||||||
|
'LabelFormat', '%1.1d nm');
|
||||||
|
|
||||||
|
% Colormap and colorbar
|
||||||
|
colormap(flip(cbrewer2('RdYlGn',100)));
|
||||||
|
clim([1260 1310]);
|
||||||
|
% c = colorbar;
|
||||||
|
% ylabel(c, 'λ_{null} [nm]', 'Rotation', 90);
|
||||||
|
|
||||||
|
% Axis formatting
|
||||||
|
xlabel('Signal Bandwidth [GHz]');
|
||||||
|
ylabel('Fiber length L [km]');
|
||||||
|
% X-axis ticks (every 16 GHz starting at 56 GHz)
|
||||||
|
xticks(56:8:120);
|
||||||
|
xlim([56,120])
|
||||||
|
grid on; box on;
|
||||||
|
|
||||||
|
%% Optional overlay: accumulated dispersion contours
|
||||||
|
hold on;
|
||||||
|
[CS, h] = contour(f_GHz, L_km, Dacc_surface, 10, 'k--', 'LineWidth', 0.8);
|
||||||
|
clabel(CS, h, 'Color','k', 'FontSize',8);
|
||||||
|
legend('λ_{null} contours','|D_{acc}| [ps/nm]','Location','best');
|
||||||
|
|
||||||
|
%% ============================================================
|
||||||
|
% Helper function: lambda_for_first_null_full
|
||||||
|
% Stable, single-branch, clamped to O-band
|
||||||
|
% ============================================================
|
||||||
|
function [lambda_vec, Dacc_vec] = lambda_for_first_null_full(f_target, L, lambda0, S0)
|
||||||
|
c = physconst('lightspeed');
|
||||||
|
S0_si = S0 * 1e3; % ps/(nm²·km) -> s/(m³)
|
||||||
|
|
||||||
|
% Define O-band boundaries (in meters)
|
||||||
|
lambda_min = 1260e-9;
|
||||||
|
lambda_max = 1360e-9;
|
||||||
|
|
||||||
|
% Force column vector
|
||||||
|
f_target = f_target(:);
|
||||||
|
N = numel(f_target);
|
||||||
|
|
||||||
|
lambda_vec = zeros(N,1);
|
||||||
|
Dacc_vec = zeros(N,1);
|
||||||
|
|
||||||
|
for k = 1:N
|
||||||
|
RHS = c * 0.5 / (f_target(k)^2 * L);
|
||||||
|
|
||||||
|
% Normal-dispersion branch (λ < λ0)
|
||||||
|
fun = @(lambda) -(S0_si/4).*(lambda - (lambda0^4)./(lambda.^3)).*lambda.^2 - RHS;
|
||||||
|
|
||||||
|
% Solve within the normal-dispersion range
|
||||||
|
try
|
||||||
|
lambda_sol = fzero(fun, [lambda_min, lambda0 * 0.999]);
|
||||||
|
catch
|
||||||
|
lambda_sol = lambda_min;
|
||||||
|
end
|
||||||
|
|
||||||
|
% Clamp to O-band range
|
||||||
|
lambda_sol = min(max(lambda_sol, lambda_min), lambda_max);
|
||||||
|
lambda_vec(k) = lambda_sol;
|
||||||
|
|
||||||
|
% Compute D(lambda) and accumulated dispersion
|
||||||
|
D_lambda = (S0_si/4) * (lambda_sol - (lambda0^4)/(lambda_sol^3)) / 1e-6; % ps/(nm·km)
|
||||||
|
Dacc_val = D_lambda * (L/1000); % ps/nm
|
||||||
|
|
||||||
|
% Clamp to physical range
|
||||||
|
Dacc_val = min(max(Dacc_val, -100), 100);
|
||||||
|
Dacc_vec(k) = Dacc_val;
|
||||||
|
end
|
||||||
|
end
|
||||||
120
Functions/Theory/matched_filter_rrc.m
Normal file
120
Functions/Theory/matched_filter_rrc.m
Normal file
@@ -0,0 +1,120 @@
|
|||||||
|
%% Matched Filter SNR Demonstration (Correct Timing)
|
||||||
|
% clear; close all; clc;
|
||||||
|
|
||||||
|
%% Parameters
|
||||||
|
M = 4; % QPSK
|
||||||
|
numSymbols = 1e6;
|
||||||
|
sps = 25; % samples per symbol
|
||||||
|
rolloff = 0.5;
|
||||||
|
EbNo_dB = 10;
|
||||||
|
|
||||||
|
%% Generate random data
|
||||||
|
data = randi([0 M-1], numSymbols, 1);
|
||||||
|
txSym = qammod(data, M, 'UnitAveragePower', true);
|
||||||
|
|
||||||
|
%% Root Raised Cosine filters
|
||||||
|
span = 64; % filter span in symbols
|
||||||
|
rrcTx = rcosdesign(rolloff, span, sps, 'sqrt');
|
||||||
|
rrcRx = rrcTx; % matched filter
|
||||||
|
|
||||||
|
txSignal2 = ifft(fft(rrcTx).*fft(txSym));
|
||||||
|
|
||||||
|
%% Transmit filtering (includes upsampling)
|
||||||
|
txSignal = upfirdn(txSym, rrcTx, sps, 1);
|
||||||
|
|
||||||
|
%% AWGN channel
|
||||||
|
rxSignal = awgn(txSignal, EbNo_dB + 10*log10(sps), 'measured');
|
||||||
|
|
||||||
|
%% Receiver matched filter
|
||||||
|
rxFilt = conv(rxSignal, rrcRx, 'same');
|
||||||
|
|
||||||
|
%% Symbol timing (group delay compensation)
|
||||||
|
delay = span * sps / 2; % total delay per filter is span*sps/2
|
||||||
|
rxAligned = rxFilt(delay+1 : end-delay);
|
||||||
|
|
||||||
|
%% Downsample to symbol rate
|
||||||
|
rxSampled = rxAligned(1:sps:end);
|
||||||
|
|
||||||
|
%% Align lengths
|
||||||
|
L = min(length(rxSampled), length(txSym));
|
||||||
|
rxSampled = rxSampled(1:L);
|
||||||
|
txSym = txSym(1:L);
|
||||||
|
|
||||||
|
%% Decision and BER
|
||||||
|
rxSym = qamdemod(rxSampled, M, 'UnitAveragePower', true);
|
||||||
|
[~, ber] = biterr(data(1:L), rxSym);
|
||||||
|
|
||||||
|
%% Compute effective SNR
|
||||||
|
snr_meas = 10*log10(mean(abs(txSym).^2) / mean(abs(txSym - rxSampled).^2));
|
||||||
|
|
||||||
|
fprintf('Measured BER: %.3e | Effective SNR: %.2f dB\n', ber, snr_meas);
|
||||||
|
|
||||||
|
|
||||||
|
%% Eye diagrams
|
||||||
|
eyediagram(rxSignal(1:4000), 2*sps);
|
||||||
|
title('Received Signal (Before Matched Filter)');
|
||||||
|
eyediagram(rxFilt(1:4000), 2*sps);
|
||||||
|
title('After Matched Filter (RRC)');
|
||||||
|
|
||||||
|
%% --------------------------------------------------------------
|
||||||
|
%% Spectrum analysis of shaped and filtered signals
|
||||||
|
%% --------------------------------------------------------------
|
||||||
|
|
||||||
|
Fs = sps; % normalized sample rate (symbol rate = 1)
|
||||||
|
Nfft = 2^16; % FFT size for high resolution
|
||||||
|
f = (-Nfft/2:Nfft/2-1)/Nfft * Fs; % normalized frequency axis (symbol-rate units)
|
||||||
|
|
||||||
|
% Spectra
|
||||||
|
S_tx = 20*log10(abs(fftshift(fft(txSignal, Nfft)))/max(abs(fft(txSignal, Nfft))));
|
||||||
|
S_rx = 20*log10(abs(fftshift(fft(rxFilt, Nfft)))/max(abs(fft(rxFilt, Nfft))));
|
||||||
|
|
||||||
|
% Unshaped (rectangular pulse) for comparison
|
||||||
|
txRect_unf = upfirdn(txSym, ones(1, sps), sps, 1);
|
||||||
|
S_rect = 20*log10(abs(fftshift(fft(txRect_unf, Nfft)))/max(abs(fft(txRect_unf, Nfft))));
|
||||||
|
|
||||||
|
% Plot
|
||||||
|
figure('Name','Spectrum after Pulse Shaping');
|
||||||
|
plot(f, S_rect, '--', 'DisplayName','Rectangular pulse');
|
||||||
|
hold on;
|
||||||
|
plot(f, S_tx, 'LineWidth',1.4, 'DisplayName','RRC (TX)');
|
||||||
|
plot(f, S_rx, 'LineWidth',1.4, 'DisplayName','After Matched Filter');
|
||||||
|
grid on;
|
||||||
|
xlabel('Normalized frequency (× symbol rate)');
|
||||||
|
ylabel('Magnitude [dB]');
|
||||||
|
title('Spectra Before and After RRC Pulse Shaping');
|
||||||
|
legend('Location','best');
|
||||||
|
xlim([-1.5 1.5]);
|
||||||
|
ylim([-60 0]);
|
||||||
|
|
||||||
|
|
||||||
|
%% --------------------------------------------------------------
|
||||||
|
%% Visualization: RRC and Raised-Cosine Frequency Responses
|
||||||
|
%% --------------------------------------------------------------
|
||||||
|
|
||||||
|
% Frequency axis for plotting (normalized to symbol rate)
|
||||||
|
Nfft = 4096;
|
||||||
|
H_rrc = fftshift(fft(rrcTx, Nfft));
|
||||||
|
H_rc = H_rrc .* H_rrc; % cascade of TX and RX RRC = full RC
|
||||||
|
|
||||||
|
f = linspace(-0.5, 0.5, Nfft); % normalized frequency (symbol-rate units)
|
||||||
|
|
||||||
|
figure('Name','Raised Cosine Filter Characteristics');
|
||||||
|
|
||||||
|
subplot(2,1,1);
|
||||||
|
plot(f, 20*log10(abs(H_rrc)/max(abs(H_rrc))), 'LineWidth', 1.5);
|
||||||
|
hold on;
|
||||||
|
plot(f, 20*log10(abs(H_rc)/max(abs(H_rc))), '--', 'LineWidth', 1.5);
|
||||||
|
grid on;
|
||||||
|
xlabel('Normalized frequency (× symbol rate)');
|
||||||
|
ylabel('Magnitude [dB]');
|
||||||
|
title(sprintf('RRC (rolloff = %.2f) and Full RC Spectrum', rolloff));
|
||||||
|
legend('Root Raised Cosine','Raised Cosine (TX×RX)','Location','best');
|
||||||
|
ylim([-60 5]);
|
||||||
|
|
||||||
|
subplot(2,1,2);
|
||||||
|
t = (-span*sps/2 : span*sps/2) / sps; % time axis in symbol durations
|
||||||
|
plot(t, rrcTx, 'LineWidth', 1.5);
|
||||||
|
grid on;
|
||||||
|
xlabel('Time [symbols]');
|
||||||
|
ylabel('Amplitude');
|
||||||
|
title('RRC Impulse Response');
|
||||||
40
Functions/Theory/power_fading.m
Normal file
40
Functions/Theory/power_fading.m
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
%% ============================================================
|
||||||
|
% Minimal IM/DD Power Fading Plot
|
||||||
|
% ============================================================
|
||||||
|
|
||||||
|
|
||||||
|
%% Fiber and system parameters
|
||||||
|
lambda0 = 1310e-9; % zero-dispersion wavelength [m]
|
||||||
|
lambda = 1275e-9; % operating wavelength [m]
|
||||||
|
S0 = 0.08; % dispersion slope [ps/(nm²·km)]
|
||||||
|
L = 10e3; % fiber length [m]
|
||||||
|
c = physconst('lightspeed');
|
||||||
|
|
||||||
|
%% Derived quantities
|
||||||
|
S0_si = S0 * 1e3; % → s/m³
|
||||||
|
D_lambda = (S0/4) * (lambda*1e9 - (lambda0*1e9)^4/(lambda*1e9)^3); % ps/(nm·km)
|
||||||
|
D_si = D_lambda * 1e-6; % → s/m²
|
||||||
|
b2 = -D_si * lambda^2 / (2*pi*c); % s²/m
|
||||||
|
|
||||||
|
%% Frequency grid
|
||||||
|
f_max = 150e9;
|
||||||
|
f = linspace(0, f_max, 4000); % [Hz]
|
||||||
|
|
||||||
|
%% IM/DD transfer function (power fading)
|
||||||
|
phi = 2*pi^2 * b2 * f.^2 * L;
|
||||||
|
H = abs(cos(phi));
|
||||||
|
|
||||||
|
%% Plot
|
||||||
|
figure('Color','w');
|
||||||
|
plot(f/1e9, 10*log10(H), 'LineWidth', 1.8);
|
||||||
|
grid on; box on;
|
||||||
|
xlabel('Frequency [GHz]');
|
||||||
|
ylabel('Magnitude [dB]');
|
||||||
|
title(sprintf('IM/DD Power Fading |H| for λ = %.1f nm, L = %.1f km', lambda*1e9, L/1000));
|
||||||
|
ylim([-30 0]);
|
||||||
|
|
||||||
|
%% Mark analytic first-null frequency
|
||||||
|
f_null = sqrt(c*(0.5)/(abs(D_si)*lambda^2*L));
|
||||||
|
xline(f_null/1e9, 'r--', 'LineWidth', 1.2, ...
|
||||||
|
'Label', sprintf('f_{null}=%.1f GHz', f_null/1e9), ...
|
||||||
|
'LabelOrientation', 'horizontal', 'LabelVerticalAlignment', 'bottom');
|
||||||
11
Functions/Theory/propagation_time.m
Normal file
11
Functions/Theory/propagation_time.m
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
function prop_time = propagation_time(fiber_len_m)
|
||||||
|
|
||||||
|
c = physconst('lightspeed'); % Speed of light in vacuum (m/s)
|
||||||
|
n = 1.46; % Refractive index of the fiber
|
||||||
|
|
||||||
|
% Calculate the propagation speed in the fiber
|
||||||
|
propagation_speed = c / n;
|
||||||
|
|
||||||
|
% Calculate the propagation time
|
||||||
|
prop_time = fiber_len_m ./ propagation_speed;
|
||||||
|
end
|
||||||
62
Functions/convert_freq_lambda.m
Normal file
62
Functions/convert_freq_lambda.m
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
%% ============================================================
|
||||||
|
% Wavelength–Frequency Conversion Utilities
|
||||||
|
% ============================================================
|
||||||
|
|
||||||
|
% Example usage:
|
||||||
|
% f = lambda2freq(1310e-9); % 1310 nm -> Hz
|
||||||
|
% lambda = freq2lambda(224e12); % 224 THz -> m
|
||||||
|
% delta_lambda_nm = df2dlambda(224e12, 400e9); % 400 GHz @ 224 THz -> nm
|
||||||
|
% delta_freq_GHz = dlambda2df(1310e-9, 3.45); % 3.45 nm @ 1310 nm -> GHz
|
||||||
|
|
||||||
|
%% ---- Core conversion functions ----
|
||||||
|
function f = lambda2freq(lambda)
|
||||||
|
% lambda2freq Convert wavelength [m] → frequency [Hz]
|
||||||
|
c = physconst('lightspeed');
|
||||||
|
f = c ./ lambda;
|
||||||
|
end
|
||||||
|
|
||||||
|
function lambda = freq2lambda(f)
|
||||||
|
% freq2lambda Convert frequency [Hz] → wavelength [m]
|
||||||
|
c = physconst('lightspeed');
|
||||||
|
lambda = c ./ f;
|
||||||
|
end
|
||||||
|
|
||||||
|
%% ---- Differential conversions ----
|
||||||
|
function d_lambda = df2dlambda(f_center, d_f)
|
||||||
|
% df2dlambda Convert frequency spacing Δf [Hz] → wavelength spacing Δλ [m]
|
||||||
|
% around a given center frequency f_center [Hz].
|
||||||
|
% Uses first-order differential: Δλ ≈ (c / f^2) * Δf
|
||||||
|
|
||||||
|
c = physconst('lightspeed');
|
||||||
|
d_lambda = (c ./ (f_center.^2)) .* d_f;
|
||||||
|
end
|
||||||
|
|
||||||
|
function d_f = dlambda2df(lambda_center, d_lambda)
|
||||||
|
% dlambda2df Convert wavelength spacing Δλ [m] → frequency spacing Δf [Hz]
|
||||||
|
% around a given center wavelength λ_center [m].
|
||||||
|
% Uses first-order differential: Δf ≈ (c / λ^2) * Δλ
|
||||||
|
|
||||||
|
c = physconst('lightspeed');
|
||||||
|
d_f = (c ./ (lambda_center.^2)) .* d_lambda;
|
||||||
|
end
|
||||||
|
|
||||||
|
%% ============================================================
|
||||||
|
% Example section (can be commented out)
|
||||||
|
% ============================================================
|
||||||
|
|
||||||
|
if ~isdeployed
|
||||||
|
fprintf('--- Example conversions ---\n');
|
||||||
|
|
||||||
|
lambda_nm = 1310; % nm
|
||||||
|
lambda = lambda_nm * 1e-9; % m
|
||||||
|
f = lambda2freq(lambda); % Hz
|
||||||
|
fprintf('λ = %.1f nm → f = %.3f THz\n', lambda_nm, f/1e12);
|
||||||
|
|
||||||
|
d_f = 2000e9; % 400 GHz spacing
|
||||||
|
d_lambda = df2dlambda(f, d_f); % [m]
|
||||||
|
fprintf('Δf = %.0f GHz @ %.1f nm → Δλ = %.3f nm\n', d_f/1e9, lambda_nm, d_lambda*1e9);
|
||||||
|
|
||||||
|
% Verify reverse direction
|
||||||
|
d_f_back = dlambda2df(lambda, d_lambda);
|
||||||
|
fprintf('Δλ = %.3f nm @ %.1f nm → Δf = %.0f GHz\n', d_lambda*1e9, lambda_nm, d_f_back/1e9);
|
||||||
|
end
|
||||||
33
Functions/getFigureSize.m
Normal file
33
Functions/getFigureSize.m
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
% GETFIGURESIZE Retrieve the size of the current MATLAB figure window.
|
||||||
|
% [WIDTH, HEIGHT] = GETFIGURESIZE() returns the width and height of the
|
||||||
|
% current figure in pixels.
|
||||||
|
%
|
||||||
|
% Example:
|
||||||
|
% % Get size of current figure
|
||||||
|
% [w, h] = getFigureSize();
|
||||||
|
% fprintf('Current figure is %d pixels wide and %d pixels tall.\n', w, h);
|
||||||
|
%
|
||||||
|
% Adapt snippet for other figures:
|
||||||
|
% % Suppose H is a handle to any MATLAB figure (existing or new):
|
||||||
|
% H = figure; % or H = <some existing figure handle>;
|
||||||
|
% % Retrieve current size of the active (or any) figure:
|
||||||
|
% [wCur, hCur] = getFigureSize();
|
||||||
|
% % Set the other figure H to match that size, preserving its position:
|
||||||
|
% posH = get(H, 'Position'); % [left, bottom, width, height]
|
||||||
|
% newPos = [posH(1), posH(2), wCur, hCur];
|
||||||
|
% set(H, 'Position', newPos);
|
||||||
|
%
|
||||||
|
% Note:
|
||||||
|
% - Position vector is given as [left, bottom, width, height] in pixels.
|
||||||
|
% - If you want to specify a custom size directly, you can replace wCur/hCur
|
||||||
|
% with desired values.
|
||||||
|
|
||||||
|
function [width, height] = getFigureSize()
|
||||||
|
% Ensure a figure is available
|
||||||
|
fig = gcf;
|
||||||
|
% Get the position vector: [left, bottom, width, height]
|
||||||
|
pos = get(fig, 'Position');
|
||||||
|
% Extract width and height
|
||||||
|
width = pos(3);
|
||||||
|
height = pos(4);
|
||||||
|
end
|
||||||
133
Libs/wesanderson_colors/WesPalette.m
Normal file
133
Libs/wesanderson_colors/WesPalette.m
Normal file
@@ -0,0 +1,133 @@
|
|||||||
|
classdef WesPalette
|
||||||
|
% WESPALETTE Wes Anderson color palettes with auto-completion
|
||||||
|
% Usage:
|
||||||
|
% cmap = WesPalette.Zissou1.rgb()
|
||||||
|
% cmap = WesPalette.Zissou1.rgb(3)
|
||||||
|
|
||||||
|
% https://github.com/karthik/wesanderson?tab=readme-ov-file
|
||||||
|
|
||||||
|
enumeration
|
||||||
|
BottleRocket1
|
||||||
|
BottleRocket2
|
||||||
|
Rushmore1
|
||||||
|
Rushmore
|
||||||
|
Royal1
|
||||||
|
Royal2
|
||||||
|
Zissou1
|
||||||
|
Zissou1Continuous
|
||||||
|
Darjeeling1
|
||||||
|
Darjeeling2
|
||||||
|
Chevalier1
|
||||||
|
FantasticFox1
|
||||||
|
Moonrise1
|
||||||
|
Moonrise2
|
||||||
|
Moonrise3
|
||||||
|
Cavalcanti1
|
||||||
|
GrandBudapest1
|
||||||
|
GrandBudapest2
|
||||||
|
IsleofDogs1
|
||||||
|
IsleofDogs2
|
||||||
|
FrenchDispatch
|
||||||
|
AsteroidCity1
|
||||||
|
AsteroidCity2
|
||||||
|
AsteroidCity3
|
||||||
|
end
|
||||||
|
|
||||||
|
methods
|
||||||
|
function cmap = rgb(obj, n)
|
||||||
|
% Return palette as Nx3 RGB colormap [0–1]
|
||||||
|
|
||||||
|
hex = obj.hex();
|
||||||
|
|
||||||
|
rgb = hex2rgb(hex);
|
||||||
|
|
||||||
|
if nargin == 2
|
||||||
|
if n > size(rgb,1)
|
||||||
|
error('Requested %d colors, but only %d available.', ...
|
||||||
|
n, size(rgb,1))
|
||||||
|
end
|
||||||
|
cmap = rgb(1:n,:);
|
||||||
|
else
|
||||||
|
cmap = rgb;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
methods (Access = private)
|
||||||
|
function hex = hex(obj)
|
||||||
|
% Internal HEX storage
|
||||||
|
|
||||||
|
switch obj
|
||||||
|
case WesPalette.BottleRocket1
|
||||||
|
hex = {'#A42820','#5F5647','#9B110E','#3F5151','#4E2A1E','#550307','#0C1707'};
|
||||||
|
|
||||||
|
case WesPalette.BottleRocket2
|
||||||
|
hex = {'#FAD510','#CB2314','#273046','#354823','#1E1E1E'};
|
||||||
|
|
||||||
|
case {WesPalette.Rushmore1, WesPalette.Rushmore}
|
||||||
|
hex = {'#E1BD6D','#EABE94','#0B775E','#35274A','#F2300F'};
|
||||||
|
|
||||||
|
case WesPalette.Royal1
|
||||||
|
hex = {'#899DA4','#C93312','#FAEFD1','#DC863B'};
|
||||||
|
|
||||||
|
case WesPalette.Royal2
|
||||||
|
hex = {'#9A8822','#F5CDB4','#F8AFA8','#FDDDA0','#74A089'};
|
||||||
|
|
||||||
|
case WesPalette.Zissou1
|
||||||
|
hex = {'#3B9AB2','#78B7C5','#EBCC2A','#E1AF00','#F21A00'};
|
||||||
|
|
||||||
|
case WesPalette.Zissou1Continuous
|
||||||
|
hex = {'#3A9AB2','#6FB2C1','#91BAB6','#A5C2A3','#BDC881', ...
|
||||||
|
'#DCCB4E','#E3B710','#E79805','#EC7A05','#EF5703','#F11B00'};
|
||||||
|
|
||||||
|
case WesPalette.Darjeeling1
|
||||||
|
hex = {'#FF0000','#00A08A','#F2AD00','#F98400','#5BBCD6'};
|
||||||
|
|
||||||
|
case WesPalette.Darjeeling2
|
||||||
|
hex = {'#ECCBAE','#046C9A','#D69C4E','#ABDDDE','#000000'};
|
||||||
|
|
||||||
|
case WesPalette.Chevalier1
|
||||||
|
hex = {'#446455','#FDD262','#D3DDDC','#C7B19C'};
|
||||||
|
|
||||||
|
case WesPalette.FantasticFox1
|
||||||
|
hex = {'#DD8D29','#E2D200','#46ACC8','#E58601','#B40F20'};
|
||||||
|
|
||||||
|
case WesPalette.Moonrise1
|
||||||
|
hex = {'#F3DF6C','#CEAB07','#D5D5D3','#24281A'};
|
||||||
|
|
||||||
|
case WesPalette.Moonrise2
|
||||||
|
hex = {'#798E87','#C27D38','#CCC591','#29211F'};
|
||||||
|
|
||||||
|
case WesPalette.Moonrise3
|
||||||
|
hex = {'#85D4E3','#F4B5BD','#9C964A','#CDC08C','#FAD77B'};
|
||||||
|
|
||||||
|
case WesPalette.Cavalcanti1
|
||||||
|
hex = {'#D8B70A','#02401B','#A2A475','#81A88D','#972D15'};
|
||||||
|
|
||||||
|
case WesPalette.GrandBudapest1
|
||||||
|
hex = {'#F1BB7B','#FD6467','#5B1A18','#D67236'};
|
||||||
|
|
||||||
|
case WesPalette.GrandBudapest2
|
||||||
|
hex = {'#E6A0C4','#C6CDF7','#D8A499','#7294D4'};
|
||||||
|
|
||||||
|
case WesPalette.IsleofDogs1
|
||||||
|
hex = {'#9986A5','#79402E','#CCBA72','#0F0D0E','#D9D0D3','#8D8680'};
|
||||||
|
|
||||||
|
case WesPalette.IsleofDogs2
|
||||||
|
hex = {'#EAD3BF','#AA9486','#B6854D','#39312F','#1C1718'};
|
||||||
|
|
||||||
|
case WesPalette.FrenchDispatch
|
||||||
|
hex = {'#90D4CC','#BD3027','#B0AFA2','#7FC0C6','#9D9C85'};
|
||||||
|
|
||||||
|
case WesPalette.AsteroidCity1
|
||||||
|
hex = {'#0A9F9D','#CEB175','#E54E21','#6C8645','#C18748'};
|
||||||
|
|
||||||
|
case WesPalette.AsteroidCity2
|
||||||
|
hex = {'#C52E19','#AC9765','#54D8B1','#B67C3B','#175149','#AF4E24'};
|
||||||
|
|
||||||
|
case WesPalette.AsteroidCity3
|
||||||
|
hex = {'#FBA72A','#D3D4D8','#CB7A5C','#5785C1'};
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
20
Libs/wesanderson_colors/hex2rgb.m
Normal file
20
Libs/wesanderson_colors/hex2rgb.m
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
function rgb = hex2rgb(hex)
|
||||||
|
% HEX2RGB Convert HEX color codes to RGB [0–1]
|
||||||
|
|
||||||
|
if ischar(hex)
|
||||||
|
hex = {hex};
|
||||||
|
end
|
||||||
|
|
||||||
|
n = numel(hex);
|
||||||
|
rgb = zeros(n,3);
|
||||||
|
|
||||||
|
for k = 1:n
|
||||||
|
h = hex{k};
|
||||||
|
h = strrep(h,'#','');
|
||||||
|
rgb(k,1) = hex2dec(h(1:2));
|
||||||
|
rgb(k,2) = hex2dec(h(3:4));
|
||||||
|
rgb(k,3) = hex2dec(h(5:6));
|
||||||
|
end
|
||||||
|
|
||||||
|
rgb = rgb / 255;
|
||||||
|
end
|
||||||
64
Libs/wesanderson_colors/minimal_example_wespalette.m
Normal file
64
Libs/wesanderson_colors/minimal_example_wespalette.m
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
x = -10:2:25; % Input power [dBm]
|
||||||
|
|
||||||
|
y1 = 1e-5 * 10.^(0.12*x); % Dispersion-only
|
||||||
|
y2 = 1e0 ./ (1 + exp(-0.4*(x-12))); % NLPN
|
||||||
|
y3 = 1e-6 * 10.^(0.45*x); % RP on gamma
|
||||||
|
y4 = 1e-2 * 10.^(0.18*(x-8)); % RP on beta2
|
||||||
|
|
||||||
|
cmap = WesPalette.AsteroidCity1.rgb(4);
|
||||||
|
cmap = linspecer(4);
|
||||||
|
figure1=figure(202998);clf;hold on
|
||||||
|
lw = 0.8; ms = 4;
|
||||||
|
plot(x,y1,'LineWidth',lw,'Color',cmap(1,:),'Marker','o','MarkerEdgeColor',cmap(1,:),'MarkerFaceColor',[1,1,1],'MarkerSize',ms);
|
||||||
|
plot(x,y2,'LineWidth',lw,'Color',cmap(2,:),'Marker','square','MarkerEdgeColor',cmap(2,:),'MarkerFaceColor',[1,1,1],'MarkerSize',ms);
|
||||||
|
plot(x,y3,'LineWidth',lw,'Color',cmap(3,:),'Marker','o','MarkerEdgeColor',cmap(3,:),'MarkerFaceColor',[1,1,1],'MarkerSize',ms);
|
||||||
|
plot(x,y4,'LineWidth',lw,'Color',cmap(4,:),'Marker','o','MarkerEdgeColor',cmap(4,:),'MarkerFaceColor',[1,1,1],'MarkerSize',ms);
|
||||||
|
yline(3.8e-3)
|
||||||
|
|
||||||
|
grid on
|
||||||
|
xlabel('Input power [dBm]')
|
||||||
|
ylabel('NSD ($\%$)')
|
||||||
|
legend({'Dispersion','NLPN','RP','RP on $\beta_2$'}, ...
|
||||||
|
'Location','best')
|
||||||
|
|
||||||
|
grid off
|
||||||
|
set(gca,'MinorGridLineWidth',0.5);
|
||||||
|
set(gca,'GridLineWidth',0.5,'GridLineStyle','--','GridColor',[0.9,0.9,0.9]);
|
||||||
|
|
||||||
|
set(gca,'FontSize',12,'YScale','log');
|
||||||
|
ylim([1e-6 1e3])
|
||||||
|
xlim([-10 23])
|
||||||
|
|
||||||
|
% % Create textarrow
|
||||||
|
% annotation(figure1,'textarrow',[0.564444444444444 0.548148148148148],...
|
||||||
|
% [0.768523809523809 0.63047619047619],'String',{'(A)'});
|
||||||
|
%
|
||||||
|
% % Create doublearrow
|
||||||
|
% annotation(figure1,'doublearrow',[0.724444444444444 0.699259259259259],...
|
||||||
|
% [0.854238095238095 0.723809523809524]);
|
||||||
|
%
|
||||||
|
% % Create line
|
||||||
|
% annotation(figure1,'line',[0.700740740740741 0.699259259259259],...
|
||||||
|
% [0.554285714285714 0.405714285714286]);
|
||||||
|
%
|
||||||
|
% % Create textbox
|
||||||
|
% annotation(figure1,'textbox',...
|
||||||
|
% [0.578777777777778 0.194285714285714 0.104185185185185 0.0685714285714286],...
|
||||||
|
% 'String',{'BOX'},...
|
||||||
|
% 'FitBoxToText','off');
|
||||||
|
|
||||||
|
%
|
||||||
|
fig_path = 'C:\Users\Silas\Documents\Dissertation\00_Examples\tikz\textfig.tikz';
|
||||||
|
matlab2tikz(fig_path, ...
|
||||||
|
'width','\fwidth', ...
|
||||||
|
'height','\fheight', ...
|
||||||
|
'showInfo',false, ...
|
||||||
|
'extraAxisOptions',{ ...
|
||||||
|
'legend style={font=\footnotesize}', ...
|
||||||
|
'xlabel style={font=\color{white!15!black},font=\small},',...
|
||||||
|
'ylabel style={font=\color{white!15!black},font=\small},',...
|
||||||
|
'legend columns=1', ...
|
||||||
|
'every axis/.append style={font=\scriptsize}',...
|
||||||
|
'legend columns=2',...
|
||||||
|
'legend style={at={(0.02,0.98)},font=\footnotesize,draw=black!60,rounded corners=2pt,inner sep=1pt,fill=white,column sep=6pt,anchor= north west}',...
|
||||||
|
});
|
||||||
79
Libs/wesanderson_colors/wes_palettes.m
Normal file
79
Libs/wesanderson_colors/wes_palettes.m
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
function palettes = wes_palettes()
|
||||||
|
% WES_PALETTES Full Wes Anderson color palette collection for MATLAB
|
||||||
|
% Colors are stored as HEX and converted to RGB on demand.
|
||||||
|
|
||||||
|
palettes = struct();
|
||||||
|
|
||||||
|
palettes.BottleRocket1 = { ...
|
||||||
|
'#A42820', '#5F5647', '#9B110E', '#3F5151', '#4E2A1E', '#550307', '#0C1707'};
|
||||||
|
|
||||||
|
palettes.BottleRocket2 = { ...
|
||||||
|
'#FAD510', '#CB2314', '#273046', '#354823', '#1E1E1E'};
|
||||||
|
|
||||||
|
palettes.Rushmore1 = { ...
|
||||||
|
'#E1BD6D', '#EABE94', '#0B775E', '#35274A', '#F2300F'};
|
||||||
|
|
||||||
|
palettes.Rushmore = palettes.Rushmore1;
|
||||||
|
|
||||||
|
palettes.Royal1 = { ...
|
||||||
|
'#899DA4', '#C93312', '#FAEFD1', '#DC863B'};
|
||||||
|
|
||||||
|
palettes.Royal2 = { ...
|
||||||
|
'#9A8822', '#F5CDB4', '#F8AFA8', '#FDDDA0', '#74A089'};
|
||||||
|
|
||||||
|
palettes.Zissou1 = { ...
|
||||||
|
'#3B9AB2', '#78B7C5', '#EBCC2A', '#E1AF00', '#F21A00'};
|
||||||
|
|
||||||
|
palettes.Zissou1Continuous = { ...
|
||||||
|
'#3A9AB2', '#6FB2C1', '#91BAB6', '#A5C2A3', '#BDC881', ...
|
||||||
|
'#DCCB4E', '#E3B710', '#E79805', '#EC7A05', '#EF5703', '#F11B00'};
|
||||||
|
|
||||||
|
palettes.Darjeeling1 = { ...
|
||||||
|
'#FF0000', '#00A08A', '#F2AD00', '#F98400', '#5BBCD6'};
|
||||||
|
|
||||||
|
palettes.Darjeeling2 = { ...
|
||||||
|
'#ECCBAE', '#046C9A', '#D69C4E', '#ABDDDE', '#000000'};
|
||||||
|
|
||||||
|
palettes.Chevalier1 = { ...
|
||||||
|
'#446455', '#FDD262', '#D3DDDC', '#C7B19C'};
|
||||||
|
|
||||||
|
palettes.FantasticFox1 = { ...
|
||||||
|
'#DD8D29', '#E2D200', '#46ACC8', '#E58601', '#B40F20'};
|
||||||
|
|
||||||
|
palettes.Moonrise1 = { ...
|
||||||
|
'#F3DF6C', '#CEAB07', '#D5D5D3', '#24281A'};
|
||||||
|
|
||||||
|
palettes.Moonrise2 = { ...
|
||||||
|
'#798E87', '#C27D38', '#CCC591', '#29211F'};
|
||||||
|
|
||||||
|
palettes.Moonrise3 = { ...
|
||||||
|
'#85D4E3', '#F4B5BD', '#9C964A', '#CDC08C', '#FAD77B'};
|
||||||
|
|
||||||
|
palettes.Cavalcanti1 = { ...
|
||||||
|
'#D8B70A', '#02401B', '#A2A475', '#81A88D', '#972D15'};
|
||||||
|
|
||||||
|
palettes.GrandBudapest1 = { ...
|
||||||
|
'#F1BB7B', '#FD6467', '#5B1A18', '#D67236'};
|
||||||
|
|
||||||
|
palettes.GrandBudapest2 = { ...
|
||||||
|
'#E6A0C4', '#C6CDF7', '#D8A499', '#7294D4'};
|
||||||
|
|
||||||
|
palettes.IsleofDogs1 = { ...
|
||||||
|
'#9986A5', '#79402E', '#CCBA72', '#0F0D0E', '#D9D0D3', '#8D8680'};
|
||||||
|
|
||||||
|
palettes.IsleofDogs2 = { ...
|
||||||
|
'#EAD3BF', '#AA9486', '#B6854D', '#39312F', '#1C1718'};
|
||||||
|
|
||||||
|
palettes.FrenchDispatch = { ...
|
||||||
|
'#90D4CC', '#BD3027', '#B0AFA2', '#7FC0C6', '#9D9C85'};
|
||||||
|
|
||||||
|
palettes.AsteroidCity1 = { ...
|
||||||
|
'#0A9F9D', '#CEB175', '#E54E21', '#6C8645', '#C18748'};
|
||||||
|
|
||||||
|
palettes.AsteroidCity2 = { ...
|
||||||
|
'#C52E19', '#AC9765', '#54D8B1', '#B67C3B', '#175149', '#AF4E24'};
|
||||||
|
|
||||||
|
palettes.AsteroidCity3 = { ...
|
||||||
|
'#FBA72A', '#D3D4D8', '#CB7A5C', '#5785C1'};
|
||||||
|
|
||||||
|
end
|
||||||
60
projects/ECOC_2025/auswertung_algorithms/mpi_dsp_debug.m
Normal file
60
projects/ECOC_2025/auswertung_algorithms/mpi_dsp_debug.m
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
|
||||||
|
load("ffe_debug_snapshot.mat");
|
||||||
|
|
||||||
|
|
||||||
|
dc_buffer_len = logspace(0,3,12);
|
||||||
|
dc_buffer_len = 1024;
|
||||||
|
|
||||||
|
mu_dc = logspace(-3,0,24);
|
||||||
|
|
||||||
|
parfor d = 1:length(mu_dc)
|
||||||
|
|
||||||
|
eq_lin = FFE_DCremoval_adaptive_mu("epochs_tr",5,"epochs_dd",3,"len_tr",4096*2,"mu_dd",...
|
||||||
|
0.0002,"mu_tr",0,"order",25,"sps",2,"decide",0,...
|
||||||
|
"mu_dc",mu_dc(d),...
|
||||||
|
"dc_buffer_len",1024, ...
|
||||||
|
"ffe_buffer_len",1,...
|
||||||
|
"smoothing_buffer_length",0,...
|
||||||
|
"smoothing_buffer_update",1,...
|
||||||
|
"adaptive_mu_mode",0);
|
||||||
|
%
|
||||||
|
% eq_lin = FFE("epochs_tr",5,"epochs_dd",3,"len_tr",4096*2,"mu_dd",...
|
||||||
|
% 0.0002,"mu_tr",0,"order",25,"sps",2,"decide",0);
|
||||||
|
|
||||||
|
ffe_results = ffe(eq_lin,M,Scpe_sig,Symbols,Tx_bits,...
|
||||||
|
"precode_mode",duob_mode,...
|
||||||
|
'showAnalysis',0,...
|
||||||
|
"postFFE",[],...
|
||||||
|
"eth_style_symbol_mapping",0);
|
||||||
|
|
||||||
|
ffe_results.metrics.print
|
||||||
|
|
||||||
|
% % eq_lin = FFE_DFE("epochs_tr",5,"epochs_dd",5,"len_tr",4096*2,"ffe_mu_dd",1e-4,"dfe_mu_dd",5e-4,"ffe_mu_tr",0,"dfe_mu_tr",0,"ffe_order",21,"dfe_order",2,"sps",2,"decide",0);
|
||||||
|
%
|
||||||
|
% eq_lin = FFE("epochs_tr",5,"epochs_dd",3,"len_tr",4096*2,"mu_dd",...
|
||||||
|
% 0.0002,"mu_tr",0,"order",25,"sps",2,"decide",0);
|
||||||
|
% pf_ = Postfilter("ncoeff",2,"useBurg",1);
|
||||||
|
% mlse_ = MLSE_viterbi("duobinary_output",0,'M',4,'trellis_states',PAMmapper(4,0).levels);
|
||||||
|
%
|
||||||
|
% [ffe_results2, mlse_results] = vnle_postfilter_mlse(eq_lin, pf_, mlse_, M, Scpe_sig, Symbols, Tx_bits, ...
|
||||||
|
% "precode_mode", duob_mode,...
|
||||||
|
% 'showAnalysis', 1, ...
|
||||||
|
% "postFFE", [],...
|
||||||
|
% "eth_style_symbol_mapping", 0);
|
||||||
|
|
||||||
|
ber(d) = ffe_results.metrics.BER;
|
||||||
|
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
figure(10)
|
||||||
|
hold on
|
||||||
|
plot(mu_dc,ber,'LineWidth',1,'DisplayName',sprintf('DC buffer len = 1024'),'Marker','.','MarkerSize',10);
|
||||||
|
xlabel('BER');
|
||||||
|
xlabel('MU DC');
|
||||||
|
title('BER Optimization over dc\_buffer\_len');
|
||||||
|
yline([4.85e-3,2e-2],'HandleVisibility', 'off','LineWidth',1,'LineStyle','--');
|
||||||
|
ylim([9e-4, 0.5]);
|
||||||
|
set(gca, 'YScale', 'log'); % BER is usually plotted log-scale
|
||||||
|
legend('show', 'Location', 'best');
|
||||||
|
grid on;
|
||||||
118
projects/ECOC_2025/auswertung_algorithms/run_offline_dsp.m
Normal file
118
projects/ECOC_2025/auswertung_algorithms/run_offline_dsp.m
Normal file
@@ -0,0 +1,118 @@
|
|||||||
|
% === SETTINGS ===
|
||||||
|
|
||||||
|
dsp_options.append_to_db = 0;
|
||||||
|
dsp_options.max_occurences = 15;
|
||||||
|
dsp_options.database_path = 'C:\Users\Silas\Documents\MATLAB\Datensätze\sioe_labor\';
|
||||||
|
dsp_options.database_name = 'silas_labor_newdsp_newstructure.db';
|
||||||
|
dsp_options.storage_path = 'Z:\2024\sioe_labor\';
|
||||||
|
|
||||||
|
dsp_options.parameters = struct();
|
||||||
|
dsp_options.parameters.mu_dc = [0.005];
|
||||||
|
|
||||||
|
% === Get Run ID's ===
|
||||||
|
db = DBHandler("pathToDB", [dsp_options.database_path, dsp_options.database_name], "type", "sqlite");
|
||||||
|
fp = QueryFilter();
|
||||||
|
% fp.where('Runs', 'run_id','EQUALS', 5108);
|
||||||
|
fp.where('Runs', 'is_mpi','EQUALS', 0);
|
||||||
|
fp.where('Runs', 'fiber_length','EQUALS', 1);
|
||||||
|
fp.where('Runs', 'wavelength','EQUALS', 1310);
|
||||||
|
fp.where('Runs', 'db_mode','EQUALS', 1);
|
||||||
|
fp.where('Runs', 'rop_attenuation','EQUALS', 0);
|
||||||
|
fp.where('Runs', 'pam_level','EQUALS', 4);
|
||||||
|
fp.where('Runs', 'bitrate','EQUALS', 360e9);
|
||||||
|
% fp.where('Runs', 'power_pd_in','GREATER_THAN', 7);
|
||||||
|
[dataTable,~] = db.queryDB(fp, db.getTableFieldNames('Runs'));
|
||||||
|
|
||||||
|
% === Initialize DataStorage ===
|
||||||
|
wh = DataStorage(dsp_options.parameters);
|
||||||
|
wh.addStorage("ffe_package");
|
||||||
|
wh.addStorage("mlse_package");
|
||||||
|
wh.addStorage("vnle_package");
|
||||||
|
wh.addStorage("dbtgt_package");
|
||||||
|
wh.addStorage("dbenc_package");
|
||||||
|
|
||||||
|
% === RUN IT ===
|
||||||
|
|
||||||
|
% [results,wh] = submitJobs(dataTable.run_id(:), dsp_options, "serial", 'wh', wh, 'waitbar', true);
|
||||||
|
% wh.getStoValue('ffe_package',0.005);
|
||||||
|
% wh.getStoValue('mlse_package',0.005);
|
||||||
|
|
||||||
|
[dataTable,~] = db.queryDB(fp, [db.getTableFieldNames('Runs');db.getTableFieldNames('Results');db.getTableFieldNames('Equalizer')]);
|
||||||
|
|
||||||
|
dataTable = cleanUpTable(dataTable);
|
||||||
|
|
||||||
|
% === Look at it ===
|
||||||
|
y_var = 'BER_precoded';
|
||||||
|
x_var = 'bitrate';
|
||||||
|
fixedVars = {'equalizer_structure', x_var};
|
||||||
|
|
||||||
|
[dataTableClean, outliersTable] = removeGroupOutliers(dataTable, fixedVars, y_var);
|
||||||
|
|
||||||
|
% --- Group and aggregate ---
|
||||||
|
dataTableGrpd_mean = groupIt(fixedVars, dataTableClean, @mean);
|
||||||
|
dataTableGrpd_min = groupIt(fixedVars, dataTableClean, @min);
|
||||||
|
dataTableGrpd_max = groupIt(fixedVars, dataTableClean, @max);
|
||||||
|
|
||||||
|
% Choose a color map
|
||||||
|
cols = linspecer(numel(unique(dataTableGrpd_mean.equalizer_structure)));
|
||||||
|
|
||||||
|
figure;
|
||||||
|
hold on;
|
||||||
|
|
||||||
|
% Get unique equalizer structures for grouping
|
||||||
|
unique_eq = unique(dataTableGrpd_mean.equalizer_structure);
|
||||||
|
|
||||||
|
for i = 1:numel(unique_eq)
|
||||||
|
eq_val = unique_eq(i);
|
||||||
|
|
||||||
|
% Filter grouped data for this equalizer structure
|
||||||
|
filt = dataTableGrpd_mean.equalizer_structure == eq_val;
|
||||||
|
|
||||||
|
x = dataTableGrpd_mean.(x_var)(filt);
|
||||||
|
y_mean = dataTableGrpd_mean.(y_var)(filt);
|
||||||
|
y_min = dataTableGrpd_min.(y_var)(filt);
|
||||||
|
y_max = dataTableGrpd_max.(y_var)(filt);
|
||||||
|
|
||||||
|
% Bounds for boundedline (distance from mean)
|
||||||
|
y_lower = y_mean - y_min;
|
||||||
|
y_upper = y_max - y_mean;
|
||||||
|
y_bounds = [y_lower, y_upper];
|
||||||
|
|
||||||
|
% --- Bounded line (mean ± min/max) ---
|
||||||
|
if exist('boundedline', 'file')
|
||||||
|
[hl, hp] = boundedline(x, y_mean, y_bounds, ...
|
||||||
|
'alpha', 'transparency', 0.1, ...
|
||||||
|
'cmap', cols(i,:), ...
|
||||||
|
'nan', 'fill', ...
|
||||||
|
'orientation', 'vert');
|
||||||
|
set(hl, 'LineWidth', 1.2, 'DisplayName', sprintf('Eq %s', eq_val));
|
||||||
|
set(hp, 'HandleVisibility', 'off');
|
||||||
|
else
|
||||||
|
% If boundedline is not available, use errorbar
|
||||||
|
errorbar(x, y_mean, y_lower, y_upper, ...
|
||||||
|
'o-', 'Color', cols(i,:), 'LineWidth', 1.2, ...
|
||||||
|
'DisplayName', sprintf('Eq %d', eq_val),'HandleVisibility', 'off');
|
||||||
|
end
|
||||||
|
|
||||||
|
% --- Normal line (mean only) ---
|
||||||
|
plot(x, y_mean, '-', 'Color', cols(i,:), 'LineWidth', 1.5, ...
|
||||||
|
'DisplayName', sprintf('Mean Eq %s', eq_val),'HandleVisibility', 'off');
|
||||||
|
|
||||||
|
% --- Scatter plot for individual points (from original data) ---
|
||||||
|
% Filter original data for this group
|
||||||
|
orig_filt = dataTableClean.equalizer_structure == eq_val;
|
||||||
|
x_scatter = dataTableClean.(x_var)(orig_filt);
|
||||||
|
y_scatter = dataTableClean.(y_var)(orig_filt);
|
||||||
|
|
||||||
|
scatter(x_scatter, y_scatter, 10,cols(i,:), 'filled', ...
|
||||||
|
'MarkerFaceAlpha', 0.5, 'DisplayName', sprintf('Scatter Eq %s', eq_val),'HandleVisibility', 'off');
|
||||||
|
end
|
||||||
|
|
||||||
|
yline([2.2e-4,4.85e-3,2e-2],'HandleVisibility', 'off','LineWidth',1,'LineStyle','--');
|
||||||
|
set(gca, 'YScale', 'log'); % BER is usually plotted log-scale
|
||||||
|
xlabel(x_var, 'Interpreter', 'none');
|
||||||
|
ylabel(y_var, 'Interpreter', 'none');
|
||||||
|
legend('show', 'Location', 'best');
|
||||||
|
grid on;
|
||||||
|
title(sprintf('%s vs. %s', y_var, x_var), 'Interpreter', 'none');
|
||||||
|
hold off;
|
||||||
63
projects/ECOC_2025/dsp_standalone_2.m
Normal file
63
projects/ECOC_2025/dsp_standalone_2.m
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
savePath = 'Z:\2025\ECOC Silas\ecoc_2025\';
|
||||||
|
databasePath = 'C:\Users\Silas\Documents\MATLAB\imdd_simulation\projects\ECOC_2025\';
|
||||||
|
database_name = 'ecoc2025_loops.db';
|
||||||
|
db = DBHandler("type","mysql");
|
||||||
|
% db = DBHandler("pathToDB", [databasePath, database_name],"type","sqlite");
|
||||||
|
|
||||||
|
filterParams = db.tables;
|
||||||
|
% filterParams.Configurations = struct('run_id', run_id);
|
||||||
|
filterParams.Configurations = struct( ...
|
||||||
|
'symbolrate', 112e9, ... %[224,336,360,390,420,448]
|
||||||
|
'fiber_length', 0, ...
|
||||||
|
'db_mode', '"no_db"', ...
|
||||||
|
'interference_attenuation', [], ...
|
||||||
|
'interference_path_length', 0, ...
|
||||||
|
'is_mpi', 1, ...
|
||||||
|
'pam_level', 4, ...
|
||||||
|
'wavelength', 1310, ...
|
||||||
|
'precomp_amp', [], ...
|
||||||
|
'signal_attenuation', [], ...
|
||||||
|
'v_awg', [], ...
|
||||||
|
'v_bias', 2.65 ...
|
||||||
|
);
|
||||||
|
|
||||||
|
selectedFields = {'Runs.run_id','Runs.loop_id','Runs.tx_bits_path','Runs.tx_signal_path','Runs.tx_symbols_path','Runs.rx_sync_path','Runs.rx_raw_path',...
|
||||||
|
'Configurations.db_mode','Configurations.pam_level','Configurations.bitrate','Configurations.symbolrate','Configurations.fiber_length','Configurations.wavelength','Configurations.precomp_amp','Measurements.power_rop','Configurations.v_bias',...
|
||||||
|
'Configurations.interference_attenuation', 'Configurations.interference_path_length'};
|
||||||
|
|
||||||
|
[dataTable,sql_query] = db.queryDB(filterParams, selectedFields);
|
||||||
|
|
||||||
|
dataTable(dataTable.loop_id~=217,:) = [];
|
||||||
|
|
||||||
|
num_occ = 10;
|
||||||
|
run_par = true;
|
||||||
|
run_id = dataTable.run_id;
|
||||||
|
|
||||||
|
params.dc_buffer_len = 224;
|
||||||
|
params.ffe_buffer_len = 1;
|
||||||
|
params.smoothing_buffer_length = 0;
|
||||||
|
params.smoothing_buffer_update = 0;
|
||||||
|
params.mu_dc = 0.005;
|
||||||
|
|
||||||
|
futures_list = parallel.FevalFuture.empty();
|
||||||
|
for id = 1:length(dataTable.run_id)
|
||||||
|
run_id = dataTable.run_id(id);
|
||||||
|
[out, futures_list(id)] = submit_dsp(run_id, databasePath, database_name, savePath,"parallel",run_par,'max_occurences',num_occ,'paramstruct',params);
|
||||||
|
end
|
||||||
|
|
||||||
|
% Extract all ber_mlse values from the vnle_pf_package using cellfun
|
||||||
|
ber_mlse = cellfun(@(pkg) pkg.ber_mlse, future.OutputArguments{1,1}.vnle_pf_package);
|
||||||
|
ber_vnle = cellfun(@(pkg) pkg.ber_vnle, future.OutputArguments{1,1}.vnle_pf_package);
|
||||||
|
|
||||||
|
figure(101)
|
||||||
|
hold on;
|
||||||
|
scatter(1:num_occ,ber_mlse,15,'Marker','*');
|
||||||
|
scatter(1:num_occ,ber_vnle,15,'Marker','*');
|
||||||
|
legend('Interpreter', 'latex');
|
||||||
|
xlabel('Occurences');
|
||||||
|
ylabel('BER');
|
||||||
|
grid on;
|
||||||
|
beautifyBERplot;
|
||||||
58
projects/ECOC_2025/dsp_test/hyperparam_tuning.m
Normal file
58
projects/ECOC_2025/dsp_test/hyperparam_tuning.m
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
|
||||||
|
|
||||||
|
Scpe_sig = load("imdd_simulation\projects\ECOC_2025\dsp_test\pam4_scopesignal.mat");Scpe_sig = Scpe_sig.Scpe_sig;
|
||||||
|
Tx_bits = load("imdd_simulation\projects\ECOC_2025\dsp_test\pam4_bits.mat");Tx_bits = Tx_bits.Tx_bits;
|
||||||
|
Symbols = load("imdd_simulation\projects\ECOC_2025\dsp_test\pam4_symbols.mat");Symbols = Symbols.Symbols;
|
||||||
|
|
||||||
|
eq_ = FFE_DCremoval("epochs_tr",5,"epochs_dd",3,"len_tr",4096*2,"mu_dd",1e-5,"mu_tr",0,"order",50,"sps",2,"decide",0,"mu_dc",0.005,"dc_buffer_len",1);
|
||||||
|
|
||||||
|
% savePath = 'Z:\2025\ECOC Silas\ecoc_2025\';
|
||||||
|
% databasePath = 'C:\Users\Silas\Documents\MATLAB\imdd_simulation\projects\ECOC_2025\';
|
||||||
|
% database_name = 'ecoc2025_loops.db';
|
||||||
|
% db = DBHandler("type","mysql");
|
||||||
|
|
||||||
|
params = (logspace(-6,-2,20));
|
||||||
|
params = floor((logspace(2,3,20)));
|
||||||
|
params = 224;
|
||||||
|
|
||||||
|
for i = 1:length(params)
|
||||||
|
|
||||||
|
eq_ = FFE_DCremoval_adaptive_mu("epochs_tr",5,"epochs_dd",3,"len_tr",4096*2,"mu_dd",...
|
||||||
|
0.0002,"mu_tr",0,"order",25,"sps",2,"decide",0,...
|
||||||
|
"mu_dc",0.005,"dc_buffer_len",1, ...
|
||||||
|
"ffe_buffer_len",1,...
|
||||||
|
"smoothing_buffer_length",0,...
|
||||||
|
"smoothing_buffer_update",1);
|
||||||
|
|
||||||
|
result = ffe(eq_,4,Scpe_sig,Symbols,Tx_bits,"precode_mode",db_mode.no_db,'showAnalysis',1,"postFFE",[],"eth_style_symbol_mapping",0);
|
||||||
|
ber_ffe(i) = result.metrics;
|
||||||
|
fprintf(" FFE Results: %.2e\n", ber_ffe(i));
|
||||||
|
|
||||||
|
% db.addProcessingResult(run_id, result.resultsVNLE, result.equalizerConfigVNLE);
|
||||||
|
|
||||||
|
% eq_ = FFE_adaptive_decision("epochs_tr",5,"epochs_dd",3,"len_tr",4096*2,"mu_dd",...
|
||||||
|
% 0.0003,"mu_tr",0,"order",50,"sps",2,"decide",1,"buffer_length",params(i));
|
||||||
|
%
|
||||||
|
% result = vnle(eq_,4,Scpe_sig,Symbols,Tx_bits,"precode_mode",db_mode.no_db,'showAnalysis',1,"postFFE",[],"eth_style_symbol_mapping",0);
|
||||||
|
% ber_dc(i) = result.ber_vnle;
|
||||||
|
%
|
||||||
|
% fprintf(" FFE+dc tr. Results: %.2e\n", ber_dc(i));
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
figure(103435)
|
||||||
|
hold on;
|
||||||
|
% scatter(params,ber_dc,15,'Marker','o','LineWidth',1,'DisplayName','DC tracking');
|
||||||
|
% [a,b]=min(ber_dc);
|
||||||
|
% scatter(params(b),a,45,'Marker','x','MarkerEdgeColor','r','LineWidth',1);
|
||||||
|
|
||||||
|
scatter(params,ber_ffe,15,'Marker','square','LineWidth',1);
|
||||||
|
[a,b]=min(ber_ffe);
|
||||||
|
scatter(params(b),a,45,'Marker','x','MarkerEdgeColor','r','LineWidth',1,'DisplayName','FFE');
|
||||||
|
|
||||||
|
legend('Interpreter', 'latex');
|
||||||
|
xlabel('Occurences');
|
||||||
|
ylabel('BER');
|
||||||
|
grid on;
|
||||||
|
beautifyBERplot;
|
||||||
|
ylim([1e-4,0.1 ])
|
||||||
BIN
projects/ECOC_2025/ecoc2025.db
Normal file
BIN
projects/ECOC_2025/ecoc2025.db
Normal file
Binary file not shown.
1
projects/ECOC_2025/ecoc2025.sqbpro
Normal file
1
projects/ECOC_2025/ecoc2025.sqbpro
Normal file
File diff suppressed because one or more lines are too long
BIN
projects/ECOC_2025/ecoc2025_einmessung.db
Normal file
BIN
projects/ECOC_2025/ecoc2025_einmessung.db
Normal file
Binary file not shown.
BIN
projects/ECOC_2025/ecoc2025_fail.db
Normal file
BIN
projects/ECOC_2025/ecoc2025_fail.db
Normal file
Binary file not shown.
BIN
projects/ECOC_2025/ecoc2025_loops - Kopie.db
Normal file
BIN
projects/ECOC_2025/ecoc2025_loops - Kopie.db
Normal file
Binary file not shown.
BIN
projects/ECOC_2025/ecoc2025_loops.db
Normal file
BIN
projects/ECOC_2025/ecoc2025_loops.db
Normal file
Binary file not shown.
163
projects/ECOC_2025/sqlite_sequence.sql
Normal file
163
projects/ECOC_2025/sqlite_sequence.sql
Normal file
@@ -0,0 +1,163 @@
|
|||||||
|
BEGIN TRANSACTION;
|
||||||
|
CREATE TABLE IF NOT EXISTS "Configurations" (
|
||||||
|
"configuration_id" INTEGER,
|
||||||
|
"run_id" INTEGER,
|
||||||
|
"unique_elab_id" TEXT,
|
||||||
|
"bitrate" REAL,
|
||||||
|
"symbolrate" REAL,
|
||||||
|
"pam_level" INTEGER,
|
||||||
|
"db_mode" TEXT,
|
||||||
|
"pulsef_alpha" INTEGER,
|
||||||
|
"v_bias" REAL,
|
||||||
|
"v_awg" REAL,
|
||||||
|
"precomp_amp" REAL,
|
||||||
|
"rop_attenuation" REAL,
|
||||||
|
"wavelength" REAL,
|
||||||
|
"laser_power" REAL,
|
||||||
|
"fiber_length" REAL,
|
||||||
|
"pd_in_desired" REAL,
|
||||||
|
"is_mpi" BIT,
|
||||||
|
"signal_attenuation" REAL,
|
||||||
|
"interference_path_length" REAL,
|
||||||
|
"interference_attenuation" REAL,
|
||||||
|
"pam_source" TEXT,
|
||||||
|
PRIMARY KEY("configuration_id" AUTOINCREMENT),
|
||||||
|
FOREIGN KEY("run_id") REFERENCES "Runs"("run_id")
|
||||||
|
);
|
||||||
|
CREATE TABLE IF NOT EXISTS "EqualizerParameters" (
|
||||||
|
"eq_id" INTEGER,
|
||||||
|
"equalizer_structure" REAL,
|
||||||
|
"M" INTEGER,
|
||||||
|
"target_constellation" TEXT,
|
||||||
|
"db_target" INTEGER,
|
||||||
|
"diff_precode" INTEGER,
|
||||||
|
"postFFE" INTEGER,
|
||||||
|
"NpostFFE" INTEGER,
|
||||||
|
"Ne1" INTEGER,
|
||||||
|
"Ne2" INTEGER,
|
||||||
|
"Ne3" INTEGER,
|
||||||
|
"Nb1" INTEGER,
|
||||||
|
"Nb2" INTEGER,
|
||||||
|
"Nb3" INTEGER,
|
||||||
|
"K" INTEGER,
|
||||||
|
"DCmu" REAL,
|
||||||
|
"ideal_dfe" INTEGER,
|
||||||
|
"training_length" INTEGER,
|
||||||
|
"training_loops" INTEGER,
|
||||||
|
"TRmu1" REAL,
|
||||||
|
"TRmu2" REAL,
|
||||||
|
"TRmu3" REAL,
|
||||||
|
"TRmuDFE" REAL,
|
||||||
|
"dd_loops" INTEGER,
|
||||||
|
"DDmu1" REAL,
|
||||||
|
"DDmu2" REAL,
|
||||||
|
"DDmu3" REAL,
|
||||||
|
"DDmuDFE" REAL,
|
||||||
|
"MLSE_mode" TEXT,
|
||||||
|
"MLSE_trellis_states" TEXT,
|
||||||
|
"comment" TEXT,
|
||||||
|
"config_hash" TEXT,
|
||||||
|
UNIQUE("config_hash"),
|
||||||
|
PRIMARY KEY("eq_id" AUTOINCREMENT)
|
||||||
|
);
|
||||||
|
CREATE TABLE IF NOT EXISTS "Measurements" (
|
||||||
|
"measurement_id" INTEGER,
|
||||||
|
"run_id" INTEGER,
|
||||||
|
"power_laser" REAL,
|
||||||
|
"power_rop" REAL,
|
||||||
|
"power_pd_in" REAL,
|
||||||
|
"power_mpi_interference" REAL,
|
||||||
|
"power_mpi_signal" REAL,
|
||||||
|
"voa_class" TEXT,
|
||||||
|
"pdfa_class" TEXT,
|
||||||
|
"laser_class" TEXT,
|
||||||
|
PRIMARY KEY("measurement_id" AUTOINCREMENT),
|
||||||
|
FOREIGN KEY("run_id") REFERENCES "Runs"("run_id")
|
||||||
|
);
|
||||||
|
CREATE TABLE IF NOT EXISTS "Results" (
|
||||||
|
"result_id" INTEGER,
|
||||||
|
"run_id" INTEGER,
|
||||||
|
"eqParam_id" INTEGER,
|
||||||
|
"date_of_processing" DATETIME DEFAULT (datetime('now', 'localtime')),
|
||||||
|
"numBits" INTEGER,
|
||||||
|
"numBitErr" INTEGER,
|
||||||
|
"BER" REAL,
|
||||||
|
"numBitErr_precoded" REAL,
|
||||||
|
"BER_precoded" REAL,
|
||||||
|
"SNR" REAL,
|
||||||
|
"SNR_level" TEXT,
|
||||||
|
"GMI" REAL,
|
||||||
|
"AIR" REAL,
|
||||||
|
"EVM" REAL,
|
||||||
|
"EVM_level" TEXT,
|
||||||
|
"Alpha" REAL,
|
||||||
|
"result_hash" TEXT UNIQUE,
|
||||||
|
"MLSE_dir" INTEGER,
|
||||||
|
PRIMARY KEY("result_id" AUTOINCREMENT),
|
||||||
|
FOREIGN KEY("eqParam_id") REFERENCES "EqualizerParameters"("eq_id"),
|
||||||
|
FOREIGN KEY("run_id") REFERENCES "Runs"("run_id")
|
||||||
|
);
|
||||||
|
CREATE TABLE IF NOT EXISTS "Runs" (
|
||||||
|
"run_id" INTEGER,
|
||||||
|
"date_of_run" DATETIME DEFAULT (datetime('now', 'localtime')),
|
||||||
|
"tx_bits_path" TEXT,
|
||||||
|
"tx_symbols_path" TEXT,
|
||||||
|
"rx_sync_path" TEXT,
|
||||||
|
"rx_raw_path" TEXT,
|
||||||
|
"filename" TEXT,
|
||||||
|
"tx_signal_path" TEXT,
|
||||||
|
PRIMARY KEY("run_id" AUTOINCREMENT)
|
||||||
|
);
|
||||||
|
CREATE VIEW "View_ResultOverview" AS
|
||||||
|
SELECT
|
||||||
|
-- Run info
|
||||||
|
Runs.run_id,
|
||||||
|
Runs.date_of_run,
|
||||||
|
|
||||||
|
Results.BER,
|
||||||
|
Results.SNR,
|
||||||
|
Results.GMI,
|
||||||
|
Results.AIR,
|
||||||
|
Results.EVM,
|
||||||
|
Results.Alpha,
|
||||||
|
|
||||||
|
-- Configurations
|
||||||
|
Configurations.symbolrate,
|
||||||
|
Configurations.pam_level,
|
||||||
|
Configurations.db_mode,
|
||||||
|
Configurations.pulsef_alpha,
|
||||||
|
Configurations.v_bias,
|
||||||
|
Configurations.v_awg,
|
||||||
|
Configurations.precomp_amp,
|
||||||
|
Configurations.is_mpi,
|
||||||
|
Configurations.signal_attenuation,
|
||||||
|
Configurations.interference_path_length,
|
||||||
|
Configurations.interference_attenuation,
|
||||||
|
|
||||||
|
-- Measurement data
|
||||||
|
Measurements.power_laser,
|
||||||
|
Measurements.power_rop,
|
||||||
|
Measurements.power_pd_in,
|
||||||
|
Measurements.power_mpi_interference,
|
||||||
|
Measurements.power_mpi_signal,
|
||||||
|
|
||||||
|
-- Equalizer parameters
|
||||||
|
EqualizerParameters.equalizer_structure,
|
||||||
|
EqualizerParameters.db_target,
|
||||||
|
EqualizerParameters.diff_precode
|
||||||
|
|
||||||
|
|
||||||
|
FROM Results
|
||||||
|
|
||||||
|
-- Join related tables
|
||||||
|
LEFT JOIN Runs ON Results.run_id = Runs.run_id
|
||||||
|
LEFT JOIN Configurations ON Configurations.run_id = Runs.run_id
|
||||||
|
LEFT JOIN Measurements ON Measurements.run_id = Runs.run_id
|
||||||
|
LEFT JOIN EqualizerParameters ON Results.eqParam_id = EqualizerParameters.eq_id;
|
||||||
|
CREATE INDEX IF NOT EXISTS "idx_run_id_on_Configurations" ON "Configurations" (
|
||||||
|
"run_id"
|
||||||
|
);
|
||||||
|
CREATE INDEX IF NOT EXISTS "idx_run_id_on_Measurements" ON "Measurements" (
|
||||||
|
"run_id"
|
||||||
|
);
|
||||||
|
COMMIT;
|
||||||
85
projects/ECOC_2025/theory/analytic_mpi_evaluation.m
Normal file
85
projects/ECOC_2025/theory/analytic_mpi_evaluation.m
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
% This script is used to evaluate Fig. 1b) in the paper "Adaptive Removal of Multipath Interference in Short Reach 112 GBd PAM-4 IM/DD Systems"
|
||||||
|
|
||||||
|
%% Parameters
|
||||||
|
df = 1e6; % Laser linewidth [Hz]
|
||||||
|
SIR_dB = 20; % Interference attenuation [dB]
|
||||||
|
alpha = 10^(-SIR_dB/20); % Interference attenuation [linear]
|
||||||
|
n_fiber = 1.467; % Refractive index
|
||||||
|
c = physconst('lightspeed'); % [m/s]
|
||||||
|
|
||||||
|
L = linspace(0,250,50); % Interference delay [m]
|
||||||
|
tau = n_fiber./c.*L; % Interference time (= tau) [s]
|
||||||
|
|
||||||
|
tau_c = 1/(pi*df); % laser coherence time [s]
|
||||||
|
L_c = (c/n_fiber)*tau_c; % laser coherence length [m]
|
||||||
|
|
||||||
|
var_sat = 2*alpha^2; % Analytical saturation of variance
|
||||||
|
|
||||||
|
%% Monte–Carlo Simulation
|
||||||
|
fs = 100e9; % sampling rate [Hz]
|
||||||
|
Tsim = 50e-6; % sim duration [s]
|
||||||
|
N = round(Tsim*fs); % number of samples for each realization
|
||||||
|
max_delay_samples = round(max(tau)*fs); % largest delay that is evaluated (based on max. Interference delay)
|
||||||
|
phase_noise_std = sqrt(2*pi*df/fs); % standard dev. phase noise
|
||||||
|
|
||||||
|
num_realizations = 50; % number of parallel runs
|
||||||
|
monte_carlo_variance = zeros(num_realizations, length(L));
|
||||||
|
parfor r = 1:num_realizations
|
||||||
|
|
||||||
|
% generate a realization of phase noise random walk
|
||||||
|
dphi = phase_noise_std * randn(1, N + max_delay_samples); % matlab randn process has std = 1
|
||||||
|
phi = cumsum(dphi);
|
||||||
|
phi_direct = phi(max_delay_samples+1 : max_delay_samples+N);
|
||||||
|
var_k = zeros(1, length(L));
|
||||||
|
for t = 1:length(tau)
|
||||||
|
|
||||||
|
nd = round( tau(t)*fs ); % delay in samples for current interference time
|
||||||
|
phi_delayed = phi(max_delay_samples+1-nd : max_delay_samples+N-nd); %cut out interfering signal part (was earlier)
|
||||||
|
|
||||||
|
E = exp(1j*phi_direct) + alpha*exp(1j*phi_delayed); % E-fields combined
|
||||||
|
I = abs(E).^2; % photo current as magnitude square of E-field
|
||||||
|
var_k(t) = var(I);
|
||||||
|
|
||||||
|
end
|
||||||
|
monte_carlo_variance(r, :) = var_k;
|
||||||
|
end
|
||||||
|
|
||||||
|
avg_of_mc_variances = mean(monte_carlo_variance, 1);
|
||||||
|
std_of_mc_variances = std(monte_carlo_variance, 0, 1);
|
||||||
|
|
||||||
|
%% Analytic variance
|
||||||
|
L_ = linspace(0,250,500); % Interference delay [m]
|
||||||
|
tau_ = n_fiber./c.*L_;
|
||||||
|
analytic_variance = 2*alpha^2 * (1 - exp(-2*pi*df.*tau_)).^2;
|
||||||
|
|
||||||
|
%% Plot
|
||||||
|
cols = [0.3467 0.5360 0.6907
|
||||||
|
0.9153 0.2816 0.2878
|
||||||
|
0.4416 0.7490 0.4322];
|
||||||
|
|
||||||
|
coherence_length_multiples = 0.5:0.5:ceil(L(end)/L_c);
|
||||||
|
|
||||||
|
figure();
|
||||||
|
hold on;
|
||||||
|
plot(L, avg_of_mc_variances, 'LineWidth',2, 'DisplayName','Simulation','Color',cols(1,:),'LineStyle','-');
|
||||||
|
errorbar(L, avg_of_mc_variances,std_of_mc_variances, 'LineWidth',0.7,'LineStyle','none', 'DisplayName','Simulation','Color',cols(1,:),'HandleVisibility','off');
|
||||||
|
|
||||||
|
plot(L_, analytic_variance, 'LineWidth',2, 'DisplayName','Analytic','Color',cols(2,:),'LineStyle','-');
|
||||||
|
xticks(coherence_length_multiples.*L_c);
|
||||||
|
xticklabels(round(coherence_length_multiples.*L_c,1));
|
||||||
|
|
||||||
|
norm_to_coherence_len = 1;
|
||||||
|
if norm_to_coherence_len
|
||||||
|
xticklabels(coherence_length_multiples);
|
||||||
|
xlabel('$n \cdot L_c$', 'FontSize',12);
|
||||||
|
else
|
||||||
|
xlabel('Interference Delay [m]', 'FontSize',12);
|
||||||
|
end
|
||||||
|
|
||||||
|
xline(L_c.*coherence_length_multiples, 'LineWidth',1.5, 'DisplayName','Coh. Length','HandleVisibility','off','Color',[0.7,0.7,0.7],'LineStyle','-');
|
||||||
|
xlim([0,L(end)]);
|
||||||
|
yline(var_sat, '-.k','LineWidth',1.5, 'DisplayName','Saturation: 2$\alpha ^2$');
|
||||||
|
grid on;
|
||||||
|
ylabel('Intensity Variance', 'FontSize',12);
|
||||||
|
title(sprintf('MPI Variance; %d MHz; SIR: %d dB',df.*1e-6,SIR_dB), 'FontSize',14);
|
||||||
|
legend('Location','southeast');
|
||||||
32
projects/ECOC_2025/theory/coherence_length_plot.m
Normal file
32
projects/ECOC_2025/theory/coherence_length_plot.m
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
%% Parameters
|
||||||
|
df = linspace(1,50e6,10000); % Laser FWHM linewidth [Hz]
|
||||||
|
n_fiber = 1.467; % Fiber group index
|
||||||
|
c = 3e8; % Speed of light [m/s]
|
||||||
|
|
||||||
|
% Compute coherence length (1/e of mean-fringe decay)
|
||||||
|
tau_c = 1./(pi*df);
|
||||||
|
L_c = (c.* tau_c/n_fiber) ; % Coherence length [m]
|
||||||
|
|
||||||
|
%% Plot
|
||||||
|
figure('Color','w');
|
||||||
|
loglog(df/1e6, L_c, 'LineWidth',2,'LineStyle','-'); % linewidth in MHz
|
||||||
|
% xticks([0.1, 1, 10, 50]);
|
||||||
|
% yticks([1, 10, 100, 1000]);
|
||||||
|
% yticklabels({'1','10','100','1000'})
|
||||||
|
grid on; box on;
|
||||||
|
xlabel('Laser linewidth [MHz]','FontSize',12,'Interpreter','latex');
|
||||||
|
ylabel('Coherence length [m]','FontSize',12,'Interpreter','latex');
|
||||||
|
title('Coherence Length vs. Laser Linewidth','FontSize',14,'Interpreter','latex');
|
||||||
|
|
||||||
|
%% Annotate some key points
|
||||||
|
% hold on;
|
||||||
|
% freqs = [150e3, 1e6, 10e6, 50e6]; % [Hz]
|
||||||
|
% for f = freqs
|
||||||
|
% x = f/1e6;
|
||||||
|
% y = (c/n_fiber) * (1/(pi*f));
|
||||||
|
% scatter(x,y,'Marker','x','LineWidth',1,'MarkerEdgeColor','black');
|
||||||
|
%
|
||||||
|
% text(x*1.1,y, sprintf('%.2f MHz', f/1e6), ...
|
||||||
|
% 'FontSize',10,'HorizontalAlignment','left');
|
||||||
|
%
|
||||||
|
% end
|
||||||
@@ -0,0 +1,111 @@
|
|||||||
|
|
||||||
|
database_type = 'mysql';
|
||||||
|
dataBase = 'labor_highspeed';%'C:\Users\Silas\Documents\MATLAB\Datensätze\sioe_labor\silas_labor_newdsp_newstructure.db';
|
||||||
|
db = DBHandler("dataBase", [dataBase], "type", database_type);
|
||||||
|
|
||||||
|
fp = QueryFilter();
|
||||||
|
% fp.where('Runs', 'run_id','EQUALS', 987);
|
||||||
|
M = 6;
|
||||||
|
fp.where('Runs', 'pam_level','EQUALS', M);
|
||||||
|
baudrate = 162e9;
|
||||||
|
fp.where('Runs', 'symbolrate','EQUALS', baudrate);
|
||||||
|
% fp.where('Runs', 'fiber_length','EQUALS', 2);
|
||||||
|
fp.where('Runs', 'is_mpi','EQUALS', 0);
|
||||||
|
% fp.where('Runs', 'interference_path_length','EQUALS', 1000);
|
||||||
|
% fp.where('Runs', 'loop_id','GREATER_THAN', 11);
|
||||||
|
% fp.where('Runs', 'sir','EQUALS',18);
|
||||||
|
% fp.where('Runs', 'wavelength','EQUALS', 1310);
|
||||||
|
fp.where('Runs', 'db_mode','EQUALS', 1); % 0 == high preemphasis // 1 == low preemphasis
|
||||||
|
fp.where('Runs', 'rop_attenuation','EQUALS', 0);
|
||||||
|
|
||||||
|
|
||||||
|
fields = db.getTableFieldNames('power_state_info');
|
||||||
|
fields = [fields; db.getTableFieldNames('dashboard_ungrouped_new')];
|
||||||
|
[dataTable,~] = db.queryDB(fp, fields);
|
||||||
|
|
||||||
|
eqstructures = unique(dataTable.equalizer_structure);
|
||||||
|
fiber_len = unique(dataTable.fiber_length);
|
||||||
|
cnt = 1;
|
||||||
|
f=figure();
|
||||||
|
clf
|
||||||
|
hold on
|
||||||
|
|
||||||
|
markers = {'o', 's', 'd', '^', 'v', '>', '<', 'p', 'h'}; % Define marker styles
|
||||||
|
|
||||||
|
for fl = 1:numel(fiber_len)
|
||||||
|
|
||||||
|
fl_filtered = dataTable(dataTable.fiber_length == fiber_len(fl),:);
|
||||||
|
|
||||||
|
for eqs = [equalizer_structure.vnle_pf_mlse]
|
||||||
|
|
||||||
|
eq_choice = equalizer_structure(eqs);
|
||||||
|
if sum(eqstructures == eq_choice)~=1
|
||||||
|
disp(eq_choice)
|
||||||
|
continue
|
||||||
|
end
|
||||||
|
|
||||||
|
eq_filtered = fl_filtered(fl_filtered.equalizer_structure == eq_choice,:);
|
||||||
|
|
||||||
|
dispersion_sorted = sortrows(eq_filtered, {'accumulated_dispersion'}, 'ascend');
|
||||||
|
% dispersion_sorted = dispersion_sorted(dispersion_sorted.wavelength <= 1320,:);
|
||||||
|
% dispersion_sorted = dispersion_sorted(dispersion_sorted.BER < 0.02,:);
|
||||||
|
% pull out your vectors
|
||||||
|
accumulated_dispersion = dispersion_sorted.accumulated_dispersion;
|
||||||
|
ber = dispersion_sorted.BER;
|
||||||
|
% ber = dispersion_sorted.BER_precoded;
|
||||||
|
run_ids = dispersion_sorted.run_id; % <-- this is what we want in the datatip
|
||||||
|
len = dispersion_sorted.fiber_length;
|
||||||
|
lambda = dispersion_sorted.wavelength;
|
||||||
|
cols = cbrewer2('Set1',8);
|
||||||
|
% cols = flip(cbrewer2('RdYlGn',14));
|
||||||
|
cols = linspecer(8);
|
||||||
|
|
||||||
|
ber_wavelen_grouped = groupsummary( ...
|
||||||
|
dispersion_sorted, ... % input table
|
||||||
|
"wavelength", ... % grouping variable
|
||||||
|
"min", ... % which summary statistic
|
||||||
|
"BER_precoded");
|
||||||
|
|
||||||
|
dname = sprintf('%s; %d km',eq_choice, fiber_len(fl));
|
||||||
|
h1 = plot(ber_wavelen_grouped.wavelength, ber_wavelen_grouped.min_BER_precoded,'LineWidth', 2, 'MarkerSize', 5,'Marker',markers(cnt),'LineStyle','-','Color',cols(cnt,:),'MarkerEdgeColor','auto','MarkerFaceColor','white','DisplayName',dname);
|
||||||
|
|
||||||
|
|
||||||
|
plotallscatters=0;
|
||||||
|
if plotallscatters
|
||||||
|
% plot the two curves and capture their Line handles
|
||||||
|
dname = sprintf('%s; %d km',eq_choice, fiber_len(fl));
|
||||||
|
h1 = plot(lambda, ber,'LineWidth', 1.5, 'MarkerSize', 5,'Marker','o','LineStyle','none','Color',cols(cnt,:),'MarkerFaceColor',cols(cnt,:),'DisplayName',dname);
|
||||||
|
% —————— Add run_id as a datatip row ——————
|
||||||
|
% For each line, tell the datatip template where to find the run_id:
|
||||||
|
h1.DataTipTemplate.DataTipRows(end+1) = ...
|
||||||
|
dataTipTextRow('run\_id', run_ids);
|
||||||
|
h1.DataTipTemplate.DataTipRows(end+1) = ...
|
||||||
|
dataTipTextRow('len', len);
|
||||||
|
h1.DataTipTemplate.DataTipRows(end+1) = ...
|
||||||
|
dataTipTextRow('lambda', lambda);
|
||||||
|
end
|
||||||
|
|
||||||
|
xticks(sort(unique(lambda)));
|
||||||
|
xticklabels(sort(unique(lambda)));
|
||||||
|
|
||||||
|
grid on;
|
||||||
|
|
||||||
|
% Labels, scales, legend, etc.
|
||||||
|
xlabel('Wavelength in nm','FontSize',12);
|
||||||
|
ylabel('BER','FontSize',12);
|
||||||
|
tit = sprintf('%d GBd PAM-%d',baudrate.*1e-9, M);
|
||||||
|
title(tit,'FontSize',14,'FontWeight','bold');
|
||||||
|
set(gca, 'XScale','linear','YScale','log','FontSize',11);
|
||||||
|
legend
|
||||||
|
|
||||||
|
xlim([min(lambda)-2, max(lambda)+2]);
|
||||||
|
ylim([1e-4, 0.2]);
|
||||||
|
|
||||||
|
cnt = cnt+1;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
yline([4.85e-3, 2e-2],'--','LineWidth',1,'HandleVisibility','off');
|
||||||
|
posH = get(f, 'Position'); % [left, bottom, width, height]
|
||||||
|
newPos = [posH(1), posH(2), 750, 300];
|
||||||
|
set(f, 'Position', newPos);
|
||||||
284
projects/HighSpeedExperiment_2024/Auswertung_JLT/ber_vs_rate.m
Normal file
284
projects/HighSpeedExperiment_2024/Auswertung_JLT/ber_vs_rate.m
Normal file
@@ -0,0 +1,284 @@
|
|||||||
|
|
||||||
|
database_type = 'mysql';
|
||||||
|
dataBase = 'labor_highspeed';%'C:\Users\Silas\Documents\MATLAB\Datensätze\sioe_labor\silas_labor_newdsp_newstructure.db';
|
||||||
|
db = DBHandler("dataBase", [dataBase], "type", database_type);
|
||||||
|
|
||||||
|
fp = QueryFilter();
|
||||||
|
% fp.where('Runs', 'run_id','EQUALS', 987);
|
||||||
|
M = 6;
|
||||||
|
fp.where('Runs', 'pam_level','EQUALS', M);
|
||||||
|
% fp.where('Runs', 'bitrate','LESS_THAN', 310e9);
|
||||||
|
fp.where('Runs', 'fiber_length','EQUALS', 2);
|
||||||
|
fp.where('Runs', 'is_mpi','EQUALS', 0);
|
||||||
|
% fp.where('Runs', 'interference_path_length','EQUALS', 1000);
|
||||||
|
% fp.where('Runs', 'loop_id','GREATER_THAN', 11);
|
||||||
|
% fp.where('Runs', 'sir','EQUALS',18);
|
||||||
|
fp.where('Runs', 'wavelength','EQUALS', 1310);
|
||||||
|
% fp.where('Runs', 'db_mode','EQUALS', 0);
|
||||||
|
fp.where('Runs', 'rop_attenuation','EQUALS', 0);
|
||||||
|
|
||||||
|
fields = db.getTableFieldNames('power_state_info');
|
||||||
|
fields = [fields; db.getTableFieldNames('dashboard_ungrouped_aug_nov_2025')];
|
||||||
|
[dataTable,~] = db.queryDB(fp, fields);
|
||||||
|
|
||||||
|
eqstructures = unique(dataTable.equalizer_structure);
|
||||||
|
% Create the figure
|
||||||
|
showFiltered = true;
|
||||||
|
showPrecoded = false;
|
||||||
|
show_bitrate = true;
|
||||||
|
figure(5);
|
||||||
|
hold on
|
||||||
|
|
||||||
|
for eqs = [equalizer_structure.vnle]
|
||||||
|
|
||||||
|
% figure('Name',string([char(eqs),'']));
|
||||||
|
% hold on
|
||||||
|
|
||||||
|
for pre_emph = [0,1]
|
||||||
|
|
||||||
|
dbmode_filtered = dataTable(dataTable.db_mode == ~pre_emph,:);
|
||||||
|
|
||||||
|
eq_choice = equalizer_structure(eqs);
|
||||||
|
|
||||||
|
if sum(eqstructures == eq_choice)~=1
|
||||||
|
disp(eq_choice)
|
||||||
|
continue
|
||||||
|
end
|
||||||
|
|
||||||
|
eq_filtered = dbmode_filtered(dbmode_filtered.equalizer_structure == eq_choice,:);
|
||||||
|
|
||||||
|
% ===== NEW: compute averages + per-row keep masks (robust filtering) =====
|
||||||
|
[Tav, keepMask, keepMaskP] = avgBerBySymbolrate(eq_filtered); % <= NEW
|
||||||
|
|
||||||
|
% x-values (bitrate) for raw points (same mapping as your lines)
|
||||||
|
M = unique(eq_filtered.pam_level); % (assumes single PAM per curve)
|
||||||
|
if show_bitrate
|
||||||
|
x_raw = eq_filtered.symbolrate.*1e-9 .* floor(log2(M)*10)/10;
|
||||||
|
else
|
||||||
|
x_raw = eq_filtered.symbolrate.*1e-9;
|
||||||
|
end
|
||||||
|
|
||||||
|
% ===== NEW: scatter kept raw BER points (hidden from legend) =====
|
||||||
|
cols = cbrewer2('Paired',12);
|
||||||
|
thisColor = cols((2*eqs)+1+pre_emph,:);
|
||||||
|
scatter(x_raw(keepMask), ... % kept points
|
||||||
|
eq_filtered.BER(keepMask), ...
|
||||||
|
14, thisColor, 'filled', ...
|
||||||
|
'MarkerFaceAlpha', 0.35, ...
|
||||||
|
'MarkerEdgeAlpha', 0.35, ...
|
||||||
|
'HandleVisibility','off');
|
||||||
|
|
||||||
|
if showPrecoded
|
||||||
|
scatter(x_raw(keepMaskP), ... % kept precoded points
|
||||||
|
eq_filtered.BER_precoded(keepMaskP), ...
|
||||||
|
14, thisColor, 'filled', ...
|
||||||
|
'Marker', 'square', ...
|
||||||
|
'MarkerFaceAlpha', 0.35, ...
|
||||||
|
'MarkerEdgeAlpha', 0.35, ...
|
||||||
|
'HandleVisibility','off');
|
||||||
|
end
|
||||||
|
|
||||||
|
% ===== NEW: optionally show filtered-out points in red =====
|
||||||
|
if showFiltered
|
||||||
|
bad = ~keepMask;
|
||||||
|
if any(bad)
|
||||||
|
scatter(x_raw(bad), eq_filtered.BER(bad), ...
|
||||||
|
18, 'r', 'x', 'LineWidth', 1.2, ...
|
||||||
|
'HandleVisibility','off');
|
||||||
|
end
|
||||||
|
badp = ~keepMaskP;
|
||||||
|
if any(badp)
|
||||||
|
scatter(x_raw(badp), eq_filtered.BER_precoded(badp), ...
|
||||||
|
18, 'r', '+', 'LineWidth', 1.2, ...
|
||||||
|
'HandleVisibility','off');
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
% Keep your sorting and one-per-symbolrate behavior (using Tav)
|
||||||
|
symbolrate_sorted = sortrows(Tav,{'symbolrate','avg_BER_calc'}, 'ascend');
|
||||||
|
[~, ia] = unique(symbolrate_sorted.symbolrate, 'first');
|
||||||
|
symbolrate_sorted = symbolrate_sorted(ia, :);
|
||||||
|
|
||||||
|
if show_bitrate
|
||||||
|
% Bitrate for the averaged curves (unchanged)
|
||||||
|
xraw = symbolrate_sorted.symbolrate.*1e-9 .* floor(log2(M)*10)/10;
|
||||||
|
else
|
||||||
|
xraw = symbolrate_sorted.symbolrate.*1e-9;
|
||||||
|
end
|
||||||
|
% Use the MATLAB-averaged BERs
|
||||||
|
ber = symbolrate_sorted.avg_BER_calc;
|
||||||
|
ber_precoded = symbolrate_sorted.avg_BER_precoded_calc;
|
||||||
|
|
||||||
|
|
||||||
|
dname = strrep([char(eq_choice)],'_',' ');
|
||||||
|
if pre_emph
|
||||||
|
dname = [dname,' with pre-emph.'];
|
||||||
|
else
|
||||||
|
dname = [dname,' w/o pre-emph.'];
|
||||||
|
end
|
||||||
|
|
||||||
|
plot(xraw, ber, ...
|
||||||
|
'LineWidth', 1.5, 'MarkerSize', 5, ...
|
||||||
|
'Marker','o','LineStyle','-', ...
|
||||||
|
'Color',thisColor,'MarkerEdgeColor',thisColor,'MarkerFaceColor',[1,1,1], ...
|
||||||
|
'DisplayName', dname);
|
||||||
|
|
||||||
|
if showPrecoded
|
||||||
|
plot(xraw, ber_precoded, ...
|
||||||
|
'LineWidth', 1.5, 'MarkerSize', 5, ...
|
||||||
|
'Marker','square','LineStyle',':', ...
|
||||||
|
'Color',thisColor,'MarkerEdgeColor',thisColor,'MarkerFaceColor',[1,1,1], ...
|
||||||
|
'DisplayName', [dname,'; pre-coded']);
|
||||||
|
end
|
||||||
|
|
||||||
|
grid on;
|
||||||
|
|
||||||
|
if show_bitrate
|
||||||
|
xlabel('Net bitrate [GBps]', 'FontSize', 12);
|
||||||
|
else
|
||||||
|
xlabel('Symbol rate [GBd]', 'FontSize', 12);
|
||||||
|
end
|
||||||
|
ylabel('BER', 'FontSize', 12);
|
||||||
|
title('BER vs. Baud Rate','FontSize', 14, 'FontWeight', 'bold');
|
||||||
|
|
||||||
|
set(gca, 'XScale', 'linear', ...
|
||||||
|
'YScale', 'log', ...
|
||||||
|
'TickLabelInterpreter', 'latex', ...
|
||||||
|
'FontSize', 11);
|
||||||
|
|
||||||
|
xticks(xraw);
|
||||||
|
if show_bitrate
|
||||||
|
% xticks(200:25:500);
|
||||||
|
% xlim([350 500]);
|
||||||
|
xlim([min(xraw), max(xraw)]);
|
||||||
|
else
|
||||||
|
xlim([min(xraw), max(xraw)]);
|
||||||
|
end
|
||||||
|
|
||||||
|
ylim([1e-4, 0.5]);
|
||||||
|
|
||||||
|
end
|
||||||
|
yline([2.2e-4, 4.85e-3, 2e-2],'LineWidth',1,'LineStyle','--','HandleVisibility','off');
|
||||||
|
end
|
||||||
|
|
||||||
|
function [Tav, keepAll, keepAllP] = avgBerBySymbolrate(T, ZT, MIN_G)
|
||||||
|
% Minimal robust averaging of BER per symbolrate (+ masks for kept points).
|
||||||
|
% Usage: [Tav, keepAll, keepAllP] = avgBerBySymbolrate(T, ZT, MIN_G)
|
||||||
|
% Defaults: ZT=3 (MAD z-thresh in log10), MIN_G=2 (min points to filter)
|
||||||
|
|
||||||
|
if nargin < 2, ZT = 5; end
|
||||||
|
if nargin < 5, MIN_G = 0; end
|
||||||
|
|
||||||
|
hasP = ismember('BER_precoded', T.Properties.VariableNames);
|
||||||
|
hasNB = ismember('numBits', T.Properties.VariableNames);
|
||||||
|
|
||||||
|
[G,~,idx] = unique(T.symbolrate);
|
||||||
|
nG = numel(G);
|
||||||
|
|
||||||
|
avgBER = nan(nG,1);
|
||||||
|
avgBERp = nan(nG,1);
|
||||||
|
keepAll = false(height(T),1);
|
||||||
|
keepAllP = false(height(T),1);
|
||||||
|
|
||||||
|
for gi = 1:nG
|
||||||
|
r = idx==gi;
|
||||||
|
|
||||||
|
x = T.BER(r);
|
||||||
|
nb = hasNB * T.numBits(r) + ~hasNB; % if missing, nb==1 (scalar expansion ok)
|
||||||
|
|
||||||
|
[avgBER(gi), keepAll(r)] = rmeanBer(x, nb, ZT, MIN_G);
|
||||||
|
|
||||||
|
if hasP
|
||||||
|
xp = T.BER_precoded(r);
|
||||||
|
[avgBERp(gi), keepAllP(r)] = rmeanBer(xp, nb, ZT, MIN_G);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
Tav = table(G, avgBER, avgBERp, ...
|
||||||
|
'VariableNames', {'symbolrate','avg_BER_calc','avg_BER_precoded_calc'});
|
||||||
|
end
|
||||||
|
|
||||||
|
function [mu, keep] = rmeanBer(x, nb, ZT, MIN_G, onlyHighOutliers, minKeepThreshold)
|
||||||
|
% Robust arithmetic mean of BER with log-domain MAD filtering (returns keep mask)
|
||||||
|
%
|
||||||
|
% Params:
|
||||||
|
% x : BER values
|
||||||
|
% nb : numBits (for floor)
|
||||||
|
% ZT : MAD z-threshold
|
||||||
|
% MIN_G : min group size before filtering
|
||||||
|
% onlyHighOutliers : (bool) if true, only discard values above mean
|
||||||
|
% minKeepThreshold : values below this BER are always kept
|
||||||
|
%
|
||||||
|
% Returns:
|
||||||
|
% mu : robust mean
|
||||||
|
% keep : logical mask of kept samples
|
||||||
|
|
||||||
|
if nargin < 5, onlyHighOutliers = false; end
|
||||||
|
if nargin < 6, minKeepThreshold = 0; end
|
||||||
|
|
||||||
|
x(~isfinite(x)) = NaN;
|
||||||
|
|
||||||
|
if ~isscalar(nb), nb(~isfinite(nb)) = NaN; end
|
||||||
|
if isscalar(nb) && ~isfinite(nb), nb = 1; end
|
||||||
|
|
||||||
|
floorVal = realmin;
|
||||||
|
if ~isscalar(nb) || (isscalar(nb) && isfinite(nb) && nb~=1)
|
||||||
|
fv = 0.5 ./ max(nb, eps); % rule-of-three style floor
|
||||||
|
if isscalar(fv), floorVal = fv; else, floorVal = fv; end
|
||||||
|
end
|
||||||
|
|
||||||
|
xAdj = x;
|
||||||
|
bad = ~isfinite(xAdj) | xAdj <= 0;
|
||||||
|
if isscalar(floorVal)
|
||||||
|
xAdj(bad) = floorVal;
|
||||||
|
else
|
||||||
|
xAdj(bad) = floorVal(bad);
|
||||||
|
end
|
||||||
|
|
||||||
|
valid = isfinite(xAdj) & xAdj > 0;
|
||||||
|
keep = false(size(xAdj));
|
||||||
|
|
||||||
|
if nnz(valid)==0
|
||||||
|
mu = NaN; return
|
||||||
|
end
|
||||||
|
if nnz(valid) < MIN_G
|
||||||
|
mu = mean(xAdj(valid),'omitnan'); keep(valid)=true; return
|
||||||
|
end
|
||||||
|
|
||||||
|
lx = log10(xAdj(valid));
|
||||||
|
med = median(lx,'omitnan');
|
||||||
|
mad = median(abs(lx-med),'omitnan');
|
||||||
|
|
||||||
|
if mad<=0 || ~isfinite(mad)
|
||||||
|
keep(valid) = true;
|
||||||
|
mu = mean(xAdj(valid),'omitnan');
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
sigma = 1.4826*mad;
|
||||||
|
ksel = abs(lx-med) <= ZT*sigma;
|
||||||
|
|
||||||
|
% convert to linear indices
|
||||||
|
vIdx = find(valid);
|
||||||
|
|
||||||
|
% === Extension A: only drop high outliers ===
|
||||||
|
if onlyHighOutliers
|
||||||
|
logMean = mean(lx,'omitnan');
|
||||||
|
highIdx = lx > logMean;
|
||||||
|
ksel = ksel | ~highIdx; % always keep values below/equal to mean
|
||||||
|
end
|
||||||
|
|
||||||
|
% === Extension B: always keep values below minKeepThreshold ===
|
||||||
|
belowThr = xAdj(valid) < minKeepThreshold;
|
||||||
|
ksel = ksel | belowThr;
|
||||||
|
|
||||||
|
keep(vIdx(ksel)) = true;
|
||||||
|
|
||||||
|
if any(keep)
|
||||||
|
mu = mean(xAdj(keep),'omitnan');
|
||||||
|
else
|
||||||
|
mu = mean(xAdj(valid),'omitnan');
|
||||||
|
keep(valid) = true;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
@@ -0,0 +1,117 @@
|
|||||||
|
|
||||||
|
database_type = 'mysql';
|
||||||
|
dataBase = 'labor_highspeed';%'C:\Users\Silas\Documents\MATLAB\Datensätze\sioe_labor\silas_labor_newdsp_newstructure.db';
|
||||||
|
db = DBHandler("dataBase", [dataBase], "type", database_type);
|
||||||
|
|
||||||
|
fp = QueryFilter();
|
||||||
|
% fp.where('Runs', 'run_id','EQUALS', 987);
|
||||||
|
M = 8;
|
||||||
|
fp.where('Runs', 'pam_level','EQUALS', M);
|
||||||
|
% fp.where('Runs', 'bitrate','LESS_THAN', 310e9);
|
||||||
|
fp.where('Runs', 'fiber_length','EQUALS', 2);
|
||||||
|
fp.where('Runs', 'is_mpi','EQUALS', 0);
|
||||||
|
% fp.where('Runs', 'interference_path_length','EQUALS', 1000);
|
||||||
|
% fp.where('Runs', 'loop_id','GREATER_THAN', 11);
|
||||||
|
% fp.where('Runs', 'sir','EQUALS',18);
|
||||||
|
fp.where('Runs', 'wavelength','EQUALS', 1310);
|
||||||
|
% fp.where('Runs', 'db_mode','EQUALS', 1);
|
||||||
|
fp.where('Runs', 'rop_attenuation','EQUALS', 0);
|
||||||
|
|
||||||
|
[dataTable,~] = db.queryDB(fp, db.getTableFieldNames('dashboard_ungrouped_after_nov_2025'));
|
||||||
|
|
||||||
|
eqstructures = unique(dataTable.equalizer_structure);
|
||||||
|
|
||||||
|
% Create the figure
|
||||||
|
f=figure(4);
|
||||||
|
hold on
|
||||||
|
|
||||||
|
eqs = [equalizer_structure.vnle, equalizer_structure.vnle_pf_mlse , equalizer_structure.vnle_db_mlse];
|
||||||
|
cols = [0.4660 0.6740 0.1880 ; 0.9290 0.6940 0.1250 ; 0 0.4470 0.7410; 0.4940 0.1840 0.5560]; %VNLE; PF ; DFE ; DB tgt
|
||||||
|
|
||||||
|
eq_choice = equalizer_structure.vnle;
|
||||||
|
pre_emph = 1;
|
||||||
|
dbmode_filtered = dataTable(dataTable.db_mode == ~pre_emph,:);
|
||||||
|
eq_filtered = dbmode_filtered(dbmode_filtered.equalizer_structure == eq_choice,:);
|
||||||
|
symbolrate_sorted = sortrows(eq_filtered,{'symbolrate','min_BER_precoded'}, 'ascend');
|
||||||
|
[~, ia] = unique(symbolrate_sorted.symbolrate, 'first');
|
||||||
|
symbolrate_sorted = symbolrate_sorted(ia, :);
|
||||||
|
symbolrate = symbolrate_sorted.symbolrate.*1e-9; % in baud
|
||||||
|
bitrate = symbolrate * floor(log2(M)*10)/10;
|
||||||
|
ber = symbolrate_sorted.min_BER; % BER
|
||||||
|
ber_precoded = symbolrate_sorted.min_BER_precoded; % BER
|
||||||
|
plot(bitrate, ber, 'LineWidth', 1.5, 'MarkerSize', 5,'Marker','v','LineStyle',':','Color',cols(1,:),'MarkerEdgeColor',cols(1,:),'MarkerFaceColor',cols(1,:),'DisplayName',['Tx pre-emphasis + VNLE']);
|
||||||
|
|
||||||
|
eq_choice = equalizer_structure.vnle_pf_mlse;
|
||||||
|
pre_emph = 0;
|
||||||
|
dbmode_filtered = dataTable(dataTable.db_mode == ~pre_emph,:);
|
||||||
|
eq_filtered = dbmode_filtered(dbmode_filtered.equalizer_structure == eq_choice,:);
|
||||||
|
symbolrate_sorted = sortrows(eq_filtered,{'symbolrate','min_BER_precoded'}, 'ascend');
|
||||||
|
[~, ia] = unique(symbolrate_sorted.symbolrate, 'first');
|
||||||
|
symbolrate_sorted = symbolrate_sorted(ia, :);
|
||||||
|
symbolrate = symbolrate_sorted.symbolrate.*1e-9; % in baud
|
||||||
|
bitrate = symbolrate * floor(log2(M)*10)/10;
|
||||||
|
ber = symbolrate_sorted.min_BER; % BER
|
||||||
|
ber_precoded = symbolrate_sorted.min_BER_precoded; % BER
|
||||||
|
plot(bitrate, ber, 'LineWidth', 1.5, 'MarkerSize', 5,'Marker','diamond','LineStyle',':','Color',cols(2,:),'MarkerEdgeColor',cols(2,:),'MarkerFaceColor',cols(2,:),'DisplayName',['VNLE+2-tap post-filter+MLSE']);
|
||||||
|
|
||||||
|
% eq_choice = equalizer_structure.dfe;
|
||||||
|
% pre_emph = 1;
|
||||||
|
% dbmode_filtered = dataTable(dataTable.db_mode == ~pre_emph,:);
|
||||||
|
% eq_filtered = dbmode_filtered(dbmode_filtered.equalizer_structure == eq_choice,:);
|
||||||
|
% symbolrate_sorted = sortrows(eq_filtered,{'symbolrate','min_BER_precoded'}, 'ascend');
|
||||||
|
% [~, ia] = unique(symbolrate_sorted.symbolrate, 'first');
|
||||||
|
% symbolrate_sorted = symbolrate_sorted(ia, :);
|
||||||
|
% symbolrate = symbolrate_sorted.symbolrate.*1e-9; % in baud
|
||||||
|
% bitrate = symbolrate * floor(log2(M)*10)/10;
|
||||||
|
% ber = symbolrate_sorted.min_BER; % BER
|
||||||
|
% ber_precoded = symbolrate_sorted.min_BER_precoded; % BER
|
||||||
|
% plot(bitrate, ber, 'LineWidth', 1.5, 'MarkerSize', 5,'Marker','o','LineStyle','-','Color',cols(3,:),'MarkerEdgeColor',cols(3,:),'MarkerFaceColor',cols(3,:),'DisplayName',[char(eq_choice)]);
|
||||||
|
|
||||||
|
eq_choice = equalizer_structure.vnle_db_mlse;
|
||||||
|
pre_emph = 0;
|
||||||
|
dbmode_filtered = dataTable(dataTable.db_mode == ~pre_emph,:);
|
||||||
|
eq_filtered = dbmode_filtered(dbmode_filtered.equalizer_structure == eq_choice,:);
|
||||||
|
symbolrate_sorted = sortrows(eq_filtered,{'symbolrate','min_BER_precoded'}, 'ascend');
|
||||||
|
[~, ia] = unique(symbolrate_sorted.symbolrate, 'first');
|
||||||
|
symbolrate_sorted = symbolrate_sorted(ia, :);
|
||||||
|
symbolrate = symbolrate_sorted.symbolrate.*1e-9; % in baud
|
||||||
|
bitrate = symbolrate * floor(log2(M)*10)/10;
|
||||||
|
ber = symbolrate_sorted.min_BER; % BER
|
||||||
|
ber_precoded = symbolrate_sorted.min_BER_precoded; % BER
|
||||||
|
plot(bitrate, ber_precoded, 'LineWidth', 1.5, 'MarkerSize', 5,'Marker','square','LineStyle',':','Color',cols(4,:),'MarkerEdgeColor',cols(4,:),'MarkerFaceColor',cols(4,:),'DisplayName',['DB precoding + DB tgt. + MLSE']);
|
||||||
|
|
||||||
|
|
||||||
|
% Axis labels and title with Arial font
|
||||||
|
xlabel('Gross bitrate [Gb/s]', 'FontSize', 12, 'FontName', 'Arial', 'Interpreter', 'none');
|
||||||
|
ylabel('BER', 'FontSize', 12, 'FontName', 'Arial', 'Interpreter', 'none');
|
||||||
|
title('', 'FontSize', 14, 'FontWeight', 'bold', 'FontName', 'Arial', 'Interpreter', 'none');
|
||||||
|
|
||||||
|
% Improve tick formatting
|
||||||
|
set(gca, 'XScale', 'linear', ...
|
||||||
|
'YScale', 'log', ...
|
||||||
|
'TickLabelInterpreter', 'none', ...
|
||||||
|
'FontSize', 11, ...
|
||||||
|
'FontName', 'Arial');
|
||||||
|
|
||||||
|
% Legend with Arial font
|
||||||
|
% legend('FontName', 'Arial', 'Interpreter', 'none','Location','best');
|
||||||
|
|
||||||
|
xticks(bitrate);
|
||||||
|
|
||||||
|
% Optional: tighten axis limits
|
||||||
|
xlim([min(bitrate), max(bitrate)]);
|
||||||
|
ylim([5e-4, 0.05]);
|
||||||
|
|
||||||
|
yline([3.8e-3], 'LineWidth', 2, 'LineStyle', '--', ...
|
||||||
|
'HandleVisibility', 'off', 'LabelHorizontalAlignment', 'left');
|
||||||
|
|
||||||
|
posH = get(f, 'Position'); % [left, bottom, width, height]
|
||||||
|
newPos = [posH(1), posH(2), 350, 200];
|
||||||
|
set(f, 'Position', newPos);
|
||||||
|
|
||||||
|
annotation(f,'textbox',...
|
||||||
|
[0.398095238095238 0.273381294964029 0.491428571428572 0.140287769784173],...
|
||||||
|
'String',{'PAM-8; 2 km; 1293 nm'},...
|
||||||
|
'LineWidth',0.5,...
|
||||||
|
'FitBoxToText','off',...
|
||||||
|
'BackgroundColor',[1 1 1]);
|
||||||
@@ -0,0 +1,146 @@
|
|||||||
|
%% ============================================================
|
||||||
|
% SETTINGS
|
||||||
|
% ============================================================
|
||||||
|
database_type = 'mysql';
|
||||||
|
db = DBHandler("dataBase", "labor_highspeed", "type", database_type);
|
||||||
|
|
||||||
|
fiberL = 1; % km
|
||||||
|
wlen = 1310; % nm
|
||||||
|
bit = 300e9; % example (adjust if needed)
|
||||||
|
max_pd = 7; % ROP limit (same as before)
|
||||||
|
|
||||||
|
PAM_list = [4 6 8]; % formats to compare
|
||||||
|
|
||||||
|
% Colors for PAM formats
|
||||||
|
colors = {clr.Paired.red, clr.Paired.green, clr.Paired.blue};
|
||||||
|
|
||||||
|
% Best DSP selection:
|
||||||
|
bestDSP = struct;
|
||||||
|
bestDSP = struct;
|
||||||
|
bestDSP.P4 = equalizer_structure.vnle_db_mlse; % PAM-4
|
||||||
|
bestDSP.P6 = equalizer_structure.vnle; % PAM-6
|
||||||
|
bestDSP.P8 = equalizer_structure.vnle; % PAM-8
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
%% ============================================================
|
||||||
|
% LOOP over PAM formats — extract data
|
||||||
|
% ============================================================
|
||||||
|
results = struct;
|
||||||
|
|
||||||
|
for pi = 1:numel(PAM_list)
|
||||||
|
M = PAM_list(pi);
|
||||||
|
eq = bestDSP.(sprintf('P%d', M));
|
||||||
|
|
||||||
|
% ---- DB FILTER ----
|
||||||
|
fp = QueryFilter();
|
||||||
|
fp.where('Runs','pam_level','EQUALS',M);
|
||||||
|
fp.where('Runs','fiber_length','EQUALS',fiberL);
|
||||||
|
fp.where('Runs','wavelength','EQUALS',wlen);
|
||||||
|
fp.where('Runs','bitrate','EQUALS',bit);
|
||||||
|
fp.where('Runs','power_pd_in','LESS_THAN',max_pd);
|
||||||
|
|
||||||
|
fields = [
|
||||||
|
db.getTableFieldNames('power_state_info');
|
||||||
|
db.getTableFieldNames('dashboard_ungrouped_alltime')
|
||||||
|
];
|
||||||
|
[T,~] = db.queryDB(fp, fields);
|
||||||
|
|
||||||
|
% ---- DSP OPTIONS ----
|
||||||
|
pre_emph = decide_preemph(M, eq);
|
||||||
|
precoded = decide_precoded(M, eq);
|
||||||
|
|
||||||
|
cfg = struct;
|
||||||
|
cfg.x_axis = 'power_mzm';
|
||||||
|
cfg.y_axis = 'BER';
|
||||||
|
cfg.agg = 'min';
|
||||||
|
cfg.outlier = 'none';
|
||||||
|
cfg.show_raw = false;
|
||||||
|
|
||||||
|
cfg.filters = struct( ...
|
||||||
|
'pam_level', M, ...
|
||||||
|
'fiber_length', fiberL, ...
|
||||||
|
'wavelength', wlen, ...
|
||||||
|
'bitrate', bit, ...
|
||||||
|
'is_mpi', 0, ...
|
||||||
|
'equalizer_structure', eq, ...
|
||||||
|
'pre_emph', pre_emph);
|
||||||
|
|
||||||
|
A = analyze_measurements_gpt(T, cfg);
|
||||||
|
|
||||||
|
results(pi).M = M;
|
||||||
|
results(pi).x = A.group{1}.x;
|
||||||
|
results(pi).color = colors{pi};
|
||||||
|
|
||||||
|
if precoded
|
||||||
|
results(pi).ber = A.group{1}.y_precoded;
|
||||||
|
else
|
||||||
|
results(pi).ber = A.group{1}.y;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
%% ============================================================
|
||||||
|
% PLOT — all PAM formats in one ROP plot
|
||||||
|
% ============================================================
|
||||||
|
fig = figure(91); hold on;
|
||||||
|
|
||||||
|
lw = 2.2; ms = 7;
|
||||||
|
|
||||||
|
for pi = 1:numel(results)
|
||||||
|
plot(results(pi).x, results(pi).ber, ...
|
||||||
|
'-o', ...
|
||||||
|
'LineWidth', lw, ...
|
||||||
|
'MarkerSize', ms, ...
|
||||||
|
'MarkerFaceColor', results(pi).color, ...
|
||||||
|
'Color', results(pi).color, ...
|
||||||
|
'DisplayName', sprintf('PAM-%d', results(pi).M));
|
||||||
|
end
|
||||||
|
|
||||||
|
set(gca,'YScale','log');
|
||||||
|
grid minor;
|
||||||
|
|
||||||
|
xlabel('ROP / Power (MZM) [dBm]');
|
||||||
|
ylabel('BER');
|
||||||
|
|
||||||
|
ylim([1e-4 2e-1]);
|
||||||
|
|
||||||
|
legend('Location','best');
|
||||||
|
title(sprintf('BER vs ROP — Best DSP (4,6,8) at %.0f GBd, λ=%d nm, %.0f km', ...
|
||||||
|
bit*1e-9, wlen, fiberL));
|
||||||
|
|
||||||
|
beautifyBERplot();
|
||||||
|
|
||||||
|
set(fig,'Position',1e3*[0.35 0.45 1.0 0.45]);
|
||||||
|
|
||||||
|
%% ============================================================
|
||||||
|
% DECISION LOGIC (INLINE FUNCTIONS)
|
||||||
|
% ============================================================
|
||||||
|
|
||||||
|
function pe = decide_preemph(M, eq)
|
||||||
|
% PRE-EMPH RULES:
|
||||||
|
switch M
|
||||||
|
case 4
|
||||||
|
if eq == equalizer_structure.vnle
|
||||||
|
pe = 1; % PAM4: VNLE → pre-emph on
|
||||||
|
else
|
||||||
|
pe = 0; % PAM4: all others → off
|
||||||
|
end
|
||||||
|
case {6,8}
|
||||||
|
pe = 1; % PAM6/8: all → pre-emph on
|
||||||
|
otherwise
|
||||||
|
pe = 0;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function flag = decide_precoded(M, eq)
|
||||||
|
% PRE-CODE RULES:
|
||||||
|
if eq == equalizer_structure.vnle_db_mlse
|
||||||
|
flag = 1; % Always for DB-target
|
||||||
|
elseif eq == equalizer_structure.ml_mlse && M == 4
|
||||||
|
flag = 1; % PAM4: ML-based → precoded
|
||||||
|
else
|
||||||
|
flag = 0;
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,272 @@
|
|||||||
|
%% ============================================================
|
||||||
|
% LOAD DATA FOR PAM = 4,6,8
|
||||||
|
% ============================================================
|
||||||
|
database_type = 'mysql';
|
||||||
|
db = DBHandler("dataBase", "labor_highspeed", "type", database_type);
|
||||||
|
|
||||||
|
pam_levels = [4, 6, 8]; % three tiles
|
||||||
|
bitrate_set = 360e9;
|
||||||
|
fiberL = 10;
|
||||||
|
|
||||||
|
fields = [
|
||||||
|
db.getTableFieldNames('power_state_info');
|
||||||
|
db.getTableFieldNames('dashboard_ungrouped_alltime')
|
||||||
|
];
|
||||||
|
|
||||||
|
%% ============================================================
|
||||||
|
% DEFINE DSP SCHEMES
|
||||||
|
% ============================================================
|
||||||
|
curves = struct;
|
||||||
|
|
||||||
|
curves(1).name = 'VNLE';
|
||||||
|
curves(1).eq = equalizer_structure.vnle;
|
||||||
|
curves(1).color = clr.Paired.red;
|
||||||
|
|
||||||
|
curves(2).name = 'PF + MLSE';
|
||||||
|
curves(2).eq = equalizer_structure.vnle_pf_mlse;
|
||||||
|
curves(2).color = clr.Paired.green;
|
||||||
|
|
||||||
|
curves(3).name = 'DB-target + MLSE';
|
||||||
|
curves(3).eq = equalizer_structure.vnle_db_mlse;
|
||||||
|
curves(3).color = clr.Paired.blue;
|
||||||
|
|
||||||
|
curves(4).name = 'ML-based MLSE';
|
||||||
|
curves(4).eq = equalizer_structure.ml_mlse;
|
||||||
|
curves(4).color = clr.Paired.purple;
|
||||||
|
|
||||||
|
%% ============================================================
|
||||||
|
% ANALYSIS — NO PLOTTING
|
||||||
|
% results(p, k) → p: PAM index, k: DSP index
|
||||||
|
% ============================================================
|
||||||
|
results = struct;
|
||||||
|
|
||||||
|
for p = 1:length(pam_levels)
|
||||||
|
M = pam_levels(p);
|
||||||
|
|
||||||
|
% --- Load DB rows for this PAM ---
|
||||||
|
fp = QueryFilter();
|
||||||
|
fp.where('Runs','pam_level','EQUALS', M);
|
||||||
|
fp.where('Runs','fiber_length','EQUALS', fiberL);
|
||||||
|
fp.where('Runs','bitrate','EQUALS', bitrate_set);
|
||||||
|
fp.where('Runs','is_mpi','EQUALS', 0);
|
||||||
|
|
||||||
|
[dataTable, ~] = db.queryDB(fp, fields);
|
||||||
|
|
||||||
|
for k = 1:numel(curves)
|
||||||
|
|
||||||
|
%% =====================================================
|
||||||
|
% DECIDE PRE-EMPHASIS AND PRECoded BER
|
||||||
|
% ======================================================
|
||||||
|
pre_emph = decide_preemph(M, curves(k).eq);
|
||||||
|
use_precoded = decide_precoded(M, curves(k).eq);
|
||||||
|
|
||||||
|
%% ---- base config ----
|
||||||
|
cfg = struct;
|
||||||
|
cfg.x_axis = 'wavelength';
|
||||||
|
cfg.y_axis = 'BER';
|
||||||
|
cfg.agg = 'min';
|
||||||
|
cfg.outlier = 'none';
|
||||||
|
% cfg.group_by = {'wavelength'};
|
||||||
|
cfg.show_raw = false;
|
||||||
|
|
||||||
|
cfg.filters = struct( ...
|
||||||
|
'pam_level', M, ...
|
||||||
|
'is_mpi', 0, ...
|
||||||
|
'bitrate', bitrate_set, ...
|
||||||
|
'fiber_length', fiberL, ...
|
||||||
|
'equalizer_structure', curves(k).eq, ...
|
||||||
|
'pre_emph', pre_emph);
|
||||||
|
|
||||||
|
%% ---- Run analysis ----
|
||||||
|
A = analyze_measurements_gpt(dataTable, cfg);
|
||||||
|
|
||||||
|
results(p,k).wavelength = A.group{1}.x;
|
||||||
|
|
||||||
|
%% ---- store BER variant ----
|
||||||
|
if use_precoded
|
||||||
|
results(p,k).ber = A.group{1}.y_precoded;
|
||||||
|
else
|
||||||
|
results(p,k).ber = A.group{1}.y;
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
%% ============================================================
|
||||||
|
% PLOT — 1×3 (PAM-4, PAM-6, PAM-8)
|
||||||
|
% ============================================================
|
||||||
|
fig = figure(9110); clf;
|
||||||
|
tiledlayout(1,3,'TileSpacing','compact','Padding','compact');
|
||||||
|
|
||||||
|
lw = 1.8;
|
||||||
|
ms = 6;
|
||||||
|
|
||||||
|
for p = 1:length(pam_levels)
|
||||||
|
nexttile; hold on;
|
||||||
|
|
||||||
|
for k = 1:numel(curves)
|
||||||
|
plot(results(p,k).wavelength, results(p,k).ber, ...
|
||||||
|
'-o', ...
|
||||||
|
'Color', curves(k).color, ...
|
||||||
|
'MarkerFaceColor', curves(k).color, ...
|
||||||
|
'MarkerSize', ms, ...
|
||||||
|
'LineWidth', lw, ...
|
||||||
|
'DisplayName', curves(k).name);
|
||||||
|
end
|
||||||
|
|
||||||
|
set(gca,'YScale','log');
|
||||||
|
grid on;
|
||||||
|
if p == 1
|
||||||
|
ylabel('BER');
|
||||||
|
else
|
||||||
|
ylabel('');
|
||||||
|
end
|
||||||
|
xlabel('wavelength');
|
||||||
|
|
||||||
|
ylim([4e-4, 0.1]);
|
||||||
|
|
||||||
|
beautifyBERplot();
|
||||||
|
|
||||||
|
yline([2.2e-4 4.85e-3 2e-2], ...
|
||||||
|
'LineWidth',1.1, 'Color',[0.2 0.2 0.2], ...
|
||||||
|
'LineStyle',':','HandleVisibility','off');
|
||||||
|
|
||||||
|
|
||||||
|
if p == 1
|
||||||
|
|
||||||
|
x1 = 1290;
|
||||||
|
x2 = 1297;
|
||||||
|
x3 = 1300;
|
||||||
|
x4 = 1323;
|
||||||
|
x5 = 1325;
|
||||||
|
x6 = 1330;
|
||||||
|
|
||||||
|
elseif p == 2
|
||||||
|
|
||||||
|
x1 = 1290;
|
||||||
|
x2 = 1295;
|
||||||
|
x3 = 1300;
|
||||||
|
x4 = 1323.5;
|
||||||
|
x5 = 1325;
|
||||||
|
x6 = 1330;
|
||||||
|
|
||||||
|
elseif p == 3
|
||||||
|
|
||||||
|
x1 = 1290;
|
||||||
|
x2 = 1292;
|
||||||
|
x3 = 1298;
|
||||||
|
x4 = 1323;
|
||||||
|
x5 = 1327.5;
|
||||||
|
x6 = 1330;
|
||||||
|
end
|
||||||
|
|
||||||
|
% --- Get current y-limits ---
|
||||||
|
yl = ylim;
|
||||||
|
|
||||||
|
% --- LEFT AREA BELOW KP4 FEC ---
|
||||||
|
patch([x1 x2 x2 x1], [yl(1) yl(1) yl(2) yl(2)], ...
|
||||||
|
clr.Set1.red, ... % RGB = red
|
||||||
|
'FaceAlpha', 0.1, ... % transparency 0.1
|
||||||
|
'EdgeColor', 'none'); % no border
|
||||||
|
|
||||||
|
% --- RIGHT AREA BELOW KP4 FEC ---
|
||||||
|
patch([x2 x3 x3 x2], [yl(1) yl(1) yl(2) yl(2)], ...
|
||||||
|
clr.Set1.blue, ... % RGB = red
|
||||||
|
'FaceAlpha', 0.10, ... % transparency 0.1
|
||||||
|
'EdgeColor', 'none'); % no border
|
||||||
|
|
||||||
|
% --- LEFT AREA BELOW O-FEC ---
|
||||||
|
patch([x4 x5 x5 x4], [yl(1) yl(1) yl(2) yl(2)], ...
|
||||||
|
clr.Set1.blue, ... % RGB = red
|
||||||
|
'FaceAlpha', 0.10, ... % transparency 0.1
|
||||||
|
'EdgeColor', 'none'); % no border
|
||||||
|
|
||||||
|
% --- RIGHT AREA BELOW O-FEC ---
|
||||||
|
patch([x5 x6 x6 x5], [yl(1) yl(1) yl(2) yl(2)], ...
|
||||||
|
clr.Set1.red, ... % RGB = red
|
||||||
|
'FaceAlpha', 0.10, ... % transparency 0.1
|
||||||
|
'EdgeColor', 'none'); % no border
|
||||||
|
|
||||||
|
uistack(findobj(gca,'Type','patch'),'bottom'); % send the patch behind curves
|
||||||
|
|
||||||
|
|
||||||
|
% ax = gca;
|
||||||
|
% axpos = ax.Position; % [x y w h] normalized
|
||||||
|
% xl = xlim;
|
||||||
|
% yl = ylim;
|
||||||
|
%
|
||||||
|
% % Convert axis coords → normalized figure coords
|
||||||
|
% toNorm = @(x,y) [ ...
|
||||||
|
% axpos(1) + (x - xl(1)) / (xl(2)-xl(1)) * axpos(3), ...
|
||||||
|
% axpos(2) + (y - yl(1)) / (yl(2)-yl(1)) * axpos(4) ...
|
||||||
|
% ];
|
||||||
|
%
|
||||||
|
% % Choose vertical placement (10% above bottom of axis)
|
||||||
|
% y_arrow = yl(1) * (yl(2)/yl(1))^0.10; % works with log-scale axes
|
||||||
|
%
|
||||||
|
% % === Arrow 1: x3 <-> x4 ======================================
|
||||||
|
% p1 = toNorm(x3, y_arrow);
|
||||||
|
% p2 = toNorm(x4, y_arrow);
|
||||||
|
%
|
||||||
|
% annotation('doublearrow', ...
|
||||||
|
% [p1(1) p2(1)], [p1(2) p2(2)], ...
|
||||||
|
% 'Color', [0 0 0], 'LineWidth', 1.4);
|
||||||
|
%
|
||||||
|
% % === Arrow 2: x2 <-> x5 ======================================
|
||||||
|
% p3 = toNorm(x2, y_arrow);
|
||||||
|
% p4 = toNorm(x5, y_arrow);
|
||||||
|
%
|
||||||
|
% annotation('doublearrow', ...
|
||||||
|
% [p3(1) p4(1)], [p3(2) p4(2)], ...
|
||||||
|
% 'Color', [0 0 0], 'LineWidth', 1.4);
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
pos = 1e3.*[2.7770 1.2017 1.4000 0.3200];
|
||||||
|
set(fig, 'Position', pos);
|
||||||
|
|
||||||
|
%% === EXPORT ===
|
||||||
|
outfile = 'C:\Users\Silas\Documents\latex\JLT_400G copy\media\matlab2tikz\wavelength_analysis.tikz';
|
||||||
|
matlab2tikz(outfile, ...
|
||||||
|
'width','\fwidth', ...
|
||||||
|
'height','\fheight', ...
|
||||||
|
'showInfo',false, ...
|
||||||
|
'extraAxisOptions',{ ...
|
||||||
|
'legend style={font=\footnotesize}', ...
|
||||||
|
'legend columns=1' ...
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
%% ============================================================
|
||||||
|
% DECISION LOGIC (INLINE FUNCTIONS)
|
||||||
|
% ============================================================
|
||||||
|
|
||||||
|
function pe = decide_preemph(M, eq)
|
||||||
|
% PRE-EMPH RULES:
|
||||||
|
switch M
|
||||||
|
case 4
|
||||||
|
if eq == equalizer_structure.vnle
|
||||||
|
pe = 1; % PAM4: VNLE → pre-emph on
|
||||||
|
else
|
||||||
|
pe = 0; % PAM4: all others → off
|
||||||
|
end
|
||||||
|
case {6,8}
|
||||||
|
pe = 1; % PAM6/8: all → pre-emph on
|
||||||
|
otherwise
|
||||||
|
pe = 0;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function flag = decide_precoded(M, eq)
|
||||||
|
% PRE-CODE RULES:
|
||||||
|
if eq == equalizer_structure.vnle_db_mlse
|
||||||
|
flag = 1; % Always for DB-target
|
||||||
|
elseif eq == equalizer_structure.ml_mlse && M == 4
|
||||||
|
flag = 1; % PAM4: ML-based → precoded
|
||||||
|
else
|
||||||
|
flag = 0;
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,132 @@
|
|||||||
|
database_type = 'mysql';
|
||||||
|
dataBase = 'labor_highspeed';
|
||||||
|
db = DBHandler("dataBase", dataBase, "type", database_type);
|
||||||
|
|
||||||
|
%% FILTER QUERY
|
||||||
|
fp = QueryFilter();
|
||||||
|
fp.where('Runs', 'fiber_length','EQUALS', 2);
|
||||||
|
fp.where('Runs', 'wavelength','EQUALS', 1310);
|
||||||
|
fp.where('Runs', 'rop_attenuation','EQUALS', 0);
|
||||||
|
|
||||||
|
fields = db.getTableFieldNames('power_state_info');
|
||||||
|
fields = [fields; db.getTableFieldNames('dashboard_ungrouped_alltime')];
|
||||||
|
|
||||||
|
[dataTable,~] = db.queryDB(fp, fields);
|
||||||
|
|
||||||
|
%% ---- CONFIG ----
|
||||||
|
cfg = struct;
|
||||||
|
cfg.x_axis = 'grossrate';
|
||||||
|
cfg.y_axis = 'BER';
|
||||||
|
cfg.y_scale = 'log';
|
||||||
|
cfg.outlier = 'mad';
|
||||||
|
cfg.show_raw = false;
|
||||||
|
cfg.show_spread = 'none';
|
||||||
|
cfg.agg = 'min';
|
||||||
|
cfg.show_precoded = 1;
|
||||||
|
cfg.fec_lines = [];
|
||||||
|
|
||||||
|
cfg.plot = struct;
|
||||||
|
cfg.plot.use_cbrewer2 = false;
|
||||||
|
cfg.plot.lineWidth = 2.0;
|
||||||
|
cfg.plot.errWidth = 1.2;
|
||||||
|
cfg.plot.scatterAlpha = 0.35;
|
||||||
|
cfg.plot.legendLocation = 'best';
|
||||||
|
cfg.plot.fecLineWidth = 2.4;
|
||||||
|
cfg.plot.custom_colors_scatter = []; % disabled
|
||||||
|
|
||||||
|
%% ---- DSP DEFINITIONS ----
|
||||||
|
DSP(1).name = 'VNLE';
|
||||||
|
DSP(1).eq = equalizer_structure.vnle;
|
||||||
|
DSP(1).color = clr.Paired.red;
|
||||||
|
DSP(1).lightcolor = clr.Paired.lightred;
|
||||||
|
|
||||||
|
DSP(2).name = 'VNLE PF MLSE';
|
||||||
|
DSP(2).eq = equalizer_structure.vnle_pf_mlse;
|
||||||
|
DSP(2).color = clr.Paired.green;
|
||||||
|
DSP(2).lightcolor = clr.Paired.lightgreen;
|
||||||
|
|
||||||
|
DSP(3).name = 'VNLE DB MLSE';
|
||||||
|
DSP(3).eq = equalizer_structure.vnle_db_mlse;
|
||||||
|
DSP(3).color = clr.Paired.blue;
|
||||||
|
DSP(3).lightcolor = clr.Paired.lightblue;
|
||||||
|
|
||||||
|
DSP(4).name = 'ML MLSE';
|
||||||
|
DSP(4).eq = equalizer_structure.ml_mlse;
|
||||||
|
DSP(4).color = clr.Paired.purple;
|
||||||
|
DSP(4).lightcolor = clr.Paired.lightpurple;
|
||||||
|
|
||||||
|
%% ---- GRID CONFIG ----
|
||||||
|
rows = 3; % PAM 4,6,8
|
||||||
|
cols = 4; % DSP schemes
|
||||||
|
pam = [4 6 8];
|
||||||
|
|
||||||
|
cfg.figure_number = 46;
|
||||||
|
fig = figure(cfg.figure_number); clf;
|
||||||
|
|
||||||
|
t = tiledlayout(rows, cols, ...
|
||||||
|
'TileSpacing','compact', ...
|
||||||
|
'Padding','compact');
|
||||||
|
|
||||||
|
cfg.group_by = {'equalizer_structure','pre_emph'};
|
||||||
|
cfg.plot.use_cbrewer2 = false;
|
||||||
|
|
||||||
|
%% ==== MAIN PLOT LOOP =====
|
||||||
|
for r = 1:rows
|
||||||
|
Mlev = pam(r);
|
||||||
|
|
||||||
|
for c = 1:cols
|
||||||
|
ax = nexttile(t, (r-1)*cols + c);
|
||||||
|
cfg.ax = ax;
|
||||||
|
|
||||||
|
% ---- PRE-EMPH = 1 ----
|
||||||
|
cfg.filters = struct('is_mpi',0,'pam_level',Mlev, ...
|
||||||
|
'equalizer_structure',DSP(c).eq, ...
|
||||||
|
'pre_emph',1);
|
||||||
|
cfg.plot.custom_colors = DSP(c).lightcolor;
|
||||||
|
cfg.plot.custom_linetypes = {'-'};
|
||||||
|
[~, M1] = plot_measurements_gpt(dataTable, cfg);
|
||||||
|
|
||||||
|
% ---- PRE-EMPH = 0 ----
|
||||||
|
cfg.filters.pre_emph = 0;
|
||||||
|
cfg.plot.custom_colors = DSP(c).color;
|
||||||
|
cfg.plot.custom_linetypes = {'-'};
|
||||||
|
[~, M0] = plot_measurements_gpt(dataTable, cfg);
|
||||||
|
|
||||||
|
% Axis limits
|
||||||
|
if Mlev == 4
|
||||||
|
ylim([1e-5 0.3]);
|
||||||
|
elseif Mlev == 6
|
||||||
|
ylim([6e-4 0.1]);
|
||||||
|
elseif Mlev == 8
|
||||||
|
ylim([9e-4 0.1]);
|
||||||
|
end
|
||||||
|
|
||||||
|
% ---- FEC lines ----
|
||||||
|
yline([2.2e-4 4.85e-3 2e-2], ...
|
||||||
|
'LineWidth',1.1, 'Color',[0.2 0.2 0.2], ...
|
||||||
|
'LineStyle',':','HandleVisibility','off');
|
||||||
|
|
||||||
|
beautifyBERplot;
|
||||||
|
|
||||||
|
% ---- Remove redundant labels ----
|
||||||
|
if c > 1, ax.YLabel = []; end
|
||||||
|
if r < rows, ax.XLabel = []; end
|
||||||
|
|
||||||
|
grid(ax,'on'); box(ax,'on');
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
%% ---- FIXED FIGURE SIZE ----
|
||||||
|
pos = 1e3.*[0.1070 0.5497 1.4113 0.6847];
|
||||||
|
set(fig, 'Position', pos);
|
||||||
|
|
||||||
|
% %% === EXPORT ===
|
||||||
|
% outfile = 'C:\Users\Silas\Documents\latex\JLT_400G copy\media\matlab2tikz\compare_pre_emphasis.tikz';
|
||||||
|
% matlab2tikz(outfile, ...
|
||||||
|
% 'width','\fwidth', ...
|
||||||
|
% 'height','\fheight', ...
|
||||||
|
% 'showInfo',false, ...
|
||||||
|
% 'extraAxisOptions',{ ...
|
||||||
|
% 'legend style={font=\footnotesize}', ...
|
||||||
|
% 'legend columns=1' ...
|
||||||
|
% });
|
||||||
@@ -0,0 +1,257 @@
|
|||||||
|
dsp_options.storage_path = 'Z:\2024\sioe_labor\';
|
||||||
|
dsp_options.max_occurences = 1;
|
||||||
|
database = DBHandler("dataBase", 'labor_highspeed', "type", 'mysql' );
|
||||||
|
|
||||||
|
rate = [300e9];
|
||||||
|
cols = cbrewer2('BuPu',25);
|
||||||
|
cols = [cols(end-10:2:end,:)];
|
||||||
|
cols = cbrewer2('Set1',6);
|
||||||
|
|
||||||
|
fignum = 200;
|
||||||
|
fig=figure(fignum);clf;
|
||||||
|
|
||||||
|
dbmode = 0;
|
||||||
|
|
||||||
|
|
||||||
|
% 1 - PAM 4 with preemphasis
|
||||||
|
fp = QueryFilter();
|
||||||
|
M = 6;
|
||||||
|
fp.where('Runs', 'pam_level','EQUALS', M);
|
||||||
|
fp.where('Runs', 'bitrate','EQUALS', rate);%360,390
|
||||||
|
fp.where('Runs', 'fiber_length','EQUALS', 2);
|
||||||
|
fp.where('Runs', 'wavelength','EQUALS', 1310);
|
||||||
|
fp.where('Runs', 'db_mode','EQUALS', dbmode);
|
||||||
|
fp.where('Runs', 'rop_attenuation','EQUAL', 0);
|
||||||
|
|
||||||
|
[dataTable,~] = db.queryDB(fp, database.getTableFieldNames('Runs'));
|
||||||
|
|
||||||
|
dataTable = queryRunid(dataTable.run_id, database);
|
||||||
|
fsym = dataTable.symbolrate;
|
||||||
|
M = double(dataTable.pam_level);
|
||||||
|
duob_mode = db_mode(strrep(dataTable.db_mode,'"',''));
|
||||||
|
|
||||||
|
% Load and Sync signal data from DB
|
||||||
|
[Tx_bits, Symbols, Scpe_cell, ~] = loadAndSyncSignalDataFromDb(dataTable, dsp_options);
|
||||||
|
|
||||||
|
% Preprocess signal
|
||||||
|
Scpe_sig = preprocessSignal(Scpe_cell{1}, Symbols, fsym);
|
||||||
|
|
||||||
|
Scpe_sig.eye(fsym,M,"fignum",M*10);
|
||||||
|
|
||||||
|
%% === EXPORT TO TIKZ ===
|
||||||
|
% outfile = ['C:\Users\Silas\Documents\latex\JLT_400G copy\media\matlab2tikz\eye_pam_',num2str(M),'.tikz'];
|
||||||
|
% outfile = ['C:\Users\Silas\Documents\latex\JLT_400G copy\media\matlab2tikz\vnle_optimization.tikz'];
|
||||||
|
% matlab2tikz(outfile, ...
|
||||||
|
% 'width','\fwidth', ...
|
||||||
|
% 'height','\fheight', ...
|
||||||
|
% 'showInfo',false, ...
|
||||||
|
% 'extraAxisOptions',{ ...
|
||||||
|
% 'legend style={font=\footnotesize}', ...
|
||||||
|
% 'legend columns=1' ...
|
||||||
|
% } );
|
||||||
|
|
||||||
|
%%
|
||||||
|
|
||||||
|
if duob_mode == db_mode.no_db && M == 6 %only for PAM-6 and no duobinary precoding, otherwise leads to false sequence estimation
|
||||||
|
trellexlusion = 1;
|
||||||
|
else
|
||||||
|
trellexlusion = 0;
|
||||||
|
end
|
||||||
|
mlse_db_ = MLSE("DIR",[1,1],"duobinary_output",0,"M",M,"trellis_states",PAMmapper(M,0).levels,'scale_mode',2,'trellis_exclusion',trellexlusion,'trellis_state_mode',3);
|
||||||
|
len_tr = 4096*2;
|
||||||
|
|
||||||
|
ffe_order = [50, 5, 5];
|
||||||
|
dfe_order = [0, 0, 0];
|
||||||
|
pf_ncoeffs = 1;
|
||||||
|
mu_ffe = [0.0001, 0.0008, 0.001];
|
||||||
|
mu_dfe = 0.0004;
|
||||||
|
mu_dc = 0.005;
|
||||||
|
dc_buffer_len = 1;
|
||||||
|
|
||||||
|
mu_tr = 0;
|
||||||
|
mu_dd = 0.05;
|
||||||
|
adaption= 1;
|
||||||
|
use_dd_mode = 1;
|
||||||
|
ffe_order = [50, 5, 5];
|
||||||
|
eq_ = EQ("Ne",ffe_order,"Nb",dfe_order,"training_length",len_tr,"training_loops",5,"dd_loops",5,"K",2,"DCmu",mu_dc,"DDmu",[mu_ffe mu_dfe],"DFEmu",0.005,"FFEmu",0,"plotfinal",0,"ideal_dfe",1);
|
||||||
|
|
||||||
|
dbt_results = duobinary_target(eq_, mlse_db_, M, Scpe_sig, Symbols, Tx_bits, ...
|
||||||
|
"precode_mode", duob_mode, ...
|
||||||
|
'showAnalysis', 1,...
|
||||||
|
"postFFE", []);
|
||||||
|
|
||||||
|
%% === FINAL FIGURE SIZE ===
|
||||||
|
|
||||||
|
% Existing figure numbers
|
||||||
|
figEye = 249;
|
||||||
|
figConst = 341;
|
||||||
|
|
||||||
|
% Find axes in the source figures
|
||||||
|
srcAxEye = findobj(figEye, 'Type', 'axes');
|
||||||
|
srcAxConst = findobj(figConst, 'Type', 'axes');
|
||||||
|
|
||||||
|
% Create new combined figure
|
||||||
|
figCombined = figure;
|
||||||
|
t = tiledlayout(figCombined, 1, 2);
|
||||||
|
t.TileSpacing = 'compact';
|
||||||
|
t.Padding = 'compact';
|
||||||
|
|
||||||
|
% ------------------------------------------------------------
|
||||||
|
% LEFT TILE: EYE DIAGRAM
|
||||||
|
% ------------------------------------------------------------
|
||||||
|
ax1 = nexttile(t, 1);
|
||||||
|
hold(ax1, 'on')
|
||||||
|
|
||||||
|
% Copy children (images, lines, patches, hist objects, etc.)
|
||||||
|
copyobj(srcAxEye.Children, ax1);
|
||||||
|
|
||||||
|
% Copy labels and title
|
||||||
|
ax1.XLabel.String = srcAxEye.XLabel.String;
|
||||||
|
ax1.YLabel.String = srcAxEye.YLabel.String;
|
||||||
|
ax1.Title.String = srcAxEye.Title.String;
|
||||||
|
|
||||||
|
% Copy axis limits
|
||||||
|
ax1.XLim = srcAxEye.XLim;
|
||||||
|
ax1.YLim = srcAxEye.YLim;
|
||||||
|
ax1.YDir = srcAxEye.YDir;
|
||||||
|
|
||||||
|
% Copy ticks + labels EXACTLY (including remapped/scaled ones)
|
||||||
|
ax1.XTick = srcAxEye.XTick;
|
||||||
|
ax1.XTickLabel = srcAxEye.XTickLabel;
|
||||||
|
ax1.YTick = srcAxEye.YTick;
|
||||||
|
ax1.YTickLabel = srcAxEye.YTickLabel;
|
||||||
|
|
||||||
|
% Copy colormap + clim (important for density eye)
|
||||||
|
colormap(ax1, colormap(srcAxEye.Parent));
|
||||||
|
ax1.CLim = srcAxEye.CLim;
|
||||||
|
|
||||||
|
% Copy any style props that matter
|
||||||
|
ax1.TickDir = srcAxEye.TickDir;
|
||||||
|
ax1.TickLength = srcAxEye.TickLength;
|
||||||
|
ax1.FontSize = srcAxEye.FontSize;
|
||||||
|
ax1.Box = srcAxEye.Box;
|
||||||
|
|
||||||
|
grid(ax1,'on');
|
||||||
|
|
||||||
|
|
||||||
|
% ------------------------------------------------------------
|
||||||
|
% RIGHT TILE: CONSTELLATION HISTOGRAM
|
||||||
|
% ------------------------------------------------------------
|
||||||
|
ax2 = nexttile(t, 2);
|
||||||
|
hold(ax2, 'on')
|
||||||
|
|
||||||
|
copyobj(srcAxConst.Children, ax2);
|
||||||
|
|
||||||
|
% Copy labels and title
|
||||||
|
ax2.XLabel.String = srcAxConst.XLabel.String;
|
||||||
|
ax2.YLabel.String = srcAxConst.YLabel.String;
|
||||||
|
ax2.Title.String = srcAxConst.Title.String;
|
||||||
|
|
||||||
|
% The histogram uses the same y-axis as the eye
|
||||||
|
% Extract mapping from eye
|
||||||
|
rawTicks = ax1.YTick;
|
||||||
|
rawLabelsCell = ax1.YTickLabel;
|
||||||
|
trueVoltages = str2double(rawLabelsCell);
|
||||||
|
|
||||||
|
% Apply true voltages to the histogram axis
|
||||||
|
ax2.XTick = flip(trueVoltages);
|
||||||
|
ax2.XTickLabel = flip(rawLabelsCell);
|
||||||
|
|
||||||
|
% Set histogram y-limits to match the actual voltages
|
||||||
|
ax2.XLim = [min(trueVoltages) max(trueVoltages)];
|
||||||
|
|
||||||
|
% Ensure eye diagram prints the same (we *do not* touch ax1.YLim)
|
||||||
|
ax1.XTickLabel = rawLabelsCell;
|
||||||
|
|
||||||
|
|
||||||
|
% Copy colormap (your histogram uses same palette)
|
||||||
|
colormap(ax2, colormap(srcAxConst.Parent));
|
||||||
|
|
||||||
|
% Style properties
|
||||||
|
ax2.TickDir = srcAxConst.TickDir;
|
||||||
|
ax2.TickLength = srcAxConst.TickLength;
|
||||||
|
ax2.FontSize = srcAxConst.FontSize;
|
||||||
|
ax2.Box = srcAxConst.Box;
|
||||||
|
|
||||||
|
grid(ax2,'on');
|
||||||
|
|
||||||
|
% ============================================================
|
||||||
|
% remove right y-axis completely
|
||||||
|
% ============================================================
|
||||||
|
ax2.XAxis.Visible = 'off'; % hides ticks + labels + axis line
|
||||||
|
|
||||||
|
% BUT we still keep the YTick positions internally for alignment:
|
||||||
|
% ax2.YTick = <values already set earlier> ;
|
||||||
|
|
||||||
|
|
||||||
|
% ============================================================
|
||||||
|
% minimize distance between the two plots
|
||||||
|
% ============================================================
|
||||||
|
t.TileSpacing = 'none'; % no space between tiles
|
||||||
|
t.Padding = 'none'; % no outer padding
|
||||||
|
|
||||||
|
% Also reduce internal padding for each axis
|
||||||
|
ax1.Position(3) = ax1.Position(3) + 0.02; % widen eye a bit
|
||||||
|
ax2.Position(1) = ax2.Position(1) - 0.02; % pull histogram closer
|
||||||
|
|
||||||
|
|
||||||
|
% Keep left axis grid visible
|
||||||
|
ax2.YGrid = 'off';
|
||||||
|
|
||||||
|
%
|
||||||
|
% =====================================================================
|
||||||
|
% FINAL POLISHING: unified visual style
|
||||||
|
% =======================================================================
|
||||||
|
|
||||||
|
% --- unified font size ---
|
||||||
|
FS = 12;
|
||||||
|
set([ax1 ax2], 'FontSize', FS);
|
||||||
|
|
||||||
|
% --- unified axis line width (outline stroke thickness) ---
|
||||||
|
LW = 1.0;
|
||||||
|
set([ax1 ax2], 'LineWidth', LW);
|
||||||
|
|
||||||
|
% --- unified tick length ---
|
||||||
|
TL = [.015 .015];
|
||||||
|
set([ax1 ax2], 'TickLength', TL);
|
||||||
|
|
||||||
|
% --- unified grid style ---
|
||||||
|
set([ax1 ax2], 'XGrid', 'on', 'YGrid', 'on');
|
||||||
|
set([ax1 ax2], 'GridLineStyle', '--');
|
||||||
|
set([ax1 ax2], 'GridAlpha', 0.2);
|
||||||
|
|
||||||
|
% --- remove right y-axis ticks and labels ---
|
||||||
|
ax2.YAxis.Visible = 'off';
|
||||||
|
|
||||||
|
% --- copy colormap + CLim from the eye to histogram (synchronize look) ---
|
||||||
|
colormap(ax1, colormap(srcAxEye.Parent));
|
||||||
|
colormap(ax2, colormap(srcAxEye.Parent));
|
||||||
|
ax2.CLim = ax1.CLim;
|
||||||
|
|
||||||
|
% --- minimal spacing between tiles ---
|
||||||
|
t.TileSpacing = 'none';
|
||||||
|
t.Padding = 'none';
|
||||||
|
|
||||||
|
|
||||||
|
% --- pull the panels together (touching boundary effect) ---
|
||||||
|
pos1 = ax1.Position;
|
||||||
|
pos2 = ax2.Position;
|
||||||
|
|
||||||
|
% Shift histogram left until the outlines touch
|
||||||
|
pos2(1) = pos1(1) + pos1(3) - 0.002; % 0.002 = fine overlap control
|
||||||
|
ax2.Position = pos2;
|
||||||
|
|
||||||
|
% Expand histogram slightly, remove white band
|
||||||
|
pos2 = ax2.Position;
|
||||||
|
pos2(3) = pos2(3) + 0.01;
|
||||||
|
ax2.Position = pos2;
|
||||||
|
|
||||||
|
% Ensure the left plot stays correct after the move
|
||||||
|
ax1.Position = pos1;
|
||||||
|
|
||||||
|
% --- enforce same visible outline ---
|
||||||
|
% For ax2, create a fake left spine (since YAxis is hidden)
|
||||||
|
ax2.Box = 'on'; % keep outline but no ticks on the right
|
||||||
|
ax1.Box = 'on';
|
||||||
|
|
||||||
|
ax2.View = [90 -90];
|
||||||
@@ -0,0 +1,221 @@
|
|||||||
|
%% ============================================================
|
||||||
|
% GRID: NGMI, AIR, HD-NetRate, SD-NetRate (1 × 4)
|
||||||
|
% ============================================================
|
||||||
|
|
||||||
|
db = DBHandler("dataBase","labor_highspeed","type","mysql");
|
||||||
|
|
||||||
|
%% --- Base DB Filters (shared across all curves)
|
||||||
|
fp = QueryFilter();
|
||||||
|
fp.where('Runs','fiber_length','EQUALS', 2);
|
||||||
|
fp.where('Runs','wavelength','EQUALS', 1310);
|
||||||
|
fp.where('Runs','rop_attenuation','EQUALS', 0);
|
||||||
|
fp.where('Runs','is_mpi','EQUALS', 0);
|
||||||
|
|
||||||
|
fields = db.getTableFieldNames('dashboard_ungrouped_alltime');
|
||||||
|
[dataTable,~] = db.queryDB(fp, fields);
|
||||||
|
|
||||||
|
|
||||||
|
%% === Curve Definitions =======================================
|
||||||
|
curves = struct;
|
||||||
|
|
||||||
|
% PAM-8 — VNLE PF MLSE — no_emph = 1 — RED
|
||||||
|
curves(1).pam = 8;
|
||||||
|
curves(1).eq = equalizer_structure.vnle_pf_mlse;
|
||||||
|
curves(1).pre = 0;
|
||||||
|
curves(1).color = clr.Paired.red;
|
||||||
|
curves(1).mkr = 'o';
|
||||||
|
|
||||||
|
% PAM-6 — VNLE PF MLSE — no_emph = 1 — BLUE
|
||||||
|
curves(2).pam = 6;
|
||||||
|
curves(2).eq = equalizer_structure.vnle_pf_mlse;
|
||||||
|
curves(2).pre = 1;
|
||||||
|
curves(2).color = clr.Paired.blue;
|
||||||
|
curves(2).mkr = 'square';
|
||||||
|
|
||||||
|
% PAM-4 — VNLE DB MLSE — pre_emph = 0 — GREEN
|
||||||
|
curves(3).pam = 4;
|
||||||
|
curves(3).eq = equalizer_structure.vnle_db_mlse;
|
||||||
|
curves(3).pre = 0;
|
||||||
|
curves(3).color = clr.Paired.green;
|
||||||
|
curves(3).mkr = 'diamond';
|
||||||
|
|
||||||
|
%% === Prepare Analysis Config ==================================
|
||||||
|
base = struct;
|
||||||
|
base.group_by = {'equalizer_structure','pre_emph'};
|
||||||
|
base.x_axis = 'symbolrate';
|
||||||
|
base.outlier = 'none';
|
||||||
|
base.show_raw = false;
|
||||||
|
base.filters = struct; % will be filled per curve
|
||||||
|
|
||||||
|
|
||||||
|
%% === Precompute All Curves ====================================
|
||||||
|
results = struct;
|
||||||
|
|
||||||
|
for k = 1:numel(curves)
|
||||||
|
|
||||||
|
% --- BER ---
|
||||||
|
cfg = base;
|
||||||
|
cfg.y_axis = 'BER';
|
||||||
|
cfg.agg = 'min';
|
||||||
|
cfg.filters = struct('pam_level', curves(k).pam, ...
|
||||||
|
'equalizer_structure', curves(k).eq, ...
|
||||||
|
'pre_emph', curves(k).pre);
|
||||||
|
|
||||||
|
A = analyze_measurements_gpt(dataTable, cfg);
|
||||||
|
cfg.x_axis = 'grossrate';
|
||||||
|
B = analyze_measurements_gpt(dataTable, cfg);
|
||||||
|
|
||||||
|
results(k).baudr = A.group{1}.x;
|
||||||
|
results(k).gross = B.group{1}.x;
|
||||||
|
|
||||||
|
if curves(k).pam == 4
|
||||||
|
results(k).ber = A.group{1}.y_precoded;
|
||||||
|
else
|
||||||
|
results(k).ber = A.group{1}.y;
|
||||||
|
end
|
||||||
|
|
||||||
|
% --- NGMI ---
|
||||||
|
cfg.y_axis = 'NGMI';
|
||||||
|
cfg.agg = 'max';
|
||||||
|
A = analyze_measurements_gpt(dataTable, cfg);
|
||||||
|
results(k).ngmi = A.group{1}.y;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
% --- AIR ---
|
||||||
|
cfg.y_axis = 'AIR';
|
||||||
|
cfg.agg = 'max';
|
||||||
|
A = analyze_measurements_gpt(dataTable, cfg);
|
||||||
|
results(k).air = A.group{1}.y;
|
||||||
|
results(k).air = results(k).ngmi .* results(k).gross;
|
||||||
|
|
||||||
|
% --- Net Rates ---
|
||||||
|
tp = TransmissionPerformance;
|
||||||
|
results(k).ndr = tp.calculateNetRate(results(k).gross, ...
|
||||||
|
'NGMI', results(k).ngmi, ...
|
||||||
|
'BER', results(k).ber);
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
%% ============================================================
|
||||||
|
% FIGURE: 1 × 4 GRID
|
||||||
|
% ============================================================
|
||||||
|
fig = figure(71); clf;
|
||||||
|
t = tiledlayout(1,4, 'TileSpacing','compact', 'Padding','compact');
|
||||||
|
|
||||||
|
lw = 1.0;
|
||||||
|
|
||||||
|
% === NGMI vs Grossrate ===
|
||||||
|
ax = nexttile(t,1);
|
||||||
|
hold on;
|
||||||
|
for k = 1:3
|
||||||
|
plot(results(k).baudr, results(k).ngmi, ...
|
||||||
|
'LineWidth', lw, ...
|
||||||
|
'Color', curves(k).color, ...
|
||||||
|
'MarkerSize', 1, ...
|
||||||
|
'MarkerFaceColor', curves(k).color,...
|
||||||
|
'Marker',curves(k).mkr);
|
||||||
|
end
|
||||||
|
ylabel('NGMI');
|
||||||
|
xlabel('Baud rate [GBd]');
|
||||||
|
xlim([100 210]);
|
||||||
|
xticks(100:15:225);
|
||||||
|
ylim([0.9, 1]);
|
||||||
|
grid minor; box on;
|
||||||
|
beautifyBERplot("logscale",0,"setmarkers",0);
|
||||||
|
|
||||||
|
|
||||||
|
% === AIR vs Grossrate ===
|
||||||
|
ax = nexttile(t,2);
|
||||||
|
hold on;
|
||||||
|
for k = 1:3
|
||||||
|
plot(results(k).baudr, results(k).air, ...
|
||||||
|
'-', 'LineWidth', lw, ...
|
||||||
|
'Color', curves(k).color, ...
|
||||||
|
'MarkerSize', 2, ...
|
||||||
|
'MarkerFaceColor', curves(k).color,'Marker',curves(k).mkr);
|
||||||
|
end
|
||||||
|
ylabel('AIR [Gb/s]');
|
||||||
|
xlabel('Baud rate [GBd]');
|
||||||
|
ylim([280 430]);
|
||||||
|
yticks(280:30:440)
|
||||||
|
xlim([100 210]);
|
||||||
|
xticks(100:15:225);
|
||||||
|
grid minor; box on;
|
||||||
|
beautifyBERplot("logscale",0,"setmarkers",0);
|
||||||
|
yline(400,'LineStyle','--');
|
||||||
|
|
||||||
|
% === SD-FEC Net Rate ===
|
||||||
|
ax = nexttile(t,3);
|
||||||
|
hold on;
|
||||||
|
for k = 1:3
|
||||||
|
plot(results(k).baudr, results(k).ndr.SDHD.NetRate, ...
|
||||||
|
'LineWidth', lw, ...
|
||||||
|
'Color', curves(k).color, ...
|
||||||
|
'MarkerSize', 2, ...
|
||||||
|
'MarkerFaceColor', curves(k).color,...
|
||||||
|
'Marker',curves(k).mkr);
|
||||||
|
end
|
||||||
|
ylabel('NDR [Gb/s]');
|
||||||
|
xlabel('Baud rate [GBd]');
|
||||||
|
ylim([280 430]);
|
||||||
|
yticks(280:30:440)
|
||||||
|
xlim([100 210]);
|
||||||
|
xticks(100:15:225);
|
||||||
|
grid minor; box on;
|
||||||
|
beautifyBERplot("logscale",0,"setmarkers",0);
|
||||||
|
yline(400,'LineStyle','--');
|
||||||
|
|
||||||
|
% === HD-FEC Net Rate ===
|
||||||
|
ax = nexttile(t,4);
|
||||||
|
hold on;
|
||||||
|
for k = 1:3
|
||||||
|
% plot(results(k).baudr, results(k).ndr.STAIR.NetRate, ...
|
||||||
|
% '-', 'LineWidth', lw, ...
|
||||||
|
% 'Color', curves(k).color, ...
|
||||||
|
% 'MarkerSize', 4,'Marker','+', ...
|
||||||
|
% 'MarkerFaceColor', curves(k).color);
|
||||||
|
|
||||||
|
plot(results(k).baudr, results(k).ndr.O_FEC.NetRate, ...
|
||||||
|
':', 'LineWidth', lw, ...
|
||||||
|
'Color', curves(k).color, ...
|
||||||
|
'MarkerSize', 2,...
|
||||||
|
'MarkerFaceColor', curves(k).color,...
|
||||||
|
'Marker',curves(k).mkr);
|
||||||
|
|
||||||
|
plot(results(k).baudr, results(k).ndr.KP4_hamming.NetRate, ...
|
||||||
|
'--', 'LineWidth', lw, ...
|
||||||
|
'Color', curves(k).color, ...
|
||||||
|
'MarkerSize', 2,'Marker','diamond', ...
|
||||||
|
'MarkerFaceColor', curves(k).color,...
|
||||||
|
'Marker',curves(k).mkr);
|
||||||
|
end
|
||||||
|
|
||||||
|
yline(400,'LineStyle','--');
|
||||||
|
ylabel('');
|
||||||
|
xlabel('Baud rate [GBd]');
|
||||||
|
ylim([280 430]);
|
||||||
|
yticks(280:30:440)
|
||||||
|
xlim([100 210]);
|
||||||
|
xticks(100:15:225);
|
||||||
|
grid minor; box on;
|
||||||
|
beautifyBERplot("logscale",0,"setmarkers",0);
|
||||||
|
|
||||||
|
% === FINAL FIGURE SIZE ===
|
||||||
|
pos = 1e3.*[0.7950 1.1150 1.4113 0.1900];
|
||||||
|
set(fig, 'Position', pos);
|
||||||
|
|
||||||
|
% % % %% === EXPORT ===
|
||||||
|
outfile = 'C:\Users\Silas\Documents\latex\JLT_400G copy\media\matlab2tikz\compare_ndr_v3.tikz';
|
||||||
|
matlab2tikz(outfile, ...
|
||||||
|
'width','\fwidth', ...
|
||||||
|
'height','\fheight', ...
|
||||||
|
'showInfo',false, ...
|
||||||
|
'extraAxisOptions',{ ...
|
||||||
|
'legend style={font=\footnotesize}', ...
|
||||||
|
'legend columns=1' ...
|
||||||
|
'every axis/.append style={font=\scriptsize}',...
|
||||||
|
'minor grid style={line width=0.2pt, solid, color=black!10}',...
|
||||||
|
'grid style={line width=0.4pt, solid, color=black!20}',...
|
||||||
|
'grid style={dashed}',...
|
||||||
|
});
|
||||||
@@ -0,0 +1,180 @@
|
|||||||
|
%% ============================================================
|
||||||
|
% GRID (1 × 4):
|
||||||
|
% 1) NGMI overview (PAM4+PAM6+PAM8 superimposed)
|
||||||
|
% 2) PAM-4 tile (AIR + SD-NDR + HD-NDR)
|
||||||
|
% 3) PAM-6 tile
|
||||||
|
% 4) PAM-8 tile
|
||||||
|
% ============================================================
|
||||||
|
|
||||||
|
db = DBHandler("dataBase","labor_highspeed","type","mysql");
|
||||||
|
|
||||||
|
%% --- Base DB Filters (shared across all curves)
|
||||||
|
fp = QueryFilter();
|
||||||
|
fp.where('Runs','fiber_length','EQUALS', 2);
|
||||||
|
fp.where('Runs','wavelength','EQUALS', 1310);
|
||||||
|
fp.where('Runs','rop_attenuation','EQUALS', 0);
|
||||||
|
fp.where('Runs','is_mpi','EQUALS', 0);
|
||||||
|
|
||||||
|
fields = db.getTableFieldNames('dashboard_ungrouped_alltime');
|
||||||
|
[dataTable,~] = db.queryDB(fp, fields);
|
||||||
|
|
||||||
|
%% === CURVE DEFINITIONS =================================================
|
||||||
|
curves = struct;
|
||||||
|
|
||||||
|
curves(1).pam = 8;
|
||||||
|
curves(1).eq = equalizer_structure.vnle_pf_mlse;
|
||||||
|
curves(1).pre = 0;
|
||||||
|
curves(1).color = clr.Paired.red;
|
||||||
|
|
||||||
|
curves(2).pam = 6;
|
||||||
|
curves(2).eq = equalizer_structure.vnle_pf_mlse;
|
||||||
|
curves(2).pre = 1;
|
||||||
|
curves(2).color = clr.Paired.blue;
|
||||||
|
|
||||||
|
curves(3).pam = 4;
|
||||||
|
curves(3).eq = equalizer_structure.vnle_db_mlse;
|
||||||
|
curves(3).pre = 0;
|
||||||
|
curves(3).color = clr.Paired.green;
|
||||||
|
|
||||||
|
% === ANALYSIS ENGINE (extract BER/NGMI/AIR/netrates) ===================
|
||||||
|
base = struct;
|
||||||
|
base.group_by = {'equalizer_structure','pre_emph'};
|
||||||
|
base.x_axis = 'grossrate';
|
||||||
|
base.outlier = 'none';
|
||||||
|
base.show_raw = false;
|
||||||
|
|
||||||
|
results = struct;
|
||||||
|
|
||||||
|
for k = 1:numel(curves)
|
||||||
|
|
||||||
|
% ========== BER ==========
|
||||||
|
cfg = base;
|
||||||
|
cfg.y_axis = 'BER';
|
||||||
|
cfg.agg = 'min';
|
||||||
|
|
||||||
|
cfg.filters = struct('pam_level', curves(k).pam, ...
|
||||||
|
'equalizer_structure', curves(k).eq, ...
|
||||||
|
'pre_emph', curves(k).pre);
|
||||||
|
A = analyze_measurements_gpt(dataTable, cfg);
|
||||||
|
|
||||||
|
results(k).gross = A.group{1}.x;
|
||||||
|
if curves(k).pam == 4
|
||||||
|
results(k).ber = A.group{1}.y_precoded;
|
||||||
|
else
|
||||||
|
results(k).ber = A.group{1}.y;
|
||||||
|
end
|
||||||
|
|
||||||
|
% ========== NGMI ==========
|
||||||
|
cfg.y_axis = 'NGMI'; cfg.agg = 'max';
|
||||||
|
A = analyze_measurements_gpt(dataTable, cfg);
|
||||||
|
results(k).ngmi = A.group{1}.y;
|
||||||
|
|
||||||
|
% ========== AIR ==========
|
||||||
|
cfg.y_axis = 'AIR'; cfg.agg = 'max';
|
||||||
|
A = analyze_measurements_gpt(dataTable, cfg);
|
||||||
|
results(k).air = A.group{1}.y;
|
||||||
|
|
||||||
|
% ========== NET RATES ==========
|
||||||
|
tp = TransmissionPerformance;
|
||||||
|
results(k).ndr = tp.calculateNetRate(results(k).gross, ...
|
||||||
|
'NGMI', results(k).ngmi, ...
|
||||||
|
'BER', results(k).ber);
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
% ============================================================
|
||||||
|
% FIGURE
|
||||||
|
% ============================================================
|
||||||
|
fig = figure(3);
|
||||||
|
t = tiledlayout(1,4,'TileSpacing','compact','Padding','compact');
|
||||||
|
|
||||||
|
lw = 1.7;
|
||||||
|
|
||||||
|
% =======================================================================
|
||||||
|
% (1) NGMI OVERVIEW TILE (all 3 curves)
|
||||||
|
% =======================================================================
|
||||||
|
ax = nexttile(t,1); hold on;
|
||||||
|
|
||||||
|
for k = 1:3
|
||||||
|
plot(results(k).gross, results(k).ngmi, ...
|
||||||
|
'-o', 'Color', curves(k).color, ...
|
||||||
|
'LineWidth',lw,'MarkerSize',5, ...
|
||||||
|
'MarkerFaceColor',curves(k).color);
|
||||||
|
end
|
||||||
|
|
||||||
|
ylabel('NGMI');
|
||||||
|
xlabel('Grossrate [Gb/s]');
|
||||||
|
ylim([0.9 1]); % your chosen limits
|
||||||
|
xlim([300 480]);
|
||||||
|
xticks(300:30:480)
|
||||||
|
grid minor; box on;
|
||||||
|
beautifyBERplot;
|
||||||
|
|
||||||
|
% =======================================================================
|
||||||
|
% (2–4) PAM-SPECIFIC TILES: AIR, SD-NDR, HD-NDR
|
||||||
|
% =======================================================================
|
||||||
|
|
||||||
|
pam_order = [4 6 8]; % left → right
|
||||||
|
|
||||||
|
for ti = 1:3
|
||||||
|
pam_target = pam_order(ti);
|
||||||
|
ax = nexttile(t, 1+ti); hold on;
|
||||||
|
|
||||||
|
% find matching curve
|
||||||
|
for k = 1:3
|
||||||
|
if curves(k).pam ~= pam_target, continue; end
|
||||||
|
|
||||||
|
col = curves(k).color;
|
||||||
|
|
||||||
|
% AIR
|
||||||
|
plot(results(k).gross, results(k).air, ...
|
||||||
|
'-','Color',col,'LineWidth',lw,'Marker','*', ...
|
||||||
|
'MarkerSize',5,'MarkerFaceColor',col,'DisplayName','AIR');
|
||||||
|
|
||||||
|
% SD-based net rate
|
||||||
|
plot(results(k).gross, results(k).ndr.SDHD.NetRate, ...
|
||||||
|
'--','Color',col,'LineWidth',lw,'Marker','v', ...
|
||||||
|
'MarkerSize',5,'MarkerFaceColor',col,'DisplayName','SD+HD');
|
||||||
|
|
||||||
|
% HD-based net rate
|
||||||
|
plot(results(k).gross, results(k).ndr.STAIR.NetRate, ...
|
||||||
|
':','Color',col,'LineWidth',lw,'Marker','x', ...
|
||||||
|
'MarkerSize',5,'MarkerFaceColor',col,'DisplayName','HD-FEC (Staircase)');
|
||||||
|
|
||||||
|
% HD-based net rate
|
||||||
|
plot(results(k).gross, results(k).ndr.O_FEC.NetRate, ...
|
||||||
|
'LineStyle','-.','Color',col,'LineWidth',lw,'Marker','+', ...
|
||||||
|
'MarkerSize',5,'MarkerFaceColor',col,'DisplayName','O-FEC');
|
||||||
|
|
||||||
|
% HD-based net rate
|
||||||
|
plot(results(k).gross, results(k).ndr.KP4_hamming.NetRate, ...
|
||||||
|
'LineStyle','-','Color',col,'LineWidth',lw,'Marker','x', ...
|
||||||
|
'MarkerSize',5,'MarkerFaceColor',col,'DisplayName','KP4+Hamming');
|
||||||
|
end
|
||||||
|
|
||||||
|
ylabel('NDR [Gb/s]');
|
||||||
|
xlabel('Grossrate [Gb/s]');
|
||||||
|
ylim([300 440]); % your chosen limits
|
||||||
|
yticks(300:20:480)
|
||||||
|
xlim([300 480]);
|
||||||
|
xticks(300:30:480)
|
||||||
|
grid minor; box on;
|
||||||
|
beautifyBERplot;
|
||||||
|
yline(400,'HandleVisibility','off');
|
||||||
|
end
|
||||||
|
|
||||||
|
% === FIX FIGURE SIZE FOR TIKZ ==========================================
|
||||||
|
if 0
|
||||||
|
pos = 1e3.*[0.3643 0.9943 1.4113 0.2120];
|
||||||
|
set(fig,'Position',pos);
|
||||||
|
|
||||||
|
% outfile = 'C:\Users\Silas\Documents\latex\JLT_400G copy\media\matlab2tikz\compare_ndr.tikz';
|
||||||
|
% matlab2tikz(outfile, ...
|
||||||
|
% 'width','\fwidth', ...
|
||||||
|
% 'height','\fheight', ...
|
||||||
|
% 'showInfo',false, ...
|
||||||
|
% 'extraAxisOptions',{ ...
|
||||||
|
% 'legend style={font=\footnotesize}', ...
|
||||||
|
% 'legend columns=1' ...
|
||||||
|
% });
|
||||||
|
end
|
||||||
@@ -0,0 +1,153 @@
|
|||||||
|
%% ============================================================
|
||||||
|
% LOAD DATA (PAM-4, sweep over ROP)
|
||||||
|
% ============================================================
|
||||||
|
database_type = 'mysql';
|
||||||
|
db = DBHandler("dataBase", "labor_highspeed", "type", database_type);
|
||||||
|
|
||||||
|
pam_level = 4;
|
||||||
|
fiberL = 1; % 1 km
|
||||||
|
wlen = 1310;
|
||||||
|
baudrate = 360e9;
|
||||||
|
|
||||||
|
fp = QueryFilter();
|
||||||
|
fp.where('Runs','pam_level','EQUALS', pam_level);
|
||||||
|
fp.where('Runs','fiber_length','EQUALS', fiberL);
|
||||||
|
fp.where('Runs','wavelength','EQUALS', wlen);
|
||||||
|
fp.where('Runs','bitrate','EQUALS', baudrate);
|
||||||
|
fp.where('Runs','power_pd_in','LESS_THAN', 7);
|
||||||
|
|
||||||
|
fields = [
|
||||||
|
db.getTableFieldNames('power_state_info');
|
||||||
|
db.getTableFieldNames('dashboard_ungrouped_alltime')
|
||||||
|
];
|
||||||
|
|
||||||
|
[dataTable,~] = db.queryDB(fp, fields);
|
||||||
|
|
||||||
|
|
||||||
|
%% ============================================================
|
||||||
|
% DSP SCHEMES (Best combinations only)
|
||||||
|
% ============================================================
|
||||||
|
curves = struct;
|
||||||
|
|
||||||
|
curves(1).name = 'VNLE';
|
||||||
|
curves(1).eq = equalizer_structure.vnle;
|
||||||
|
curves(1).color = clr.Paired.red;
|
||||||
|
|
||||||
|
curves(2).name = 'PF + MLSE';
|
||||||
|
curves(2).eq = equalizer_structure.vnle_pf_mlse;
|
||||||
|
curves(2).color = clr.Paired.green;
|
||||||
|
|
||||||
|
curves(3).name = 'DB-target + MLSE';
|
||||||
|
curves(3).eq = equalizer_structure.vnle_db_mlse;
|
||||||
|
curves(3).color = clr.Paired.blue;
|
||||||
|
|
||||||
|
curves(4).name = 'ML-based MLSE';
|
||||||
|
curves(4).eq = equalizer_structure.ml_mlse;
|
||||||
|
curves(4).color = clr.Paired.purple;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
%% ============================================================
|
||||||
|
% ANALYSIS ENGINE (No plotting)
|
||||||
|
% ============================================================
|
||||||
|
results = struct;
|
||||||
|
|
||||||
|
for k = 1:numel(curves)
|
||||||
|
|
||||||
|
pre_emph = decide_preemph(pam_level,curves(k).eq);
|
||||||
|
precoded = decide_precoded(pam_level,curves(k).eq);
|
||||||
|
|
||||||
|
cfg = struct;
|
||||||
|
cfg.x_axis = 'power_mzm'; % ROP axis
|
||||||
|
cfg.y_axis = 'BER';
|
||||||
|
cfg.agg = 'min';
|
||||||
|
cfg.outlier = 'none';
|
||||||
|
cfg.show_raw = false;
|
||||||
|
|
||||||
|
cfg.filters = struct( ...
|
||||||
|
'pam_level', pam_level, ...
|
||||||
|
'fiber_length', fiberL, ...
|
||||||
|
'wavelength', wlen, ...
|
||||||
|
'bitrate', baudrate, ...
|
||||||
|
'is_mpi', 0, ...
|
||||||
|
'equalizer_structure', curves(k).eq, ...
|
||||||
|
'pre_emph', pre_emph);
|
||||||
|
|
||||||
|
A = analyze_measurements_gpt(dataTable, cfg);
|
||||||
|
|
||||||
|
results(k).x = A.group{1}.x;
|
||||||
|
if precoded
|
||||||
|
results(k).ber = A.group{1}.y_precoded;
|
||||||
|
else
|
||||||
|
results(k).ber = A.group{1}.y;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
%% ============================================================
|
||||||
|
% PLOT — BER vs ROP (Single Axis)
|
||||||
|
% ============================================================
|
||||||
|
fig = figure(); clf; hold on;
|
||||||
|
|
||||||
|
lw = 2.0;
|
||||||
|
ms = 7;
|
||||||
|
|
||||||
|
for k = 1:numel(curves)
|
||||||
|
plot(results(k).x, results(k).ber, ...
|
||||||
|
'-o', ...
|
||||||
|
'Color', curves(k).color, ...
|
||||||
|
'MarkerFaceColor', curves(k).color, ...
|
||||||
|
'MarkerSize', ms, ...
|
||||||
|
'LineWidth', lw, ...
|
||||||
|
'DisplayName', curves(k).name);
|
||||||
|
end
|
||||||
|
|
||||||
|
set(gca,'YScale','log');
|
||||||
|
grid on;
|
||||||
|
|
||||||
|
xlabel('ROP / Power (MZM) [dBm]');
|
||||||
|
ylabel('BER');
|
||||||
|
|
||||||
|
ylim([1e-4 2e-1]);
|
||||||
|
|
||||||
|
title(sprintf('BER vs ROP — PAM-%d, %.0f km, %.0f GBd, %.0f nm', ...
|
||||||
|
pam_level, fiberL, baudrate*1e-9, wlen));
|
||||||
|
|
||||||
|
legend('Location','best');
|
||||||
|
beautifyBERplot();
|
||||||
|
|
||||||
|
pos = 1e3.*[0.2 0.6 1.3 0.4];
|
||||||
|
set(fig, 'Position', pos);
|
||||||
|
|
||||||
|
%% ============================================================
|
||||||
|
% DECISION LOGIC (INLINE FUNCTIONS)
|
||||||
|
% ============================================================
|
||||||
|
|
||||||
|
function pe = decide_preemph(M, eq)
|
||||||
|
% PRE-EMPH RULES:
|
||||||
|
switch M
|
||||||
|
case 4
|
||||||
|
if eq == equalizer_structure.vnle
|
||||||
|
pe = 1; % PAM4: VNLE → pre-emph on
|
||||||
|
else
|
||||||
|
pe = 0; % PAM4: all others → off
|
||||||
|
end
|
||||||
|
case {6,8}
|
||||||
|
pe = 1; % PAM6/8: all → pre-emph on
|
||||||
|
otherwise
|
||||||
|
pe = 0;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function flag = decide_precoded(M, eq)
|
||||||
|
% PRE-CODE RULES:
|
||||||
|
if eq == equalizer_structure.vnle_db_mlse
|
||||||
|
flag = 1; % Always for DB-target
|
||||||
|
elseif eq == equalizer_structure.ml_mlse && M == 4
|
||||||
|
flag = 1; % PAM4: ML-based → precoded
|
||||||
|
else
|
||||||
|
flag = 0;
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,182 @@
|
|||||||
|
dsp_options.storage_path = 'Z:\2024\sioe_labor\';
|
||||||
|
dsp_options.max_occurences = 1;
|
||||||
|
database = DBHandler("dataBase", 'labor_highspeed', "type", 'mysql' );
|
||||||
|
|
||||||
|
rates = [300e9];
|
||||||
|
cols = cbrewer2('BuPu',25);
|
||||||
|
cols = [cols(end-10:2:end,:)];
|
||||||
|
cols = cbrewer2('Set1',6);
|
||||||
|
|
||||||
|
fignum = 200;
|
||||||
|
fig=figure(fignum);clf;
|
||||||
|
|
||||||
|
for dbmode = 0:1%length(rates)
|
||||||
|
|
||||||
|
|
||||||
|
if 0
|
||||||
|
rcalpha = 0.05;
|
||||||
|
fsym = rates/2;
|
||||||
|
pulsef = 1;
|
||||||
|
Pform = Pulseformer("fsym",fsym,"fdac",4*fsym,"pulse","rrc","pulselength",16,"alpha",rcalpha);
|
||||||
|
|
||||||
|
Pamsource = PAMsource(...
|
||||||
|
"fsym",fsym,"M",4,"order",18,"useprbs",0,...
|
||||||
|
"fs_out",fdac,...
|
||||||
|
"applyclipping",0,"clipfactor",1.2,...
|
||||||
|
"applypulseform",pulsef,"pulseformer",Pform,...
|
||||||
|
"randkey",20,...
|
||||||
|
"db_precode",dbmode,"db_encode",0,...
|
||||||
|
"mrds_code",0,"mrds_blocklength",512);
|
||||||
|
|
||||||
|
[Digi_sig,Symbols,Bits] = Pamsource.process();
|
||||||
|
|
||||||
|
Digi_sig = Digi_sig.normalize("mode","rms");
|
||||||
|
|
||||||
|
%%% 1) PLOT FULL RESPONSE SIGNAL
|
||||||
|
Digi_sig.spectrum("displayname","Full Response","fignum",fignum+dbmode,"normalizeToNyquist",0,"normalizeTo0dB",0,"color",[0.2,0.2,0.2],"linestyle",'-','addDCoffset',0,'normalizeToDC',1);
|
||||||
|
|
||||||
|
|
||||||
|
%%% 2) PLOT PREEMPH. TX SIGNAL
|
||||||
|
if dbmode == 0
|
||||||
|
maxamp = -37;
|
||||||
|
precomp_est = ChannelFreqResp("Nacq",2048,"Navg",100,"Ncp",63,'f_ref',Digi_sig.fs);
|
||||||
|
|
||||||
|
precomp_path = "C:\Users\Silas\Documents\MATLAB\Datensätze\sioe_labor\precomp";
|
||||||
|
precomp_fn = "lab_high_speed";
|
||||||
|
Digi_sig_pre = precomp_est.precomp(Digi_sig,'maxampdb',maxamp,'loadPath',precomp_path,'fileName',precomp_fn);
|
||||||
|
|
||||||
|
Digi_sig_pre = Digi_sig_pre.resample("fs_out",fdac);
|
||||||
|
|
||||||
|
Digi_sig_pre= Digi_sig_pre.normalize("mode","rms");
|
||||||
|
|
||||||
|
Digi_sig_pre.spectrum("displayname","Strong Precomp","fignum",fignum+dbmode,"normalizeToNyquist",0,"normalizeTo0dB",0,"color",[0,0,0],"linestyle",'-.','addDCoffset',0,'normalizeToDC',1);
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
% 1 - PAM 4 with preemphasis
|
||||||
|
fp = QueryFilter();
|
||||||
|
M = 4;
|
||||||
|
fp.where('Runs', 'pam_level','EQUALS', M);
|
||||||
|
fp.where('Runs', 'bitrate','EQUALS', rates);%360,390
|
||||||
|
fp.where('Runs', 'fiber_length','EQUALS', 10);
|
||||||
|
fp.where('Runs', 'wavelength','EQUALS', 1322.7); %1327.4
|
||||||
|
fp.where('Runs', 'db_mode','EQUALS', dbmode);
|
||||||
|
fp.where('Runs', 'rop_attenuation','EQUAL', 0);
|
||||||
|
|
||||||
|
[dataTable,~] = database.queryDB(fp, database.getTableFieldNames('Runs'));
|
||||||
|
|
||||||
|
dataTable = queryRunid(dataTable.run_id, database);
|
||||||
|
fsym = dataTable.symbolrate;
|
||||||
|
M = double(dataTable.pam_level);
|
||||||
|
|
||||||
|
% Load and Sync signal data from DB
|
||||||
|
[Tx_bits, Symbols, Scpe_cell, ~] = loadAndSyncSignalDataFromDb(dataTable, dsp_options);
|
||||||
|
|
||||||
|
% Preprocess signal
|
||||||
|
Scpe_sig = preprocessSignal(Scpe_cell{1}, Symbols, fsym);
|
||||||
|
Scpe_sig = Scpe_cell{1};
|
||||||
|
|
||||||
|
%%% 3) PLOT DB Tgt. SIGNAL
|
||||||
|
if 1
|
||||||
|
DB_Symbols = Duobinary().encode(Symbols);
|
||||||
|
DB_Symbols.spectrum("fignum",fignum+dbmode,"normalizeTo0dB",1,"displayname",'DB-Response','addDCoffset',0,'color',clr.Set1.blue,'normalizeToNyquist',0,'linestyle','--');
|
||||||
|
end
|
||||||
|
|
||||||
|
%%% 4) Plot RX Signal
|
||||||
|
Scpe_sig.spectrum("fignum",fignum+dbmode,"normalizeTo0dB",1,"displayname",'Rx','addDCoffset',1,'color',[0,0,0],'normalizeToNyquist',0,'linestyle',':');
|
||||||
|
Scpe_sig.eye(fsym,M,"fignum",47,"displayname",' Eye of AVG Signal');
|
||||||
|
% xline(Symbols.fs/2.*1e-9,'Color',cols(r,:),'HandleVisibility','off');
|
||||||
|
|
||||||
|
average_signals = 1;
|
||||||
|
if average_signals
|
||||||
|
Scpe_sig_avg = Scpe_sig;
|
||||||
|
scope_mean = zeros(size(Scpe_cell{1}.signal));
|
||||||
|
for n=1:numel(Scpe_cell)
|
||||||
|
scope_mean = scope_mean + Scpe_cell{n}.signal;
|
||||||
|
end
|
||||||
|
scope_mean = scope_mean ./ n;
|
||||||
|
Scpe_sig_avg.signal = scope_mean;
|
||||||
|
|
||||||
|
Scpe_sig_avg.spectrum("displayname","Scope PSD","fignum",20,"normalizeTo0dB",1);
|
||||||
|
Scpe_sig_avg.plot("displayname","Scope raw signal","fignum",27,"clear",1);
|
||||||
|
Scpe_sig_avg.eye(fsym,M,"fignum",48,"displayname",' Eye of AVG Signal');
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
fig = figure(fignum+dbmode);
|
||||||
|
if dbmode == 0
|
||||||
|
ylim([-22,12]);
|
||||||
|
else
|
||||||
|
ylim([-22,2]);
|
||||||
|
end
|
||||||
|
xlim([0,105]);
|
||||||
|
xticks(-100:20:100);
|
||||||
|
yticks(-20:10:10);
|
||||||
|
|
||||||
|
beautifyBERplot("logscale",0,"setmarkers",0)
|
||||||
|
pos = [100.3333 991.6667 358.0000 192.6667];
|
||||||
|
set(fig, 'Position', pos);
|
||||||
|
|
||||||
|
%%%%%%%%%%%%
|
||||||
|
drawnow;
|
||||||
|
|
||||||
|
% Do EQ and find alpha's
|
||||||
|
len_tr = 4096*2;
|
||||||
|
|
||||||
|
ffe_order = [50, 5, 5];
|
||||||
|
dfe_order = [0, 0, 0];
|
||||||
|
pf_ncoeffs = 1;
|
||||||
|
mu_ffe = [0.0001, 0.0008, 0.001];
|
||||||
|
mu_dfe = 0.0004;
|
||||||
|
mu_dc = 0.005;
|
||||||
|
|
||||||
|
%%% FULL RESP TARGET
|
||||||
|
eq_ = EQ("Ne",ffe_order,"Nb",dfe_order,"training_length",len_tr,"training_loops",5,"dd_loops",5,"K",2,"DCmu",mu_dc,"DDmu",[mu_ffe mu_dfe],"DFEmu",0.005,"FFEmu",0,"plotfinal",0,"ideal_dfe",0);
|
||||||
|
pf_1 = Postfilter("ncoeff",1,"useBurg",1);
|
||||||
|
|
||||||
|
[eq_signal_sd, eq_noise] = eq_.process(Scpe_sig, Symbols);
|
||||||
|
|
||||||
|
% eq_noise.signal = eq_noise.signal - mean(eq_noise.signal);
|
||||||
|
% eq_noise = eq_noise.normalize("mode","rms");
|
||||||
|
|
||||||
|
[mlse_sig_sd,whitened_noise] = pf_1.process(eq_signal_sd, eq_noise);
|
||||||
|
|
||||||
|
fig = figure(fignum+dbmode+10); hold on
|
||||||
|
|
||||||
|
[h, w] = freqz(1, pf_1.coefficients, length(eq_noise), "whole", eq_noise.fs);
|
||||||
|
h = h / max(abs(h)); % Normalize the filter response
|
||||||
|
w_ = (w - eq_noise.fs / 2);
|
||||||
|
|
||||||
|
%%% DB TARGET
|
||||||
|
db_ref_sequence = Duobinary().encode(Symbols);
|
||||||
|
eq_ = EQ("Ne",ffe_order,"Nb",dfe_order,"training_length",len_tr,"training_loops",5,"dd_loops",5,"K",2,"DCmu",mu_dc,"DDmu",[mu_ffe mu_dfe],"DFEmu",0.005,"FFEmu",0,"plotfinal",0,"ideal_dfe",0);
|
||||||
|
[eq_signal, db_noise] = eq_.process(Scpe_sig,db_ref_sequence);
|
||||||
|
|
||||||
|
% db_noise.signal = db_noise.signal - mean(db_noise.signal);
|
||||||
|
% db_noise = db_noise.normalize("mode","rms");
|
||||||
|
|
||||||
|
%%% 1-3) Plot EQ Noise EEN
|
||||||
|
figure(fignum+dbmode+10)
|
||||||
|
eq_noise.spectrum("displayname", 'Noise', "fignum", fignum+dbmode+10, "normalizeTo0dB", 0,"color",clr.Set1.green,"normalizeToDC",0,"addDCoffset",0);
|
||||||
|
if dbmode == 1
|
||||||
|
offset = 27.7;
|
||||||
|
else
|
||||||
|
offset = 29.8;
|
||||||
|
end
|
||||||
|
plot(w_ * 1e-9, 20 * log10(fftshift(abs(h)))-offset, 'DisplayName', ['Burg Coeffs: ', num2str(round(pf_1.coefficients, 2)), ' '], 'LineWidth', 1,'Color',clr.Set1.green,'LineStyle','--');
|
||||||
|
db_noise.spectrum("displayname", 'DBt. Noise', "fignum", fignum+dbmode+10, "normalizeTo0dB", 0,"color",clr.Set1.blue,"normalizeToDC",0,"addDCoffset",0);
|
||||||
|
|
||||||
|
ylim([-54,-25]);
|
||||||
|
xlim([0,105]);
|
||||||
|
xticks(0:20:110);
|
||||||
|
yticks(-50:10:10);
|
||||||
|
|
||||||
|
beautifyBERplot("logscale",0,"setmarkers",0)
|
||||||
|
pos = [100.3333 991.6667 358.0000 192.6667];
|
||||||
|
set(fig, 'Position', pos);
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
% === FINAL FIGURE SIZE ===
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user