Introduction to Track Logic
This example shows how to define and use confirmation and deletion logic that are based on history or score. It introduces the trackHistoryLogic
and trackScoreLogic
objects and shows how to use them as stand-alone objects and how to use them as part of the trackerGNN
.
Introduction
The tracker maintains a list of tracks, or estimates of the 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, it is unclear whether the new track represents a true target or a false one. At first, a track is created with tentative status. If enough evidence is obtained, the track becomes confirmed. Similarly, if no detections are assigned to a track, the track is coasted (predicted without correction), but after a few missed updates, the tracker deletes the track.
There are two main ways of confirming and deleting tracks used in the literature:
History-based: the tracker counts the number of detections assigned to a track in several recent updates. If enough detections are assigned, the track is confirmed. If the track is not assigned to any detection for enough updates, it is deleted. This type of logic is often referred to as M-out-of-N or Last-N, meaning that out of N updates, the track must be detected at least _M _ times for it to be confirmed.
Score-based: the tracker calculates the likelihood that a track is of a real target. Instead of likelihood, we use the score, defined as the log of the likelihood. A high positive track score means that the track is very likely to be of a real target. A very negative track score means that the track is likely to be false. As a result, we can set a threshold for confirming a track if the score is high enough. If the score is low, or falls enough from the maximum score, the track is deleted.
In the following sections, you can see how to define and use the two types of objects that implement the history-based and score-based track logic.
Use a History-Based Track Logic to Confirm and Delete a Track
The simplest type of track logic is based on history. This type of logic counts how many times the track is detected (or missed) in the recent N updates. You want to confirm a track after 3 detections in 5 updates (3-out-of-5), and delete it after 6 consecutive misses. First, create the trackHistoryLogic
object that maintains the track history by defining the confirmation and deletion thresholds.
historyLogic = trackHistoryLogic('ConfirmationThreshold', [3 5], 'DeletionThreshold', 6)
historyLogic = trackHistoryLogic with properties: ConfirmationThreshold: [3 5] DeletionThreshold: [6 6] History: [0 0 0 0 0 0]
To illustrate this, in the first 5 updates, the track is detected every other update. The following shows how the track logic gets confirmed after exactly 3 out of 5 hits. Use the init
method to initialize the object with the first hit. Then use either the hit
or miss
methods to indicate whether the track logic is updated by a hit or a miss, respectively.
The checkConfirmation
method is used to check if the track can be confirmed based on its history. Use the output
method to get the track history, which is a logical array of length Nmax = max(Nconf, Ndel)
. In this example, Nmax
is 6.
wasInitialized = false; % Has the object been initialized yet? for i = 1:5 detectedFlag = logical(mod(i,2)); % Only odd updates are true if detectedFlag && ~wasInitialized init(historyLogic) wasInitialized = true; elseif detectedFlag && wasInitialized hit(historyLogic) else miss(historyLogic) end history = output(historyLogic); confFlag = checkConfirmation(historyLogic); disp(['Track history is: ', num2str(history),'. Confirmation Flag is: ',num2str(confFlag)]) end
Track history is: 1 0 0 0 0 0. Confirmation Flag is: 0 Track history is: 0 1 0 0 0 0. Confirmation Flag is: 0 Track history is: 1 0 1 0 0 0. Confirmation Flag is: 0 Track history is: 0 1 0 1 0 0. Confirmation Flag is: 0 Track history is: 1 0 1 0 1 0. Confirmation Flag is: 1
Now, suppose that the track is not detected for several updates. After the sixth update it should be deleted. Use the checkDeletion
method to check if the track was deleted.
for i = 1:6 miss(historyLogic); % Every update the track is not detected history = output(historyLogic); deleteFlag = checkDeletion(historyLogic); disp(['Track history is: ', num2str(history),'. Deletion Flag is: ',num2str(deleteFlag)]) end
Track history is: 0 1 0 1 0 1. Deletion Flag is: 0 Track history is: 0 0 1 0 1 0. Deletion Flag is: 0 Track history is: 0 0 0 1 0 1. Deletion Flag is: 0 Track history is: 0 0 0 0 1 0. Deletion Flag is: 0 Track history is: 0 0 0 0 0 1. Deletion Flag is: 0 Track history is: 0 0 0 0 0 0. Deletion Flag is: 1
Use a Score-Based Track Logic to Confirm and Delete a Track
In many cases, it is not enough to know if a track is assigned a detection. You may need to account for the likelihood that the assignment is correct. There is also a need to know how likely the detection is that of a real target, based on its detection probability, or how likely it is to be false, based on its false alarm rate. Additionally, if the track is new, you need to account for the rate, beta , at which new targets are likely to be detected in a unit volume.
Use the trackScoreLogic
object to create a score-based track confirmation and deletion logic. Define the ConfirmationThreshold
and DeletionThreshold
as two scalar values.
When a track is assigned a detection, you update the track logic with a hit and in most cases the track score increases. The ConfirmationThreshold
defines the minimum score that is required to confirm a track.
The track score decreases when a track is not assigned a detection. The DeletionThreshold
is used to define how much we allow the score to decrease from the maximum score before deleting the track.
scoreLogic = trackScoreLogic('ConfirmationThreshold', 25, 'DeletionThreshold', -5)
scoreLogic = trackScoreLogic with properties: ConfirmationThreshold: 25 DeletionThreshold: -5 Score: 0 MaxScore: 0
pd = 0.9; % Probability of detection pfa = 1e-6; % Probability of false alarm volume = 1; % The volume of a sensor detection bin beta = 0.1; % New target rate in a unit volume wasInitialized = false; % Has the object been initialized yet?
Confirming a track using score-based logic is very similar to confirming a track using history-based logic. The main difference is that now additional parameters are taken into account that include the statistical performance of the sensor as well as the residual distance of the track relative to the detection.
You use the init
, hit
, and miss
methods to initialize on first hit, update the trackScoreLogic
with a subsequent hit, or update with a miss, respectively.
You use the checkConfirmation
method to check if the track should be confirmed. You use the output
method to get the current score and maximum score as a [currentScore, maxScore]
array.
r = rng(2018); % Set the random seed for repeatable results numSteps1 = 6; scores = zeros(numSteps1,2); for i = 1:numSteps1 l = 0.05 + 0.05 * rand; % likelihood of the measurement detectedFlag = logical(mod(i,2)); % Only even updates are true in this example if detectedFlag && ~wasInitialized init(scoreLogic, volume, beta); wasInitialized = true; elseif detectedFlag && wasInitialized hit(scoreLogic, volume, l); else miss(scoreLogic); end scores(i,:) = output(scoreLogic); confFlag = checkConfirmation(scoreLogic); disp(['Score and MaxScore: ', num2str(scores(i,:)),'. Confirmation Flag is: ',num2str(confFlag)]) end
Score and MaxScore: 11.4076 11.4076. Confirmation Flag is: 0 Score and MaxScore: 9.10498 11.4076. Confirmation Flag is: 0 Score and MaxScore: 20.4649 20.4649. Confirmation Flag is: 0 Score and MaxScore: 18.1624 20.4649. Confirmation Flag is: 0 Score and MaxScore: 29.2459 29.2459. Confirmation Flag is: 1 Score and MaxScore: 26.9433 29.2459. Confirmation Flag is: 1
rng(r); % Return the random seed to its previous setting
Notice how the track score increases with every successful update and decreases with every missed detection. Once the track score is higher than the ConfirmationThreshold, the checkConfirmation function returns true, meaning that the track is confirmed now.
As in the history-based track logic, if the track is not assigned to any detection, it should eventually be deleted. The DeletionThreshold
property is used to determine when the track score has decreased enough so that the track should be deleted. Note that the score does not have to fall below the DeletionThreshold
, only that the difference between the current score and the maximum score obtained by the track should go below the threshold. The reason is that if a track obtains a high score after many successful updates, and if we used the absolute score, it would take too many missed updates to delete the track. The following shows a track being deleted after three misses.
numSteps2 = 3; scores(end+1:end+numSteps2,:) = zeros(numSteps2,2); for i = 1:numSteps2 miss(scoreLogic); deleteFlag = checkDeletion(scoreLogic); scores(numSteps1+i,:) = output(scoreLogic); disp(['Score and MaxScore: ', num2str(scores(numSteps1+i,:)),'. Deletion Flag is: ',num2str(deleteFlag)]) end
Score and MaxScore: 24.6407 29.2459. Deletion Flag is: 0 Score and MaxScore: 22.3381 29.2459. Deletion Flag is: 1 Score and MaxScore: 20.0355 29.2459. Deletion Flag is: 1
deletionScore = scores(:,2) + scoreLogic.DeletionThreshold; stairs(scores) hold on plot([1,numSteps1+numSteps2],[scoreLogic.ConfirmationThreshold scoreLogic.ConfirmationThreshold],'--') stairs(deletionScore,'--') title('Track Score and Maximum Score') legend('Score','MaxScore','ConfirmationThreshold','DeletionThreshold','Location','best')
If you want to delay the track deletion until more misses happen, simply change the DeletionThreshold
to a more negative value.
Use a Track Logic in a Tracker
Typically, track logic is used inside a tracker. Configure the trackerGNN
to use history-based track logic with confirmation after 3 successes in 5 updates and deletion after 5 misses in 6 updates.
tracker = trackerGNN('Assignment', 'Auction', 'ConfirmationThreshold', [3 5], 'DeletionThreshold', [5 6], 'TrackLogic', 'History')
tracker = trackerGNN with properties: TrackerIndex: 0 FilterInitializationFcn: 'initcvekf' MaxNumTracks: 100 MaxNumDetections: Inf MaxNumSensors: 20 Assignment: 'Auction' AssignmentThreshold: [30 Inf] AssignmentClustering: 'off' OOSMHandling: 'Terminate' TrackLogic: 'History' ConfirmationThreshold: [3 5] DeletionThreshold: [5 6] HasCostMatrixInput: false HasDetectableTrackIDsInput: false StateParameters: [1x1 struct] ClassFusionMethod: 'None' NumTracks: 0 NumConfirmedTracks: 0 EnableMemoryManagement: false
The following loop updates the tracker with a detection at every odd numbered update. After 5 updates, the tracker confirms the track. You can look at the track history and the track confirmation flag after each update by examining the TrackLogicState
and IsConfirmed
fields of the track output.
for i = 1:5 detectedFlag = logical(mod(i,2)); % Only odd updates are true if detectedFlag detection = {objectDetection(i,[1;2;3])}; else detection = {}; end [~,~,allTracks] = tracker(detection, i) end
allTracks = objectTrack with properties: TrackID: 1 BranchID: 0 SourceIndex: 0 UpdateTime: 1 Age: 1 State: [6x1 double] StateCovariance: [6x6 double] StateParameters: [1x1 struct] ObjectClassID: 0 ObjectClassProbabilities: 1 TrackLogic: 'History' TrackLogicState: [1 0 0 0 0 0] IsConfirmed: 0 IsCoasted: 0 IsSelfReported: 1 ObjectAttributes: [1x1 struct]
allTracks = objectTrack with properties: TrackID: 1 BranchID: 0 SourceIndex: 0 UpdateTime: 2 Age: 2 State: [6x1 double] StateCovariance: [6x6 double] StateParameters: [1x1 struct] ObjectClassID: 0 ObjectClassProbabilities: 1 TrackLogic: 'History' TrackLogicState: [0 1 0 0 0 0] IsConfirmed: 0 IsCoasted: 1 IsSelfReported: 1 ObjectAttributes: [1x1 struct]
allTracks = objectTrack with properties: TrackID: 1 BranchID: 0 SourceIndex: 0 UpdateTime: 3 Age: 3 State: [6x1 double] StateCovariance: [6x6 double] StateParameters: [1x1 struct] ObjectClassID: 0 ObjectClassProbabilities: 1 TrackLogic: 'History' TrackLogicState: [1 0 1 0 0 0] IsConfirmed: 0 IsCoasted: 0 IsSelfReported: 1 ObjectAttributes: [1x1 struct]
allTracks = objectTrack with properties: TrackID: 1 BranchID: 0 SourceIndex: 0 UpdateTime: 4 Age: 4 State: [6x1 double] StateCovariance: [6x6 double] StateParameters: [1x1 struct] ObjectClassID: 0 ObjectClassProbabilities: 1 TrackLogic: 'History' TrackLogicState: [0 1 0 1 0 0] IsConfirmed: 0 IsCoasted: 1 IsSelfReported: 1 ObjectAttributes: [1x1 struct]
allTracks = objectTrack with properties: TrackID: 1 BranchID: 0 SourceIndex: 0 UpdateTime: 5 Age: 5 State: [6x1 double] StateCovariance: [6x6 double] StateParameters: [1x1 struct] ObjectClassID: 0 ObjectClassProbabilities: 1 TrackLogic: 'History' TrackLogicState: [1 0 1 0 1 0] IsConfirmed: 1 IsCoasted: 0 IsSelfReported: 1 ObjectAttributes: [1x1 struct]
The following loop updates the tracker 5 more times with 5 misses. The track is deleted after 4 additional updates (the 9th update overall) because it has missed detections in the 4th, 6th, 7th, 8th and 9th updates (5 out of the last 6 updates).
for i = 1:5 detection = {}; confirmedTrack = tracker(detection, i+5) end
confirmedTrack = objectTrack with properties: TrackID: 1 BranchID: 0 SourceIndex: 0 UpdateTime: 6 Age: 6 State: [6x1 double] StateCovariance: [6x6 double] StateParameters: [1x1 struct] ObjectClassID: 0 ObjectClassProbabilities: 1 TrackLogic: 'History' TrackLogicState: [0 1 0 1 0 1] IsConfirmed: 1 IsCoasted: 1 IsSelfReported: 1 ObjectAttributes: [1x1 struct]
confirmedTrack = objectTrack with properties: TrackID: 1 BranchID: 0 SourceIndex: 0 UpdateTime: 7 Age: 7 State: [6x1 double] StateCovariance: [6x6 double] StateParameters: [1x1 struct] ObjectClassID: 0 ObjectClassProbabilities: 1 TrackLogic: 'History' TrackLogicState: [0 0 1 0 1 0] IsConfirmed: 1 IsCoasted: 1 IsSelfReported: 1 ObjectAttributes: [1x1 struct]
confirmedTrack = objectTrack with properties: TrackID: 1 BranchID: 0 SourceIndex: 0 UpdateTime: 8 Age: 8 State: [6x1 double] StateCovariance: [6x6 double] StateParameters: [1x1 struct] ObjectClassID: 0 ObjectClassProbabilities: 1 TrackLogic: 'History' TrackLogicState: [0 0 0 1 0 1] IsConfirmed: 1 IsCoasted: 1 IsSelfReported: 1 ObjectAttributes: [1x1 struct]
confirmedTrack = 0x1 objectTrack array with properties: TrackID BranchID SourceIndex UpdateTime Age State StateCovariance StateParameters ObjectClassID ObjectClassProbabilities TrackLogic TrackLogicState IsConfirmed IsCoasted IsSelfReported ObjectAttributes confirmedTrack = 0x1 objectTrack array with properties: TrackID BranchID SourceIndex UpdateTime Age State StateCovariance StateParameters ObjectClassID ObjectClassProbabilities TrackLogic TrackLogicState IsConfirmed IsCoasted IsSelfReported ObjectAttributes
Summary
Trackers require a way to confirm tracks that are considered to be of true targets and delete tracks after they are not assigned any detections after a while. Two types of track confirmation and deletion logic were presented: a history-based track logic and a score-based track logic. The history-based track logic only considers whether a track is assigned detections in the recent past updates. The score-based track logic provides a statistical measure of how likely a track is to represent a real target. Both types of track logic objects can be used as stand-alone objects, but are typically used inside a tracker object.