Many changes

This commit is contained in:
Silas Oettinghaus
2025-02-14 14:54:03 +01:00
parent 2be1254611
commit becaf3f6c9
26 changed files with 1507 additions and 1052 deletions

View File

@@ -1,10 +1,11 @@
function [eq_signal,eq_noise,ber,numErrors] = duobinary_signaling(EQ, MLSE,M ,rx_signal, tx_symbols, tx_bits)
function [eq_package] = duobinary_signaling(eq_, mlse_,M ,rx_signal, tx_symbols, tx_bits)
%Duobinary Signaling
[eq_signal, eq_noise] = EQ.process(rx_signal,tx_symbols);
[eq_signal, eq_noise] = eq_.process(rx_signal,tx_symbols);
eq_signal = MLSE.process(eq_signal);
eq_signal = mlse_.process(eq_signal);
eq_signal = Duobinary().encode(eq_signal);
eq_signal = Duobinary().decode(eq_signal);
% M = numel(unique(eq_signal.signal));
@@ -12,4 +13,6 @@ function [eq_signal,eq_noise,ber,numErrors] = duobinary_signaling(EQ, MLSE,M ,rx
[~,numErrors,ber,~] = calc_ber(rx_bits.signal,tx_bits.signal,"skip_front",100,"skip_end",150,"returnErrorLocation",1);
eq_package.ber = ber;
end

View File

@@ -1,17 +1,77 @@
function [eq_signal,eq_noise,ber,numErrors] = duobinary_target(EQ, MLSE,M, rx_signal, tx_symbols, tx_bits)
function [eq_package] = duobinary_target(eq_, mlse_,M, rx_signal, tx_symbols, tx_bits, options)
arguments
eq_
mlse_
M
rx_signal
tx_symbols
tx_bits
options.precode_mode db_mode
options.showAnalysis = 0;
end
%Duobinary Targeting
[eq_signal, eq_noise] = EQ.process(rx_signal,Duobinary().encode(tx_symbols));
[eq_signal, eq_noise] = eq_.process(rx_signal,Duobinary().encode(tx_symbols));
% dir = [1,1];
eq_signal = MLSE.process(eq_signal);
mlse_sig_sd = mlse_.process(eq_signal);
eq_signal = Duobinary().decode(eq_signal);
mlse_sig_hd = PAMmapper(M,0).quantize(mlse_sig_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)
% takes:
% -> eq_signal_hd: hard decision signal after eq
% -> tx_symbols: that where used as reference for eq
switch options.precode_mode
case db_mode.db_emulate
mlse_sig_hd = Duobinary().encode(mlse_sig_hd,"M",M);
mlse_sig_hd = Duobinary().decode(mlse_sig_hd,"M",M);
tx_symbols_precoded = Duobinary().encode(tx_symbols);
tx_symbols_precoded = Duobinary().decode(tx_symbols_precoded);
tx_bits = PAMmapper(M,0).demap(tx_symbols_precoded);
case db_mode.db_discard
% normal dsp for precoded sequence == discard/omit/ignore precode
tx_bits = PAMmapper(M,0).demap(tx_symbols);
case db_mode.db_encoded
% normal DB encoded data (only for 10KM)
case db_mode.db_precoded
mlse_sig_hd = Duobinary().encode(mlse_sig_hd,"M",M);
mlse_sig_hd = Duobinary().decode(mlse_sig_hd,"M",M);
end
% M = numel(unique(tx_symbols.signal));
rx_bits = PAMmapper(M,0).demap(eq_signal);
rx_bits = PAMmapper(M,0).demap(mlse_sig_hd);
[~,numErrors,ber,~] = calc_ber(rx_bits.signal,tx_bits.signal,"skip_front",100,"skip_end",150,"returnErrorLocation",1);
eq_package.ber = ber;
if options.showAnalysis
eq_noise = eq_noise - mean(eq_noise.signal);
rx_signal.spectrum("normalizeTo0dB",1,"fignum",250);
showEQNoisePSD(eq_noise,"fignum",250,"displayname",'Duobinary Target Noise');
Duobinary().encode(tx_symbols).spectrum("normalizeTo0dB",1,"fignum",250);
end
end

View File

@@ -1,4 +1,4 @@
function [eq_signal,eq_noise,ber,numErrors] = vnle(EQ,M,rx_signal,tx_symbols,tx_bits,emulate_precode)
function [eq_package] = vnle(eq_,M,rx_signal,tx_symbols,tx_bits,options)
%VNLE Apply an equalization algorithm to the received signal and calculate BER
% This function takes an equalizer object, a received signal, and the
% transmitted symbols to apply equalization, map the received signal back to bits,
@@ -14,23 +14,73 @@ function [eq_signal,eq_noise,ber,numErrors] = vnle(EQ,M,rx_signal,tx_symbols,tx_
% ber - Bit error rate after equalization
% numErrors - Number of bit errors detected
%FFE or VNLE
[eq_signal,eq_noise] = EQ.process(rx_signal,tx_symbols);
eq_signal = PAMmapper(M,0).quantize(eq_signal);
if emulate_precode
eq_signal = Duobinary().encode(eq_signal);
eq_signal = Duobinary().decode(eq_signal);
tx_symbols= Duobinary().encode(tx_symbols);
tx_symbols = Duobinary().decode(tx_symbols);
tx_bits = PAMmapper(M,0).demap(tx_symbols);
arguments
eq_
M
rx_signal
tx_symbols
tx_bits
options.precode_mode db_mode
options.showAnalysis = 0
end
% M = numel(unique(tx_symbols.signal));
rx_bits = PAMmapper(M,0).demap(eq_signal);
%FFE or VNLE
[eq_signal_sd,eq_noise] = eq_.process(rx_signal,tx_symbols);
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)
% takes:
% -> eq_signal_hd: hard decision signal after eq
% -> tx_symbols: that where used as reference for eq
switch options.precode_mode
case db_mode.db_emulate
% re
eq_signal_hd = Duobinary().encode(eq_signal_hd,"M",M);
eq_signal_hd = Duobinary().decode(eq_signal_hd,"M",M);
tx_symbols_precoded = Duobinary().encode(tx_symbols);
tx_symbols_precoded = Duobinary().decode(tx_symbols_precoded);
tx_bits = PAMmapper(M,0).demap(tx_symbols_precoded);
case db_mode.db_discard
% normal dsp for precoded sequence == discard/omit/ignore precode
tx_bits = PAMmapper(M,0).demap(tx_symbols);
case db_mode.db_encoded
% normal DB encoded data (only for 10KM)
case db_mode.db_precoded
eq_signal_hd = Duobinary().encode(eq_signal_hd,"M",M);
eq_signal_hd = Duobinary().decode(eq_signal_hd,"M",M);
end
rx_bits = PAMmapper(M,0).demap(eq_signal_hd);
[~,numErrors,ber,~] = calc_ber(rx_bits.signal,tx_bits.signal,"skip_front",100,"skip_end",150,"returnErrorLocation",1);
[evm_total,evm_lvl] = calc_evm(eq_signal_sd,tx_symbols);
[inf_rate] = calc_air(eq_signal_sd,tx_symbols,"skip_front",10000,"skip_end",10000);
eq_package.ber_vnle = ber;
eq_package.evm_total = evm_total;
eq_package.evm_lvl = evm_lvl;
eq_package.inf_rate_vnle = inf_rate;
if options.showAnalysis
fprintf(['VNLE EVM lvl: ',repmat('%.3f ',1,numel(evm_lvl)),' \n'],evm_lvl);
fprintf('VNLE BER: %.2e \n',ber);
end
end

View File

@@ -1,21 +1,125 @@
function [eq_signal,eq_noise,ber,numErrors] = vnle_postfilter_mlse(eq_,pf_,mlse_,M,rx_signal,tx_symbols,tx_bits)
function [eq_package] = vnle_postfilter_mlse(eq_,pf_,mlse_,M,rx_signal,tx_symbols,tx_bits,options)
arguments
eq_
pf_
mlse_
M
rx_signal
tx_symbols
tx_bits
options.precode_mode db_mode
options.showAnalysis = 0;
end
%FFE or VNLE
[eq_signal,eq_noise] = eq_.process(rx_signal,tx_symbols);
[eq_signal_sd,eq_noise] = eq_.process(rx_signal,tx_symbols);
% eq_noise.signal = eq_noise.signal - movmean(eq_noise.signal,[5000,0]);
eq_signal_hd = PAMmapper(M,0).quantize(eq_signal_sd);
eq_signal = pf_.process(eq_signal,eq_noise);
mlse_sig_sd = pf_.process(eq_signal_sd,eq_noise);
%M = numel(unique(tx_symbols.signal));
mlse_.DIR = pf_.burg_coeff;
mlse_.trellis_states = PAMmapper(M,0).levels;
mlse_.M = M;
mlse_.DIR = pf_.coefficients;
% [mlse_sig_hd,mlse_sig_sd] = mlse_.process(mlse_sig_sd,tx_symbols);
mlse_sig_sd = mlse_.process(mlse_sig_sd);
eq_signal = mlse_.process(eq_signal);
mlse_sig_hd = PAMmapper(M,0).quantize(mlse_sig_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)
% takes:
% -> M
% -> eq_signal_hd: hard decision signal after eq
% -> tx_symbols: that where used as reference for eq
switch options.precode_mode
case db_mode.db_emulate
% re
eq_signal_hd = Duobinary().encode(eq_signal_hd,"M",M);
eq_signal_hd = Duobinary().decode(eq_signal_hd,"M",M);
mlse_sig_hd = Duobinary().encode(mlse_sig_hd,"M",M);
mlse_sig_hd = Duobinary().decode(mlse_sig_hd,"M",M);
tx_symbols_precoded = Duobinary().encode(tx_symbols);
tx_symbols_precoded = Duobinary().decode(tx_symbols_precoded);
tx_bits = PAMmapper(M,0).demap(tx_symbols_precoded);
case db_mode.db_discard
% normal dsp for precoded sequence == discard/omit/ignore precode
tx_bits = PAMmapper(M,0).demap(tx_symbols);
case db_mode.db_encoded
% normal DB encoded data (only for 10KM)
case db_mode.db_precoded
eq_signal_hd = Duobinary().encode(eq_signal_hd,"M",M);
eq_signal_hd = Duobinary().decode(eq_signal_hd,"M",M);
mlse_sig_hd = Duobinary().encode(mlse_sig_hd,"M",M);
mlse_sig_hd = Duobinary().decode(mlse_sig_hd,"M",M);
end
% METRICS OF VNLE %
rx_bits_vnle = PAMmapper(M,0).demap(eq_signal_hd);
[~,~,ber_vnle,~] = calc_ber(rx_bits_vnle.signal,tx_bits.signal,"skip_front",100,"skip_end",150,"returnErrorLocation",1);
rx_bits = PAMmapper(M,0).demap(eq_signal);
% correct TUM implementation of AIR
[inf_rate_vnle] = calc_air(eq_signal_sd,tx_symbols,"skip_front",10000,"skip_end",10000);
[evm_vnle_total,evm_vnle_lvl] = calc_evm(eq_signal_sd,tx_symbols);
% METRICS OF MLSE (HD-VITERBI)
rx_bits_mlse = PAMmapper(M,0).demap(mlse_sig_hd);
[~,~,ber_mlse,~] = calc_ber(rx_bits_mlse.signal,tx_bits.signal,"skip_front",100,"skip_end",150,"returnErrorLocation",1);
eq_package.ber_mlse = ber_mlse;
eq_package.ber_vnle = ber_vnle;
eq_package.evm_vnle_total = evm_vnle_total;
eq_package.evm_vnle_lvl = evm_vnle_lvl;
eq_package.air = inf_rate_vnle;
eq_package.eq = eq_;
eq_package.pf = pf_;
eq_package.mlse = mlse_;
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);
showEQNoisePSD(eq_noise,"fignum",336,"displayname",'VNLE+DFE','postfilter_taps',pf_.coefficients);
rx_signal.spectrum("normalizeTo0dB",1,"fignum",337,"displayname",'Rx Signal');
tx_symbols.spectrum("normalizeTo0dB",1,"fignum",337,'displayname','Tx Signal');
showLevelHistogram(eq_signal_sd,tx_symbols)
% showLevelHistogram(mlse_sig_sd,tx_symbols)
showEQcoefficients(eq_.e,eq_.e2,eq_.e3,"displayname",'Coefficients');
showEQNoiseSNR(tx_symbols,eq_noise,"displayname",'vnle snr','fignum',101);
%%% EQ SNR Spectrum %230
%snr
snr_vnle = snr(tx_symbols.signal,eq_noise.signal);
% showErrorBurstCount(eq_signal_sd,tx_symbols)
end
[~,numErrors,ber,~] = calc_ber(rx_bits.signal,tx_bits.signal,"skip_front",100,"skip_end",150,"returnErrorLocation",1);
end

