// file: $isip/class/algo/KalmanFilter/KalmanFilter.h
// version: $Id: KalmanFilter.h 10602 2006-08-17 17:43:12Z ss754 $
//

// make sure definitions are only made once
//
#ifndef ISIP_KALMANFILTER
#define ISIP_KALMANFILTER

// isip include files
//
#ifndef ISIP_ALGORITHM_BASE
#include <AlgorithmBase.h>
#endif

// KalmanFilter: a class that computes the states (features) of a
// signal using a kalman filter.
//
// kalman filters are used to model signals using sequential prediction
// techniques. a kalman filter is represented by two state space equations:
//
//  state equation :       x(k) = A x(k-1) + u(k-1)
//  observation equation:  y(k) = H x(k)   + v(k)
//  using basic matrix computation.
//
// where:
//  k -> time instant
//  x -> hidden (to find) state vector
//  y -> observation (measurement) vector
//  u -> process noise - Gaussian N(0, Q)
//  v -> observation noise - Gaussian N(0, R)
//  A -> state transition model (matrix)
//  H -> observation model (matrix)
//  P -> estimate error covariance (mentioned below)
//
// the following parameters are given or known:
//
//  A, H, u(k), v(k), x(0), P(0), y(k)
// 
// kalman filtering consists of two steps:
//
// stage 1:  prediction stage.
//
//  stage 1a: predict the state based on the previous state.
//            x^(k) = A x(k-1)
//
//  stage 1b: predict the initial estimate error
//            P^(k) = A P(k-1) A'
//
// stage 2:  Correction stage (accept the observation)
//
//  stage 2a: find Kalman gain
//            K(k) = P^(k) H' [H P^(k) H' + R]inverse
//
//  stage 2b: correct the state
//            x(k) = x^(k) + K(k) [ y(k) - H x^(k) ]
//
//  stage 2c: correct the estimate error
//            P(k) = [ I - K(k) H] P^(k)
//
// where,
//        ^ denotes predicted values,
//        ' denotes transpose,
//        I denotes identity matrix of appropriate dimension
//
// the hidden states are estimated using the observables.
// the next state is predicted based on the previous state and transition
// model. a degree of uncentainty associated with the estimation is
// accounted for by process noise. based on the above predicted state,
// the observation is predicted. the difference between the predicted
// observation and the actual observation is the error. a gain
// term corrects the predicted state by a term proportional to the error.
//
// the implementations in this class follow:
//
//  G. Welch and G. Bishop, "An Introduction to the Kalman filter,"
//  Technical report TR 95-041,Department of Computer Science, University of
//  North Carolina at Chapel Hill, Chapel Hill, NC, USA, April 2004.
//
// the unscented Kalman filter follows:
//
//  E. Wan and R. Merwe, "The Unscented Kalman Filter for Nonlinear
//  Estimation," Adaptive systems for Signal Processing,
//  Communications, and Control Symposium 2000, AS-SPCC, pp 153-158.
//  
// for the unscented Kalman filter (UKF), the given starting values are
// converted into sigma points and a similar procedure to the
// kalman filter is used. UKF are generally used with nonlinear
// Gaussian state space models
//
// the weights associated with sigma points are defined as:
//
// the zeroth element of weights_m_d is defined as
//
//                              lambda_d
//  weights_m_d(0) = ------------------------------------
//                   (augumented_state_length + lambda_d)
//
// for all other indices,              
//                               lambda_d
//  weights_m_d(i) = ---------------------------------------- 
//                   2 * (augumented_state_length + lambda_d)
// 
// the zeroth element of weights_c_d is defined as
//
//                             lambda_d
//  weights_c_d(0) = ----------------------------- + (1 - alpha^2 + beta)
//                   (aug_state_length + lambda_d)
//
// for all other indices,              
//                                 lambda_d
//   weights_c_d(i) = --------------------------------------- 
//                    2 * (augumented_state_length + lambda_d)
//
//
//   weights_m_d --> weights used to calculate the mean value
//   weights_c_d --> weights used to calculate the covariance
//
// with alpha, beta, kappa, lambda being constants as defined in the
// unscented kalman filtering literature as referred above
//
// currently, one one implementation mode is supported ->  AR_SCALAR.
// both algorithms are supported -> CONVENTIONAL and UNSCENTED.
//      
class KalmanFilter : public AlgorithmBase {
  
  //---------------------------------------------------------------------------
  //
  // public constants
  //
  //---------------------------------------------------------------------------
public:
  
