- Fixed 'ML_MLSE'

- Added weighted DFE (work in progress)
- Added 'Evaluation Scripts' and 'Data' to 'projects\FSO_transmission', which contain different evaluations and measured data regarding the DSP applications for the FSO transmission data.
This commit is contained in:
magf
2026-01-20 13:45:53 +01:00
16 changed files with 615 additions and 151 deletions

View File

@@ -973,8 +973,8 @@ classdef Signal
maxA = max(sig(100:end-100))*1.3;
minA = min(sig(100:end-100))*1.3;
% maxA = 0.12;
% minA = -0.08;
maxA = 0.12;
minA = -0.08;
difference= maxA-minA;
@@ -995,7 +995,9 @@ classdef Signal
% beautify
cm=flip(cbrewer2("RdYlBu",4096));
% cm=flip(cbrewer2("RdBu",4096));
% cm=flip(cbrewer2("Blues",4096));
cm(1,:) = [1,1,1]; % set zeros to white => clean background
colormap(cm);
% colormap('turbo');
% ax.CLim = [0 50];

View File

@@ -27,11 +27,19 @@ classdef Timing_Recovery < handle
obj.(fn{n}) = options.(fn{n});
end
<<<<<<< HEAD
%obj-Initialization here%
end
function [data_out, timing_error] = process(obj, data_in)
=======
end
function [data_out,timing_error] = process(obj, data_in)
>>>>>>> 719e5508e776c18e3dcf72a954c71bdedda179e0
timing_synchronization = comm.SymbolSynchronizer( ...
"Modulation", obj.modulation,...
@@ -40,8 +48,14 @@ classdef Timing_Recovery < handle
"DampingFactor", obj.damping_factor, ...
"NormalizedLoopBandwidth", obj.normalized_loop_bandwidth, ...
"DetectorGain", obj.detector_gain);
<<<<<<< HEAD
data_out = data_in;
[data_out.signal, timing_error] = timing_synchronization(data_in.signal);
=======
data_out = data_in;
[data_out.signal,timing_error] = timing_synchronization(data_in.signal);
>>>>>>> 719e5508e776c18e3dcf72a954c71bdedda179e0
end
end

View File

@@ -95,7 +95,7 @@ try
adaption= 1;
use_dd_mode = 1;
use_ffe = 0;
use_ffe = 1;
use_dfe = 0;
use_vnle_mlse = 0;
use_dbtgt = 0;
@@ -149,6 +149,9 @@ try
% Scpe_sig.spectrum("fignum",22233,"normalizeTo0dB",0,"displayname",'Rx');
% Scpe_sig.eye(fsym,M,"fignum",1024);
Scpe_sig.signal = Scpe_sig.signal(1:2*Symbols.length);
Scpe_sig.signal = real(Scpe_sig.signal);
if duob_mode ~= db_mode.db_encoded
if use_ffe
@@ -246,7 +249,7 @@ try
%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, ...
"len_tr",length(Scpe_sig)/4,"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);

View File

@@ -157,7 +157,7 @@ function displayAnalysis(eq_noise, eq_signal_sd, rx_signal, eq_, tx_symbols, M,
% 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);
% showLevelScatter(rx_signal.resample("fs_out", tx_symbols.fs), tx_symbols, "fignum", 100);
warning off
showLevelScatter(eq_signal_sd, tx_symbols, "fignum", 101);
@@ -174,19 +174,20 @@ function displayAnalysis(eq_noise, eq_signal_sd, rx_signal, eq_, tx_symbols, M,
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);
figure(339);hold on
showEQfilter(eq_.e, 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);
% 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

View File

@@ -45,6 +45,7 @@ end
ml_mlse_results.config = Equalizerstruct();
<<<<<<< HEAD
eq_small = strip_eq(eq_, 10);
fn = fieldnames(eq_small);
for k = 1:numel(fn)
@@ -53,6 +54,9 @@ for k = 1:numel(fn)
end
end
json_str = jsonencode(eq_small);
=======
eq_ = strip_eq(eq_, 10);
>>>>>>> 719e5508e776c18e3dcf72a954c71bdedda179e0
fn = fieldnames(eq_);
for k = 1:numel(fn)
@@ -148,6 +152,9 @@ function eq_out = strip_eq(eq_, max_elems)
eq_.(props{i}) = [];
end
end
if issparse(val)
eq_.(props{i}) = find(eq_.(props{i}));
end
end
eq_out = eq_;
end

View File

@@ -283,7 +283,7 @@ if ~isempty(postFFE)
showEQcoefficients('n1', postFFE.e, "displayname", 'Coefficients', 'fignum', 338);
end
showEQcoefficients('n1', eq_.e,'n2', eq_.e2,'n3', eq_.e3, "displayname", 'Coefficients', 'fignum', 339);
% showEQcoefficients('n1', eq_.e1,'n2', eq_.e2,'n3', eq_.e3, "displayname", 'Coefficients', 'fignum', 339);
showEQfilter(eq_.e, eq_signal_sd.fs.*2);
figure(340); clf;

View File

