Main Content

trackingFilterTuner

Tracking filter tuner

Since R2022b

Description

The trackingFilterTuner object creates a tracking filter tuner that tunes the tunable properties of a tracking filter object, such as the trackingEKF object. Use the FilterInitializationFcn property to initialize a tracking filter for tuning. Use the tune object function to tune the filter.

Creation

Description

example

tuner = trackingFilterTuner creates a tracking filter tuner with default property values.

example

tuner = trackingFilterTuner(Name=Value) specifies properties using one or more name-value arguments. For example, trackingFilterTuner(Solver="patternsearch") specifies the pattern search algorithm as the solver algorithm.

Properties

expand all

Filter initialization function, specified as a string scalar or a character vector representing the name of a valid filter initialization function. For this property, a valid filter initialization function is a function that returns a tunable tracking filter object. These tracking filter objects are tunable:

You can use any of these built-in filter initialization functions.

To write a custom initialization function, refer to the code for any of the initialization functions. For example, type the following command in the command window to see the implementation for the initcvekf function.

edit initcvekf

Note

If you specify the UseMex property to true, changing the value of the FilterInitializationFcn property triggers code generation.

Data Types: char | string

Source of filter tunable properties, specified as:

  • "Default" — The filter object specified in the FilterInitializationFcn property defines the properties to be tuned, the tuned elements, and the tuning bounds. To get the tunable properties of the filter, use the tunableProperties object function of the tunable filter object.

  • "Custom" — Specify the tunable properties as a tunableFilterProperties object in the CustomTunableProperties property.

Note

If you set the UseMex property to true, changing the value of the TunablePropertiesSource property triggers code generation.

Data Types: char | string

Custom tunable properties, specified as a tunableFilterProperties object. You can use the tunableProperties function of the filter object to obtain the default tunableFilterProperties object and modify it to obtain a custom tunableFilterProperties object.

Note

If you set the UseMex property to true, changing the value of the CustomTunableProperties property triggers code generation.

Dependencies

To enable this property, set the TunablePropertiesSource property to "Custom".

Data Types: object

Tuning cost, specified as one of these options:

  • "RMSE" — The tuner minimizes the root mean square of the error between the ground truth and the filter estimates over all the time steps and Monte-Carlo runs. Use this option if the absolute distance between the truth and estimate is the most important aspect for your tuning. See Objective Function for RMSE for more algorithm details.

  • "NEES" — The tuner minimizes the normalized estimate error squared between the ground truth and the filter estimates over all the time steps and Monte-Carlo runs. Use this option if you want to optimize the state estimate error covariance for a consistent filter. See Objective Function for NEES for more algorithm details.

  • "NLL" — The tuner minimizes the negative log likelihood between the ground truth and the filter estimates over all the time steps and Monte-Carlo runs. Use this option if you want to optimize the filter for a tracker that uses this cost for data association. See Objective Function for NLL for more algorithm details.

  • "Custom" — Specify the cost function in the CustomCostFcn property. Use a custom cost function if any of these conditions is true:

    • You want to tune the filter using a custom cost.

    • The truth table used in the tune function contains data other than target position, velocity, or state.

Data Types: char | string

Custom cost function, specified as a string scalar, a character vector, or a function handle. The custom cost function must use the following syntax:

cost = myCostFun(trackHistory,truth)

  • trackHistoryN-by-M array of track structures, where N is the number of the rows in the truth time table and M is the number of Monte-Carlo runs specified in the detection log input of the tune object function. Each structure has these fields:

    • UpdateTime — The time at which the filter was updated, specified as a scalar.

    • State — The state estimate at the update time.

    • StateCovariance — The state estimate error covariance at the update time.

  • truth — A truth time table that is the same as the truth time table input for the tune object function.

  • cost — A scalar value representing the cost.

Dependencies

To enable this property, set the Cost property to "Custom".

Data Types: char | string | function_handle

Optimization solver, specified as one of these options:

  • "active-set" — Tune the filter by using the active-set optimization algorithm.

    Note

    When using this solver, the tuner can possibly violate the bounds of tunable properties during the tuning process and cause an error. In this case, either reduce the bounds of the tunable property or use a different solver.

  • "fmincon" — This option requires Optimization Toolbox™. See fmincon (Optimization Toolbox) for details.

  • "patternsearch" — This option requires Global Optimization Toolbox. See patternsearch (Global Optimization Toolbox) for details.

  • "particleswarm" — This option requires Global Optimization Toolbox. See particleswarm (Global Optimization Toolbox) for details.

Data Types: char | string

