diff --git a/@miSim/miSim.m b/@miSim/miSim.m index 9034478..cbb3d9b 100644 --- a/@miSim/miSim.m +++ b/@miSim/miSim.m @@ -14,6 +14,9 @@ classdef miSim sensorPerformanceMinimum = 1e-6; % minimum sensor performance to allow assignment of a point in the domain to a partition partitioning = NaN; performance = NaN; % current cumulative sensor performance + oldMeanTotalPerf = 0; + + fPerf; % performance plot figure end properties (Access = private) @@ -29,7 +32,6 @@ classdef miSim graphPlot; % objects for abstract network graph plot partitionPlot; % objects for partition plot - fPerf; % performance plot figure performancePlot; % objects for sensor performance plot % Indicies for various plot types in the main tiled layout figure diff --git a/@miSim/run.m b/@miSim/run.m index 0615549..437693e 100644 --- a/@miSim/run.m +++ b/@miSim/run.m @@ -10,6 +10,7 @@ function [obj] = run(obj) v = obj.setupVideoWriter(); v.open(); + steady = 0; for ii = 1:size(obj.times, 1) % Display current sim time obj.t = obj.times(ii); @@ -18,6 +19,19 @@ function [obj] = run(obj) % Check if it's time for new partitions updatePartitions = false; if ismember(obj.t, obj.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; obj = obj.partition(); end diff --git a/test/test_miSim.m b/test/test_miSim.m index 8a53890..33de5b9 100644 --- a/test/test_miSim.m +++ b/test/test_miSim.m @@ -104,10 +104,11 @@ classdef test_miSim < matlab.unittest.TestCase if ii == 1 while agentsCrowdObjective(tc.domain.objective, candidatePos, mean(tc.domain.dimensions) / 2) candidatePos = tc.domain.random(); - candidatePos(3) = 2 + rand * 1.5; % place agents at decent altitudes for sensing + candidatePos(3) = 1 + rand * 3; % place agents at decent altitudes for sensing end else 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 % Make sure that the candidate position is within the @@ -239,6 +240,7 @@ classdef test_miSim < matlab.unittest.TestCase end else 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 % Make sure that the candidate position is within the @@ -359,10 +361,12 @@ classdef test_miSim < matlab.unittest.TestCase sensor = sigmoidSensor; % Homogeneous sensor model parameters sensor = sensor.initialize(2.75, 9, NaN, NaN, 22.5, 9); - f = sensor.plotParameters(); % 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 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)); @@ -376,6 +380,7 @@ classdef test_miSim < matlab.unittest.TestCase % 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 function test_single_partition(tc) % make basic domain @@ -383,7 +388,7 @@ classdef test_miSim < matlab.unittest.TestCase 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)), tc.domain, tc.discretizationStep, tc.protectedRange); + 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; @@ -395,6 +400,8 @@ classdef test_miSim < matlab.unittest.TestCase % 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 @@ -403,7 +410,7 @@ classdef test_miSim < matlab.unittest.TestCase % 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 diff --git a/test/test_sigmoidSensor.m b/test/test_sigmoidSensor.m index 199cc10..007932d 100644 --- a/test/test_sigmoidSensor.m +++ b/test/test_sigmoidSensor.m @@ -36,8 +36,8 @@ classdef test_sigmoidSensor < matlab.unittest.TestCase h = 1e-6; tc.testClass = tc.testClass.initialize(alphaDist, betaDist, NaN, NaN, alphaTilt, betaTilt); - % Plot - tc.testClass.plotParameters(); + % Plot (optional) + % tc.testClass.plotParameters(); % Anticipate perfect performance for a point directly below and % extremely close