Линейно-нарастающая функция

Линейно-нарастающие процессы чаще всего используются там, где есть задачи термостатирования. Когда температуру печи или любого другого устройства нельзя по технологии быстро нагревать или остужать. Использовал такие функции в работе тепличных комплексов, при сушке и обжиге кирпича, при закалке изделий из металла, системах дозаривания фруктов. Мы управляем не самой переменной объекта, а работаем с устанавливаем значением регулятора, который с помощью тенов, газа или других способов управления регулирует температуру объекта.
График температуры
В данной статье поделюсь способом программирования функции RAMP для линейно-инкрементированных технологических процессов. Когда нужно повышать или понижать установленное значение от начального значения до конечного за заданный интервал времени или с заданной скоростью, например 2С в час.
Тут важно отметить, что для корректной работы данной функции нам потребуется переменная, связанная с системным временем контроллера. Переменная постоянно меняется в коде данного блока. Сам процесс запуска основан на запоминании начального времени и расчета времени, до которого функция будет следовать.
Данный программный код взят из программы написанной для Codesys 2.3, но он с небольшими доработками будет работать и в других системах, где реализован в соответствии со стандартом язык ST(Structured Text).
Начинается блок с объявления. Обязательно комментируйте свой код. Это уменьшит защиту Вашего решения, но увеличит понятность и читабельность.
Линейно-временная функция RAMP
FUNCTION_BLOCK TE_CALC_SP
VAR_INPUT
    TE_SP_1:REAL;(*Значение с которого мы начали стартовать*)
    TE_SP_2:REAL;(*Значение к которому мы идем*)
    SPEED:REAL;(*Скорость с какой мы должны достичь установленного значения*)
END_VAR
VAR_IN_OUT
START:BOOL;
END_VAR
VAR_OUTPUT
    OUT:REAL; (*Выходная переменная, которая привязывается к уставке *)
    State:INT; (*Номер шага, на котором мы находимся*)
    Complite:BOOL;(*Выставляем флаг, что рамп закончил*)
    START_TIME:TIME;(*Время, когда ожидается завершение подсчета*)
    FINISH_TIME:TIME;(*Время, когда ожидается завершение подсчета*)
END_VAR

VAR
TIME_MAIN:TIME;(*Общее время прироста рамп-функции*)
First:REAL;(*Начальное значение интервала*)
Second:REAL;(*Конечное значение интервала*)
GRADUS:REAL;(*Считаем разницу в градусах*)
TON2:TON;(*Таймер от зависания в стадии перехода через 0*)
Cur_Timei:DWORD;(*Для расчета перехода через 00:00:00*)
AM:REAL;(*Разница между уставкой и переменной процесса*)
OS:REAL;(*Значение переменной процесса в начале функции*)
Err:REAL;(*Уменьшающаяся ошибка*)
tx:TIME;(*Текущее время ПЛК*)
tx1:TIME;(*Запоминаем время ПЛК в начале счета*)
txr_diff:REAL;(*Нарастающее время в формате REAL*)
fr:REAL;(*Расчитанный коэффициент приращения, угол наклона*)
R_TRIG:R_TRIG;(*Ловим переход, окончание RAMP*)
END_VAR

Теперь немного о коде этого функционального блока. Код выполнен на операторе CASE, что удобно для реализации конечного автомата. Это когда в каждый конкретный момент времени выполняется какая-то часть программного кода, причем весь остальной программный код находится в состоянии ожидания. Возможно делать различные гибкие комбинации подобно языку SFC. Управляется переход с шага на шаг при помощи целочисленной переменной State

CASE State OF
0:(*На этом шаге мы стоим и ждем, инициализируем переменные*)
OUT:=TE_SP_1; (*Присваиваем начальное значение выходу*)
START_TIME:=T#0m; (*Обнуляем начальное время*)
FINISH_TIME:=T#0m; (*Обнуляем конечное время*)
IF START THEN  State:=1; END_IF; (*Если нажата кнопка старт, то переходим на следующий уровень*)

1:(*Определяем время начала работы функции, высчитываем время и переходим дальше*)
Complite:=FALSE;(*Сбрасываем признак окончания*)
GRADUS:=ABS(TE_SP_2 - TE_SP_1);(*Посчитали сколько градусов разница*)
First:=TE_SP_1;(* Запомнили первое число*)
Second:=TE_SP_2;(*Запомнили второе число*)
txr_diff:=1;(*Присваиваем 1 переменной, которая отвечает за угол наклона функции*)
TIME_MAIN:=(REAL_TO_TIME(GRADUS/SPEED)*1000*60*60);(*Вычисляем, за сколько времени приращать функцию*)
fr:=txr_diff/DINT_TO_REAL(TIME_TO_DINT(TIME_MAIN));(*Время за которое должна нарастать или убывать функция. Высчитывает коэффициент приращения/убавления*)
tx:=T#0s;(*Обнулили инкремент по времени*)
Err:=0.0;(*Обнулили инкремент по рассогласованию*)
AM:=Second - First;(*Посчитали расстояние в градусах между двумя точками*)
OS:=First; (*Запомнили откуда мы идем*)
tx1:=PLC_TIME; (*Запоминаем время до начала работы рамп*)
START_TIME:=PLC_TIME;
FINISH_TIME:=PLC_TIME+TIME_MAIN;
State:=2;

