auswertungsfiles und algos for ECOC 2025 rush...

This commit is contained in:
Silas Oettinghaus
2025-04-25 10:31:43 +02:00
parent e407c8953d
commit 727c3d9364
18 changed files with 1152 additions and 233 deletions

View File

@@ -141,7 +141,7 @@ classdef Signal
arguments
obj
options.fignum
options.fignum = []
options.displayname = [];
options.timeframe = 0;
options.clear = 0;

View File

@@ -57,6 +57,8 @@ classdef FFE_DCremoval < handle
obj.e = zeros(obj.order,1);
obj.error = 0;
obj.dc_buffer_len = floor(obj.dc_buffer_len);
end
function [X,Noi] = process(obj, X, D)
@@ -155,16 +157,15 @@ classdef FFE_DCremoval < handle
end
end
if ~training
figure(1122)
hold on
scatter(1:numel(e_dc_save),e_dc_save,1,'.');
scatter(1:numel(y),y,1,'.');
end
% if ~training
% figure(1122)
% hold on
% scatter(1:numel(e_dc_save),e_dc_save,1,'.');
% % scatter(1:numel(y),y,1,'.');
%
% end
end
end
end

View File

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

View File

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

View File

@@ -70,7 +70,7 @@ classdef DBHandler < handle
% Get table names and the first rows of each table to understand the structure
obj.getTableNames();
obj.getTables();
obj.getDistinctValues();
% obj.getDistinctValues();
end
function obj = getTableNames(obj)

View File

