Вход

Просмотр полной версии : Реализация алгоритма наполнения емкости с тремя стадиями



Григори
08.05.2024, 16:18
Всем добрый день. Недавно подкинули интересную задачку, но которую не могу нормально реализовать.
Дано:
Аналоговый датчик уровня воды (0-6м, но я делал динамическую подгонку).
Необходимо реализовать три стадии:
1) Если опустилось ниже определенного порога 1 высоты, включается Насос 1. Если поднялось до порога 1.1 Выключить насос 1(полное заполнение)
2) Если опустилось ниже порога 2, отключить насос 1 и перейти на насос 2. Если поднялось до порога 2.1 выключить насос 2 и перейти на насос 1
3) Если опустилось ниже порога 3, работают насосы 1 и 2. Если поднялось до порога 3.1 выключить насос 1, насос 2 оставить в работе
(То есть каждая стадия имеет пороги включения и выключения)

Сам реализовывал в ФБ STшном на IFах с >= и <=, выходила полная шляпа(Стадии накладывались друг на друга)
Прикладываю проект со своими пробами, но там все уже перемешано и напеределывано 100 раз.

EFrol
08.05.2024, 17:20
Вам осталось совсем чуть-чуть дажать и получилось бы так:


function_block Control

var_input
level : real; // Текущий уровень
level1 : real; // Максимальный
level2 : real; // Средний
level3 : real; // Минимальный
end_var

var_output
pump1 : bool; // Насос 1
pump2 : bool; // Насос 2
end_var

if level >= level1 then
pump1:=false; pump2:=false;
elsif level < level1 and level >= level2 then
pump1:=true; pump2:=false;
elsif level < level2 and level >= level3 then
pump1:=false; pump2:=true;
elsif level < level3 then
pump1:=true; pump2:=true;
end_if

end_function_block

EFrol
08.05.2024, 17:38
Да или так:


if level < level3 then
pump1:=true; pump2:=true;
elsif level < level2 then
pump1:=false; pump2:=true;
elsif level < level1 then
pump1:=true; pump2:=false;
else
pump1:=false; pump2:=false;
end_if

Dimensy
08.05.2024, 18:11
а у меня так получилось



function_block WaterLevel

var_input
rCurrent_lvl: real; //тек. уровень
iD_AlarmLamp_high_on: real;
iD_AlarmLamp_high_off: real;
iD_Pump1_Off: real;
iD_Pump1_On: real;
iD_Pump2_Off: real;
iD_Pump2_On: real;
iD_Pumps_vmeste_Off: real;
iD_Pumps_vmeste_On: real;
iD_AlarmLamp_low_on: real;
iD_AlarmLamp_low_off: real;
end_var

var_output
xPump1: BOOL;
xPump2: BOOL;
xAlarmUp: BOOL;
xAlarmLow: BOOL;
end_var

var
xFlag1: SYS.RS;
xFlag2: SYS.RS;
xFlag3: SYS.RS;
end_var

xFlag1(S := rCurrent_lvl < iD_Pump1_On, R := rCurrent_lvl >= iD_Pump1_Off);
xFlag2(S := rCurrent_lvl < iD_Pump2_On, R := rCurrent_lvl >= iD_Pump2_Off);
xFlag3(S := rCurrent_lvl < iD_Pumps_vmeste_On, R := rCurrent_lvl >= iD_Pumps_vmeste_Off);

xPump1 := (xFlag1.Q and not xFlag2.Q) or xFlag3.Q;
xPump2 := xFlag2.Q or xFlag3.Q;

xAlarmUp := xPump1 and xPump2;

end_function_block

Григори
08.05.2024, 18:17
пропускаем через центрифугу и посыпаем реальностью

Смотрю анализирую. Как понимаю, что активации находятся в диапазонах между условными уровнями.
Но таким макаром насос 1 будет срабатывать сразу, как текущий уровень опустится ниже отметки выключения даже на чуть-чуть(проверил, да, начинает работать как только опустилось ниже отметки)

Но алгоритм хотя бы работает, сейчас посижу покумекаю с разумом, может добавить насосу 1 две разных точки вкл/выкл