Enable using code generation, specified as a logical 0 (false) or 1 (true). Specifying true requires MATLAB® Coder™ license.

If you set the property to true, the object first generates mex code and then runs the tuning based on the generated code. For large data sets, using generated code can expedite the tuning process.

Data Types: logical

Enable using parallel processing, specified as a logical 0 (false) or 1 (true). Specifying true requires Parallel Computing Toolbox™. For large data sets, using parallel processing can expedite the tuning process.

Note

If you set the UseMex property to true, changing the value of the useParallel property triggers code generation.

Data Types: logical

Tuner progress display options, specified as one of these:

  • "Text" — The tuner displays the progress using an iterative textual display in the command window.

  • "None" — The tuner does not display any information while tuning.

  • "Plot" — The tuner displays the tuning progress as a plot of tuning cost versus number of iterations.

  • "SolverOptions" — The tuner displays the tuning information based on the configuration specified in the SolverOptions property. To use this option, set the Solver property as "fmincon", "patternsearch", or "particleswarm".

Data Types: char | string

Options to control the solver in the Solver property, specified as an optimoptions (Optimization Toolbox) object. The default value of [] represents the default setup for the solver.

Object Functions

tuneTune tracking filter
exportToFunctionExport filter initialization function
plotFilterErrorsPlot tracking filter errors
tuningDataGenerate detection log and truth table for tuning
parameterCostGet cost for tuning parameters
tunedParametersGet tuned parameters

Examples

collapse all

Load the tuning data containing the truth and detection data. The truth data has the position and velocity of one target for a duration of 9.5 seconds. The detection data has object detections of ten Monte-Carlo runs for the same period.

load("filterTuningData.mat","truth","detlog");

Create a trackingFilterTuner object and set the Solver property to "fmincon".

tuner = trackingFilterTuner(Solver="fmincon");

By default, the FilterInitialization property of the tuner returns an initialization function that initializes a trackingEKF object.

initFcn = tuner.FilterInitializationFcn
initFcn = 
"initcvekf"

Initialize the trackingEKF object and display the untuned process noise.

filter = feval(tuner.FilterInitializationFcn,detlog{1});
disp(filter.ProcessNoise);
     1     0     0
     0     1     0
     0     0     1

Specify the SolverOptions property so that the tuner displays the tuning progress for every iteration and set the maximum number of iterations to 30.

tuner.SolverOptions = optimoptions("fmincon",MaxIterations=30);

Using the tune object function, tune the filter with the detection log and the truth data. Return the tuned properties.

tunedProps = tune(tuner,detlog,truth);
Iter        RMSE          Step Size
   0       9.2941          0.0000
   1       9.2749          0.1313
   2       9.1827          0.6852
   3       9.0777          1.1658
   4       9.0734          0.0937
   5       9.0548          0.2909
   6       9.0472          0.2754
   7       9.0477          0.0348
   8       9.0474          0.0501
   9       9.0474          0.0148
  10       9.0473          0.0141
  11       9.0473          0.0072
  12       9.0459          0.0621
  13       9.0455          0.0237
  14       9.0455          0.0054
  15       9.0455          0.0021
  16       9.0455          0.0019
  17       9.0452          0.0250
  18       9.0451          0.0177
  19       9.0451          0.0024
  20       9.0451          0.0005
  21       9.0451          0.0010
  22       9.0451          0.0007
  23       9.0451          0.0012
  24       9.0451          0.0007
  25       9.0451          0.0006
  26       9.0451          0.0003
  27       9.0451          0.0002
  28       9.0450          0.0153
  29       9.0450          0.0073
  30       9.0450          0.0013

Solver stopped prematurely.

fmincon stopped because it exceeded the iteration limit,
options.MaxIterations = 3.000000e+01.

Set the filter tunable properties by using the setTunedProperty object function of the filter. Display the tuned process noise.

setTunedProperties(filter,tunedProps);
disp(filter.ProcessNoise);
    0.0000    0.0001    0.0000
    0.0001    0.0149    0.0007
    0.0000    0.0007    0.0002

Plot the filter estimation error after tuning by using the plotFilterErrors object function.

plotFilterErrors(tuner)

Load the tuning data containing the truth and detection data. The truth data has the position and velocity of one target for a duration of 9.5 seconds. The detection data has object detections of ten Monte-Carlo runs for the same period.

load("filterTuningData.mat","truth","detlog");

Create a trackingFilterTuner object. Specify the FilterInitializationFcn property as "initcvkf" that corresponds to a trackingKF filter object with a constant velocity model.

tuner = trackingFilterTuner(FilterInitializationFcn ="initcvkf");

