classdef recursiveARMA < recursiveARMAX
    %recursiveARMA  Estimate ARMA models using recursive estimation algorithms
    %
    %   Estimate the coefficients of the ARMA models of the
    %   following form:
    %     A(q) y(t) =  C(q) e(t)
    %   where y(t) is the output measurement. A(q) and C(q) are polynomials
    %   of the time-delay operator 1/q, whose coefficients are estimated.
    %   e(t) is an unknown scalar that represents white noise.
    %
    %   X = recursiveARMA returns the recursiveARMA estimator system
    %   object, X, to estimate 1 parameter in  A(q) and C(q) each. The
    %   initial guess for all parameters are 'eps'.
    %
    %   X = recursiveARMA([na nc]) returns the recursiveARMA estimator
    %   system object, X, to estimate na parameters in A(q) and nc
    %   parameters in C(q). na and nc are non-negative scalars.
    %
    %   X = recursiveARMA([na nc],A0,C0) returns the
    %   recursiveARMA estimator system object, X, with initial guesses
    %   for the polynomial coefficients in A0 and C0. A0 and C0 are row
    %   vectors of length na+1 and nc+1 respectively. The first elements of
    %   A0 and C0 must be 1. C0 must also be a stable discrete-time
    %   polynomial (all roots in the unit disk, i.e.
    %   all(abs(roots(C0))<1)==true).
    %
    %   X = recursiveARMA([na nc],'PropertyName',PropertyValue)
    %   returns a recursiveARMA estimator object, X, with each specified
    %   property set to the specified value.
    %
    %   step method syntax:
    %
    %   [A,C,yHat] = step(X, y) carries out the recursive algorithm over
    %   the measurement y(t). A and C and are the current parameter
    %   estimates for A(q) and  C(q) respectively. yHat is the estimate of
    %   y(t) based on A, C as well as the past values of y.
    %
    %   recursiveARMA methods:
    %
    %   step     - See above description for use of this method
    %   release  - Allow property value and input characteristics changes
    %   clone    - Create another recursiveARMA System object with same property values
    %   isLocked - Locked status (logical)
    %   <a href="matlab:help matlab.System/reset   ">reset</a>    - Reset the internal states to initial conditions
    %
    %   recursiveARMA properties:
    %
    %   InitialA                   - The initial polynomial coefficients of A(q)
    %   InitialC                   - The initial polynomial coefficients of C(q)   
    %   EstimationMethod           - 'ForgettingFactor' (Default),
    %                                'KalmanFilter', 'Gradient' or
    %                                'NormalizedGradient'
    %   ForgettingFactor           - Forgetting factor. Only used by the
    %                                ForgettingFactor algorithm
    %   ProcessNoiseCovariance     - The covariance of the process noise acting
    %                                on the parameter values. Only used by the
    %                                KalmanFilter algorithm    
    %   AdaptationGain             - Adaptation gain. Only used by the
    %                                Gradient and NormalizedGradient
    %                                algorithms
    %   NormalizationBias          - Bias on adaptation gain scaling. Only 
    %                                used by the NormalizedGradient algorithm
    %   InitialParameterCovariance - Initial value for covariance of the
    %                                parameter estimation error
    %   EnableAdaptation           - Can be used to enable/disable the
    %                                parameter (theta) adaptation
    %
    %
    %   EXAMPLE: Estimating a time-invariant ARMA model
    %      % Construct the estimator.
    %      X = recursiveARMA([4 2]); % na=4, nc=2
    %      % Provide initial parameter guesses. Optional, but recommended.
    %      X.InitialA = [1 -1.8 0.8 0.4 0.2];
    %      X.InitialC = [1 -1.7 0.9];
    %      % Provide variances of initial parameter guesses. Optional, but recommended.
    %      X.InitialParameterCovariance = 0.1;
    %      % Load the estimation data.
    %      load iddata9 z9;
    %      % Call the estimator's step command with the output data one piece at a
    %      % time to update parameters. This illustrates online operation of the
    %      % estimator.
    %      for kk=1:numel(z9.y);
    %          [A,C,yHat] = step(X,z9.y(kk));
    %      end
    %      % Take a snapshot of the current model parameters.
    %      sysX = idpoly(X);
    %      % Set the sample time of the model snapshot from the data.
    %      sysX.Ts = z9.Ts;
    %      % Compare 
    %      compare(z9,sysX);
    %
    %
    % See also ar, recursiveAR, recursiveARMAX, recursiveARX, recursiveOE,
    % recursiveBJ, recursiveLS
    
    %   Copyright 2015-2017 The MathWorks, Inc.
    
    %#codegen
    
    methods
        function this = recursiveARMA(varargin)
            this@recursiveARMAX(varargin{:});
        end
    end
    
    methods(Access = protected)
        function setInitialParameters(this,tunablePropNVPairs,firstNVIndex,varargin)
            setInitialPolynomialCoefficients(this,'AC',[2 3],tunablePropNVPairs,firstNVIndex,varargin{:});
        end         
        
        function validateOrdersPreSetImpl(~,val)
            % Orders must be a row vector with 2 non-negative integer
            % elements. Nonnegative and integer checks are done in the
            % superclass
            validateattributes(val,{'numeric'},{'row','numel',2},'','Orders',1);
        end        
        
        function setOrdersImpl(this,val)          
            nInputs = (numel(val)-2)/2;
            this.na = val(1);
            this.nc = val(nInputs+2);
        end        
        
        function [A,C,yHat] = stepImpl(this,y)
            [A,~,C,yHat] = stepImpl@recursiveARMAX(this,y,cast(0,'like',y));
        end
        
        function validateInputsImpl(this,y)
            validateInputsImpl@recursiveARMAX(this,y,cast(0,'like',y));
        end
        
        function s = getDiscreteStateImpl(this)
            % Present estimator states to the user
            s = getDiscreteStateImpl@idRecursivePolynomialModelEstimator(this);
            s.A = this.A;
            s.C = this.C;
        end
        
        function isInactive = isInactivePropertyImpl(this,propName)
            % Hide the unused properties of the superclass
            isInactive = isInactivePropertyImpl@recursiveARMAX(this,propName);
            if isInactive
                return;
            end
            switch propName
                case {'InitialB','B'}
                    isInactive = true();
            end
        end
    end
    
    methods(Static,Access=protected)
        function val = defaultOrders()
            val = [1 1];
        end
        
        function val = latestPossibleNVPairPosition()
            val = 4;
        end        
    end      
end
