MATLAB Examples

Search and Track Scheduling for Multifunction Phased Array Radar

This example simulates a multifunction phased array radar system. A multifunction radar can perform jobs that usually require multiple traditional radars. For example, scanning radars are responsible for searching targets while track radars are responsible for tracking targets. In this example, the multifunction phased array radar performs both scan (search) and track tasks. Based on the detections and tracks obtained from the current echo, the radar decides what to do next to ensure that targets of interest are tracked and the desired airspace is searched. The multifunction phased array radar works as a closed loop from task scheduling and waveform selection to detection generation and target tracking.

This example requires Phased Array System Toolbox™.

Contents

Radar Configuration

Assume the multifunction radar operates at S band and must detect targets with a radar cross section (RCS) of 1 $m^2$ that are between 2 km and 100 km.

fc     = 2e9;                 % Radar carrier frequency (Hz)
c      = 3e8;                 % Propagation speed (m/s)
lambda = c/fc;                % Radar wavelength (m)

maxrng = 100e3;               % Maximum range (m)
minrng = 2e3;                 % Minimum range (m)

Waveform

To satisfy the range requirement, a linear FM waveform with a 1 MHz bandwidth is used. The waveform can be defined as

bw     = 1e6;
fs     = 1.5*bw;
prf    = 1/range2time(maxrng,c);
dcycle = 0.1;

wav = phased.LinearFMWaveform('SampleRate', fs, ...
    'DurationSpecification', 'Duty cycle', 'DutyCycle', dcycle, ...
    'PRF', prf, 'SweepBandwidth', bw);

The range resolution achievable by the waveform is

rngres = bw2range(bw,c)
rngres =

   150

Radar Antenna

The multifunction radar is equipped with a phased array that can electronically scan the radar beams in space. Use a 50-by-50 rectangular array with elements separated by half wavelength to achieve a half power beam width of approximately 2 degrees.

arraysz   = 50;
ant       = phased.URA('Size',arraysz,'ElementSpacing',lambda/2);
ant.Element.BackBaffled = true;

arraystv  = phased.SteeringVector('SensorArray',ant,'PropagationSpeed',c);
radiator  = phased.Radiator('OperatingFrequency',fc, ...
    'PropagationSpeed', c, 'Sensor',ant, 'WeightsInputPort', true);
collector = phased.Collector('OperatingFrequency',fc, ...
    'PropagationSpeed', c, 'Sensor',ant);

beamw = rad2deg(lambda/(arraysz*lambda/2))
beamw =

    2.2918

Transmitter and Receiver

The detection requirements are used to derive the appropriate transmit power. Assume the noise figure on the receiving preamplifier is 7 dB.

pd      = 0.9;                     % Probability of detection
pfa     = 1e-6;                    % Probability of false alarm
snr_min = albersheim(pd, pfa, 1);
ampgain = 20;
tgtrcs  = 1;
ant_snrgain = pow2db(arraysz^2);

ppower  = radareqpow(lambda,maxrng,snr_min,wav.PulseWidth,...
    'RCS',tgtrcs,'Gain',ampgain+ant_snrgain);

tx = phased.Transmitter('PeakPower',ppower,'Gain',ampgain,'InUseOutputPort',true);
rx = phased.ReceiverPreamp('Gain',ampgain,'NoiseFigure',7,'EnableInputPort',true);

Signal Processing

The multifunction radar applies a sequence of operations to the received signal, including matched filtering, time varying gain, monopulse, and detection to generate range and angle measurements of the detected targets.

% matched filter
mfcoeff = getMatchedFilter(wav);
mf      = phased.MatchedFilter('Coefficients',mfcoeff,'GainOutputPort', true);

% time varying gain
tgrid   = unigrid(0,1/fs,1/prf,'[)');
rgates  = c*tgrid/2;
rngloss = 2*fspl(rgates,lambda);
refloss = 2*fspl(maxrng,lambda);
tvg     = phased.TimeVaryingGain('RangeLoss',rngloss,'ReferenceLoss',refloss);