You can obtain the filter by evaluating the initialization function on an object detection.

filter = feval(tuner.FilterInitializationFcn,detlog{1})
filter = 
  trackingKF with properties:

               State: [6x1 double]
     StateCovariance: [6x6 double]

         MotionModel: '3D Constant Velocity'
        ProcessNoise: [3x3 double]

    MeasurementModel: [3x6 double]
    MeasurementNoise: [3x3 double]

     MaxNumOOSMSteps: 0

     EnableSmoothing: 0

To customize the tunable properties of the filter, first get the default tunable properties of the filter.

tps = tunableProperties(filter)
tps = 
Tunable properties for object of type: trackingKF

Property:      ProcessNoise
   PropertyValue:   [1 0 0;0 1 0;0 0 1]
   TunedQuantity:   Square root
   IsTuned:         true
       TunedQuantityValue:  [1 0 0;0 1 0;0 0 1]
       TunableElements:     [1 4 5 7 8 9]
       LowerBound:          [0 0 0 0 0 0]
       UpperBound:          [10 10 10 10 10 10]
Property:      StateCovariance
   PropertyValue:   [3.53553390593274 0 0 0 0 0;0 100 0 0 0 0;0 0 3.53553390593274 0 0 0;0 0 0 100 0 0;0 0 0 0 3.53553390593274 0;0 0 0 0 0 100]
   TunedQuantity:   Square root of initial value
   IsTuned:         false

Based on the display, the tuner tunes only the ProcessNoise property, which is a 3-by-3 matrix. Change the tunable elements to be only the diagonal elements by using the setPropertyTunability object function. Set the lower and upper bounds for tuning the diagonal elements.

setPropertyTunability(tps,"ProcessNoise",TunableElements=[1 5 9], ...
    LowerBound=[0.01 0.01 0.01],UpperBound = [20 20 20])

To enable custom tunable properties, set the TunablePropertiesSource and CustomTunable properties to "Custom" and tps, respectively.

tuner.TunablePropertiesSource = "Custom";
tuner.CustomTunableProperties = tps;

Using the tune object function, tune the filter with the detection log and the truth data.

tune(tuner,detlog,truth);
Iter        RMSE          Step Size
   0       9.2177                
   1       9.1951          0.1509
   2       9.0458          1.5108
   3       9.0456          0.0186
   4       9.0452          0.0705
   5       9.0452          0.0068
   6       9.0452          0.0016
   7       9.0451          0.1422
   8       9.0450          0.0600
   9       9.0450          0.0182
  10       9.0450          0.0105

Generate the filter initialization function after tuning by using the exportToFunction object function.

exportToFunction(tuner,"tunedInitFcn")

Obtain the tuned filter by evaluating the tuned initialization function on an object detection. Show the tuned process noise.

tunedFilter = tunedInitFcn(detlog{1})
tunedFilter = 
  trackingKF with properties:

               State: [6x1 double]
     StateCovariance: [6x6 double]

         MotionModel: '3D Constant Velocity'
        ProcessNoise: [3x3 double]

    MeasurementModel: [3x6 double]
    MeasurementNoise: [3x3 double]

     MaxNumOOSMSteps: 0

     EnableSmoothing: 0

tunedFilter.ProcessNoise
ans = 3×3

    0.0001         0         0
         0    0.0156         0
         0         0    0.0001

Create a trackingFilterTuner object and set its Display property to "Plot".

tuner = trackingFilterTuner(Display="Plot")
tuner = 
  trackingFilterTuner with properties:

    FilterInitializationFcn: "initcvekf"
    TunablePropertiesSource: "Default"

                       Cost: "RMSE"

                     UseMex: 0
                UseParallel: 0
                     Solver: "active-set"

Load the air traffic control scenario. Use the moterCarloRun and tuningData functions to generate the tuning data.

load("ATCScenario.mat")
recordings = monteCarloRun(scenario,1);
[detlog,truthTable] = tuner.tuningData(recordings);

Tune the tracking filter based on the tuning data.

tune(tuner,detlog,truthTable)

Figure contains an axes object. The axes object with title Filter Tuning Progress, xlabel Iteration, ylabel RMSE contains an object of type line.

ans = struct with fields:
       ProcessNoise: [3×3 double]
    StateCovariance: [6×6 double]

Generate the filter initialization function after tuning by using the exportToFunction object function.

exportToFunction(tuner,"tunedInitFcn")

Obtain the tuned filter by evaluating the tuned initialization function on an object detection. Show the tuned process noise.

