Files
imdd_silas/projects/Diss/MPI_revisit/verify_mpi_noise_power.m
Silas Oettinghaus 1879441999 more and more
2026-07-08 21:36:08 +02:00

664 lines
23 KiB
Matlab

%% Investigate stored std values per PAM level
% Assumes mpi_superview contains:
% run_id, pam_level, sir, interference_path_length, std_rawlevels, mean_rawlevels
% std_rawlevels / mean_rawlevels stored as JSON arrays, e.g. [0.1,0.2,0.3,0.4]
dsp_options.database_type = "mysql";
dsp_options.dataBase = "labor";
dsp_options.server = "192.168.178.192";
dsp_options.port = 3306;
dsp_options.user = "silas";
dsp_options.password = "silas";
db = DBHandler("dataBase", dsp_options.dataBase, "type", dsp_options.database_type, ...
"server", dsp_options.server, "port", dsp_options.port, ...
"user", dsp_options.user, "password", dsp_options.password);
%% Query
fp = QueryFilter();
% fp.where('Runs','run_id','GREATER_EQUAL',3153);
fp.where('Runs', 'fiber_length', 'EQUALS', 0);
fp.where('Runs', 'db_mode', 'EQUALS', '"no_db"');
fp.where('Runs', 'interference_path_length', 'NOT_EQUAL', 0);
fp.where('Runs', 'symbolrate', 'EQUALS', 112e9);
fp.where('Runs', 'pam_level','EQUALS', 4);
[dataTable,~] = db.queryDB(fp, db.getTableFieldNames('Runs'));
% Basic filtering
% Keep only rows with available level statistics
valid = hasStoredLevelStats(dataTable);
dataTable = dataTable(valid,:);
% % Optional analysis filters
% dataTable = dataTable(dataTable.sir < 25, :);
% dataTable = dataTable(dataTable.pam_level == 4, :);
nRuns = height(dataTable);
M = 8;
std_levels = nan(M,nRuns);
mean_levels = nan(M,nRuns);
var_levels = nan(M,nRuns);
std_slope = nan(nRuns,1);
var_slope = nan(nRuns,1);
var_offset = nan(nRuns,1);
gamma = nan(nRuns,1);
% Decode JSON arrays and compute variance slopes
for i = 1:nRuns
std_i = jsondecode(char(dataTable.std_rawlevels(i)));
mean_i = jsondecode(char(dataTable.mean_rawlevels(i)));
std_i = std_i(:);
mean_i = mean_i(:);
% Keep only valid entries
valid_i = isfinite(std_i) & isfinite(mean_i);
if ~sum(valid_i)
continue
end
std_i = std_i(valid_i);
mean_i = mean_i(valid_i);
% Sort by measured level mean
[mean_i, idx] = sort(mean_i, 'ascend');
std_i = std_i(idx);
var_i = std_i.^2;
% Store
std_levels(1:numel(std_i),i) = std_i;
mean_levels(1:numel(mean_i),i) = mean_i;
var_levels(1:numel(var_i),i) = var_i;
% 1) Fit variance over measured raw level mean
p_k = polyfit(mean_i, var_i, 1);
% 2) Normalized x-axis slope, better cross-PAM comparable
x_i = (mean_i - min(mean_i)) ./ (max(mean_i) - min(mean_i));
p_std = polyfit(x_i, std_i, 1);
std_slope(i) = p_std(1);
var_slope(i) = p_k(1);
var_offset(i) = p_k(2);
gamma(i) = std_i(end) / std_i(1);
end
% Add calculated values to table
dataTable.var_slope_calc = var_slope;
dataTable.std_slope_calc = std_slope;
dataTable.var_offset_calc = var_offset;
dataTable.gamma_calc = gamma;
dataTable.sir = -7 - dataTable.power_mpi_interference;
%% Plot 1: variance per level at fixed path length, grouped by PAM level
% NICHT GENUTZT
path_length_filter = -1;
idx_path = dataTable.interference_path_length > path_length_filter;
pam_levels = unique(dataTable.pam_level(idx_path));
cols = linspecer(numel(pam_levels));
figure; hold on;
sir_values_plot = dataTable.sir(idx_path & isfinite(dataTable.sir));
if isempty(sir_values_plot)
sir_limits = [0, 1];
else
sir_limits = [min(sir_values_plot), max(sir_values_plot)];
end
if diff(sir_limits) == 0
sir_limits = sir_limits + [-0.5, 0.5];
end
sir_cmap = cbrewer2('RdBu',256);%parula(256);
colormap(sir_cmap);
caxis(sir_limits);
mkr = ['+','o','*','square'];
for g = 1:numel(pam_levels)
pamLevel = pam_levels(g);
idx_g = idx_path & dataTable.pam_level == pamLevel;
mean_g = mean_levels(:,idx_g);
var_g = std_levels(:,idx_g);
run_sir_g = dataTable.sir(idx_g);
sir_g = repmat(dataTable.sir(idx_g).', M, 1);
run_id_g = repmat(dataTable.run_id(idx_g).', M, 1);
path_length_g = repmat(dataTable.interference_path_length(idx_g).', M, 1);
pam_level_g = repmat(dataTable.pam_level(idx_g).', M, 1);
% Scatter all runs
hScatter = scatter(mean_g(:), var_g(:), 5, sir_g(:), ...
'filled', ...
'MarkerFaceAlpha', 0.55, ...
'MarkerEdgeAlpha', 0.35, ...
'HandleVisibility','off');
for runIdx = 1:5:size(mean_g, 2)
if isfinite(run_sir_g(runIdx))
sirColorIdx = round(interp1(sir_limits, [1, size(sir_cmap,1)], run_sir_g(runIdx), 'linear', 'extrap'));
sirColorIdx = min(max(sirColorIdx, 1), size(sir_cmap,1));
lineColor = sir_cmap(sirColorIdx,:);
else
lineColor = [0.5, 0.5, 0.5];
end
hLine = plot(mean_g(:,runIdx), var_g(:,runIdx), ...
'LineWidth', 0.1, ...
'LineStyle', '-', ...
'Marker', 'none', ...
'HandleVisibility', 'off');
try
hLine.Color = [lineColor, 0.25];
catch
hLine.Color = lineColor;
end
end
hScatter.DataTipTemplate.DataTipRows(1).Label = 'mean level';
hScatter.DataTipTemplate.DataTipRows(2).Label = 'variance';
hScatter.DataTipTemplate.DataTipRows(3).Label = 'SIR';
hScatter.DataTipTemplate.DataTipRows(end+1) = dataTipTextRow('run id', run_id_g(:));
hScatter.DataTipTemplate.DataTipRows(end+1) = dataTipTextRow('interference length', path_length_g(:));
hScatter.DataTipTemplate.DataTipRows(end+1) = dataTipTextRow('pam_level', pam_level_g(:));
% Group mean curve
mean_level_g = mean(mean_g, 2, 'omitnan');
mean_var_g = mean(var_g, 2, 'omitnan');
plot(mean_level_g, mean_var_g, '-o', ...
'Color', [0,0,0], ...
'LineWidth', 2, ...
'MarkerFaceColor', cols(g,:), ...
'MarkerEdgeColor', cols(g,:), ...
'DisplayName', sprintf('PAM %.0f', pamLevel), 'MarkerSize', 5,'Marker','o');
end
grid on;
xlabel('Mean raw level');
ylabel('Stored level variance');
title(sprintf('Level variance at %.0f m path length, grouped by PAM level', path_length_filter));
legend('Location','best');
cb = colorbar;
ylabel(cb, 'SIR / dB');
%% Plot 1b: variance per level at fixed path length, grouped by SIR
sir_filter_max_slope = 60;
idx_path_sir = idx_path ...
& isfinite(dataTable.sir) ...
& dataTable.sir < sir_filter_max_slope;
sir_group_edges = [-inf,17.5 20, 22.5, 25, 30, 40, inf];
sir_group_labels = {'SIR < 17.5 dB','17.5 < SIR < 20 dB', '20 < SIR < 22.5 dB','22.5 < SIR < 25 dB', '25 < SIR < 30 dB', '30 < SIR < 40 dB', sprintf('40 < SIR < %.0f dB', sir_filter_max_slope)};
sir_group_cols = cbrewer2('RdBu',numel(sir_group_labels));
pam_marker_styles = {'o','square','diamond','^','v','>','<','pentagram','hexagram'};
figure; hold on;
pam_levels_plot = unique(dataTable.pam_level(idx_path_sir));
max_slope_lines = numel(sir_group_labels) * numel(pam_levels_plot);
slope_annotation_lines = cell(max_slope_lines, 1);
slope_annotation_idx = 0;
fit_line_x = cell(max_slope_lines, 1);
fit_line_y = cell(max_slope_lines, 1);
fit_line_color = cell(max_slope_lines, 1);
fit_line_label = cell(max_slope_lines, 1);
mean_point_x = cell(max_slope_lines, 1);
mean_point_y = cell(max_slope_lines, 1);
mean_point_marker = cell(max_slope_lines, 1);
fit_text_x = nan(max_slope_lines, 1);
fit_text_y = nan(max_slope_lines, 1);
fit_text_label = cell(max_slope_lines, 1);
fit_line_idx = 0;
for sirGroupIdx = numel(sir_group_labels):-1:1
idx_sir_group = idx_path_sir ...
& dataTable.sir > sir_group_edges(sirGroupIdx) ...
& dataTable.sir < sir_group_edges(sirGroupIdx+1);
if ~any(idx_sir_group)
continue
end
pam_levels_sir = unique(dataTable.pam_level(idx_sir_group));
for pamIdx = 1:numel(pam_levels_sir)
pamLevel = pam_levels_sir(pamIdx);
idx_sir_pam = idx_sir_group & dataTable.pam_level == pamLevel;
markerStyle = pam_marker_styles{mod(pamIdx-1,numel(pam_marker_styles))+1};
mean_g = mean_levels(:,idx_sir_pam);
var_g = std_levels(:,idx_sir_pam);
sir_g = repmat(dataTable.sir(idx_sir_pam).', M, 1);
run_id_g = repmat(dataTable.run_id(idx_sir_pam).', M, 1);
path_length_g = repmat(dataTable.interference_path_length(idx_sir_pam).', M, 1);
pam_level_g = repmat(dataTable.pam_level(idx_sir_pam).', M, 1);
hScatter = scatter(mean_g(:), var_g(:), 5, sir_group_cols(sirGroupIdx,:), markerStyle, ...
'filled', ...
'MarkerFaceAlpha', 0.25, ...
'MarkerEdgeAlpha', 0.20, ...
'HandleVisibility','off');
hScatter.DataTipTemplate.DataTipRows(1).Label = 'mean level';
hScatter.DataTipTemplate.DataTipRows(2).Label = 'std';
hScatter.DataTipTemplate.DataTipRows(end+1) = dataTipTextRow('SIR', sir_g(:));
hScatter.DataTipTemplate.DataTipRows(end+1) = dataTipTextRow('run id', run_id_g(:));
hScatter.DataTipTemplate.DataTipRows(end+1) = dataTipTextRow('interference length', path_length_g(:));
hScatter.DataTipTemplate.DataTipRows(end+1) = dataTipTextRow('pam_level', pam_level_g(:));
mean_level_g = mean(mean_g, 2, 'omitnan');
mean_std_g = mean(var_g, 2, 'omitnan');
valid_mean_curve = isfinite(mean_level_g) & isfinite(mean_std_g);
if nnz(valid_mean_curve) >= 2
p_mean_slope = polyfit(mean_level_g(valid_mean_curve), mean_std_g(valid_mean_curve), 1);
fit_x_g = linspace(min(mean_level_g(valid_mean_curve)), max(mean_level_g(valid_mean_curve)), 100);
fit_y_g = polyval(p_mean_slope, fit_x_g);
slope_text_g = strrep(sprintf('%.2f', p_mean_slope(1)), '.', ',');
label_x_g = fit_x_g(end);
label_y_g = fit_y_g(end);
else
fit_x_g = [];
fit_y_g = [];
slope_text_g = 'NaN';
label_x_g = NaN;
label_y_g = NaN;
end
slope_annotation_idx = slope_annotation_idx + 1;
slope_annotation_lines{slope_annotation_idx} = sprintf('%s, PAM %.0f: %s', sir_group_labels{sirGroupIdx}, pamLevel, slope_text_g);
fit_line_idx = fit_line_idx + 1;
mean_point_x{fit_line_idx} = mean_level_g;
mean_point_y{fit_line_idx} = mean_std_g;
mean_point_marker{fit_line_idx} = markerStyle;
fit_line_x{fit_line_idx} = fit_x_g;
fit_line_y{fit_line_idx} = fit_y_g;
fit_line_color{fit_line_idx} = sir_group_cols(sirGroupIdx,:);
fit_line_label{fit_line_idx} = sprintf('%s, PAM %.0f', sir_group_labels{sirGroupIdx}, pamLevel);
fit_text_x(fit_line_idx) = label_x_g;
fit_text_y(fit_line_idx) = label_y_g;
fit_text_label{fit_line_idx} = sprintf(' m=%s', slope_text_g);
end
end
for lineIdx = 1:fit_line_idx
plot(mean_point_x{lineIdx}, mean_point_y{lineIdx}, ...
'LineStyle', 'none', ...
'Color', fit_line_color{lineIdx}, ...
'Marker', 'x', ...
'MarkerFaceColor', fit_line_color{lineIdx}, ...
'MarkerEdgeColor', fit_line_color{lineIdx}, ...
'HandleVisibility', 'off', ...
'MarkerSize', 3);
plot(fit_line_x{lineIdx}, fit_line_y{lineIdx}, '-', ...
'Color', fit_line_color{lineIdx}, ...
'LineWidth', 0.8, ...
'DisplayName', fit_line_label{lineIdx});
text(fit_text_x(lineIdx), fit_text_y(lineIdx), fit_text_label{lineIdx}, ...
'Color', fit_line_color{lineIdx}, ...
'FontSize', 8, ...
'VerticalAlignment', 'middle', ...
'HorizontalAlignment', 'left', ...
'Interpreter', 'none');
end
grid on;
xlabel('Mean raw level');
ylabel('Stored level std');
title(sprintf('Mean level-std curves at %.0f m path length, grouped by SIR and PAM level', path_length_filter));
legend('Location','eastoutside');
slope_annotation_lines = slope_annotation_lines(1:slope_annotation_idx);
%% Plot 2: slope vs interference path length
figure; hold on;
valid = dataTable.interference_path_length > 0;
scatter(dataTable.interference_path_length(valid), dataTable.var_slope_calc(valid), ...
45, dataTable.sir(valid), 'filled');
grid on;
xlabel('Interference path length / m');
ylabel('Slope of level variance');
title('Level-variance slope vs. interference path length');
cb = colorbar;
ylabel(cb, 'SIR / dB');
%% Plot 3:
figure; hold on;
valid = dataTable.interference_path_length > 50;
sir_group_edges = [-inf,20, 30, inf];
for sirGroupIdx = 1:numel(sir_group_edges)-1
idx_sir_group = validSlopeSir ...
& dataTable.sir > sir_group_edges(sirGroupIdx) ...
& dataTable.sir < sir_group_edges(sirGroupIdx+1)...
& dataTable.interference_path_length > 50;
scatter(dataTable.sir(idx_sir_group), ...
dataTable.var_slope_calc(idx_sir_group), ...
8, 'filled', ...
'MarkerFaceColor', sir_group_cols(sirGroupIdx,:), ...
'MarkerEdgeColor', sir_group_cols(sirGroupIdx,:), ...
'MarkerFaceAlpha', 1, ...
'MarkerEdgeAlpha', 1, ...
'HandleVisibility','off');
end
set(gca, 'YScale', 'log');
grid on;
xlabel('SIR');
ylabel('Slope of level variance');
%% Plot 4:
sir_filter_max_slope = 60;
validSlopeSir = isfinite(dataTable.interference_path_length) ...
& isfinite(dataTable.var_slope_calc) ...
& isfinite(dataTable.sir) ...
& dataTable.sir < sir_filter_max_slope ...
& dataTable.interference_path_length > 0 ...
& dataTable.var_slope_calc > 0;
path_lengths_slope = unique(dataTable.interference_path_length(validSlopeSir));
sir_group_edges = [-inf,20, 30, inf];
sir_group_labels = {'SIR < 20 dB','20 < SIR < 30 dB', sprintf('30 < SIR < %.0f dB', sir_filter_max_slope)};
tmp_cols = cbrewer2('RdBu', numel(sir_group_labels)+4);
% remove 4 colors from the middle to avoid the bright central colors
mid = ceil(size(tmp_cols,1)/2);
rm_idx = mid + (-1:2); % two before mid and two after (2x2 removal centered)
rm_idx = max(1,min(size(tmp_cols,1),rm_idx));
tmp_cols(rm_idx,:) = [];
sir_group_cols = tmp_cols(1:numel(sir_group_labels),:);
figure(6);clf; hold on;
% Plot raw values first. Use one single-color scatter object per SIR group
% so matlab2tikz does not need unsupported RGB scatter CData.
for sirGroupIdx = 1:numel(sir_group_labels)
idx_sir_group = validSlopeSir ...
& dataTable.sir > sir_group_edges(sirGroupIdx) ...
& dataTable.sir < sir_group_edges(sirGroupIdx+1);
scatter(dataTable.interference_path_length(idx_sir_group), ...
dataTable.var_slope_calc(idx_sir_group), ...
8, 'filled', ...
'MarkerFaceColor', sir_group_cols(sirGroupIdx,:), ...
'MarkerEdgeColor', sir_group_cols(sirGroupIdx,:), ...
'MarkerFaceAlpha', 0.35, ...
'MarkerEdgeAlpha', 0.35, ...
'HandleVisibility','off');
end
% Plot grouped averages on top of the raw points.
for sirGroupIdx = 1:numel(sir_group_labels)
idx_sir_group = validSlopeSir ...
& dataTable.sir > sir_group_edges(sirGroupIdx) ...
& dataTable.sir < sir_group_edges(sirGroupIdx+1);
mean_slope = nan(numel(path_lengths_slope),1);
for g = 1:numel(path_lengths_slope)
idx_g = idx_sir_group ...
& dataTable.interference_path_length == path_lengths_slope(g);
slope_g = dataTable.var_slope_calc(idx_g);
slope_g = slope_g(isfinite(slope_g));
if numel(slope_g) >= 3
slope_g = slope_g(~isoutlier(slope_g, 'median'));
end
mean_slope(g) = mean(slope_g, 'omitnan');
end
valid_mean_slope = isfinite(mean_slope) & mean_slope > 0;
plot(path_lengths_slope(valid_mean_slope), mean_slope(valid_mean_slope), ...
'-o', ...
'Color', sir_group_cols(sirGroupIdx,:), ...
'MarkerFaceColor', sir_group_cols(sirGroupIdx,:), ...
'MarkerEdgeColor', sir_group_cols(sirGroupIdx,:), ...
'LineWidth', 1, ...
'DisplayName', sir_group_labels{sirGroupIdx});
end
xlim([10,1000])
ylim([0.006,0.1])
set(gca, 'XScale', 'log');
set(gca, 'YScale', 'log');
grid on;
xlabel('Interference path length / m');
ylabel('Mean slope of level variance');
title(sprintf('Grouped level-variance slope vs. interference path length, SIR < %.0f dB', sir_filter_max_slope));
xticks(path_lengths_slope);
xticklabels(compose('%.0f', path_lengths_slope));
legend('Location','northwest');
beautifyBERplot("setcolors",false)
% mat2tikz_improved('C:/Users/Silas/Documents/6971e0b65b380ca6d71c837f/04_Experimental_Evaluation/tikz/mpi/interference_path_len_vs_slope_logdomain.tikz');
%% Optional: slope vs SIR sanity check
figure; hold on;
sir_cmap = cbrewer2('RdBu',256);
validSlopeCategory = isfinite(dataTable.interference_path_length) ...
& isfinite(dataTable.std_slope_calc) ...
& isfinite(dataTable.sir);
path_lengths_plot = unique(dataTable.interference_path_length(validSlopeCategory));
sir_values_plot = dataTable.sir(validSlopeCategory);
if isempty(sir_values_plot)
sir_limits = [0, 1];
else
sir_limits = [min(sir_values_plot), max(sir_values_plot)];
end
if diff(sir_limits) == 0
sir_limits = sir_limits + [-0.5, 0.5];
end
colormap(sir_cmap);
caxis(sir_limits);
has_symbolrate = ismember('symbolrate', dataTable.Properties.VariableNames);
for g = 1:numel(path_lengths_plot)
idx_g = validSlopeCategory ...
& dataTable.interference_path_length == path_lengths_plot(g);
n_g = sum(idx_g);
sir_g = dataTable.sir(idx_g);
slope_g = dataTable.var_slope_calc(idx_g);
run_id_g = dataTable.run_id(idx_g);
pam_level_g = dataTable.pam_level(idx_g);
if has_symbolrate
symbolrate_g = dataTable.symbolrate(idx_g);
else
symbolrate_g = nan(n_g,1);
end
if n_g == 1 || range(sir_g) == 0
x_g = g * ones(n_g,1);
else
x_g = g + 0.9 * ((sir_g - min(sir_g)) ./ range(sir_g) - 0.5);
end
hScatter = scatter(x_g, slope_g, ...
5, sir_g, 'filled', ...
'DisplayName', sprintf('%.0f m', path_lengths_plot(g)));
hScatter.DataTipTemplate.DataTipRows(1).Label = 'interference path category';
hScatter.DataTipTemplate.DataTipRows(2).Label = 'slope';
hScatter.DataTipTemplate.DataTipRows(3).Label = 'SIR';
hScatter.DataTipTemplate.DataTipRows(end+1) = dataTipTextRow('run id', run_id_g);
hScatter.DataTipTemplate.DataTipRows(end+1) = dataTipTextRow('PAM format', pam_level_g);
hScatter.DataTipTemplate.DataTipRows(end+1) = dataTipTextRow('symbol rate', symbolrate_g);
end
grid on;
xlabel('Interference path length / m');
ylabel('Slope of level variance');
title('Level-variance slope grouped by interference path length');
xticks(1:numel(path_lengths_plot));
xticklabels(compose('%.0f', path_lengths_plot));
cb = colorbar;
ylabel(cb, 'SIR / dB');
%% Optional: 3D slope vs SIR by interference path length
figure(7);clf; hold on;
sir_cmap_3d = cbrewer2('RdBu',256);
validSlope3D = isfinite(dataTable.interference_path_length) ...
& isfinite(dataTable.var_slope_calc) ...
& isfinite(dataTable.sir);
path_lengths_3d = unique(dataTable.interference_path_length(validSlope3D));
path_categories_3d = 0:numel(path_lengths_3d)-1;
sir_values_3d = dataTable.sir(validSlope3D);
if isempty(sir_values_3d)
sir_limits_3d = [0, 1];
else
sir_limits_3d = [min(sir_values_3d), max(sir_values_3d)];
end
if diff(sir_limits_3d) == 0
sir_limits_3d = sir_limits_3d + [-0.5, 0.5];
end
colormap(gca, sir_cmap_3d);
clim(sir_limits_3d);
has_symbolrate = ismember('symbolrate', dataTable.Properties.VariableNames);
for g = 1:numel(path_lengths_3d)
idx_g = validSlope3D ...
& dataTable.interference_path_length == path_lengths_3d(g);
n_g = sum(idx_g);
sir_g = dataTable.sir(idx_g);
slope_g = dataTable.var_slope_calc(idx_g);
path_length_g = dataTable.interference_path_length(idx_g);
run_id_g = dataTable.run_id(idx_g);
pam_level_g = dataTable.pam_level(idx_g);
if has_symbolrate
symbolrate_g = dataTable.symbolrate(idx_g);
else
symbolrate_g = nan(n_g,1);
end
path_category_g = path_categories_3d(g) * ones(n_g,1);
hScatter = scatter3(path_category_g, sir_g, slope_g, ...
8, sir_g, 'filled', ...
'DisplayName', sprintf('%.0f m', path_lengths_3d(g)));
hScatter.DataTipTemplate.DataTipRows(1).Label = 'interference path category';
hScatter.DataTipTemplate.DataTipRows(2).Label = 'SIR';
hScatter.DataTipTemplate.DataTipRows(3).Label = 'slope';
hScatter.DataTipTemplate.DataTipRows(end+1) = dataTipTextRow('interference path length', path_length_g);
hScatter.DataTipTemplate.DataTipRows(end+1) = dataTipTextRow('run id', run_id_g);
hScatter.DataTipTemplate.DataTipRows(end+1) = dataTipTextRow('PAM format', pam_level_g);
hScatter.DataTipTemplate.DataTipRows(end+1) = dataTipTextRow('symbol rate', symbolrate_g);
end
set(gca, 'XScale', 'lin');
set(gca, 'YScale', 'lin');
set(gca, 'ZScale', 'log');
grid on;
box on;
xlabel('Interference path length / m');
ylabel('SIR / dB');
zlabel('Slope');
title('Level-variance slope vs. SIR by interference path length');
xticks(path_categories_3d);
xticklabels(compose('%.0f', path_lengths_3d));
view([-35 20]);
cb = colorbar;
ylabel(cb, 'SIR / dB');
%%
sir_all = -7 - dataTable.power_mpi_interference;
% for i = 1:height(dataTable)
% sigma_all(i,:) = jsondecode(char(dataTable.std_rawlevels(i)))';
% end
slope_var = dataTable.var_slope_calc;
slope_std = dataTable.std_slope_calc;
pl = dataTable.interference_path_length;
col = cbrewer2('RdBu',256);
% map path lengths to colormap indices
pl_unique = unique(pl(isfinite(pl)));
if isempty(pl_unique)
pl_idx = ones(size(pl));
else
% normalize pl to [1, size(col,1)]
pl_norm = (pl - min(pl_unique)) ./ max(1, (max(pl_unique)-min(pl_unique)));
pl_idx = round(1 + pl_norm * (size(col,1)-1));
pl_idx(~isfinite(pl_idx)) = 1;
end
figure(); hold on;
% scatter slope_var colored by path length
for i = 1:numel(sir_all)
scatter(sir_all(i), slope_var(i), 30, col(pl_idx(i),:), '.', 'MarkerEdgeColor', col(pl_idx(i),:));
end
% scatter slope_std colored by path length with different marker edge brightness
for i = 1:numel(sir_all)
scatter(sir_all(i), slope_std(i), 30, col(pl_idx(i),:), '.', 'MarkerEdgeColor', col(pl_idx(i),:));
end
cb = colorbar;
colormap(col);
caxis([min(pl_unique), max(pl_unique)]);
ylabel(cb, 'Interference path length / m');
function valid = hasStoredLevelStats(dataTable)
valid = ~cellfun(@isempty, cellstr(string(dataTable.std_rawlevels))) & ...
~cellfun(@isempty, cellstr(string(dataTable.mean_rawlevels)));
end
function [stdLevels, meanLevels] = decodeStoredLevelStats(dataTable)
nRuns = height(dataTable);
numLevels = 0;
stdCells = cell(nRuns, 1);
meanCells = cell(nRuns, 1);
for i = 1:nRuns
std_i = jsondecode(char(dataTable.std_rawlevels(i)));
mean_i = jsondecode(char(dataTable.mean_rawlevels(i)));
std_i = std_i(:);
mean_i = mean_i(:);
valid_i = isfinite(std_i) & isfinite(mean_i);
std_i = std_i(valid_i);
mean_i = mean_i(valid_i);
[mean_i, idx] = sort(mean_i, 'ascend');
std_i = std_i(idx);
stdCells{i} = std_i;
meanCells{i} = mean_i;
numLevels = max(numLevels, numel(std_i));
end
stdLevels = nan(numLevels, nRuns);
meanLevels = nan(numLevels, nRuns);
for i = 1:nRuns
std_i = stdCells{i};
mean_i = meanCells{i};
stdLevels(1:numel(std_i), i) = std_i;
meanLevels(1:numel(mean_i), i) = mean_i;
end
end