PDA

Просмотр полной версии : Пишем свой ПИД-регулатор



Keldish
15.10.2025, 12:28
Я думал тема ПИД регуляторов закрыта.
но снова вижу оживление.
придется написать свой (тем более я обещал еще в 20 году).
вот есть тема будем называть ее 1 частью Здесь (https://owen.ru/forum/showthread.php?t=34012)

итак начнем с маленьких шагов и сделаем большое дело.

ПИД регуляторы имею обширное применение от простейших термостатов до дронов (будь они не лады – последнее время) и 3Д принтеров.

почему ПИД -ПИД
Пропорциональный
Интегральный
Дифференциальный
регулятор

вычисляются эти три составляющие, суммируются и получаем итоговое воздействие на систему для достижения требуемого результата

Пропорциональная - Реагирует на текущую ошибку. Чем она больше, тем быстрее система, но слишком большое значение приводит к перерегулированию и колебаниям.

Интегральная - Накапливает прошлые ошибки. Позволяет устранить статическую ошибку (когда система стабилизируется не точно на уставке). Чрезмерное увеличение может вызвать "интегральное насыщение" и большие перерегулирования.

Дифференциальная - Предсказывает будущее поведение ошибки, учитывая скорость ее изменения. "Сглаживает" переходный процесс и помогает уменьшить перерегулирование. Чувствительна к шуму.

С теорией все, перейдем к практике
имеем
setpoint - уставку (то что мы хотим получить)
feedback – текущее значение (то что есть сейчас)
Коэффициенты Kp, Ki, Kd – это задаваемые нами значения которые задают пропорцию влияния каждого из расчетов на конечный результат (к ним мы вернемся позже)

вычисляем error – ошибку = setpoint – feedback
P - пропорциональная составляющая = error * Kp
I – интегральная составляющая = I_prev + error * Ki (тут I_prev это I сохраненное с предыдущего вызова макроса, при первом цикле = 0)
D – дифференциальная составляющая = Kd * (error – error_prev) (тут error_prev это error сохраненное с предыдущего вызова макроса, при первом цикле = 0)
Out - ну и наконец выход нашего блока = P+I+D

вот и готов наш первый ПИД-регулятор

вот его код на ST


function_block first_PID

var_input
setpoint: real;
feedback: real;
Kp: real;
Ki: real;
Kd: real;
end_var

var_output
Out : real;
end_var

var
error : real;
I_prev : real;
error_prev : real;
P : real;
I : real;
D : real;
end_var

error := setpoint - feedback;
P := error * Kp;
I := I_prev + (error * Ki);
// назовем это место в программе как (точка 1)
D := Kd * (error - error_prev);
Out := P+I+D;
// назовем это место в программе как (точка 2)

I_prev := I;
error_prev := error;

end_function_block

Но его практически не возможно использовать

когда измеренное значение будет рядом с заданным интегральная составляющая будет накапливаться для устранения ошибки и в какой то момент может стать очень большой и для обратного хода при изменений уставки или смене измеренного значения ей потребуется время для «смотки» назад, а нам нужен регулятор с быстрым реагированием.
по тому ограничим величину I максимальным и минимальным возможным значением выхода. Вставим в точку 1 – этот код

IF I > 1 then
I := 1;
elsif I < -1 then
I := -1;
end_IF

тоже самое с выходом расчитанное значение может превышать возможные значения на выходе и их нужно ограничить. Вставим в точку 2 – этот код

IF Out > 1 then
Out := 1;
elsif Out < -1 then
Out := -1;
end_IF

Или интегральную составляющую можно сохранять только если выход не перенасыщен. Вот новый код


function_block first_PID

var_input
setpoint: real;
feedback: real;
Kp: real;
Ki: real;
Kd: real;
end_var

var_output
Out : real;
end_var

var
error : real;
I_prev : real;
error_prev : real;
P : real;
I : real;
D : real;
output_saturated: bool;
end_var

error := setpoint - feedback;
P := error * Kp;
I := I_prev + (error * Ki);

D := kD * (error - error_prev);

Out := P+I+D;

IF Out > 1 then
Out := 1;
output_saturated := true;
elsif Out < -1 then
Out := -1;
output_saturated := true;
else
output_saturated := false;
end_IF

// назовем это место в программе как (точка 3)

if not output_saturated then
I_prev := I;
end_if;

error_prev := error;

end_function_block

он практически единетичен первому с внесенными правками. Но есть и отличия мы ограничиваем I только когда регулятор не может повлиять на установку из за физических ограничений не смотря на максимальный выход (например отапливание 100 ватной лампочкой комнаты в 30 м2)

Вот это уже вполне правильный и рабочий вариант.

Сейчас выходной сигнал у нас в диапазоне -1…1. Давайте приведем его в диапазон 0..100(%), для этого вставим в точку 3 следующий код Out := (Out+1) * 50;
Хотя это спорный вопрос
выход -1…1 (симетричный диапазон) удобен для управления двигателями (вперед/назад) и реверсивными приводами
выход 0..100 для насосов, вентиляторов, нагревателей

Я не думаю что ограничение диапазона нужно вносить в сам регулятор, но приведем НАШ регулятор в соответствие с библиотечным и добавим параметры «Минимальная мощность» и «Максимальная мощность».
Вот итоговый код:


function_block first_PID

var_input
setpoint: real;
feedback: real;
Kp: real;
Ki: real;
Kd: real;
min_P: real;
max_P: real;
end_var

var_output
Out : real;
end_var

var
error : real;
I_prev : real;
error_prev : real;
P : real;
I : real;
D : real;
output_saturated: bool;
end_var

error := setpoint - feedback;
P := error * Kp;
I := I_prev + (error * Ki);
D := Kd * (error - error_prev);

Out := P+I+D;

IF Out > 1 then
Out := 1;
output_saturated := true;
elsif Out < -1 then
Out := -1;
output_saturated := true;
else
output_saturated := false;
end_IF

Out := (Out+1) * 50;

IF Out > max_P then Out := max_P; elsif Out < min_P then Out := min_P; end_IF

if not output_saturated then I_prev := I; end_if;

error_prev := error;

end_function_block

а вот разрешение работы или «Ручной режим», что по моему одно и тоже лучше внести в регулятор.
Сразу приведу итоговый код (в нем я отказался от последних изменений, уже говорил что по моему им здесь не место, и далее приведем более красивое решение)


function_block first_PID

var_input
setpoint: real;
feedback: real;
Kp: real;
Ki: real;
Kd: real;
EN_manual: bool;
Set_manual: real;
end_var

var_output
Out : real;
end_var

var
error : real;
I_prev : real;
error_prev : real;
P : real;
I : real;
D : real;
output_saturated: bool;
raw_output: real;
end_var

IF EN_manual THEN
raw_output := Set_manual;
I_prev := Set_manual;
error_prev := setpoint - feedback;
ELSE
error := setpoint - feedback;
P := error * Kp;
I := I_prev + (error * Ki);
D := Kd * (error - error_prev);

raw_output := P+I+D;

IF raw_output > 1 then
raw_output := 1;
output_saturated := true;
elsif raw_output< -1 then
raw_output := -1;
output_saturated := true;
else
output_saturated := false;
end_IF

if not output_saturated then I_prev := I; end_if;

error_prev := error;
end_IF

Out := (raw_output+1) * 50;

end_function_block

здесь в ручном режиме мы сохраняем старую ошибку для дифференциальной составляющей и интегральную составляющую делаем равной ручному заданию для плавного подхвата регулятором при выходе из ручного режима.
подхват можно сделать и еще более плавным заменив строку
I_prev := Set_manual; на I_prev := Set_manual - (error * Kp);


Эти входы можно использовать и как в библиотечном регуляторе задать жесткое значение выхода при отключенном регуляторе в Set_manual и включать/выключать регулирование через инверсию EN_manual.

Все это уже идеальный регулятор, который достаточен для большинства применений.

Далее ограничение выхода минимальной и максимальной мощностью рекомендую делать отдельным блоком на выходе регулятора.

В следующий раз напишем блок «Надзиратель» для этого регулятора он будет осуществлять авто настройку коэффициентов.

AlexCrane
16.10.2025, 10:46
В следующий раз напишем блок «Надзиратель» для этого регулятора он будет осуществлять авто настройку коэффициентов.

Через 5 лет?

kondor3000
16.10.2025, 15:26
Сначала надо довести ФБ до ума. 86235
Проверил последние 2 варианта в эмуляции, задача всех коэффициентов по 1, мгновенно отправляет ПИД в 0 или в максимум.
Боле менее реально работает, с задачей их от 0.001 до 0.01, спрашивается зачем так сделано? Как их вообще подобрать можно?
Вариант с Max и Min тоже нормально не работает, ставишь Max=10 или 1, выход перестаёт реагировать вообще.
Похоже автор вообще не тестировал свои ФБ, даже в эмуляции, не говоря про реальный объект.

Евгений Зубков
16.10.2025, 16:59
Коэффициенты приходится делать мизерными, потому что в коде нет учета времени цикла (dt). Без него интеграл на каждом такте прибавляет всю ошибку целиком и мгновенно улетает в насыщение. А Min/Max не работает, потому что логика защиты от насыщения не видит этих ограничений. Интеграл продолжает копиться, думая, что выход свободен, хотя он уже уперся в лимит. В итоге регулятор просто "залипает".

Еще без хотя бы простого сглаживания D-ветвь превращается в помехоусилитель. Плюс нет зоны нечувствительности, регулятор будет гонять исполнительный механизм даже при ошибке в сотые доли, пытаясь «допилить до идеала». Это красиво на графике, но убивает механику. Ну и форма с Ki/Kd это боль для настройки. Без Ti/Td (в секундах) ни один нормальный метод автоподбора не применим.

FPavel
16.10.2025, 18:19
Скажу в защиту Ki и Kd - дело в том, применение в форме Ti и Td не совсем отражает, что это не параметры времени - это именно коэффициенты, т.к. они сразу учитывают единицы измерения и диапазон измерений регулируемой величины. Поэтому - это действительно - коэффициенты.
И для автонастройки, наверное, возможно выполнить пересчёт коэффициентов Ti=1/Ki.

И для корректной работы интегральной - нужно считать по формуле I := I_prev + (error * Ki * TCycle), где TCycle - время прошедшее от предыдущего вычисления.
Или выполнять пересчёт строго по таймеру через заданные промежутки времени - и при этом в формуле также учитывать это время.

Евгений Зубков
16.10.2025, 19:27
Скажу в защиту Ki и Kd - дело в том, применение в форме Ti и Td не совсем отражает, что это не параметры времени - это именно коэффициенты, т.к. они сразу учитывают единицы измерения и диапазон измерений регулируемой величины. Поэтому - это действительно - коэффициенты.
И для автонастройки, наверное, возможно выполнить пересчёт коэффициентов Ti=1/Ki.

И для корректной работы интегральной - нужно считать по формуле I := I_prev + (error * Ki * TCycle), где TCycle - время прошедшее от предыдущего вычисления.
Или выполнять пересчёт строго по таймеру через заданные промежутки времени - и при этом в формуле также учитывать это время.

Интересный, свежий взгляд на классику. Ваше наблюдение, что «время интегрирования» по сути не является временем, открывает простор для новой, более образной терминологии. Вероятно, и «время дифференцирования» стоит называть «коэффициентом предчувствия ошибки», чтобы не вводить инженеров в заблуждение простыми физическими величинами.

Формула Ti=1/Ki также весьма элегантна в своей простоте. Правда, не совсем понятно, что же в этой изящной концепции сталось с пропавшим пропорциональным коэффициентом Kp, но, возможно, это деталь для менее продвинутых пользователей.

И отдельное спасибо, что акцентировали внимание на необходимости учета времени цикла. Это действительно ключевой момент, с которого, собственно, и началось сообщение выше.

FPavel
16.10.2025, 20:08
Интересный, свежий взгляд на классику. Ваше наблюдение, что «время интегрирования» по сути не является временем, открывает простор для новой, более образной терминологии. Вероятно, и «время дифференцирования» стоит называть «коэффициентом предчувствия ошибки», чтобы не вводить инженеров в заблуждение простыми физическими величинами.
Просто, исходя из формулы
OUT=error*Kp + error*(1/Ti)*TCycle + DeltaError*Td/TCycle
видно, что размерность слагаемых
[%]=[EU]*[1] + [EU]/[c]*[c] + [EU]*[c]/[c]
[%]=[EU] + [EU] + [EU]
что явно противоречит смыслу
А значит все параметры ПИД регулятора зависят и от единиц измерения и от их диапазона, т.е. не являются какими либо временами, а лишь коэффициентами с размерностями и времени в том числе.

Можно сделать эмуляцию ПИД регулятора объекта управления (на основе звена 1-порядка) и сделать два эксперимента - у объекта управления коэффициент умножения 4000 и 0,4 - при смене коэффициента поплывут все настройки - и K и Ti и Td.
Для OwenLogic как-то делал такой эмулятор
https://owen.ru/forum/showthread.php?t=25068&p=447749&viewfull=1#post447749

Евгений Зубков
17.10.2025, 09:54
Просто, исходя из формулы
OUT=error*Kp + error*(1/Ti)*TCycle + DeltaError*Td/TCycle
видно, что размерность слагаемых
[%]=[EU]*[1] + [EU]/[c]*[c] + [EU]*[c]/[c]
[%]=[EU] + [EU] + [EU]
что явно противоречит смыслу
А значит все параметры ПИД регулятора зависят и от единиц измерения и от их диапазона, т.е. не являются какими либо временами, а лишь коэффициентами с размерностями и времени в том числе.

Можно сделать эмуляцию ПИД регулятора объекта управления (на основе звена 1-порядка) и сделать два эксперимента - у объекта управления коэффициент умножения 4000 и 0,4 - при смене коэффициента поплывут все настройки - и K и Ti и Td.
Для OwenLogic как-то делал такой эмулятор
https://owen.ru/forum/showthread.php?t=25068&p=447749&viewfull=1#post447749


У вас при разборе формулы у интегральной и дифференциальной частей по дороге потерялся общий множитель Kp. В классической форме весь ПИД в скобках умножается на Kp, а Ti и Td это реальные времена в секундах. В параллельной форме они связаны как Ki = Kp / Ti и Kd = Kp * Td, поэтому с размерностями там все в порядке: именно Kp отвечает за перевод ошибки из [EU] в [%].

Ваш эксперимент с усилением объекта 4000 и 0.4, хороший пример того, почему Ti и Td не должны меняться. Вы изменили усиление объекта (Ko), а не его динамику. Усиление определяет, насколько сильно объект реагирует, а динамика - как быстро. Когда меняется Ko, нужно подправить Kp (чтобы не сорвать устойчивость), но времена Ti и Td, отражающие инерционность системы, должны остаться теми же. Физика у объекта не поменялась, он не стал нагреваться или остывать быстрее.

Если при этом «плывут» все три параметра, это значит, где-то уже смешались разные формы записи. Ki/Kd в вашей реализации, вероятно, уже содержат Kp и/или не учитывают dt. Отсюда и эффект.

Ваш эмулятор, кстати, отличная идея, как раз помогает увидеть, почему важно разделять статическую настройку (Kp) и динамическую (Ti, Td). Когда это сделано корректно, секунды остаются секундами, а ПИД - ПИДом, а не «коэффициентом философского времени» :)

