반응형

PID 제어기는 비례-적분-미분 제어(Proportional-Integral-Differential)의 합으로 구성된다.

이 제어기는 본래의 특성으로 인해 발생하는 문제가 있어서 다음과 같은 해법들이 있다.

전체적으로는 제어 모드 변경으로 인한 제어 출력의 충격을 감쇄하는 Bumpless transtion algorithm

미분 제어기는 제어 명령 변화로 인한 derivative kick 문제는 모델의 상태 변화량 만을 사용하는 방법,

적분 제어기는 Integral Windup/Reset Windup 문제에 대해 Anti-Windup Algorithm

등이 있다.

 

본 글은 Anti-Windup과 Bumpless Transition에 대해 정리한다. 서술하기에 앞서, 모델 출력 $y(t)$에 대해서 setpoint $r(t)$를 추종하는 PID 제어기는 다음과 같다. 아래의 첫 번째 형태는 

$$e(t) = r(t) - y(t) $$

$$u(t) = K_p e(t) + K_i \int^t e(\tau) d\tau + K_d \frac{e(t)}{dt}$$

$$u(t) = K_p \left( e(t) + \frac{1}{T_i} \int^t e(\tau) d\tau + T_d \frac{e(t)}{dt} \right)$$

디지털 제어를 한다면..

$$e(kT) = r(kT) - y(kT)$$

$$\cases{u_P (kT) = k_p \cdot e(kT) \\ u_I (kT) = u_I (kT) + k_i \cdot e(kT) \cdot \Delta T \\ u_D (kT) = k_d \cdot \frac{e(kT) - e(kT-T)}{\Delta T} }$$

$$u(kT) = u_P (kT) + u_I (kT) + u_D (kT) $$

 

Anti-Windup

Integral Windup/Reset Windup 이란?

 구동기가 포화되었음에도 불구하고 적분 제어기에 지속적으로 오차를 누적하고 있는 상황을 말한다. 이후에 구동기 포화에 벗어난다고 해도 적분 누적 값이 커서 함께하는 P, D 제어기 등의 정상적인 작동을 방해한다. 이를 해소하는 방법이 Anti-Windup 이다.

 이 방법은 구동기의 포화를 알 수 있다면 혹은 지정한다면, 적분기의 누적 상하한값을 주는 것보다 효과적이다. 적분기의 누적 상하한값이 작다면 적분 제어기의 구동 범위가 작을 수 있으며, 상하한값이 크다면 Windup 현상이 나타나기 때문이다. 연속 공간에서 Anti-Windup 기능을 가지는 PID 제어기의 형태는 다음과 같다. 적분 제어기의 적분항 $K_{aw} (\text{sat} (u) -u) $는 구동기가 포화되었을때만 작동한다. 여기서 tracking gain $K_{aw}$는 계측 소음이 불필요한 reset을 유발 할 수 있으므로, $1/T_i$로 선정하는 것이 합리적이라고 말한다. [2]
$$u(t) = K_p \cdot e(t) + \int^t K_i \left( e(\tau) - K_{aw}(\text{sat}(u)-u) \right)d\tau + K_d \frac{e(t)}{dt}$$

 간단하게 적어본 Anti-Windup을 사용하는 PID 제어기의 코드는 다음과 같다. 여기서 $u_{max}$와 $u_{min}$은 구동기의 최대 변위이며 Trim은 제어기의 트림값이다. 주석된 부분 dydt는 derivative kick을 방지할 때 사용되는 부분이다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
double PID_with_AntiWindup(double dT, double r, double y, CtrlParam param)
    // Share Trim, e_prev
    e = r - y;
    dedt = (e - e_prev) / dT;
    //dydt =-(y - y_prev) / dT;
    
    double Pctrl = param.Kp * e;
           Ictrl+= param.Ki * e * dT;
    double Dctrl = param.Kd * dedt;
    //double Dctrl = param.Kd * dydt;
    double u_temp = Pctrl + Ictrl + Dctrl + param.Trim;
 
    // Anti-Windup
    if (u_temp > param.u_max)
        Ictrl = u_max - P_ctrl - Dctrl - param.Trim;
    else if (u_temp < param.u_min)
        Ictrl = u_min - P_ctrl - Dctrl - param.Trim;
 
    // Control Output
    double u = Pctrl + Ictrl + Dctrl + param.Trim;
    
    // Save error for derivative
    e_prev = e;
    //y_prev = y;