% monopulse
monfeed = phased.MonopulseFeed('SensorArray',ant,'PropagationSpeed',c,...
    'OperatingFrequency',fc,'SquintAngle',1);
monest  = getMonopulseEstimator(monfeed);

Data processing

The detections are fed into a tracker which performs several operations. The tracker maintains a list of tracks, or estimates of targets states in the area of interest. If a detection cannot be assigned to any track already maintained by the tracker, the tracker initiates a new track. In most cases, it is unclear whether the new track represents a true target or a false one. At first, a track is created with tentative status. If enough evidence is obtained, the track becomes confirmed. Similarly, if no detections are assigned to a track, the track is coasted (predicted without correction), but after a few missed updates, the tracker deletes the track.

The multifunction radar uses a tracker that associates the detections to the tracks using a global nearest neighbor (GNN) algorithm.

tracker = trackerGNN('FilterInitializationFcn',@initMPARGNN,...
    'ConfirmationThreshold',[2 3], 'DeletionThreshold',5,...
    'HasDetectableTrackIDsInput',true,'AssignmentThreshold',100,...
    'MaxNumTracks',2,'MaxNumSensors',1);

Group all radar components together in a struct for easier reference the simulation loop.

mfradar.Tx      = tx;
mfradar.Rx      = rx;
mfradar.TxAnt   = radiator;
mfradar.RxAnt   = collector;
mfradar.Wav     = wav;
mfradar.RxFeed  = monfeed;
mfradar.MF      = mf;
mfradar.TVG     = tvg;
mfradar.DOA     = monest;
mfradar.STV     = arraystv;
mfradar.Tracker = tracker;
mfradar.IsTrackerInitialized = false;

Target and Scene Definition

This example assumes the radar is stationary at the origin with two targets in its field of view. One target is departing from the radar and is at a range of around 50 km. The other target is approaching and is 30 km away. Both of them have an RCS of 1 $m^2$.

% Define the targets.
tgtpos = [29875 49637; 0 4225; 0 0];
tgtvel = [-100 120; 0 100; 0 0];

ntgt = size(tgtpos,2);
tgtmotion = phased.Platform('InitialPosition',tgtpos,'Velocity',tgtvel);
target = phased.RadarTarget('MeanRCS',tgtrcs*ones(1,ntgt),'OperatingFrequency',fc);

The propagation environment is assumed to be free space.

channel = phased.FreeSpace('SampleRate',fs,'TwoWayPropagation',true,'OperatingFrequency',fc);

Group targets and propagation channels together in a struct for easier reference in the simulation loop.

env.Target       = target;
env.TargetMotion = tgtmotion;
env.Channel      = channel;

Radar Resource Management

The advantage of using one multifunction radar to perform multiple tasks comes at a price of higher cost and more sophisticated logic. In general, a radar has finite resources to spend on its tasks. If resources are used for tracking tasks, then those resources are not available for searching tasks until the tracking tasks are finished. Hence, a critical component in a multifunction radar is resource management.

Search Tasks

The search tasks can be considered as deterministic. In this example, a raster scan is used to cover the desired airspace. If no other tasks exist, the radar will scan the space one angular cell a time. The size of an angular cell is determined by the beam width of the antenna array.

Assume that we will cover a space between -30 to 30 degrees azimuth and 0 to 20 degrees elevation. The angular search grid can be computed using the beam width as

scanregion   = [-30, 30, 0, 20];
azscanspan   = diff(scanregion(1:2));
numazscan    = ceil(azscanspan/beamw);
azscanangles = linspace(scanregion(1),scanregion(2),numazscan);
elscanspan   = diff(scanregion(3:4));
numelscan    = ceil(elscanspan/beamw);
elscanangles = linspace(scanregion(3),scanregion(4),numelscan);
[elscangrid,azscangrid] = meshgrid(elscanangles,azscanangles);
scanangles   = [azscangrid(:) elscangrid(:)].';

The beam position grid and target scene are shown below.