@@ -1,129 +1,192 @@
function [eq_package] = vnle(eq_,M,rx_signal,tx_symbols,tx_bits,options)
%VNLE Apply an equalization algorithm to the received signal and calculate BER
% This function takes an equalizer object, a received signal, and the
% transmitted symbols to apply equalization, map the received signal back to bits,
% and compute the bit error rate (BER).
%
% Inputs:
% EQ - Equalizer object that provides the equalization method
% rx_signal - Received signal that needs to be equalized
% tx_symbols - Transmitted symbols used as a reference for BER calculation
%
% Outputs:
% eq_signal - Equalized version of the received signal
% ber - Bit error rate after equalization
% numErrors - Number of bit errors detected
arguments
arguments
eq_
M
rx_signal
tx_symbols
tx_bits
options.precode_mode db_mode
options.showAnalysis = 0
options.eth_style = 0;
options.showAnalysis = 0;
options.eth_style_symbol_mapping = 0;
options.postFFE = [];
end
options.database = [];
end
%FFE or VNLE
if length(rx_signal)/2 == length(tx_symbols)+0.5
rx_signal.signal = rx_signal.signal(1:end-1);
elseif length(rx_signal)/2 == length(tx_symbols)-1
end
[eq_signal_sd,eq_noise] = eq_.process(rx_signal,tx_symbols);
mudc_given = eq_.mu_dc;
if ~isempty(options.postFFE)
%FFE or VNLE
[eq_signal_sd,eq_noise] = eq_.process(rx_signal,tx_symbols);
if ~isempty(options.postFFE)
tic
[eq_signal_sd,eq_noise] = options.postFFE.process(eq_signal_sd,tx_symbols);
end
toc
end
eq_signal_hd = PAMmapper(M,0).quantize(eq_signal_sd);
eq_signal_hd = PAMmapper(M,0).quantize(eq_signal_sd);
% precoding to mitigate error propagation, most prominently used in
% combination with duobinary signaling to avoid catastrophic error
% behavior (see J.W.M. Bergmans, Digital Baseband Transmission and Recording -> partial response signaling)
% precoding to mitigate error propagation, most prominently used in
% combination with duobinary signaling to avoid catastrophic error
% behavior (see J.W.M. Bergmans, Digital Baseband Transmission and Recording -> partial response signaling)
% takes:
% -> eq_signal_hd: hard decision signal after eq
% -> tx_symbols: that where used as reference for eq
switch options.precode_mode
switch options.precode_mode
case db_mode.db_emulate
% re
eq_signal_hd = Duobinary().encode(eq_signal_hd,"M",M);
eq_signal_hd = Duobinary().decode(eq_signal_hd,"M",M);
case db_mode.no_db
% TX Data is not precoded:
% A) Emulate diff precoding
eq_signal_hd_precoded = Duobinary().encode(eq_signal_hd,"M",M);
eq_signal_hd_precoded = Duobinary().decode(eq_signal_hd_precoded,"M",M);
tx_symbols_precoded = Duobinary().encode(tx_symbols);
tx_symbols_precoded = Duobinary().decode(tx_symbols_precoded);
tx_bits = PAMmapper(M,0,"eth_style",options.eth_style).demap(tx_symbols_precoded);
tx_bits_precoded = PAMmapper(M,0,"eth_style",options.eth_style_symbol_mapping).demap(tx_symbols_precoded);
case db_mode.db_discard
rx_bits_vnle = PAMmapper(M,0,"eth_style",options.eth_style_symbol_mapping).demap(eq_signal_hd_precoded);
[~,errors_vnle_diff_precoded,ber_vnle_diff_precoded,~] = calc_ber(rx_bits_vnle.signal,tx_bits_precoded.signal,"skip_front",30000,"skip_end",150,"returnErrorLocation",1);
% normal dsp for precoded sequence == discard/omit/ignore precode
tx_bits = PAMmapper(M,0).demap(tx_symbols);
%B) Just determine BER
rx_bits_vnle = PAMmapper(M,0,"eth_style",options.eth_style_symbol_mapping).demap(eq_signal_hd);
[bits_vnle,errors_vnle,ber_vnle,error_pos_vnle] = calc_ber(rx_bits_vnle.signal,tx_bits.signal,"skip_front",30000,"skip_end",150,"returnErrorLocation",1);
case db_mode.db_encoded
% normal DB encoded data (only for 10KM)
max_burst_length = 10;
burst_count = count_error_bursts(error_pos_vnle, max_burst_length);
case db_mode.db_precoded
eq_signal_hd = Duobinary().encode(eq_signal_hd,"M",M);
eq_signal_hd = Duobinary().decode(eq_signal_hd,"M",M);
% Daten SIND TATSÄCHLICH precoded auf TX Seite:
end
% A) Decode at Rx if no DB targeting was applied (we are in VNLE or MLSE EQ structure here!
eq_signal_hd_decoded = Duobinary().encode(eq_signal_hd,"M",M);
eq_signal_hd_decoded = Duobinary().decode(eq_signal_hd_decoded,"M",M);
rx_bits_vnle_decoded = PAMmapper(M,0,"eth_style",options.eth_style_symbol_mapping).demap(eq_signal_hd_decoded);
[~,errors_vnle_diff_precoded,ber_vnle_diff_precoded,~] = calc_ber(rx_bits_vnle_decoded.signal,tx_bits.signal,"skip_front",30000,"skip_end",150,"returnErrorLocation",1);
rx_bits = PAMmapper(M,0,"eth_style",options.eth_style).demap(eq_signal_hd);
% B) Omit the Coding by comparing with demapped TX symbol sequence
[~,numErrors,ber,~] = calc_ber(rx_bits.signal,tx_bits.signal,"skip_front",100,"skip_end",150,"returnErrorLocation",1);
[evm_total,evm_lvl] = calc_evm(eq_signal_sd,tx_symbols);
[inf_rate] = calc_air(eq_signal_sd,tx_symbols,"skip_front",10000,"skip_end",10000);
tx_bits = PAMmapper(M,0,"eth_style",options.eth_style_symbol_mapping).demap(tx_symbols);
rx_bits_vnle = PAMmapper(M,0,"eth_style",options.eth_style_symbol_mapping).demap(eq_signal_hd);
[bits_vnle,errors_vnle,ber_vnle,~] = calc_ber(rx_bits_vnle.signal,tx_bits.signal,"skip_front",30000,"skip_end",150,"returnErrorLocation",1);
eq_package.ber_vnle = ber;
eq_package.evm_total = evm_total;
eq_package.evm_lvl = evm_lvl;
eq_package.inf_rate_vnle = inf_rate;
eq_package.snr = snr(eq_signal_sd.signal,eq_noise.signal);
eq_package.signal = eq_signal_sd;
if options.showAnalysis
fprintf('SNR: %d dB \n',snr(eq_signal_sd.signal,eq_noise.signal));
if M == 6
logm = 2.5;
else
logm = log2(M);
end
fprintf('NGMI: %.4f \n', inf_rate/logm);
fprintf(['VNLE EVM lvl: ',repmat('%.3f ',1,numel(evm_lvl)),' \n'],evm_lvl);
fprintf('VNLE BER: %.2e \n',ber);
disp("%%%%%%%%%%%%%%%%%%%%%")
% showEQcoefficients('n1',eq_.e,'n2',eq_.e2,'n3',eq_.e3,"displayname",'Coefficients');
%
% if ~isempty(options.postFFE)
% showEQcoefficients('n1',options.postFFE.e,"displayname",'Coefficients');
% end
%
% showEQNoisePSD(eq_noise);
%
% showEQfilter(eq_.e,eq_signal_sd.fs.*2)
% noiselessness(tx_symbols,eq_noise,"displayname",'SNR after VNLE','fignum',301);
% showLevelHistogram(eq_signal_sd,tx_symbols,"fignum",302);
end
end
% METRICS OF VNLE SD Signal:
[snr_vnle,snr_vnle_lvl] = calc_snr(tx_symbols.signal,eq_noise.signal);
[gmi_vnle] = calc_air(eq_signal_sd,tx_symbols,"skip_front",10000,"skip_end",10000);
air_vnle = tx_symbols.fs .* floor(log2(double(M))*10)/10 .* gmi_vnle ./ log2(double(M));
[evm_vnle_total,evm_vnle_lvl] = calc_evm(eq_signal_sd,tx_symbols);
[std_vnle_total,std_vnle_lvl] = calc_std(eq_signal_sd,tx_symbols);
[std_rxraw_total,std_rxraw_lvl] = calc_std(rx_signal.resample("fs_out",tx_symbols.fs),tx_symbols);
eq_package.ber_vnle = ber_vnle;
eq_package.evm_vnle_total = evm_vnle_total;
eq_package.evm_vnle_lvl = evm_vnle_lvl;
eq_package.gmi = gmi_vnle;
eq_package.eq = eq_;
resultsVNLE = struct( ...
'result_id', NaN, ... %
'run_id', NaN, ... % Beispielhafte Run-ID
'eqParam_id', NaN, ... % Beispielhafter Fremdschlüssel zur EqualizerParameters-Tabelle
'date_of_processing', datetime('now'), ... % Aktuelles Datum und Uhrzeit
'BER', ber_vnle, ... % BER = 120 / 1.000.000
'numBits', bits_vnle, ... % Beispiel: 1.000.000 Bits
'numBitErr', errors_vnle, ... % Beispiel: 120 Bitfehler
'BER_precoded', ber_vnle_diff_precoded, ... % BER = 120 / 1.000.000
'numBitErr_precoded', errors_vnle_diff_precoded, ... % Beispiel: 120 Bitfehler
'SNR', snr_vnle, ... % Beispielhafte SNR
'SNR_level', jsonencode(snr_vnle_lvl), ... % SNR-Level als JSON-codiertes Array
'STD', std_vnle_total, ...
'STD_level', jsonencode(std_vnle_lvl),...
'STDrx' , std_rxraw_total, ...
'STDrx_level', jsonencode(std_rxraw_lvl),...
'GMI', gmi_vnle, ... % Beispielhafter GMI-Wert
'AIR', air_vnle, ... % Beispielhafter AIR-Wert
'EVM', evm_vnle_total, ... % Beispielhafte EVM
'EVM_level', jsonencode(evm_vnle_lvl), ... % EVM-Level als JSON-codiertes Array
'Alpha', [] ... % Beispielhafter Alpha-Wert
);
if ~isempty(options.postFFE)
npostFFE = options.postFFE.order;
else
npostFFE = 0;
end
equalizerConfigVNLE = struct( ...
'eq_id', NaN, ... % Auto-Inkrement, wird in der DB gesetzt
'equalizer_structure', int32(equalizer_structure.vnle), ... % Beispiel: 1 (z.B. für vnle)
'M', M, ... % Ordnung der PAM-Konstellation
'target_constellation', jsonencode(round(unique(tx_symbols.signal),5)), ... % Beispielhafter Target-String
'db_target', 0, ... % 0 oder 1
'diff_precode', int32(options.precode_mode), ... % 0 oder 1
'postFFE', int32(~isempty(options.postFFE)), ... % Beispielwert
'NpostFFE', npostFFE, ... % Beispielwert
'Ne1', eq_.order, ... % Feedforward Koeffizienten 1. Ordnung
'K', eq_.sps, ... % Samples pro Symbol
'DCmu', mudc_given, ... % Anpassungsrate für DC-Tap
'training_length', eq_.len_tr, ... % Anzahl Trainingssymbole
'training_loops', eq_.epochs_tr, ... % Anzahl Trainingsdurchläufe
'TRmu1', eq_.mu_tr, ... % mu für DD-Modus (1. Ordnung)
'dd_loops', eq_.epochs_dd, ... % Anzahl Durchläufe im DD-Modus
'DDmu1', eq_.mu_dd, ... % mu für DD-Modus (1. Ordnung)
'comment', 'function: ffe dc removal', ... % Zusätzliche Kommentare
'ffe_buffer_len', eq_.ffe_buffer_len, ...
'smoothing_buffer_len', eq_.smoothing_buffer_length, ...
'smoothing_buffer_update', eq_.smoothing_buffer_update, ...
'dc_buffer_len', eq_.dc_buffer_len, ...
'config_hash', NaN ...
);
eq_package.resultsVNLE = resultsVNLE;
eq_package.equalizerConfigVNLE = equalizerConfigVNLE;
% eq_package.vnle_out = eq_signal_sd;
if options.showAnalysis
% fprintf(['VNLE EVM lvl: ',repmat('%.3f ',1,numel(evm_lvl)),' \n'],evm_lvl);
% fprintf('VNLE BER: %.2e \n',ber_vnle);
%
% fprintf('MLSE BER: %.2e \n',ber_mlse);
figure(336);
showEQNoisePSD(eq_noise,"fignum",336,"displayname",'Residual Noise after VNLE');
% figure(337);clf;
% rx_signal.spectrum("normalizeTo0dB",1,"fignum",337,"displayname",'Rx Signal');
% figure(338);clf;
% showEQcoefficients('n1',eq_.e,'n2',eq_.e2,'n3',eq_.e3,"displayname",'Coefficients','fignum',338);
if ~isempty(options.postFFE)
showEQcoefficients('n1',options.postFFE.e,"displayname",'Coefficients','fignum',338);
end
showEQfilter(eq_.e,eq_signal_sd.fs.*2);
% figure(340);clf;
% eq_signal_sd.eye(eq_signal_sd.fs,M,"fignum",340);
figure(341);clf;
showLevelHistogram(eq_signal_sd,tx_symbols,"fignum",341);
figure(400);clf;
warning off
showLevelScatter(eq_signal_sd,tx_symbols,"fignum",400);
showLevelScatter(rx_signal.resample("fs_out",tx_symbols.fs),tx_symbols,"fignum",400);
warning on
% autoArrangeFigures(3,3,2)
end
end