FPavel
17.10.2025, 18:37
В классической форме весь ПИД в скобках умножается на Kp, а Ti и Td это реальные времена в секундах.
К сожалению, живу и работаю в несовершенном мире, где даже Ваши классические коллеги реализуют неклассические встроенные ПИД регуляторы для ПР в Owen Logic - среди них нет ни одного классического.
Если не затруднит - Вы уж их (коллег) приведите в классическую форму! Научите ПИД любить!

Dimensy
17.10.2025, 20:09
К сожалению, живу и работаю в несовершенном мире, где даже Ваши классические коллеги реализуют неклассические встроенные ПИД регуляторы для ПР в Owen Logic - среди них нет ни одного классического.
Если не затруднит - Вы уж их (коллег) приведите в классическую форму! Научите ПИД любить!

А это разве не классический ПИД?
86250

FPavel
17.10.2025, 20:43
А это разве не классический ПИД?
Увы мне!

Пользовался только из компонентов - для переносимости между разными поколениями ПР - и думал, что и встроенные на том же принципе... Не перепроверил!

Уйду в монастырь!

P.S. А как устроен PID для приборов первого поколения?

P.P.S. А параметры-то в справке называют коэффициентами... Видимо, что-то подозревают...

Dimensy
17.10.2025, 20:50
P.S. А как устроен PID для приборов первого поколения?


