Restore lost changes from pre-merge state

This commit is contained in:
magf
2026-02-02 13:38:56 +01:00
parent 005e821131
commit 7565ed0cf1
6 changed files with 7223 additions and 64 deletions

View File

@@ -10,6 +10,10 @@ classdef EQ < handle
training_length %Number of training symbols
training_loops %Number of loops through sequence for training mode
ideal_dfe %Error free DFE decisions
weighted_DFE %Weighted DFE on/off
weighted_DFE_mode %Weighted DFE mode
weighted_DFE_d_min %d_min threshold parameter for weighted DFE mode 1
weighted_DFE_I_mode %[a_s, b_s, I_max]-parameters for the weighted DFE
DB_aim %Aim at duobinary output sequence
@@ -68,6 +72,10 @@ classdef EQ < handle
options.training_length = 1024 %Number of training symbols
options.training_loops = 1 %Number of loops through sequence for training mode
options.ideal_dfe = 0 %Error free DFE decisions
options.weighted_DFE = 0;
options.weighted_DFE_mode = 'R1';
options.weighted_DFE_d_min = 0.5;
options.weighted_DFE_I_mode = [5,0.5,0.6];
options.DB_aim %Aim at duobinary output sequence
@@ -438,6 +446,43 @@ classdef EQ < handle
dd_out(k) = constellation_in_(dd_idx);
end
% Implementation of a weighted DFE in
% order to prevent error propagation.
% For further details, study [1], chapter 3.2.2 -
% Modifications of DFE
if obj.weighted_DFE
% define new constellations
const = unique(ref_in);
% determine reliability factor gamma_k
if output_vec(m) > min(const) && output_vec(m) < max(const)
gamma_k = 1 - abs(output_vec(m) - dd_out(k));
else
gamma_k = 1;
end
% select mode
if strcmp(obj.weighted_DFE_mode,'R1')
if gamma_k >= obj.weighted_DFE_d_min
f_gamma_k = 1;
else
f_gamma_k = 0;
end
elseif strcmp(obj.weighted_DFE_mode,'R2')
f_gamma_k = gamma_k;
elseif strcmp(obj.weighted_DFE_mode,'I1')
nom = 1-exp(-obj.weighted_DFE_I_mode(1)*((gamma_k/obj.weighted_DFE_I_mode(2))-1));
denom = 1+exp(-obj.weighted_DFE_I_mode(1)*((gamma_k/obj.weighted_DFE_I_mode(2))-1));
f_gamma_k = (1/2)*((nom/denom) - 1);
elseif strcmp(obj.weighted_DFE_mode,'I2')
nom = 1-exp(-obj.weighted_DFE_I_mode(1)*((gamma_k/obj.weighted_DFE_I_mode(2))-1));
denom = 1+exp(-obj.weighted_DFE_I_mode(1)*((gamma_k/obj.weighted_DFE_I_mode(2))-1));
f_gamma_k = (obj.weighted_DFE_I_mode(3)/2)*((nom/denom) - 1);
end
% calculate weighted output
output_vec(m) = f_gamma_k.*dd_out(k)+(1-f_gamma_k).*output_vec(m);
end
if obj.Nb(1) > 0
dd_DFE(2:end) = dd_DFE(1:end-1);
@@ -739,3 +784,6 @@ classdef EQ < handle
end
end
% References
% [1] T. J. Wettlin, Experimental Evaluation of Advanced Digital Signal Processing for Intra-Datacenter Systems using Direct-Detection, 2023. [Online]. Available: https://nbn-resolving.org/urn:nbn:de:gbv:8:3-2023-00703-8

View File

@@ -597,7 +597,7 @@ classdef ML_MLSE < handle
obj.S = obj.nSym;
obj.Nf = obj.order * obj.sps;
obj.nStates = obj.S^obj.L;
obj.nFeasible = obj.nStates * obj.S; %feasible state transitions
obj.nFeasible = obj.nStates * obj.S;
% --- Trellis mapping
obj.trellis_states = reshape(obj.constellation,1,[]);

View File

