Compare commits
7
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a19209f736 | ||
|
|
24b0411af0 | ||
|
|
c3a840bae2 | ||
|
|
175a0e02a1 | ||
|
|
8dd24bdba6 | ||
|
|
e7127365bd | ||
|
|
18b690d9d8 |
No files matched your search
@@ -41,10 +41,3 @@ codegen/
|
|||||||
|
|
||||||
# Sandbox contents
|
# Sandbox contents
|
||||||
sandbox/*
|
sandbox/*
|
||||||
|
|
||||||
# Videos
|
|
||||||
*.mp4
|
|
||||||
*.avi
|
|
||||||
|
|
||||||
# Figures
|
|
||||||
*.fig
|
|
||||||
+1
-1
@@ -29,5 +29,5 @@ function obj = initialize(obj, pos, vel, pan, tilt, collisionGeometry, sensorMod
|
|||||||
|
|
||||||
% Initialize FOV cone
|
% Initialize FOV cone
|
||||||
obj.fovGeometry = cone;
|
obj.fovGeometry = cone;
|
||||||
obj.fovGeometry = obj.fovGeometry.initialize([obj.pos(1:2), 0], tand(obj.sensorModel.alphaTilt) * obj.pos(3), obj.pos(3), REGION_TYPE.FOV, sprintf("%s FOV", obj.label));
|
obj.fovGeometry = obj.fovGeometry.initialize([obj.pos(1:2), 0], tan(obj.sensorModel.alphaTilt) * obj.pos(3), obj.pos(3), REGION_TYPE.FOV, sprintf("%s FOV", obj.label));
|
||||||
end
|
end
|
||||||
+4
-11
@@ -1,4 +1,4 @@
|
|||||||
function obj = initialize(obj, domain, objective, agents, timestep, partitoningFreq, 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};
|
||||||
@@ -11,11 +11,12 @@ function obj = initialize(obj, domain, objective, agents, timestep, partitoningF
|
|||||||
end
|
end
|
||||||
arguments (Output)
|
arguments (Output)
|
||||||
obj (1, 1) {mustBeA(obj, 'miSim')};
|
obj (1, 1) {mustBeA(obj, 'miSim')};
|
||||||
|
f (1, 1) {mustBeA(f, 'matlab.ui.Figure')};
|
||||||
end
|
end
|
||||||
|
|
||||||
% Define simulation time parameters
|
% Define simulation time parameters
|
||||||
obj.timestep = timestep;
|
obj.timestep = timestep;
|
||||||
obj.maxIter = maxIter - 1;
|
obj.maxIter = maxIter;
|
||||||
|
|
||||||
% Define domain
|
% Define domain
|
||||||
obj.domain = domain;
|
obj.domain = domain;
|
||||||
@@ -33,17 +34,9 @@ function obj = initialize(obj, domain, objective, agents, timestep, partitoningF
|
|||||||
% Compute adjacency matrix
|
% Compute adjacency matrix
|
||||||
obj = obj.updateAdjacency();
|
obj = obj.updateAdjacency();
|
||||||
|
|
||||||
% Set up times to iterate over
|
|
||||||
obj.times = linspace(0, obj.timestep * obj.maxIter, obj.maxIter+1)';
|
|
||||||
obj.partitioningTimes = obj.times(obj.partitioningFreq:obj.partitioningFreq:size(obj.times, 1));
|
|
||||||
|
|
||||||
% Prepare performance data store (at t = 0, all have 0 performance)
|
|
||||||
obj.fPerf = figure;
|
|
||||||
obj.perf = [zeros(size(obj.agents, 1) + 1, 1), NaN(size(obj.agents, 1) + 1, size(obj.partitioningTimes, 1) - 1)];
|
|
||||||
|
|
||||||
% Create initial partitioning
|
% Create initial partitioning
|
||||||
obj = obj.partition();
|
obj = obj.partition();
|
||||||
|
|
||||||
% Set up plots showing initialized state
|
% Set up plots showing initialized state
|
||||||
obj = obj.plot();
|
[obj, f] = obj.plot();
|
||||||
end
|
end
|
||||||
+7
-20
@@ -13,27 +13,14 @@ classdef miSim
|
|||||||
adjacency = NaN; % Adjacency matrix representing communications network graph
|
adjacency = NaN; % Adjacency matrix representing communications network graph
|
||||||
sensorPerformanceMinimum = 1e-6; % minimum sensor performance to allow assignment of a point in the domain to a partition
|
sensorPerformanceMinimum = 1e-6; % minimum sensor performance to allow assignment of a point in the domain to a partition
|
||||||
partitioning = NaN;
|
partitioning = NaN;
|
||||||
performance = NaN; % current cumulative sensor performance
|
|
||||||
oldMeanTotalPerf = 0;
|
|
||||||
|
|
||||||
fPerf; % performance plot figure
|
|
||||||
end
|
end
|
||||||
|
|
||||||
properties (Access = private)
|
properties (Access = private)
|
||||||
% Sim
|
|
||||||
t = NaN; % current sim time
|
|
||||||
perf; % sensor performance timeseries array
|
|
||||||
times;
|
|
||||||
partitioningTimes;
|
|
||||||
|
|
||||||
% Plot objects
|
% Plot objects
|
||||||
f = firstPlotSetup(); % main plotting tiled layout figure
|
|
||||||
connectionsPlot; % objects for lines connecting agents in spatial plots
|
connectionsPlot; % objects for lines connecting agents in spatial plots
|
||||||
graphPlot; % objects for abstract network graph plot
|
graphPlot; % objects for abstract network graph plot
|
||||||
partitionPlot; % objects for partition plot
|
partitionPlot; % objects for partition plot
|
||||||
|
|
||||||
performancePlot; % objects for sensor performance plot
|
|
||||||
|
|
||||||
% Indicies for various plot types in the main tiled layout figure
|
% Indicies for various plot types in the main tiled layout figure
|
||||||
spatialPlotIndices = [6, 4, 3, 2];
|
spatialPlotIndices = [6, 4, 3, 2];
|
||||||
objectivePlotIndices = [6, 4];
|
objectivePlotIndices = [6, 4];
|
||||||
@@ -42,15 +29,15 @@ classdef miSim
|
|||||||
end
|
end
|
||||||
|
|
||||||
methods (Access = public)
|
methods (Access = public)
|
||||||
[obj] = initialize(obj, domain, objective, agents, timestep, partitoningFreq, maxIter, obstacles);
|
[obj, f] = initialize(obj, domain, objective, agents, timestep, partitoningFreq, maxIter, obstacles);
|
||||||
[obj] = run(obj);
|
[obj, f] = run(obj, f);
|
||||||
[obj] = partition(obj);
|
[obj] = partition(obj);
|
||||||
[obj] = updateAdjacency(obj);
|
[obj] = updateAdjacency(obj);
|
||||||
[obj] = plot(obj);
|
[obj, f] = plot(obj);
|
||||||
[obj] = plotConnections(obj);
|
[obj, f] = plotConnections(obj, ind, f);
|
||||||
[obj] = plotPartitions(obj);
|
[obj, f] = plotPartitions(obj, ind, f);
|
||||||
[obj] = plotGraph(obj);
|
[obj, f] = plotGraph(obj, ind, f);
|
||||||
[obj] = updatePlots(obj, updatePartitions);
|
[obj, f] = updatePlots(obj, f, updatePartitions);
|
||||||
end
|
end
|
||||||
methods (Access = private)
|
methods (Access = private)
|
||||||
[v] = setupVideoWriter(obj);
|
[v] = setupVideoWriter(obj);
|
||||||
|
|||||||
+5
-19
@@ -15,27 +15,13 @@ function obj = partition(obj)
|
|||||||
% Get highest performance value at each point
|
% Get highest performance value at each point
|
||||||
[~, idx] = max(agentPerformances, [], 3);
|
[~, idx] = max(agentPerformances, [], 3);
|
||||||
|
|
||||||
% Collect agent indices in the same way as performance
|
% Collect agent indices in the same way
|
||||||
agentInds = cellfun(@(x) x.index * ones(size(obj.objective.X)), obj.agents, 'UniformOutput', false);
|
agentInds = cellfun(@(x) x.index * ones(size(obj.objective.X)), obj.agents, 'UniformOutput', false);
|
||||||
agentInds{end + 1} = zeros(size(agentInds{end})); % index for no assignment
|
agentInds{end + 1} = zeros(size(agentInds{end})); % index for no assignment
|
||||||
agentInds = cat(3, agentInds{:});
|
agentInds = cat(3, agentInds{:});
|
||||||
|
|
||||||
% Use highest performing agent's index to form partitions
|
% Get highest performing agent's index
|
||||||
[m, n, ~] = size(agentInds);
|
[m,n,~] = size(agentInds);
|
||||||
[jj, kk] = ndgrid(1:m, 1:n);
|
[i,j] = ndgrid(1:m, 1:n);
|
||||||
obj.partitioning = agentInds(sub2ind(size(agentInds), jj, kk, idx));
|
obj.partitioning = agentInds(sub2ind(size(agentInds), i, j, idx));
|
||||||
|
|
||||||
% Get individual agent sensor performance
|
|
||||||
nowIdx = [0; obj.partitioningTimes] == obj.t;
|
|
||||||
if isnan(obj.t)
|
|
||||||
nowIdx = 1;
|
|
||||||
end
|
|
||||||
for ii = 1:size(obj.agents, 1)
|
|
||||||
idx = obj.partitioning == ii;
|
|
||||||
agentPerformance = squeeze(agentPerformances(:, :, ii));
|
|
||||||
obj.perf(ii, nowIdx) = sum(agentPerformance(idx) .* obj.objective.values(idx));
|
|
||||||
end
|
|
||||||
|
|
||||||
% Current total performance
|
|
||||||
obj.perf(end, nowIdx) = sum(obj.perf(1:(end - 1), nowIdx));
|
|
||||||
end
|
end
|
||||||
+12
-14
@@ -1,43 +1,41 @@
|
|||||||
function obj = plot(obj)
|
function [obj, f] = plot(obj)
|
||||||
arguments (Input)
|
arguments (Input)
|
||||||
obj (1, 1) {mustBeA(obj, 'miSim')};
|
obj (1, 1) {mustBeA(obj, 'miSim')};
|
||||||
end
|
end
|
||||||
arguments (Output)
|
arguments (Output)
|
||||||
obj (1, 1) {mustBeA(obj, 'miSim')};
|
obj (1, 1) {mustBeA(obj, 'miSim')};
|
||||||
|
f (1, 1) {mustBeA(f, 'matlab.ui.Figure')};
|
||||||
end
|
end
|
||||||
|
|
||||||
% Plot domain
|
% Plot domain
|
||||||
[obj.domain, obj.f] = obj.domain.plotWireframe(obj.spatialPlotIndices);
|
[obj.domain, f] = obj.domain.plotWireframe(obj.spatialPlotIndices);
|
||||||
|
|
||||||
% Plot obstacles
|
% Plot obstacles
|
||||||
for ii = 1:size(obj.obstacles, 1)
|
for ii = 1:size(obj.obstacles, 1)
|
||||||
[obj.obstacles{ii}, obj.f] = obj.obstacles{ii}.plotWireframe(obj.spatialPlotIndices, obj.f);
|
[obj.obstacles{ii}, f] = obj.obstacles{ii}.plotWireframe(obj.spatialPlotIndices, f);
|
||||||
end
|
end
|
||||||
|
|
||||||
% Plot objective gradient
|
% Plot objective gradient
|
||||||
obj.f = obj.domain.objective.plot(obj.objectivePlotIndices, obj.f);
|
f = obj.domain.objective.plot(obj.objectivePlotIndices, f);
|
||||||
|
|
||||||
% Plot agents and their collision geometries
|
% Plot agents and their collision geometries
|
||||||
for ii = 1:size(obj.agents, 1)
|
for ii = 1:size(obj.agents, 1)
|
||||||
[obj.agents{ii}, obj.f] = obj.agents{ii}.plot(obj.spatialPlotIndices, obj.f);
|
[obj.agents{ii}, f] = obj.agents{ii}.plot(obj.spatialPlotIndices, f);
|
||||||
end
|
end
|
||||||
|
|
||||||
% Plot communication links
|
% Plot communication links
|
||||||
obj = obj.plotConnections();
|
[obj, f] = obj.plotConnections(obj.spatialPlotIndices, f);
|
||||||
|
|
||||||
% Plot abstract network graph
|
% Plot abstract network graph
|
||||||
obj = obj.plotGraph();
|
[obj, f] = obj.plotGraph(obj.networkGraphIndex, f);
|
||||||
|
|
||||||
% Plot domain partitioning
|
% Plot domain partitioning
|
||||||
obj = obj.plotPartitions();
|
[obj, f] = obj.plotPartitions(obj.partitionGraphIndex, f);
|
||||||
|
|
||||||
% Enforce plot limits
|
% Enforce plot limits
|
||||||
for ii = 1:size(obj.spatialPlotIndices, 2)
|
for ii = 1:size(obj.spatialPlotIndices, 2)
|
||||||
xlim(obj.f.Children(1).Children(obj.spatialPlotIndices(ii)), [obj.domain.minCorner(1), obj.domain.maxCorner(1)]);
|
xlim(f.Children(1).Children(obj.spatialPlotIndices(ii)), [obj.domain.minCorner(1), obj.domain.maxCorner(1)]);
|
||||||
ylim(obj.f.Children(1).Children(obj.spatialPlotIndices(ii)), [obj.domain.minCorner(2), obj.domain.maxCorner(2)]);
|
ylim(f.Children(1).Children(obj.spatialPlotIndices(ii)), [obj.domain.minCorner(2), obj.domain.maxCorner(2)]);
|
||||||
zlim(obj.f.Children(1).Children(obj.spatialPlotIndices(ii)), [obj.domain.minCorner(3), obj.domain.maxCorner(3)]);
|
zlim(f.Children(1).Children(obj.spatialPlotIndices(ii)), [obj.domain.minCorner(3), obj.domain.maxCorner(3)]);
|
||||||
end
|
end
|
||||||
|
|
||||||
% Plot performance
|
|
||||||
obj = obj.plotPerformance();
|
|
||||||
end
|
end
|
||||||
+14
-11
@@ -1,9 +1,12 @@
|
|||||||
function obj = plotConnections(obj)
|
function [obj, f] = plotConnections(obj, ind, f)
|
||||||
arguments (Input)
|
arguments (Input)
|
||||||
obj (1, 1) {mustBeA(obj, 'miSim')};
|
obj (1, 1) {mustBeA(obj, 'miSim')};
|
||||||
|
ind (1, :) double = NaN;
|
||||||
|
f (1, 1) {mustBeA(f, 'matlab.ui.Figure')} = figure;
|
||||||
end
|
end
|
||||||
arguments (Output)
|
arguments (Output)
|
||||||
obj (1, 1) {mustBeA(obj, 'miSim')};
|
obj (1, 1) {mustBeA(obj, 'miSim')};
|
||||||
|
f (1, 1) {mustBeA(f, 'matlab.ui.Figure')};
|
||||||
end
|
end
|
||||||
|
|
||||||
% Iterate over lower triangle off-diagonal region of the
|
% Iterate over lower triangle off-diagonal region of the
|
||||||
@@ -21,20 +24,20 @@ function obj = plotConnections(obj)
|
|||||||
X = X'; Y = Y'; Z = Z';
|
X = X'; Y = Y'; Z = Z';
|
||||||
|
|
||||||
% Plot the connections
|
% Plot the connections
|
||||||
if isnan(obj.spatialPlotIndices)
|
if isnan(ind)
|
||||||
hold(obj.f.CurrentAxes, "on");
|
hold(f.CurrentAxes, "on");
|
||||||
o = plot3(obj.f.CurrentAxes, X, Y, Z, 'Color', 'g', 'LineWidth', 2, 'LineStyle', '--');
|
o = plot3(f.CurrentAxes, X, Y, Z, 'Color', 'g', 'LineWidth', 2, 'LineStyle', '--');
|
||||||
hold(obj.f.CurrentAxes, "off");
|
hold(f.CurrentAxes, "off");
|
||||||
else
|
else
|
||||||
hold(obj.f.Children(1).Children(obj.spatialPlotIndices(1)), "on");
|
hold(f.Children(1).Children(ind(1)), "on");
|
||||||
o = plot3(obj.f.Children(1).Children(obj.spatialPlotIndices(1)), X, Y, Z, 'Color', 'g', 'LineWidth', 2, 'LineStyle', '--');
|
o = plot3(f.Children(1).Children(ind(1)), X, Y, Z, 'Color', 'g', 'LineWidth', 2, 'LineStyle', '--');
|
||||||
hold(obj.f.Children(1).Children(obj.spatialPlotIndices(1)), "off");
|
hold(f.Children(1).Children(ind(1)), "off");
|
||||||
end
|
end
|
||||||
|
|
||||||
% Copy to other plots
|
% Copy to other plots
|
||||||
if size(obj.spatialPlotIndices, 2) > 1
|
if size(ind, 2) > 1
|
||||||
for ii = 2:size(obj.spatialPlotIndices, 2)
|
for ii = 2:size(ind, 2)
|
||||||
o = [o, copyobj(o(:, 1), obj.f.Children(1).Children(obj.spatialPlotIndices(ii)))];
|
o = [o, copyobj(o(:, 1), f.Children(1).Children(ind(ii)))];
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
+13
-10
@@ -1,26 +1,29 @@
|
|||||||
function obj = plotGraph(obj)
|
function [obj, f] = plotGraph(obj, ind, f)
|
||||||
arguments (Input)
|
arguments (Input)
|
||||||
obj (1, 1) {mustBeA(obj, 'miSim')};
|
obj (1, 1) {mustBeA(obj, 'miSim')};
|
||||||
|
ind (1, :) double = NaN;
|
||||||
|
f (1, 1) {mustBeA(f, 'matlab.ui.Figure')} = figure;
|
||||||
end
|
end
|
||||||
arguments (Output)
|
arguments (Output)
|
||||||
obj (1, 1) {mustBeA(obj, 'miSim')};
|
obj (1, 1) {mustBeA(obj, 'miSim')};
|
||||||
|
f (1, 1) {mustBeA(f, 'matlab.ui.Figure')};
|
||||||
end
|
end
|
||||||
|
|
||||||
% Form graph from adjacency matrix
|
% Form graph from adjacency matrix
|
||||||
G = graph(obj.adjacency, 'omitselfloops');
|
G = graph(obj.adjacency, 'omitselfloops');
|
||||||
|
|
||||||
% Plot graph object
|
% Plot graph object
|
||||||
if isnan(obj.networkGraphIndex)
|
if isnan(ind)
|
||||||
hold(obj.f.CurrentAxes, 'on');
|
hold(f.CurrentAxes, 'on');
|
||||||
o = plot(obj.f.CurrentAxes, G, 'LineStyle', '--', 'EdgeColor', 'g', 'NodeColor', 'k', 'LineWidth', 2);
|
o = plot(f.CurrentAxes, G, 'LineStyle', '--', 'EdgeColor', 'g', 'NodeColor', 'k', 'LineWidth', 2);
|
||||||
hold(obj.f.CurrentAxes, 'off');
|
hold(f.CurrentAxes, 'off');
|
||||||
else
|
else
|
||||||
hold(obj.f.Children(1).Children(obj.networkGraphIndex(1)), 'on');
|
hold(f.Children(1).Children(ind(1)), 'on');
|
||||||
o = plot(obj.f.Children(1).Children(obj.networkGraphIndex(1)), G, 'LineStyle', '--', 'EdgeColor', 'g', 'NodeColor', 'k', 'LineWidth', 2);
|
o = plot(f.Children(1).Children(ind(1)), G, 'LineStyle', '--', 'EdgeColor', 'g', 'NodeColor', 'k', 'LineWidth', 2);
|
||||||
hold(obj.f.Children(1).Children(obj.networkGraphIndex(1)), 'off');
|
hold(f.Children(1).Children(ind(1)), 'off');
|
||||||
if size(obj.networkGraphIndex, 2) > 1
|
if size(ind, 2) > 1
|
||||||
for ii = 2:size(ind, 2)
|
for ii = 2:size(ind, 2)
|
||||||
o = [o; copyobj(o(1), obj.f.Children(1).Children(obj.networkGraphIndex(ii)))];
|
o = [o; copyobj(o(1), f.Children(1).Children(ind(ii)))];
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
+13
-10
@@ -1,22 +1,25 @@
|
|||||||
function obj = plotPartitions(obj)
|
function [obj, f] = plotPartitions(obj, ind, f)
|
||||||
arguments (Input)
|
arguments (Input)
|
||||||
obj (1, 1) {mustBeA(obj, 'miSim')};
|
obj (1, 1) {mustBeA(obj, 'miSim')};
|
||||||
|
ind (1, :) double = NaN;
|
||||||
|
f (1, 1) {mustBeA(f, 'matlab.ui.Figure')} = figure;
|
||||||
end
|
end
|
||||||
arguments (Output)
|
arguments (Output)
|
||||||
obj (1, 1) {mustBeA(obj, 'miSim')};
|
obj (1, 1) {mustBeA(obj, 'miSim')};
|
||||||
|
f (1, 1) {mustBeA(f, 'matlab.ui.Figure')};
|
||||||
end
|
end
|
||||||
|
|
||||||
if isnan(obj.partitionGraphIndex)
|
if isnan(ind)
|
||||||
hold(obj.f.CurrentAxes, 'on');
|
hold(f.CurrentAxes, 'on');
|
||||||
o = imagesc(obj.f.CurrentAxes, obj.partitioning);
|
o = imagesc(f.CurrentAxes, obj.partitioning);
|
||||||
hold(obj.f.CurrentAxes, 'off');
|
hold(f.CurrentAxes, 'off');
|
||||||
else
|
else
|
||||||
hold(obj.f.Children(1).Children(obj.partitionGraphIndex(1)), 'on');
|
hold(f.Children(1).Children(ind(1)), 'on');
|
||||||
o = imagesc(obj.f.Children(1).Children(obj.partitionGraphIndex(1)), obj.partitioning);
|
o = imagesc(f.Children(1).Children(ind(1)), obj.partitioning);
|
||||||
hold(obj.f.Children(1).Children(obj.partitionGraphIndex(1)), 'on');
|
hold(f.Children(1).Children(ind(1)), 'on');
|
||||||
if size(obj.partitionGraphIndex, 2) > 1
|
if size(ind, 2) > 1
|
||||||
for ii = 2:size(ind, 2)
|
for ii = 2:size(ind, 2)
|
||||||
o = [o, copyobj(o(1), obj.f.Children(1).Children(obj.partitionGraphIndex(ii)))];
|
o = [o, copyobj(o(1), f.Children(1).Children(ind(ii)))];
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,36 +0,0 @@
|
|||||||
function obj = plotPerformance(obj)
|
|
||||||
arguments (Input)
|
|
||||||
obj (1, 1) {mustBeA(obj, 'miSim')};
|
|
||||||
end
|
|
||||||
arguments (Output)
|
|
||||||
obj (1, 1) {mustBeA(obj, 'miSim')};
|
|
||||||
end
|
|
||||||
|
|
||||||
axes(obj.fPerf);
|
|
||||||
title(obj.fPerf.Children(1), "Sensor Performance");
|
|
||||||
xlabel(obj.fPerf.Children(1), 'Time (s)');
|
|
||||||
ylabel(obj.fPerf.Children(1), 'Sensor Performance');
|
|
||||||
grid(obj.fPerf.Children(1), 'on');
|
|
||||||
|
|
||||||
% Plot current cumulative performance
|
|
||||||
hold(obj.fPerf.Children(1), 'on');
|
|
||||||
o = plot(obj.fPerf.Children(1), obj.perf(end, :));
|
|
||||||
hold(obj.fPerf.Children(1), 'off');
|
|
||||||
|
|
||||||
% Plot current agent performance
|
|
||||||
for ii = 1:(size(obj.perf, 1) - 1)
|
|
||||||
hold(obj.fPerf.Children(1), 'on');
|
|
||||||
o = [o; plot(obj.fPerf.Children(1), obj.perf(ii, :))];
|
|
||||||
hold(obj.fPerf.Children(1), 'off');
|
|
||||||
end
|
|
||||||
|
|
||||||
% Add legend
|
|
||||||
agentStrings = repmat("Agent %d", size(obj.perf, 1) - 1, 1);
|
|
||||||
for ii = 1:size(agentStrings, 1)
|
|
||||||
agentStrings(ii) = sprintf(agentStrings(ii), ii);
|
|
||||||
end
|
|
||||||
agentStrings = ["Total"; agentStrings];
|
|
||||||
legend(obj.fPerf.Children(1), agentStrings, 'Location', 'northwest');
|
|
||||||
|
|
||||||
obj.performancePlot = o;
|
|
||||||
end
|
|
||||||
+17
-22
@@ -1,37 +1,32 @@
|
|||||||
function [obj] = run(obj)
|
function [obj, f] = run(obj, f)
|
||||||
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;
|
||||||
end
|
end
|
||||||
arguments (Output)
|
arguments (Output)
|
||||||
obj (1, 1) {mustBeA(obj, 'miSim')};
|
obj (1, 1) {mustBeA(obj, 'miSim')};
|
||||||
|
f (1, 1) {mustBeA(f, 'matlab.ui.Figure')};
|
||||||
end
|
end
|
||||||
|
|
||||||
|
% Create axes if they don't already exist
|
||||||
|
f = firstPlotSetup(f);
|
||||||
|
|
||||||
|
% Set up times to iterate over
|
||||||
|
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 = obj.setupVideoWriter();
|
v = obj.setupVideoWriter();
|
||||||
v.open();
|
v.open();
|
||||||
|
|
||||||
steady = 0;
|
for ii = 1:size(times, 1)
|
||||||
for ii = 1:size(obj.times, 1)
|
|
||||||
% Display current sim time
|
% Display current sim time
|
||||||
obj.t = obj.times(ii);
|
t = times(ii);
|
||||||
fprintf("Sim Time: %4.2f (%d/%d)\n", obj.t, ii, obj.maxIter + 1);
|
fprintf("Sim Time: %4.2f (%d/%d)\n", t, ii, obj.maxIter)
|
||||||
|
|
||||||
% Check if it's time for new partitions
|
% Check if it's time for new partitions
|
||||||
updatePartitions = false;
|
updatePartitions = false;
|
||||||
if ismember(obj.t, obj.partitioningTimes)
|
if ismember(t, partitioningTimes)
|
||||||
% Check if it's time to end the sim (performance has settled)
|
|
||||||
if obj.t >= obj.partitioningTimes(5)
|
|
||||||
idx = find(obj.t == obj.partitioningTimes);
|
|
||||||
newMeanTotalPerf = mean(obj.perf(end, ((idx - 5 + 1):idx)));
|
|
||||||
if (obj.oldMeanTotalPerf * 0.95 <= newMeanTotalPerf) && (newMeanTotalPerf <= max(1e-6, obj.oldMeanTotalPerf * 1.05))
|
|
||||||
steady = steady + 1;
|
|
||||||
if steady >= 3
|
|
||||||
fprintf("Performance is stable, terminating early at %4.2f (%d/%d)\n", obj.t, ii, obj.maxIter + 1);
|
|
||||||
break; % performance is not improving further, exit main sim loop
|
|
||||||
end
|
|
||||||
end
|
|
||||||
obj.oldMeanTotalPerf = newMeanTotalPerf;
|
|
||||||
end
|
|
||||||
updatePartitions = true;
|
updatePartitions = true;
|
||||||
obj = obj.partition();
|
obj = obj.partition();
|
||||||
end
|
end
|
||||||
@@ -42,13 +37,13 @@ function [obj] = run(obj)
|
|||||||
end
|
end
|
||||||
|
|
||||||
% Update adjacency matrix
|
% Update adjacency matrix
|
||||||
obj = obj.updateAdjacency();
|
obj = obj.updateAdjacency;
|
||||||
|
|
||||||
% Update plots
|
% Update plots
|
||||||
obj = obj.updatePlots(updatePartitions);
|
[obj, f] = obj.updatePlots(f, updatePartitions);
|
||||||
|
|
||||||
% Write frame in to video
|
% Write frame in to video
|
||||||
I = getframe(obj.f);
|
I = getframe(f);
|
||||||
v.writeVideo(I);
|
v.writeVideo(I);
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ function v = setupVideoWriter(obj)
|
|||||||
if ispc || ismac
|
if ispc || ismac
|
||||||
v = VideoWriter(fullfile('sandbox', strcat(string(datetime('now'), 'yyyy_MM_dd_HH_mm_ss'), '_miSimHist')), 'MPEG-4');
|
v = VideoWriter(fullfile('sandbox', strcat(string(datetime('now'), 'yyyy_MM_dd_HH_mm_ss'), '_miSimHist')), 'MPEG-4');
|
||||||
elseif isunix
|
elseif isunix
|
||||||
v = VideoWriter(fullfile('.', strcat(string(datetime('now'), 'yyyy_MM_dd_HH_mm_ss'), '_miSimHist')), 'Motion JPEG AVI');
|
v = VideoWriter(fullfile('sandbox', strcat(string(datetime('now'), 'yyyy_MM_dd_HH_mm_ss'), '_miSimHist')), 'Motion JPEG AVI');
|
||||||
end
|
end
|
||||||
|
|
||||||
v.FrameRate = 1 / obj.timestep;
|
v.FrameRate = 1 / obj.timestep;
|
||||||
|
|||||||
+10
-21
@@ -1,10 +1,12 @@
|
|||||||
function [obj] = updatePlots(obj, updatePartitions)
|
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;
|
||||||
updatePartitions (1, 1) logical = false;
|
updatePartitions (1, 1) logical = false;
|
||||||
end
|
end
|
||||||
arguments (Output)
|
arguments (Output)
|
||||||
obj (1, 1) {mustBeA(obj, 'miSim')};
|
obj (1, 1) {mustBeA(obj, 'miSim')};
|
||||||
|
f (1, 1) {mustBeA(f, 'matlab.ui.Figure')};
|
||||||
end
|
end
|
||||||
|
|
||||||
% Update agent positions, collision geometries
|
% Update agent positions, collision geometries
|
||||||
@@ -18,37 +20,24 @@ function [obj] = updatePlots(obj, updatePartitions)
|
|||||||
|
|
||||||
% Update agent connections plot
|
% Update agent connections plot
|
||||||
delete(obj.connectionsPlot);
|
delete(obj.connectionsPlot);
|
||||||
obj = obj.plotConnections();
|
[obj, f] = obj.plotConnections(obj.spatialPlotIndices, f);
|
||||||
|
|
||||||
% Update network graph plot
|
% Update network graph plot
|
||||||
delete(obj.graphPlot);
|
delete(obj.graphPlot);
|
||||||
obj = obj.plotGraph();
|
[obj, f] = obj.plotGraph(obj.networkGraphIndex, f);
|
||||||
|
|
||||||
% Update partitioning plot
|
% Update partitioning plot
|
||||||
if updatePartitions
|
if updatePartitions
|
||||||
delete(obj.partitionPlot);
|
delete(obj.partitionPlot);
|
||||||
obj = obj.plotPartitions();
|
[obj, f] = obj.plotPartitions(obj.partitionGraphIndex, f);
|
||||||
end
|
end
|
||||||
|
|
||||||
% reset plot limits to fit domain
|
% reset plot limits to fit domain
|
||||||
for ii = 1:size(obj.spatialPlotIndices, 2)
|
for ii = 1:size(obj.spatialPlotIndices, 2)
|
||||||
xlim(obj.f.Children(1).Children(obj.spatialPlotIndices(ii)), [obj.domain.minCorner(1), obj.domain.maxCorner(1)]);
|
xlim(f.Children(1).Children(obj.spatialPlotIndices(ii)), [obj.domain.minCorner(1), obj.domain.maxCorner(1)]);
|
||||||
ylim(obj.f.Children(1).Children(obj.spatialPlotIndices(ii)), [obj.domain.minCorner(2), obj.domain.maxCorner(2)]);
|
ylim(f.Children(1).Children(obj.spatialPlotIndices(ii)), [obj.domain.minCorner(2), obj.domain.maxCorner(2)]);
|
||||||
zlim(obj.f.Children(1).Children(obj.spatialPlotIndices(ii)), [obj.domain.minCorner(3), obj.domain.maxCorner(3)]);
|
zlim(f.Children(1).Children(obj.spatialPlotIndices(ii)), [obj.domain.minCorner(3), obj.domain.maxCorner(3)]);
|
||||||
end
|
end
|
||||||
|
|
||||||
drawnow;
|
drawnow;
|
||||||
|
|
||||||
% Update performance plot
|
|
||||||
if updatePartitions
|
|
||||||
% find index corresponding to the current time
|
|
||||||
nowIdx = [0; obj.partitioningTimes] == obj.t;
|
|
||||||
nowIdx = find(nowIdx);
|
|
||||||
|
|
||||||
% Re-normalize performance plot
|
|
||||||
normalizingFactor = 1/max(obj.perf(end, 1:nowIdx));
|
|
||||||
obj.performancePlot(1).YData(1:nowIdx) = obj.perf(end, 1:nowIdx) * normalizingFactor;
|
|
||||||
for ii = 2:size(obj.performancePlot, 1)
|
|
||||||
obj.performancePlot(ii).YData(1:nowIdx) = obj.perf(ii - 1, 1:nowIdx) * normalizingFactor;
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
@@ -29,11 +29,8 @@ function obj = initialize(obj, objectiveFunction, domain, discretizationStep, pr
|
|||||||
obj.objectiveFunction = objectiveFunction;
|
obj.objectiveFunction = objectiveFunction;
|
||||||
obj.values = reshape(obj.objectiveFunction(obj.X, obj.Y), size(obj.X));
|
obj.values = reshape(obj.objectiveFunction(obj.X, obj.Y), size(obj.X));
|
||||||
|
|
||||||
% Normalize
|
|
||||||
obj.values = obj.values ./ max(obj.values, [], "all");
|
|
||||||
|
|
||||||
% store ground position
|
% store ground position
|
||||||
idx = obj.values == 1;
|
idx = obj.values == max(obj.values, [], "all");
|
||||||
obj.groundPos = [obj.X(idx), obj.Y(idx)];
|
obj.groundPos = [obj.X(idx), obj.Y(idx)];
|
||||||
|
|
||||||
assert(domain.distance([obj.groundPos, domain.center(3)]) > protectedRange, "Domain is crowding the sensing objective")
|
assert(domain.distance([obj.groundPos, domain.center(3)]) > protectedRange, "Domain is crowding the sensing objective")
|
||||||
|
|||||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -0,0 +1,2 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<Info Ref="sensingModels" Type="Relative"/>
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<Info location="420d04e4-3880-4a45-8609-11cb30d87302" type="Reference"/>
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<Info Ref="sensorModels" Type="Relative"/>
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<Info location="d143c27d-6824-4569-9093-8150b60976cb" type="Reference"/>
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<Info>
|
|
||||||
<Category UUID="FileClassCategory">
|
|
||||||
<Label UUID="test"/>
|
|
||||||
</Category>
|
|
||||||
</Info>
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<Info location="test_sigmoidSensor.m" type="File"/>
|
|
||||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -1,2 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<Info location="plotPerformance.m" type="File"/>
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<Info location="sensorModels" type="File"/>
|
|
||||||
File renamed without changes.
@@ -0,0 +1,2 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<Info location="sensingModels" type="File"/>
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<Info location="tiltMembership.m" type="File"/>
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<Info location="plotParameters.m" type="File"/>
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<Info>
|
|
||||||
<Category UUID="FileClassCategory">
|
|
||||||
<Label UUID="design"/>
|
|
||||||
</Category>
|
|
||||||
</Info>
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<Info location="distanceMembership.m" type="File"/>
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<Info>
|
|
||||||
<Category UUID="FileClassCategory">
|
|
||||||
<Label UUID="design"/>
|
|
||||||
</Category>
|
|
||||||
</Info>
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<Info>
|
|
||||||
<Category UUID="FileClassCategory">
|
|
||||||
<Label UUID="design"/>
|
|
||||||
</Category>
|
|
||||||
</Info>
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<Info>
|
|
||||||
<Category UUID="FileClassCategory">
|
|
||||||
<Label UUID="design"/>
|
|
||||||
</Category>
|
|
||||||
</Info>
|
|
||||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
+5
-7
@@ -10,16 +10,14 @@ function value = sensorPerformance(obj, agentPos, agentPan, agentTilt, targetPos
|
|||||||
value (:, 1) double;
|
value (:, 1) double;
|
||||||
end
|
end
|
||||||
|
|
||||||
% compute direct distance and distance projected onto the ground
|
|
||||||
d = vecnorm(agentPos - targetPos, 2, 2); % distance from sensor to target
|
d = vecnorm(agentPos - targetPos, 2, 2); % distance from sensor to target
|
||||||
x = vecnorm(agentPos(1:2) - targetPos(:, 1:2), 2, 2); % distance from sensor nadir to target nadir (i.e. distance ignoring height difference)
|
x = vecnorm(agentPos(1:2) - targetPos(:, 1:2), 2, 2); % distance from sensor nadir to target nadir (i.e. distance ignoring height difference)
|
||||||
|
tiltAngle = atan2(targetPos(:, 3) - agentPos(3), x) - agentTilt;
|
||||||
% compute tilt angle
|
|
||||||
tiltAngle = (180 - atan2d(x, targetPos(:, 3) - agentPos(3))) - agentTilt; % degrees
|
|
||||||
|
|
||||||
% Membership functions
|
% Membership functions
|
||||||
mu_d = obj.distanceMembership(d);
|
mu_d = 1 - (1 ./ (1 + exp(-obj.betaDist .* (d - obj.alphaDist)))); % distance
|
||||||
mu_t = obj.tiltMembership(tiltAngle);
|
mu_p = 1; % pan
|
||||||
|
mu_t = (1 ./ (1 + exp(-obj.betaTilt .* (tiltAngle + obj.alphaTilt)))) - (1 ./ (1 + exp(-obj.betaTilt .* (tiltAngle - obj.alphaTilt)))); % tilt
|
||||||
|
|
||||||
value = mu_d .* mu_t; % assume pan membership is always 1
|
value = mu_d .* mu_p .* mu_t;
|
||||||
end
|
end
|
||||||
+1
-6
@@ -5,7 +5,7 @@ classdef sigmoidSensor
|
|||||||
betaDist = NaN;
|
betaDist = NaN;
|
||||||
alphaPan = NaN;
|
alphaPan = NaN;
|
||||||
betaPan = NaN;
|
betaPan = NaN;
|
||||||
alphaTilt = NaN; % degrees
|
alphaTilt = NaN;
|
||||||
betaTilt = NaN;
|
betaTilt = NaN;
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -13,10 +13,5 @@ classdef sigmoidSensor
|
|||||||
[obj] = initialize(obj, alphaDist, betaDist, alphaPan, betaPan, alphaTilt, betaTilt);
|
[obj] = initialize(obj, alphaDist, betaDist, alphaPan, betaPan, alphaTilt, betaTilt);
|
||||||
[values, positions] = sense(obj, agent, sensingObjective, domain, partitioning);
|
[values, positions] = sense(obj, agent, sensingObjective, domain, partitioning);
|
||||||
[value] = sensorPerformance(obj, agentPos, agentPan, agentTilt, targetPos);
|
[value] = sensorPerformance(obj, agentPos, agentPan, agentTilt, targetPos);
|
||||||
[f] = plotParameters(obj);
|
|
||||||
end
|
|
||||||
methods (Access = private)
|
|
||||||
x = distanceMembership(obj, d);
|
|
||||||
x = tiltMembership(obj, t);
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
function x = distanceMembership(obj, d)
|
|
||||||
arguments (Input)
|
|
||||||
obj (1, 1) {mustBeA(obj, 'sigmoidSensor')};
|
|
||||||
d (:, 1) double;
|
|
||||||
end
|
|
||||||
arguments (Output)
|
|
||||||
x (:, 1) double;
|
|
||||||
end
|
|
||||||
x = 1 - (1 ./ (1 + exp(-obj.betaDist .* (abs(d) - obj.alphaDist))));
|
|
||||||
end
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
function f = plotParameters(obj)
|
|
||||||
arguments (Input)
|
|
||||||
obj (1, 1) {mustBeA(obj, 'sigmoidSensor')};
|
|
||||||
end
|
|
||||||
arguments (Output)
|
|
||||||
f (1, 1) {mustBeA(f, 'matlab.ui.Figure')};
|
|
||||||
end
|
|
||||||
|
|
||||||
% Distance and tilt sample points
|
|
||||||
d = 0:(obj.alphaDist / 100):(2*obj.alphaDist);
|
|
||||||
t = -90:1:90;
|
|
||||||
|
|
||||||
% Sample membership functions
|
|
||||||
d_x = obj.distanceMembership(d);
|
|
||||||
t_x = obj.tiltMembership(t);
|
|
||||||
|
|
||||||
% Plot resultant sigmoid curves
|
|
||||||
f = figure;
|
|
||||||
tiledlayout(f, 2, 1, "TileSpacing", "tight", "Padding", "compact");
|
|
||||||
|
|
||||||
% Distance
|
|
||||||
nexttile(1, [1, 1]);
|
|
||||||
grid("on");
|
|
||||||
title("Distance Membership Sigmoid");
|
|
||||||
xlabel("Distance (m)");
|
|
||||||
ylabel("Membership");
|
|
||||||
hold('on');
|
|
||||||
plot(d, d_x, 'LineWidth', 2);
|
|
||||||
hold('off');
|
|
||||||
ylim([0, 1]);
|
|
||||||
|
|
||||||
% Tilt
|
|
||||||
nexttile(2, [1, 1]);
|
|
||||||
grid("on");
|
|
||||||
title("Tilt Membership Sigmoid");
|
|
||||||
xlabel("Tilt (deg)");
|
|
||||||
ylabel("Membership");
|
|
||||||
hold('on');
|
|
||||||
plot(t, t_x, 'LineWidth', 2);
|
|
||||||
hold('off');
|
|
||||||
ylim([0, 1]);
|
|
||||||
end
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
function x = tiltMembership(obj, t)
|
|
||||||
arguments (Input)
|
|
||||||
obj (1, 1) {mustBeA(obj, 'sigmoidSensor')};
|
|
||||||
t (:, 1) double; % degrees
|
|
||||||
end
|
|
||||||
arguments (Output)
|
|
||||||
x (:, 1) double;
|
|
||||||
end
|
|
||||||
x = (1 ./ (1 + exp(-obj.betaTilt .* (t + obj.alphaTilt)))) - (1 ./ (1 + exp(-obj.betaTilt .* (t - obj.alphaTilt))));
|
|
||||||
end
|
|
||||||
+18
-71
@@ -1,6 +1,5 @@
|
|||||||
classdef test_miSim < matlab.unittest.TestCase
|
classdef test_miSim < matlab.unittest.TestCase
|
||||||
properties (Access = private)
|
properties (Access = private)
|
||||||
% System under test
|
|
||||||
testClass = miSim;
|
testClass = miSim;
|
||||||
|
|
||||||
% Sim
|
% Sim
|
||||||
@@ -25,8 +24,8 @@ classdef test_miSim < matlab.unittest.TestCase
|
|||||||
objective = sensingObjective;
|
objective = sensingObjective;
|
||||||
|
|
||||||
% Agents
|
% Agents
|
||||||
minAgents = 2; % Minimum number of agents to be randomly generated
|
minAgents = 3; % Minimum number of agents to be randomly generated
|
||||||
maxAgents = 4; % Maximum number of agents to be randomly generated
|
maxAgents = 6; % Maximum number of agents to be randomly generated
|
||||||
sensingLength = 0.05; % length parameter used by sensing function
|
sensingLength = 0.05; % length parameter used by sensing function
|
||||||
agents = cell(0, 1);
|
agents = cell(0, 1);
|
||||||
|
|
||||||
@@ -35,18 +34,8 @@ classdef test_miSim < matlab.unittest.TestCase
|
|||||||
maxCollisionRange = 0.5; % Maximum randomly generated collision geometry size
|
maxCollisionRange = 0.5; % Maximum randomly generated collision geometry size
|
||||||
collisionRanges = NaN;
|
collisionRanges = NaN;
|
||||||
|
|
||||||
% Sensing
|
|
||||||
betaDistMin = 3;
|
|
||||||
betaDistMax = 15;
|
|
||||||
betaTiltMin = 3;
|
|
||||||
betaTiltMax = 15;
|
|
||||||
alphaDistMin = 2.5;
|
|
||||||
alphaDistMax = 3;
|
|
||||||
alphaTiltMin = 15; % degrees
|
|
||||||
alphaTiltMax = 30; % degrees
|
|
||||||
|
|
||||||
% Communications
|
% Communications
|
||||||
comRange = 8; % Maximum range between agents that forms a communications link
|
comRange = 5; % Maximum range between agents that forms a communications link
|
||||||
end
|
end
|
||||||
|
|
||||||
% Setup for each test
|
% Setup for each test
|
||||||
@@ -104,11 +93,9 @@ classdef test_miSim < matlab.unittest.TestCase
|
|||||||
if ii == 1
|
if ii == 1
|
||||||
while agentsCrowdObjective(tc.domain.objective, candidatePos, mean(tc.domain.dimensions) / 2)
|
while agentsCrowdObjective(tc.domain.objective, candidatePos, mean(tc.domain.dimensions) / 2)
|
||||||
candidatePos = tc.domain.random();
|
candidatePos = tc.domain.random();
|
||||||
candidatePos(3) = 1 + rand * 3; % place agents at decent altitudes for sensing
|
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
candidatePos = tc.agents{randi(ii - 1)}.pos + sign(randn([1, 3])) .* (rand(1, 3) .* tc.comRange/sqrt(2));
|
candidatePos = tc.agents{randi(ii - 1)}.pos + sign(randn([1, 3])) .* (rand(1, 3) .* tc.comRange/sqrt(2));
|
||||||
candidatePos(3) = 1 + rand * 3; % place agents at decent altitudes for sensing
|
|
||||||
end
|
end
|
||||||
|
|
||||||
% Make sure that the candidate position is within the
|
% Make sure that the candidate position is within the
|
||||||
@@ -152,7 +139,7 @@ classdef test_miSim < matlab.unittest.TestCase
|
|||||||
|
|
||||||
% Initialize candidate agent sensor model
|
% Initialize candidate agent sensor model
|
||||||
sensor = sigmoidSensor;
|
sensor = sigmoidSensor;
|
||||||
sensor = sensor.initialize(tc.alphaDistMin + rand * (tc.alphaDistMax - tc.alphaDistMin), tc.betaDistMin + rand * (tc.betaDistMax - tc.betaDistMin), NaN, NaN, tc.alphaTiltMin + rand * (tc.alphaTiltMax - tc.alphaTiltMin), tc.betaTiltMin + rand * (tc.betaTiltMax - tc.betaTiltMin));
|
sensor = sensor.initialize(2.5, 3, NaN, NaN, deg2rad(15), 3);
|
||||||
|
|
||||||
% Initialize candidate agent
|
% Initialize candidate agent
|
||||||
newAgent = tc.agents{ii}.initialize(candidatePos, zeros(1,3), 0, 0, candidateGeometry, sensor, @gradientAscent, tc.comRange, ii, sprintf("Agent %d", ii));
|
newAgent = tc.agents{ii}.initialize(candidatePos, zeros(1,3), 0, 0, candidateGeometry, sensor, @gradientAscent, tc.comRange, ii, sprintf("Agent %d", ii));
|
||||||
@@ -203,7 +190,7 @@ classdef test_miSim < matlab.unittest.TestCase
|
|||||||
end
|
end
|
||||||
|
|
||||||
% Initialize the simulation
|
% Initialize the simulation
|
||||||
tc.testClass = tc.testClass.initialize(tc.domain, tc.domain.objective, tc.agents, tc.timestep, tc.partitoningFreq, tc.maxIter, tc.obstacles);
|
[tc.testClass, f] = tc.testClass.initialize(tc.domain, tc.domain.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
|
||||||
@@ -236,11 +223,9 @@ classdef test_miSim < matlab.unittest.TestCase
|
|||||||
if ii == 1
|
if ii == 1
|
||||||
while agentsCrowdObjective(tc.domain.objective, candidatePos, mean(tc.domain.dimensions) / 2)
|
while agentsCrowdObjective(tc.domain.objective, candidatePos, mean(tc.domain.dimensions) / 2)
|
||||||
candidatePos = tc.domain.random();
|
candidatePos = tc.domain.random();
|
||||||
candidatePos(3) = min([tc.domain.maxCorner(3) * 0.95, 0.5 + rand * (tc.alphaDistMax * (1.1) - 0.5)]); % place agents at decent altitudes for sensing
|
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
candidatePos = tc.agents{randi(ii - 1)}.pos + sign(randn([1, 3])) .* (rand(1, 3) .* tc.comRange/sqrt(2));
|
candidatePos = tc.agents{randi(ii - 1)}.pos + sign(randn([1, 3])) .* (rand(1, 3) .* tc.comRange/sqrt(2));
|
||||||
candidatePos(3) = min([tc.domain.maxCorner(3) * 0.95, 0.5 + rand * (tc.alphaDistMax * (1.1) - 0.5)]); % place agents at decent altitudes for sensing
|
|
||||||
end
|
end
|
||||||
|
|
||||||
% Make sure that the candidate position is within the
|
% Make sure that the candidate position is within the
|
||||||
@@ -284,7 +269,7 @@ classdef test_miSim < matlab.unittest.TestCase
|
|||||||
|
|
||||||
% Initialize candidate agent sensor model
|
% Initialize candidate agent sensor model
|
||||||
sensor = sigmoidSensor;
|
sensor = sigmoidSensor;
|
||||||
sensor = sensor.initialize(tc.alphaDistMin + rand * (tc.alphaDistMax - tc.alphaDistMin), tc.betaDistMin + rand * (tc.betaDistMax - tc.betaDistMin), NaN, NaN, tc.alphaTiltMin + rand * (tc.alphaTiltMax - tc.alphaTiltMin), tc.betaTiltMin + rand * (tc.betaTiltMax - tc.betaTiltMin));
|
sensor = sensor.initialize(2.5, 3, NaN, NaN, deg2rad(15), 3);
|
||||||
|
|
||||||
% Initialize candidate agent
|
% Initialize candidate agent
|
||||||
newAgent = tc.agents{ii}.initialize(candidatePos, zeros(1,3), 0, 0, candidateGeometry, sensor, @gradientAscent, tc.comRange, ii, sprintf("Agent %d", ii));
|
newAgent = tc.agents{ii}.initialize(candidatePos, zeros(1,3), 0, 0, candidateGeometry, sensor, @gradientAscent, tc.comRange, ii, sprintf("Agent %d", ii));
|
||||||
@@ -335,10 +320,10 @@ classdef test_miSim < matlab.unittest.TestCase
|
|||||||
end
|
end
|
||||||
|
|
||||||
% Initialize the simulation
|
% Initialize the simulation
|
||||||
tc.testClass = tc.testClass.initialize(tc.domain, tc.domain.objective, tc.agents, tc.timestep, tc.partitoningFreq, tc.maxIter, tc.obstacles);
|
[tc.testClass, f] = tc.testClass.initialize(tc.domain, tc.domain.objective, tc.agents, tc.timestep, tc.partitoningFreq, tc.maxIter, tc.obstacles);
|
||||||
|
|
||||||
% Run simulation loop
|
% Run simulation loop
|
||||||
tc.testClass = tc.testClass.run();
|
[tc.testClass, f] = tc.testClass.run(f);
|
||||||
end
|
end
|
||||||
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
|
||||||
@@ -351,66 +336,28 @@ classdef test_miSim < matlab.unittest.TestCase
|
|||||||
tc.domain.objective = tc.domain.objective.initialize(@(x, y) mvnpdf([x(:), y(:)], tc.domain.center(1:2)), tc.domain, tc.discretizationStep, tc.protectedRange);
|
tc.domain.objective = tc.domain.objective.initialize(@(x, y) mvnpdf([x(:), y(:)], tc.domain.center(1:2)), tc.domain, tc.discretizationStep, tc.protectedRange);
|
||||||
|
|
||||||
% Initialize agent collision geometry
|
% Initialize agent collision geometry
|
||||||
dh = [0,0,-1]; % bias agent altitude from domain center
|
|
||||||
geometry1 = rectangularPrism;
|
geometry1 = rectangularPrism;
|
||||||
geometry2 = geometry1;
|
geometry2 = geometry1;
|
||||||
geometry1 = geometry1.initialize([tc.domain.center + dh + [d, 0, 0] - tc.collisionRanges(1) * ones(1, 3); tc.domain.center + dh + [d, 0, 0] + tc.collisionRanges(1) * ones(1, 3)], REGION_TYPE.COLLISION, sprintf("Agent %d collision volume", 1));
|
geometry1 = geometry1.initialize([tc.domain.center + [d, 0, 0] - tc.collisionRanges(1) * ones(1, 3); tc.domain.center + [d, 0, 0] + tc.collisionRanges(1) * ones(1, 3)], REGION_TYPE.COLLISION, sprintf("Agent %d collision volume", 1));
|
||||||
geometry2 = geometry2.initialize([tc.domain.center + dh - [d, 0, 0] - tc.collisionRanges(1) * ones(1, 3); tc.domain.center + dh - [d, 0, 0] + tc.collisionRanges(1) * ones(1, 3)], REGION_TYPE.COLLISION, sprintf("Agent %d collision volume", 2));
|
geometry2 = geometry2.initialize([tc.domain.center - [d, 0, 0] - tc.collisionRanges(1) * ones(1, 3); tc.domain.center - [d, 0, 0] + tc.collisionRanges(1) * ones(1, 3)], REGION_TYPE.COLLISION, sprintf("Agent %d collision volume", 2));
|
||||||
|
|
||||||
% Initialize agent sensor model
|
% Initialize agent sensor model
|
||||||
sensor = sigmoidSensor;
|
sensor = sigmoidSensor;
|
||||||
% Homogeneous sensor model parameters
|
sensor = sensor.initialize(2.5, 3, NaN, NaN, deg2rad(15), 3);
|
||||||
sensor = sensor.initialize(2.75, 9, NaN, NaN, 22.5, 9);
|
|
||||||
% Heterogeneous sensor model parameters
|
|
||||||
% sensor = sensor.initialize(tc.alphaDistMin + rand * (tc.alphaDistMax - tc.alphaDistMin), tc.betaDistMin + rand * (tc.betaDistMax - tc.betaDistMin), NaN, NaN, tc.alphaTiltMin + rand * (tc.alphaTiltMax - tc.alphaTiltMin), tc.betaTiltMin + rand * (tc.betaTiltMax - tc.betaTiltMin));
|
|
||||||
|
|
||||||
% Plot sensor parameters (optional)
|
|
||||||
% f = sensor.plotParameters();
|
|
||||||
|
|
||||||
% Initialize agents
|
% Initialize agents
|
||||||
tc.agents = {agent; agent};
|
tc.agents = {agent; agent};
|
||||||
tc.agents{1} = tc.agents{1}.initialize(tc.domain.center + dh + [d, 0, 0], zeros(1,3), 0, 0, geometry1, sensor, @gradientAscent, 3*d, 1, sprintf("Agent %d", 1));
|
tc.agents{1} = tc.agents{1}.initialize(tc.domain.center + [d, 0, 0], zeros(1,3), 0, 0, geometry1, sensor, @gradientAscent, 3*d, 1, sprintf("Agent %d", 1));
|
||||||
tc.agents{2} = tc.agents{2}.initialize(tc.domain.center + dh - [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));
|
||||||
|
|
||||||
% Optional third agent along the +Y axis
|
% Optional third agent along the +Y axis
|
||||||
geometry3 = rectangularPrism;
|
% geometry3 = rectangularPrism;
|
||||||
geometry3 = geometry3.initialize([tc.domain.center + dh - [0, d, 0] - tc.collisionRanges(1) * ones(1, 3); tc.domain.center + dh - [0, d, 0] + tc.collisionRanges(1) * ones(1, 3)], REGION_TYPE.COLLISION, sprintf("Agent %d collision volume", 3));
|
% geometry3 = geometry3.initialize([tc.domain.center - [0, d, 0] - tc.collisionRanges(1) * ones(1, 3); tc.domain.center - [0, d, 0] + tc.collisionRanges(1) * ones(1, 3)], REGION_TYPE.COLLISION, sprintf("Agent %d collision volume", 3));
|
||||||
tc.agents{3} = agent;
|
% tc.agents{3} = agent;
|
||||||
tc.agents{3} = tc.agents{3}.initialize(tc.domain.center + dh - [0, d, 0], zeros(1, 3), 0, 0, geometry3, sensor, @gradientAscent, 3*d, 3, sprintf("Agent %d", 3));
|
% tc.agents{3} = tc.agents{3}.initialize(tc.domain.center - [0, d, 0], zeros(1, 3), 0, 0, geometry3, sensor, @gradientAscent, 3*d, 3, sprintf("Agent %d", 3));
|
||||||
|
|
||||||
% Initialize the simulation
|
% Initialize the simulation
|
||||||
tc.testClass = tc.testClass.initialize(tc.domain, tc.domain.objective, tc.agents, tc.timestep, tc.partitoningFreq, tc.maxIter);
|
[tc.testClass, f] = tc.testClass.initialize(tc.domain, tc.domain.objective, tc.agents, tc.timestep, tc.partitoningFreq, tc.maxIter);
|
||||||
close(tc.testClass.fPerf);
|
|
||||||
end
|
|
||||||
function test_single_partition(tc)
|
|
||||||
% make basic domain
|
|
||||||
l = 10; % domain size
|
|
||||||
tc.domain = tc.domain.initialize([zeros(1, 3); l * ones(1, 3)], REGION_TYPE.DOMAIN, "Domain");
|
|
||||||
|
|
||||||
% make basic sensing objective
|
|
||||||
tc.domain.objective = tc.domain.objective.initialize(@(x, y) mvnpdf([x(:), y(:)], tc.domain.center(1:2) + rand(1, 2) * 6 - 3), tc.domain, tc.discretizationStep, tc.protectedRange);
|
|
||||||
|
|
||||||
% Initialize agent collision geometry
|
|
||||||
geometry1 = rectangularPrism;
|
|
||||||
geometry1 = geometry1.initialize([[tc.domain.center(1:2), 3] - tc.collisionRanges(1) * ones(1, 3); [tc.domain.center(1:2), 3] + tc.collisionRanges(1) * ones(1, 3)], REGION_TYPE.COLLISION, sprintf("Agent %d collision volume", 1));
|
|
||||||
|
|
||||||
% Initialize agent sensor model
|
|
||||||
sensor = sigmoidSensor;
|
|
||||||
% Homogeneous sensor model parameters
|
|
||||||
% sensor = sensor.initialize(2.5666, 5.0807, NaN, NaN, 20.8614, 13); % 13
|
|
||||||
alphaDist = l/2; % half of domain length/width
|
|
||||||
sensor = sensor.initialize(alphaDist, 3, NaN, NaN, 20, 3);
|
|
||||||
|
|
||||||
% Plot sensor parameters (optional)
|
|
||||||
f = sensor.plotParameters();
|
|
||||||
|
|
||||||
% Initialize agents
|
|
||||||
tc.agents = {agent};
|
|
||||||
tc.agents{1} = tc.agents{1}.initialize([tc.domain.center(1:2), 3], zeros(1,3), 0, 0, geometry1, sensor, @gradientAscent, 3, 1, sprintf("Agent %d", 1));
|
|
||||||
|
|
||||||
% Initialize the simulation
|
|
||||||
tc.testClass = tc.testClass.initialize(tc.domain, tc.domain.objective, tc.agents, tc.timestep, tc.partitoningFreq, tc.maxIter);
|
|
||||||
close(tc.testClass.fPerf);
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -1,62 +0,0 @@
|
|||||||
classdef test_sigmoidSensor < matlab.unittest.TestCase
|
|
||||||
properties (Access = private)
|
|
||||||
% System under test
|
|
||||||
testClass = sigmoidSensor;
|
|
||||||
|
|
||||||
% Domain
|
|
||||||
domain = rectangularPrism;
|
|
||||||
|
|
||||||
% Sensor parameter ranges
|
|
||||||
betaDistMin = 3;
|
|
||||||
betaDistMax = 15;
|
|
||||||
betaTiltMin = 3;
|
|
||||||
betaTiltMax = 15;
|
|
||||||
alphaDistMin = 2.5;
|
|
||||||
alphaDistMax = 3;
|
|
||||||
alphaTiltMin = 15; % degrees
|
|
||||||
alphaTiltMax = 30; % degrees
|
|
||||||
end
|
|
||||||
|
|
||||||
methods (TestMethodSetup)
|
|
||||||
function tc = setup(tc)
|
|
||||||
% Reinitialize sensor with random parameters
|
|
||||||
tc.testClass = sigmoidSensor;
|
|
||||||
tc.testClass = tc.testClass.initialize(tc.alphaDistMin + rand * (tc.alphaDistMax - tc.alphaDistMin), tc.betaDistMin + rand * (tc.betaDistMax - tc.betaDistMin), NaN, NaN, tc.alphaTiltMin + rand * (tc.alphaTiltMax - tc.alphaTiltMin), tc.betaTiltMin + rand * (tc.betaTiltMax - tc.betaTiltMin));
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
methods (Test)
|
|
||||||
% Test methods
|
|
||||||
function test_sensorPerformance(tc)
|
|
||||||
tc.testClass = sigmoidSensor;
|
|
||||||
alphaDist = 2.5;
|
|
||||||
betaDist = 3;
|
|
||||||
alphaTilt = 15; % degrees
|
|
||||||
betaTilt = 3;
|
|
||||||
h = 1e-6;
|
|
||||||
tc.testClass = tc.testClass.initialize(alphaDist, betaDist, NaN, NaN, alphaTilt, betaTilt);
|
|
||||||
|
|
||||||
% Plot (optional)
|
|
||||||
% tc.testClass.plotParameters();
|
|
||||||
|
|
||||||
% Anticipate perfect performance for a point directly below and
|
|
||||||
% extremely close
|
|
||||||
tc.verifyEqual(tc.testClass.sensorPerformance([0, 0, h], NaN, 0, [0, 0, 0]), 1, 'RelTol', 1e-3);
|
|
||||||
% It looks like mu_t can max out at really low values like 0.37
|
|
||||||
% when alphaTilt and betaTilt are small, which seems wrong
|
|
||||||
|
|
||||||
% Performance at nadir point, distance alphaDist should be 1/2 exactly
|
|
||||||
tc.verifyEqual(tc.testClass.sensorPerformance([0, 0, alphaDist], NaN, 0, [0, 0, 0]), 1/2);
|
|
||||||
|
|
||||||
% Performance at (almost) 0 distance, alphaTilt should be 1/2
|
|
||||||
tc.verifyEqual(tc.testClass.sensorPerformance([0, 0, h], NaN, 0, [tand(alphaTilt)*h, 0, 0]), 1/2, 'RelTol', 1e-3);
|
|
||||||
|
|
||||||
% Performance at great distance should be 0
|
|
||||||
tc.verifyEqual(tc.testClass.sensorPerformance([0, 0, 10], NaN, 0, [0, 0, 0]), 0, 'AbsTol', 1e-9);
|
|
||||||
|
|
||||||
% Performance at great tilt should be 0
|
|
||||||
tc.verifyEqual(tc.testClass.sensorPerformance([0, 0, h], NaN, 0, [5, 5, 0]), 0, 'AbsTol', 1e-9);
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
Reference in new issue
Block a user