В этом примере показано, как настроить и запустить трекер для отслеживания нескольких объектов в сцене. Пример объясняет и демонстрирует важность ключевых свойств трекеров в Sensor Fusion and Tracking Toolbox.
В порядок, чтобы протестировать возможность трекера отслеживать несколько объектов, вы настраиваете базовый сценарий. В сценарии вы задаете три объекта с каждым перемещением по прямой линии с постоянной скоростью. Первоначально вы устанавливаете скорости объекта 48 м/с, 60 м/с и 72 м/с, соответственно.
stopTime = 10; v = 60; scenario = trackingScenario; scenario.StopTime = stopTime; scenario.UpdateRate = 0; p1 = platform(scenario); p1.Trajectory = waypointTrajectory([30 20 0; 30 .8*v*stopTime 0], [0 stopTime]); p2 = platform(scenario); p2.Trajectory = waypointTrajectory([0 0 0; 0 v*stopTime 0], [0 stopTime]); p3 = platform(scenario); p3.Trajectory = waypointTrajectory([-30 -20 0; -30 1.2*v*stopTime 0], [0 stopTime]);
Кроме сложения, вы задаете радар, который смотрит на сцену и обновляется 5 раз в секунду. Вы монтируете его на платформе, расположенной со стороны движущихся объектов.
pRadar = platform(scenario); pRadar.Trajectory = kinematicTrajectory('Position', [-v*stopTime 0.5*v*stopTime 0]); radar = monostaticRadarSensor(1, 'No scanning', 'UpdateRate', 5, ... 'MountingAngles', [0 0 0], 'AzimuthResolution', 1, ... 'FieldOfView', [100 1], 'HasINS', true, 'DetectionCoordinates', 'Scenario', ... 'MaxUnambiguousRange', 1000); pRadar.Sensors = radar;
Вы создаете театральный график, чтобы отобразить сцену.
fig = figure; ax = axes(fig); tp = theaterPlot('Parent', ax, 'XLimits', [-11*v 100], 'YLimits', [-50 15*v], 'ZLimits', [-100 100]); rp = platformPlotter(tp, 'DisplayName', 'Radar', 'Marker', 'd'); pp = platformPlotter(tp, 'DisplayName', 'Platforms'); dp = detectionPlotter(tp, 'DisplayName', 'Detections'); trp = trackPlotter(tp, 'DisplayName', 'Tracks', 'ConnectHistory', 'on', 'ColorizeHistory', 'on'); covp = coveragePlotter(tp, 'DisplayName', 'Radar Coverage', 'Alpha', [0.1 0]);
Наконец, вы создаете trackerGNN
по умолчанию объект, запуск сценария и наблюдение результатов. Вы используете
trackGOSPAMetric
для оценки эффективности трекера.
tracker = trackerGNN; tgm = trackGOSPAMetric("Distance","posabserr"); gospa = zeros(1,51); % number of timesteps is 51 i = 0; % Define the random number generator seed for repeatable results s = rng(2019); while advance(scenario) % Get detections dets = detect(scenario); % Update the tracker if isLocked(tracker) || ~isempty(dets) [tracks, ~, ~, info] = tracker(dets, scenario.SimulationTime); end % Evaluate GOSPA i = i + 1; truth = platformPoses(scenario); gospa(i) = tgm(tracks, truth); % Update the display updateDisplay(rp, pp, dp, trp, covp, scenario, dets, tracks); end
rng(s)
figure
plot(gospa)
title('Generalized OSPA vs. Timestep')
Вы замечаете, что трекер не смог отследить три объекта. В какой-то момент дополнительные дорожки подтверждаются и показываются в дополнение к трекам, ожидаемым для трех движущихся объектов. В результате значение метрики GOSPA увеличивается. Обратите внимание, что более низкие значения метрики GOSPA указывают на лучшую эффективность трекера.
Посмотрите на info
структурировать, что трекер выводит и замечает, что CostMatrix
и Assignments
не отображать назначение пар треков и объектов, которые вы ожидаете. Это означает, что AssignmentThreshold
слишком маленькая и должна быть увеличена. Увеличьте порог назначения до 50.
release(tracker); tracker.AssignmentThreshold = 50; rerunScenario(scenario, tracker, tgm, tp);
Свойство порога назначения также имеет максимальное расстояние от обнаружения, которое можно задать. Это последний элемент в AssignmentThreshold
значение. Вы можете использовать это значение, чтобы ускорить трекер при обработке большого количества обнаружений и треков. Для получения дополнительной информации см. пример «Как эффективно отслеживать большое количество объектов». Здесь вы устанавливаете значение 2000
вместо inf
, что позволит уменьшить количество комбинаций дорожек и обнаружений, которые используются для вычисления стоимости назначения.
release(tracker); tracker.AssignmentThreshold = [50 2000]; rerunScenario(scenario, tracker, tgm, tp);
Результаты выше показывают, что трекер способен поддерживать три трека для трех движущихся объектов, не создавая ложных треков. Однако будет ли эффективность трекера удерживаться, если объекты будут двигаться с большей скоростью? Чтобы проверить это, вы изменяете сценарий и увеличиваете скорость объекта в 160, 200 и 240 м/с, соответственно.
v = 200;
p1.Trajectory = waypointTrajectory([30 0 0; 30 0.8*v*stopTime 0], [0 stopTime]);
p2.Trajectory = waypointTrajectory([0 0 0; 0 v*stopTime 0], [0 stopTime]);
p3.Trajectory = waypointTrajectory([-30 0 0; -30 1.2*v*stopTime 0], [0 stopTime]);
pRadar.Trajectory = kinematicTrajectory('Position', [-v*stopTime 0.5*v*stopTime 0]);
tp.XLimits = [-100-v*stopTime 300];
tp.YLimits = [-100 100+v*1.2*stopTime];
release(radar);
radar.MaxUnambiguousRange = 3000;
rerunScenario(scenario, tracker, tgm, tp);
Как вы, вероятно, и ожидали, трекер не смог установить стабильные треки трех объектов. Возможным решением является увеличение AssignmentThreshold
даже далее, чтобы позволить обновлять дорожки. Однако эта опция может увеличить вероятность назначения случайных ложных треков нескольким обнаружениям и подтверждения. Таким образом, вы принимаете решение изменить способ инициализации фильтра.
Вы устанавливаете FilterInitializationFcn
свойство функции initFastCVEKF
. Функция аналогична функции по умолчанию initcvekf
кроме того, это увеличивает неопределенность в скорость компонентах состояния. Это позволяет начальному состоянию принимать во внимание большие неизвестные значения скорости, но как только дорожка устанавливает, неопределенность снова уменьшается.
release(tracker) tracker.FilterInitializationFcn = @initFastCVEKF; rerunScenario(scenario, tracker, tgm, tp);
Вы замечаете, что трекер в очередной раз способен поддерживать дорожки, и есть 3 дорожки для трех движущихся объектов, хотя они движутся быстрее сейчас. Значение GOSPA также уменьшается после нескольких шагов.
Вы хотите убедиться, что ваш трекер надежен до более высокой частоты ложных предупреждений. Для этого вы конфигурируете радар с частотой ложных предупреждений, которая в 250 раз выше, чем ранее.
Вы масштабируете, чтобы просмотреть большой фрагмент сцены и увидеть, созданы ли ложные дорожки.
release(radar); radar.FalseAlarmRate = 2.5e-4; tp.XLimits = [-2100 300]; tp.YLimits = [-100 3100]; tp.ZLimits = [-1000 1000]; rerunScenario(scenario, tracker, tgm, tp);
Создается несколько ложных треков (не все из них показаны), и они увеличивают значение GOSPA.
Вы хотите быстрее удалить ложные треки, для чего используете DeletionThreshold
свойство. Значение по умолчанию для порога удаления является [5 5], что требует 5 последовательных промахов перед удалением подтвержденной дорожки. Можно ускорить процесс удаления, уменьшив это значение до [3 3] или 3 промаха из 3. Альтернативно, так как радар DetectionProbability
высоко, можно даже удалить дорожку после промахов 2 из 3, путем установки:
release(tracker) tracker.DeletionThreshold = [2 3]; rerunScenario(scenario, tracker, tgm, tp);
Как ожидалось, уменьшение количества шагов, которые требуется предпринять для удаления дорожек, уменьшает значение GOSPA, потому что эти ложные дорожки являются кратковременными. Однако эти ложные дорожки все еще подтверждаются и ухудшают общее качество отслеживания.
Итак, вы хотите сделать подтверждение новых треков более строгим в попытке уменьшить количество ложных треков. Рассмотрим трекер ConfirmationThreshold
свойство.
disp(tracker.ConfirmationThreshold);
2 3
Значение показывает, что трекер подтверждает каждый трек, если ему назначено два обнаружения в первых трех обновлениях. Вы решаете затруднить подтверждение дорожки и сбросить значение 3 из 4 назначений.
release(tracker) tracker.ConfirmationThreshold = [3 4]; rerunScenario(scenario, tracker, tgm, tp);
Сделав подтверждение трека более строгим, вы смогли устранить ложные следы. В результате значения GOSPA снова сократились примерно до 20, за исключением первых нескольких шагов.
Сделать подтверждение более строгим позволило вам устранить ложные следы. Однако трекер все равно инициализирует дорожку для каждого ложного обнаружения, которое можно наблюдать, глядя на количество треков, которые трекер в данный момент поддерживает.
Количество треков колеблется на протяжении всей жизни трекера. Однако вы не хотите, чтобы он превышал максимальное количество треков, которые может поддерживать трекер, заданное как MaxNumTracks
, который по умолчанию равен 100. Если трекер превышает это число, выдается предупреждение о том, что новый трек не может быть добавлен, но выполнение может быть продолжено.
Увеличьте максимальное количество дорожек, чтобы трекер мог отслеживать даже с более высокой частотой ложных предупреждений, не выдавая предупреждение. Вы также хотите сделать подтверждение трека еще более строгим, чтобы уменьшить количество ложных треков и уменьшить метрику GOSPA.
release(tracker) tracker.MaxNumTracks = 200; tracker.ConfirmationThreshold = [5 6]; release(radar) radar.FalseAlarmRate = 1e-3; rerunScenario(scenario, tracker, tgm, tp);
Обратите внимание, что для более строгого подтверждения дорожки требуется больше шагов для подтверждения дорожек. В результате для первых нескольких шагов нет подтвержденных треков и значение GOSPA остается высоким. Можно сравнить это с графиками GOSPA в начале этого примера.
Вы хотите попробовать использовать другой трекер, в данном случае, трекер Joint Probabilistic Data Association, trackerJPDA
. Многие свойства, определенные для предыдущего трекера, все еще действительны в трекере JPDA. Вы используете helperGNN2JPDA
для создания трекера JPDA.
jpda = helperGNN2JPDA(tracker); jpda.ClutterDensity = 1e-3; rerunScenario(scenario, tracker, tgm, tp);
В этом примере вы научились настраивать мультиобъект трекеры в порядок, чтобы поддерживать треки реальных объектов в сцене, избегать ложных треков, поддерживать правильное количество треков и переключаться между различными трекерами.
При настройке мультиобъекта трекера рассмотрите изменение следующих свойств:
FilterInitializationFcn - задает фильтр, используемый для инициализации новой дорожки с неназначенным обнаружением.
Функция определяет модели движения и измерения.
Проверяйте, что неопределенности состояния правильно представлены StateCovariation фильтра. Для примера большая ковариация начальной скорости позволяет отслеживать быстро движущиеся объекты.
AssignmentThreshold - максимальное нормированное расстояние, используемое при присвоении обнаружений трекам.
Уменьшите это значение, чтобы ускорить назначение, особенно в больших сценах со многими треками и избежать ложных треков, избыточных треков и свопов треков. При использовании trackerJPDA
уменьшение этого значения уменьшает количество обнаружений, которые считаются назначенными одной дорожке. При использовании trackerTOMHT
уменьшение порогов назначения уменьшает количество созданных ветвей дорожки.
Увеличьте это значение, чтобы избежать расхождения и разрыва треков даже при наличии новых обнаружений.
MaxNumTracks - максимальное количество треков, поддерживаемых трекером.
Уменьшите это значение, чтобы минимизировать использование памяти и ускорить инициализацию трекера.
Увеличьте это значение, чтобы избежать того, чтобы новые дорожки не инициализировались из-за достижения предела.
ConfirmationThreshold - контролирует подтверждение новых треков.
Уменьшите это значение, чтобы подтвердить больше треков и подтвердить треки быстрее.
Увеличьте это значение, чтобы уменьшить количество ложных дорожек.
DeletionThreshold - управляет открытием и удалением треков.
Уменьшите это значение, чтобы быстрее удалить дорожки (для примера, когда вероятность обнаружения высока).
Увеличьте это значение, чтобы компенсировать более низкую вероятность обнаружения (для примера береговых путей во время окклюзий).
Для получения дополнительной информации можно обратиться к следующим примерам: Как сгенерировать код С для трекера, Введение в логику трека, Отслеживать тесно расположенные цели под неоднозначностью и Отслеживать цели точки в плотном загромождении с помощью GM-PHD Tracker.
updateDisplay
Эта функция обновляет отображение на каждом шаге симуляции.
function updateDisplay(rp, pp, dp, trp, covp, scenario, dets, tracks) % Plot the platform positions poses = platformPoses(scenario); pos = reshape([poses(1:3).Position], 3, [])'; % Only the platforms plotPlatform(pp, pos); radarPos = poses(4).Position; % Only the radar plotPlatform(rp, radarPos) % Plot the detection positions if ~isempty(dets) ds = [dets{:}]; dPos = reshape([ds.Measurement], 3, [])'; else dPos = zeros(0,3); end plotDetection(dp, dPos); % Plot the tracks tPos = getTrackPositions(tracks, [1 0 0 0 0 0; 0 0 1 0 0 0; 0 0 0 0 1 0]); tIDs = string([tracks.TrackID]); plotTrack(trp, tPos, tIDs); % Plot the coverage covcon = coverageConfig(scenario); plotCoverage(covp, covcon); end
rerunScenario
Эта функция запускает сценарий с заданным трекером и объектом метрики track GOSPA. Он использует объект график театра, чтобы отобразить результаты.
function info = rerunScenario(scenario, tracker, tgm, tp) % Reset the objects after the previous run restart(scenario); reset(tracker); reset(tgm); rp = findPlotter(tp, 'DisplayName', 'Radar'); pp = findPlotter(tp, 'DisplayName', 'Platforms'); trp = findPlotter(tp, 'DisplayName', 'Tracks'); dp = findPlotter(tp, 'DisplayName', 'Detections'); covp = findPlotter(tp, 'DisplayName', 'Radar Coverage'); clearPlotterData(tp); gospa = zeros(1,51); % number of timesteps is 51 i = 0; s = rng(2019); while advance(scenario) % Get detections dets = detect(scenario); % Update the tracker if isLocked(tracker) || ~isempty(dets) [tracks, ~, ~, info] = tracker(dets, scenario.SimulationTime); end % Evaluate GOSPA i = i + 1; truth = platformPoses(scenario); gospa(i) = tgm(tracks, truth); % Update the display updateDisplay(rp, pp, dp, trp, covp, scenario, dets, tracks); end rng(s) figure plot(gospa(gospa>0)) title('Generalized OSPA vs. Timestep') end
initFastCVEKF
Эта функция изменяет значение по умолчанию initcvekf
функция инициализации фильтра для обеспечения большей неопределенности в скорости объекта.
function ekf = initFastCVEKF(detection) ekf = initcvekf(detection); initialCovariance = diag(ekf.StateCovariance); initialCovariance([2,4,6]) = 300^2; % Increase the speed covariance ekf.StateCovariance = diag(initialCovariance); end
helperGNN2JPDA
Эта функция предоставляет трекер JPDA, эквивалентный трекеру GNN, заданному в качестве входов.
function jpda = helperGNN2JPDA(gnn) jpda = trackerJPDA(... 'MaxNumTracks', gnn.MaxNumTracks, ... 'AssignmentThreshold', gnn.AssignmentThreshold, ... 'FilterInitializationFcn', gnn.FilterInitializationFcn, ... 'MaxNumSensors', gnn.MaxNumSensors, ... 'ConfirmationThreshold', gnn.ConfirmationThreshold, ... 'DeletionThreshold', gnn.DeletionThreshold, ... 'HasCostMatrixInput', gnn.HasCostMatrixInput, ... 'HasDetectableTrackIDsInput', gnn.HasDetectableTrackIDsInput); if strcmpi(gnn.TrackLogic, 'History') jpda.TrackLogic = 'History'; else jpda.TrackLogic = 'Integrated'; jpda.DetectionProbability = gnn.DetectionProbability; jpda.ClutterDensity = gnn.FalseAlarmRate / gnn.Volume; end end