View File

@@ -1,9 +1,5 @@
function beautifyBERplot()
% BEAUTIFYBERPLOT Enhances a BER plot for publication-quality figures.
%
% This function automatically adjusts the aesthetics of an existing plot.
% It sets limits based on the data already plotted and modifies the
% appearance for publication-ready figures.
% Set line properties for all current plot lines
lines = findall(gca, 'Type', 'Line');
@@ -11,10 +7,10 @@ function beautifyBERplot()
num_markers = length(markers);
for i = 1:length(lines)
lines(i).LineWidth = 1.5; % Set a thicker line width
lines(i).LineStyle = '-'; % Solid lines for simplicity
lines(i).LineWidth = 1.3; % Thicker line width
%lines(i).LineStyle = '-'; % Solid lines for simplicity
lines(i).Marker = markers{mod(i-1, num_markers) + 1}; % Assign markers cyclically
lines(i).MarkerSize = 6; % Set marker size
lines(i).MarkerSize = 4; % Marker size
lines(i).MarkerFaceColor = 'auto'; % Use line color for marker face
end
@@ -24,34 +20,16 @@ function beautifyBERplot()
% Set figure background to white
set(gcf, 'Color', 'w');
% Set axis labels with LaTeX
xlabel('Bit Rate in Gbps', 'Interpreter', 'latex');
ylabel('Bit Error Rate', 'Interpreter', 'latex');
% Determine x and y limits from the data in the plot
x_data = [];
y_data = [];
for i = 1:length(lines)
x_data = [x_data; lines(i).XData(:)]; %#ok<AGROW> % Append x data
y_data = [y_data; lines(i).YData(:)]; %#ok<AGROW> % Append y data
end
x_min = min(x_data);
x_max = max(x_data);
y_min = 1e-4; % Ensure no negative or zero values for log scale
y_max = 0.5;
% Adjust axis ranges
xlim([x_min, x_max]);
ylim([y_min, y_max]);
% Set logarithmic scale for y-axis
set(gca, 'YScale', 'log');
% Set logarithmic scale for y-axis, but only if it makes sense.
% If this is not always desired, you could condition this on the presence of lines or data.
% set(gca, 'YScale', 'log');
% Customize grid and box appearance
set(gca, 'Box', 'on', 'LineWidth', 1.2); % Add a thicker border
set(gca, 'Box', 'on', 'LineWidth', 0.8); % Thicker border
grid on;
grid minor;
% grid minor;
% Adjust font size and style for better readability
set(gca, 'FontSize', 12, 'FontName', 'Times New Roman');
set(gca, 'FontSize', 10, 'FontName', 'Times New Roman');
end

