Main Content

Create Tracking Scenario Using Imported ADS-B Data

Since R2026a

This example demonstrates how to use the Tracking Data Importer app to import recorded Automatic Dependent Surveillance–Broadcast (ADS-B) data, create a tracking scenario based on the imported data, and generate detections of flight targets by adding radar sensors to the scenario.

ADS-B is a modern aviation surveillance technology in which aircraft automatically transmit their position, altitude, velocity, and identification information at regular intervals. These broadcasts can be received by ground stations, other aircraft, and hobbyist receivers, providing real-time data on aircraft movements. Recording ADS-B data involves capturing these transmissions and storing details such as flight number, position, altitude, speed, and timestamp.

Load and Preprocess ADS-B Data

This example utilizes a segment of recorded ADS-B data saved as a text file "ADSBData.txt", which contains ADS-B data near Boston area. You can read the data into a table variable in workspace by using the readtable function as follows.

rawTable = readtable("ADSBData.txt",TextType="string");
head(rawTable)
    Var1     Var2    Var3    Var4      Var5      Var6        Var7            Var8            Var9           Var10          Var11      Var12    Var13    Var14    Var15      Var16     Var17    Var18    Var19    Var20    Var21    Var22
    _____    ____    ____    ____    ________    ____    ____________    ____________    ____________    ____________    _________    _____    _____    _____    ______    _______    _____    _____    _____    _____    _____    _____

    "MSG"     3       1       1      "5F2697"     1      "2025/08/08"    15:56:32.279    "2025/08/08"    15:56:32.293    <missing>    23175     NaN      NaN     42.293    -71.564      NaN     NaN        0      NaN        0        0 
    "MSG"     7       1       1      "99A0E1"     1      "2025/08/08"    15:56:32.338    "2025/08/08"    15:56:32.348    <missing>     5525     NaN      NaN        NaN        NaN      NaN     NaN      NaN      NaN      NaN      NaN 
    "MSG"     7       1       1      "4BCA4E"     1      "2025/08/08"    15:56:32.344    "2025/08/08"    15:56:32.397    <missing>    40775     NaN      NaN        NaN        NaN      NaN     NaN      NaN      NaN      NaN      NaN 
    "MSG"     4       1       1      "6776E8"     1      "2025/08/08"    15:56:32.350    "2025/08/08"    15:56:32.398    <missing>      NaN     440      237        NaN        NaN    -1280     NaN      NaN      NaN      NaN        0 
    "MSG"     7       1       1      "6776E8"     1      "2025/08/08"    15:56:32.367    "2025/08/08"    15:56:32.400    <missing>    23875     NaN      NaN        NaN        NaN      NaN     NaN      NaN      NaN      NaN      NaN 
    "MSG"     7       1       1      "6776E8"     1      "2025/08/08"    15:56:32.371    "2025/08/08"    15:56:32.401    <missing>    23875     NaN      NaN        NaN        NaN      NaN     NaN      NaN      NaN      NaN      NaN 
    "MSG"     3       1       1      "67F71D"     1      "2025/08/08"    15:56:32.378    "2025/08/08"    15:56:32.401    <missing>    30850     NaN      NaN     41.856    -71.212      NaN     NaN        0      NaN        0        0 
    "MSG"     7       1       1      "5F2697"     1      "2025/08/08"    15:56:32.379    "2025/08/08"    15:56:32.402    <missing>    23175     NaN      NaN        NaN        NaN      NaN     NaN      NaN      NaN      NaN      NaN 

The raw table contains a total of 22 columns and approximately 100,000 rows. Below are the definitions for each column. Please note that the Hex Ident or ICAO codes shown in the table have been modified to distinguish them from real-world flight numbers.

Field #

Name

Description

1

Message Type

Always MSG for ADS-B messages

2

Transmission Type

Indicates the type of message (see below)

3

Session ID

Internal session ID

4

Aircraft ID

Internal aircraft ID

5

Hex Indent

ICAO 24-bit aircraft address (e.g., A99B83)

6

Flight ID

Internal flight ID

7

Date Generated

Date the message was generated

8

Time Generated

Time the message was generated

9

Date Logged

Date the message was logged

10

Time Logged

Time the message was logged

11

Callsign

Aircraft callsign (if available)

12

Altitude

Altitude in feet

13

Ground Speed

