exponenta event banner

Адаптивное сопровождение маневрирующих целей управляемой РЛС

В этом примере показано, как использовать управление радиолокационными ресурсами для эффективного отслеживания нескольких маневрирующих целей. Сопровождение маневрирующих целей требует от РЛС более частого повторного захода на цели, чем сопровождение маневрирующих целей. Фильтр взаимодействия с несколькими моделями (IMM) оценивает, когда цель маневрирует. Эта оценка помогает управлять временем повторного посещения радара и, следовательно, улучшает отслеживание. В этом примере используется Toolbox™ радара для модели радара и Toolbox™ слияния и отслеживания датчиков для отслеживания.

Введение

Многофункциональные РЛС могут искать цели, подтверждать новые дорожки и повторно посещать дорожки для обновления состояния. Для выполнения этих функций многофункциональный радар часто управляется менеджером ресурсов, который создает радиолокационные задачи для поиска, подтверждения и слежения. Эти задачи планируются в соответствии с приоритетом и временем, так что на каждом шаге времени многофункциональный радар может указывать свой луч в нужном направлении. Пример планирования поиска и отслеживания для многофункционального радиолокатора с фазированной решеткой показывает многофункциональный радиолокатор с фазированной решеткой, управляемый менеджером ресурсов.

В этом примере мы распространяем пример адаптивного слежения за маневрирующими целями с управляемым радаром на случай множественных маневрирующих целей. Существует два противоречивых требования к радару, используемому для слежения за маневрирующими целями:

  1. Количество целей и их начальное местоположение, как правило, не известны заранее. Поэтому радар должен постоянно искать интересующую область, чтобы найти цели. Кроме того, радар должен обнаруживать и устанавливать путь на каждой цели, как только она попадает в зону действия радара.

  2. Временной период маневрирования цели заранее неизвестен. Если известно, что цели не маневрируют, радар может возвращаться к целям нечасто. Однако, поскольку время начала и окончания маневра неизвестно, радар должен достаточно часто посещать каждую трассу, чтобы быть в состоянии распознать, когда маневр начинается и заканчивается.

Радар должен балансировать между обеспечением достаточного количества лучей, центрированных на отслеживаемых целях, и оставлением достаточного времени для поиска новых целей. Один из подходов заключается в том, чтобы просто определить скорость повторного посещения каждой отслеживаемой цели независимо от ее статуса маневрирования и оставить оставшееся время для поиска новой цели. Эту схему управления РЛС иногда называют активным отслеживанием [1]. По мере отслеживания большего числа целей радар может либо выполнять меньшее количество поисковых задач, либо отслеживать каждую цель реже. Очевидно, что если количество целей велико, радар может быть переполнен.

Активное отслеживание обрабатывает все дорожки одинаково, что делает его алгоритмом управления ресурсами на основе режима. Более сложный способ управления РЛС основан на свойствах каждого пути. Например, используйте свойства дорожки, такие как размер ковариации неопределенности состояния, маневрирует ли трасса и насколько быстро она движется к активу, защищаемому радиолокационным узлом. При использовании таких свойств управление радиолокационными ресурсами называется адаптивным отслеживанием [1].

В этом примере сравниваются результаты активного и адаптивного слежения, когда радар адаптируется на основе расчетного маневра пути.

Определение сценария и радиолокационной модели

Вы определяете сценарий и радар с частотой обновления 20 Гц, что означает, что радар имеет 20 лучей в секунду, выделенных для поиска, подтверждения или отслеживания. Загружаются траектории эталонного теста, используемые в примере «Траектории эталонного теста для многообъектного отслеживания» (Sensor Fusion and Tracking Toolbox). Существует шесть эталонных траекторий, и вы определяете траекторию для каждой из них. На рисунке ниже шесть платформ следуют за неманевренными ногами вперемежку с маневрирующими ногами. Траектории можно просмотреть на рисунке ниже.

% Create scenario
updateRate = 20;
scenario = trackingScenario('UpdateRate',updateRate);
% Add the benchmark trajectories
load('BenchmarkTrajectories.mat','-mat');
platform(scenario,'Trajectory',v1Trajectory);
platform(scenario,'Trajectory',v2Trajectory);
platform(scenario,'Trajectory',v3Trajectory);
platform(scenario,'Trajectory',v4Trajectory);
platform(scenario,'Trajectory',v5Trajectory);
platform(scenario,'Trajectory',v6Trajectory);

