В этом примере показано, как сконфигурировать и использовать глобальный ближайший соседний трекер (GNN).
The trackerGNN
является глобальным ближайшим соседом (GNN), трекером с одной гипотезой. The 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
входной параметр или struct с аналогичными полями. Необходимо указать время обнаружения и его измерения. Другие свойства имеют значения по умолчанию. Для примера:
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]
Создаются два типа треков: подтвержденные и ориентировочные. Подтвержденная дорожка является дорожкой, которая рассматривается как оценка действительной цели, в то время как ориентировочная дорожка все еще может быть ложной целью. The 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
и использовали его для отслеживания нескольких целей. Вы модифицировали трекер, чтобы использовать различные алгоритмы назначения, два типа логики подтверждения и удаления и различные фильтры отслеживания. В сложение вы видели, как соединить трекер с помощью сканирующего радара и как получить предсказания дорожки для управления отображения или датчиком.