View File

@@ -1,62 +0,0 @@
function [bits,errors,ber,errorIndice] = calc_ber(data_in,data_ref,options)
arguments(Input)
data_in;
data_ref;
options.skip_front = 0;
options.skip_end = 0;
options.returnErrorLocation = 0;
end
options.skip_end = abs(options.skip_end);
options.skip_front = abs(options.skip_front);
assert((options.skip_end+options.skip_front)<length(data_in),"You can not skip more bits than overall length of data! Set skip_front or skip_end to lower value or check data_in");
bits = 0;
errors= 0;
ber= 0;
errorIndice= [];
% trim sequence to given start; stop. trim reference if signal is shorter
[data_in,data_ref]=trimseq(data_in,data_ref,options.skip_front,options.skip_end);
if length(data_ref) == length(data_in)
bits = 0;
bits = bits+numel(data_in(:,options.skip_front+1:end));
try
if options.returnErrorLocation == 0
errors = sum( data_in ~= data_ref,"all" );
else
errorIndice = sum(data_in ~= data_ref,1);
errors = sum(errorIndice ,"all" );
[~,errorIndice] = find(errorIndice~=0);
end
catch
warning('BER calculation not optimal: Arrays have incompatible sizes for this operation.')
errors = NaN;
end
% Determine BER
ber = sum(errors)/sum(bits);
else
error('Sequence length does not match');
end
function [data_,reference_]=trimseq(data,reference,skipstart,skip_end)
data_ = logical(data(skipstart+1:end-skip_end,:))';
delta_bits = length(reference) - length(data);
% skip_end = max(skip_end,delta_bits);
skip_end = delta_bits + skip_end;
reference_ = logical(reference(skipstart+1:end-skip_end,:))';
end
end

View File

@@ -1,19 +0,0 @@
function [evm,stdev] = calc_evm(vector_received,vector_ideal)
error_vector = (vector_received-vector_ideal);
k = unique(vector_ideal);
error = repmat(zeros(size(vector_ideal)),1,length(k));
for lvl = 1:length(k)
error(vector_ideal==k(lvl),lvl) = error_vector(vector_ideal==k(lvl));
end
error(error==0) = NaN;
stdev = std(error,"omitnan");
error = sqrt(error.^2);
evm = sqrt( 1/length(error) .* sum(error.^2,1,'omitnan') ) ;
end