Ну, это легко проверить, натравив оба ПИДа на ваш эмулятор

FPavel
17.10.2025, 21:09
Справедливости ради - идею эмулятора я подрезал из руководства по программированию известной фирмы.

Сейчас уже не очень ясно соображаю, поэтому ничего предпринимать не буду. А завтра попробую тестовые проекты для ПР200 и ПР205 - по сообщениям встроенные ПИД работают в симуляторе без реального железа. Наверное, настала пора учиться. Тем более, что эти ПИД можно оборачивать в макросы (в компонентах такие макросы лежат), т.е. получить сразу макрос ПИД с режимами "сна", заполнения трубопроводов на пониженной скорости, рампой уставки и прочими удобствами.

Валенок
17.10.2025, 22:08
На эмуляциях имеет смысл пропустить выход пида ещё и через эмулятор исполнительного устройства (ИУ). Именно через ИУ производится воздействие на обьект регулирования. А получить разнонаправленное изменения выхода пида и ИУ как нефиг делать.
Имхо, лучше изначально встроить какой то вид ограничителей как итоговой суммы, так и скорости изменения выхода ПИДа динамически корректирующих И-часть. Частично это реализовано в КДС/util/ПИД

FPavel
18.10.2025, 10:24
На эмуляциях имеет смысл пропустить выход пида ещё и через эмулятор исполнительного устройства (ИУ). Именно через ИУ производится воздействие на обьект регулирования. А получить разнонаправленное изменения выхода пида и ИУ как нефиг делать.
Да, так и хочу поступить - по ссылке именно такой эмулятор объекта управления (исполнительного устройства).