sceneplot = helperMPARTaskPlot('initialize',scanangles,azscanangles,maxrng,beamw,tgtpos);

All these search beams will be transmitted one by one sequentially until the entire search area is covered, at which time it will repeat. The searches are performed along the azimuthal direction one elevation angle a time. The search tasks are often contained in a job queue

searchq = struct('JobType','Search','BeamDirection',num2cell(scanangles,1),...
    'Priority',1000,'WaveformIndex',1);
current_search_idx = 1;

Each job in the queue specifies the job type as well as the pointing direction of the beam. It also contains a priority value for the job. This priority value is determined by the job type but number wise is arbitrary. This example uses a value of 1000 as the priority for search jobs.

disp(searchq(current_search_idx))
          JobType: 'Search'
    BeamDirection: [2x1 double]
         Priority: 1000
    WaveformIndex: 1

Track Tasks

Unlike search tasks, track tasks cannot be planned. They are created only when a target is detected by a search task or when the target has already been tracked. Therefore, track tasks are dynamic tasks that get created and executed based on the changing scenario. Tracking tasks are also managed in a job queue.

trackq(10) = struct('JobType',[],'BeamDirection',[],'Priority',3000,'WaveformIndex',[],...
    'Time',[],'Range',[],'TrackID',[]);
num_trackq_items = 0;
disp(trackq(1))
          JobType: []
    BeamDirection: []
         Priority: []
    WaveformIndex: []
             Time: []
            Range: []
          TrackID: []

Group search and track queues together in a struct for easier reference in the simulation loop.

jobq.SearchQueue  = searchq;
jobq.SearchIndex  = current_search_idx;
jobq.TrackQueue   = trackq;
jobq.NumTrackJobs = num_trackq_items;

Because a tracking job cannot be initialized beforehand, all jobs start as empty jobs for the time being. Once a job is created, it will contain the information such as job type, the direction of the beam, and when to execute. Note that the tracking task has a priority of 3000, which is higher than the priority of 1000 for a search job. This means that when the time is in conflict, the system will execute the tracking job first.

Normally there is a size limit for the queue and in this example it is set to 10.

Task Scheduling

In this example, for simplicity, the multifunction radar executes only one type of job within a small time period, often referred to as a dwell, but can switch tasks at the beginning of each dwell. Hence, for each dwell, the radar looks at all tasks that are due for execution and picks the one that has the highest priority. Consequently, jobs that get postponed will now have an increased priority and are more likely to be executed in the next dwell.

Simulation

This section simulates a short run of the multifunction radar system. The entire structure of the multifunction radar simulation can be represented by the following diagram.

The simulation starts with the radar manager, which provides an initial job. Based on this job, the radar transmits the waveform, simulates the echo, and applies signal processing to generate the detection. The detection is processed by a tracker to create tracks for targets. Then the track goes back to the radar manager. Based on the track and the knowledge about the scene, the radar manager schedules the track job and picks the job for the next dwell.

The logic of radar manager operation can be summarized as follows:

  1. The radar starts with a search job.
  2. If there is a target present in the detection, the radar will schedule a confirmation job in the same direction to ensure that this is not a false alarm. The confirmation task has a higher priority than the search task but not as high as the track task. If the detection gets confirmed, a track is established and a track job is created to be executed after a given revisit time. If the detection is not confirmed, then the original detection is considered as a false alarm and no track is created.
  3. For a track job, the radar performs the detection, updates the track and creates a future track job.
  4. Based on the priority and time for execution, the radar selects the next job.

Assume a dwell is 10 ms. At the beginning of the simulation, the radar is configured to perform search one beam a time. The following code snippet would run until a detection is found.

rng(2018);
current_time = 0;
Npulses      = 10;
numdwells    = 200;
dwelltime    = 0.01;

jobload.num_search_job = zeros(1,numdwells);
jobload.num_track_job  = zeros(1,numdwells);

