Files
imdd_silas/Functions/EQ_structures/vnle.m
2025-04-25 10:31:43 +02:00

193 lines
7.9 KiB
Matlab

function [eq_package] = vnle(eq_,M,rx_signal,tx_symbols,tx_bits,options)
arguments
eq_
M
rx_signal
tx_symbols
tx_bits
options.precode_mode db_mode
options.showAnalysis = 0;
options.eth_style_symbol_mapping = 0;
options.postFFE = [];
options.database = [];
end
mudc_given = eq_.mu_dc;
%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);
toc
end
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)
switch options.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 = PAMmapper(M,0,"eth_style",options.eth_style_symbol_mapping).demap(tx_symbols_precoded);
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);
%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);
max_burst_length = 10;
burst_count = count_error_bursts(error_pos_vnle, max_burst_length);
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!
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);
% B) Omit the Coding by comparing with demapped TX symbol sequence
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);
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