SD stuff working for PAM6 and MLSE is also calibrated
This commit is contained in:
@@ -29,7 +29,7 @@ classdef PAMmapper
|
||||
|
||||
obj.levels = obj.get_levels();
|
||||
|
||||
obj.scaling = rms(obj.get_levels());
|
||||
obj.scaling = obj.get_scaling;%rms(obj.get_levels());
|
||||
|
||||
obj.eth_style = options.eth_style;
|
||||
|
||||
@@ -283,6 +283,21 @@ classdef PAMmapper
|
||||
end
|
||||
end
|
||||
|
||||
function scaling = get_scaling(obj)
|
||||
switch obj.M
|
||||
case 2
|
||||
scaling = 1;
|
||||
case 4
|
||||
scaling = sqrt(5);
|
||||
case 6
|
||||
scaling = sqrt(10);
|
||||
case 8
|
||||
scaling = sqrt(21);
|
||||
case 16
|
||||
scaling = 1;
|
||||
end
|
||||
end
|
||||
|
||||
function [data_out] = demap_(obj,data_in)
|
||||
|
||||
data_in= data_in';
|
||||
@@ -450,7 +465,7 @@ classdef PAMmapper
|
||||
function [Signal_out] = quantize(obj,Signal_in)
|
||||
|
||||
constellation = obj.get_levels();
|
||||
constellation = constellation ./ rms(constellation);
|
||||
constellation = constellation ./ obj.scaling;
|
||||
|
||||
issignalclass = 0;
|
||||
if isa(Signal_in,'Signal')
|
||||
@@ -481,7 +496,9 @@ classdef PAMmapper
|
||||
end
|
||||
|
||||
function bitmap = showBitMapping(obj)
|
||||
bitmap = obj.demap([obj.levels ./ obj.scaling]');
|
||||
|
||||
bitmap = obj.demap((obj.levels ./ obj.scaling)');
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -83,11 +83,6 @@ 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);
|
||||
|
||||
@@ -122,21 +117,54 @@ classdef MLSE < handle
|
||||
count_row = 1;
|
||||
end
|
||||
|
||||
% first: RMS normalization of input data (rms==1)
|
||||
data_in = data_in ./ rms(data_in);
|
||||
data_in = data_in - mean(data_in);
|
||||
% Was used earlier from Tom Wettlin etc. Sufficient for Viterbi
|
||||
% but the BCJR is sensitive to the scaling, so I use another
|
||||
% apporach
|
||||
% % first: RMS normalization of input data (rms==1)
|
||||
% data_in = data_in ./ rms(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)
|
||||
% if isreal(data_in)
|
||||
% if obj.M == round(obj.M)
|
||||
% data_in = data_in * rms(noise_free_received(noise_free_received ~= inf),'all','omitnan');
|
||||
% end
|
||||
% end
|
||||
|
||||
% 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)
|
||||
if isreal(data_in)
|
||||
if obj.M == round(obj.M)
|
||||
data_in = data_in * rms(noise_free_received(noise_free_received ~= inf),'all','omitnan');
|
||||
end
|
||||
% quick and dirty alignment with xcorr
|
||||
y = data_in;
|
||||
x = data_ref;
|
||||
h = flip(obj.DIR(:)).';
|
||||
y_ideal = conv(x, h, "same");
|
||||
[c,lags] = xcorr(y, y_ideal, 64); % small max lag is enough
|
||||
[~,ix] = max(abs(c));
|
||||
lag = lags(ix);
|
||||
y_ideal = circshift(y_ideal, lag);
|
||||
|
||||
% center, skip transients, rm mean
|
||||
skip = max(100, numel(obj.DIR)+50);
|
||||
y_prep = y(1+skip:end-skip) - mean(y(1+skip:end-skip));
|
||||
y_ideal_prep = y_ideal(1+skip:end-skip) - mean(y_ideal(1+skip:end-skip));
|
||||
|
||||
% one-tap LS/MMSE gain and optional bias
|
||||
g = (y_ideal_prep' * y_prep) / (y_ideal_prep' * y_ideal_prep); % complex allowed
|
||||
b = mean(data_in) - g*mean(y_ideal); % intercept (if you keep means)
|
||||
|
||||
dp = dot(y_ideal_prep, y_prep - g*y_ideal_prep); %shall be close to zero
|
||||
|
||||
sigma2 = mean(abs(y_prep - g*y_ideal_prep).^2);
|
||||
inv2s2 = 1/(2*sigma2);
|
||||
|
||||
debug = 0;
|
||||
if debug
|
||||
figure(100); hold on
|
||||
plot(1:length(y),y,'DisplayName','Y: Received Signal','LineStyle','none','Marker','.','MarkerSize',1);
|
||||
plot(1:length(y_ideal),y_ideal,'DisplayName','Y ideal: x * DIR','LineStyle','none','Marker','.','MarkerSize',1);
|
||||
yline(noise_free_received(:),'DisplayName','All Transition States','HandleVisibility','off','Color','red');
|
||||
yline(g*noise_free_received(:)+ b,'DisplayName','Scaled Transition States','HandleVisibility','off');
|
||||
end
|
||||
|
||||
y_clean = conv( data_ref, flip(obj.DIR), "same" );
|
||||
sigma2 = var( data_in - y_clean );
|
||||
inv2s2 = 1/(2*sigma2);
|
||||
noise_free_received = (g*noise_free_received + b);
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
%%%%% FORWARD PASS (VITERBI -Alpha's) %%%%%
|
||||
@@ -199,50 +227,47 @@ classdef MLSE < handle
|
||||
|
||||
end
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
%%%%% FORWARD PASS PAM 2,4,8 (Combine Alpha and Beta to yield LLP's) %%%%%
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
%%%%% FORWARD PASS PAM 2,4,8 (Combine Alpha and Beta to yield LLP's) %%%%%
|
||||
|
||||
%calc the log probabilities (llp's)
|
||||
%calc the log probabilities (llp's)
|
||||
|
||||
for k = 1:length(data_in)
|
||||
for k = 1:length(data_in)
|
||||
|
||||
if k == 1
|
||||
if k == 1
|
||||
|
||||
alpha_ = repmat(alpha(:,k)',[nStates,1])';
|
||||
beta_ = beta(:,k);
|
||||
alpha_ = repmat(alpha(:,k)',[nStates,1])';
|
||||
beta_ = beta(:,k);
|
||||
|
||||
LLP(:,k) = max(alpha_ + beta_,[],2);
|
||||
LLP(:,k) = max(alpha_ + beta_,[],2);
|
||||
|
||||
else
|
||||
else
|
||||
|
||||
alpha_ = repmat(alpha(:,k-1)',[nStates,1])';
|
||||
gamma_ = bm_fw(:,:,k)';
|
||||
beta_ = beta(:,k);
|
||||
|
||||
LLP(:,k) = max(alpha_ + gamma_,[],1) + beta_';
|
||||
end
|
||||
alpha_ = repmat(alpha(:,k-1)',[nStates,1])';
|
||||
gamma_ = bm_fw(:,:,k)';
|
||||
beta_ = beta(:,k);
|
||||
|
||||
LLP(:,k) = max(alpha_ + gamma_,[],1) + beta_';
|
||||
end
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
%%%%% FORWARD PASS PAM2,4,8 %%%%%
|
||||
end
|
||||
|
||||
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)
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
%%%%% FORWARD PASS PAM2,4,8 %%%%%
|
||||
|
||||
% compute symbol‐posteriors from LLP in the log‐domain:
|
||||
amax = max(LLP,[],1);
|
||||
logZ = amax + log(sum(exp(LLP - amax), 1));
|
||||
logPstate = LLP - logZ; % still in log‐domain
|
||||
state_prob = exp(logPstate); % exact, sums to 1
|
||||
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)
|
||||
|
||||
% figure
|
||||
% hold on;
|
||||
% for i = 1:obj.M
|
||||
% scatter(1:length(expLLP),expLLP(i,:),1,'.');
|
||||
% end
|
||||
% scatter(1:length(expLLP),max(expLLP(:,:)),3,'.');
|
||||
% compute symbol‐posteriors from LLP in the log‐domain:
|
||||
amax = max(LLP,[],1);
|
||||
logZ = amax + log(sum(exp(LLP - amax), 1));
|
||||
logPstate = LLP - logZ; % still in log‐domain
|
||||
state_prob = exp(logPstate); % exact, sums to 1
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
if obj.M == 6
|
||||
|
||||
@@ -250,30 +275,22 @@ classdef MLSE < handle
|
||||
|
||||
% all possible transitions (for now 36, including the "edges"
|
||||
% of the QAM 32 constellation)
|
||||
pam6transitions = combvec(obj.trellis_states,obj.trellis_states)'; % pam6transitions =
|
||||
states = PAMmapper(6,0,"eth_style",0).levels;
|
||||
pam6transitions = combvec(states,states)'; % pam6transitions =
|
||||
% [-5 -5;
|
||||
% -3 -5;
|
||||
% -1 -5; ...
|
||||
|
||||
pam6bits = PAMmapper(6,0,"eth_style",0).demap(reshape(pam6transitions',[],1)./sqrt(10));
|
||||
|
||||
pam6bits = reshape(pam6bits',5,[])';
|
||||
%pam6bits =
|
||||
% 0 0 0 1 0
|
||||
% 0 0 0 1 0
|
||||
% 0 0 0 1 1
|
||||
% 1 0 0 1 1
|
||||
% 1 0 0 1 0
|
||||
% 1 0 0 1 0
|
||||
% 0 0 1 1 0
|
||||
% ....
|
||||
pam6bits = reshape(pam6bits',5,[])';
|
||||
|
||||
[ok1, idx_bit_0] = ismember(pam6transitions(:,1), obj.trellis_states);
|
||||
[ok2, idx2] = ismember(pam6transitions(:,2), obj.trellis_states);
|
||||
[ok1, idx_sym_1] = ismember(pam6transitions(:,1), states);
|
||||
[ok2, idx_sym_2] = ismember(pam6transitions(:,2), states);
|
||||
assert(all(ok1)&all(ok2), 'Some transition amplitude not found in trellis_states')
|
||||
pam6ind = [idx_bit_0, idx2];
|
||||
pam6ind = [idx_sym_1, idx_sym_2];
|
||||
|
||||
tx_bits_pam6_reshaped = reshape(tx_bits,5,[])';
|
||||
tx_bits_pam6_reshaped = reshape(tx_bits,5,[])'; % N x 5
|
||||
|
||||
numPairs = floor(size(LLP,2)/2);
|
||||
LLR_exact = zeros(numPairs,5);
|
||||
@@ -289,33 +306,33 @@ classdef MLSE < handle
|
||||
prob2 = state_prob(:,symbol2);
|
||||
|
||||
% 36 joint‐metrics M = log P(i)*P(j) = L1(i)+L2(j)
|
||||
Mij = LLP1(pam6ind(:,1)) + LLP2(pam6ind(:,2));
|
||||
pij = prob1(pam6ind(:,1)) .* prob2(pam6ind(:,2));
|
||||
Mij = LLP1(pam6ind(:,1)) + LLP2(pam6ind(:,2));
|
||||
pij = prob1(pam6ind(:,1)) .* prob2(pam6ind(:,2));
|
||||
|
||||
% now for each of the 5 bits do exact-LLR or max-log
|
||||
for b = 1:num_bits
|
||||
idx_bit_0 = pam6bits(:,b)==1;
|
||||
idx_sym_1 = pam6bits(:,b)==1;
|
||||
idx_bit_1 = pam6bits(:,b)==0;
|
||||
|
||||
%--- exact LLR from probabilities
|
||||
P1 = sum(pij(idx_bit_0));
|
||||
P1 = sum(pij(idx_sym_1));
|
||||
P0 = sum(pij(idx_bit_1));
|
||||
LLR_exact(k,b) = log(P1./P0);
|
||||
|
||||
%--- max-log:
|
||||
LLR_maxlogmap(k,b) = max( Mij(idx_bit_0) ) - max( Mij(idx_bit_1) ); % N x num_bits
|
||||
LLR_maxlogmap(k,b) = max( Mij(idx_sym_1) ) - max( Mij(idx_bit_1) ); % N x num_bits
|
||||
end
|
||||
end
|
||||
|
||||
MI = zeros(1, num_bits);
|
||||
MI = zeros(1, num_bits);
|
||||
for k = 1:num_bits
|
||||
|
||||
idx_bit_1 = (tx_bits_pam6_reshaped(:,k) == 0); %wo sind die 1en
|
||||
idx_bit_0 = (tx_bits_pam6_reshaped(:,k) == 1); %wo sind die 0en
|
||||
idx_sym_1 = (tx_bits_pam6_reshaped(:,k) == 1); %wo sind die 0en
|
||||
|
||||
%LLR's for all actually transmitted ones or zeros
|
||||
llr0 = LLR_exact(idx_bit_1,k);
|
||||
llr1 = LLR_exact(idx_bit_0,k);
|
||||
llr0 = LLR_exact(idx_bit_1,k);
|
||||
llr1 = LLR_exact(idx_sym_1,k);
|
||||
|
||||
% Calculate mutual information for bit position k
|
||||
I0 = mean(log2(1 + exp(llr0))); % exp(--LLR) = exp(positive) > 1
|
||||
@@ -324,7 +341,7 @@ classdef MLSE < handle
|
||||
end
|
||||
|
||||
GMI = sum(MI); % Total mutual information per symbol
|
||||
GMI = GMI/2;
|
||||
GMI = GMI/2;
|
||||
|
||||
else
|
||||
|
||||
@@ -340,14 +357,14 @@ classdef MLSE < handle
|
||||
for bit_idx = 1:num_bits
|
||||
|
||||
% Find indices where bit is 0 and where it is 1
|
||||
idx_bit_0 = bit_mapping(:,bit_idx) == 0;
|
||||
idx_sym_1 = bit_mapping(:,bit_idx) == 0;
|
||||
idx_bit_1 = bit_mapping(:,bit_idx) == 1;
|
||||
|
||||
% Sum over log-probabilities (Max-Log approximation: using max instead of sum)
|
||||
LLR_maxlogmap(:,bit_idx) = max(LLP(idx_bit_1,:), [], 1) - max(LLP(idx_bit_0,:), [], 1);
|
||||
LLR_maxlogmap(:,bit_idx) = max(LLP(idx_bit_1,:), [], 1) - max(LLP(idx_sym_1,:), [], 1);
|
||||
|
||||
% Sum probabilities over states for which the bit is 1 and 0, respectively.
|
||||
P0 = sum(state_prob(idx_bit_0, :),1);
|
||||
P0 = sum(state_prob(idx_sym_1, :),1);
|
||||
P1 = sum(state_prob(idx_bit_1, :),1);
|
||||
LLR_exact(:,bit_idx) = log(P1./P0); % N x num_bits
|
||||
|
||||
@@ -356,16 +373,16 @@ classdef MLSE < handle
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
%%%%% CALC NGMI %%%%%
|
||||
|
||||
MI = zeros(1, num_bits);
|
||||
MI = zeros(1, num_bits);
|
||||
LLR_exact = LLR_exact;
|
||||
for k = 1:num_bits
|
||||
|
||||
idx_bit_1 = (tx_bits(:,k) == 0); %wo sind die 1en
|
||||
idx_bit_0 = (tx_bits(:,k) == 1); %wo sind die 0en
|
||||
idx_sym_1 = (tx_bits(:,k) == 1); %wo sind die 0en
|
||||
|
||||
%LLR's for all actually transmitted ones or zeros
|
||||
llr0 = LLR_exact(idx_bit_1,k);
|
||||
llr1 = LLR_exact(idx_bit_0,k);
|
||||
llr0 = LLR_exact(idx_bit_1,k);
|
||||
llr1 = LLR_exact(idx_sym_1,k);
|
||||
|
||||
% Calculate mutual information for bit position k
|
||||
I0 = mean(log2(1 + exp(llr0))); % exp(--LLR) = exp(positive) > 1
|
||||
@@ -379,7 +396,7 @@ classdef MLSE < handle
|
||||
|
||||
VITERBI_ESTIMATION_SYMBOLS = VITERBI_ESTIMATION_SYMBOLS./rms(VITERBI_ESTIMATION_SYMBOLS);
|
||||
|
||||
debug = 1;
|
||||
|
||||
if debug
|
||||
%%% DEBUG PLOT LIKELIHOOD RATIOS %%%
|
||||
figure(115);clf
|
||||
@@ -389,7 +406,7 @@ classdef MLSE < handle
|
||||
histogram(LLR_exact(:,bit),1000,"DisplayName",sprintf('Actual LLR of Bit Pos %d',bit),'LineStyle','none','FaceAlpha',0.4);
|
||||
end
|
||||
legend
|
||||
|
||||
|
||||
subplot(2,1,2)
|
||||
for bit = 1:num_bits
|
||||
hold on;
|
||||
@@ -403,7 +420,7 @@ classdef MLSE < handle
|
||||
|
||||
if debug
|
||||
tx_bits = reshape(tx_bits',[],1);
|
||||
|
||||
fprintf('\n')
|
||||
disp('Start DEBUG MLSE:')
|
||||
% DECIDE based on Viterbi traceback
|
||||
VITERBI_ESTIMATION_SYMBOLS = VITERBI_ESTIMATION_SYMBOLS./rms(VITERBI_ESTIMATION_SYMBOLS);
|
||||
@@ -443,7 +460,7 @@ classdef MLSE < handle
|
||||
[~,~,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('')
|
||||
fprintf('\n')
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user