2019-10-11 13:24:39 -07:00
/*
* @ file pid_open_loop_models . h
*
* Analytic plant models for the real measured step - response data of the open loop test .
* Models are used to calculate the estimated PID parameters .
* These parameters come from Taylor - McLaurin expansion of the model
*
* @ date Sep 27 , 2019
* @ author andreika , ( c ) 2019
*/
# pragma once
# include "global.h"
# include "pid_functions.h"
// should be multiple of 2
# define MAX_DATA_POINTS 700
2019-10-19 05:56:17 -07:00
typedef enum {
2019-10-11 13:24:39 -07:00
// 1st order
PID_TUNE_CHR1 ,
PID_TUNE_AUTO1 ,
// 2nd order approximated with 1st order
PID_TUNE_IMC2_1 ,
PID_TUNE_CHR2_1 ,
// 2nd order
PID_TUNE_CHR2 ,
PID_TUNE_VDG2 ,
PID_TUNE_HP2 ,
PID_TUNE_AUTO2 ,
2019-10-19 05:56:17 -07:00
} pid_tune_method_e ;
2019-10-11 13:24:39 -07:00
// Used as an open-loop plant model for the "manual bump test" and as an input of a transfer function
class ModelOpenLoopPlant
{
public :
ModelOpenLoopPlant ( ) { }
2019-10-23 07:45:12 -07:00
ModelOpenLoopPlant ( const double_t * params_ ) : params ( ( double_t * ) params_ ) {
2019-10-11 13:24:39 -07:00
}
2019-10-23 07:45:12 -07:00
double_t * getParams ( ) {
2019-10-11 13:24:39 -07:00
return params ;
}
2019-10-23 07:45:12 -07:00
virtual float_t getKp ( ) const = 0 ;
virtual float_t getKi ( ) const = 0 ;
virtual float_t getKd ( ) const = 0 ;
2019-10-11 13:24:39 -07:00
protected :
2019-10-23 07:45:12 -07:00
double_t * params ;
2019-10-11 13:24:39 -07:00
} ;
// Based on FOPDT model approximated from Overdamped-SOPDT model
class ModelFopdtApproximatedFromSopdt : public ModelOpenLoopPlant {
public :
2019-10-23 07:45:12 -07:00
ModelFopdtApproximatedFromSopdt ( double_t * soParams ) : ModelOpenLoopPlant ( p ) {
double_t T2divT1 = soParams [ PARAM_T2 ] / soParams [ PARAM_T ] ;
double_t T2mulT1 = soParams [ PARAM_T2 ] * soParams [ PARAM_T ] ;
2019-10-11 13:24:39 -07:00
params [ PARAM_K ] = soParams [ PARAM_K ] ;
params [ PARAM_T ] = 0.828 + 0.812 * T2divT1 + 0.172 * exp ( - 6.9 * T2divT1 ) * soParams [ PARAM_T ] ;
params [ PARAM_L ] = 1.116 * T2mulT1 / ( soParams [ PARAM_T ] + 1.208 * soParams [ PARAM_T2 ] ) + soParams [ PARAM_L ] ;
# ifdef PID_DEBUG
printf ( " Params-1: K=%g T=%g L=%g \r \n " , p [ PARAM_K ] , p [ PARAM_T ] , p [ PARAM_L ] ) ;
# endif
}
// we don't really need them, because this model is just an intermediate
2019-10-23 07:45:12 -07:00
virtual float_t getKp ( ) const {
2019-10-11 13:24:39 -07:00
return 0.0f ;
}
2019-10-23 07:45:12 -07:00
virtual float_t getKi ( ) const {
2019-10-11 13:24:39 -07:00
return 0.0f ;
}
2019-10-23 07:45:12 -07:00
virtual float_t getKd ( ) const {
2019-10-11 13:24:39 -07:00
return 0.0f ;
}
private :
// A storage for the new 1st order params
2019-10-23 07:45:12 -07:00
double_t p [ 3 ] ;
2019-10-11 13:24:39 -07:00
} ;
2019-10-19 05:56:17 -07:00
// Standard PID model: Kc * (1 + 1/(Ti*S) + Td * S)
// This class converts in into our "Parallel" form: Kp + Ki / S + Kd * S
class ModelStandard : public ModelOpenLoopPlant {
public :
2019-10-23 07:45:12 -07:00
ModelStandard ( const double_t * params_ ) : ModelOpenLoopPlant ( params_ ) {
2019-10-11 13:24:39 -07:00
}
2019-10-23 07:45:12 -07:00
virtual float_t getKp ( ) const {
return ( float_t ) Kc ;
2019-10-11 13:24:39 -07:00
}
2019-10-23 07:45:12 -07:00
virtual float_t getKi ( ) const {
return ( float_t ) ( Kc / Ti ) ;
2019-10-11 13:24:39 -07:00
}
2019-10-23 07:45:12 -07:00
virtual float_t getKd ( ) const {
return ( float_t ) ( Kc * Td ) ;
2019-10-11 13:24:39 -07:00
}
2019-10-19 05:56:17 -07:00
protected :
// "Standard" PID coefs
2019-10-23 07:45:12 -07:00
double_t Kc , Ti , Td ;
2019-10-11 13:24:39 -07:00
} ;
2019-10-19 05:56:17 -07:00
class ModelStandardIMC : public ModelStandard {
2019-10-11 13:24:39 -07:00
public :
2019-10-23 07:45:12 -07:00
ModelStandardIMC ( const double_t * params_ ) : ModelStandard ( params_ ) {
2019-10-19 05:56:17 -07:00
lambda = fmax ( 0.25 * params [ PARAM_L ] , 0.2 * Ti ) ;
}
protected :
// closed-loop speed of response
2019-10-23 07:45:12 -07:00
double_t lambda ;
2019-10-19 05:56:17 -07:00
} ;
// Chien-Hrones-Reswick PID implementation for the 1st order model (generic model).
class ModelChienHronesReswickFirstOrder : public ModelStandardIMC {
public :
2019-10-23 07:45:12 -07:00
ModelChienHronesReswickFirstOrder ( const double_t * params_ ) : ModelStandardIMC ( params_ ) {
double_t l2 = params [ PARAM_L ] / 2.0 ;
2019-10-19 05:56:17 -07:00
Ti = params [ PARAM_T ] + l2 ;
Td = params [ PARAM_T ] * params [ PARAM_L ] / ( 2 * params [ PARAM_T ] + params [ PARAM_L ] ) ;
Kc = Ti / ( params [ PARAM_K ] * ( lambda + l2 ) ) ;
}
} ;
// Chien-Hrones-Reswick PID implementation for the 1st order model (set-point regulation).
class ModelChienHronesReswickFirstOrderSetpoint : public ModelOpenLoopPlant {
public :
2019-10-23 07:45:12 -07:00
ModelChienHronesReswickFirstOrderSetpoint ( const double_t * params_ ) : ModelOpenLoopPlant ( params_ ) {
2019-10-11 13:24:39 -07:00
}
2019-10-23 07:45:12 -07:00
virtual float_t getKp ( ) const {
return ( float_t ) ( 0.6f / params [ PARAM_K ] ) ;
2019-10-11 13:24:39 -07:00
}
2019-10-23 07:45:12 -07:00
virtual float_t getKi ( ) const {
return ( float_t ) ( 1.0f / params [ PARAM_T ] ) ;
2019-10-11 13:24:39 -07:00
}
2019-10-23 07:45:12 -07:00
virtual float_t getKd ( ) const {
return ( float_t ) ( 1.0f / ( 0.5f * params [ PARAM_L ] ) ) ;
2019-10-11 13:24:39 -07:00
}
} ;
2019-10-19 05:56:17 -07:00
// Chien-Hrones-Reswick PID implementation for the 1st order model (disturbance rejection).
class ModelChienHronesReswickFirstOrderDisturbance : public ModelOpenLoopPlant {
2019-10-11 13:24:39 -07:00
public :
2019-10-23 07:45:12 -07:00
ModelChienHronesReswickFirstOrderDisturbance ( const double_t * params_ ) : ModelOpenLoopPlant ( params_ ) {
2019-10-11 13:24:39 -07:00
}
2019-10-23 07:45:12 -07:00
virtual float_t getKp ( ) const {
return ( float_t ) ( 0.95f / params [ PARAM_K ] ) ;
2019-10-11 13:24:39 -07:00
}
2019-10-23 07:45:12 -07:00
virtual float_t getKi ( ) const {
return ( float_t ) ( 2.4f / params [ PARAM_T ] ) ;
2019-10-11 13:24:39 -07:00
}
2019-10-23 07:45:12 -07:00
virtual float_t getKd ( ) const {
return ( float_t ) ( 1.0f / ( 0.42f * params [ PARAM_L ] ) ) ;
2019-10-19 05:56:17 -07:00
}
} ;
// "IMC-PID" Rivera-Morari-Zafiriou implementation for the 1st order model
// See "Panda R.C., Yu C.C., Huang H.P. PID tuning rules for SOPDT systems: Review and some new results"
class ModelRiveraMorariFirstOrder : public ModelStandardIMC {
public :
2019-10-23 07:45:12 -07:00
ModelRiveraMorariFirstOrder ( const double_t * params_ ) : ModelStandardIMC ( params_ ) {
2019-10-19 05:56:17 -07:00
Kc = ( 2 * params [ PARAM_T ] + params [ PARAM_L ] ) / ( 2 * params [ PARAM_K ] * ( lambda + params [ PARAM_L ] ) ) ;
Ti = params [ PARAM_T ] + 0.5 * params [ PARAM_L ] ;
Td = params [ PARAM_T ] * params [ PARAM_L ] / ( 2.0 * params [ PARAM_T ] + params [ PARAM_L ] ) ;
2019-10-11 13:24:39 -07:00
}
2019-10-19 05:56:17 -07:00
} ;
2019-10-11 13:24:39 -07:00
2019-10-19 05:56:17 -07:00
// Based on "IMC-Chien" (aka Rivera/Smith) model: "Chien, I.L., IMC-PID controller design - An extension."
// "Proceedings of the IFAC adaptive control of chemical processes conference, Copenhagen, Denmark, 1988, pp. 147-152."
class ModelChienHronesReswickSecondOrder : public ModelStandardIMC {
public :
2019-10-23 07:45:12 -07:00
ModelChienHronesReswickSecondOrder ( const double_t * params_ ) : ModelStandardIMC ( params_ ) {
2019-10-19 05:56:17 -07:00
Ti = params [ PARAM_T ] + params [ PARAM_T2 ] ;
Td = params [ PARAM_T ] * params [ PARAM_T2 ] / Ti ;
Kc = Ti / ( params [ PARAM_K ] * ( lambda + params [ PARAM_L ] ) ) ;
}
2019-10-11 13:24:39 -07:00
} ;
// Basen on Van der Grinten Model (1963)
// "Step disturbance".
2019-10-19 05:56:17 -07:00
class ModelVanDerGrintenSecondOrder : public ModelStandard {
2019-10-11 13:24:39 -07:00
public :
2019-10-23 07:45:12 -07:00
ModelVanDerGrintenSecondOrder ( const double_t * params_ ) : ModelStandard ( params_ ) {
double_t T12 = params [ PARAM_T ] + params [ PARAM_T2 ] ;
2019-10-11 13:24:39 -07:00
Ti = T12 + 0.5 * params [ PARAM_L ] ;
Td = ( T12 * params [ PARAM_L ] + 2.0 * params [ PARAM_T ] * params [ PARAM_T2 ] ) / ( params [ PARAM_L ] + 2.0 * T12 ) ;
Kc = ( 0.5 + T12 / params [ PARAM_L ] ) / params [ PARAM_K ] ;
}
} ;
// Based on Haalman-Pemberton model: "Haalman, A.: Adjusting controllers for a deadtime process. Control Eng. 65, 71<37> 73 (1965)"
// Suited for overdamped response and significant delay.
2019-10-19 05:56:17 -07:00
class ModelHaalmanPembertonSecondOrder : public ModelStandard {
2019-10-11 13:24:39 -07:00
public :
2019-10-23 07:45:12 -07:00
ModelHaalmanPembertonSecondOrder ( const double_t * params_ ) : ModelStandard ( params_ ) {
double_t T1divT2 = params [ PARAM_T ] / params [ PARAM_T2 ] ;
double_t LdivT2 = params [ PARAM_L ] / params [ PARAM_T2 ] ;
2019-10-11 13:24:39 -07:00
Ti = params [ PARAM_T ] + params [ PARAM_T2 ] ;
Kc = 2.0 * Ti / ( 3 * params [ PARAM_K ] * params [ PARAM_L ] ) ;
if ( T1divT2 > = 0.1 & & T1divT2 < = 1.0 & & LdivT2 > = 0.2 & & LdivT2 < = 1.0 ) {
Td = Ti / 4.0 ;
} else {
Td = params [ PARAM_T ] * params [ PARAM_T2 ] / Ti ;
}
}
} ;
2019-10-19 05:56:17 -07:00
// Based on IMC-Maclaurin model:
// Lee, Y., Park, S., Lee, M., and Brosilow, C., PID controller tuning for desired closed - loop responses for SI / SO systems. AIChE J. 44, 106<30> 115 1998.
class ModelMaclaurinSecondOrder : public ModelStandardIMC {
2019-10-11 13:24:39 -07:00
public :
2019-10-23 07:45:12 -07:00
ModelMaclaurinSecondOrder ( const double_t * params_ ) : ModelStandardIMC ( params_ ) {
double_t T1T2 = params [ PARAM_T ] + params [ PARAM_T2 ] ;
double_t L = params [ PARAM_L ] ;
double_t L2 = L * L ;
double_t twolL = 2.0 * lambda + L ;
2019-10-19 05:56:17 -07:00
Ti = T1T2 - ( 2.0 * lambda * lambda - L2 ) / ( 2.0 * twolL ) ;
Kc = Ti / ( params [ PARAM_K ] * twolL ) ;
Td = Ti - T1T2 + ( params [ PARAM_T ] * params [ PARAM_T2 ] - L2 * L / ( 6.0 * twolL ) ) / Ti ;
2019-10-11 13:24:39 -07:00
}
} ;
class ModelAutoSolver : public ModelOpenLoopPlant {
public :
ModelAutoSolver ( const ModelOpenLoopPlant * initial ) : ModelOpenLoopPlant ( pidParams ) {
pidParams [ PARAM_Kp ] = initial - > getKp ( ) ;
pidParams [ PARAM_Ki ] = initial - > getKi ( ) ;
pidParams [ PARAM_Kd ] = initial - > getKd ( ) ;
}
2019-10-23 07:45:12 -07:00
virtual float_t getKp ( ) const {
return ( float_t ) pidParams [ PARAM_Kp ] ;
2019-10-11 13:24:39 -07:00
}
2019-10-23 07:45:12 -07:00
virtual float_t getKi ( ) const {
return ( float_t ) pidParams [ PARAM_Ki ] ;
2019-10-11 13:24:39 -07:00
}
2019-10-23 07:45:12 -07:00
virtual float_t getKd ( ) const {
return ( float_t ) pidParams [ PARAM_Kd ] ;
2019-10-11 13:24:39 -07:00
}
protected :
2019-10-23 07:45:12 -07:00
double_t pidParams [ numParamsForPid ] ;
2019-10-11 13:24:39 -07:00
} ;