Dependencies:   FastPWM

Dependents:   RT2_Cuboid

PID_Cntrl.cpp

Committer:
pmic
Date:
2022-05-05
Revision:
10:eb29810d831b
Parent:
8:3a2131231969

File content as of revision 10:eb29810d831b:

#include "PID_Cntrl.h"

/*
                    Ts
    C(z) = (P + I ---------- + D * tustin(s / (tau_f * s + 1))) * tustin(1 / (tau_ro * s + 1))
                 1 - z^-1
    - Corresponds to MATLAB command: C = pid(P, I, D, tau_f, Ts, 'IFormula', 'BackwardEuler', 'DFormula', 'Trapezoidal') * c2d(tf(1, [tau_ro 1]), Ts, 'tustin')
    - Anti-Windup: Saturation of Ipart and u = P*e + IPart + DPart
*/

PID_Cntrl::PID_Cntrl(float I, float Ts, float uMin, float uMax)
{
    setup(I, Ts, uMin, uMax);
}

PID_Cntrl::PID_Cntrl(float P, float I, float Ts, float uMin, float uMax)
{
    setup(P, I, Ts, uMin, uMax);
}

PID_Cntrl::PID_Cntrl(float P, float I, float D, float Ts, float uMin, float uMax)
{
    setup(P, I, D, Ts, uMin, uMax);
}

PID_Cntrl::PID_Cntrl(float P, float I, float D, float tau_f, float Ts, float uMin, float uMax)
{
    setup(P, I, D, tau_f, Ts, uMin, uMax);
}

PID_Cntrl::PID_Cntrl(float P, float I, float D, float tau_f, float tau_ro, float Ts, float uMin, float uMax)
{
    setup(P, I, D, tau_f, tau_ro, Ts, uMin, uMax);
}

PID_Cntrl::~PID_Cntrl() {}

void PID_Cntrl::reset()
{
    reset(0.0f);
}

void PID_Cntrl::reset(float initValue)
{
    IPart = initValue;
    Dpart = 0.0f;
    d_old = 0.0f;
    u_old = initValue;
    uf = initValue;
}

void PID_Cntrl::setup(float I, float Ts, float uMin, float uMax)
{
    P = 0.0f;
    D = 0.0f;
    double Ts_d = static_cast<double>( Ts );
    tau_f  = static_cast<float>( Ts_d/(0.95*pi) ); // unused
    tau_ro = 0.0f;
    setup(P, I, D, tau_f, tau_ro, Ts, uMin, uMax);
}

void PID_Cntrl::setup(float P, float I, float Ts, float uMin, float uMax)
{
    D = 0.0f;
    double Ts_d = static_cast<double>( Ts );
    tau_f  = static_cast<float>( Ts_d/(0.95*pi) ); // unused
    tau_ro = 0.0f;
    setup(P, I, D, tau_f, tau_ro, Ts, uMin, uMax);
}

void PID_Cntrl::setup(float P, float I, float D, float Ts, float uMin, float uMax)
{
    double Ts_d = static_cast<double>( Ts );
    tau_f  = static_cast<float>( Ts_d/(0.95*pi) ); // 1.0/(0.95*2.0*pi*fnyq)
    tau_ro = 0.0f;
    setup(P, I, D, tau_f, tau_ro, Ts, uMin, uMax);
}

void PID_Cntrl::setup(float P, float I, float D, float tau_f, float Ts, float uMin, float uMax)
{
    tau_ro = 0.0f;
    setup(P, I, D, tau_f, tau_ro, Ts, uMin, uMax);
}

void PID_Cntrl::setup(float P, float I, float D, float tau_f, float tau_ro, float Ts, float uMin, float uMax)
{
    setCoefficients(P, I, D, tau_f, tau_ro, Ts);
    this->uMin = uMin;
    this->uMax = uMax;
    reset();
}

void PID_Cntrl::setCoeff_P(float P)
{
    this->P = P;
}

void PID_Cntrl::setCoeff_I(float I)
{
    this->I = I;
    updateCoeff_I(I, Ts);
}

void PID_Cntrl::setCoeff_D(float D)
{
    this->D = D;
    updateCoeff_D(D, Ts, tau_f);
}

void PID_Cntrl::scale_PIDT2_param(float scale)
{
    P = P_init * scale;
    I = I_init * scale;
    D = D_init * scale;
    updateCoeff_I(I, Ts);
    updateCoeff_D(D, Ts, tau_f);
}

