%trackingUKF   An unscented Kalman filter for object tracking
%   The unscented Kalman filter is designed for tracking objects that
%   follow a nonlinear motion model or that are measured by a nonlinear
%   measurement model. You can use the filter to predict an object's future
%   location, to reduce noise in the detected location, or to help
%   associate multiple object detections with their tracks.
%
%   The unscented Kalman filter estimates the uncertainty about the state,
%   and its propagation through the nonlinear state and measurement
%   equations, using a fixed number of "Sigma Points". These points are
%   chosen using the Unscented Transformation, and are governed by three
%   parameters: Alpha, Beta, and Kappa. The valid ranges of values for
%   these parameters are (defaults are in parenthesis):
%       0 <  Alpha <= 1     (1e-3)
%       0 <= Beta           (2)
%       0 <= Kappa <= 3     (0)
%
%   UKF = trackingUKF returns an unscented Kalman filter object with
%   state transition function (@constvel), measurement function (@cvmeas)
%   and state ([0;0;0;0]), and assumes an additive noise model.
% 
%   UKF = trackingUKF(StateTransitionFcn, MeasurementFcn, State) lets you
%   specify the state transition function, f, and the measurement function,
%   h. Both must be specified as function_handles. In addition, the object
%   lets you specify an initial value for the state.
% 
%   UKF = trackingUKF(..., Name, Value) specifies additional
%   name-value pair arguments to define the properties described below.
%
%   trackingUKF properties:
%   State                       - State, (x)
%   StateCovariance             - State estimation error covariance, (P)
%   StateTransitionFcn          - Propagates the state to next time step, (f)
%   ProcessNoise                - Process noise covariance, (Q)
%   HasAdditiveProcessNoise     - True if process noise is additive
%   MeasurementFcn              - Calculates the measurement, (h)
%   HasMeasurementWrapping      - True if the measurement wraps (read only)
%   MeasurementNoise            - Measurement noise covariance, (R)
%   HasAdditiveMeasurementNoise - True if measurement noise is additive
%   Alpha                       - Unscented transformation parameter alpha
%   Beta                        - Unscented transformation parameter beta
%   Kappa                       - Unscented transformation parameter kappa
%   EnableSmoothing             - Enable backward smoothing for the filter
%   MaxNumSmoothingSteps        - Maximum number of backward smoothing steps
%                                 allowed for smoothing
%
%   trackingUKF methods: 
%   predict	           - Predict the state and state estimation error covariance
%   correct	           - Correct the state and state estimation error covariance
%   correctjpda        - Correct using joint probabilistic detection assignment
%   smooth             - Smooth the filter estimate using backward recursion
%   distance           - Calculate the distance between measurements and the filter
%   residual           - Calculate the measurement residual and residual noise
%   likelihood         - Calculate the likelihood of a measurement
%   clone              - Create a copy of the object with the same property values
%   initialize         - Initialize filter properties
%   tunableProperties  - Get the filter tunable properties
%   setTunedProperties - Set the tuned properties
%
%   Notes:
%   ------
%   * If the measurement exists, e.g., the object has been detected, you
%     can call the predict method and the correct method together. If the
%     measurement is missing, you can call the predict method but not the
%     correct method.
%   * You can use the distance method to compute distances that describe
%     how a set of measurements matches the Kalman filter. You can thus
%     find a measurement that best fits the filter. This strategy can be
%     used for matching object detections against object tracks in a
%     multi-object tracking problem.
%
%   % Example 1: Create a trackingUKF for a 2D constant velocity model
%   % ----------------------------------------------------------------
%   %   Use the pre-packaged constant velocity motion model, constvel, and  
%   %   the associated measurement model, cvmeas. These models assume that
%   %   the state is [x;vx;y;vy] and a position measurement is [x;y;z].
%   state = [0;0;0;0];
%   UKF = trackingUKF(@constvel, @cvmeas, state);
%
%   % Example 2: Create a trackingUKF with an additional name-value pair
%   % ------------------------------------------------------------------
%   %   Use an additional name-value pair to define the Unscented
%   %   Transformation parameter alpha.
%   state = [0;0;0;0];
%   UKF = trackingUKF(@constvel, @cvmeas, state, 'Alpha', 1e-2);
%
%   % Example 3: Running the filter
%   % -----------------------------
%   %   After constructing a filter, use the following steps to call
%   %   predict and correct. You may call predict and correct in any order
%   %   and as many times you would like to call each.
%   state = [0;0;0;0];
%   UKF = trackingUKF(@constvel, @cvmeas, state);
%   meas = [1;1;0];
%   [x_pred, P_pred] = predict(UKF, 0.5)    % Predict over 0.5 seconds
%   [x_corr, P_corr] = correct(UKF, meas)   % Correct using the measurement   
%   [x_pred, P_pred] = predict(UKF)         % Predict over 1 second
%   [x_pred, P_pred] = predict(UKF, 2)      % Predict over 2 seconds
%
%   % Example 4: Using the distance method
%   % ------------------------------------
%   %   You can measure the distance between the filter and a set of
%   %   measurements, z_matrix, by calling the distance method.
%   state = [0;0;0;0];
%   UKF = trackingUKF(@constvel, @cvmeas, state, 'Alpha', 1e-2);
%   [x_pred, P_pred] = predict(UKF);
%   z_matrix = [0, 0, 0; 1, 1, 0; 2, 2, 0];
%   d = distance(UKF, z_matrix)
%
%  See also: trackingKF, trackingEKF, constvel, cvmeas