You can run the example in its entirety to see the plots being dynamically updated during execution. In the top two plots, the color of the beams indicate the types of the current job: red for search, yellow for confirm, and purple for track. The bottom two plots show the true locations (triangle), detections (circle), and tracks (square) of the two targets, respectively. System log is also displayed in the command line to help you understand the system behavior at current moment. Next, we explain details at several critical moments.

The code snippet below simulates the system behavior until it detects the first target. You can see that the simulation loop follows aforementioned system diagram.

for dwell_idx = 1:14
    % Scheduler to provide current job
    [current_job,jobq]       = getCurrentJob(jobq,current_time);

    % Simulate the received I/Q signal
    [xsum,xdaz,xdel,mfradar] = generateEcho(mfradar,env,current_job);

    % Signal processor to extract detection
    [detection,mfradar]      = generateDetection(xsum,xdaz,xdel,mfradar,current_job,current_time);

    % Radar manager to perform data processing and update track queue
    [jobq,allTracks,mfradar] = updateTrackAndJob(detection,jobq,mfradar,current_job,current_time,dwelltime);

    % Visualization
    helperMPARTaskPlot('update',sceneplot,current_job,maxrng,beamw,tgtpos,allTracks,detection.Measurement);

    % Update time
    tgtpos = env.TargetMotion(dwelltime-Npulses/mfradar.Wav.PRF);
    current_time = current_time+dwelltime;

    % Record resource allocation
    if strcmp(current_job.JobType,'Search')
        jobload.num_search_job(dwell_idx) = 1;
    else
        jobload.num_track_job(dwell_idx)  = 1;
    end

end
0.000000 sec:	Search	[-30.000000 0.000000]
0.010000 sec:	Search	[-27.692308 0.000000]
0.020000 sec:	Search	[-25.384615 0.000000]
0.030000 sec:	Search	[-23.076923 0.000000]
0.040000 sec:	Search	[-20.769231 0.000000]
0.050000 sec:	Search	[-18.461538 0.000000]
0.060000 sec:	Search	[-16.153846 0.000000]
0.070000 sec:	Search	[-13.846154 0.000000]
0.080000 sec:	Search	[-11.538462 0.000000]
0.090000 sec:	Search	[-9.230769 0.000000]
0.100000 sec:	Search	[-6.923077 0.000000]
0.110000 sec:	Search	[-4.615385 0.000000]
0.120000 sec:	Search	[-2.307692 0.000000]
0.130000 sec:	Search	[0.000000 0.000000]	Target detected at 29900.000000 m

As expected, the radar gets a detection when the radar beam illuminates the target, as shown in the figure. When this happens, the radar sends a confirmation beam immediately to make sure it is not a false detection.

Next section shows the result for the confirmation job. To simplify the code, we have combined the simulation loop into a system simulation function.

[mfradar,env,jobq,jobload,current_time,tgtpos] = MPARSimRun(...
    mfradar,env,jobq,jobload,current_time,dwelltime,sceneplot,maxrng,beamw,tgtpos,15,15);
0.140000 sec:	Confirm	[-0.000586 -0.000034]	Created track 1 at 29900.000000 m

Note that the figure now shows the confirmation beam. Once the detection is confirmed, a track is established for the target and a track job is scheduled to execute after a short interval.

This process repeats for every detected target until the revisit time, at which point the multifunction radar stops the search sequence and performs the track task again.

[mfradar,env,jobq,jobload,current_time,tgtpos] = MPARSimRun(...
    mfradar,env,jobq,jobload,current_time,dwelltime,sceneplot,maxrng,beamw,tgtpos,16,25);
0.150000 sec:	Search	[2.307692 0.000000]
0.160000 sec:	Search	[4.615385 0.000000]	Target detected at 49900.000000 m
0.170000 sec:	Confirm	[4.881676 0.000739]	Created track 2 at 49900.000000 m
0.180000 sec:	Search	[6.923077 0.000000]
0.190000 sec:	Search	[9.230769 0.000000]
0.200000 sec:	Search	[11.538462 0.000000]
0.210000 sec:	Search	[13.846154 0.000000]
0.220000 sec:	Search	[16.153846 0.000000]
0.230000 sec:	Search	[18.461538 0.000000]
0.240000 sec:	Track	[-0.000399 0.000162]	Track 1 at 29900.000000 m

