ML Equalizer works now.
Not yet perfectly integrated into all the routines
This commit is contained in:
@@ -13,14 +13,13 @@ arguments
|
||||
end
|
||||
|
||||
try
|
||||
|
||||
|
||||
% Initialize output structures
|
||||
output.ffe_package = {};
|
||||
output.mlse_package = {};
|
||||
output.vnle_package = {};
|
||||
output.dbtgt_package = {};
|
||||
output.dbenc_package = {};
|
||||
output.mlmlse_package = {};
|
||||
|
||||
if options.mode == "load_run_id" || options.append_to_db
|
||||
% Initialize database connection
|
||||
@@ -98,9 +97,10 @@ try
|
||||
|
||||
use_ffe = 0;
|
||||
use_dfe = 0;
|
||||
use_vnle_mlse = 1;
|
||||
use_vnle_mlse = 0;
|
||||
use_dbtgt = 0;
|
||||
use_dbenc = 0;
|
||||
use_ml_mlse = 1;
|
||||
|
||||
addProcessingResultToDatabase = 0;
|
||||
|
||||
@@ -130,7 +130,7 @@ try
|
||||
mlse_ = MLSE("duobinary_output",0,'M',M,'trellis_states',PAMmapper(M,0).levels);
|
||||
|
||||
eq_post = FFE("epochs_tr",5,"epochs_dd",5,"len_tr",4096*2,"mu_dd",1e-4,"mu_tr",0,"order",2001,"sps",1,"decide",0,"adaption_technique","lms");
|
||||
eq_post =FFE("epochs_tr",5,"epochs_dd",2,"len_tr",2^13,"mu_dd",mu_dd,"mu_tr",mu_tr,"order",25,"sps",2,"decide",0, "adaption",adaption_method(adaption),"dd_mode",use_dd_mode);
|
||||
eq_post = FFE("epochs_tr",5,"epochs_dd",2,"len_tr",2^13,"mu_dd",mu_dd,"mu_tr",mu_tr,"order",25,"sps",2,"decide",0, "adaption",adaption_method(adaption),"dd_mode",use_dd_mode);
|
||||
% Duobinary signaling (db encoded)
|
||||
mlse_db_enc = MLSE("DIR", [1,1], "duobinary_output", 0, "M", M, "trellis_states", PAMmapper(M,0).levels);
|
||||
eq_db_enc = EQ("Ne", ffe_order, "Nb", dfe_order, "training_length", len_tr, ...
|
||||
@@ -233,30 +233,25 @@ try
|
||||
database.addProcessingResult(run_id, ffe_results.metrics, ffe_results.config);
|
||||
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', 0, ...
|
||||
% "postFFE", [],...
|
||||
% "eth_style_symbol_mapping", 0);
|
||||
%
|
||||
% ffe_results.metrics.print;
|
||||
% mlse_results.metrics.print;
|
||||
%
|
||||
% output.mlse_package{r} = mlse_results;
|
||||
% output.vnle_package{r} = ffe_results;
|
||||
%
|
||||
% if options.append_to_db
|
||||
% database.addProcessingResult(run_id, mlse_results.metrics, mlse_results.config);
|
||||
% database.addProcessingResult(run_id, ffe_results.metrics, ffe_results.config);
|
||||
% end
|
||||
end
|
||||
|
||||
if use_ml_mlse
|
||||
|
||||
%ML-based MLSE (L=2)
|
||||
mu_ml = 0.01; training_epochs = 250;
|
||||
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",2,"delta",4,"adaptive_mu",0);
|
||||
|
||||
[ml_mlse_results] = ml_mlse(ml_mlse_equalizer, M, Scpe_sig, Symbols, Tx_bits,"precode_mode",duob_mode);
|
||||
output.mlmlse_package{r} = ml_mlse_results;
|
||||
|
||||
if options.append_to_db
|
||||
database.addProcessingResult(run_id, ml_mlse_results.metrics, ml_mlse_results.config);
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
if use_dbtgt
|
||||
|
||||
@@ -292,6 +287,7 @@ try
|
||||
|
||||
if duob_mode == db_mode.db_encoded
|
||||
|
||||
mlse_db_enc = MLSE_viterbi("duobinary_output",0,'M',M,'trellis_states',PAMmapper(M,0).levels);
|
||||
db_results = duobinary_signaling(eq_db_enc, mlse_db_enc, M, Scpe_sig, Symbols, Tx_bits, "precode_mode",duob_mode, "showAnalysis",0,"postFFE",[]);
|
||||
output.dbenc_package{r} = db_results;
|
||||
if options.append_to_db
|
||||
|
||||
@@ -36,8 +36,9 @@ if ~isempty(options.postFFE)
|
||||
end
|
||||
|
||||
% Process through MLSE
|
||||
% [mlse_signal] = mlse_.process(eq_signal);
|
||||
[mlse_signal,~,GMI_MLSE] = mlse_.process(eq_signal,tx_symbols);
|
||||
[mlse_signal] = mlse_.process(eq_signal);
|
||||
% tx_symbols_ = Duobinary().decode(tx_symbols);
|
||||
% [mlse_signal,~,GMI_MLSE] = mlse_.process(eq_signal,tx_symbols);
|
||||
|
||||
% Apply duobinary encoding and decoding
|
||||
mlse_signal = Duobinary().encode(mlse_signal);
|
||||
|
||||
113
Functions/EQ_structures/ml_mlse.m
Normal file
113
Functions/EQ_structures/ml_mlse.m
Normal file
@@ -0,0 +1,113 @@
|
||||
function [ml_mlse_results] = ml_mlse(eq_, M, rx_signal, tx_symbols, tx_bits, options)
|
||||
%
|
||||
%
|
||||
% Inputs:
|
||||
% eq_ - Equalizer object
|
||||
% M - Modulation order
|
||||
% rx_signal - Received signal
|
||||
% tx_symbols - Transmitted symbols
|
||||
% tx_bits - Transmitted bits
|
||||
% options - Optional parameters
|
||||
%
|
||||
% Outputs:
|
||||
% ffe_results - Results from FFE processing
|
||||
|
||||
arguments
|
||||
eq_
|
||||
M
|
||||
rx_signal
|
||||
tx_symbols
|
||||
tx_bits
|
||||
options.precode_mode db_mode
|
||||
options.eth_style_symbol_mapping = 0;
|
||||
options.postFFE = [];
|
||||
|
||||
end
|
||||
|
||||
%% Process signals through equalizer
|
||||
|
||||
[eq_signal_hd,y_ref] = eq_.process(rx_signal,tx_symbols);
|
||||
|
||||
%% Calculate BER based on precoding mode
|
||||
[bits, errors, ber, error_pos, errors_precoded, ber_precoded] = calculateBER(eq_signal_hd, tx_symbols, tx_bits, options.precode_mode, M, options.eth_style_symbol_mapping);
|
||||
|
||||
|
||||
% Create FFE results structure
|
||||
ml_mlse_results = struct();
|
||||
try
|
||||
eq_.e = [];
|
||||
eq_.e2 = [];
|
||||
eq_.e3 = [];
|
||||
eq_.b = [];
|
||||
eq_.b2 = [];
|
||||
eq_.b3 = [];
|
||||
end
|
||||
|
||||
ml_mlse_results.config = Equalizerstruct();
|
||||
ml_mlse_results.config.eq = jsonencode(eq_);
|
||||
ml_mlse_results.config.equalizer_structure = int32(equalizer_structure.ml_mlse);
|
||||
ml_mlse_results.config.comment = 'function: ML-based MLSE';
|
||||
|
||||
ml_mlse_results.metrics = Metricstruct;
|
||||
ml_mlse_results.metrics.result_id = NaN;
|
||||
ml_mlse_results.metrics.run_id = NaN;
|
||||
ml_mlse_results.metrics.eqParam_id = NaN;
|
||||
ml_mlse_results.metrics.date_of_processing = datetime('now');
|
||||
ml_mlse_results.metrics.BER = ber;
|
||||
ml_mlse_results.metrics.numBits = bits;
|
||||
ml_mlse_results.metrics.numBitErr = errors;
|
||||
ml_mlse_results.metrics.BER_precoded = ber_precoded;
|
||||
ml_mlse_results.metrics.numBitErr_precoded = errors_precoded;
|
||||
ml_mlse_results.metrics.SNR = NaN;
|
||||
ml_mlse_results.metrics.SNR_level = NaN;
|
||||
ml_mlse_results.metrics.STD = NaN;
|
||||
ml_mlse_results.metrics.STD_level = NaN;
|
||||
ml_mlse_results.metrics.STDrx = NaN;
|
||||
ml_mlse_results.metrics.STDrx_level = NaN;
|
||||
ml_mlse_results.metrics.GMI = NaN;
|
||||
ml_mlse_results.metrics.AIR = NaN;
|
||||
ml_mlse_results.metrics.EVM = NaN;
|
||||
ml_mlse_results.metrics.EVM_level = NaN;
|
||||
ml_mlse_results.metrics.Alpha = NaN;
|
||||
|
||||
|
||||
end
|
||||
|
||||
%% Helper Functions
|
||||
function [bits, errors, ber, error_pos, errors_precoded, ber_precoded] = calculateBER(eq_signal_hd, tx_symbols, tx_bits, precode_mode, M, eth_style)
|
||||
% Calculate BER based on precoding mode
|
||||
mapper = PAMmapper(M, 0, "eth_style", eth_style);
|
||||
|
||||
switch precode_mode
|
||||
case db_mode.no_db
|
||||
% TX Data is not precoded
|
||||
% A) Emulate diff precoding
|
||||
eq_signal_hd_precoded = Duobinary().encode(eq_signal_hd, "M", M);
|
||||
eq_signal_hd_precoded = Duobinary().decode(eq_signal_hd_precoded, "M", M);
|
||||
|
||||
tx_symbols_precoded = Duobinary().encode(tx_symbols);
|
||||
tx_symbols_precoded = Duobinary().decode(tx_symbols_precoded);
|
||||
|
||||
tx_bits_precoded = mapper.demap(tx_symbols_precoded);
|
||||
|
||||
rx_bits = mapper.demap(eq_signal_hd_precoded);
|
||||
[~, errors_precoded, ber_precoded, ~] = calc_ber(rx_bits.signal, tx_bits_precoded.signal, "skip_front", 30000, "skip_end", 150, "returnErrorLocation", 1);
|
||||
|
||||
% B) Just determine BER
|
||||
rx_bits = mapper.demap(eq_signal_hd);
|
||||
[bits, errors, ber, error_pos] = calc_ber(rx_bits.signal, tx_bits.signal, "skip_front", 30000, "skip_end", 150, "returnErrorLocation", 1);
|
||||
|
||||
case db_mode.db_precoded
|
||||
% Data is precoded on TX side
|
||||
% A) Decode at Rx if no DB targeting was applied
|
||||
eq_signal_hd_decoded = Duobinary().encode(eq_signal_hd, "M", M);
|
||||
eq_signal_hd_decoded = Duobinary().decode(eq_signal_hd_decoded, "M", M);
|
||||
rx_bits_decoded = mapper.demap(eq_signal_hd_decoded);
|
||||
[~, errors_precoded, ber_precoded, ~] = calc_ber(rx_bits_decoded.signal, tx_bits.signal, "skip_front", 30000, "skip_end", 150, "returnErrorLocation", 1);
|
||||
|
||||
% B) Omit the Coding by comparing with demapped TX symbol sequence
|
||||
tx_bits_demapped = mapper.demap(tx_symbols);
|
||||
rx_bits = mapper.demap(eq_signal_hd);
|
||||
[bits, errors, ber, error_pos] = calc_ber(rx_bits.signal, tx_bits_demapped.signal, "skip_front", 30000, "skip_end", 150, "returnErrorLocation", 1);
|
||||
end
|
||||
end
|
||||
@@ -1,40 +0,0 @@
|
||||
function [eq_, pf_, mlse_, mlse_db_, eq_post] = configureEqualizers(M, len_tr, vnle_order, dfe_order, mu_dc, mu_ffe, mu_dfe, pf_ncoeffs)
|
||||
% CONFIGUREEQUALIZERS Creates and configures equalizer objects
|
||||
%
|
||||
% Inputs:
|
||||
% M - PAM level
|
||||
% len_tr - Training length
|
||||
% vnle_order - Array with orders for VNLE [order1, order2, order3]
|
||||
% dfe_order - Array with orders for DFE
|
||||
% mu_dc - DC adaptation rate
|
||||
% mu_ffe - Array with adaptation rates for FFE [mu1, mu2, mu3]
|
||||
% mu_dfe - Adaptation rate for DFE
|
||||
% pf_ncoeffs - Number of coefficients for postfilter
|
||||
%
|
||||
% Outputs:
|
||||
% eq_ - Configured EQ object
|
||||
% pf_ - Configured Postfilter object
|
||||
% mlse_ - Configured MLSE_viterbi object
|
||||
% mlse_db_ - Configured MLSE_viterbi object for duobinary
|
||||
% eq_post - Configured FFE object for post-processing
|
||||
|
||||
% Configure main equalizer
|
||||
eq_ = EQ("Ne", vnle_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);
|
||||
|
||||
% Configure postfilter
|
||||
pf_ = Postfilter("ncoeff", pf_ncoeffs, "useBurg", 1);
|
||||
|
||||
% Configure MLSE objects
|
||||
mlse_ = MLSE_viterbi("duobinary_output", 0, 'M', M, ...
|
||||
'trellis_states', PAMmapper(M,0).levels);
|
||||
mlse_db_ = MLSE_viterbi("DIR", [1,1], "duobinary_output", 0, ...
|
||||
"M", M, "trellis_states", PAMmapper(M,0).levels);
|
||||
|
||||
% Configure post-FFE
|
||||
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);
|
||||
end
|
||||
@@ -16,9 +16,9 @@ Scpe_sig = Scpe_sig.resample("fs_out", 2*fsym);
|
||||
[Scpe_sig, ~] = Scpe_sig.tsynch("reference", Symbols, "fs_ref", fsym, "debug_plots", 0);
|
||||
|
||||
% Apply Gaussian filter
|
||||
% Scpe_sig = Filter('filtdegree', 4, "f_cutoff", Symbols.fs.*0.6, ...
|
||||
% "fs", Scpe_sig.fs, "filterType", filtertypes.gaussian, ...
|
||||
% "active", true).process(Scpe_sig);
|
||||
Scpe_sig = Filter('filtdegree', 4, "f_cutoff", Symbols.fs.*0.6, ...
|
||||
"fs", Scpe_sig.fs, "filterType", filtertypes.gaussian, ...
|
||||
"active", true).process(Scpe_sig);
|
||||
|
||||
% Remove DC offset
|
||||
Scpe_sig = Scpe_sig - mean(Scpe_sig.signal);
|
||||
|
||||
@@ -209,6 +209,7 @@ wh = submit_options.wh;
|
||||
wh.addValueToStorageByLinIdx(val.vnle_package, 'vnle_package', jobIndex);
|
||||
wh.addValueToStorageByLinIdx(val.dbtgt_package,'dbtgt_package',jobIndex);
|
||||
wh.addValueToStorageByLinIdx(val.dbenc_package,'dbenc_package',jobIndex);
|
||||
wh.addValueToStorageByLinIdx(val.mlmlse_package,'mlmlse_package',jobIndex);
|
||||
end
|
||||
end
|
||||
function p = setupParallelPool(numWorkers, idleTimeout)
|
||||
|
||||
@@ -1,43 +1,97 @@
|
||||
function beautifyBERplot(options)
|
||||
% BEAUTIFYBERPLOT Enhances BER-style plots for publication-quality figures.
|
||||
% Supports automatic smoothing and trend-line overlay.
|
||||
%
|
||||
% Usage examples:
|
||||
% beautifyBERplot; % default
|
||||
% beautifyBERplot("polyfit",1); % add polynomial fit
|
||||
% beautifyBERplot("polyfit",1,"fitmethod","pchip") % piecewise cubic fit
|
||||
%
|
||||
% Supported fitmethod options: 'polyfit', 'smoothingspline', 'loess', 'pchip'
|
||||
|
||||
arguments
|
||||
options.logscale = 1
|
||||
options.logscale (1,1) logical = 1
|
||||
options.polyfit (1,1) logical = 0
|
||||
options.polyorder (1,1) double = 2
|
||||
options.fitmethod (1,1) string = "polyfit" % choose fit type
|
||||
end
|
||||
% BEAUTIFYBERPLOT Enhances a BER plot for publication-quality figures.
|
||||
|
||||
% Set line properties for all current plot lines
|
||||
lines = findall(gca, 'Type', 'Line');
|
||||
markers = {'o', 's', 'd', '^', 'v', '>', '<', 'p', 'h'}; % Define marker styles
|
||||
num_markers = length(markers);
|
||||
|
||||
% --- find all line objects in current axes
|
||||
lines = findall(gca, 'Type', 'Line');
|
||||
markers = {'o', 's', 'd', '^', 'v', '>', '<', 'p', 'h'};
|
||||
num_markers = length(markers);
|
||||
|
||||
% --- style all lines consistently
|
||||
for i = 1:length(lines)
|
||||
lines(i).LineWidth = 1.1;
|
||||
lines(i).LineStyle = '-';
|
||||
if string(lines(i).Marker) == "none"
|
||||
lines(i).Marker = markers{mod(i-1, num_markers) + 1};
|
||||
end
|
||||
lines(i).MarkerSize = 4;
|
||||
lines(i).MarkerFaceColor = lines(i).Color;
|
||||
end
|
||||
|
||||
% --- optional smoothing/fitting overlay
|
||||
if options.polyfit
|
||||
hold on
|
||||
for i = 1:length(lines)
|
||||
lines(i).LineWidth = 1.3; % Thicker line width
|
||||
lines(i).LineStyle = '-'; % Solid lines for simplicity
|
||||
if string(lines(i).Marker) == "none"
|
||||
lines(i).Marker = markers{mod(i-1, num_markers) + 1}; % Assign markers cyclically
|
||||
x = lines(i).XData;
|
||||
y = lines(i).YData;
|
||||
valid = isfinite(x) & isfinite(y);
|
||||
if sum(valid) < options.polyorder + 1
|
||||
continue;
|
||||
end
|
||||
lines(i).MarkerSize = 7; % Marker size
|
||||
lines(i).MarkerFaceColor = lines(i).Color; % Use line color for marker face
|
||||
lines(i).MarkerEdgeColor = 'white';
|
||||
|
||||
xf = linspace(min(x(valid)), max(x(valid)), 200);
|
||||
|
||||
% ----- choose fitting method -----
|
||||
switch lower(options.fitmethod)
|
||||
case "polyfit"
|
||||
p = polyfit(x(valid), y(valid), options.polyorder);
|
||||
yf = polyval(p, xf);
|
||||
|
||||
case "smoothingspline"
|
||||
try
|
||||
f = fit(x(valid)', y(valid)', 'smoothingspline');
|
||||
yf = feval(f, xf);
|
||||
catch
|
||||
yf = interp1(x(valid), y(valid), xf, 'pchip');
|
||||
end
|
||||
|
||||
case "loess"
|
||||
yf = smooth(x(valid), y(valid), 0.2, 'loess');
|
||||
yf = interp1(x(valid), yf, xf, 'linear', 'extrap');
|
||||
|
||||
case "pchip"
|
||||
yf = interp1(x(valid), y(valid), xf, 'pchip');
|
||||
|
||||
otherwise
|
||||
warning('Unknown fitmethod "%s". Using polyfit.', options.fitmethod);
|
||||
p = polyfit(x(valid), y(valid), options.polyorder);
|
||||
yf = polyval(p, xf);
|
||||
end
|
||||
|
||||
% --- lightened color for fit overlay
|
||||
lightcol = lines(i).Color + 0.4 * (1 - lines(i).Color);
|
||||
lightcol(lightcol > 1) = 1;
|
||||
|
||||
plot(xf, yf, '-', 'Color', lightcol, ...
|
||||
'LineWidth', 0.7, 'Marker', 'none', ...
|
||||
'HandleVisibility','off');
|
||||
end
|
||||
|
||||
% Change all text interpreters to LaTeX
|
||||
set(findall(gca, '-property', 'Interpreter'), 'Interpreter', 'latex');
|
||||
|
||||
% Set figure background to white
|
||||
set(gcf, 'Color', 'w');
|
||||
|
||||
|
||||
% Set logarithmic scale for y-axis, but only if it makes sense.
|
||||
% If this is not always desired, you could condition this on the presence of lines or data.
|
||||
if options.logscale
|
||||
set(gca, 'YScale', 'log');
|
||||
end
|
||||
|
||||
% Customize grid and box appearance
|
||||
set(gca, 'Box', 'on', 'LineWidth', 0.8); % Thicker border
|
||||
grid on;
|
||||
% grid minor;
|
||||
|
||||
% Adjust font size and style for better readability
|
||||
set(gca, 'FontSize', 10, 'FontName', 'Times New Roman');
|
||||
hold off
|
||||
end
|
||||
|
||||
% --- axis scaling and cosmetics
|
||||
if options.logscale
|
||||
set(gca, 'YScale', 'log');
|
||||
end
|
||||
|
||||
set(findall(gca, '-property', 'Interpreter'), 'Interpreter', 'latex');
|
||||
set(gcf, 'Color', 'w');
|
||||
set(gca, 'Box', 'on', 'LineWidth', 0.8);
|
||||
grid on;
|
||||
set(gca, 'FontSize', 10, 'FontName', 'Times New Roman');
|
||||
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user