Непрерывный регулятор CONT_C (FB41) стандартный блок ПИД регулятора Siemens
Дата: 2009-04-28
Добавлено: komatic
Тема: PIDcontrol
В этом материале рассмотрим стандартный блок ПИД регулятора Siemens (CONT_C)
Лучшая документация к программному блоку - ее исходный текст.
Скомпилированный блок идентичен оригинальному.
Документация по функции:
english - download .pdf 0.3Мб
русская - скачать .pdf 0.3Мб
FUNCTION_BLOCK FB41
TITLE =
AUTHOR : SIMATIC
FAMILY : ICONT
NAME : CONT_C
VERSION : " 1.5"
//reversed by komatic
VAR_INPUT
COM_RST : BOOL ; //
MAN_ON : BOOL :=
PVPER_ON : BOOL ; //Чтение входной переменной с периферии включить
P_SEL : BOOL
I_SEL : BOOL
INT_HOLD : BOOL ; //Удержание интегральной составляющей
I_ITL_ON : BOOL ; //Инициализировать интегральную составляющую
D_SEL : BOOL ;
CYCLE : TIME
SP_INT : REAL ; //Внутреннее задание
PV_IN : REAL ; //Входная переменная
PV_PER : WORD ; //Входная переменная (периферия)
MAN : REAL ; //Ручной выход
GAIN : REAL
TI : TIME
TD : TIME
TM_LAG : TIME
DEADB_W : REAL ; //Ширина зоны нечувствительности
LMN_HLM : REAL
LMN_LLM : REAL ; //Нижний предел выходного сигнала
PV_FAC : REAL
PV_OFF : REAL ; //Коэффициент для корректировки входной переменной (сложение)
LMN_FAC : REAL
LMN_OFF : REAL ; //Коэффициент для корректировки входной переменной (сложение)
I_ITLVAL : REAL ; //Начальное значение интегральной составляющей
DISV : REAL ; //Возмущающая переменная
END_VAR
VAR_OUTPUT
LMN : REAL ; //Выходное значение
LMN_PER : WORD ; //Выходное значение (переферия)
QLMN_HLM : BOOL ; //Верхний предел выхода достигнут
QLMN_LLM : BOOL ; //Нижний предел выхода достигнут
LMN_P : REAL ; //Пропорциональная составляющая
LMN_I : REAL ; //Интегральная составляющая
LMN_D : REAL ; //Дифференциальная составляющая
PV : REAL ; //Входная переменная
ER : REAL ; //Сигнал рассогласования
END_VAR
VAR
sInvAlt : REAL ;
sIanteilAlt : REAL ;
sRestInt : REAL ;
sRestDif : REAL ;
sRueck : REAL ;
sLmn : REAL ;
sbArwHLmOn : BOOL ; //Выход достиг максимального значения
sbArwLLmOn : BOOL ; //Выход достиг минимального значения
sbILimOn : BOOL :=
END_VAR
VAR_TEMP
Hvar : REAL ; //Hilfsvariable
rCycle : REAL ; //Abtastzeit in real
Diff : REAL ; //
Istwert : REAL ; //Istwert
ErKp : REAL ; //
rTi : REAL ; //Integrationszeit in real
rTd : REAL ; //Differentiationszeit in real
rTmLag : REAL ; //Verz
Panteil : REAL ; //P-Anteil
Ianteil : REAL ; //I-Anteil
Danteil : REAL ; //D-Anteil
Verstaerk : REAL ; //Verst
RueckDiff : REAL ; //Differenz des R
RueckAlt : REAL ; //Alter R
dLmn : REAL ; //Stellwert
gf : REAL ; //Hilfwert
rVal : REAL ; //Real Hilfsvariable
END_VAR
BEGIN
IF COM_RST //
THEN
//
sIanteilAlt:=I_ITLVAL;
LMN
QLMN_HLM:=0; //Верхний предел выхода достигнут
QLMN_LLM:=0; //Нижний предел выхода достигнут
LMN_P:=0.0; //Пропорциональная составляющая
LMN_I:=0.0; //Интегральная составляющая
LMN_D:=0.0; //Дифференциальная составляющая
LMN_PER:=0; //Выходное значение (периферия)
PV:=0.0; //Входная переменная
ER:=0.0; //Сигнал рассогласования
sInvAlt
sRestInt:=
sRestDif:=
sRueck:=
sLmn:=
sbArwHLmOn:=
sbArwLLmOn:=
ELSE
rCycle:=
Istwert
Istwert:=Istwert * PV_FAC + PV_OFF;
IF NOT PVPER_ON THEN Istwert
PV:= Istwert;
ErKp:=SP_INT - PV; // Получили рассогласование между заданием и входом
IF ErKp < (-DEADB_W) THEN ER:=ErKp+DEADB_W; // Если рассогласование больше зоны нечувствительности
ELSIF ErKp > DEADB_W THEN ER
ELSE ER
END_IF;
ErKp:=ER * GAIN; // Рассогласование, умноженное на кфт пропорциональности
rTi
rTd:=
rTmLag:=
// Проверка на допустимость временных настроек регулятора
IF rTi < (rCycle
IF rTd
IF rTmLag
// Вычисление пропорциональной составляющей
IF P_SEL
THEN
Panteil:=ErKp; // Если выбрана пропорциональная составляющая
ELSE
Panteil:=0.0;
END_IF;
//---------------------------------------------------------------------------------------------
// Вычисление интегральной составляющей
//---------------------------------------------------------------------------------------------
IF I_SEL
THEN
IF I_ITL_ON
THEN
Ianteil:=I_ITLVAL;
sRestInt:=
ELSE
IF MAN_ON //
THEN
Ianteil:=sLmn - Panteil - DISV;
sRestInt:=
ELSE //Автоматический
Diff:=rCycle / rTi *(ErKp
IF ((Diff>0.0) AND sbArwHLmOn OR INT_HOLD)OR ((Diff<
Ianteil:=sIanteilAlt + Diff;
sRestInt:=sIanteilAlt - Ianteil + Diff;
END_IF;
END_IF;
ELSE
Ianteil:=
sRestInt:=
END_IF;
//---------------------------------------------------------------------------------------------
//Формирование дифференциальной составляющей
//---------------------------------------------------------------------------------------------
Diff:=ErKp;
IF (
THEN
Verstaerk:= rTd
Danteil:= (Diff
RueckAlt:= sRueck;
RueckDiff:= rCycle
sRueck:= RueckDiff
sRestDif:=RueckAlt
ELSE
Danteil:=
sRestDif:=
sRueck:=Diff;
END_IF;
//---------------------------------------------------------------------------------------------
//
//---------------------------------------------------------------------------------------------
dLmn:=Panteil
IF MAN_ON // Если ручной режим
THEN
dLmn:=MAN;
ELSE
IF (
THEN
IF (Ianteil > (LMN_HLM - DISV)) AND (dLmn
THEN
rVal:=LMN_HLM - DISV;
gf:= dLmn
rVal:=Ianteil - rVal;
IF rVal > gf THEN rVal:=gf; END_IF;
Ianteil:=Ianteil - rVal;
ELSE
IF (Ianteil < (LMN_LLM - DISV)) AND (dLmn
THEN
rVal:=LMN_LLM - DISV;
gf:=dLmn - LMN_LLM;
rVal:=Ianteil - rVal;
IF rVal < gf THEN rVal:=gf; END_IF;
Ianteil:=Ianteil - rVal;
END_IF;
END_IF;
END_IF;
END_IF;
LMN_P:=Panteil;
LMN_I:=Ianteil;
LMN_D:=Danteil;
sInvAlt:=ErKp;
sIanteilAlt:=Ianteil;
sbArwHLmOn:=
sbArwLLmOn:=
IF (dLmn
THEN
QLMN_HLM:=
QLMN_LLM:=
dLmn:=LMN_HLM;
sbArwHLmOn:=
ELSE
QLMN_HLM:=
IF (dLmn
THEN
QLMN_LLM:=
dLmn:=LMN_LLM;
sbArwLLmOn:=
ELSE
QLMN_LLM:=
END_IF;
END_IF;
sLmn:=dLmn;
dLmn:=sLmn
LMN:=dLmn;
dLmn:=LMN
IF dLmn
THEN
dLmn:=
ELSE
IF dLmn
THEN
dLmn:=-
END_IF;
END_IF;
LMN_PER:=
END_IF;
END_FUNCTION_BLOCK
Просмотров: 77465
Комментарии к материалу
Добавлен: KruFFT Дата: 2009-11-23
Спасибо! Вот именно сейчас этот код понадобился. Как оказалось, в S7-412H нет SFB41. :(
Добавлен: Миша Дата: 2013-03-10
Спасибо огромное! Очень выручили! :)
Добавлен: Николай Дата: 2014-04-02
Круто, к 1200 прикрутить :)
Добавлен: Юрий Дата: 2014-04-02
А какой смысл этих 2-х строк:
Ianteil:=sIanteilAlt + Diff;
sRestInt:=sIanteilAlt - Ianteil + Diff;
При каких обстоятедьствах sRestInt будет не равно нулю?
Добавлен: Колян Дата: 2014-04-03
sRestInt:=sIanteilAlt-sIanteilAlt- Diff+ Diff=0
Добавлен: komatic Дата: 2014-04-03
>При каких обстоятедьствах sRestInt будет не равно нулю?
Самое смешное - что при любых обстоятельствах, в реальном контроллере оно нулю равно не будет. легко проверить промониторив работающий регулятор.
Добавлен: komatic Дата: 2014-04-04
почему не получается 0?
скорее всего из-за ограниченной точности операций с числами в real формате
http://plc4good.org.ua/view_post.php?id=165
Добавлен: sergio green Дата: 2014-04-21
Подобная конструкция и по диф. составляющей. Это борьба с погрешностью?
И есть ли смысл оставлять эти строчки?
Добавлен: пид Дата: 2014-08-22
А что нужно исправить, что бы пропорциональный канал был параллелен -И и -Д каналу?
Добавлен: ПИД Дата: 2014-08-22
ErKp:=ER * GAIN; -> ErKp:=ER * 1.0;
Panteil:=ErKp; ->
Panteil:=ErKp*GAIN;
Добавлен: Сергей Дата: 2014-12-10
Огромное спасибо!
На работе обслуживаю\программирую PLC (в основном Siemens S7-200..S7-400), дома (хобби) AVR.. Для проекта терморегулятора (DS18B20 + ATTiny85) искал Сяшную библиотеку PID. Пробовал использовать готовую от Atmel (AVR221) и другие по форумам искал. Не подходят. В симуляторе видна огромная разница между решениями PID Control, применёнными в промышленных контроллерах и тем, что я смог накопать в интернете.
В итоге, взял отсюда исходник FB41 и с SCL перевёл на Си. На ATTiny85 отлично (идеально!) работает. Убрал лишнее, немного оптимизировал для быстродейсвия. На 8Мгц время обработки FB41 занимает 0.8-1.2 мсек. На порядок дольше чем алгоритмы с целочисленной арифметикой, но зато имеем понятные коэффициенты, безудароное переключение ручн\автомат, правильную реализацию D составляющей...
Если кому нужно, могу выложить сяшные исходники на файлообменник QIP, ссылку здесь кину.
Добавлен: Сергей Дата: 2014-12-10
Выложил исходники + проект на IAR + проект Proteus h**p://file.qip.ru/arch/6yfGw-Lm/PID_FB41_IAR_project.html
Картинка с протеуса h**p://shot.qip.ru/00CQYB-595nqPfJV
Всем удачи и спасибо komatic
Добавлен: komatic Дата: 2014-12-10
спасибо за добрые слова и полезный материал, обязательно оформлю и выложу
Добавлен: Сергей Дата: 2014-12-10
Не зачто ;) Странно, что в интернете нет подобной темы. Готовый, хорошо документированный, проверенный в промышленности алгоритм. Для 32-bit ARM вообще самое то.
>При каких обстоятедьствах sRestInt будет не равно нулю?
Всё верно, борьба с погрешностью REAL вычислений. Смотрел в отладчике, там постоянно "мельтешат" микро-значения в районе 10Е-8...10Е-10. Для "облегчения жизни" AVR "убрал" sRestInt и sRestDif, проверил - разницы в поведении регулятора не заметил. Зато выиграл ~220uS (~1700 тактов CPU) + место. Также не заметил разницы при переходе с float на double float.
Если бы портировал под STM32, то оставил бы как есть. Всё таки программисты Siemens не зря это сделали.
Добавлен: Old Bell Дата: 2015-04-19
LMN_HLM : REAL := 1.000000e+002; //Верхний предел выходного сигнала
----------------
у оригинала выход не привязан к 100 процентам?
Добавлен: komatic Дата: 2015-04-19
1.000000e+002 это и есть 100.0 или я не понял вопроса
Добавлен: Old Дата: 2015-04-19
да, в этом варианте привязано к 100. у оригинала, насколько я понимаю, нет. Значит вы доработали регулятор. входные переменные так же жестко прописаны у вас.
Или уже настроенный PID взяли для этого кода.
мне выход нужен от нуля до HEX 4000.
Или второй вопрос, чем ориганал отличается от этоого варианта. кроме того, что я заметил.
спасибо
Добавлен: komatic Дата: 2015-04-19
>Old
нет, я ничего не добавлял от себя, такой код инициализаций получается после команды "Generate source" на оригинальном FB.
Вы можете это с легкостью проверить.
Добавлен: komatic Дата: 2015-04-19
если у вас другой результат, обратите внимание, что версия этого регулятора - 1.5 (указано в шапке свойств блока)
Добавлен: Old Bell Дата: 2015-04-19
Спасибо, Komatic, все верно говорите. Я немного не понял работу ограничения верхнего и нижнего уровня.
Ограничение в процентах от выходного сигнала ю
Не мог понять, отчего ограничение 100, а на выходе LMN_PER максимальная величина 27648.
Посмотрел еще раз в симуляторе и прояснилось.
еще вопрос один, если открываю 41 блок канопеном, то код в IT (AWL)ассемблер.
И в шапке открытого блока вижу "generiert vom SCL Übersetzer Version: SCL K5.1.5.1 (C5.1.9.17)"
чир код был сгенерирован "переводчиком" кода SCL и далее версия.
Это такая версия с ассемлером от сименса или при открытии блока (в редакторе степа) инсталлированный модуль языка SCL автоматически переводит в ассемблер.
Полагаю, что первое, но хотелось бы, что бы второе )))
если второе, где и что нужно отключить, что бы оригинальный код увидеть?
Добавлен: Old Bell Дата: 2016-12-16
переведу пару коментариев
Hilfsvariable - вспомогательная переменная
Abtastzeit in real-время обработки в REAL
Дnderungswert -Änderungswert-величина изменения
Istwert-действительное значение
Integrationszeit in real-время интегрирования в REAL
Differentiationszeit in real-время дифференцирования в REAL
VerzцgerungszeitVerzögerungszeit in real- время задержки в REAL
P-Anteil- P-составляющая
I-Anteil- I-составляющая
D-Anteil- D-составляющая
Verstдrkung-Verstäkung-усиление
Differenz des Rьckkopplungswertes-разница величины обратной связи
Alter Rьckkopplungswert-старое значение величины обратной связи
Stellwert-
Hilfwert- вспомогательная величина
Real Hilfsvariable - истинная текущая вспомогательная переменная
Добавлен: Old Bell Дата: 2016-12-16
Stellwert-значение управляющего или регулирующего воздействия
Добавлен: CORSAR Дата: 2016-12-29
Добрый день!
К вопросу о назначении строки: sRestInt:=sIanteilAlt - Ianteil + Diff;
Это метод суммирования Кохена. Описан здесь: http://www.machinelearning.ru/wiki/index.php?title=%D0%A1%D0%BB%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D0%B5_%D0%B1%D0%BE%D0%BB%D1%8C%D1%88%D0%BE%D0%B3%D0%BE_%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D1%81%D1%82%D0%B2%D0%B0_%D1%87%D0%B8%D1%81%D0%B5%D0%BB%2C_%D1%81%D1%83%D1%89%D0%B5%D1%81%D1%82%D0%B2%D0%B5%D0%BD%D0%BD%D0%BE_%D0%BE%D1%82%D0%BB%D0%B8%D1%87%D0%B0%D1%8E%D1%89%D0%B8%D1%85%D1%81%D1%8F_%D0%BF%D0%BE_%D0%B2%D0%B5%D0%BB%D0%B8%D1%87%D0%B8%D0%BD%D0%B5
Добавлен: CORSAR Дата: 2016-12-29
Для S7-1200/1500 возможен перевод математических вычислений в формат LREAL. В этом случае строки коррекции вычислений, о которых писал выше, можно убрать.
Добавлен: dmw Дата: 2017-11-06
в строках
IF (Ianteil > (LMN_HLM - DISV)) AND (dLmn > LMN_HLM) AND ((dLmn - LMN_D)> LMN_HLM)
и
IF (Ianteil < (LMN_LLM - DISV)) AND (dLmn < LMN_LLM) AND ((dLmn - LMN_D) < LMN_LLM)
выходная переменная LMN_D появляется прежде, чем ей присвоено значение.
Может быть строку
LMN_D:=Danteil;
перенести сразу после этой
dLmn:=Panteil + Ianteil + Danteil + DISV;
Добавлен: dmw Дата: 2017-11-07
Или LMN_D в приведенных строках - это предыдущее значение, рассчитанное на предыдущем цикле, тогда логичнее LMN_D сделать переменной IN_OUT?
Добавлен: skalar Дата: 2022-04-18
Добрый день. Если пост еще живой - может кто поможет с переводом STL на SCL? Результат перевода всех вариантов, которые я перебрал не тождественен исходному коду SCL. Уже подозрение возникло, что разрабы после компиляции своего SCL листинга дополнительно его оптимизировали в STL
CLR
O(
A #A
A #B
O
AN #C
AN #D
)
JCN A001;
Добавлен: komatic Дата: 2022-04-20
>skalar
если бы было только A и B, структура похожа на:
IF A<>B THEN ...
Добавлен: skalar Дата: 2022-05-04
>komatic спасибо за ответ.
Весь вопрос в C и D. Компилятор упорно использует операцию NOT после операции A #C, но я не понимаю как его заставить использовать AN #C - как это в исходном тексте на STL. Пробовал даже использовать ту версию компилятора, которой компилировали исходник разрабы.
Добавлен: VA Дата: 2022-07-03
https://github.com/DIYPLC/LibPlc/blob/main/FbPIDcontrol.SCL
Добавить комментарий