175 lines
5.4 KiB
Matlab
175 lines
5.4 KiB
Matlab
clear;
|
|
|
|
%% Load data
|
|
dataPath = fullfile('.', 'sandbox', 'plot1');
|
|
dataFiles = dir(dataPath);
|
|
dataFiles = dataFiles(~startsWith({dataFiles.name}, '.'));
|
|
simInits = dataFiles(endsWith({dataFiles.name}, 'miSimInits.mat'));
|
|
simHists = dataFiles(endsWith({dataFiles.name}, 'miSimHist.mat'));
|
|
assert(length(simHists) == length(simInits), "input data availability mismatch");
|
|
|
|
%% Aggregate run data
|
|
nRuns = length(simHists);
|
|
Cfinal = NaN(nRuns, 1);
|
|
nAgents = NaN(nRuns, 1);
|
|
doubleIntegrator = NaN(nRuns, 1);
|
|
numObjective = NaN(nRuns, 1);
|
|
commsRadius = NaN(nRuns, 1);
|
|
collisionRadius = NaN(nRuns, 1);
|
|
maxAgents = 6;
|
|
alphaDist = NaN(maxAgents, nRuns);
|
|
positions = cell(maxAgents, nRuns);
|
|
adjacency = cell(nRuns, 1);
|
|
|
|
for ii = 1:nRuns
|
|
initName = strrep(simInits(ii).name, "_miSimInits.mat", "");
|
|
histName = strrep(simHists(ii).name, "_miSimHist.mat", "");
|
|
assert(initName == histName);
|
|
|
|
init = load(fullfile(simInits(ii).folder, simInits(ii).name));
|
|
hist = load(fullfile(simHists(ii).folder, simHists(ii).name));
|
|
|
|
Cfinal(ii) = hist.out.perf(end) / init.objectiveIntegral;
|
|
nAgents(ii) = init.numAgents;
|
|
doubleIntegrator(ii) = init.useDoubleIntegrator;
|
|
numObjective(ii) = size(init.objectivePos, 1);
|
|
commsRadius(ii) = unique(init.comRange);
|
|
collisionRadius(ii) = unique(init.collisionRadius);
|
|
|
|
adjacency{ii} = hist.out.constraintAdjacency(:, :, 1);
|
|
for jj = 1:nAgents(ii)
|
|
alphaDist(jj, ii) = hist.out.agent(jj).sensor.alphaDist;
|
|
positions{jj, ii} = hist.out.agent(jj).pos;
|
|
assert(hist.out.agent(jj).commsRadius == commsRadius(ii));
|
|
assert(hist.out.agent(jj).collisionRadius == collisionRadius(ii));
|
|
end
|
|
end
|
|
|
|
commsRadius = unique(commsRadius); assert(isscalar(commsRadius));
|
|
collisionRadius = unique(collisionRadius); assert(isscalar(collisionRadius));
|
|
sensorTypes = flip(unique(alphaDist(1, :)));
|
|
nValues = sort(unique(nAgents));
|
|
nGroups = length(nValues);
|
|
|
|
%% Build config labels
|
|
baseConfig = strings(nRuns, 1);
|
|
for ii = 1:nRuns
|
|
s = "";
|
|
if numObjective(ii) == 1
|
|
s = s + "A";
|
|
elseif numObjective(ii) == 2
|
|
s = s + "B";
|
|
end
|
|
if alphaDist(1, ii) == sensorTypes(1)
|
|
s = s + "_I";
|
|
elseif alphaDist(1, ii) == sensorTypes(2)
|
|
s = s + "_II";
|
|
end
|
|
if ~doubleIntegrator(ii)
|
|
s = s + "_alpha";
|
|
else
|
|
s = s + "_beta";
|
|
end
|
|
baseConfig(ii) = s;
|
|
end
|
|
configOrder = unique(baseConfig(nAgents == nValues(1)), 'stable');
|
|
nConfigs = length(configOrder);
|
|
configLabels = ["$AI\alpha$"; "$AI\beta$"; "$AII\alpha$"; "$BI\beta$"];
|
|
|
|
%% Plot 1: Final normalized coverage
|
|
close all;
|
|
f1 = figure;
|
|
x1 = axes;
|
|
|
|
C_mean = NaN(nGroups, nConfigs);
|
|
C_var = NaN(nGroups, nConfigs);
|
|
for ii = 1:nGroups
|
|
for jj = 1:nConfigs
|
|
mask = (nAgents == nValues(ii)) & (baseConfig == configOrder(jj));
|
|
C_mean(ii, jj) = mean(Cfinal(mask));
|
|
C_var(ii, jj) = var(Cfinal(mask));
|
|
end
|
|
end
|
|
|
|
bar(x1, C_mean);
|
|
set(x1, 'XTickLabel', string(nValues));
|
|
xlabel(x1, "Number of agents");
|
|
ylabel(x1, "Final coverage (normalized)");
|
|
title(x1, "Final performance of parameterizations");
|
|
legend(x1, configLabels, "Interpreter", "latex", "Location", "northwest");
|
|
grid(x1, "on");
|
|
ylim(x1, [0, 1/2]);
|
|
|
|
savefig(f1, "plot1.fig");
|
|
exportgraphics(f1, "plot1.png");
|
|
|
|
%% Plot 2: Pairwise agent distances
|
|
f2 = figure;
|
|
x2 = axes;
|
|
|
|
% Compute pairwise distances only for connected agents (static topology)
|
|
maxPairs = nchoosek(maxAgents, 2);
|
|
pairDist = cell(maxPairs, nRuns);
|
|
for ii = 1:nRuns
|
|
A = adjacency{ii};
|
|
pp = 0;
|
|
for jj = 1:nAgents(ii)-1
|
|
for kk = jj+1:nAgents(ii)
|
|
pp = pp + 1;
|
|
if A(jj, kk)
|
|
pairDist{pp, ii} = vecnorm(positions{jj, ii} - positions{kk, ii}, 2, 2);
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
% Per-run statistics across all pairs and timesteps
|
|
meanPairDist = NaN(nRuns, 1);
|
|
minPairDist = NaN(nRuns, 1);
|
|
maxPairDist = NaN(nRuns, 1);
|
|
for ii = 1:nRuns
|
|
nPairs = nchoosek(nAgents(ii), 2);
|
|
D = vertcat(pairDist{1:nPairs, ii});
|
|
meanPairDist(ii) = mean(D, "omitmissing");
|
|
minPairDist(ii) = min(D);
|
|
maxPairDist(ii) = max(D);
|
|
end
|
|
|
|
% Aggregate across trials per (n, config) group
|
|
meanD = NaN(nGroups, nConfigs);
|
|
minD = NaN(nGroups, nConfigs);
|
|
maxD = NaN(nGroups, nConfigs);
|
|
for ii = 1:nGroups
|
|
for jj = 1:nConfigs
|
|
mask = (nAgents == nValues(ii)) & (baseConfig == configOrder(jj));
|
|
meanD(ii, jj) = mean(meanPairDist(mask));
|
|
minD(ii, jj) = min(minPairDist(mask));
|
|
maxD(ii, jj) = max(maxPairDist(mask));
|
|
end
|
|
end
|
|
|
|
% Plot whiskers (min to max) with mean markers
|
|
barWidth = 0.8;
|
|
groupWidth = barWidth / nConfigs;
|
|
hold(x2, 'on');
|
|
for jj = 1:nConfigs
|
|
xPos = (1:nGroups) + (jj - (nConfigs + 1) / 2) * groupWidth;
|
|
errorbar(x2, xPos, meanD(:, jj), meanD(:, jj) - minD(:, jj), maxD(:, jj) - meanD(:, jj), ...
|
|
'o', 'LineWidth', 1.5, 'MarkerSize', 6, 'CapSize', 10);
|
|
end
|
|
hold(x2, 'off');
|
|
set(x2, 'XTick', 1:nGroups, 'XTickLabel', string(nValues));
|
|
xlabel(x2, "Number of agents");
|
|
ylabel(x2, "Pairwise distance");
|
|
title(x2, "Pairwise Agent Distances (min/mean/max)");
|
|
legend(x2, configLabels, "Interpreter", "latex");
|
|
grid(x2, "on");
|
|
yline(x2, collisionRadius, 'r--', "Label", "Collision Radius", ...
|
|
"LabelHorizontalAlignment", "left", "HandleVisibility", "off");
|
|
yline(x2, commsRadius, 'r--', "Label", "Communications Radius", ...
|
|
"LabelHorizontalAlignment", "left", "HandleVisibility", "off");
|
|
ylim(x2, [0, commsRadius + 5]);
|
|
|
|
savefig(f2, "plot2.fig");
|
|
exportgraphics(f2, "plot2.png");
|