more and more

This commit is contained in:
Silas Oettinghaus
2026-07-08 21:36:08 +02:00
parent 699d146fb5
commit 1879441999
22 changed files with 2197 additions and 174 deletions

View File

@@ -23,7 +23,8 @@ end
end
% Ensure the figure is ready before calling spectrum
eq_noise.spectrum("displayname", options.displayname, "fignum", fig.Number, "normalizeTo0dB", 1,"color",options.color);
eq_noise = eq_noise - mean(eq_noise.signal);
eq_noise.spectrum("displayname", options.displayname, "fignum", fig.Number, "normalizeTo0dB", 0,"color",options.color,"fft_length",4096*2);
if ~isnan(options.postfilter_taps)
% Hold on to the figure for further plotting

View File

@@ -38,6 +38,8 @@ end
eq_signal = max(min(eq_signal,3),-3);
eq_signal = eq_signal .* -1;
%%% histogram
clf
if isempty(ref_symbol_uncoded)
@@ -47,6 +49,15 @@ end
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);
@@ -71,7 +82,15 @@ end
% 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 = 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);

View File

@@ -21,15 +21,19 @@ arguments
options.clear (1,1) logical = true
options.windowLength (1,1) double {mustBePositive, mustBeInteger} = 500
options.xLimits double = []
options.yLimits (1,2) double = [-3 3]
options.yLimits (1,2) double = [-2.5 2.5]
options.showStdAnnotations (1,1) logical = true
options.scatterAlpha (1,1) double {mustBeGreaterThanOrEqual(options.scatterAlpha, 0), mustBeLessThanOrEqual(options.scatterAlpha, 1)} = 0.2
options.scatterSize (1,1) double {mustBePositive} = 1
options.avgLineMaxPoints (1,1) double {mustBePositive, mustBeInteger} = 1000
options.avgLineSmoothWindow (1,1) double {mustBePositive, mustBeInteger} = 1
end
fsym = resolveSymbolRate(rxInput, refSymbols, options);
[symbols_for_lvl, avg_for_lvl, xAxisUs, info] = prepareLevelScatterData(rxInput, refSymbols, fsym, options);
if options.showPlot
plotLevelScatter(symbols_for_lvl, avg_for_lvl, refSymbols, xAxisUs, options);
info.plot = plotLevelScatter(symbols_for_lvl, avg_for_lvl, refSymbols, xAxisUs, options);
end
end
@@ -73,6 +77,7 @@ info.shifts = [];
info.fsym = fsym;
info.shiftFs = fsym;
info.varianceByLevel = [];
info.plot = struct();
end
function [symbols_for_lvl, avg_for_lvl, info] = prepareSignalInput(rxSignal, refSymbols, fsym, options, info)
@@ -250,50 +255,95 @@ else
end
end
function plotLevelScatter(symbols_for_lvl, avg_for_lvl, refSymbols, xAxisUs, options)
function plotInfo = plotLevelScatter(symbols_for_lvl, avg_for_lvl, refSymbols, xAxisUs, options)
plotInfo = struct();
if isempty(symbols_for_lvl)
return
end
if isnan(options.fignum)
figure;
figHandle = figure;
else
figure(options.fignum);
figHandle = figure(options.fignum);
if options.clear
clf;
end
end
hold on
ax = gca;
hold(ax, "on");
numLevels = size(symbols_for_lvl, 1);
cols = cbrewer2("Paired", 2*numLevels);
cols = cbrewer2("RdBu", numLevels);
% cols = linspecer(numLevels);
xLimits = getXLimits(options.xLimits, xAxisUs, symbols_for_lvl);
for levelIdx = 1:numLevels
scatter(xAxisUs, symbols_for_lvl(levelIdx, :), 10, ".", ...
"MarkerEdgeColor", cols((2*levelIdx)-1, :), ...
"MarkerEdgeAlpha", 0.5);
if 1
for levelIdx = numLevels:-1:1
scatter(ax, xAxisUs, symbols_for_lvl(levelIdx, :), options.scatterSize, ".", ...
"MarkerEdgeColor", cols(levelIdx, :), ...
"MarkerEdgeAlpha", options.scatterAlpha);
end
end
for levelIdx = 1:numLevels
plot(xAxisUs, avg_for_lvl(levelIdx, :), ...
"LineWidth", 1, ...
"Color", cols(2*levelIdx, :));
[xReduced, yReduced] = reduceAverageLineForPlot( ...
xAxisUs, avg_for_lvl(levelIdx, :), ...
options.avgLineMaxPoints, options.avgLineSmoothWindow);
plot(ax, xReduced, yReduced, ...
"LineWidth", 2, ...
"Color", cols(levelIdx, :));
end
refValues = numericSignal(refSymbols);
yline(unique(refValues), "HandleVisibility", "off");
% refValues = unique(numericSignal(refSymbols));
% for refIdx = 1:numel(refValues)
% yline(ax, refValues(refIdx), "--", ...
% "Color", [0.35 0.35 0.35], ...
% "LineWidth", 0.75, ...
% "HandleVisibility", "off");
% end
if options.showStdAnnotations
annotateLevelStd(symbols_for_lvl, avg_for_lvl, xAxisUs, options.xLimits);
end
xlabel('Time in $\mu$s');
ylabel('Normalized Amplitude');
xlim(getXLimits(options.xLimits, xAxisUs, symbols_for_lvl));
ylim(options.yLimits);
grid on
xlabel(ax, 'Time in $\mu$s');
ylabel(ax, 'Normalized Amplitude');
xlim(ax, xLimits);
ylim(ax, options.yLimits);
grid(ax, "on");
figure(figHandle);
drawnow;
end
function [xReduced, yReduced] = reduceAverageLineForPlot(xAxisUs, yTrace, maxPoints, smoothWindow)
valid = isfinite(xAxisUs) & isfinite(yTrace);
xValid = xAxisUs(valid);
yValid = yTrace(valid);
if isempty(xValid)
xReduced = [];
yReduced = [];
return
end
[xValid, uniqueIdx] = unique(xValid, "stable");
yValid = yValid(uniqueIdx);
if smoothWindow > 1
yValid = smoothdata(yValid, "movmean", smoothWindow);
end
numOut = min(maxPoints, numel(xValid));
if numOut >= numel(xValid)
xReduced = xValid;
yReduced = yValid;
return
end
xReduced = linspace(xValid(1), xValid(end), numOut);
yReduced = interp1(xValid, yValid, xReduced, "pchip");
end
function xLimits = getXLimits(configuredLimits, xAxisUs, symbols_for_lvl)
if ~isempty(configuredLimits)
xLimits = configuredLimits;
@@ -308,12 +358,12 @@ end
lastFilledColumn = find(filledColumns, 1, "last");
xMax = xAxisUs(lastFilledColumn);
xLimits = [0, 1.05*xMax];
xLimits = [0, 1*xMax];
end
function annotateLevelStd(symbols_for_lvl, avg_for_lvl, xAxisUs, configuredXLimits)
xLimits = getXLimits(configuredXLimits, xAxisUs, symbols_for_lvl);
xText = xLimits(1) + 0.96*diff(xLimits);
xText = xLimits(1) + 0.2*diff(xLimits);
for levelIdx = 1:size(symbols_for_lvl, 1)
levelSamples = symbols_for_lvl(levelIdx, :);
@@ -328,9 +378,9 @@ for levelIdx = 1:size(symbols_for_lvl, 1)
yText = median(levelSamples(~isnan(levelSamples)), 'omitnan');
end
label = ['std = ', sprintf('%.3f', levelStd)];
label = ['$\sigma^2_',sprintf('%d', levelIdx),'$ = ', sprintf('%.3f', levelStd)];
text(xText, yText, label, ...
'Interpreter', 'none', ...
'Interpreter', 'latex', ...
'HorizontalAlignment', 'right', ...
'VerticalAlignment', 'middle', ...
'FontSize', 10, ...