Имхо, лучше изначально встроить какой то вид ограничителей как итоговой суммы, так и скорости изменения выхода ПИДа динамически корректирующих И-часть. Частично это реализовано в КДС/util/ПИД
Предлагаемый ПИД, встроенный во 2-поколение ПР - имеет ограничитель скорости уставки. При необходимости на выход ПИД можно самостоятельно добавить самодельный ограничитель скорости.
Хотя, возможно, что встроенный изначально в сам регулятор, не просто ограничивает выход, а ограничивает само интегральное слагаемое - нужно смотреть исходники в CDS.

FPavel
18.10.2025, 12:45
А это разве не классический ПИД?

Увы мне!

По результатам эксперимента
https://owen.ru/forum/showthread.php?t=42055
выяснилось, что по крайней мере при симуляции Owen Logic 2.11.369.0 - формула из справки ошибочна и используется прямая, а не обратная зависимость выхода от Xp, и, возможно, всю формулу из справки нужно ставить под сомнение - там "неклассическое" параллельное вычисление слагаемых.

Dimensy
18.10.2025, 13:15
По результатам эксперимента
https://owen.ru/forum/showthread.php?t=42055
выяснилось, что по крайней мере при симуляции Owen Logic 2.11.369.0 - формула из справки ошибочна и используется прямая, а не обратная зависимость выхода от Xp, и, возможно, всю формулу из справки нужно ставить под сомнение - там "неклассическое" параллельное вычисление слагаемых.
Ну, Ti - это точно постоянная времени и она умножается на пропорциональный коэффициент, потому что, при значении, например, 10, ПИД через 10 секунд удвоит значение на выходе. Думаю, и с Td та же ситуация будет

