partitioning introduced to main loop
This commit is contained in:
7
agent.m
7
agent.m
@@ -58,18 +58,19 @@ classdef agent
|
|||||||
obj.index = index;
|
obj.index = index;
|
||||||
obj.label = label;
|
obj.label = label;
|
||||||
end
|
end
|
||||||
function obj = run(obj, objectiveFunction, domain)
|
function obj = run(obj, sensingObjective, domain, partitioning)
|
||||||
arguments (Input)
|
arguments (Input)
|
||||||
obj (1, 1) {mustBeA(obj, 'agent')};
|
obj (1, 1) {mustBeA(obj, 'agent')};
|
||||||
objectiveFunction (1, 1) {mustBeA(objectiveFunction, 'function_handle')};
|
sensingObjective (1, 1) {mustBeA(sensingObjective, 'sensingObjective')};
|
||||||
domain (1, 1) {mustBeGeometry};
|
domain (1, 1) {mustBeGeometry};
|
||||||
|
partitioning (:, :) double;
|
||||||
end
|
end
|
||||||
arguments (Output)
|
arguments (Output)
|
||||||
obj (1, 1) {mustBeA(obj, 'agent')};
|
obj (1, 1) {mustBeA(obj, 'agent')};
|
||||||
end
|
end
|
||||||
|
|
||||||
% Do sensing
|
% Do sensing
|
||||||
[sensedValues, sensedPositions] = obj.sensorModel.sense(objectiveFunction, domain, obj.pos);
|
[sensedValues, sensedPositions] = obj.sensorModel.sense(obj, sensingObjective, domain, partitioning);
|
||||||
|
|
||||||
% Determine next planned position
|
% Determine next planned position
|
||||||
nextPos = obj.guidanceModel(sensedValues, sensedPositions, obj.pos);
|
nextPos = obj.guidanceModel(sensedValues, sensedPositions, obj.pos);
|
||||||
|
|||||||
@@ -1,14 +1,26 @@
|
|||||||
function nextPos = gradientAscent(sensedValues, sensedPositions, pos)
|
function nextPos = gradientAscent(sensedValues, sensedPositions, pos, rate)
|
||||||
arguments (Input)
|
arguments (Input)
|
||||||
sensedValues (:, 1) double;
|
sensedValues (:, 1) double;
|
||||||
sensedPositions (:, 3) double;
|
sensedPositions (:, 3) double;
|
||||||
pos (1, 3) double;
|
pos (1, 3) double;
|
||||||
|
rate (1, 1) double = 0.1;
|
||||||
end
|
end
|
||||||
arguments (Output)
|
arguments (Output)
|
||||||
nextPos(1, 3) double;
|
nextPos(1, 3) double;
|
||||||
end
|
end
|
||||||
|
|
||||||
|
% As a default, maintain current position
|
||||||
|
if size(sensedValues, 1) == 0 && size(sensedPositions, 1) == 0
|
||||||
|
nextPos = pos;
|
||||||
|
return;
|
||||||
|
end
|
||||||
|
|
||||||
% Select next position by maximum sensed value
|
% Select next position by maximum sensed value
|
||||||
nextPos = sensedPositions(sensedValues == max(sensedValues), :);
|
nextPos = sensedPositions(sensedValues == max(sensedValues), :);
|
||||||
nextPos = [nextPos(1, 1:2), pos(3)]; % just in case two get selected, simply pick one
|
nextPos = [nextPos(1, 1:2), pos(3)]; % just in case two get selected, simply pick one
|
||||||
|
|
||||||
|
% rate-limit motion
|
||||||
|
v = nextPos - pos;
|
||||||
|
nextPos = pos + (v / norm(v, 2)) * rate;
|
||||||
|
|
||||||
end
|
end
|
||||||
30
miSim.m
30
miSim.m
@@ -4,6 +4,7 @@ classdef miSim
|
|||||||
% Simulation parameters
|
% Simulation parameters
|
||||||
properties (SetAccess = private, GetAccess = public)
|
properties (SetAccess = private, GetAccess = public)
|
||||||
timestep = NaN; % delta time interval for simulation iterations
|
timestep = NaN; % delta time interval for simulation iterations
|
||||||
|
partitioningFreq = NaN; % number of simulation timesteps at which the partitioning routine is re-run
|
||||||
maxIter = NaN; % maximum number of simulation iterations
|
maxIter = NaN; % maximum number of simulation iterations
|
||||||
domain = rectangularPrism;
|
domain = rectangularPrism;
|
||||||
objective = sensingObjective;
|
objective = sensingObjective;
|
||||||
@@ -27,13 +28,14 @@ classdef miSim
|
|||||||
end
|
end
|
||||||
|
|
||||||
methods (Access = public)
|
methods (Access = public)
|
||||||
function [obj, f] = initialize(obj, domain, objective, agents, timestep, maxIter, obstacles)
|
function [obj, f] = initialize(obj, domain, objective, agents, timestep, partitoningFreq, maxIter, obstacles)
|
||||||
arguments (Input)
|
arguments (Input)
|
||||||
obj (1, 1) {mustBeA(obj, 'miSim')};
|
obj (1, 1) {mustBeA(obj, 'miSim')};
|
||||||
domain (1, 1) {mustBeGeometry};
|
domain (1, 1) {mustBeGeometry};
|
||||||
objective (1, 1) {mustBeA(objective, 'sensingObjective')};
|
objective (1, 1) {mustBeA(objective, 'sensingObjective')};
|
||||||
agents (:, 1) cell;
|
agents (:, 1) cell;
|
||||||
timestep (:, 1) double = 0.05;
|
timestep (:, 1) double = 0.05;
|
||||||
|
partitoningFreq (:, 1) double = 0.25
|
||||||
maxIter (:, 1) double = 1000;
|
maxIter (:, 1) double = 1000;
|
||||||
obstacles (:, 1) cell {mustBeGeometry} = cell(0, 1);
|
obstacles (:, 1) cell {mustBeGeometry} = cell(0, 1);
|
||||||
end
|
end
|
||||||
@@ -48,6 +50,7 @@ classdef miSim
|
|||||||
|
|
||||||
% Define domain
|
% Define domain
|
||||||
obj.domain = domain;
|
obj.domain = domain;
|
||||||
|
obj.partitioningFreq = partitoningFreq;
|
||||||
|
|
||||||
% Add geometries representing obstacles within the domain
|
% Add geometries representing obstacles within the domain
|
||||||
obj.obstacles = obstacles;
|
obj.obstacles = obstacles;
|
||||||
@@ -106,6 +109,7 @@ classdef miSim
|
|||||||
|
|
||||||
% Set up times to iterate over
|
% Set up times to iterate over
|
||||||
times = linspace(0, obj.timestep * obj.maxIter, obj.maxIter+1)';
|
times = linspace(0, obj.timestep * obj.maxIter, obj.maxIter+1)';
|
||||||
|
partitioningTimes = times(obj.partitioningFreq:obj.partitioningFreq:size(times, 1));
|
||||||
|
|
||||||
% Start video writer
|
% Start video writer
|
||||||
v = setupVideoWriter(obj.timestep);
|
v = setupVideoWriter(obj.timestep);
|
||||||
@@ -116,16 +120,23 @@ classdef miSim
|
|||||||
t = times(ii);
|
t = times(ii);
|
||||||
fprintf("Sim Time: %4.2f (%d/%d)\n", t, ii, obj.maxIter)
|
fprintf("Sim Time: %4.2f (%d/%d)\n", t, ii, obj.maxIter)
|
||||||
|
|
||||||
|
% Check if it's time for new partitions
|
||||||
|
updatePartitions = false;
|
||||||
|
if ismember(t, partitioningTimes)
|
||||||
|
updatePartitions = true;
|
||||||
|
obj = obj.partition();
|
||||||
|
end
|
||||||
|
|
||||||
% Iterate over agents to simulate their motion
|
% Iterate over agents to simulate their motion
|
||||||
for jj = 1:size(obj.agents, 1)
|
for jj = 1:size(obj.agents, 1)
|
||||||
obj.agents{jj} = obj.agents{jj}.run(obj.objective.objectiveFunction, obj.domain);
|
obj.agents{jj} = obj.agents{jj}.run(obj.objective, obj.domain, obj.partitioning);
|
||||||
end
|
end
|
||||||
|
|
||||||
% Update adjacency matrix
|
% Update adjacency matrix
|
||||||
obj = obj.updateAdjacency;
|
obj = obj.updateAdjacency;
|
||||||
|
|
||||||
% Update plots
|
% Update plots
|
||||||
[obj, f] = obj.updatePlots(f);
|
[obj, f] = obj.updatePlots(f, updatePartitions);
|
||||||
|
|
||||||
% Write frame in to video
|
% Write frame in to video
|
||||||
I = getframe(f);
|
I = getframe(f);
|
||||||
@@ -160,10 +171,11 @@ classdef miSim
|
|||||||
[i,j] = ndgrid(1:m, 1:n);
|
[i,j] = ndgrid(1:m, 1:n);
|
||||||
obj.partitioning = agentInds(sub2ind(size(agentInds), i, j, idx));
|
obj.partitioning = agentInds(sub2ind(size(agentInds), i, j, idx));
|
||||||
end
|
end
|
||||||
function [obj, f] = updatePlots(obj, f)
|
function [obj, f] = updatePlots(obj, f, updatePartitions)
|
||||||
arguments (Input)
|
arguments (Input)
|
||||||
obj (1, 1) {mustBeA(obj, 'miSim')};
|
obj (1, 1) {mustBeA(obj, 'miSim')};
|
||||||
f (1, 1) {mustBeA(f, 'matlab.ui.Figure')} = figure;
|
f (1, 1) {mustBeA(f, 'matlab.ui.Figure')} = figure;
|
||||||
|
updatePartitions (1, 1) logical = false;
|
||||||
end
|
end
|
||||||
arguments (Output)
|
arguments (Output)
|
||||||
obj (1, 1) {mustBeA(obj, 'miSim')};
|
obj (1, 1) {mustBeA(obj, 'miSim')};
|
||||||
@@ -181,11 +193,17 @@ classdef miSim
|
|||||||
|
|
||||||
% Update agent connections plot
|
% Update agent connections plot
|
||||||
delete(obj.connectionsPlot);
|
delete(obj.connectionsPlot);
|
||||||
[obj, f] = obj.plotConnections(f);
|
[obj, f] = obj.plotConnections(obj.spatialPlotIndices, f);
|
||||||
|
|
||||||
% Update network graph plot
|
% Update network graph plot
|
||||||
delete(obj.graphPlot);
|
delete(obj.graphPlot);
|
||||||
[obj, f] = obj.plotGraph(f);
|
[obj, f] = obj.plotGraph(obj.networkGraphIndex, f);
|
||||||
|
|
||||||
|
% Update partitioning plot
|
||||||
|
if updatePartitions
|
||||||
|
delete(obj.partitionPlot);
|
||||||
|
[obj, f] = obj.plotPartitions(obj.partitionGraphIndex, f);
|
||||||
|
end
|
||||||
|
|
||||||
drawnow;
|
drawnow;
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -15,12 +15,13 @@ classdef fixedCardinalSensor
|
|||||||
end
|
end
|
||||||
obj.r = r;
|
obj.r = r;
|
||||||
end
|
end
|
||||||
function [neighborValues, neighborPos] = sense(obj, objectiveFunction, domain, pos)
|
function [neighborValues, neighborPos] = sense(obj, agent, sensingObjective, domain, partitioning)
|
||||||
arguments (Input)
|
arguments (Input)
|
||||||
obj (1, 1) {mustBeA(obj, 'fixedCardinalSensor')};
|
obj (1, 1) {mustBeA(obj, 'fixedCardinalSensor')};
|
||||||
objectiveFunction (1, 1) {mustBeA(objectiveFunction, 'function_handle')};
|
agent (1, 1) {mustBeA(agent, 'agent')};
|
||||||
|
sensingObjective (1, 1) {mustBeA(sensingObjective, 'sensingObjective')};
|
||||||
domain (1, 1) {mustBeGeometry};
|
domain (1, 1) {mustBeGeometry};
|
||||||
pos (1, 3) double;
|
partitioning (:, :) double = NaN;
|
||||||
end
|
end
|
||||||
arguments (Output)
|
arguments (Output)
|
||||||
neighborValues (4, 1) double;
|
neighborValues (4, 1) double;
|
||||||
@@ -28,7 +29,7 @@ classdef fixedCardinalSensor
|
|||||||
end
|
end
|
||||||
|
|
||||||
% Evaluate objective at position offsets +/-[r, 0, 0] and +/-[0, r, 0]
|
% Evaluate objective at position offsets +/-[r, 0, 0] and +/-[0, r, 0]
|
||||||
currentPos = pos(1:2);
|
currentPos = agent.pos(1:2);
|
||||||
neighborPos = [currentPos(1) + obj.r, currentPos(2); ... % (+x)
|
neighborPos = [currentPos(1) + obj.r, currentPos(2); ... % (+x)
|
||||||
currentPos(1), currentPos(2) + obj.r; ... % (+y)
|
currentPos(1), currentPos(2) + obj.r; ... % (+y)
|
||||||
currentPos(1) - obj.r, currentPos(2); ... % (-x)
|
currentPos(1) - obj.r, currentPos(2); ... % (-x)
|
||||||
@@ -44,13 +45,13 @@ classdef fixedCardinalSensor
|
|||||||
end
|
end
|
||||||
|
|
||||||
% Replace out of bounds positions with inoffensive in-bounds positions
|
% Replace out of bounds positions with inoffensive in-bounds positions
|
||||||
neighborPos(outOfBounds, 1:3) = repmat(pos, sum(outOfBounds), 1);
|
neighborPos(outOfBounds, 1:3) = repmat(agent.pos, sum(outOfBounds), 1);
|
||||||
|
|
||||||
% Sense values at selected positions
|
% Sense values at selected positions
|
||||||
neighborValues = [objectiveFunction(neighborPos(1, 1), neighborPos(1, 2)), ... % (+x)
|
neighborValues = [sensingObjective.objectiveFunction(neighborPos(1, 1), neighborPos(1, 2)), ... % (+x)
|
||||||
objectiveFunction(neighborPos(2, 1), neighborPos(2, 2)), ... % (+y)
|
sensingObjective.objectiveFunction(neighborPos(2, 1), neighborPos(2, 2)), ... % (+y)
|
||||||
objectiveFunction(neighborPos(3, 1), neighborPos(3, 2)), ... % (-x)
|
sensingObjective.objectiveFunction(neighborPos(3, 1), neighborPos(3, 2)), ... % (-x)
|
||||||
objectiveFunction(neighborPos(4, 1), neighborPos(4, 2)), ... % (-y)
|
sensingObjective.objectiveFunction(neighborPos(4, 1), neighborPos(4, 2)), ... % (-y)
|
||||||
];
|
];
|
||||||
|
|
||||||
% Prevent out of bounds locations from ever possibly being selected
|
% Prevent out of bounds locations from ever possibly being selected
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
classdef sigmoidSensor
|
classdef sigmoidSensor
|
||||||
properties (SetAccess = private, GetAccess = public)
|
properties (SetAccess = private, GetAccess = public)
|
||||||
% Sensor parameters
|
% Sensor parameters
|
||||||
alphaDist;
|
alphaDist = NaN;
|
||||||
betaDist;
|
betaDist = NaN;
|
||||||
alphaPan;
|
alphaPan = NaN;
|
||||||
betaPan;
|
betaPan = NaN;
|
||||||
alphaTilt;
|
alphaTilt = NaN;
|
||||||
betaTilt;
|
betaTilt = NaN;
|
||||||
end
|
end
|
||||||
|
|
||||||
methods (Access = public)
|
methods (Access = public)
|
||||||
@@ -31,19 +31,26 @@ classdef sigmoidSensor
|
|||||||
obj.alphaTilt = alphaTilt;
|
obj.alphaTilt = alphaTilt;
|
||||||
obj.betaTilt = betaTilt;
|
obj.betaTilt = betaTilt;
|
||||||
end
|
end
|
||||||
function [neighborValues, neighborPos] = sense(obj, objectiveFunction, domain, pos)
|
function [values, positions] = sense(obj, agent, sensingObjective, domain, partitioning)
|
||||||
arguments (Input)
|
arguments (Input)
|
||||||
obj (1, 1) {mustBeA(obj, 'sigmoidSensor')};
|
obj (1, 1) {mustBeA(obj, 'sigmoidSensor')};
|
||||||
objectiveFunction (1, 1) {mustBeA(objectiveFunction, 'function_handle')};
|
agent (1, 1) {mustBeA(agent, 'agent')};
|
||||||
|
sensingObjective (1, 1) {mustBeA(sensingObjective, 'sensingObjective')};
|
||||||
domain (1, 1) {mustBeGeometry};
|
domain (1, 1) {mustBeGeometry};
|
||||||
pos (1, 3) double;
|
partitioning (:, :) double;
|
||||||
end
|
end
|
||||||
arguments (Output)
|
arguments (Output)
|
||||||
neighborValues (4, 1) double;
|
values (:, 1) double;
|
||||||
neighborPos (4, 3) double;
|
positions (:, 3) double;
|
||||||
end
|
end
|
||||||
|
|
||||||
|
% Find positions for this agent's assigned partition in the domain
|
||||||
|
idx = partitioning == agent.index;
|
||||||
|
positions = [sensingObjective.X(idx), sensingObjective.Y(idx), zeros(size(sensingObjective.X(idx)))];
|
||||||
|
|
||||||
|
% Evaluate objective function at every point in this agent's
|
||||||
|
% assigned partiton
|
||||||
|
values = sensingObjective.values(idx);
|
||||||
end
|
end
|
||||||
function value = sensorPerformance(obj, agentPos, agentPan, agentTilt, targetPos)
|
function value = sensorPerformance(obj, agentPos, agentPan, agentTilt, targetPos)
|
||||||
arguments (Input)
|
arguments (Input)
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ classdef test_miSim < matlab.unittest.TestCase
|
|||||||
domain = rectangularPrism; % domain geometry
|
domain = rectangularPrism; % domain geometry
|
||||||
maxIter = 250;
|
maxIter = 250;
|
||||||
timestep = 0.05
|
timestep = 0.05
|
||||||
|
partitoningFreq = 5;
|
||||||
|
|
||||||
% Obstacles
|
% Obstacles
|
||||||
minNumObstacles = 1; % Minimum number of obstacles to be randomly generated
|
minNumObstacles = 1; % Minimum number of obstacles to be randomly generated
|
||||||
@@ -242,7 +243,7 @@ classdef test_miSim < matlab.unittest.TestCase
|
|||||||
end
|
end
|
||||||
|
|
||||||
% Initialize the simulation
|
% Initialize the simulation
|
||||||
[tc.testClass, f] = tc.testClass.initialize(tc.domain, tc.objective, tc.agents, tc.timestep, tc.maxIter, tc.obstacles);
|
[tc.testClass, f] = tc.testClass.initialize(tc.domain, tc.objective, tc.agents, tc.timestep, tc.partitoningFreq, tc.maxIter, tc.obstacles);
|
||||||
end
|
end
|
||||||
function misim_run(tc)
|
function misim_run(tc)
|
||||||
% randomly create obstacles
|
% randomly create obstacles
|
||||||
@@ -410,7 +411,7 @@ classdef test_miSim < matlab.unittest.TestCase
|
|||||||
end
|
end
|
||||||
|
|
||||||
% Initialize the simulation
|
% Initialize the simulation
|
||||||
[tc.testClass, f] = tc.testClass.initialize(tc.domain, tc.objective, tc.agents, tc.timestep, tc.maxIter, tc.obstacles);
|
[tc.testClass, f] = tc.testClass.initialize(tc.domain, tc.objective, tc.agents, tc.timestep, tc.partitoningFreq, tc.maxIter, tc.obstacles);
|
||||||
|
|
||||||
% Run simulation loop
|
% Run simulation loop
|
||||||
[tc.testClass, f] = tc.testClass.run(f);
|
[tc.testClass, f] = tc.testClass.run(f);
|
||||||
@@ -418,7 +419,6 @@ classdef test_miSim < matlab.unittest.TestCase
|
|||||||
function test_basic_partitioning(tc)
|
function test_basic_partitioning(tc)
|
||||||
% place agents a fixed distance +/- X from the domain's center
|
% place agents a fixed distance +/- X from the domain's center
|
||||||
d = 1;
|
d = 1;
|
||||||
c = 0.1;
|
|
||||||
|
|
||||||
% make basic domain
|
% make basic domain
|
||||||
tc.domain = tc.domain.initialize([zeros(1, 3); 10 * ones(1, 3)], REGION_TYPE.DOMAIN, "Domain");
|
tc.domain = tc.domain.initialize([zeros(1, 3); 10 * ones(1, 3)], REGION_TYPE.DOMAIN, "Domain");
|
||||||
@@ -442,7 +442,7 @@ classdef test_miSim < matlab.unittest.TestCase
|
|||||||
tc.agents{2} = tc.agents{2}.initialize(tc.domain.center - [d, 0, 0], zeros(1,3), 0, 0, geometry2, sensor, @gradientAscent, 3*d, 2, sprintf("Agent %d", 2));
|
tc.agents{2} = tc.agents{2}.initialize(tc.domain.center - [d, 0, 0], zeros(1,3), 0, 0, geometry2, sensor, @gradientAscent, 3*d, 2, sprintf("Agent %d", 2));
|
||||||
|
|
||||||
% Initialize the simulation
|
% Initialize the simulation
|
||||||
[tc.testClass, f] = tc.testClass.initialize(tc.domain, tc.objective, tc.agents, tc.timestep, tc.maxIter);
|
[tc.testClass, f] = tc.testClass.initialize(tc.domain, tc.objective, tc.agents, tc.timestep, tc.partitoningFreq, tc.maxIter);
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
Reference in New Issue
Block a user