@@ -135,10 +135,10 @@ Time_Rec = 1;
if Time_Rec
% [Rx_Time_Rec, Timing_Error] = Timing_Recovery("modulation", 'PAM/PSK/QAM', "timing_error_detector",'Gardner (non-data-aided)','sps',Kov,'damping_factor',1,'normalized_loop_bandwidth',1e-4,'detector_gain',2.7).process(Rx_matched_1);
[Rx_Time_Rec, Timing_Error_MG] = Godard_Timing_Recovery('mode',3,'num_blocks',1,'fft_length',length(Rx_matched_1),'sps',Kov,'rolloff',0.6,'mu',-0.2,'Ki',1e-4).process(Rx_matched_1);
Rx_Time_Rec = Rx_Time_Rec.resample('fs_in',Kov*fsym,'fs_out',fsym);
% [Rx_Time_Rec, Timing_Error_MG] = Godard_Timing_Recovery('mode',3,'num_blocks',1,'fft_length',length(Rx_matched_1),'sps',Kov,'rolloff',0.6,'mu',-0.2,'Ki',1e-4).process(Rx_matched_1);
% Rx_Time_Rec = Rx_Time_Rec.resample('fs_in',Kov*fsym,'fs_out',fsym);
% Rx_Time_Rec = MaxVar_Timing_Recovery('mode',0,'fsym',fsym,'fadc',Kov*fsym,'num_tau',Kov*128,'sps',Kov,'comp_signal',Rx_tr_mf,'comp_mode',0).process(Rx_matched_1);
Rx_Time_Rec = MaxVar_Timing_Recovery('mode',0,'fsym',fsym,'fadc',Kov*fsym,'num_tau',Kov*128,'sps',Kov,'comp_signal',Rx_tr_mf,'comp_mode',0).process(Rx_matched_1);
sps = 1;
else
@@ -232,40 +232,40 @@ for our_signal = 1
% end
%% -------------------- VNLE + MLSE --------------------
pf_ncoeffs = 4;
eq_v = EQ("Ne",[300, 0, 0],"Nb",[0, 0, 0], ...
"training_length",len_tr,"training_loops",5,"dd_loops",5, ...
"K",sps,"DCmu",mu_dc,"DDmu",[mu_ffe mu_dfe],"DFEmu",0.005, ...
"FFEmu",0,"plotfinal",0,"ideal_dfe",1, ...
'weighted_DFE',0,'weighted_DFE_d_min',0.5,'weighted_DFE_mode','R2','weighted_DFE_I_mode',[5,0.5,0.6]);
% eq_v = FFE_DFE('ffe_order',300,'dfe_order',5,'len_tr',len_tr,'epochs_tr',5,'epochs_dd',5, ...
% 'ffe_mu_dd',mu_ffe,'ffe_mu_tr',0,'dfe_mu_dd',mu_dfe,'dfe_mu_tr',0.005,'sps',sps,'decide',0);
pf_ = Postfilter("ncoeff",pf_ncoeffs,"useBurg",1);
mlse_ = MLSE("duobinary_output",0,'M',M,'trellis_states',PAMmapper(M,0,"eth_style",mapping_style).levels);
[vnle_results, mlse_results] = vnle_postfilter_mlse(eq_v, pf_, mlse_, M, Rx_synced, Symbols, Bits, ...
"precode_mode", duob_mode, 'showAnalysis', 1, "postFFE", [], "eth_style_symbol_mapping", mapping_style);
mlse_results.metrics.print
if our_signal
fprintf('Our Signal: %.1e \n',mlse_results.metrics.BER);
fprintf('Paper: %.1e \n \n',ber_in_paper);
else
fprintf('Their Signal: %.1e \n',mlse_results.metrics.BER);
fprintf('Paper: %.1e \n \n',ber_in_paper);
end
%% -------------------- ML-based MLSE (L=2) --------------------
% ml_mlse_equalizer = ML_MLSE("epochs_tr",100,"epochs_dd",1, ...
% "len_tr",length(Rx_synced),"mu_dd",0.03,"mu_tr",0.03,"order",11,"sps",sps, ...
% "traceback_depth",256,"L",4,"delta",4,"adaptive_mu",0);
% pf_ncoeffs = 4;
% eq_v = EQ("Ne",[300, 0, 0],"Nb",[0, 0, 0], ...
% "training_length",len_tr,"training_loops",5,"dd_loops",5, ...
% "K",sps,"DCmu",mu_dc,"DDmu",[mu_ffe mu_dfe],"DFEmu",0.005, ...
% "FFEmu",0,"plotfinal",0,"ideal_dfe",1, ...
% 'weighted_DFE',0,'weighted_DFE_d_min',0.5,'weighted_DFE_mode','R2','weighted_DFE_I_mode',[5,0.5,0.6]);
% % eq_v = FFE_DFE('ffe_order',300,'dfe_order',5,'len_tr',len_tr,'epochs_tr',5,'epochs_dd',5, ...
% % 'ffe_mu_dd',mu_ffe,'ffe_mu_tr',0,'dfe_mu_dd',mu_dfe,'dfe_mu_tr',0.005,'sps',sps,'decide',0);
% pf_ = Postfilter("ncoeff",pf_ncoeffs,"useBurg",1);
% mlse_ = MLSE("duobinary_output",0,'M',M,'trellis_states',PAMmapper(M,0,"eth_style",mapping_style).levels);
%
% [ml_mlse_results] = ml_mlse(ml_mlse_equalizer, M, Rx_synced, Symbols, Bits,"precode_mode",duob_mode,"eth_style_symbol_mapping",mapping_style);
% [vnle_results, mlse_results] = vnle_postfilter_mlse(eq_v, pf_, mlse_, M, Rx_synced, Symbols, Bits, ...
% "precode_mode", duob_mode, 'showAnalysis', 1, "postFFE", [], "eth_style_symbol_mapping", mapping_style);
%
% mlse_results.metrics.print
% if our_signal
% fprintf('Our Signal: %.1e \n',ml_mlse_results.metrics.BER);
% fprintf('Our Signal: %.1e \n',mlse_results.metrics.BER);
% fprintf('Paper: %.1e \n \n',ber_in_paper);
% else
% fprintf('Their EQ: %.1e \n',ml_mlse_results.metrics.BER);
% fprintf('Their Signal: %.1e \n',mlse_results.metrics.BER);
% fprintf('Paper: %.1e \n \n',ber_in_paper);
% end
%% -------------------- ML-based MLSE (L=2) --------------------
ml_mlse_equalizer = ML_MLSE("epochs_tr",100,"epochs_dd",1, ...
"len_tr",length(Rx_synced),"mu_dd",0.03,"mu_tr",0.03,"order",11,"sps",sps, ...
"traceback_depth",256,"L",1,"delta",4,"adaptive_mu",0);
[ml_mlse_results] = ml_mlse(ml_mlse_equalizer, M, Rx_synced, Symbols, Bits,"precode_mode",duob_mode,"eth_style_symbol_mapping",mapping_style);
if our_signal
fprintf('Our Signal: %.1e \n',ml_mlse_results.metrics.BER);
fprintf('Paper: %.1e \n \n',ber_in_paper);
else
fprintf('Their EQ: %.1e \n',ml_mlse_results.metrics.BER);
fprintf('Paper: %.1e \n \n',ber_in_paper);
end
end