% Create visualization
f = figure;
mp = uipanel('Parent',f,'Title','Theater Plot','FontSize',12,...
    'BackgroundColor','white','Position',[.01 .25 .98 .73]);
tax = axes(mp,'ZDir','reverse');

% Visualize scenario
thp = theaterPlot('Parent',tax,'AxesUnits',["km","km","km"],'XLimits',[0 85000],'YLimits',[-45000 70000],'ZLimits',[-10000 1000]);
plp = platformPlotter(thp, 'DisplayName', 'Platforms');
pap = trajectoryPlotter(thp, 'DisplayName', 'Trajectories', 'LineWidth', 1);
dtp = detectionPlotter(thp, 'DisplayName', 'Detections');
cvp = coveragePlotter(thp, 'DisplayName', 'Radar Coverage');
trp = trackPlotter(thp, 'DisplayName', 'Tracks', 'ConnectHistory', 'on', 'ColorizeHistory', 'on');
numPlatforms = numel(scenario.Platforms);
trajectoryPositions = cell(1,numPlatforms);
for i = 1:numPlatforms
    trajectoryPositions{i} = lookupPose(scenario.Platforms{i}.Trajectory,(0:0.1:185));
end
plotTrajectory(pap, trajectoryPositions);
view(tax,3)

Радар определяется с помощью helperManagedRadarDataGenerator , который является объектом, наследуемым от radarDataGenerator Системный объект. helperManagedRadarDataGenerator обеспечивает вероятностную модель РЛС и позволяет наводить РЛС на определённое направление. Эта настройка позволяет диспетчеру радиолокационных ресурсов планировать радар для поиска, подтверждения и слежения за целями. Радар моделирует электронные лучи, имеющие азимутальные пределы обзора [-90 60] градусов и высотные пределы [-9,9 0] градусов. Отрицательные углы возвышения означают, что РЛС указывает луч от горизонта вверх. Установите радар на новую платформу в сценарии.

radar = helperManagedRadarDataGenerator(1, ...
    'ScanMode', 'Electronic', ...
    'UpdateRate', updateRate, ...
    'MountingLocation', [0 0 -15], ...
    'FieldOfView', [3;10], ...
    'AzimuthResolution', 1.5, ...
    'ElectronicAzimuthLimits', [-90 60], ...
    'ElectronicElevationLimits', [-9.9 0], ...
    'HasElevation', true, ...
    'DetectionCoordinates', 'Sensor spherical');
platform(scenario,'Position',[0 0 0],'Sensors',radar);

Определение трекера

После того, как радар обнаруживает объекты, он подает обнаруженные объекты на трекер, который выполняет несколько операций. Трекер поддерживает список дорожек, которые являются оценками целевых состояний в интересующей области. Если обнаружение не может быть назначено какой-либо дорожке, уже поддерживаемой трекером, трекер инициирует новую дорожку. В большинстве случаев неясно, представляет ли новая дорожка истинную цель или ложную цель. Сначала создается трек с предварительным статусом. Если получено достаточно обнаружений, дорожка становится подтвержденной. Аналогично, если дорожке не назначено никаких обнаружений, дорожка покрывается (прогнозируется без коррекции). Если дорожка имеет несколько пропущенных обновлений, трекер удаляет дорожку.

В этом примере используется трекер, который связывает обнаружения с дорожками с помощью глобального алгоритма ближайшего соседа (GNN). Для отслеживания маневрирующих целей необходимо определить FilterInitializationFcn инициализирует фильтр Interacting Multiple Model (IMM). initMPARIMM функция использует две модели движения: модель постоянной скорости и модель скорости постоянного поворота. trackingIMM (Sensor Fusion and Tracking Toolbox) фильтр отвечает за оценку вероятности каждой модели, доступ к которой можно получить из ее ModelProbabilities собственность. В этом примере цель классифицируется как маневрирующая, когда вероятность модели скорости с постоянным поворотом выше 0,6.

tracker = trackerGNN('FilterInitializationFcn',@initMPARIMM,...
    'ConfirmationThreshold',[2 3], 'DeletionThreshold',[5 5],...
    'HasDetectableTrackIDsInput',true,'AssignmentThreshold',150,...
    'MaxNumTracks',10,'MaxNumSensors',1);
