Вход

Просмотр полной версии : ПР200 зависимая(плавающая) уставка



barrymore
25.02.2025, 11:24
Здравствуйте!
Цель: нагрев котла до температуры, зависящей от уличной температуры. Чем холоднее на улице, тем горячее котел в помещении. Не знаю, с чего начать.
Зависимость t улицы -> t котла должна быть табличной, задаваемой пользователем, 15-20 точек, хранящихся в энергонезависимой памяти, желательно с интерполяцией.
Как я это представляю: создать 15-20 переменных, каждую по одной выводить на дисплей для редактирования и сохранения, для этого создать столько же экранов. Уличную t сравнивать 20 раз с фиксированной таблицей (-30, -25, -20, ...), находя вилку, в которой она сейчас находится, затем найти относительное смещение в этой вилке 0..5 гр. затем взять два соседних значения из таблицы и найти "среднее" в соответствии с найденным смещением. Полученное значение поместить в уставку, до которой нагревать котел.
Подскажите, правильно ли я двигаюсь в этом направлении? Или есть другой, более простой способ?

kondor3000
25.02.2025, 11:31
Здравствуйте!
Цель: нагрев котла до температуры, зависящей от уличной температуры. Чем холоднее на улице, тем горячее котел в помещении. Не знаю, с чего начать.
Зависимость t улицы -> t котла должна быть табличной, задаваемой пользователем, 15-20 точек, хранящихся в энергонезависимой памяти, желательно с интерполяцией.
Как я это представляю: создать 15-20 переменных, каждую по одной выводить на дисплей для редактирования и сохранения, для этого создать столько же экранов. Уличную t сравнивать 20 раз с фиксированной таблицей (-30, -25, -20, ...), находя вилку, в которой она сейчас находится, затем найти относительное смещение в этой вилке 0..5 гр. затем взять два соседних значения из таблицы и найти "среднее" в соответствии с найденным смещением. Полученное значение поместить в уставку, до которой нагревать котел.
Подскажите, правильно ли я двигаюсь в этом направлении? Или есть другой, более простой способ?

Тут готовая функция, на ST вариант макроса PLA (кусочно-линейная аппроксимация) на 10 точек, зависимость Т котла от Т улицы.82184
Задавать можно константами или переменными.
https://owen.ru/forum/showthread.php?t=35489&page=5

Таблица должна быть отсортирована по X в порядке возрастания.

Сергей0308
25.02.2025, 11:39
Здравствуйте!
Цель: нагрев котла до температуры, зависящей от уличной температуры. Чем холоднее на улице, тем горячее котел в помещении. Не знаю, с чего начать.
Зависимость t улицы -> t котла должна быть табличной, задаваемой пользователем, 15-20 точек, хранящихся в энергонезависимой памяти, желательно с интерполяцией.
Как я это представляю: создать 15-20 переменных, каждую по одной выводить на дисплей для редактирования и сохранения, для этого создать столько же экранов. Уличную t сравнивать 20 раз с фиксированной таблицей (-30, -25, -20, ...), находя вилку, в которой она сейчас находится, затем найти относительное смещение в этой вилке 0..5 гр. затем взять два соседних значения из таблицы и найти "среднее" в соответствии с найденным смещением. Полученное значение поместить в уставку, до которой нагревать котел.
Подскажите, правильно ли я двигаюсь в этом направлении? Или есть другой, более простой способ?

Я обычно формулу придумывал за 5-10 минут, чтобы функция выполнялась с точностью до одной десятой градуса, что мне кажется вполне достаточно, можно конечно и кусочно-линейной интерполяцией забацать, но это немного сложней, в смысле, Вы не найдёте готовых макросов на 20 точек, на форуме встречал до 10 точек и предпочитаю использовать один экран для ввода всех точек, зачем все стремятся для каждой точки свой экран использовать, мне неведомо, наверно занять себя больше нечем!
Здесь подобное делали: https://owen.ru/forum/showthread.php?t=34853&page=4