FPavel
18.10.2025, 13:34
Спасибо.

Отправил вопрос в техподдержку, скоро исправят ошибку или в формуле или в симуляторе - т.к. на железе проверить нет возможности.

По большому счёту, безразлично, как реализована формула - Xp или Kp, зависимые или независимые Ti и Td.
Достаточно точного описания в справке, чтобы при ПНР не заниматься исследовательской работой по реверс-инжинирингу чужих ФБ с закрытым исходным кодом.

Валенок
18.10.2025, 13:50
...по ссылке именно такой эмулятор объекта управления (исполнительного устройства).
.
Вроде не.
(ну и закритиковал бы, но со своей колокольни)


..- имеет ограничитель скорости уставки..
Это зачем?


При необходимости на выход ПИД можно самостоятельно добавить самодельный ограничитель скорости..
Да, но с коррекцией И-части


...
Хотя, возможно, что встроенный изначально в сам регулятор, не просто ограничивает выход, а ограничивает само интегральное слагаемое - нужно смотреть исходники в CDS.
Местный (ОЛ) исходник не смотрел (а он тут есть?). В КДСный ограничивает только лимиты, а не скорость. Т.е. ближе к классике на шкале "эльфийская классика* ... жизнь".

*Это у ТС. Оторванный напрочь.