View File

@@ -252,7 +252,7 @@ if options.showAnalysis
%
% fprintf('MLSE BER: %.2e \n',ber_mlse);
figure(336);clf;
figure(336);
showEQNoisePSD(eq_noise,"fignum",336,"displayname",'Residual Noise after VNLE','postfilter_taps',pf_.coefficients);
% figure(337);clf;
@@ -273,9 +273,12 @@ if options.showAnalysis
figure(341);clf;
showLevelHistogram(eq_signal_sd,tx_symbols,"fignum",341);
warning off
showLevelScatter(eq_signal_sd,tx_symbols,"fignum",400);
showLevelScatter(rx_signal.resample("fs_out",tx_symbols.fs),tx_symbols,"fignum",401);
warning on
drawnow;
% autoArrangeFigures(3,3,2)

View File

@@ -20,7 +20,6 @@ if isnan(options.fignum)
fig = figure; % Create a new figure and get its handle
else
fig = figure(options.fignum); % Use the specified figure number
clf;
end
assert(~isempty(options.f_sym),'No fsym given');
@@ -40,7 +39,7 @@ ende = length(correct_symbols);
% start = 30000;
% ende = 40000;
for l = 1:4
for l = 1:numel(levels)
ccnt = ccnt+2;
level_amplitude = levels(l);
@@ -50,23 +49,24 @@ for l = 1:4
std_lvl(l) = std(symbols_for_lvl,'omitnan');
xax_in_sec = ((1:length(correct_symbols)) / f_sym) * 1e6;
% xax_in_sec = 1:length(correct_symbols);
if 0
scatter(xax_in_sec(start:ende),symbols_for_lvl(start:ende),10,'.','MarkerFaceAlpha',0.5,'MarkerEdgeAlpha',0.5,'MarkerEdgeColor',col(ccnt,:));
hold on;
end
end
std_lvl = round(std_lvl,2);
ccnt = 0;
% Add the windowed/ smoothed curves
for l = 1:4
for l = 1:numel(levels)
ccnt = ccnt+2;
level_amplitude = levels(l);
symbols_for_lvl = NaN(1,length(correct_symbols));
movmean = 1/250 .* movsum(rx_symbols(correct_symbols==level_amplitude),[250/2,250/2]);
movmean = 1/250 .* movsum(rx_symbols(correct_symbols==level_amplitude),[250/2,250/2], 'Endpoints', 'fill');
symbols_for_lvl(correct_symbols==level_amplitude) = movmean;