petera
25.02.2025, 11:40
Здравствуйте!
Цель: нагрев котла до температуры, зависящей от уличной температуры. Чем холоднее на улице, тем горячее котел в помещении. Не знаю, с чего начать.
Зависимость t улицы -> t котла должна быть табличной, задаваемой пользователем, 15-20 точек, хранящихся в энергонезависимой памяти, желательно с интерполяцией.
Как я это представляю: создать 15-20 переменных, каждую по одной выводить на дисплей для редактирования и сохранения, для этого создать столько же экранов. Уличную t сравнивать 20 раз с фиксированной таблицей (-30, -25, -20, ...), находя вилку, в которой она сейчас находится, затем найти относительное смещение в этой вилке 0..5 гр. затем взять два соседних значения из таблицы и найти "среднее" в соответствии с найденным смещением. Полученное значение поместить в уставку, до которой нагревать котел.
Подскажите, правильно ли я двигаюсь в этом направлении? Или есть другой, более простой способ?

ST функция графика кусочно-линейной апроксимации https://owen.ru/forum/showthread.php?t=35489&p=369459&viewfull=1#post369459

function PLA_ST: real; // (c) PeterA
var_input //объявление входных переменных
x1: real;
x2: real;
x3: real;
x4: real;
x5: real;
x6: real;
x7: real;
x8: real;
x9: real;
x10: real;
y1: real;
y2: real;
y3: real;
y4: real;
y5: real;
y6: real;
y7: real;
y8: real;
y9: real;
y10: real;
In: real;
end_var

var //объявление локальных переменных
a:udint; (*Начало интервала поиска*)
b: udint; (*Конец интервала поиска*)
N: udint; (*Число точек в графике*)
i: udint;
x: array [0..9] of real;
y: array [0..9] of real;
end_var

N:= 10;
x[0]:= x1;
x[1]:= x2;
x[2]:= x3;
x[3]:= x4;
x[4]:= x5;
x[5]:= x6;
x[6]:= x7;
x[7]:= x8;
x[8]:= x9;
x[9]:= x10;

y[0]:= y1;
y[1]:= y2;
y[2]:= y3;
y[3]:= y4;
y[4]:= y5;
y[5]:= y6;
y[6]:= y7;
y[7]:= y8;
y[8]:= y9;
y[9]:= y10;

(*Начальные значения интервала поиска*)
a:=0;
b:=N-1;

(*Обрезание графика для крайних точек*)
IF IN<=x[0] THEN
PLA_ST:=y1;
ELSIF IN>= x[N-1] THEN
PLA_ST:= y[N-1];
(*Теперь можно начать поиск*)
ELSE
WHILE (b-a) <> 1 DO (*В конце концов, входной сигнал ТОЧНО попадет между двумя соседними точками X(a) и Х(а+1)*)
i:=(a+b)/2; (*Делим интервал поиска пополам*)
IF IN=x[i+1] THEN (*Может нам повезло, и мы сразу нашли точку? *)
a:=i; b:=i+1; (*Бинго! прекращаем итераций, нечего в пустую молотить :) *)
(*мимо :( ,тогда посмотрим в какую половину интервала попали*)
ELSIF IN>x[i] THEN (*Если входной сигнал больше середины интервала поиска,*)
a:=i; (*то следующий поиск будем делать начиная от середины и до конца массива*)
ELSE (*А если входной сигнал меньше середины интервала поиска,*)
b:=i; (*то следующий поиск будем делать начиная от начала и до середины массива*)
END_IF
(*Таким образом на каждой итерации отбрасываем из поиска заведомо ненужную половину значений
две соседние координаты X(a) и Х(а+1), меду которыми попадает входной сигнал найдем очень быстро
для 8 точек графика нужно не более 3 итераций
при 9..16 точек в графике нужно не более 4 итераций
при 17..32 точек в графике нужно не более 5 итераций
при 33..64 точек в графике нужно не более 6 итераций
при 65..128 точек в графике нужно не более 7 итераций
инфа точная - 100% ;) *)
END_WHILE;
(*Теперь самое простое - сделать линейную аппроксимацию по двум точкам ;) *)
PLA_ST:= y[b] - (x[b] - IN) * (y[b] - y[a]) / (x[b] - x[a]);
END_IF


end_function

Количество пар точек Xi Yi можно увеличить

