function [db_results] = duobinary_signaling(eq_, mlse_, M, rx_signal, tx_symbols, tx_bits, options) % DUOBINARY_SIGNALING Processes signals through duobinary signaling % % Inputs: % eq_ - Equalizer object % mlse_ - MLSE object % M - Modulation order % rx_signal - Received signal % tx_symbols - Transmitted symbols % tx_bits - Transmitted bits % options - Optional parameters % % Outputs: % db_results - Results from duobinary signaling processing arguments eq_ mlse_ 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 %% Process signals through equalizer [eq_signal, eq_noise] = eq_.process(rx_signal, tx_symbols); % Apply post-FFE if provided if ~isempty(options.postFFE) [eq_signal, eq_noise] = options.postFFE.process(eq_signal, tx_symbols); end if isa(mlse_,'MLSE_viterbi') [mlse_signal] = mlse_.process(eq_signal); else % Aufpassen mit welcher Sequenz man hier vergleicht für LLR stuff... % gespeichtere "Symbols" sind schon DB codiert, das wollen wir hier % nicht! Sondern die precoded aber nicht db-encoded müssen als ref in % die LLR berechnung gehen! ref_sym = PAMmapper(M,0).map(tx_bits); %ist klar ref_sym_dpc = Duobinary().precode(ref_sym); % precoded % ref_sym_dbenc = Duobinary().encode(ref_sym_dpc); %encoded - das wurde gesendet! % ref_sym_dec = Duobinary().decode(ref_sym_dbenc); %ref_sym wieder zurück! mlse_.trellis_states = PAMmapper(M,0).levels; mlse_.trellis_state_mode = 1; [mlse_signal,LLR,GMI_MLSE] = mlse_.process(eq_signal,ref_sym_dpc); end % 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); mlse_signal = Duobinary().decode(mlse_signal); % Demap symbols to bits rx_bits = PAMmapper(M, 0, "eth_style", options.eth_style_symbol_mapping).demap(mlse_signal); %% Calculate BER and metrics [bits_db, errors_db, ber_db, error_pos] = calc_ber(rx_bits.signal, tx_bits.signal, "skip_front", 100, "skip_end", 150, "returnErrorLocation", 1); % Calculate performance metrics after duobinary FFE! [snr, snr_lvl] = calc_snr(tx_symbols.signal, eq_noise.signal); %SNR of duobinary sequence - not directly comparable to [gmi] = calc_air(eq_signal, tx_symbols, "skip_front", 10000, "skip_end", 10000); air = tx_symbols.fs .* floor(log2(double(M))*10)/10 .* gmi ./ log2(double(M)); [evm_total, evm_lvl] = calc_evm(eq_signal, tx_symbols); [std_total, std_lvl] = calc_std(eq_signal, tx_symbols); [std_rxraw_total, std_rxraw_lvl] = calc_std(rx_signal.resample("fs_out", tx_symbols.fs), tx_symbols); %% Prepare output structure % Determine postFFE order if ~isempty(options.postFFE) npostFFE = options.postFFE.order; else npostFFE = 0; end % Create results structure db_results = struct(); db_results.metrics = Metricstruct; db_results.metrics.result_id = NaN; db_results.metrics.run_id = NaN; db_results.metrics.eqParam_id = NaN; db_results.metrics.date_of_processing = datetime('now'); db_results.metrics.BER = ber_db; db_results.metrics.numBits = bits_db; db_results.metrics.numBitErr = errors_db; db_results.metrics.SNR = snr; db_results.metrics.SNR_level = snr_lvl; db_results.metrics.STD = std_total; db_results.metrics.STD_level = std_lvl; db_results.metrics.STDrx = std_rxraw_total; db_results.metrics.STDrx_level = std_rxraw_lvl; db_results.metrics.GMI = gmi; db_results.metrics.AIR = air; db_results.metrics.EVM = evm_total; db_results.metrics.EVM_level = evm_lvl; db_results.metrics.MLSE_dir = mlse_.DIR; % Create configuration structure eq_.e = []; eq_.e2 = []; eq_.e3 = []; db_results.config = Equalizerstruct(); db_results.config.eq = jsonencode(eq_); mlse_.DIR = []; db_results.config.mlse = jsonencode(mlse_); db_results.config.equalizer_structure = int32(equalizer_structure.db_encoded); db_results.config.comment = 'function: duobinary_signaling'; %% Display analysis if requested if options.showAnalysis displayAnalysis(eq_noise, eq_signal, rx_signal, eq_, tx_symbols, M, options.postFFE); end end %% Helper Function function displayAnalysis(eq_noise, eq_signal, rx_signal, eq_, tx_symbols, M, postFFE) % Display analysis plots and metrics figure(336); showEQNoisePSD(eq_noise, "fignum", 336, "displayname", 'Residual Noise after Duobinary'); if ~isempty(postFFE) showEQcoefficients('n1', postFFE.e, "displayname", 'Coefficients', 'fignum', 338); end showEQfilter(eq_.e, eq_signal.fs.*2); figure(341); clf; showLevelHistogram(eq_signal, tx_symbols, "fignum", 341); warning off figure(400); clf; showLevelScatter(eq_signal, tx_symbols, "fignum", 400); figure(401); clf; showLevelScatter(rx_signal.resample("fs_out", tx_symbols.fs), tx_symbols, "fignum", 401); warning on end