Speed over ground in knots

14

Track

True track angle in degrees

15

Latitude

Aircraft latitude

16

Longitude

Aircraft longitude

17

Vertical Rate

Rate of climb/descent in feet/min

18

Squawk

Transponder squawk code

19

Alert

Emergency alert flag (0 or 1)

20

Emergency

Emergency code flag (0 or 1)

21

SPI

Special Position Identification flag (0 or 1)

22

IsOnGround

Boolean flag indicating if aircraft is on ground (0 or 1)

To recreate a tracking scenario, you need to extract positional information from the data. Note that rows with a Transmission Type value of 3 contain the aircraft’s latitude, longitude, and altitude information.

tempTable = rawTable(rawTable.Var2 == 3,:);

Columns 7 through 10 of the table represent recording time information, where columns 7 and 8 contain the time that the message was generated and columns 9 and 10 contain the time that the message was received. Therefore, you combine columns 7 and 8 as a datetime string column and save it back to column 7.

tempTable.Var7 = tempTable.Var7 + " " + string(tempTable.Var8);

Next, keep only the columns that contain identification, time, or position information, and remove all other columns.

columnIndices = [5,7,12,15,16];
processedTable = tempTable(:,columnIndices);

Display the processed table. As shown below, the table now contains the ICAO, time, altitude in ft, latitude in degrees, and longitude in degrees.

head(processedTable);
      Var5                Var7               Var12    Var15      Var16 
    ________    _________________________    _____    ______    _______

    "5F2697"    "2025/08/08 15:56:32.279"    23175    42.293    -71.564
    "67F71D"    "2025/08/08 15:56:32.378"    30850    41.856    -71.212
    "C8EF7A"    "2025/08/08 15:56:33.009"    43000    42.148    -71.213
    "5F2697"    "2025/08/08 15:56:33.302"    23200    42.294    -71.567
    "D108CE"    "2025/08/08 15:56:33.904"    15100    42.167    -71.058
    "4BCA4E"    "2025/08/08 15:56:33.988"    40800    42.119     -72.12
    "C8EF7A"    "2025/08/08 15:56:34.031"    43000    42.147    -71.215
    "5F2697"    "2025/08/08 15:56:34.263"    23200    42.294    -71.569

Import Data in Tracking Data Importer App

Import Data

To import data, first launch the Tracking Data Importer app using the command:

trackingDataImporter

The app opens and prompts you to import truth data to begin. Click on the Import button and select the Import from workspace option. Follow the workspace importation dialog and import the processedTable variable into the app as follows.

Create Converter and Convert

To identify information in the table, you create a converter that contains a list of data elements expected by the app and then map the imported table columns to these data elements. First, click the New Converter button in the toolstrip and select Flight Log. Click on the Confirm button in the opened dialog, which creates a new flight log converter.

After that, the app opens a mapping panel that allows you to map between columns in the imported table with state elements contained in the flight log. Map Var7, Var5, Var15, Var16, Var12 to the elements of Data Time, Platform ID, Latitude, Longitude, and Altitude, respectively. Additionally, select the corresponding formats and units for these variables as shown below.

After the mapping, click the Convert button to convert the data based on the mapping. Please note that the original data sheet contains invalid or missing values; these cells are automatically detected by the app and highlighted in yellow, as shown below. The app will remove data rows containing invalid values during export.

Visualize Data

Click the Visualize button in the toolstrip to display the trajectories of aircraft on a globe. The display shows flight trajectories near the Boston area. You can further explore the data, such as platform waypoints and trajectories, by using context menus of the converted table. For more details, see the Import Flight Log Data Using Tracking Data Importer App example.

Export

Finally, export the ADS-B data from the app as tuning data. The tuning data format stores each platform's pose history as a timetable, making it easy to define trajectories for a tracking scenario.

Click the Export button from the toolstrip and select the Tuning Data option. The export dialog opens and you can click the Export button to export the tuningData variable to workspace.

Create and Simulate Tracking Scenario

In this section, you create a tracking scenario based on the exported data and use simulated radar sensors to generate detections.

First, load the tuning data that was saved in a previous app session. The loaded data is identical to what was exported from the app.

load tuningData.mat

Create a trackingScenario object. Set the IsEarthCentered property as true to define platform trajectories using geodetic coordinates.