  // define the class name
  //
  static const String CLASS_NAME;

  //----------------------------------------
  //
  // other important constants
  //
  //----------------------------------------

  // define the algorithm choices
  //
  enum ALGORITHM { CONVENTIONAL = 0, UNSCENTED, DEF_ALGORITHM = CONVENTIONAL };

  // define the implementation choices
  //
  enum IMPLEMENTATION { AR_SCALAR = 0, AR_VECTOR,
			DEF_IMPLEMENTATION = AR_SCALAR };
  
  // define the static NameMap objects
  //
  static const NameMap ALGO_MAP;
  static const NameMap IMPL_MAP;

  //----------------------------------------
  //
  // i/o related constants
  //
  //----------------------------------------  

  static const String DEF_PARAM;
  static const String PARAM_ALGORITHM;  
  static const String PARAM_IMPLEMENTATION;
  static const String PARAM_CMODE;

  // specific to algorithms: CONVENTIONAL, UNSCENTED
  //
  static const String PARAM_ORDER;
  static const String PARAM_NOISE_PRC;
  static const String PARAM_NOISE_OBS;
  static const String PARAM_NOISE_ERR;

  static const String PARAM_STATE_MEM;
  static const String PARAM_TRN;
  static const String PARAM_OBS;
  
  // specific to algorithm: UNSCENTED
  //
  static const String PARAM_ALPHA;
  static const String PARAM_BETA;
  static const String PARAM_KAPPA;
  
  //----------------------------------------
  //
  // default values and arguments
  //
  //----------------------------------------  

  // define the default value(s) of the class data
  // std default values -
  // DEF_NOISE_PRC = 0.03, DEF_NOISE_OBS = 0.0238,
  // DEF_NOISE_ERR = 0.0001
  //
  static const long DEF_ORDER = -1;
  static const double DEF_NOISE_PRC = -1.0;
  static const double DEF_NOISE_OBS = -1.0;
  static const double DEF_NOISE_ERR = -1.0;
  static const VectorDouble DEF_STATE_MEM;
  static const VectorDouble DEF_OBS;
  static const MatrixDouble DEF_TRN;
  
  // specific to algorithm: UNSCENTED
  // std default values -
  // DEF_ALPHA = 0.001, DEF_BETA = 2.0, DEF_KAPPA = 0.0
  //
  static const double DEF_ALPHA = -1.0;
  static const double DEF_BETA  = -1.0;
  static const double DEF_KAPPA = -1.0;
  
  // define default argument(s)
  //
  static const AlgorithmData::COEF_TYPE DEF_COEF_TYPE =
  AlgorithmData::SIGNAL;   
  
  //----------------------------------------
  //
  // error codes
  //
  //----------------------------------------

  // ERR -> KalmanFilter class general error
  // ERR_MISDIM -> dimension mismatch with data members
  // ERR_UNIPAR -> parameter data members not initialized properly
  //
  // use ERR_UNKALG -> unknown algorithm
  // use ERR_UNKIMP -> unknown implementation
  // use ERR_UNSUPA -> unsupported algorithm
  // use ERR_UNSUPI -> unsupported implementation
  // use ERR_ORDER -> incorrect analysis order
  //
  static const long ERR = 73300;
  static const long ERR_MISDIM = 73301;
  static const long ERR_UNIPAR = 73302;

  
  //---------------------------------------------------------------------------
  //
  // protected data
  //
  //---------------------------------------------------------------------------
protected:

  // algorithm name
  //
  ALGORITHM algorithm_d;

  // implementation name
  //
  IMPLEMENTATION implementation_d;

  // static memory manager
  //
  static MemoryManager mgr_d;

  // algorithm: CONVENTIONAL AND UNSCENTED
  // implementation: AR_SCALAR
  // 
  // define a regression order:
  //  this is similar to a linear prediction order and specifies
  //  the number of past elements on which the current state depends
  //
  Long order_d;

  // define models for the state and observation sequence calculations
  //
  //  state_d   = trn_d * state_d    + u
  //  obs_est_d = obs_d * state_d(k) + v
  //
  MatrixDouble trn_d;      // relates the current state to the previous state
  VectorDouble obs_d;      // relates the current obsn to the current state

  // define a buffer to hold the history of the filter
  //
  VectorDouble state_mem_d;

  // define parameters for noise modeling:
  //
  MatrixDouble covar_nse_pro_d;   // associated with the state prediction
  Double covar_nse_obs_d;         // associated with the observations
  MatrixDouble covar_err_est_d;   // associated with the error signal

