#ifndef _PID_SOURCE_ #define _PID_SOURCE_ #include #include #include #include "pid.h" using namespace std; #define STAGE_INIT (0) #define STAGE_LOW (1) #define STAGE_MID (2) #define STAGE_HIGH (3) class PIDImpl { public: PIDImpl( double dt, double max, double min, double Kp, double Kd, double Ki); PIDImpl( double dt, double max, double min, double Kp, double Kd, double Ki, double maxI); PIDImpl( double dt, double max, double min, double Kp, double Kd, double Ki, double maxI, double maxIstep, double maxDstep); ~PIDImpl(); double calculate( double setpoint, double pv ); double calculate_v2( double setpoint, double pv ); void reset(); private: double _dt; double _max; double _min; double _Kp; double _Kd; double _Ki; double _pre_error; double _integral; double _maxI; double _maxIstep; double _maxDstep; double _pre_output; double _start_pv; double _critical_output; int _stage; }; PID::PID( double dt, double max, double min, double Kp, double Kd, double Ki) { pimpl = new PIDImpl(dt,max,min,Kp,Kd,Ki); } PID::PID( double dt, double max, double min, double Kp, double Kd, double Ki, double maxI) { pimpl = new PIDImpl(dt,max,min,Kp,Kd,Ki,maxI); } PID::PID( double dt, double max, double min, double Kp, double Kd, double Ki, double maxI, double maxIstep, double maxDstep) { pimpl = new PIDImpl(dt,max,min,Kp,Kd,Ki,maxI, maxIstep, maxDstep); } double PID::calculate( double setpoint, double pv ) { return pimpl->calculate(setpoint,pv); } double PID::calculate_v2( double setpoint, double pv ) { return pimpl->calculate_v2(setpoint,pv); } void PID::reset() { return pimpl->reset(); } PID::~PID() { delete pimpl; } /** * Implementation */ PIDImpl::PIDImpl( double dt, double max, double min, double Kp, double Kd, double Ki) : _dt(dt), _max(max), _min(min), _Kp(Kp), _Kd(Kd), _Ki(Ki), _pre_error(0), _integral(0) { _maxI = 0; _maxIstep = 0; _maxDstep = 0; _pre_output = 0; _start_pv = 0; _critical_output = 0; _stage = STAGE_INIT; } /** * Implementation */ PIDImpl::PIDImpl( double dt, double max, double min, double Kp, double Kd, double Ki, double maxI) : _dt(dt), _max(max), _min(min), _Kp(Kp), _Kd(Kd), _Ki(Ki), _pre_error(0), _integral(0), _maxI(maxI) { _maxIstep = 0; _maxDstep = 0; _pre_output = 0; _start_pv = 0; _critical_output = 0; _stage = STAGE_INIT; } /** * Implementation */ PIDImpl::PIDImpl( double dt, double max, double min, double Kp, double Kd, double Ki, double maxI, double maxIstep, double maxDstep) : _dt(dt), _max(max), _min(min), _Kp(Kp), _Kd(Kd), _Ki(Ki), _pre_error(0), _integral(0), _maxI(maxI), _maxIstep(maxIstep), _maxDstep(maxDstep) { _pre_output = 0; _start_pv = 0; _critical_output = 0; _stage = STAGE_INIT; } double PIDImpl::calculate( double setpoint, double pv ) { // Calculate error double error = setpoint - pv; // Proportional term double Pout = _Kp * error; // Integral term if(setpoint < 0.05){ _integral += error * _dt; } double Iout = _Ki * _integral; //积分限幅 if(_maxI > 0){ if(Iout > _maxI){ Iout = _maxI; }else if(Iout < -_maxI){ Iout = -_maxI; } } // Derivative term double derivative = (error - _pre_error) / _dt; double Dout = _Kd * derivative; qDebug("calculate : pOut : %f, Iout: %f, Dout: %f ", Pout, Iout, Dout); // Calculate total output //double output = Pout + Iout + Dout; double output = Pout + Iout ;//+ Dout; // Save error to previous error _pre_error = error; if(_maxIstep > 0 && output - _pre_output > _maxIstep){ output = _pre_output + _maxIstep; }else if(_maxDstep > 0 && _pre_output - output > _maxDstep){ output = _pre_output - _maxDstep; } // Restrict to max/min if( output > _max ) output = _max; else if( output < _min ) output = _min; _pre_output = output; return output; } double PIDImpl::calculate_v2( double setpoint, double pv ) { // Calculate error double error = setpoint - pv; // Proportional term double Pout = _Kp * error; // Integral term _integral += error * _dt; double Iout = _Ki * _integral; // Derivative term double derivative = (error - _pre_error) / _dt; double Dout = _Kd * derivative; qDebug("calculate_V2 : pOut : %f, Iout: %f, Dout: %f ", Pout, Iout, Dout); // Calculate total output //double output = Pout + Iout + Dout; double output = Pout + Iout ;//+ Dout; // Restrict to max/min if( output > _max ) output = _max; else if( output < _min ) output = _min; // Save error to previous error _pre_error = error; //belows add by avansguo if(STAGE_INIT == _stage){ _start_pv = pv; _stage = STAGE_LOW; }else{ if(pv < _start_pv){ _start_pv = pv; qDebug("calculate _start_pv: %f ", _start_pv); } } if(_critical_output < 1.0){ if(derivative <= (-0.02)){ //压力开始增加了,记录前值作为临界值 _critical_output = _pre_output; qDebug("calculate _critical_output: %f ", _critical_output); } } double _distance = 0; if(setpoint - _start_pv < 0.5){ _distance = 1; }else{ _distance = error/(setpoint - _start_pv); } if(_distance <= 0.2){ output = _critical_output + (_distance+0.1)*( _pre_output - _critical_output); }else if((_distance > 0.2) &&(_distance <= 0.5)){ if(derivative > (-0.02)){ //压力不变或在下降 }else if(derivative < (-0.2)){ output = _pre_output+Dout; _integral = output; }{ output = _pre_output; _integral = output; } }else{ if(derivative < (-0.2)){ output = _pre_output+Dout; _integral = output; }else if(derivative > (-0.02)){ //压力不变或在下降 //解决当 开始压力与初始压力差距太小, 积分太慢的问题 if(output-_pre_output < 2){ output = _pre_output+2; _integral = output; } }else{ output = _pre_output; _integral = output; } // } _pre_output = output; return output; } void PIDImpl::reset() { _pre_error = 0; _integral = 0; _pre_output = 0; _start_pv = 0; _critical_output = 0; _stage = STAGE_INIT; } PIDImpl::~PIDImpl() { } #endif