View File

@@ -0,0 +1,29 @@
function burst_count = count_error_bursts(err_pos, max_burst_length)
% err_pos: Vector of error positions
% max_burst_length: Maximum length for which bursts are counted (e.g., 10)
% Sort the error positions to ensure they're in increasing order
err_pos = sort(err_pos);
% Initialize burst_count array to hold the counts for each burst length
burst_count = zeros(1, max_burst_length);
% Find the differences between consecutive error positions
diffs = diff(err_pos);
% Find the start of the bursts (where the difference is greater than 1)
burst_starts = [1, find(diffs > 1) + 1]; % Starts at index 1 and after gaps
burst_ends = [find(diffs > 1), length(err_pos)]; % Ends where gaps are
% Loop over the bursts
for b = 1:length(burst_starts)
burst_length = burst_ends(b) - burst_starts(b) + 1;
% Check if the burst length exceeds any of the thresholds
for i = 1:max_burst_length
if burst_length > i
burst_count(i) = burst_count(i) + 1;
end
end
end
end

View 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', 10, ...
'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;

View File

@@ -48,15 +48,14 @@ mu_ffe3 = 0.001;
mu_dfe = 0.0004;
mu_dc = 0.00;
% mu_ffe1 = 0;
% mu_ffe2 = 0;
% mu_ffe3 = 0;
% mu_dfe =0;
% mu_dc = 0.00;
mu_ffe = [mu_ffe1 mu_ffe2 mu_ffe3];
vnle_order=[vnle_order1,vnle_order2,vnle_order3];
dc_buffer_len = 224;
ffe_buffer_len = 1;
smoothing_buffer_length = 4096;
smoothing_buffer_update = 224;
% Overwrite default parameters if given in options.parameters
paramStruct = options.parameters;
if ~isempty(paramStruct)
@@ -78,7 +77,7 @@ eq_post = FFE("epochs_tr",5,"epochs_dd",5,"len_tr",4096*2,"mu_dd",1e-4,"mu_tr",0
output = struct();
vnle_pf_package = {};
vnle_dfe_package = {};
vnle_package = {};
dbtgt_package = {};
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -121,7 +120,7 @@ if ~found_sync
end
record_realizations = min(options.max_occurences,length(Scpe_cell));
for occ = 1:record_realizations
for occ = 4:record_realizations
Scpe_sig = Scpe_cell{occ};
@@ -137,16 +136,27 @@ for occ = 1:record_realizations
if duob_mode ~= db_mode.db_encoded
vnle_pf = 1;
vnle_pf = 0;
dbtgt = 0;
% %%%%% VNLE + DFE %%%%
if 0
if 1
eq_vnle_dfe = EQ("Ne",vnle_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);
eq_post = FFE("epochs_tr",5,"epochs_dd",5,"len_tr",4096*2,"mu_dd",1e-4,"mu_tr",0,"order",2001,"sps",1,"decide",0);
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",mu_dc,...
"dc_buffer_len",dc_buffer_len, ...
"ffe_buffer_len",ffe_buffer_len,...
"smoothing_buffer_length",smoothing_buffer_length,...
"smoothing_buffer_update",smoothing_buffer_update);
[result] = vnle(eq_vnle_dfe,M,Scpe_sig,Symbols,Tx_bits,"precode_mode",duob_mode,"showAnalysis",1,"postFFE",[]);
vnle_dfe_package{occ} = result;
result = vnle(eq_,M,Scpe_sig,Symbols,Tx_bits,"precode_mode",duob_mode,'showAnalysis',1,"postFFE",[],"eth_style_symbol_mapping",0);
vnle_package{occ} = result;
fprintf("FFE Results: %.2e\n", result.ber_vnle);
if options.append_to_db
database.addProcessingResult(run_id, result.resultsVNLE, result.equalizerConfigVNLE);
end
end
@@ -176,32 +186,32 @@ for occ = 1:record_realizations
% % fprintf("BER VNLE: %.2e | %.2e; BER MLSE: %.2e | %.2e \n",vnle_pf_package{occ}.resultsVNLE.BER,vnle_pf_package{occ}.resultsVNLE.BER_precoded ,vnle_pf_package{occ}.resultsMLSE.BER,vnle_pf_package{occ}.resultsMLSE.BER_precoded);
if vnle_pf
occ = 1; % or whatever your loop index is
% occ = 1; % or whatever your loop index is
% Extract VNLE results for readability
vnle = vnle_pf_package{occ}.resultsVNLE;
mlse = vnle_pf_package{occ}.resultsMLSE;
vnle_result = vnle_pf_package{occ}.resultsVNLE;
mlse_result = vnle_pf_package{occ}.resultsMLSE;
% Print header
fprintf("==== EQUALIZATION RUN-ID %d | PAM-%d | %.2f GBd ====\n\n", run_id, M, Symbols.fs.*1e-9);
s
% VNLE Results
fprintf(">> VNLE Results:\n");
fprintf(" BER %.2e\n", vnle.BER);
fprintf(" BER (pre-code) %.2e\n", vnle.BER_precoded);
fprintf(" SNR: %.2f dB\n", vnle.SNR);
fprintf(" GMI: %.4f\n", vnle.GMI);
fprintf(" BER %.2e\n", vnle_result.BER);
fprintf(" BER (pre-code) %.2e\n", vnle_result.BER_precoded);
fprintf(" SNR: %.2f dB\n", vnle_result.SNR);
fprintf(" GMI: %.4f\n", vnle_result.GMI);
fprintf(" Linerate: %.2f Gbps\n", Symbols.fs .* floor(log2(M)*10)/10 .*1e-9);
fprintf(" AIR: %.2f Gbps\n", vnle.AIR.*1e-9);
fprintf(" AIR: %.2f Gbps\n", vnle_result.AIR.*1e-9);
fprintf("\n");
% MLSE Results
fprintf(">> MLSE Results:\n");
fprintf(" BER : %.2e\n", mlse.BER);
fprintf(" BER (pre-code): %.2e\n", mlse.BER_precoded);
fprintf(" Channel Alpha : %.2f\n", mlse.Alpha);
fprintf(" BER : %.2e\n", mlse_result.BER);
fprintf(" BER (pre-code): %.2e\n", mlse_result.BER_precoded);
fprintf(" Channel Alpha : %.2f\n", mlse_result.Alpha);
fprintf("\n");
end
@@ -244,6 +254,7 @@ end
output.dataTable = dataTable;
output.vnle_pf_package = vnle_pf_package;
output.vnle_package = vnle_package;
output.dbtgt_package = dbtgt_package;
end