  // define a buffer for filtered data
  //
  VectorDouble data_filt_d;

  // algorithm: UNSCENTED
  // implementation: AR_SCALAR
  //
  // define parameters to fine tune the filter
  // 
  Double alpha_d;         // heuristic parameter for weights_c_d
  Double beta_d;          // heuristic parameter for weights_c_d
  Double kappa_d;         // heuristic parameter for weights_c_d
  double lambda_d;        // computed weighting factor 

  //---------------------------------------------------------------------------
  //
  // required public methods
  //
  //---------------------------------------------------------------------------
public:
 
  // method: name
  //
  static const String& name() {
    return CLASS_NAME;
  }

  // other static methods
  //
  static boolean diagnose(Integral::DEBUG debug_level);
  
  // debug methods:
  // setDebug is inherited from the AlgorithmBase class
  //
  boolean debug(const unichar* msg) const;

  // method: destructor
  //
  ~KalmanFilter() {}

  // method: default constructor
  //
  KalmanFilter(ALGORITHM algorithm = DEF_ALGORITHM,
	       IMPLEMENTATION implementation = DEF_IMPLEMENTATION) {
    algorithm_d = algorithm;
    implementation_d = implementation;
    is_valid_d = false;
  }
  
  // method: copy constructor
  //
  KalmanFilter(const KalmanFilter& arg) {
    assign(arg);
  }

  // method: assign
  //
  boolean assign(const KalmanFilter& arg);
  
  // method: operator=
  //
  KalmanFilter& operator= (const KalmanFilter& arg) {
    assign(arg);
    return *this;
  }
  
  // i/o methods
  //
  long sofSize() const;
  
  boolean read(Sof& sof, long tag, const String& name = CLASS_NAME);
  boolean write(Sof& sof, long tag, const String& name = CLASS_NAME) const;
  
  boolean readData(Sof& sof, const String& pname = DEF_PARAM,
                   long size = SofParser::FULL_OBJECT,
                   boolean param = true,
		   boolean nested = false);
  boolean writeData(Sof& sof, const String& pname = DEF_PARAM) const;
  
  // method: eq
  //
  boolean eq(const KalmanFilter& arg) const;
    
  // method: new
  //
  static void* operator new(size_t size) {
    return mgr_d.get();
  }
  
  // method: new[]
  //
  static void* operator new[](size_t size) {
    return mgr_d.getBlock(size);
  }

  // method: delete
  //
  static void operator delete(void* ptr) {
    mgr_d.release(ptr);
  }
  
  // method: delete[]
  //
  static void operator delete[](void* ptr) {
    mgr_d.releaseBlock(ptr);
  }
  
  // method: setGrowSize
  //
  static boolean setGrowSize(long grow_size) {
    return mgr_d.setGrow(grow_size);
  }
  
  // other memory management methods
  //
  boolean clear(Integral::CMODE ctype = Integral::DEF_CMODE);
  
  //---------------------------------------------------------------------------
  //
  // class-specific public methods:
  //  set methods  
  //
  //---------------------------------------------------------------------------

  // method: setAlgorithm
  //
  boolean setAlgorithm(ALGORITHM algorithm) {
    algorithm_d = algorithm;
    is_valid_d = false;
    return true;  
  }

  // method: setImplementation
  //
  boolean setImplementation(IMPLEMENTATION implementation) {
    implementation_d = implementation;
    is_valid_d = false;
    return true;  
  }

  // method: setOrder
  //
  boolean setOrder(long order = DEF_ORDER);

  // right now, we are having the AR_SCALAR implementation which
  // insists on user giving order
  //
  // method: setProcessNoise
  //
  boolean setProcessNoise(double covar_nse_pro) {
    if ((int)order_d < 1) {
      Error::handle(name(), L"setProcessNoise", ERR_ORDER,
		    __FILE__, __LINE__);
    }
    else {
      if(algorithm_d == CONVENTIONAL) {
	covar_nse_pro_d.setDimensions((int)order_d, (int)order_d);
	covar_nse_pro_d.setDiagonal((double)covar_nse_pro);
      }
      if (algorithm_d == UNSCENTED) {
	covar_nse_pro_d.setDimensions(0, 0);
	covar_nse_pro_d.setValue(0, 0, (double)covar_nse_pro);
      }
      is_valid_d = false;
    }
    return true;
  }
  
