149 lines
4.8 KiB
Matlab
149 lines
4.8 KiB
Matlab
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 |