Григори
08.05.2024, 18:20
жмём еще

pump1 := level < level3 or (level >= level2 and level < level1);
pump2 := level < level2;

Очень красивый код, однако, но тоже начинает срабатывать почти сразу, как вода утекла на 0.01 мм от верхней границы(

kondor3000
08.05.2024, 18:27
А может кто-нибудь PUTBIT в Лоджике на ST изобразить?
В биб-ке Util.lib код выглядит так 75647

А в Лоджике как то так, соответственно AND, OR и ROL не работают


function PUTBIT: udint; //имя функции и тип данных выхода
VAR_INPUT
X: udint; (* value to be manipulated *)
N: udint; (* position of bit to be changed *)
B:BOOL; (* value of specified bit *)
END_VAR

IF B=TRUE THEN
PUTBIT:=(X OR SHL(1,N));
ELSE
PUTBIT:=(X AND ROL(4294967294,N));
END_IF;

end_function

Григори
08.05.2024, 18:29
а у меня так получилось



function_block WaterLevel

var_input
rCurrent_lvl: real; //тек. уровень
iD_AlarmLamp_high_on: real;
iD_AlarmLamp_high_off: real;
iD_Pump1_Off: real;
iD_Pump1_On: real;
iD_Pump2_Off: real;
iD_Pump2_On: real;
iD_Pumps_vmeste_Off: real;
iD_Pumps_vmeste_On: real;
iD_AlarmLamp_low_on: real;
iD_AlarmLamp_low_off: real;
end_var

var_output
xPump1: BOOL;
xPump2: BOOL;
xAlarmUp: BOOL;
xAlarmLow: BOOL;
end_var

var
xFlag1: SYS.RS;
xFlag2: SYS.RS;
xFlag3: SYS.RS;
end_var

xFlag1(S := rCurrent_lvl < iD_Pump1_On, R := rCurrent_lvl >= iD_Pump1_Off);
xFlag2(S := rCurrent_lvl < iD_Pump2_On, R := rCurrent_lvl >= iD_Pump2_Off);
xFlag3(S := rCurrent_lvl < iD_Pumps_vmeste_On, R := rCurrent_lvl >= iD_Pumps_vmeste_Off);

xPump1 := (xFlag1.Q and not xFlag2.Q) or xFlag3.Q;
xPump2 := xFlag2.Q or xFlag3.Q;

xAlarmUp := xPump1 and xPump2;

end_function_block


Вы докрутили мою идею с флагами и триггерами, я даже не додумался сделать правило для исключения первого насоса при флаге на второй.
Вы с Сергеем0308 какие-то великие хранителя форума, спасибо большое)

Григори
08.05.2024, 18:32
что значит однако?
как описали, так и предложили

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

Dimensy
08.05.2024, 18:47
А может кто-нибудь PUTBIT в Лоджике на ST изобразить?
В биб-ке Util.lib код выглядит так 75647

А в Лоджике как то так, соответственно AND, OR и ROL не работают


я тупо через case перебирал биты

Григори
08.05.2024, 18:52
Общий и легко масштабируемый алгоритм (0...до_хрена насосов)
По уровню определить не насосы, а нужное их кол-во.
А вот по нужному кол-ву:
-если сейчас больше - тушить самых уставших
-если меньше включать самых отдохнувших из доступных.

И чередование, и автозамена аварийных.
Массивы и циклы. Не считайте строчки, делайте сразу универсально.

Да, думал по поводу масштабирования. С видосов по Codesys смотрел чередование насосов (с канала CodesysOneLove).
Думаю, что тот алгоритм можно скрестить с анализом уровня и вычислением количества нужных насосов(но там через массивы, а массивов в лоджике я не видел.. ну или слепой). Но это надо думать и напрягать мозги)

EFrol
08.05.2024, 19:02
А может кто-нибудь PUTBIT в Лоджике на ST изобразить?
В биб-ке Util.lib код выглядит так 75647

А в Лоджике как то так, соответственно AND, OR и ROL не работают


Можно еще так попробовать:


function putbit: udint;
var_input
X : udint;
N : udint;
B : bool;
end_var

putbit := shr(X, N); putbit.0 := B; putbit := shl(putbit, N);
putbit := putbit + shr(shl(X, 32-N), 32-N);

end_function

kondor3000
08.05.2024, 19:27
Можно еще так попробовать:


function putbit: udint;
var_input
X : udint;
N : udint;
B : bool;
end_var

putbit := shr(X, N); putbit.0 := B; putbit := shl(putbit, N);
putbit := putbit + shr(shl(X, 32-N), 32-N);

end_function


EFrol, класс, проверку на скорую руку прошло на ура)))

Валенок
08.05.2024, 19:29
EFrol
да - бомбически))

EFrol
08.05.2024, 19:31
Я еще крестиком вышивать могу.:rolleyes:

Сергей0308
08.05.2024, 21:21
Всем добрый день. Недавно подкинули интересную задачку, но которую не могу нормально реализовать.
Дано:
Аналоговый датчик уровня воды (0-6м, но я делал динамическую подгонку).
Необходимо реализовать три стадии:
1) Если опустилось ниже определенного порога 1 высоты, включается Насос 1. Если поднялось до порога 1.1 Выключить насос 1(полное заполнение)
2) Если опустилось ниже порога 2, отключить насос 1 и перейти на насос 2. Если поднялось до порога 2.1 выключить насос 2 и перейти на насос 1
3) Если опустилось ниже порога 3, работают насосы 1 и 2. Если поднялось до порога 3.1 выключить насос 1, насос 2 оставить в работе
(То есть каждая стадия имеет пороги включения и выключения)

Сам реализовывал в ФБ STшном на IFах с >= и <=, выходила полная шляпа(Стадии накладывались друг на друга)
Прикладываю проект со своими пробами, но там все уже перемешано и напеределывано 100 раз.

Это же очень простой алгоритм, думаю любой школьник за 5 минут сделает, типа так: формируете эти ваши стадии, например с помощью макроса двухпозиционного регулятора с гистерезисом из менеджера компонентов, я в одной из тем выкладывал подобный макрос, но с явным назначением уровней срабатывания, мне кажется это намного удобней! Каждой стадии соответствует её порядковый номер, в смысле, 1, 2 и 3 и из этого значения извлекаем нулевой бит(с весовым коэффициентом "1") и используем для работы первого насоса и первый бит(с весовым коэффициентом "2") и используем для работы второго насоса, всё!

Примерно как-то так, в смысле, мой вариант:

75654

75679

75655

Или так:

75665

75666

75668

75667

Григори
06.06.2024, 22:20
Это же очень простой алгоритм, думаю любой школьник за 5 минут сделает, типа так: формируете эти ваши стадии, например с помощью макроса двухпозиционного регулятора с гистерезисом из менеджера компонентов, я в одной из тем выкладывал подобный макрос, но с явным назначением уровней срабатывания, мне кажется это намного удобней! Каждой стадии соответствует её порядковый номер, в смысле, 1, 2 и 3 и из этого значения извлекаем нулевой бит(с весовым коэффициентом "1") и используем для работы первого насоса и первый бит(с весовым коэффициентом "2") и используем для работы второго насоса, всё!

Примерно как-то так, в смысле, мой вариант:

75654

75679

75655

Или так:

75665

75666

75668

75667

Да, ваше решение красивое, но с битами привык в modbus только работать, о них в таком ключе и не подумал(а про блок CD32 услышал вот впервые). Сколько людей, столько и решений, благодарю за ответ.
Проект с БКК все еще не установлен, но я помню, когда его ребята поставят, отпишу :)

Сергей0308
06.06.2024, 23:30
Да, ваше решение красивое, но с битами привык в modbus только работать, о них в таком ключе и не подумал(а про блок CD32 услышал вот впервые). Сколько людей, столько и решений, благодарю за ответ.
Проект с БКК все еще не установлен, но я помню, когда его ребята поставят, отпишу :)

Очень рад за вас, согласен, вариантов тьма, вот ещё один:

76350