  // method: setObsnNoise
  //
  boolean setObsnNoise(double covar_nse_obs) {
    covar_nse_obs_d = covar_nse_obs;
    is_valid_d = false;
    return true;
  }
  
  // right now, we are having the AR_SCALAR implementation which
  // insists on user giving order
  //
  // method: setEstimateError
  //
  boolean setEstimateError(double covar_err_est) {
    if ((int)order_d < 1) {
      Error::handle(name(), L"setEstimateError", ERR_ORDER,
		    __FILE__, __LINE__);
    }
    else {
      if (algorithm_d == CONVENTIONAL) {
	covar_err_est_d.setDimensions((int)order_d, (int)order_d);
	covar_err_est_d.setDiagonal(covar_err_est);
      }
      if(algorithm_d == UNSCENTED) {
	covar_err_est_d.setDimensions((int)order_d, (int)order_d);
	covar_err_est_d.setDiagonal(covar_err_est);
      }
      is_valid_d = false;
    }
    return true;
  }

  // method: setNoise
  // user must use this set method after setOrder method
  //
  boolean setNoise(double covar_nse_pro, double covar_nse_obs,
		   double covar_err_est) {
    if ((int)order_d < 1) {
      Error::handle(name(), L"setNoise", ERR_ORDER,
		    __FILE__, __LINE__);
    }
    else {
      if (algorithm_d == CONVENTIONAL) {
	covar_nse_pro_d.setDimensions((int)order_d, (int)order_d);
	covar_err_est_d.setDimensions((int)order_d, (int)order_d);
	covar_nse_pro_d.setDiagonal((double)covar_nse_pro);
	covar_nse_obs_d = covar_nse_obs;
	covar_err_est_d.setDiagonal(covar_err_est);
      }
      if (algorithm_d == UNSCENTED) {
	covar_nse_pro_d.setDimensions(0, 0);
	covar_err_est_d.setDimensions((int)order_d + 2, (int)order_d + 2);
	covar_nse_pro_d.setValue(0, 0, (double)covar_nse_pro);
	covar_nse_obs_d = covar_nse_obs;
	covar_err_est_d.setDiagonal(covar_err_est);
      }
      is_valid_d = false;
    }
    return true;
  }
  
  // method: setInitialState
  //
  boolean setInitialState(VectorDouble state_mem = DEF_STATE_MEM) {
    state_mem.assign(state_mem);
    is_valid_d = false;
    return true;
  }
  
  // method: setTransitionModel
  //
  boolean setTransitionModel(MatrixDouble trn = DEF_TRN) {
    trn_d.assign(trn);
    is_valid_d = false;
    return true;
  }
  
  // method: setObsnModel
  //
  boolean setObsnModel(VectorDouble obs = DEF_OBS) {
    obs_d.assign(obs);
    is_valid_d = false;
    return true;
  }
  
  // method: setModel
  //
  boolean setModel(MatrixDouble trn = DEF_TRN, VectorDouble obs = DEF_OBS) {
    trn_d.assign(trn);
    obs_d.assign(obs);
    is_valid_d = false;
    return true;
  }
  
  // method: setAlpha
  // set methods specific to unscented kalman filter
  // 
  boolean setAlpha(double alpha = DEF_ALPHA) {
    alpha_d = alpha;
    is_valid_d = false;
    return true;
  }
  
  // method: setBeta
  //
  boolean setBeta(double beta = DEF_BETA) {
    beta_d = beta;
    is_valid_d = false;
    return true;
  }

  // method: setKappa
  //
  boolean setKappa(double kappa = DEF_KAPPA) {
    kappa_d = kappa;
    is_valid_d = false;
    return true;
  }

  // method: setParameters
  //
  boolean setParameters(double alpha = DEF_ALPHA, double beta = DEF_BETA,
			double kappa = DEF_KAPPA) {
    alpha_d = alpha;
    beta_d = beta;
    kappa_d = kappa;
    is_valid_d = false;
    return true;
  }

  // method: setKF
  //
  // this method sets values for a conventional kalman filter
  // AR modeled time-series defined by ar order
  //
  boolean setKF(long order, double covar_nse_pro, double covar_nse_obs,
		double covar_err_est, VectorDouble state_mem = DEF_STATE_MEM) {
    if ((int)order_d < 1) {
      Error::handle(name(), L"setKF", ERR_ORDER,
		    __FILE__, __LINE__);
    }
    else {
      order_d = order;
      covar_nse_pro_d.setDimensions((int)order_d, (int)order_d);
      covar_err_est_d.setDimensions((int)order_d, (int)order_d);
      covar_nse_pro_d.setDiagonal((double) covar_nse_pro);
      covar_nse_obs_d = (double) covar_nse_obs;
      covar_err_est_d.setDiagonal((double) covar_err_est);
    }
    return true;
  }