FPavel
18.10.2025, 14:23
Вроде не.
(ну и закритиковал бы, но со своей колокольни)
Критикуйте, хуже не будет. В крайнем случае скажу "ВыНеПонимаете - ЭтоДругое, У_МеняВсёРаботает" ))))

Там макрос эмуляции объекта управления для проверки самодельных регуляторов, т.к. не всегда есть возможность собрать аппаратный макет для проверки.
Увидел в описании идею и на скорую руку реализовал.

При работе с какой-то старой библиотекой ПрософтСистемы (наверное, PsBase) видел подобный эмулятор - назывался эмулятором клапана или похожим образом. Сейчас этот ФБ уже исключён из библиотеки и даже описания не найти. Думаю, что существуют подобные ФБ и у других производителей.
Может быть по подобию Вы называете такие ФБ эмуляторами ИУ?



Это зачем?
Не знаю, видел в справке к ФБ. Иногда, востребовано - при штатном изменении уставки ограничивают скорость.


Да, но с коррекцией И-части
В реализации для Koyo DirectLogic встречал ограничение И-части в виде "заморозка И-части при переполнении выхода" - когда выход (П+И+Д) превышал 100%, он ограничивался 100% и пересчёт И не производился.


Местный (ОЛ) исходник не смотрел (а он тут есть?). В КДСный ограничивает только лимиты, а не скорость. Т.е. ближе к классике на шкале "эльфийская классика* ... жизнь".

*Это у ТС. Оторванный напрочь.
Нет, исходника ПИД от встроенного в прошивку ПР - нет, только описание.
Впрочем, и в Codesys есть такие закрытые библиотеки для ФБ, реализованных в прошивках - те же ПИД регуляторы из PID_Regulators.lib

Валенок
19.10.2025, 12:01
Критикуйте, хуже не будет. В крайнем случае скажу "ВыНеПонимаете - ЭтоДругое, У_МеняВсёРаботает" ))))да?

///<Description>Эмулятор объекта управления. Эмулируется последовательное соединение трёх апериодических звеньев 1-го порядка.</Description>
///<Author>!!FPA!!</Author>
///<GroupName>Управляющие и регулирующие модули</GroupName>

function_block Emulator_Cont_ST_

var_input
///<Description>Перезапуск работы блока (инициализация всех переменных состояния) по фронту</Description>
xReset: bool := false;
///<Description>Входная переменная. Управляющий сигнал с ПИД</Description>
rVLV_Pos: real;
///<Description>Внешнее возмущающее воздействие (суммируется с rVLV_Pos для вычислений внутри ФБ)</Description>
rDisturbance: REAL;
///<Description>Значение выхода при rVLV_Pos=0</Description>
rPV_0: REAL:=20.0;
///<Description>Коэффициент передачи объекта управления (трёх последовательных апериодических звеньев 1-го порядка)</Description>
rGain: REAL:=1.5;
///<Description>Постоянная времени первого апериодического звена 1-го порядка, [мс]</Description>
dwTime_T1: udint:=60000;
///<Description>Постоянная времени второго апериодического звена 1-го порядка, [мс]</Description>
dwTime_T2: udint:=10000;
///<Description>Постоянная времени третьего апериодического звена 1-го порядка, [мс]</Description>
dwTime_T3: udint:=0;
end_var

