rf sensor model cleanup

This commit is contained in:
kdee committed 2026-05-29 19:38:51 -07:00
1 parent 8e8bb39cd9
commit 2f9f13fdc8
8 files changed
+42 -44

No files matched your search

+1 -2
View File
@@ -19,6 +19,5 @@ function value = RSS(obj, d, dx, dy, dz)
cos_theta = (st .* (dx .* sa + dy .* ca) - ct .* dz) ./ max(d, eps);
cos_theta = max(-1, min(1, cos_theta));
theta = acosd(cos_theta);
gain = 10 .* obj.beamwidthExponent .* log10((1 + cosd(theta)) ./ 2);
value = obj.P_TX_dBm + gain + obj.G_RX_dBi - obj.pathLoss(d);
value = obj.P_TX_dBm + obj.transmitterGain(theta) + obj.G_RX_dBi - obj.pathLoss(d);
end
+1 -5
View File
@@ -5,12 +5,8 @@ function value = halfAngle(obj)
arguments (Output)
value (1, 1) double;
end
% Sweep angular offset from boresight by evaluating transmitterGain at
% (obj.tilt + dtheta, obj.azimuth). The cosine difference identity guarantees
% the resulting angular offset from boresight equals dtheta exactly,
% independent of the actual pointing direction.
dtheta = (0:0.1:179.9)';
gain = obj.transmitterGain(obj.tilt + dtheta, obj.azimuth * ones(size(dtheta)));
gain = obj.transmitterGain(dtheta);
target = gain(1) - 3;
idx = find(gain <= target, 1);
if isempty(idx) || idx == 1
+4 -1
View File
@@ -1,7 +1,8 @@
function obj = initialize(obj, txPower, bandwidth, centerFreq, rxGain_dBi, beamwidthExponent, tilt, azimuth, lossExponent)
function obj = initialize(obj, txPower, temperature, bandwidth, centerFreq, rxGain_dBi, beamwidthExponent, tilt, azimuth, lossExponent)
arguments (Input)
obj (1, 1) {mustBeA(obj, "rfSensor")}
txPower (1, 1) double;
temperature (1, 1) double;
bandwidth (1, 1) double;
centerFreq (1, 1) double;
rxGain_dBi (1, 1) double;
@@ -16,6 +17,7 @@ function obj = initialize(obj, txPower, bandwidth, centerFreq, rxGain_dBi, beamw
%% Provided values
obj.P_TX = txPower; % Transmit power (W)
obj.T_0 = temperature; % Temperature (K)
obj.BW = bandwidth; % Bandwidth (Hz)
obj.f_c = centerFreq; % Center frequency (Hz)
obj.G_RX_dBi = rxGain_dBi; % Receiving Antenna Gain (dBi)
@@ -29,4 +31,5 @@ function obj = initialize(obj, txPower, bandwidth, centerFreq, rxGain_dBi, beamw
%% Computed values
obj.P_TX_dBm = 10*log10(obj.P_TX/1e-3); % Transmit power in dBm
obj.N = obj.k_B * obj.T_0 * obj.BW; % Thermal noise
obj.constantGainTerm_dB = 10 .* log10(2 * (obj.beamwidthExponent + 1)); % used in RSS calculation, only need to compute once
end
+5 -2
View File
@@ -23,8 +23,11 @@ function f = plotParameters(obj)
% For agent at altitude alt, ground target at tilt T has slant distance:
D = alt ./ cosd(T);
% Compute RSS for each (d, t, a) triple
rss = obj.RSS(D(:), T(:), A(:));
% Convert LOS (D, T, A) to displacement vectors for RSS
dx = D .* sind(T) .* sind(A);
dy = D .* sind(T) .* cosd(A);
dz = -D .* cosd(T); % negative: ground targets are below agent
rss = obj.RSS(D(:), dx(:), dy(:), dz(:));
Fslice = reshape(rss, size(D));
% Disc geometry: t=0 (nadir) -> center, t~90 (horizon) -> edge
+3 -2
View File
@@ -14,6 +14,7 @@ classdef rfSensor
% Values computed at initialization
P_TX_dBm = NaN; % Transmit power (dBm)
N = NaN; % Thermal noise
constantGainTerm_dB = NaN; % used in RSS calculation, only need to compute once
% Cached state (per timestep)
end
properties (Access = public)
@@ -23,7 +24,7 @@ classdef rfSensor
end
methods (Access = public)
[obj] = initialize(obj, txPower, bandwidth, centerFreq, rxGain, beamwidthExponent, tilt, azimuth); % initialize sensor, define parameters
[obj] = initialize(obj, txPower, temperature, bandwidth, centerFreq, rxGain, beamwidthExponent, tilt, azimuth); % initialize sensor, define parameters
[SINR, SNR, obj, otherSensors] = sensorPerformance(obj, agentPos, targetPos, otherSensorsPos, otherSensors); % determine sensor performance for a given single sensor and target geometry
[d, dx, dy, dz] = computePointToPoints(obj, agentPos, targetPos);
[value] = halfAngle(obj); % tilt angle (deg) at which sensor performance is halved
@@ -34,7 +35,7 @@ classdef rfSensor
end
methods (Access = private)
x = RSS(obj, d, dx, dy, dz); % Received signal strength (function of distance and tilt angle)
G_TX_dB = transmitterGain(obj, t, a); % Antenna gain for a given TX/RX pair
G_TX_dB = transmitterGain(obj, theta); % Antenna gain for a given angle from boresight (degrees)
L_FSPL_dB = pathLoss(obj, d); % Free space path loss for a given TX/RX pair
end
end
+5 -16
View File
@@ -1,23 +1,12 @@
function value = transmitterGain(obj, t, a)
function value = transmitterGain(obj, theta)
arguments (Input)
obj (1, 1) {mustBeA(obj, "rfSensor")};
t (:, 1) double; % LOS tilt angle
a (:, 1) double; % LOS azimuth angle
theta (:, 1) double; % angle from boresight (degrees)
end
arguments (Output)
value (:, 1) double
end
if ~isequal(size(t), size(a))
error("t and a must be the same size");
end
% Angular offset from boresight via spherical law of cosines
% Convention: t=0° nadir, t=90° horizon; a=0° +y, a=90° +x
cos_theta = sind(obj.tilt) .* sind(t) .* cosd(a - obj.azimuth) + ...
cosd(obj.tilt) .* cosd(t);
cos_theta = max(-1, min(1, cos_theta)); % clamp for numerical safety
theta = acosd(cos_theta);
% Cardioid family: peak at boresight (theta=0), null opposite (theta=180°)
value = 10 .* obj.beamwidthExponent .* log10((1 + cosd(theta)) ./ 2);
% Cosine pattern: peak at boresight, -inf dB at 90°.
% Clamped so targets behind the antenna (theta > 90°) get -inf rather than NaN.
value = obj.constantGainTerm_dB + 10 .* obj.beamwidthExponent .* log10(max(0, cosd(theta)));
end
+4 -3
View File
@@ -57,6 +57,7 @@ classdef test_miSim < matlab.unittest.TestCase
opticalPartitioningMin = 1e-6;
% rfSensor
P_TX = 1e-3; % Transmit power (Watts)
T_0 = 300; % Temperature (K)
BW = 20e6; % Bandwidth (Hz)
f_c = 3e9; % Center frequency (Hz)
G_RX_dBi = 3; % Receiving Antenna Gain (dBi)
@@ -323,7 +324,7 @@ classdef test_miSim < matlab.unittest.TestCase
% Initialize candidate agent sensor model
tc.sensor = rfSensor;
tilt = 0; azimuth = 0;
tc.sensor = tc.sensor.initialize(tc.P_TX * 1 + rand * 4, tc.BW, tc.f_c, tc.G_RX_dBi, tc.beamwidthExponent + randi(100), tilt, azimuth, tc.lossExponent);
tc.sensor = tc.sensor.initialize(tc.P_TX * 1 + rand * 4, tc.T_0, tc.BW, tc.f_c, tc.G_RX_dBi, tc.beamwidthExponent + randi(100), tilt, azimuth, tc.lossExponent);
% Initialize candidate agent
newAgent = tc.agents{ii}.initialize(candidatePos, candidateGeometry, tc.sensor, tc.commsRanges(ii), tc.maxIter, tc.initialStepSize, tc.initialMaxAngleStepSize);
@@ -659,7 +660,7 @@ classdef test_miSim < matlab.unittest.TestCase
geometry1 = geometry1.initialize([tc.domain.center(1:2)-tc.domain.dimensions(1)/4, 3], tc.collisionRanges(1), REGION_TYPE.COLLISION);
tc.sensor = rfSensor;
tc.sensor = tc.sensor.initialize(tc.P_TX, tc.BW, tc.f_c, tc.G_RX_dBi, tc.beamwidthExponent, 45, 45, tc.lossExponent);
tc.sensor = tc.sensor.initialize(tc.P_TX, tc.T_0, tc.BW, tc.f_c, tc.G_RX_dBi, tc.beamwidthExponent, 45, 45, tc.lossExponent);
% Initialize agents
tc.maxIter = 75;
@@ -717,7 +718,7 @@ classdef test_miSim < matlab.unittest.TestCase
% Initialize agent sensor model
tc.sensor = rfSensor;
tc.sensor = tc.sensor.initialize(tc.P_TX, tc.BW, tc.f_c, tc.G_RX_dBi, tc.beamwidthExponent, 0, 0, tc.lossExponent);
tc.sensor = tc.sensor.initialize(tc.P_TX, tc.T_0, tc.BW, tc.f_c, tc.G_RX_dBi, tc.beamwidthExponent, 0, 0, tc.lossExponent);
% Initialize agents
tc.maxIter = 75;
+19 -13
View File
@@ -15,28 +15,30 @@ classdef test_rfSensor < matlab.unittest.TestCase
function plot_RSS(tc)
% Plot sensor performance with no sources of interference
P_TX = 1e-3; % Transmit power (Watts)
T_0 = 300; % Temperature (K)
BW = 20e6; % Bandwidth (Hz)
f_c = 2e9; % Center frequency (Hz)
G_RX_dBi = 3; % Receiving Antenna Gain (dBi)
beamwidthExponent = 6;
lossExponent = 2;
tc.testClass = tc.testClass.initialize(P_TX, BW, f_c, G_RX_dBi, beamwidthExponent, 0, 0, lossExponent);
tc.testClass = tc.testClass.initialize(P_TX, T_0, BW, f_c, G_RX_dBi, beamwidthExponent, 0, 0, lossExponent);
tc.testClass.plotParameters();
end
function plot_SNR(tc)
% Plot sensor performance with no sources of interference
P_TX = 1e-3; % Transmit power (Watts)
T_0 = 300; % Temperature (K)
BW = 20e6; % Bandwidth (Hz)
f_c = 2e9; % Center frequency (Hz)
G_RX_dBi = 3; % Receiving Antenna Gain (dBi)
beamwidthExponent = 6;
lossExponent = 2;
tc.testClass = tc.testClass.initialize(P_TX, BW, f_c, G_RX_dBi, beamwidthExponent, 30, 135, lossExponent);
tc.testClass = tc.testClass.initialize(P_TX, T_0, BW, f_c, G_RX_dBi, beamwidthExponent, 30, 135, lossExponent);
altitude = 30;
altitude = 20;
% Boresight azimuth=135° (between +X at 90° and -Y at 180°) → hotspot at +X,-Y.
% SNR at (5,-5) should be higher than at (5,+5).
@@ -51,13 +53,14 @@ classdef test_rfSensor < matlab.unittest.TestCase
function plot_SINR_one_interferer(tc)
% Plot sensor performance with no sources of interference
P_TX = 1e-3; % Transmit power (Watts)
T_0 = 300; % Temperature (K)
BW = 20e6; % Bandwidth (Hz)
f_c = 2e9; % Center frequency (Hz)
G_RX_dBi = 3; % Receiving Antenna Gain (dBi)
beamwidthExponent = 6;
lossExponent = 2;
tc.testClass = tc.testClass.initialize(P_TX, BW, f_c, G_RX_dBi, beamwidthExponent, 0, 0, lossExponent);
tc.testClass = tc.testClass.initialize(P_TX, T_0, BW, f_c, G_RX_dBi, beamwidthExponent, 0, 0, lossExponent);
altitude = 30;
otherSensorsPos = [6, -4, -1]; % relative to main sensor
@@ -70,13 +73,14 @@ classdef test_rfSensor < matlab.unittest.TestCase
function plot_SINR_heterogenous_interferers(tc)
% Plot sensor performance with no sources of interference
P_TX = 1e-3; % Transmit power (Watts)
T_0 = 300; % Temperature (K)
BW = 20e6; % Bandwidth (Hz)
f_c = 2e9; % Center frequency (Hz)
G_RX_dBi = 3; % Receiving Antenna Gain (dBi)
beamwidthExponent = 6;
lossExponent = 2;
tc.testClass = tc.testClass.initialize(P_TX, BW, f_c, G_RX_dBi, beamwidthExponent, 0, 0, lossExponent);
tc.testClass = tc.testClass.initialize(P_TX, T_0, BW, f_c, G_RX_dBi, beamwidthExponent, 0, 0, lossExponent);
altitude = 30;
otherSensorsPos = [6, -4, -1; -2, 6, 0]; % relative to main sensor
@@ -85,13 +89,14 @@ classdef test_rfSensor < matlab.unittest.TestCase
otherSensors{2} = rfSensor;
% Must use same center frequency and bandwidth for interference sources
otherSensors{1} = otherSensors{1}.initialize(10 * P_TX, BW, f_c, G_RX_dBi, beamwidthExponent, 0, 0, lossExponent);
otherSensors{2} = otherSensors{2}.initialize(10 * P_TX, BW, f_c, G_RX_dBi, beamwidthExponent, 0, 0, lossExponent);
otherSensors{1} = otherSensors{1}.initialize(10 * P_TX, T_0, BW, f_c, G_RX_dBi, beamwidthExponent, 0, 0, lossExponent);
otherSensors{2} = otherSensors{2}.initialize(10 * P_TX, T_0, BW, f_c, G_RX_dBi, beamwidthExponent, 0, 0, lossExponent);
tc.testClass.plotPerformance(altitude, otherSensorsPos, otherSensors);
end
function plot_SINR_heterogenous_interferers_efficiently(tc)
P_TX = 1e-3;
T_0 = 300;
BW = 20e6;
f_c = 2e9;
G_RX_dBi = 3;
@@ -100,11 +105,11 @@ classdef test_rfSensor < matlab.unittest.TestCase
lossExponent = 2;
sensor1 = rfSensor;
sensor1 = sensor1.initialize(P_TX, BW, f_c, G_RX_dBi, beamwidthExponent(1), 15, 45, lossExponent);
sensor1 = sensor1.initialize(P_TX, T_0, BW, f_c, G_RX_dBi, beamwidthExponent(1), 15, 45, lossExponent);
sensor2 = rfSensor;
sensor2 = sensor2.initialize(P_TX, BW, f_c, G_RX_dBi, beamwidthExponent(2), 10, 150, lossExponent);
sensor2 = sensor2.initialize(P_TX, T_0, BW, f_c, G_RX_dBi, beamwidthExponent(2), 10, 150, lossExponent);
sensor3 = rfSensor;
sensor3 = sensor3.initialize(P_TX, BW, f_c, G_RX_dBi, beamwidthExponent(3), 20, 200, lossExponent);
sensor3 = sensor3.initialize(P_TX, T_0, BW, f_c, G_RX_dBi, beamwidthExponent(3), 20, 200, lossExponent);
pos1 = [0, 0, altitude];
pos2 = [6, -4, altitude - 1];
@@ -141,6 +146,7 @@ classdef test_rfSensor < matlab.unittest.TestCase
end
function plot_SINR_heterogenous_interferers_3d(tc)
P_TX = 1e-3;
T_0 = 300;
BW = 20e6;
f_c = 2e9;
G_RX_dBi = 3;
@@ -149,11 +155,11 @@ classdef test_rfSensor < matlab.unittest.TestCase
lossExponent = 2;
sensor1 = rfSensor;
sensor1 = sensor1.initialize(P_TX, BW, f_c, G_RX_dBi, beamwidthExponent(1), 15, 45, lossExponent);
sensor1 = sensor1.initialize(P_TX, T_0, BW, f_c, G_RX_dBi, beamwidthExponent(1), 15, 45, lossExponent);
sensor2 = rfSensor;
sensor2 = sensor2.initialize(P_TX, BW, f_c, G_RX_dBi, beamwidthExponent(2), 10, 150, lossExponent);
sensor2 = sensor2.initialize(P_TX, T_0, BW, f_c, G_RX_dBi, beamwidthExponent(2), 10, 150, lossExponent);
sensor3 = rfSensor;
sensor3 = sensor3.initialize(P_TX, BW, f_c, G_RX_dBi, beamwidthExponent(3), 20, 200, lossExponent);
sensor3 = sensor3.initialize(P_TX, T_0, BW, f_c, G_RX_dBi, beamwidthExponent(3), 20, 200, lossExponent);
pos1 = [0, 0, altitude];
pos2 = [6, -4, altitude - 5];