%   References:
%   [1] Eric A. Wan and Rudolph van der Merwe, "The Unscented Kalman Filter
%       for Nonlinear Estimation", Adaptive Systems for Signal Processing,
%       Communications, and Control, pages 153-158, AS-SPCC, IEEE, 2000.
%   [2] Wan, Merle "The Unscented Kalman Filter", chapter in Kalman
%       Filtering and Neural Networks, John Wiley & Sons, Inc., 2001
%   [3] Sarkka S., "Recursive Bayesian Inference on Stochastic Differential
%       Equations", Doctoral Dissertation, Helsinki University of
%       Technology, 2006.

%   Copyright 2016-2019 The MathWorks, Inc.

%#codegen
%#ok<*EMCLS>
%#ok<*EMCA>
%#ok<*MCSUP>

classdef trackingUKF < matlabshared.tracking.internal.UnscentedKalmanFilter ...
        & matlabshared.tracking.internal.fusion.CustomDisplay ...
        & matlabshared.tracking.internal.AbstractTrackingFilter ...
        & matlabshared.tracking.internal.AbstractJPDAFilter ...
        & matlabshared.smoothers.internal.UKFSmoother ...
        & matlabshared.tracking.internal.fusion.AbstractTunableFilter
    
    methods
       function UKF = trackingUKF(varargin)
           %trackingUKF  The constructor to create an unscented
           %Kalman filter object.
           [smoothArgs,idx1,idx2] = trackingUKF.parseSmoothingNVPairs(varargin{:});
           filterArgs = {varargin{1:idx1-1},varargin{idx1 + 2:idx2 - 1},varargin{idx2 + 2:end}};
           UKF@matlabshared.tracking.internal.UnscentedKalmanFilter(filterArgs{:});
           UKF@matlabshared.smoothers.internal.UKFSmoother(smoothArgs{:});
           
           % If user didn't specify StateTransitionFcn and MeasurementFcn,
           % use a 2-D constant velocity model as a default.
           if nargin == 0
               UKF.StateTransitionFcn = @constvel;
               UKF.MeasurementFcn = @cvmeas;
               UKF.State = zeros(4,1);
           end
       end
       
       function varargout = predict(filter,varargin)
           %
           
           % The above line is intentionally left empty to divert the help
           % text to superclass.
           
           % Predict must be called with a single object
           coder.internal.assert(numel(filter) == 1, ...
                'shared_tracking:UnscentedKalmanFilter:NonScalarFilter', ...
                'unscented Kalman filter', 'predict');
            
           % Call setup on smoother, the smoother knows when to return
           % safely without doing setup multiple times. 
           setupInitialDistributions(filter);
           
           % Predict using the superclass 
           [varargout{1:nargout}] = predict@matlabshared.tracking.internal.UnscentedKalmanFilter(filter,varargin{:});
           
           % Update the data for the smoother
           filter.LastCrossCov = filter.pCrossCov;
           updatePredictionData(filter);
       end
       
       function varargout = correct(filter,varargin)
           %
           
           % The above line is intentionally left empty to divert the help
           % text to superclass.
           
           % Correct using the superclass
           [varargout{1:nargout}] = correct@matlabshared.tracking.internal.UnscentedKalmanFilter(filter,varargin{:});
           
           % Update the data for the smoother
           updateCorrectionData(filter);
       end
       %-------------------------------------------------------------------
       % Distance method: cannot be inherited from superclass, because the
       % superclass doesn't have this method
       %-------------------------------------------------------------------
       function d = distance(UKF, z_matrix, measurementParams)
           % distance Computes distances between measurements and the
           % unscented Kalman filter object.
           %   d = distance(UKF, z_matrix) computes a distance between one
           %   or more measurements supplied by the z_matrix and the
           %   measurement predicted by the unscented Kalman filter object.
           %   This computation takes into account the covariance of the
           %   predicted state and the measurement noise. Each row of the
           %   input z_matrix must contain a measurement vector of length
           %   N.
           %
           %   d = distance(UKF, z_matrix, measurementParams) allows to
           %   define additional parameters that will be used by the
           %   UKF.MeasurementFcn. It should be specified as a cell array,
           %   e.g., {1, [2;3]}. If unspecified, it will be assumed to be
           %   an empty cell array.
           %
           %   The distance method returns a row vector where each element
           %   is a distance associated with the corresponding measurement
           %   input.
           
           % The procedure for computing the distance is described in Page
           % 93 of "Multiple-Target Tracking with Radar Applications" by
           % Samuel Blackman.
           
           cond = (numel(UKF) > 1);
           coder.internal.errorIf(cond, ...
               'shared_tracking:UnscentedKalmanFilter:NonScalarFilter', ...
               'unscented Kalman filter', 'distance');

           if nargin == 2
               measurementParams = cell(0,0);
           end

           % Validate z_matrix. Skip the size check if it's not known yet
           % (first call to distance)
           if coder.internal.is_defined(UKF.pN)
               matlabshared.tracking.internal.validateMeasurementMatrix(...
                   z_matrix, 'trackingUKF', UKF.pN);
           else
               matlabshared.tracking.internal.validateMeasurementMatrix(...
                   z_matrix, 'trackingUKF');
           end

           % Validate x, P, R
           if isvector(z_matrix)
               zcol = z_matrix(:);
           else
               zcol = z_matrix(1,:).';
           end
           validateMeasurementAndRelatedProperties(UKF, zcol,'distance', measurementParams{:});

            if UKF.HasAdditiveMeasurementNoise
                d = matlabshared.tracking.internal.UKFDistanceAdditive...
                    (UKF, z_matrix, measurementParams);
            else
                d = matlabshared.tracking.internal.UKFDistanceNonAdditive...
                    (UKF, z_matrix, measurementParams);
            end
	   end

	  function [res, S] = residual(UKF, z, measurementParams)
           % RESIDUAL Computes the residual of measurement z and the
           % filter.
           %   [res, S] = RESIDUAL(UKF, z) computes a residual, res, and
           %   the residual matrix, S, where:
           %       res = z-h(UKF.State), h is the measurement function
           %       S = Rp+R, where Rp is the state covariance matrix
           %       projected onto the measurement space using the unscented
           %       transformation.
           %
           %   [...] = RESIDUAL(UKF, z_matrix, measurementParams) allows
           %   passing additional parameters that will be used by the
           %   UKF.MeasurementFcn. It should be specified as a cell array,
           %   e.g., {1, [2;3]}. If unspecified, it will be assumed to be
           %   an empty cell array.
           
           if nargin == 2
               measurementParams = cell(0,0);
           end
           
          [res, S] = residual@matlabshared.tracking.internal.UnscentedKalmanFilter(UKF, z, measurementParams{:});   
               
       end
	   
       function [x_corr, P_corr] = correctjpda(filter, z, jpda, varargin)
       %CORRECTJPDA Correct using joint probabilistic detection assignment
           %   Corrects the state and state error covariance with
           %   a set of measurements and their probabilistic data association 
           %   coefficients.
           %
           %   [x_corr, P_corr] = CORRECTJPDA(filter, z, jpda) returns the
           %   correction of state, x_corr, and state estimation error
           %   covariance, P_corr, based on the current set of measurements
           %   z and their joint probabilistic data association
           %   coefficients jpda.
           %
           %   Inputs:
           %           - filter    filter of the class trackingUKF
           %
           %           - z         measurements matrix of size m-M  where m
           %                       is the dimension of a measurement and M
           %                       is the number of measurements.
           %
           %           - jpda      jpda coefficients. jpda is a M+1 column
           %                       vector. For i=1:M, jpda(i) is the jpda
           %                       coefficient of measurement z(:,i).
           %                       jpda(M+1) is the coefficient associated
           %                       with the data association event that no
           %                       measurement should be associated to the
           %                       track. To comply with the jpda
           %                       algorithm, the sum of all entries in
           %                       jpda must equal 1.
           %   [x_corr, P_corr] = CORRECTJPDA(filter, z, jpda, varargin) 
           %   additionally, allows the definition of parameters used by 
           %   the MeasurementFcn in addition to obj.State. For example, 
           %   the sensor's location.
            

           % number of inputs should be at least 3
           narginchk(3,inf)
           % correctjpda must be called with a single object
           coder.internal.errorIf(numel(filter) > 1, ...
               'shared_tracking:UnscentedKalmanFilter:NonScalarFilter', ...
               'trackingUKF', 'correctjpda');
           
           % validate some basic attributes of the measurement matrix
           validateattributes(z,{'numeric'}, ...
               {'real', 'finite', 'nonsparse','2d'},...
               'trackingUKF', 'z');
           
           % Further validate the dimension of a measurement
           if coder.internal.is_defined(filter.pN)
               matlabshared.tracking.internal.validateInputSizeAndType...
                   ('z(:,1)', 'trackingUKF', z(:,1), filter.pN);
           else
               matlabshared.tracking.internal.validateInputSizeAndType...
                   ('z(:,1)', 'trackingUKF', z(:,1));
           end

           % Measurements z is a m by M matrix, validate a single
           % column of it using the inherited validation function:
           validateMeasurementAndRelatedProperties(filter, z(:,1),'correctjpda', varargin{:});
                  
           % jpda should have length of numMeasurements + 1
           numMeasurements = matlabshared.tracking.internal.fusion.codegen.StrictSingleUtilities.IntIndex(size(z,2));
           ONE = matlabshared.tracking.internal.fusion.codegen.StrictSingleUtilities.IntOne();
           expectedNumel = numMeasurements + ONE;
           matlabshared.tracking.internal.validateInputSizeAndType...
               ('jpda','correctjpda',jpda,expectedNumel);
           
           % jpda coefficients must sum to 1
           coder.internal.errorIf(abs(sum(jpda)-1)>sqrt(eps(filter.pDataType)),...
               'shared_tracking:UnscentedKalmanFilter:InvalidJPDAInput'...
               ,'jpda')
            
            % Perform the UKF correction
            [filter.pState, filter.pStateCovariance] = ...
                filter.pCorrector.correctjpda(...
                z,...
                jpda,...
                filter.pMeasurementNoise, ...
                filter.pState, ...
                filter.pStateCovariance, ...
                filter.Alpha, ...
                filter.Beta, ...
                filter.Kappa, ...
                filter.MeasurementFcn, ...
                varargin{:});
            filter.pHasPrediction = false;
            
            % obj.State outputs the estimated state in the orientation of
            % initial state provided by the user
            if nargout
                x_corr = filter.State;
                if nargout > 1
                    P_corr = filter.StateCovariance;
                end
            end
            
            % Update the data for the smoother
            updateCorrectionData(filter);
        end
       
	   %-------------------------------------------------------------------
	   % initialize method: cannot be inherited from superclass, because
	   % the superclass doesn't have this method
	   %-------------------------------------------------------------------
	   function initialize(UKF, varargin)
		   %INITIALIZE Initialize the state and state covariance of the filter
		   %   INITIALIZE(UKF, state, stateCovariance) initializes the
		   %   extended Kalman filter by setting its State property to
		   %   state and its StateCovariance property to stateCovariance.
		   %
		   %   INITIALIZE(UKF, state, stateCovariance 'Name', value)
		   %   allows you to initialize additional properties of the
		   %   filter using 'Name'-value pairs.
		   %
		   % Note: you must not change the size or type of the properties
		   % you are initializing.
		   
		   % Validation for each property is done on setting
		   UKF.State           = varargin{1}; % Set the state
		   UKF.StateCovariance = varargin{2}; % Set the state covariance
		   
		   if numel(varargin) > 2
			   for i = 3:2:numel(varargin)
				   UKF.(varargin{i}) = varargin{i+1};
			   end
		   end
       end
       
       %-------------------------------------------------------------------
       % likelihood method: calculate the likelihood of a measurement
       %-------------------------------------------------------------------
       function l = likelihood(UKF, z, varargin)
           %LIKELIHOOD Calculate the likelihood of a measurement
           %  l = likelihood(UKF, Z) calculates the likelihood of a
           %  measurement, Z, given the object, KF.
           %
           %  l = likelihood(UKF, Z, measurementParams) allows you to
           %  define additional parameters that will be used by the
           %  UKF.MeasurementFcn. It should be specified as a cell array,
           %  e.g., {1, [2;3]}. If unspecified, it will be assumed to be
           %  an empty cell array.
           
           % Validation is done in the residual method
           [zres, S] = residual(UKF,z,varargin{:});
           l = matlabshared.tracking.internal.KalmanLikelihood(zres,S);
       end
       
       function obj2 = clone(obj)
          obj2 = clone@matlabshared.tracking.internal.UnscentedKalmanFilter(obj); 
          copySmootherProperties(obj, obj2);
       end
    end

    % Methods related to tuning
    methods
        function tunableProps = tunableProperties(obj)
            %tunableProperties Get the filter tunable properties
            % TP = tunableProperties(FILTER) returns the filter tunable
            % properties, TP, as a tunableFilterProperties object.
            Qelements = matlabshared.tracking.internal.fusion.tunableElements("full", size(obj.ProcessNoise,1));
            Pelements = matlabshared.tracking.internal.fusion.tunableElements("full", size(obj.StateCovariance,1));
            q = obj.pSqrtProcessNoise';
            p = obj.pSqrtStateCovariance';
            maxQValue = max(q(Qelements))*10;
            maxPValue = max(p(Pelements))*10;
            strval = getString(message('shared_tracking:TunableFilter:Value'));
            s = struct(...
                Property = {'ProcessNoise','StateCovariance','Alpha','Beta','Kappa'}, ...
                PropertyValue = {obj.pProcessNoise,obj.pStateCovariance,obj.Alpha,obj.Beta,obj.Kappa}, ...
                TunedQuantity = {getString(message('shared_tracking:TunableFilter:SQRT')),getString(message('shared_tracking:TunableFilter:InitialSQRT')),strval,strval,strval}, ...
                IsTuned = {true,false,true,false,false}, ...
                IsSQRT = {true,true,false,false,false}, ...
                TunableElements = {Qelements,Pelements,1,1,1}, ...
                CurrentValue = {q,p,obj.Alpha,obj.Beta,obj.Kappa}, ...
                LowerBound = {zeros(1,numel(Qelements),obj.pDataType),zeros(1,numel(Pelements),obj.pDataType),1e-5,0,0}, ...
                UpperBound = {maxQValue*ones(1,numel(Qelements),obj.pDataType),maxPValue*ones(1,numel(Pelements),obj.pDataType),1,inf,3}, ...
                TunedValue = {q,p,obj.Alpha,obj.Beta,obj.Kappa} ...
                );
            tunableProps = tunableFilterProperties("trackingUKF", s);
        end
        
        function setTunedProperties(obj,s)
            %setTunedProperties Set the tuned properties
            % setTunedProperties(FILTER, S) uses the tuned values specified
            % in the structure, S, to set the corresponding filter
            % properties.
            %
            % The structure S can be the output of the
            % trackingFilterTuner/tune object function, see help for that
            % function. For this filter, the structure contains the
            % following fields: ProcessNoise and InitialStateCovariance,
            % which must be the same size and type as the current
            % properties.
            if isfield(s,'ProcessNoise')
                obj.pProcessNoise = s.ProcessNoise;
            end
            if isfield(s,'StateCovariance')
                obj.pStateCovariance = s.StateCovariance;
            end
            if isfield(s,'Alpha')
                obj.Alpha = s.Alpha;
            end
            if isfield(s,'Beta')
                obj.Beta = s.Beta;
            end
            if isfield(s,'Kappa')
                obj.Kappa = s.Kappa;
            end
        end
    end
    
    methods (Access = ...
            {?matlabshared.tracking.internal.AbstractTrackingFilter, ...
            ?matlabshared.tracking.internal.AbstractContainsFilters, ...
            ?matlab.unittest.TestCase})
       %-------------------------------------------------------------------
	   % nullify method: cannot be inherited from superclass, because the
	   % superclass doesn't have this method
	   %-------------------------------------------------------------------
	   function nullify(UKF)
		   % nullify: sets the State and StateCovariance to zeros
		   UKF.State           = zeros(numel(UKF.State), 1, 'like', UKF.State);
		   UKF.StateCovariance = eye(numel(UKF.State), numel(UKF.State), 'like', UKF.State);
       end
       
       %-------------------------------------------------------------------
       % modelName method: cannot be inherited from the superclass, because
       % the superclass does not have this method
       %-------------------------------------------------------------------
       function name = modelName(UKF)
           % modelName Return the name of the motion model
           %    name = modelName(filter) returns the motion model name,
           %    name.
          coder.internal.assert(coder.internal.is_defined(UKF.StateTransitionFcn),...
               'shared_tracking:UnscentedKalmanFilter:undefinedStateTransitionFcn');
           name =  func2str(UKF.StateTransitionFcn);
       end
       
       %-------------------------------------------------------------------
       % sync method: Sync the filter with the filter provided as second
       % input. 
       %-------------------------------------------------------------------
       function sync(UKF, UKF2)
           % sync: Synchronizes the KF with KF2 to make sure that: 
           % 1. State is same
           % 2. StateCovariance is same.
           % 3. Measurement and Process Noise are same. 
           
           % Validation is performed via set method of each property. 
           UKF.pState = UKF2.State;
           UKF.pStateCovariance = UKF2.StateCovariance;
           UKF.pMeasurementNoise = UKF2.MeasurementNoise;
           UKF.pProcessNoise = UKF2.ProcessNoise;
       end
       
       %-------------------------------------------------------------------
       % models method: Returns the state transition and measurement models
       %-------------------------------------------------------------------
       function [stm, mm] = models(filter,~)
           % MODELS Return the state transition and measurement models
           %   [stm, mm] = MODELS(filter) returns stm, the state transition
           %   model, and mm, the measurement model. Both are returned as
           %   function handles.
           if filter.HasAdditiveProcessNoise
               stm = filter.StateTransitionFcn;
           else
               v = zeros(1,1,'like',filter.State);
               stm = @(state,dt) filter.StateTransitionFcn(state,v,dt);
           end
           
           if filter.HasAdditiveMeasurementNoise
               mm = filter.MeasurementFcn;
           else
               w = zeros(1,1,'like',filter.State);
               mm = @(state,varargin) filter.MeasurementFcn(state,w,varargin{:});
           end
       end

    end
   
   methods (Access = protected)
        % saveobj to make sure the filter is saved correctly. The
        % method is overridden to save smoother properties in addition
        % to filter properties.
        function s = saveobj(obj)
            sEKF = saveobj@matlabshared.tracking.internal.UnscentedKalmanFilter(obj);
            s = saveSmootherProperties(obj, sEKF);
        end
   end
    
   methods (Static = true)
      %--------------------------------------------------------------------
      % loadobj to make sure that the filter is loaded correctly.
      % This method cannot be inherited from the superclass because the
      % correct object type has to be created. 
      function retUKF = loadobj(sobj)
          if isfield(sobj,'HasMeasurementWrapping')
              hasWrap = sobj.HasMeasurementWrapping;
          else
              hasWrap = false;
          end
          retUKF = trackingUKF ...
              ('DataType', sobj.pDataType, ...
               'HasAdditiveProcessNoise', sobj.HasAdditiveProcessNoise, ... % set pPredictor
               'HasAdditiveMeasurementNoise', sobj.HasAdditiveMeasurementNoise, ... % set pCorrector
               'HasMeasurementWrapping', hasWrap); % set measurement wrapping
            % Load the remaining properties
            loadobjHelper(retUKF,sobj); 
            
            % Load smoother properties
            loadSmootherProperties(retUKF,sobj);
	  end
    end
	%------------------------------------------------------------------
	% Overrides for Custom Display
	%------------------------------------------------------------------
	methods (Access=protected)
	   function propGroups = getPropertyGroups(obj)

		   propGroups = [ matlab.mixin.util.PropertyGroup( {'State', 'StateCovariance'}, ...
			   ''); ...
			   matlab.mixin.util.PropertyGroup( {'StateTransitionFcn', 'ProcessNoise', 'HasAdditiveProcessNoise'}, ...
			   ''); ...
			   matlab.mixin.util.PropertyGroup( {'MeasurementFcn', 'HasMeasurementWrapping', 'MeasurementNoise', 'HasAdditiveMeasurementNoise'}, ...
			   ''); ...
			   matlab.mixin.util.PropertyGroup( {'Alpha', 'Beta', 'Kappa'}, ...
			   '')];
           smoothGroups = getPropertyGroups@matlabshared.smoothers.internal.UKFSmoother(obj);
           propGroups = [propGroups;smoothGroups];
	   end
	end
    %------------------------------------------------------------------
    % Overrides for Custom Display when calling get(UKF)
    %------------------------------------------------------------------
    methods (Hidden)
        function getdisp(obj)
            display(obj);
        end
    end
    
    methods (Static, Hidden)
        function props = matlabCodegenNontunableProperties(~)
            propsUKF = matlabshared.tracking.internal.UnscentedKalmanFilter.matlabCodegenNontunableProperties;
            propsSmoother = matlabshared.smoothers.internal.UKFSmoother.matlabCodegenNontunableProperties;
            props = {propsUKF{:} propsSmoother{:}};
        end

        function validateBounds(prop,r)
            switch prop
                case 'Alpha'
                    validatedBounds = r.LowerBound >= 0 && r.UpperBound <= 1;
                case 'Beta'
                    validatedBounds = r.LowerBound >= 0;
                case 'Kappa'
                    validatedBounds = r.LowerBound >= 0 && r.UpperBound <= 3;
                otherwise
                    return
            end
            assert(validatedBounds, ...
                message('fusion:tunableFilterProperties:ViolatesPropLimit', ...
                prop, mfilename));
        end
    end
end
