made SINR threshold check bidirectional

This commit is contained in:
kdee committed 2026-07-05 20:54:59 -07:00
1 parent f9aa9cc44d
commit 1d414e2bd4
5 files changed
+63 -28

No files matched your search

+32 -10
View File
@@ -169,11 +169,11 @@ function [obj] = constrainMotion(obj)
end end
end end
else else
% SINR comms: keep the SINR of each maintained link above threshold via % SINR comms: a link is feasible only if each agent receives the other
% the barrier h = SINR - gammaLin. Per the connectivity convention the % above threshold, so every maintained pair is held with TWO barrier
% lower-index agent (ii) receives the higher-index transmitter (jj). The % rows, h = SINR - gammaCbf, one per receiver direction. Each gradient
% gradient couples the receiver, transmitter, and every interferer, so % couples the receiver, transmitter, and every interferer, so the QP
% the QP row is dense across all agent blocks. % rows are dense across all agent blocks.
% Maintain SINR a margin above the connectivity threshold so that % Maintain SINR a margin above the connectivity threshold so that
% discrete-time overshoot of the (convex) SINR does not transiently % discrete-time overshoot of the (convex) SINR does not transiently
% drop a maintained link below threshold. Mirrors the fixed-radius % drop a maintained link below threshold. Mirrors the fixed-radius
@@ -188,19 +188,33 @@ function [obj] = constrainMotion(obj)
for ii = 1:(nAgents - 1) for ii = 1:(nAgents - 1)
for jj = (ii + 1):nAgents for jj = (ii + 1):nAgents
if obj.constraintAdjacencyMatrix(ii, jj) if obj.constraintAdjacencyMatrix(ii, jj)
[sinr, grad] = obj.sinrLink(lastPositions, ii, jj); % receiver ii, transmitter jj % Direction 1: lower-index agent (ii) receives higher (jj).
hComms(ii, jj) = sinr - gammaCbf; % Upper triangle of hComms stores this direction's barrier.
[sinr1, grad1] = obj.sinrLink(lastPositions, ii, jj);
hComms(ii, jj) = sinr1 - gammaCbf;
% CBF row: A = -grad(h), b = h/dt (one-step forward invariance) % CBF row: A = -grad(h), b = h/dt (one-step forward invariance)
for aa = 1:nAgents for aa = 1:nAgents
A(kk, (3 * aa - 2):(3 * aa)) = -grad(aa, :); A(kk, (3 * aa - 2):(3 * aa)) = -grad1(aa, :);
end end
if norm(A(kk, :)) < 1e-9 if norm(A(kk, :)) < 1e-9
b(kk) = 0; b(kk) = 0;
else else
b(kk) = hComms(ii, jj) / obj.timestep; b(kk) = hComms(ii, jj) / obj.timestep;
end end
kk = kk + 1;
% Direction 2: higher-index agent (jj) receives lower (ii).
% Lower triangle of hComms stores this direction's barrier.
[sinr2, grad2] = obj.sinrLink(lastPositions, jj, ii);
hComms(jj, ii) = sinr2 - gammaCbf;
for aa = 1:nAgents
A(kk, (3 * aa - 2):(3 * aa)) = -grad2(aa, :);
end
if norm(A(kk, :)) < 1e-9
b(kk) = 0;
else
b(kk) = hComms(jj, ii) / obj.timestep;
end
kk = kk + 1; kk = kk + 1;
end end
end end
@@ -208,7 +222,15 @@ function [obj] = constrainMotion(obj)
end end
if coder.target('MATLAB') if coder.target('MATLAB')
obj.barriers(idx:(idx + length(hComms(triu(true(size(hComms)), 1))) - 1), obj.timestepIndex) = hComms(triu(true(size(hComms)), 1)); if obj.useSinrComms
% Both directions are maintained: log the upper triangle
% (lower-index receiver) then the lower triangle (higher-index
% receiver), matching the doubled comms-barrier allocation.
commsLog = [hComms(triu(true(size(hComms)), 1)); hComms(tril(true(size(hComms)), -1))];
else
commsLog = hComms(triu(true(size(hComms)), 1));
end
obj.barriers(idx:(idx + numel(commsLog) - 1), obj.timestepIndex) = commsLog;
end end
% Double-integrator: transform QP from velocity to acceleration space. % Double-integrator: transform QP from velocity to acceleration space.
+6 -1
View File
@@ -143,8 +143,13 @@ function [obj] = initialize(obj, domain, agents, barrierGain, barrierExponent, m
% Comms barriers: size to the upper bound (full mesh) rather than the initial % Comms barriers: size to the upper bound (full mesh) rather than the initial
% constraint-adjacency count. Connectivity is dynamic (lesser-neighbor and, % constraint-adjacency count. Connectivity is dynamic (lesser-neighbor and,
% especially, SINR) and can later maintain more pairs than at init; sizing to % especially, SINR) and can later maintain more pairs than at init; sizing to
% nAAPairs prevents the QP A/b matrices from overflowing mid-run. % nAAPairs prevents the QP A/b matrices from overflowing mid-run. SINR mode
% enforces both directions per link, so it needs two barrier rows per pair.
if obj.useSinrComms
nLNAPairs = 2 * nAAPairs;
else
nLNAPairs = nAAPairs; nLNAPairs = nAAPairs;
end
obj.numBarriers = nAAPairs + nAOPairs + nADPairs + nLNAPairs; obj.numBarriers = nAAPairs + nAOPairs + nADPairs + nLNAPairs;
if coder.target('MATLAB') if coder.target('MATLAB')
+11 -7
View File
@@ -36,15 +36,19 @@ function obj = plotGraph(obj)
for kk = 1:nAgents for kk = 1:nAgents
positions(kk, :) = obj.agents{kk}.pos; positions(kk, :) = obj.agents{kk}.pos;
end end
% Directional convention (matches updateAdjacency/constrainMotion): % A link is feasible only if BOTH directions clear the threshold, so
% the lower-index node is the receiver, the higher-index node the % label each edge with the binding (worse) directional SINR: the min of
% transmitter, with interference from all other agents at the receiver. % the lower-index-receiver and higher-index-receiver links, with
% Labels are bare numbers (no units) so they stay compact; GraphPlot % interference from all other agents at each receiver. Labels are bare
% renders them horizontally, left-to-right. % numbers (no units) so they stay compact; GraphPlot renders them
% horizontally, left-to-right.
edgeLabels = strings(size(endNodes, 1), 1); edgeLabels = strings(size(endNodes, 1), 1);
for ee = 1:size(endNodes, 1) for ee = 1:size(endNodes, 1)
sinrLin = obj.sinrLink(positions, endNodes(ee, 1), endNodes(ee, 2)); lo = endNodes(ee, 1);
edgeLabels(ee) = sprintf("%.1f", 10 * log10(sinrLin)); hi = endNodes(ee, 2);
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; o(1).EdgeLabel = edgeLabels;
% Threshold goes in the existing single-line title (not a subtitle) so % Threshold goes in the existing single-line title (not a subtitle) so
+9 -6
View File
@@ -23,9 +23,11 @@ function obj = updateAdjacency(obj)
end end
end end
else else
% SINR model: pair (ii, jj) connected iff the lower-index agent (jj) % SINR model: a link between a pair is feasible only if BOTH directional
% receives the higher-index agent's (ii) signal above the SINR % SINRs clear the threshold, i.e. each agent receives the other's signal
% threshold, with interference from all other agents at the receiver. % above gammaLin (with interference from all other agents at the
% receiver). Every ordered pair (permutation) is evaluated; a single
% failing direction eliminates the undirected link.
gammaLin = 10^(obj.sinrThreshold / 10); % dB threshold -> linear gammaLin = 10^(obj.sinrThreshold / 10); % dB threshold -> linear
positions = zeros(nAgents, 3); positions = zeros(nAgents, 3);
for kk = 1:nAgents for kk = 1:nAgents
@@ -33,9 +35,10 @@ function obj = updateAdjacency(obj)
end end
for ii = 2:nAgents for ii = 2:nAgents
for jj = 1:(ii - 1) for jj = 1:(ii - 1)
sinr = obj.sinrLink(positions, jj, ii); % receiver jj, transmitter ii sinrLoRx = obj.sinrLink(positions, jj, ii); % receiver jj (lower), transmitter ii
if sinr < gammaLin sinrHiRx = obj.sinrLink(positions, ii, jj); % receiver ii (higher), transmitter jj
A(ii, jj) = false; % SINR below threshold if sinrLoRx < gammaLin || sinrHiRx < gammaLin
A(ii, jj) = false; % at least one direction below threshold
continue; continue;
end end
end end
+5 -4
View File
@@ -857,18 +857,19 @@ classdef test_miSim < matlab.unittest.TestCase
% fixed-radius variant of this test (so the two agents still cannot % fixed-radius variant of this test (so the two agents still cannot
% reach their objectives without breaking connectivity). % reach their objectives without breaking connectivity).
useSinrComms = true; useSinrComms = true;
txPower = 0.1; % transmit power per agent (W) txPower = [0.01, 0.01]; % transmit power per agent (W)
pathLossExponent = 2.0; pathLossExponent = 2.0;
ambientTemp = 290; % K ambientTemp = 290; % K
centerFreq = 2.4e9; % Hz centerFreq = 2.4e9; % Hz
bandwidth = 20e6; % Hz bandwidth = 20e6; % Hz
effRange = 4.0; % desired effective comms range (m) effRange = 4.0; % desired effective comms range (m)
K_pl = (4 * pi * centerFreq / 3e8)^2; % free-space path-loss reference K_pl = (4 * pi * centerFreq / 3e8)^2; % free-space path-loss reference
noiseW = 1.380649e-23 * ambientTemp * bandwidth; % thermal noise (W) noiseW = 1.380649e-23 * ambientTemp * bandwidth; % thermal noise (W)
sinrThreshold = 10 * log10(txPower / (K_pl * effRange^pathLossExponent * noiseW)); % dB sinrThreshold = 10 * log10(mean(txPower) / (K_pl * effRange^pathLossExponent * noiseW)); % dB
tc.agents{1}.txPower = txPower; tc.agents{1}.txPower = txPower(1);
tc.agents{2}.txPower = txPower; tc.agents{2}.txPower = txPower(2);
% Initialize the simulation in SINR comms mode % Initialize the simulation in SINR comms mode
tc.testClass = tc.testClass.initialize(tc.domain, tc.agents, tc.barrierGain, tc.barrierExponent, tc.minAlt, tc.timestep, tc.maxIter, tc.obstacles, tc.makePlots, tc.makeVideo, tc.useDoubleIntegrator, tc.dampingCoeff, tc.useFixedTopology, tc.optimizeSensorPointing, useSinrComms, sinrThreshold, pathLossExponent, ambientTemp, centerFreq, bandwidth); tc.testClass = tc.testClass.initialize(tc.domain, tc.agents, tc.barrierGain, tc.barrierExponent, tc.minAlt, tc.timestep, tc.maxIter, tc.obstacles, tc.makePlots, tc.makeVideo, tc.useDoubleIntegrator, tc.dampingCoeff, tc.useFixedTopology, tc.optimizeSensorPointing, useSinrComms, sinrThreshold, pathLossExponent, ambientTemp, centerFreq, bandwidth);