Here the simulation stops at a track beam. The zoomed-in figures around the two targets show how the tracks are updated based on the detection and measurements. Note that a track job for the next revisit is also added to the job queue during the execution of a track job.

Such process repeats for each dwell. The simulation below runs the radar system for a 2-second period. Note that after a while, the second target is detected beyond 50 km. Based on this information, the radar manager reduces how often the system needs to track the second target so that more resources can be freed up for other more urgent needs.

[mfradar,env,jobq,jobload,current_time,tgtpos] = MPARSimRun(...
    mfradar,env,jobq,jobload,current_time,dwelltime,sceneplot,maxrng,beamw,tgtpos,26,numdwells);
0.250000 sec:	Search	[20.769231 0.000000]
0.260000 sec:	Search	[23.076923 0.000000]
0.270000 sec:	Track	[4.882892 -0.000030]	Track 2 at 49900.000000 m
0.280000 sec:	Search	[25.384615 0.000000]
0.290000 sec:	Search	[27.692308 0.000000]
0.340000 sec:	Track	[0.001390 0.000795]	Track 1 at 29900.000000 m
0.370000 sec:	Track	[4.895153 0.000529]	Track 2 at 49900.000000 m
0.440000 sec:	Track	[0.000284 0.000446]	Track 1 at 29900.000000 m
0.470000 sec:	Track	[4.909764 -0.000394]	Track 2 at 49900.000000 m
0.540000 sec:	Track	[0.000455 -0.000130]	Track 1 at 29800.000000 m
0.570000 sec:	Track	[4.921876 -0.000210]	Track 2 at 49900.000000 m
0.640000 sec:	Track	[0.000181 -0.000020]	Track 1 at 29800.000000 m
0.670000 sec:	Track	[4.932942 -0.000988]	Track 2 at 49900.000000 m
0.740000 sec:	Track	[0.000348 0.000212]	Track 1 at 29800.000000 m
0.770000 sec:	Track	[4.944255 -0.001073]	Track 2 at 49900.000000 m
0.840000 sec:	Track	[0.000171 -0.000125]	Track 1 at 29800.000000 m
0.870000 sec:	Track	[4.954431 -0.000943]	Track 2 at 50000.000000 m
0.940000 sec:	Track	[0.000296 -0.000288]	Track 1 at 29800.000000 m
1.040000 sec:	Track	[0.000108 -0.000147]	Track 1 at 29800.000000 m
1.140000 sec:	Track	[-0.000096 -0.000179]	Track 1 at 29800.000000 m
1.240000 sec:	Track	[-0.000110 -0.000315]	Track 1 at 29800.000000 m
1.340000 sec:	Track	[-0.000291 -0.000515]	Track 1 at 29800.000000 m
1.370000 sec:	Track	[5.005679 -0.000877]	Track 2 at 50000.000000 m
1.440000 sec:	Track	[-0.000191 -0.000592]	Track 1 at 29800.000000 m
1.540000 sec:	Track	[-0.000140 -0.000787]	Track 1 at 29700.000000 m
1.640000 sec:	Track	[0.000069 -0.000600]	Track 1 at 29700.000000 m
1.740000 sec:	Track	[-0.000001 -0.000714]	Track 1 at 29700.000000 m
1.840000 sec:	Track	[0.000030 -0.000686]	Track 1 at 29700.000000 m
1.870000 sec:	Track	[5.057762 0.000107]	Track 2 at 50100.000000 m
1.940000 sec:	Track	[0.000067 -0.000511]	Track 1 at 29700.000000 m

Resource Distribution Analysis

It is often of interest to see how the radar resource is distributed among different tasks. The following figure shows how the multifunction radar system in this example assigns its resources between search and track.