View File

@@ -212,40 +212,40 @@ for our_signal = 1
% end
%% -------------------- VNLE + MLSE --------------------
pf_ncoeffs = 4;
eq_v = EQ("Ne",[300, 0, 0],"Nb",[0, 0, 0], ...
"training_length",len_tr,"training_loops",5,"dd_loops",5, ...
"K",sps,"DCmu",mu_dc,"DDmu",[mu_ffe mu_dfe],"DFEmu",0.005, ...
"FFEmu",0,"plotfinal",0,"ideal_dfe",1, ...
'weighted_DFE',0,'weighted_DFE_d_min',0.5,'weighted_DFE_mode','R2','weighted_DFE_I_mode',[5,0.5,0.6]);
% eq_v = FFE_DFE('ffe_order',300,'dfe_order',5,'len_tr',len_tr,'epochs_tr',5,'epochs_dd',5, ...
% 'ffe_mu_dd',mu_ffe,'ffe_mu_tr',0,'dfe_mu_dd',mu_dfe,'dfe_mu_tr',0.005,'sps',sps,'decide',0);
pf_ = Postfilter("ncoeff",pf_ncoeffs,"useBurg",1);
mlse_ = MLSE("duobinary_output",0,'M',M,'trellis_states',PAMmapper(M,0,"eth_style",mapping_style).levels);
[vnle_results, mlse_results] = vnle_postfilter_mlse(eq_v, pf_, mlse_, M, Rx_synced, Symbols, Bits, ...
"precode_mode", duob_mode, 'showAnalysis', 1, "postFFE", [], "eth_style_symbol_mapping", mapping_style);
mlse_results.metrics.print
if our_signal
fprintf('Our Signal: %.1e \n',mlse_results.metrics.BER);
fprintf('Paper: %.1e \n \n',ber_in_paper);
else
fprintf('Their Signal: %.1e \n',mlse_results.metrics.BER);
fprintf('Paper: %.1e \n \n',ber_in_paper);
end
%% -------------------- ML-based MLSE (L=2) --------------------
% ml_mlse_equalizer = ML_MLSE("epochs_tr",100,"epochs_dd",1, ...
% "len_tr",length(Rx_synced),"mu_dd",0.03,"mu_tr",0.03,"order",11,"sps",sps, ...
% "traceback_depth",256,"L",4,"delta",4,"adaptive_mu",0);
% pf_ncoeffs = 4;
% eq_v = EQ("Ne",[300, 0, 0],"Nb",[0, 0, 0], ...
% "training_length",len_tr,"training_loops",5,"dd_loops",5, ...
% "K",sps,"DCmu",mu_dc,"DDmu",[mu_ffe mu_dfe],"DFEmu",0.005, ...
% "FFEmu",0,"plotfinal",0,"ideal_dfe",1, ...
% 'weighted_DFE',0,'weighted_DFE_d_min',0.5,'weighted_DFE_mode','R2','weighted_DFE_I_mode',[5,0.5,0.6]);
% % eq_v = FFE_DFE('ffe_order',300,'dfe_order',5,'len_tr',len_tr,'epochs_tr',5,'epochs_dd',5, ...
% % 'ffe_mu_dd',mu_ffe,'ffe_mu_tr',0,'dfe_mu_dd',mu_dfe,'dfe_mu_tr',0.005,'sps',sps,'decide',0);
% pf_ = Postfilter("ncoeff",pf_ncoeffs,"useBurg",1);
% mlse_ = MLSE("duobinary_output",0,'M',M,'trellis_states',PAMmapper(M,0,"eth_style",mapping_style).levels);
%
% [ml_mlse_results] = ml_mlse(ml_mlse_equalizer, M, Rx_synced, Symbols, Bits,"precode_mode",duob_mode,"eth_style_symbol_mapping",mapping_style);
% [vnle_results, mlse_results] = vnle_postfilter_mlse(eq_v, pf_, mlse_, M, Rx_synced, Symbols, Bits, ...
% "precode_mode", duob_mode, 'showAnalysis', 1, "postFFE", [], "eth_style_symbol_mapping", mapping_style);
%
% mlse_results.metrics.print
% if our_signal
% fprintf('Our Signal: %.1e \n',ml_mlse_results.metrics.BER);
% fprintf('Our Signal: %.1e \n',mlse_results.metrics.BER);
% fprintf('Paper: %.1e \n \n',ber_in_paper);
% else
% fprintf('Their EQ: %.1e \n',ml_mlse_results.metrics.BER);
% fprintf('Their Signal: %.1e \n',mlse_results.metrics.BER);
% fprintf('Paper: %.1e \n \n',ber_in_paper);
% end
%% -------------------- ML-based MLSE (L=2) --------------------
ml_mlse_equalizer = ML_MLSE("epochs_tr",100,"epochs_dd",1, ...
"len_tr",length(Rx_synced),"mu_dd",0.03,"mu_tr",0.03,"order",80,"sps",sps, ...
"traceback_depth",256,"L",1,"delta",4,"adaptive_mu",0);
[ml_mlse_results] = ml_mlse(ml_mlse_equalizer, M, Rx_synced, Symbols, Bits,"precode_mode",duob_mode,"eth_style_symbol_mapping",mapping_style);
if our_signal
fprintf('Our Signal: %.1e \n',ml_mlse_results.metrics.BER);
fprintf('Paper: %.1e \n \n',ber_in_paper);
else
fprintf('Their EQ: %.1e \n',ml_mlse_results.metrics.BER);
fprintf('Paper: %.1e \n \n',ber_in_paper);
end
end

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,150 @@
diff --git a/Classes/00_signals/Signal.m b/Classes/00_signals/Signal.m
index e06c41f..f09a03e 100644
--- a/Classes/00_signals/Signal.m
+++ b/Classes/00_signals/Signal.m
@@ -172,11 +172,9 @@ classdef Signal