2:(*Делаем RAMP от первой до второй точки*)
tx:=PLC_TIME;(*Время циклически накапливается*)
txr_diff:=DINT_TO_REAL(TIME_TO_DINT(tx)) - DINT_TO_REAL(TIME_TO_DINT(tx1));(*Разница между запомненным временем и текущим*)
fr:=txr_diff/DINT_TO_REAL(TIME_TO_DINT(TIME_MAIN));(*Время за которое должна нарастать или убывать функция. Высчитывает коэффициент приращения/убавления*)
IF First<Second THEN Err:=Second - OUT; END_IF;(*0-рост*)
IF First>Second THEN Err:=OUT - Second; END_IF;(*1-падение*)
OUT:=AM * fr + OS;(*Общая линейная зависимость*)
R_TRIG(CLK:=Err< 0);(*Ждем перехода через ноль*)
IF  R_TRIG.Q THEN State:=3; END_IF;
IF NOT START THEN  State:=3; END_IF;

3:(*Рамп отработал*)
OUT:=TE_SP_2;(*Оставляем второе значение на выходе*)
START_TIME:=T#0m;(*Делаем визуализацию переменных времени*)
FINISH_TIME:=TIME_MAIN;(*Делаем визуализацию переменных времени*)
Complite:=TRUE;(*Выставляем признак того, что завершилось*)

IF NOT START THEN State:=0; END_IF;(*Возвращаем, если кнопка START прекратила действовать, на 0 шаг*)
END_CASE;
END_FUNCTION_BLOCK