L = 10;
searchpercent = sum(buffer(jobload.num_search_job,L,L-1,'nodelay'))/L;
trackpercent  = sum(buffer(jobload.num_track_job,L,L-1,'nodelay'))/L;
figure;
plot((1:numel(searchpercent))*L*dwelltime,[searchpercent(:) trackpercent(:)]);
xlabel('Time (s)');
ylabel('Job Percentage');
title('Resource Distribution between Search and Track');
legend('Search','Track','Location','best');
grid on;

The figure suggests that at the beginning of the simulation, all resources are spent on search. Once the targets are detected, the radar resources get split 80% to 20% between search and track, respectively. However, once the second target gets farther away, more resources are freed up for search. The track load increases briefly when the time arrives to track the second target again.

Summary

This example introduces the concept of resource management and task scheduling in a multifunctional phased array radar system. It is shown that with the resource management component, the radar acts as a closed loop system. Although the multifunction radar in this example only deals with search and track tasks, the concept can be extended to more realistic situations where other functions, such as self-check and communication, are also involved.

References

[1] Walter Weinstock, Computer Control of a Multifunction Radar, Lecture 11 and 12 in Eli Brookner, Practical Phased Array Antenna Systems, Lex Book, 1997

Appendices

Below are several helper functions that model the radar resource management workflow.

getCurrentJob

The function getCurrentJob compares the jobs in the search queue and the track queue and selects the job with the highest priority to execute.

function [currentjob,jobq] = getCurrentJob(jobq,current_time)

searchq   = jobq.SearchQueue;
trackq    = jobq.TrackQueue;
searchidx = jobq.SearchIndex;
num_trackq_items = jobq.NumTrackJobs;

% update search queue index
searchqidx = mod(searchidx-1,numel(searchq))+1;

% find the track job that is due and has the highest priority
readyidx = find([trackq(1:num_trackq_items).Time]<=current_time);
[~,maxpidx] = max([trackq(readyidx).Priority]);
taskqidx = readyidx(maxpidx);

% if the track job found has a higher priority, use that as the current job
% and increase the next search job priority since it gets postponed.
% otherwise, the next search job due is the current job.
if ~isempty(taskqidx) && trackq(taskqidx).Priority >= searchq(searchqidx).Priority
    currentjob = trackq(taskqidx);
    for m = taskqidx+1:num_trackq_items
        trackq(m-1) = trackq(m);
    end
    num_trackq_items = num_trackq_items-1;
    searchq(searchqidx).Priority = searchq(searchqidx).Priority+100;
else
    currentjob = searchq(searchqidx);
    searchidx = searchqidx+1;

end

jobq.SearchQueue  = searchq;
jobq.SearchIndex  = searchidx;
jobq.TrackQueue   = trackq;
jobq.NumTrackJobs = num_trackq_items;

generateEcho

The function generateEcho simulates the complex (I/Q) baseband representation of the target echo received at the radar.

function [xrsint,xrdazint,xrdelint,mfradar] = generateEcho(mfradar,env,current_job)

% Radar position
radarpos = [0;0;0];
radarvel = [0;0;0];

% Number of pulses and operating frequency
Npulses = 10;
fc = mfradar.TxAnt.OperatingFrequency;

for m = 1:Npulses
    % Waveform
    x = mfradar.Wav();
    
    % Update target motion
    [tgtpos,tgtvel] = env.TargetMotion(1/mfradar.Wav.PRF);
    [~,tgtang]      = rangeangle(tgtpos);
    
    % Transmit
    [xt,inuseflag]  = mfradar.Tx(x);
    w  = mfradar.STV(fc,current_job.BeamDirection);
    xt = mfradar.TxAnt(xt,tgtang,conj(w));
    
    % Propagation
    xp = env.Channel(xt,radarpos,tgtpos,radarvel,tgtvel);
    xp = env.Target(xp);
    
    % Receive and monopulse
    xr = mfradar.RxAnt(xp,tgtang);
    [xrs,xrdaz,xrdel] = mfradar.RxFeed(xr,current_job.BeamDirection);
    
    % Pulse integration
    if m == 1
        xrsint   = mfradar.Rx(xrs,~(inuseflag>0));
        xrdazint = mfradar.Rx(xrdaz,~(inuseflag>0));
        xrdelint = mfradar.Rx(xrdel,~(inuseflag>0));
    else
        xrsint   = xrsint+mfradar.Rx(xrs,~(inuseflag>0));
        xrdazint = xrdazint+mfradar.Rx(xrdaz,~(inuseflag>0));
        xrdelint = xrdelint+mfradar.Rx(xrdel,~(inuseflag>0));
    end