hold on;
if isempty(options.color)
- % plot(t* 1e6, sig(1:length(t)), 'DisplayName', dn, 'LineWidth', 0.1, 'Marker', '.', 'LineStyle','none', 'MarkerSize', 0.1);
- plot(t* 1e6, sig(1:length(t)), 'DisplayName', dn, 'LineWidth', 0.1);
+ plot(t* 1e6, sig(1:length(t)), 'DisplayName', dn, 'LineWidth', 0.1, 'Marker', '.', 'LineStyle','none', 'MarkerSize', 0.1);

else
- % plot(t* 1e6, sig(1:length(t)), 'DisplayName', dn, 'LineWidth', 0.1, 'Marker', '.', 'LineStyle','none', 'MarkerSize', 0.1,'Color',options.color);
- plot(t* 1e6, sig(1:length(t)), 'DisplayName', dn, 'LineWidth', 0.1, 'Color',options.color);
+ plot(t* 1e6, sig(1:length(t)), 'DisplayName', dn, 'LineWidth', 0.1, 'Marker', '.', 'LineStyle','none', 'MarkerSize', 0.1,'Color',options.color);

end
% 2 c)
% - xlabel if not already here: time in readable format (1 ms and not 1e-3 s)
diff --git a/Classes/02_optical/DP_Fiber.m b/Classes/02_optical/DP_Fiber.m
index a5f3dce..c1f08ea 100644
--- a/Classes/02_optical/DP_Fiber.m
+++ b/Classes/02_optical/DP_Fiber.m
@@ -24,6 +24,8 @@ classdef DP_Fiber
SS_dzmax % [m] max dz (adaptive SSFM)
SS_dzmin % [m] min dz (adaptive SSFM)
n_waveplates % number of PMD waveplates
+ useGPU % GPU acceleration: true, false, or 'auto' (default)
+ useSingle % Use single precision on GPU (default: false)

