Many changes here and there. I lost track... :-(

Current work is on MLSE and SD Decoding etc. MLSE is currently not 100% working, the scalings are maybe off?!
This commit is contained in:
Silas Oettinghaus
2025-08-11 07:42:04 +02:00
parent 09d9e5011c
commit 5dbc48abc0
37 changed files with 1506 additions and 570 deletions

View File

@@ -83,6 +83,14 @@ classdef MLSE < handle
% impulse respnse to remove from signal
obj.DIR = flip(obj.DIR); %i.e. -0.2676 -0.0478 1.0000
% % make the combined impulse-response have net gain = 1
% h = obj.DIR(:);
% h = h / sum(h);
% obj.DIR = h.';
% Normalize the Trellis states to =1 RMS
obj.trellis_states = obj.trellis_states ./ rms(obj.trellis_states);
% seems to be the only way to use combvec for a flexible amount
% of vectors. 'combs' contains all trellis states
pre_comb_mat = repmat(obj.trellis_states,length(obj.DIR)-1,1);
@@ -116,6 +124,7 @@ classdef MLSE < handle
% first: RMS normalization of input data (rms==1)
data_in = data_in ./ rms(data_in);
data_in = data_in - mean(data_in);
% then, match amplitude levels of input signal to those of the calculated ideal symbols
% i.e. match the rms values of data_in to noise_free_received (rms=1.xx)
@@ -125,6 +134,10 @@ classdef MLSE < handle
end
end
y_clean = conv( data_ref, flip(obj.DIR), "same" );
sigma2 = var( data_in - y_clean );
inv2s2 = 1/(2*sigma2);
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%% FORWARD PASS (VITERBI -Alpha's) %%%%%
@@ -134,7 +147,7 @@ classdef MLSE < handle
% first start is evaluated without ISI/ wihout the full Impulse response
% so simply use the constellation here
bm = -(data_in(1) - last_sym).^2 ;
bm = -(data_in(1) - last_sym).^2 * inv2s2;
pm = pm + bm;
[alpha(:,1),pm_survivor_fw_idx(:,1)] = max(pm,[],2);
pm = repmat(alpha(:,1).',nStates,1);
@@ -143,10 +156,10 @@ classdef MLSE < handle
% Forward Recursion (FSM Computation)
for n = 2:length(data_in)
bm = -(data_in(n) - noise_free_received).^2 ;
bm = -(data_in(n) - noise_free_received).^2 * inv2s2;
pm = pm + bm;
[alpha(:,n),pm_survivor_fw_idx(:,n)] = max(pm,[],2); % choose lowest path metric as new state
pm = repmat(alpha(:,n).',nStates,1); % update pm (chosen state to 2nd dimension -> FROM state)
[alpha(:,n),pm_survivor_fw_idx(:,n)] = max(pm,[],2); % choose lowest path metric as new state
pm = repmat(alpha(:,n).',nStates,1); % update pm (chosen state to 2nd dimension -> FROM state)
bm_fw(:,:,n) = bm;
@@ -177,7 +190,7 @@ classdef MLSE < handle
% predecessor
for h = length(data_in)-1:-1:1
bm = -(data_in(h+1) - noise_free_received).^2 ;
bm = -(data_in(h+1) - noise_free_received).^2 * inv2s2;
pm = pm + bm.';
[beta(:,h),pm_survivor_bw_idx(:,h)] = max(pm,[],2); % choose lowest path metric as new state
pm = repmat(beta(:,h).',nStates,1); % update pm (chosen state to 2nd dimension -> FROM state)
@@ -214,10 +227,22 @@ classdef MLSE < handle
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%% FORWARD PASS PAM2,4,8 %%%%%
nml_LLP = LLP - max(LLP);
expLLP = exp(nml_LLP); %subtract highst value for better numerical stability, LLP's are not always close to zero
state_prob = expLLP ./ sum(expLLP);
nml_LLP = LLP - max(LLP); %subtract highest value for better numerical stability, LLP's are not always close to zero
expLLP = exp(nml_LLP);
state_prob = expLLP ./ sum(expLLP); % sums to one (or numerically close to one)
% compute symbolposteriors from LLP in the logdomain:
amax = max(LLP,[],1);
logZ = amax + log(sum(exp(LLP - amax), 1));
logPstate = LLP - logZ; % still in logdomain
state_prob = exp(logPstate); % exact, sums to 1
% figure
% hold on;
% for i = 1:obj.M
% scatter(1:length(expLLP),expLLP(i,:),1,'.');
% end
% scatter(1:length(expLLP),max(expLLP(:,:)),3,'.');
if obj.M == 6
@@ -305,8 +330,8 @@ classdef MLSE < handle
% Number of symbols and bits per symbol
num_bits = log2(length(obj.trellis_states)); % 2 bits per symbol
bit_mapping = PAMmapper(length(obj.trellis_states),0,"eth_style",0).demap(first_sym./rms(first_sym));
% bit_mapping = PAMmapper(length(obj.trellis_states),0,"eth_style",0).demap(first_sym./rms(first_sym));
bit_mapping = PAMmapper(length(obj.trellis_states),0,"eth_style",0).showBitMapping;
% Initialize LLR storage
LLR_maxlogmap = zeros(length(data_in),num_bits);
LLR_exact = zeros(length(data_in),num_bits);
@@ -343,8 +368,8 @@ classdef MLSE < handle
llr1 = LLR_exact(idx_bit_0,k);
% Calculate mutual information for bit position k
I0 = mean(log2(1 + exp(llr0(100:end-100)))); % exp(--LLR) = exp(positive) > 1
I1 = mean(log2(1 + exp(-llr1(100:end-100)))); % exp(-+LLR) = exp(negative) < 1
I0 = mean(log2(1 + exp(llr0))); % exp(--LLR) = exp(positive) > 1
I1 = mean(log2(1 + exp(-llr1))); % exp(-+LLR) = exp(negative) < 1
MI(k) = 1 - 0.5 * (I0 + I1);
end
@@ -354,8 +379,7 @@ classdef MLSE < handle
VITERBI_ESTIMATION_SYMBOLS = VITERBI_ESTIMATION_SYMBOLS./rms(VITERBI_ESTIMATION_SYMBOLS);
debug = 0;
debug = 1;
if debug
%%% DEBUG PLOT LIKELIHOOD RATIOS %%%
figure(115);clf
@@ -380,6 +404,7 @@ classdef MLSE < handle
if debug
tx_bits = reshape(tx_bits',[],1);
disp('Start DEBUG MLSE:')
% DECIDE based on Viterbi traceback
VITERBI_ESTIMATION_SYMBOLS = VITERBI_ESTIMATION_SYMBOLS./rms(VITERBI_ESTIMATION_SYMBOLS);
rx_bits = PAMmapper(obj.M,0,"eth_style",0).demap(VITERBI_ESTIMATION_SYMBOLS');
@@ -417,13 +442,19 @@ classdef MLSE < handle
rx_bits = reshape(rx_bits',[],1);
[~,~,ber_fw,~] = calc_ber(rx_bits,tx_bits,"skip_front",100,"skip_end",150,"returnErrorLocation",1);
fprintf('FW BER: %.2e \n',ber_fw);
disp('Stop DEBUG MLSE:')
disp('')
end
end
end
methods (Access=private)
function s = logsumexp(a,dim)
% returns log(sum(exp(a),dim)) safely
amax = max(a,[],dim);
s = amax + log(sum(exp(a - amax), dim));
end
end
end