return u;
cs

a

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
class pid:
    def __init__(self, x0, p, i, d, dt, min, max):
        self._int = x0 / p
        self._x_prev = x0
        self._gain_p = p
        self._gain_i = i
        self._gain_d = d
        self._dt = dt
        self._min = min
        self._max = max
 
    def update(self, x_cmd, x):
        e = x_cmd - x
        i_ctrl = self._int
 
        p_ctrl = self._gain_p * e
        i_ctrl+= self._gain_i * e * self._dt
        d_ctrl = self._gain_d * (self._x_prev - x) / self.dt
 
        cmd_tmp = p_ctrl + i_ctrl + d_ctrl
 
        # Anti-windup
        if(cmd_tmp > self._max):
            i_ctrl = self._max - p_ctrl
        elif(cmd_tmp < self._min):
            i_ctrl = self._min - p_ctrl
 
        cmd = p_ctrl + i_ctrl + d_ctrl
        self._x_prev = x
        self._int = i_ctrl
 
        return cmd
cs
 

Bumpless Transition Algorithm, 무충돌 알고리즘

 비행 모드의 변경, 혹은 제어기의 변경으로 의도치 않게 제어기의 출력이 튀는 경우가 있다. 그러면 공정 모델의 상태 또한 이상 응답이 나오게 되는데 이를 bump한다고 한다. 말 그대로 쿵쿵 부딫히는 듯 하는거다. 따라서 이렇게 충돌하는 현상을 방지하기 위한 알고리즘이 bumpless transition algorithm 무충돌 알고리즘이라고 한다. 비행기를 예로 들면, 수동 조종에서 자동 조종으로 변경하는 것이다. 

 적분 제어를 사용한다면 적분 누적값을 조정함으로써, 적분 제어를 사용하지 않는다면 트림을 조정함으로써 무충돌 알고리즘을 구현할 수 있다.

간단히 코드로 구현하면 다음과 같다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
double PID_with_BumplessTransition_AntiWindup(double dT, double r, double y, CtrlParam param, bool bump)
    // Share Trim, e_prev
    e = r - y;
    dedt = (e - e_prev) / dT;
    //dydt =-(y - y_prev) / dT;
    
    double Pctrl = param.Kp * e;
           Ictrl+= param.Ki * e * dT;
    double Dctrl = param.Kd * dedt;    //double Dctrl = param.Kd * dydt;
    double u_rest= Pctrl + Dctrl + param.Trim; // without Ictrl
    
    // Bumpless Transition Algorithm
    // It occurs once
    if(bump)
        Ictrl = u_prev - u_rest;
    double u_temp= u_rest + Ictrl;
    
    // Anti-Windup
    if (u_temp > param.u_max)
        Ictrl = u_max - u_rest;
    else if (u_temp < param.u_min)
        Ictrl = u_min - u_rest;
 
    // Control Output : u = Pctrl + Ictrl + Dctrl + Trim;
    u = u_rest + Ictrl;
    
    // Save error for derivative
    e_prev = e;
    //y_prev = y;
    u_prev = u;
return u;
cs

 

 

동적 시스템에 적용한 구현은 다음 글을 확인해보자.

https://stella47.tistory.com/485

 

 

Reference

1. Åström, K., J. (2002) Chapter 6. PID Control, Control System Design - Lecture Notes for ME155A, University of California, pp.226-230, pp.249-250, Available at www.cds.caltech.edu/~murray/courses/cds101/fa02/caltech/astrom-ch6.pdf

2. Åström, K., J. and Murray R., M., (2009) Feedback Systems - An Introduction for Scientists and Engineers, Ver 2.10b, pp.306-312.

3. Lee, J., H., Choi, J., H., and Lee, K., S. (1997) Part I - Overview of Process Control, Available at www.cheric.org/files/education/practical/mpc1.pdf

4. 김태신, 권오규 (2008) 무충돌 전환 구현 알고리즘을 사용한 전비행영역 제어기 교체법, 한국항공우주학회지 , 제 36권, 제 6호, pp.574-580.

 

 

728x90

+ Recent posts