float PID_Cntrl::update(float e)
{
    if(bi !=0) {
        IPart = saturate(IPart + bi*e, uMin, uMax);
    } else {
        IPart = 0.0f;
    }
    Dpart = bd*(e - d_old) - ad*Dpart;
    d_old = e;
    float u = P*e + IPart + Dpart;
    uf = saturate(bf*(u + u_old) - af*uf, uMin, uMax);
    u_old = u;
    return uf;
}

float PID_Cntrl::update(float e, float y)
{
    if(bi !=0) {
        IPart = saturate(IPart + bi*e, uMin, uMax);
    } else {
        IPart = 0.0f;
    }
    Dpart = bd*(y - d_old) - ad*Dpart;
    d_old = y;
    float u = P*e + IPart - Dpart;
    uf = saturate(bf*(u + u_old) - af*uf, uMin, uMax);
    u_old = u;
    return uf;
}

bool PID_Cntrl::update_param(int cntrlr_param, float value)
{
    switch (cntrlr_param) {
        case 0:
            setCoeff_P(value);
            return true;
            break;
        case 1:
            setCoeff_I(value);
            return true;
            break;
        case 2:
            setCoeff_D(value);
            return true;
            break;
        case 3:
            this->tau_f = value;
            break;
        case 4:
            this->tau_ro = value;
            break;
        case 5:
            return false;
            break;
        case 6:
            this->uMin = value;
            return true;
            break;
        case 7:
            this->uMax = value;
            return true;
            break;
        default:
            return false;
            break;
    }
    updateCoeff_I(I, Ts);
    updateCoeff_D(D, Ts, tau_f);
    updateCoeff_RO(Ts, tau_ro);
    return true;
}

void PID_Cntrl::set_limits(float uMin, float uMax)
{
    this->uMin = uMin;
    this->uMax = uMax;
}

float PID_Cntrl::prewarp(float T, float Ts)
{
    double T_d  = static_cast<double>( T );
    double Ts_d = static_cast<double>( Ts );
    return static_cast<float>( Ts_d/(2.0*tan(Ts_d/(2.0*T_d))) );
}

float PID_Cntrl::get_ulimit()
{
    return uMax;
}

float PID_Cntrl::get_P_gain()
{
    return P;
}

float PID_Cntrl::get_bd()
{
    return bd;
}

float PID_Cntrl::get_ad()
{
    return ad;
}

void PID_Cntrl::setCoefficients(float P, float I, float D, float tau_f, float tau_ro, float Ts)
{
    /* store parameters */
    this->P = P;
    this->I = I;
    this->D = D;
    this->tau_f = tau_f;
    this->tau_ro = tau_ro;
    this->Ts = Ts;
    updateCoeff_I(I, Ts);
    updateCoeff_D(D, Ts, tau_f);
    updateCoeff_RO(Ts, tau_ro);

    /* store initial parameters */
    this->P_init = P;
    this->I_init = I;
    this->D_init = D;
}

float PID_Cntrl::saturate(float u, float uMin, float uMax)
{
    if(u > uMax) {
        u = uMax;
    } else if(u < uMin) {
        u = uMin;
    }
    return u;
}

void PID_Cntrl::updateCoeff_I(float I, float Ts)
{
    double I_d  = static_cast<double>( I  );
    double Ts_d = static_cast<double>( Ts );
    bi = static_cast<float>( I_d*Ts_d );
}

void PID_Cntrl::updateCoeff_D(float D, float Ts, float tau_f)
{
    double D_d     = static_cast<double>( D  );
    double Ts_d    = static_cast<double>( Ts );
    double tau_f_d = static_cast<double>( tau_f );
    bd = static_cast<float>( 2.0*D_d/(Ts_d + 2.0*tau_f_d) );
    ad = static_cast<float>( (Ts_d - 2.0*tau_f_d)/(Ts_d + 2.0*tau_f_d) );
}

void PID_Cntrl::updateCoeff_RO(float Ts, float tau_ro)
{
    double Ts_d     = static_cast<double>( Ts );
    double tau_ro_d = static_cast<double>( tau_ro );
    bf = static_cast<float>( Ts_d/(Ts_d + 2.0*tau_ro_d) );
    af = static_cast<float>( (Ts_d - 2.0*tau_ro_d)/(Ts_d + 2.0*tau_ro_d) );
}