posSelector = [1 0 0 0 0 0; 0 0 1 0 0 0; 0 0 0 0 1 0];

Управление радиолокационными ресурсами

В этом разделе кратко описывается управление радиолокационными ресурсами. Дополнительные сведения см. в примере Адаптивное отслеживание маневрирующих целей с управляемым радиолокатором.

Задачи поиска

В этом примере задания поиска присваиваются детерминированно. Растровое сканирование используется для покрытия требуемого воздушного пространства. Если других задач не существует, радар сканирует пространство по одной угловой ячейке за раз. Размер угловой ячейки определяется радаром FieldOfView свойство и ограничено радиолокатором ElectronicAzimuthLimits и ElectronicElevatonLimits свойства.

azscanspan   = diff(radar.ElectronicAzimuthLimits);
numazscan    = floor(azscanspan/radar.FieldOfView(1))+1;
azscanangles = linspace(radar.ElectronicAzimuthLimits(1),radar.ElectronicAzimuthLimits(2),numazscan)+radar.MountingAngles(1);
elscanspan   = diff(radar.ElectronicElevationLimits);
numelscan    = floor(elscanspan/radar.FieldOfView(2))+1;
elscanangles = linspace(radar.ElectronicElevationLimits(1),radar.ElectronicElevationLimits(2),numelscan)+radar.MountingAngles(2);
[elscangrid,azscangrid] = meshgrid(elscanangles,azscanangles);  
scanangles   = [azscangrid(:) elscangrid(:)].';
searchq = struct('JobType','Search','BeamDirection',num2cell(scanangles,1),...
    'Priority',1000,'WaveformIndex',1);
current_search_idx = 1;

Отслеживать задачи

В отличие от задач поиска, задачи отслеживания нельзя планировать заранее. Вместо этого менеджер ресурсов создает задачи подтверждения и отслеживания на основе изменяющегося сценария. Основное отличие этого примера от примера адаптивного слежения за маневрирующими целями с управляемым радаром состоит в том, что JobType для каждой задачи дорожки может быть либо "TrackNonManeuvering" или "TrackManeuvering". Различие между двумя типами задач отслеживания позволяет планировать задачи для каждого типа трека с различной скоростью повторного посещения, что делает его адаптивным алгоритмом отслеживания. Аналогично задачам поиска, задачи отслеживания также управляются в очереди заданий.

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

Группирование очередей поиска и отслеживания в структуре для упрощения ссылок в цикле моделирования.

jobq.SearchQueue  = searchq;
jobq.SearchIndex  = current_search_idx;
jobq.TrackQueue   = trackq;
jobq.NumTrackJobs = num_trackq_items;
jobq.PositionSelector = posSelector;
% Keep a reset state of jobq
resetJobQ = jobq;

Планирование задач

В этом примере для простоты многофункциональный радар выполняет только один тип задания в течение небольшого периода времени, часто называемого задержкой, но может переключать задачи в начале каждой остановки. Для каждого пребывания радар просматривает все задачи, которые должны быть выполнены, и выбирает задачу подтверждения или отслеживания, если их время выполнения пришло. В противном случае радар выбирает задачу поиска. Для управления временем выполнения задач необходимо установить managerPreferences структура определена ниже. Самая высокая скорость повторного посещения, которая равна скорости обновления радара, задается для confirm задача гарантировать, что луч подтверждения следует за каждой новой предварительной дорожкой, которая существует. Точно так же можно управлять скоростью повторного посещения неманевренных и маневрирующих целей. При этом выбираются значения 1Hz и 4 Гц для неманевренных и маневрирующих целей соответственно. Поскольку существует шесть целей, в то время как скорость обновления РЛС составляет 20, если цели не маневрируют, то РЛС должна проводить около 70% времени в режиме поиска и 30% времени в режиме сопровождения. Когда новые дорожки инициализируются и когда трекер считает, что цели маневрируют, менеджер ресурсов выделяет больше отслеживающих лучей за счет поисковых лучей.

В разделе Анализ результатов (Analyze Results) показаны результаты других опций.

