Define and Test Tracking Architectures for System-of-Systems
This example shows how to define the tracking architecture of a system-of-systems that includes multiple detection-level multi-object trackers and track-level fusion algorithms. You can use the tracking architectures to compare different tracking system designs and find the best solution for your system.
Introduction
The Simulate and Track En-Route Aircraft in Earth-Centered Scenarios example shows how to track aircraft using multiple long-range radar systems and fuse data from Automatic Dependent Surveillance Broadcast (ADS-B) transponders to get an accurate air situation picture. In that example, radar detections are fused centrally by a tracker before these tracks are fused with tracks from the ADS-B reports. You first load scenario data from that example and set up a globe-based visualization.
% Create the scenario and globe viewer load('recordedScenario','scenarioData'); viewer = createGlobe(scenarioData);
The architecture described above is only one possible architecture and tracking system engineers often consider various other options. There are many factors that determine how a system can be architected, some of them are:
Sensor outputs: Some sensor manufacturers design their sensors to output detection lists while others track objects internally and only provide sensor tracks as an output.
Communication networks: The amount of data that is required to be transmitted can be reduced if sensors report tracks instead of detections. Additionally, latency, physical distance, and other limitations may require that sensors report tracks.
Computational resources: Processing all the detections in a single central tracker usually requires more memory and computations than if processing data distributively between different nodes.
However, there are reasons to prefer central processing over decentralized architectures. First, centralized tracking systems can be optimal, because all the available data is processed in one place and there are no constraints on the data being processed. In addition, the architecture is much simpler as there is only one tracker.
Centralized Air Surveillance Architecture
As a baseline for comparison, you define an architecture that reflects the centralized tracking system described in the Simulate and Track En-Route Aircraft in Earth-Centered Scenarios example. To do that, you first define the same centralized trackerGNN
for the radars. Note that the radars update every 12 seconds and the ADS-B receiver updates every second. To accommodate different update rates, you wrap the tracker inside a helperScheduledTracker
object.
gnn = trackerGNN(... 'TrackerIndex',2,... 'FilterInitializationFcn',@initfilter,... 'ConfirmationThreshold',[3 5],... 'DeletionThreshold',[5 5],... 'AssignmentThreshold',[1000 Inf]); tracker = helperScheduledTracker(gnn, 12);
You define the ADS-B and tracker as two sources that are fused by a trackFuser
. Note that the SourceIndex
value for each source configuration must match the SourceIndex
value of the ADS-B tracks (1) and the TrackerIndex
value of the tracker (2). Additionally, the FuserIndex
value must be unique as well. In this case you set it to 3.
sources = {... fuserSourceConfiguration("SourceIndex", 1);... % ADS-B fuserSourceConfiguration("SourceIndex", 2) ... % Tracker }; fuser = trackFuser("FuserIndex",3, ... "MaxNumSources", 2,... "SourceConfigurations", sources, ... "AssignmentThreshold", [1000 Inf],... "StateFusion", "Intersection",... "StateFusionParameters", "trace",... "ProcessNoise", 10*eye(3));
With the tracker and track fuser defined, you define the trackingArchitecture
. You add the tracker to it, with sensors 1, 2, and 3 reporting to the tracker. You also add the track fuser to the trackingArchitecture
. The trackingArchitecture
directs fuser sources to the fuser based on the fuser's SoucreConfigurations
property. Finally, you use the show
object function to display the architecture.
centralizedArchitecture = trackingArchitecture; addTracker(centralizedArchitecture,tracker,'Name','Tracker','SensorIndices',[1 2 3],'ToOutput',false); addTrackFuser(centralizedArchitecture,fuser,'Name','Fuser','ToOutput',true); show(centralizedArchitecture)
Run the scenario and track using the tracking architecture
% Clear previous viewer data and reset the architecture if previously used clear(viewer); plotTruth(scenarioData, viewer); reset(centralizedArchitecture); for i = 1:numel(scenarioData) % Read the timestamp from the recorded scenario data time = scenarioData(i).Time; % Read detections from all radars in the scenario detections = scenarioData(i).Detections; % Update detections on the globe plotDetection(viewer, detections); % Read ADS-B tracks truePose = scenarioData(i).TruePose; adsbTracks = scenarioData(i).ADSBTrack; % Pass the detections and ADS-B tracks to the tracking architecture tracks = centralizedArchitecture(detections,adsbTracks,time); % Update display plotTrack(viewer, tracks); end % Provide an output image snap(viewer);
Decentralized Architecture
You want to explore how the system works when each radar reports sensor-level tracks that are fused with the ADS-B tracks by a track-level fusion algorithm. You define the trackingArchitecture
that represents this decentralized architecture.
decentralizedArchitecture = trackingArchitecture;
Next, you define a tracker for each radar. There are three radar sensors in the original example, so you define three trackers. For simplicity, assume that these trackers are defined in the same way as the central case. Since the SourceIndex of the ADS-B tracks is 1
, you define the trackers with TrackerIndex
of 2, 3, and 4. Meanwhile, the radar detections have SensorIndex
= 1, 2, and 3.
sensorTracker = trackerGNN(... 'TrackerIndex',2,... 'FilterInitializationFcn',@initfilter,... 'ConfirmationThreshold',[3 5],... 'DeletionThreshold',[5 5],... 'AssignmentThreshold',[1000 Inf]); % Add one tracker to each radar for i = 2:4 tracker = helperScheduledTracker(clone(sensorTracker),12); tracker.TrackerIndex = i; % Specify each radar tracker with a different index addTracker(decentralizedArchitecture, tracker, 'Name', strcat('Radar',num2str(i-1)), 'SensorIndices', i-1, 'ToOutput', false); % Connect the tracker to the correct radar index end
You add a trackFuser
that fuses tracks from four sources, the ADS-B and the three radar trackers.
% Define the sources sources = {... fuserSourceConfiguration(1);... % ADS-B fuserSourceConfiguration(2);... % Tracker for radar 1 fuserSourceConfiguration(3);... % Tracker for radar 2 fuserSourceConfiguration(4);... % Tracker for radar 3 }; % Add the fuser fuser = trackFuser("FuserIndex", 5, ... "MaxNumSources", 4,... "SourceConfigurations", sources, ... "AssignmentThreshold", [1000 Inf],... "StateFusion", "Intersection", ... "StateFusionParameters", "trace", ... "ProcessNoise", 10*eye(3)); addTrackFuser(decentralizedArchitecture, fuser, 'Name', 'Fuser'); % Show the tracking architecture in a figure show(decentralizedArchitecture)
The replayScenario
function reads the recorded scenario data, steps the new architecture, and displays the results.
% Rerun the scenario and observe tracking results
replayScenario(decentralizedArchitecture,scenarioData,viewer)
Regional Air Surveillance Architecture
Another possible configuration can fall between the centralized and decentralized architectures above. In many cases, there is no need for an air traffic control center to track aircraft that are too far away from it. In that case, regional air traffic control centers can be used, where one or more radars report to each region.
regionalArchitecture = trackingArchitecture; for i = 2:4 tracker = helperScheduledTracker(clone(sensorTracker),12); tracker.TrackerIndex = i; % Specify each radar with a different index addTracker(regionalArchitecture, tracker, 'Name', strcat('Radar',num2str(i-1)), 'SensorIndices', i-1, 'ToOutput', false); end
You define two regions and attach two radar sensors to each. Additionally, each region only fuses ADS-B tracks if the reporting aircraft is close enough to the region.
region1Fuser = trackFuser('FuserIndex',5, 'MaxNumSources',3, ... 'SourceConfigurations',sources([1,2,3]),... % Two radars and ADS-B "AssignmentThreshold",[1000 Inf],... "StateFusion",'Intersection',... 'StateFusionParameters','trace',... 'ProcessNoise',10*eye(3)); region2Fuser = trackFuser('FuserIndex',6, 'MaxNumSources',3, ... 'SourceConfigurations',sources([1,3,4]),... % Two radars and ADS-B "AssignmentThreshold",[1000 Inf],... "StateFusion",'Intersection',... 'StateFusionParameters','trace',... 'ProcessNoise',10*eye(3)); addTrackFuser(regionalArchitecture, region1Fuser, 'Name', 'Region1'); addTrackFuser(regionalArchitecture, region2Fuser, 'Name', 'Region2'); show(regionalArchitecture)
% Rerun the scenario and observe tracking results
replayScenario(regionalArchitecture,scenarioData,viewer)
Summary
In this example, you learned how to define tracking architectures for system-of-systems that use multiple trackers and track-to-track fusion algorithms. You saw how to pass detections and tracks as inputs to the tracking architecture and how to output tracks from it.
Supporting Functions
createGlobe
Creates the globe visualization
function gl = createGlobe(scenarioData) % You use the helperGlobeViewer object attached in this example to display % platforms, trajectories, detections, and tracks on the Earth. gl = helperGlobeViewer; setCamera(gl,[28.9176 -95.3388 5.8e5],[0 -30 10]); % Show flight route plotTruth(scenarioData, gl); end
plotTruth
plots the ground truth position
function plotTruth(scenarioData, viewer) poses = [scenarioData.TruePose]; positions = vertcat(poses.Position); plotLines(viewer, positions(:,1), positions(:,2), positions(:,3)) end
initfilter
defines the extended Kalman filter used by the tracker
Airplane motion is well approximated by a constant velocity motion model. Therefore a rather small process noise will give more weight to the dynamics compared to the measurements which are expected to be quite noisy at long ranges.
function filter = initfilter(detection) filter = initcvekf(detection); filter.StateCovariance = 10*filter.StateCovariance; % initcvekf uses measurement noise as the default filter.ProcessNoise = eye(3); end
replayScenario
Replays the recorded scenario and generates results
function replayScenario(arch,scenarioData,viewer) clear(viewer); plotTruth(scenarioData, viewer); reset(arch); numFusers = numel(arch.TrackFusers); tracks = cell(1,numFusers); for i = 1:numel(scenarioData) time = scenarioData(i).Time; % Create detections from all radars in the scenario detections = scenarioData(i).Detections; % Update detections on the globe plotDetection(viewer, detections); % Generate ADS-B tracks adsbTracks = scenarioData(i).ADSBTrack; % Pass the detections and ADS-B tracks to the tracking architecture [tracks{1:numFusers}] = arch(detections,adsbTracks,time); % Update display plotTrack(viewer, vertcat(tracks{:})); end snap(viewer); end