plot radio metrics as a function of distance
This commit is contained in:
@@ -1,9 +1,12 @@
|
|||||||
function [f, R] = plotRadioLogs(resultsPath)
|
function [f, fDist, R] = plotRadioLogs(resultsPath, G, tLim)
|
||||||
arguments (Input)
|
arguments (Input)
|
||||||
resultsPath (1, 1) string;
|
resultsPath (1, 1) string;
|
||||||
|
G cell = {};
|
||||||
|
tLim (1, 2) datetime = [datetime(-Inf, 'ConvertFrom', 'datenum'), datetime(Inf, 'ConvertFrom', 'datenum')];
|
||||||
end
|
end
|
||||||
arguments (Output)
|
arguments (Output)
|
||||||
f (1, 1) matlab.ui.Figure;
|
f (1, 1) matlab.ui.Figure;
|
||||||
|
fDist (1, 1) matlab.ui.Figure;
|
||||||
R cell;
|
R cell;
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -41,6 +44,7 @@ function [f, R] = plotRadioLogs(resultsPath)
|
|||||||
metricNames = ["SNR", "Power", "Quality", "PathLoss", "NoiseFloor", "FreqOffset"];
|
metricNames = ["SNR", "Power", "Quality", "PathLoss", "NoiseFloor", "FreqOffset"];
|
||||||
yLabels = ["SNR (dB)", "Power (dB)", "Quality", "Path Loss (dB)", "Noise Floor (dB)", "Freq Offset (MHz)"];
|
yLabels = ["SNR (dB)", "Power (dB)", "Quality", "Path Loss (dB)", "Noise Floor (dB)", "Freq Offset (MHz)"];
|
||||||
|
|
||||||
|
% --- Time-based figure ---
|
||||||
f = figure;
|
f = figure;
|
||||||
tl = tiledlayout(numel(metricNames), 1, 'TileSpacing', 'compact', 'Padding', 'compact');
|
tl = tiledlayout(numel(metricNames), 1, 'TileSpacing', 'compact', 'Padding', 'compact');
|
||||||
|
|
||||||
@@ -57,10 +61,10 @@ function [f, R] = plotRadioLogs(resultsPath)
|
|||||||
for ti = 1:numel(txIDs)
|
for ti = 1:numel(txIDs)
|
||||||
txID = txIDs(ti);
|
txID = txIDs(ti);
|
||||||
rows = tbl(tbl.TxUAVID == txID, :);
|
rows = tbl(tbl.TxUAVID == txID, :);
|
||||||
|
rows = rows(rows.Timestamp >= tLim(1) & rows.Timestamp <= tLim(2), :);
|
||||||
vals = rows.(metricNames(mi));
|
vals = rows.(metricNames(mi));
|
||||||
|
|
||||||
% Skip if all NaN for this metric
|
if isempty(rows) || all(isnan(vals))
|
||||||
if all(isnan(vals))
|
|
||||||
continue;
|
continue;
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -81,4 +85,100 @@ function [f, R] = plotRadioLogs(resultsPath)
|
|||||||
end
|
end
|
||||||
|
|
||||||
title(tl, 'Radio Channel Metrics');
|
title(tl, 'Radio Channel Metrics');
|
||||||
|
|
||||||
|
% --- Distance-based figure ---
|
||||||
|
fDist = figure;
|
||||||
|
|
||||||
|
if isempty(G)
|
||||||
|
return;
|
||||||
|
end
|
||||||
|
|
||||||
|
tl2 = tiledlayout(numel(metricNames), 1, 'TileSpacing', 'compact', 'Padding', 'compact');
|
||||||
|
|
||||||
|
for mi = 1:numel(metricNames)
|
||||||
|
ax = nexttile(tl2);
|
||||||
|
hold(ax, 'on');
|
||||||
|
grid(ax, 'on');
|
||||||
|
|
||||||
|
legendEntries = string.empty;
|
||||||
|
ci = 1;
|
||||||
|
for rxIdx = 1:nUAV
|
||||||
|
tbl = R{rxIdx};
|
||||||
|
txIDs = unique(tbl.TxUAVID);
|
||||||
|
for ti = 1:numel(txIDs)
|
||||||
|
txID = txIDs(ti);
|
||||||
|
rows = tbl(tbl.TxUAVID == txID, :);
|
||||||
|
|
||||||
|
if isempty(rows)
|
||||||
|
continue;
|
||||||
|
end
|
||||||
|
|
||||||
|
rows = rows(rows.Timestamp >= tLim(1) & rows.Timestamp <= tLim(2), :);
|
||||||
|
if isempty(rows)
|
||||||
|
continue;
|
||||||
|
end
|
||||||
|
|
||||||
|
vals = rows.(metricNames(mi));
|
||||||
|
if all(isnan(vals))
|
||||||
|
continue;
|
||||||
|
end
|
||||||
|
|
||||||
|
% Map 0-based UAV IDs to 1-based GPS cell indices
|
||||||
|
txGpsIdx = double(txID) + 1;
|
||||||
|
rxGpsIdx = double(rows.RxUAVID(1)) + 1;
|
||||||
|
|
||||||
|
if txGpsIdx > numel(G) || rxGpsIdx > numel(G)
|
||||||
|
continue;
|
||||||
|
end
|
||||||
|
|
||||||
|
Gtx = G{txGpsIdx};
|
||||||
|
Grx = G{rxGpsIdx};
|
||||||
|
|
||||||
|
if ~ismember('East', Gtx.Properties.VariableNames) || ...
|
||||||
|
~ismember('East', Grx.Properties.VariableNames)
|
||||||
|
continue;
|
||||||
|
end
|
||||||
|
|
||||||
|
% Strip timezone before posixtime so radio and GPS timestamps
|
||||||
|
% are treated on the same scale (both are AERPAW wall-clock time)
|
||||||
|
txTs = Gtx.Timestamp; txTs.TimeZone = '';
|
||||||
|
rxTs = Grx.Timestamp; rxTs.TimeZone = '';
|
||||||
|
txPt = posixtime(txTs);
|
||||||
|
rxPt = posixtime(rxTs);
|
||||||
|
radioPt = posixtime(rows.Timestamp);
|
||||||
|
|
||||||
|
% Interpolate GPS positions at radio measurement times.
|
||||||
|
% Exclude NaN ENU entries (outside algorithm flight range).
|
||||||
|
validTx = ~isnan(Gtx.East);
|
||||||
|
validRx = ~isnan(Grx.East);
|
||||||
|
|
||||||
|
txE = interp1(txPt(validTx), Gtx.East(validTx), radioPt, 'linear', NaN);
|
||||||
|
txN = interp1(txPt(validTx), Gtx.North(validTx), radioPt, 'linear', NaN);
|
||||||
|
txU = interp1(txPt(validTx), Gtx.Up(validTx), radioPt, 'linear', NaN);
|
||||||
|
rxE = interp1(rxPt(validRx), Grx.East(validRx), radioPt, 'linear', NaN);
|
||||||
|
rxN = interp1(rxPt(validRx), Grx.North(validRx), radioPt, 'linear', NaN);
|
||||||
|
rxU = interp1(rxPt(validRx), Grx.Up(validRx), radioPt, 'linear', NaN);
|
||||||
|
|
||||||
|
dist = vecnorm([txE - rxE, txN - rxN, txU - rxU], 2, 2);
|
||||||
|
|
||||||
|
if all(isnan(dist))
|
||||||
|
continue;
|
||||||
|
end
|
||||||
|
|
||||||
|
si = mod(ci - 1, numel(styles)) + 1;
|
||||||
|
scatter(ax, dist, vals, 9, colors(ci, :), strrep(styles(si), "-", ""), 'filled');
|
||||||
|
legendEntries(end+1) = sprintf("TX %d → RX %d", txID, rows.RxUAVID(1)); %#ok<AGROW>
|
||||||
|
ci = ci + 1;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
ylabel(ax, yLabels(mi));
|
||||||
|
if mi == numel(metricNames)
|
||||||
|
xlabel(ax, 'Distance (m)');
|
||||||
|
end
|
||||||
|
legend(ax, legendEntries, 'Location', 'best');
|
||||||
|
hold(ax, 'off');
|
||||||
|
end
|
||||||
|
|
||||||
|
title(tl2, 'Radio Channel Metrics vs Distance');
|
||||||
end
|
end
|
||||||
@@ -26,9 +26,8 @@ seaToGroundLevel = 110; % measured approximately from USGS national map viewer
|
|||||||
plotWholeFlight = true; % do not attempt to automatically trim initial and final positioning and landing from flight plot (buggy)
|
plotWholeFlight = true; % do not attempt to automatically trim initial and final positioning and landing from flight plot (buggy)
|
||||||
[fGlobe, G] = plotGpsLogs(resultsPath, seaToGroundLevel, true);
|
[fGlobe, G] = plotGpsLogs(resultsPath, seaToGroundLevel, true);
|
||||||
|
|
||||||
% Plot radio statistics
|
% Plot radio statistics (time-based and distance-based)
|
||||||
[fRadio, R] = plotRadioLogs(resultsPath);
|
[fRadio, fRadioDist, R] = plotRadioLogs(resultsPath, G, controller.timestamp([1, end]));
|
||||||
set(findobj(fRadio, 'Type', 'axes'), 'XLim', controller.timestamp([1, end]));
|
|
||||||
|
|
||||||
%% Run simulation
|
%% Run simulation
|
||||||
% Run miSim using same AERPAW scenario definition CSV
|
% Run miSim using same AERPAW scenario definition CSV
|
||||||
|
|||||||
Reference in New Issue
Block a user