managerPreferences = struct(...
    'Type', {"Search","Confirm","TrackNonManeuvering","TrackManeuvering"}, ...
    'RevisitRate', {0, updateRate, 1, 4}, ...
    'Priority', {1000, 3000, 1500, 2500});

Выполнить сценарий

Во время моделирования радиолокационный луч изображается синими или фиолетовыми цветами, представляющими соответственно поисковые и связанные с дорожкой лучи. Распределение задач между поиском и определенными дорожками для последней секунды моделирования можно также просмотреть с помощью функции «Распределение ресурсов» на панели «Последняя секунда» в нижней части рисунка. На верхней фигуре можно увидеть историю каждого трека и сравнить её с траекторией.

% Create a radar resource allocation display
rp = uipanel('Parent',f,'Title','Resource Allocation in the Last Second','FontSize',12,...
    'BackgroundColor','white','Position',[.01 0.01 0.98 0.23]);
rax = axes(rp);

% Run the scenario
allocationType = helperAdaptiveTrackingSim(scenario, thp, rax, tracker, resetJobQ, managerPreferences);

Анализ результатов

Проанализируйте нагрузку на радар и ее разделение между заданиями поиска, подтверждения и отслеживания. График ниже показывает, что в течение большей части времени радар выделяет около 70% поисковых заданий и 30% заданий слежения, что соответствует ожиданиям, когда цели не маневрируют. Когда цели маневрируют, менеджер ресурсов адаптируется к выделению большего количества заданий отслеживания. Когда одновременно маневрирует больше трасс, появляется больше заданий слежения, как видно, например, около 700-го шага времени. Задания подтверждения занимают очень мало времени радара, потому что трекер сконфигурирован для подтверждения дорожек после двух ассоциаций обнаружения в трех попытках. Поэтому подтверждение или отклонение предварительных дорожек происходит быстро.

numSteps = numel(allocationType);
allocationSummary = zeros(3,numSteps);
for i = 1:numSteps
    for jobType = 1:3
        allocationSummary(jobType,i) = sum(allocationType(1,max(1,i-2*updateRate+1):i)==jobType)/min(i-1,2*updateRate);
    end
end
figure;
plot(1:numSteps,allocationSummary(:,1:numSteps))
title('Radar Allocation vs. Time Step');
xlabel('Time Step');
ylabel('Fraction of step in the last two seconds in each mode');
legend('Search','Confirmation','Tracking');
grid on

Теперь вы хотите сравнить результат, приведенный выше, с результатом активного отслеживания 1Hz скорости повторного посещения трека. На следующих рисунках показаны результаты отслеживания и график распределения радаров для случая активного отслеживания. Результаты отслеживания показывают, что некоторые следы были потеряны и сломаны, но график распределения радиолокационных ресурсов показывает такой же 70% поиск и 30% разделение задач отслеживания, как в случае адаптивного отслеживания. Эти результаты можно получить, выполнив приведенный ниже пример кода.

% Modify manager preferences to 1Hz revisit rate for both non-maneuvering and maneuvering targets
managerPreferences = struct(...
    'Type', {"Search","Confirm","TrackNonManeuvering","TrackManeuvering"}, ...
    'RevisitRate', {0, updateRate, 1, 1}, ...
    'Priority', {1000, 3000, 1500, 2500});
% Run the scenario
allocationType = helperAdaptiveTrackingSim(scenario, thp, rax, tracker, resetJobQ, managerPreferences);

Очевидно, что для активного отслеживания требуется более высокая частота повторных посещений. Два графика ниже показывают, что увеличение скорости повторного захода на трассу до 2Hz улучшает сопровождение маневрирующих целей. Однако стоимость заключается в том, что радар посвящает более 50% своего времени отслеживанию задач даже тогда, когда трассы не маневрируют. Если бы количество целей было больше, радар стал бы переполнен.

Предыдущие результаты показывают, что достаточно вернуться к маневрирующим целям со скоростью 2Hz. Однако можно ли использовать Adaptive Tracking для снижения скорости повторного посещения неманевренных целей до 0.5Hz? Приведенные ниже графики показывают, что отслеживание по-прежнему хорошо. При такой настройке распределение РЛС позволяет 80% -90% времени в режиме поиска, оставляя РЛС с возможностью поиска и отслеживания ещё большего количества целей.

Резюме

