147 lines
5.4 KiB
Matlab
147 lines
5.4 KiB
Matlab
function showLevelHistogram(eq_signal,ref_symbols,options)
|
|
arguments
|
|
eq_signal
|
|
ref_symbols
|
|
options.fignum (1,1) double = NaN % Default to NaN if not provided
|
|
options.displayname (1,:) char = '' % Default to an empty string if not provided
|
|
options.ref_symbol_uncoded = []
|
|
options.nbins (1,1) double = 1000
|
|
end
|
|
|
|
if isa(eq_signal,'Signal')
|
|
eq_signal = eq_signal.signal;
|
|
end
|
|
if isa(ref_symbols,'Signal')
|
|
ref_symbols = ref_symbols.signal;
|
|
end
|
|
if isa(options.ref_symbol_uncoded,'Signal')
|
|
options.ref_symbol_uncoded = options.ref_symbol_uncoded.signal;
|
|
end
|
|
|
|
eq_signal = eq_signal(:);
|
|
ref_symbols = ref_symbols(:);
|
|
ref_symbol_uncoded = options.ref_symbol_uncoded(:);
|
|
|
|
assert(numel(eq_signal) == numel(ref_symbols), ...
|
|
'showLevelHistogram:LengthMismatch', ...
|
|
'eq_signal and ref_symbols must have the same number of samples.');
|
|
assert(isempty(ref_symbol_uncoded) || numel(ref_symbol_uncoded) == numel(eq_signal), ...
|
|
'showLevelHistogram:LengthMismatch', ...
|
|
'options.ref_symbol_uncoded must have the same number of samples as eq_signal.');
|
|
|
|
% Determine the figure number to use or create a new figure
|
|
if isnan(options.fignum)
|
|
fig = figure; % Create a new figure and get its handle
|
|
else
|
|
fig = figure(options.fignum); % Use the specified figure number
|
|
end
|
|
|
|
eq_signal = max(min(eq_signal,3),-3);
|
|
|
|
eq_signal = eq_signal .* -1;
|
|
|
|
%%% histogram
|
|
clf
|
|
if isempty(ref_symbol_uncoded)
|
|
% Normal mode: split the received signal by the actually
|
|
% transmitted reference level.
|
|
constellation = unique(ref_symbols);
|
|
received_sd = NaN(numel(constellation),numel(ref_symbols));
|
|
lvlcol = linspecer(numel(constellation));
|
|
|
|
lvlcol = cbrewer2('RdBu',numel(constellation)+4);
|
|
|
|
% remove 4 colors from the middle to avoid the bright central colors
|
|
mid = ceil(size(lvlcol,1)/2);
|
|
rm_idx = mid + (-1:2); % two before mid and two after (2x2 removal centered)
|
|
rm_idx = max(1,min(size(lvlcol,1),rm_idx));
|
|
lvlcol(rm_idx,:) = [];
|
|
lvlcol = lvlcol(1:numel(constellation),:);
|
|
|
|
for lvl = 1:numel(constellation)
|
|
class_mask = ref_symbols == constellation(lvl);
|
|
received_sd(lvl,class_mask) = eq_signal(class_mask);
|
|
end
|
|
|
|
for lvl = 1:numel(constellation)
|
|
intermediate = received_sd(lvl,:);
|
|
cnt(lvl) = round(numel(intermediate(~isnan(intermediate)))./numel(eq_signal),3).*100;
|
|
hold on
|
|
warning off
|
|
histogram(received_sd(lvl,:),options.nbins, ...
|
|
"EdgeAlpha",0, ...
|
|
"DisplayName",['Lvl ',num2str(lvl),' ; ',num2str(cnt(lvl)),' '], ...
|
|
"FaceColor",lvlcol(lvl,:), ...
|
|
"Normalization","pdf");
|
|
warning on
|
|
end
|
|
else
|
|
% Plot p(y | x_n): y is the noisy observation and x_n is the
|
|
% uncoded PAM class. For duobinary this naturally gives multi-modal
|
|
% PDFs because one x_n class can map to multiple DB amplitudes. Each
|
|
% DB lobe is drawn separately so the DB-level structure stays visible.
|
|
db_constellation = unique(ref_symbols);
|
|
classes = unique(ref_symbol_uncoded);
|
|
% lvlcol = linspecer(numel(classes));
|
|
lvlcol = cbrewer2('RdBu',numel(classes)+4);
|
|
|
|
% remove 4 colors from the middle to avoid the bright central colors
|
|
mid = ceil(size(lvlcol,1)/2);
|
|
rm_idx = mid + (-1:2); % two before mid and two after (2x2 removal centered)
|
|
rm_idx = max(1,min(size(lvlcol,1),rm_idx));
|
|
lvlcol(rm_idx,:) = [];
|
|
lvlcol = lvlcol(1:numel(sir_group_labels),:);
|
|
|
|
for db_lvl = 1:numel(db_constellation)
|
|
db_mask = ref_symbols == db_constellation(db_lvl);
|
|
mapped_class = mode(ref_symbol_uncoded(db_mask));
|
|
[~,class_idx] = min(abs(classes - mapped_class));
|
|
cnt = round(nnz(ref_symbol_uncoded == mapped_class)./numel(eq_signal),3).*100;
|
|
|
|
if db_lvl == findFirstMappedDbLevel(ref_symbols,ref_symbol_uncoded,db_constellation,mapped_class)
|
|
display_name = ['p(y|x_',num2str(class_idx),') ; ',num2str(cnt),' '];
|
|
display_name = ['p(y|x_',num2str(class_idx),')'];
|
|
handle_visibility = "on";
|
|
else
|
|
display_name = ['p(y|x_',num2str(class_idx),') ; ',num2str(cnt),' '];
|
|
display_name = ['p(y|x_',num2str(class_idx),')'];
|
|
handle_visibility = "off";
|
|
end
|
|
|
|
weighted_lobe = NaN(size(eq_signal));
|
|
weighted_lobe(db_mask) = eq_signal(db_mask);
|
|
|
|
hold on
|
|
warning off
|
|
histogram(weighted_lobe,options.nbins, ...
|
|
"EdgeAlpha",0, ...
|
|
"DisplayName",display_name, ...
|
|
"FaceColor",lvlcol(class_idx,:), ...
|
|
"HandleVisibility",handle_visibility, ...
|
|
"Normalization","pdf");
|
|
warning on
|
|
end
|
|
end
|
|
xlim([-3 3]);
|
|
legend
|
|
grid on
|
|
|
|
% view([90 -90]);
|
|
|
|
|
|
|
|
end
|
|
|
|
function first_db_lvl = findFirstMappedDbLevel(ref_symbols,ref_symbol_uncoded,db_constellation,mapped_class)
|
|
first_db_lvl = NaN;
|
|
|
|
for db_lvl = 1:numel(db_constellation)
|
|
db_mask = ref_symbols == db_constellation(db_lvl);
|
|
if mode(ref_symbol_uncoded(db_mask)) == mapped_class
|
|
first_db_lvl = db_lvl;
|
|
return
|
|
end
|
|
end
|
|
end
|
|
|