An state-observer that deals with delay in measurements, also compatible with the standard state-observer

Revision:
0:0699f8e638ca
Child:
1:085d41355949
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/STATES_OBSERVER_DELAY.cpp	Wed Jan 11 09:30:18 2017 +0000
@@ -0,0 +1,432 @@
+#include "STATES_OBSERVER_DELAY.h"
+
+STATES_OBSERVER_DELAY::STATES_OBSERVER_DELAY(size_t num_state, size_t num_in, size_t num_out, size_t delay_sample, float samplingTime):
+        n(num_state), p(num_in), q(num_out), d(delay_sample), Ts(samplingTime),
+        states_est_buffer((delay_sample+1),num_state)
+{
+    // To enble, run *.start() function
+    enable = false;
+    flag_reset = false;
+    //
+    zeros_n.assign(n, 0.0);
+    zeros_p.assign(p, 0.0);
+    zeros_q.assign(q, 0.0);
+    // Parameters for observer
+    Ad.assign(n,zeros_n);
+    Bd.assign(n,zeros_p);
+    if (num_out == 0){
+        enable_Cd = false; // Default: not using Cd
+        q = n;
+        zeros_q.resize(q, 0.0);
+    }else{
+        enable_Cd = true; // using Cd
+        Cd.assign(q,zeros_n);
+    }
+    // Gain matrix
+    Ld.assign(n*(d+1),zeros_q); // Ld is an n(d+1) by q matrix (or n(d+1) by n if Cd is not used)
+
+    // Input-signals of the observer
+    sys_inputs = zeros_p;
+    sys_outputs = zeros_q;
+    sys_extraDisturbance = zeros_n;
+    // Variables of the observer
+    states_est_buffer.Reset(zeros_n);
+    state_est = zeros_n;
+    // states_est_delay_d = zeros_n;
+    y_est = zeros_q;
+    est_error = zeros_q;
+}
+void STATES_OBSERVER_DELAY::start(){
+    enable = true;
+}
+void STATES_OBSERVER_DELAY::stop(){
+    if (!enable){
+        return;
+    }
+    enable = false;
+    flag_reset = true;
+}
+void STATES_OBSERVER_DELAY::reset(){
+    //
+    // Input-signals of the observer
+    sys_inputs = zeros_p;
+    sys_outputs = zeros_q;
+    // Variables of the observer
+    states_est_buffer.Reset(zeros_n);
+    state_est = zeros_n;
+    // states_est_delay_d = zeros_n;
+    y_est = zeros_q;
+    est_error = zeros_q;
+}
+
+
+// Assignments for observer
+// Assign continuous-time version of system matrices
+void STATES_OBSERVER_DELAY::assign_At(float* At_in, size_t n_in){ // Continuous-time version
+    // At_in is the pointer of a mutidimentional array with size n_in by n_in
+    if (n != n_in){
+        n = n_in;
+        zeros_n.resize(n, 0.0);
+        Ad.assign(n, zeros_n);
+    }
+    //
+    for (size_t i = 0; i < n; ++i){
+        for (size_t j = 0; j < n; ++j){
+            // Ad[i][j] = At_in[i][j];
+            Ad[i][j] = (*At_in)*Ts;
+            //
+            if (i == j){
+                Ad[i][j] += 1.0;
+            }
+            //
+            At_in++;
+        }
+    }
+}
+void STATES_OBSERVER_DELAY::assign_Bt(float* Bt_in, size_t n_in, size_t p_in){ // Continuous-time version
+    // Bt_in is the pointer of a mutidimentional array with size n_in by p_in
+    if (n != n_in || p != p_in){
+        n = n_in;
+        p = p_in;
+        zeros_n.resize(n, 0.0);
+        zeros_p.resize(p, 0.0);
+        Bd.assign(n, zeros_p);
+    }
+    //
+    for (size_t i = 0; i < n; ++i){
+        for (size_t j = 0; j < p; ++j){
+            // Bd[i][j] = Bt_in[i][j];
+            Bd[i][j] = (*Bt_in)*Ts;
+            Bt_in++;
+        }
+    }
+}
+// ** Assign the continuous-time version of system matrices by matrices
+void STATES_OBSERVER_DELAY::assign_At(const vector<vector<float> > &At_in){
+    size_t n_in = At_in.size();
+    if (n != n_in){
+        n = n_in;
+        zeros_n.resize(n, 0.0);
+        Ad.assign(n, zeros_n);
+    }
+    // Ad
+    for (size_t i = 0; i < n; ++i){
+        for (size_t j = 0; j < n; ++j){
+            //
+            Ad[i][j] = Ts*At_in[i][j];
+            //
+            if (i == j){
+                Ad[i][j] += 1.0;
+            }
+        }
+    }
+}
+void STATES_OBSERVER_DELAY::assign_Bt(const vector<vector<float> > &Bt_in){
+    size_t n_in = Bt_in.size();
+    size_t p_in = Bt_in[0].size();
+    if (n != n_in || p != p_in){
+        n = n_in;
+        p = p_in;
+        zeros_n.resize(n, 0.0);
+        zeros_p.resize(p, 0.0);
+        Bd.assign(n, zeros_p);
+    }
+    // Bd
+    for (size_t i = 0; i < n; ++i){
+        for (size_t j = 0; j < p; ++j){
+            // Bd[i][j] = Bt_in[i][j];
+            Bd[i][j] = Ts*Bt_in[i][j];
+        }
+    }
+}
+// Assign discrete-time version of system matrices directly
+void STATES_OBSERVER_DELAY::assign_Ad(float* Ad_in, size_t n_in){ // Discrete-time version
+    // Ad_in is the pointer of a mutidimentional array with size n_in by n_in
+    if (n != n_in){
+        n = n_in;
+        zeros_n.resize(n, 0.0);
+        Ad.assign(n, zeros_n);
+    }
+    //
+    for (size_t i = 0; i < n; ++i){
+        for (size_t j = 0; j < n; ++j){
+            // Ad[i][j] = Ad_in[i][j];
+            Ad[i][j] = *Ad_in;
+            Ad_in++;
+        }
+    }
+}
+void STATES_OBSERVER_DELAY::assign_Bd(float* Bd_in, size_t n_in, size_t p_in){ // Discrete-time version
+    // Bd_in is the pointer of a mutidimentional array with size n_in by p_in
+    if (n != n_in || p != p_in){
+        n = n_in;
+        p = p_in;
+        zeros_n.resize(n, 0.0);
+        zeros_p.resize(p, 0.0);
+        Bd.assign(n, zeros_p);
+    }
+    //
+    for (size_t i = 0; i < n; ++i){
+        for (size_t j = 0; j < p; ++j){
+            // Bd[i][j] = Bd_in[i][j];
+            Bd[i][j] = *Bd_in;
+            Bd_in++;
+        }
+    }
+}
+//
+void STATES_OBSERVER_DELAY::assign_Cd(float* Cd_in, size_t q_in, size_t n_in){
+    // Cd_in is the pointer of a mutidimentional array with size q_in by n_in
+    if (n != n_in || q != q_in){
+        n = n_in;
+        q = q_in;
+        zeros_n.resize(n, 0.0);
+        zeros_q.resize(q, 0.0);
+        Cd.assign(q, zeros_n);
+    }
+    //
+    for (size_t i = 0; i < q; ++i){
+        for (size_t j = 0; j < n; ++j){
+            // Cd[i][j] = Cd_in[i][j];
+            Cd[i][j] = *Cd_in;
+            Cd_in++;
+        }
+    }
+    // q = n if not using Cd
+    if (q == 0){
+        enable_Cd = false; // Default: not using Cd
+        q = n;
+        zeros_q.resize(q, 0.0);
+    }else{
+        enable_Cd = true; // using Cd
+        Cd.assign(q,zeros_n);
+    }
+}
+// Assignment for observer Gain
+void STATES_OBSERVER_DELAY::assign_Ld(float* Ld_in, size_t n_in, size_t d_in, size_t q_in){
+    // Ld_in is the pointer of a mutidimentional array with size n_in*(d_in+1) by q_in
+    if (n != n_in || d != d_in || q != q_in){
+        n = n_in;
+        q = q_in;
+        zeros_n.resize(n, 0.0);
+        zeros_q.resize(q, 0.0);
+        //
+        if (d != d_in){
+            d = d_in;
+            states_est_buffer.Init((d+1), zeros_n);
+        }
+        Ld.assign(n*(d+1), zeros_q);
+    }
+    //
+    for (size_t i = 0; i < n*(d+1); ++i){
+        for (size_t j = 0; j < q; ++j){
+            // Ld[i][j] = Ld_in[i][j];
+            Ld[i][j] = *Ld_in;
+            Ld_in++;
+        }
+    }
+}
+
+
+void STATES_OBSERVER_DELAY::iterateOnce(void){
+    if(!enable){
+        if (flag_reset){
+            reset();
+            flag_reset = false;
+        }
+        return;
+    }
+
+    // Inputs of the observer:  sys_inputs, sys_outputs
+    //
+    // Get the delayed estimation of states
+    // states_est_delay_d = states_est_buffer.Get(d); // Get the element that is d samples ago
+    //
+    if (enable_Cd){
+        // y_est = Cd*states_est_delay_d
+        y_est = Mat_multiply_Vec(Cd, states_est_buffer.Get(d));
+        // est_error = y_est - sys_outputs
+        est_error = Get_VectorPlus(y_est,sys_outputs,true); // minus
+    }else{
+        // est_error = y_est - sys_outputs
+        est_error = Get_VectorPlus(states_est_buffer.Get(d), sys_outputs,true); // minus
+    }
+
+    // Get estimation
+    state_est = states_est_buffer.Get(0);
+
+    //-------------------------------Update-----------------------------//
+    static vector<vector<float> >::iterator it_Ld;
+    it_Ld = Ld.begin(); // it_Ld points to L0
+    //
+    static vector<float> states_new;
+    // x_(k+1) = (Ad*x_k + Bd*sys_inputs + sys_extraDisturbance) - L*est_error)
+    states_new = Get_VectorPlus(Mat_multiply_Vec(Ad,state_est), Mat_multiply_Vec(Bd,sys_inputs), false); // plus
+    Get_VectorIncrement(states_new, sys_extraDisturbance, false); // +=, extra disturbances
+    Get_VectorIncrement(states_new, Partial_Mat_multiply_Vec(it_Ld, n, est_error), true); // -=
+    // states_new is equal to x_(k+1) and will be used to .Insert() the buffer
+
+    // Update all the other states
+    // from k to (k-d)+1, totally d samples
+    // Currently it_Ld is pointing to "L1"
+    for (size_t i = 0; i < d; ++i){
+        // it_Ld will be automatically updated during iteration
+        states_est_buffer.Increase(i, Partial_Mat_multiply_Vec(it_Ld, n, est_error), true); // -=
+    }
+
+    // Rotate the buffer
+    states_est_buffer.Insert(states_new);
+}
+
+// Utilities
+void STATES_OBSERVER_DELAY::Mat_multiply_Vec(vector<float> &v_out, const vector<vector<float> > &m_left, const vector<float> &v_right){ // v_out = m_left*v_right
+    static vector<float>::iterator it_out;
+    static vector<const float>::iterator it_m_row;
+    static vector<const float>::iterator it_v;
+    // Size check
+    if (v_out.size() != m_left.size()){
+        v_out.resize(m_left.size());
+    }
+    //
+    it_out = v_out.begin();
+    for (size_t i = 0; i < m_left.size(); ++i){
+        *it_out = 0.0;
+        it_m_row = m_left[i].begin();
+        it_v = v_right.begin();
+        for (size_t j = 0; j < m_left[i].size(); ++j){
+            // *it_out += m_left[i][j] * v_right[j];
+            if (*it_m_row != 0.0 && *it_v != 0.0){
+                (*it_out) += (*it_m_row) * (*it_v);
+            }else{
+                // (*it_out) += 0.0
+            }
+            // (*it_out) += (*it_m_row) * (*it_v);
+            //
+            it_m_row++;
+            it_v++;
+        }
+        it_out++;
+    }
+}
+vector<float> STATES_OBSERVER_DELAY::Mat_multiply_Vec(const vector<vector<float> > &m_left, const vector<float> &v_right){ // v_out = m_left*v_right
+    static vector<float> v_out;
+    // Size check
+    if (v_out.size() != m_left.size()){
+        v_out.resize(m_left.size());
+    }
+    // Iterators
+    static vector<float>::iterator it_out;
+    static vector<const float>::iterator it_m_row;
+    static vector<const float>::iterator it_v;
+    //
+    it_out = v_out.begin();
+    for (size_t i = 0; i < m_left.size(); ++i){
+        *it_out = 0.0;
+        it_m_row = m_left[i].begin();
+        it_v = v_right.begin();
+        for (size_t j = 0; j < m_left[i].size(); ++j){
+            // *it_out += m_left[i][j] * v_right[j];
+            if (*it_m_row != 0.0 && *it_v != 0.0){
+                (*it_out) += (*it_m_row) * (*it_v);
+            }else{
+                // (*it_out) += 0.0
+            }
+            // (*it_out) += (*it_m_row) * (*it_v);
+            //
+            it_m_row++;
+            it_v++;
+        }
+        it_out++;
+    }
+    return v_out;
+}
+vector<float> STATES_OBSERVER_DELAY::Get_VectorPlus(const vector<float> &v_a, const vector<float> &v_b, bool is_minus) // v_a + (or -) v_b
+{
+    static vector<float> v_c;
+    // Size check
+    if (v_c.size() != v_a.size()){
+        v_c.resize(v_a.size());
+    }
+    //
+    for (size_t i = 0; i < v_a.size(); ++i){
+        if (is_minus){
+            v_c[i] = v_a[i] - v_b[i];
+        }else{
+            v_c[i] = v_a[i] + v_b[i];
+        }
+    }
+    return v_c;
+}
+vector<float> STATES_OBSERVER_DELAY::Get_VectorScalarMultiply(const vector<float> &v_a, float scale) // scale*v_a
+{
+    static vector<float> v_c;
+    // Size check
+    if (v_c.size() != v_a.size()){
+        v_c.resize(v_a.size());
+    }
+    // for pure negative
+    if (scale == -1.0){
+        for (size_t i = 0; i < v_a.size(); ++i){
+            v_c[i] = -v_a[i];
+        }
+        return v_c;
+    }
+    // else
+    for (size_t i = 0; i < v_a.size(); ++i){
+        v_c[i] = scale*v_a[i];
+
+    }
+    return v_c;
+}
+// Increment
+void STATES_OBSERVER_DELAY::Get_VectorIncrement(vector<float> &v_a, const vector<float> &v_b, bool is_minus){ // v_a += (or -=) v_b
+    // Size check
+    if (v_a.size() != v_b.size()){
+        v_a.resize(v_b.size());
+    }
+    //
+    if (is_minus){ // -=
+        for (size_t i = 0; i < v_b.size(); ++i){
+            v_a[i] -= v_b[i];
+        }
+    }else{ // +=
+        for (size_t i = 0; i < v_b.size(); ++i){
+            v_a[i] += v_b[i];
+        }
+    }
+
+}
+// Partial matrix multiplication
+vector<float> STATES_OBSERVER_DELAY::Partial_Mat_multiply_Vec(vector<vector<float> >::iterator &it_m_left, size_t numRow_m_left, const vector<float> &v_right){ // v_out = m_left*v_right
+    static vector<float> v_out;
+    // Size check
+    if (v_out.size() != numRow_m_left){
+        v_out.resize(numRow_m_left);
+    }
+    // Iterators
+    static vector<float>::iterator it_out;
+    static vector<float>::iterator it_m_row;
+    static vector<const float>::iterator it_v;
+    //
+    it_out = v_out.begin();
+    for (size_t i = 0; i < numRow_m_left; ++i){
+        *it_out = 0.0;
+        it_m_row = (*it_m_left).begin();
+        it_v = v_right.begin();
+        for (size_t j = 0; j < (*it_m_left).size(); ++j){
+            // *it_out += m_left[i][j] * v_right[j];
+            if (*it_m_row != 0.0 && *it_v != 0.0){
+                (*it_out) += (*it_m_row) * (*it_v);
+            }else{
+                // (*it_out) += 0.0
+            }
+            // (*it_out) += (*it_m_row) * (*it_v);
+            //
+            it_m_row++;
+            it_v++;
+        }
+        it_out++;
+        it_m_left++;
+    }
+    return v_out;
+}