В этом примере показано, как использовать сочетание отслеживания и управления радиолокационными ресурсами для адаптации скорости повторного посещения для маневрирующих трасс. Адаптивное отслеживание позволяет выбрать скорость повторного посещения, подходящую для каждого типа цели и статуса маневрирования. В результате радар становится более эффективным и может отслеживать большее количество маневрирующих целей.

Ссылки

[1] Александр Шарлиш, Фолкер Гофман, Кристоф Деген и Изабель Шланген, «Развитие от адаптивного к управлению когнитивными радиолокационными ресурсами», в журнале IEEE Aerospace and Electronic Systems Magazine, том 35, № 6, стр. 8-19, 1 июня 2020 г., дои: 10.1109/MAES.2019.2957847.

Вспомогательные функции

getCurrentRadarTask

Возвращает задачу радара, которая используется для наведения луча радара.

type('getCurrentRadarTask.m')
function [currentjob,jobq] = getCurrentRadarTask(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;

helperAdaptiveRadarSim

Выполнение моделирования

type('helperAdaptiveTrackingSim.m')
function allocationType = helperAdaptiveTrackingSim(scenario, thp, rax, tracker, resetJobQ, managerPreferences)
% Initialize variables
radar = scenario.Platforms{end}.Sensors{1};
updateRate = radar.UpdateRate;
resourceAllocation = nan(1,updateRate);
h = histogram(rax,resourceAllocation,'BinMethod','integers');
xlabel(h.Parent,'TrackID')
ylabel(h.Parent,'Num beams');
numSteps = updateRate * 185;
allocationType = nan(1,numSteps);
currentStep = 1;
restart(scenario);
reset(tracker);
% Return to a reset state of jobq
jobq = resetJobQ;

% Plotters and axes
plp = thp.Plotters(1);
dtp = thp.Plotters(3);
cvp = thp.Plotters(4);
trp = thp.Plotters(5);

% For repeatable results, set the random seed and revert it when done
s = rng(2020);
oc = onCleanup(@() rng(s));

% Main loop
while advance(scenario)
    time = scenario.SimulationTime;
    
    % Update ground truth display
    poses = platformPoses(scenario);
    plotPlatform(plp, reshape([poses.Position],3,[])');
    
    % Point the radar based on the scheduler current job
    [currentJob,jobq] = getCurrentRadarTask(jobq,time);
    currentStep = currentStep + 1;
    if currentStep > updateRate
        resourceAllocation(1:end-1) = resourceAllocation(2:updateRate);
    end
    if strcmpi(currentJob.JobType,'Search')
        detectableTracks = zeros(0,1,'uint32');
        resourceAllocation(min([currentStep,updateRate])) = 0;
        allocationType(currentStep) = 1;
        cvp.Color = [0 0 1]; 
    else
        detectableTracks = currentJob.TrackID;
        resourceAllocation(min([currentStep,updateRate])) = currentJob.TrackID;
        cvp.Color = [1 0 1];
        if strcmpi(currentJob.JobType,'Confirm')
            allocationType(currentStep) = 2;
        else
            allocationType(currentStep) = 3;
        end
    end
    ra = resourceAllocation(~isnan(resourceAllocation));
    h.Data = ra;
    h.Parent.YLim = [0 updateRate];
    h.Parent.XTick = 0:max(ra);
    point(radar, currentJob.BeamDirection);
    plotCoverage(cvp, coverageConfig(scenario));
    
    % Collect detections and plot them
    detections = detect(scenario);
    if isempty(detections)
        meas = zeros(0,3);
    else
        dets = [detections{:}];
        meassph = reshape([dets.Measurement],3,[])';
        [x,y,z] = sph2cart(deg2rad(meassph(1)),deg2rad(meassph(2)),meassph(3));
        meas = (detections{1}.MeasurementParameters.Orientation*[x;y;z]+detections{1}.MeasurementParameters.OriginPosition)';
    end
    plotDetection(dtp, meas);
    
    % Track and plot tracks
    if isLocked(tracker) || ~isempty(detections)
        tracks = tracker(detections, time, detectableTracks);
        pos = getTrackPositions(tracks,jobq.PositionSelector);
        plotTrack(trp,pos,string([tracks.TrackID]));
    end
        
    % Manage resources for next jobs
    jobq = manageResource(detections,jobq,tracker,currentJob,time,managerPreferences);
end

initMPARIMM

Инициализирует взаимодействующий фильтр нескольких моделей, используемый трекером.

type('initMPARIMM.m')
function imm = initMPARIMM(detection)

cvekf = initcvekf(detection);
cvekf.StateCovariance(2,2) = 1e6;
cvekf.StateCovariance(4,4) = 1e6;
cvekf.StateCovariance(6,6) = 1e6;

ctekf = initctekf(detection);
ctekf.StateCovariance(2,2) = 1e6;
ctekf.StateCovariance(4,4) = 1e6;
ctekf.StateCovariance(7,7) = 1e6;
ctekf.ProcessNoise(3,3) = 1e6; % Large noise for unknown angular acceleration

imm = trackingIMM('TrackingFilters', {cvekf;ctekf}, 'TransitionProbabilities', [0.99, 0.99]);

manageResources

Управляет очередью заданий и создает новые задачи на основе результатов отслеживания.

type('manageResource.m')
function jobq = manageResource(detections,jobq,tracker,current_job,current_time,managerPreferences)

trackq           = jobq.TrackQueue;
num_trackq_items = jobq.NumTrackJobs;
if ~isempty(detections)
    detection = detections{1};
else
    detection = [];
end

% 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)
            rng_est = detection.Measurement(3);
            revisit_time = current_time+1;
            allTracks = predictTracksToTime(tracker, 'all', revisit_time);
            
            % A search task can still find a track we already have. Define
            % a confirmation task only if it's a tentative track. There
            % could be more than one if there are false alarms.
            toConfirm = find(~[allTracks.IsConfirmed]);
            numToConfirm = numel(toConfirm);
            for i = 1:numToConfirm
                trackid = allTracks(toConfirm(i)).TrackID;
                job = revisitTrackJob(tracker, trackid, current_time, managerPreferences, 'Confirm');
                num_trackq_items = num_trackq_items+1;
                trackq(num_trackq_items) = job;
            end
        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;
            job = revisitTrackJob(tracker, trackid, current_time, managerPreferences, 'TrackNonManeuvering');
            if ~isempty(job)
                num_trackq_items = num_trackq_items+1;
                trackq(num_trackq_items) = job;
            end
        end

    otherwise % Covers both types of track jobs
        % 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;
            job = revisitTrackJob(tracker, trackid, current_time, managerPreferences, 'TrackNonManeuvering');
            if ~isempty(job)
                num_trackq_items = num_trackq_items+1;
                trackq(num_trackq_items) = job;
            end
        else
            trackid = current_job.TrackID;
            job = revisitTrackJob(tracker, trackid, current_time, managerPreferences, 'TrackNonManeuvering');
            if ~isempty(job)
                num_trackq_items = num_trackq_items+1;
                trackq(num_trackq_items) = job;
            end
        end

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

function job = revisitTrackJob(tracker, trackID, currentTime, managerPreferences, jobType)
types = [managerPreferences.Type];
inTypes = strcmpi(jobType,types);
revisitTime = 1/managerPreferences(inTypes).RevisitRate + currentTime;
predictedTracks = predictTracksToTime(tracker,'All',revisitTime);

% If the track is not dropped, try to revisit it
allTrackIDs = [predictedTracks.TrackID];
if any(trackID == allTrackIDs)
    mdlProbs = getTrackFilterProperties(tracker, trackID, 'ModelProbabilities');
    if mdlProbs{1}(2) > 0.6
        jobType = 'TrackManeuvering';
        inTypes = strcmpi(jobType,types);
        revisitTime = 1/managerPreferences(inTypes).RevisitRate+currentTime;
        predictedTracks = predictTracksToTime(tracker,trackID,revisitTime);
        xpred = predictedTracks.State([1 3 5]);
    else
        xpred = predictedTracks(trackID == allTrackIDs).State([1 3 5]);   
    end
    
    [phipred,thetapred,rpred] = cart2sph(xpred(1),xpred(2),xpred(3));
    job = struct('JobType',jobType,'Priority',3000,...
        'BeamDirection',rad2deg([phipred thetapred]),'WaveformIndex',1,'Time',revisitTime,...
        'Range',rpred,'TrackID',trackID);
    
else
    job = [];
end
end