% ---- Internal state (persistent between calls) ----
state % struct mirroring legacy 'state'
@@ -56,6 +58,8 @@ classdef DP_Fiber
options.SS_dzmax = 2e4 % m
options.SS_dzmin = 100 % m
options.n_waveplates = 100
+ options.useGPU = 'auto' % 'auto', true, or false
+ options.useSingle = false % single precision GPU
end

% Copy provided options into properties
@@ -208,7 +212,7 @@ classdef DP_Fiber
% Frequency-dependent PMD phase term (legacy form)
st.brf.db0 = (R.rand(st.wave_plates,1)*2*pi - pi) * brf_multiplier;
st.brf.db1 = sqrt(3*pi/8)*(st.dgd/obj.fa)/st.wave_plates .* st.omega;
- st.brf.simdgd = 0; 
+ st.brf.simdgd = 0;
% cumsum used in legacy only for debug; keep compatibility variable:
~cumsum(st.brf.db0); % no-op to mirror legacy path

@@ -228,7 +232,18 @@ classdef DP_Fiber
x_in = signal_in(:,1).';
y_in = signal_in(:,2).';

- [x_out, y_out, obj.state] = CNLSE_plain(x_in, y_in, obj.state);
+ % Determine GPU usage
+ if ischar(obj.useGPU) || isstring(obj.useGPU)
+ if strcmpi(obj.useGPU, 'auto')
+ gpuFlag = []; % Let CNLSE_plain auto-detect
+ else
+ error('DP_Fiber:InvalidGPU', 'useGPU must be true, false, or ''auto''');
+ end
+ else
+ gpuFlag = logical(obj.useGPU);
+ end
+
+ [x_out, y_out, obj.state] = CNLSE_plain(x_in, y_in, obj.state, gpuFlag, obj.useSingle);

