/*! \file \brief Controllers for linear Gaussian systems \author Vaclav Smidl. ----------------------------------- BDM++ - C++ library for Bayesian Decision Making under Uncertainty Using IT++ for numerical operations ----------------------------------- */ #include "../base/bdmbase.h" #include "ctrlbase.h" #include "../estim/arx.h" #include "../estim/kalman.h" //#include <../applications/pmsm/simulator_zdenek/ekf_example/pmsm_mod.h> namespace bdm { //! Controller using ARX model for estimation and LQG designer for control class LQG_ARX : public Controller { protected: //! Internal ARX estimator shared_ptr ar; //! Internal LQG designer LQG lq; //! Intermediate StateSpace model shared_ptr Stsp; //! AR predictor shared_ptr > pred; //! datalink from rvc to ar.bayes datalink rvc2ar_y; //! datalink from rvc to ar.bayes datalink_buffered rvc2ar_cond; //! flag to use iterations spread in time (ist) bool ist; //! flag to use windsurfer approach bool windsurfer; public: //! Default constructor LQG_ARX() : ar(), lq() { } //! adaptation is to store arx estimates in stsp void adapt ( const vec &data ) { ar->bayes ( rvc2ar_y.pushdown ( data ), rvc2ar_cond.pushdown ( data ) ); rvc2ar_cond.store_data ( data ); ar->ml_predictor_update ( *pred ); } void redesign() { Stsp->update_from ( *pred ); if ( windsurfer ) { mat Ry = pred->_R(); lq.set_control_Qy ( inv ( Ry ) ); } if ( !ist ) { lq.initial_belmann(); } lq.redesign(); } vec ctrlaction ( const vec &cond ) const { //cond is xt + ut vec state = cond.left ( Stsp->_A().rows() ); if ( Stsp->_have_constant() ) { state ( state.length() - 1 ) = 1; } vec tmp=lq.ctrlaction ( state, cond.right ( Stsp->_B().cols() ) ); if (!std::isfinite(sum(tmp))) { cout << "infinite ctrl action"; } return tmp; } //! //! LQG is defined by quadratic loss function /*! \f[ L(y,u) = (y-y_{req})'Q_y (y-y_{req}) + (u-u_{req})' Q_u (u-u_{req}) \f] expected input \code { class="LQG"; arx = {class="ARX", ...} // internal arx model, see Qy = ("matrix", ...); Qu = ("matrix", ...); yreq = []; // requested output ureq = []; // requested input value } \endcode */ void from_setting ( const Setting &set ) { ar = UI::build ( set, "ARX", UI::compulsory ); mat Qu; mat Qy; UI::get ( Qu, set, "Qu", UI::compulsory ); UI::get ( Qy, set, "Qy", UI::compulsory ); vec y_req; if ( !UI::get ( y_req, set, "yreq", UI::optional ) ) y_req = zeros ( ar->_yrv()._dsize() ); int horizon; UI::get ( horizon, set, "horizon", UI::compulsory ); lq.set_control_parameters ( Qy, Qu, y_req, horizon ); int wind; if ( UI::get ( wind, set, "windsurfer", UI::optional ) ) { windsurfer = wind > 0; } else { windsurfer = false; }; int ist_; if ( UI::get ( ist_, set, "ist", UI::optional ) ) { ist = ist_ > 0; } else { ist = false; }; validate(); } void validate() { // ar is valid pred = ar->ml_predictor(); Stsp = new StateFromARX; RV xrv; RV urvm; //old ut Stsp->connect_mlnorm ( *pred, xrv, urvm ); lq.set_system ( Stsp ); lq.validate(); rv = urvm; // rv is not shifted to t+1!! rvc = concat ( xrv, urvm ); rvc2ar_y.set_connection ( ar->_yrv(), rvc ); rvc2ar_cond.set_connection ( ar->_rvc(), rvc ); //datalink from ARX to rvc } void log_register ( logger &L, const string &prefix ) { ar->log_register ( L, prefix ); } void log_write ( ) const { ar->log_write(); } //! access function const ARX& _ar() {return *ar.get();} //! access function mlnorm* _pred() {return pred.get();} }; UIREGISTER ( LQG_ARX ); } // namespace