193 lines
7.9 KiB
Matlab
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
|
|
|