比例項可以讓系統儘快達到一個小的誤差範圍,積分項對比例項作用產生的誤差進行積分,也就是放大產生的誤差,讓其更快達到目標,但這時會導致系統過沖量較大,微分項的引入會抑制過沖。
作用:
進行離散化處理
假設系統採樣時間爲,將序列化爲:
將輸出序列化得到:
比例項:
積分項:
微分項:
因此,連續PID式變爲:
上式即爲位置式PID。
實際工程中,常用增量式PID:
即:
previous_error := 0 //上一次偏差
integral := 0 //積分和
//回圈
//採樣週期爲dt
loop:
//setpoint 設定值
//measured_value 反饋值
error := setpoint − measured_value //計算得到偏差
integral := integral + error × dt //計算得到積分累加和
derivative := (error − previous_error) / dt //計算得到微分
output := Kp × error + Ki × integral + Kd × derivative //計算得到PID輸出
previous_error := error //儲存當前偏差爲下一次採樣時所需要的歷史偏差
wait(dt) //等待下一次採用
goto loop
#ifndef _PID_H_
#define _PID_H_
class PIDImpl;
class PID
{
public:
// Kp - proportional gain
// Ki - Integral gain
// Kd - derivative gain
// dt - loop interval time
// max - maximum value of manipulated variable
// min - minimum value of manipulated variable
PID( double dt, double max, double min, double Kp, double Kd, double Ki );
// Returns the manipulated variable given a setpoint and current process value
double calculate( double setpoint, double pv );
~PID();
private:
PIDImpl *pimpl;
};
#endif
#ifndef _PID_SOURCE_
#define _PID_SOURCE_
#include <iostream>
#include <cmath>
#include "pid.h"
using namespace std;
class PIDImpl
{
public:
PIDImpl( double dt, double max, double min, double Kp, double Kd, double Ki );
~PIDImpl();
double calculate( double setpoint, double pv );
private:
double _dt;
double _max;
double _min;
double _Kp;
double _Kd;
double _Ki;
double _pre_error;
double _integral;
};
PID::PID( double dt, double max, double min, double Kp, double Kd, double Ki )
{
pimpl = new PIDImpl(dt,max,min,Kp,Kd,Ki);
}
double PID::calculate( double setpoint, double pv )
{
return pimpl->calculate(setpoint,pv);
}
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)
{
}
double PIDImpl::calculate( 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;
// Calculate total output
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;
return output;
}
PIDImpl::~PIDImpl()
{
}
#endif
#include "pid.h"
#include <stdio.h>
int main() {
PID pid = PID(0.1, 100, -100, 0.1, 0.01, 0.5);
double val = 20;
for (int i = 0; i < 100; i++) {
double inc = pid.calculate(0, val);
printf("val:% 7.3f inc:% 7.3f\n", val, inc);
val += inc;
}
return 0;
}
class PositionalPID:
def __init__(self, P, I, D):
self.Kp = P
self.Ki = I
self.Kd = D
self.SystemOutput = 0.0#系統輸出值
self.ResultValueBack = 0.0
self.PidOutput = 0.0#PID控制器輸出
self.PIDErrADD = 0.0
self.ErrBack = 0.0
#設定一階慣性環節系統 其中InertiaTime爲慣性時間常數
def SetInertiaTime(self, InertiaTime,SampleTime):
self.SystemOutput = (InertiaTime * self.ResultValueBack + SampleTime * self.PidOutput) / (SampleTime + InertiaTime)
self.ResultValueBack = self.SystemOutput
#設定PID控制器參數
def SetStepSignal(self,StepSignal):
Err = StepSignal - self.SystemOutput
KpWork = self.Kp * Err
KiWork = self.Ki * self.PIDErrADD
KdWork = self.Kd * (Err - self.ErrBack)
self.PidOutput = KpWork + KiWork + KdWork
self.PIDErrADD += Err