obj.state.propagated_length = obj.state.propagated_length + obj.state.L;

diff --git a/Classes/02_optical/Optical_Demultiplex.m b/Classes/02_optical/Optical_Demultiplex.m
index 7d7c39e..8e272d2 100644
--- a/Classes/02_optical/Optical_Demultiplex.m
+++ b/Classes/02_optical/Optical_Demultiplex.m
@@ -42,7 +42,7 @@ classdef Optical_Demultiplex < handle

function signalclasses_out = process(obj, signalclass_in)

- % ---- Infer wavelength: either given or from input total signal 
+ % ---- Infer wavelength: either given or from input total signal
if isempty(obj.wavelengthplan)
obj.wavelengthplan = signalclass_in.lambda; %meter
else
@@ -81,7 +81,7 @@ classdef Optical_Demultiplex < handle
obj
signal_in
end
- 
+
w = obj.fs_out ./ obj.fs_in ;
blocklen_in = length(signal_in);
blocklen_out = w*blocklen_in;
@@ -119,30 +119,31 @@ classdef Optical_Demultiplex < handle
N = size(lo,1);
C = size(lo,2);

- x_envelopes = zeros(N, C, 'like', signal_in);
- y_envelopes = zeros(N, C, 'like', signal_in);
+ % ---- VECTORIZED: Process all channels in parallel ----
+ % Batched FFT operates on each column simultaneously on GPU

- s1 = signal_in(:,1);
- s2 = signal_in(:,2);
+ % Extract polarization signals
+ s1 = signal_in(:,1); % X polarization [N×1]
+ s2 = signal_in(:,2); % Y polarization [N×1]

- % Reusable work buffers (avoid reallocations)
- wrk_time = zeros(N,1, 'like', signal_in);
- wrk_freq = zeros(N,1, 'like', signal_in);
+ % Broadcast signal to all channels and multiply with LO
+ % s1, s2 are [N×1], lo is [N×C] → result is [N×C]
+ x_mixed = att .* s1 .* lo; % [N×C]
+ y_mixed = att .* s2 .* lo; % [N×C]
+
+ % Batched FFT: each column computed in parallel
+ x_freq = fft(x_mixed); % [N×C]
+ y_freq = fft(y_mixed); % [N×C]
+
+ % Apply filter (H is [N×1], broadcasts across columns)
+ x_filtered = x_freq .* H; % [N×C]
+ y_filtered = y_freq .* H; % [N×C]
+
+ % Batched IFFT
+ x_envelopes = ifft(x_filtered); % [N×C]
+ y_envelopes = ifft(y_filtered); % [N×C]

- for c = 1:C
- % ---- X branch ----
- wrk_time(:) = att .* s1 .* lo(:,c); % N×1
- wrk_freq(:) = fft(wrk_time); % N×1
- wrk_freq(:) = wrk_freq .* H; % N×1
- x_envelopes(:,c) = ifft(wrk_freq); % N×1

- % ---- Y branch ----
- wrk_time(:) = att .* s2 .* lo(:,c);
- wrk_freq(:) = fft(wrk_time);
- wrk_freq(:) = wrk_freq .* H;
- y_envelopes(:,c) = ifft(wrk_freq);
- end
- 
end
end
end
diff --git a/Classes/02_optical/Optical_Multiplex.m b/Classes/02_optical/Optical_Multiplex.m
index 1d722b0..7fc8a33 100644
--- a/Classes/02_optical/Optical_Multiplex.m
+++ b/Classes/02_optical/Optical_Multiplex.m
@@ -1,10 +1,10 @@