← Back to Blog

PID Control System

engineering > control

2025-08-292 min read

#control #systems #engineering #pid #vectors

PID (Proportional Integral Differential)는 피드백 기반 제어 알고리즘이다.
이 알고리즘은 목표값(setpoint, SP)과 실제값(process variable, PV)의 차이를 비교한다.
이 차이를 에러값, e(t)e(t)라고 표현한다.

pid-controller-wikipedia
출처: Wikipedia: Proportional-integral-derivative controller

3가지 제어로 나누어져 있다.

pid-parameter-plot

1. Proportional Control

비례 제어(Proportional Control) 는 목표값과 실제값 간의 '현재 오차(Error)'에 비례하여 제어량을 결정한다.

2. Integral Control

적분 제어(Integral Control) 는 시간에 따라 누적된 '과거의 오차'를 바탕으로 제어량을 결정한다.

3. Derivative Control

미분 제어(Derivative Control) 는 오차의 변화율, 즉 오차가 얼마나 빠르게 변하는지를 감지하여 '미래의 오차'를 예측하고 이에 대응한다.


수학적 해석

Control function

u(t)=Kpe(t)+Ki0te(τ)dτ+Kdde(t)dtu(t) = K_p e(t) + K_i \int_{0}^{t} e(\tau)d\tau + K_d \frac{de(t)}{dt}

Standard form

위 Control function에서 KpK_p를 괄호 밖으로 묶어내고, 적분 및 미분 동작을 시간 상수(TiT_i, TdT_d)로 표현한다.

u(t)=Kp(e(t)+1Ti0te(τ)dτ+Tdde(t)dt)u(t) = K_p \left( e(t) + \frac{1}{T_i} \int_{0}^{t} e(\tau)d\tau + T_d\frac{de(t)}{dt} \right) Ti=KpKiT_i = \frac{K_p}{K_i} Td=KdKpT_d = \frac{K_d}{K_p}

Mass Spring Damper 예제

import matplotlib.pyplot as plt
import numpy as np


Kp = 40.0  # Proportional Gain
Ki = 35.0  # Integral Gain
Kd = 10.0  # Derivative Gain

# System: Mass-Spring-Damper
m = 1.0  # Mass (kg)
k = 20.0 # Spring constant (N/m)
c = 2.0  # Damping coefficient (Ns/m)

# Simulation Parameters
dt = 0.01
total_time = 10.0
steps = int(total_time / dt)
setpoint = 1.0


def run_simulation(gains, system_params):
    kp, ki, kd = gains
    m, k, c = system_params

    # Initialize state
    y = 0.0
    y_dot = 0.0
    integral = 0.0
    prev_err = 0.0

    # Data log
    y_history = []

    for _ in range(steps):
        # 1. Calculate Error
        err = setpoint - y

        # 2. Calculate Integral and Derivative terms
        integral += err * dt
        derivative = (err - prev_err) / dt

        # 3. Calculate PID Control Input (u)
        u = kp * err + ki * integral + kd * derivative
        prev_err = err

        # 4. Update System Model based on physics
        # m*a + c*v + k*x = u  =>  a = (u - c*v - k*x) / m
        y_ddot = (u - c * y_dot - k * y) / m  # Acceleration
        y_dot += y_ddot * dt                  # Velocity
        y += y_dot * dt                       # Position

        y_history.append(y)

    return y_history


y_p_only = run_simulation((Kp, 0, 0), (m, k, c))

# Run PD simulation
y_pd = run_simulation((Kp, 0, Kd), (m, k, c))

# Run full PID simulation
y_pid = run_simulation((Kp, Ki, Kd), (m, k, c))

# Time vector for plotting
t_his = np.arange(0, total_time, dt)

plt.figure(figsize=(10, 6))
plt.plot(t_his, [setpoint] * steps, 'r--', linewidth=2, label='Setpoint')
plt.plot(t_his, y_p_only, linewidth=2, label=f'P-Only Control (Kp={Kp})')
plt.plot(t_his, y_pd, linewidth=2, label=f'PD Control (Kp={Kp}, Kd={Kd})')
plt.plot(t_his, y_pid, 'g-', linewidth=3, label=f'Full PID Control (Kp={Kp}, Ki={Ki}, Kd={Kd})')

plt.title('PID Parameter Tuning Process', fontsize=16)
plt.xlabel('Time (s)', fontsize=12)
plt.ylabel('Position (m)', fontsize=12)
plt.grid(True)
plt.legend(fontsize=12)
plt.xlim(0, total_time)
plt.tight_layout()
plt.show()