Search and Track Scheduling for Multifunction Phased Array Radar

This example shows how to simulate a multifunction phased array radar system. A multifunction radar can perform jobs that usually require multiple traditional radars. Examples of traditional radars are scanning radars, which are responsible for searching targets, and tracking radars, which are responsible for tracking targets. In this example, the multifunction phased array radar performs both scanning (searching) and tracking 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, including features such as task scheduling, waveform selection, detection generation, and target tracking.

This example requires Sensor Fusion and Tracking Toolbox™.

Radar Configuration

Assume the multifunction radar operates at S band and must detect targets between 2 km and 100 km, with a minimum target radar cross section (RCS) of 1 square meters.

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, define and use a linear FM waveform with a 1 MHz bandwidth.

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);

Calculate the range resolution achievable by the waveform.

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

Use the detection requirements 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, including matched filtering, time varying gain, monopulse, and detection, to the received signal 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, that is, estimates of target 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, whether the new track represents a true target or false target is unclear. At first, a track is created with a tentative status. If enough detections are obtained, the track becomes confirmed. Similarly, if no detections are assigned to a track, the track is coasted (predicted without correction). If the track has 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 structure for easier reference in 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 departs from the radar and is at a distance of around 50 km. The other target approaches the radar and is 30 km away. Both targets have an RCS of 1 square meters.

% 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);

Assume the propagation environment is free space.

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

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

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

Radar Resource Management

While using one multifunction radar to perform multiple tasks has its advantages, it also has a 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. Because of this resource allocation, a critical component when using 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 scans the space one angular cell at a time. The size of an angular cell is determined by the beam width of the antenna array.

Assume the radar scans a space from -30 to 30 degrees azimuth and 0 to 20 degrees elevation. Calculate the angular search grid using the beam width.

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);

The search beams are transmitted one at a time sequentially until the entire search area is covered. Once the entire search area is covered, the radar repeats the search sequence. 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. 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. Track tasks are created only when a target is detected by a search task or when the target has already been tracked. Track tasks are dynamic tasks that get created and executed based on the changing scenario. Similar to search tasks, track 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 structure 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 before a target is detected, all tracking jobs start as empty jobs. Once a job is created, it contains the information such as its job type, the direction of the beam, and time to execute. The tracking task has a priority of 3000, which is higher than the priority of 1000 for a search job. This higher priority value means that when the time is in conflict, the system will execute the tracking job first.

The size limit for the queue in this example 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. 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 of the example simulates a short run of the multifunction radar system. The entire structure of the multifunction radar simulation is represented by this 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. The tracks then go back to the radar manager. Based on the tracks and the knowledge about the scene, the radar manager schedules new track jobs and picks the job for the next dwell.

The logic of the radar manager operation is shown in this flowchart and described in these steps.

  1. The radar starts with a search job.

  2. If a target is present in the detection, the radar schedules a confirmation job in the same direction to ensure that the presence of this target 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. If the current job is 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 search one beam at a time.

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 also displays in the command line to explain the system behavior at the current moment. Next, the example shows more details about several critical moments of the simulation.

Simulate the system behavior until it detects the first target. The simulation loop follows the previous 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, show the results for the confirmation job. The rest of this example shows simplified code that combines 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

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

The results show that 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. A new track job for the next revisit is also added to the job queue during the execution of a track job.

This process repeats for each dwell. This simulation runs the radar system for a 2-second period. 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. This reduction frees up resources 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

This section of the example shows how the radar resource is distributed among different tasks. This figure shows how the multifunction radar system in this example distributes 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 into 80% and 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 shows that, with the resource management component, the radar acts as a closed loop system. Although the multifunction radar in this example deals only 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", Practical Phased Array Antenna Systems, Lex Book, 1997

Appendices

These helper functions models 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 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 tracks the detection and then passes 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;