tunedFilter = tunedInitFcn(detlog{1}{1})
tunedFilter = 
  trackingEKF with properties:

                          State: [6×1 double]
                StateCovariance: [6×6 double]

             StateTransitionFcn: @constvel
     StateTransitionJacobianFcn: @constveljac
                   ProcessNoise: [3×3 double]
        HasAdditiveProcessNoise: 0

                 MeasurementFcn: @cvmeas
         MeasurementJacobianFcn: @cvmeasjac
         HasMeasurementWrapping: 1
               MeasurementNoise: [3×3 double]
    HasAdditiveMeasurementNoise: 1

                MaxNumOOSMSteps: 0

                EnableSmoothing: 0

tunedFilter.ProcessNoise
ans = 3×3

  100.0029         0  100.0000
         0  100.0000         0
  100.0000         0  100.0000

Load the tuning data containing the truth and detection data. The truth data has the position and velocity of one target for a duration of 9.5 seconds. The detection data has object detections of ten Monte-Carlo runs for the same period.

load("filterTuningData.mat","truth","detlog");

Create a trackingFilterTuner object. Specify the FilterInitializationFcn property as "initekfIMM", which corresponds to a trackingIMM filter object containing three trackingEKF filter objects.

tuner = trackingFilterTuner(FilterInitializationFcn ="initekfimm")
tuner = 
  trackingFilterTuner with properties:

    FilterInitializationFcn: "initekfimm"
    TunablePropertiesSource: "Default"

                       Cost: "RMSE"

                     UseMex: 0
                UseParallel: 0
                     Solver: "active-set"
                    Display: "Text"

Obtain the filter by evaluating the initialization function on an object detection.

filter = feval(tuner.FilterInitializationFcn,detlog{1});
tps = tunableProperties(filter)
tps = 
Tunable properties for object of type: trackingIMM

Property:      TransitionProbabilities
   PropertyValue:   [0.9 0.05 0.05;0.05 0.9 0.05;0.05 0.05 0.9]
   TunedQuantity:   Rows sum to one
   IsTuned:         true
       TunedQuantityValue:  [0.9 0.05 0.05;0.05 0.9 0.05;0.05 0.05 0.9]
       TunableElements:     [1 2 3 4 5 6 7 8 9]
       LowerBound:          [0.001 0.001 0.001 0.001 0.001 0.001 0.001 0.001 0.001]
       UpperBound:          [1 1 1 1 1 1 1 1 1]
Property:      ModelProbabilities
   PropertyValue:   [0.333333333333333;0.333333333333333;0.333333333333333]
   TunedQuantity:   Columns sum to one
   IsTuned:         true
       TunedQuantityValue:  [0.333333333333333;0.333333333333333;0.333333333333333]
       TunableElements:     [1 2 3]
       LowerBound:          [0.001 0.001 0.001]
       UpperBound:          [1 1 1]

The filter contains 3 tracking filters
   Show tunable properties for filter 1
   Show tunable properties for filter 2
   Show tunable properties for filter 3

Disable the tuning of the ProcessNoise properties in the three tracking filters by using the setProperTuanbility function. With this setup, the tuner tunes only the TransitionProbabilities and ModelProbabilities properties.

setPropertyTunability(tps,"ProcessNoise",FilterIndex=1,IsTuned=false);
setPropertyTunability(tps,"ProcessNoise",FilterIndex=2,IsTuned=false);
setPropertyTunability(tps,"ProcessNoise",FilterIndex=3,IsTuned=false);

To enable custom tunable properties, set the TunablePropertiesSource and CustomTunableProperties properties to "Custom" and tps, respectively.

tuner.TunablePropertiesSource = "Custom";
tuner.CustomTunableProperties = tps;

Tune the filter and obtain the tuned properties.

