full simulation with RF sensors
This commit is contained in:
+18
-9
@@ -1,15 +1,24 @@
|
||||
function value = RSS(obj, d, t, a)
|
||||
function value = RSS(obj, d, dx, dy, dz)
|
||||
arguments (Input)
|
||||
obj (1, 1) {mustBeA(obj, "rfSensor")};
|
||||
d (:, 1) double; % distance from agent to target
|
||||
t (:, 1) double; % LOS tilt angle
|
||||
a (:, 1) double; % LOS azimuth angle
|
||||
d (:, 1) double;
|
||||
dx (:, 1) double;
|
||||
dy (:, 1) double;
|
||||
dz (:, 1) double;
|
||||
end
|
||||
arguments (Output)
|
||||
value (:, 1) double
|
||||
end
|
||||
assert(size(d, 1) == size(t, 1), "Mismatch in number of distances (%d) and tilts (%d) provided", size(d, 1), size(t, 1));
|
||||
|
||||
% RSS (dBm) = TX Power (dBm) + TX Antenna Gain (dBi) + RX Antenna Gain (dBi) - Path Loss (dB)
|
||||
value = obj.P_TX_dBm + obj.transmitterGain(t, a) + obj.G_RX_dBi - obj.pathLoss(d);
|
||||
end
|
||||
% Boresight unit vector: [st*sa, st*ca, -ct]
|
||||
% Target direction unit vector: [dx, dy, dz] / d
|
||||
% cos_theta = dot product of the two, computed without per-point trig.
|
||||
st = sind(obj.tilt);
|
||||
ct = cosd(obj.tilt);
|
||||
sa = sind(obj.azimuth);
|
||||
ca = cosd(obj.azimuth);
|
||||
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);
|
||||
end
|
||||
|
||||
@@ -1,24 +1,6 @@
|
||||
function [d, t, a] = computePointToPoints(obj, agentPos, targetPos)
|
||||
arguments (Input)
|
||||
obj (1, 1) {mustBeA(obj, "rfSensor")};
|
||||
agentPos (1, 3) double;
|
||||
targetPos (:, 3) double;
|
||||
end
|
||||
arguments (Output)
|
||||
d (:, 1) double;
|
||||
t (:, 1) double;
|
||||
a (:, 1) double;
|
||||
end
|
||||
|
||||
% distance from sensor to target
|
||||
d = vecnorm(agentPos - targetPos, 2, 2);
|
||||
|
||||
% distance from sensor nadir to target nadir (i.e. distance ignoring altitude)
|
||||
x = vecnorm(agentPos(1:2) - targetPos(:, 1:2), 2, 2);
|
||||
|
||||
% tilt angle (degrees) (0 (nadir), 180 (zenith))
|
||||
t = (180 - atan2d(x, targetPos(:, 3) - agentPos(3)));
|
||||
|
||||
% azimuth angle (degrees) (0 (+y) clockwise to 360)
|
||||
a = mod(atan2d(targetPos(:,1) - agentPos(1), targetPos(:,2) - agentPos(2)), 360);
|
||||
end
|
||||
function [d, dx, dy, dz] = computePointToPoints(~, agentPos, targetPos)
|
||||
dx = targetPos(:,1) - agentPos(1);
|
||||
dy = targetPos(:,2) - agentPos(2);
|
||||
dz = targetPos(:,3) - agentPos(3);
|
||||
d = sqrt(dx.^2 + dy.^2 + dz.^2);
|
||||
end
|
||||
|
||||
@@ -15,17 +15,17 @@ classdef rfSensor
|
||||
P_TX_dBm = NaN; % Transmit power (dBm)
|
||||
N = NaN; % Thermal noise
|
||||
% Cached state (per timestep)
|
||||
rssCache (:,1) double = double.empty(0,1); % linear-scale RSS to last ground targets grid
|
||||
end
|
||||
properties (Access = public)
|
||||
tilt = NaN; % Antenna boresight tilt (deg): 0=nadir, 90=horizon
|
||||
azimuth = NaN; % Antenna boresight azimuth (deg): 0=+y, 90=+x, 180=-y, 270=-x
|
||||
rssCache (:,1) double = double.empty(0,1); % linear-scale RSS to last ground targets grid
|
||||
end
|
||||
|
||||
methods (Access = public)
|
||||
[obj] = initialize(obj, txPower, 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, t, a] = computePointToPoints(obj, agentPos, targetPos);
|
||||
[d, dx, dy, dz] = computePointToPoints(obj, agentPos, targetPos);
|
||||
[value] = halfAngle(obj); % tilt angle (deg) at which sensor performance is halved
|
||||
[f] = plotParameters(obj); % debug, plot sensor response as a function of distance and tilt angle
|
||||
[f] = plotPerformance(obj, altitude, otherSensorsPos, otherSensors); % debug, plot SNR or SINR ground heatmap for a given geometry
|
||||
@@ -33,7 +33,7 @@ classdef rfSensor
|
||||
obj = clearRssCache(obj);
|
||||
end
|
||||
methods (Access = private)
|
||||
x = RSS(obj, d, t, a); % Received signal strength (function of distance and tilt angle)
|
||||
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
|
||||
L_FSPL_dB = pathLoss(obj, d); % Free space path loss for a given TX/RX pair
|
||||
end
|
||||
|
||||
@@ -14,22 +14,21 @@ function [SINR, SNR, obj, otherSensors] = sensorPerformance(obj, agentPos, targe
|
||||
end
|
||||
assert(size(otherSensorsPos, 1) == size(otherSensors, 1), "Mismatch in number of other sensor positions (%d) and number of other sensors (%d) provided", size(otherSensorsPos, 1), size(otherSensors, 1));
|
||||
|
||||
[d, t, a] = obj.computePointToPoints(agentPos, targetPos);
|
||||
|
||||
if isempty(obj.rssCache)
|
||||
obj.rssCache = 1e-3 .* 10 .^ (0.1 .* obj.RSS(d, t, a)); % dBm → W
|
||||
[d, dx, dy, dz] = obj.computePointToPoints(agentPos, targetPos);
|
||||
obj.rssCache = 1e-3 .* 10 .^ (0.1 .* obj.RSS(d, dx, dy, dz)); % dBm → W
|
||||
end
|
||||
S = obj.rssCache;
|
||||
|
||||
I = zeros(size(d));
|
||||
I = zeros(size(S));
|
||||
for ii = 1:size(otherSensors, 1)
|
||||
if isempty(otherSensors{ii}.rssCache)
|
||||
[d_other, t_other, a_other] = otherSensors{ii}.computePointToPoints(otherSensorsPos(ii, 1:3), targetPos);
|
||||
otherSensors{ii}.rssCache = 1e-3 .* 10 .^ (0.1 .* otherSensors{ii}.RSS(d_other, t_other, a_other)); % dBm → W
|
||||
[d_o, dx_o, dy_o, dz_o] = otherSensors{ii}.computePointToPoints(otherSensorsPos(ii, 1:3), targetPos);
|
||||
otherSensors{ii}.rssCache = 1e-3 .* 10 .^ (0.1 .* otherSensors{ii}.RSS(d_o, dx_o, dy_o, dz_o)); % dBm → W
|
||||
end
|
||||
I = I + otherSensors{ii}.rssCache;
|
||||
end
|
||||
|
||||
SINR = 10*log10(S ./ (I + obj.N));
|
||||
SNR = 10*log10(S ./ obj.N);
|
||||
SNR = 10*log10(S ./ obj.N);
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user