В этом примере показано, как настроить и использовать глобальный трекер ближайшего соседа (GNN).
trackerGNN - глобальный ближайший сосед (GNN), трекер с одной гипотезой. trackerGNN позволяет:
Выберите алгоритм назначения, чтобы связать обнаружения с дорожками.
Используйте логику треков на основе истории или оценки для подтверждения и удаления треков.
Используйте любой тип фильтра отслеживания, включая взаимодействующий фильтр нескольких моделей.
Подключите трекер к сканирующим и управляемым датчикам, которые обновляют только подмножество треков, управляемых трекером.
Прогнозирование путей в будущее без изменения их внутреннего состояния. Это позволяет отобразить прогнозируемое состояние дорожек или предоставить прогнозирование дорожек менеджеру ресурсов датчика.
trackerGNNМожно создать trackerGNN и выберите один из алгоритмов назначения. По умолчанию trackerGNN использует 'Munkres' алгоритм, который гарантирует оптимальное назначение, но может занять больше времени для вычисления. Вы можете использовать 'Auction' или 'Jonker-Volgenant' или предоставить 'Custom' свою собственную функцию. В этом примере выбирается 'Auction' алгоритм.
tracker = trackerGNN('Assignment','Auction')
tracker =
trackerGNN with properties:
TrackerIndex: 0
FilterInitializationFcn: 'initcvekf'
Assignment: 'Auction'
AssignmentThreshold: [30 Inf]
MaxNumTracks: 100
MaxNumSensors: 20
OOSMHandling: 'Terminate'
TrackLogic: 'History'
ConfirmationThreshold: [2 3]
DeletionThreshold: [5 5]
HasCostMatrixInput: false
HasDetectableTrackIDsInput: false
StateParameters: [1x1 struct]
NumTracks: 0
NumConfirmedTracks: 0
Основной способ использования trackerGNN она вызывается с новыми обнаружениями на каждом шаге моделирования. Обнаружение - это objectDetection ввод или структура с аналогичными полями. Необходимо указать время обнаружения и его измерения. Другие свойства имеют значения по умолчанию. Например:
detections = {objectDetection(0,[1;2;3]); % Using default values on the detection ...
objectDetection(0, [10;0;0], 'ObjectClassID', 2)}; % Using a non-default object class
disp(detections{1})
objectDetection with properties:
Time: 0
Measurement: [3x1 double]
MeasurementNoise: [3x3 double]
SensorIndex: 1
ObjectClassID: 0
MeasurementParameters: {}
ObjectAttributes: {}
time = 0; [confirmedTracks, tentativeTracks] = tracker(detections, time); disp(confirmedTracks) disp(tentativeTracks)
objectTrack with properties:
TrackID: 2
BranchID: 0
SourceIndex: 0
UpdateTime: 0
Age: 1
State: [6x1 double]
StateCovariance: [6x6 double]
StateParameters: [1x1 struct]
ObjectClassID: 2
TrackLogic: 'History'
TrackLogicState: [1 0 0 0 0]
IsConfirmed: 1
IsCoasted: 0
IsSelfReported: 1
ObjectAttributes: [1x1 struct]
objectTrack with properties:
TrackID: 1
BranchID: 0
SourceIndex: 0
UpdateTime: 0
Age: 1
State: [6x1 double]
StateCovariance: [6x6 double]
StateParameters: [1x1 struct]
ObjectClassID: 0
TrackLogic: 'History'
TrackLogicState: [1 0 0 0 0]
IsConfirmed: 0
IsCoasted: 0
IsSelfReported: 1
ObjectAttributes: [1x1 struct]
Создаются два типа треков: подтвержденный и ориентировочный. Подтвержденная дорожка - это дорожка, которая считается оценкой реальной цели, в то время как предварительная дорожка все еще может быть ложной целью. IsConfirmed флаг различает их. Дорожка, созданная вторым обнаружением, имеет ненулевое значение ObjectClassID поле и немедленно подтверждается, потому что датчик, который сообщил, что он смог классифицировать его и, таким образом, он считается реальной целью. Альтернативно, трек может быть подтвержден, если имеется достаточно доказательств его существования. В логике подтверждения на основе истории, используемой здесь, если дорожке присвоено 2 обнаружения из 3, она будет подтверждена. Это контролируется ConfirmationThreshold собственность. Например, следующее обнаружение назначается предварительной дорожке и подтверждает ее:
detections = {objectDetection(1,[1.1;2.2;3.3])};
time = time + 1; % Time must increase from one update of the tracker to the next
confirmedTracks = tracker(detections,time);
confirmedTracks(1)
ans =
objectTrack with properties:
TrackID: 1
BranchID: 0
SourceIndex: 0
UpdateTime: 1
Age: 2
State: [6x1 double]
StateCovariance: [6x6 double]
StateParameters: [1x1 struct]
ObjectClassID: 0
TrackLogic: 'History'
TrackLogicState: [1 1 0 0 0]
IsConfirmed: 1
IsCoasted: 0
IsSelfReported: 1
ObjectAttributes: [1x1 struct]
Во многих случаях логика подтверждения и удаления на основе истории считается слишком упрощенной, поскольку она не учитывает статистические метрики. Эти метрики включают в себя вероятность обнаружения датчика и частоту ложных аварийных сигналов, вероятность появления новых целей или расстояние между обнаружением и оценочным состоянием назначенной ему трассы. Логика подтверждения и удаления на основе оценки учитывает такие метрики и обеспечивает более подходящий статистический тест.
Для преобразования трекера в логику подтверждения и удаления на основе оценки сначала деблокируйте трекер, а затем установите трекер TrackLogic кому 'Score':
release(tracker)
tracker.TrackLogic = 'Score'
tracker =
trackerGNN with properties:
TrackerIndex: 0
FilterInitializationFcn: 'initcvekf'
Assignment: 'Auction'
AssignmentThreshold: [30 Inf]
MaxNumTracks: 100
MaxNumSensors: 20
OOSMHandling: 'Terminate'
TrackLogic: 'Score'
ConfirmationThreshold: 20
DeletionThreshold: -7
DetectionProbability: 0.9000
FalseAlarmRate: 1.0000e-06
Volume: 1
Beta: 1
HasCostMatrixInput: false
HasDetectableTrackIDsInput: false
StateParameters: [1x1 struct]
NumTracks: 0
NumConfirmedTracks: 0
Обратите внимание, что пороги подтверждения и удаления изменились на скалярные значения, которые представляют оценку, используемую для подтверждения и удаления дорожки. Кроме того, для обеспечения параметров подтверждения и удаления на основе оценки теперь используется еще несколько свойств.
Теперь обновите трекер, чтобы увидеть подтверждение треков.
detections = {objectDetection(0,[1;2;3]); % Using default values on the detection ...
objectDetection(0, [10;0;0], 'ObjectClassID', 2)}; % Using a non-default object class
time = 0;
tracker(detections, time); % Same as the first step above
detections = {objectDetection(1,[1.1;2.2;3.3])};
time = time + 1; % Time must increase from one update of the tracker to the next
[confirmedTracks, tentativeTracks] = tracker(detections,time);
confirmedTracks
confirmedTracks =
objectTrack with properties:
TrackID: 2
BranchID: 0
SourceIndex: 0
UpdateTime: 1
Age: 2
State: [6x1 double]
StateCovariance: [6x6 double]
StateParameters: [1x1 struct]
ObjectClassID: 2
TrackLogic: 'Score'
TrackLogicState: [11.4076 13.7102]
IsConfirmed: 1
IsCoasted: 1
IsSelfReported: 1
ObjectAttributes: [1x1 struct]
Поскольку подтвержденный трек не был назначен никакому обнаружению в этом обновлении, его оценка снизилась. Вы можете видеть это, глядя на TrackLogicState поле и видя, что первый элемент, текущий балл, ниже, чем второй элемент, максимальный балл. Если трасса продолжает уменьшаться относительно максимального балла, более чем на DeletionThreshold значение, дорожка удаляется.
tentativeTracks
tentativeTracks =
objectTrack with properties:
TrackID: 1
BranchID: 0
SourceIndex: 0
UpdateTime: 1
Age: 2
State: [6x1 double]
StateCovariance: [6x6 double]
StateParameters: [1x1 struct]
ObjectClassID: 0
TrackLogic: 'Score'
TrackLogicState: [17.7217 17.7217]
IsConfirmed: 0
IsCoasted: 0
IsSelfReported: 1
ObjectAttributes: [1x1 struct]
Если дорожки не назначены для каких-либо обнаружений, они сначала будут покрыты и после нескольких «промахов» они будут удалены. Для этого вызовите трекер без обнаружений:
for i = 1:3 time = time + 1; [~,~,allTracks] = tracker({},time) end
allTracks =
2x1 objectTrack array with properties:
TrackID
BranchID
SourceIndex
UpdateTime
Age
State
StateCovariance
StateParameters
ObjectClassID
TrackLogic
TrackLogicState
IsConfirmed
IsCoasted
IsSelfReported
ObjectAttributes
allTracks =
2x1 objectTrack array with properties:
TrackID
BranchID
SourceIndex
UpdateTime
Age
State
StateCovariance
StateParameters
ObjectClassID
TrackLogic
TrackLogicState
IsConfirmed
IsCoasted
IsSelfReported
ObjectAttributes
allTracks =
objectTrack with properties:
TrackID: 1
BranchID: 0
SourceIndex: 0
UpdateTime: 4
Age: 5
State: [6x1 double]
StateCovariance: [6x6 double]
StateParameters: [1x1 struct]
ObjectClassID: 0
TrackLogic: 'Score'
TrackLogicState: [10.8139 17.7217]
IsConfirmed: 0
IsCoasted: 1
IsSelfReported: 1
ObjectAttributes: [1x1 struct]
Вторая дорожка была удалена, так как ей не было назначено никаких обнаружений в 4 обновлениях. Это привело к тому, что его оценка упала более чем на 7, значение DeletionThreshold. Первый трек до сих пор не удален, но его оценка сейчас ниже и близка к порогу удаления.
TrackerGNN поддерживает любой фильтр отслеживания, реализующий интерфейс фильтра отслеживания. Выбор функции инициализации фильтра определяется с помощью FilterInitializationFcn свойство trackerGNN. Это обеспечивает следующую гибкость:
Можно использовать любую функцию инициализации фильтра, доступную в продукте. Некоторые примеры включают initcvekf (по умолчанию), initcvkf , initcvukf , initcvckf , initcaekf и т.д.
Можно создать собственную функцию инициализации фильтра и использовать любой фильтр отслеживания. К ним относятся trackingABF , trackingEKF , trackingKF , trackingUKF , trackingCKF , trackingPF , trackingMSCEKF , trackingGSF , и trackingIMM .
Можно создать фильтр отслеживания, который наследует и реализует интерфейс, определенный абстрактным matlabshared.tracking.internal.AbstractTrackingFilter класс.
В следующем примере показано, как использовать фильтр взаимодействующей модели движения (IMM), который имеет 3 типа моделей движения: постоянная скорость, постоянное ускорение и постоянная скорость поворота.
Изменение трекера для использования фильтра IMM
release(tracker) % Release the tracker tracker.FilterInitializationFcn = 'initekfimm'
tracker =
trackerGNN with properties:
TrackerIndex: 0
FilterInitializationFcn: 'initekfimm'
Assignment: 'Auction'
AssignmentThreshold: [30 Inf]
MaxNumTracks: 100
MaxNumSensors: 20
OOSMHandling: 'Terminate'
TrackLogic: 'Score'
ConfirmationThreshold: 20
DeletionThreshold: -7
DetectionProbability: 0.9000
FalseAlarmRate: 1.0000e-06
Volume: 1
Beta: 1
HasCostMatrixInput: false
HasDetectableTrackIDsInput: false
StateParameters: [1x1 struct]
NumTracks: 0
NumConfirmedTracks: 0
Затем обновите трекер с помощью обнаружения и просмотрите три модели движения, которые его составляют. Вы можете увидеть, какая модель используется, посмотрев на StateTransitionFcn каждого фильтра.
% Update the tracker with a single detection to get a single track detection = {objectDetection(0, [1;2;3], 'ObjectClassID', 2)}; time = 0; tracker(detection, time);
Используйте getTrackFilterProperties для просмотра TrackingFilters собственность. Он возвращает массив ячеек, содержащий TrackingFilters свойство: {filter1;filter2;filter3}
filters = getTrackFilterProperties(tracker,1,'TrackingFilters'); for i = 1:numel(filters{1}) disp(filters{1}{i}) end
trackingEKF with properties:
State: [6x1 double]
StateCovariance: [6x6 double]
StateTransitionFcn: @constvel
StateTransitionJacobianFcn: @constveljac
ProcessNoise: [3x3 double]
HasAdditiveProcessNoise: 0
MeasurementFcn: @cvmeas
MeasurementJacobianFcn: @cvmeasjac
MeasurementNoise: [3x3 double]
HasAdditiveMeasurementNoise: 1
EnableSmoothing: 0
trackingEKF with properties:
State: [9x1 double]
StateCovariance: [9x9 double]
StateTransitionFcn: @constacc
StateTransitionJacobianFcn: @constaccjac
ProcessNoise: [3x3 double]
HasAdditiveProcessNoise: 0
MeasurementFcn: @cameas
MeasurementJacobianFcn: @cameasjac
MeasurementNoise: [3x3 double]
HasAdditiveMeasurementNoise: 1
EnableSmoothing: 0
trackingEKF with properties:
State: [7x1 double]
StateCovariance: [7x7 double]
StateTransitionFcn: @constturn
StateTransitionJacobianFcn: @constturnjac
ProcessNoise: [4x4 double]
HasAdditiveProcessNoise: 0
MeasurementFcn: @ctmeas
MeasurementJacobianFcn: @ctmeasjac
MeasurementNoise: [3x3 double]
HasAdditiveMeasurementNoise: 1
EnableSmoothing: 0
По умолчанию трекер предполагает, что каждый шаг обновляет все дорожки, управляемые трекером в зоне покрытия. Это не так, когда датчики имеют ограниченный охват и сканируют небольшую область, или когда они управляются и управляются для сканирования определенных областей из общей зоны покрытия. Если это так, датчики должны сообщить трекеру, что некоторые дорожки не были покрыты датчиками на этом этапе. В противном случае трекер предполагает, что треки должны были быть обнаружены, и будет считать «промах» против них, что приведет к их преждевременному удалению.
В следующем примере показано, как датчики указывают, что дорожка не будет обнаружена, и как дорожка не будет удалена.
Создайте трекер, обеспечивающий обратную связь с датчиками.
release(tracker) % Release the tracker tracker.FilterInitializationFcn = 'initcvekf'; tracker.HasDetectableTrackIDsInput = true % Allows the tracker to get input about the track detectability by the sensors % Update the tracker with a single detection to get a single track detection = {objectDetection(0, [1;2;3], 'ObjectClassID', 2)}; time = 0; trackIDs = []; % Initially, there are no tracks, so trackIDs has zero rows track = tracker(detection, time, trackIDs) % Update the tracker 2 more times without any detections. Let the tracker % know that the track was not detectable by any sensor. Note how the % TrackLogicState, shown as [currentScore, maxScore], does not change even % though the track is not detected. for i=1:2 time = time + 1; trackIDs = [1, 0]; % Zero probability of detection means the track score should not decrease track = tracker({}, time, trackIDs) % No detections end
tracker =
trackerGNN with properties:
TrackerIndex: 0
FilterInitializationFcn: 'initcvekf'
Assignment: 'Auction'
AssignmentThreshold: [30 Inf]
MaxNumTracks: 100
MaxNumSensors: 20
OOSMHandling: 'Terminate'
TrackLogic: 'Score'
ConfirmationThreshold: 20
DeletionThreshold: -7
DetectionProbability: 0.9000
FalseAlarmRate: 1.0000e-06
Volume: 1
Beta: 1
HasCostMatrixInput: false
HasDetectableTrackIDsInput: true
StateParameters: [1x1 struct]
NumTracks: 0
NumConfirmedTracks: 0
track =
objectTrack with properties:
TrackID: 1
BranchID: 0
SourceIndex: 0
UpdateTime: 0
Age: 1
State: [6x1 double]
StateCovariance: [6x6 double]
StateParameters: [1x1 struct]
ObjectClassID: 2
TrackLogic: 'Score'
TrackLogicState: [13.7102 13.7102]
IsConfirmed: 1
IsCoasted: 0
IsSelfReported: 1
ObjectAttributes: [1x1 struct]
track =
objectTrack with properties:
TrackID: 1
BranchID: 0
SourceIndex: 0
UpdateTime: 1
Age: 2
State: [6x1 double]
StateCovariance: [6x6 double]
StateParameters: [1x1 struct]
ObjectClassID: 2
TrackLogic: 'Score'
TrackLogicState: [13.7102 13.7102]
IsConfirmed: 1
IsCoasted: 1
IsSelfReported: 1
ObjectAttributes: [1x1 struct]
track =
objectTrack with properties:
TrackID: 1
BranchID: 0
SourceIndex: 0
UpdateTime: 2
Age: 3
State: [6x1 double]
StateCovariance: [6x6 double]
StateParameters: [1x1 struct]
ObjectClassID: 2
TrackLogic: 'Score'
TrackLogicState: [13.7102 13.7102]
IsConfirmed: 1
IsCoasted: 1
IsSelfReported: 1
ObjectAttributes: [1x1 struct]
Как видно, оценка трека не уменьшилась и трек не был удален трекером, даже несмотря на то, что он не был обнаружен в 5 обновлениях.
Последнее усовершенствование позволяет прогнозировать треки в будущее без изменения их внутреннего состояния. Для этого существуют два распространенных варианта использования:
Отображение прогнозируемых дорожек на дисплее.
Передача предсказанных дорожек в сенсорную систему так, чтобы сенсорная система могла выдать сигнал на шаблон поиска для их обнаружения.
Вы используете predictTracksToTime способ получения прогнозируемых дорожек.
Обновление трекера с помощью дополнительных обнаружений
time = time + 1;
detections = {objectDetection(time, [4,2,3]); ...
objectDetection(time, [10;0;0])};
track = tracker(detections, time, trackIDs);
disp('State of track #1 at time 3:')
disp(track.State)
% Predict tracks to different time steps:
predictedTrack1 = predictTracksToTime(tracker,1, time+0.5); % Predict track number 1 half a second to the future
disp('State of track #1 at time 3.5:')
predictedTrack1.State
% Predict all the confirmed tracks 2 seconds to the future
predictedConfirmedTracks = predictTracksToTime(tracker, 'Confirmed', time+2);
disp('State of track #1 at time 5:')
predictedConfirmedTracks.State
% Predict all the tracks 0.3 seconds to the future
disp('State of all the tracks at time 3.3:')
predictedTracks = predictTracksToTime(tracker, 'all', time+0.3);
predictedTracks.State
State of track #1 at time 3:
3.9967
1.0030
2.0000
0
3.0000
0
State of track #1 at time 3.5:
ans =
4.4982
1.0030
2.0000
0
3.0000
0
State of track #1 at time 5:
ans =
6.0027
1.0030
2.0000
0
3.0000
0
State of all the tracks at time 3.3:
ans =
4.2976
1.0030
2.0000
0
3.0000
0
ans =
10
0
0
0
0
0
Вы можете использовать predictTracksToTime способ визуализации прогнозируемого состояния дорожек.
% First, use a |theaterPlot| and a |trackPlotter| to plot the tracks. thPlot = theaterPlot('XLimits',[-20 20], 'Ylimits', [-20 20]); trPlotter = trackPlotter(thPlot, 'DisplayName', 'Predicted Track'); posSelector = [1 0 0 0 0 0; 0 0 1 0 0 0; 0 0 0 0 1 0]; velSelector = [0 1 0 0 0 0; 0 0 0 1 0 0; 0 0 0 0 0 1]; % Then, plot the predicted tracks every 0.1 seconds for t = time+(0.1:0.1:5) predictedTracks = predictTracksToTime(tracker, 'Confirmed', t); [pos,cov] = getTrackPositions(predictedTracks,posSelector); vel = getTrackVelocities(predictedTracks,velSelector); plotTrack(trPlotter,pos,vel,cov); drawnow end
![]()
В этом примере создается trackerGNN и использовал его для отслеживания нескольких целей. Трекер был изменен для использования различных алгоритмов присвоения, двух типов логики подтверждения и удаления и различных фильтров отслеживания. Кроме того, вы видели, как соединить трекер с сканирующим радаром и как получить прогнозы дорожки для управления дисплеем или сенсором.