scene = trackingScenario(IsEarthCentered=true,UpdateRate=0,InitialAdvance="UpdateInterval");

Create platforms and associated trajectories using the tuning data.

for ii = 1:numel(tuningData)
    tt = tuningData{ii};
    toas = seconds(tt.Time);
    waypoints = tt.Position;
    if size(waypoints,1) > 1 % Discard single waypoint   
        traj = geoTrajectory(waypoints,toas);
        platform(scene,Trajectory=traj);
    end
end

Define three radar stations as platforms in the tracking scenario.

stations = [42.3656 -71.0096 2; ... Boston
    42.2626 -71.8023 146; ... Worcester
    41.8240 -71.4128 19]; % Providence

stationBoston = platform(scene,Position=stations(1,:));
stationWorcester = platform(scene,Position=stations(2,:));
stationProvidence = platform(scene,Position=stations(3,:));

Create a monostatic radar for each station.

% First radar
rpm = 10; % Revolutions per minute
fov = [5;20]; % degree
scanrate = rpm*360/60;  % deg/s
updateRate = scanrate/fov(1); % Hz

radar1 = fusionRadarSensor(1,"Rotator",...
     UpdateRate=updateRate,... 
     MountingLocation=[0 0 -50], ... m, top of tower 
     FieldOfView=fov,... degrees
     MechanicalElevationLimits=[-15 -5], ... degree
     ReferenceRange=1e5,... m
     RangeLimits=[0 1e5],... m
     ReferenceRCS=10,... dBsm
     HasFalseAlarms=false,...
     HasElevation=true,...
     AzimuthResolution=0.01,... degree
     ElevationResolution=0.01,... degree
     RangeResolution=100,... m
     HasINS=true,...
     DetectionCoordinates="Sensor spherical");
stationBoston.Sensors = {radar1};

% Second radar
radar2 = clone(radar1);
radar2.SensorIndex = 2;
radar2.MountingAngles(1) = 120;
stationWorcester.Sensors = {radar2};

% Third radar
radar3 = clone(radar1);
radar3.SensorIndex = 3;
radar3.MountingAngles(1) = 240;
stationProvidence.Sensors = {radar3};

Create a trackingGlobeViewer object to visualize the scenario.

f = uifigure;
viewer = trackingGlobeViewer(f);
% Set camera orientation
camorient(viewer,[0 -90 0]);
% Set camera position
campos(viewer,[42.115 -71.46631 1.71357e5]);

The scenario simulation spans 50 minutes and includes 75 targets. For brevity, the simulation stop time is set to 60 seconds, but you can adjust this value to run the simulation for a longer duration as needed.

detLogs = []; % Save all the generated detections
scene.StopTime = 60; % seconds

Run the scenario, update the globe, and record detections.

restart(scene);
while advance(scene)
    platPoses = scene.platformPoses();
    plotPlatform(viewer,platPoses,"ECEF",TrajectoryMode="None");
    covcon = coverageConfig(scene);
    plotCoverage(viewer,covcon,"ECEF");
    detections = detect(scene);
    if ~isempty(detections)
        detLogs = [detLogs; detections]; %#ok<AGROW>
        plotDetection(viewer,detections,"ECEF");
    end  
end

Take snapshot of the globe.

snapshot(viewer);

Figure contains an axes object. The hidden axes object contains an object of type image.

Calculate the total number of detections, as well as the number of unique platforms identified.

numDetections = numel(detLogs)
numDetections = 
86
platformIDs = cellfun(@(det) det.ObjectAttributes{1}.TargetIndex, detLogs);
uniquePlatformIDs = numunique(platformIDs)
uniquePlatformIDs = 
10

The results show that the sensors generated 86 detections over one minute period, corresponding to 10 unique platforms, representing all the platforms that appeared during this time. You can increase the simulation time or change the sensor configurations to produce more detections. As the next step, you can create a multi-object tracker to track the platforms based on the detections. For more details, see Air Traffic Control, Simulate and Track En-Route Aircraft in Earth-Centered Scenarios, and Track Heterogeneous Aircraft using Heterogeneous Sensors.

Summary

The example provides a step-by-step guide to importing and cleaning ADS-B flight data, mapping and converting it using Tracking Data Importer, and building a simulated air traffic scenario with radar sensors for detection generation. This enables testing and development of tracking algorithms using real-world-like flight data.