View File

@@ -4,9 +4,89 @@
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("pathToDB", [databasePath, database_name],"type","mysql");
% db = DBHandler("type","mysql");
num_occ = 5;
run_par = false;
run_id = 1958;
[out, future] = submit_dsp(run_id, databasePath, database_name, savePath,"parallel",run_par,'max_occurences',num_occ);
db = DBHandler("type","mysql");
% db = DBHandler("pathToDB", [databasePath, database_name],"type","sqlite");
filterParams = db.tables;
% filterParams.Configurations = struct('run_id', 4001);
filterParams.Configurations = struct( ...
'symbolrate', 112e9, ... %[224,336,360,390,420,448]
'fiber_length', 0, ...
'db_mode', '"no_db"', ...
'interference_attenuation', [], ...
'interference_path_length', [], ...
'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<200,:) = [];
num_occ = 15;
run_par = true;
run_id = dataTable.run_id;
params = struct();
% slow DC tracking
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
% ideal DC tracking
params.dc_buffer_len = 1;
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
% DC smoothing
params.dc_buffer_len = 1;
params.ffe_buffer_len = 1;
params.smoothing_buffer_length = 4096;
params.smoothing_buffer_update = 224;
params.mu_dc = 0.00;
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
% only FFE
params.dc_buffer_len = 1;
params.ffe_buffer_len = 1;
params.smoothing_buffer_length = 0;
params.smoothing_buffer_update = 0;
params.mu_dc = 0.00;
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

View 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",224, ...
"ffe_buffer_len",1,...
"smoothing_buffer_length",0,...
"smoothing_buffer_update",224);
result = vnle(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.ber_vnle;
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 ])

View File