вот вообще смотрю и не пойму. Даже пиво поставил и очки взял.

//GroupName: Управляющие и регулирующие модули
//Эмулятор объекта управления (ОУ)
//Последовательное соединение апериодических звеньев (АЗ) 1-го порядка
//Author: !!FPA!!
function_block Emulator_Cont_ST_

var_input
xReset: bool := false; //Перезапуск. Инициализация всех состояний по фронту
rVLV_Pos: real; //Управляющий сигнал с ПИД
rDisturbance: REAL; //Возмущающее воздействие (суммируется с rVLV_Pos)
rPV_0: REAL:=20.0; //Значение выхода при rVLV_Pos=0. 0 - норм сигнал же?
rGain: REAL:=1.5; //Коэффициент передачи ОУ для АЗ-1..3
dwTime_T1: udint:=60000; //Постоянная времени АЗ-1, [мс]
dwTime_T2: udint:=10000; //... АЗ-2, [мс]
dwTime_T3: udint:=0; //... АЗ-3, [мс]
end_var

стал воспринимать)) но не всё понимать



ПИД.выход -> rVLV_Pos
...
rPV_Inner := (rVLV_Pos + rDisturbance) * rGain;
... rPV_Inner := ...
rPV := rPV_0 + rPV_Inner;
rPV -> обр.связь.ПИД
rPV может и эмулятор объекта управления (ОУ), ну вот ни разу не эмулятор ИУ* которое:

ПИД.выход -> хотелка_Pos.ИУ.rVLV_Pos -> воздействие.ОУ.rPV -> обр.связь.ПИД
и которое имеет 3 состояния :
1.Не крутится.
2.Крутится со скоростью const A
3.Крутится со скоростью const B (которое часто просто = -A)

*Достаточо часто встречающихся



Не знаю, видел в справке к ФБ. Иногда, востребовано - при штатном изменении уставки ограничивают скорость.
Если нужное встроено в ПИД на уровне динамической коррекции И-части то не нужно.



В реализации для Koyo DirectLogic встречал ограничение И-части в виде "заморозка И-части при переполнении выхода" - когда выход (П+И+Д) превышал 100%, он ограничивался 100% и пересчёт И не производился.
Допускаю что это описание чуть-чуть неверное, по факту примерно так:
И-часть пересчитывается всегда, чтобы выход ПИДа не выходил за края.
Если же как описано, то для меня это - в корзину.


Нет, исходника ПИД от встроенного в прошивку ПР - нет, только описание.
Жаль. То же справочное описание замечательного КДС/util/PID не совсем соответствует реальности примерно так же.


закрытые библиотеки для ФБ, реализованных в прошивках
Как для меня это странно. Что в ПИД секретного? И что в матформуле может быть привязано к прошивке?
Поэтому тоже всегда сам ПИД делаю - не доверяю и свои хотелки реализую.
И тоже предпочитаю Kp,Ki,Kd ))


...Или выполнять пересчёт строго по таймеру через заданные промежутки времени..
Вот это - "строго" и это - "по таймеру" тоже странное в общем случае, хотя сами же подсказали

...время прошедшее от предыдущего вычисления..
Место вычисления только не подсказали))

FPavel
19.10.2025, 17:56
Я не очень хорошо описал эмулятор.

На вход rGain поступает значение выхода аналогового ПИД регулятора в [%], т.е. число от 0 до 100.
Т.к. что одно, что три последовательных звена 1-го порядка это всего лишь усилитель с множителем rGain и некоторой задержкой, то выход в установившемся режиме будет равен
rPV := rVLV_Pos * rGain
т.е. от 0 до 100*rGain
Но при закрытой задвижке (при rVLV_Pos=0%) возможно, что выход не должен быть равным 0, например, равен rPV_0.
В итоге, получается в установившемся режиме значение выхода
rPV := rVLV_Pos * rGain + rPV_0
Поэтому и такой комментарий к параметру rPV_0 - значение выхода rPV при нулевом значении входа rVLV_Pos=0.

