Полный ПИД-регулятор как класс
Собираем P, I и D в один регулятор — рабочую лошадку всей индустрии.
ПИД-регулятор объединяет три составляющие:
u = Kp·e + Ki·∫e·dt + Kd·de/dt. P реагирует на настоящее, I — на прошлое, D — на будущее ошибки.
Полная формула и роли составляющих
ПИД (PID) — самый распространённый регулятор в мире: им управляют печи, двигатели, дроны, химические реакторы, 3D-принтеры. Его сила — в сочетании трёх взглядов на ошибку. P даёт быструю реакцию, пропорциональную текущему отклонению. I добивает остаточную ошибку, накапливая её. D демпфирует колебания, реагируя на скорость. Вместе они дают быструю, точную и устойчивую систему.
| Часть | Смотрит на | Даёт | Риск |
| P (Kp) | настоящее (e) | скорость реакции | остаточная ошибка, раскачка |
| I (Ki) | прошлое (∫e) | нулевую статическую ошибку | windup, колебания |
| D (Kd) | будущее (de/dt) | демпфирование | усиление шума |
Реализуем ПИД как класс
Грамотная реализация — отдельный объект с памятью (интеграл и прошлая ошибка). Это ровно то, что живёт в прошивке микроконтроллера или узле ROS.
class PID:
def __init__(self, Kp, Ki, Kd, dt):
self.Kp, self.Ki, self.Kd, self.dt = Kp, Ki, Kd, dt
self.integral = 0.0
self.prev_err = 0.0
def update(self, setpoint, measurement):
err = setpoint - measurement
self.integral += err * self.dt
deriv = (err - self.prev_err) / self.dt
self.prev_err = err
return self.Kp*err + self.Ki*self.integral + self.Kd*deriv
# Управляем нагревом бака до 60 градусов
pid = PID(Kp=8.0, Ki=0.3, Kd=12.0, dt=1.0)
C, k, Tamb = 50.0, 2.0, 20.0
T = 20.0
print("шаг T U(мощн.)")
for step in range(0, 41):
u = pid.update(60.0, T)
u = max(0.0, min(400.0, u))
T += (u - k*(T-Tamb))/C
if step % 5 == 0:
print(f"{step:3d} {T:6.2f} {u:7.2f}")
print(f"финал: T={T:.2f}, ошибка={60-T:.3f}")Вывод:
шаг T U(мощн.) 0 28.00 400.00 5 43.72 165.57 10 52.10 124.45 15 56.34 103.03 20 58.46 91.95 25 59.49 86.21 30 59.98 83.24 35 60.19 81.70 40 60.26 80.90 финал: T=60.26, ошибка=-0.258
ПИД быстро вышел на 60, почти без перерегулирования, и в равновесии держит мощность ~80 Вт (ровно компенсация потерь k·(60-20)=80), при этом ошибка нулевая. Обратите внимание, как интеграл «запомнил» нужные 80 Вт даже при нулевой ошибке — этого P-регулятор не умел. Это и есть красота ПИД: три составляющие закрывают слабости друг друга.
Параллельная и стандартная формы
Мы записали ПИД в параллельной форме (три независимых коэффициента Kp, Ki, Kd). В литературе и приборах часто встречается стандартная форма через время интегрирования Ti и дифференцирования Td: u = Kp·(e + (1/Ti)·∫e + Td·de/dt). Связь простая: Ki = Kp/Ti, Kd = Kp·Td. Формы эквивалентны — выбирайте удобную, но не путайте, читая чужие настройки.
Почему ПИД так живуч
ПИД-регулятору больше века, и его многократно «хоронили» с приходом более умных методов — а он по-прежнему управляет около 90% промышленных контуров в мире. Причин несколько. Он не требует точной модели объекта: три коэффициента можно настроить эмпирически прямо на установке. Он интуитивно понятен: каждая часть имеет ясный смысл, и наладчик чувствует, что крутить. Он дёшев: реализуется в несколько строк на любом микроконтроллере. И он достаточно хорош для подавляющего большинства задач: где не нужно выжимать последние проценты качества, ПИД закрывает вопрос. Более сложные методы (LQR, MPC, адаптивное управление) выигрывают там, где объект сложен, связан и хорошо известен, — но цена за это растёт, и ПИД остаётся рабочей лошадкой по умолчанию.
Частые ошибки
- Настраивать все три коэффициента сразу. Лучше по очереди: сначала P, потом I, потом D (об этом — следующий раздел).
- Игнорировать насыщение и windup. Полный ПИД без анти-windup в реальной системе с ограниченным приводом ведёт себя хуже, чем на бумаге.
- Путать формы. Коэффициенты из стандартной формы (Ti, Td) нельзя подставлять в параллельную напрямую.
Итоги
- ПИД = Kp·e + Ki·∫e·dt + Kd·de/dt: настоящее, прошлое и будущее ошибки.
- Реализуется как объект с памятью (интеграл, прошлая ошибка) — основа прошивок и узлов ROS.
- Существуют параллельная (Kp,Ki,Kd) и стандартная (Kp,Ti,Td) формы — не путайте их.