@@ -1,15 +1,26 @@
<<<<<<< HEAD
base = "C:\Users\magf\Desktop\Desktop\MATLAB-Zeugs\FSO Equalizer\FSO_FP_QCL_60umUTC\";
=======
base = "C:\Users\Silas\Nextcloud4\Dokumente\02_Ablage_Office\FSO_FP_QCL_60umUTC";
>>>>>>> 719e5508e776c18e3dcf72a954c71bdedda179e0
mode = 0; %0 oder 1
M = 2;
all_files = dir(fullfile(base, "**/*.mat"));
if M == 2
<<<<<<< HEAD
tx_data_path = fullfile(base, "14G_PAM2\tx_info\tx_info_PAM2_14Gbd0.75RRC.mat");
filename = fullfile(base, "14G_PAM2\M=2_Rs=1.4e10_Fs=8e10_I=265mA_RoP=46.3mW_L=31m_PS=RRC_rolloff=0.75_Mode=Rise.mat");
elseif M == 4
tx_data_path = fullfile(base, "6G_PAM4\tx_info\tx_info_PAM4_6Gbd0.6RRC.mat");
=======
tx_data = load("C:\Users\Silas\Nextcloud4\Dokumente\02_Ablage_Office\FSO_FP_QCL_60umUTC\14G_PAM2\tx_info\tx_info_PAM2_14Gbd0.75RRC.mat");
filename = fullfile(base, "14G_PAM2\M=2_Rs=1.4e10_Fs=8e10_I=265mA_RoP=46.3mW_L=31m_PS=RRC_rolloff=0.75_Mode=Rise.mat");
elseif M == 4
tx_data = load("C:\Users\Silas\Nextcloud4\Dokumente\02_Ablage_Office\FSO_FP_QCL_60umUTC\6G_PAM4\tx_info\tx_info_PAM4_6Gbd0.6RRC.mat");
>>>>>>> 719e5508e776c18e3dcf72a954c71bdedda179e0
filename = fullfile(base, "6G_PAM4\M=4_Rs=6e9_Fs=8e10_I=255mA_RoP=42.3mW_L=31m_PS=RRC_rolloff=0.6_Mode=Rise.mat");
end
@@ -53,10 +64,14 @@ Bits_ = PM.demap(Symbols);
assert(ber == 0);
%% For comparison, apply pulsef on Tx Symbols
Pform = Pulseformer("fsym",fsym,"fdac",fs,"pulse","rc","pulselength",16,"alpha",rolloff);
Digi_sig_compare = Pform.process(Symbols);
MF = Pulseformer("fsym",fsym,"fdac",2*fsym,"pulse","rrc","pulselength",16,"alpha",rolloff);
Rx_sig_compare = MF.process(Digi_sig_compare);
Pform = Pulseformer("fsym",fsym,"fdac",fs,"pulse","rrc","pulselength",16,"alpha",rolloff);
Digi_sig_tx_compare = Pform.process(Symbols);
Pform = Pulseformer("fsym",fsym,"fdac",4*fsym,"pulse","rrc","pulselength",16,"alpha",rolloff);
Digi_sync = Pform.process(Symbols);
MF = Pulseformer("fsym",fsym,"fdac",4*fsym,"pulse","rrc","pulselength",16,"alpha",rolloff);
Rx_sig_compare = MF.process(Digi_sig_tx_compare);
%%
@@ -68,20 +83,31 @@ scoperead_volts = (traceData.RawData - traceData.YReference) * traceData.YIncrem
demystified = isequal(traceData.YData,scoperead_volts);
assert(demystified);
timesig_compare = [0:1:datas.tr.lastData(1).trace.ch3.Points-1] ./ fs;
timesig = datas.tr.lastData(1).trace.ch3.XData;
assert(isequal(traceData.YData,scoperead_volts));
Scope_sig = Electricalsignal(traceData.YData,"fs",fs);
Scope_sig.plot("displayname",'raw','fignum',100);
Scope_sig.spectrum("displayname",'raw','fignum',101)
%%
% 1) matched filter
% pulse is symmetric, hence we can use pulsef firectly as matched filter.
% pulse is symmetric, hence we can use pulsef directly as matched filter.
% It feels off (bit I think correct) that the fsym is now the output freq.!!
% -> output 2 sps to omit timing recovery!?
Pform = Pulseformer("fsym",fsym,"fdac",2*fsym,"pulse","rrc","pulselength",16,"alpha",rolloff,"matched",1);
Rx_matched = Pform.process(Scope_sig);
Rx_matched.spectrum("displayname",'Signal after matched filter','fignum',1);
apply_matched_filter = 0;
k = 4;
if apply_matched_filter
Pform = Pulseformer("fsym",fsym,"fdac",k*fsym,"pulse","rrc","pulselength",16,"alpha",rolloff,"matched",1);
Rx_matched = Pform.process(Scope_sig);
else
Rx_matched = Filter('filtdegree',4,"f_cutoff",fsym*0.5,"fs",Scope_sig.fs,"filterType",filtertypes.gaussian,"active",true).process(Scope_sig);
Rx_matched = Rx_matched.resample("fs_out",k*fsym);
end
Rx_matched.spectrum();
<<<<<<< HEAD
%%
sys = comm.SymbolSynchronizer('TimingErrorDetector', 'Gardner (non-data-aided)', ...
@@ -121,6 +147,25 @@ Rx_synced.plot("displayname",'RX: Matched+Sync+2sps','fignum',2);
Digi_sig_compare.normalize("mode","rms").spectrum("displayname",'Tx: RC-shaped','fignum',1,'normalizeTo0dB',0);
Rx_sig_compare.normalize("mode","rms").spectrum("displayname",'Tx: RC-shaped + matched filtered ','fignum',1,'normalizeTo0dB',0);
Rx_synced.normalize("mode","rms").spectrum("displayname",'RX: matched filtered + synced','fignum',1,'normalizeTo0dB',0);
=======
%% Timing Rec
apply_timing_rec = 1;
if apply_timing_rec
[Rx_symbolsync, timing_error] = Timing_Recovery("timing_error_detector",'Gardner (non-data-aided)','sps',k,'damping_factor',0.1,'normalized_loop_bandwidth',0.1,'detector_gain',2.7).process(Rx_matched);
figure();plot(timing_error);
Rx_symbolsync.fs = fsym;
% Tsynch
[~,Rx_synced_cell,inverted,sequenceFound,sequenceStarts] = Rx_symbolsync.tsynch("reference", Symbols, "fs_ref", fsym, "debug_plots", 0);
Rx_synced = Rx_synced_cell{1};
sps = 1;
else
% Tsynch
[~,Rx_synced_cell,inverted,sequenceFound,sequenceStarts] = Rx_matched.tsynch("reference", Symbols, "fs_ref", fsym, "debug_plots", 0);
Rx_synced = Rx_synced_cell{1};
Rx_synced = Rx_synced.resample("fs_out",2*fsym);
sps = 2;
end
>>>>>>> 719e5508e776c18e3dcf72a954c71bdedda179e0
if M == 2
ber_in_paper = 10^(-2.6); %fig 3a) 4 Gb/s MWIR FSO Transmission using Directly Modulated QCL and an Uncooled UTC-PD at Room-Temperature
@@ -128,50 +173,121 @@ elseif M == 4
ber_in_paper = 10^(-2.5);
end
%% -------------------- FFE --------------------
% requires some more digging what is going on :-)
eq_ffe = EQ("Ne",[50, 5, 5],"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, ...
%%
Rx_synced = Rx_synced_cell{1};
% -------------------- FFE --------------------
% requires some more digging what is going on :-)
eq_ffe = EQ("Ne",[50, 1, 1],"Nb",[2,0,0], ...
"training_length",512,"training_loops",5,"dd_loops",5, ...
"K",sps,"DCmu",mu_dc,"DDmu",[mu_ffe mu_dfe],"DFEmu",0.005, ...
"FFEmu",0,"plotfinal",0,"ideal_dfe",1);
ffe_results = ffe(eq_ffe,M,Rx_synced,Symbols,Bits, ...
"precode_mode",duob_mode,'showAnalysis',0,"postFFE",[], ...
"eth_style_symbol_mapping",mapping_style);
vars = logspace(-4,-3,36);
% ffe_results.metrics.print
fprintf('My EQ: %.1e \n',ffe_results.metrics.BER);
parfor i = 1:numel(vars)
len_tr = 4096;
mu_ffe1 = 0.01;% mus(i);%0.0001;
mu_ffe2 = 0.0008;
mu_ffe3 = 0.001;
mu_dc = 0.005;
mu_ffe = [mu_ffe1 mu_ffe2 mu_ffe3];
mu_dfe = vars(i);
duob_mode = db_mode.no_db;
% requires some more digging what is going on :-)
eq_ffe_1 = EQ("Ne",[150, 1, 0],"Nb",[50,0,0], ...
"training_length",len_tr,"training_loops",5,"dd_loops",5, ...
"K",sps,"DCmu",mu_dc,"DDmu",[mu_ffe mu_dfe],"DFEmu",0.005, ...
"FFEmu",0,"plotfinal",0,"ideal_dfe",0);
eq_ffe_2 = FFE("epochs_tr",1,"epochs_dd",vars(i),"len_tr",4096,"mu_dd",vars(i),"mu_tr",vars(i),"order",999,"sps",1,"decide",0, "adaption",adaption_method.nlms,"dd_mode",0);
% eq_ffe_2 = FFE_DFE("epochs_tr",5,"epochs_dd",5,"len_tr",4096*2,"ffe_mu_dd",1e-5,"dfe_mu_dd",mus(i),"ffe_mu_tr",0,"dfe_mu_tr",0,"ffe_order",50,"dfe_order",10,"sps",1,"decide",1);
ffe_results = ffe(eq_ffe_1,M,Rx_synced,Symbols,Bits, ...
"precode_mode",duob_mode,'showAnalysis',1,"postFFE",[], ...
"eth_style_symbol_mapping",mapping_style);
ffe_results.metrics.BER
bers(i) = ffe_results.metrics.BER;
end
figure();
plot(vars,bers);
yline(ber_in_paper)
beautifyBERplot();
%
fprintf('Paper: %.1e \n \n',ber_in_paper);
ffe_results.metrics.print("description",'FFE');
fprintf('FFE: %.1e \n',ffe_results.metrics.BER);
%% -------------------- VNLE + MLSE --------------------
len_tr = 4096;
mu_ffe1 = 0.0001;% mus(i);%0.0001;
mu_ffe2 = 0.0008;
mu_ffe3 = 0.001;
mu_dc = 0.005;
mu_ffe = [mu_ffe1 mu_ffe2 mu_ffe3];
mu_dfe = 0.0004;
duob_mode = db_mode.no_db;
pf_ncoeffs = 1;
eq_v = EQ("Ne",[100, 5, 5],"Nb",[0, 0, 0], ...
pf_ncoeffs = 4;
vars = 1:7;
bers = zeros(size(vars));
parfor i = 1:numel(vars)
eqv = EQ("Ne",[200, 1, 0],"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, ...
"K",sps,"DCmu",mu_dc,"DDmu",[mu_ffe mu_dfe],"DFEmu",0.005, ...
"FFEmu",0,"plotfinal",0,"ideal_dfe",1);
pf_ = Postfilter("ncoeff",pf_ncoeffs,"useBurg",1);
mlse_ = MLSE("duobinary_output",0,'M',M,'trellis_states',PAMmapper(M,0,"eth_style",mapping_style).levels);
[vnle_results, mlse_results] = vnle_postfilter_mlse(eq_v, pf_, mlse_, M, Rx_synced, Symbols, Bits, ...
"precode_mode", duob_mode, 'showAnalysis', 1, "postFFE", [], "eth_style_symbol_mapping", mapping_style);
mlse_results.metrics.print("description",'MLSE')
fprintf('My EQ: %.1e \n',mlse_results.metrics.BER);
fprintf('Paper: %.1e \n \n',ber_in_paper);
pf_ncoeffs = vars(i);
pf = Postfilter("ncoeff",pf_ncoeffs,"useBurg",1);
mlse_ = MLSE("duobinary_output",0,'M',M,'trellis_states',PAMmapper(M,0,"eth_style",mapping_style).levels);
[vnle_results, mlse_results] = vnle_postfilter_mlse(eqv, pf, mlse_, M, Rx_synced, Symbols, Bits, ...
"precode_mode", duob_mode, 'showAnalysis', 1, "postFFE", [], "eth_style_symbol_mapping", mapping_style);
fprintf('Paper: %.1e \n \n',ber_in_paper);
vnle_results.metrics.print("description",'VNLE');
mlse_results.metrics.print("description",'MLSE');
bers(i) = mlse_results.metrics.BER;
end
%%
figure();hold on
plot(vars,bers_ffe,'DisplayName','FFE [200,0,0] + PF + MLSE');
plot(vars,bers_vnle,'DisplayName','VNLE [200,1,0] + PF + MLSE');
plot(vars,bers_vnledfe,'DisplayName','VNLE [200,1,0] + DFE [2] + PF + MLSE');
plot(vars,bers_vnledfe_ideal,'DisplayName','VNLE [200,1,0] + ideal DFE [2] + PF + MLSE');
yline(ber_in_paper);
yline([2e-2, 4.85e-3, 3.8e-3, 2,2e-4],'LineWidth',2,'Color',[0.8,0.8,0.8],'LineStyle',':','HandleVisibility','off');
ylim([1e-5,0.1]);
beautifyBERplot();
%% -------------------- DB target --------------------
mlse_db_ = MLSE("DIR",[1,1],"duobinary_output",0,"M",M,'trellis_states',PAMmapper(M,0).levels);
eq_ = EQ("Ne",[50, 5, 5],"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",1);
"K",sps,"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, Rx_synced, Symbols, Bits, ...
"precode_mode", duob_mode, 'showAnalysis', 0, "postFFE", [],"eth_style_symbol_mapping",mapping_style);
dbt_results.metrics.print("description",'Duobinary');
mlse_results.metrics.print
fprintf('My EQ: %.1e \n',dbt_results.metrics.BER);
fprintf('Paper: %.1e \n \n',ber_in_paper);
dbt_results.metrics.print("description",'Duobinary');
%%
%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",len_tr,"mu_dd",mu_ml,"mu_tr",mu_ml,"order",11,"sps",1, ...
"traceback_depth",128,"L",3,"delta",4,"adaptive_mu",0);
[ml_mlse_results] = ml_mlse(ml_mlse_equalizer, M, Rx_synced, Symbols, Bits,"precode_mode",duob_mode);
ml_mlse_results.metrics.print("description",'ML ');

