Анти-windup, насыщение и фильтрация D
Делаем ПИД пригодным для реального мира: анти-windup, насыщение, фильтр D.
Анти-windup — приёмы, не дающие интегралу разбухать, пока привод в насыщении. Без них ПИД на реальном железе работает заметно хуже, чем в теории.
Проблема: реальный привод ограничен
В теории привод может выдать любое воздействие. В реальности нагреватель имеет максимум мощности, мотор — максимальный момент, клапан открыт максимум на 100%. Это насыщение привода. Когда регулятор требует больше, чем привод может дать, выход «упирается в потолок», и именно тогда интеграл начинает опасно разбухать (windup из урока про I-составляющую). Грамотный ПИД обязан это учитывать.
Анти-windup: ограничение интеграла
Самый простой и популярный приём — не накапливать интеграл, пока привод в насыщении (метод «clamping»). Логика: если воздействие уже упёрлось в предел, добавлять ещё бессмысленно — значит, и интеграл копить незачем. Как только система выйдет из насыщения, накопление возобновляется. Сравним ПИД с анти-windup и без.
def run(anti_windup):
Kp, Ki, dt = 1.0, 0.3, 1.0
sp, y = 50.0, 0.0
integral, u_max = 0.0, 10.0
peak, ys = 0.0, []
for _ in range(60):
e = sp - y
integral += e*dt
u = Kp*e + Ki*integral
u_sat = max(-u_max, min(u_max, u))
if anti_windup and u != u_sat:
integral -= e*dt # откатываем накопление в насыщении
y += 0.5*u_sat*dt
ys.append(y); peak = max(peak, y)
return peak, ys[-1]
p0, f0 = run(False)
p1, f1 = run(True)
print(f"БЕЗ анти-windup: пик={p0:.1f} (перелёт {(p0-50)/50*100:.0f}%)")
print(f"С анти-windup: пик={p1:.1f} (перелёт {(p1-50)/50*100:.0f}%)")Вывод:
БЕЗ анти-windup: пик=87.8 (перелёт 76%) С анти-windup: пик=51.4 (перелёт 3%)
Разница драматична: без анти-windup интеграл разбухает за время насыщения и даёт огромное перерегулирование; с анти-windup система выходит на уставку аккуратно. Это одна из самых важных практических доработок — без неё ПИД на реальном железе ведёт себя непредсказуемо.
Насыщение привода как часть модели
Второй принцип: всегда моделируйте насыщение привода и учитывайте его при проектировании. Регулятор должен «знать», что привод ограничен, и не строить планы, которые тот не сможет исполнить. Ограничение воздействия (clamp) ставится всегда, даже если кажется, что до предела далеко — это страховка от выбросов.
Фильтрация дифференциальной составляющей
Третья доработка касается шумной D. Чтобы производная не дёргала привод от шума, её фильтруют. Простейший приём — экспоненциальное сглаживание: новое значение D — это смесь свежей производной и предыдущего сглаженного значения. Это убирает высокочастотный шум, почти не портя полезную динамику. Часто также применяют D от выхода, а не от ошибки, чтобы избежать «derivative kick» — гигантского всплеска при ступенчатом изменении уставки.
# Экспоненциальный фильтр гасит шум в производной
import random
random.seed(3)
alpha = 0.3 # коэффициент сглаживания (0..1): меньше -> сильнее фильтр
d_filt = 0.0
prev = 1.0
print("сырая_D фильтр_D")
for _ in range(6):
measured = 1.0 + random.uniform(-0.05, 0.05) # шумная "ошибка" ~1
raw_d = (measured - prev)/0.1
d_filt = alpha*raw_d + (1-alpha)*d_filt # сглаживание
prev = measured
print(f"{raw_d:7.2f} {d_filt:7.2f}")
print("фильтр сглаживает скачки, не давая D дёргать привод")Вывод:
сырая_D фильтр_D -0.26 -0.08 0.31 0.04 -0.17 -0.03 0.23 0.05 0.02 0.04 -0.56 -0.14 фильтр сглаживает скачки, не давая D дёргать привод
Другие схемы анти-windup
Мы показали простейший «clamping» — остановку интеграла в насыщении. Есть и более изящная схема — back-calculation (обратный пересчёт): когда привод насыщается, в интеграл подаётся корректирующий сигнал, пропорциональный разнице между требуемым и реально выданным воздействием, плавно «сдувающий» накопленное. Эта схема мягче и настраивается отдельным коэффициентом скорости разрядки. Ещё один практический приём — условное интегрирование: копить интеграл только когда ошибка и воздействие одного знака. Какую схему выбрать — зависит от задачи, но любой анти-windup почти всегда лучше его отсутствия. Это тот случай, когда простое решение (clamping) закрывает 90% проблем, а изысканные схемы добирают последние проценты для ответственных применений.
Частые ошибки
- ПИД без анти-windup на ограниченном приводе. Самая распространённая практическая ошибка; даёт большое перерегулирование на старте.
- Нефильтрованная D на шумном датчике. Привод дёргается, механика изнашивается; всегда фильтруйте производную.
- Забыть про derivative kick. Дифференцирование ошибки при скачке уставки даёт всплеск; берите D от измерения выхода.
Итоги
- Реальный привод насыщается; без анти-windup интеграл разбухает и даёт перерегулирование.
- Анти-windup (clamping) останавливает накопление интеграла в насыщении.
- D фильтруют от шума и берут от выхода, чтобы избежать derivative kick.