  // method: setKF
  //
  // set method specific to conventional kalman filter 
  // not specific to ar model
  // for a scalar time series data
  // 
  boolean setKF(MatrixDouble& covar_nse_pro,
		double covar_nse_obs, MatrixDouble& covar_err_est,
		VectorDouble state_mem = DEF_STATE_MEM,
		MatrixDouble trn = DEF_TRN, VectorDouble obs = DEF_OBS) {
    covar_nse_pro_d.assign(covar_nse_pro);
    covar_nse_pro_d = covar_nse_obs;
    covar_err_est_d.assign(covar_err_est);
    state_mem_d.assign(state_mem);
    trn_d.assign(trn);
    obs_d.assign(obs);
    return true;
  }

  // method: setUKF
  //
  // this method sets values for an UNSCENTED Kalman filter
  //
  boolean setUKF(long order, double covar_nse_pro,
		 double covar_nse_obs, double covar_err_est,
		 VectorDouble state_mem = DEF_STATE_MEM,
		 double alpha = DEF_ALPHA, double beta = DEF_BETA,
		 double kappa = DEF_KAPPA) {
    if ((int)order_d < 1) {
      Error::handle(name(), L"setUKF", ERR_ORDER,
		    __FILE__, __LINE__);
    }
    else {
      order_d = order;
      covar_nse_pro_d.setDimensions(0, 0);
      covar_err_est_d.setDimensions((int)order_d + 2, (int)order_d + 2);
      covar_nse_pro_d.setValue(0, 0, (double) covar_nse_pro);
      covar_nse_obs_d = (double) covar_nse_obs;
      covar_err_est_d.setDiagonal((double) covar_err_est);
      alpha_d = alpha;
      beta_d = beta;
      kappa_d = kappa;
      is_valid_d = false;
    }
      return true;
  }
  
  // method: setUKF
  //
  // this method sets values for a USNCENTED Kalman filter
  // to have a implementation which may not be AR specific
  // for a scalar time series data
  // 
  boolean setUKF(MatrixDouble& covar_nse_pro,
		 double covar_nse_obs, MatrixDouble& covar_err_est,
		 VectorDouble state_mem = DEF_STATE_MEM,
		 MatrixDouble trn = DEF_TRN, VectorDouble obs = DEF_OBS,
		 double alpha = DEF_ALPHA, double beta = DEF_BETA,
		 double kappa = DEF_KAPPA) {
    covar_nse_pro_d.assign(covar_nse_pro);
    covar_nse_pro_d = covar_nse_obs;
    covar_err_est_d.assign(covar_err_est);
    state_mem_d.assign(state_mem);
    trn_d.assign(trn);
    obs_d.assign(obs);
    alpha_d = alpha;
    beta_d = beta;
    kappa_d = kappa;
    is_valid_d = false;
    return true;
  }

  // method: set
  //
  boolean set(ALGORITHM algorithm = DEF_ALGORITHM,
	      IMPLEMENTATION implementation = DEF_IMPLEMENTATION,
	      long order = DEF_ORDER) {
    algorithm_d = algorithm;
    implementation_d = implementation;
    order_d = order;
    is_valid_d = false;
    return true;
  }

  //---------------------------------------------------------------------------
  //
  // class-specific public methods:
  //  get methods  
  //
  //---------------------------------------------------------------------------
  
  // method: getAlgorithm
  //
  ALGORITHM getAlgorithm() const {
    return algorithm_d;
  }

  // method: getImplementation
  //
  IMPLEMENTATION getImplementation() const {
    return implementation_d;
  }
  
  // method: getOrder
  //
  long getOrder() const {
    return order_d;
  }

  // method: getInitialState
  //
  boolean getInitialState(VectorDouble& state_mem) const {
    return state_mem.assign(state_mem_d);
  }
  
  // method: getTransitionModel
  // transition model relates the current state with the previous state
  //
  boolean getTransitionModel(MatrixDouble& trn) const {
    return trn.assign(trn_d);
  }

  // method: getObsnModel
  //
  boolean getObservationModel(VectorDouble& obs) const {
    return obs.assign(obs_d);
  }

