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