end

generateDetection

The function generateDetection applies the signal processing techniques on the echo to generate target detection.

function [detection,mfradar] = generateDetection(xrsint,xrdazint,xrdelint,mfradar,current_job,current_time)

% compute detection threshold
nbw         = mfradar.Rx.SampleRate/(mfradar.Wav.SampleRate/mfradar.Wav.SweepBandwidth);
npower      = noisepow(nbw,mfradar.Rx.NoiseFigure,mfradar.Rx.ReferenceTemperature);
pfa         = 1e-6;
threshold   = npower * db2pow(npwgnthresh(pfa,1,'noncoherent'));
arraysz     = mfradar.TxAnt.Sensor.Size(1);
ant_snrgain = pow2db(arraysz^2);
mfcoeff     = getMatchedFilter(mfradar.Wav);
mfgain      = pow2db(norm(mfcoeff)^2);
threshold   = threshold * db2pow(mfgain+2*ant_snrgain); 
threshold   = sqrt(threshold);    

tgrid   = unigrid(0,1/mfradar.Wav.SampleRate,1/mfradar.Wav.PRF,'[)');
rgates  = mfradar.TxAnt.PropagationSpeed*tgrid/2;

% matched filtering and time varying gain
xrsmf = mfradar.TVG(mfradar.MF(xrsint));

% detection in range and angle estimation via monopulse
if any(abs(xrsmf)>threshold)
    [~,tgtidx] = findpeaks(abs(xrsmf),'MinPeakHeight',threshold,...
        'Sortstr','Descend','NPeaks',1);
    rng_est = rgates(tgtidx-(numel(mfcoeff)-1));
    ang_est = mfradar.DOA(xrsint(tgtidx-1),xrdazint(tgtidx-1),xrdelint(tgtidx-1),current_job.BeamDirection);
    % Form the detection object.  
    measNoise = diag([0.1, 0.1, 150].^2);           % Measurement noise matrix
    detection = objectDetection(current_time,...
        [ang_est(1);ang_est(2);rng_est], 'MeasurementNoise', measNoise,...
        'MeasurementParameters',struct('Frame','spherical', 'HasVelocity', false));  
else
    detection = objectDetection.empty;
end

if current_time < 0.3 || strcmp(current_job.JobType,'Track')
    fprintf('\n%f sec:\t%s\t[%f %f]',current_time,current_job.JobType,current_job.BeamDirection(1),...
        current_job.BeamDirection(2));
end


updateTrackAndJob

The function updateTrackAndJob performs the tracking on the detection and then pass tracks to the radar manager to update the track task queue.

function [jobq,allTracks,mfradar] = updateTrackAndJob(detection,jobq,mfradar,current_job,current_time,dwellinterval)

trackq           = jobq.TrackQueue;
num_trackq_items = jobq.NumTrackJobs;