  // method: getModel
  //
  boolean getModel(MatrixDouble& trn, VectorDouble& obs) const {
    trn.assign(trn_d);
    return obs.assign(obs_d);
  }
  
  // method: getProcessNoise
  //
  boolean getProcessNoise(MatrixDouble& covar_nse_pro) const {
    return covar_nse_pro.assign(covar_nse_pro_d);
  }
  
  // method: getObsnNoise
  //
  boolean getObservationNoise(double covar_nse_obs) const {
    covar_nse_obs = covar_nse_obs_d;
    return true;
  }

  // method: getEstimateError
  //
  boolean getEstimateError(MatrixDouble& covar_err_est) const {
    return covar_err_est.assign(covar_err_est_d);
  }

  // method: getNoise
  //
  boolean getNoise(MatrixDouble& covar_nse_pro, double covar_nse_obs,
		   MatrixDouble& covar_err_est) const {
    covar_nse_pro.assign(covar_nse_pro_d);
    covar_nse_obs = covar_nse_obs_d;
    return covar_err_est.assign(covar_err_est_d);
  }

  // get methods related to unscented kalman filter
  //
  // method: getAlpha
  //
  boolean getAlpha(double alpha) const {
    alpha = alpha_d;
    return true;
  }

  // method: getBeta
  //
  boolean getBeta(double beta) const {
    beta = beta_d;
    return true;
  }

  // method: getKappa
  //
  boolean getKappa(double kappa) const {
    kappa = kappa_d;
    return true;
  }

  // method: getParameters
  //
  boolean getParameters(double alpha, double beta, double kappa) const {
    alpha = alpha_d;
    beta = beta_d;
    kappa = kappa_d;
    return true;
  }

  // get method related to both conventional and unscented kalman filter
  //
  // method: getResult
  // to get the filtered data from a particular frame
  //
  boolean getResult(VectorDouble& data_filt) const {
    return data_filt.assign(data_filt_d);
  }

  // method: get
  //
  boolean get(ALGORITHM& algorithm,
	      IMPLEMENTATION& implementation,
	      long& order) const {
    algorithm = algorithm_d;
    implementation = implementation_d;
    order = order_d;
    return true;
  }

  //---------------------------------------------------------------------------
  //
  // class-specific public methods:
  //  computational methods
  //
  //---------------------------------------------------------------------------

  // compute methods
  //
  boolean compute(VectorDouble& output, const VectorDouble& input,
		  AlgorithmData::COEF_TYPE input_coef_type = DEF_COEF_TYPE,
		  long index = DEF_CHANNEL_INDEX);
  boolean compute(VectorComplexDouble& output,
		  const VectorComplexDouble& input,
		  AlgorithmData::COEF_TYPE input_coef_type = DEF_COEF_TYPE,
		  long index = DEF_CHANNEL_INDEX);
  
  //---------------------------------------------------------------------------
  //
  // class-specific public methods:
  //  public methods required by the AlgorithmBase interface contract
  //
  //---------------------------------------------------------------------------

  // assign method
  //
  boolean assign(const AlgorithmBase& arg);

  // equality method
  //
  boolean eq(const AlgorithmBase& arg) const;

  // method: className
  //
  const String& className() const {
    return CLASS_NAME;
  }

  // initialization method
  //
  boolean init();
  
  // apply method
  //
  boolean apply(Vector<AlgorithmData>& output,
		const Vector< CircularBuffer<AlgorithmData> >& input);
  
  // method to set the parser
  //
  boolean setParser(SofParser* parser);

  //---------------------------------------------------------------------------
  //
  // private methods
  //
  //---------------------------------------------------------------------------
private:

  // common i/o methods
  //
  boolean readDataKalmanFilter(Sof& sof, const String& pname,
			       long size, boolean param, boolean nested);
  boolean writeDataKalmanFilter(Sof& sof, const String& pname) const;

  // algorithm-specific compute methods:
  // algorithm: CONVENTIONAL and UNSCENTED
  // implementation: AR_SCALAR 
  //
  // to compute the states, actually current state is calculated and
  // passed to the data_filt_d which keeps on storing the data
  // from the complete frame
  //
  boolean computeStates(const VectorDouble& obsn, VectorDouble& filtered_data);

  // to initialize the transition model matrix with the LP
  // coefficients
  boolean initTransitionModel(const VectorDouble& obsn);

  // to find the square root of the matrix
  //
  boolean matrixSqrt(MatrixDouble& mat_in, MatrixDouble& mat_sqrt);

};
// end of include file
// 
#endif