tunedProps = tune(tuner,detlog,truth)
Iter        RMSE          Step Size
   0      11.4984                
   1      10.5860          0.6467
   2      10.3850          0.2469
   3      10.2415          0.0553
   4      10.2505          0.0338
   5      10.2278          0.0658
   6      10.1940          0.1806
   7      10.2251          0.1738
   8      10.2225          0.0066
   9      10.2042          0.1454
  10      10.1976          0.1352
  11      10.3699          0.4188
  12      10.2894          0.2968
  13      10.2965          0.2498
  14      10.2886          0.0362
  15      10.1763          0.5250
  16      10.2446          0.3159
  17      10.2597          0.0263
  18      10.1836          0.3079
  19      10.1794          0.0172
  20      10.1890          0.1725
  21      10.1870          0.0145
  22      10.1484          0.1162
  23      10.1435          0.0033
  24      10.1384          0.0082
  25      10.1354          0.0099
  26      10.1322          0.0158
  27      10.1331          0.0838
  28      10.1316          0.0188
  29      10.1145          0.6438
  30      10.1338          0.2801
  31      10.1312          0.3709
  32      10.1153          0.6495
  33      10.1118          0.1515
  34      10.1340          0.4673
  35      10.1164          0.6180
  36      10.1344          0.3019
  37      10.1244          0.1909
  38      10.1162          0.4880
  39      10.1141          0.1283
  40      10.1127          0.0911
  41      10.1116          0.0588
  42      10.1112          0.0473
  43      10.1110          0.0308
  44      10.1109          0.0363
  45      10.1107          0.0433
  46      10.1104          0.0436
  47      10.1096          0.0569
  48      10.1041          0.0228
  49      10.1041          0.0009
  50      10.0953          0.3454
  51      10.0953          0.0000
  52      10.0949          0.0169
  53      10.0798          0.6475
  54      10.0452          0.6132
  55      10.0008          0.5961
  56      10.0007          0.0000
  57      10.0007          0.0002
  58       9.9981          0.0283
  59       9.9977          0.0122
  60       9.9976          0.0084
  61       9.9976          0.0023
tunedProps = struct with fields:
    TransitionProbabilities: [3×3 double]
         ModelProbabilities: [3×1 double]
            TrackingFilters: {3×1 cell}

Set the properties of the filter using the tuned properties.

setTunedProperties(filter,tunedProps);

Show the tuned properties.

filter.TransitionProbabilities
ans = 3×3

    0.9980    0.0010    0.0010
    0.1733    0.4133    0.4133
    0.4995    0.0010    0.4995

filter.ModelProbabilities
ans = 3×1

    0.9980
    0.0010
    0.0010

Generate a log of range-only detections and the truth data by using the helperGenerateDetectionAndTruth function.

rng(2023) % For repeatable results
[detlog,truth] = helperGenerateDetectionAndTruth;

Create an angle-parameterized trackingGSF object that has ten tracking filters by using the initapekf function. Display the untuned process noise.

filter = initapekf(detlog{1});
disp(filter.TrackingFilters{1}.ProcessNoise)
     1     0     0
     0     1     0
     0     0     1

Create a trackingFilterTuner object. Specify the FilterInitializationFcn property as "initapekf".

tuner = trackingFilterTuner(FilterInitializationFcn="initapekf");

Tune the filter and obtain the tuned properties.

tunedProps = tune(tuner,detlog,truth)
Iter        RMSE          Step Size
   0     178.8318                
   1     177.5988         19.5448
tunedProps = struct with fields:
    ProcessNoise: [3x3 double]

Set the properties of the filter using the tuned properties.

setTunedProperties(filter,tunedProps);

Show the tuned process noise.

disp(filter.TrackingFilters{10}.ProcessNoise)
  100.0000  100.0000  100.0000
  100.0000  100.0000  100.0000
  100.0000  100.0000  201.0000

Helper Functions

function [detlog,truth] = helperGenerateDetectionAndTruth
% Function to generate a detection log and the corresponding truth.
% Define initial conditions. Assume a constant velcoity truth model.
s0 = [10 10 0]';
v = [2 2 0]';
dt = 5;
tFinal = 100;
tspan = (0:dt:tFinal)';
numSteps = numel(tspan);

% Specify measurement structure for range-only detection.
mp = struct(Frame="Spherical", ...
    HasAzimuth=false, ...
    HasElevation=false, ...
    HasRange=true,...
    HasVelocity=false);
detlog = cell(numSteps,1);
sigma = 5; % Standar deviation of range measurements
detlog{1} = objectDetection(tspan(1),norm(s0), ...
    MeasurementNoise=sigma^2,MeasurementParameters=mp);
s = s0;
Position = NaN(numSteps,3);
Position(1,:) = s;
Velocity = repmat(v',numSteps,1);

% Iterate to obtain the truth and detections
for ii = 2:numSteps
    s = s + v *dt;
    Position(ii,:) = s;
    measure = norm(s) + sqrt(sigma^2)*randn;
    detlog{ii} = objectDetection(tspan(ii),measure, ...
        MeasurementNoise=sigma^2,MeasurementParameters=mp);
end
truth = timetable(seconds(tspan),Position,Velocity);
end

Algorithms

expand all

References

[1] Chen, Zhaozhong, et al. “Time Dependence in Kalman Filter Tuning.” IEEE 24th International Conference on Information Fusion , IEEE, 2021, pp. 1–8.

Version History

Introduced in R2022b

expand all