Поделюсь макросом ПИ (урезанный ПИД) регулятора для привода с 3-позиционным управлением без обратной связи по положению.

Проверил его на одном объекте - регулировка температуры подачи теплосети при помощи смесительного клапана после гидравлического разделителя.
Т.е. процесс инерционный, время полного хода привода 60 с.

Понадобился такой, а на форуме предлагают или "аналоговый" ПИД с управлением по псевдо-обратной связи от математической модели привода или выход "аналогового" регулятора перерабатывают в ШИМ.

По формуле из РЭ ТРМ12 получил приращение выхода на каждом шаге пересчёта регулятора
dY.PNG
Физический смысл приращения - доля (-1,0...+1,0) от времени полного хода для перемещения привода с учётом направления.
Tm - время пересчёта регулятора

При каждом пересчёте обновляю также и расчётное положение привода, т.е. суммирую перемещения
SY.PNG

Сразу же ограничиваю "взвинчивание интегральной составляющей" значением в 20%, т.е. диапазоном (-1,2...+1,2). Этот параметр не выводил ко входам, а задал константой.

Для "отключения" интегральной, достаточно сделать время интегрирования менее 0,001, т.е. приравнять к 0.

алгоритм:
Преобразование в перемещение привода сделал по алгоритму со следующей аналогией:
- в момент пересчёта регулятора мгновенно заряжается конденсатор
- когда заряд на конденсаторе превысит значение пропорциональное минимальному импульсу, включается триггер начала (разрешения) перемещения
- конденсатор начинает разряжаться пропорционально времени полного хода
- останов и сброс триггера происходят при полном разряде конденсатора

В самой программе это дополнено свойствами
- перемещение не может остановиться до истечения времени минимального импульса - как бы за это время не изменилось расчётое положение
- пока производится перемещение привода работает тактовый генератор (с периодом 0,100 с), расчётное значение корректируется на величину, пропорциональную доле этого периода ко времени полного хода
- останов и сброс триггера происходят при уменьшении расчётного положения менее доли одного такта (0,100 с) по отношению ко времени полного хода.

Также добавлено ограничение на паузу после реверса.

Кроме того, ввёл диагностику, останавливающую вычисления и выводящую сигнализацию на выход ФБ при некорректных входных параметрах.
Наверняка, можно расширить список проверок.

Входные параметры:
fPV — переменная процесса (process variable);
fSP — уставка (задание) процесса (setpoint);
fDeadBand — зона нечувствительности (dead band) - в каждую сторону, т.е. в итоге вся зона в два раза больше;
fKp — коэффициент пропорциональности, значение полосы пропорциональности Xp=1/Kp равно величине невязки (рассогласования) при котором регулятор сформирует импульс длительностью равный времени полного хода привода;
fTi — время интегрирования;
nTRecalc_[ms] — период пересчёта (квантования) значения выхода регулятора,
nTFullStroke_[ms] — время полного хода (full stroke);
nTPulseMin_[ms] — длительность минимального импульса;
nTPauseReverse_[ms] — минимальная длительность паузы между командами реверса;
bEnable - разрешение работы регулятора (при запрете не только останов, но и сброс накопленной интегральной составляющей)
bReset - задумывал, как установку "интегральной" в заданное со входа значение, но не реализовал, поэтому получил второй вход bEnablr, но инверсный

Выходные параметры:
bOpen - команда на привод "открыть" регулирующий орган;
bClose - команда на привод "закрыть" регулирующий орган;
bError - ошибка введённых параметров, вычисления остановлены.

Ошибка введённых параметров для случаев:
1. nTRecalc_[ms] < 1000 мс
2. nTPulseMin_[ms] < 200 мс
3. nTFullStroke_[ms] < 1000 мс

Для зоны нечувствительности покажу изображением
DB.PNG

test_PID_3pos.owle