@@ -1,6 +1,6 @@
run_id = 231;
run_id = 3966;
savePath = 'Z:\2025\ECOC Silas\ecoc_2025\';
databasePath = 'C:\Users\Silas\Documents\MATLAB\imdd_simulation\projects\ECOC_2025\';
@@ -9,7 +9,22 @@ 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('run_id', run_id);
filterParams.Configurations = struct( ...
'symbolrate', [], ... %[224,336,360,390,420,448]
'fiber_length', 0, ...
'db_mode', '"no_db"', ...
'interference_attenuation', 4, ...
'interference_path_length', 10, ...
'is_mpi', 1, ...
'pam_level', [], ...
'wavelength', 1310, ...
'precomp_amp', [], ...
'signal_attenuation', [], ...
'v_awg', [], ...
'v_bias', 2.65 ...
);
selectedFields = {'Runs.run_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',...
@@ -18,29 +33,36 @@ selectedFields = {'Runs.run_id','Runs.tx_bits_path','Runs.tx_signal_path','Runs.
[dataTable,sql_query] = db.queryDB(filterParams, selectedFields);
[~, uniqueIdx] = unique(dataTable.run_id); % Get unique run_id indices
dataTable = dataTable(uniqueIdx,:); % Extract unique configurations for each run_id
fsym = dataTable.symbolrate;
M = double(dataTable.pam_level);
duob_mode = db_mode.(strrep(char(dataTable.db_mode),'"',''));
Tx_signal = load([savePath, char(dataTable.tx_signal_path)]);
Tx_signal = Tx_signal.Digi_sig;
for i = 1:4%size(dataTable,1)
dataTable_ = dataTable(i,:); % Extract unique configurations for each run_id
Tx_bits = load([savePath, char(dataTable.tx_bits_path)]);
Tx_bits = Tx_bits.Bits;
Symbols_mapped = PAMmapper(M,0).map(Tx_bits);
Symbols_mapped.fs = dataTable.symbolrate;
fsym = dataTable_.symbolrate;
M = double(dataTable_.pam_level);
duob_mode = db_mode.(strrep(char(dataTable_.db_mode),'"',''));
Symbols = load([savePath, char(dataTable.tx_symbols_path)]);
Symbols = Symbols.Symbols;
Tx_signal = load([savePath, char(dataTable_.tx_signal_path)]);
Tx_signal = Tx_signal.Digi_sig;
Scpe_sig_raw = load([savePath, char(dataTable.rx_raw_path(1))]);
Scpe_sig_raw = Scpe_sig_raw.Scpe_sig_raw;
Scpe_sig_resampled = Scpe_sig_raw.resample("fs_in",Scpe_sig_raw.fs,"fs_out",2*fsym);
[~,Scpe_cell,found_sync,~,shifts] = Scpe_sig_resampled.tsynch("reference",Symbols,"fs_ref",dataTable.symbolrate,"debug_plots",1);
Tx_bits = load([savePath, char(dataTable_.tx_bits_path)]);
Tx_bits = Tx_bits.Bits;
Symbols_mapped = PAMmapper(M,0).map(Tx_bits);
Symbols_mapped.fs = dataTable_.symbolrate;
shifts_mus = shifts./Scpe_sig_resampled.fs .*1e6;
Scpe_sig_raw.plot("displayname",['Scope Signal (Run ID: ',num2str(run_id)],"fignum",2024,"clear",1);
hold on;
xline(shifts_mus,'HandleVisibility','off');
Symbols = load([savePath, char(dataTable_.tx_symbols_path)]);
Symbols = Symbols.Symbols;
Scpe_sig_raw = load([savePath, char(dataTable_.rx_raw_path(1))]);
Scpe_sig_raw = Scpe_sig_raw.Scpe_sig_raw;
Scpe_sig_raw.plot("displayname",['Scope Signal (Run ID: ',num2str(dataTable_.run_id)],"fignum",dataTable_.run_id,"clear",0);
Scpe_sig_resampled = Scpe_sig_raw.resample("fs_in",Scpe_sig_raw.fs,"fs_out",2*fsym);
[~,Scpe_cell,found_sync,~,shifts] = Scpe_sig_resampled.tsynch("reference",Symbols,"fs_ref",dataTable_.symbolrate,"debug_plots",1);
shifts_mus = shifts./Scpe_sig_resampled.fs .*1e6;
Scpe_sig_raw.plot("displayname",['Scope Signal (Run ID: ',num2str(dataTable_.run_id)],"fignum",dataTable_.run_id,"clear",0);
hold on;
xline(shifts_mus,'HandleVisibility','off');
end

View File

@@ -1,67 +1,129 @@
local = 1;
if local
databasePath = 'C:\Users\sioe\Documents\MATLAB\imdd_simulation\projects\ECOC_2025\';
else
databasePath = '\\ntserver.tf.uni-kiel.de\scratch\sioe\ECOC_2025\';
end
database_name = 'ecoc2025_loops.db';
database = DBHandler("pathToDB", [databasePath, database_name]);
figure();
plotBoundaries = 1;
plotRealizations = 1;
cols = linspecer(3); % Ensure color count matches
% cols = cols(8,:);
basePath = 'C:\Users\Silas\Documents\MATLAB\Datensätze\sioe_labor\';
% database = DBHandler("pathToDB",[basePath,'silas_labor.db']);
database = DBHandler("type",'mysql');
filterParams = database.tables;
%filterParams.Runs.loop_id = 209;
filterParams.Configurations = struct( ...
'symbolrate', 112e9, ... %[224,336,360,390,420,448]
'fiber_length', 0, ...
'db_mode', '"no_db"', ...
'interference_attenuation', [], ...
'interference_path_length', 10, ...
'interference_path_length', [], ...
'is_mpi', 1, ...
'pam_level', 4, ...
'wavelength', 1310, ...
'precomp_amp', [], ...
'signal_attenuation', [], ...
'v_awg', 0.95, ...
'v_bias', 2.5 ...
'v_awg', [], ...
'v_bias', [] ...
);
% filterParams.EqualizerParameters.diff_precode = int32(db_mode.db_encoded);
% filterParams.EqualizerParameters.equalizer_structure = int32(equalizer_structure.vnle);
% if 1
% % filterParams.EqualizerParameters.dc_buffer_len = 1;
% filterParams.EqualizerParameters.ffe_buffer_len = 1;
% filterParams.EqualizerParameters.smoothing_buffer_len = 4096;
% filterParams.EqualizerParameters.smoothing_buffer_update = 224;
% filterParams.EqualizerParameters.DCmu = 0;
% end
selectedFields = {'Configurations.run_id' 'Runs.loop_id' 'Runs.date_of_run' 'Runs.rx_raw_path' 'Configurations.bitrate' 'Configurations.v_bias' 'Configurations.v_awg' 'Configurations.precomp_amp' 'Configurations.symbolrate' 'Configurations.pam_level'...
'Configurations.db_mode' 'Configurations.rop_attenuation' 'Configurations.is_mpi' 'Configurations.interference_attenuation' 'Configurations.interference_path_length' 'Configurations.signal_attenuation' ...
'EqualizerParameters.equalizer_structure' 'EqualizerParameters.diff_precode' 'EqualizerParameters.eq_id' 'Measurements.power_pd_in' ...
'Measurements.power_mpi_interference' 'Measurements.power_mpi_signal' 'Results.BER' 'Results.BER_precoded' 'Results.SNR' 'Results.GMI' 'Results.Alpha' 'Results.date_of_processing'};
'EqualizerParameters.equalizer_structure' 'EqualizerParameters.diff_precode' 'EqualizerParameters.eq_id' 'EqualizerParameters.dc_buffer_len' 'EqualizerParameters.ffe_buffer_len' 'EqualizerParameters.smoothing_buffer_len' 'EqualizerParameters.smoothing_buffer_update' 'EqualizerParameters.DCmu' 'Measurements.power_pd_in' ...
'Measurements.power_mpi_interference' 'Measurements.power_mpi_signal' 'Results.BER' 'Results.BER_precoded' 'Results.EVM' 'Results.SNR' 'Results.GMI' 'Results.Alpha' 'Results.date_of_processing'};
[dataTable,sql_query] = database.queryDB(filterParams, selectedFields);
dataTable.SIR = round(-6 - dataTable.power_mpi_interference);
dataTable = cleanUpTable(dataTable);
% [dataTable_raw,sql_query] = database.queryDB(filterParams, selectedFields);
%%
dataTable_clean = dataTable_raw;
dataTable_clean.SIR = round(-7.5 - dataTable_clean.power_mpi_interference);
dataTable_clean.NGMI = dataTable_clean.GMI ./ log2(dataTable_clean.pam_level);
dataTable_clean = cleanUpTable(dataTable_clean);
%%
dataTable = dataTable_clean;
figure(26);
plotBoundaries = 1;
plotRealizations = 0;
cols = linspecer(8); % Ensure color count matches
% ideal DC tracking
if 0
dataTable = dataTable(dataTable.dc_buffer_len == 1, :);
dataTable = dataTable(dataTable.ffe_buffer_len == 1, :);
dataTable = dataTable(dataTable.smoothing_buffer_len == 0, :);
dataTable = dataTable(dataTable.smoothing_buffer_update == 0, :);
dataTable = dataTable(dataTable.DCmu == 0.005, :);
cols = cols(1:1+1,:);
method = 'ideal dc tracking';
% slow DC tracking
elseif 1
dataTable = dataTable(dataTable.dc_buffer_len == 224, :);
dataTable = dataTable(dataTable.ffe_buffer_len == 1, :);
dataTable = dataTable(dataTable.smoothing_buffer_len == 0, :);
dataTable = dataTable(dataTable.smoothing_buffer_update == 0, :);
dataTable = dataTable(dataTable.DCmu == 0.005, :);
cols = cols(2:2+1,:);
method = 'parallelized dc tracking';
% slow DC smoothing
elseif 0
dataTable = dataTable(dataTable.dc_buffer_len == 1, :);
dataTable = dataTable(dataTable.ffe_buffer_len == 1, :);
dataTable = dataTable(dataTable.smoothing_buffer_len == 4096, :);
dataTable = dataTable(dataTable.smoothing_buffer_update == 224, :);
dataTable = dataTable(dataTable.DCmu == 0, :);
cols = cols(3:3+1,:);
method = 'dc smoothing';
elseif 0
% No compensation method
dataTable = dataTable(dataTable.dc_buffer_len == 1, :);
dataTable = dataTable(dataTable.ffe_buffer_len == 1, :);
dataTable = dataTable(dataTable.smoothing_buffer_len == 0, :);
dataTable = dataTable(dataTable.smoothing_buffer_update == 0, :);
dataTable = dataTable(dataTable.DCmu == 0, :);
cols = cols(4:4+1,:);
method = 'ffe only';
end
dataTable(dataTable.eq_id==0,:) = [];
dataTable(dataTable.equalizer_structure~=1,:) = [];
% dataTable.interference_path_length(dataTable.interference_path_length < 20, :) = 20;
dataTable = dataTable(dataTable.interference_path_length == 1000, :);
% dataTable(dataTable.interference_path_length ~= 50, :) = [];
% dataTable = dataTable(dataTable.interference_path_length < 51, :);
% dataTable(dataTable.loop_id<200,:) = [];
% Filter by time
filter_by_time = 0;
if filter_by_time
startTime = datetime('2025-04-14 13:00:00', 'InputFormat', 'yyyy-MM-dd HH:mm:ss');
stopTime = datetime('2025-04-14 19:30:00', 'InputFormat', 'yyyy-MM-dd HH:mm:ss');
startTime = datetime('2025-04-20 18:00:00', 'InputFormat', 'yyyy-MM-dd HH:mm:ss');
stopTime = datetime('2025-04-30 19:30:00', 'InputFormat', 'yyyy-MM-dd HH:mm:ss');
dataTable.date_of_run = datetime(dataTable.date_of_run, 'InputFormat', 'yyyy-MM-dd HH:mm:ss.SSSSSS');
dataTable.date_of_processing = datetime(dataTable.date_of_processing, 'InputFormat', 'yyyy-MM-dd HH:mm:ss.SSSSSS');
dataTable = dataTable(dataTable.date_of_processing > startTime, :);
dataTable = dataTable(dataTable.date_of_processing < stopTime, :);
end
% Group by smth
y_var = 'BER';
x_var = 'SIR';
loop_var = 'eq_id';
fixedVars = {'eq_id',x_var};
loop_var = 'interference_path_length';
fixedVars = {'equalizer_structure','interference_path_length',x_var};
[dataTable, outliersTable] = removeGroupOutliers(dataTable, fixedVars, y_var);
@@ -69,14 +131,13 @@ dataTableGrpd_mean = groupIt(fixedVars, dataTable, @mean);
dataTableGrpd_min = groupIt(fixedVars, dataTable, @min);
dataTableGrpd_max = groupIt(fixedVars, dataTable, @max);
% Create a new figure
mkr = '.';
hold on
unique_loop_var = unique(dataTable.(loop_var));
for i = 1%:numel(unique_loop_var)
for i = 1:numel(unique_loop_var)
% Prepare filtered data for this loop variable
loopValue = unique_loop_var(i);
@@ -98,32 +159,43 @@ for i = 1%:numel(unique_loop_var)
y_bounds = [y_lower, y_upper];
% Display name (optional)
try
idx = find(dataTable.(loop_var) == loopValue, 1, 'first');
dispname = equalizer_structure(dataTable.equalizer_structure(idx));
dispname = [char(dispname),'; ',num2str(unique(dataTable.interference_path_length)),' m'];
% dispname = char(equalizer_structure(dataTable.equalizer_structure(idx)));
dispname = [method];
dispname = [dispname, '/ ',num2str(unique_loop_var(i)) ,' m'];
% dispname = [dispname,'; ',num2str(unique(dataTable.interference_path_length)),' m'];
dispname = [dispname, '/ PAM ', num2str(filterParams.Configurations.pam_level)];
dispname = [dispname, '/ ', num2str(filterParams.Configurations.symbolrate.*1e-9),' GBd'];
end
if plotBoundaries
% Plot bounded line
[hl, hp] = boundedline(x_values, y_mean, y_bounds, ...
'alpha', 'transparency', 0.2, ...
'alpha', 'transparency', 0.1, ...
'cmap', cols(i,:), ...
'nan', 'fill', ...
'orientation', 'vert');
% Style the main line: thinnest, dotted, no marker
% % Style the main line: thinnest, dotted, no marker
set(hl, 'LineWidth', 1, 'LineStyle', '-', 'Marker', 'none', ...
'Color', cols(i,:), 'DisplayName', string(dispname));
plt = errorbar(x_values,y_mean,y_lower,y_upper,'LineWidth', 0.1, 'LineStyle', 'none', 'Marker', 'none','Color', cols(i,:), 'DisplayName', string(dispname),'HandleVisibility','off');
% Hide patch (shaded area) from legend
set(hp, 'HandleVisibility', 'off','LineStyle',':','LineWidth',0.5,'Marker','none');
% Add invisible scatter for DataTips
plt = scatter(x_values, y_mean, ...
'Marker', 'o', 'MarkerEdgeColor', 'none', 'MarkerFaceColor', 'none', ...
'HandleVisibility', 'off', 'PickableParts', 'all');
% % Add invisible scatter for DataTips
% plt = scatter(x_values, y_mean, ...
% 'Marker', 'o', 'MarkerEdgeColor', 'none', 'MarkerFaceColor', 'none', ...
% 'HandleVisibility', 'off', 'PickableParts', 'all');
else
plt= plot(x_values,y_mean,'LineWidth', 1, 'LineStyle', '-', 'Marker', 'none', ...
'Color', cols(i,:), 'DisplayName', string(dispname));
% plt= errorbar(x_values,y_mean,y_lower,y_upper,'LineWidth', 1, 'LineStyle', '-', 'Marker', 'none','Color', cols(i,:), 'DisplayName', string(dispname));
end
% Add data tips to the invisible scatter
pair_one = {'Run ID', dataTableGrpd_mean.run_id(loopFiltGrpd, :)};
@@ -146,7 +218,7 @@ for i = 1%:numel(unique_loop_var)
y_single = double(dataTable.(y_var)(loopFiltSingle, :));
sc = scatter(x_single, y_single, 'Marker', mkr, 'MarkerEdgeColor', cols(i, :), ...
'LineWidth', 0.5, 'HandleVisibility', 'on', 'DisplayName', string(dispname));
'LineWidth', 0.5, 'HandleVisibility', 'off', 'DisplayName', string(dispname));
pair_one = {'Run ID', dataTable.run_id(loopFiltSingle, :)};
pair_two = {'Rate', dataTable.bitrate(loopFiltSingle, :) * 1e-9};
@@ -161,12 +233,14 @@ xlabel(x_var);
ylabel(y_var);
title([x_var, ' vs. ', y_var]);
if y_var == 'BER'
if string(y_var) == "BER"
yline(4e-4, 'LineWidth', 1, 'LineStyle', '--', 'HandleVisibility', 'off');
yline(3.8e-3, 'LineWidth', 1, 'LineStyle', '--', 'HandleVisibility', 'off');
yline(2e-2, 'LineWidth', 1, 'LineStyle', '--', 'HandleVisibility', 'off');
ylim([1e-5, 0.1]);
end
xlim([15,50]);
xlim([13,35]);
% Enable grid and beautify
grid on;
@@ -243,7 +317,6 @@ resultTable.nRows = groupCount;
end
function addDatatips(sc, varargin)
% addDatatips Adds custom data tip rows to a scatter plot.
%
@@ -283,7 +356,6 @@ end
end
function cleanedTable = cleanUpTable(inputTable)
% cleanUpTable Cleans a MATLAB table where numbers and NaNs are stored as strings or structs.
%
@@ -335,7 +407,7 @@ for i = 1:numel(varNames)
else
% Try convert to datetime
try
cleanedTable.(varNames{i}) = datetime(col, 'InputFormat', 'yyyy-MM-dd HH:mm:ss.SSSSSS');
cleanedTable.(varNames{i}) = datetime(col, 'InputFormat', 'yyyy-MM-dd HH:mm:ss');
catch
% Leave as string
end
@@ -391,8 +463,9 @@ for groupIdx = 1:height(groupKeys)
continue;
end
% Detect outliers
outlierMask = isoutlier(y_values, 'quartiles');
% Detect outliers in log space
y_log = log10(y_values);
outlierMask = isoutlier(y_log, 'quartiles'); % or 'median', 'grubbs', etc.
% If any outliers found, collect their data
if any(outlierMask)