% execute current job
switch current_job.JobType
    case 'Search'
        % For search job, if there is a detection, establish tentative
        % track and schedule a confirmation job
        if ~isempty(detection)
            ang_est = detection.Measurement(1:2);
            rng_est = detection.Measurement(3);
            if ~mfradar.IsTrackerInitialized
                [~,~,allTracks] = mfradar.Tracker(detection,current_time,uint32([]));
                mfradar.IsTrackerInitialized = true;
            else
                [~,~,allTracks] = mfradar.Tracker(detection,current_time,uint32([]));
            end
            num_trackq_items = num_trackq_items+1;
            trackq(num_trackq_items) = struct('JobType','Confirm','Priority',2000,...
                'BeamDirection',ang_est,'WaveformIndex',1,'Time',current_time+dwellinterval,...
                'Range',rng_est,'TrackID',allTracks(~[allTracks.IsConfirmed]).TrackID);
            if current_time < 0.3 || strcmp(current_job.JobType,'Track')
                fprintf('\tTarget detected at %f m',rng_est);
            end
        else
            allTracks = [];
        end

    case 'Confirm'
        % For confirm job, if the detection is confirmed, establish a track
        % and create a track job corresponding to the revisit time
        if ~isempty(detection)
            trackid = current_job.TrackID;
            [~,~,allTracks] = mfradar.Tracker(detection,current_time,trackid);

            rng_est = detection.Measurement(3);
            if rng_est >= 50e3
                updateinterval = 0.5;
            else
                updateinterval = 0.1;
            end
            revisit_time = current_time+updateinterval;
            predictedTrack = predictTracksToTime(mfradar.Tracker,trackid,revisit_time);
            xpred = predictedTrack.State([1 3 5]);
            [phipred,thetapred,rpred] = cart2sph(xpred(1),xpred(2),xpred(3));
            num_trackq_items = num_trackq_items+1;
            trackq(num_trackq_items) = struct('JobType','Track','Priority',3000,...
                'BeamDirection',rad2deg([phipred;thetapred]),'WaveformIndex',1,'Time',revisit_time,...
                'Range',rpred,'TrackID',trackid);
            if current_time < 0.3 || strcmp(current_job.JobType,'Track')
                fprintf('\tCreated track %d at %f m',trackid,rng_est);
            end
        else
            allTracks = [];
        end

    case 'Track'
        % For track job, if there is a detection, update the track and
        % schedule a track job corresponding to the revisit time. If there
        % is no detection, predict and schedule a track job sooner so the
        % target is not lost.
        if ~isempty(detection)
            trackid = current_job.TrackID;
            [~,~,allTracks] = mfradar.Tracker(detection,current_time,trackid);

            rng_est = detection.Measurement(3);
            if rng_est >= 50e3
                updateinterval = 0.5;
            else
                updateinterval = 0.1;
            end

            revisit_time = current_time+updateinterval;
            predictedTrack = predictTracksToTime(mfradar.Tracker,trackid,revisit_time);
            xpred = predictedTrack.State([1 3 5]);
            [phipred,thetapred,rpred] = cart2sph(xpred(1),xpred(2),xpred(3));
            num_trackq_items = num_trackq_items+1;
            trackq(num_trackq_items) = struct('JobType','Track','Priority',3000,...
                'BeamDirection',rad2deg([phipred;thetapred]),'WaveformIndex',1,'Time',revisit_time,...
                'Range',rpred,'TrackID',trackid);

            if current_time < 0.3 || strcmp(current_job.JobType,'Track')
                fprintf('\tTrack %d at %f m',trackid,rng_est);
            end
        else
            trackid = current_job.TrackID;
            [~,~,allTracks] = mfradar.Tracker(detection,current_time,trackid);

            updateinterval = 0.1;  % revisit sooner
            revisit_time = current_time+updateinterval;
            predictedTrack = predictTracksToTime(mfradar.Tracker,trackid,revisit_time);
            xpred = predictedTrack.State([1 3 5]);

            [phipred,thetapred,rpred] = cart2sph(xpred(1),xpred(2),xpred(3));
            num_trackq_items = num_trackq_items+1;
            trackq(num_trackq_items) = struct('JobType','Track','Priority',3000,...
                'BeamDirection',rad2deg([phipred;thetapred]),'WaveformIndex',1,'Time',revisit_time,...
                'Range',rpred,'TrackID',trackid);

            if current_time < 0.3 || strcmp(current_job.JobType,'Track')
                fprintf('\tNo detection, track %d predicted',current_job.TrackID);
            end
        end

end
    
jobq.TrackQueue   = trackq;
jobq.NumTrackJobs = num_trackq_items;