EFrol
25.02.2025, 12:07
Я раньше тоже использовал таблицы, но задавал их константами в самом проекте (редактирование таблицы крайне редкое занятие).
Сейчас просто подбираю формулу (функцию), которая как можно ближе подходит к описанию зависимости и рассчитываю коэффициенты (обычно 2 числа с плавающей запятой). Взял из п, дьяконов СПРАВОЧНИК ПО РАСЧЕТАМ НА МИКРОКАЛЬКУЛЯТОРАХ (https://ideafix.su/wp-content/uploads/stuff/book61.pdf)
82185

Dimensy
25.02.2025, 12:07
Ну и до кучи, еще здесь можно посмотреть
https://owen.ru/forum/showthread.php?t=38709&p=422461&viewfull=1#post422461

barrymore
25.02.2025, 12:23
Не ожидал такой быстрой реакции! Спасибо всем ответившим!
Перед вызовом функции или макроса значения таблицы перекодировки уже должны быть заполнены, как я понимаю. То есть все пары (Xn, Yn).
Значения Xn редактировать не нужно(константы), они будут идти с фиксированным шагом 5 градусов, например. А вот выходные значения должен вводить пользователь кнопками на дисплее и далее иметь возможность их редактировать в процессе эксплуатации. Как это проще всего реализовать, если будет 20 переменных?

kondor3000
25.02.2025, 12:34
Не ожидал такой быстрой реакции! Спасибо всем ответившим!
Перед вызовом функции или макроса значения таблицы перекодировки уже должны быть заполнены, как я понимаю. То есть все пары (Xn, Yn).
Значения Xn редактировать не нужно(константы), они будут идти с фиксированным шагом 5 градусов, например. А вот выходные значения должен вводить пользователь кнопками на дисплее и далее иметь возможность их редактировать в процессе эксплуатации. Как это проще всего реализовать, если будет 20 переменных?

Лучший вариант наверно будет добавлять или убавлять коррекцию к рассчитанной уставке.
И 20 переменных это лишнее, 10 точек за глаза. Иногда даже уменьшают до 2-4 точек.

1exan
25.02.2025, 12:45
Не ожидал такой быстрой реакции! Спасибо всем ответившим!
Перед вызовом функции или макроса значения таблицы перекодировки уже должны быть заполнены, как я понимаю. То есть все пары (Xn, Yn).
Значения Xn редактировать не нужно(константы), они будут идти с фиксированным шагом 5 градусов, например. А вот выходные значения должен вводить пользователь кнопками на дисплее и далее иметь возможность их редактировать в процессе эксплуатации. Как это проще всего реализовать, если будет 20 переменных?

В реальной жизни не нужно такое количество точек. График легко задаётся максимум 6 точками, причём крайние точки могут одновременно являться его "срезками" сверху и снизу.
Таким образом, вам понадобится 6 пар переменных. Лучше иметь возможность изменять все значения

EFrol
25.02.2025, 13:11
Ну, если очень хочется, то я бы сделал так:


function PLAst: real;

var_input
Y0, Y1, Y2, Y3, Y4, Y5, Y6, Y7, Y8, Y9, Y10: real;
Y11, Y12, Y13, Y14, Y15, Y16, Y17, Y18, Y19, Y20: real;
X: real;
end_var

var
i: udint;
ri: real;
end_var

for i := 0 to 20 do
ri := udint_to_real(i);
if X * ri >= 5 * ri and X * ri < (ri + 1) * 5 then exit; end_if
end_for

case i of
0: PLAst := Y0 + (Y1 - Y0) / 5 * (X - (5 * ri));
1: PLAst := Y1 + (Y2 - Y1) / 5 * (X - (5 * ri));
2: PLAst := Y2 + (Y3 - Y2) / 5 * (X - (5 * ri));
3: PLAst := Y3 + (Y4 - Y3) / 5 * (X - (5 * ri));
4: PLAst := Y4 + (Y5 - Y4) / 5 * (X - (5 * ri));
5: PLAst := Y5 + (Y6 - Y5) / 5 * (X - (5 * ri));
6: PLAst := Y6 + (Y7 - Y6) / 5 * (X - (5 * ri));
7: PLAst := Y7 + (Y8 - Y7) / 5 * (X - (5 * ri));
8: PLAst := Y8 + (Y9 - Y8) / 5 * (X - (5 * ri));
9: PLAst := Y9 + (Y10 - Y9) / 5 * (X - (5 * ri));
10: PLAst := Y10 + (Y11 - Y10) / 5 * (X - (5 * ri));
11: PLAst := Y11 + (Y12 - Y11) / 5 * (X - (5 * ri));
12: PLAst := Y12 + (Y13 - Y12) / 5 * (X - (5 * ri));
13: PLAst := Y13 + (Y14 - Y13) / 5 * (X - (5 * ri));
14: PLAst := Y14 + (Y15 - Y14) / 5 * (X - (5 * ri));
15: PLAst := Y15 + (Y16 - Y15) / 5 * (X - (5 * ri));
16: PLAst := Y16 + (Y17 - Y16) / 5 * (X - (5 * ri));
17: PLAst := Y17 + (Y18 - Y17) / 5 * (X - (5 * ri));
18: PLAst := Y18 + (Y19 - Y18) / 5 * (X - (5 * ri));
19: PLAst := Y19 + (Y20 - Y19) / 5 * (X - (5 * ri));
20: PLAst := Y20;
end_case

end_function


Все Yn на одном экране по порядку.

82186

Валенок
25.02.2025, 17:21
В реальной жизни и 2 точек достаточно. Мин/макс отсечки и линейка между ними. Но тут видимо кому то дальше продаётся и надо солидно, РЭ потолще и тп

FPavel
25.02.2025, 20:05
Вот эквивалент отопительного графика
https://owen.ru/forum/showthread.php?t=40008&p=442717&viewfull=1#post442717

barrymore
26.02.2025, 08:41
Я согласен, что можно обойтись меньшим количеством точек, кроме совета "2 точки и линейка между ними". Если есть готовая таблица или график, то можно подобрать кривую 2-го или 3-го порядка, это понятно. Готовые отопительные графики не подходят, т.к. это не жилой дом в отопительный сезон. В общем это должна получится действующая установка для снятия такого графика, которую будут крутить весь год, и летом тоже - отсюда и большое количество точек. Как сделать функцию или макрос преобразования (t улицы -> уставка) уже подсказали несколько вариантов, а EFrol так вообще привёл готовое решение, спасибо!
Про несколько экранов вопрос был не про OwenLogic, а про текстовый дисплей 16х2 в ПР200. Есть ли способ реализовать редактирование значений Y1..Y20, кроме как создать 20 шт. пользовательских экранов, в каждом из которых редактируется и запоминается отдельный Yn?

1exan
26.02.2025, 08:51
...
Про несколько экранов вопрос был не про OwenLogic, а про текстовый дисплей 16х2 в ПР200. Есть ли способ реализовать редактирование значений Y1..Y20, кроме как создать 20 шт. пользовательских экранов, в каждом из которых редактируется и запоминается отдельный Yn?

В одной строке - две переменных (одна точка), итого 10 строк на экране.
Перебор при редактировании по SEL

EFrol
26.02.2025, 08:52
Вы можете добавить несколько строк в один экран:
82209
Кнопкой "Вниз" экран окно будет перемещаться по списку.

barrymore
26.02.2025, 09:42
Вы можете добавить несколько строк в один экран:
...
Кнопкой "Вниз" экран окно будет перемещаться по списку.
Спасибо, буду пробовать.

capzap
26.02.2025, 20:04
Вот эквивалент отопительного графика
https://owen.ru/forum/showthread.php?t=40008&p=442717&viewfull=1#post442717

возможно мне удалось повторить такую схему


function Heizkurve: real;
// score 0.9996870942820887
var_input
AI : real; // aktuelle Au&#223;entemperatur
S : real; // Steilheit der Heizkurve
end_var
var
W1, W2, W3, W4, W5, W6, W7, W8 : real;
X : real;
end_var
if AI > 20.0 or AI < -20.0 then
Heizkurve := 3.402824E+38;
else
W1 := AI * -0.5792829739656218 + S * 8.015604080755882 + 6.281415373836082;
W2 := AI * -0.1692977030392752 + S * 3.3858575796086994 + -9.311180708307369;
W3 := AI * 1.1769132063530134 + S * 7.517901746254371 + 2.1254538882211627;
W4 := AI * -1.3167052124322038 + S * -2.3755200888180275 + 3.908753505986686;
W5 := AI * 0.33338979527765633 + S * 1.7309160008410338 + -5.72290446661017;
W6 := AI * 0.26902841638508385 + S * 1.2046862153870057 + -6.681275113428686;
W7 := AI * -1.5964554880439357 + S * 9.825191062779632 + 2.4977526907954655;
W8 := AI * 1.0901116668885527 + S * -2.401026994687886 + 3.649515318025436;
if W1 <= 0.0 then W1 := 0.0; end_if;
if W2 <= 0.0 then W2 := 0.0; end_if;
if W3 <= 0.0 then W3 := 0.0; end_if;
if W4 <= 0.0 then W4 := 0.0; end_if;
if W5 <= 0.0 then W5 := 0.0; end_if;
if W6 <= 0.0 then W6 := 0.0; end_if;
if W7 <= 0.0 then W7 := 0.0; end_if;
if W8 <= 0.0 then W8 := 0.0; end_if;
Heizkurve := W1 * 3.290238717042206 + W2 * -8.296191847174335 + W3 * -1.0406458720895808 + W4 * -2.1549126227294004 + W5 * -3.94738296175786 + W6 * -5.4024513332619035 + W7 * 0.6552893871999437 + W8 * 2.162584768208996 + 5.779520982690067;
end_if;
end_function

Валенок
26.02.2025, 22:38
Норм народ резвится. Для флоата32 задать 16 знаков это сильно.


можно подобрать кривую 2-го или 3-го порядка, это понятно

Мало! Мало порядков. Но на что не пойдешь лишь бы 3х ходовый не ставить.


Цель: нагрев котла до температуры, зависящей от уличной температуры. Чем холоднее на улице, тем горячее котел в помещении.
Цель - нагрев котла, это как цель двигла в машине - поддержать нужный уровень шума. Но у каждого свои цели.

FPavel
26.02.2025, 23:03
Ну, вообще то, комплект КТР-121 поддерживает комбинированный режим погодозависимого регулирования:
- на выходе котла (котлов) поддерживается 70-90 градусов в зависимости от уличной температуры
- в контуре теплосети при помощи трёхходового поддерживается 35-90 градусов в зависимости от уличной температуры

Мы же не знаем, какая структура управления у автора темы...

В макросе по ссылке формула чуть попроще, но число разрядов тоже велико - это связано со степенью полинома.
Heizkurve из макроса

82216

Валенок
26.02.2025, 23:24
- на выходе котла (котлов) поддерживается 70-90 градусов в зависимости от уличной температуры
- в контуре теплосети при помощи трёхходового поддерживается 35-90 градусов в зависимости от уличной температуры

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

Валенок
26.02.2025, 23:28
82216
А где N и S?

barrymore
27.02.2025, 08:21
Мало! Мало порядков. Но на что не пойдешь лишь бы 3х ходовый не ставить.
...
Цель - нагрев котла, это как цель двигла в машине - поддержать нужный уровень шума. Но у каждого свои цели.
Вы предложили линейную зависимость - это кривая первого порядка. Константа - нулевого. Не всегда достаточно линейной функции, но и выше 3-го тоже редко применятся для практических задач. Почему Вы относитесь с сарказмом к обычным решениям?
Заказчик сам теплотехник, знает, что делает, но с программированием - никак. Установка сложнее, чем просто котёл, и 3х ходовой там есть, и не только он.
Мне была поставлена конкретная задача - сделать настраиваемую уставку в зависимости от уличной t, чем я и занимаюсь. У каждого свои цели, это верно.

barrymore
02.04.2025, 11:35
[QUOTE=EFrol;458208]Ну, если очень хочется, то я бы сделал так:


function PLAst: real;

var_input
Y0, Y1, Y2, Y3, Y4, Y5, Y6, Y7, Y8, Y9, Y10: real;
Y11, Y12, Y13, Y14, Y15, Y16, Y17, Y18, Y19, Y20: real;
X: real;
end_var

var
i: udint;
ri: real;
end_var

for i := 0 to 20 do
ri := udint_to_real(i);
if X * ri >= 5 * ri and X * ri < (ri + 1) * 5 then exit; end_if
end_for

case i of
0: PLAst := Y0 + (Y1 - Y0) / 5 * (X - (5 * ri));
1: PLAst := Y1 + (Y2 - Y1) / 5 * (X - (5 * ri));
2: PLAst := Y2 + (Y3 - Y2) / 5 * (X - (5 * ri));
3: PLAst := Y3 + (Y4 - Y3) / 5 * (X - (5 * ri));
4: PLAst := Y4 + (Y5 - Y4) / 5 * (X - (5 * ri));
5: PLAst := Y5 + (Y6 - Y5) / 5 * (X - (5 * ri));
6: PLAst := Y6 + (Y7 - Y6) / 5 * (X - (5 * ri));
7: PLAst := Y7 + (Y8 - Y7) / 5 * (X - (5 * ri));
8: PLAst := Y8 + (Y9 - Y8) / 5 * (X - (5 * ri));
9: PLAst := Y9 + (Y10 - Y9) / 5 * (X - (5 * ri));
10: PLAst := Y10 + (Y11 - Y10) / 5 * (X - (5 * ri));
11: PLAst := Y11 + (Y12 - Y11) / 5 * (X - (5 * ri));
12: PLAst := Y12 + (Y13 - Y12) / 5 * (X - (5 * ri));
13: PLAst := Y13 + (Y14 - Y13) / 5 * (X - (5 * ri));
14: PLAst := Y14 + (Y15 - Y14) / 5 * (X - (5 * ri));
15: PLAst := Y15 + (Y16 - Y15) / 5 * (X - (5 * ri));
16: PLAst := Y16 + (Y17 - Y16) / 5 * (X - (5 * ri));
17: PLAst := Y17 + (Y18 - Y17) / 5 * (X - (5 * ri));
18: PLAst := Y18 + (Y19 - Y18) / 5 * (X - (5 * ri));
19: PLAst := Y19 + (Y20 - Y19) / 5 * (X - (5 * ri));
20: PLAst := Y20;
end_case

end_function


Здравствуйте!
Начал помаленьку разбираться с задачей. Не вижу, где в Вашем примере задаётся нижняя граница t, с которой сравнивается Х ?
Нижний порог согласован: -50
Если Х<-50, то уставка = Y0
Если -50<= Х <-45, то уставка = Y0 + (Y1-Y0)*(X - (-50)) / 5
Если -45<= Х <-40, то уставка = Y1 + (Y2-Y1)*(X - (-45)) / 5
...
Получается, в функцию надо добавить константу base := -50
И выход рассчитывать так: 0: PLAst := Y0 + (Y1 - Y0) / 5 * (X - (5 * ri + base));
Но надо и вход как-то подправить, чтоб правильно попадать в нужные Y(n)..Y(n+1), пока не понимаю как это сделать.

EFrol
02.04.2025, 13:10
Можно и c базовой:


function PLAst: real;

var_input
Y0, Y1, Y2, Y3, Y4, Y5, Y6, Y7, Y8, Y9, Y10: real;
Y11, Y12, Y13, Y14, Y15, Y16, Y17, Y18, Y19, Y20: real;
X: real; // Текущая
end_var

var
i: udint; // Номер отрезка
dX: real; // Смещение от начала отрезка
base: real := -50.0; // Базовая
end_var

if X < base then // Меньше базовой
i := 0;
else // Больше базовой - определяем номер отрезка
for i := 1 to 20 do // Проверяем каждый отрезок
// Если X попадает в отрезок - определяем смещения от начала отрезка и выходим из цикла
if X < base + 5 * udint_to_real(i) then
dX := X - base - 5 * udint_to_real(i - 1); exit;
end_if
// В i будет номер найденного отрезка
end_for
end_if

if X > base + 5 * 20 then i := 21; end_if // X выходит за диапазон

// Определяем значение Y
case i of
0: PLAst := Y0; // Меньше базовой
1: PLAst := Y0 + (Y1 - Y0) / 5 * dX;
2: PLAst := Y1 + (Y2 - Y1) / 5 * dX;
3: PLAst := Y2 + (Y3 - Y2) / 5 * dX;
4: PLAst := Y3 + (Y4 - Y3) / 5 * dX;
5: PLAst := Y4 + (Y5 - Y4) / 5 * dX;
6: PLAst := Y5 + (Y6 - Y5) / 5 * dX;
7: PLAst := Y6 + (Y7 - Y6) / 5 * dX;
8: PLAst := Y7 + (Y8 - Y7) / 5 * dX;
9: PLAst := Y8 + (Y9 - Y8) / 5 * dX;
10: PLAst := Y9 + (Y10 - Y9) / 5 * dX;
11: PLAst := Y10 + (Y11 - Y10) / 5 * dX;
12: PLAst := Y11 + (Y12 - Y11) / 5 * dX;
13: PLAst := Y12 + (Y13 - Y12) / 5 * dX;
14: PLAst := Y13 + (Y14 - Y13) / 5 * dX;
15: PLAst := Y14 + (Y15 - Y14) / 5 * dX;
16: PLAst := Y15 + (Y16 - Y15) / 5 * dX;
17: PLAst := Y16 + (Y17 - Y16) / 5 * dX;
18: PLAst := Y17 + (Y18 - Y17) / 5 * dX;
19: PLAst := Y18 + (Y19 - Y18) / 5 * dX;
20: PLAst := Y19 + (Y20 - Y19) / 5 * dX;
21: PLAst := Y20; // Выходит за диапазон
end_case

end_function

Dimensy
02.04.2025, 14:01
Можно и c базовой:


function PLAst: real;

var_input
Y0, Y1, Y2, Y3, Y4, Y5, Y6, Y7, Y8, Y9, Y10: real;
Y11, Y12, Y13, Y14, Y15, Y16, Y17, Y18, Y19, Y20: real;
X: real; // Текущая
end_var

var
i: udint; // Номер отрезка
dX: real; // Смещение от начала отрезка
base: real := -50.0; // Базовая
end_var

if X < base then // Меньше базовой
i := 0;
else // Больше базовой - определяем номер отрезка
for i := 1 to 20 do // Проверяем каждый отрезое
// Если X попадает в отрезок - определяем смещения от начала отрезка и выходим из цикла
if X >= base + 5 * udint_to_real(i - 1) and X < base + 5 * udint_to_real(i) then
dX := X - base - 5 * udint_to_real(i - 1); exit;
end_if
// В i будет номер найденного отрезка
end_for
end_if

if X > base + 5 * 20 then i := 21; end_if // X выходит за диапазон

// Определяем значение Y
case i of
0: PLAst := Y0; // Меньше базовой
1: PLAst := Y0 + (Y1 - Y0) / 5 * dX;
2: PLAst := Y1 + (Y2 - Y1) / 5 * dX;
3: PLAst := Y2 + (Y3 - Y2) / 5 * dX;
4: PLAst := Y3 + (Y4 - Y3) / 5 * dX;
5: PLAst := Y4 + (Y5 - Y4) / 5 * dX;
6: PLAst := Y5 + (Y6 - Y5) / 5 * dX;
7: PLAst := Y6 + (Y7 - Y6) / 5 * dX;
8: PLAst := Y7 + (Y8 - Y7) / 5 * dX;
9: PLAst := Y8 + (Y9 - Y8) / 5 * dX;
10: PLAst := Y9 + (Y10 - Y9) / 5 * dX;
11: PLAst := Y10 + (Y11 - Y10) / 5 * dX;
12: PLAst := Y11 + (Y12 - Y11) / 5 * dX;
13: PLAst := Y12 + (Y13 - Y12) / 5 * dX;
14: PLAst := Y13 + (Y14 - Y13) / 5 * dX;
15: PLAst := Y14 + (Y15 - Y14) / 5 * dX;
16: PLAst := Y15 + (Y16 - Y15) / 5 * dX;
17: PLAst := Y16 + (Y17 - Y16) / 5 * dX;
18: PLAst := Y17 + (Y18 - Y17) / 5 * dX;
19: PLAst := Y18 + (Y19 - Y18) / 5 * dX;
20: PLAst := Y19 + (Y20 - Y19) / 5 * dX;
21: PLAst := Y20; // Выходит за диапазон
end_case

end_function


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

if X < X[i]

EFrol
02.04.2025, 14:53
Да. Если есть выход из цикла, то можно.

FPavel
02.04.2025, 19:44
А если номер отрезка определять делением?

EFrol
02.04.2025, 20:59
А если номер отрезка определять делением?

Отличное предложение!!!


function PLAst: real;

var_input
Y0, Y1, Y2, Y3, Y4, Y5, Y6, Y7, Y8, Y9, Y10: real;
Y11, Y12, Y13, Y14, Y15, Y16, Y17, Y18, Y19, Y20: real;
X: real; // Текущая
end_var

var
i: udint; // Номер отрезка
dX: real; // Смещение от начала отрезка
base: real := -50.0; // Базовая
end_var

if X < base then // Меньше базовой
i := 0;
else // Больше базовой - определяем номер отрезка
i := real_to_udint(X - base) / 5 + 1;
if i > 20 then i := 21; else dX := X - base - 5 * udint_to_real(i - 1); end_if
end_if

// Определяем значение Y
case i of
0: PLAst := Y0; // Меньше базовой
1: PLAst := Y0 + (Y1 - Y0) / 5 * dX;
2: PLAst := Y1 + (Y2 - Y1) / 5 * dX;
3: PLAst := Y2 + (Y3 - Y2) / 5 * dX;
4: PLAst := Y3 + (Y4 - Y3) / 5 * dX;
5: PLAst := Y4 + (Y5 - Y4) / 5 * dX;
6: PLAst := Y5 + (Y6 - Y5) / 5 * dX;
7: PLAst := Y6 + (Y7 - Y6) / 5 * dX;
8: PLAst := Y7 + (Y8 - Y7) / 5 * dX;
9: PLAst := Y8 + (Y9 - Y8) / 5 * dX;
10: PLAst := Y9 + (Y10 - Y9) / 5 * dX;
11: PLAst := Y10 + (Y11 - Y10) / 5 * dX;
12: PLAst := Y11 + (Y12 - Y11) / 5 * dX;
13: PLAst := Y12 + (Y13 - Y12) / 5 * dX;
14: PLAst := Y13 + (Y14 - Y13) / 5 * dX;
15: PLAst := Y14 + (Y15 - Y14) / 5 * dX;
16: PLAst := Y15 + (Y16 - Y15) / 5 * dX;
17: PLAst := Y16 + (Y17 - Y16) / 5 * dX;
18: PLAst := Y17 + (Y18 - Y17) / 5 * dX;
19: PLAst := Y18 + (Y19 - Y18) / 5 * dX;
20: PLAst := Y19 + (Y20 - Y19) / 5 * dX;
21: PLAst := Y20; // Выходит за диапазон
end_case

end_function

barrymore
03.04.2025, 10:00
Отличное предложение!!!

if i > 20 then i := 21; else dX := X - base - 5 * udint_to_real(i - 1); end_if

Спасибо!
После сравнения последних вариантов, надеюсь я разобрался, как они работают.
Если операция MOD работает с типом real, то нахождение dX можно упростить до
dX := X mod 5
Проверил, ошибок нет, в железе ещё не проверял.
PS: Нет, не прокатило. MOD работает только с целыми числами.

Возникла ещё ошибка/предупреждение при подключении макроса Pt1000 из онлайн базы.
Там было подключение с выхода на вход в блоке SEL_FLOAT2, заменил на линию задержки.
82849

barrymore
08.04.2025, 07:56
Всё получилось, больше всего времени ушло на пользовательское меню: вывод значений, сообщение о неисправных датчиках и настройка параметров.
В процессе понадобилось добавить гистерезис, и чтобы не изобретать велосипед, решил воспользовался поиском на этом форуме. Результатов много, но в выдаче не конкретные сообщения, а только темы с десятками-сотнями страниц. На тот момент я не разобрался в поиске, можно выводить темы, а можно сообщения. В общем, сделал по своему:
82949
За пределами скриншота только чуть изменённый макрос PLAst от EFrol. Кстати, насчёт высоких порядков - в макросе Pt1000 из онлайн базы используется кв.корень, 1, 2, 3 и 4-я степень входного параметра. И самодельные макросы SEL_FLOAT - наверное на момент написания Pt1000 ещё не было встроенных fSEL и SEL.