Всякие ///<Description> - это теги документирования - если поместить ФБ в библиотеку Owen Logic, то описание будет выведено в виде таблицы.

rPV может и эмулятор объекта управления (ОУ), ну вот ни разу не эмулятор ИУ* которое:
Да, так и есть - для проверки работы ПИД регулятора и его автонастройки, полезнее получить значение переменной процесса, чем состояние (скорость и направление перемещения) привода.

Вот это - "строго" и это - "по таймеру" тоже странное в общем случае, хотя сами же подсказали
По таймеру - это обычная практика:
- Это примерный эквивалент задачи с периодическим вызовом в Codesys - именно в такую задачу и рекомендуют помещать ФБ ПИД
- ТРМ12, ТРМ32 работают с периодическим пересчётом значения выхода.

Место вычисления только не подсказали))
С Owen Logic всё непросто - для FBD и ST способы определения длительности прошедшего цикла неравнозначны и для ST даёт точный результат, а для FBD - условно точный.
Поэтому для FBD удобнее выполнять пересчёт периодически по таймеру.
А для ST есть возможность в начале программы добавить строки

// вычисление длительности предыдущего цикла
dwCurrent := time_to_udint(get_time()); //текущее время
dwCycle := dwCurrent - dwPrevious; //длительность прошедшего цикла
dwPrevious := dwCurrent;

Валенок
19.10.2025, 19:29
На вход rGain поступает значение выхода аналогового ПИД регулятора в [%], т.е. число от 0 до 100.
На вход rGain у Вас - константа
выход ПИДа у Вас - на rVLV_pos


Да, так и есть - для проверки работы ПИД регулятора и его автонастройки, полезнее получить значение переменной процесса, чем состояние (скорость и направление перемещения) привода.
А толку от такого ПИДа если (например) его выход уже падает, а воздействие (через ИУ) спокойно растет?


По таймеру - это обычная практика:
Так себе практика


С Owen Logic всё непросто - для FBD и ST
FBD/ST - без разницы для определения времени. ПИД, если это ПИД (а я незнаю - закрыто же) сам определяет dt. Вот то, что в ОЛ.FBD нет EN - действительно плохо.


А для ST есть возможность в начале программы добавить строки
Не о этом речь. Место вычисления определяющее необходимость расчета ПИДом - не ПИД)) Особенно актуально для КДС

FPavel
19.10.2025, 21:37
На вход rGain у Вас - константа
выход ПИДа у Вас - на rVLV_pos
Да, опечатался. Конечно же rVLV_pos - выход ПИД и вход в эмулятор объекта.


А толку от такого ПИДа если (например) его выход уже падает, а воздействие (через ИУ) спокойно растет?
Паровой котёл: и после резкого снижения расхода газа некоторое время рост давления пара продолжится.
Инерция температуры перегретого пара такова, что после 100% перемещения клапана подачи воды в пароперегреватель ещё минут 15 не будет изменения направления графика температуры.
Разрежение в топке котла изменяется через 5-15 секунд после изменения скорости дымососа.

Так что эмуляция инерции - то, что требуется для проверки регулятора.


Так себе практика
Если назвать - ФБ ПИД вызывается в периодической задаче с периодом 500 мс, то это будет эквивалентом вызова по таймеру в реалиях Owen Logic.


FBD/ST - без разницы для определения времени. ПИД, если это ПИД (а я незнаю - закрыто же) сам определяет dt. Вот то, что в ОЛ.FBD нет EN - действительно плохо.
Мы же говорим об Owen Logic - если пересчёт выхода по таймеру, то время это один из входных параметров и его можно использовать при расчётах.
Встроенный ПИД не имеет такого параметра - значит предположительно вычисляет время между вызовами.


Не о этом речь. Место вычисления определяющее необходимость расчета ПИДом - не ПИД)) Особенно актуально для КДС
OL - не имеет средств планирования вызова задач. А в Codesys - наверное, можно определить время между вызовами.