View File

@@ -12,6 +12,7 @@ arguments
savePath
options.parallel (1,1) logical = true
options.max_occurences = 1;
options.paramstruct = struct();
end
if options.parallel
@@ -29,7 +30,8 @@ if options.parallel
"database_name", database_name, ...
'storage_path', savePath, ...
'append_to_db', 1, ...
'max_occurences', options.max_occurences ...
'max_occurences', options.max_occurences, ...
'parameters', options.paramstruct ...
);
output = [];
@@ -46,7 +48,8 @@ else
"database_name", database_name, ...
'storage_path', savePath, ...
'append_to_db', 1, ...
'max_occurences', options.max_occurences ...
'max_occurences', options.max_occurences,...
'parameters', options.paramstruct ...
);
future = []; % No future since it's synchronous

View File

@@ -2,17 +2,18 @@
% 1) Find RUN ID's
basePath = 'C:\Users\Silas\Documents\MATLAB\Datensätze\sioe_labor\';
database = DBHandler("pathToDB",[basePath,'silas_labor.db']);
% database = DBHandler("pathToDB",[basePath,'silas_labor.db']);
database = DBHandler("type",'mysql');
filterParams = database.tables;
filterParams.Configurations = struct( ...
'bitrate', [], ... %[224,336,360,390,420,448]
'bitrate', 112e9, ... %[224,336,360,390,420,448]
'db_mode', [], ...
'fiber_length', [], ...
'interference_attenuation',[], ...
'is_mpi', 0, ...
'pam_level', [], ...
'rop_attenuation', 0 ...
'interference_path_length',300, ...
'is_mpi', 1, ...
'pam_level', 4 ...
);
selectedFields = {'Runs.run_id',...

View File

@@ -124,7 +124,7 @@ for occ = 1:proc_occ
% %%%%% VNLE + DFE %%%%
if 0
eq_vnle_dfe = EQ("Ne",vnle_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);
eq_vnle_dfe = EQ("Ne",vnle_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.001,"FFEmu",0,"plotfinal",0,"ideal_dfe",0);
eq_post = FFE("epochs_tr",5,"epochs_dd",5,"len_tr",4096*2,"mu_dd",1e-4,"mu_tr",0,"order",2001,"sps",1,"decide",0);
[result] = vnle(eq_vnle_dfe,M,Scpe_sig,Symbols,Tx_bits,"precode_mode",duob_mode,"showAnalysis",1,"postFFE",[]);