halfway merged and pulled?!
This commit is contained in:
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 ===
|
||||
@@ -0,0 +1,124 @@
|
||||
%% ============================================================
|
||||
% LOAD DATA
|
||||
% ============================================================
|
||||
database_type = 'mysql';
|
||||
db = DBHandler("dataBase", "labor_highspeed", "type", database_type);
|
||||
|
||||
M = 4; % PAM level for this analysis
|
||||
|
||||
fp = QueryFilter();
|
||||
fp.where('Runs', 'pam_level', 'EQUALS', M);
|
||||
fp.where('Runs', 'fiber_length', 'EQUALS', 10);
|
||||
fp.where('Runs', 'bitrate', 'EQUALS', 360e9);
|
||||
fp.where('Runs', 'is_mpi', 'EQUALS', 0);
|
||||
|
||||
fields = [
|
||||
db.getTableFieldNames('power_state_info');
|
||||
db.getTableFieldNames('dashboard_ungrouped_alltime')
|
||||
];
|
||||
|
||||
[dataTable, ~] = db.queryDB(fp, fields);
|
||||
|
||||
|
||||
%% ============================================================
|
||||
% COMMON CONFIGURATION FOR ALL SUBPLOTS
|
||||
% ============================================================
|
||||
%% ============================================================
|
||||
% DEFINE DSP ALGORITHMS FOR THE 4 SUBPLOTS
|
||||
% ============================================================
|
||||
curves = struct;
|
||||
|
||||
curves(1).name = 'VNLE';
|
||||
curves(1).eq = equalizer_structure.vnle;
|
||||
curves(1).pre = 0;
|
||||
curves(1).color = clr.Paired.red;
|
||||
|
||||
curves(2).name = 'PF + MLSE';
|
||||
curves(2).eq = equalizer_structure.vnle_pf_mlse;
|
||||
curves(2).pre = 0;
|
||||
curves(2).color = clr.Paired.green;
|
||||
|
||||
curves(3).name = 'DB-target + MLSE';
|
||||
curves(3).eq = equalizer_structure.vnle_db_mlse;
|
||||
curves(3).pre = 0;
|
||||
curves(3).color = clr.Paired.blue;
|
||||
|
||||
curves(4).name = 'ML-based MLSE';
|
||||
curves(4).eq = equalizer_structure.ml_mlse;
|
||||
if M == 4
|
||||
curves(4).pre = 0;
|
||||
else
|
||||
curves(4).pre = 1;
|
||||
end
|
||||
curves(4).color = clr.Paired.purple;
|
||||
|
||||
|
||||
%% ============================================================
|
||||
% ANALYSIS ENGINE — NO PLOTTING
|
||||
% ============================================================
|
||||
results = struct;
|
||||
|
||||
for k = 1:numel(curves)
|
||||
|
||||
%% ---- 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', 360e9, ...
|
||||
'fiber_length', 10, ...
|
||||
'equalizer_structure', curves(k).eq, ...
|
||||
'pre_emph', curves(k).pre);
|
||||
|
||||
%% ---- GET BER ----
|
||||
cfg.y_axis = 'BER';
|
||||
A = analyze_measurements_gpt(dataTable, cfg);
|
||||
|
||||
results(k).wavelength = A.group{1}.x;
|
||||
|
||||
if curves(k).eq == equalizer_structure.vnle_db_mlse || ...
|
||||
curves(k).eq == equalizer_structure.ml_mlse
|
||||
% DB and ML-based need precoded BER
|
||||
results(k).ber = A.group{1}.y_precoded;
|
||||
else
|
||||
results(k).ber = A.group{1}.y;
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
%% ============================================================
|
||||
% 1×4 TILED BER-vs-WAVELENGTH FIGURE
|
||||
% ============================================================
|
||||
fig=figure(901);
|
||||
tiledlayout(1,4,'TileSpacing','compact','Padding','compact');
|
||||
|
||||
lw = 1.8; % line width
|
||||
ms = 6; % marker size
|
||||
|
||||
for k = 1:numel(curves)
|
||||
nexttile; hold on;
|
||||
|
||||
plot(results(k).wavelength, results(k).ber, ...
|
||||
'-o', ...
|
||||
'Color', curves(k).color, ...
|
||||
'MarkerFaceColor', curves(k).color, ...
|
||||
'MarkerSize', ms, ...
|
||||
'LineWidth', lw);
|
||||
|
||||
set(gca,'YScale','log');
|
||||
grid on;
|
||||
xlabel('wavelength');
|
||||
ylabel('BER');
|
||||
title(curves(k).name);
|
||||
ylim([1e-4, 0.1])
|
||||
beautifyBERplot();
|
||||
end
|
||||
pos = 1e3.*[0.1070 0.5497 1.4113 0.3253];
|
||||
set(fig, 'Position', pos);
|
||||
@@ -0,0 +1,160 @@
|
||||
%% ============================================================
|
||||
% PARAMETERS
|
||||
% ============================================================
|
||||
database_type = 'mysql';
|
||||
db = DBHandler("dataBase", "labor_highspeed", "type", database_type);
|
||||
|
||||
pam_level = 4; % FIXED for this figure
|
||||
baudrates = [300e9 330e9 360e9 390e9];
|
||||
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 — results(b, k): b = baudrate index, k = DSP scheme index
|
||||
% ============================================================
|
||||
results = struct;
|
||||
|
||||
for b = 1:length(baudrates)
|
||||
|
||||
Rb = baudrates(b);
|
||||
|
||||
% --- query matching runs ---
|
||||
fp = QueryFilter();
|
||||
fp.where('Runs','pam_level','EQUALS', pam_level);
|
||||
fp.where('Runs','fiber_length','EQUALS', fiberL);
|
||||
fp.where('Runs','bitrate','EQUALS', Rb);
|
||||
fp.where('Runs','is_mpi','EQUALS', 0);
|
||||
|
||||
[dataTable, ~] = db.queryDB(fp, fields);
|
||||
|
||||
for k = 1:numel(curves)
|
||||
|
||||
%% ---- DECIDE PRE-EMPH & PRECoded RULES for PAM-4 ----
|
||||
pre_emph = decide_preemph(pam_level, curves(k).eq);
|
||||
use_precoded = decide_precoded(pam_level, curves(k).eq);
|
||||
|
||||
%% ---- SETUP ANALYSIS 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', pam_level, ...
|
||||
'is_mpi', 0, ...
|
||||
'bitrate', Rb, ...
|
||||
'fiber_length', fiberL, ...
|
||||
'equalizer_structure', curves(k).eq, ...
|
||||
'pre_emph', pre_emph);
|
||||
|
||||
%% ---- RUN ANALYSIS ----
|
||||
A = analyze_measurements_gpt(dataTable, cfg);
|
||||
|
||||
results(b,k).wavelength = A.group{1}.x;
|
||||
|
||||
if use_precoded
|
||||
results(b,k).ber = A.group{1}.y_precoded;
|
||||
else
|
||||
results(b,k).ber = A.group{1}.y;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
%% ============================================================
|
||||
% PLOT — 1×4 (one tile per baudrate)
|
||||
% ============================================================
|
||||
fig = figure(); clf;
|
||||
tiledlayout(1,4,'TileSpacing','compact','Padding','compact');
|
||||
|
||||
lw = 1.8;
|
||||
ms = 6;
|
||||
|
||||
for b = 1:length(baudrates)
|
||||
nexttile; hold on;
|
||||
|
||||
for k = 1:numel(curves)
|
||||
plot(results(b,k).wavelength, results(b,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('Wavelength [nm]');
|
||||
ylabel('BER');
|
||||
ylim([1e-4 0.1]);
|
||||
title(sprintf('PAM-%d @ %.0f GBd',pam_level, baudrates(b)/1e9));
|
||||
legend('Location','best');
|
||||
beautifyBERplot();
|
||||
end
|
||||
|
||||
% Optional figure size
|
||||
pos = 1e3.*[0.1 0.55 1.4 0.32];
|
||||
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,88 @@
|
||||
%% ============================================================
|
||||
% PLOT
|
||||
% ============================================================
|
||||
figure; hold on;
|
||||
ms = 32; % scatter size
|
||||
lw = 0.8; % line width
|
||||
|
||||
for k = 1:4 % PAM-2/4/6/8
|
||||
|
||||
M = pam_list(k);
|
||||
idxPam = (Mvals == M);
|
||||
|
||||
% Extract for this PAM
|
||||
x = baud(idxPam);
|
||||
y = netrate(idxPam);
|
||||
n = names(idxPam);
|
||||
|
||||
% Get color for this PAM format
|
||||
col = colors(k,:);
|
||||
|
||||
% ----- LEGEND FLAG (only add one entry per PAM) -----
|
||||
firstLegend = true;
|
||||
|
||||
% ---- PLOT ALL POINTS (marker based on publication) ----
|
||||
for i = 1:sum(idxPam)
|
||||
|
||||
% marker selection by publication
|
||||
pubIdx = find(pub_list == n(i), 1);
|
||||
marker = markerlist{mod(pubIdx-1, nMarkers) + 1};
|
||||
|
||||
if firstLegend
|
||||
h = scatter(x(i), y(i), ms, ...
|
||||
'Marker', marker, ...
|
||||
'MarkerEdgeColor', col, ...
|
||||
'MarkerFaceColor', col, ...
|
||||
'DisplayName', sprintf('PAM-%d', M));
|
||||
firstLegend = false;
|
||||
else
|
||||
h = scatter(x(i), y(i), ms, ...
|
||||
'Marker', marker, ...
|
||||
'MarkerEdgeColor', col, ...
|
||||
'MarkerFaceColor', col, ...
|
||||
'HandleVisibility','off');
|
||||
end
|
||||
|
||||
% ====== CUSTOM DATATIP CONTENT ======
|
||||
dt = h.DataTipTemplate;
|
||||
dt.DataTipRows(1).Label = 'Baud rate';
|
||||
dt.DataTipRows(2).Label = 'Net rate';
|
||||
|
||||
% Add publication name
|
||||
dt.DataTipRows(end+1) = dataTipTextRow('Publication', n(i));
|
||||
|
||||
|
||||
end
|
||||
|
||||
% ---- Fit (PAM-specific) ----
|
||||
valid = ~isnan(x) & ~isnan(y);
|
||||
if sum(valid) >= 3
|
||||
p = polyfit(x(valid), y(valid), 2);
|
||||
xfit = linspace(min(x(valid)), max(x(valid)), 200);
|
||||
yfit = polyval(p, xfit);
|
||||
|
||||
plot(xfit, yfit, ':', ...
|
||||
'LineWidth', lw, ...
|
||||
'Color', col, ...
|
||||
'HandleVisibility', 'off'); % do NOT add to legend
|
||||
end
|
||||
end
|
||||
|
||||
grid on;
|
||||
xlabel('Baud rate [GBd]');
|
||||
ylabel('Net rate [Gb/s]');
|
||||
|
||||
legend('Location','northwest');
|
||||
set(gca,'FontSize',11);
|
||||
|
||||
|
||||
%% === EXPORT ===
|
||||
outfile = 'C:\Users\Silas\Documents\latex\JLT_400G copy\media\matlab2tikz\highspeedresults.tikz';
|
||||
matlab2tikz(outfile, ...
|
||||
'width','\fwidth', ...
|
||||
'height','\fheight', ...
|
||||
'showInfo',false, ...
|
||||
'extraAxisOptions',{ ...
|
||||
'legend style={font=\footnotesize}', ...
|
||||
'legend columns=1' ...
|
||||
});
|
||||
Binary file not shown.
@@ -0,0 +1,334 @@
|
||||
function [M, cfg] = analyze_measurements_gpt(T, cfg)
|
||||
% ANALYZE_MEASUREMENTS_GPT
|
||||
% Filter, compute X/Y, group and aggregate measurements from table T.
|
||||
% No plotting here.
|
||||
%
|
||||
% Usage:
|
||||
% [M, cfg] = analyze_measurements_gpt(dataTable, cfg);
|
||||
%
|
||||
% Typical result (single group):
|
||||
% M.x -> aggregated x-values (e.g., grossrate)
|
||||
% M.y -> aggregated y-values (e.g., BER or NGMI)
|
||||
% M.y_precoded -> aggregated precoded BER (if available)
|
||||
%
|
||||
% For multiple groups:
|
||||
% M.group(g).x, M.group(g).y, M.group(g).label, ...
|
||||
|
||||
%% ---- Defaults (non-plot) ----
|
||||
if nargin < 2, cfg = struct; end
|
||||
defaults = struct( ...
|
||||
'x_axis' , 'symbolrate', ...
|
||||
'y_axis' , 'BER', ...
|
||||
'y_scale' , 'auto', ...
|
||||
'group_by' , {{'equalizer_structure','pre_emph'}}, ...
|
||||
'filters' , struct, ...
|
||||
'agg' , 'mean', ...
|
||||
'outlier' , 'auto', ...
|
||||
'mad_z' , 4, ...
|
||||
'pct_limits' , [2.5 97.5], ...
|
||||
'min_pts_x' , 3, ...
|
||||
'show_raw' , true, ...
|
||||
'show_precoded', [], ...
|
||||
'show_spread' , 'none', ...
|
||||
'fec_lines' , [], ...
|
||||
'plot' , struct() ... % plot settings handled in plot function
|
||||
);
|
||||
cfg = filldefaults(cfg, defaults);
|
||||
|
||||
%% ---- Derived/prep columns ----
|
||||
if ~ismember('pre_emph', T.Properties.VariableNames)
|
||||
if ~ismember('db_mode', T.Properties.VariableNames)
|
||||
error('Missing column "db_mode" for pre_emph derivation.');
|
||||
end
|
||||
T.pre_emph = T.db_mode == 0;
|
||||
end
|
||||
|
||||
if ~ismember(cfg.y_axis, T.Properties.VariableNames)
|
||||
error('y_axis "%s" not found in table.', cfg.y_axis);
|
||||
end
|
||||
|
||||
isBER = startsWith(cfg.y_axis, "BER", 'IgnoreCase', true);
|
||||
M.isBER = isBER;
|
||||
|
||||
if strcmpi(cfg.y_scale,'auto')
|
||||
cfg.y_scale = tern(isBER, 'log', 'linear');
|
||||
end
|
||||
if strcmpi(cfg.outlier,'auto')
|
||||
cfg.outlier = tern(isBER, 'mad', 'none');
|
||||
end
|
||||
if isempty(cfg.show_precoded)
|
||||
cfg.show_precoded = isBER && ismember('BER_precoded', T.Properties.VariableNames);
|
||||
end
|
||||
|
||||
%% ---- Filters & core X/Y extraction ----
|
||||
T = applyFilters(T, cfg.filters);
|
||||
|
||||
[x_raw, x_label] = computeX(T, cfg.x_axis);
|
||||
y_raw = T.(cfg.y_axis);
|
||||
|
||||
validXY = isfinite(x_raw) & isfinite(y_raw);
|
||||
T = T(validXY, :);
|
||||
x_raw = x_raw(validXY);
|
||||
y_raw = y_raw(validXY);
|
||||
|
||||
% Degiga if needed
|
||||
if mean(abs(y_raw)) > 1e8
|
||||
y_raw = y_raw .* 1e-9;
|
||||
end
|
||||
|
||||
if cfg.show_precoded && ismember('BER_precoded', T.Properties.VariableNames)
|
||||
y_raw_p = T.BER_precoded(validXY);
|
||||
else
|
||||
y_raw_p = [];
|
||||
end
|
||||
|
||||
%% ---- Grouping ----
|
||||
group_by = cfg.group_by;
|
||||
if ~all(ismember(group_by, T.Properties.VariableNames))
|
||||
error('Some group_by columns are missing in table.');
|
||||
end
|
||||
[G, grpTbl] = findgroups(T(:, group_by));
|
||||
nG = max(G);
|
||||
|
||||
%% ---- Aggregation per group ----
|
||||
M = struct;
|
||||
M.cfg = cfg;
|
||||
M.x_label = x_label;
|
||||
M.y_axis = cfg.y_axis;
|
||||
M.x_axis = cfg.x_axis;
|
||||
M.nGroups = nG;
|
||||
|
||||
% raw (filtered) data
|
||||
M.raw = struct;
|
||||
M.raw.x = x_raw;
|
||||
M.raw.y = y_raw;
|
||||
M.raw.y_precoded = y_raw_p;
|
||||
M.raw.T = T;
|
||||
|
||||
M.group = cell(nG,1);
|
||||
|
||||
useLog = strcmpi(cfg.y_scale,'log');
|
||||
for gi = 1:nG
|
||||
idx = (G == gi);
|
||||
Ti = T(idx,:);
|
||||
xi = x_raw(idx);
|
||||
yi = y_raw(idx);
|
||||
|
||||
[xu, ~, iu] = unique(xi);
|
||||
yu = nan(size(xu));
|
||||
ylo = nan(size(xu));
|
||||
yhi = nan(size(xu));
|
||||
|
||||
for k = 1:numel(xu)
|
||||
bin = (iu==k);
|
||||
yy = yi(bin);
|
||||
yy = yy(isfinite(yy));
|
||||
if isempty(yy), continue; end
|
||||
|
||||
km = outlierMask(yy, cfg, useLog);
|
||||
if nnz(km) < cfg.min_pts_x, km = true(size(yy)); end
|
||||
yy = yy(km);
|
||||
|
||||
switch lower(cfg.agg)
|
||||
case 'median'
|
||||
yu(k) = median(yy,'omitnan');
|
||||
case 'mean'
|
||||
yu(k) = mean(yy,'omitnan');
|
||||
case 'min'
|
||||
yu(k) = min(yy);
|
||||
case 'max'
|
||||
yu(k) = max(yy);
|
||||
otherwise
|
||||
error('Unknown agg mode "%s".', cfg.agg);
|
||||
end
|
||||
|
||||
if strcmpi(cfg.show_spread,'iqr')
|
||||
q = prctile(yy,[25 75]);
|
||||
ylo(k) = max(yu(k)-q(1), eps);
|
||||
yhi(k) = max(q(2)-yu(k), eps);
|
||||
elseif strcmpi(cfg.show_spread,'minmax')
|
||||
ylo(k) = min(yy);
|
||||
yhi(k) = max(yy);
|
||||
end
|
||||
end
|
||||
|
||||
% sort by x
|
||||
[xu, ord] = sort(xu);
|
||||
yu = yu(ord);
|
||||
ylo = ylo(ord);
|
||||
yhi = yhi(ord);
|
||||
|
||||
g = struct;
|
||||
g.label = buildLabel(grpTbl(gi,:), group_by);
|
||||
g.idx = find(G==gi);
|
||||
g.T = Ti;
|
||||
g.x_raw = xi;
|
||||
g.y_raw = yi;
|
||||
g.x = xu;
|
||||
g.y = yu;
|
||||
g.y_lo = ylo;
|
||||
g.y_hi = yhi;
|
||||
g.y_precoded = [];
|
||||
g.y_precoded_lo = [];
|
||||
g.y_precoded_hi = [];
|
||||
|
||||
% Precoded aggregation (if requested & available)
|
||||
if cfg.show_precoded && ~isempty(y_raw_p) && strcmpi(cfg.y_axis,'BER')
|
||||
ypi = y_raw_p(idx);
|
||||
ypu = nan(size(xu));
|
||||
|
||||
for k = 1:numel(xu)
|
||||
bin = (iu==k);
|
||||
yy = ypi(bin);
|
||||
yy = yy(isfinite(yy));
|
||||
if isempty(yy), continue; end
|
||||
|
||||
km = outlierMask(yy, cfg, true);
|
||||
if nnz(km) < cfg.min_pts_x, km = true(size(yy)); end
|
||||
yy = yy(km);
|
||||
|
||||
switch lower(cfg.agg)
|
||||
case 'median'
|
||||
ypu(k) = median(yy,'omitnan');
|
||||
case 'mean'
|
||||
ypu(k) = mean(yy,'omitnan');
|
||||
case 'min'
|
||||
ypu(k) = min(yy);
|
||||
case 'max'
|
||||
ypu(k) = max(yy);
|
||||
end
|
||||
end
|
||||
|
||||
g.y_precoded = ypu(ord);
|
||||
end
|
||||
|
||||
M.group{gi} = g;
|
||||
end
|
||||
|
||||
% Convenience flatten for single-group case
|
||||
if nG == 1
|
||||
g = M.group{1};
|
||||
M.x = g.x;
|
||||
M.y = g.y;
|
||||
M.y_precoded = g.y_precoded;
|
||||
end
|
||||
|
||||
end % ===== main =====
|
||||
|
||||
|
||||
%% ===================== Helpers =====================
|
||||
|
||||
function cfg = filldefaults(cfg, defs)
|
||||
fn = fieldnames(defs);
|
||||
for i = 1:numel(fn)
|
||||
f = fn{i};
|
||||
if ~isfield(cfg, f) || isempty(cfg.(f))
|
||||
cfg.(f) = defs.(f);
|
||||
elseif isstruct(defs.(f)) && isstruct(cfg.(f))
|
||||
cfg.(f) = filldefaults(cfg.(f), defs.(f)); % recursive
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function out = tern(cond, a, b)
|
||||
if cond
|
||||
out = a;
|
||||
else
|
||||
out = b;
|
||||
end
|
||||
end
|
||||
|
||||
function T2 = applyFilters(T, filters)
|
||||
if isempty(filters), T2 = T; return; end
|
||||
keep = true(height(T),1);
|
||||
fns = fieldnames(filters);
|
||||
for i = 1:numel(fns)
|
||||
name = fns{i};
|
||||
if ~ismember(name, T.Properties.VariableNames)
|
||||
warning('Filter column "%s" not found. Ignored.', name);
|
||||
continue
|
||||
end
|
||||
val = filters.(name);
|
||||
col = T.(name);
|
||||
if isa(val,'function_handle')
|
||||
m = val(col);
|
||||
if ~islogical(m) || ~isequal(size(m), size(col))
|
||||
error('Filter for %s must return logical mask of same size.', name);
|
||||
end
|
||||
keep = keep & m;
|
||||
else
|
||||
keep = keep & ismember(col, val);
|
||||
end
|
||||
end
|
||||
T2 = T(keep,:);
|
||||
end
|
||||
|
||||
function [x, label] = computeX(T, whichX)
|
||||
switch lower(whichX)
|
||||
case {'symbolrate','baudrate'}
|
||||
x = T.symbolrate * 1e-9;
|
||||
label = 'Symbol rate [GBd]';
|
||||
case 'bitrate'
|
||||
if ~ismember('pam_level', T.Properties.VariableNames)
|
||||
error('bitrate requires "pam_level" column.');
|
||||
end
|
||||
bits = floor(log2(double(T.pam_level))*10)/10;
|
||||
x = (T.symbolrate .* bits) * 1e-9;
|
||||
label = 'Grossrate [Gb/s]';
|
||||
case 'grossrate'
|
||||
x = T.grossrate * 1e-9;
|
||||
label = 'Grossrate [Gb/s]';
|
||||
otherwise
|
||||
if ~ismember(whichX, T.Properties.VariableNames)
|
||||
error('x_axis "%s" not found in table.', whichX);
|
||||
end
|
||||
x = T.(whichX);
|
||||
label = whichX;
|
||||
end
|
||||
x = double(x(:));
|
||||
end
|
||||
|
||||
function keep = outlierMask(y, cfg, useLog)
|
||||
if isempty(y), keep = false(size(y)); return; end
|
||||
y = y(:);
|
||||
switch lower(cfg.outlier)
|
||||
case 'none'
|
||||
keep = true(size(y)); return
|
||||
case 'mad'
|
||||
z = tern(useLog, log10(y), y);
|
||||
med = median(z,'omitnan');
|
||||
madv = median(abs(z-med),'omitnan');
|
||||
if ~(isfinite(madv) && madv>0)
|
||||
keep = true(size(y)); return
|
||||
end
|
||||
sigma = 1.4826*madv;
|
||||
zz = tern(useLog, log10(y), y);
|
||||
keep = abs(zz - med) <= cfg.mad_z*sigma;
|
||||
case 'pctl'
|
||||
pr = prctile(y, cfg.pct_limits);
|
||||
keep = (y >= pr(1)) & (y <= pr(2));
|
||||
otherwise
|
||||
error('Unknown outlier mode "%s".', cfg.outlier);
|
||||
end
|
||||
end
|
||||
|
||||
function s = buildLabel(grpRow, group_by)
|
||||
parts = strings(1, numel(group_by));
|
||||
for i = 1:numel(group_by)
|
||||
key = group_by{i};
|
||||
val = grpRow.(key);
|
||||
if iscell(val), val = val{1}; end
|
||||
if islogical(val), val = tern(val,'w/','w/o'); end
|
||||
if key == "equalizer_structure"
|
||||
key = '';
|
||||
val = upper(val);
|
||||
val = strrep(val,'_',' ');
|
||||
end
|
||||
if key == "pre_emph"
|
||||
val = [val, ' pre-emph.'];
|
||||
key = '';
|
||||
end
|
||||
parts(i) = sprintf('%s %s', key, string(val));
|
||||
end
|
||||
s = strjoin(parts, ', ');
|
||||
end
|
||||
@@ -0,0 +1,240 @@
|
||||
|
||||
|
||||
database_type = 'mysql';
|
||||
dataBase = 'labor_highspeed';
|
||||
db = DBHandler("dataBase", [dataBase], "type", database_type);
|
||||
|
||||
|
||||
% M = 4;
|
||||
fp = QueryFilter();
|
||||
% fp.where('Runs', 'pam_level','EQUALS', M);
|
||||
fp.where('Runs', 'fiber_length','EQUALS', 2);
|
||||
fp.where('Runs', 'wavelength','LESS_THAN', 1312);
|
||||
% 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_alltime')]; %dashboard_ungrouped_after_nov_2025 dashboard_ungrouped_aug_nov_2025
|
||||
[dataTable,~] = db.queryDB(fp, fields);
|
||||
|
||||
%%
|
||||
cfg = struct;
|
||||
cfg.x_axis = 'grossrate'; % 'symbol rate' | 'bitrate' | 'wavelength' grossrate
|
||||
cfg.y_axis = 'BER'; % 'BER' | 'GMI' | 'AIR' | ...
|
||||
|
||||
cfg.y_scale = 'auto'; % auto -> log for BER*, linear otherwise
|
||||
cfg.outlier = 'mad'; % simple, robust; 'none' or 'pctl' also available
|
||||
cfg.show_raw = false;
|
||||
cfg.show_spread = 'none'; % 'none' or 'iqr' or minmax
|
||||
cfg.agg = 'min'; % or 'median'
|
||||
cfg.show_precoded = 0;
|
||||
|
||||
% cfg.fec_lines = [2.2e-4 4.85e-3 2e-2]; % optional
|
||||
cfg.fec_lines = [];
|
||||
cfg.plot.custom_colors = [
|
||||
clr.Paired.red;
|
||||
clr.Paired.blue;
|
||||
clr.Paired.green;
|
||||
clr.Paired.orange;
|
||||
clr.Paired.purple
|
||||
];
|
||||
|
||||
cfg.plot.custom_colors_scatter = [
|
||||
clr.Paired.lightred;
|
||||
clr.Paired.lightblue;
|
||||
clr.Paired.lightgreen;
|
||||
clr.Paired.lightorange;
|
||||
clr.Paired.lightpurple
|
||||
];
|
||||
|
||||
|
||||
% New styling knobs
|
||||
cfg.plot.use_cbrewer2 = true;
|
||||
cfg.plot.colormap = 'Paired';
|
||||
cfg.plot.paired_dark_first = false; % dark for lines, light for scatter
|
||||
cfg.plot.lineWidth = 2.0;
|
||||
cfg.plot.errWidth = 1.2;
|
||||
cfg.plot.scatterAlpha = 0.35;
|
||||
cfg.plot.legendLocation = 'best';
|
||||
cfg.plot.fecLineWidth = 2.4; % thicker FEC limits
|
||||
cfg.plot.lineStyle_pre_emph_on = '-';
|
||||
cfg.plot.lineStyle_pre_emph_off = '-';
|
||||
|
||||
%% PLOT NGMI
|
||||
|
||||
% Common cfg
|
||||
cfg.show_precoded = 1;
|
||||
cfg.group_by = {'equalizer_structure','pre_emph'};
|
||||
cfg.x_axis = 'grossrate';
|
||||
cfg.y_axis = 'NGMI'; % 'BER' | 'GMI' | 'AIR' | ...
|
||||
cfg.y_scale = 'lin';
|
||||
cfg.plot.custom_colors_scatter = [];
|
||||
cfg.plot.use_cbrewer2 = false;
|
||||
cfg.fec_lines = [];
|
||||
cfg.agg = 'max';
|
||||
|
||||
cfg.figure_number = 45;
|
||||
% fig = figure(cfg.figure_number);
|
||||
|
||||
lambda = 1310;
|
||||
% PAM 4
|
||||
cfg.plot.custom_colors = clr.Paired.red;
|
||||
cfg.plot.custom_linetypes = {'-'};
|
||||
cfg.filters = struct('is_mpi',0,'pam_level',4, ...
|
||||
'equalizer_structure',equalizer_structure.vnle_db_mlse, ...
|
||||
'pre_emph',0,'wavelength',lambda);
|
||||
cfg.show_precoded = 1;
|
||||
a = plot_measurements_gpt(dataTable, cfg);
|
||||
ngmi_pam4 = a.lines(1).YData;
|
||||
grossrates = a.lines(1).XData;
|
||||
tp = TransmissionPerformance;
|
||||
netrates_vnle = tp.calculateNetRate(grossrates, ...
|
||||
'NGMI', ngmi_pam4, ...
|
||||
'BER', BER_VNLE);
|
||||
|
||||
cfg.plot.custom_colors = clr.Paired.red;
|
||||
cfg.plot.custom_linetypes = {'--'};
|
||||
cfg.filters = struct('is_mpi',0,'pam_level',4, ...
|
||||
'equalizer_structure',equalizer_structure.vnle_db_mlse, ...
|
||||
'pre_emph',0,'wavelength',1293);
|
||||
cfg.show_precoded = 1;
|
||||
plot_measurements_gpt(dataTable, cfg);
|
||||
|
||||
% PAM 6
|
||||
cfg.plot.custom_colors = clr.Paired.blue;
|
||||
cfg.plot.custom_linetypes = {'-'};
|
||||
cfg.filters = struct('is_mpi',0,'pam_level',6, ...
|
||||
'equalizer_structure',equalizer_structure.vnle_pf_mlse, ...
|
||||
'pre_emph',1,'wavelength',lambda);
|
||||
cfg.show_precoded = 0;
|
||||
plot_measurements_gpt(dataTable, cfg);
|
||||
|
||||
cfg.plot.custom_colors = clr.Paired.blue;
|
||||
cfg.plot.custom_linetypes = {'--'};
|
||||
cfg.filters = struct('is_mpi',0,'pam_level',6, ...
|
||||
'equalizer_structure',equalizer_structure.vnle_pf_mlse, ...
|
||||
'pre_emph',1,'wavelength',1293);
|
||||
cfg.show_precoded = 0;
|
||||
plot_measurements_gpt(dataTable, cfg);
|
||||
|
||||
% PAM 8
|
||||
cfg.plot.custom_colors = clr.Paired.green;
|
||||
cfg.plot.custom_linetypes = {'-'};
|
||||
cfg.filters = struct('is_mpi',0,'pam_level',8, ...
|
||||
'equalizer_structure',equalizer_structure.vnle_pf_mlse, ...
|
||||
'pre_emph',1,'wavelength',lambda);
|
||||
cfg.show_precoded = 0;
|
||||
plot_measurements_gpt(dataTable, cfg);
|
||||
|
||||
cfg.plot.custom_colors = clr.Paired.green;
|
||||
cfg.plot.custom_linetypes = {'--'};
|
||||
cfg.filters = struct('is_mpi',0,'pam_level',8, ...
|
||||
'equalizer_structure',equalizer_structure.vnle_pf_mlse, ...
|
||||
'pre_emph',1,'wavelength',1293);
|
||||
cfg.show_precoded = 0;
|
||||
plot_measurements_gpt(dataTable, cfg);
|
||||
|
||||
beautifyBERplot
|
||||
ylim([0.87,1.01]);
|
||||
% xlim([290,480]);
|
||||
|
||||
%% PLOT AIR
|
||||
|
||||
% Common cfg
|
||||
cfg.show_precoded = 1;
|
||||
cfg.group_by = {'equalizer_structure','pre_emph'};
|
||||
cfg.x_axis = 'grossrate';
|
||||
cfg.y_axis = 'AIR'; % 'BER' | 'GMI' | 'AIR' | ...
|
||||
cfg.y_scale = 'lin';
|
||||
cfg.plot.custom_colors_scatter = [];
|
||||
cfg.plot.use_cbrewer2 = false;
|
||||
cfg.fec_lines = [];
|
||||
cfg.agg = 'max';
|
||||
|
||||
cfg.figure_number = 47;
|
||||
|
||||
lambda = 1310;
|
||||
|
||||
% cfg = struct;
|
||||
cfg.filters = struct('is_mpi',0,'pam_level',4, ...
|
||||
'equalizer_structure',equalizer_structure.vnle_db_mlse, ...
|
||||
'pre_emph',0,'wavelength',lambda);
|
||||
cfg.x_axis = 'grossrate';
|
||||
cfg.y_axis = 'NGMI'; % or 'NGMI', etc.
|
||||
cfg.show_precoded = 1;
|
||||
|
||||
[M, cfg] = analyze_measurements_gpt(dataTable, cfg);
|
||||
|
||||
grossrates = M.x; % aggregated X
|
||||
ber = M.y; % aggregated Y (BER or NGMI)
|
||||
ber_prec = M.y_precoded; % precoded BER (if available)
|
||||
|
||||
[h, M] = plot_measurements_gpt(dataTable, cfg);
|
||||
|
||||
|
||||
% PAM 4
|
||||
cfg.plot.custom_colors = clr.Paired.red;
|
||||
cfg.plot.custom_linetypes = {'-'};
|
||||
cfg.filters = struct('is_mpi',0,'pam_level',4, ...
|
||||
'equalizer_structure',equalizer_structure.vnle_db_mlse, ...
|
||||
'pre_emph',0,'wavelength',lambda);
|
||||
cfg.show_precoded = 1;
|
||||
plot_measurements_gpt(dataTable, cfg);
|
||||
|
||||
|
||||
|
||||
cfg.plot.custom_colors = clr.Paired.red;
|
||||
cfg.plot.custom_linetypes = {'--'};
|
||||
cfg.filters = struct('is_mpi',0,'pam_level',4, ...
|
||||
'equalizer_structure',equalizer_structure.vnle_db_mlse, ...
|
||||
'pre_emph',0,'wavelength',1293);
|
||||
cfg.show_precoded = 1;
|
||||
plot_measurements_gpt(dataTable, cfg);
|
||||
|
||||
% PAM 6
|
||||
cfg.plot.custom_colors = clr.Paired.blue;
|
||||
cfg.plot.custom_linetypes = {'-'};
|
||||
cfg.filters = struct('is_mpi',0,'pam_level',6, ...
|
||||
'equalizer_structure',equalizer_structure.vnle_pf_mlse, ...
|
||||
'pre_emph',1,'wavelength',lambda);
|
||||
cfg.show_precoded = 0;
|
||||
plot_measurements_gpt(dataTable, cfg);
|
||||
|
||||
cfg.plot.custom_colors = clr.Paired.blue;
|
||||
cfg.plot.custom_linetypes = {'--'};
|
||||
cfg.filters = struct('is_mpi',0,'pam_level',6, ...
|
||||
'equalizer_structure',equalizer_structure.vnle_pf_mlse, ...
|
||||
'pre_emph',1,'wavelength',1293);
|
||||
cfg.show_precoded = 0;
|
||||
plot_measurements_gpt(dataTable, cfg);
|
||||
|
||||
% PAM 8
|
||||
cfg.plot.custom_colors = clr.Paired.green;
|
||||
cfg.plot.custom_linetypes = {'-'};
|
||||
cfg.filters = struct('is_mpi',0,'pam_level',8, ...
|
||||
'equalizer_structure',equalizer_structure.vnle_pf_mlse, ...
|
||||
'pre_emph',1,'wavelength',lambda);
|
||||
cfg.show_precoded = 0;
|
||||
plot_measurements_gpt(dataTable, cfg);
|
||||
|
||||
cfg.plot.custom_colors = clr.Paired.green;
|
||||
cfg.plot.custom_linetypes = {'--'};
|
||||
cfg.filters = struct('is_mpi',0,'pam_level',8, ...
|
||||
'equalizer_structure',equalizer_structure.vnle_pf_mlse, ...
|
||||
'pre_emph',1,'wavelength',1293);
|
||||
cfg.show_precoded = 0;
|
||||
plot_measurements_gpt(dataTable, cfg);
|
||||
|
||||
ax = gca;
|
||||
|
||||
beautifyBERplot
|
||||
|
||||
ylim([275,435]);
|
||||
xlim([290,480]);
|
||||
|
||||
|
||||
%%
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,112 @@
|
||||
database_type = 'mysql';
|
||||
dataBase = 'labor_highspeed';
|
||||
db = DBHandler("dataBase", [dataBase], "type", database_type);
|
||||
|
||||
|
||||
M = 4;
|
||||
fp = QueryFilter();
|
||||
fp.where('Runs', 'pam_level','EQUALS', M);
|
||||
fp.where('Runs', 'fiber_length','EQUALS', 2);
|
||||
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_aug_nov_2025')]; %dashboard_ungrouped_after_nov_2025 dashboard_ungrouped_aug_nov_2025
|
||||
[dataTable,~] = db.queryDB(fp, fields);
|
||||
|
||||
%%
|
||||
cfg = struct;
|
||||
cfg.x_axis = 'grossrate'; % 'symbol rate' | 'bitrate' | 'wavelength' grossrate
|
||||
cfg.y_axis = 'BER'; % 'BER' | 'GMI' | 'AIR' | ...
|
||||
|
||||
cfg.y_scale = 'auto'; % auto -> log for BER*, linear otherwise
|
||||
cfg.outlier = 'mad'; % simple, robust; 'none' or 'pctl' also available
|
||||
cfg.show_raw = false;
|
||||
cfg.show_spread = 'none'; % 'none' or 'iqr' or minmax
|
||||
cfg.agg = 'min'; % or 'median'
|
||||
cfg.show_precoded = 0;
|
||||
% cfg.fec_lines = [2.2e-4 4.85e-3 2e-2]; % optional
|
||||
cfg.fec_lines = [];
|
||||
cfg.plot.custom_colors = [
|
||||
clr.Paired.red;
|
||||
clr.Paired.blue;
|
||||
clr.Paired.green;
|
||||
clr.Paired.orange;
|
||||
clr.Paired.purple
|
||||
];
|
||||
|
||||
cfg.plot.custom_colors_scatter = [
|
||||
clr.Paired.lightred;
|
||||
clr.Paired.lightblue;
|
||||
clr.Paired.lightgreen;
|
||||
clr.Paired.lightorange;
|
||||
clr.Paired.lightpurple
|
||||
];
|
||||
|
||||
|
||||
% New styling knobs
|
||||
cfg.plot.use_cbrewer2 = true;
|
||||
cfg.plot.colormap = 'Paired';
|
||||
cfg.plot.paired_dark_first = false; % dark for lines, light for scatter
|
||||
cfg.plot.lineWidth = 2.0;
|
||||
cfg.plot.errWidth = 1.2;
|
||||
cfg.plot.scatterAlpha = 0.35;
|
||||
cfg.plot.legendLocation = 'best';
|
||||
cfg.plot.fecLineWidth = 2.4; % thicker FEC limits
|
||||
cfg.plot.lineStyle_pre_emph_on = '-';
|
||||
cfg.plot.lineStyle_pre_emph_off = '-';
|
||||
|
||||
%%
|
||||
cfg.figure_number = 42;
|
||||
|
||||
|
||||
% ---- VNLE, no pre-emph (solid red) ----
|
||||
cfg.plot.custom_colors = [clr.Paired.red];
|
||||
cfg.plot.custom_linetypes = {'-'};
|
||||
cfg.filters = struct('is_mpi',0,'pam_level',M, ...
|
||||
'equalizer_structure',equalizer_structure.vnle, ...
|
||||
'pre_emph',0);
|
||||
plot_measurements_gpt(dataTable, cfg);
|
||||
|
||||
% ---- VNLE, with pre-emph (dashed red) ----
|
||||
cfg.plot.custom_colors = [clr.Paired.red];
|
||||
cfg.plot.custom_linetypes = {'--'};
|
||||
cfg.filters.pre_emph = 1;
|
||||
plot_measurements_gpt(dataTable, cfg);
|
||||
|
||||
% ---- VNLE PF MLSE, no pre-emph (solid green) ----
|
||||
cfg.plot.custom_colors = [clr.Paired.green];
|
||||
cfg.plot.custom_linetypes = {'-'};
|
||||
cfg.filters.equalizer_structure = equalizer_structure.vnle_pf_mlse;
|
||||
cfg.filters.pre_emph = 0;
|
||||
plot_measurements_gpt(dataTable, cfg);
|
||||
|
||||
% ---- VNLE PF MLSE, with pre-emph (dashed green) ----
|
||||
cfg.plot.custom_colors = [clr.Paired.green];
|
||||
cfg.plot.custom_linetypes = {'--'};
|
||||
cfg.filters.pre_emph = 1;
|
||||
plot_measurements_gpt(dataTable, cfg);
|
||||
|
||||
|
||||
% === FEC LINES (no legend) ===
|
||||
yline([2.2e-4 4.85e-3 2e-2], ...
|
||||
'LineWidth',1.5,'Color',[0.4 0.4 0.4], ...
|
||||
'LineStyle',':','HandleVisibility','off');
|
||||
|
||||
|
||||
% === BEAUTIFY ===
|
||||
% beautifyBERplot; % your function
|
||||
|
||||
|
||||
%% === EXPORT TO TIKZ ===
|
||||
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,92 @@
|
||||
% ============================================================
|
||||
% MINIMAL EXAMPLE: Query → Analyze → Plot → Extract X/Y data
|
||||
% ============================================================
|
||||
|
||||
%% === Load from database ===
|
||||
db = DBHandler("dataBase","labor_highspeed","type","mysql");
|
||||
|
||||
fp = QueryFilter();
|
||||
fp.where('Runs','fiber_length','EQUALS',2);
|
||||
% fp.where('Runs','pam_level','EQUALS',6); % PAM-4
|
||||
% fp.where('Runs','db_mode','EQUALS',0); % w/o pre-emph
|
||||
|
||||
fields = db.getTableFieldNames('dashboard_ungrouped_alltime');
|
||||
[dataTable,~] = db.queryDB(fp, fields);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
%% === Define config ===
|
||||
|
||||
for m = [4,6,8]
|
||||
|
||||
cfg = struct;
|
||||
cfg.x_axis = 'symbolrate';
|
||||
cfg.y_axis = 'Alpha';
|
||||
cfg.group_by = {'equalizer_structure','pre_emph'};
|
||||
cfg.filters = struct('is_mpi',0,'pam_level',m, ...
|
||||
'equalizer_structure',equalizer_structure.vnle_pf_mlse, ...
|
||||
'pre_emph',0);
|
||||
cfg.agg = 'max';
|
||||
cfg.outlier = 'mad';
|
||||
cfg.show_raw = false;
|
||||
cfg.show_precoded = 0;
|
||||
|
||||
% Plot cosmetics (minimal)
|
||||
cfg.plot = struct;
|
||||
cfg.plot.custom_colors = linspecer(8);
|
||||
cfg.plot.custom_linetypes = {'-'};
|
||||
cfg.plot.lineWidth = 2;
|
||||
|
||||
|
||||
% ============================================================
|
||||
% === ANALYSIS ONLY (no plotting) =============================
|
||||
% ============================================================
|
||||
A = analyze_measurements_gpt(dataTable, cfg);
|
||||
|
||||
% Now you have:
|
||||
% A.raw.x = raw x-values
|
||||
% A.raw.y = raw BER values
|
||||
% A.group{1}.x = unique sorted x-values
|
||||
% A.group{1}.y = aggregated BER for each x
|
||||
|
||||
x_values = A.group{1}.x;
|
||||
y_values = A.group{1}.y;
|
||||
|
||||
|
||||
% ============================================================
|
||||
% === PLOT ====================================================
|
||||
% ============================================================
|
||||
|
||||
figure(10);hold on
|
||||
cfg.ax = gca; % optional: plot into existing axes
|
||||
plot(x_values,y_values,...
|
||||
'LineWidth', 2, ...
|
||||
'Color', clr.Set1.red, ...
|
||||
'MarkerSize', 5, ...
|
||||
'MarkerFaceColor', clr.Set1.red,...
|
||||
'Marker','o');
|
||||
% [h, ~] = plot_measurements_gpt(dataTable, cfg);
|
||||
|
||||
title('Minimal VNLE BER Example')
|
||||
xlabel('Grossrate [Gb/s]')
|
||||
ylabel('BER')
|
||||
xticks(100:30:220)
|
||||
xlim([100,220]);
|
||||
ylim([0,1]);
|
||||
|
||||
end
|
||||
% outfile = 'C:\Users\Silas\Documents\latex\JLT_400G copy\media\matlab2tikz\alphas.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,111 @@
|
||||
dsp_options.storage_path = 'Z:\2024\sioe_labor\';
|
||||
dsp_options.max_occurences = 1;
|
||||
database = DBHandler("dataBase", 'labor_highspeed', "type", 'mysql' );
|
||||
|
||||
rate = 390e9;
|
||||
|
||||
%% 1 - PAM 4 with preemphasis
|
||||
fp = QueryFilter();
|
||||
M = 4;
|
||||
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', 0);
|
||||
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);
|
||||
|
||||
% 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);
|
||||
|
||||
if rate == 390e9
|
||||
Scpe_sig.spectrum("fignum",200,"normalizeTo0dB",1,"displayname",'Rx','addDCoffset',-5.8);
|
||||
elseif rate == 300e9
|
||||
Scpe_sig.spectrum("fignum",200,"normalizeTo0dB",1,"displayname",'Rx','addDCoffset',-4.7);
|
||||
end
|
||||
ylim([-30,3]);
|
||||
xlim([-5,100]);
|
||||
Scpe_sig.spectrum("fignum",201,"normalizeTo0dB",0,"displayname",'Rx');
|
||||
|
||||
|
||||
%% 1 - PAM 4 without preemphasis
|
||||
fp = QueryFilter();
|
||||
M = 4;
|
||||
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', 1);
|
||||
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);
|
||||
|
||||
% 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.spectrum("fignum",200,"normalizeTo0dB",1,"displayname",'Rx','addDCoffset',0);
|
||||
ylim([-30,3]);
|
||||
xlim([-5,100]);
|
||||
Scpe_sig.spectrum("fignum",201,"normalizeTo0dB",0,"displayname",'Rx');
|
||||
|
||||
|
||||
|
||||
if 1
|
||||
%% show freuqncy response of filter
|
||||
|
||||
measure = 1;
|
||||
|
||||
freqresp = ChannelFreqResp("Nacq",1024,"Navg",64,"Ncp",70,"f_ref",256e9);
|
||||
%
|
||||
Digi_sig = freqresp.buildOFDM();
|
||||
|
||||
% Digi_sig.spectrum("fignum",1112,"displayname",['maxamp:',num2str(maxamp)]);
|
||||
|
||||
Digi_sig = Filter('filtdegree',3,"f_cutoff",70e9,"fs",256e9,"filterType",filtertypes.butterworth,"active",true).process(Digi_sig);
|
||||
|
||||
Digi_sig = Filter('filtdegree',3,"f_cutoff",70e9,"fs",256e9,"filterType",filtertypes.bessel_inp,"active",true).process(Digi_sig);
|
||||
|
||||
freqresp.estimate(Digi_sig,"fileName",'','save',false);
|
||||
|
||||
freqresp.plot()
|
||||
|
||||
a = gca;
|
||||
a.YTick = [-30,-20,-10,0];
|
||||
|
||||
%% system frex
|
||||
|
||||
|
||||
precomp_filename ='lab_high_speed';
|
||||
precomp_path = "C:\Users\Silas\Documents\MATLAB\Datensätze\sioe_labor\precomp";
|
||||
freqresp = ChannelFreqResp("Nacq",1024,"Navg",64,"Ncp",63,'f_ref',92e9);
|
||||
freqresp.load('loadPath', precomp_path, 'fileName', precomp_filename);
|
||||
|
||||
fprintf('Plotting: %s\n', precomp_filename);
|
||||
freqresp.plot();
|
||||
|
||||
outfile = 'C:\Users\Silas\Documents\latex\JLT_400G copy\media\matlab2tikz\spectrum_2.tikz';
|
||||
matlab2tikz(outfile, ...
|
||||
'width','\fwidth', ...
|
||||
'height','\fheight', ...
|
||||
'showInfo',false, ...
|
||||
'extraAxisOptions',{ ...
|
||||
'legend style={font=\footnotesize}', ...
|
||||
'legend columns=1' ...
|
||||
});
|
||||
|
||||
end
|
||||
@@ -0,0 +1,222 @@
|
||||
function [h, M, cfg] = plot_measurements_gpt(T, cfg)
|
||||
% PLOT_MEASUREMENTS_GPT
|
||||
% Plot measurements, using analyze_measurements_gpt for data handling.
|
||||
%
|
||||
% Usage:
|
||||
% h = plot_measurements_gpt(dataTable, cfg);
|
||||
% [h, M] = plot_measurements_gpt(dataTable, cfg);
|
||||
%
|
||||
% For values only, without plotting, call:
|
||||
% [M, cfg] = analyze_measurements_gpt(dataTable, cfg);
|
||||
|
||||
if nargin < 2, cfg = struct; end
|
||||
|
||||
% --- First: run analysis (filtering, grouping, aggregation) ---
|
||||
[M, cfg] = analyze_measurements_gpt(T, cfg);
|
||||
|
||||
nG = M.nGroups;
|
||||
|
||||
%% ---- Plot defaults ----
|
||||
plotdefs = struct( ...
|
||||
'use_cbrewer2' , true, ...
|
||||
'colormap' , 'Paired', ...
|
||||
'paired_dark_first' , true, ...
|
||||
'lineWidth' , 1.8, ...
|
||||
'errWidth' , 1.0, ...
|
||||
'scatterSize' , 14, ...
|
||||
'scatterAlpha' , 0.35, ...
|
||||
'marker' , 'o', ...
|
||||
'marker_precoded' , 's', ...
|
||||
'legendLocation' , 'best', ...
|
||||
'fecLineWidth' , 2.2, ...
|
||||
'fecColor' , [0.25 0.25 0.25], ...
|
||||
'capSize' , 6, ...
|
||||
'lineStyle_default' , '-', ...
|
||||
'custom_colors' , [], ...
|
||||
'custom_colors_scatter' , [] ...
|
||||
);
|
||||
if ~isfield(cfg,'plot') || isempty(cfg.plot)
|
||||
cfg.plot = struct;
|
||||
end
|
||||
cfg.plot = filldefaults(cfg.plot, plotdefs);
|
||||
|
||||
%% ---- Colors ----
|
||||
[cols_line, cols_scatter] = buildGroupColors(nG, cfg.plot);
|
||||
|
||||
%% ---- Axes / Figure handling ----
|
||||
if isfield(cfg,'ax') && ~isempty(cfg.ax) && isgraphics(cfg.ax,'axes')
|
||||
ax = cfg.ax;
|
||||
set(gcf,'CurrentAxes',ax);
|
||||
else
|
||||
if isfield(cfg,'figure_number') && ~isempty(cfg.figure_number)
|
||||
figure(cfg.figure_number);
|
||||
else
|
||||
figure;
|
||||
end
|
||||
ax = gca;
|
||||
end
|
||||
hold(ax,'on');
|
||||
grid(ax,'on');
|
||||
|
||||
h.lines = gobjects(nG,1);
|
||||
h.err = gobjects(nG,1);
|
||||
h.scat = gobjects(nG,1);
|
||||
h.lines_p = gobjects(nG,1);
|
||||
|
||||
%% ---- Plot each group ----
|
||||
for gi = 1:nG
|
||||
g = M.group{gi};
|
||||
xu = g.x;
|
||||
yu = g.y;
|
||||
ylo = g.y_lo;
|
||||
yhi = g.y_hi;
|
||||
|
||||
% --- Linestyle selection ---
|
||||
ls = cfg.plot.lineStyle_default;
|
||||
if isfield(cfg.plot,'custom_linetypes') && ~isempty(cfg.plot.custom_linetypes)
|
||||
L = cfg.plot.custom_linetypes;
|
||||
ls = L{ mod(gi-1, numel(L)) + 1 };
|
||||
end
|
||||
|
||||
colL = cols_line(gi,:);
|
||||
lbl = g.label;
|
||||
|
||||
% Main line
|
||||
h.lines(gi) = plot(ax, xu, yu, ...
|
||||
'LineWidth', cfg.plot.lineWidth, ...
|
||||
'Marker', cfg.plot.marker, 'MarkerSize', 3, ...
|
||||
'Color', colL, 'LineStyle', ls, ...
|
||||
'DisplayName', char(lbl));
|
||||
|
||||
% Spread
|
||||
if any(isfinite(ylo)) && any(isfinite(yhi))
|
||||
h.err(gi) = errorbar(ax, xu, yu, ylo, yhi, 'LineStyle','none', ...
|
||||
'Color', colL, 'CapSize', cfg.plot.capSize, 'HandleVisibility','off');
|
||||
h.err(gi).LineWidth = cfg.plot.errWidth;
|
||||
end
|
||||
|
||||
% Raw scatter
|
||||
if cfg.show_raw
|
||||
% reuse stored raw data (no extra filtering)
|
||||
xi = g.x_raw;
|
||||
yi = g.y_raw;
|
||||
colS = cols_scatter(gi,:);
|
||||
scatter(ax, xi, yi, cfg.plot.scatterSize, colS, 'filled', ...
|
||||
'MarkerFaceAlpha', cfg.plot.scatterAlpha, ...
|
||||
'MarkerEdgeAlpha', cfg.plot.scatterAlpha, ...
|
||||
'HandleVisibility','off');
|
||||
end
|
||||
|
||||
% Precoded overlay
|
||||
if cfg.show_precoded && ~isempty(g.y_precoded) && strcmpi(M.y_axis,'BER')
|
||||
ypu = g.y_precoded;
|
||||
h.lines_p(gi) = plot(ax, xu, ypu, ...
|
||||
'LineWidth', max(1.2, cfg.plot.lineWidth-0.2), ...
|
||||
'Marker', cfg.plot.marker_precoded, 'MarkerSize', 3, ...
|
||||
'Color', colL, 'LineStyle', ':', ...
|
||||
'DisplayName', [char(lbl) ' (precoded)']);
|
||||
end
|
||||
end
|
||||
|
||||
%% ---- Axes / Labels / FEC ----
|
||||
ylabel(ax, M.y_axis, 'Interpreter','none');
|
||||
xlabel(ax, M.x_label, 'Interpreter','none');
|
||||
set(ax, 'YScale', cfg.y_scale, 'FontSize', 11);
|
||||
|
||||
% X ticks/limits using all group x-values
|
||||
allX = cellfun(@(g) g.x(:), M.group, 'UniformOutput', false);
|
||||
allX = unique(vertcat(allX{:}));
|
||||
if ~isempty(allX)
|
||||
xticks(ax, allX);
|
||||
xticklabels(cellstr(num2str(round(allX,1), '%.4f')))
|
||||
xlim(ax, [min(allX), max(allX)]);
|
||||
end
|
||||
|
||||
if startsWith(M.y_axis,"BER",'IgnoreCase',true)
|
||||
for v = cfg.fec_lines
|
||||
yline(ax, v, '--', 'Color', cfg.plot.fecColor, ...
|
||||
'LineWidth', cfg.plot.fecLineWidth, 'HandleVisibility','off');
|
||||
end
|
||||
ylim(ax, [1e-5, 0.5]);
|
||||
yticks(ax, [1e-5, 1e-4, 1e-3, 1e-2, 1e-1]);
|
||||
end
|
||||
|
||||
% legend(ax, 'Location', cfg.plot.legendLocation); % if you want legends
|
||||
|
||||
box(ax,'on');
|
||||
|
||||
end % ===== main =====
|
||||
|
||||
|
||||
%% ===================== Helpers =====================
|
||||
|
||||
function cfg = filldefaults(cfg, defs)
|
||||
fn = fieldnames(defs);
|
||||
for i = 1:numel(fn)
|
||||
f = fn{i};
|
||||
if ~isfield(cfg, f) || isempty(cfg.(f))
|
||||
cfg.(f) = defs.(f);
|
||||
elseif isstruct(defs.(f)) && isstruct(cfg.(f))
|
||||
cfg.(f) = filldefaults(cfg.(f), defs.(f));
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function [cols_line, cols_scatter] = buildGroupColors(nG, plotcfg)
|
||||
|
||||
% 1) User-provided custom colors
|
||||
if isfield(plotcfg,'custom_colors') && ~isempty(plotcfg.custom_colors)
|
||||
C = plotcfg.custom_colors;
|
||||
if size(C,1) < nG
|
||||
error('custom_colors must have at least nG=%d rows.', nG);
|
||||
end
|
||||
cols_line = C(1:nG, :);
|
||||
|
||||
if isfield(plotcfg,'custom_colors_scatter') && ~isempty(plotcfg.custom_colors_scatter)
|
||||
Cs = plotcfg.custom_colors_scatter;
|
||||
if size(Cs,1) < nG
|
||||
error('custom_colors_scatter must have at least nG=%d rows.', nG);
|
||||
end
|
||||
cols_scatter = Cs(1:nG, :);
|
||||
else
|
||||
cols_scatter = zeros(nG,3);
|
||||
for i = 1:nG
|
||||
cols_scatter(i,:) = lightenColor(cols_line(i,:), 0.40);
|
||||
end
|
||||
end
|
||||
return;
|
||||
end
|
||||
|
||||
% 2) Standard behavior
|
||||
useBrewer = plotcfg.use_cbrewer2 && exist('cbrewer2','file')==2;
|
||||
if useBrewer
|
||||
N = max(2*nG, 12);
|
||||
C = cbrewer2(plotcfg.colormap, N);
|
||||
cols_line = zeros(nG,3);
|
||||
cols_scatter = zeros(nG,3);
|
||||
for i = 1:nG
|
||||
if plotcfg.paired_dark_first
|
||||
dark = C(2*i-1, :);
|
||||
light = C(2*i, :);
|
||||
else
|
||||
light = C(2*i-1, :);
|
||||
dark = C(2*i, :);
|
||||
end
|
||||
cols_line(i,:) = dark;
|
||||
cols_scatter(i,:) = light;
|
||||
end
|
||||
else
|
||||
C = lines(max(nG,7));
|
||||
cols_line = C(1:nG,:);
|
||||
cols_scatter = zeros(nG,3);
|
||||
for i = 1:nG
|
||||
cols_scatter(i,:) = lightenColor(cols_line(i,:), 0.50);
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function c2 = lightenColor(c, fracTowardWhite)
|
||||
c = c(:).';
|
||||
c2 = (1-fracTowardWhite)*c + fracTowardWhite*1;
|
||||
end
|
||||
@@ -0,0 +1,436 @@
|
||||
function h = plot_measurements_gpt_old(T, cfg)
|
||||
% Versatile plotting from your DB table (with cbrewer2 'Paired' palette).
|
||||
%
|
||||
% Usage:
|
||||
% h = plot_measurements_flex(dataTable, cfg)
|
||||
|
||||
%% ---- Defaults
|
||||
if nargin < 2, cfg = struct; end
|
||||
defaults = struct( ...
|
||||
'x_axis' , 'symbolrate', ...
|
||||
'y_axis' , 'BER', ...
|
||||
'y_scale' , 'auto', ...
|
||||
'group_by' , {{'equalizer_structure','pre_emph'}}, ...
|
||||
'filters' , struct, ...
|
||||
'agg' , 'mean', ...
|
||||
'outlier' , 'auto', ...
|
||||
'mad_z' , 4, ...
|
||||
'pct_limits' , [2.5 97.5], ...
|
||||
'min_pts_x' , 3, ...
|
||||
'show_raw' , true, ...
|
||||
'show_precoded', [], ...
|
||||
'show_spread' , 'none', ...
|
||||
'fec_lines' , [], ...
|
||||
'plot', struct() ...
|
||||
);
|
||||
cfg = filldefaults(cfg, defaults);
|
||||
|
||||
% ---- Plot defaults (new)
|
||||
plotdefs = struct( ...
|
||||
'use_cbrewer2' , true, ...
|
||||
'colormap' , 'Paired', ... % ColorBrewer 'Paired'
|
||||
'paired_dark_first' , true, ... % dark for lines, light for scatter
|
||||
'lineWidth' , 1.8, ...
|
||||
'errWidth' , 1.0, ...
|
||||
'scatterSize' , 14, ...
|
||||
'scatterAlpha' , 0.35, ...
|
||||
'marker' , 'o', ...
|
||||
'marker_precoded' , 's', ...
|
||||
'lineStyle_pre_emph_on' , '--', ...
|
||||
'lineStyle_pre_emph_off', '-', ...
|
||||
'legendLocation' , 'best', ...
|
||||
'fecLineWidth' , 2.2, ... % thicker FEC limits
|
||||
'fecColor' , [0.25 0.25 0.25], ...
|
||||
'capSize' , 6, ...
|
||||
'lineStyle_default' , '-', ...
|
||||
'use_pre_emph_styling' , true ...
|
||||
);
|
||||
cfg.plot = filldefaults(cfg.plot, plotdefs);
|
||||
|
||||
%% ---- Derived/prep columns
|
||||
if ~ismember('pre_emph', T.Properties.VariableNames)
|
||||
if ~ismember('db_mode', T.Properties.VariableNames)
|
||||
error('Missing column "db_mode" for pre_emph derivation.');
|
||||
end
|
||||
T.pre_emph = T.db_mode == 0;
|
||||
end
|
||||
if ~ismember(cfg.y_axis, T.Properties.VariableNames)
|
||||
error('y_axis "%s" not found in table.', cfg.y_axis);
|
||||
end
|
||||
|
||||
isBER = startsWith(cfg.y_axis, "BER", 'IgnoreCase', true);
|
||||
if strcmpi(cfg.y_scale,'auto'), cfg.y_scale = tern(isBER, 'log', 'linear'); end
|
||||
if strcmpi(cfg.outlier,'auto'), cfg.outlier = tern(isBER, 'mad', 'none'); end
|
||||
if isempty(cfg.show_precoded)
|
||||
cfg.show_precoded = isBER && ismember('BER_precoded', T.Properties.VariableNames);
|
||||
end
|
||||
|
||||
%% ---- Filters
|
||||
T = applyFilters(T, cfg.filters);
|
||||
[x_raw, x_label] = computeX(T, cfg.x_axis);
|
||||
y_raw = T.(cfg.y_axis);
|
||||
|
||||
validXY = isfinite(x_raw) & isfinite(y_raw);
|
||||
T = T(validXY, :);
|
||||
x_raw = x_raw(validXY);
|
||||
y_raw = y_raw(validXY);
|
||||
|
||||
if mean(abs(y_raw)) > 1e8
|
||||
%giga values
|
||||
y_raw = y_raw.*1e-9;
|
||||
end
|
||||
|
||||
if cfg.show_precoded && ismember('BER_precoded', T.Properties.VariableNames)
|
||||
y_raw_p = T.BER_precoded(validXY);
|
||||
else
|
||||
y_raw_p = [];
|
||||
end
|
||||
|
||||
%% ---- Grouping
|
||||
group_by = cfg.group_by;
|
||||
if ~all(ismember(group_by, T.Properties.VariableNames))
|
||||
error('Some group_by columns are missing in table.');
|
||||
end
|
||||
[G, grpTbl] = findgroups(T(:, group_by));
|
||||
nG = max(G);
|
||||
|
||||
% ==== Colors (cbrewer2 'Paired' with dark/ light pairs) ====
|
||||
[cols_line, cols_scatter] = buildGroupColors(nG, cfg.plot);
|
||||
|
||||
%% ---- Axes / Figure handling (new unified logic)
|
||||
|
||||
% Priority:
|
||||
% 1) cfg.ax → use existing axes (subplots/tiles)
|
||||
% 2) cfg.figure_number → select/create figure
|
||||
% 3) fallback: create new figure
|
||||
|
||||
if isfield(cfg,'ax') && ~isempty(cfg.ax) && isgraphics(cfg.ax,'axes')
|
||||
ax = cfg.ax; % use caller-provided axes
|
||||
set(gcf,'CurrentAxes',ax);
|
||||
else
|
||||
if isfield(cfg,'figure_number') && ~isempty(cfg.figure_number)
|
||||
figure(cfg.figure_number);
|
||||
else
|
||||
figure;
|
||||
end
|
||||
ax = gca; % active axes
|
||||
end
|
||||
|
||||
hold(ax,'on');
|
||||
grid(ax,'on');
|
||||
|
||||
|
||||
h.lines = gobjects(nG,1);
|
||||
h.err = gobjects(nG,1);
|
||||
h.scat = gobjects(nG,1);
|
||||
h.lines_p = gobjects(nG,1);
|
||||
|
||||
for gi = 1:nG
|
||||
idx = (G==gi);
|
||||
Ti = T(idx,:);
|
||||
xi = x_raw(idx);
|
||||
yi = y_raw(idx);
|
||||
|
||||
% Aggregate per unique x
|
||||
[xu, ia, iu] = unique(xi);
|
||||
yu = nan(size(xu));
|
||||
ylo = nan(size(xu));
|
||||
yhi = nan(size(xu));
|
||||
|
||||
for k = 1:numel(xu)
|
||||
bin = (iu==k);
|
||||
yy = yi(bin);
|
||||
yy = yy(isfinite(yy));
|
||||
if isempty(yy), continue; end
|
||||
km = outlierMask(yy, cfg, strcmpi(cfg.y_scale,'log'));
|
||||
if nnz(km) < cfg.min_pts_x, km = true(size(yy)); end
|
||||
yy = yy(km);
|
||||
|
||||
if strcmpi(cfg.agg,'median'), yu(k)=median(yy,'omitnan'); elseif strcmpi(cfg.agg,'mean'), yu(k)=mean(yy,'omitnan'); elseif strcmpi(cfg.agg,'min'), yu(k)=min(yy); elseif strcmpi(cfg.agg,'max'), yu(k)=max(yy); end
|
||||
if strcmpi(cfg.show_spread,'iqr')
|
||||
q = prctile(yy,[25 75]);
|
||||
ylo(k) = max(yu(k)-q(1), eps);
|
||||
yhi(k) = max(q(2)-yu(k), eps);
|
||||
elseif strcmpi(cfg.show_spread,'minmax')
|
||||
ylo(k) = min(yy);
|
||||
yhi(k) = max(yy);
|
||||
end
|
||||
end
|
||||
|
||||
% sort
|
||||
[xu, ord] = sort(xu);
|
||||
yu = yu(ord);
|
||||
ylo = ylo(ord);
|
||||
yhi = yhi(ord);
|
||||
|
||||
% Styles
|
||||
% Decide if we style by pre_emph
|
||||
% --- LINE TYPE SELECTION (no pre-emphasis logic) ---
|
||||
ls = cfg.plot.lineStyle_default;
|
||||
|
||||
% User-defined override (cycled)
|
||||
if isfield(cfg.plot,'custom_linetypes') && ~isempty(cfg.plot.custom_linetypes)
|
||||
L = cfg.plot.custom_linetypes;
|
||||
ls = L{ mod(gi-1, numel(L)) + 1 };
|
||||
end
|
||||
|
||||
lbl = buildLabel(grpTbl(gi,:), group_by);
|
||||
|
||||
% Main line (dark)
|
||||
colL = cols_line(gi,:);
|
||||
h.lines(gi) = plot(xu, yu, ...
|
||||
'LineWidth', cfg.plot.lineWidth, ...
|
||||
'Marker', cfg.plot.marker, 'MarkerSize', 3, ...
|
||||
'Color', colL, 'LineStyle', ls, ...
|
||||
'DisplayName', char(lbl));
|
||||
|
||||
% Spread (IQR) in line color
|
||||
if any(isfinite(ylo)) && any(isfinite(yhi))
|
||||
h.err(gi) = errorbar(xu, yu, ylo, yhi, 'LineStyle','none', ...
|
||||
'Color', colL, 'CapSize', cfg.plot.capSize, 'HandleVisibility','off');
|
||||
h.err(gi).LineWidth = cfg.plot.errWidth;
|
||||
end
|
||||
|
||||
% Raw kept scatter (light)
|
||||
if cfg.show_raw
|
||||
keep_all = false(size(yi));
|
||||
for k = 1:numel(xu)
|
||||
bin = (iu==k);
|
||||
yy = yi(bin);
|
||||
km = outlierMask(yy, cfg, strcmpi(cfg.y_scale,'log'));
|
||||
if nnz(km) < cfg.min_pts_x, km = true(size(yy)); end
|
||||
keep_all(bin) = km;
|
||||
end
|
||||
colS = cols_scatter(gi,:);
|
||||
scatter(xi(keep_all), yi(keep_all), cfg.plot.scatterSize, colS, 'filled', ...
|
||||
'MarkerFaceAlpha', cfg.plot.scatterAlpha, 'MarkerEdgeAlpha', cfg.plot.scatterAlpha, ...
|
||||
'HandleVisibility','off');
|
||||
end
|
||||
|
||||
% Precoded overlay (dotted, squares), in line color
|
||||
if cfg.show_precoded && ~isempty(y_raw_p) && strcmpi(cfg.y_axis,'BER')
|
||||
ypi = y_raw_p(idx);
|
||||
ypu = nan(size(xu));
|
||||
for k = 1:numel(xu)
|
||||
bin = (iu==k);
|
||||
yy = ypi(bin);
|
||||
yy = yy(isfinite(yy));
|
||||
if isempty(yy), continue; end
|
||||
km = outlierMask(yy, cfg, true);
|
||||
if nnz(km) < cfg.min_pts_x, km = true(size(yy)); end
|
||||
yy = yy(km);
|
||||
if strcmpi(cfg.agg,'median'), ypu(k)=median(yy,'omitnan'); elseif strcmpi(cfg.agg,'mean'), ypu(k)=mean(yy,'omitnan'); elseif strcmpi(cfg.agg,'min'), ypu(k)=min(yy); elseif strcmpi(cfg.agg,'max'), ypu(k)=max(yy); end
|
||||
end
|
||||
h.lines_p(gi) = plot(xu, ypu, ...
|
||||
'LineWidth', max(1.2, cfg.plot.lineWidth-0.2), ...
|
||||
'Marker', cfg.plot.marker_precoded, 'MarkerSize', 3, ...
|
||||
'Color', colL, 'LineStyle', ':', ...
|
||||
'DisplayName', [char(lbl) ' (precoded)']);
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
||||
%% ---- Axes / Labels / FEC
|
||||
ylabel(cfg.y_axis, 'Interpreter','none');
|
||||
xlabel(x_label, 'Interpreter','none');
|
||||
set(gca, 'YScale', cfg.y_scale, 'FontSize', 11);
|
||||
% legend('Location', cfg.plot.legendLocation); box on;
|
||||
|
||||
xticks(floor(xu));
|
||||
xlim([min(xu), max(xu)])
|
||||
|
||||
if startsWith(cfg.y_axis,"BER",'IgnoreCase',true)
|
||||
for v = cfg.fec_lines
|
||||
yline(v, '--', 'Color', cfg.plot.fecColor, ...
|
||||
'LineWidth', cfg.plot.fecLineWidth, 'HandleVisibility','off');
|
||||
end
|
||||
ylim([1e-5, 0.5]);
|
||||
yticks([1e-5, 1e-4, 1e-3, 1e-2, 1e-1]);
|
||||
end
|
||||
|
||||
|
||||
|
||||
end % ===== main =====
|
||||
|
||||
|
||||
%% ===================== Helpers =====================
|
||||
|
||||
function cfg = filldefaults(cfg, defs)
|
||||
fn = fieldnames(defs);
|
||||
for i = 1:numel(fn)
|
||||
f = fn{i};
|
||||
if ~isfield(cfg, f) || isempty(cfg.(f))
|
||||
cfg.(f) = defs.(f);
|
||||
elseif isstruct(defs.(f)) && isstruct(cfg.(f))
|
||||
cfg.(f) = filldefaults(cfg.(f), defs.(f)); % recursive for structs
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function out = tern(cond, a, b)
|
||||
if cond
|
||||
out = a;
|
||||
else
|
||||
out = b;
|
||||
end
|
||||
end
|
||||
|
||||
function T2 = applyFilters(T, filters)
|
||||
if isempty(filters), T2 = T; return; end
|
||||
keep = true(height(T),1);
|
||||
fns = fieldnames(filters);
|
||||
for i = 1:numel(fns)
|
||||
name = fns{i};
|
||||
if ~ismember(name, T.Properties.VariableNames)
|
||||
warning('Filter column "%s" not found. Ignored.', name); %#ok<*WNTAG>
|
||||
continue
|
||||
end
|
||||
val = filters.(name);
|
||||
col = T.(name);
|
||||
if isa(val,'function_handle')
|
||||
m = val(col);
|
||||
if ~islogical(m) || ~isequal(size(m), size(col))
|
||||
error('Filter for %s must return logical mask of same size.', name);
|
||||
end
|
||||
keep = keep & m;
|
||||
else
|
||||
keep = keep & ismember(col, val);
|
||||
end
|
||||
end
|
||||
T2 = T(keep,:);
|
||||
end
|
||||
|
||||
function [x, label] = computeX(T, whichX)
|
||||
switch lower(whichX)
|
||||
case {'symbolrate','baudrate'}
|
||||
x = T.symbolrate * 1e-9;
|
||||
label = 'Symbol rate [GBd]';
|
||||
case 'bitrate'
|
||||
if ~ismember('pam_level', T.Properties.VariableNames)
|
||||
error('bitrate requires "pam_level" column.');
|
||||
end
|
||||
bits = floor(log2(double(T.pam_level))*10)/10;
|
||||
x = (T.symbolrate .* bits) * 1e-9;
|
||||
label = 'Grossrate [Gb/s]';
|
||||
case 'grossrate'
|
||||
x = (T.grossrate) * 1e-9;
|
||||
label = 'Grossrate [Gb/s]';
|
||||
otherwise
|
||||
if ~ismember(whichX, T.Properties.VariableNames)
|
||||
error('x_axis "%s" not found in table.', whichX);
|
||||
end
|
||||
x = T.(whichX);
|
||||
label = whichX;
|
||||
end
|
||||
x = double(x(:));
|
||||
end
|
||||
|
||||
function keep = outlierMask(y, cfg, useLog)
|
||||
if isempty(y), keep = false(size(y)); return; end
|
||||
y = y(:);
|
||||
switch lower(cfg.outlier)
|
||||
case 'none'
|
||||
keep = true(size(y)); return
|
||||
case 'mad'
|
||||
z = tern(useLog, log10(y), y);
|
||||
med = median(z,'omitnan');
|
||||
madv = median(abs(z-med),'omitnan');
|
||||
if ~(isfinite(madv) && madv>0)
|
||||
keep = true(size(y)); return
|
||||
end
|
||||
sigma = 1.4826*madv;
|
||||
zz = tern(useLog, log10(y), y);
|
||||
keep = abs(zz - med) <= cfg.mad_z*sigma;
|
||||
case 'pctl'
|
||||
pr = prctile(y, cfg.pct_limits);
|
||||
keep = (y >= pr(1)) & (y <= pr(2));
|
||||
otherwise
|
||||
error('Unknown outlier mode "%s".', cfg.outlier);
|
||||
end
|
||||
end
|
||||
|
||||
function s = buildLabel(grpRow, group_by)
|
||||
parts = strings(1, numel(group_by));
|
||||
for i = 1:numel(group_by)
|
||||
key = group_by{i};
|
||||
val = grpRow.(key);
|
||||
if iscell(val), val = val{1}; end
|
||||
if islogical(val), val = tern(val,'w/','w/o'); end
|
||||
if key == "equalizer_structure"
|
||||
key = '';
|
||||
val = upper(val);
|
||||
val = strrep(val,'_',' ');
|
||||
end
|
||||
|
||||
if key == "pre_emph"
|
||||
% key = strrep(key,'_','-');
|
||||
val = [val, ' pre-emph.'];
|
||||
key = '';
|
||||
end
|
||||
|
||||
parts(i) = sprintf('%s %s', key, string(val));
|
||||
end
|
||||
s = strjoin(parts, ', ');
|
||||
end
|
||||
|
||||
function [cols_line, cols_scatter] = buildGroupColors(nG, plotcfg)
|
||||
|
||||
% --- 1) User-provided custom colors -------------------------------
|
||||
if isfield(plotcfg,'custom_colors') && ~isempty(plotcfg.custom_colors)
|
||||
C = plotcfg.custom_colors;
|
||||
if size(C,1) < nG
|
||||
error('custom_colors must have at least nG=%d rows.', nG);
|
||||
end
|
||||
cols_line = C(1:nG, :);
|
||||
|
||||
% Scatter colors: either user-provided or lightened
|
||||
if isfield(plotcfg,'custom_colors_scatter') && ~isempty(plotcfg.custom_colors_scatter)
|
||||
Cs = plotcfg.custom_colors_scatter;
|
||||
if size(Cs,1) < nG
|
||||
error('custom_colors_scatter must have at least nG=%d rows.', nG);
|
||||
end
|
||||
cols_scatter = Cs(1:nG, :);
|
||||
else
|
||||
% auto-lighten scatter colors
|
||||
cols_scatter = zeros(nG,3);
|
||||
for i = 1:nG
|
||||
cols_scatter(i,:) = lightenColor(cols_line(i,:), 0.40);
|
||||
end
|
||||
end
|
||||
return;
|
||||
end
|
||||
|
||||
% --- 2) Standard behavior (using cbrewer2 or fallback) ------------
|
||||
useBrewer = plotcfg.use_cbrewer2 && exist('cbrewer2','file')==2;
|
||||
if useBrewer
|
||||
N = max(2*nG, 12);
|
||||
C = cbrewer2(plotcfg.colormap, N);
|
||||
cols_line = zeros(nG,3);
|
||||
cols_scatter = zeros(nG,3);
|
||||
for i = 1:nG
|
||||
if plotcfg.paired_dark_first
|
||||
dark = C(2*i-1, :);
|
||||
light = C(2*i, :);
|
||||
else
|
||||
light = C(2*i-1, :);
|
||||
dark = C(2*i, :);
|
||||
end
|
||||
cols_line(i,:) = dark;
|
||||
cols_scatter(i,:) = light;
|
||||
end
|
||||
else
|
||||
C = lines(max(nG,7));
|
||||
cols_line = C(1:nG,:);
|
||||
cols_scatter = zeros(nG,3);
|
||||
for i = 1:nG
|
||||
cols_scatter(i,:) = lightenColor(cols_line(i,:), 0.50);
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function c2 = lightenColor(c, fracTowardWhite)
|
||||
c = c(:).';
|
||||
c2 = (1-fracTowardWhite)*c + fracTowardWhite*1;
|
||||
end
|
||||
@@ -0,0 +1,38 @@
|
||||
X-Werte;PAM-2;PAM-4;PAM-6;PAM-8;PAM-12
|
||||
224;204;;;;
|
||||
205,5;193,4;;;;
|
||||
205,1;189,7;;;;
|
||||
192;168;;;;
|
||||
240;;427,4;;;
|
||||
225;;420,5;;;
|
||||
210;;336;;;
|
||||
184;;332;;;
|
||||
192;;320;;;
|
||||
176;;306,0869565;;;
|
||||
190;;304;;;
|
||||
168;;294;;;
|
||||
156,2;;287,1;;;
|
||||
160,8;;286,9;;;
|
||||
170;;272;;;
|
||||
132;;250,9505703;;;
|
||||
112;;209,3457944;;;
|
||||
172;;337;;;
|
||||
216;;;474,6;;
|
||||
147,2;;;329,9;;
|
||||
132;;;319,7891753;;
|
||||
143,1;;;318;;
|
||||
160;;;377;;
|
||||
225;;;;562,5;
|
||||
200;;;;510;
|
||||
160;;;;438;
|
||||
180;;;;432;
|
||||
180;;;;432;
|
||||
144;;;;384;
|
||||
143,7;;;;363,4;
|
||||
144;;;;360;
|
||||
136;;;;353,859497;
|
||||
136;;;;342,7995295;
|
||||
128;;;;329,0488432;
|
||||
129,7;;;;311,2;
|
||||
160;;;;413;
|
||||
160;;;;;481,2
|
||||
|
@@ -0,0 +1,76 @@
|
||||
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);
|
||||
|
||||
M = 8;
|
||||
fp = QueryFilter();
|
||||
% fp.where('Runs', 'run_id','EQUALS', 987);
|
||||
fp.where('Runs', 'pam_level','EQUALS', M);
|
||||
% fp.where('Runs', 'symbolrate','EQUALS', 165e9); %150, 165, 180, 195, 210, 225, 240
|
||||
fp.where('Runs', 'fiber_length','EQUALS', 2);
|
||||
% fp.where('Runs', 'is_mpi','EQUALS', 0);
|
||||
% fp.where('Runs', 'power_pd_in','GREATER_THAN', 7);
|
||||
% 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_alltime')]; %dashboard_ungrouped_after_nov_2025 dashboard_ungrouped_aug_nov_2025
|
||||
[dataTable,~] = db.queryDB(fp, fields);
|
||||
|
||||
|
||||
%%
|
||||
cfg = struct;
|
||||
cfg.x_axis = 'grossrate'; % 'symbol rate' | 'bitrate' | 'wavelength' grossrate
|
||||
cfg.y_axis = 'BER'; % 'BER' | 'GMI' | 'AIR' | ...
|
||||
cfg.group_by = {'equalizer_structure','pre_emph'};
|
||||
cfg.filters = struct('is_mpi',0,'pam_level',M,'equalizer_structure',[equalizer_structure.ml_mlse]);%,equalizer_structure.vnle_pf_mlse,equalizer_structure.vnle]);
|
||||
|
||||
cfg.y_scale = 'auto'; % auto -> log for BER*, linear otherwise
|
||||
cfg.outlier = 'mad'; % simple, robust; 'none' or 'pctl' also available
|
||||
cfg.show_raw = false;
|
||||
cfg.show_spread = 'none'; % 'none' or 'iqr' or minmax
|
||||
cfg.agg = 'min'; % or 'median'
|
||||
cfg.show_precoded = 0;
|
||||
cfg.fec_lines = [2.2e-4 4.85e-3 2e-2]; % optional
|
||||
|
||||
cfg.figure_number = 42;
|
||||
cfg.plot.custom_colors = [
|
||||
clr.Paired.red;
|
||||
clr.Paired.blue;
|
||||
clr.Paired.green;
|
||||
clr.Paired.orange;
|
||||
clr.Paired.purple
|
||||
];
|
||||
|
||||
cfg.plot.custom_colors_scatter = [
|
||||
clr.Paired.lightred;
|
||||
clr.Paired.lightblue;
|
||||
clr.Paired.lightgreen;
|
||||
clr.Paired.lightorange;
|
||||
clr.Paired.lightpurple
|
||||
];
|
||||
|
||||
|
||||
% New styling knobs
|
||||
cfg.plot.use_cbrewer2 = true;
|
||||
cfg.plot.colormap = 'Paired';
|
||||
cfg.plot.paired_dark_first = false; % dark for lines, light for scatter
|
||||
cfg.plot.lineWidth = 2.0;
|
||||
cfg.plot.errWidth = 1.2;
|
||||
cfg.plot.scatterAlpha = 0.35;
|
||||
cfg.plot.legendLocation = 'best';
|
||||
cfg.plot.fecLineWidth = 2.4; % thicker FEC limits
|
||||
|
||||
plot_measurements_gpt(dataTable, cfg);
|
||||
|
||||
% beautifyBERplot()
|
||||
|
||||
%% FIG PRE EMPHASIS
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
|
||||
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);
|
||||
|
||||
M = 8;
|
||||
fp = QueryFilter();
|
||||
% fp.where('Runs', 'run_id','EQUALS', 987);
|
||||
fp.where('Runs', 'pam_level','EQUALS', M);
|
||||
% fp.where('Runs', 'symbolrate','EQUALS', 165e9);
|
||||
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);
|
||||
|
||||
% Create the figure
|
||||
figure(18);
|
||||
hold on
|
||||
|
||||
for pre_emph = [0,1]
|
||||
|
||||
dbmode_filtered = dataTable(dataTable.db_mode == ~pre_emph,:);
|
||||
|
||||
for eqs = [equalizer_structure.vnle]
|
||||
|
||||
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,:);
|
||||
if eqs ==equalizer_structure.vnle_pf_mlse
|
||||
eq_filtered = eq_filtered(eq_filtered.DIR == "1",:);
|
||||
end
|
||||
symbolrate_sorted = sortrows(eq_filtered,{'symbolrate'}, 'ascend');
|
||||
|
||||
|
||||
% Example data (replace these with your real vectors)
|
||||
symbolrate = symbolrate_sorted.symbolrate.*1e-9; % in baud
|
||||
bitrate = symbolrate * 2;
|
||||
gmi = symbolrate_sorted.GMI; % BER
|
||||
snr = symbolrate_sorted.SNR; % BER
|
||||
cols = cbrewer2('Paired',12);
|
||||
|
||||
dname = [char(eq_choice)];
|
||||
dname = strrep(dname,'_','+');
|
||||
if pre_emph
|
||||
dname = [dname,'; w/ pre-emph.'];
|
||||
else
|
||||
dname = [dname,'; w/o pre-emph.'];
|
||||
end
|
||||
|
||||
plot(symbolrate, snr, 'LineWidth', 1.5, 'MarkerSize', 5,'Marker','o','LineStyle','-','Color',cols((2*eqs)+1+pre_emph,:),'MarkerEdgeColor',cols((2*eqs)+1+pre_emph,:),'MarkerFaceColor',[1,1,1],'DisplayName',[dname]);
|
||||
grid on;
|
||||
|
||||
% Axis labels and title
|
||||
xlabel('Bit Rate Gbps', 'FontSize', 12);
|
||||
ylabel('GMI', 'FontSize', 12);
|
||||
title('GMI vs. Bit Rate', 'FontSize', 14, 'FontWeight', 'bold');
|
||||
|
||||
% Improve tick formatting
|
||||
set(gca, 'XScale', 'linear', ...
|
||||
'YScale', 'linear', ...
|
||||
'TickLabelInterpreter', 'none', ...
|
||||
'FontSize', 11);
|
||||
legend
|
||||
|
||||
xticks(symbolrate);
|
||||
|
||||
% Optional: tighten axis limits
|
||||
xlim([min(symbolrate), max(symbolrate)]);
|
||||
% ylim([log2(M)-1, log2(M)]);
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
@@ -0,0 +1,96 @@
|
||||
|
||||
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('power_state_info', 'pam_level','EQUALS', 4);
|
||||
fp.where('power_state_info', 'db_mode','EQUALS', 1);
|
||||
% fp.where('power_state_info', 'fiber_length','EQUALS', 1);
|
||||
fp.where('power_state_info', 'is_mpi','EQUALS', 0);
|
||||
|
||||
fields = db.getTableFieldNames('power_state_info');
|
||||
% [dataTable,~] = db.queryDB(fp, fields);
|
||||
|
||||
fiber_len = unique(dataTable.fiber_length);
|
||||
cnt = 0;
|
||||
|
||||
y_variable = 'power_mzm';
|
||||
x_variable = "wavelength";
|
||||
f = figure(3);
|
||||
clf
|
||||
hold on
|
||||
for fl = 1:numel(fiber_len)
|
||||
|
||||
|
||||
fl_filtered = dataTable(dataTable.fiber_length == fiber_len(fl),:);
|
||||
[~, ia] = unique(fl_filtered.run_id, 'first');
|
||||
fl_filtered = fl_filtered(ia, :);
|
||||
|
||||
fl_filtered_ = groupsummary( ...
|
||||
fl_filtered, ... % input table
|
||||
x_variable, ... % grouping variable
|
||||
"mean", ... % which summary statistic
|
||||
y_variable); % which column to average
|
||||
|
||||
wavelength_sorted = sortrows(fl_filtered, {'wavelength'}, 'ascend');
|
||||
|
||||
% pull out your vectors
|
||||
lambda = wavelength_sorted.wavelength;
|
||||
power_laser = wavelength_sorted.power_laser;
|
||||
power_mzm = wavelength_sorted.power_mzm;
|
||||
power_rop = wavelength_sorted.power_rop;
|
||||
power_pd = wavelength_sorted.power_pd_in;
|
||||
voa = wavelength_sorted.voa_atten;
|
||||
len = wavelength_sorted.fiber_length;
|
||||
run_ids = wavelength_sorted.run_id; % <-- this is what we want in the datatip
|
||||
cols = linspecer(8);
|
||||
|
||||
|
||||
% plot the two curves and capture their Line handles
|
||||
% h1 = plot(lambda, power_laser,'LineWidth', 0.5, 'MarkerSize', 4,'Marker','o','LineStyle','none','Color',cols(fl,:),'MarkerFaceColor',cols(fl,:),'DisplayName','Laser Output');
|
||||
% % —————— 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', run_ids);
|
||||
% h1.DataTipTemplate.DataTipRows(end+1) = ...
|
||||
% dataTipTextRow('voaatten', voa);
|
||||
|
||||
%
|
||||
dname = sprintf('%s; %d km',y_variable, fiber_len(fl));
|
||||
h2 = plot(fl_filtered_.(x_variable), fl_filtered_.(['mean_',y_variable]), 'LineWidth', 1, 'MarkerSize', 4,'Marker','o','LineStyle','-','Color',cols(fl,:),'MarkerFaceColor',cols(fl,:),'DisplayName',dname);
|
||||
|
||||
h2.DataTipTemplate.DataTipRows(end+1) = ...
|
||||
dataTipTextRow('run\_id', run_ids);
|
||||
h2.DataTipTemplate.DataTipRows(end+1) = ...
|
||||
dataTipTextRow('len', len);
|
||||
h2.DataTipTemplate.DataTipRows(end+1) = ...
|
||||
dataTipTextRow('voaatten', voa);
|
||||
|
||||
grid on;
|
||||
xticks(sort(unique(lambda)));
|
||||
xticklabels(sort(unique(lambda)));
|
||||
|
||||
% Labels, scales, legend, etc.
|
||||
xlabel('Wavelength in nm','FontSize',12);
|
||||
ylabel('Power in dB','FontSize',12);
|
||||
title('Power ','FontSize',14,'FontWeight','bold');
|
||||
set(gca, 'XScale','linear','YScale','linear','FontSize',11);
|
||||
legend
|
||||
|
||||
xlim([min(lambda)-2, max(lambda)+2]);
|
||||
ylim([floor(min(fl_filtered_.(['mean_',y_variable])))-1 12]);
|
||||
ylim([-12 12]);
|
||||
|
||||
cnt = cnt+1;
|
||||
|
||||
yline(8,'HandleVisibility','off');
|
||||
|
||||
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);
|
||||
@@ -0,0 +1,379 @@
|
||||
% === SETTINGS ===
|
||||
dsp_options.append_to_db = 1;
|
||||
dsp_options.max_occurences = 1;
|
||||
|
||||
experiment = "highspeed_2024";
|
||||
dsp_options.mode = "load_run_id"; % 'simulate' & 'load_files'
|
||||
dsp_options.load_file_path = struct();
|
||||
|
||||
if dsp_options.mode == "load_run_id"
|
||||
|
||||
if experiment == "highspeed_2024"
|
||||
|
||||
dsp_options.database_type = 'mysql';
|
||||
dsp_options.dataBase = 'labor_highspeed';%'C:\Users\Silas\Documents\MATLAB\Datensätze\sioe_labor\silas_labor_newdsp_newstructure.db';
|
||||
dsp_options.storage_path = 'Z:\2024\sioe_labor\';
|
||||
db = DBHandler("dataBase", [dsp_options.dataBase], "type", dsp_options.database_type);
|
||||
|
||||
elseif experiment == "mpi_ecoc_2025"
|
||||
|
||||
dsp_options.database_type = 'mysql';
|
||||
dsp_options.dataBase = 'labor';
|
||||
dsp_options.storage_path = 'Z:\2025\ECOC Silas\ecoc_2025\';
|
||||
db = DBHandler("dataBase", [dsp_options.dataBase], "type", dsp_options.database_type);
|
||||
|
||||
end
|
||||
|
||||
elseif dsp_options.mode == "load_files"
|
||||
|
||||
dsp_options.load_file_path.tx_bits_path = "Z:\2025\ECOC Silas\ecoc_2025\mpi_opti_1000m_pam2 4 6 8\20250417_091513_PAM_4_R_112_bits.mat"';
|
||||
dsp_options.load_file_path.tx_symbols_path = "Z:\2025\ECOC Silas\ecoc_2025\mpi_opti_1000m_pam2 4 6 8\20250417_091513_PAM_4_R_112_symbols.mat"';
|
||||
dsp_options.load_file_path.rx_raw_path = "Z:\2025\ECOC Silas\ecoc_2025\mpi_opti_1000m_pam2 4 6 8\20250417_091525_PAM_4_R_112_rec01_rx_signal_raw.mat"';
|
||||
|
||||
elseif dsp_options.mode == "simulate"
|
||||
|
||||
error('Not yet implemented')
|
||||
|
||||
end
|
||||
|
||||
% === Get Run ID's ===
|
||||
|
||||
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', 'symbolrate','EQUALS', 195e9);
|
||||
fp.where('Runs', 'fiber_length','EQUALS', 10);
|
||||
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','EQUAL', 0);
|
||||
% fp.where('Runs', 'power_pd_in','LESS_THAN', 7);
|
||||
|
||||
[dataTable,~] = db.queryDB(fp, db.getTableFieldNames('Runs'));
|
||||
|
||||
% === Set LOOPS & Initialize DataStorage ===
|
||||
dsp_options.parameters = struct();
|
||||
% dsp_options.parameters.pf_ncoeffs = [1,2];%s[0,logspace(-4,0,10)];
|
||||
|
||||
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");
|
||||
wh.addStorage("mlmlse_package");
|
||||
|
||||
%% === RUN IT ===
|
||||
|
||||
[results,wh] = submitJobs(dataTable.run_id(:), dsp_options, "parallel", 'wh', wh, 'waitbar', true);
|
||||
|
||||
|
||||
|
||||
%% =========================================================================
|
||||
% LOAD METADATA
|
||||
% =========================================================================
|
||||
[dataTable, ~] = db.queryDB(fp, db.getTableFieldNames('Runs'));
|
||||
results = results(:).'; % ensure row vector
|
||||
N = numel(results);
|
||||
|
||||
% =========================================================================
|
||||
% PREALLOCATE METRIC ARRAYS
|
||||
% =========================================================================
|
||||
BER_VNLE = nan(1,N);
|
||||
BER_MLSE = nan(1,N);
|
||||
BER_DB = nan(1,N);
|
||||
BER_DB_PREC = nan(1,N);
|
||||
BER_MLMLSE = nan(1,N);
|
||||
BER_MLMLSE_PREC = nan(1,N);
|
||||
|
||||
% =========================================================================
|
||||
% EXTRACT METRICS (ONE LOOP, ROBUST)
|
||||
% =========================================================================
|
||||
for i = 1:N
|
||||
r = results{i};
|
||||
|
||||
% ---- VNLE (no-DB mode) ----
|
||||
if isfield(r, 'vnle_package') && ~isempty(r.vnle_package)
|
||||
pkg = r.vnle_package;
|
||||
BER_VNLE(i) = min(cellfun(@(c) c.metrics.BER, pkg));
|
||||
end
|
||||
|
||||
% ---- Classical MLSE (DB mode) ----
|
||||
if isfield(r, 'mlse_package') && ~isempty(r.mlse_package)
|
||||
pkg = r.mlse_package;
|
||||
BER_MLSE(i) = min(cellfun(@(c) c.metrics.BER, pkg));
|
||||
BER_MLSE_PREC(i) = min(cellfun(@(c) c.metrics.BER_precoded, pkg));
|
||||
end
|
||||
|
||||
% ---- DB Target (DB mode) ----
|
||||
if isfield(r, 'dbtgt_package') && ~isempty(r.dbtgt_package)
|
||||
pkg = r.dbtgt_package;
|
||||
BER_DB(i) = min(cellfun(@(c) c.metrics.BER, pkg));
|
||||
BER_DB_PREC(i) = min(cellfun(@(c) c.metrics.BER_precoded, pkg));
|
||||
end
|
||||
|
||||
% ---- ML-based MLSE (both modes) ----
|
||||
if isfield(r, 'mlmlse_package') && ~isempty(r.mlmlse_package)
|
||||
pkg = r.mlmlse_package;
|
||||
|
||||
% raw BER
|
||||
BER_MLMLSE(i) = min(cellfun(@(c) c.metrics.BER, pkg));
|
||||
|
||||
% precoded BER
|
||||
if isfield(pkg{1}.metrics, 'BER_precoded')
|
||||
BER_MLMLSE_PREC(i) = min(cellfun(@(c) c.metrics.BER_precoded, pkg));
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
%% =========================================================================
|
||||
% METADATA (ALWAYS INDEX-ALIGNED WITH RESULTS)
|
||||
% =========================================================================
|
||||
bitrate = dataTable.bitrate(:).';
|
||||
baudrate = dataTable.symbolrate(:).';
|
||||
|
||||
rop_atten = dataTable.rop_attenuation(2:2:end).';
|
||||
rop_pre = dataTable.power_rop(1:2:end).';
|
||||
rop = dataTable.power_rop(2:2:end).';
|
||||
|
||||
% =========================================================================
|
||||
% PLOT STYLE
|
||||
% =========================================================================
|
||||
STYLE_BASE = 2;
|
||||
MARKER_SIZE = STYLE_BASE;
|
||||
LINE_WIDTH = max(2, STYLE_BASE/3);
|
||||
|
||||
cols = cbrewer2('Paired', 8);
|
||||
|
||||
cm.VNLE = cols(1,:);
|
||||
cm.MLSE = cols(2,:);
|
||||
cm.DB_PREC = cols(3,:);
|
||||
cm.DB = cols(4,:);
|
||||
cm.ML_MLSE = cols(6,:);
|
||||
|
||||
mk = @(col,shape) {'Marker',shape,'MarkerFaceColor',col,'MarkerEdgeColor',col,'MarkerSize',MARKER_SIZE};
|
||||
|
||||
% =========================================================================
|
||||
% FIGURE 1: BER vs BAUDRATE
|
||||
% =========================================================================
|
||||
figure(112+M); clf; hold on;
|
||||
xGHz = baudrate * 1e-9;
|
||||
|
||||
plot(xGHz, BER_VNLE, 'DisplayName','VNLE', 'LineStyle','-','LineWidth',LINE_WIDTH,'Color',cm.VNLE);
|
||||
plot(xGHz, BER_MLSE, 'DisplayName','MLSE', 'LineStyle','-','LineWidth',LINE_WIDTH,'Color',cm.MLSE);
|
||||
% plot(xGHz, BER_MLSE_PREC, 'DisplayName','MLSE', 'LineStyle',':','LineWidth',LINE_WIDTH,'Color',cm.MLSE);
|
||||
plot(xGHz, BER_DB_PREC, 'DisplayName','Diff. Precode + DB', 'LineStyle','-','LineWidth',LINE_WIDTH,'Color',cm.DB_PREC);
|
||||
plot(xGHz, BER_MLMLSE_PREC, 'DisplayName','ML-based MLSE', 'LineStyle',':','LineWidth',LINE_WIDTH,'Color',cm.ML_MLSE);
|
||||
|
||||
yline(2e-2,'LineWidth',1,'HandleVisibility','off');
|
||||
yline(4.85e-3,'LineWidth',1,'HandleVisibility','off');
|
||||
yline(2.2e-4,'LineWidth',1,'HandleVisibility','off');
|
||||
|
||||
xlabel('Baudrate in GBd');
|
||||
ylabel('BER');
|
||||
set(gca, 'YScale', 'log'); grid on; legend('Location','best');
|
||||
% beautifyBERplot;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
%% ---------------- FIGURE 15 : GMI ----------------
|
||||
figure(113+M); clf; hold on;
|
||||
plot(xGHz, GMI_VNLE, ...
|
||||
'DisplayName','VNLE', ...
|
||||
mk.VNLE{:}, 'LineStyle','-','LineWidth',LINE_WIDTH,'Color',cm.VNLE);
|
||||
plot(xGHz, GMI_MLSE, ...
|
||||
'DisplayName','MLSE', ...
|
||||
mk.MLSE{:}, 'LineStyle','-','LineWidth',LINE_WIDTH,'Color',cm.MLSE);
|
||||
plot(xGHz, GMI_DB, ...
|
||||
'DisplayName','DB tgt.', ...
|
||||
mk.DB{:}, 'LineStyle','-','LineWidth',LINE_WIDTH,'Color',cm.DB);
|
||||
|
||||
ylim([log2(M)-1, log2(M)]);
|
||||
xlabel('Baudrate in GBd');
|
||||
ylabel('GMI');
|
||||
set(gca, 'XTick', xticks_vals(1:2:end), 'XTickLabel', xtick_labels(1:2:end));
|
||||
grid on;
|
||||
legend('Location','best');
|
||||
|
||||
|
||||
|
||||
% ---------------- FIGURE 15 : AIR ----------------
|
||||
m = floor(log2(M)*10)/10;
|
||||
figure(114+M); clf; hold on;
|
||||
plot(xGHz, GMI_VNLE.*xGHz, ...
|
||||
'DisplayName','AIR VNLE', ...
|
||||
mk.VNLE{:}, 'LineStyle','-','LineWidth',LINE_WIDTH,'Color',cm.VNLE);
|
||||
% duobinary has only one GMI curve (DB output)
|
||||
plot(xGHz, GMI_MLSE.*xGHz, ...
|
||||
'DisplayName','AIR MLSE', ...
|
||||
mk.MLSE{:}, 'LineStyle','-','LineWidth',LINE_WIDTH,'Color',cm.MLSE);
|
||||
% MLSE symbol-wise (if present)
|
||||
plot(xGHz, GMI_DB.*xGHz, ...
|
||||
'DisplayName','AIR DB tgt.', ...
|
||||
mk.DB{:}, 'LineStyle','-','LineWidth',LINE_WIDTH,'Color',cm.DB);
|
||||
|
||||
% ylim([log2(M)-1, log2(M)]);
|
||||
xlabel('Baudrate in GBd');
|
||||
ylabel('AIR in Gbps');
|
||||
set(gca, 'XTick', xticks_vals(1:2:end), 'XTickLabel', xtick_labels(1:2:end));
|
||||
grid on;
|
||||
legend('Location','best');
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
% ---------------- FIGURE 15 : Information Rates ----------------
|
||||
tp = TransmissionPerformance;
|
||||
|
||||
|
||||
m = floor(log2(M)*10)/10;
|
||||
figure(213+M); clf; hold on;
|
||||
|
||||
netrates_vnle = tp.calculateNetRate(baudrate.* m, ...
|
||||
'NGMI', GMI_VNLE./m, ...
|
||||
'BER', BER_VNLE);
|
||||
%
|
||||
% plot(xGHz, GMI_VNLE.*xGHz, ...
|
||||
% 'DisplayName','GMI*R VNLE', ...
|
||||
% mk.VNLE{:}, 'LineStyle','-','LineWidth',LINE_WIDTH,'Color',cm.VNLE);
|
||||
%
|
||||
% plot(xGHz, netrates_vnle.SDHD.NetRate.*1e-9, ...
|
||||
% 'DisplayName','SD+HD VNLE', ...
|
||||
% mk.VNLE{:}, 'LineStyle',':','LineWidth',LINE_WIDTH,'Color',cm.VNLE);
|
||||
% plot(xGHz, netrates_vnle.HD.NetRate.*1e-9, ...
|
||||
% 'DisplayName','Staircase VNLE', ...
|
||||
% mk.VNLE{:}, 'LineStyle','-.','LineWidth',LINE_WIDTH,'Color',cm.VNLE);
|
||||
%
|
||||
%
|
||||
% %
|
||||
% % MLSE symbol-wise (if present)
|
||||
% plot(xGHz, GMI_MLSE.*xGHz, ...
|
||||
% 'DisplayName','GMI*R MLSE', ...
|
||||
% mk.MLSE{:}, 'LineStyle','-','LineWidth',LINE_WIDTH,'Color',cm.MLSE);
|
||||
%
|
||||
% netrates_mlse = tp.calculateNetRate(baudrate.* m, ...
|
||||
% 'NGMI', GMI_MLSE./m, ...
|
||||
% 'BER', BER_MLSE);
|
||||
% plot(xGHz, netrates_mlse.SDHD.NetRate.*1e-9, ...
|
||||
% 'DisplayName','SD+HD MLSE', ...
|
||||
% mk.MLSE{:}, 'LineStyle',':','LineWidth',LINE_WIDTH,'Color',cm.MLSE);
|
||||
% plot(xGHz, netrates_mlse.HD.NetRate.*1e-9, ...
|
||||
% 'DisplayName','Staircase MLSE', ...
|
||||
% mk.MLSE{:}, 'LineStyle','-.','LineWidth',LINE_WIDTH,'Color',cm.MLSE);
|
||||
|
||||
|
||||
% duobinary has only one GMI curve (DB output)
|
||||
figure(1111); clf; hold on;
|
||||
plot(xGHz, GMI_DB.*xGHz, ...
|
||||
'DisplayName','GMI*R DB tgt.', ...
|
||||
mk.DB{:}, 'LineStyle','-','LineWidth',LINE_WIDTH,'Color',cm.DB);
|
||||
|
||||
netrates_db = tp.calculateNetRate(baudrate.* m, ...
|
||||
'NGMI', GMI_DB./m, ...
|
||||
'BER', BER_DB_PREC);
|
||||
|
||||
plot(xGHz, netrates_db.SDHD.NetRate.*1e-9, ...
|
||||
'DisplayName','SD+HD DB', ...
|
||||
mk.DB{:}, 'LineStyle',':','LineWidth',LINE_WIDTH,'Color',cm.DB);
|
||||
plot(xGHz, netrates_db.STAIR.NetRate.*1e-9, ...
|
||||
'DisplayName','Staircase DB', ...
|
||||
mk.DB_precode{:}, 'LineStyle','-.','LineWidth',LINE_WIDTH,'Color',cm.DB_precode);
|
||||
plot(xGHz, netrates_db.O_FEC.NetRate.*1e-9, ...
|
||||
'DisplayName','O-FEC DB', ...
|
||||
mk.DB_precode{:}, 'LineStyle','--','LineWidth',LINE_WIDTH,'Color',cm.DB_precode);
|
||||
plot(xGHz, netrates_db.KP4_hamming.NetRate.*1e-9, ...
|
||||
'DisplayName','KP4 Hamming DB', ...
|
||||
mk.DB_precode{:}, 'LineStyle',':','LineWidth',LINE_WIDTH,'Color',cm.DB_precode);
|
||||
|
||||
% ylim([log2(M)-1, log2(M)]);
|
||||
xlabel('Baudrate in GBd');
|
||||
ylabel('AIR in Gbps');
|
||||
set(gca, 'XTick', xticks_vals(1:2:end), 'XTickLabel', xtick_labels(1:2:end));
|
||||
grid on;
|
||||
legend('Location','best');
|
||||
% xlim([1, 256])
|
||||
|
||||
|
||||
|
||||
figure(2222); clf; hold on;
|
||||
plot(xGHz, GMI_MLSE.*xGHz, ...
|
||||
'DisplayName','GMI*R DB tgt.', ...
|
||||
mk.MLSE{:}, 'LineStyle','-','LineWidth',LINE_WIDTH,'Color',cm.MLSE);
|
||||
|
||||
netrates_mlse = tp.calculateNetRate(baudrate.* m, ...
|
||||
'NGMI', GMI_MLSE./m, ...
|
||||
'BER', BER_MLSE);
|
||||
|
||||
plot(xGHz, netrates_mlse.SDHD.NetRate.*1e-9, ...
|
||||
'DisplayName','SD+HD DB', ...
|
||||
mk.MLSE{:}, 'LineStyle',':','LineWidth',LINE_WIDTH,'Color',cm.MLSE);
|
||||
plot(xGHz, netrates_mlse.STAIR.NetRate.*1e-9, ...
|
||||
'DisplayName','Staircase DB', ...
|
||||
mk.VNLE{:}, 'LineStyle','-.','LineWidth',LINE_WIDTH,'Color',cm.VNLE);
|
||||
plot(xGHz, netrates_mlse.O_FEC.NetRate.*1e-9, ...
|
||||
'DisplayName','O-FEC DB', ...
|
||||
mk.VNLE{:}, 'LineStyle','--','LineWidth',LINE_WIDTH,'Color',cm.VNLE);
|
||||
plot(xGHz, netrates_mlse.KP4_hamming.NetRate.*1e-9, ...
|
||||
'DisplayName','KP4 Hamming DB', ...
|
||||
mk.VNLE{:}, 'LineStyle',':','LineWidth',LINE_WIDTH,'Color',cm.VNLE);
|
||||
|
||||
% ylim([log2(M)-1, log2(M)]);
|
||||
xlabel('Baudrate in GBd');
|
||||
ylabel('AIR in Gbps');
|
||||
set(gca, 'XTick', xticks_vals(1:2:end), 'XTickLabel', xtick_labels(1:2:end));
|
||||
grid on;
|
||||
legend('Location','best');
|
||||
% xlim([1, 256])
|
||||
|
||||
|
||||
|
||||
figure(3333); clf; hold on;
|
||||
plot(xGHz, GMI_VNLE.*xGHz, ...
|
||||
'DisplayName','GMI*R DB tgt.', ...
|
||||
mk.MLSE{:}, 'LineStyle','-','LineWidth',LINE_WIDTH,'Color',cm.MLSE);
|
||||
|
||||
netrates_vnle = tp.calculateNetRate(baudrate.* m, ...
|
||||
'NGMI', GMI_VNLE./m, ...
|
||||
'BER', BER_VNLE);
|
||||
|
||||
plot(xGHz, netrates_vnle.SDHD.NetRate.*1e-9, ...
|
||||
'DisplayName','SD+HD DB', ...
|
||||
mk.MLSE{:}, 'LineStyle',':','LineWidth',LINE_WIDTH,'Color',cm.MLSE);
|
||||
plot(xGHz, netrates_vnle.STAIR.NetRate.*1e-9, ...
|
||||
'DisplayName','Staircase DB', ...
|
||||
mk.VNLE{:}, 'LineStyle','-.','LineWidth',LINE_WIDTH,'Color',cm.VNLE);
|
||||
plot(xGHz, netrates_vnle.O_FEC.NetRate.*1e-9, ...
|
||||
'DisplayName','O-FEC DB', ...
|
||||
mk.VNLE{:}, 'LineStyle','--','LineWidth',LINE_WIDTH,'Color',cm.VNLE);
|
||||
plot(xGHz, netrates_vnle.KP4_hamming.NetRate.*1e-9, ...
|
||||
'DisplayName','KP4 Hamming DB', ...
|
||||
mk.VNLE{:}, 'LineStyle',':','LineWidth',LINE_WIDTH,'Color',cm.VNLE);
|
||||
|
||||
% ylim([log2(M)-1, log2(M)]);
|
||||
xlabel('Baudrate in GBd');
|
||||
ylabel('AIR in Gbps');
|
||||
set(gca, 'XTick', xticks_vals(1:2:end), 'XTickLabel', xtick_labels(1:2:end));
|
||||
grid on;
|
||||
legend('Location','best');
|
||||
% xlim([1, 256])
|
||||
@@ -0,0 +1,236 @@
|
||||
|
||||
precomp_mode = 0;
|
||||
precomp_path = "C:\Users\Silas\Documents\MATLAB\imdd_simulation\projects\HighSpeedExperiment_2024\Auswertung_JLT";
|
||||
precomp_fn = "precomp_simulated.mat";
|
||||
|
||||
% TX
|
||||
M = 4;
|
||||
fsym = 72e9;
|
||||
f_nyquist = fsym/2;
|
||||
apply_pulsef = 1;
|
||||
fdac = 256e9;
|
||||
fadc = 256e9;
|
||||
% fdac = 2*fsym;
|
||||
% fadc = 2*fsym;
|
||||
random_key = 1;
|
||||
|
||||
duob_mode = db_mode.no_db;
|
||||
|
||||
tx_bwl = 0.8.*f_nyquist;
|
||||
rx_bwl = 0.8.*f_nyquist;
|
||||
|
||||
rcalpha = 0.05;
|
||||
kover = 16;
|
||||
vbias_rel = 0.5;
|
||||
u_pi = 2.9;
|
||||
vbias = -vbias_rel*u_pi;
|
||||
laser_wavelength = 1293;
|
||||
laser_linewidth = 0;
|
||||
|
||||
|
||||
% Channel
|
||||
link_length = 60000;
|
||||
|
||||
% RX
|
||||
rop = -8;
|
||||
|
||||
% EQ
|
||||
eq_mode = equalizer_structure.vnle_pf_mlse;
|
||||
ffe_order=[50,0,0];
|
||||
vnle_order=[50,5,5];
|
||||
dfe_order = [0 0 0];
|
||||
|
||||
len_tr = 4096*2;
|
||||
mu_ffe = [0.0004 0.0004 0.0004];
|
||||
mu_dfe = 0.0004;
|
||||
mu_dc = 0.00;
|
||||
|
||||
dfe_ = sum(dfe_order)>0;
|
||||
|
||||
Pform = Pulseformer("fsym",fsym,"fdac",4*fsym,"pulse","rc","pulselength",16,"alpha",rcalpha);
|
||||
|
||||
[Digi_sig,Symbols,Tx_bits] = PAMsource(...
|
||||
"fsym",fsym,"M",M,"order",18,"useprbs",0,...
|
||||
"fs_out",fdac,...
|
||||
"applyclipping",0,"clipfactor",1.5,...
|
||||
"applypulseform",apply_pulsef,"pulseformer",Pform,...
|
||||
"randkey",random_key,...
|
||||
"duobinary_mode",duob_mode).process();
|
||||
|
||||
if precomp_mode == 1 % measure channel
|
||||
precomp_est = ChannelFreqResp("Nacq",1024,"Navg",64,"Ncp",63,'f_ref',fdac);
|
||||
Digi_sig = precomp_est.buildOFDM();
|
||||
elseif precomp_mode == 2 % apply precomp
|
||||
precomp_est = ChannelFreqResp("Nacq",1024,"Navg",64,"Ncp",63,'f_ref',Digi_sig.fs);
|
||||
Digi_sig = precomp_est.precomp(Digi_sig,'maxampdb',-50,'loadPath',precomp_path,'fileName',precomp_fn);
|
||||
end
|
||||
|
||||
% Symbols.spectrum("displayname",'Tx Symbols','fignum',10,'normalizeTo0dB',1);
|
||||
|
||||
Digi_sig.eye(fsym,M,"fignum",1234567);
|
||||
%%%%% AWG
|
||||
%El_sig = M8199B("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 = El_sig.setPower(0,"dBm");
|
||||
El_sig.spectrum("displayname",'Tx Signal','fignum',10,'normalizeTo0dB',0);
|
||||
%%%%% Low-pass el. components %%%%%%
|
||||
|
||||
El_sig = Filter('filtdegree',4,"f_cutoff",tx_bwl,"fs",fdac*kover,"filterType",filtertypes.gaussian,"active",true).process(El_sig);
|
||||
% El_sig.spectrum("displayname",'Digi Spectrum','fignum',100,'normalizeTo0dB',1);
|
||||
|
||||
%%%%% Electrical Driver Amplifier %%%%%%
|
||||
El_sig = Amplifier("amp_mode","ideal_no_noise","gain_mode","gain","amplification_db",3).process(El_sig);
|
||||
El_sig = El_sig.normalize("mode","oneone");
|
||||
|
||||
%%%%% MODULATE E/O CONVERSION %%%%%%
|
||||
[Opt_sig] = EML("mode",eml_mode.im_cosinus,"power",3,"fsimu",El_sig.fs,"lambda",laser_wavelength,"bias",vbias,"u_pi",u_pi,"linewidth",laser_linewidth,"randomkey",random_key+1).process(El_sig);
|
||||
|
||||
Opt_sig = Fiber("fsimu",Opt_sig.fs,"fiber_length",link_length/1000,"alpha",0.3,"D",0,"lambda0",1310,"gamma",0,"Dslope",0.07).process(Opt_sig);
|
||||
|
||||
%%%%%% ROP %%%%%%
|
||||
Rx_sig = Amplifier("amp_mode","ideal_no_noise","gain_mode","output_power","amplification_db",rop).process(Opt_sig);
|
||||
|
||||
%%%%%% PD Square Law %%%%%%
|
||||
Rx_sig = Photodiode("fsimu",fdac*kover,"dark_current",2e-08,"responsivity",1,"temperature",20,"nep",1.8e-11).process(Rx_sig);
|
||||
|
||||
%%%%%% Low-pass RX (PD, El. Connectors and Scope %%%%%%
|
||||
Rx_sig = Filter('filtdegree',4,"f_cutoff",rx_bwl,"fs",fdac*kover,"filterType",filtertypes.bessel_inp,"active",true).process(Rx_sig);
|
||||
|
||||
% %%%%%% Low-pass Scope %%%%%%
|
||||
Lp_scpe = Filter('filtdegree',4,"f_cutoff",35e9,"fs",fadc,"filterType",filtertypes.butterworth,"active",true);
|
||||
|
||||
% Rx_sig.spectrum("displayname",'Analog Rx Spectrum','fignum',100,'normalizeTo0dB',1);
|
||||
|
||||
%%%%%% Scope %%%%%%
|
||||
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);
|
||||
|
||||
Scpe_sig.spectrum("displayname",'Rx Signal','fignum',10,'normalizeTo0dB',1);
|
||||
Scpe_sig.eye(fsym,M,"fignum",1973763)
|
||||
|
||||
%%%%% Precompensation Routine %%%%%%
|
||||
if precomp_mode == 1
|
||||
Scpe_sig_resampled = Scpe_sig.resample("fs_in",fadc,"fs_out",2*fsym);
|
||||
precomp_est.estimate(Scpe_sig_resampled,"save",false,"savePath",precomp_path,"fileName",precomp_fn);
|
||||
precomp_est.plot();
|
||||
precomp_est.save();
|
||||
end
|
||||
|
||||
% Preprocess signal
|
||||
Scpe_sig = preprocessSignal(Scpe_sig, Symbols, fsym);
|
||||
Scpe_sig.signal = Scpe_sig.signal(1:2*Symbols.length);
|
||||
use_ffe = 0;
|
||||
use_dfe = 0;
|
||||
use_vnle_mlse = 1;
|
||||
use_dbtgt = 1;
|
||||
use_dbenc = 1;
|
||||
|
||||
|
||||
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',1,...
|
||||
"postFFE",[],...
|
||||
"eth_style_symbol_mapping",0);
|
||||
|
||||
disp('FFE:')
|
||||
ffe_results.metrics.print;
|
||||
|
||||
|
||||
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);
|
||||
|
||||
disp('DFE:')
|
||||
dfe_results.metrics.print;
|
||||
|
||||
|
||||
end
|
||||
|
||||
if use_vnle_mlse
|
||||
|
||||
if 0
|
||||
pf_ncoeffs = 1;
|
||||
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);
|
||||
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);
|
||||
|
||||
[ffe_results, mlse_results] = vnle_postfilter_mlse(eq_, pf_, mlse_, M, Scpe_sig, Symbols, Tx_bits, ...
|
||||
"precode_mode", duob_mode,...
|
||||
'showAnalysis', 1, ...
|
||||
"postFFE", [],...
|
||||
"eth_style_symbol_mapping", 0);
|
||||
|
||||
disp('VNLE:')
|
||||
ffe_results.metrics.print;
|
||||
disp('MLSE:')
|
||||
mlse_results.metrics.print;
|
||||
end
|
||||
|
||||
pf_ncoeffs = 2;
|
||||
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);
|
||||
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);
|
||||
|
||||
[ffe_results, mlse_results] = vnle_postfilter_mlse(eq_, pf_, mlse_, M, Scpe_sig, Symbols, Tx_bits, ...
|
||||
"precode_mode", duob_mode,...
|
||||
'showAnalysis', 1, ...
|
||||
"postFFE", [],...
|
||||
"eth_style_symbol_mapping", 0);
|
||||
|
||||
disp('VNLE:')
|
||||
ffe_results.metrics.print;
|
||||
disp('MLSE:')
|
||||
mlse_results.metrics.print;
|
||||
|
||||
|
||||
end
|
||||
|
||||
if use_dbtgt
|
||||
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);
|
||||
|
||||
mlse_db_ = MLSE("DIR",[1,1],"duobinary_output",0,"M",M,"trellis_states",PAMmapper(M,0).levels);
|
||||
|
||||
dbt_results = duobinary_target(eq_, mlse_db_, M, Scpe_sig, Symbols, Tx_bits, ...
|
||||
"precode_mode", duob_mode, ...
|
||||
'showAnalysis',1 ,...
|
||||
"postFFE", []);
|
||||
|
||||
disp('DB:')
|
||||
dbt_results.metrics.print;
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
if duob_mode == db_mode.db_encoded
|
||||
|
||||
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);
|
||||
|
||||
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",1,"postFFE",[]);
|
||||
|
||||
db_results.metrics.print;
|
||||
end
|
||||
118
projects/HighSpeedExperiment_2024/a_minimal_example.m
Normal file
118
projects/HighSpeedExperiment_2024/a_minimal_example.m
Normal file
@@ -0,0 +1,118 @@
|
||||
|
||||
|
||||
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);
|
||||
|
||||
|
||||
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);
|
||||
|
||||
% Show spectrum
|
||||
Scpe_sig.spectrum("fignum",1,"displayname",'Rx')
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
%% simple FFE
|
||||
|
||||
mu_ffe = [0.0001, 0.0008, 0.001];
|
||||
mu_dfe = 0.0004;
|
||||
ffe_order = [50, 0, 0];
|
||||
eq_dfe = EQ("Ne",ffe_order,"Nb",[0,0,0],"training_length",4096,"training_loops",5,"dd_loops",5,"K",2,"DCmu",0.005,"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);
|
||||
|
||||
|
||||
ffe_results.metrics.print("description",'FFE');
|
||||
ffe_results.config.equalizer_structure = "ffe";
|
||||
|
||||
%% a) VNLE // b) concatenated VNLE + MLSE
|
||||
|
||||
pf_ncoeffs = 1;
|
||||
ffe_order = [50, 5, 5];
|
||||
dfe_order = [0,0,0];
|
||||
eq_ = EQ("Ne",ffe_order,"Nb",dfe_order,"training_length",4096,"training_loops",5,"dd_loops",5,"K",2,"DCmu",0.005,"DDmu",[mu_ffe mu_dfe],"DFEmu",0.005,"FFEmu",0,"plotfinal",0,"ideal_dfe",0);
|
||||
pf_ = Postfilter("ncoeff",pf_ncoeffs,"useBurg",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
|
||||
|
||||
%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);
|
||||
|
||||
[vnle_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);
|
||||
|
||||
vnle_results.metrics.print("description",'VNLE');
|
||||
mlse_results.metrics.print("description",'VNLE + PF + MLSE');
|
||||
|
||||
|
||||
%% Duobinary Equalization
|
||||
|
||||
|
||||
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);
|
||||
|
||||
ffe_order = [50, 5, 5];
|
||||
dfe_order = [0,0,0];
|
||||
eq_ = EQ("Ne",ffe_order,"Nb",dfe_order,"training_length",4096,"training_loops",5,"dd_loops",5,"K",2,"DCmu",0.005,"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("description",'Duobinary EQ');
|
||||
|
||||
%% Ml based Viterbi
|
||||
|
||||
%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);
|
||||
|
||||
ml_mlse_results.metrics.print("description",'ML pre Eq. + Viterbi')
|
||||
181
projects/IMDD_base_system/model_linewidth_evaluation.m
Normal file
181
projects/IMDD_base_system/model_linewidth_evaluation.m
Normal file
@@ -0,0 +1,181 @@
|
||||
%%% Run parameters
|
||||
% TX
|
||||
M = 4;
|
||||
|
||||
apply_pulsef = 1;
|
||||
fdac = 256e9;
|
||||
fadc = 256e9;
|
||||
random_key = 2;
|
||||
|
||||
rcalpha = 0.05;
|
||||
kover = 8;
|
||||
vbias_rel = 0.5;
|
||||
u_pi = 3.2;
|
||||
vbias = -vbias_rel*u_pi;
|
||||
laser_wavelength = 1300;
|
||||
laser_linewidth = logspace(0,6.2,24);
|
||||
|
||||
% Channel
|
||||
link_length = 10;
|
||||
|
||||
alpha = 0;
|
||||
|
||||
doub_mode = db_mode.no_db;
|
||||
cols = linspecer(6);
|
||||
rop = [-6];
|
||||
bwl = [0.5:0.1:1.5];
|
||||
fsym = [200:16:256].*1e9;
|
||||
% nonlin_mod = [0.5:0.01:0.75];
|
||||
fsym = ones(size(laser_linewidth)).*fsym(1);
|
||||
nonlin_mod = ones(size(laser_linewidth)).*0.5;
|
||||
|
||||
ffe_results = {};
|
||||
mlse_results_lin= {};
|
||||
|
||||
parfor r = 1:length(laser_linewidth)
|
||||
|
||||
Pform = Pulseformer("fsym",fsym(r),"fdac",4*fsym(r),"pulse","rc","pulselength",16,"alpha",rcalpha);
|
||||
|
||||
db_precode = 0;
|
||||
db_encode = 0;
|
||||
duob_mode = db_mode.no_db;
|
||||
apply_pulsef = 1;
|
||||
|
||||
[Digi_sig,Symbols,Tx_bits] = PAMsource(...
|
||||
"fsym",fsym(r),"M",M,"order",18,"useprbs",1,...
|
||||
"fs_out",fdac,...
|
||||
"applyclipping",0,"clipfactor",1.5,...
|
||||
"applypulseform",apply_pulsef,"pulseformer",Pform,...
|
||||
"randkey",random_key,...
|
||||
"db_precode",db_precode,"db_encode",db_encode,...
|
||||
"mrds_code",0,"mrds_blocklength",512,"duobinary_mode",duob_mode).process();
|
||||
|
||||
El_sig = M8199B("kover",kover).process(Digi_sig);
|
||||
|
||||
%%%%% Electrical Driver Amplifier %%%%%%
|
||||
El_sig = El_sig.normalize("mode","oneone");
|
||||
|
||||
%%%%% MODULATE E/O CONVERSION %%%%%
|
||||
u_pi = 3.2;
|
||||
vbias = -u_pi*nonlin_mod(r);
|
||||
[Opt_sig] = EML("mode",eml_mode.im_cosinus,"power",3,"fsimu",El_sig.fs,"lambda",laser_wavelength,"bias",vbias,"u_pi",u_pi,"linewidth",laser_linewidth(r),"randomkey",random_key+1).process(El_sig);
|
||||
|
||||
%%%%%% Fiber %%%%%%
|
||||
mpi = 1;
|
||||
if mpi
|
||||
Combined_sig = Fiber("fsimu",Opt_sig.fs,"fiber_length",link_length/1000,"alpha",0.3,"D",0,"lambda0",1310,"gamma",0,"Dslope",0.07).process(Opt_sig);
|
||||
else
|
||||
|
||||
% 2) ping pong fiber propagation
|
||||
mpi_path = 00;
|
||||
Interference_sig = Fiber("fsimu",Opt_sig.fs,"fiber_length",mpi_path*2,"alpha",0,"D",0,"lambda0",1310,"gamma",0).process(Opt_sig);
|
||||
|
||||
Interference_sig = Amplifier("amp_mode","ideal_no_noise","gain_mode","gain","amplification_db",-30).process(Interference_sig);
|
||||
|
||||
[Main_sig,dly] = Opt_sig.delay("delay_meter",mpi_path*2);
|
||||
|
||||
% Add
|
||||
Combined_sig = Main_sig + Interference_sig;
|
||||
|
||||
% Cut (due to the delays there is a jump in the signals)
|
||||
if dly == 0;dly = 1;end
|
||||
Combined_sig.signal = Combined_sig.signal(ceil(dly):end);
|
||||
|
||||
% Fiber
|
||||
Combined_sig = Fiber("fsimu",Combined_sig.fs,"fiber_length",2,"alpha",0.3,"D",0,"lambda0",1310,"gamma",0,"Dslope",0.08).process(Combined_sig);
|
||||
end
|
||||
|
||||
|
||||
%%%%%% ROP %%%%%%
|
||||
Opt_sig = Amplifier("amp_mode","ideal_no_noise","gain_mode","output_power","amplification_db",rop).process(Combined_sig);
|
||||
|
||||
%%%%%% PD Square Law %%%%%%
|
||||
PD_sig = Photodiode("fsimu",fdac*kover,"dark_current",2e-08,"responsivity",1,"temperature",20,"nep",1.8e-11,"randomkey",random_key).process(Opt_sig);
|
||||
|
||||
%%%%%% Low-pass RX (PD, El. Connectors and Scope %%%%%%
|
||||
rx_bwl = 70e9;
|
||||
PD_sig = Filter('filtdegree',4,"f_cutoff",rx_bwl,"fs",fdac*kover,"filterType",filtertypes.butterworth,"active",true).process(PD_sig);
|
||||
|
||||
% %%%%%% Low-pass Scope %%%%%%
|
||||
Lp_scpe = Filter('filtdegree',4,"f_cutoff",110e9,"fs",fadc,"filterType",filtertypes.butterworth,"active",true);
|
||||
|
||||
%%%%%% Scope %%%%%%
|
||||
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(PD_sig);
|
||||
|
||||
Scpe_sig_2sps = Scpe_sig.resample("fs_out",2*fsym(r));
|
||||
% Symbols.signal = Symbols.signal(1:Scpe_sig_2sps.length/2);
|
||||
|
||||
% 2sps
|
||||
[~, Scpe_cell, ~, found_sync] = Scpe_sig_2sps.tsynch("reference", Symbols, "fs_ref", fsym(r), "debug_plots", 0);
|
||||
Rx_sig_2sps = Scpe_cell{1};
|
||||
Rx_sig_2sps = Rx_sig_2sps.normalize("mode","rms");
|
||||
|
||||
% 1sps
|
||||
Scpe_sig_1sps = Scpe_sig.resample("fs_out",1*fsym(r));
|
||||
|
||||
[~, Scpe_cell_1sps, ~, found_sync] = Scpe_sig_1sps.tsynch("reference", Symbols, "fs_ref", fsym(r), "debug_plots", 0);
|
||||
Rx_sig_1sps = Scpe_cell_1sps{1};
|
||||
Rx_sig_1sps = Rx_sig_1sps.normalize("mode","rms");
|
||||
|
||||
|
||||
%% RUN DSP
|
||||
len_tr = 4096*2;
|
||||
|
||||
mu_ffe1 = 0.0001;
|
||||
mu_ffe2 = 0.0008;
|
||||
mu_ffe3 = 0.001;
|
||||
mu_dc = 0.005;
|
||||
% mu_dc = 0;
|
||||
|
||||
mu_ffe = [mu_ffe1 mu_ffe2 mu_ffe3];
|
||||
mu_dfe = 0.0004;
|
||||
pf_ncoeffs = 1;
|
||||
ffe_order = [50, 3, 3];
|
||||
mu_lms = 0.0005;
|
||||
eq_ = FFE("epochs_tr",5,"epochs_dd",5,"len_tr",2^13,"mu_dd",mu_lms,"mu_tr",mu_lms,"order",50,"sps",2,"dd_mode",1,"adaption_technique","lms");
|
||||
% eq_ = EQ("Ne",ffe_order,"Nb",[0,0,0],"training_length",len_tr,"training_loops",5,"dd_loops",5,"K",1,"DCmu",0.00,"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).levels,'scale_mode',0,'trellis_exclusion',0,'trellis_state_mode',2,'debug',0);
|
||||
|
||||
[ffe_results{r}, mlse_results_lin{r}] = vnle_postfilter_mlse(eq_, pf_, mlse_, M, Rx_sig_2sps, Symbols, Tx_bits, ...
|
||||
"precode_mode", duob_mode,...
|
||||
'showAnalysis', 0, ...
|
||||
"postFFE", [],...
|
||||
"eth_style_symbol_mapping", 0);
|
||||
|
||||
|
||||
ffe_results{r}.metrics.print;
|
||||
mlse_results_lin{r}.metrics.print;
|
||||
|
||||
end
|
||||
|
||||
|
||||
figure(1);hold on;
|
||||
plot(laser_linewidth.*1e-6,cellfun(@(x) x.metrics.BER, ffe_results),'DisplayName','VNLE')
|
||||
plot(laser_linewidth.*1e-6,cellfun(@(x) x.metrics.BER, mlse_results_lin),'DisplayName','VNLE+MLSE')
|
||||
xlabel('Linewidth [GHz]');
|
||||
ylabel('BER')
|
||||
set(gca,'YScale','log');
|
||||
legend;
|
||||
ylim([1e-5 1e-1]);
|
||||
beautifyBERplot;
|
||||
|
||||
figure();hold on;
|
||||
plot(laser_linewidth.*1e-6,cellfun(@(x) x.metrics.AIR.*1e-9, ffe_results),'DisplayName','FFE')
|
||||
plot(laser_linewidth.*1e-6,cellfun(@(x) x.metrics.AIR.*1e-9, mlse_results_lin),'DisplayName','FFE+MLSE')
|
||||
xlabel('Linewidth [GHz]');
|
||||
ylabel('AIR [GBd]')
|
||||
% set(gca,'YScale','log');
|
||||
legend;
|
||||
beautifyBERplot("logscale",0);
|
||||
|
||||
figure(); hold on
|
||||
stem(calcWavelengthPlan(16,400e9,1310),ones(16,1),'DisplayName','16x400','Marker','.','LineWidth',1);
|
||||
stem(calcWavelengthPlan(8,800e9,1310),ones(8,1),'DisplayName','8x800','Marker','.','LineWidth',1);
|
||||
stem(calcWavelengthPlan(16,800e9,1310),ones(16,1),'DisplayName','16x800','Marker','.','LineWidth',1);
|
||||
ylim([0,1.2]);
|
||||
ylabel('wavelength [nm]');
|
||||
xlim([1270, 1350])
|
||||
569
projects/IMDD_base_system/simulation_bwl.m
Normal file
569
projects/IMDD_base_system/simulation_bwl.m
Normal file
@@ -0,0 +1,569 @@
|
||||
%%% Run parameters
|
||||
% TX
|
||||
M = 4;
|
||||
m = floor(log2(M)*10)/10;
|
||||
fsym = 224e9;
|
||||
|
||||
apply_pulsef = 1;
|
||||
fdac = 256e9;
|
||||
fadc = 256e9;
|
||||
random_key = 2;
|
||||
|
||||
rcalpha = 0.05;
|
||||
kover = 8;
|
||||
vbias_rel = 0.5;
|
||||
u_pi = 3.2;
|
||||
vbias = -vbias_rel*u_pi;
|
||||
laser_wavelength = 1310;
|
||||
laser_linewidth = 1e6;
|
||||
|
||||
|
||||
% Channel
|
||||
link_length = 0;
|
||||
|
||||
vnle_order1 = 50;
|
||||
vnle_order2 = 0;
|
||||
vnle_order3 = 0;
|
||||
|
||||
vnle_order=[vnle_order1,vnle_order2,vnle_order3];
|
||||
dfe_order = [0 0 0];
|
||||
|
||||
alpha = 0;
|
||||
|
||||
len_tr = 4096*2;
|
||||
|
||||
mu_ffe1 = 0.0001;
|
||||
mu_ffe2 = 0.0008;
|
||||
mu_ffe3 = 0.001;
|
||||
mu_dc = 0.005;
|
||||
% mu_dc = 0;
|
||||
|
||||
mu_ffe = [mu_ffe1 mu_ffe3 mu_ffe3];
|
||||
mu_dfe = 0.0004;
|
||||
|
||||
dfe_ = sum(dfe_order)>0;
|
||||
|
||||
doub_mode = db_mode.no_db;
|
||||
cols = linspecer(6);
|
||||
rop = [-6];
|
||||
bwl = [0.5:0.1:1.5];
|
||||
fsym = [192:16:256].*1e9;
|
||||
fsym = 208e9;
|
||||
|
||||
ber_vnle = [];
|
||||
ber_mlse = [];
|
||||
ber_mlse_burg = [];
|
||||
ber_viterbi = [];
|
||||
ber_db = [];
|
||||
ber_db_diff_precoded = [];
|
||||
gmi_vnle_bitwise = [];
|
||||
gmi_mlse = [];
|
||||
gmi_mlse_db = [];
|
||||
|
||||
for r = 1:length(fsym)
|
||||
|
||||
Pform = Pulseformer("fsym",fsym(r),"fdac",4*fsym(r),"pulse","rc","pulselength",16,"alpha",rcalpha);
|
||||
|
||||
db_precode = 0;
|
||||
db_encode = 0;
|
||||
duob_mode = db_mode.no_db;
|
||||
apply_pulsef = 1;
|
||||
|
||||
[Digi_sig,Symbols,Tx_bits] = PAMsource(...
|
||||
"fsym",fsym(r),"M",M,"order",19,"useprbs",0,...
|
||||
"fs_out",fdac,...
|
||||
"applyclipping",0,"clipfactor",1.5,...
|
||||
"applypulseform",apply_pulsef,"pulseformer",Pform,...
|
||||
"randkey",random_key,...
|
||||
"db_precode",db_precode,"db_encode",db_encode,...
|
||||
"mrds_code",0,"mrds_blocklength",512,"duobinary_mode",duob_mode).process();
|
||||
|
||||
% El_sig = AWG("fdac",fdac,"f_cutoff",fsym(r),"lpf_active",0,"kover",kover,"bit_resolution",12,"upsampling_method","samplehold","precomp_sinc_rolloff",0).process(Digi_sig);
|
||||
El_sig = M8199B("kover",kover).process(Digi_sig);
|
||||
% AWG("fdac",fdac,"f_cutoff",fsym(r),"lpf_active",0,"kover",kover,"bit_resolution",12,"upsampling_method","samplehold","precomp_sinc_rolloff",0).process(Digi_sig);
|
||||
|
||||
%%%%% Low-pass el. components %%%%%%
|
||||
% tx_bwl = 100e9;
|
||||
% El_sig = Filter('filtdegree',3,"f_cutoff",tx_bwl,"fs",fdac*kover,"filterType",filtertypes.butterworth,"active",true).process(El_sig);
|
||||
|
||||
%%%%% Electrical Driver Amplifier %%%%%%
|
||||
El_sig = El_sig.normalize("mode","oneone");
|
||||
% El_sig = El_sig.setPower(1,"dBm");
|
||||
% figure;histogram(El_sig.signal);
|
||||
|
||||
%%%%% MODULATE E/O CONVERSION %%%%%
|
||||
u_pi = 3.2;
|
||||
vbias = -u_pi*0.5;
|
||||
[Opt_sig] = EML("mode",eml_mode.im_cosinus,"power",3,"fsimu",El_sig.fs,"lambda",laser_wavelength,"bias",vbias,"u_pi",u_pi,"linewidth",laser_linewidth,"randomkey",random_key+1).process(El_sig);
|
||||
|
||||
if 0
|
||||
figure(15);
|
||||
hold on
|
||||
scatter(El_sig.signal(1:100000)+vbias,(abs(Opt_sig.signal(1:100000)).^2)*1e3,0.1,'.','DisplayName','Modulator TF')
|
||||
xlabel('Input in V')
|
||||
ylabel('abs(Eopt)2 in mW','Interpreter','latex')
|
||||
ylim([0 2]);
|
||||
xlim([-3.2 0]);
|
||||
|
||||
Opt_sig.eye(fsym(r),M,"fignum",103837);
|
||||
end
|
||||
|
||||
%%%%%% Fiber %%%%%%
|
||||
Opt_sig = Fiber("fsimu",Opt_sig.fs,"fiber_length",link_length/1000,"alpha",0.3,"D",0,"lambda0",1310,"gamma",0,"Dslope",0.07).process(Opt_sig);
|
||||
|
||||
%%%%%% ROP %%%%%%
|
||||
Opt_sig = Amplifier("amp_mode","ideal_no_noise","gain_mode","output_power","amplification_db",rop).process(Opt_sig);
|
||||
|
||||
% Opt_sig.eye(fsym(r),M,"fignum",103838);
|
||||
|
||||
% % Opt_sig.signal = Opt_sig.signal + 5*abs(mean(Opt_sig.signal));
|
||||
% Opt_sig.move_it_spectrum("displayname",'Opt Sig after Amp','fignum',1223323);
|
||||
% Pc = abs(mean(Opt_sig.signal)).^2; % carrier power
|
||||
% Ptot = mean(abs(Opt_sig.signal).^2); % total power
|
||||
% Ps = max(Ptot - Pc, eps);
|
||||
% Pcdb = 10*log10(Pc);
|
||||
% Psdb = 10*log10(Ps);
|
||||
%
|
||||
% cspr_dB = 10*log10(Pc / Ps);
|
||||
%
|
||||
% % Minimal in-place CSPR set (real, nonnegative field constraint)
|
||||
% E = Opt_sig.signal; % real field samples
|
||||
% target_cspr_dB = 20; % <-- set your target CSPR (dB)
|
||||
%
|
||||
% % Decompose into DC + zero-mean waveform
|
||||
% m = mean(E);
|
||||
% x0 = E - m; % zero-mean modulation
|
||||
% Ps0 = mean(x0.^2); % sideband power (fixed if shape kept)
|
||||
%
|
||||
% % Current CSPR (for reference)
|
||||
% Pc_cur = m^2;
|
||||
% Ptot_cur = mean(E.^2);
|
||||
% Ps_cur = max(Ptot_cur - Pc_cur, eps);
|
||||
% cspr_in = 10*log10(Pc_cur / Ps_cur);
|
||||
%
|
||||
% % Bias needed for target CSPR, and minimal bias to keep E>=0
|
||||
% R_tgt = 10^(target_cspr_dB/10); % Pc/Ps
|
||||
% a_req = sqrt(R_tgt * Ps0); % required DC bias
|
||||
% a_min = -min(x0); % to avoid negatives everywhere
|
||||
% a = max(a_req, a_min); % if infeasible, lands at CSPR_min
|
||||
%
|
||||
% % Apply bias (preserves waveform shape)
|
||||
% E_new = a + x0;
|
||||
%
|
||||
% % Achieved CSPR
|
||||
% Pc_new = mean(E_new)^2;
|
||||
% Ptot_new = mean(E_new.^2);
|
||||
% Ps_new = max(Ptot_new - Pc_new, eps);
|
||||
% cspr_out = 10*log10(Pc_new / Ps_new);
|
||||
%
|
||||
% % (Optional) show feasibility info
|
||||
% cspr_min = 10*log10((a_min^2)/max(Ps0,eps));
|
||||
% disp(table(cspr_in, target_cspr_dB, cspr_min, cspr_out));
|
||||
%
|
||||
% % Use E_new as your adjusted field
|
||||
% Opt_sig.signal = E_new;
|
||||
|
||||
%%%%%% PD Square Law %%%%%%
|
||||
PD_sig = Photodiode("fsimu",fdac*kover,"dark_current",2e-08,"responsivity",1,"temperature",20,"nep",1.8e-11,"randomkey",random_key).process(Opt_sig);
|
||||
|
||||
%%%%%% Low-pass RX (PD, El. Connectors and Scope %%%%%%
|
||||
rx_bwl = 70e9;
|
||||
PD_sig = Filter('filtdegree',4,"f_cutoff",rx_bwl,"fs",fdac*kover,"filterType",filtertypes.butterworth,"active",true).process(PD_sig);
|
||||
|
||||
% %%%%%% Low-pass Scope %%%%%%
|
||||
Lp_scpe = Filter('filtdegree',4,"f_cutoff",110e9,"fs",fadc,"filterType",filtertypes.butterworth,"active",true);
|
||||
|
||||
%%%%%% Scope %%%%%%
|
||||
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(PD_sig);
|
||||
|
||||
Scpe_sig_2sps = Scpe_sig.resample("fs_out",2*fsym(r));
|
||||
% Scpe_sig_resampled.signal = Scpe_sig_resampled.signal(1:2*length(Symbols));
|
||||
|
||||
[~, Scpe_cell, ~, found_sync] = Scpe_sig_2sps.tsynch("reference", Symbols, "fs_ref", fsym(r), "debug_plots", 0);
|
||||
Rx_sig = Scpe_cell{1};
|
||||
Rx_sig = Rx_sig.normalize("mode","rms");
|
||||
|
||||
if 1
|
||||
%Duobinary Targeting
|
||||
|
||||
eq_ = EQ("Ne",[vnle_order1,vnle_order2,vnle_order3],"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);
|
||||
|
||||
db_ref_sequence = Duobinary().encode(Symbols);
|
||||
db_ref_constellation = unique(db_ref_sequence.signal);
|
||||
[eq_signal, eq_noise] = eq_.process(Rx_sig,db_ref_sequence);
|
||||
|
||||
viterbi = 0;
|
||||
if viterbi
|
||||
mlse_ = MLSE_viterbi("duobinary_output",0,'M',M,'trellis_states',PAMmapper(M,0).levels);
|
||||
mlse_.DIR = [1,1];
|
||||
[eq_signal_whitened] = mlse_.process(eq_signal);
|
||||
else
|
||||
mlse_ = MLSE("DIR",[1,1],"duobinary_output",0,"M",M,"trellis_states",PAMmapper(M,0).get_levels ./ PAMmapper(M,0).get_scaling);
|
||||
mlse_.DIR = [1,1];
|
||||
[eq_signal_whitened,LLR,gmi_mlse_db(r)] = mlse_.process(eq_signal,Symbols);
|
||||
end
|
||||
|
||||
mlse_sig_hd = PAMmapper(M,0,"eth_style",0).quantize(eq_signal_whitened);
|
||||
mlse_sig_hd_precoded = Duobinary().encode(mlse_sig_hd,"M",M);
|
||||
mlse_sig_hd_precoded = Duobinary().decode(mlse_sig_hd_precoded,"M",M);
|
||||
|
||||
tx_symbols_precoded = Duobinary().encode(Symbols);
|
||||
tx_symbols_precoded = Duobinary().decode(tx_symbols_precoded);
|
||||
|
||||
tx_bits_precoded = PAMmapper(M,0,"eth_style",0).demap(tx_symbols_precoded);
|
||||
|
||||
rx_bits_mlse = PAMmapper(M,0,"eth_style",0).demap(mlse_sig_hd_precoded);
|
||||
[~,errors_db_diff_precoded,ber_db_diff_precoded(r),a] = calc_ber(rx_bits_mlse.signal,tx_bits_precoded.signal,"skip_front",100,"skip_end",150,"returnErrorLocation",1);
|
||||
burst_db_pre(r,:) = count_error_bursts(a, 15)./numel(Tx_bits.signal);
|
||||
|
||||
%B) Just determine BER
|
||||
rx_bits_mlse = PAMmapper(M,0,"eth_style",0).demap(mlse_sig_hd);
|
||||
[bits_mlse,errors_db,ber_db(r),a] = calc_ber(rx_bits_mlse.signal,Tx_bits.signal,"skip_front",100,"skip_end",150,"returnErrorLocation",1);
|
||||
burst_db(r,:) = count_error_bursts(a, 15)./numel(Tx_bits.signal);
|
||||
|
||||
fprintf('BER ber_db_diff_precoded: %.2e \n',ber_db_diff_precoded(r));
|
||||
fprintf('BER Vber_dbNLE: %.2e \n',ber_db(r));
|
||||
% figure();hold on;stem(1:15,burst_db(r,:),'LineWidth',1,'Color',cols(1,:));stem(1:15,burst_db_pre(r,:),'LineWidth',1,'Color',cols(2,:));set(gca, 'yscale', 'log');
|
||||
|
||||
end
|
||||
|
||||
|
||||
% FFE or VNLE
|
||||
eq_ = EQ("Ne",[vnle_order1,vnle_order2,vnle_order3],"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.00,"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,"order",[50,2,2],"sps",2,"decide",0);
|
||||
|
||||
[eq_signal_fullresp, eq_noise] = eq_.process(Rx_sig, Symbols);
|
||||
showEQNoisePSD(eq_noise, "fignum",1273876,"displayname",'noise after EQ');
|
||||
[mi_gomez(r)] = calc_air(eq_signal_fullresp, Symbols, "skip_front", 100, "skip_end", 100);
|
||||
[gmi_vnle_bitwise(r)] = calc_ngmi(eq_signal_fullresp,Symbols);
|
||||
[gmi_bitwise_2(r)] = calc_gmi_bitwise(eq_signal_fullresp,Symbols);
|
||||
snr_vnle(r) = calc_snr(Symbols, eq_signal_fullresp-Symbols);
|
||||
|
||||
% eq_signal_fullresp.plot("displayname",'bla','fignum',199);
|
||||
% eq_signal_fullresp.eye(fsym(r),M,"fignum",103837);
|
||||
|
||||
% Hard decision on VNLE output
|
||||
eq_signal_hd = PAMmapper(M, 0).quantize(eq_signal_fullresp);
|
||||
rx_bits = PAMmapper(M,0,"eth_style",0).demap(eq_signal_hd);
|
||||
[~,tot_err,ber_vnle(r),a] = calc_ber(rx_bits.signal,Tx_bits.signal,"skip_front",100,"skip_end",150,"returnErrorLocation",1);
|
||||
burst_vnle(r,:) = count_error_bursts(a, 10)./tot_err;
|
||||
|
||||
% showLevelConfusionMatrix(eq_signal_hd,Symbols,"M",M,"fignum",200,"displayname",'bla');
|
||||
% showLevelScatter(eq_signal_fullresp,Symbols,"displayname",'VNLE Out','f_sym',fsym(r),'fignum',201);
|
||||
% show2Dconstellation(eq_signal_fullresp,Symbols,"displayname",'VNLE Out','fignum',2241);
|
||||
|
||||
fprintf('BER VNLE: %.2e \n',ber_vnle(r));
|
||||
fprintf('NGMI VNLE: %.2f \n',gmi_vnle_bitwise(r)./m);
|
||||
|
||||
if 1
|
||||
|
||||
% Process through postfilter and MLSE
|
||||
pf_ncoeffs = 1;
|
||||
if fsym(r) < 200e9
|
||||
pf_ = Postfilter("ncoeff",pf_ncoeffs,"useBurg",1,"coefficients",[1,0.1]);
|
||||
else
|
||||
pf_ = Postfilter("ncoeff",pf_ncoeffs,"useBurg",1,"coefficients",[1,0.85]);
|
||||
end
|
||||
|
||||
% showEQNoisePSD(eq_noise,"postfilter_taps",pf_.coefficients,"displayname",'Postfilter Burg based');
|
||||
alpha(r) = pf_.coefficients(2);
|
||||
alpha_vec = max(0,round(alpha(r),2)-0.2):0.025:round(alpha(r),2)+0.4;
|
||||
alpha_vec = unique(sort([alpha_vec, 1, alpha(r)]));
|
||||
|
||||
gmi_mlse_ = zeros(size(alpha_vec));
|
||||
ber_mlse_ = zeros(size(alpha_vec));
|
||||
parfor a=1:numel(alpha_vec)
|
||||
|
||||
mlse_ = MLSE("duobinary_output",0,'M',M,'trellis_states',PAMmapper(M,0).get_levels ./ PAMmapper(M,0).get_scaling,'DIR',[1,alpha_vec(a)]);
|
||||
|
||||
pf_ = Postfilter("ncoeff",1,"useBurg",0,"coefficients",[1,alpha_vec(a)]);
|
||||
[eq_signal_whitened,whitened_noise] = pf_.process(eq_signal_fullresp, eq_noise);
|
||||
|
||||
[signalclass_hd,LLR,gmi_mlse_(a)] = mlse_.process(eq_signal_whitened,Symbols);
|
||||
|
||||
mlse_sig_hd = PAMmapper(M, 0, "eth_style", 0).quantize(signalclass_hd);
|
||||
|
||||
rx_bits = PAMmapper(M,0,"eth_style",0).demap(mlse_sig_hd);
|
||||
|
||||
[~,tot_err,ber_mlse_(a),errpos] = calc_ber(rx_bits.signal,Tx_bits.signal,"skip_front",100,"skip_end",150,"returnErrorLocation",1);
|
||||
% burst_mlse(r,:) = count_error_bursts(errpos, 10);
|
||||
|
||||
% if 0
|
||||
% fprintf('BER MLSE: %.2e \n',ber_mlse(r));
|
||||
% fprintf('NGMI MLSE: %.5f \n',gmi_mlse(r)./m);
|
||||
%
|
||||
% showLevelConfusionMatrix(mlse_sig_hd,Symbols,"M",M,"fignum",300,"displayname",'bla');
|
||||
%
|
||||
% levels = sort(unique(Symbols.signal(:)).'); % 1×6
|
||||
% pairs = reshape(mlse_sig_hd.signal,2,[]).';
|
||||
% isedge = ismember(pairs, [levels(1) levels(end)]);
|
||||
% isforbidden = sum(isedge,2)==2;
|
||||
% fprintf('Found %d forbidden transitions (even→odd edges).\n', nnz(isforbidden));
|
||||
%
|
||||
%
|
||||
% % Process through postfilter and MLSE
|
||||
% pf_ncoeffs = 1;
|
||||
% pf_ = Postfilter("ncoeff",pf_ncoeffs,"useBurg",1);
|
||||
% mlse_ = MLSE_viterbi("duobinary_output",0,'M',M,'trellis_states',PAMmapper(M,0).levels);
|
||||
% [eq_signal_whitened,whitened_noise] = pf_.process(eq_signal_fullresp, eq_noise);
|
||||
% mlse_.DIR = pf_.coefficients;
|
||||
% mlse_output = mlse_.process(eq_signal_whitened);
|
||||
% mlse_sig_hd = PAMmapper(M, 0, "eth_style", 0).quantize(mlse_output);
|
||||
% rx_bits = PAMmapper(M,0,"eth_style",0).demap(mlse_sig_hd);
|
||||
% [~,~,ber_viterbi(r),~] = calc_ber(rx_bits.signal,Tx_bits.signal,"skip_front",100,"skip_end",150,"returnErrorLocation",1);
|
||||
% fprintf('Viterbi BER: %.2e \n',ber_viterbi(r));
|
||||
% end
|
||||
end
|
||||
|
||||
[ber_mlse(r),idx] = min(ber_mlse_);
|
||||
gmi_mlse(r) = gmi_mlse_(idx);
|
||||
ber_mlse_burg(r) = ber_mlse_(alpha_vec==alpha(r));
|
||||
best_alpha(r) = alpha_vec(idx);
|
||||
|
||||
end
|
||||
|
||||
% IR target in EQ
|
||||
if 1
|
||||
|
||||
% alpha_vec = max(0,round(alpha(r),2)-0.1):0.01:min(1,round(alpha(r),2)+0.1);
|
||||
plot_stuff = 0;
|
||||
gmi_mlse_pr_tgt_ = zeros(size(alpha_vec));
|
||||
ber_mlse_pr_tgt_ = zeros(size(alpha_vec));
|
||||
for a = 1:numel(alpha_vec)
|
||||
|
||||
alpha_vec(a) = 0.9;
|
||||
eq_ = EQ("Ne",[vnle_order1,vnle_order2,vnle_order3],"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.00,"FFEmu",0,"plotfinal",0,"ideal_dfe",0);
|
||||
Symbols_filt = Symbols.filter([1,alpha_vec(a)],1);
|
||||
[eq_signal_prtgt, eq_noise] = eq_.process(Rx_sig, Symbols_filt);
|
||||
|
||||
showLevelHistogram(eq_signal_prtgt,Symbols_filt,"displayname",'VNLE Out','fignum',201);
|
||||
|
||||
if plot_stuff
|
||||
% Plot the response for respective EQ targets
|
||||
Symbols_filt.spectrum("displayname",'IDEAL Filtered Reference','fignum',240587);
|
||||
eq_signal_whitened.spectrum("displayname",'Full tgt. EQ + PF','fignum',240587);
|
||||
eq_signal_prtgt.spectrum("displayname",'Partial Resp. Target EQ','fignum',240587);
|
||||
|
||||
noise_pf_out = Symbols_filt-eq_signal_whitened;
|
||||
noise_pr_tgt = Symbols_filt-eq_signal_prtgt;
|
||||
|
||||
noise_pf_out.spectrum("displayname",'Ideal PR - Whitening Out','fignum',240588);
|
||||
noise_pr_tgt.spectrum("displayname",'Ideal PR - PR Target Out','fignum',240588);
|
||||
end
|
||||
|
||||
mlse_ = MLSE("duobinary_output",0,'M',M,'trellis_states',PAMmapper(M,0).get_levels ./ PAMmapper(M,0).get_scaling,'DIR',[1,alpha_vec(a)],'debug',0);
|
||||
|
||||
[signalclass_hd,LLR,gmi_mlse_pr_tgt_(a)] = mlse_.process(eq_signal_prtgt,Symbols);
|
||||
|
||||
mlse_sig_hd = PAMmapper(M, 0, "eth_style", 0).quantize(signalclass_hd);
|
||||
|
||||
rx_bits = PAMmapper(M,0,"eth_style",0).demap(mlse_sig_hd);
|
||||
|
||||
[~,tot_err,ber_mlse_pr_tgt_(a),errpos] = calc_ber(rx_bits.signal,Tx_bits.signal,"skip_front",100,"skip_end",150,"returnErrorLocation",1);
|
||||
|
||||
% burst_mlse_(a,:) = count_error_bursts(errpos, 10);
|
||||
|
||||
% fprintf('BER MLSE: %.2e \n',ber_mlse_pr_tgt_(a));
|
||||
% fprintf('NGMI MLSE: %.5f \n',gmi_mlse_pr_tgt_(a)./m);
|
||||
|
||||
end
|
||||
|
||||
[ber_mlse_pr_tgt(r),idx] = min(ber_mlse_pr_tgt_);
|
||||
gmi_mlse_pr_tgt(r) = gmi_mlse_pr_tgt_(idx);
|
||||
best_alpha_pr_tgt(r) = alpha_vec(idx);
|
||||
|
||||
end
|
||||
|
||||
|
||||
cols = cbrewer2('paired',8);
|
||||
figure(); hold on
|
||||
title(sprintf('%d GBd',fsym(r).*1e-9));
|
||||
scatter(alpha_vec,ber_mlse_,15,'Marker','o','LineWidth',1,'DisplayName','MLSE','MarkerEdgeColor',cols(1,:));
|
||||
scatter(best_alpha(r),ber_mlse(r),15,'Marker','o','LineWidth',2,'DisplayName','MLSE','MarkerEdgeColor',cols(2,:));
|
||||
scatter(alpha(r),ber_mlse_burg(r),25,'Marker','+','LineWidth',2,'DisplayName','MLSE','MarkerEdgeColor',cols(2,:));
|
||||
|
||||
scatter(1,ber_db_diff_precoded(r),15,'Marker','diamond','LineWidth',2,'DisplayName','Duobinary','MarkerEdgeColor',cols(4,:));
|
||||
scatter(1,ber_db(r),15,'Marker','diamond','LineWidth',2,'DisplayName','Duobinary','MarkerEdgeColor',cols(4,:));
|
||||
|
||||
scatter(alpha_vec,ber_mlse_pr_tgt_,15,'Marker','x','LineWidth',1,'DisplayName','MLSE Partial Resp tgt','MarkerEdgeColor',cols(5,:));
|
||||
scatter(best_alpha_pr_tgt(r),ber_mlse_pr_tgt(r),25,'Marker','x','LineWidth',2,'DisplayName','MLSE','MarkerEdgeColor',cols(6,:));
|
||||
|
||||
set(gca,"YScale","log");
|
||||
% ylim([1e-6 0.5]);
|
||||
% xlim([0.1 1]);
|
||||
drawnow;
|
||||
|
||||
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
% --- style control (one variable controls both marker size and linewidth) ---
|
||||
STYLE_BASE = 2; % adjust this single number to scale markers & lines
|
||||
MARKER_SIZE = STYLE_BASE; % marker size (MATLAB MarkerSize)
|
||||
LINE_WIDTH = max(1.5, STYLE_BASE/3); % line width (keeps lines reasonable when STYLE_BASE large)
|
||||
|
||||
% --- color map / method -> color assignment (keeps colors consistent) ---
|
||||
cols = cbrewer2('Paired',8);
|
||||
cols = linspecer(6);
|
||||
d = 0;
|
||||
cm.VNLE = cols(1 + d, :);
|
||||
cm.MLSE = cols(2 + d, :);
|
||||
cm.DB_precode = cols(3 + d, :);
|
||||
cm.DB = cols(4 + d, :); % duobinary
|
||||
|
||||
% prepare x values in GBd
|
||||
xGHz = fsym .* 1e-9;
|
||||
xticks_vals = xGHz;
|
||||
xtick_labels = arrayfun(@(v) sprintf('%d', round(v)), xticks_vals, 'UniformOutput', false);
|
||||
|
||||
% common marker settings (filled, same face+edge color)
|
||||
mk.VNLE = {'Marker','none','MarkerFaceColor',cm.MLSE,'MarkerEdgeColor',cm.VNLE,'MarkerSize',MARKER_SIZE};
|
||||
mk.MLSE = {'Marker','none','MarkerFaceColor',cm.MLSE,'MarkerEdgeColor',cm.MLSE,'MarkerSize',MARKER_SIZE};
|
||||
mk.DB_precode = {'Marker','none','MarkerFaceColor',cm.DB_precode,'MarkerEdgeColor',cm.DB_precode,'MarkerSize',MARKER_SIZE};
|
||||
mk.DB = {'Marker','none','MarkerFaceColor',cm.DB,'MarkerEdgeColor',cm.DB,'MarkerSize',MARKER_SIZE};
|
||||
|
||||
% ---------------- FIGURE 11 : alpha (VNLE) ----------------
|
||||
figure(110+M); clf; hold on;
|
||||
plot(xGHz, alpha, ...
|
||||
'DisplayName','VNLE', ...
|
||||
mk.VNLE{:}, 'LineStyle','-','LineWidth',LINE_WIDTH,'Color',cm.VNLE);
|
||||
xlabel('Baudrate in GBd');
|
||||
ylabel('alpha');
|
||||
set(gca, 'XTick', xticks_vals, 'XTickLabel', xtick_labels);
|
||||
grid on;
|
||||
legend('Location','best');
|
||||
|
||||
% ---------------- FIGURE 15 : GMI ----------------
|
||||
figure(111+M); clf; hold on;
|
||||
plot(xGHz, mi_gomez, ...
|
||||
'DisplayName','MI VNLE', ...
|
||||
mk.VNLE{:}, 'LineStyle',':','LineWidth',LINE_WIDTH,'Color',cm.VNLE);
|
||||
plot(xGHz, gmi_vnle_bitwise, ...
|
||||
'DisplayName','GMI VNLE', ...
|
||||
mk.VNLE{:}, 'LineStyle','-','LineWidth',LINE_WIDTH,'Color',cm.VNLE);
|
||||
% duobinary has only one GMI curve (DB output)
|
||||
plot(xGHz, gmi_mlse_db, ...
|
||||
'DisplayName','GMI DB tgt.', ...
|
||||
mk.DB{:}, 'LineStyle','-','LineWidth',LINE_WIDTH,'Color',cm.DB);
|
||||
% MLSE symbol-wise (if present)
|
||||
plot(xGHz, gmi_mlse, ...
|
||||
'DisplayName','GMI MLSE', ...
|
||||
mk.MLSE{:}, 'LineStyle','-','LineWidth',LINE_WIDTH,'Color',cm.MLSE);
|
||||
|
||||
ylim([log2(M)-1, log2(M)]);
|
||||
xlabel('Baudrate in GBd');
|
||||
ylabel('GMI');
|
||||
set(gca, 'XTick', xticks_vals(1:2:end), 'XTickLabel', xtick_labels(1:2:end));
|
||||
grid on;
|
||||
legend('Location','best');
|
||||
% xlim([184, 256])
|
||||
|
||||
% ---------------- FIGURE 13 : BER ----------------
|
||||
figure(312+M); hold on;
|
||||
plot(xGHz, ber_vnle, ...
|
||||
'DisplayName','VNLE', ...
|
||||
mk.VNLE{:}, 'LineStyle','-','LineWidth',LINE_WIDTH,'Color',cm.VNLE);
|
||||
plot(xGHz, ber_mlse, ...
|
||||
'DisplayName','MLSE', ...
|
||||
mk.MLSE{:}, 'LineStyle','-','LineWidth',LINE_WIDTH,'Color',cm.MLSE);
|
||||
plot(xGHz, ber_viterbi, ...
|
||||
'DisplayName','Viterbi', ...
|
||||
mk.MLSE{:}, 'LineStyle','--','LineWidth',LINE_WIDTH,'Color',cm.MLSE);
|
||||
|
||||
yline(4.85e-3,'LineWidth',1,'HandleVisibility','off');
|
||||
yline(2.2e-4,'LineWidth',1,'HandleVisibility','off');
|
||||
|
||||
plot(xGHz, ber_db, ...
|
||||
'DisplayName','DB tgt.', ...
|
||||
mk.DB{:}, 'LineStyle','-','LineWidth',LINE_WIDTH,'Color',cm.DB);
|
||||
|
||||
plot(xGHz, ber_db_diff_precoded, ...
|
||||
'DisplayName','Prec. + DB tgt.', ...
|
||||
mk.DB{:}, 'LineStyle',':','LineWidth',LINE_WIDTH,'Color',cm.DB);
|
||||
|
||||
xlabel('Baudrate in GBd');
|
||||
ylabel('BER');
|
||||
set(gca, 'yscale', 'log');
|
||||
set(gca, 'XTick', xticks_vals(1:2:end), 'XTickLabel', xtick_labels(1:2:end));
|
||||
grid on;
|
||||
legend('Location','best');
|
||||
% xlim([184, 256])
|
||||
|
||||
% ---------------- FIGURE 15 : Information Rates ----------------
|
||||
tp = TransmissionPerformance;
|
||||
|
||||
|
||||
m = floor(log2(M)*10)/10;
|
||||
figure(113+M); clf; hold on;
|
||||
|
||||
netrates_vnle = tp.calculateNetRate(fsym.* m, ...
|
||||
'NGMI', gmi_vnle_bitwise./m, ...
|
||||
'BER', ber_vnle);
|
||||
%
|
||||
plot(xGHz, gmi_vnle_bitwise.*xGHz, ...
|
||||
'DisplayName','GMI*R VNLE', ...
|
||||
mk.VNLE{:}, 'LineStyle','-','LineWidth',LINE_WIDTH,'Color',cm.VNLE);
|
||||
|
||||
plot(xGHz, netrates_vnle.SDHD.NetRate.*1e-9, ...
|
||||
'DisplayName','SD+HD VNLE', ...
|
||||
mk.VNLE{:}, 'LineStyle',':','LineWidth',LINE_WIDTH,'Color',cm.VNLE);
|
||||
plot(xGHz, netrates_vnle.HD.NetRate.*1e-9, ...
|
||||
'DisplayName','Staircase VNLE', ...
|
||||
mk.VNLE{:}, 'LineStyle','-.','LineWidth',LINE_WIDTH,'Color',cm.VNLE);
|
||||
|
||||
|
||||
%
|
||||
% MLSE symbol-wise (if present)
|
||||
plot(xGHz, gmi_mlse.*xGHz, ...
|
||||
'DisplayName','GMI*R MLSE', ...
|
||||
mk.MLSE{:}, 'LineStyle','-','LineWidth',LINE_WIDTH,'Color',cm.MLSE);
|
||||
|
||||
netrates_mlse = tp.calculateNetRate(fsym.* m, ...
|
||||
'NGMI', gmi_mlse./m, ...
|
||||
'BER', ber_mlse);
|
||||
plot(xGHz, netrates_mlse.SDHD.NetRate.*1e-9, ...
|
||||
'DisplayName','SD+HD MLSE', ...
|
||||
mk.MLSE{:}, 'LineStyle',':','LineWidth',LINE_WIDTH,'Color',cm.MLSE);
|
||||
plot(xGHz, netrates_mlse.HD.NetRate.*1e-9, ...
|
||||
'DisplayName','Staircase MLSE', ...
|
||||
mk.MLSE{:}, 'LineStyle','-.','LineWidth',LINE_WIDTH,'Color',cm.MLSE);
|
||||
|
||||
|
||||
% duobinary has only one GMI curve (DB output)
|
||||
plot(xGHz, gmi_mlse_db.*xGHz, ...
|
||||
'DisplayName','GMI*R DB tgt.', ...
|
||||
mk.DB{:}, 'LineStyle','-','LineWidth',LINE_WIDTH,'Color',cm.DB);
|
||||
|
||||
netrates_db = tp.calculateNetRate(fsym.* m, ...
|
||||
'NGMI', gmi_mlse_db./m, ...
|
||||
'BER', ber_db);
|
||||
|
||||
plot(xGHz, netrates_db.SDHD.NetRate.*1e-9, ...
|
||||
'DisplayName','SD+HD DB', ...
|
||||
mk.DB{:}, 'LineStyle',':','LineWidth',LINE_WIDTH,'Color',cm.DB);
|
||||
plot(xGHz, netrates_db.HD.NetRate.*1e-9, ...
|
||||
'DisplayName','Staircase DB', ...
|
||||
mk.DB{:}, 'LineStyle','-.','LineWidth',LINE_WIDTH,'Color',cm.DB);
|
||||
|
||||
|
||||
|
||||
% ylim([log2(M)-1, log2(M)]);
|
||||
xlabel('Baudrate in GBd');
|
||||
ylabel('AIR in Gbps');
|
||||
set(gca, 'XTick', xticks_vals(1:2:end), 'XTickLabel', xtick_labels(1:2:end));
|
||||
grid on;
|
||||
legend('Location','best');
|
||||
xlim([184, 256])
|
||||
|
||||
% Auxiliary nested helper for numerically stable log-sum-exp
|
||||
function s = logsumexp(a)
|
||||
% LOGSUMEXP Compute log(sum(exp(a))) in a numerically stable way
|
||||
m = max(a);
|
||||
s = m + log(sum(exp(a - m)));
|
||||
end
|
||||
192
projects/IMDD_base_system/simulation_bwl_2.m
Normal file
192
projects/IMDD_base_system/simulation_bwl_2.m
Normal file
@@ -0,0 +1,192 @@
|
||||
%%% Run parameters
|
||||
% TX
|
||||
M = 4;
|
||||
fsym = 180e9;
|
||||
|
||||
apply_pulsef = 1;
|
||||
fdac = 256e9;
|
||||
fadc = 256e9;
|
||||
random_key = 1;
|
||||
|
||||
db_precode = 0;
|
||||
db_encode = 0;
|
||||
|
||||
rcalpha = 0.05;
|
||||
kover = 16;
|
||||
vbias_rel = 0.5;
|
||||
u_pi = 2.9;
|
||||
vbias = -vbias_rel*u_pi;
|
||||
laser_wavelength = 1310;
|
||||
laser_linewidth = 0;
|
||||
tx_bw_nyquist = 1;
|
||||
|
||||
% Channel
|
||||
link_length = 1;
|
||||
|
||||
% RX
|
||||
rop = 0;
|
||||
rx_bw_nyquist = 0.99;
|
||||
|
||||
vnle_order1 = 50;
|
||||
vnle_order2 = 3;
|
||||
vnle_order3 = 3;
|
||||
|
||||
vnle_order=[vnle_order1,vnle_order2,vnle_order3];
|
||||
dfe_order = [0 0 0];
|
||||
|
||||
pf_ncoeffs = 1;
|
||||
|
||||
alpha = 0;
|
||||
|
||||
len_tr = 4096*2;
|
||||
|
||||
mu_ffe1 = 0.0001;
|
||||
mu_ffe2 = 0.0008;
|
||||
mu_ffe3 = 0.001;
|
||||
mu_dc = 0.005;
|
||||
% mu_dc = 0;
|
||||
|
||||
mu_ffe = [mu_ffe1 mu_ffe3 mu_ffe3];
|
||||
mu_dfe = 0.0004;
|
||||
|
||||
|
||||
dfe_ = sum(dfe_order)>0;
|
||||
|
||||
doub_mode = db_mode.no_db;
|
||||
|
||||
|
||||
Pform = Pulseformer("fsym",fsym,"fdac",4*fsym,"pulse","rc","pulselength",16,"alpha",rcalpha);
|
||||
|
||||
db_precode = 0;
|
||||
db_encode = 0;
|
||||
duob_mode = db_mode.db_precoded;
|
||||
apply_pulsef = 1;
|
||||
[Digi_sig,Symbols,Tx_bits] = PAMsource(...
|
||||
"fsym",fsym,"M",M,"order",18,"useprbs",0,...
|
||||
"fs_out",fdac,...
|
||||
"applyclipping",0,"clipfactor",1.5,...
|
||||
"applypulseform",apply_pulsef,"pulseformer",Pform,...
|
||||
"randkey",random_key,...
|
||||
"mrds_code",0,"mrds_blocklength",512,"duobinary_mode",duob_mode).process();
|
||||
|
||||
Digi_sig.spectrum("displayname",'Digi Spectrum','fignum',10,'normalizeTo0dB',1);
|
||||
|
||||
|
||||
%% proof of concept
|
||||
Symbols_db = Duobinary().encode(Symbols);
|
||||
mim_decoded = Duobinary().decode(Symbols_db,"M",M);
|
||||
rx_bits_mim_decoded = PAMmapper(M,0,"eth_style",0).demap(mim_decoded);
|
||||
rx_bits_mim_decoded_.signal = circshift(rx_bits_mim_decoded.signal,0);
|
||||
[~,~,ber_mim_decode,~] = calc_ber(rx_bits_mim_decoded_.signal,Tx_bits.signal,"skip_front",100,"skip_end",150,"returnErrorLocation",1);
|
||||
fprintf('BER mim: %.2e \n',ber_mim_decode);
|
||||
|
||||
%%
|
||||
|
||||
|
||||
%%%%% 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 = El_sig.setPower(0,"dBm");
|
||||
|
||||
%%%%% Low-pass el. components %%%%%%
|
||||
f_nyquist = fsym/2;
|
||||
tx_bwl = tx_bw_nyquist.*f_nyquist;
|
||||
% tx_bwl = 80e9;
|
||||
El_sig = Filter('filtdegree',4,"f_cutoff",tx_bwl,"fs",fdac*kover,"filterType",filtertypes.butterworth,"active",true).process(El_sig);
|
||||
% El_sig.spectrum("displayname",'Digi Spectrum','fignum',100,'normalizeTo0dB',1);
|
||||
|
||||
%%%%% Electrical Driver Amplifier %%%%%%
|
||||
El_sig = Amplifier("amp_mode","ideal_no_noise","gain_mode","gain","amplification_db",3).process(El_sig);
|
||||
El_sig = El_sig.normalize("mode","oneone");
|
||||
|
||||
%%%%% MODULATE E/O CONVERSION %%%%%%
|
||||
[Opt_sig] = EML("mode",eml_mode.im_cosinus,"power",3,"fsimu",El_sig.fs,"lambda",laser_wavelength,"bias",vbias,"u_pi",u_pi,"linewidth",laser_linewidth,"randomkey",random_key+1).process(El_sig);
|
||||
|
||||
Opt_sig = Fiber("fsimu",Opt_sig.fs,"fiber_length",link_length/1000,"alpha",0.3,"D",0,"lambda0",1310,"gamma",0,"Dslope",0.07).process(Opt_sig);
|
||||
|
||||
%%%%%% ROP %%%%%%
|
||||
Rx_sig = Amplifier("amp_mode","ideal_no_noise","gain_mode","output_power","amplification_db",rop).process(Opt_sig);
|
||||
|
||||
%%%%%% PD Square Law %%%%%%
|
||||
Rx_sig = Photodiode("fsimu",fdac*kover,"dark_current",2e-08,"responsivity",1,"temperature",20,"nep",1.8e-11).process(Rx_sig);
|
||||
|
||||
%%%%%% Low-pass RX (PD, El. Connectors and Scope %%%%%%
|
||||
rx_bwl = rx_bw_nyquist.*f_nyquist;
|
||||
% rx_bwl = 80e9;
|
||||
Rx_sig = Filter('filtdegree',4,"f_cutoff",rx_bwl,"fs",fdac*kover,"filterType",filtertypes.butterworth,"active",true).process(Rx_sig);
|
||||
|
||||
% %%%%%% Low-pass Scope %%%%%%
|
||||
Lp_scpe = Filter('filtdegree',4,"f_cutoff",110e9,"fs",fadc,"filterType",filtertypes.butterworth,"active",true);
|
||||
|
||||
% Rx_sig.spectrum("displayname",'Analog Rx Spectrum','fignum',100,'normalizeTo0dB',1);
|
||||
|
||||
%%%%%% Scope %%%%%%
|
||||
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);
|
||||
|
||||
Scpe_sig_resampled = Scpe_sig.resample("fs_out",2*fsym);
|
||||
|
||||
[~, Scpe_cell, ~, found_sync] = Scpe_sig_resampled.tsynch("reference", Symbols, "fs_ref", fsym, "debug_plots", 1);
|
||||
|
||||
eq_ = EQ("Ne",[vnle_order1,vnle_order2,vnle_order3],"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);
|
||||
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);
|
||||
|
||||
if duob_mode == db_mode.no_db
|
||||
|
||||
% FFE or VNLE
|
||||
[eq_signal_sd, eq_noise] = eq_.process(Scpe_cell{1}, Symbols);
|
||||
|
||||
% Hard decision on VNLE output
|
||||
eq_signal_hd = PAMmapper(M, 0).quantize(eq_signal_sd);
|
||||
|
||||
% Process through postfilter and MLSE
|
||||
[mlse_sig_sd,whitened_noise] = pf_.process(eq_signal_sd, eq_noise);
|
||||
mlse_.DIR = pf_.coefficients;
|
||||
mlse_sig_sd = mlse_.process(mlse_sig_sd,Symbols);
|
||||
|
||||
|
||||
% BER
|
||||
rx_bits = PAMmapper(M,0,"eth_style",0).demap(eq_signal_hd);
|
||||
[~,tot_err,ber_vnle,a] = calc_ber(rx_bits.signal,Tx_bits.signal,"skip_front",100,"skip_end",150,"returnErrorLocation",1);
|
||||
|
||||
rx_bits = PAMmapper(M,0,"eth_style",0).demap(mlse_sig_sd);
|
||||
[~,tot_err,ber_mlse,a] = calc_ber(rx_bits.signal,Tx_bits.signal,"skip_front",100,"skip_end",150,"returnErrorLocation",1);
|
||||
|
||||
elseif duob_mode == db_mode.db_precoded
|
||||
|
||||
%%
|
||||
[EQ_sig, Noi] = eq_.process(Scpe_cell{1},Duobinary().encode(Symbols));
|
||||
|
||||
showLevelHistogram(EQ_sig,Duobinary().encode(Symbols),"displayname",101);
|
||||
|
||||
mim_decoded = Duobinary().decode(EQ_sig,"M",M);
|
||||
|
||||
showLevelHistogram(mim_decoded,Symbols,"displayname",101);
|
||||
|
||||
rx_bits_mim_decoded = PAMmapper(M,0,"eth_style",0).demap(mim_decoded);
|
||||
|
||||
rx_bits_mim_decoded_.signal = circshift(rx_bits_mim_decoded.signal,0);
|
||||
|
||||
[~,~,ber_mim_decode,~] = calc_ber(rx_bits_mim_decoded_.signal,Tx_bits.signal,"skip_front",100,"skip_end",150,"returnErrorLocation",1);
|
||||
|
||||
fprintf('BER mim: %.2e \n',ber_mim_decode);
|
||||
|
||||
%%
|
||||
mlse_sig_hd = MLSE("DIR",[1,1],"duobinary_output",1,"M",M,"trellis_states",PAMmapper(M,0).levels).process(EQ_sig,Symbols);
|
||||
|
||||
mlse_sig_hd_decoded = Duobinary().encode(mlse_sig_hd,"M",M);
|
||||
|
||||
mlse_sig_hd_decoded = Duobinary().decode(mlse_sig_hd_decoded,"M",M);
|
||||
|
||||
rx_bits_mlse_decoded = PAMmapper(M,0,"eth_style",0).demap(mlse_sig_hd_decoded);
|
||||
|
||||
[~,errors_db_diff_precoded,ber_db_diff_precoded,a] = calc_ber(rx_bits_mlse_decoded.signal,Tx_bits.signal,"skip_front",100,"skip_end",150,"returnErrorLocation",1);
|
||||
|
||||
%%
|
||||
|
||||
end
|
||||
164
projects/ML_based_MLSE/analyze_filter_length.m
Normal file
164
projects/ML_based_MLSE/analyze_filter_length.m
Normal file
@@ -0,0 +1,164 @@
|
||||
%% analyze_filter_length.m
|
||||
clear; clc;
|
||||
|
||||
M = 4;
|
||||
randkey = 1;
|
||||
|
||||
% --- Parameter sweep
|
||||
order_range = 2:3:11; % FFE order
|
||||
delta_range = 0:2:4; % delta
|
||||
SNR_dB = 20;
|
||||
|
||||
% --- Prepare bit sequence
|
||||
order_bits = 19;
|
||||
s = RandStream('twister','Seed',randkey);
|
||||
for i = 1:log2(M)
|
||||
N = 2^(order_bits-1);
|
||||
bitpattern(:,i) = randi(s,[0 1], N, 1);
|
||||
end
|
||||
Bits = Informationsignal(bitpattern);
|
||||
Symbols = PAMmapper(M,0).map(Bits);
|
||||
Symbols.fs = 200e9;
|
||||
|
||||
% --- Channel (minimal ISI + AWGN)
|
||||
h = [0.3 0.9 0.3]; h = h/norm(h);
|
||||
symbols_filt = Symbols.filter(h,1);
|
||||
symbols_noi = symbols_filt;
|
||||
symbols_noi.signal = awgn(symbols_filt.signal,SNR_dB,'measured');
|
||||
|
||||
% --- Generate all parameter pairs
|
||||
[O,D] = ndgrid(order_range, delta_range);
|
||||
pairs = [O(:), D(:)];
|
||||
|
||||
training_len = 100;
|
||||
|
||||
ber_vec = nan(size(pairs,1),1); % initialize with NaN
|
||||
ber_training = nan(size(pairs,1),training_len);
|
||||
ce_vec = nan(size(pairs,1),1);
|
||||
ce_training = nan(size(pairs,1),training_len);
|
||||
|
||||
% --- Parallel loop over parameter pairs
|
||||
parfor k = 1:size(pairs,1)
|
||||
order_k = pairs(k,1);
|
||||
delta_k = pairs(k,2);
|
||||
|
||||
% Skip invalid combinations (delay cannot exceed filter length)
|
||||
if abs(delta_k) >= order_k
|
||||
fprintf('Skip: order=%d, delta=%d (invalid)\n', order_k, delta_k);
|
||||
continue;
|
||||
end
|
||||
|
||||
try
|
||||
ml = ML_MLSE("epochs_tr",training_len,"epochs_dd",1,"len_tr",2^15, ...
|
||||
"mu_dd",0.1,"mu_tr",0.1,"order",order_k,"sps",1, ...
|
||||
"traceback_depth",128,"L",3,"delta",delta_k,"adaptive_mu",0);
|
||||
|
||||
[y_ml,y_ref] = ml.process(symbols_noi,Symbols);
|
||||
ref_bits = PAMmapper(M,0).demap(y_ref);
|
||||
eq_bits = PAMmapper(M,0).demap(y_ml);
|
||||
|
||||
ber_training(k,:) = ml.ber;
|
||||
ce_training(k,:) = ml.ce;
|
||||
|
||||
[~,~,ber_vec(k)] = calc_ber(eq_bits.signal, ref_bits.signal, ...
|
||||
"skip_front",10,"skip_end",10);
|
||||
L = min(length(ml.ce),30);
|
||||
ce_vec(k) = mean(ml.ce(end-L+1:end));
|
||||
|
||||
fprintf('order=%d, delta=%d → BER=%.2e, CE=%.3f\n', ...
|
||||
order_k, delta_k, ber_vec(k), ce_vec(k));
|
||||
catch ME
|
||||
fprintf('Error at order=%d, delta=%d: %s\n', ...
|
||||
order_k, delta_k, ME.message);
|
||||
ber_vec(k) = NaN;
|
||||
ce_vec(k) = NaN;
|
||||
end
|
||||
end
|
||||
|
||||
% --- reshape to 2D matrices
|
||||
ber_mat = reshape(ber_vec, numel(order_range), numel(delta_range));
|
||||
ce_mat = reshape(ce_vec, numel(order_range), numel(delta_range));
|
||||
|
||||
|
||||
%% --- Plot BER
|
||||
figure; hold on
|
||||
cols = cbrewer2('Set1',10);
|
||||
for i = 1:numel(delta_range)
|
||||
plot(order_range,ber_mat(:,i),'DisplayName',sprintf('delta: %d',delta_range(i)),'Color',cols(i,:))
|
||||
end
|
||||
beautifyBERplot
|
||||
ylabel('BER'); xlabel('Filter Order [N]');
|
||||
title('BER vs. Filter order');
|
||||
ylim([1e-4, 0.1]);
|
||||
yline(3.8e-3,'HandleVisibility','off');
|
||||
yline(2.2e-4,'HandleVisibility','off');
|
||||
|
||||
%% --- Plot Cross-Entropy
|
||||
figure; hold on
|
||||
for i = 1:numel(delta_range)
|
||||
plot(order_range,ce_mat(:,i),'DisplayName',sprintf('delta: %d',delta_range(i)))
|
||||
end
|
||||
% beautifyBERplot
|
||||
ylabel('BER'); xlabel('Filter Order [N]');
|
||||
title('BER vs. Filter order');
|
||||
|
||||
%% --- Training Curves: BER and CE per combination
|
||||
figure('Name','Training Convergence'); hold on
|
||||
cols = cbrewer2('Set1', 10); % one color per delta
|
||||
|
||||
[O, D] = ndgrid(order_range, delta_range);
|
||||
|
||||
for i = 1:size(ber_training,1)
|
||||
ord = O(i);
|
||||
del = D(i);
|
||||
|
||||
if ord <= del
|
||||
continue;
|
||||
end
|
||||
% --- show only order 2 and 10
|
||||
if ord == 2
|
||||
lnst = '-';
|
||||
elseif ord == 5
|
||||
lnst = ':';
|
||||
elseif ord == 8
|
||||
lnst = '--';
|
||||
elseif ord == 11
|
||||
lnst = '-.';
|
||||
end
|
||||
|
||||
|
||||
b = ber_training(i,:);
|
||||
|
||||
|
||||
plot_label = sprintf('order=%d, delta=%d', ord, del);
|
||||
plot(1:length(b), b, 'Color', cols(del+1, :), ...
|
||||
'DisplayName', plot_label,'LineStyle',lnst);
|
||||
end
|
||||
|
||||
set(gca,'YScale','log');
|
||||
xlabel('Epoch');
|
||||
ylabel('BER');
|
||||
title('Training Convergence (BER)');
|
||||
legend('show');
|
||||
grid on;
|
||||
|
||||
|
||||
%% --- Cross-Entropy curves
|
||||
figure('Name','Cross-Entropy'); hold on
|
||||
cols = cbrewer2('Set1',size(ce_training,1));
|
||||
for i = 1:size(ce_training,1)
|
||||
|
||||
[O, D] = ndgrid(order_range, delta_range);
|
||||
plot_label = sprintf('order=%d, delta=%d', O(i), D(i));
|
||||
c = ce_training(i,:);
|
||||
c(~isfinite(c) | c==0) = NaN;
|
||||
if all(isnan(c)), continue; end
|
||||
plot(1:length(c), c, 'Color', cols(D(i)+1,:), ...
|
||||
'DisplayName', plot_label);
|
||||
end
|
||||
set(gca,'YScale','log');
|
||||
xlabel('Epoch');
|
||||
ylabel('Cross-Entropy');
|
||||
title('Training Convergence (CE)');
|
||||
legend('show');
|
||||
grid on;
|
||||
113
projects/ML_based_MLSE/analyze_mu.m
Normal file
113
projects/ML_based_MLSE/analyze_mu.m
Normal file
@@ -0,0 +1,113 @@
|
||||
|
||||
M = 4;
|
||||
order = 19;
|
||||
randkey = 1;
|
||||
|
||||
bitpattern = [];
|
||||
s = RandStream('twister','Seed',randkey);
|
||||
for i = 1:log2(M)
|
||||
N = 2^(order-1); %length of prbs
|
||||
bitpattern(:,i) = randi(s,[0 1], N, 1);
|
||||
end
|
||||
|
||||
if M == 6
|
||||
bitpattern = reshape(bitpattern',[],1);
|
||||
bitpattern = bitpattern(1:end-mod(length(bitpattern),5));
|
||||
end
|
||||
|
||||
Bits = Informationsignal(bitpattern);
|
||||
|
||||
Symbols = PAMmapper(M,0).map(Bits);
|
||||
Symbols.fs = 200e9;
|
||||
|
||||
Bits_ = PAMmapper(M, 0, "eth_style", 0).demap(Symbols);
|
||||
|
||||
% --- Channel: minimal ISI response + AWGN ---
|
||||
h = [0.3 0.9 0.3]; % impulse response (normalized later if desired)
|
||||
h = h / norm(h); % optional normalization for unit energy
|
||||
|
||||
symbols_filt = Symbols.filter(h,1);
|
||||
|
||||
|
||||
%% SHOW Loss during training
|
||||
|
||||
mu = logspace(-3,-0.8,12);
|
||||
ber_ml_mlse = zeros(size(mu));
|
||||
ber_training = [];
|
||||
ce_training = [];
|
||||
|
||||
parfor i = 1:numel(mu)
|
||||
|
||||
symbols_noi = symbols_filt;
|
||||
SNR_dB = 20;
|
||||
symbols_noi.signal = awgn(symbols_filt.signal, SNR_dB, 'measured'); % AWGN with given SNR
|
||||
|
||||
ml_mlse_equalizer = ML_MLSE("epochs_tr",200,"epochs_dd",1,"len_tr",2^15,...
|
||||
"mu_dd",mu(i),"mu_tr",mu(i),"order",5,"sps",1,...
|
||||
"traceback_depth",128,"L",3,"delta",0,'adaptive_mu',0);
|
||||
|
||||
[y_ml_mlse,y_ref] = ml_mlse_equalizer.process(symbols_noi,Symbols);
|
||||
ref_bits = PAMmapper(M, 0, "eth_style", 0).demap(y_ref);
|
||||
ml_mlse_bits = PAMmapper(M, 0, "eth_style", 0).demap(y_ml_mlse);
|
||||
[~, errors, ber_ml_mlse(i), errpos] = calc_ber(ml_mlse_bits.signal, ref_bits.signal, "skip_front", 10, "skip_end", 10, "returnErrorLocation", 1);
|
||||
fprintf('ML MLSE BER: %.2e \n',ber_ml_mlse(i));
|
||||
ber_training(i,:) = ml_mlse_equalizer.ber;
|
||||
ce_training(i,:) = ml_mlse_equalizer.ce;
|
||||
end
|
||||
|
||||
%%
|
||||
symbols_noi = symbols_filt;
|
||||
SNR_dB = 20;
|
||||
symbols_noi.signal = awgn(symbols_filt.signal, SNR_dB, 'measured'); % AWGN with given SNR
|
||||
ml_mlse_equalizer_adap = ML_MLSE("epochs_tr",200,"epochs_dd",1,"len_tr",2^16,...
|
||||
"mu_dd",1,"mu_tr",1,"order",5,"sps",1,...
|
||||
"traceback_depth",128,"L",3,"delta",0,"adaptive_mu",1);
|
||||
|
||||
[y_ml_mlse,y_ref] = ml_mlse_equalizer_adap.process(symbols_noi,Symbols);
|
||||
ref_bits = PAMmapper(M, 0, "eth_style", 0).demap(y_ref);
|
||||
ml_mlse_bits = PAMmapper(M, 0, "eth_style", 0).demap(y_ml_mlse);
|
||||
[~, errors, ber_ml_mlse_, errpos] = calc_ber(ml_mlse_bits.signal, ref_bits.signal, "skip_front", 10, "skip_end", 10, "returnErrorLocation", 1);
|
||||
fprintf('ML MLSE BER: %.2e \n',ber_ml_mlse_);
|
||||
|
||||
%%
|
||||
figure();hold on
|
||||
|
||||
plot(mu,ber_ml_mlse,'DisplayName','ML-based MLSE');
|
||||
|
||||
beautifyBERplot;
|
||||
xlim([mu(1), mu(end)]);
|
||||
xlabel('mu');
|
||||
ylabel('BER');
|
||||
title('PAM-4; M=3; AWGN Channel');
|
||||
ylim([1e-5 0.1]);
|
||||
|
||||
%%
|
||||
figure()
|
||||
hold on;
|
||||
cols = cbrewer2('Spectral',12);
|
||||
for i = 1:12
|
||||
plot(1:200,ber_training(i,:),'DisplayName', sprintf('mu=%.3f ',mu(i)),'Color',cols(i,:));
|
||||
end
|
||||
set(gca,'YScale','log');
|
||||
xlabel('Epoch');
|
||||
ylabel('BER');
|
||||
title('PAM-4; L=3; SNR=20; AWGN Channel');
|
||||
plot(1:200,ml_mlse_equalizer_adap.ber,'DisplayName','Adaptive mu');
|
||||
|
||||
%%
|
||||
figure()
|
||||
hold on;
|
||||
cols = cbrewer2('Spectral',12);
|
||||
for i = 1:12
|
||||
plot(1:200,ce_training(i,:),'DisplayName', sprintf('mu=%.3f ',mu(i)),'Color',cols(i,:));
|
||||
end
|
||||
set(gca,'YScale','log');
|
||||
xlabel('Epoch');
|
||||
ylabel('Cross-Entropy');
|
||||
title('PAM-4; L=3; SNR=20; AWGN Channel');
|
||||
plot(1:200,ml_mlse_equalizer_adap.ce,'DisplayName','Adaptive mu');
|
||||
|
||||
|
||||
%% SUPER LONG EPOCHS
|
||||
|
||||
|
||||
163
projects/ML_based_MLSE/experimental_data.m
Normal file
163
projects/ML_based_MLSE/experimental_data.m
Normal file
@@ -0,0 +1,163 @@
|
||||
|
||||
|
||||
dsp_options.storage_path = 'Z:\2024\sioe_labor\';
|
||||
dsp_options.max_occurences = 1;
|
||||
database = DBHandler("dataBase", 'labor_highspeed', "type", 'mysql' );
|
||||
run_id = 2776;
|
||||
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, dsp_options);
|
||||
|
||||
% Preprocess signal
|
||||
Scpe_sig = preprocessSignal(Scpe_cell{1}, Symbols, fsym);
|
||||
|
||||
Scpe_sig.spectrum("fignum",1,"displayname",'Rx')
|
||||
|
||||
%%
|
||||
|
||||
ffe_order = [50, 5, 5];
|
||||
mu_ffe = [0.0001, 0.0008, 0.001];
|
||||
mu_dfe = 0.0004;
|
||||
eq_ = EQ("Ne",ffe_order,"Nb",[0,0,0],"training_length",2^14,"training_loops",5,"dd_loops",5,"K",2,"DCmu",0.005,"DDmu",[mu_ffe mu_dfe],"DFEmu",0.005,"FFEmu",0,"plotfinal",0,"ideal_dfe",1);
|
||||
mlse_ = MLSE("DIR",[1,1],"duobinary_output",0,"M",M,"trellis_states",PAMmapper(M,0).levels,'scale_mode',2,'trellis_exclusion',0,'trellis_state_mode',3);
|
||||
|
||||
|
||||
%Duobinary Targeting
|
||||
db_ref_sequence = Duobinary().encode(Symbols);
|
||||
db_ref_constellation = unique(db_ref_sequence.signal);
|
||||
[eq_signal, eq_noise] = eq_.process(Scpe_sig,db_ref_sequence);
|
||||
|
||||
%%
|
||||
if 1
|
||||
[mlse_sig_sd,LLR,GMI_MLSE] = mlse_.process(eq_signal,Symbols);
|
||||
else
|
||||
% Ml MLSE
|
||||
ml_mlse_equalizer = ML_MLSE("epochs_tr",20,"epochs_dd",1,"len_tr",length(eq_signal),...
|
||||
"mu_dd",0.01,"mu_tr",0.01,"order",11,"sps",2,...
|
||||
"traceback_depth",128,"L",1,"delta",4,'adaptive_mu',0);
|
||||
[mlse_sig_sd,ref_sig] = ml_mlse_equalizer.process(Scpe_sig,db_ref_sequence);
|
||||
end
|
||||
|
||||
%%
|
||||
mlse_sig_sd_decoded = Duobinary().decode(mlse_sig_sd,"M",M);
|
||||
ref_sig_decoded = Duobinary().decode(db_ref_sequence,"M",M);
|
||||
|
||||
mlse_sig_bits = PAMmapper(M,0,"eth_style",0).demap(mlse_sig_sd_decoded);
|
||||
ref_sig_bits = PAMmapper(M,0,"eth_style",0).demap(ref_sig_decoded);
|
||||
|
||||
err = sum(ref_sig_decoded.signal ~= mlse_sig_sd_decoded.signal);
|
||||
|
||||
[bits_db,errors_db,ber_db,a] = calc_ber(mlse_sig_bits.signal,ref_sig_bits.signal,"skip_front",0,"skip_end",0,"returnErrorLocation",1);
|
||||
|
||||
%%
|
||||
switch duob_mode
|
||||
|
||||
case db_mode.no_db
|
||||
% TX Data is not precoded:
|
||||
|
||||
% A) Emulate diff precoding
|
||||
mlse_sig_hd_precoded = Duobinary().encode(mlse_sig_hd,"M",M);
|
||||
mlse_sig_hd_precoded = Duobinary().decode(mlse_sig_hd_precoded,"M",M);
|
||||
|
||||
tx_symbols_precoded = Duobinary().encode(Symbols);
|
||||
tx_symbols_precoded = Duobinary().decode(tx_symbols_precoded);
|
||||
|
||||
tx_bits_precoded = PAMmapper(M,0,"eth_style",options.eth_style_symbol_mapping).demap(tx_symbols_precoded);
|
||||
rx_bits_mlse = PAMmapper(M,0,"eth_style",options.eth_style_symbol_mapping).demap(mlse_sig_hd_precoded);
|
||||
|
||||
[~,errors_db_diff_precoded,ber_db_diff_precoded,~] = calc_ber(rx_bits_mlse.signal,tx_bits_precoded.signal,"skip_front",100,"skip_end",150,"returnErrorLocation",1);
|
||||
|
||||
%B) Just determine BER
|
||||
rx_bits_mlse = PAMmapper(M,0,"eth_style",options.eth_style_symbol_mapping).demap(mlse_sig_hd);
|
||||
[bits_mlse,errors_mlse,ber_db,~] = calc_ber(rx_bits_mlse.signal,Tx_bits.signal,"skip_front",100,"skip_end",150,"returnErrorLocation",1);
|
||||
|
||||
case db_mode.db_precoded
|
||||
|
||||
% Daten SIND TATSÄCHLICH precoded auf TX Seite:
|
||||
|
||||
% A) Decode at Rx if no DB targeting was applied (we are in VNLE or MLSE EQ structure here!
|
||||
mlse_sig_hd_decoded = Duobinary().encode(mlse_sig_hd,"M",M);
|
||||
mlse_sig_hd_decoded = Duobinary().decode(mlse_sig_hd_decoded,"M",M);
|
||||
rx_bits_mlse_decoded = PAMmapper(M,0,"eth_style",0).demap(mlse_sig_hd_decoded);
|
||||
[~,errors_db_diff_precoded,ber_db_diff_precoded,a] = calc_ber(rx_bits_mlse_decoded.signal,Tx_bits.signal,"skip_front",100,"skip_end",150,"returnErrorLocation",1);
|
||||
burst_db_precoded = count_error_bursts(a, 40);
|
||||
% B) Omit the Coding by comparing with demapped TX symbol sequence
|
||||
|
||||
Tx_bits_ = PAMmapper(M,0,"eth_style",0).demap(Symbols);
|
||||
rx_bits_mlse = PAMmapper(M,0,"eth_style",0).demap(mlse_sig_hd);
|
||||
[bits_db,errors_db,ber_db,a] = calc_ber(rx_bits_mlse.signal,Tx_bits_.signal,"skip_front",100,"skip_end",150,"returnErrorLocation",1);
|
||||
burst_db = count_error_bursts(a, 40);
|
||||
|
||||
cols = linspecer(8);
|
||||
figure();hold on;
|
||||
stem(1:40,burst_db,'LineWidth',1,'Color',cols(4,:),'Marker','_','DisplayName','w/o diff. precoder');
|
||||
stem(1:40,burst_db_precoded,'LineWidth',1,'Color',cols(3,:),'Marker','.','LineStyle','-','DisplayName','w diff. precoder');
|
||||
xlabel('Bit Error Burst Length')
|
||||
ylabel('Occurence')
|
||||
set(gca, 'yscale', 'log');
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
%% SHOW Loss during training
|
||||
|
||||
mu = logspace(-3,-0.8,12);
|
||||
ber_ml_mlse = zeros(size(mu));
|
||||
ber_training = [];
|
||||
ce_training = [];
|
||||
|
||||
parfor i = 1:numel(mu)
|
||||
|
||||
|
||||
|
||||
ml_mlse_equalizer = ML_MLSE("epochs_tr",200,"epochs_dd",1,"len_tr",length(Scpe_sig),...
|
||||
"mu_dd",mu(i),"mu_tr",mu(i),"order",11,"sps",2,...
|
||||
"traceback_depth",128,"L",2,"delta",4,'adaptive_mu',0);
|
||||
|
||||
[y_ml_mlse,y_ref] = ml_mlse_equalizer.process(Scpe_sig,Symbols);
|
||||
ref_bits = PAMmapper(M, 0, "eth_style", 0).demap(y_ref);
|
||||
ml_mlse_bits = PAMmapper(M, 0, "eth_style", 0).demap(y_ml_mlse);
|
||||
[~, errors, ber_ml_mlse(i), errpos] = calc_ber(ml_mlse_bits.signal, ref_bits.signal, "skip_front", 10, "skip_end", 10, "returnErrorLocation", 1);
|
||||
fprintf('ML MLSE BER: %.2e \n',ber_ml_mlse(i));
|
||||
|
||||
ber_training(i,:) = ml_mlse_equalizer.ber;
|
||||
ce_training(i,:) = ml_mlse_equalizer.ce;
|
||||
end
|
||||
|
||||
%%
|
||||
figure();hold on
|
||||
|
||||
plot(mu,ber_ml_mlse,'DisplayName','ML-based MLSE');
|
||||
|
||||
beautifyBERplot;
|
||||
xlim([mu(1), mu(end)]);
|
||||
xlabel('mu');
|
||||
ylabel('BER');
|
||||
title('PAM-4; M=3; AWGN Channel');
|
||||
ylim([1e-5 0.1]);
|
||||
|
||||
|
||||
%%
|
||||
figure()
|
||||
hold on;
|
||||
cols = cbrewer2('Spectral',12);
|
||||
for i = 1:12
|
||||
plot(1:200,ber_training(i,:),'DisplayName', sprintf('mu=%.3f ',mu(i)),'Color',cols(i,:));
|
||||
end
|
||||
set(gca,'YScale','log');
|
||||
xlabel('Epoch');
|
||||
ylabel('BER');
|
||||
title('PAM-4; L=3; SNR=20; AWGN Channel');
|
||||
plot(1:200,ml_mlse_equalizer_adap.ber,'DisplayName','Adaptive mu');
|
||||
13
projects/ML_based_MLSE/interp_fec_cross.m
Normal file
13
projects/ML_based_MLSE/interp_fec_cross.m
Normal file
@@ -0,0 +1,13 @@
|
||||
function rop_fec = interp_fec_cross(rops, ber, fec_thr)
|
||||
if all(~isfinite(ber))
|
||||
rop_fec = NaN; return;
|
||||
end
|
||||
idx = find(ber < fec_thr, 1, 'first');
|
||||
if isempty(idx) || idx == 1
|
||||
rop_fec = NaN; return; % no crossing
|
||||
end
|
||||
% linear interpolation between the two nearest points
|
||||
x1 = rops(idx-1); x2 = rops(idx);
|
||||
y1 = ber(idx-1); y2 = ber(idx);
|
||||
rop_fec = interp1([y1 y2], [x1 x2], fec_thr, 'linear', NaN);
|
||||
end
|
||||
BIN
projects/ML_based_MLSE/minimal_example_huawei.zip
Normal file
BIN
projects/ML_based_MLSE/minimal_example_huawei.zip
Normal file
Binary file not shown.
555
projects/ML_based_MLSE/minimal_example_huawei/bcjr_pam.m
Normal file
555
projects/ML_based_MLSE/minimal_example_huawei/bcjr_pam.m
Normal file
@@ -0,0 +1,555 @@
|
||||
classdef bcjr_pam < handle
|
||||
%MLSE calculates the most probable sequence for an input signal with given/ known channel impulse response of any length
|
||||
|
||||
properties(Access=public)
|
||||
M %PAM-M
|
||||
DIR
|
||||
trellis_states
|
||||
duobinary_output
|
||||
end
|
||||
|
||||
methods (Access=public)
|
||||
|
||||
function obj = bcjr_pam(options)
|
||||
%NAME Construct an instance of this class
|
||||
% Detailed explanation goes here
|
||||
|
||||
arguments
|
||||
options.M double = 4;
|
||||
options.DIR double = [1];
|
||||
options.trellis_states double = [-3 -1 1 3];
|
||||
options.duobinary_output logical = false;
|
||||
|
||||
end
|
||||
|
||||
%
|
||||
fn = fieldnames(options);
|
||||
for n = 1:numel(fn)
|
||||
try
|
||||
obj.(fn{n}) = options.(fn{n});
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function [VITERBI_ESTIMATION_SYMBOLS,LLR_exact,GMI] = process(obj,data_in,data_ref,tx_bits,bit_mapping)
|
||||
|
||||
|
||||
debug = 0;
|
||||
|
||||
% States should match the target states of the prev. EQ (EQ's job was to reduce the error between signal and the target)
|
||||
trellis_state_mode = 2;
|
||||
% 0 = use provided states (MUST provide the correct states);
|
||||
% 1 = normalize to = 1 rms;
|
||||
% 2 = use target symbols;
|
||||
% 3 = use statistical levels
|
||||
% 3 analyzes avg of rx signal levels - can help with nonlinear impairments
|
||||
|
||||
trellis_exclusion = 1; % PAM-6 only (only if data is NOT precoded!)
|
||||
|
||||
% Additional scaling between states, expected output (noiseless_received) and the noisy, filtered input signal
|
||||
scale_mode = 2; % scale_mode:
|
||||
% 0 = no scaling,
|
||||
% 1 = use RMS to scale MODEL,
|
||||
% 2 = use MMSE/time-corr to scale MODEL, -> This best to get the GMI right -> sometimes the LLP's are not centered around zero...
|
||||
% 3 = use RMS to scale DATA,
|
||||
% 4 = use MMSE/time-corr to scale DATA
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
%%%%%% PREPARATIONS %%%%%%%%
|
||||
|
||||
% remove unnecessary zeros at start of impulse response to keep
|
||||
% number of trellis states minimal
|
||||
DIR_nonzero = find(obj.DIR ~= 0);
|
||||
if DIR_nonzero(1) > 1
|
||||
obj.DIR(1:DIR_nonzero(1)-1) = [];
|
||||
end
|
||||
|
||||
if isscalar(obj.DIR)
|
||||
obj.DIR = [0 obj.DIR];
|
||||
end
|
||||
|
||||
% impulse respnse to remove from signal
|
||||
obj.DIR = flip(obj.DIR); %i.e. -0.2676 -0.0478 1.0000
|
||||
|
||||
% Trellis States
|
||||
obj.trellis_states = reshape(obj.trellis_states,1,[]);
|
||||
if trellis_state_mode == 1 % Normalize the Trellis states to =1 RMS
|
||||
|
||||
obj.trellis_states = obj.trellis_states ./ rms(obj.trellis_states);
|
||||
|
||||
elseif trellis_state_mode == 2 %simply use the states from the ref signal (should be a robust option)
|
||||
|
||||
obj.trellis_states = reshape(unique(data_ref),size(obj.trellis_states));
|
||||
|
||||
elseif trellis_state_mode == 3 %use_statistical_levels
|
||||
|
||||
%%%% Separate the equalized signal into the respective levels based on the actually transmitted level
|
||||
constellation = unique(data_ref);
|
||||
|
||||
% find actual levels from rx signal
|
||||
symbols_for_lvl = NaN(numel(constellation),length(data_ref));
|
||||
for l = 1:numel(constellation)
|
||||
level_amplitude = constellation(l);
|
||||
symbols_for_lvl(l,data_ref==level_amplitude) = data_in(data_ref==level_amplitude);
|
||||
end
|
||||
|
||||
%replace the trellis states
|
||||
avg_levels = mean(symbols_for_lvl,2,'omitnan');
|
||||
obj.trellis_states = sort(avg_levels)';
|
||||
|
||||
%also replace the whole ref signal (PAM-M) levels
|
||||
[~, idx] = ismember(data_ref, unique(data_ref));
|
||||
data_ref = avg_levels(idx);
|
||||
|
||||
end
|
||||
|
||||
|
||||
% seems to be the only way to use combvec for a flexible amount
|
||||
% of vectors. 'combs' contains all trellis states
|
||||
pre_comb_mat = repmat(obj.trellis_states,length(obj.DIR)-1,1);
|
||||
pre_comb_cell = mat2cell(pre_comb_mat,ones(1,size(pre_comb_mat,1)),size(pre_comb_mat,2));
|
||||
combs = fliplr(combvec(pre_comb_cell{:}).');
|
||||
first_sym = combs(:,1); % das ist das älteste/ trailing Symbol aus der sequenz
|
||||
last_sym = combs(:,end); %hiermit wird entschieden/ das ist das cursor symbol am ende der sequenz
|
||||
nStates = length(last_sym);
|
||||
|
||||
% % Calculate all possible input symbols for the desired impulse
|
||||
% % response. Row number is the index of the previous state,
|
||||
% % column number is the index of the next state
|
||||
% % noise free received == branch metrics
|
||||
% assumes: last_sym = combs(:,end); % already defined earlier
|
||||
levels = sort(unique(obj.trellis_states(:)).');
|
||||
edges = [levels(1) levels(end)]; % edge levels (0 and 5 in PAM6)
|
||||
|
||||
noise_free_received = inf(nStates,nStates); % rows: to, cols: from
|
||||
edge_edge_mask = false(nStates,nStates); % rows: to, cols: from
|
||||
|
||||
for from = 1:nStates
|
||||
for to = 1:nStates
|
||||
% valid transition if shift-register overlap holds
|
||||
if all(combs(to,2:end) == combs(from,1:end-1))
|
||||
% noiseless sample for the 'to' state reached from 'from'
|
||||
noise_free_received(to,from) = ...
|
||||
dot(combs(to,:), obj.DIR(end:-1:2)) + last_sym(from)*obj.DIR(1);
|
||||
|
||||
% mark edge→edge candidate (to be excluded only on even→odd steps)
|
||||
edge_edge_mask(to,from) = ...
|
||||
(last_sym(from)==edges(1) || last_sym(from)==edges(2)) && ...
|
||||
(last_sym(to) ==edges(1) || last_sym(to) ==edges(2));
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
h = flip(obj.DIR(:)).';
|
||||
data_in = data_in(:);
|
||||
y_ideal = conv(data_ref(:), h, "same");
|
||||
|
||||
switch scale_mode
|
||||
case 0
|
||||
g = 1; b = 0;
|
||||
case 1 % RMS: scale model to data
|
||||
g = rms(data_in)/rms(y_ideal); b = mean(data_in) - g*mean(y_ideal);
|
||||
case 2 % MMSE/time-corr: scale states to data
|
||||
[c,lags] = xcorr(data_in(:), y_ideal, 64);
|
||||
[~,ix] = max(abs(c));
|
||||
lag = lags(ix);
|
||||
y_ideal = circshift(y_ideal, lag);
|
||||
mu_y = mean(data_in(:));
|
||||
mu_i = mean(y_ideal);
|
||||
y_c = data_in(:)-mu_y;
|
||||
yi_c = y_ideal-mu_i;
|
||||
g = (yi_c'*y_c)/(yi_c'*yi_c);
|
||||
b = mu_y - g*mu_i;
|
||||
case 3 % RMS flipped: scale data to model
|
||||
gd = rms(y_ideal)/rms(data_in); bd = mean(y_ideal) - gd*mean(data_in);
|
||||
data_in = gd*data_in + bd;
|
||||
g = 1; b = 0;
|
||||
case 4 % MMSE/time-corr flipped: scale data to states
|
||||
[c,lags] = xcorr(data_in(:), y_ideal(:), 64);
|
||||
[~,ix] = max(abs(c));
|
||||
lag = lags(ix);
|
||||
y_ideal = circshift(y_ideal(:), lag);
|
||||
mu_y = mean(data_in(:));
|
||||
mu_i = mean(y_ideal);
|
||||
y_c = data_in(:) - mu_y; % data_in centered
|
||||
yi_c = y_ideal - mu_i; % ideal centered
|
||||
g = (y_c' * yi_c) / (y_c' * y_c);
|
||||
b = mu_i - g * mu_y;
|
||||
data_in = g * data_in(:) + b;
|
||||
g = 1; b = 0;
|
||||
end
|
||||
|
||||
% apply (g,b) to states/ expected values
|
||||
noise_free_received = g*noise_free_received + b;
|
||||
last_sym = g*last_sym + b;
|
||||
|
||||
% calculate noise power
|
||||
sigma2 = mean(abs(data_in - (g*y_ideal + b)).^2); %noise = mean(abs((RX Signal - IDEAL Signal)))^2
|
||||
inv2s2 = 1/(2*sigma2);
|
||||
|
||||
if debug
|
||||
figure(100); clf; hold on
|
||||
obj.showLevelScatter_(data_in, data_ref);
|
||||
yline(noise_free_received(:), 'DisplayName','Transition States','Color','red','HandleVisibility','off');
|
||||
yline(obj.trellis_states(:), 'DisplayName','Transition States','Color','green','LineWidth',2,'HandleVisibility','off')
|
||||
end
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
%%%%% FORWARD PASS (VITERBI -Alpha's) %%%%%
|
||||
|
||||
% Initialize the output vector
|
||||
pm = zeros(nStates,nStates);
|
||||
bm_fw = zeros(nStates,nStates,length(data_in));
|
||||
|
||||
% first start is evaluated without ISI/ wihout the full Impulse response
|
||||
% so simply use the constellation here
|
||||
bm = -(data_in(1) - last_sym).^2 * inv2s2;
|
||||
pm = pm + bm;
|
||||
[alpha(:,1),pm_survivor_fw_idx(:,1)] = max(pm,[],2);
|
||||
pm = repmat(alpha(:,1).',nStates,1);
|
||||
bm_fw(:,:,1) = pm;
|
||||
|
||||
% Forward Recursion (FSM Computation)
|
||||
for n = 2:length(data_in)
|
||||
|
||||
bm = -(data_in(n) - noise_free_received).^2 * inv2s2;
|
||||
|
||||
% exclude edge to edge transitions only for even->odd steps && PAM-6
|
||||
if mod(n,2) == 0 && obj.M == 6 && trellis_exclusion
|
||||
bm(edge_edge_mask) = -Inf;
|
||||
end
|
||||
|
||||
pm = pm + bm;
|
||||
[alpha(:,n),pm_survivor_fw_idx(:,n)] = max(pm,[],2); % choose lowest path metric as new state (get min distance for all state transitions towards a new state)
|
||||
pm = repmat(alpha(:,n).',nStates,1); % update pm (chosen state to 2nd dimension -> FROM state)
|
||||
|
||||
bm_fw(:,:,n) = bm;
|
||||
|
||||
end
|
||||
|
||||
% we can now get the best path as min
|
||||
viterbi_path = NaN(1,length(data_in));
|
||||
|
||||
% find ideal trellis path by going through the trellis backwards
|
||||
[~,viterbi_path(length(data_in))] = max(alpha(:,length(data_in)));
|
||||
for n = length(data_in):-1:2
|
||||
viterbi_path(n-1) = pm_survivor_fw_idx(viterbi_path(n),n);
|
||||
end
|
||||
|
||||
|
||||
if debug
|
||||
alpha_ = alpha - min(alpha) + eps;
|
||||
figure();hold on;
|
||||
n = 10;
|
||||
scatter(1:n,obj.trellis_states(repmat([1:numel(obj.trellis_states)]',1,n)),abs(alpha_(:,end-n+1:end)),'Marker','o','LineWidth',1);
|
||||
scatter(1:n,obj.trellis_states(viterbi_path(end-n+1:end)),500,'Marker','x','LineWidth',1,'MarkerEdgeColor','green');
|
||||
% scatter(1:n,data_ref(end-n+1:end),500,'Marker','x','LineWidth',1,'MarkerEdgeColor','red');
|
||||
yticks(obj.trellis_states);
|
||||
ylim([min(obj.trellis_states)-1 max(obj.trellis_states)+1]);
|
||||
end
|
||||
|
||||
VITERBI_ESTIMATION_SYMBOLS(1:length(data_in)) = first_sym(viterbi_path);
|
||||
VITERBI_ESTIMATION_SYMBOLS = reshape(VITERBI_ESTIMATION_SYMBOLS,size(data_in));
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
%%%%% BACKWARD (Beta's) %%%%%
|
||||
|
||||
% Initialize the output vector
|
||||
pm = zeros(nStates,nStates);
|
||||
beta = zeros(nStates,length(data_in));
|
||||
pm_survivor_bw_idx = zeros(nStates,length(data_in));
|
||||
bm_bw = zeros(nStates,nStates,length(data_in));
|
||||
|
||||
% starting with the state that has the lowest sum path
|
||||
% metric, follow the stored information about the
|
||||
% predecessor
|
||||
for h = length(data_in)-1:-1:1
|
||||
|
||||
bm = -(data_in(h+1) - noise_free_received).^2 * inv2s2;
|
||||
|
||||
% exclude edge to edge transitions for even->odd steps && PAM-6
|
||||
if mod(h+1, 2) == 0 && obj.M == 6 && trellis_exclusion
|
||||
bm(edge_edge_mask) = -Inf;
|
||||
end
|
||||
|
||||
pm = pm + bm.';
|
||||
[beta(:,h),pm_survivor_bw_idx(:,h)] = max(pm,[],2); % choose lowest path metric as new state
|
||||
pm = repmat(beta(:,h).',nStates,1); % update pm (chosen state to 2nd dimension -> FROM state)
|
||||
|
||||
bm_bw(:,:,h) = bm;
|
||||
|
||||
end
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
%%%%% FORWARD (Combine Alpha and Beta to yield LLP's) %%%%%
|
||||
|
||||
%calc the log probabilities (llp's)
|
||||
|
||||
for k = 1:length(data_in)
|
||||
|
||||
if k == 1
|
||||
|
||||
alpha_ = repmat(alpha(:,k)',[nStates,1])';
|
||||
beta_ = beta(:,k);
|
||||
|
||||
LLP(:,k) = max(alpha_ + beta_,[],2);
|
||||
|
||||
else
|
||||
|
||||
alpha_ = repmat(alpha(:,k-1)',[nStates,1])';
|
||||
gamma_ = bm_fw(:,:,k)';
|
||||
beta_ = beta(:,k);
|
||||
|
||||
LLP(:,k) = max(alpha_ + gamma_,[],1) + beta_';
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
%%%%% Calc LLR's %%%%%
|
||||
|
||||
% These are interchangeable...
|
||||
nml_LLP = LLP - max(LLP); %subtract highest value for better numerical stability, LLP's are not always close to zero
|
||||
expLLP = exp(nml_LLP);
|
||||
state_prob = expLLP ./ sum(expLLP); % sums to one (or numerically close to one)
|
||||
|
||||
% compute symbol‐posteriors from LLP in the log‐domain:
|
||||
amax = max(LLP,[],1);
|
||||
logZ = amax + log(sum(exp(LLP - amax), 1));
|
||||
logPstate = LLP - logZ; % still in log‐domain
|
||||
state_prob = exp(logPstate); % exact, sums to 1
|
||||
|
||||
if obj.M == 6
|
||||
|
||||
num_bits = 5;
|
||||
|
||||
% all possible transitions (for now 36, including the "edges"
|
||||
% of the QAM 32 constellation)
|
||||
states = [-5 -3 -1 1 3 5];
|
||||
pam6transitions = combvec(states,states)'; % pam6transitions =
|
||||
% [-5 -5;
|
||||
% -3 -5;
|
||||
% -1 -5; ...
|
||||
|
||||
[~, idx_sym_1] = ismember(pam6transitions(:,1), states);
|
||||
[~, idx_sym_2] = ismember(pam6transitions(:,2), states);
|
||||
pam6ind = [idx_sym_1, idx_sym_2];
|
||||
|
||||
numPairs = floor(size(LLP,2)/2);
|
||||
LLR_exact = zeros(numPairs,5);
|
||||
LLR_maxlogmap = zeros(numPairs,5);
|
||||
|
||||
for k = 1:numPairs
|
||||
symbol1 = 2*k-1;
|
||||
symbol2 = 2*k;
|
||||
|
||||
LLP1 = LLP(:,symbol1);
|
||||
LLP2 = LLP(:,symbol2);
|
||||
prob1 = state_prob(:,symbol1);
|
||||
prob2 = state_prob(:,symbol2);
|
||||
|
||||
% All 36 Combinations: M = LLP Symbol 1 + LLP Symbol 2
|
||||
Mij = LLP1(pam6ind(:,1)) + LLP2(pam6ind(:,2));
|
||||
pij = prob1(pam6ind(:,1)) .* prob2(pam6ind(:,2));
|
||||
|
||||
% for each of the 5 bits sum exact-probs or max-log
|
||||
for b = 1:num_bits
|
||||
idx_sym_1 = bit_mapping(:,b)==1;
|
||||
idx_bit_1 = bit_mapping(:,b)==0;
|
||||
|
||||
% exact LLR from probabilities
|
||||
P1 = sum(pij(idx_sym_1)); %prob that bit == 1
|
||||
P0 = sum(pij(idx_bit_1));
|
||||
LLR_exact(k,b) = log(P1./P0); %ratio by multiplication
|
||||
|
||||
% max-log:
|
||||
LLR_maxlogmap(k,b) = max( Mij(idx_sym_1) ) - max( Mij(idx_bit_1) ); % ratio by subtraction
|
||||
end
|
||||
end
|
||||
|
||||
% GMI calc includes the Tx-bitstream
|
||||
tx_bits_pam6_reshaped = reshape(tx_bits',5,[])'; % N x 5
|
||||
MI = zeros(1, num_bits);
|
||||
for k = 1:num_bits
|
||||
|
||||
idx_bit_1 = (tx_bits_pam6_reshaped(:,k) == 0); %wo sind die 1en
|
||||
idx_sym_1 = (tx_bits_pam6_reshaped(:,k) == 1); %wo sind die 0en
|
||||
|
||||
%LLR's for all actually transmitted ones or zeros
|
||||
llr0 = LLR_exact(idx_bit_1,k);
|
||||
llr1 = LLR_exact(idx_sym_1,k);
|
||||
|
||||
% Calculate mutual information for bit position k
|
||||
I0 = mean(log2(1 + exp(llr0))); % exp(--LLR) = exp(positive) > 1
|
||||
I1 = mean(log2(1 + exp(-llr1))); % exp(-+LLR) = exp(negative) < 1
|
||||
MI(k) = 1 - 0.5 * (I0 + I1);
|
||||
end
|
||||
|
||||
GMI = sum(MI); % Total mutual information per symbol
|
||||
GMI = GMI/2; % GMI per single symbol not per two symbols
|
||||
|
||||
else
|
||||
|
||||
% Number of symbols and bits per symbol
|
||||
num_bits = log2(length(obj.trellis_states)); % 2 bits per symbol
|
||||
|
||||
% bit_mapping = PAMmapper(length(obj.trellis_states),0,"eth_style",0).showBitMapping;
|
||||
|
||||
% Initialize LLR storage
|
||||
LLR_maxlogmap = zeros(length(data_in),num_bits);
|
||||
LLR_exact = zeros(length(data_in),num_bits);
|
||||
|
||||
% Compute bit-wise LLRs
|
||||
for bit_idx = 1:num_bits
|
||||
|
||||
% Find indices where bit is 0 and where it is 1
|
||||
idx_bit_0 = bit_mapping(:,bit_idx) == 0;
|
||||
idx_bit_1 = bit_mapping(:,bit_idx) == 1;
|
||||
|
||||
% Sum over log-probabilities
|
||||
% Max-Log approximation uses the single max LLP value
|
||||
% instead of sum over all LLP's
|
||||
LLR_maxlogmap(:,bit_idx) = max(LLP(idx_bit_1,:), [], 1) - max(LLP(idx_bit_0,:), [], 1);
|
||||
|
||||
% Sum probabilities over states for which the bit is 1 and 0, respectively.
|
||||
P0 = sum(state_prob(idx_bit_0, :),1);
|
||||
P1 = sum(state_prob(idx_bit_1, :),1);
|
||||
LLR_exact(:,bit_idx) = log(P1./P0); % N x num_bits
|
||||
|
||||
|
||||
end
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
%%%%% CALC NGMI %%%%%
|
||||
|
||||
MI = zeros(1, num_bits);
|
||||
for k = 1:num_bits
|
||||
|
||||
idx_bit_0 = (tx_bits(:,k) == 0); %wo sind die 1en
|
||||
idx_bit_1 = (tx_bits(:,k) == 1); %wo sind die 0en
|
||||
|
||||
%LLR's for all actually transmitted ones or zeros
|
||||
llr0 = LLR_exact(idx_bit_0,k);
|
||||
llr1 = LLR_exact(idx_bit_1,k);
|
||||
|
||||
% mutual information for bit position k
|
||||
I0 = mean(log2(1 + exp(llr0))); % exp(--LLR) = exp(positive) > 1
|
||||
I1 = mean(log2(1 + exp(-llr1))); % exp(-+LLR) = exp(negative) < 1
|
||||
MI(k) = 1 - 0.5 * (I0 + I1); % assumes equally distributed ones and zeros
|
||||
end
|
||||
|
||||
GMI = sum(MI); % Total bitwise mutual information
|
||||
|
||||
end
|
||||
|
||||
|
||||
if debug
|
||||
%%% DEBUG PLOT LIKELIHOOD RATIOS %%%
|
||||
figure(115);clf
|
||||
subplot(2,1,1)
|
||||
for bit = 1:num_bits
|
||||
hold on;
|
||||
histogram(LLR_exact(:,bit),1000,"DisplayName",sprintf('Actual LLR of Bit Pos %d',bit),'LineStyle','none','FaceAlpha',0.4);
|
||||
end
|
||||
legend
|
||||
|
||||
subplot(2,1,2)
|
||||
for bit = 1:num_bits
|
||||
hold on;
|
||||
histogram(LLR_maxlogmap(:,bit),1000,"DisplayName",sprintf('Max Log LLR of Bit Pos %d',bit),'LineStyle','none','FaceAlpha',0.4);
|
||||
end
|
||||
legend
|
||||
|
||||
if obj.M == 6
|
||||
pairs = reshape(VITERBI_ESTIMATION_SYMBOLS,2,[]).';
|
||||
levels = sort(unique(VITERBI_ESTIMATION_SYMBOLS));
|
||||
isedge = ismember(pairs, [levels(1) levels(end)]);
|
||||
isforbidden = sum(isedge,2)==2;
|
||||
fprintf('Found %d forbidden transitions (even -> odd ; edge -> edge).\n', nnz(isforbidden));
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
||||
function [symbols_for_lvl,avg_for_lvl] = showLevelScatter_(~,eq_signal,ref_symbols)
|
||||
|
||||
figure()
|
||||
|
||||
rx_symbols = eq_signal; %./ rms(eq_signal);
|
||||
correct_symbols = ref_symbols;
|
||||
|
||||
% col = cbrewer2('Paired',numel(unique(correct_symbols))*2);
|
||||
col = ...
|
||||
[0.6510 0.8078 0.8902; ...
|
||||
0.1216 0.4706 0.7059; ...
|
||||
0.6980 0.8745 0.5412; ...
|
||||
0.2000 0.6275 0.1725; ...
|
||||
0.9843 0.6039 0.6000; ...
|
||||
0.8902 0.1020 0.1098; ...
|
||||
0.9922 0.7490 0.4353; ...
|
||||
1.0000 0.4980 0; ...
|
||||
0.7922 0.6980 0.8392; ...
|
||||
0.4157 0.2392 0.6039; ...
|
||||
1.0000 1.0000 0.6000; ...
|
||||
0.6941 0.3490 0.1569; ...
|
||||
0.6510 0.8078 0.8902; ...
|
||||
0.1216 0.4706 0.7059; ...
|
||||
0.6980 0.8745 0.5412; ...
|
||||
0.2000 0.6275 0.1725];
|
||||
ccnt = -1;
|
||||
|
||||
levels = unique(correct_symbols);
|
||||
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);
|
||||
std_lvl(l) = std(symbols_for_lvl(l,:),'omitnan');
|
||||
xax = 1:length(correct_symbols);
|
||||
|
||||
scatter(xax(start:ende),symbols_for_lvl(l,start:ende),10,'.','MarkerFaceAlpha',0.5,'MarkerEdgeAlpha',0.5,'MarkerEdgeColor',col(ccnt,:));
|
||||
hold on;
|
||||
|
||||
|
||||
end
|
||||
|
||||
std_lvl = round(std_lvl,2);
|
||||
|
||||
ccnt = 0;
|
||||
avg_for_lvl = NaN(numel(levels),length(correct_symbols));
|
||||
% Add the windowed/ smoothed curves
|
||||
for l = 1:numel(levels)
|
||||
ccnt = ccnt+2;
|
||||
level_amplitude = levels(l);
|
||||
|
||||
L = 500;
|
||||
movmean = 1/L .* movsum(rx_symbols(correct_symbols==level_amplitude),[L/2,L/2], 'Endpoints', 'fill');
|
||||
|
||||
avg_for_lvl(l,correct_symbols==level_amplitude) = movmean;
|
||||
|
||||
nanx = isnan(avg_for_lvl(l,:));
|
||||
t = 1:numel(avg_for_lvl(l,:));
|
||||
avg_for_lvl(l,nanx) = interp1(t(~nanx), avg_for_lvl(l,~nanx), t(nanx));
|
||||
|
||||
plot(xax(start:ende),avg_for_lvl(l,start:ende),'Color',col(ccnt,:));
|
||||
|
||||
hold on
|
||||
end
|
||||
|
||||
% yline(levels);
|
||||
xlabel('Samples');
|
||||
ylabel('Amplitude');
|
||||
ylim([-3 3]);
|
||||
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
end
|
||||
193
projects/ML_based_MLSE/minimal_example_huawei/minimal_example.m
Normal file
193
projects/ML_based_MLSE/minimal_example_huawei/minimal_example.m
Normal file
@@ -0,0 +1,193 @@
|
||||
|
||||
if 0
|
||||
% A) RUN FULL LOOP
|
||||
M_format = [2,4,6,8];
|
||||
snr = 10:25;
|
||||
else
|
||||
% B) RUN FOR DEBUG AND TEST
|
||||
M_format = 4;
|
||||
snr = 20;
|
||||
end
|
||||
|
||||
for m = 1:length(M_format)
|
||||
% --- Parameters ---
|
||||
M = M_format(m); % PAM order (e.g., 2,4,8)
|
||||
Nsym = 1e5; % number of symbols
|
||||
h = [1, 0.5, 0.2]; % Impulse response to remove
|
||||
|
||||
b = log2(M);
|
||||
if M == 6 b = 5; end
|
||||
rng(1);
|
||||
bits_tx = logical(randi([0 1], Nsym, b, 'uint8'));
|
||||
|
||||
tx_symbols = pammap(bits_tx,M);
|
||||
|
||||
if M == 6
|
||||
states = unique(tx_symbols);
|
||||
pam6transitions = combvec(states',states')'; % pam6transitions =
|
||||
bitmapping = pamdemap(reshape(pam6transitions',1,[])',M);
|
||||
else
|
||||
bitmapping = pamdemap(unique(tx_symbols),M);
|
||||
end
|
||||
|
||||
scaling = sqrt(sum(unique(tx_symbols).^2)/numel(unique(tx_symbols)));
|
||||
tx_symbols = tx_symbols ./ scaling;
|
||||
|
||||
% apply impulse response to signal
|
||||
y_filt = filter(h, 1, tx_symbols);
|
||||
|
||||
for s = 1:length(snr)
|
||||
|
||||
% apply noise
|
||||
y = awgn(y_filt,snr(s),"measured",1);
|
||||
|
||||
% apply ml-MLSE
|
||||
adaptive_mu = 0;
|
||||
mu_lms = 0.15;
|
||||
ml_mlse_equalizer = ml_mlse_pam("epochs_tr",50,"epochs_dd",1,"len_tr",length(y)/2,...
|
||||
"mu_dd",mu_lms,"mu_tr",mu_lms,"order",11,"sps",1,...
|
||||
"L",2,"delta",4,"adaptive_mu",adaptive_mu);
|
||||
|
||||
[ml_mlse_estimate,~] = ml_mlse_equalizer.process(y,tx_symbols);
|
||||
rx_symbols = ml_mlse_estimate .* scaling;
|
||||
bits_rx = pamdemap(rx_symbols,M);
|
||||
|
||||
BER_ml(m,s) = nnz(bits_tx ~= bits_rx) / numel(bits_tx);
|
||||
fprintf('BER = %.2e \n', BER_ml(m,s));
|
||||
|
||||
|
||||
% apply bcjr
|
||||
BCJR = bcjr_pam("DIR",h,"duobinary_output",0,"M",M,"trellis_states",unique(tx_symbols));
|
||||
[viterbi_estimate,LLR,GMI(m,s)] = BCJR.process(y,tx_symbols,bits_tx,bitmapping);
|
||||
|
||||
% decode LLR's
|
||||
bits_LLR = LLR > 0;
|
||||
|
||||
% demap viterbi symbols sequence
|
||||
rx_symbols = viterbi_estimate .* scaling;
|
||||
bits_rx = pamdemap(rx_symbols,M);
|
||||
|
||||
% BER calc
|
||||
BER_vit(m,s) = nnz(bits_tx ~= bits_LLR) / numel(bits_tx);
|
||||
fprintf('BER LLR = %.2e \n', BER_vit(m,s));
|
||||
|
||||
BER_llr(m,s) = nnz(bits_tx ~= bits_rx) / numel(bits_tx);
|
||||
fprintf('BER = %.2e \n', BER_llr(m,s));
|
||||
end
|
||||
end
|
||||
%%
|
||||
figure();hold on
|
||||
for m = 1:length(M_format)
|
||||
p=plot(snr,BER_llr(m,:),'DisplayName',sprintf('Viterbi: PAM %d',M_format(m)));
|
||||
plot(snr,BER_ml(m,:),'DisplayName',sprintf('ML-Based: PAM %d',M_format(m)),'LineStyle',':','Color',p.Color);
|
||||
end
|
||||
ylabel('BER');
|
||||
xlabel('SNR')
|
||||
title('BER vs. SNR');
|
||||
set(gca, 'XScale', 'linear', ...
|
||||
'YScale', 'log', ...
|
||||
'TickLabelInterpreter', 'latex', ...
|
||||
'FontSize', 11);
|
||||
|
||||
%%
|
||||
figure();hold on
|
||||
for m = 1:length(M_format)
|
||||
plot(snr,GMI(m,:),'DisplayName',sprintf('GMI PAM %d',M_format(m)))
|
||||
end
|
||||
ylabel('GMI');
|
||||
xlabel('SNR')
|
||||
title('GMI vs. SNR');
|
||||
set(gca, 'XScale', 'linear', ...
|
||||
'YScale', 'linear', ...
|
||||
'TickLabelInterpreter', 'latex', ...
|
||||
'FontSize', 11);
|
||||
|
||||
function symbols = pammap(bits,M)
|
||||
bits = logical(bits);
|
||||
if M == 2
|
||||
symbols = bits;
|
||||
elseif M == 4
|
||||
symbols= 2*bits(:,1) + (bits(:,1)==bits(:,2));
|
||||
symbols=2*symbols-3;
|
||||
|
||||
elseif M == 6
|
||||
|
||||
m = 1;
|
||||
|
||||
if size(bits,2)>size(bits,1)
|
||||
bits = bits'; %vector aufrecht stellen
|
||||
end
|
||||
bits = reshape(bits',1,[])';
|
||||
thres = [-3 5;-1 5;-3 -5;-1 -5;-5 3;-5 1;-5 -3;-5 -1;-1 3;-1 1;-1 -3;-1 -1;-3 3;-3 1;-3 -3;-3 -1;3 5;1 5;3 -5;1 -5;5 3;5 1;5 -3;5 -1;1 3;1 1;1 -3;1 -1;3 3;3 1;3 -3;3 -1];
|
||||
% LUT based mapping
|
||||
for k = 1:5:fix(length(bits)/5)*5
|
||||
symbols(m:m+1,1) = thres(bin2dec(int2str(bits(k:k+4)'))+1,:);
|
||||
m = m+2;
|
||||
end
|
||||
|
||||
elseif M == 8
|
||||
x1 = bits(:,1);
|
||||
x2 = (bits(:,1)==bits(:,3));
|
||||
x3 = x2~=bits(:,2);
|
||||
|
||||
symbols = 4*x1 + 2*x2 + x3;
|
||||
symbols=2*symbols-7;
|
||||
end
|
||||
end
|
||||
|
||||
function bits = pamdemap(symbols,M)
|
||||
|
||||
if M == 2
|
||||
thres=0;
|
||||
elseif M == 4
|
||||
thres=[-2,0,2];
|
||||
elseif M == 6
|
||||
thres = [-3 5;-1 5;-3 -5;-1 -5;-5 3;-5 1;-5 -3;-5 -1;-1 3;-1 1;-1 -3;-1 -1;-3 3;-3 1;-3 -3;-3 -1;3 5;1 5;3 -5;1 -5;5 3;5 1;5 -3;5 -1;1 3;1 1;1 -3;1 -1;3 3;3 1;3 -3;3 -1];
|
||||
elseif M == 8
|
||||
thres=-6:2:6;
|
||||
end
|
||||
|
||||
if M ~= 6
|
||||
symbols = symbols';
|
||||
a = squeeze(repmat(real(symbols),[1 1 length(thres)])); %Eingangssignal in 3 spalten
|
||||
b = squeeze(repmat(reshape(thres(:).',[1 1 length(thres)]),[1 length(symbols) 1])); %Threshold in 3 Spalten
|
||||
comp_real = a > b; %check for each symbol/ sampling if it exeeds the obj.thresholdseshold 1, 2 or 3
|
||||
comp_real=repmat(real(symbols),[1 1 length(thres)]) > repmat(reshape(thres(:).',[1 1 length(thres)]),[1 length(symbols) 1]);
|
||||
s1=size(comp_real,1);
|
||||
s2=size(comp_real,2);
|
||||
end
|
||||
|
||||
if M == 2
|
||||
data_out=abs(comp_real(:,:,1));
|
||||
elseif M == 4
|
||||
data_out=[comp_real(:,:,2); ones(s1,s2) - comp_real(:,:,1) + comp_real(:,:,3)];
|
||||
elseif M == 6
|
||||
|
||||
if size(symbols,2) > 1
|
||||
symbols = symbols.';
|
||||
end
|
||||
|
||||
if length(symbols)/2 ~= round(length(symbols)/2)
|
||||
symbols = [symbols;0];
|
||||
end
|
||||
|
||||
m = 1;
|
||||
for n = 1:2:length(symbols)
|
||||
dist = sqrt((symbols(n)-thres(:,1)).^2+(symbols(n+1)-thres(:,2)).^2);
|
||||
[~,dd_idx] = min(dist);
|
||||
% dec_out(n:n+1) = LUT(dd_idx,:);
|
||||
data_out(m:m+4) = bitget(dd_idx-1,5:-1:1);
|
||||
m = m+5;
|
||||
end
|
||||
|
||||
data_out = reshape(data_out',5,[]);
|
||||
|
||||
elseif M == 8
|
||||
data_out=[comp_real(:,:,4);
|
||||
comp_real(:,:,1)-comp_real(:,:,3)+comp_real(:,:,5)-comp_real(:,:,7);
|
||||
1-comp_real(:,:,2)+comp_real(:,:,6)];
|
||||
end
|
||||
|
||||
bits = data_out';
|
||||
|
||||
end
|
||||
473
projects/ML_based_MLSE/minimal_example_huawei/ml_mlse_pam.m
Normal file
473
projects/ML_based_MLSE/minimal_example_huawei/ml_mlse_pam.m
Normal file
@@ -0,0 +1,473 @@
|
||||
classdef ml_mlse_pam < handle
|
||||
|
||||
% ALGORITHM DESCRIBED IN:
|
||||
% W. Lanneer and Y. Lefevre, “Machine Learning-Based Pre-Equalizers for
|
||||
% Maximum Likelihood Sequence Estimation in High-Speed PONs,”
|
||||
% in 2023 31st European Signal Processing Conference
|
||||
|
||||
% Further ML Refs:
|
||||
% https://machinelearningmastery.com/cross-entropy-for-machine-learning/
|
||||
% https://docs.pytorch.org/docs/stable/generated/torch.nn.CrossEntropyLoss.html
|
||||
|
||||
% The central idea is to overcome the (white-) noise assumption within the previously described
|
||||
% Viterbi algorithm, more precisely a closed-loop optimization is proposed that finds a suitable
|
||||
% filter-set to directly compute the branch metrics c_k (s,s^' ). These can directly be used to
|
||||
% carry out the conventional Viterbi algorithm. The system consists of S^L S=F linear FIR filters,
|
||||
% combined with one bias coefficient respectively. These filters take the received input samples to
|
||||
% compute the branch metrics estimates (c_k ) ̂(s,s^' ) according toThe central idea is to overcome
|
||||
% the (white-) noise assumption within the previously described Viterbi algorithm, more precisely
|
||||
% a closed-loop optimization is proposed that finds a suitable filter-set to directly compute the
|
||||
% branch metrics c_k (s,s^' ). These can directly be used to carry out the conventional Viterbi
|
||||
% algorithm. The system consists of S^L S=F linear FIR filters, combined with one bias coefficient
|
||||
% respectively. These filters take the received input samples to compute the branch metrics
|
||||
% estimates. Finally, the usual Viterbi is carried out...
|
||||
|
||||
% Recommended Settings and some findings:
|
||||
|
||||
% Requires many training epochs. According to ML people, 100,200 or
|
||||
% even up to 1000 epochs are normal for ML-convergence
|
||||
|
||||
% The mu parameter _can_ be adaptive - using the cross entropy and when
|
||||
% analyzing the isolated training it looks very promisig. However, is
|
||||
% later use I found this is not as stable as a fixed learning rate.
|
||||
% mu = 0.1 worked good for me
|
||||
|
||||
% Longer orders/ filter length are not always better. For me order=11
|
||||
% was good.
|
||||
|
||||
% Delay factor (delta) is good when the order is also increased. With
|
||||
% order = 11, a delta of =4 shows good results
|
||||
|
||||
properties
|
||||
sps % usually 2
|
||||
order
|
||||
e
|
||||
e_tr
|
||||
error
|
||||
|
||||
len_tr
|
||||
mu_tr
|
||||
epochs_tr
|
||||
|
||||
% dd_mode -> not implemented here!
|
||||
mu_dd %weight update in dd mode
|
||||
epochs_dd
|
||||
|
||||
adaptive_mu
|
||||
|
||||
constellation
|
||||
|
||||
L %viterbi memory length
|
||||
|
||||
alpha
|
||||
DIR
|
||||
DIR_flip
|
||||
trellis_states
|
||||
|
||||
traceback_depth
|
||||
|
||||
S
|
||||
Nf
|
||||
delta
|
||||
nStates
|
||||
nFeasible
|
||||
combs
|
||||
first_sym
|
||||
last_sym
|
||||
valid
|
||||
valid_to_idx
|
||||
valid_from_idx
|
||||
w
|
||||
nbiasTerms
|
||||
|
||||
true_to_state_idx
|
||||
state_dict % containers.Map: key(sequence)->state index
|
||||
key_fmt = '%.8g_'; % key format for sequence strings
|
||||
nSym % |constellation|
|
||||
|
||||
ber = []
|
||||
ce = ones(1,1);
|
||||
end
|
||||
|
||||
methods
|
||||
function obj = ml_mlse_pam(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.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
|
||||
|
||||
function [x_viterbi,x_ref] = process(obj, X, D)
|
||||
|
||||
% actual processing of the signal (steps 1. - 3.)
|
||||
% 1 normalize RMS
|
||||
X = X./rms(X);
|
||||
|
||||
% Use sorted constellation for deterministic mapping
|
||||
obj.constellation = sort(unique(D),'ascend');
|
||||
obj.nSym = numel(obj.constellation);
|
||||
|
||||
if length(X)/length(D) ~= obj.sps
|
||||
warning('Signal length does not fit to reference!');
|
||||
end
|
||||
|
||||
% ==============================================================
|
||||
% INITIALIZATION
|
||||
% ==============================================================
|
||||
|
||||
% --- Parameters
|
||||
obj.S = numel(obj.constellation); % Num of Symbols
|
||||
obj.Nf = obj.order*obj.sps; % filter length (auto adapt for n-SPS...)
|
||||
obj.nStates = obj.S^obj.L; % S^L states
|
||||
obj.nFeasible = obj.nStates*obj.S; % S^(L+1) feasible states
|
||||
|
||||
% --- Trellis mapping
|
||||
obj.trellis_states = reshape(obj.constellation,1,[]); % make row vector
|
||||
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{:}).'); % rows: states, columns: [x_k, x_{k-1}, ...]
|
||||
obj.first_sym = obj.combs(:,1);
|
||||
obj.last_sym = obj.combs(:,end);
|
||||
obj.nStates = size(obj.combs,1);
|
||||
|
||||
% --- Valid transitions; adapted from the old Viterbi in
|
||||
% Move-It where the "noise free received" states are calculated
|
||||
% using the same loop and clause
|
||||
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);
|
||||
|
||||
% Allocate vectors and weights
|
||||
% !! IF SHAPE FIT, then we already have smth there an we want
|
||||
% to start with the existing filter-set (saves comp. time/ or to test fixed filter on new data)
|
||||
obj.nbiasTerms = 1;
|
||||
if isempty(obj.w) || any(size(obj.w) ~= [obj.Nf+obj.nbiasTerms,obj.nFeasible])
|
||||
obj.w = zeros(obj.Nf+obj.nbiasTerms,obj.nFeasible); % filter weights per transition + bias tap
|
||||
% obj.w = randn(obj.Nf+obj.nbiasTerms,obj.nFeasible);
|
||||
end
|
||||
|
||||
% This is a weird workaround - but it works and is much faster
|
||||
% than findig the state indices every time:
|
||||
% Precompute dictionary for fast state lookup (sequence -> state)
|
||||
keys = cell(obj.nStates,1);
|
||||
for i = 1:obj.nStates
|
||||
keys{i} = obj.seq_key(obj.combs(i,:)); % combs row is already [x_k, x_{k-1}, ...]
|
||||
end
|
||||
obj.state_dict = containers.Map(keys, 1:obj.nStates);
|
||||
|
||||
% ==============================================================
|
||||
% TRAINING
|
||||
% ==============================================================
|
||||
|
||||
n = obj.len_tr;
|
||||
training = 1;
|
||||
obj.equalize(X, D,obj.mu_tr,obj.epochs_tr,n,training);
|
||||
obj.e_tr = obj.e;
|
||||
|
||||
% ==============================================================
|
||||
% Testing; Fixed Mode
|
||||
% ==============================================================
|
||||
|
||||
n = length(X);
|
||||
training = 0;
|
||||
obj.mu_dd = obj.mu_tr; %For now no DD mode is implemented...
|
||||
[x_viterbi,x_ref]=obj.equalize(X, D,obj.mu_dd,obj.epochs_dd,n,training);
|
||||
|
||||
end
|
||||
|
||||
function [y,y_ref] = equalize(obj,x,d,mu,epochs,N,training)
|
||||
% ==============================================================
|
||||
% ML-Based Branch Metric Estimation + Viterbi
|
||||
% ==============================================================
|
||||
debug = 1;
|
||||
showPlots = 1;
|
||||
|
||||
nSymbols = ceil(N/obj.sps);
|
||||
|
||||
for epoch = 1:epochs
|
||||
|
||||
% state metrics (log-domain costs): keep as column [nStatesx1]
|
||||
pm = zeros(obj.nStates,1);
|
||||
v_tilde = zeros(1,obj.nFeasible);
|
||||
pred = zeros(nSymbols, obj.nStates);
|
||||
pm_sto = nan(obj.nStates, nSymbols);
|
||||
CE_accum = 0;
|
||||
|
||||
% START IDX can be randomized during training, but this
|
||||
% requires some testing - it is not better, maybe a
|
||||
% solutiuon is to use the same window for 10-20 epochs
|
||||
% and then switch to another window
|
||||
% for now: simply use the first parts of the signal for
|
||||
% training and also for testing... not "the
|
||||
randomize_training_window = 0;
|
||||
if randomize_training_window && training
|
||||
max_start = length(x) - ( (ceil(N/obj.sps)-1)*obj.sps + 1 );
|
||||
max_start = max(1, max_start); % safety
|
||||
start_sample = randi([1, max_start], 1); %rnd training; not really good
|
||||
else
|
||||
start_sample = 1;
|
||||
end
|
||||
|
||||
end_sample = start_sample + (ceil(N/obj.sps)-1)*obj.sps;
|
||||
start_symbol = 1 + floor((start_sample - 1)/obj.sps); % ABSOLUTE symbol index
|
||||
|
||||
symbol = 0;
|
||||
for sample = start_sample:obj.sps:end_sample
|
||||
symbol = symbol + 1;
|
||||
k = symbol;
|
||||
sym_idx = start_symbol + (symbol - 1);
|
||||
|
||||
% input signal window y_k; delayed by 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)]; % Nfx1
|
||||
yk = [yk;ones( obj.nbiasTerms,1)];
|
||||
|
||||
% Apply Filter; Predict branch metrics for all feasible transitions: c_hat
|
||||
% Formula (8)
|
||||
c_hat = (yk.' * obj.w); % [1xnFeasible]
|
||||
c_hat = c_hat.'; % [nFeasiblex1]
|
||||
|
||||
% Extended path metrics: v_tilde = pm(from) + c_hat
|
||||
v_tilde = pm(obj.valid_from_idx) + c_hat; % [nFeasiblex1]
|
||||
|
||||
% ===== Cross Entropy Loss Update =====
|
||||
|
||||
if 1 %training
|
||||
% --- allocate storage once
|
||||
if epoch == 1 && symbol == 1
|
||||
obj.true_to_state_idx = ones(ceil(N/obj.sps),1,'uint32');
|
||||
end
|
||||
|
||||
% --- previous "to" becomes current "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
|
||||
% only compute in first epoch
|
||||
if sym_idx >= obj.L
|
||||
key_to = obj.seq_key(flip(d(sym_idx-obj.L+1 : sym_idx)));
|
||||
if isKey(obj.state_dict, key_to)
|
||||
obj.true_to_state_idx(symbol) = obj.state_dict(key_to);
|
||||
else
|
||||
obj.true_to_state_idx(symbol) = true_from_state_idx;
|
||||
end
|
||||
else
|
||||
obj.true_to_state_idx(symbol) = true_from_state_idx;
|
||||
end
|
||||
end
|
||||
|
||||
% --- ensure valid (from,to)
|
||||
dirac = zeros(obj.nFeasible,1);
|
||||
mask = obj.valid_from_idx==true_from_state_idx & ...
|
||||
obj.valid_to_idx == obj.true_to_state_idx(symbol);
|
||||
if any(mask)
|
||||
dirac(mask) = 1;
|
||||
else
|
||||
idx = find(obj.valid_from_idx==true_from_state_idx,1,'first');
|
||||
dirac(idx) = 1;
|
||||
obj.true_to_state_idx(symbol) = obj.valid_to_idx(idx);
|
||||
end
|
||||
|
||||
% softmax over -v_tilde (numerically safe shift)
|
||||
v_shift = -(v_tilde - min(v_tilde)); % shift to small positive numbers
|
||||
v_shift = min(v_shift, 100); % clamp exponent argument to avoid extreme numbers/ overflow (exp(50)=5e21)
|
||||
expv = exp(v_shift);
|
||||
p = expv ./ (sum(expv) + eps);
|
||||
|
||||
% Cross entropy
|
||||
CE_symbol(symbol) = -log(p(dirac==1) + eps);
|
||||
|
||||
if sym_idx > obj.L
|
||||
CE_smooth(symbol) = 0.01*CE_symbol(symbol) + 0.99*CE_smooth(symbol-1);
|
||||
else
|
||||
if epoch > 1
|
||||
CE_smooth(symbol) = obj.ce(end); %stitch together ce from last epoch? or =1 for very first round?!
|
||||
else
|
||||
CE_smooth(symbol) = CE_symbol(symbol);
|
||||
end
|
||||
end
|
||||
|
||||
CE_accum = CE_symbol(symbol) + CE_accum;
|
||||
|
||||
% Formula (10)
|
||||
% gradient term (t - p)
|
||||
dmp = (dirac - p)'; % 1xnFeasible
|
||||
|
||||
% Formula (10)
|
||||
dL_Dw = (yk) .* dmp;
|
||||
|
||||
% Start updates only when the symbol index has ≥ L history
|
||||
if sym_idx >= obj.L
|
||||
if obj.adaptive_mu
|
||||
mu_eff = CE_smooth(sym_idx);
|
||||
mu_eff = max(min(mu_eff, 0.2), 1e-4);
|
||||
else
|
||||
mu_eff = mu;
|
||||
end
|
||||
|
||||
% see Algorithm 1 in paper
|
||||
obj.w = obj.w - mu_eff .* dL_Dw; % (Nf+1)xnFeasible
|
||||
end
|
||||
|
||||
% if debug && epoch > 2
|
||||
% figure(100);
|
||||
% subplot(4,1,1);
|
||||
% heatmap(p');
|
||||
% title('Probs')
|
||||
% subplot(4,1,2);
|
||||
% heatmap(dmp);
|
||||
% title('Update')
|
||||
% subplot(4,1,3);
|
||||
% heatmap(dL_Dw);
|
||||
% title('Update')
|
||||
% subplot(4,1,4);
|
||||
% heatmap(bj.w);
|
||||
% title('Update')
|
||||
%
|
||||
% end
|
||||
|
||||
end
|
||||
|
||||
% Compare-Select
|
||||
v_tilde_mat = inf(obj.nStates, obj.nStates);
|
||||
v_tilde_mat(obj.valid) = v_tilde; %reshapes to usual (from x to) matrix
|
||||
[pm_next, pred(k,:)] = min(v_tilde_mat, [], 2); %here, calc min for each column
|
||||
|
||||
% re-center, otherwise it will overflow
|
||||
pm_next = pm_next - min(pm_next);
|
||||
|
||||
pm = pm_next;
|
||||
pm_sto(:,symbol) = pm;
|
||||
end
|
||||
|
||||
% Traceback
|
||||
[~, s_end] = min(pm);
|
||||
viterbi_path = zeros(symbol,1);
|
||||
viterbi_path(symbol) = s_end;
|
||||
for n = symbol:-1:2
|
||||
viterbi_path(n-1) = pred(n, viterbi_path(n));
|
||||
end
|
||||
|
||||
% cut here to have the same indices when shuffling/
|
||||
% starting the start_symbol indx != 1
|
||||
y_ref = d(start_symbol:end);
|
||||
y = obj.first_sym(viterbi_path);
|
||||
|
||||
% Debug and Plots
|
||||
if debug && training
|
||||
sym_start = start_symbol;
|
||||
sym_end = start_symbol + symbol - 1;
|
||||
ref_slice = d(sym_start : sym_end);
|
||||
err = sum(y ~= ref_slice(1:numel(y)));
|
||||
|
||||
try %works with demapper, not provided in Deliverable
|
||||
ref_bits = PAMmapper(obj.S,0).demap(ref_slice);
|
||||
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: %.1e \n',epoch, ber);
|
||||
obj.ber(epoch) = ber;
|
||||
berlabel = 'BER';
|
||||
catch %fallback ser
|
||||
ser = err./length(y);
|
||||
fprintf('Epoch: %d - SER: %.1e \n',epoch, ser);
|
||||
obj.ber(epoch) = ser;
|
||||
berlabel = 'BER';
|
||||
end
|
||||
|
||||
obj.ce(epoch) = CE_accum./symbol;
|
||||
|
||||
if showPlots
|
||||
figure(10);clf
|
||||
subplot(3,2,1:2);
|
||||
heatmap(obj.w);
|
||||
title('Filter')
|
||||
|
||||
subplot(3,2,3);
|
||||
v_tildemat = NaN(obj.nStates, obj.nStates);
|
||||
v_tildemat(obj.valid) = v_tilde; % log-domain scores
|
||||
heatmap(v_tildemat);
|
||||
title('Extended Path Metrics v-tilde')
|
||||
|
||||
subplot(3,2,4);
|
||||
scatter(1:symbol,pm_sto,1,'.')
|
||||
title('Path Metric Winners v')
|
||||
|
||||
subplot(3,2,5);hold on
|
||||
scatter(1:symbol,CE_symbol,1,'.');
|
||||
scatter(1:symbol,CE_smooth,1,'.')
|
||||
title('Cross Entropy')
|
||||
ylabel('Cross Entropy')
|
||||
xlabel('Symbols')
|
||||
|
||||
subplot(3,2,6); hold on
|
||||
% Left y-axis: Cross Entropy
|
||||
yyaxis left
|
||||
scatter(1:length(obj.ce), obj.ce, 10, 's', 'filled')
|
||||
ylabel('Cross Entropy')
|
||||
|
||||
% Right y-axis: BER
|
||||
yyaxis right
|
||||
scatter(1:length(obj.ber), obj.ber, 10, 'd', 'filled')
|
||||
set(gca, 'YScale', 'log')
|
||||
ylabel(berlabel)
|
||||
|
||||
xlim([1, epochs])
|
||||
xlabel('Epoch')
|
||||
title('Cross Entropy // BER')
|
||||
grid on
|
||||
|
||||
drawnow
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
methods (Access=private)
|
||||
function k = seq_key(obj, seq)
|
||||
% Build a stable key string for a sequence row vector in the *same order as combs rows* ([x_k, x_{k-1}, ...])
|
||||
% Use rounding via sprintf to avoid floating-point issues.
|
||||
% seq must be a row vector.
|
||||
k = sprintf(obj.key_fmt, seq);
|
||||
end
|
||||
end
|
||||
end
|
||||
222
projects/ML_based_MLSE/model.m
Normal file
222
projects/ML_based_MLSE/model.m
Normal file
@@ -0,0 +1,222 @@
|
||||
%%% Run parameters
|
||||
% TX
|
||||
M = 4;
|
||||
|
||||
apply_pulsef = 1;
|
||||
fdac = 256e9;
|
||||
fadc = 256e9;
|
||||
random_key = 2;
|
||||
|
||||
rcalpha = 0.05;
|
||||
kover = 8;
|
||||
vbias_rel = 0.5;
|
||||
u_pi = 3.2;
|
||||
vbias = -vbias_rel*u_pi;
|
||||
laser_wavelength = 1310;
|
||||
laser_linewidth = 1e6;
|
||||
|
||||
% Channel
|
||||
link_length = 0;
|
||||
|
||||
|
||||
doub_mode = db_mode.no_db;
|
||||
cols = linspecer(6);
|
||||
rop = [-8];
|
||||
bwl = [0.5:0.1:1.5];
|
||||
fsym = [160:16:256].*1e9;
|
||||
% nonlin_mod = [0.5:0.01:0.75];
|
||||
nonlin_mod = ones(size(fsym)).*0.5;
|
||||
|
||||
ffe_results = {};
|
||||
mlse_results_lin= {};
|
||||
|
||||
for r = 1:length(fsym)
|
||||
|
||||
Pform = Pulseformer("fsym",fsym(r),"fdac",4*fsym(r),"pulse","rc","pulselength",16,"alpha",rcalpha);
|
||||
|
||||
db_precode = 0;
|
||||
db_encode = 0;
|
||||
duob_mode = db_mode.no_db;
|
||||
apply_pulsef = 1;
|
||||
|
||||
[Digi_sig,Symbols,Tx_bits] = PAMsource(...
|
||||
"fsym",fsym(r),"M",M,"order",18,"useprbs",0,...
|
||||
"fs_out",fdac,...
|
||||
"applyclipping",0,"clipfactor",1.5,...
|
||||
"applypulseform",apply_pulsef,"pulseformer",Pform,...
|
||||
"randkey",random_key,...
|
||||
"db_precode",db_precode,"db_encode",db_encode,...
|
||||
"mrds_code",0,"mrds_blocklength",512,"duobinary_mode",duob_mode).process();
|
||||
|
||||
El_sig = M8199B("kover",kover).process(Digi_sig);
|
||||
|
||||
%%%%% Electrical Driver Amplifier %%%%%%
|
||||
El_sig = El_sig.normalize("mode","oneone");
|
||||
|
||||
%%%%% MODULATE E/O CONVERSION %%%%%
|
||||
u_pi = 3.2;
|
||||
vbias = -u_pi*nonlin_mod(r);
|
||||
[Opt_sig] = EML("mode",eml_mode.im_cosinus,"power",3,"fsimu",El_sig.fs,"lambda",laser_wavelength,"bias",vbias,"u_pi",u_pi,"linewidth",laser_linewidth,"randomkey",random_key+1).process(El_sig);
|
||||
|
||||
%%%%%% Fiber %%%%%%
|
||||
Opt_sig = Fiber("fsimu",Opt_sig.fs,"fiber_length",link_length/1000,"alpha",0.3,"D",0,"lambda0",1310,"gamma",0,"Dslope",0.07).process(Opt_sig);
|
||||
|
||||
%%%%%% ROP %%%%%%
|
||||
Opt_sig = Amplifier("amp_mode","ideal_no_noise","gain_mode","output_power","amplification_db",rop).process(Opt_sig);
|
||||
|
||||
%%%%%% PD Square Law %%%%%%
|
||||
PD_sig = Photodiode("fsimu",fdac*kover,"dark_current",2e-08,"responsivity",1,"temperature",20,"nep",1.8e-11,"randomkey",random_key).process(Opt_sig);
|
||||
|
||||
%%%%%% Low-pass RX (PD, El. Connectors and Scope %%%%%%
|
||||
rx_bwl = 70e9;
|
||||
PD_sig = Filter('filtdegree',4,"f_cutoff",rx_bwl,"fs",fdac*kover,"filterType",filtertypes.butterworth,"active",true).process(PD_sig);
|
||||
|
||||
% %%%%%% Low-pass Scope %%%%%%
|
||||
Lp_scpe = Filter('filtdegree',4,"f_cutoff",110e9,"fs",fadc,"filterType",filtertypes.butterworth,"active",true);
|
||||
|
||||
%%%%%% Scope %%%%%%
|
||||
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(PD_sig);
|
||||
|
||||
Scpe_sig_2sps = Scpe_sig.resample("fs_out",2*fsym(r));
|
||||
|
||||
% 2sps
|
||||
[~, Scpe_cell, ~, found_sync] = Scpe_sig_2sps.tsynch("reference", Symbols, "fs_ref", fsym(r), "debug_plots", 1);
|
||||
Rx_sig_2sps = Scpe_cell{1};
|
||||
Rx_sig_2sps = Rx_sig_2sps.normalize("mode","rms");
|
||||
|
||||
% 1sps
|
||||
Scpe_sig_1sps = Scpe_sig.resample("fs_out",1*fsym(r));
|
||||
|
||||
[~, Scpe_cell_1sps, ~, found_sync] = Scpe_sig_1sps.tsynch("reference", Symbols, "fs_ref", fsym(r), "debug_plots", 1);
|
||||
Rx_sig_1sps = Scpe_cell_1sps{1};
|
||||
Rx_sig_1sps = Rx_sig_1sps.normalize("mode","rms");
|
||||
showLevelHistogram(Rx_sig_1sps,Symbols,"displayname",'ffe','fignum',111);
|
||||
|
||||
|
||||
%%
|
||||
|
||||
mu_lms = 0.0005;
|
||||
pf_ncoeffs = 2;
|
||||
eq_ = FFE("epochs_tr",5,"epochs_dd",5,"len_tr",2^13,"mu_dd",mu_lms,"mu_tr",mu_lms,"order",50,"sps",2,"dd_mode",1,"adaption_technique","lms");
|
||||
pf_ = Postfilter("ncoeff",pf_ncoeffs,"useBurg",1);
|
||||
|
||||
% FFE
|
||||
[y_ffe, ffe_noise] = eq_.process(Rx_sig_2sps, Symbols);
|
||||
|
||||
Eq_bits = PAMmapper(M, 0, "eth_style", 0).demap(y_ffe);
|
||||
[~, errors, ber_ffe, ~] = calc_ber(Eq_bits.signal, Tx_bits.signal, "skip_front", 0, "skip_end", 0, "returnErrorLocation", 1);
|
||||
fprintf('FFE: %.2e \n',ber_ffe);
|
||||
|
||||
% Postfilter
|
||||
[y_white,whitened_noise] = pf_.process(y_ffe, ffe_noise);
|
||||
|
||||
% Sequence Est
|
||||
mlse_ = MLSE("duobinary_output",0,'M',M,'trellis_states',PAMmapper(M,0).levels,'scale_mode',0,'trellis_exclusion',0,'trellis_state_mode',2,'debug',0,'DIR',pf_.coefficients);
|
||||
[y_mlse] = mlse_.process(y_white,Symbols);
|
||||
mlse_bits = PAMmapper(M, 0, "eth_style", 0).demap(y_mlse);
|
||||
[~, errors, ber_mlse_normal, errpos] = calc_ber(mlse_bits.signal, Tx_bits.signal, "skip_front", 10, "skip_end", 10, "returnErrorLocation", 1);
|
||||
fprintf('MLSE: %.2e \n',ber_mlse_normal);
|
||||
|
||||
showLevelHistogram(y_ffe,Symbols,"displayname",'ffe','fignum',111);
|
||||
|
||||
bursts = count_error_bursts(errpos, 10);
|
||||
e = zeros(size(mlse_bits.signal));
|
||||
e(errpos) = 1;
|
||||
figure(8)
|
||||
stem(e)
|
||||
|
||||
%% RUN ML-Based MLSE
|
||||
|
||||
mu_lms = 0.15;
|
||||
ml_mlse_equalizer = ML_MLSE("epochs_tr",50,"epochs_dd",10,"len_tr",Rx_sig_2sps.length-100,...
|
||||
"mu_dd",mu_lms,"mu_tr",mu_lms,"order",15,"sps",2,...
|
||||
"traceback_depth",128,"L",3,"delta",5);
|
||||
|
||||
%%
|
||||
ml_mlse_equalizer.epochs_tr = 50;
|
||||
ml_mlse_equalizer.epochs_dd = 1;
|
||||
[y_ml_mlse,Vit_signal] = ml_mlse_equalizer.process(Rx_sig_2sps,Symbols);
|
||||
ml_mlse_bits = PAMmapper(M, 0, "eth_style", 0).demap(y_ml_mlse);
|
||||
[~, errors, ber, errpos] = calc_ber(ml_mlse_bits.signal, Tx_bits.signal, "skip_front", 10, "skip_end", 10, "returnErrorLocation", 1);
|
||||
fprintf('ML MLSE BER: %.2e \n',ber);
|
||||
|
||||
bursts = count_error_bursts(errpos, 10);
|
||||
e = zeros(size(ml_mlse_bits.signal));
|
||||
e(errpos) = 1;
|
||||
figure(8)
|
||||
stem(e)
|
||||
|
||||
figure()
|
||||
plot(ml_mlse_equalizer.ber)
|
||||
beautifyBERplot
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
%% optimize delta
|
||||
deltas = [-1:4];
|
||||
ber = zeros(1,length(deltas));
|
||||
parfor m = 1:numel(deltas)
|
||||
|
||||
mu_lms = 0.2;
|
||||
ml_mlse_equalizer = ML_MLSE("epochs_tr",2,"epochs_dd",5,"len_tr",2^13,...
|
||||
"mu_dd",mu_lms,"mu_tr",mu_lms,"order",4,"sps",1,...
|
||||
"traceback_depth",128,"L",3,"delta",deltas(m));
|
||||
|
||||
[y_ml_mlse,Vit_signal] = ml_mlse_equalizer.process(y_ffe,Symbols);
|
||||
y_ml_mlse_ = y_ml_mlse;
|
||||
y_ml_mlse_.signal = circshift(y_ml_mlse.signal,0);
|
||||
mlse_bits = PAMmapper(M, 0, "eth_style", 0).demap(y_ml_mlse_);
|
||||
[~, errors, ber(m), errpos] = calc_ber(mlse_bits.signal, Tx_bits.signal, "skip_front", 0, "skip_end", 0, "returnErrorLocation", 1);
|
||||
fprintf('ML MLSE: %.2e \n',ber(m));
|
||||
end
|
||||
|
||||
|
||||
figure(7); hold on
|
||||
title('ML MLSE')
|
||||
plot(deltas,ber,'DisplayName','BER');
|
||||
yline(ber_ffe,'DisplayName','BER FFE');
|
||||
yline(ber_mlse_normal,'DisplayName','BER MLSE');
|
||||
xlabel('deltas')
|
||||
beautifyBERplot
|
||||
legend
|
||||
ylim([1e-5, 1e-1]);
|
||||
set(gca,'YScale','log');
|
||||
|
||||
|
||||
|
||||
|
||||
%% RUN Comparison
|
||||
len_tr = 4096*2;
|
||||
|
||||
mu_ffe1 = 0.0001;
|
||||
mu_ffe2 = 0.0008;
|
||||
mu_ffe3 = 0.001;
|
||||
mu_dc = 0.005;
|
||||
% mu_dc = 0;
|
||||
|
||||
mu_ffe = [mu_ffe1 mu_ffe2 mu_ffe3];
|
||||
mu_dfe = 0.0004;
|
||||
pf_ncoeffs = 1;
|
||||
ffe_order = [50, 0, 0];
|
||||
mu_lms = 0.0005;
|
||||
eq_ = FFE("epochs_tr",5,"epochs_dd",5,"len_tr",2^13,"mu_dd",mu_lms,"mu_tr",mu_lms,"order",50,"sps",2,"dd_mode",1,"adaption_technique","lms");
|
||||
% eq_ = EQ("Ne",ffe_order,"Nb",[0,0,0],"training_length",len_tr,"training_loops",5,"dd_loops",5,"K",1,"DCmu",0.00,"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).levels,'scale_mode',0,'trellis_exclusion',0,'trellis_state_mode',2,'debug',0);
|
||||
|
||||
[ffe_results{r}, mlse_results_lin{r}] = vnle_postfilter_mlse(eq_, pf_, mlse_, M, Rx_sig_2sps, Symbols, Tx_bits, ...
|
||||
"precode_mode", duob_mode,...
|
||||
'showAnalysis', 0, ...
|
||||
"postFFE", [],...
|
||||
"eth_style_symbol_mapping", 0);
|
||||
|
||||
mlse_results_lin{r}.metrics.print;
|
||||
ffe_results{r}.metrics.print;
|
||||
|
||||
end
|
||||
116
projects/ML_based_MLSE/rate_evaluation.m
Normal file
116
projects/ML_based_MLSE/rate_evaluation.m
Normal file
@@ -0,0 +1,116 @@
|
||||
|
||||
ber_ffe = [];
|
||||
ber_mlse = [];
|
||||
ber_dbtgt = [];
|
||||
ber_ml = [];
|
||||
|
||||
mlse = 1;
|
||||
dbtgt = 0;
|
||||
duob_mode = db_mode.no_db;
|
||||
baudrates = [136:8:224].*1e9;
|
||||
for i = 1:length(baudrates)
|
||||
|
||||
rop = -8;
|
||||
M = 4;
|
||||
[Rx_sig_2sps_v1, Symbols_v1, Tx_bits_v1] = standard_link_model("M",M,"fsym",baudrates(i),"rop",rop,"laser_linewidth",1310,"link_length_m",0,"random_key",1,"apply_pulsef",1);
|
||||
% [Rx_sig_2sps_v2, Symbols_v2, Tx_bits_v2] = standard_link_model("M",M,"fsym",200e9,"rop",rop,"laser_linewidth",1300,"link_length_m",0,"random_key",2);
|
||||
% [Rx_sig_2sps_v3, Symbols_v3, Tx_bits_v3] = standard_link_model("M",M,"fsym",200e9,"rop",rop,"laser_linewidth",1300,"link_length_m",0,"random_key",3);
|
||||
|
||||
%% FFE + MLSE
|
||||
if mlse
|
||||
pf_ncoeffs = 1;
|
||||
ffe_order = [50, 0, 0];
|
||||
mu_ffe = [0.0001, 0.0008, 0.001];
|
||||
mu_dfe = 0.0004;
|
||||
eq_ = EQ("Ne",ffe_order,"Nb",[0,0,0],"training_length",2^13,"training_loops",5,"dd_loops",5,"K",2,"DCmu",0.005,"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).levels,'scale_mode',2,'trellis_exclusion',0,'trellis_state_mode',2,'debug',0,'DIR',pf_.coefficients);
|
||||
|
||||
[ffe_results, mlse_results] = vnle_postfilter_mlse(eq_, pf_, mlse_, M, Rx_sig_2sps_v1, Symbols_v1, Tx_bits_v1, ...
|
||||
"precode_mode", duob_mode,...
|
||||
'showAnalysis', 0, ...
|
||||
"postFFE", [],...
|
||||
"eth_style_symbol_mapping", 0);
|
||||
|
||||
ber_ffe(i) = ffe_results.metrics.BER;
|
||||
ber_mlse(i) = mlse_results.metrics.BER;
|
||||
|
||||
fprintf('BER FFE: %.2e \n',ber_ffe(i));
|
||||
fprintf('BER MLSE: %.2e \n',ber_mlse(i));
|
||||
end
|
||||
|
||||
|
||||
%% FFE DB tgt. + MLSE
|
||||
if dbtgt
|
||||
mlse_db_ = MLSE("DIR",[1,1],"duobinary_output",0,"M",M,"trellis_states",PAMmapper(M,0).levels,'scale_mode',2,'trellis_exclusion',0,'trellis_state_mode',3);
|
||||
ffe_order = [50, 0, 0];
|
||||
mu_ffe = [0.0001, 0.0008, 0.001];
|
||||
mu_dfe = 0.0004;
|
||||
eq_ = EQ("Ne",ffe_order,"Nb",[0,0,0],"training_length",2^13,"training_loops",5,"dd_loops",5,"K",2,"DCmu",0.005,"DDmu",[mu_ffe mu_dfe],"DFEmu",0.005,"FFEmu",0,"plotfinal",0,"ideal_dfe",1);
|
||||
|
||||
dbt_results = duobinary_target(eq_, mlse_db_, M, Rx_sig_2sps_v1, Symbols_v1, Tx_bits_v1, ...
|
||||
"precode_mode", duob_mode, ...
|
||||
'showAnalysis', 0,...
|
||||
"postFFE", []);
|
||||
|
||||
ber_dbtgt(i) = dbt_results.metrics.BER;
|
||||
end
|
||||
|
||||
|
||||
%%
|
||||
mu_lms = 0.0005;
|
||||
pf_ncoeffs = 2;
|
||||
eq_ = FFE("epochs_tr",5,"epochs_dd",5,"len_tr",2^13,"mu_dd",mu_lms,"mu_tr",mu_lms,"order",50,"sps",2,"dd_mode",1,"adaption_technique","lms");
|
||||
pf_ = Postfilter("ncoeff",pf_ncoeffs,"useBurg",1);
|
||||
|
||||
% FFE
|
||||
[y_ffe, ffe_noise] = eq_.process(Rx_sig_2sps_v1, Symbols_v1);
|
||||
|
||||
|
||||
% Postfilter
|
||||
[y_white,whitened_noise] = pf_.process(y_ffe, ffe_noise);
|
||||
|
||||
%% RUN ML-Based MLSE
|
||||
|
||||
mu_lms = 0.15;
|
||||
ml_mlse_equalizer = ML_MLSE("epochs_tr",50,"epochs_dd",1,"len_tr",2^16,...
|
||||
"mu_dd",mu_lms,"mu_tr",mu_lms,"order",4,"sps",2,...
|
||||
"traceback_depth",128,"L",2,"delta",0);
|
||||
|
||||
ml_mlse_equalizer.mu_tr = 0.005;
|
||||
ml_mlse_equalizer.epochs_tr = 2;
|
||||
ml_mlse_equalizer.epochs_dd = 1;
|
||||
[y_ml_mlse,~] = ml_mlse_equalizer.process(Rx_sig_2sps_v1,Symbols_v1);
|
||||
ml_mlse_bits = PAMmapper(M, 0, "eth_style", 0).demap(y_ml_mlse);
|
||||
[~, errors, ber_ml(i), errpos] = calc_ber(ml_mlse_bits.signal, Tx_bits_v1.signal, "skip_front", 10, "skip_end", 10, "returnErrorLocation", 1);
|
||||
fprintf('ML MLSE BER: %.2e \n',ber_ml(i));
|
||||
|
||||
% figure(11);hold on
|
||||
% plot(1:numel(ml_mlse_equalizer.ber),ml_mlse_equalizer.ber);
|
||||
% beautifyBERplot;
|
||||
% xlim([1,numel(ml_mlse_equalizer.ber)])
|
||||
|
||||
end
|
||||
|
||||
%%
|
||||
|
||||
figure(6); hold on;
|
||||
if mlse
|
||||
plot(baudrates,ber_ffe,'DisplayName','FFE');
|
||||
plot(baudrates,ber_mlse,'DisplayName','MLSE');
|
||||
end
|
||||
if dbtgt
|
||||
plot(baudrates,ber_dbtgt,'DisplayName','DB tgt');
|
||||
end
|
||||
plot(baudrates,ber_ml,'DisplayName','ML-MLSE');
|
||||
beautifyBERplot;
|
||||
legend
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
30
projects/ML_based_MLSE/read_csv.m
Normal file
30
projects/ML_based_MLSE/read_csv.m
Normal file
@@ -0,0 +1,30 @@
|
||||
%% read_wpd_csv.m
|
||||
% Minimal importer for WebPlotDigitizer multi-curve CSV
|
||||
|
||||
filename = 'wpd_datasets.csv'; % <-- set your file path here
|
||||
T = readtable(filename);
|
||||
|
||||
% Read header row manually
|
||||
fid = fopen(filename);
|
||||
hdr1 = strsplit(strrep(fgetl(fid), '"', ''), ','); % curve names
|
||||
hdr2 = strsplit(strrep(fgetl(fid), '"', ''), ','); % X/Y header row
|
||||
fclose(fid);
|
||||
|
||||
% Extract unique curve names
|
||||
names = hdr1(~cellfun('isempty',hdr1));
|
||||
|
||||
% Create struct for each curve
|
||||
mii = struct();
|
||||
for i = 1:numel(names)
|
||||
base = matlab.lang.makeValidName(strrep(names{i},' ','_'));
|
||||
xi = 2*(i-1)+1; % X column
|
||||
yi = xi+1; % Y column
|
||||
mii.(base).X = T{:,xi};
|
||||
mii.(base).Y = T{:,yi};
|
||||
|
||||
% also create workspace variable "name_wpd"
|
||||
assignin('base',[base '_wpd'], mii.(base));
|
||||
end
|
||||
|
||||
disp('Imported datasets:');
|
||||
disp(fieldnames(mii));
|
||||
139
projects/ML_based_MLSE/rop_evaluation.m
Normal file
139
projects/ML_based_MLSE/rop_evaluation.m
Normal file
@@ -0,0 +1,139 @@
|
||||
clear; clc;
|
||||
|
||||
M = 4;
|
||||
randkey = 1;
|
||||
duob_mode = db_mode.no_db;
|
||||
|
||||
mlse = 1;
|
||||
dbtgt = 1;
|
||||
|
||||
baudrates = 180e9:2e9:220e9; % outer loop
|
||||
rops = linspace(-10,0,12); % inner sweep
|
||||
FEC_thr = 3.8e-3; % BER target
|
||||
|
||||
% --- allocate results
|
||||
reqROP_FFE = nan(size(baudrates));
|
||||
reqROP_MLSE = nan(size(baudrates));
|
||||
reqROP_DBTGT = nan(size(baudrates));
|
||||
reqROP_ML_MLSE2 = nan(size(baudrates));
|
||||
reqROP_ML_MLSE3 = nan(size(baudrates));
|
||||
|
||||
%% ====================== OUTER LOOP ======================
|
||||
for b = 1:numel(baudrates)
|
||||
baudrate = baudrates(b);
|
||||
fprintf('\n=== %.0f GBd ===\n', baudrate/1e9);
|
||||
|
||||
ber_ffe = nan(size(rops));
|
||||
ber_mlse = nan(size(rops));
|
||||
ber_dbtgt = nan(size(rops));
|
||||
ber_ml2 = nan(size(rops));
|
||||
ber_ml3 = nan(size(rops));
|
||||
|
||||
%% -------- inner ROP loop --------
|
||||
for i = 1:length(rops)
|
||||
rop = rops(i);
|
||||
|
||||
[Rx_sig_2sps_v1, Symbols_v1, Tx_bits_v1] = standard_link_model( ...
|
||||
"M",M,"fsym",baudrate,"rop",rop,"laser_linewidth",1310, ...
|
||||
"link_length_m",0,"random_key",1);
|
||||
|
||||
|
||||
|
||||
%% FFE + MLSE
|
||||
if mlse
|
||||
pf_ncoeffs = 1;
|
||||
ffe_order = [50, 0, 0];
|
||||
mu_ffe = [0.0001, 0.0008, 0.001];
|
||||
mu_dfe = 0.0004;
|
||||
eq_ = EQ("Ne",ffe_order,"Nb",[0,0,0],"training_length",2^13, ...
|
||||
"training_loops",5,"dd_loops",5,"K",2,"DCmu",0.005, ...
|
||||
"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).levels,'scale_mode',2, ...
|
||||
'trellis_exclusion',0,'trellis_state_mode',2,'debug',0, ...
|
||||
'DIR',pf_.coefficients);
|
||||
|
||||
[ffe_results, mlse_results] = vnle_postfilter_mlse(eq_, pf_, mlse_, M, ...
|
||||
Rx_sig_2sps_v1, Symbols_v1, Tx_bits_v1, ...
|
||||
"precode_mode", duob_mode,'showAnalysis', 0, "postFFE", [], ...
|
||||
"eth_style_symbol_mapping", 0);
|
||||
|
||||
ber_ffe(i) = ffe_results.metrics.BER;
|
||||
ber_mlse(i) = mlse_results.metrics.BER;
|
||||
end
|
||||
|
||||
%% FFE + duobinary target MLSE
|
||||
if dbtgt
|
||||
mlse_db_ = MLSE("DIR",[1,1],"duobinary_output",0,"M",M, ...
|
||||
"trellis_states",PAMmapper(M,0).levels,'scale_mode',2, ...
|
||||
'trellis_exclusion',0,'trellis_state_mode',3);
|
||||
ffe_order = [50, 0, 0];
|
||||
mu_ffe = [0.0001, 0.0008, 0.001];
|
||||
mu_dfe = 0.0004;
|
||||
eq_ = EQ("Ne",ffe_order,"Nb",[0,0,0],"training_length",2^13, ...
|
||||
"training_loops",5,"dd_loops",5,"K",2,"DCmu",0.005, ...
|
||||
"DDmu",[mu_ffe mu_dfe],"DFEmu",0.005,"FFEmu",0, ...
|
||||
"plotfinal",0,"ideal_dfe",1);
|
||||
|
||||
dbt_results = duobinary_target(eq_, mlse_db_, M, Rx_sig_2sps_v1, ...
|
||||
Symbols_v1, Tx_bits_v1, "precode_mode", duob_mode, ...
|
||||
'showAnalysis', 0, "postFFE", []);
|
||||
ber_dbtgt(i) = dbt_results.metrics.BER;
|
||||
end
|
||||
|
||||
%% ML-based MLSE (L=2)
|
||||
mu_ml = 0.1; training_epochs = 100;
|
||||
ml_mlse_equalizer = ML_MLSE("epochs_tr",training_epochs,"epochs_dd",1, ...
|
||||
"len_tr",2^16,"mu_dd",mu_ml,"mu_tr",mu_ml,"order",11,"sps",2, ...
|
||||
"traceback_depth",128,"L",2,"delta",4,"adaptive_mu",0);
|
||||
[y_ml_mlse,y_ref] = ml_mlse_equalizer.process(Rx_sig_2sps_v1,Symbols_v1);
|
||||
ref_bits = PAMmapper(M,0).demap(y_ref);
|
||||
ml_bits = PAMmapper(M,0).demap(y_ml_mlse);
|
||||
[~,~,ber_ml2(i)] = calc_ber(ml_bits.signal, ref_bits.signal, ...
|
||||
"skip_front",10,"skip_end",10);
|
||||
|
||||
%% ML-based MLSE (L=3)
|
||||
ml_mlse_equalizer = ML_MLSE("epochs_tr",training_epochs,"epochs_dd",1, ...
|
||||
"len_tr",2^16,"mu_dd",mu_ml,"mu_tr",mu_ml,"order",11,"sps",2, ...
|
||||
"traceback_depth",128,"L",3,"delta",4,"adaptive_mu",0);
|
||||
[y_ml_mlse,y_ref] = ml_mlse_equalizer.process(Rx_sig_2sps_v1,Symbols_v1);
|
||||
ref_bits = PAMmapper(M,0).demap(y_ref);
|
||||
ml_bits = PAMmapper(M,0).demap(y_ml_mlse);
|
||||
[~,~,ber_ml3(i)] = calc_ber(ml_bits.signal, ref_bits.signal, ...
|
||||
"skip_front",10,"skip_end",10);
|
||||
end % ROP loop
|
||||
|
||||
%% --- find required ROP (FEC crossing)
|
||||
reqROP_FFE(b) = interp_fec_cross(rops, ber_ffe, FEC_thr);
|
||||
reqROP_MLSE(b) = interp_fec_cross(rops, ber_mlse, FEC_thr);
|
||||
reqROP_DBTGT(b) = interp_fec_cross(rops, ber_dbtgt, FEC_thr);
|
||||
reqROP_ML_MLSE2(b) = interp_fec_cross(rops, ber_ml2, FEC_thr);
|
||||
reqROP_ML_MLSE3(b) = interp_fec_cross(rops, ber_ml3, FEC_thr);
|
||||
|
||||
% --- diagnostic
|
||||
fprintf('Baud %.0f GBd: FFE %.1f, MLSE %.1f, DB %.1f, ML2 %.1f, ML3 %.1f\n', ...
|
||||
baudrate/1e9, reqROP_FFE(b), reqROP_MLSE(b), reqROP_DBTGT(b), ...
|
||||
reqROP_ML_MLSE2(b), reqROP_ML_MLSE3(b));
|
||||
end
|
||||
|
||||
%% ====================== PLOT REQUIRED ROP ======================
|
||||
cols = cbrewer2('Set1',8);
|
||||
colFFE = cols(1,:);
|
||||
colMLSE = cols(2,:);
|
||||
colDBTGT = cols(4,:);
|
||||
colML_MLSE = cols(3,:);
|
||||
|
||||
figure(); hold on
|
||||
plot(baudrates/1e9, reqROP_FFE, '-o','Color',colFFE, 'DisplayName','FFE');
|
||||
plot(baudrates/1e9, reqROP_MLSE, '-s','Color',colMLSE, 'DisplayName','FFE+PF+MLSE');
|
||||
plot(baudrates/1e9, reqROP_DBTGT, '--^','Color',colDBTGT, 'DisplayName','DB tgt. MLSE');
|
||||
plot(baudrates/1e9, reqROP_ML_MLSE2, '-v','Color',colML_MLSE, 'DisplayName','ML-based MLSE (L=2)');
|
||||
plot(baudrates/1e9, reqROP_ML_MLSE3, '-d','Color',colML_MLSE*0.8,'DisplayName','ML-based MLSE (L=3)');
|
||||
|
||||
xlabel('Baud rate [GBd]');
|
||||
ylabel('Required ROP [dBm]');
|
||||
title('ROP required for FEC threshold');
|
||||
grid on; legend('Location','northwest');
|
||||
beautifyBERplot("logscale",0,"polyfit",1,"polyorder",4,"fitmethod",'polyfit');
|
||||
140
projects/ML_based_MLSE/rrop_vs_length_evaluation.m
Normal file
140
projects/ML_based_MLSE/rrop_vs_length_evaluation.m
Normal file
@@ -0,0 +1,140 @@
|
||||
clear; clc;
|
||||
|
||||
M = 4;
|
||||
randkey = 1;
|
||||
duob_mode = db_mode.no_db;
|
||||
|
||||
mlse = 1;
|
||||
dbtgt = 1;
|
||||
|
||||
link_lengths = 0:1:8; % [m] --- outer loop
|
||||
rops = linspace(-10, 0, 12); % [dBm] --- inner sweep
|
||||
FEC_thr = 3.8e-3; % BER target
|
||||
baudrate = 200e9;
|
||||
|
||||
% --- allocate results
|
||||
reqROP_FFE = nan(size(link_lengths));
|
||||
reqROP_MLSE = nan(size(link_lengths));
|
||||
reqROP_DBTGT = nan(size(link_lengths));
|
||||
reqROP_ML_MLSE2 = nan(size(link_lengths));
|
||||
reqROP_ML_MLSE3 = nan(size(link_lengths));
|
||||
|
||||
%% ====================== OUTER LOOP ======================
|
||||
for L = 1:numel(link_lengths)
|
||||
link_length_m = link_lengths(L);
|
||||
fprintf('\n=== %.0f m fiber length ===\n', link_length_m);
|
||||
|
||||
ber_ffe = nan(size(rops));
|
||||
ber_mlse = nan(size(rops));
|
||||
ber_dbtgt = nan(size(rops));
|
||||
ber_ml2 = nan(size(rops));
|
||||
ber_ml3 = nan(size(rops));
|
||||
|
||||
%% -------- inner ROP loop --------
|
||||
parfor i = 1:length(rops)
|
||||
rop = rops(i);
|
||||
|
||||
[Rx_sig_2sps_v1, Symbols_v1, Tx_bits_v1] = standard_link_model( ...
|
||||
"M",M,"fsym",baudrate,"rop",rop,"laser_wavelength",1290, ...
|
||||
"link_length_km",link_length_m,"random_key",1);
|
||||
|
||||
Rx_sig_2sps_v1.spectrum("displayname",'Rx Sig','normalizeTo0dB',1);
|
||||
|
||||
%% FFE + MLSE
|
||||
if mlse
|
||||
pf_ncoeffs = 1;
|
||||
ffe_order = [50, 0, 0];
|
||||
mu_ffe = [0.0001, 0.0008, 0.001];
|
||||
mu_dfe = 0.0004;
|
||||
eq_ = EQ("Ne",ffe_order,"Nb",[0,0,0],"training_length",2^13, ...
|
||||
"training_loops",5,"dd_loops",5,"K",2,"DCmu",0.005, ...
|
||||
"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).levels,'scale_mode',2, ...
|
||||
'trellis_exclusion',0,'trellis_state_mode',2,'debug',0, ...
|
||||
'DIR',pf_.coefficients);
|
||||
|
||||
[ffe_results, mlse_results] = vnle_postfilter_mlse(eq_, pf_, mlse_, M, ...
|
||||
Rx_sig_2sps_v1, Symbols_v1, Tx_bits_v1, ...
|
||||
"precode_mode", duob_mode,'showAnalysis', 0, "postFFE", [], ...
|
||||
"eth_style_symbol_mapping", 0);
|
||||
|
||||
ber_ffe(i) = ffe_results.metrics.BER;
|
||||
ber_mlse(i) = mlse_results.metrics.BER;
|
||||
end
|
||||
|
||||
%% FFE + duobinary target MLSE
|
||||
if dbtgt
|
||||
mlse_db_ = MLSE("DIR",[1,1],"duobinary_output",0,"M",M, ...
|
||||
"trellis_states",PAMmapper(M,0).levels,'scale_mode',2, ...
|
||||
'trellis_exclusion',0,'trellis_state_mode',3);
|
||||
ffe_order = [50, 0, 0];
|
||||
mu_ffe = [0.0001, 0.0008, 0.001];
|
||||
mu_dfe = 0.0004;
|
||||
eq_ = EQ("Ne",ffe_order,"Nb",[0,0,0],"training_length",2^13, ...
|
||||
"training_loops",5,"dd_loops",5,"K",2,"DCmu",0.005, ...
|
||||
"DDmu",[mu_ffe mu_dfe],"DFEmu",0.005,"FFEmu",0, ...
|
||||
"plotfinal",0,"ideal_dfe",1);
|
||||
|
||||
dbt_results = duobinary_target(eq_, mlse_db_, M, Rx_sig_2sps_v1, ...
|
||||
Symbols_v1, Tx_bits_v1, "precode_mode", duob_mode, ...
|
||||
'showAnalysis', 0, "postFFE", []);
|
||||
ber_dbtgt(i) = dbt_results.metrics.BER;
|
||||
end
|
||||
|
||||
%% ML-based MLSE (L=2)
|
||||
mu_ml = 0.1; training_epochs = 100;
|
||||
ml_mlse_equalizer = ML_MLSE("epochs_tr",training_epochs,"epochs_dd",1, ...
|
||||
"len_tr",2^16,"mu_dd",mu_ml,"mu_tr",mu_ml,"order",11,"sps",2, ...
|
||||
"traceback_depth",128,"L",2,"delta",4,"adaptive_mu",0);
|
||||
[y_ml_mlse,y_ref] = ml_mlse_equalizer.process(Rx_sig_2sps_v1,Symbols_v1);
|
||||
ref_bits = PAMmapper(M,0).demap(y_ref);
|
||||
ml_bits = PAMmapper(M,0).demap(y_ml_mlse);
|
||||
[~,~,ber_ml2(i)] = calc_ber(ml_bits.signal, ref_bits.signal, ...
|
||||
"skip_front",10,"skip_end",10);
|
||||
|
||||
%% ML-based MLSE (L=3)
|
||||
ml_mlse_equalizer = ML_MLSE("epochs_tr",training_epochs,"epochs_dd",1, ...
|
||||
"len_tr",2^16,"mu_dd",mu_ml,"mu_tr",mu_ml,"order",11,"sps",2, ...
|
||||
"traceback_depth",128,"L",3,"delta",4,"adaptive_mu",0);
|
||||
[y_ml_mlse,y_ref] = ml_mlse_equalizer.process(Rx_sig_2sps_v1,Symbols_v1);
|
||||
ref_bits = PAMmapper(M,0).demap(y_ref);
|
||||
ml_bits = PAMmapper(M,0).demap(y_ml_mlse);
|
||||
[~,~,ber_ml3(i)] = calc_ber(ml_bits.signal, ref_bits.signal, ...
|
||||
"skip_front",10,"skip_end",10);
|
||||
end % ROP loop
|
||||
|
||||
%% --- find required ROP (FEC crossing)
|
||||
reqROP_FFE(L) = interp_fec_cross(rops, ber_ffe, FEC_thr);
|
||||
reqROP_MLSE(L) = interp_fec_cross(rops, ber_mlse, FEC_thr);
|
||||
reqROP_DBTGT(L) = interp_fec_cross(rops, ber_dbtgt, FEC_thr);
|
||||
reqROP_ML_MLSE2(L) = interp_fec_cross(rops, ber_ml2, FEC_thr);
|
||||
reqROP_ML_MLSE3(L) = interp_fec_cross(rops, ber_ml3, FEC_thr);
|
||||
|
||||
fprintf('Length %.0f m: FFE %.1f, MLSE %.1f, DB %.1f, ML2 %.1f, ML3 %.1f\n', ...
|
||||
link_length_m, reqROP_FFE(L), reqROP_MLSE(L), reqROP_DBTGT(L), ...
|
||||
reqROP_ML_MLSE2(L), reqROP_ML_MLSE3(L));
|
||||
end
|
||||
|
||||
%% ====================== PLOT REQUIRED ROP ======================
|
||||
cols = cbrewer2('Set1',8);
|
||||
colFFE = cols(1,:);
|
||||
colMLSE = cols(2,:);
|
||||
colDBTGT = cols(4,:);
|
||||
colML_MLSE = cols(3,:);
|
||||
|
||||
figure(); hold on
|
||||
plot(link_lengths, reqROP_FFE, '-o','Color',colFFE, 'DisplayName','FFE');
|
||||
plot(link_lengths, reqROP_MLSE, '-s','Color',colMLSE, 'DisplayName','FFE+PF+MLSE');
|
||||
plot(link_lengths, reqROP_DBTGT, '--^','Color',colDBTGT, 'DisplayName','DB tgt. MLSE');
|
||||
plot(link_lengths, reqROP_ML_MLSE2, '-v','Color',colML_MLSE, 'DisplayName','ML-based MLSE (L=2)');
|
||||
plot(link_lengths, reqROP_ML_MLSE3, '-d','Color',colML_MLSE*0.8,'DisplayName','ML-based MLSE (L=3)');
|
||||
|
||||
xlabel('Link length [km]');
|
||||
ylabel('Required ROP [dBm]');
|
||||
title(sprintf('Required ROP the reach FEC threshold (3.8e-3); %.0f GBd PAM-%d', baudrate.*1e-9, M));
|
||||
legend('Location','northwest');
|
||||
grid on;
|
||||
beautifyBERplot("logscale",0,"polyfit",1,"polyorder",3,"fitmethod",'smoothingspline');
|
||||
99
projects/ML_based_MLSE/standard_link_model.m
Normal file
99
projects/ML_based_MLSE/standard_link_model.m
Normal file
@@ -0,0 +1,99 @@
|
||||
function [Rx_sig_2sps,Symbols,Tx_bits] = standard_link_model(options)
|
||||
|
||||
% STANDARD_LINK_MODEL Basic IM/DD link simulation
|
||||
% Rx_sig_2sps = standard_link_model(...optional args...)
|
||||
%
|
||||
% All arguments are optional and default to standard parameters
|
||||
% if not provided.
|
||||
|
||||
arguments
|
||||
|
||||
% --- Transmitter settings ---
|
||||
options.M (1,1) double = 4
|
||||
options.apply_pulsef (1,1) logical = true
|
||||
options.fdac (1,1) double = 256e9
|
||||
options.fadc (1,1) double = 256e9
|
||||
options.random_key (1,1) double = 2
|
||||
options.rcalpha (1,1) double = 0.05
|
||||
options.kover (1,1) double = 8
|
||||
options.vbias_rel (1,1) double = 0.5
|
||||
options.u_pi (1,1) double = 3.2
|
||||
options.laser_wavelength (1,1) double = 1310
|
||||
options.laser_linewidth (1,1) double = 1e6
|
||||
|
||||
% --- Channel parameters ---
|
||||
options.link_length_km (1,1) double = 0
|
||||
options.rop (1,:) double = -5
|
||||
options.fsym (1,:) double = (212:16:256)*1e9
|
||||
options.doub_mode (1,1) db_mode = db_mode.no_db
|
||||
|
||||
% --- Debug ---
|
||||
options.debug (1,1) logical = false
|
||||
|
||||
end
|
||||
|
||||
% --- Pulse former ---
|
||||
Pform = Pulseformer("fsym",options.fsym,"fdac",4*options.fsym, ...
|
||||
"pulse","rc","pulselength",16,"alpha",options.rcalpha);
|
||||
|
||||
% --- Transmitter source ---
|
||||
[Digi_sig,Symbols,Tx_bits] = PAMsource( ...
|
||||
"fsym",options.fsym,"M",options.M,"order",18,"useprbs",0, ...
|
||||
"fs_out",options.fdac,"applyclipping",0,"clipfactor",1.5, ...
|
||||
"applypulseform",options.apply_pulsef,"pulseformer",Pform, ...
|
||||
"randkey",options.random_key,"db_precode",0,"db_encode",0, ...
|
||||
"mrds_code",0,"mrds_blocklength",512, ...
|
||||
"duobinary_mode",options.doub_mode).process();
|
||||
|
||||
% --- AWG driver ---
|
||||
El_sig = M8199B("kover",options.kover).process(Digi_sig);
|
||||
El_sig = El_sig.normalize("mode","oneone");
|
||||
|
||||
% --- E/O Modulation ---
|
||||
vbias = -options.vbias_rel*options.u_pi;
|
||||
Opt_sig = EML("mode",eml_mode.im_cosinus,"power",3, ...
|
||||
"fsimu",El_sig.fs,"lambda",options.laser_wavelength, ...
|
||||
"bias",vbias,"u_pi",options.u_pi,"linewidth",options.laser_linewidth, ...
|
||||
"randomkey",options.random_key+1).process(El_sig);
|
||||
|
||||
% --- Fiber ---
|
||||
Opt_sig = Fiber("fsimu",Opt_sig.fs,"fiber_length",options.link_length_km, ...
|
||||
"alpha",0.3,"D",0,"lambda0",1310,"gamma",0,"Dslope",0.07).process(Opt_sig);
|
||||
|
||||
% --- Amplifier (ROP set) ---
|
||||
Opt_sig = Amplifier("amp_mode","ideal_no_noise", ...
|
||||
"gain_mode","output_power","amplification_db",options.rop).process(Opt_sig);
|
||||
|
||||
% --- Photodiode ---
|
||||
PD_sig = Photodiode("fsimu",options.fdac*options.kover,"dark_current",2e-8, ...
|
||||
"responsivity",1,"temperature",20,"nep",1.8e-11, ...
|
||||
"randomkey",options.random_key).process(Opt_sig);
|
||||
|
||||
% --- Electrical LPF (receiver frontend) ---
|
||||
rx_bwl = 70e9;
|
||||
PD_sig = Filter('filtdegree',4,"f_cutoff",rx_bwl, ...
|
||||
"fs",options.fdac*options.kover,"filterType",filtertypes.butterworth, ...
|
||||
"active",true).process(PD_sig);
|
||||
|
||||
% --- Scope low-pass and sampling ---
|
||||
Lp_scpe = Filter('filtdegree',4,"f_cutoff",110e9,"fs",options.fadc, ...
|
||||
"filterType",filtertypes.butterworth,"active",true);
|
||||
|
||||
Scpe_sig = Scope("fsimu",options.fdac*options.kover,"fadc",options.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(PD_sig);
|
||||
|
||||
% --- Downsample to 2 sps ---
|
||||
Scpe_sig_2sps = Scpe_sig.resample("fs_out",2*options.fsym);
|
||||
[~,Scpe_cell,~,found_sync] = Scpe_sig_2sps.tsynch( ...
|
||||
"reference",Symbols,"fs_ref",options.fsym,"debug_plots",0);
|
||||
|
||||
try
|
||||
Rx_sig_2sps = Scpe_cell{1}.normalize("mode","rms");
|
||||
catch
|
||||
Rx_sig_2sps = Scpe_sig_2sps.normalize("mode","rms");
|
||||
end
|
||||
|
||||
end
|
||||
157
projects/ML_based_MLSE/theoretic_channel_evaluation.m
Normal file
157
projects/ML_based_MLSE/theoretic_channel_evaluation.m
Normal file
@@ -0,0 +1,157 @@
|
||||
|
||||
M = 4;
|
||||
order = 18;
|
||||
randkey = 1;
|
||||
|
||||
bitpattern = [];
|
||||
s = RandStream('twister','Seed',randkey);
|
||||
for i = 1:log2(M)
|
||||
N = 2^(order-1); %length of prbs
|
||||
bitpattern(:,i) = randi(s,[0 1], N, 1);
|
||||
end
|
||||
|
||||
if M == 6
|
||||
bitpattern = reshape(bitpattern',[],1);
|
||||
bitpattern = bitpattern(1:end-mod(length(bitpattern),5));
|
||||
end
|
||||
|
||||
Bits = Informationsignal(bitpattern);
|
||||
|
||||
Symbols = PAMmapper(M,0).map(Bits);
|
||||
Symbols.fs = 200e9;
|
||||
|
||||
Bits_ = PAMmapper(M, 0, "eth_style", 0).demap(Symbols);
|
||||
|
||||
% --- Channel: minimal ISI response + AWGN ---
|
||||
h = [0.3 0.9 0.3,0.1]; % impulse response (normalized later if desired)
|
||||
h = h / norm(h); % optional normalization for unit energy
|
||||
|
||||
symbols_filt = Symbols.filter(h,1);
|
||||
|
||||
|
||||
%% SHOW FIG 3 in Paper: "ML Base Pre-Eq"
|
||||
|
||||
SNR_dB = [20:1:25];
|
||||
SNR_db = linspace(12,25,12);
|
||||
|
||||
ber_ffe = zeros(size(SNR_dB));
|
||||
ber_mlse_l5 = zeros(size(SNR_dB));
|
||||
ber_nwf_mlse_l2 = zeros(size(SNR_dB));
|
||||
ber_ml_mlse_l2 = zeros(size(SNR_dB));
|
||||
ber_ml_mlse_l3 = zeros(size(SNR_dB));
|
||||
ber_ml_mlse_l4 = zeros(size(SNR_dB));
|
||||
|
||||
epochs_training = 100;
|
||||
|
||||
for i = 1:numel(SNR_dB)
|
||||
|
||||
symbols_noi = symbols_filt;
|
||||
symbols_noi.signal = awgn(symbols_filt.signal, SNR_dB(i), 'measured'); % AWGN with given SNR
|
||||
|
||||
% Sequence Est L=5
|
||||
mlse_ = MLSE("duobinary_output",0,'M',M,'trellis_states',PAMmapper(M,0).levels,'scale_mode',0,'trellis_exclusion',0,'trellis_state_mode',2,'debug',0,'DIR',h);
|
||||
mlse_.DIR = h;
|
||||
[y_mlse] = mlse_.process(symbols_noi,Symbols);
|
||||
mlse_bits = PAMmapper(M, 0, "eth_style", 0).demap(y_mlse);
|
||||
[~, ~, ber_mlse_l5(i), ~] = calc_ber(mlse_bits.signal, Bits.signal, "skip_front", 10, "skip_end", 10, "returnErrorLocation", 1);
|
||||
fprintf('MLSE L5: %.2e \n',ber_mlse_l5(i));
|
||||
|
||||
% 2nd Approach
|
||||
mu_lms = 0.0005;
|
||||
pf_ncoeffs = 1;
|
||||
eq_ = FFE("epochs_tr",5,"epochs_dd",5,"len_tr",2^13,"mu_dd",mu_lms,"mu_tr",mu_lms,"order",16,"sps",1,"dd_mode",1,"adaption_technique","lms");
|
||||
pf_ = Postfilter("ncoeff",pf_ncoeffs,"useBurg",1);
|
||||
|
||||
% FFE
|
||||
[y_ffe, ffe_noise] = eq_.process(symbols_noi, Symbols);
|
||||
|
||||
Eq_bits = PAMmapper(M, 0, "eth_style", 0).demap(y_ffe);
|
||||
[~, ~, ber_ffe(i), ~] = calc_ber(Eq_bits.signal, Bits.signal, "skip_front", 0, "skip_end", 0, "returnErrorLocation", 1);
|
||||
fprintf('FFE: %.2e \n',ber_ffe(i));
|
||||
|
||||
% Postfilter
|
||||
[y_white,~] = pf_.process(y_ffe, ffe_noise);
|
||||
|
||||
% Sequence Est
|
||||
mlse_ = MLSE("duobinary_output",0,'M',M,'trellis_states',PAMmapper(M,0).levels,'scale_mode',0,'trellis_exclusion',0,'trellis_state_mode',2,'debug',0,'DIR',pf_.coefficients);
|
||||
[y_mlse] = mlse_.process(y_white,Symbols);
|
||||
mlse_bits = PAMmapper(M, 0, "eth_style", 0).demap(y_mlse);
|
||||
[~, errors, ber_nwf_mlse_l2(i), errpos] = calc_ber(mlse_bits.signal, Bits.signal, "skip_front", 10, "skip_end", 10, "returnErrorLocation", 1);
|
||||
fprintf('MLSE: %.2e \n',ber_nwf_mlse_l2(i));
|
||||
|
||||
% ML-base MLSE L=2
|
||||
adaptive_mu = 0;
|
||||
mu_lms = 0.15;
|
||||
ml_mlse_equalizer = ML_MLSE("epochs_tr",epochs_training,"epochs_dd",1,"len_tr",2^15,...
|
||||
"mu_dd",mu_lms,"mu_tr",mu_lms,"order",11,"sps",1,...
|
||||
"traceback_depth",128,"L",2,"delta",4,"adaptive_mu",adaptive_mu);
|
||||
[y_ml_mlse,~] = ml_mlse_equalizer.process(symbols_noi,Symbols);
|
||||
ml_mlse_bits = PAMmapper(M, 0, "eth_style", 0).demap(y_ml_mlse);
|
||||
[~, errors, ber_ml_mlse_l2(i), errpos] = calc_ber(ml_mlse_bits.signal, Bits.signal, "skip_front", 10, "skip_end", 10, "returnErrorLocation", 1);
|
||||
fprintf('ML MLSE BER: %.2e \n',ber_ml_mlse_l2(i));
|
||||
|
||||
% ML-base MLSE L=3
|
||||
mu_lms = 0.15;
|
||||
ml_mlse_equalizer = ML_MLSE("epochs_tr",epochs_training,"epochs_dd",1,"len_tr",2^16,...
|
||||
"mu_dd",mu_lms,"mu_tr",mu_lms,"order",11,"sps",1,...
|
||||
"traceback_depth",128,"L",3,"delta",4,"adaptive_mu",adaptive_mu);
|
||||
[y_ml_mlse,~] = ml_mlse_equalizer.process(symbols_noi,Symbols);
|
||||
ml_mlse_bits = PAMmapper(M, 0, "eth_style", 0).demap(y_ml_mlse);
|
||||
[~, errors, ber_ml_mlse_l3(i), errpos] = calc_ber(ml_mlse_bits.signal, Bits.signal, "skip_front", 10, "skip_end", 10, "returnErrorLocation", 1);
|
||||
fprintf('ML MLSE BER: %.2e \n',ber_ml_mlse_l3(i));
|
||||
|
||||
% % ML-base MLSE L=5
|
||||
% mu_lms = 0.15;
|
||||
% ml_mlse_equalizer = ML_MLSE("epochs_tr",epochs_training,"epochs_dd",1,"len_tr",2^15,...
|
||||
% "mu_dd",mu_lms,"mu_tr",mu_lms,"order",11,"sps",1,...
|
||||
% "traceback_depth",128,"L",5,"delta",4);
|
||||
% [y_ml_mlse,~] = ml_mlse_equalizer.process(symbols_noi,Symbols);
|
||||
% ml_mlse_bits = PAMmapper(M, 0, "eth_style", 0).demap(y_ml_mlse);
|
||||
% [~, errors, ber_ml_mlse_l5(i), errpos] = calc_ber(ml_mlse_bits.signal, Bits.signal, "skip_front", 10, "skip_end", 10, "returnErrorLocation", 1);
|
||||
% fprintf('ML MLSE BER: %.2e \n',ber_ml_mlse_l5(i));
|
||||
|
||||
|
||||
end
|
||||
|
||||
%%
|
||||
figure(); hold on;
|
||||
|
||||
% --- define scheme colors (consistent palette)
|
||||
cols = cbrewer2('SET1',8);
|
||||
colFFE = cols(1,:); % blue
|
||||
colMLSE = cols(2,:); % orange
|
||||
colML_MLSE = cols(3,:); % green
|
||||
colNWF_MLSE = cols(4,:); % purple
|
||||
|
||||
% --- local simulation results
|
||||
plot(SNR_dB, ber_ffe, '-o', 'Color', colFFE, 'DisplayName','FFE (N=16)');
|
||||
if M==2, plot(FFE_wpd.X, FFE_wpd.Y, ':', 'LineWidth',1.5, 'Color', colFFE, 'DisplayName','Paper FFE'); end
|
||||
|
||||
|
||||
plot(SNR_dB, ber_mlse_l5, '-s', 'Color', colMLSE, 'DisplayName','MLSE (L=5)');
|
||||
if M==2, plot(MLSE_wpd.X, MLSE_wpd.Y, ':', 'LineWidth',1.5, 'Color', colMLSE, 'DisplayName','Paper MLSE L=5'); end
|
||||
|
||||
plot(SNR_dB, ber_nwf_mlse_l2,'--^','Color', colNWF_MLSE, 'DisplayName','FFE+PF+MLSE (L=2)');
|
||||
plot(SNR_dB, ber_ml_mlse_l2, '-v', 'Color', colML_MLSE, 'DisplayName','ML-based MLSE (L=2)');
|
||||
if M==2, plot(ML_MLSE_L_2_wpd.X,ML_MLSE_L_2_wpd.Y,':', 'LineWidth',1.5, 'Color', colML_MLSE, 'DisplayName','Paper ML-based MLSE L=2'); end
|
||||
|
||||
|
||||
plot(SNR_dB, ber_ml_mlse_l3, '-d', 'Color', colML_MLSE, 'DisplayName','ML-based MLSE (L=3)');
|
||||
|
||||
if M==2, plot(SNR_dB, ber_ml_mlse_l5, '-p', 'Color', colML_MLSE, 'DisplayName','ML-based MLSE (L=5)'); end
|
||||
if M==2, plot(ML_MLSE_L_5_wpd.X,ML_MLSE_L_5_wpd.Y,':', 'LineWidth',1.5, 'Color', colML_MLSE, 'DisplayName','Paper ML-based MLSE L=5'); end
|
||||
% --- imported WebPlotDigitizer data (dotted)
|
||||
|
||||
yline(3.8e-3,'HandleVisibility','off');
|
||||
yline(2.2e-4,'HandleVisibility','off');
|
||||
|
||||
% --- formatting
|
||||
beautifyBERplot;
|
||||
xlim([SNR_dB(1), SNR_dB(end)]);
|
||||
ylim([1e-5 0.1]);
|
||||
xlabel('Input SNR [dB]');
|
||||
ylabel('Bit Error Rate (BER)');
|
||||
title('PAM-4; M=4; AWGN Channel');
|
||||
legend('Location','southwest');
|
||||
grid on;
|
||||
|
||||
9
projects/ML_based_MLSE/wpd_datasets.csv
Normal file
9
projects/ML_based_MLSE/wpd_datasets.csv
Normal file
@@ -0,0 +1,9 @@
|
||||
FFE,,MLSE,,ML MLSE L=2,,ML MLSE L=5,
|
||||
X,Y,X,Y,X,Y,X,Y
|
||||
7.988476019722099,0.038632829886662855,7.9828552218736,0.02056096426419196,7.988825638727029,0.026145160025945406,7.982882115643211,0.01995262314968881
|
||||
8.984755714926044,0.02462092401494627,8.991855670103094,0.008868008219069292,8.991519497982967,0.012908315306800594,8.998027790228598,0.009002182769536628
|
||||
9.993487225459436,0.014339094903163154,9.988632900044824,0.0032424222072799827,9.994320932317347,0.005651632488900345,9.994751232631108,0.0034952501326754757
|
||||
10.989914836396235,0.007746944324122318,10.991730165844913,0.001020224273461357,10.997256835499776,0.002129417748571358,10.991689825190498,0.0010672369906432938
|
||||
12.005060510981624,0.0034952501326754757,12.001483639623487,0.00018978455660928717,11.994316450022412,0.0005679993334792185,12.007359928283282,0.0002680778116002006
|
||||
12.983254146122816,0.0013169376605490738,13.011492604213357,0.000026540740973404924,12.997722994173017,0.00012652429120320801,12.992384580905423,0.000049125201846734525
|
||||
13.99255042581802,0.0004081967712510506,14.00969520394442,0.000001975386920666194,13.995172568354999,0.00002183385565256239,14.015275661138503,0.0000038826695948713645
|
||||
|
229
projects/Nonlinear_MLSE/simulation_nonlin_dsp.m
Normal file
229
projects/Nonlinear_MLSE/simulation_nonlin_dsp.m
Normal file
@@ -0,0 +1,229 @@
|
||||
%%% Run parameters
|
||||
% TX
|
||||
M = 4;
|
||||
m = floor(log2(M)*10)/10;
|
||||
fsym = 224e9;
|
||||
|
||||
apply_pulsef = 1;
|
||||
fdac = 256e9;
|
||||
fadc = 256e9;
|
||||
random_key = 2;
|
||||
|
||||
rcalpha = 0.05;
|
||||
kover = 8;
|
||||
vbias_rel = 0.5;
|
||||
u_pi = 3.2;
|
||||
vbias = -vbias_rel*u_pi;
|
||||
laser_wavelength = 1310;
|
||||
laser_linewidth = 1e6;
|
||||
|
||||
|
||||
% Channel
|
||||
link_length = 0;
|
||||
|
||||
vnle_order1 = 50;
|
||||
vnle_order2 = 0;
|
||||
vnle_order3 = 0;
|
||||
|
||||
vnle_order=[vnle_order1,vnle_order2,vnle_order3];
|
||||
dfe_order = [0 0 0];
|
||||
|
||||
alpha = 0;
|
||||
|
||||
len_tr = 4096*2;
|
||||
|
||||
mu_ffe1 = 0.0001;
|
||||
mu_ffe2 = 0.0008;
|
||||
mu_ffe3 = 0.001;
|
||||
mu_dc = 0.005;
|
||||
% mu_dc = 0;
|
||||
|
||||
mu_ffe = [mu_ffe1 mu_ffe3 mu_ffe3];
|
||||
mu_dfe = 0.0004;
|
||||
|
||||
dfe_ = sum(dfe_order)>0;
|
||||
|
||||
doub_mode = db_mode.no_db;
|
||||
cols = linspecer(6);
|
||||
rop = [-8];
|
||||
bwl = [0.5:0.1:1.5];
|
||||
fsym = [208:16:256].*1e9;
|
||||
nonlin_mod = [0.5:0.01:0.75];
|
||||
fsym = ones(size(nonlin_mod)).*fsym(1);
|
||||
|
||||
ffe_results = {};
|
||||
mlse_results_lin= {};
|
||||
vnle_results= {};
|
||||
mlse_results_nonlin= {};
|
||||
mlse_results_nonlin_states= {};
|
||||
|
||||
g_eye = GifWriter('Name','eye','Parallel',true);
|
||||
g_mod = GifWriter('Name','modulator','Parallel',true);
|
||||
|
||||
for r = 1:length(nonlin_mod)
|
||||
|
||||
Pform = Pulseformer("fsym",fsym(r),"fdac",4*fsym(r),"pulse","rc","pulselength",16,"alpha",rcalpha);
|
||||
|
||||
db_precode = 0;
|
||||
db_encode = 0;
|
||||
duob_mode = db_mode.no_db;
|
||||
apply_pulsef = 1;
|
||||
|
||||
[Digi_sig,Symbols,Tx_bits] = PAMsource(...
|
||||
"fsym",fsym(r),"M",M,"order",19,"useprbs",0,...
|
||||
"fs_out",fdac,...
|
||||
"applyclipping",0,"clipfactor",1.5,...
|
||||
"applypulseform",apply_pulsef,"pulseformer",Pform,...
|
||||
"randkey",random_key,...
|
||||
"db_precode",db_precode,"db_encode",db_encode,...
|
||||
"mrds_code",0,"mrds_blocklength",512,"duobinary_mode",duob_mode).process();
|
||||
|
||||
% El_sig = AWG("fdac",fdac,"f_cutoff",fsym(r),"lpf_active",0,"kover",kover,"bit_resolution",12,"upsampling_method","samplehold","precomp_sinc_rolloff",0).process(Digi_sig);
|
||||
El_sig = M8199B("kover",kover).process(Digi_sig);
|
||||
% AWG("fdac",fdac,"f_cutoff",fsym(r),"lpf_active",0,"kover",kover,"bit_resolution",12,"upsampling_method","samplehold","precomp_sinc_rolloff",0).process(Digi_sig);
|
||||
|
||||
%%%%% Low-pass el. components %%%%%%
|
||||
% tx_bwl = 100e9;
|
||||
% El_sig = Filter('filtdegree',3,"f_cutoff",tx_bwl,"fs",fdac*kover,"filterType",filtertypes.butterworth,"active",true).process(El_sig);
|
||||
|
||||
%%%%% Electrical Driver Amplifier %%%%%%
|
||||
El_sig = El_sig.normalize("mode","oneone");
|
||||
% El_sig = El_sig.setPower(1,"dBm");
|
||||
% figure;histogram(El_sig.signal);
|
||||
|
||||
%%%%% MODULATE E/O CONVERSION %%%%%
|
||||
u_pi = 3.2;
|
||||
vbias = -u_pi*nonlin_mod(r);
|
||||
[Opt_sig] = EML("mode",eml_mode.im_cosinus,"power",3,"fsimu",El_sig.fs,"lambda",laser_wavelength,"bias",vbias,"u_pi",u_pi,"linewidth",laser_linewidth,"randomkey",random_key+1).process(El_sig);
|
||||
|
||||
if 1
|
||||
figure(15);
|
||||
hold on
|
||||
scatter(El_sig.signal(1:100000)+vbias,(abs(Opt_sig.signal(1:100000)).^2)*1e3,0.1,'.','DisplayName','Modulator TF')
|
||||
xlabel('Input in V')
|
||||
ylabel('abs(Eopt)2 in mW','Interpreter','latex')
|
||||
ylim([0 2]);
|
||||
xlim([-3.2 0]);
|
||||
g_mod.addFrame(15, r);
|
||||
|
||||
Opt_sig.eye(fsym(r), M, "fignum", 103837);
|
||||
g_eye.addFrame(103837, r);
|
||||
end
|
||||
|
||||
%%%%%% Fiber %%%%%%
|
||||
Opt_sig = Fiber("fsimu",Opt_sig.fs,"fiber_length",link_length/1000,"alpha",0.3,"D",0,"lambda0",1310,"gamma",0,"Dslope",0.07).process(Opt_sig);
|
||||
|
||||
%%%%%% ROP %%%%%%
|
||||
Opt_sig = Amplifier("amp_mode","ideal_no_noise","gain_mode","output_power","amplification_db",rop).process(Opt_sig);
|
||||
|
||||
%%%%%% PD Square Law %%%%%%
|
||||
PD_sig = Photodiode("fsimu",fdac*kover,"dark_current",2e-08,"responsivity",1,"temperature",20,"nep",1.8e-11,"randomkey",random_key).process(Opt_sig);
|
||||
|
||||
%%%%%% Low-pass RX (PD, El. Connectors and Scope %%%%%%
|
||||
rx_bwl = 70e9;
|
||||
PD_sig = Filter('filtdegree',4,"f_cutoff",rx_bwl,"fs",fdac*kover,"filterType",filtertypes.butterworth,"active",true).process(PD_sig);
|
||||
|
||||
% %%%%%% Low-pass Scope %%%%%%
|
||||
Lp_scpe = Filter('filtdegree',4,"f_cutoff",110e9,"fs",fadc,"filterType",filtertypes.butterworth,"active",true);
|
||||
|
||||
%%%%%% Scope %%%%%%
|
||||
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(PD_sig);
|
||||
|
||||
Scpe_sig_2sps = Scpe_sig.resample("fs_out",2*fsym(r));
|
||||
% Scpe_sig_resampled.signal = Scpe_sig_resampled.signal(1:2*length(Symbols));
|
||||
|
||||
[~, Scpe_cell, ~, found_sync] = Scpe_sig_2sps.tsynch("reference", Symbols, "fs_ref", fsym(r), "debug_plots", 0);
|
||||
Rx_sig = Scpe_cell{1};
|
||||
Rx_sig = Rx_sig.normalize("mode","rms");
|
||||
|
||||
if 1
|
||||
|
||||
%% FFE
|
||||
% ffe_order = [50, 0, 0];
|
||||
% eq_ffe = 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_ffe,M,Rx_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 = "ffe";
|
||||
%
|
||||
|
||||
%% MLSE linear
|
||||
|
||||
pf_ncoeffs = 1;
|
||||
ffe_order = [50, 0, 0];
|
||||
eq_ = 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",1);
|
||||
pf_ = Postfilter("ncoeff",pf_ncoeffs,"useBurg",1);
|
||||
mlse_ = MLSE("duobinary_output",0,'M',M,'trellis_states',PAMmapper(M,0).levels,'scale_mode',2,'trellis_exclusion',0,'trellis_state_mode',2,'debug',1);
|
||||
|
||||
[ffe_results{r}, mlse_results_lin{r}] = vnle_postfilter_mlse(eq_, pf_, mlse_, M, Rx_sig, Symbols, Tx_bits, ...
|
||||
"precode_mode", duob_mode,...
|
||||
'showAnalysis', 0, ...
|
||||
"postFFE", [],...
|
||||
"eth_style_symbol_mapping", 0);
|
||||
|
||||
mlse_results_lin{r}.metrics.print;
|
||||
ffe_results{r}.metrics.print;
|
||||
|
||||
%% MLSE nonlinear pre
|
||||
|
||||
pf_ncoeffs = 1;
|
||||
ffe_order = [50, 1, 0];
|
||||
eq_ = 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",1);
|
||||
pf_ = Postfilter("ncoeff",pf_ncoeffs,"useBurg",1);
|
||||
mlse_ = MLSE("duobinary_output",0,'M',M,'trellis_states',PAMmapper(M,0).levels,'scale_mode',2,'trellis_exclusion',0,'trellis_state_mode',2);
|
||||
|
||||
[vnle_results{r}, mlse_results_nonlin{r}] = vnle_postfilter_mlse(eq_, pf_, mlse_, M, Rx_sig, Symbols, Tx_bits, ...
|
||||
"precode_mode", duob_mode,...
|
||||
'showAnalysis', 0, ...
|
||||
"postFFE", [],...
|
||||
"eth_style_symbol_mapping", 0);
|
||||
|
||||
mlse_results_nonlin{r}.metrics.print;
|
||||
vnle_results{r}.metrics.print;
|
||||
|
||||
%% nonlinear states MLSE linear pre
|
||||
|
||||
pf_ncoeffs = 1;
|
||||
ffe_order = [50, 0, 0];
|
||||
eq_ = 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",1);
|
||||
pf_ = Postfilter("ncoeff",pf_ncoeffs,"useBurg",1);
|
||||
mlse_ = MLSE("duobinary_output",0,'M',M,'trellis_states',PAMmapper(M,0).levels,'scale_mode',2,'trellis_exclusion',0,'trellis_state_mode',3);
|
||||
|
||||
[~, mlse_results_nonlin_states{r}] = vnle_postfilter_mlse(eq_, pf_, mlse_, M, Rx_sig, Symbols, Tx_bits, ...
|
||||
"precode_mode", duob_mode,...
|
||||
'showAnalysis', 0, ...
|
||||
"postFFE", [],...
|
||||
"eth_style_symbol_mapping", 0);
|
||||
|
||||
mlse_results_nonlin_states{r}.metrics.print;
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
g_mod.compile(15);
|
||||
g_eye.compile(103837);
|
||||
|
||||
%%
|
||||
|
||||
figure();hold on;
|
||||
plot(nonlin_mod,cellfun(@(x) x.metrics.BER, ffe_results),'DisplayName','FFE')
|
||||
plot(nonlin_mod,cellfun(@(x) x.metrics.BER, vnle_results),'DisplayName','VNLE')
|
||||
plot(nonlin_mod,cellfun(@(x) x.metrics.BER, mlse_results_lin),'DisplayName','FFE+MLSE')
|
||||
plot(nonlin_mod,cellfun(@(x) x.metrics.BER, mlse_results_nonlin_states),'DisplayName','FFE+nonlin. states MLSE')
|
||||
plot(nonlin_mod,cellfun(@(x) x.metrics.BER, mlse_results_nonlin),'DisplayName','VNLE+MLSE')
|
||||
xlabel('Nonlinear Driving');
|
||||
ylabel('BER')
|
||||
set(gca,'YScale','log');
|
||||
legend;
|
||||
ylim([1e-4 1e-1]);
|
||||
beautifyBERplot;
|
||||
|
||||
|
||||
252
projects/WDM/WDM_auswertung.m
Normal file
252
projects/WDM/WDM_auswertung.m
Normal file
@@ -0,0 +1,252 @@
|
||||
|
||||
|
||||
try
|
||||
rop = res.settings.rop; % 12 points
|
||||
wavelengthplan = res.settings.wavelengthplan;
|
||||
catch
|
||||
wavelengthplan = [1295,1305,1315,1325];
|
||||
wavelengthplan = calcWavelengthPlan(16,400e9,1310);
|
||||
rop = -8.25:0.75:0;
|
||||
end
|
||||
|
||||
N = length(wavelengthplan);
|
||||
figure(); hold on;
|
||||
cols = cbrewer2('set2',N); % one color per wavelength (Ch)
|
||||
|
||||
fec = 2.2e-4;
|
||||
fec = 3.8e-3;
|
||||
Sffe = cell(1,N);
|
||||
Svnle = cell(1,N);
|
||||
Smlse = cell(1,N);
|
||||
Sdbt = cell(1,N);
|
||||
|
||||
% Choose your quantile band. For your old style, use 0.04/0.99:
|
||||
qLow = 0.0; % lower quantile (e.g., 0.04 for old script)
|
||||
qHigh = 1; % upper quantile (e.g., 0.99 for old script)
|
||||
cols = linspecer(N); % one color per wavelength (Ch)
|
||||
cols = cbrewer2('set1',N);
|
||||
|
||||
for l = 1:N
|
||||
% Slice 12x50 cell arrays
|
||||
ffe_cells = reshape(squeeze(res.ffe(l,:,:)),length(rop),[]);
|
||||
vnle_cells = reshape(squeeze(res.vnle(l,:,:)),length(rop),[]);
|
||||
mlse_cells = reshape(squeeze(res.mlse(l,:,:)),length(rop),[]);
|
||||
dbt_cells = reshape(squeeze(res.dbt(l,:,:)),length(rop),[]);
|
||||
|
||||
[Sffe{l}, noX_ffe] = fecCrossings(rop, ffe_cells, fec);
|
||||
|
||||
[Svnle{l}, noX_ffe] = fecCrossings(rop, vnle_cells, fec);
|
||||
|
||||
[Smlse{l}, noX_ffe] = fecCrossings(rop, mlse_cells, fec);
|
||||
|
||||
[Sdbt{l}, noX_ffe] = fecCrossings(rop, dbt_cells, fec);
|
||||
|
||||
% Extract BER matrices using only complete realizations (12/12 ROP filled)
|
||||
ffe_mat = extractCompleteBER(ffe_cells); % 12 x K_ffe
|
||||
vnle_mat = extractCompleteBER(vnle_cells); % 12 x K_vnle
|
||||
mlse_mat = extractCompleteBER(mlse_cells); % 12 x K_mlse
|
||||
mlse_alpha_mat = extractCompleteAlphas(mlse_cells); % 12 x K_mlse
|
||||
dbt_mat = extractCompleteBER(dbt_cells); % 12 x K_dbt
|
||||
|
||||
showLegend = 1; % one legend entry per technique
|
||||
|
||||
% Plot shaded band + mean line with boundedline
|
||||
% plotBandMeanBL(rop, ffe_mat, cols(l,:), sprintf('FFE @ %.1d nm',round(wavelengthplan(l))), qLow, qHigh, '--s', showLegend);
|
||||
% scatter(Sffe,fec.*ones(size(Sffe)),20,'v','MarkerFaceColor','black');
|
||||
|
||||
plotBandMeanBL(rop, vnle_mat, cols(l,:), sprintf('VNLE @ %.1d nm',round(wavelengthplan(l))), qLow, qHigh, '--x', showLegend);
|
||||
|
||||
% plotBandMeanBL(rop, mlse_mat, cols(l,:), sprintf('VNLE+PF+MLSE @ %.1d nm',round(wavelengthplan(l))), qLow, qHigh, '-o', showLegend);
|
||||
|
||||
% plotBandMeanBL(rop, dbt_mat, cols(l,:), sprintf('DBt.+MLSE @ %.1d nm',round(wavelengthplan(l))), qLow, qHigh, '--v', showLegend);
|
||||
|
||||
set(gca,'XScale','linear','YScale','log','TickLabelInterpreter','latex','FontSize',11);
|
||||
yline([3.8e-3, 2.2e-4], 'HandleVisibility','off','LineWidth',1.5);
|
||||
|
||||
end
|
||||
|
||||
ylabel('BER');
|
||||
xlabel('ROP');
|
||||
title('BER vs. ROP');
|
||||
xlim([min(rop) max(rop)]);
|
||||
ylim([1e-5 0.3]);
|
||||
grid on;
|
||||
legend show;
|
||||
|
||||
|
||||
S_cell = Sdbt;
|
||||
S_cell =Smlse;
|
||||
S_cell = {Svnle,Smlse,Sdbt};
|
||||
S_cell = {Svnle};
|
||||
figure(5); hold on;
|
||||
for i = 1:length(S_cell)
|
||||
% Pad to rectangular matrix: rows = realizations, cols = wavelengths
|
||||
Kmax = max(cellfun(@numel, S_cell{i}));
|
||||
S_mat = NaN(Kmax, N);
|
||||
for l = 1:N
|
||||
k = numel(S_cell{i}{l});
|
||||
if k > 0
|
||||
S_mat(1:k, l) = S_cell{i}{l};
|
||||
end
|
||||
end
|
||||
|
||||
% --- Violin plot over wavelengths (columns) ---
|
||||
|
||||
cols=linspecer(3);
|
||||
catLabels = arrayfun(@(nm) sprintf('%d nm', nm), wavelengthplan, 'UniformOutput', false);
|
||||
vs = violinplot(S_mat, catLabels, ...
|
||||
'ViolinColor', cols(i,:), ...
|
||||
'ViolinAlpha', 0.10, ...
|
||||
'MarkerSize', 20, ...
|
||||
'ShowMedian', true, ...
|
||||
'EdgeColor', cols(i,:), ...
|
||||
'ShowWhiskers', false, ...
|
||||
'ShowData', true, ...
|
||||
'ShowBox', false, ...
|
||||
'Bandwidth', 0.05);
|
||||
|
||||
ylim([floor(min(S_mat,[],'all')), ceil(max(S_mat,[],'all'))])
|
||||
ylim([-8 0]);
|
||||
ylabel('ROP at FEC crossing');
|
||||
title(sprintf('RROP to cross BER %.2e', fec));
|
||||
grid on; box on;
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
%% ================= helper =================
|
||||
function plotBandMeanBL(x, Y, color, techLabel, qLow, qHigh, lineSpec, showLegend)
|
||||
% Y: (nPoints x nRealizations)
|
||||
% Remove realizations that are entirely zero (like removeZeros behavior)
|
||||
badCols = all(Y == 0, 1);
|
||||
Y(:, badCols) = [];
|
||||
|
||||
Y(Y==0) = 1e-8;
|
||||
% Stats across realizations
|
||||
mu = mean(Y, 2, 'omitnan'); % mean line
|
||||
lo = quantile(Y, qLow, 2); % lower bound
|
||||
hi = quantile(Y, qHigh, 2); % upper bound
|
||||
|
||||
% Convert to asymmetric distances required by boundedline:
|
||||
% b(:,1) = distance to lower side; b(:,2) = distance to upper side
|
||||
b = [mu - lo, hi - mu];
|
||||
|
||||
% Call boundedline with alpha shading
|
||||
[hl, hp] = boundedline(x(:), mu(:), b, lineSpec, 'alpha', ...
|
||||
'transparency', 0.18);
|
||||
% Color styling
|
||||
set(hl, 'Color', color, 'LineWidth', 1.4, 'MarkerSize', 4);
|
||||
set(hp, 'FaceColor', color, 'HandleVisibility','off'); % patch hidden in legend
|
||||
|
||||
% Single legend entry per technique (use first wavelength only)
|
||||
if showLegend
|
||||
set(hl, 'DisplayName', techLabel);
|
||||
else
|
||||
set(hl, 'HandleVisibility','off');
|
||||
end
|
||||
|
||||
% Optional: outline the bounds if outlinebounds is available
|
||||
if exist('outlinebounds','file') == 2
|
||||
ho = outlinebounds(hl, hp);
|
||||
set(ho, 'linestyle', ':', 'color', color, 'linewidth', 1, ...
|
||||
'HandleVisibility','off');
|
||||
end
|
||||
end
|
||||
|
||||
function [S, noCrossingMask, Y_keep] = fecCrossings(rop, cells12xR, fec)
|
||||
% cells12xR: 12xR cell array (one wavelength + scheme slice)
|
||||
% each cell must be a struct with .metrics.BER
|
||||
% rop: 12x1 numeric vector of ROP points
|
||||
% fec: scalar FEC threshold (e.g., 3.8e-3)
|
||||
%
|
||||
% Outputs:
|
||||
% S 1xK vector of crossing ROP per kept realization (NaN if none)
|
||||
% noCrossingMask 1xK logical mask: true if no crossing for that realization
|
||||
% Y_keep 12xK numeric BER matrix used for the crossing detection
|
||||
|
||||
% 1) keep only complete realization columns
|
||||
Y = extractCompleteBER(cells12xR); % -> 12 x K
|
||||
if isempty(Y)
|
||||
S = [];
|
||||
noCrossingMask = [];
|
||||
Y_keep = Y;
|
||||
return;
|
||||
end
|
||||
|
||||
% 2) optionally drop realizations with mean BER > 0.1
|
||||
ok = mean(Y,1,'omitnan') <= 0.1;
|
||||
Y = Y(:, ok);
|
||||
if isempty(Y)
|
||||
S = [];
|
||||
noCrossingMask = [];
|
||||
Y_keep = Y;
|
||||
return;
|
||||
end
|
||||
|
||||
% 3) find crossings per realization
|
||||
nR = size(Y,2);
|
||||
S = nan(1,nR);
|
||||
noCrossingMask = true(1,nR);
|
||||
|
||||
rop = rop(:); % ensure column
|
||||
for j = 1:nR
|
||||
y = Y(:,j);
|
||||
|
||||
% sign change from >fec to <=fec (first time it drops below FEC)
|
||||
above = (y > fec);
|
||||
idx = find(above(1:end-1) & ~above(2:end), 1, 'first');
|
||||
|
||||
if ~isempty(idx)
|
||||
% linear interpolation between (x1,y1) and (x2,y2)
|
||||
x1 = rop(idx); y1 = y(idx);
|
||||
x2 = rop(idx+1); y2 = y(idx+1);
|
||||
|
||||
if isfinite(y1) && isfinite(y2) && y2 ~= y1
|
||||
t = (fec - y1) / (y2 - y1);
|
||||
S(j) = x1 + t*(x2 - x1);
|
||||
noCrossingMask(j) = false;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Y_keep = Y;
|
||||
end
|
||||
|
||||
|
||||
|
||||
function Y = extractCompleteBER(cellSlice)
|
||||
% cellSlice: 12xR cell array; each cell should be a struct with .metrics.BER
|
||||
% Keep only those realization columns where ALL 12 ROP entries are valid.
|
||||
if isempty(cellSlice), Y = []; return; end
|
||||
nR = size(cellSlice,2);
|
||||
keep = false(1,nR);
|
||||
for r = 1:nR
|
||||
col = cellSlice(:,r);
|
||||
keep(r) = all(cellfun(@(c) ~isempty(c) , col));
|
||||
end
|
||||
if ~any(keep), Y = []; return; end
|
||||
Y = cellfun(@(c) c.metrics.BER, cellSlice(:,keep), 'UniformOutput', true);
|
||||
end
|
||||
|
||||
function Y = extractCompleteAlphas(cellSlice)
|
||||
% cellSlice: 12xR cell array; each cell should be a struct with .metrics.BER
|
||||
% Keep only those realization columns where ALL 12 ROP entries are valid.
|
||||
if isempty(cellSlice), Y = []; return; end
|
||||
nR = size(cellSlice,2);
|
||||
keep = false(1,nR);
|
||||
for r = 1:nR
|
||||
col = cellSlice(:,r);
|
||||
keep(r) = all(cellfun(@(c) ~isempty(c) , col));
|
||||
end
|
||||
if ~any(keep), Y = []; return; end
|
||||
Y = cellfun(@(c) c.metrics.Alpha, cellSlice(:,keep), 'UniformOutput', true);
|
||||
end
|
||||
|
||||
278
projects/WDM/WDM_model.m
Normal file
278
projects/WDM/WDM_model.m
Normal file
@@ -0,0 +1,278 @@
|
||||
%%% Run parameters
|
||||
% TX
|
||||
% --- FIRST LINE: evaluate settings located beside this script ---
|
||||
run(fullfile(fileparts(mfilename('fullpath')),'WDM_settings.m'));
|
||||
s = struct;
|
||||
s.num_realiz = 1;
|
||||
s.wavelengthplan = calcWavelengthPlan(16,400e9,1310);
|
||||
s.wavelengthplan = [1295,1305,1315,1325];
|
||||
s.link_length = 2;
|
||||
s.pmd = 0.0;
|
||||
s.gamma = 0.00;
|
||||
|
||||
s.M = 4;
|
||||
m = floor(log2(s.M)*10)/10;
|
||||
fsym = 224e9;
|
||||
fdac = 2*fsym;
|
||||
fadc = 2*fsym;
|
||||
s.random_key = 100;
|
||||
|
||||
% Laser / s.Modulator
|
||||
vbias_rel = 0.5;
|
||||
u_pi = 3.2;
|
||||
vbias = -vbias_rel*u_pi;
|
||||
laser_linewidth = 0e6;
|
||||
|
||||
% EQ SETTINGS
|
||||
vnle_order1 = 50;
|
||||
vnle_order2 = 3;
|
||||
vnle_order3 = 3;
|
||||
vnle_order=[vnle_order1,vnle_order2,vnle_order3];
|
||||
dfe_order = [0 0 0];
|
||||
len_tr = 4096*2;
|
||||
mu_ffe1 = 0.0001;
|
||||
mu_ffe2 = 0.0008;
|
||||
mu_ffe3 = 0.001;
|
||||
mu_dc = 0.005;
|
||||
% mu_dc = 0;
|
||||
mu_ffe = [mu_ffe1 mu_ffe3 mu_ffe3];
|
||||
mu_dfe = 0.0004;
|
||||
|
||||
%DB Stuff
|
||||
db_precode = 0;
|
||||
db_encode = 0;
|
||||
duob_mode = db_mode.no_db;
|
||||
apply_pulsef = 0;
|
||||
|
||||
rcalpha = 0.05;
|
||||
Pform = Pulseformer("fsym",fsym,"fdac",4*fsym,"pulse","rc","pulselength",16,"alpha",rcalpha);
|
||||
|
||||
N = numel(s.wavelengthplan);
|
||||
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;
|
||||
upsample_required = f_nyq./(fdac*kover/2);
|
||||
upsample_pow = 2^nextpow2(upsample_required);
|
||||
upsample_ceil = ceil(upsample_required);
|
||||
|
||||
s.f_opt = fdac*kover*upsample_pow;
|
||||
s.f_opt_nyq = s.f_opt/2;
|
||||
|
||||
signal_cell = {};
|
||||
Symbols = {};
|
||||
Tx_bits = {};
|
||||
|
||||
s.rop = -6: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);
|
||||
|
||||
for realiz = 1:s.num_realiz
|
||||
|
||||
|
||||
parfor l = 1:N
|
||||
|
||||
[Digi_sig,Symbols{l},Tx_bits{l}] = PAMsource(...
|
||||
"fsym",fsym,"M",s.M,"order",18,"useprbs",0,...
|
||||
"fs_out",fdac,...
|
||||
"applyclipping",0,"clipfactor",1.5,...
|
||||
"applypulseform",apply_pulsef,"pulseformer",Pform,...
|
||||
"randkey",s.random_key+l+realiz,...
|
||||
"db_precode",db_precode,"db_encode",db_encode,...
|
||||
"mrds_code",0,"mrds_blocklength",512,"duobinary_mode",duob_mode).process();
|
||||
|
||||
% Digi_sig.spectrum("fignum",101,"displayname",'bla','normalizeTo0dB',0,'lambda0_nm',1310,'useWavelengthAxis',0);
|
||||
Lp_awg = Filter('filtdegree',3,"f_cutoff",100e9,"fs",fdac*kover,"filterType",filtertypes.gaussian,"active",true);
|
||||
El_sig = AWG("fdac",fdac,"f_cutoff",fsym,"lpf_active",1,"kover",kover,"bit_resolution",12,"upsampling_method","samplehold","precomp_sinc_rolloff",0,"H_lpf",Lp_awg,"dac_max",0.6,"dac_min",-0.6).process(Digi_sig);
|
||||
% El_sig = s.M8199B("kover",kover).process(Digi_sig);
|
||||
% El_sig.spectrum("fignum",101,"displayname",'bla','normalizeTo0dB',0,'lambda0_nm',1310,'useWavelengthAxis',0);
|
||||
|
||||
%%%%% Electrical Driver Amplifier %%%%%%
|
||||
El_sig = El_sig.normalize("mode","oneone");
|
||||
% El_sig = El_sig.setPower(1,"dBm");
|
||||
% figure;histogram(El_sig.signal);
|
||||
|
||||
%%%%% 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);
|
||||
end
|
||||
|
||||
Opt_sig_wdm = Optical_Multiplex("fs_in",fdac*kover,"fs_out",upsample_pow*fdac*kover,...
|
||||
"lambda_center",1310,"random_key",0,"filtype",1,"B",200e9).process(signal_cell);
|
||||
|
||||
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',1,'max_num_lines',2);
|
||||
|
||||
%%%%%% Fiber %%%%%%
|
||||
Opt_sig_wdm_fib=Opt_sig_wdm;
|
||||
|
||||
nSegments = 2;
|
||||
zdw = 1310;
|
||||
D_local = 0; %if ~=0, simulation uses "segmented fiber with d+,d-)
|
||||
randomize_D = true;
|
||||
Dvec = getDispersionVector(nSegments, D_local, zdw, randomize_D, s.random_key+realiz);
|
||||
for seg = 1:nSegments
|
||||
|
||||
Opt_sig_wdm_fib = DP_Fiber("L",s.link_length/nSegments,"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);
|
||||
|
||||
end
|
||||
|
||||
Opt_sig_wdm_fib.spectrum("fignum",realiz,"displayname",'bla','lambda0_nm',1310,'useWavelengthAxis',0);
|
||||
|
||||
% Opt_sig_wdm_fib.move_it_spectrum("fignum",100212,"displayname",'bla');
|
||||
|
||||
% Opt_sig = Fiber("fsimu",Opt_sig.fs,"fiber_length",s.link_length/1000,"alpha",0.3,"D",0,"lambda0",1310,"s.gamma",0,"Dslope",0.07).process(Opt_sig)
|
||||
|
||||
for ri = 1:length(s.rop)
|
||||
|
||||
%%%%%% ROP %%%%%%
|
||||
Opt_sig_wdm_rx = Amplifier("amp_mode","ideal_no_noise","gain_mode","output_power","amplification_db",s.rop(ri)+10*log10(N)).process(Opt_sig_wdm_fib);
|
||||
|
||||
Opt_sig_wdm_demux = Optical_Demultiplex("attenuation",0,"B",200e9,"filtype",1,"fs_out",Opt_sig_wdm_rx.fs/upsample_pow,"fs_in",Opt_sig_wdm_rx.fs,"lambda_center",1310).process(Opt_sig_wdm_rx);
|
||||
|
||||
PD_cell = {};
|
||||
for l = 1:N
|
||||
|
||||
%%%%%% PD Square Law %%%%%%
|
||||
assert(fdac*kover==Opt_sig_wdm_demux{l}.fs,'Sampling Frequencies do not match! Check previous steps');
|
||||
PD_sig = Photodiode("fsimu",fdac*kover,"dark_current",2e-08,"responsivity",1,"temperature",20,"nep",1.8e-11,"randomkey",s.random_key+l+realiz).process(Opt_sig_wdm_demux{l});
|
||||
|
||||
% PD_sig.spectrum("fignum",222,"displayname",'bla','normalizeTo0dB',1);
|
||||
|
||||
%%%%%% Low-pass RX (PD, El. Connectors and Scope %%%%%%
|
||||
rx_bwl = 100e9;
|
||||
PD_sig = Filter('filtdegree',4,"f_cutoff",rx_bwl,"fs",fdac*kover,"filterType",filtertypes.butterworth,"active",true).process(PD_sig);
|
||||
|
||||
% %%%%%% Low-pass Scope %%%%%%
|
||||
Lp_scpe = Filter('filtdegree',4,"f_cutoff",110e9,"fs",fadc,"filterType",filtertypes.butterworth,"active",true);
|
||||
|
||||
%%%%%% Scope %%%%%%
|
||||
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(PD_sig);
|
||||
|
||||
Scpe_sig_2sps = Scpe_sig.resample("fs_out",2*fsym);
|
||||
% Scpe_sig.spectrum("fignum",222,"displayname",'bla','normalizeTo0dB',1);
|
||||
|
||||
[~, Scpe_cell, ~, found_sync] = Scpe_sig_2sps.tsynch("reference", Symbols{l}, "fs_ref", fsym, "debug_plots", 1);
|
||||
Rx_sig = Scpe_cell{1};
|
||||
Rx_sig = Rx_sig.normalize("mode","rms");
|
||||
|
||||
|
||||
|
||||
% FFE
|
||||
ffe_order = [50, 0, 0];
|
||||
eq_ffe = 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_ffe,s.M,Rx_sig,Symbols{l},Tx_bits{l},...
|
||||
"precode_mode",duob_mode,...
|
||||
'showAnalysis',0,...
|
||||
"postFFE",[],...
|
||||
"eth_style_symbol_mapping",0);
|
||||
|
||||
output_ffe{l,ri,realiz} = ffe_results;
|
||||
|
||||
|
||||
|
||||
%VNLE
|
||||
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",1);
|
||||
pf_ = Postfilter("ncoeff",pf_ncoeffs,"useBurg",1);
|
||||
|
||||
useviterbi = 0;
|
||||
if useviterbi
|
||||
mlse_ = MLSE_viterbi("duobinary_output",0,'M',s.M,'trellis_states',PAMmapper(s.M,0).levels);
|
||||
else
|
||||
mlse_ = MLSE("duobinary_output",0,'M',s.M,'trellis_states',PAMmapper(s.M,0).levels);
|
||||
end
|
||||
|
||||
[vnle_results, mlse_results] = vnle_postfilter_mlse(eq_, pf_, mlse_, s.M, Rx_sig, Symbols{l},Tx_bits{l}, ...
|
||||
"precode_mode", duob_mode,...
|
||||
'showAnalysis', 0, ...
|
||||
"postFFE", [],...
|
||||
"eth_style_symbol_mapping", 0);
|
||||
|
||||
output_vnle{l,ri,realiz} = vnle_results;
|
||||
output_mlse{l,ri,realiz} = mlse_results;
|
||||
|
||||
|
||||
% DB tgt.
|
||||
useviterbi = 0;
|
||||
if useviterbi
|
||||
mlse_db_ = MLSE_viterbi("duobinary_output",0,'M',s.M,'trellis_states',PAMmapper(s.M,0).levels);
|
||||
else
|
||||
mlse_db_ = MLSE("DIR",[1,1],"duobinary_output",0,"M",s.M,"trellis_states",PAMmapper(s.M,0).levels);
|
||||
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_, s.M, Rx_sig, Symbols{l},Tx_bits{l}, ...
|
||||
"precode_mode", duob_mode, ...
|
||||
'showAnalysis', 0,...
|
||||
"postFFE", []);
|
||||
|
||||
output_dbt{l,ri,realiz} = dbt_results;
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
res = struct();
|
||||
res.settings = s;
|
||||
res.ffe = output_ffe;
|
||||
res.vnle = output_vnle;
|
||||
res.mlse = output_mlse;
|
||||
res.dbt = output_dbt;
|
||||
|
||||
% Save results
|
||||
save(fullfile(output_root, fname), 'res', '-v7.3');
|
||||
fprintf('Saved results to: %s\n', fullfile(output_root, fname));
|
||||
disp(datetime('now','TimeZone','local','Format','yyyyMs.Mdd_HHmmss'));
|
||||
|
||||
|
||||
end
|
||||
|
||||
function dispersion_vector = getDispersionVector(N, D, ref_zdw, randomize_ZDW, randomkey)
|
||||
% s.MATLAB version of the Python generator shown above.
|
||||
% Returns an N×1 vector (ps/(nm·km)).
|
||||
%
|
||||
% D is the nominal dispersion magnitude. For D>0 the link is segmented with
|
||||
% alternating sign (+D, -D, +D, …). For D==0 it is flat (0) except for
|
||||
% ZDW randomization. The ZDW detuning is ~N(0, 2 nm) around 1310 nm and is
|
||||
% converted to dispersion via 0.09 ps/(nm·km) per nm.
|
||||
|
||||
% constants (matching the Python code)
|
||||
meanLambda_nm = 1310; % center wavelength
|
||||
sigma_nm = 2; % ZDW sigma
|
||||
Dslope = 0.07; % ps/(nm·km) per nm detuning
|
||||
|
||||
% random ZDW-induced dispersion offset
|
||||
if randomize_ZDW
|
||||
rng(randomkey, 'twister');
|
||||
rand_zdws_nm = meanLambda_nm + sigma_nm .* randn(N,1);
|
||||
rand_D = (rand_zdws_nm - ref_zdw) .* Dslope; % ps/(nm·km)
|
||||
else
|
||||
rand_D = zeros(N,1);
|
||||
end
|
||||
|
||||
% nominal segmented pattern (match Python intent; keep length N)
|
||||
if D > 0
|
||||
base = (-1) .^ ((0:N-1).'); % +1,-1,+1,-1,...
|
||||
else % D == 0 (or anything else)
|
||||
base = ones(N,1);
|
||||
end
|
||||
|
||||
dispersion_vector = base .* D + rand_D; % ps/(nm·km)
|
||||
end
|
||||
80
projects/WDM/WDM_settings.m
Normal file
80
projects/WDM/WDM_settings.m
Normal file
@@ -0,0 +1,80 @@
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
% Add the imdd_simulation framework to the path
|
||||
if ispc
|
||||
addpath(genpath('C:\Users\Silas\Documents\MATLAB\imdd_simulation'));
|
||||
else
|
||||
% Linux path on the cluster
|
||||
addpath(genpath('/work_beegfs/sutef391/imdd_simulation'));
|
||||
end
|
||||
|
||||
% Quiet the ambiguous CET warning (best is to set TZ in sbatch; see below)
|
||||
warning('off','MATLAB:datetime:AmbiguousTimeZone');
|
||||
|
||||
% How many workers?
|
||||
cpus = str2double(getenv('SLURM_CPUS_PER_TASK'));
|
||||
if ~isfinite(cpus) || cpus < 1, cpus = max(1, feature('numcores')); end
|
||||
|
||||
% Use a per-job, node-local JobStorageLocation to avoid stale locks on $HOME
|
||||
% Prefer $TMPDIR if your cluster provides it, else tempdir().
|
||||
tmpbase = getenv('TMPDIR');
|
||||
if isempty(tmpbase), tmpbase = tempdir; end
|
||||
jsl = fullfile(tmpbase, sprintf('matlab_jobstorage_%s_%s', ...
|
||||
getenv('USER'), getenv('SLURM_JOB_ID')));
|
||||
if ~exist(jsl,'dir'); mkdir(jsl); end
|
||||
|
||||
% Configure the local cluster explicitly and start the pool
|
||||
c = parcluster('local');
|
||||
c.NumWorkers = cpus;
|
||||
c.JobStorageLocation = jsl;
|
||||
|
||||
p = gcp('nocreate');
|
||||
if isempty(p) || p.NumWorkers ~= cpus
|
||||
if ~isempty(p), delete(p); end
|
||||
p = parpool(c, cpus); % avoids the “queued” state
|
||||
end
|
||||
fprintf('parpool up with %d workers; JobStorage=%s\n', p.NumWorkers, c.JobStorageLocation);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
% result filename (timestamp + optional job id)
|
||||
t = datetime('now','TimeZone','local','Format','yyyyMMdd_HHmmss');
|
||||
jobid = getenv('SLURM_JOB_ID'); if isempty(jobid), jobid = 'nojid'; end
|
||||
host = getenv('HOSTNAME'); if isempty(host), host = 'localhost'; end
|
||||
|
||||
% Output directory depends on platform
|
||||
if ispc
|
||||
output_root = fullfile('C:\Users\Silas\Documents\MATLAB\Datensätze\FWM_2025\');
|
||||
else
|
||||
output_root = '/work_beegfs/sutef391/results_WDM';
|
||||
end
|
||||
if ~exist(output_root,'dir'), mkdir(output_root); end
|
||||
|
||||
% Build filename
|
||||
t = datetime('now','TimeZone','local','Format','yyyyMMdd_HHmmss');
|
||||
jobid = getenv('SLURM_JOB_ID'); if isempty(jobid), jobid = 'nojid'; end
|
||||
host = getenv('HOSTNAME'); if isempty(host), host = 'localhost'; end
|
||||
|
||||
fname = sprintf('WDM_%s_%s_%s.mat', char(t), host, jobid);
|
||||
Reference in New Issue
Block a user