better routing solution

This commit is contained in:
kdee committed 2026-07-12 22:50:14 -07:00
1 parent 56cc4fced5
commit 37598479cc
10 files changed
+469 -66

No files matched your search

+58 -58
View File
@@ -6,7 +6,12 @@ function obj = plotGraph(obj)
obj (1, 1) {mustBeA(obj, "miSim")};
end
nAgents = size(obj.agents, 1);
% The maintained (low-level connectivity) links are always drawn as a
% dotted undirected graph: basic traffic must be routable between any
% two drones at all times. In routing mode the bulk-data links selected
% by the LP are overlaid as SOLID DIRECTED edges (arrow = transmitter ->
% receiver) on the same node layout.
G = graph(obj.constraintAdjacencyMatrix, "omitselfloops");
% Resolve the target axes for the network graph tile
if isnan(obj.networkGraphIndex)
@@ -15,72 +20,67 @@ function obj = plotGraph(obj)
ax = obj.f.Children(1).Children(obj.networkGraphIndex(1));
end
% Build the graph to plot. The fixed-radius model is undirected. In SINR
% mode the link set (lesser-neighbor topology) is kept exactly as-is, but
% each connection is given an orientation: of the two directional SINRs on
% a link, the larger one wins, and the edge is directed from that
% direction's transmitter to its receiver (arrow = transmitter -> receiver).
% Plot graph object(s)
hold(ax, "on");
o = plot(ax, G, "LineStyle", "--", "EdgeColor", "g", "NodeColor", "k", "LineWidth", 2);
if obj.useRoutingTopology
% Bulk overlay: reuse the base layout's node coordinates and hide
% the overlay's own nodes/labels so only its edges show. Sizeable
% arrowheads so the flow direction reads at tile size.
D = digraph(obj.routingAdjacencyMatrix);
o = [o; plot(ax, D, "XData", o(1).XData, "YData", o(1).YData, ...
"LineStyle", "-", "EdgeColor", "g", "LineWidth", 2, ...
"ArrowSize", 12, "Marker", "none", "NodeLabel", {})];
end
hold(ax, "off");
nBase = size(o, 1);
if ~isnan(obj.networkGraphIndex) && size(obj.networkGraphIndex, 2) > 1
for ii = 2:size(obj.networkGraphIndex, 2)
o = [o; copyobj(o(1:nBase), obj.f.Children(1).Children(obj.networkGraphIndex(ii)))];
end
end
% In SINR comms mode, label each edge with the connection's SINR and report
% the connectivity threshold in the tile title. The fixed-radius model is
% left unchanged (no edge labels, title stays as set in firstPlotSetup).
if obj.useSinrComms
endNodes = G.Edges.EndNodes;
nAgents = size(obj.agents, 1);
positions = zeros(nAgents, 3);
for kk = 1:nAgents
positions(kk, :) = obj.agents{kk}.pos;
end
D = false(nAgents); % directed adjacency: D(tx, rx) = true
for aa = 1:(nAgents - 1)
for bb = (aa + 1):nAgents
if obj.constraintAdjacencyMatrix(aa, bb)
sinrARx = obj.sinrLink(positions, aa, bb); % aa receives bb
sinrBRx = obj.sinrLink(positions, bb, aa); % bb receives aa
if sinrARx >= sinrBRx
D(bb, aa) = true; % better as bb -> aa (tx bb, rx aa)
else
D(aa, bb) = true; % better as aa -> bb (tx aa, rx bb)
end
end
end
end
G = digraph(D);
else
G = graph(obj.constraintAdjacencyMatrix, "omitselfloops");
end
% Plot graph object (digraph renders arrowheads automatically)
hold(ax, "on");
o = plot(ax, G, "LineStyle", "--", "EdgeColor", "g", "NodeColor", "k", "LineWidth", 2);
hold(ax, "off");
if ~isnan(obj.networkGraphIndex) && size(obj.networkGraphIndex, 2) > 1
for ii = 2:size(obj.networkGraphIndex, 2)
o = [o; copyobj(o(1), obj.f.Children(1).Children(obj.networkGraphIndex(ii)))];
end
end
% Mark ground-station-connected nodes with an "x" (others keep the default
% dot). Ground stations attach to the two "router" agents: agent 1 and the
% agent with the largest ODD index (that is nAgents when odd, else
% nAgents-1). With one or two agents only agent 1 qualifies.
routers = unique([1, 2 * ceil(nAgents / 2) - 1]);
for oo = 1:numel(o)
highlight(o(oo), routers, "Marker", "x", "MarkerSize", 8);
end
% In SINR comms mode, label each directed edge with the better SINR that set
% its orientation and report the threshold in the tile title. The
% fixed-radius model is left unchanged (no edge labels, title from setup).
if obj.useSinrComms
endNodes = G.Edges.EndNodes; % each row [tx rx] for a directed edge
% Label with the SINR of the chosen (better) direction: the receiver is
% the edge target, the transmitter the edge source. Bare numbers (no
% units) keep the small tile uncluttered; GraphPlot draws labels
% horizontally, left-to-right.
% Labels are bare numbers (no units) so they stay compact; GraphPlot
% renders them horizontally, left-to-right. Dotted (low-level) edges
% are labelled with the binding (worse) directional SINR — a link is
% feasible only if BOTH directions clear the threshold. Links that
% also carry a bulk overlay leave the label to the solid edge, which
% shows the SINR of the transmission direction.
edgeLabels = strings(size(endNodes, 1), 1);
for ee = 1:size(endNodes, 1)
sinrLin = obj.sinrLink(positions, endNodes(ee, 2), endNodes(ee, 1)); % rx, tx
edgeLabels(ee) = sprintf("%.1f", 10 * log10(sinrLin));
lo = endNodes(ee, 1);
hi = endNodes(ee, 2);
if obj.useRoutingTopology && (obj.routingAdjacencyMatrix(lo, hi) || obj.routingAdjacencyMatrix(hi, lo))
edgeLabels(ee) = ""; % solid overlay carries this link's label
else
sinrLoRx = obj.sinrLink(positions, lo, hi); % receiver lo (lower index)
sinrHiRx = obj.sinrLink(positions, hi, lo); % receiver hi (higher index)
edgeLabels(ee) = sprintf("%.1f", 10 * log10(min(sinrLoRx, sinrHiRx)));
end
end
o(1).EdgeLabel = edgeLabels;
% Threshold in the existing single-line title (not a subtitle) so the
% small tile isn't compressed, and disable the hover toolbar so the
% R2026 "..." menu stops covering the readout.
if obj.useRoutingTopology
endNodesD = D.Edges.EndNodes; % each row [tx rx]
bulkLabels = strings(size(endNodesD, 1), 1);
for ee = 1:size(endNodesD, 1)
sinrTx = obj.sinrLink(positions, endNodesD(ee, 2), endNodesD(ee, 1)); % rx, tx
bulkLabels(ee) = sprintf("%.1f", 10 * log10(sinrTx));
end
o(2).EdgeLabel = bulkLabels;
end
% Threshold goes in the existing single-line title (not a subtitle) so
% the small tile is not compressed further, and the hover toolbar is
% disabled so the R2026 "..." menu stops covering the readout.
title(ax, sprintf("Network Graph (\\geq %.1f dB)", obj.sinrThreshold));
ax.Toolbar.Visible = "off";
end