View File

@@ -2,7 +2,7 @@ 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);
@@ -12,10 +12,10 @@ fig=figure(fignum);clf;
dbmode = 0;
% 1 - PAM 4 with preemphasis
fp = QueryFilter();
M = 6;
M = 8;
rate = [360e9];
fp.where('Runs', 'pam_level','EQUALS', M);
fp.where('Runs', 'bitrate','EQUALS', rate);%360,390
fp.where('Runs', 'fiber_length','EQUALS', 2);
@@ -23,7 +23,7 @@ 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,~] = database.queryDB(fp, database.getTableFieldNames('Runs'));
dataTable = queryRunid(dataTable.run_id, database);
fsym = dataTable.symbolrate;
@@ -33,14 +33,36 @@ duob_mode = db_mode(strrep(dataTable.db_mode,'"',''));
% Load and Sync signal data from DB
[Tx_bits, Symbols, Scpe_cell, ~] = loadAndSyncSignalDataFromDb(dataTable, dsp_options);
Scpe_sig_syncd = Scpe_cell{1};
Scpe_sig_syncd.eye(fsym,M,"fignum",rate.*1e-9*M+1,"displayname",' Eye of Signal');
%%%%%% SNR CHEAT - Avges the measured signal occurences found after correlation in "tsynch" %%%%%%
average_signals = 1;
if average_signals
Scpe_sig_avg = Scpe_sig_syncd;
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 = Scpe_sig_avg.*1.25;
Scpe_sig_avg.eye(fsym,M,"fignum",rate.*1e-9*M,"displayname",' Eye of AVG Signal');
end
% Preprocess signal
Scpe_sig = preprocessSignal(Scpe_cell{1}, Symbols, fsym);
Scpe_sig = preprocessSignal(Scpe_sig_avg, 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'];
% outfile = ['C:\Users\Silas\Documents\latex\JLT_400G_submission\media\matlab2tikz\eye_pam_',num2str(M),'-2.tikz'];
% % outfile = ['C:\Users\Silas\Documents\latex\JLT_400G copy\media\matlab2tikz\vnle_optimization.tikz'];
% matlab2tikz(outfile, ...
% 'width','\fwidth', ...
% 'height','\fheight', ...

View File

@@ -42,14 +42,14 @@ fp = QueryFilter();
% fp.where('Runs', 'run_id','EQUALS', 2776);
M = 6;
fp.where('Runs', 'pam_level','EQUALS', M);
% fp.where('Runs', 'bitrate','EQUALS', 390e9);%360,390
fp.where('Runs', 'bitrate','EQUALS', 360e9);%360,390
% fp.where('Runs', 'symbolrate','EQUALS', 195e9);
fp.where('Runs', 'fiber_length','EQUALS', 10);
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', 'wavelength','EQUALS', 1310);
fp.where('Runs', 'db_mode','EQUALS', 0);
fp.where('Runs', 'rop_attenuation','EQUAL', 0);
% fp.where('Runs', 'power_pd_in','LESS_THAN', 7);
@@ -70,7 +70,7 @@ wh.addStorage("mlmlse_package");
%% === RUN IT ===
[results,wh] = submitJobs(dataTable.run_id(:), dsp_options, "parallel", 'wh', wh, 'waitbar', true);
[results,wh] = submitJobs(dataTable.run_id(:), dsp_options, "serial", 'wh', wh, 'waitbar', true);

View File

@@ -4,70 +4,77 @@ dsp_options.storage_path = 'Z:\2024\sioe_labor\';
dsp_options.max_occurences = 1;
db = DBHandler("dataBase", 'labor_highspeed', "type", 'mysql' );
fp = QueryFilter();
fp.where('Runs','fiber_length','EQUALS', 2);
fp.where('Runs','wavelength','EQUALS', 1310);
fp.where('Runs','bitrate','EQUALS', 300e9);
fp.where('Runs','pam_level','EQUALS', 4);
fp.where('Runs','rop_attenuation','EQUALS', 0);
fp.where('Runs','is_mpi','EQUALS', 0);
fp.where('Runs', 'db_mode','EQUALS', 0);
% fields = db.getTableFieldNames('Runs');
% [dataTable,~] = db.queryDB(fp, fields);
fields = db.getTableFieldNames('power_state_info');
fields = [fields; db.getTableFieldNames('Runs')];
fields = [fields; db.getTableFieldNames('dashboard_ungrouped_alltime')]; %dashboard_ungrouped_after_nov_2025 dashboard_ungrouped_aug_nov_2025
fields = unique(fields);
[dataTable,~] = db.queryDB(fp, fields);
fsym = dataTable(1,:).symbolrate;
M = double(dataTable(1,:).pam_level);
duob_mode = db_mode(strrep(dataTable(1,:).db_mode,'"',''));
% Load and Sync signal data from DB
[Tx_bits, Symbols, Scpe_cell, ~] = loadAndSyncSignalDataFromDb(dataTable(1,:), dsp_options);
% Preprocess signal
Scpe_sig = preprocessSignal(Scpe_cell{1}, Symbols, fsym);
% Show spectrum
Scpe_sig.spectrum("fignum",1,"displayname",'Rx')
% meta = struct();
% meta.varnames = dataTable.Properties.VariableNames;
% fp = QueryFilter();
%
% for k = 1:numel(meta.varnames)
% v = meta.varnames{k};
% col = dataTable.(v);
% fp.where('Runs','fiber_length','EQUALS', 2);
% fp.where('Runs','wavelength','EQUALS', 1310);
% fp.where('Runs','bitrate','EQUALS', 300e9);
% fp.where('Runs','pam_level','EQUALS', 4);
% fp.where('Runs','rop_attenuation','EQUALS', 0);
% fp.where('Runs','is_mpi','EQUALS', 0);
% fp.where('Runs', 'db_mode','EQUALS', 0);
% % fields = db.getTableFieldNames('Runs');
% % [dataTable,~] = db.queryDB(fp, fields);
%
% if isnumeric(col) || islogical(col)
% meta.(v) = col;
% elseif isstring(col)
% meta.(v) = cellstr(col);
% elseif iscellstr(col)
% meta.(v) = col;
% else
% error("Unsupported table column type: %s", class(col))
% end
% end
% exp_data.metadata = meta;
exp_data = struct();
exp_data.metadata = dataTable;
exp_data.tx_bits = Tx_bits.signal;
exp_data.tx_signal = Symbols.signal;
exp_data.rx_signal_2sps = Scpe_sig.signal;
run_ids = [ 993 1205 1413 1623 1833 2043 2253 2628 2836 2958 3000 3042 3323 5098 5225 5267 5309];
fname = dataTable(1,:).rx_raw_path;
[~, filename, ext] = fileparts(fname);
filename = strrep(filename,"_raw_signal","");
filename = filename + ext;
savepath = fullfile('F:\2024\sioe_labor\export_skuehl\',filename);
save(savepath,'exp_data','-v7.3');
for id = run_ids
fp = QueryFilter();
fp.where('Runs', 'run_id','EQUALS', id);
fields = db.getTableFieldNames('power_state_info');
fields = [fields; db.getTableFieldNames('Runs')];
fields = [fields; db.getTableFieldNames('dashboard_ungrouped_alltime')]; %dashboard_ungrouped_after_nov_2025 dashboard_ungrouped_aug_nov_2025
fields = unique(fields);
[dataTable,~] = db.queryDB(fp, fields);
fsym = dataTable(1,:).symbolrate;
M = double(dataTable(1,:).pam_level);
duob_mode = db_mode(strrep(dataTable(1,:).db_mode,'"',''));
% Load and Sync signal data from DB
[Tx_bits, Symbols, Scpe_cell, ~] = loadAndSyncSignalDataFromDb(dataTable(1,:), dsp_options);
% Preprocess signal
Scpe_sig = preprocessSignal(Scpe_cell{1}, Symbols, fsym);
% Show spectrum
Scpe_sig.spectrum("fignum",1,"displayname",'Rx')
meta = struct();
meta.varnames = dataTable.Properties.VariableNames;
for k = 1:numel(meta.varnames)
v = meta.varnames{k};
col = dataTable.(v);
if isnumeric(col) || islogical(col)
meta.(v) = col;
elseif isstring(col)
meta.(v) = cellstr(col);
elseif iscellstr(col)
meta.(v) = col;
else
error("Unsupported table column type: %s", class(col))
end
end
exp_data.metadata = meta;
exp_data = struct();
exp_data.metadata = dataTable;
exp_data.tx_bits = Tx_bits.signal;
exp_data.tx_signal = Symbols.signal;
exp_data.rx_signal_2sps = Scpe_sig.signal;
fname = dataTable(1,:).rx_raw_path;
[~, filename, ext] = fileparts(fname);
filename = strrep(filename,"_raw_signal","");
filename = filename + ext;
savepath = fullfile('F:\2024\sioe_labor\export_skuehl\',filename);
save(savepath,'exp_data','-v7.3');
end

View File

@@ -1,5 +1,5 @@
filename = "C:\Users\sioe\Documents\High_Speed_Measurement_2024\baudrate_sweep_b2b\PAMX_b2b_baudrate20241024_210648_wh.mat";
filename = "F:\2024\sioe\High Speed Messungen Oktober\baudrate_sweep_b2b\PAMX_b2b_baudrate20241024_210648_wh_final.mat";
a = load(filename);
wh = a.obj;

View File

@@ -8,7 +8,7 @@ fdac = 256e9;
fadc = 256e9;
random_key = 1;
rcalpha = 0.05;
rcalpha = 0.6;
kover = 16;
duob_mode = db_mode.no_db;
@@ -25,7 +25,7 @@ tx_bw_nyquist = 0.8;
link_length = 1;
% RX
rop = -8;
rop = -9;
rx_bw_nyquist = 0.8;
vnle_order1 = 50;
@@ -51,7 +51,7 @@ mu_ffe = [mu_ffe1 mu_ffe3 mu_ffe3];
mu_dfe = 0.0004;
Pform = Pulseformer("fsym",fsym,"fdac",4*fsym,"pulse","rc","pulselength",16,"alpha",rcalpha);
Pform = Pulseformer("fsym",fsym,"fdac",4*fsym,"pulse","rrc","pulselength",16,"alpha",rcalpha);
[Digi_sig,Symbols,Tx_bits] = PAMsource(...
"fsym",fsym,"M",M,"order",18,"useprbs",0,...
@@ -65,7 +65,7 @@ Pform = Pulseformer("fsym",fsym,"fdac",4*fsym,"pulse","rc","pulselength",1
%%%%% AWG
El_sig = M8199A("kover",kover).process(Digi_sig);
% El_sig = AWG("fdac",fdac,"f_cutoff",fsym,"lpf_active",0,"kover",kover,"bit_resolution",12,"upsampling_method","samplehold","precomp_sinc_rolloff",1).process(Digi_sig);
El_sig.spectrum("displayname",'Digi Spectrum','fignum',100,'normalizeTo0dB',0);
El_sig.spectrum("displayname",'Digi Spectrum','fignum',1,'normalizeTo0dB',1);
% El_sig = El_sig.setPower(0,"dBm");
%%%%% Electrical Driver Amplifier %%%%%%
@@ -101,32 +101,53 @@ Scpe_sig = Scope("fsimu",fdac*kover,"fadc",fadc,...
"delay",0,"fixed_delay",0,"filtertype",filtertypes.butterworth,...
"samplingdelay",0,"rand_samplingdelay",0,"freq_offset",0,"samp_jitter",0,...
"adcresolution",8,"quantbuffer",0.1,'block_dc',1,'lpf_active',1,'H_lpf',Lp_scpe).process(Rx_sig);
%%
%%%%%% Sample to 2x fsym %%%%%%
Scpe_sig = Scpe_sig.resample("fs_out",2*fsym);
Scpe_sig.signal = Scpe_sig.signal(1:2*length(Symbols));
% 1) matched filter
% pulse is symmetric, hence we can use pulsef firectly as matched filter.
% It feels off (bit I think correct) that the fsym is now the output freq.!!
% -> output 2 sps to omit timing recovery!?
Pform = Pulseformer("fsym",fsym,"fdac",2*fsym,"pulse","rrc","pulselength",16,"alpha",rcalpha,"matched",1);
Scpe_sig = Pform.process(Scpe_sig);
Scpe_sig.spectrum("displayname",'Signal after matched filter','fignum',1,'normalizeTo0dB',1);
%
% %%
% %%%%%% Sample to 2x fsym %%%%%%
% Scpe_sig = Scpe_sig.resample("fs_out",2*fsym);
% Scpe_sig.signal = Scpe_sig.signal(1:2*length(Symbols));
%%
%%%%%% Sync Rx signal with reference %%%%%%
[Scpe_sig,~] = Scpe_sig.tsynch("reference",Symbols,"fs_ref",fsym,"debug_plots",0);
[Scpe_sig,~] = Scpe_sig.tsynch("reference",Symbols,"fs_ref",fsym,"debug_plots",1);
Scpe_sig.spectrum("displayname",'Opt Spectrum','fignum',11,'normalizeTo0dB',1);
Scpe_sig = Filter('filtdegree',4,"f_cutoff",Symbols.fs.*0.5,"fs",Scpe_sig.fs,"filterType",filtertypes.gaussian,"active",true).process(Scpe_sig);
% Scpe_sig = Filter('filtdegree',4,"f_cutoff",Symbols.fs.*0.5,"fs",Scpe_sig.fs,"filterType",filtertypes.gaussian,"active",true).process(Scpe_sig);
Scpe_sig = Scpe_sig - mean(Scpe_sig.signal);
Scpe_sig.signal = Scpe_sig.signal(1:2*length(Symbols));
%%
% -------------------- FFE --------------------
ffe_order = [50, 0, 0];
eq_ffe = EQ("Ne",ffe_order,"Nb",[0,0,0], ...
eq_ = 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);
output.ffe_results = ffe(eq_ffe,M,Scpe_sig,Symbols,Tx_bits, ...
"precode_mode",duob_mode,'showAnalysis',0,"postFFE",[], ...
% eq_ = FFE("epochs_tr",4,"epochs_dd",5,"len_tr",4096,"mu_dd",0.01,"mu_tr",0.01,"order",50,"sps",2,"decide",0, "adaption",adaption_method.nlms,"dd_mode",1);
eq_ = FFE_DFE("epochs_tr",5,"epochs_dd",5,"len_tr",512,"ffe_mu_dd",1e-4,"dfe_mu_dd",5e-4,"ffe_mu_tr",0,"dfe_mu_tr",0,"ffe_order",99,"dfe_order",99,"sps",2,"decide",0);
output.ffe_results = ffe(eq_,M,Scpe_sig,Symbols,Tx_bits, ...
"precode_mode",duob_mode,'showAnalysis',1,"postFFE",[], ...
"eth_style_symbol_mapping",0);
output.ffe_results.metrics.print
%%
% -------------------- VNLE + MLSE --------------------
pf_ncoeffs = 1;
ffe_order3 = [50, 5, 5];
@@ -139,8 +160,11 @@ pf_ = Postfilter("ncoeff",pf_ncoeffs,"useBurg",1);
mlse_ = MLSE("duobinary_output",0,'M',M,'trellis_states',PAMmapper(M,0).levels);
[output.vnle_results, output.mlse_results] = vnle_postfilter_mlse(eq_v, pf_, mlse_, M, Scpe_sig, Symbols, Tx_bits, ...
"precode_mode", duob_mode, 'showAnalysis', 0, "postFFE", [], "eth_style_symbol_mapping", 0);
"precode_mode", duob_mode, 'showAnalysis', 1, "postFFE", [], "eth_style_symbol_mapping", 0);
output.mlse_results.metrics.print
%%
% -------------------- DB target --------------------
mlse_db_ = MLSE("DIR",[1,1],"duobinary_output",0,"M",M,'trellis_states',PAMmapper(M,0).levels);

View File

@@ -0,0 +1,88 @@
wh_aeon = load("C:\Users\Silas\Documents\MATLAB\imdd_simulation\projects\Lab_analysis\aeon_soa_measurement_lambda_plaser_pump.mat");
wh_aeon = wh_aeon.wh;
wh_thor = load("C:\Users\Silas\Documents\MATLAB\imdd_simulation\projects\Lab_analysis\thorlabs_pdfa_measurement_lambda_plaser_pump.mat");
wh_thor = wh_thor.wh;
% Silas' custom "warehouse" datatype
wh_aeon.showInfo;
wh_thor.showInfo;
%% PLOT OSA SPECTRA
figure();hold on
cols = linspecer(4);
cols = cbrewer2('Paired',8);
subplot(1,2,1);hold on;
wh = wh_thor;
ccnt = 1;
pumps = wh.parameter.pump.values;
plasers = wh.parameter.laserpower.values;
scnt = 1;
for p = 1:numel(plasers)
for pmp = 1:numel(pumps)
subplot(numel(plasers),numel(pumps),scnt);hold on;
title(sprintf('Laser: %d dBm; Pump: %d %',plasers(p),pumps(pmp)),"Interpreter","tex")
for lambda = wh.parameter.lambda.values
spectrum_osa = wh_thor.getStoValue('spectrum_osa',plasers(p),lambda,pumps(pmp));
wavelength_osa = wh_thor.getStoValue('wavelength_osa',plasers(p),lambda,pumps(pmp));
plot(wavelength_osa,spectrum_osa,'DisplayName',sprintf('P_{in}: %d dB ',plasers(p)),'Color',cols(ccnt,:));
spectrum_osa = wh_aeon.getStoValue('spectrum_osa',plasers(p),lambda,pumps(pmp));
wavelength_osa = wh_aeon.getStoValue('wavelength_osa',plasers(p),lambda,pumps(pmp));
plot(wavelength_osa,spectrum_osa,'DisplayName',sprintf('P_{in}: %d dB ',plasers(p)),'Color',cols(ccnt+1,:));
ylim([-60, 20]);
beautifyBERplot("logscale",false,"setmarkers",0,"setcolors",0);
end
scnt = scnt +1;
end
ccnt = ccnt+2;
end
xlabel('Wavelength [nm]');
ylabel('OSNR [dB]')
%%
figure();hold on
cols = linspecer(4);
subplot(1,2,1);hold on;
wh = wh_thor;
ccnt = 1;
pumps = wh.parameter.pump.values;
plasers = wh.parameter.laserpower.values;
scnt = 1;
for p = 1:numel(plasers)
for pmp = 1:numel(pumps)
subplot(numel(plasers),numel(pumps),scnt);hold on;
ase_noise = wh_thor.getStoValue('pase_osa',plasers(p),wh.parameter.lambda.values,pumps(pmp));
signal = wh_thor.getStoValue('psig_osa',plasers(p),wh.parameter.lambda.values,pumps(pmp));
plot(wh.parameter.lambda.values,ase_noise,'DisplayName',sprintf('P_{in}: %d dB ',plasers(p)),'Color',cols(ccnt,:));
ase_noise = wh_aeon.getStoValue('pase_osa',plasers(p),wh.parameter.lambda.values,pumps(pmp));
signal = wh_aeon.getStoValue('psig_osa',plasers(p),wh.parameter.lambda.values,pumps(pmp));
plot(wh.parameter.lambda.values,ase_noise,'DisplayName',sprintf('P_{in}: %d dB ',plasers(p)),'Color',cols(ccnt,:),'LineStyle','-');
ylim([-60, 20]);
beautifyBERplot("logscale",false,"setmarkers",0,"setcolors",0);
scnt = scnt +1;
end
ccnt = ccnt+1;
end
xlabel('Wavelength [nm]');
ylabel('OSNR [dB]')

View File

@@ -1,5 +1,5 @@
base = "C:\Users\Silas\Nextcloud\Cluster";
base = "C:\Users\Silas\Nextcloud4\Cluster";
all_files = dir(fullfile(base, "**/*.mat"));
schemes = ["co","pair","alt","seg"];
@@ -13,8 +13,8 @@ T = table('Size',[0 10], ...
rx = "^WDM_(?<date>\d{8})_(?<time>\d{6})_n(?<node>\d+)_(?<jobid>\d+)_" + ...
"(?<L>\d+)km_(?<Nch>\d+)ch_(?<df>\d+)ghz_(?<scheme>[a-z]+)_alpha(?<alpha>\d+(?:_\d+)?)\.mat$";
for k = 1:numel(all_files)
f = all_files(k);
for i = 1:numel(all_files)
f = all_files(i);
folder = string(f.folder);
file = string(f.name);
@@ -44,6 +44,8 @@ for k = 1:numel(all_files)
end
%%
idx = strcmp(T.scheme,"co") & ...
T.alpha == 0.4 & ...
T.date >= datetime(2026,1,9) & ...
@@ -51,13 +53,181 @@ idx = strcmp(T.scheme,"co") & ...
T_sel = T(idx,:);
i = 2;
res = load(fullfile(T_sel.folder(i),T_sel.file(i)),'res');
res = res.res;
% ---- Load all res ----
R = cell(numel(T_sel.file),1);
for i = 1:numel(T_sel.file)
S = load(fullfile(T_sel.folder(i),T_sel.file(i)),'res');
S.res = strip_config_from_res(S.res);
R{i} = S.res;
end
res_all = combine_res_list(R);
res_all = drop_empty_realizations(res_all);
%%
%%
%%
% Routine A: plot BER curves and compute crossings
S = plot_BER_vs_ROP(res, 'fec', 3.8e-3);
S = plot_BER_vs_ROP(res_all, 'fec', 3.8e-3);
%% Routine B: violin plot (independent)
plot_FEC_violin(res, 'tech','VNLE', 'fec',3.8e-3, 'ylim',[-10 0]);
plot_FEC_violin(res_all, 'tech','VNLE', 'fec',3.8e-3, 'ylim',[-10 0],'eval_ptr',5);
%%
function res = strip_config_from_res(res)
% Remove the "config" payload from every non-empty result cell
% Works whether entries are structs-with-field or objects-with-property.
techs = {'ffe','dfe','vnle','mlse','dbt'};
for t = 1:numel(techs)
fn = techs{t};
if ~isfield(res, fn) || isempty(res.(fn)), continue; end
C = res.(fn);
if ~iscell(C), continue; end
idx = find(~cellfun('isempty', C)); % fast builtin
for k = 1:numel(idx)
x = C{idx(k)};
% Case 1: struct entry with field "config"
if isstruct(x) && isfield(x,'config')
x = rmfield(x,'config');
% Case 2: object entry with property "config"
elseif isobject(x) && isprop(x,'config')
try
x.config = []; % lighter than keeping Equalizerstruct JSON
catch
% ignore if class forbids assignment
end
end
C{idx(k)} = x;
end
res.(fn) = C;
end
end
% ===================== Local helper functions =====================
function res_out = combine_res_list(R)
% Concatenate along realization dimension (dim=3) for all techniques.
% Requires consistent sizes in dims 1,2,4 and consistent eval_dist_km.
fieldsTech = ["ffe","dfe","vnle","mlse","dbt"];
% Start with first
res_out = R{1};
% --- Build common distance axis (union, stable) ---
dist_all = res_out.eval_dist_km(:).';
for k = 2:numel(R)
dist_all = unique([dist_all, R{k}.eval_dist_km(:).'], 'stable');
end
% --- If res_out not already on dist_all, expand it ---
if ~isequal(res_out.eval_dist_km(:).', dist_all)
res_out = expand_res_dist(res_out, dist_all);
end
% --- For each file: expand to dist_all, then merge realizations (your logic) ---
for k = 2:numel(R)
R{k} = expand_res_dist(R{k}, dist_all);
end
% Concatenate technique cell arrays along dim=3 (realizations)
for f = fieldsTech
A = res_out.(f);
for k = 2:numel(R)
B = R{k}.(f);
A = cat(3, A, B);
end
res_out.(f) = A;
end
% Update num_realiz in settings to match concatenated dim
dims = size(res_out.ffe); if numel(dims)<3, dims(3)=1; end
res_out.settings.num_realiz = dims(3);
end
function res = expand_res_dist(res, dist_all)
techs = {'ffe','dfe','vnle','mlse','dbt'};
old = res.eval_dist_km(:).';
new = dist_all(:).';
[~,loc] = ismember(old, new); % mapping old -> new positions
if any(loc==0)
error('expand_res_dist: internal: old distances not found in union.');
end
% sizes from an existing field (prefer ffe)
Cref = res.ffe;
sz = size(Cref); sz(end+1:4) = 1; % ensure 4 dims
Nch=sz(1); Nrop=sz(2); Nreal=sz(3); Nnew=numel(new);
for t = 1:numel(techs)
fn = techs{t};
if ~isfield(res,fn) || isempty(res.(fn)), continue; end
Cold = res.(fn);
sz2 = size(Cold); sz2(end+1:4) = 1;
Cnew = cell(sz2(1), sz2(2), sz2(3), Nnew);
Cnew(:,:,:,loc) = Cold; % place old distances into new axis
res.(fn) = Cnew;
end
res.eval_dist_km = new;
end
function res_out = drop_empty_realizations(res_in)
% Removes realizations where ALL entries are empty across ALL techniques
% (across channels, rop, distances).
res_out = res_in;
fieldsTech = ["ffe","dfe","vnle","mlse","dbt"];
% Determine sizes from one field
dims = size(res_in.ffe);
if numel(dims) < 4, dims(end+1:4) = 1; end
Nreal = dims(3);
% For each realization, check if there is at least one non-empty result anywhere
keep = false(1, Nreal);
for r = 1:Nreal
hasAny = false;
for f = fieldsTech
C = res_in.(f); % cell array
% Slice all ch,rop,dist for this realization
slice = C(:,:,r,:); % still a cell array
hasAny = any(~cellfun(@isempty, slice(:)));
if hasAny, break; end
end
keep(r) = hasAny;
end
fprintf('drop_empty_realizations: keeping %d/%d realizations (dropping %d)\n', ...
sum(keep), Nreal, sum(~keep));
% Apply keep mask
for f = fieldsTech
res_out.(f) = res_out.(f)(:,:,keep,:);
end
% Update settings
res_out.settings.num_realiz = sum(keep);
end

View File

@@ -52,7 +52,7 @@ f_plan = physconst('lightspeed')./(s.wavelengthplan.*1e-9);
margin = 25e12; % some THz left and right
f_span = (max(f_plan)+margin)-(min(f_plan)-margin);
f_nyq = f_span/2;
kover = 8;
kover = 4;
upsample_required = f_nyq./(fdac*kover/2);
upsample_pow = 2^nextpow2(upsample_required);
upsample_ceil = ceil(upsample_required);
@@ -64,13 +64,23 @@ signal_cell = {};
Symbols = {};
Tx_bits = {};
s.rop = -6:0.75:-0.75;
s.rop = -12:0.75:-0.75;
output_ffe = cell(length(s.wavelengthplan),length(s.rop),s.num_realiz);
output_vnle = cell(length(s.wavelengthplan),length(s.rop),s.num_realiz);
output_mlse = cell(length(s.wavelengthplan),length(s.rop),s.num_realiz);
output_dbt = cell(length(s.wavelengthplan),length(s.rop),s.num_realiz);
s.p = "pair";
switch s.p
case "co"
pol_rot = 100.*ones(1,length(s.wavelengthplan));
case "pair"
pol_rot = repmat([100,100,0,0],1,length(s.wavelengthplan)/4);
case "alt"
pol_rot = repmat([100,0,100,0],1,length(s.wavelengthplan)/4);
end
for realiz = 1:s.num_realiz
@@ -99,7 +109,7 @@ for realiz = 1:s.num_realiz
%%%%% s.MODULATE E/O CONVERSION %%%%%
Eml_out = EML("mode",eml_mode.im_cosinus,"power",3,"fsimu",El_sig.fs,"lambda",s.wavelengthplan(l),"bias",vbias,"u_pi",u_pi,"linewidth",laser_linewidth,"randomkey",s.random_key+l+realiz).process(El_sig);
signal_cell{l} = Polarization_Controller("mode","rot_power","desired_power",100).process(Eml_out);
signal_cell{l} = Polarization_Controller("mode","rot_power","desired_power",pol_rot(l)).process(Eml_out);
end
Opt_sig_wdm = Optical_Multiplex("fs_in",fdac*kover,"fs_out",upsample_pow*fdac*kover,...
@@ -107,7 +117,7 @@ for realiz = 1:s.num_realiz
Opt_sig_wdm = Amplifier("amp_mode","ideal_no_noise","gain_mode","output_power","amplification_db",3+10*log10(N)).process(Opt_sig_wdm);
% Opt_sig_wdm.spectrum("fignum",101,"displayname",'bla','normalizeTo0dB',0,'lambda0_nm',1310,'useWavelengthAxis',0);
Opt_sig_wdm.spectrum("fignum",101,"displayname",'bla','normalizeTo0dB',0,'lambda0_nm',1310,'useWavelengthAxis',0);
% Opt_sig_wdm.spectrum("fignum",101,"displayname",'bla','normalizeTo0dB',1,'max_num_lines',2);
@@ -122,7 +132,7 @@ for realiz = 1:s.num_realiz
Dvec = getDispersionVector(nSegments, D_local, zdw, randomize_D, s.random_key+realiz);
for seg = 1:nSegments
Opt_sig_wdm_fib = DP_Fiber("L",segment_length,"D",Dvec(s),"Dpmd",pmd,"Ds",0.07,...
Opt_sig_wdm_fib = DP_Fiber("L",segment_length,"D",Dvec(seg),"Dpmd",s.pmd,"Ds",0.07,...
"beat_len",10,"corr_len",100,"dz",1,"manakov",0,...
"gamma",s.gamma,"lambda",zdw,"n_waveplates",10,"SS_dphimax",0.01,...
"SS_dzmax",50,"SS_dzmin",10,"X_alpha",0.3,"X_beta",0,"rng",1).process(Opt_sig_wdm_fib);