#RAMP, #Линейно-нарастающая функция, #Управление процессом нагрева
Array
(
    [ID] => 453
    [IBLOCK_ID] => 8
    [NAME] => Линейно-нарастающая функция
    [IBLOCK_SECTION_ID] => 
    [IBLOCK] => Array
        (
            [ID] => 8
            [~ID] => 8
            [TIMESTAMP_X] => 25.03.2021 17:23:33
            [~TIMESTAMP_X] => 25.03.2021 17:23:33
            [IBLOCK_TYPE_ID] => rus
            [~IBLOCK_TYPE_ID] => rus
            [LID] => s1
            [~LID] => s1
            [CODE] => articals
            [~CODE] => articals
            [API_CODE] => 
            [~API_CODE] => 
            [NAME] => Статьи
            [~NAME] => Статьи
            [ACTIVE] => Y
            [~ACTIVE] => Y
            [SORT] => 10
            [~SORT] => 10
            [LIST_PAGE_URL] => /articals/
            [~LIST_PAGE_URL] => /articals/
            [DETAIL_PAGE_URL] => /articals/#ELEMENT_CODE#.html
            [~DETAIL_PAGE_URL] => /articals/#ELEMENT_CODE#.html
            [SECTION_PAGE_URL] => 
            [~SECTION_PAGE_URL] => 
            [CANONICAL_PAGE_URL] => https://lapshinvr.ru/articals/articals.html
            [~CANONICAL_PAGE_URL] => https://lapshinvr.ru/articals/articals.html
            [PICTURE] => 1131
            [~PICTURE] => 1131
            [DESCRIPTION] => 
            [~DESCRIPTION] => 
            [DESCRIPTION_TYPE] => html
            [~DESCRIPTION_TYPE] => html
            [RSS_TTL] => 24
            [~RSS_TTL] => 24
            [RSS_ACTIVE] => Y
            [~RSS_ACTIVE] => Y
            [RSS_FILE_ACTIVE] => N
            [~RSS_FILE_ACTIVE] => N
            [RSS_FILE_LIMIT] => 
            [~RSS_FILE_LIMIT] => 
            [RSS_FILE_DAYS] => 
            [~RSS_FILE_DAYS] => 
            [RSS_YANDEX_ACTIVE] => N
            [~RSS_YANDEX_ACTIVE] => N
            [XML_ID] => 
            [~XML_ID] => 
            [TMP_ID] => 
            [~TMP_ID] => 
            [INDEX_ELEMENT] => Y
            [~INDEX_ELEMENT] => Y
            [INDEX_SECTION] => N
            [~INDEX_SECTION] => N
            [WORKFLOW] => N
            [~WORKFLOW] => N
            [BIZPROC] => N
            [~BIZPROC] => N
            [SECTION_CHOOSER] => L
            [~SECTION_CHOOSER] => L
            [LIST_MODE] => 
            [~LIST_MODE] => 
            [RIGHTS_MODE] => S
            [~RIGHTS_MODE] => S
            [SECTION_PROPERTY] => N
            [~SECTION_PROPERTY] => N
            [PROPERTY_INDEX] => N
            [~PROPERTY_INDEX] => N
            [VERSION] => 1
            [~VERSION] => 1
            [LAST_CONV_ELEMENT] => 0
            [~LAST_CONV_ELEMENT] => 0
            [SOCNET_GROUP_ID] => 
            [~SOCNET_GROUP_ID] => 
            [EDIT_FILE_BEFORE] => 
            [~EDIT_FILE_BEFORE] => 
            [EDIT_FILE_AFTER] => 
            [~EDIT_FILE_AFTER] => 
            [SECTIONS_NAME] => 
            [~SECTIONS_NAME] => 
            [SECTION_NAME] => 
            [~SECTION_NAME] => 
            [ELEMENTS_NAME] => Элементы
            [~ELEMENTS_NAME] => Элементы
            [ELEMENT_NAME] => Элемент
            [~ELEMENT_NAME] => Элемент
            [REST_ON] => N
            [~REST_ON] => N
            [EXTERNAL_ID] => 
            [~EXTERNAL_ID] => 
            [LANG_DIR] => /
            [~LANG_DIR] => /
            [SERVER_NAME] => lapshinvr.ru
            [~SERVER_NAME] => lapshinvr.ru
        )

    [LIST_PAGE_URL] => /articals/
    [~LIST_PAGE_URL] => /articals/
    [SECTION_URL] => 
    [CANONICAL_PAGE_URL] => https://lapshinvr.ru/articals/lineyno-narastayushchaya-funktsiya.html
    [SECTION] => Array
        (
            [PATH] => Array
                (
                )

        )

    [IPROPERTY_VALUES] => Array
        (
            [SECTION_META_TITLE] => Статьи по автоматизации
            [SECTION_META_KEYWORDS] => Статьи, автоматизация
            [SECTION_META_DESCRIPTION] => Встречал при производстве работ что-то достойное внимания. Сложно самому оценить необходимость размещения той или иной статьи, старался очевидный мусор убирать
            [SECTION_PAGE_TITLE] => Здесь опубликовал статьи, которые могут кому-то пригодиться при производстве работ
            [ELEMENT_META_TITLE] => Линейно-нарастающая функция
            [ELEMENT_META_KEYWORDS] => RAMP, Линейно-нарастающая функция, Управление процессом нагрева
            [ELEMENT_META_DESCRIPTION] => Описание программного кода ST для реализации функции линейно-нарастающей функции
        )

    [TIMESTAMP_X] => 08.06.2021 23:43:20
    [META_TAGS] => Array
        (
            [TITLE] => Линейно-нарастающая функция
            [BROWSER_TITLE] => Линейно-нарастающая функция
            [KEYWORDS] => RAMP, Линейно-нарастающая функция, Управление процессом нагрева
            [DESCRIPTION] => Описание программного кода ST для реализации функции линейно-нарастающей функции
        )

    [PREVIEW_TEXT] => Код выполнен на операторе CASE, что удобно для реализации конечного автомата. Это когда в каждый конкретный момент времени выполняется какая-то часть программного кода, причем весь остальной программный код находится в состоянии ожидания. Возможно делать различные гибкие комбинации подобно языку SFC. Управляется переход с шага на шаг при помощи целочисленной переменной State
    [PREVIEW_PICTURE] => Array
        (
            [ID] => 1427
            [TIMESTAMP_X] => Bitrix\Main\Type\DateTime Object
                (
                    [value:protected] => DateTime Object
                        (
                            [date] => 2021-06-08 23:43:20.000000
                            [timezone_type] => 3
                            [timezone] => Europe/Moscow
                        )

                )

            [MODULE_ID] => iblock
            [HEIGHT] => 178
            [WIDTH] => 355
            [FILE_SIZE] => 4969
            [CONTENT_TYPE] => image/png
            [SUBDIR] => iblock/005
            [FILE_NAME] => d6bdklde8mwbwv7ed5u17vdo82ap05vz.png
            [ORIGINAL_NAME] => bhbd5zmacd0p2mneh66onvhzata8sqly.png
            [DESCRIPTION] => График температуры
            [HANDLER_ID] => 
            [EXTERNAL_ID] => 19748376880ba782b15d5d657bfa6c02
            [~src] => 
            [SRC] => /upload/iblock/005/d6bdklde8mwbwv7ed5u17vdo82ap05vz.png
            [UNSAFE_SRC] => /upload/iblock/005/d6bdklde8mwbwv7ed5u17vdo82ap05vz.png
            [SAFE_SRC] => /upload/iblock/005/d6bdklde8mwbwv7ed5u17vdo82ap05vz.png
            [ALT] => Линейно-нарастающая функция
            [TITLE] => Линейно-нарастающая функция
        )

    [DETAIL_PAGE_URL] => /articals/lineyno-narastayushchaya-funktsiya.html
)
Ваш комментарий добавлен

Возврат к списку