random agent placement in parametric testing
This commit is contained in:
@@ -15,8 +15,8 @@ classdef miSim
|
|||||||
partitioning = NaN;
|
partitioning = NaN;
|
||||||
perf; % sensor performance timeseries array
|
perf; % sensor performance timeseries array
|
||||||
performance = 0; % simulation performance timeseries vector
|
performance = 0; % simulation performance timeseries vector
|
||||||
barrierGain = 100; % CBF gain parameter
|
barrierGain = NaN; % CBF gain parameter
|
||||||
barrierExponent = 3; % CBF exponent parameter
|
barrierExponent = NaN; % CBF exponent parameter
|
||||||
artifactName = "";
|
artifactName = "";
|
||||||
fPerf; % performance plot figure
|
fPerf; % performance plot figure
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -11,13 +11,20 @@ function obj = teardown(obj)
|
|||||||
close(obj.fPerf);
|
close(obj.fPerf);
|
||||||
close(obj.f);
|
close(obj.f);
|
||||||
|
|
||||||
% Reset accumulators
|
% reset parameters
|
||||||
|
obj.timestep = NaN;
|
||||||
|
obj.timestepIndex = NaN;
|
||||||
|
obj.maxIter = NaN;
|
||||||
|
obj.domain = rectangularPrism;
|
||||||
|
obj.objective = sensingObjective;
|
||||||
|
obj.obstacles = cell(0, 1);
|
||||||
|
obj.agents = cell(0, 1);
|
||||||
|
obj.adjacency = NaN;
|
||||||
|
obj.constraintAdjacencyMatrix = NaN;
|
||||||
|
obj.partitioning = NaN;
|
||||||
obj.performance = 0;
|
obj.performance = 0;
|
||||||
|
obj.barrierGain = NaN;
|
||||||
% Reset agents
|
obj.barrierExponent = NaN;
|
||||||
for ii = 1:size(obj.agents, 1)
|
obj.artifactName = "";
|
||||||
obj.agents{ii} = agent;
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
end
|
end
|
||||||
@@ -14,8 +14,7 @@ function obj = initialize(obj, objectiveFunction, domain, discretizationStep, pr
|
|||||||
obj.discretizationStep = discretizationStep;
|
obj.discretizationStep = discretizationStep;
|
||||||
|
|
||||||
obj.sensorPerformanceMinimum = sensorPerformanceMinimum;
|
obj.sensorPerformanceMinimum = sensorPerformanceMinimum;
|
||||||
|
|
||||||
obj.groundAlt = domain.minCorner(3);
|
|
||||||
obj.protectedRange = protectedRange;
|
obj.protectedRange = protectedRange;
|
||||||
|
|
||||||
% Extract footprint limits
|
% Extract footprint limits
|
||||||
|
|||||||
@@ -14,13 +14,13 @@ function f = plot(obj, ind, f)
|
|||||||
% Plot gradient on the "floor" of the domain
|
% Plot gradient on the "floor" of the domain
|
||||||
if isnan(ind)
|
if isnan(ind)
|
||||||
hold(f.CurrentAxes, "on");
|
hold(f.CurrentAxes, "on");
|
||||||
o = surf(f.CurrentAxes, obj.X, obj.Y, repmat(obj.groundAlt, size(obj.X)), obj.values ./ max(obj.values, [], "all"), 'EdgeColor', 'none');
|
o = surf(f.CurrentAxes, obj.X, obj.Y, zeros(size(obj.X)), obj.values ./ max(obj.values, [], "all"), 'EdgeColor', 'none');
|
||||||
o.HitTest = 'off';
|
o.HitTest = 'off';
|
||||||
o.PickableParts = 'none';
|
o.PickableParts = 'none';
|
||||||
hold(f.CurrentAxes, "off");
|
hold(f.CurrentAxes, "off");
|
||||||
else
|
else
|
||||||
hold(f.Children(1).Children(ind(1)), "on");
|
hold(f.Children(1).Children(ind(1)), "on");
|
||||||
o = surf(f.Children(1).Children(ind(1)), obj.X, obj.Y, repmat(obj.groundAlt, size(obj.X)), obj.values ./ max(obj.values, [], "all"), 'EdgeColor', 'none');
|
o = surf(f.Children(1).Children(ind(1)), obj.X, obj.Y, zeros(size(obj.X)), obj.values ./ max(obj.values, [], "all"), 'EdgeColor', 'none');
|
||||||
o.HitTest = 'off';
|
o.HitTest = 'off';
|
||||||
o.PickableParts = 'none';
|
o.PickableParts = 'none';
|
||||||
hold(f.Children(1).Children(ind(1)), "off");
|
hold(f.Children(1).Children(ind(1)), "off");
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ classdef sensingObjective
|
|||||||
% Sensing objective definition parent class
|
% Sensing objective definition parent class
|
||||||
properties (SetAccess = private, GetAccess = public)
|
properties (SetAccess = private, GetAccess = public)
|
||||||
label = "";
|
label = "";
|
||||||
groundAlt = NaN;
|
|
||||||
groundPos = [NaN, NaN];
|
groundPos = [NaN, NaN];
|
||||||
discretizationStep = NaN;
|
discretizationStep = NaN;
|
||||||
objectiveFunction = @(x, y) NaN; % define objective functions over a grid in this manner
|
objectiveFunction = @(x, y) NaN; % define objective functions over a grid in this manner
|
||||||
|
|||||||
@@ -5,6 +5,9 @@ classdef parametricTestSuite < matlab.unittest.TestCase
|
|||||||
domain = rectangularPrism;
|
domain = rectangularPrism;
|
||||||
obstacles = cell(1, 0);
|
obstacles = cell(1, 0);
|
||||||
|
|
||||||
|
% RNG control
|
||||||
|
seed = 1234567890;
|
||||||
|
|
||||||
%% Diagnostic Parameters
|
%% Diagnostic Parameters
|
||||||
% No effect on simulation dynamics
|
% No effect on simulation dynamics
|
||||||
makeVideo = true; % disable video writing for big performance increase
|
makeVideo = true; % disable video writing for big performance increase
|
||||||
@@ -16,6 +19,13 @@ classdef parametricTestSuite < matlab.unittest.TestCase
|
|||||||
csvPath = fullfile(matlab.project.rootProject().RootFolder, 'test', 'testIterations.csv');
|
csvPath = fullfile(matlab.project.rootProject().RootFolder, 'test', 'testIterations.csv');
|
||||||
end
|
end
|
||||||
|
|
||||||
|
methods (TestMethodSetup)
|
||||||
|
function rngSetup(tc)
|
||||||
|
% Allow for controlling the random seed for reproducibility
|
||||||
|
rng(tc.seed);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
methods (Static)
|
methods (Static)
|
||||||
function params = readIterationsCsv(csvPath)
|
function params = readIterationsCsv(csvPath)
|
||||||
arguments (Input)
|
arguments (Input)
|
||||||
@@ -30,39 +40,102 @@ classdef parametricTestSuite < matlab.unittest.TestCase
|
|||||||
assert(endsWith(csvPath, '.csv'), "%s is not a CSV file.");
|
assert(endsWith(csvPath, '.csv'), "%s is not a CSV file.");
|
||||||
|
|
||||||
% Read file
|
% Read file
|
||||||
csv = readtable(csvPath);
|
csv = readtable(csvPath, 'TextType', 'string', 'NumHeaderLines', 0, "VariableNamingRule", "Preserve");
|
||||||
|
csv.Properties.VariableNames = ["timestep", "maxIter", "minAlt", "discretizationStep", "sensorPerformanceMinimum", "initialStepSize", "barrierGain", "barrierExponent", "numAgents", "collisionRadius", "comRange", "alphaDist", "betaDist", "alphaTilt", "betaTilt"];
|
||||||
|
|
||||||
|
for ii = 1:size(csv.Properties.VariableNames, 2)
|
||||||
|
csv.(csv.Properties.VariableNames{ii}) = cell2mat(cellfun(@(x) str2num(x), csv.(csv.Properties.VariableNames{ii}), 'UniformOutput', false));
|
||||||
|
end
|
||||||
|
|
||||||
% Put params into standard structure
|
% Put params into standard structure
|
||||||
params = struct('timestep', csv.timestep, 'maxIter', csv.maxIter, 'minAlt', csv.minAlt, 'discretizationStep', csv.discretizationStep, ...
|
params = struct('timestep', csv.timestep, 'maxIter', csv.maxIter, 'minAlt', csv.minAlt, 'discretizationStep', csv.discretizationStep, ...
|
||||||
'sensorPerformanceMinimum', csv.sensorPerformanceMinimum, 'collisionRadius', csv.collisionRadius, 'alphaDist', csv.alphaDist, 'betaDist', csv.betaDist, ...
|
'sensorPerformanceMinimum', csv.sensorPerformanceMinimum, 'initialStepSize', csv.initialStepSize, 'barrierGain', csv.barrierGain, 'barrierExponent', csv.barrierExponent, ...
|
||||||
'alphaTilt', csv.alphaTilt, 'betaTilt', csv.betaTilt, 'comRange', csv.comRange, 'initialStepSize', csv.initialStepSize, 'barrierGain', csv.barrierGain, 'barrierExponent', csv.barrierExponent);
|
'numAgents', csv.numAgents, 'collisionRadius', csv.collisionRadius, 'comRange', csv.comRange, 'alphaDist', csv.alphaDist, 'betaDist', csv.betaDist, 'alphaTilt', csv.alphaTilt, 'betaTilt', csv.betaTilt);
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
methods (Test, ParameterCombination = "exhaustive")
|
methods (Test)
|
||||||
% Test cases
|
% Test cases
|
||||||
function single_agent_gradient_ascent(tc)
|
function csv_parametric_tests(tc)
|
||||||
% Read in parameters to iterate over
|
% Read in parameters to iterate over
|
||||||
params = tc.readIterationsCsv(tc.csvPath);
|
params = tc.readIterationsCsv(tc.csvPath);
|
||||||
|
|
||||||
% Test case setup
|
% Test case setup
|
||||||
l = 10;
|
l = 10; % domain size
|
||||||
sensorModel = sigmoidSensor;
|
sensorModel = sigmoidSensor;
|
||||||
agentPos = [l/4, l/4, l/4];
|
|
||||||
collisionGeometry = spherical;
|
collisionGeometry = spherical;
|
||||||
agents = {agent};
|
|
||||||
|
|
||||||
|
% Iterate over test cases defined in CSV
|
||||||
for ii = 1:size(params.timestep, 1)
|
for ii = 1:size(params.timestep, 1)
|
||||||
% Set up square domain
|
% Set up square domain
|
||||||
tc.domain = tc.domain.initialize([zeros(1, 3); l * ones(1, 3)], REGION_TYPE.DOMAIN, "Domain");
|
tc.domain = tc.domain.initialize([zeros(1, 3); l * ones(1, 3)], REGION_TYPE.DOMAIN, "Domain");
|
||||||
tc.domain.objective = tc.domain.objective.initialize(objectiveFunctionWrapper([.75 * l, 0.75 * l]), tc.domain, params.discretizationStep(ii), tc.protectedRange, params.sensorPerformanceMinimum(ii));
|
tc.domain.objective = tc.domain.objective.initialize(objectiveFunctionWrapper([.75 * l, 0.75 * l]), tc.domain, params.discretizationStep(ii), tc.protectedRange, params.sensorPerformanceMinimum(ii));
|
||||||
|
|
||||||
% Set up agent
|
% Initialize agents
|
||||||
sensorModel = sensorModel.initialize(params.alphaDist(ii), params.betaDist(ii), params.alphaTilt(ii), params.betaTilt(ii));
|
agents = cell(params.numAgents(ii), 1);
|
||||||
collisionGeometry = collisionGeometry.initialize(agentPos, params.collisionRadius(ii), REGION_TYPE.COLLISION, "Agent 1 Collision Region");
|
[agents{:}] = deal(agent);
|
||||||
agents{1} = agents{1}.initialize(agentPos, collisionGeometry, sensorModel, params.comRange(ii), params.maxIter(ii), params.initialStepSize(ii), "Agent 1", tc.plotCommsGeometry);
|
|
||||||
|
% Initialize sensor model
|
||||||
|
sensorModel = sensorModel.initialize(params.alphaDist(ii, 1), params.betaDist(ii, 1), params.alphaTilt(ii, 1), params.betaTilt(ii, 1));
|
||||||
|
|
||||||
|
% Place first agent randomly in the quadrant opposite the objective
|
||||||
|
% not too close to the domain boundaries
|
||||||
|
bounds = [params.collisionRadius(ii, 1) * ones(1, 2), max([params.collisionRadius(ii, 1), params.minAlt(ii)]); l / 2 * ones(1, 2), l - params.collisionRadius(ii, 1)];
|
||||||
|
agentPos = bounds(1, :) + (bounds(2, :) - bounds(1, :)) .* rand(1, 3);
|
||||||
|
|
||||||
|
% Keep trying new positions until the greatest possible
|
||||||
|
% sensor performance clears the threshold (meaning this
|
||||||
|
% agent has the ability to make a partition)
|
||||||
|
while sensorModel.sensorPerformance(agentPos, [agentPos(1:2), 0]) < params.sensorPerformanceMinimum(ii)
|
||||||
|
agentPos = bounds(1, :) + (bounds(2, :) - bounds(1, :)) .* rand(1, 3);
|
||||||
|
end
|
||||||
|
|
||||||
|
% Initialize agent
|
||||||
|
collisionGeometry = collisionGeometry.initialize(agentPos, params.collisionRadius(ii, 1), REGION_TYPE.COLLISION, "Agent 1 Collision Region");
|
||||||
|
agents{1} = agents{1}.initialize(agentPos, collisionGeometry, sensorModel, params.comRange(ii, 1), params.maxIter(ii), params.initialStepSize(ii), "Agent 1", tc.plotCommsGeometry);
|
||||||
|
|
||||||
|
% Set up remaining agents in random (valid) locations
|
||||||
|
for jj = 2:size(agents, 1)
|
||||||
|
% Initialize sensor model
|
||||||
|
sensorModel = sensorModel.initialize(params.alphaDist(ii, jj), params.betaDist(ii, jj), params.alphaTilt(ii, jj), params.betaTilt(ii, jj));
|
||||||
|
|
||||||
|
% Base next agent's location on random previous agent's location
|
||||||
|
baseAgentIdx = randi(jj - 1);
|
||||||
|
retry = true;
|
||||||
|
while retry
|
||||||
|
agentPos = agents{baseAgentIdx}.commsGeometry.random();
|
||||||
|
|
||||||
|
% Check that the agent's greatest sensor
|
||||||
|
% performance clears the threshold for partitioning
|
||||||
|
if sensorModel.sensorPerformance(agentPos, [agentPos(1:2), 0]) < params.sensorPerformanceMinimum(ii)
|
||||||
|
retry = true;
|
||||||
|
continue;
|
||||||
|
end
|
||||||
|
|
||||||
|
% Check that candidate position is well inside the domain
|
||||||
|
bounds = [params.collisionRadius(ii, jj) * ones(1, 2), max([params.collisionRadius(ii, jj), params.minAlt(ii)]); l / 2 * ones(1, 2), l - params.collisionRadius(ii, jj)];
|
||||||
|
if ~isequal(agentPos < bounds, [false, false, false; true, true, true])
|
||||||
|
retry = true;
|
||||||
|
continue;
|
||||||
|
end
|
||||||
|
|
||||||
|
% Check that candidate position does not collide with existing agents
|
||||||
|
for kk = 1:(jj - 1)
|
||||||
|
if norm(agents{kk}.pos - agentPos, 2) < agents{kk}.collisionGeometry.radius + params.collisionRadius(ii, jj)
|
||||||
|
retry = true;
|
||||||
|
continue;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
retry = false;
|
||||||
|
end
|
||||||
|
|
||||||
|
% Initialize agent
|
||||||
|
collisionGeometry = collisionGeometry.initialize(agentPos, params.collisionRadius(ii, jj), REGION_TYPE.COLLISION, sprintf("Agent %d Collision Region", jj));
|
||||||
|
agents{jj} = agents{jj}.initialize(agentPos, collisionGeometry, sensorModel, params.comRange(ii, jj), params.maxIter(ii), params.initialStepSize(ii), sprintf("Agent %d", jj), tc.plotCommsGeometry);
|
||||||
|
end
|
||||||
|
|
||||||
% Set up simulation
|
% Set up simulation
|
||||||
|
agents = agents(randperm(numel(agents))); % randomly shuffle agents to make the network more interesting (probably)
|
||||||
tc.testClass = tc.testClass.initialize(tc.domain, agents, params.barrierGain(ii), params.barrierExponent(ii), params.minAlt(ii), params.timestep(ii), params.maxIter(ii), tc.obstacles, tc.makePlots, tc.makeVideo);
|
tc.testClass = tc.testClass.initialize(tc.domain, agents, params.barrierGain(ii), params.barrierExponent(ii), params.minAlt(ii), params.timestep(ii), params.maxIter(ii), tc.obstacles, tc.makePlots, tc.makeVideo);
|
||||||
|
|
||||||
% Save simulation parameters to output file
|
% Save simulation parameters to output file
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
timestep, maxIter, minAlt, barrierGain, barrierExponent, sensorPerformanceMinimum, discretizationStep, collisionRadius, initialStepSize, alphaDist, betaDist, alphaTilt, betaTilt, comRange
|
timestep, maxIter, minAlt, discretizationStep, sensorPerformanceMinimum, initialStepSize, barrierGain, barrierExponent, numAgents, collisionRadius, comRange, alphaDist, betaDist, alphaTilt, betaTilt
|
||||||
1, 25, 1, 100, 3, 1e-6, 0.01, 0.1, 0.2, 2.5, 3, 15, 3, 3
|
1, 10, 1, 0.01, 1e-6, 0.2, 100, 3, 5, "0.1, 0.1, 0.1, 0.1, 0.1", "2.5, 2.5, 2.5, 2.5, 2.5", "3, 3, 3, 3, 3", "15, 15, 15, 15, 15", "3, 3, 3, 3, 3", "3, 3, 3, 3, 3"
|
||||||
1, 25, 1, 100, 3, 1e-6, 0.01, 0.1, 0.2, 5, 15, 30, 15, 3
|
1, 10, 1, 0.01, 1e-6, 0.2, 100, 3, 5, "0.1, 0.1, 0.1, 0.1, 0.1", "3.5, 3.5, 3.5, 3.5, 3.5", "15, 15, 15, 15, 15", "30, 30, 30, 30, 30", "15, 15, 15, 15, 15", "3, 3, 3, 3, 3"
|
||||||
|
|||||||
|
Reference in New Issue
Block a user