PDA

Просмотр полной версии : Создать функцию на ST



Страницы : 1 2 [3]

lagutin
30.12.2022, 09:49
Наверное, выходит, к целым нельзя пока применять побитовые операции

EFrol
30.12.2022, 10:53
Когда нельзя, но очень хочется, то ... ;)

64963

64964

melky
30.12.2022, 12:18
При этом если не ошибаюсь можно использовать просто AND без всякого ST

Сергей0308
30.12.2022, 12:28
При этом если не ошибаюсь можно использовать просто AND без всякого ST

Говорят, что уже нельзя!
Тогда мне непонятно как работают ранее сделанные проекты, у меня практически в каждом проекте такое используется!

melky
30.12.2022, 12:41
Матерюсь, при отсутствии прибора и выбора COM порт программа ТУПИТ безбожно, разработчики, почините что ли...

Можно вроде, версия 2.ххх

capzap
30.12.2022, 13:57
Можно вроде, версия 2.ххх

Ни чего что тема про ST

melky
30.12.2022, 14:41
capzap речь о том, что почему-то на ST не реализован AND с целочисленными в виде простого & , хотя в FB он работает.

Филоненко Владислав
31.12.2022, 22:18
capzap речь о том, что почему-то на ST не реализован AND с целочисленными в виде простого & , хотя в FB он работает.

Потому что это язык ST, а не C

melky
01.01.2023, 09:26
Филоненко Владислав С наступившим вас Новым(текущим) Годом :)

Как коня не назови, & или AND OR NOT, а ехать оно не хочет, судя по предыдущей странице.... при этом поставив кубик AND все работает как и задумано

wwowa
05.01.2023, 20:39
Включение и выключение насосов. Возможность вывода в ремонт. Общее число насосов можно задать вверху холста. В общем то в этом и был весь смысл. Аварии не реализованы, но это уже детали.
Чисто эксперимент.https://disk.yandex.ru/d/9A0zyGGd2R9Wwg

wwowa
07.01.2023, 21:20
Решил сделать сортировку. Объясните мне, что значит переменная udint 4 байта? Это я так понимаю что это 32 веса от 0 до 31... По справке это максимальное число 4*294*967*295. По калькулятору это 32 единички.. Все сходится. Но при попытке присвоить значение функции f.31:= true пишет ошибку "или маленькое или большое число"(это мой перевод:rolleyes:).
Объясните, где я не догоняю то???https://disk.yandex.ru/d/043NgOt7q9Ercg

capzap
07.01.2023, 21:55
Пробовали присвоить единицу?

Dimensy
07.01.2023, 22:40
Решил сделать сортировку. Объясните мне, что значит переменная udint 4 байта? Это я так понимаю что это 32 веса от 0 до 31... По справке это максимальное число 4*294*967*295. По калькулятору это 32 единички.. Все сходится. Но при попытке присвоить значение функции f.31:= true пишет ошибку "или маленькое или большое число"(это мой перевод:rolleyes:).
Объясните, где я не догоняю то???https://disk.yandex.ru/d/043NgOt7q9Ercg

Похоже еще один косяк ST обнаружился

capzap
07.01.2023, 23:37
Похоже еще один косяк ST обнаружился

у Вас тоже проявляется ошибка? Как она выглядит скрином покажите 65033

Dimensy
07.01.2023, 23:53
у Вас тоже проявляется ошибка? Как она выглядит скрином покажите 65033

65034


function function1: udint; //имя функции и тип данных выхода
var_input //объявление входных переменных
inputVariable : bool; //входная переменная с типом данных bool
end_var



function1.31 := inputVariable;

end_function

при этом

unction function1: udint; //имя функции и тип данных выхода
var_input //объявление входных переменных
inputVariable : bool; //входная переменная с типом данных bool
end_var



function1.30 := inputVariable;

end_function

отрабатывает нормально

65035

kondor3000
08.01.2023, 00:28
Это очередной БАГ на ST, на 10 Винде выглядит по другому
function1.30 :=true ; работает нормально 65038

Если function1.31 :=true ; то ошибка 65036

Если написать function1.31 :=1 ; то критическая ошибка 65037

wwowa
08.01.2023, 08:11
У меня не работает никак. Как бы я пытался что то присвоить 31 биту - сразу ошибка. И при прибавлении 2147483648 - тоже....
Это сторожевой бит)) какой то.
Вот еще цикл. Написано в справке везде во всех позициях в цикле выражения. Но вот так
for i := 0 to i<8 do тоже не дает. Говорит на месте i<8 должно быть целое. Наверное, урезали криво.
И обратится к биту по переменной тоже не дает f.var:= true -нельзя....
И без отладки тоже беда.:o Ну можно в кодесис наваять и отладить, а тут получится и то нельзя и то....
Но как то массивы есть, а какой то ерунды нет или глючит? ну как это так то????
"ps" содесис позволяет обратится к 31 биту
65039

capzap
08.01.2023, 09:27
ну раз появились проблемы с 31 разрядом, значит начались некие работы по использованию отрицательных целочисленных

wwowa
08.01.2023, 20:10
65042
На "от нуля до пока меньше 8" чё должна сказать ?

Должна провести цикл от нуля до 7... Это очень удобно, особенно при работе с массивами и прочими.
Как то так
for (var i = 0; i < items.length - 1; i++)
Ошибок на порядок уменьшается. Но в ST нет. Ну нет и нет...Чего уж тут теперь.
А что у вас присваивается 31 бит, а у меня нет - это еще хуже. У кого работает, у кого нет. Стабильности нет. В мире стабильности нет, в лоджике нет. Перебор, однако:o

lagutin
09.01.2023, 09:02
Здравствуйте! Вот такой вопрос. Два вложенных цикла. При переборе до 2500 - пишет бесконечный цикл. При 1000 уже считает все. А на основании каких данных цикл считается бесконечным, или он уложится в цикл программы. В содесис, насколько я почитал и понял есть сторожевой таймер. А здесь как то просчитать можно?

lagutin
11.01.2023, 17:02
Фоновая сортировка. https://cloud.mail.ru/public/JBy8/eQz4xByVK

ПавелП
09.02.2023, 23:34
Привет всем!

Делал кто "перевод" макросов на язык ST ?
Иногда надо подправить малость - мне проще в ST. :)

Вот попробовал с ходу перевести:
Преобразователь диапазона с ограничением SCALE.
Получаются разные результаты...

CompareADC:= (InADCa*((InMAX-InMIN)/(UotMAX-UotMIN))) - (InMIN*UotMAX-InMAX*UotMIN)/(UotMAX-UotMIN) ;
или ещё
CompareADC:= InMIN + (InADCa - UotMIN) * ( InMAX - InMIN )/(UotMAX - UotMin);

Чёт первый блин не получается...

InMIN, InMAX - предел входного параметра,
UotMIN, UotMAX - предел выходного параметра,
InADCa - входной сигнал,
CompareADC - выход.

capzap
10.02.2023, 08:25
Привет всем!

Делал кто "перевод" макросов на язык ST ?
Иногда надо подправить малость - мне проще в ST. :)

Вот попробовал с ходу перевести:
Преобразователь диапазона с ограничением SCALE.
Получаются разные результаты...[B]
установите КДС, воспользуйтесь одноименной библиотекой на oscat.de, там все функции на языке ST, адаптировать их под ОЛ куда проще чем с квадратиков переводить

ПавелП
10.02.2023, 08:52
установите КДС, воспользуйтесь одноименной библиотекой на oscat.de, там все функции на языке ST, адаптировать их под ОЛ куда проще чем с квадратиков переводить
Порылся, нашёл (https://ftp.owen.ru/CoDeSys3/98_Books/oscat_basic333_ru.pdf), посмотрел.
Много всего. Инфы поболее, чем с нуля начинать.

Спасибо! :)

ПавелП
10.02.2023, 08:55
Макросы уже есть на ST ?
Все REAL ?

математики, ля
прогеры, ля
постановщики задач, ля

:)

Первый раз, в первый класс...
Дали люди ссылку, будет поболее инфы, и меньше вопросов!

melky
10.02.2023, 09:24
double Scaler (double input, double in_min, double in_max, double out_min, double out_max)

{
double out1 = 0;
double out2 = 0;
double output = 0;
double diff = in_max - in_min;

if (diff != 0)
{
if (input > in_max) out1 = in_max;
else out1 = input;
if (in_min > out1) out2 = in_min;
else out2 = out1;
output = (out_max - out_min) / diff * (out2 - in_min) + out_min;
}
return output;
}

Скалирование на C#, вроде делал когда-то именно с oscat. хотя и не помню уже. Синтаксис примените СТшный.

ПавелП
11.02.2023, 01:30
Макросы уже есть на ST ?
Все REAL ?


математики, ля

CompareADC := (InADCa - InMIN) / (InMAX - InMIN) * (UotMAX - UotMin) + UotMin
[/CODE]
Всё работает!!! Совпадает с эталоном.

Спасибо! :)

ПавелП
11.02.2023, 01:33
double Scaler (double input, double in_min, double in_max, double out_min, double out_max)

{
double out1 = 0;
double out2 = 0;
double output = 0;
double diff = in_max - in_min;

if (diff != 0)
{
if (input > in_max) out1 = in_max;
else out1 = input;
if (in_min > out1) out2 = in_min;
else out2 = out1;
output = (out_max - out_min) / diff * (out2 - in_min) + out_min;
}
return output;
}

Скалирование на C#, вроде делал когда-то именно с oscat. хотя и не помню уже. Синтаксис примените СТшный.
Подошло.
Только контроль пределов не нужен.
Раз оттарировал, и заработало!
Спасибо! :)

ПавелП
11.02.2023, 01:46
установите КДС, воспользуйтесь одноименной библиотекой на oscat.de, там все функции на языке ST, адаптировать их под ОЛ куда проще чем с квадратиков переводить

Хм. Пролистал внимательно - оч интересно.
Много полезностей, нужное проверил - всё работает (https://ftp.owen.ru/CoDeSys3/98_Books/oscat_basic333_ru.pdf).

Прочитал шапку файла, и побродил по ссылкам:
1. 10 лет прошло, часть ссылок оттуда сдохла.
2. ST где-то рядом. Все решения достаточно описаны, но без исходников.
3. У некоторых макросов есть исходные формулы.

4. Винегрет из CFC, ST придётся городить.
Что, впрочем, позволит решить нужные задачи.

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

Cs-Cs
11.02.2023, 11:30
ПавелП
Все решения достаточно описаны, но без исходников Если речь идёт про OSCAT для CDS 2.3, то его надо не добавить в проект (тогда только шапка видна), а именно открыть как библиотеку. Тогда все исходники видны. Но написаны они ужасно. Без комментариев и с фиг какими именами переменных.
65842

kondor3000
11.02.2023, 11:42
Надо библиотеку открыть как проект, и скопировать код из блоков.

ПавелП
11.02.2023, 14:48
ПавелП Если речь идёт про OSCAT для CDS 2.3, то его надо не добавить в проект (тогда только шапка видна), а именно открыть как библиотеку. Тогда все исходники видны. Но написаны они ужасно. Без комментариев и с фиг какими именами переменных.
65842
Выходные. Посмотрел повнимательнее.
Вообще-то, если назначение и алгоритм понятные, то
в простых макросах разобраться можно.

Но есть монстры очень сложные.
Но они то и не очень нужны. :)

ПавелП
11.02.2023, 14:50
Надо библиотеку открыть как проект, и скопировать код из блоков.
Всё так. Я про комментарии.

Всё заметно упрощается, когда есть возможность
не "сидеть" в рамках макроса, а подкрутить его в свою сторону. :)

ПавелП
14.02.2023, 21:27
Привет всем.

Петренко опубликовал с год назад толковый пример (http://www.youtube.com/watch?v=Q6ETFE6dr4g)
"Овен ПЛК 110-М02 сохранение переменных REAL на USB FLASH в Excel"
но, как всегда, самое интересное утаил... :(

Макрос позволяет указанные переменные писать в лог фай на внешнюю флешку в формате Excel.
Где такое взять? Хоть в текстовый файл.

Есть описание Navigator_PLC_DVD_v3\04. Библиотеки\2022\Описание\OwenLibFileAsync.pdf.
Но там с ходу в 10 листах трудно разобраться.

capzap
14.02.2023, 22:10
Привет всем.

Петренко опубликовал с год назад толковый пример (http://www.youtube.com/watch?v=Q6ETFE6dr4g)
"Овен ПЛК 110-М02 сохранение переменных REAL на USB FLASH в Excel"
но, как всегда, самое интересное утаил... :(

Макрос позволяет указанные переменные писать в лог фай на внешнюю флешку в формате Excel.
Где такое взять? Хоть в текстовый файл.

Есть описание Navigator_PLC_DVD_v3\04. Библиотеки\2022\Описание\OwenLibFileAsync.pdf.
Но там с ходу в 10 листах трудно разобраться.

Причем здесь, в теме про реле, разговор по плк?

ПавелП
14.02.2023, 23:14
Причем здесь, в теме про реле, разговор по плк?

Тема: Создать функцию на ST (https://owen.ru/forum/showthread.php?t=35489&page=54)

Игорюня
15.02.2023, 05:34
Форум * Программируемые устройства ОВЕН * Среда программирования OWEN Logic * Создать функцию на ST

capzap
15.02.2023, 09:00
Тема: Создать функцию на ST (https://owen.ru/forum/showthread.php?t=35489&page=54)

ну так не о плк же речь, а о среде разработки, из которой можно взять исходники и адаптировать в другую среду. И включите логику, для работы с файлами нужен дескриптор, он должен быть запомнен до конца работы с файлом, а функции такой возможностью не обладают, да и нет в ПР разъема для подключения флешек

ПавелП
15.02.2023, 10:17
ну так не о плк же речь, а о среде разработки, из которой можно взять исходники и адаптировать в другую среду. И включите логику, для работы с файлами нужен дескриптор, он должен быть запомнен до конца работы с файлом, а функции такой возможностью не обладают, да и нет в ПР разъема для подключения флешекДействительно чуть промазал. :)

Сижу в двух системах: ПР200 4 шт, и ПЛК110/160...

capzap
15.02.2023, 10:21
и ПЛК110/160...
то что показано на видео это обычная запись строки в конец файла, имя которому что_то_там.csv
И указанием винде что csv файлы открывать екселем

ПавелП
15.02.2023, 11:05
то что показано на видео это обычная запись строки в конец файла, имя которому что_то_там.csv
И указанием винде что csv файлы открывать екселем

Спасибо! :)
Я уже перебрался с этим вопросом, в тему (https://owen.ru/forum/showthread.php?t=27316&p=401276&viewfull=1#post401276) - посмотрю что подскажут.

IVM
30.04.2023, 15:11
ST вариант моего макроса PLA (кусочно-линейная аппроксимация) по мотивам https://owen.ru/forum/showthread.php?t=10555&p=220263&viewfull=1#post220263
график по 10 точкам, метод поиска делением интервала пополам, известный также как двоичный поиск или Дихотомия (https://ru.wikipedia.org/wiki/Дихотомия)

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

58155

petera, зачем такие сложности. Температурный график достаточно прост (см.картинку). Таким образом, достаточно знать координаты двух точек перегиба графика.

Shiryaevo
01.05.2023, 14:17
Добрый вечер! Конечный автомат сделать можно. На входе создаете переменную, например, PrevState. И с помощью "линии задержки" передаете выходное значение Q (UDInt - код шага в автомате) на вход. Таким образом при вызове функция узнает на каком шаге автомата она остановилась в прошлом цикле. Внутри делаете CASE по PrevState и все. Получился такой себе FB с хранением предыдущего состояния "снаружи". Все таймеры внешние. Если шаг =10, то таймер 1 запустить. Таймер через время задержки Т выдает TRUE на вход функции. Управление исполнительными механизмами - по номеру состояний. 5818158182

Интерсное применение рекурсии :)
красиво!

Алексаныч
30.05.2023, 07:13
Здравствуйте. Пишу здесь первый раз. Просто хочется разобраться. У нас на производстве наливают, бочки, кубы, цистерны. И по запросу операторов им нужны переносные пульты для включение и отключение насосов, да еще и реверс. Так как за разумные деньги только ПКТ, но у него два нормально открытых. Сделал систему на ПР. Решил сделать так, чтобы при нажатии любой кнопки "Вперед" или "Назад" при работающем насосе, насос отключался. Пробовал написать несколько программ. Так вот получился у меня интересный случай. Одна функция нормально работает, как я и хотел. Другая не в какую. Кто-нибудь может помочь разобраться? Файл и код прилагаю
Эта функция не работает.

function motorvper: bool; //имя функции и тип данных выхода
var_input //объявление входных переменных
//входная переменная с типом данных bool
vper : bool;
nazad : bool;
puskv : bool;
puskn : bool;
end_var

var //объявление локальных переменных
end_var

if vper=true or puskv=true and nazad=false and puskn=false then motorvper := true;
end_if

if vper=true or nazad=true and puskv=true then motorvper := false ;
end_if

end_function
А эта работает.

function motornazad: bool; //имя функции и тип данных выхода
var_input //объявление входных переменных
vpered : bool;//входная переменная с типом данных bool
nazad : bool;
puskv : bool;
puskn : bool;
end_var

var //объявление локальных переменных
end_var

if nazad=true or puskn=true and vpered=false and puskv=false then motornazad := true;
end_if

if vpered=true or nazad=true and puskn=true then motornazad := false;
end_if

end_function

Cs-Cs
30.05.2023, 08:07
Алексаныч
при нажатии любой кнопки "Вперед" или "Назад" при работающем насосе, насос отключался
Так а если без функции делать? Взять R_TRIG по нажатию на кнопки и AND с выходом насоса? А насосом управлять по RS-триггеру (с приоритетом R)?
То есть, описать условие "Если прошёл импульс наражтия кнопки И насос работает - выключить".

Валенок
30.05.2023, 08:40
Вторые строчки в топку
Сравнение с труе/фальсе в топку
Явные скобки в логических выражениях
И разберетесь

kondor3000
30.05.2023, 08:51
Здравствуйте. Пишу здесь первый раз. Просто хочется разобраться. У нас на производстве наливают, бочки, кубы, цистерны. И по запросу операторов им нужны переносные пульты для включение и отключение насосов, да еще и реверс. Так как за разумные деньги только ПКТ, но у него два нормально открытых. Сделал систему на ПР. Решил сделать так, чтобы при нажатии любой кнопки "Вперед" или "Назад" при работающем насосе, насос отключался. Пробовал написать несколько программ. Так вот получился у меня интересный случай. Одна функция нормально работает, как я и хотел. Другая не в какую. Кто-нибудь может помочь разобраться? Файл и код прилагаю
Эта функция не работает.

У вас в обеих функциях, последние IF одинаковые, а должны быть разные.


// if vper=true or nazad=true and puskv=true then motorvper := false ; //Это ваш код
// end_if

if nazad or vper and puskv then motorvper := false ; // рабочий код
end_if
end_function

И линии задержки сделайте, вместо жёлтых линий
А можно вторые IF вообще выбросить в обеих, тоже работать будет.

Алексаныч
30.05.2023, 10:04
Алексаныч
Так а если без функции делать? Взять R_TRIG по нажатию на кнопки и AND с выходом насоса? А насосом управлять по RS-триггеру (с приоритетом R)?
Да можно. Интересно было написать на ST. Скажем честно я в нем профан и поэтому познаю потихоньку.


У вас в обеих функциях, последние IF одинаковые, а должны быть разные.


// if vper=true or nazad=true and puskv=true then motorvper := false ; //Это ваш код
// end_if
if nazad or vper and puskv then motorvper := false ; // рабочий код
end_if
end_function

И линии задержки сделайте, вместо жёлтых линий
А можно вторые IF вообще выбросить в обеих, тоже работать будет.
Спасибо. Буду дальше разбираться в ST.

kondor3000
30.05.2023, 10:15
Интересно было написать на ST. Скажем честно я в нем профан и поэтому познаю потихоньку.
Спасибо. Буду дальше разбираться в ST.
Можно обе функции записать без IF, по совету Валенка


motorvper:=(vper or puskv and not nazad); // 1 функция

motornazad:=(nazad or puskn and not vpered); // 2 функция

Алексаныч
30.05.2023, 10:54
Можно обе функции записать без IF, по совету Валенка


motorvper:=(vper or puskv and not nazad); // 1 функция

motornazad:=(nazad or puskn and not vpered); // 2 функция

Да если бы он вот так объяснил, было бы намного лучше.
Но походу или я тупой или плохо обрисовал задачу. Если вот так прописать, как в первом варианте(даже с линиями задержки, и без вторых IF) или вариант Валенка. То на симуляции это работает так. На примере команды "Вперед". Подается сигнал на первый выход(пуск двигателя вперед). Если нажать повторно кнопку "Вперед" двигатель остановится. Но вот если вместо кнопки "Вперед", нажать "Назад" двигатель не остановится, а мгновенно включиться сигнал на второй выход(пуск двигателя в реверс). А мне надо, чтобы он остановился и уже при следующем нажатии кнопки оператор может запустить двигатель в нужный момент. Просто у нас растительное масло, а оно способно сделать залипании кнопки.

kondor3000
30.05.2023, 13:44
То на симуляции это работает так. На примере команды "Вперед". Подается сигнал на первый выход(пуск двигателя вперед). Если нажать повторно кнопку "Вперед" двигатель остановится. Но вот если вместо кнопки "Вперед", нажать "Назад" двигатель не остановится, а мгновенно включиться сигнал на второй выход(пуск двигателя в реверс). А мне надо, чтобы он остановился и уже при следующем нажатии кнопки оператор может запустить двигатель в нужный момент. Просто у нас растительное масло, а оно способно сделать залипании кнопки.

Тогда схема будет такой 68069
А первая функция будет так

if vper and not puskn or puskv and not nazad then motorvper := true;
end_if
if nazad or vper and puskv then motorvper := false ;
end_if
end_function

Вторая по аналогии сами попробуйте

Dimensy
30.05.2023, 14:43
Да если бы он вот так объяснил, было бы намного лучше.
Но походу или я тупой или плохо обрисовал задачу. Если вот так прописать, как в первом варианте(даже с линиями задержки, и без вторых IF) или вариант Валенка. То на симуляции это работает так. На примере команды "Вперед". Подается сигнал на первый выход(пуск двигателя вперед). Если нажать повторно кнопку "Вперед" двигатель остановится. Но вот если вместо кнопки "Вперед", нажать "Назад" двигатель не остановится, а мгновенно включиться сигнал на второй выход(пуск двигателя в реверс). А мне надо, чтобы он остановился и уже при следующем нажатии кнопки оператор может запустить двигатель в нужный момент. Просто у нас растительное масло, а оно способно сделать залипании кнопки.

Если сделать вот так, то работает

Сергей0308
30.05.2023, 14:47
Мой вариант с защитой от залипания:

68072

68073

Вот добавил блокировку включения реверса на 5 секунд:

68085

Dimensy
30.05.2023, 14:57
Мой вариант с защитой от залипания:

68072



Ну, хочет человек ST.
Вот мой вариант
68074

capzap
30.05.2023, 15:15
мне надо, чтобы он

странное желание "ловить" события с помощью функции, да и сам алгоритм вызывает сомнения, к примеру если операторы начнут совершать двойные нажатия на кнопки. Автоматизация это же не безусловное использование вычислительной техники в любого рода задачах. Кто будет определять что привод действительно остановился, чтоб только после этого задать другое направление. По хорошему всё же должна быть третья кнопка которая просто останавливает процесс, а вперед и назад должны работать по принципу нажал и забыл, автоматом должна происходить парковка(остановка) и смена направления по единственному нажатию, надеюсь ОС с частотника заведена в контроллер

Алексаныч
31.05.2023, 06:29
Всем спасибо. Разобрался. Для себя подчерпнул много нового. Для переживающего о двойном нажатии и резкой смене движения. Еще ни разу не было обращений. Я же эту систему сначала чисто на блоках сделал. Просто как она выглядит на блоках и как с помощью ST это большая разница и если знать нюансы ST и иметь больше опыта легче в создании вразы. А уж при появлении возможности создать функциональный блок, это можно все в один блок запихать.

capzap
31.05.2023, 07:29
Еще ни разу не было обращений.

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

kaftanati
14.06.2023, 15:50
Вопрос: а когда можно будет вставлять st-функции внутрь ФБ?

Danila Kholkin
23.06.2023, 07:47
Ошибка при Включении отладки и использование блока ST
Подскажите с чем это связанно и как этого избежать


System.ArgumentException: Offset and length were out of bounds for the array or count is greater than the number of elements from index to the end of the source collection.
at System.Collections.Generic.List`1.GetRange(Int32 index, Int32 count)
at Owen.ProgrammableRelay.StackBuild.CopyCellsTo(Int3 2 sourceCellIndex, Int32 destCellIndex, Int32 cellsCount)
at ProgramRelayFBD.ApplicationLayer.ST.AnalizeFunctio nElementService.Analize(StFunctionElement element, ProgramCode program, ICompiledFunctionRepository compiledFunctionRepo)
at Owen.General.DomainEvents.RaiseEvent[T](T event, IEnumerable`1 actions)
at ProgramRelayFBD.DomainLayer.OnlineDebugging.Online DebuggingCompilerState.HandleBuildElement(IBuildin gElement element, ProgramCode program, ICompiler compiler)
at Owen.Compiling.ProgramLinker.CompilingElements(Pro gramCode program, IEnumerable`1 elements, CancellationToken cancellationToken)
at ProgramRelayFBD.DomainLayer.Compilers.BaseCompiler .CompilePrograms(ProgramItem programItem, CancellationToken cancellationToken)
at ProgramRelayFBD.DrawingView.<>c__DisplayClass91_0.b__0()
at System.Threading.ExecutionContext.RunFromThreadPoo lDispatchLoop(Thread threadPoolThread, ExecutionContext executionContext, ContextCallback callback, Object state)
--- End of stack trace from previous location ---
at System.Threading.Tasks.Task.ExecuteWithThreadLocal (Task& currentTaskSlot, Thread threadPoolThread)

Денисов Максим Сергеевич
23.06.2023, 07:54
Подскажите, какой сценарий возникновения такой ошибки и на какой версии owen logic?

lagutin
23.06.2023, 10:41
А групповой комментарий есть в редакторе? Что то вот так не комментируется /**/.

Dimensy
23.06.2023, 11:00
А групповой комментарий есть в редакторе? Что то вот так не комментируется /**/.

вот так комментируется (* *)

kondor3000
23.06.2023, 11:20
А групповой комментарий есть в редакторе? Что то вот так не комментируется /**/.

А чем вам // не подходит?

wwowa
24.06.2023, 07:16
(* *). Спасибо. Ну иногда нужно и часть кода закомментировать. Одиночным долго. Вот откуда они взяли вот это(* *)? Везде, если погуглить, комментарии в ST /**/.

Dimensy
24.06.2023, 09:04
(* *). Спасибо. Ну иногда нужно и часть кода закомментировать. Одиночным долго. Вот откуда они взяли вот это(* *)? Везде, если погуглить, комментарии в ST /**/.

Погуглил :)
68442

Danila Kholkin
26.06.2023, 07:14
Подскажите, какой сценарий возникновения такой ошибки и на какой версии owen logic?

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

добавил проблемный проект

1exan
26.06.2023, 10:58
Версия 2.3.329.0
при включение онлайн отладки и в проекте присутствует блок с написанный на ST возникает такая проблема проверил на другой машине ошибка повторилась . При этом код выполняется корректно, но из-за не возможности отладки пришлось отказаться использовать блоки на ST .

добавил проблемный проект

Ну для такого расчёта ST не очень то и нужен.
И уж не знаю, как на отладку влияет деление на 0, но лучше всё таки этого избегать

Danila Kholkin
26.06.2023, 14:10
Ну для такого расчёта ST не очень то и нужен.
И уж не знаю, как на отладку влияет деление на 0, но лучше всё таки этого избегать

там нет деления на 0 , я попробовал как работать с ST отладка не работает , выход блока как я понял может быть всего 1 что очень ограничивает функционал

1exan
26.06.2023, 17:57
там нет деления на 0 , я попробовал как работать с ST отладка не работает , выход блока как я понял может быть всего 1 что очень ограничивает функционал

Сейчас нет, а завтра может появиться:
68464

А выход у функции здесь только один, да

Danila Kholkin
27.06.2023, 06:45
Сейчас нет, а завтра может появиться:
68464

А выход у функции здесь только один, да

Спасибо с этим как то справимся. Суть только от этого не меняется не работает у меня отладка при использовании блока с ST . И более сложную фикцию разрабатывать желание отпало

1exan
27.06.2023, 08:33
Спасибо с этим как то справимся. Суть только от этого не меняется не работает у меня отладка при использовании блока с ST . И более сложную фикцию разрабатывать желание отпало

У меня онлайн отладка работает, ошибок нет:
68468

Danila Kholkin
27.06.2023, 13:49
У меня онлайн отладка работает, ошибок нет:
68468

Ну Я имею ввиду не на симуляторе а с реальной ПР200 ?

1exan
27.06.2023, 19:15
Ну Я имею ввиду не на симуляторе а с реальной ПР200 ?

Я и пишу - ОНЛАЙН, на ПР200. Правда модификация не .2 а .5, но вряд-ли существенно

TaPX
30.06.2023, 18:17
Добрый вечер. Подскажите, а можно написать на ST функцию, которая возвращает не одно, а несколько значений?

1exan
30.06.2023, 18:30
Добрый вечер. Подскажите, а можно написать на ST функцию, которая возвращает не одно, а несколько значений?

В ST OwenLodgic - нет (если не считать варианта упаковки нескольких значений в одну переменную)

TaPX
30.06.2023, 23:08
В ST OwenLodgic - нет (если не считать варианта упаковки нескольких значений в одну переменную)

Это типа битовой маски?

1exan
01.07.2023, 08:02
Это типа битовой маски?

Можно как по одному биту упаковывать, так и по 2, 3 и т.д.

Andry_EXO-Space
13.10.2023, 21:07
Здравствуйте!
Я прошу прощения, второй день программирую в Овен лоджик. и у меня вопрос:
А почему код на Паскале? почему не ни Си?
Все известное мне железо до этого прогается на Си...

Dimensy
13.10.2023, 21:23
Здравствуйте!
Я прошу прощения, второй день программирую в Овен лоджик. и у меня вопрос:
А почему код на Паскале? почему не ни Си?
Все известное мне железо до этого прогается на Си...

Потому что МЭК 61131-3

Бакдаулет
18.07.2024, 15:43
здраствуйте я в owen logic не могу создать функцию на st ионка просто не активна что делать 77403

Бакдаулет
18.07.2024, 15:45
И еще вопрос мне поручили задание считать данные с пр100 как это сделать ?

Королев Кирилл
18.07.2024, 16:12
здраствуйте я в owen logic не могу создать функцию на st ионка просто не активна что делать 77403

Уточните, пожалуйста, какой у Вас прибор? Если ПР100, то обращаю Ваше внимание, что создание функций и ФБ на языке ST доступно только для приборов с индексом М02.


И еще вопрос мне поручили задание считать данные с пр100 как это сделать ?

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

Бакдаулет
18.07.2024, 19:21
да пр100 , и можете подсказать что подходит под действие *считать данные с прибора* человек который мне сказал сделать это сам не понимает как

Dimensy
18.07.2024, 19:23
да пр100 , и можете подсказать что подходит под действие *считать данные с прибора* человек который мне сказал сделать это сам не понимает как

Ладно, человек не знает как, но, какие именно данные надо считать с прибора он знает?

З.Ы. Кино и немцы:
- Штурман, приборы
- Двадцать два
- Что, двадцать два?
- А что, приборы?

Бакдаулет
19.07.2024, 09:25
а какие данные можно считывать с пр100?

kondor3000
19.07.2024, 09:34
а какие данные можно считывать с пр100?

У вас проект (исходник), залитый в вашу ПР100 есть?
Если есть, открываете и смотрите какие адреса регистров есть в обмене. Их и можно считать из ПР.

Если вы про считывание проекта, то его считать нельзя. Придётся искать автора проекта или писать проект заново.

EFrol
19.07.2024, 09:38
а какие данные можно считывать с пр100?

Предлагаю почитать инструкцию https://owen.ru/downloads/re_pr100.pdf
начиная со стр. 17
А также ознакомиться с понятием сетевые переменные в https://owen.ru/downloads/rp_owen_logic.pdf

Объяснять это и в правду долго!

Бакдаулет
19.07.2024, 09:45
спасибо больше

shev1975
05.03.2025, 11:06
Здравствуйте, в функциональном блоке нужно изменять значение внешней переменной "Сброс", правильно ли так делать и может есть другие способы? Данный код работает, только при условии что переменная энергонезависимая, иначе ее не получается изменить с "экрана", почему?

Dimensy
05.03.2025, 12:12
Здравствуйте, в функциональном блоке нужно изменять значение внешней переменной "Сброс", правильно ли так делать и может есть другие способы? Данный код работает, только при условии что переменная энергонезависимая, иначе ее не получается изменить с "экрана", почему?

Галку надо поставить на "Запись в конце цикла"
82311

EFrol
05.03.2025, 12:45
Здравствуйте, в функциональном блоке нужно изменять значение внешней переменной "Сброс", правильно ли так делать и может есть другие способы? Данный код работает, только при условии что переменная энергонезависимая, иначе ее не получается изменить с "экрана", почему?

Я использую ФБ exchange для обмена битом между переменными:
82314


function_block exchange

var_input
I : bool;
in : udint;
end_var

var_output
Q : bool;
out : udint;
end_var

if I <> Q then
Q := I; out.0 := I; in.0 := I;
end_if
if in <> out then
out := in; Q := in.0; I := in.0;
end_if

end_function_block


Значение бита видно со всех сторон!

shev1975
05.03.2025, 14:15
Галку надо поставить на "Запись в конце цикла"
Спасибо, понял, получается что если не сделать запись, переменная не сохраняется, а получает значение каждый раз заново.

bayk
23.06.2025, 15:23
Друзья, вы уж простите дурачка, но с поиском на этом форуме справиться не могу. не делал ли кто функцию на ST для вычисления натурального логарифма, ну может и других логарифмов?

petera
23.06.2025, 15:28
Друзья, вы уж простите дурачка, но с поиском на этом форуме справиться не могу. не делал ли кто функцию на ST для вычисления натурального логарифма, ну может и других логарифмов?

Ну как же так?
https://owen.ru/forum/showthread.php?t=37203
84488


function fLb: Real; //Двоичный логарифм
var_input
X:real;
end_var
var
s:real:=0.0;
a:real:=0.5;
i:udint;
b:real;


end_var

//PRG

if X>0 then
if X>=1 then
b:=1;
X:=X;
else
b:=-1;
X:=1/X;
end_if


if x>2 then
s:=udint_to_real( cd32(real_to_udint(x)));
X:=X/ pow(2,s);
end_if;

for i:=0 to 16 do
x:=x*x;
if x>2 then
x:=x/2;
s:=s+a;
end_if;
a:=a*0.5;
end_for
fLb:=s*b;
end_if

end_function

ЗЫ
напомню:если lb(x) - Двоичный логарифм, то
ln(x)=lb(x)/lb(e)=ln(2)*lb(x) = 0,693147*lb(x)
lg(x)=lb(x)/lb(10)=lg(2)*lb(x) = 0,30103*lb(x)

Например

function fLn: Real; //Натуральный логарифм
var_input
X:real;
end_var

//PRG
fLn:=0.6931472*fLb(x); //вызов функции "fLb"
end_function

bayk
23.06.2025, 16:00
спасибо тебе большое! я не знаю как я так...

AlexCrane
24.06.2025, 10:08
Может кто делал разруливатель одновременного запуска на ST? Не хочется изобретать велосипед. Макросы видел, но не устроили (не корректно работали).

WKD
24.06.2025, 13:18
Может кто делал разруливатель одновременного запуска на ST? Не хочется изобретать велосипед. Макросы видел, но не устроили (не корректно работали).
Что понимается под "разруливатель одновременного запуска"?

Сергей0308
24.06.2025, 13:35
Может кто делал разруливатель одновременного запуска на ST? Не хочется изобретать велосипед. Макросы видел, но не устроили (не корректно работали).

Вот здесь разруливали, правда не на ST, в смысле, тогда и ST наверно ещё не было, короче, Вам шашечки или ехать:
https://owen.ru/forum/showthread.php?t=26216&p=432040&viewfull=1#post432040

84503

Настройка минимального периода(как обычно) в свойствах макроса.

И, можно очень легко(практически без усложнения алгоритма) расширить до 32 входов-выходов, в смысле, устройств, которые надо разруливать!

AlexCrane
24.06.2025, 19:39
Вот здесь разруливали, правда не на ST, в смысле, тогда и ST наверно ещё не было, короче, Вам шашечки или ехать:
https://owen.ru/forum/showthread.php?t=26216&p=432040&viewfull=1#post432040

84503

Настройка минимального периода(как обычно) в свойствах макроса.

И, можно очень легко(практически без усложнения алгоритма) расширить до 32 входов-выходов, в смысле, устройств, которые надо разруливать!

Спасибо, эту версию как-то пропустил

Сергей0308
25.06.2025, 21:53
Спасибо, эту версию как-то пропустил

При применении будьте внимательны к настройкам макросов, в смысле, многие(большинство) не обращают на это внимание, поэтому возникают проблемы!

bayk
27.06.2025, 00:51
Вот здесь разруливали, правда не на ST, в смысле, тогда и ST наверно ещё не было, короче, Вам шашечки или ехать:
https://owen.ru/forum/showthread.php?t=26216&p=432040&viewfull=1#post432040

84503

Настройка минимального периода(как обычно) в свойствах макроса.

И, можно очень легко(практически без усложнения алгоритма) расширить до 32 входов-выходов, в смысле, устройств, которые надо разруливать!
Я кстати его нашел, запустил в последнем лоджике, а он почему-то не завелся. Ушел на ст. Ребята из телеги быстренько написали мне код.
При чем когда я его сохранял я точно помню, что его отщелкал и меня все устроило. Я как раз тогда и просил помощи с этим макросом

Сергей0308
27.06.2025, 06:30
Я кстати его нашел, запустил в последнем лоджике, а он почему-то не завелся. Ушел на ст. Ребята из телеги быстренько написали мне код.
При чем когда я его сохранял я точно помню, что его отщелкал и меня все устроило. Я как раз тогда и просил помощи с этим макросом

Я же ссылку дал, в смысле, ничего искать не надо!
В моём проекте всё будет работать с приоритетом у входов-выходов с меньшим числовым значением, если хотите обратный приоритет(у входов-выходов с большим числовым значением) - сделайте настройки двух макросов(субмакросов), входящих в состав макроса в обратном порядке!
Короче, такое впечатление, что Вы либо не читаете что я пишу, либо не понимаете смысла написанного, даже не знаю что хуже!
Ещё раз повторю, мне не сложно: с состав макроса входят два других макроса(субмакроса), если Вы хотите чтобы в вашем проекте макрос работал также как в моём, надо и настройки субмакросов перенести(скопировать), много раз в разных темах об этом писал, даже представить не могу, что здесь может быть непонятным?!
https://owen.ru/forum/showthread.php?t=9398&p=421370&viewfull=1#post421370

bayk
28.06.2025, 09:15
Речь не об этом. Я взял проект который вы когда-то присылали и оно работало, а в свежем лоджике не завелось. Я так и не понял почему. Я не переносил макрос в новый проект.

kondor3000
28.06.2025, 09:59
Речь не об этом. Я взял проект который вы когда-то присылали и оно работало, а в свежем лоджике не завелось. Я так и не понял почему. Я не переносил макрос в новый проект.

Все последние вопросы, давно собраны в одном месте. Ссылку давно бы сохранили.
И логарифмы и выбор одного из нескольких нажатий ( Кто раньше встал, того и тапки на ST )
https://owen.ru/forum/showthread.php?t=37203&page=9&p=429067#81

Сергей0308
28.06.2025, 10:29
Речь не об этом. Я взял проект который вы когда-то присылали и оно работало, а в свежем лоджике не завелось. Я так и не понял почему. Я не переносил макрос в новый проект.

Если Вы основной макрос открываете на редактирование и проверяете алгоритм в симуляции внутри основного макроса, то он будет работать по другому, в смысле, уставка времени минимального периода там будет своя, в смысле, назначенная в свойствах основного макроса не действует, с этим ничего не поделаешь, так у всех макросов будет!

В принципе уставка может даже логику работы менять, например: у меня есть макрос двухпозиционного(релейного) регулятора с настройками режима работы(нагреватель или холодильник) в свойствах макроса:
https://owen.ru/forum/showthread.php?t=26216&p=424807&viewfull=1#post424807

Рогов Алексей
17.11.2025, 11:46
Добрый день!
Если нужны обратные тригонометрические функции и объём в горизонтальном цилиндре - цистерне по высоте жидкости, то прошу ознакомится. Сделано Алисой ИИ.86761

FPavel
03.02.2026, 21:38
Выкладываю новые функции на ST, версия OWEN Logic2.6.345

Sin_Cos_Tg_CTg_ArcSin_ArcCos_ArcTg (x)
Не слишком удачные реализации.

SIN_RAD:=((pow(b,9)/362880 + (((b-(pow(b,3)/6)) +pow(b,5)/120)- pow(b,7)/5040))-pow(b,11)/39916800)*Zn ;
Более рациональный подход - итерационные вычисления слагаемого на основе предыдущего значения.

Была нужна только функция sin(x), её и реализовывал. Другие функции - подождут своего часа.

Смысл алгоритма - сначала инициализация переменных, потом итерационно вычисляется очередное слагаемое на основе предыдущего его значения
У sin
слагаемое на предыдущей итерации А(i-1) равно
A(i-1) := (-1)^(i-1) * x^(2i-1) / (2i-1)!
а слагаемое на нынешней итерации А(i) равно
A(i) := (-1)^(i) * x^(2i+1) / (2i+1)!

Разделю А(i) на А(i-1) и получу множитель для перехода от A(i-1) к A(i)
A(i) := m * A(i-1)

m := A(i) / A(i-1)
= [(-1)^(i) * x^(2i+1) / (2i+1)!] / [(-1)^(i-1) * x^(2i-1) / (2i-1)!]
= (-1)^1 * x^2 / [(2i+1)*(2i)]
= -x^2 / [(2i+1)*(2i)]

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


function sin: real;

var_input
x : real;
end_var

var
n: udint;
Pi : real := 3.1415926535897932384626433832795;
Pi_2: real := 6.2831853071795864769252867665590;
a, s, xx: real;
f: udint;
end_var

// приведение аргумента к диапазону 0...2*Pi
if x < 0 then
n := real_to_udint(abs(x) / Pi_2) + 1;
x := x + udint_to_real(n) * Pi_2;
end_if;
if x > Pi_2 then
n := real_to_udint(abs(x) / Pi_2);
x := x - udint_to_real(n) * Pi_2;
end_if

f := 1;
a := x;
s := x;
xx := x*x;
repeat
a := - a * xx / udint_to_real(f+1) / udint_to_real(f+2);
f := f + 2;
s := s + a;
if f > 20 then
exit;
end_if;
until abs(a) < 0.0000001
end_repeat
sin := s;
end_function

Думаю, что можно улучшить, объявив переменную f типом real, т.к. значения небольшие и потери точности при сложении с 2 не произойдёт.

kondor3000
03.02.2026, 21:55
Не слишком удачные реализации.

SIN_RAD:=((pow(b,9)/362880 + (((b-(pow(b,3)/6)) +pow(b,5)/120)- pow(b,7)/5040))-pow(b,11)/39916800)*Zn ;
Более рациональный подход - итерационные вычисления слагаемого на основе предыдущего значения.

Была нужна только функция sin(x), её и реализовывал. Другие функции - подождут своего часа.
Думаю, что можно улучшить, объявив переменную f типом real, т.к. значения небольшие и потери точности при сложении с 2 не произойдёт.

Спасибо конечно, только написали вы не туда. Тут Рогов Алексей выложил проект Объём цисцерны на боку.owle, выше на 1 пост,
откуда я и взял вычисление ArcTg, ArcSin, ArcCos.
И на минутку у меня функция Sin считает точно до 7 знака, а ваша врёт на 5 знаке. И накой мне такая функция.

FPavel
03.02.2026, 22:07
Спасибо конечно, только написали вы не туда. Тут Рогов Алексей выложил проект Объём цисцерны на боку.owle, выше на 1 пост,
откуда я и взял вычисление ArcTg, ArcSin, ArcCos.
И на минутку у меня функция Sin считает точно до 7 знака, а ваша врёт на 5 знаке. И накой мне такая функция.
На каком контрольном значении?
Я проверю и исправлю.

Возможно, останов по условию abs(a) < 0.0000001 выполняется после пары итераций, а точность повысится, если добавить ещё - количество итераций ограничить снизу.

На каком значении аргумента погрешность?

kondor3000
03.02.2026, 22:23
На каком контрольном значении?
Я проверю и исправлю.

Возможно, останов по условию abs(a) < 0.0000001 выполняется после пары итераций, а точность повысится, если добавить ещё - количество итераций ограничить снизу.

На каком значении аргумента погрешность?

Проверял на всех, но конкретно на скрине вход -0,227, 87864
моя функция SIN_RAD -0,2250555
ваша ___________Sin -0,22501531
на калькуляторе_____ -0,22505550283358259230719813707651

FPavel
03.02.2026, 22:48
Я понял.
В самом начале функции я делаю приведение аргумента к диапазону 0...2*Pi.
Что в принципе, правильно.

Но в самом начале вычислений при x=6 (чуть меньше 2*Pi), степенная составляющая растёт быстрее факториальной и получается потеря разрядности при сложении с более мелкими слагаемыми.
Тут нужно или приводить к диапазону [-Pi...+Pi]. Хотя не проверял, но степенная часть будет расти медленнее и возможно, проблема уйдёт на более дальние незаметные разряды.
Или сделать через формулу двойного аргумента.

Сейчас поколдую, повспоминаю - уже решал на форуме именно задачу потери разрядности.
https://www.cyberforum.ru/c-beginners/thread2702191.html#post14864162

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

Видимо, задача сложнее, чем казалась сначала.

FUNCTION sin_enh: REAL;

VAR_INPUT
x: REAL;
END_VAR

VAR
Pi: REAL := 3.1415926535897932384626433832795;
Pi_x2: REAL := 6.2831853071795864769252867665590;
// Pi_2:real := 1.5707963267948966192313216916398;
// Pi_4:real := 0.78539816339744830961566084581988;
// переменные для вычислений по формуле двойного аргумента
n: UDINT;
sin_2x, cos_2x: REAL;
sin_x, cos_x: REAL;
// переменные для вычислений ряда Тейлора
f: REAL;
a_sin, a_cos: REAL;
END_VAR
// показательная функция [x^(2n+1)] в первых членах суммы ряда Тейлора
// растёт быстрее факториала [(2n+1)!], что приводит к потере точности
// буквально с первых слагаемых
// Решения:
// 1. приведение аргумента к диапазону 0...2*Pi - исходной области определения sin
// 2. приведение аргумента к эквивалентному диапазону 0...+Pi,
// при этом меняется знак аргумента, который был больше Pi
// sin(t) = sin(-x+Pi) = sin(-x)cos(Pi) + sin(Pi)cos(-x) = -sin(-x) = sin(x)
// x = Pi - t
// 3. приведение аргумента к диапазону -Pi/2...+Pi/2
// sin(t) = sin(x+Pi/2)= sin(x)cos(Pi/2) + sin(Pi/2)cos(x) = -cos(x)

(*
if x < 0 then
n := real_to_udint(abs(x) / Pi_x2) + 1;
// n:=0;
x := x + udint_to_real(n) * Pi_x2;
end_if;
if x > Pi_x2 then
n := real_to_udint(abs(x) / Pi_x2);
// n:=0;
x := x - udint_to_real(n) * Pi_x2;
end_if
*)

// для проверки сразу привожу к проблемному диапазону
x := x + Pi + Pi;

// приводим аргумент к приемлемым значениям для вычисления
n := 0;
WHILE (ABS(x) > 1.5) DO
x := x / 2.0;
n := n + 1;
END_WHILE
// вычисляем первое приближение через ряд Тейлора
f := 1;
a_sin := x;
sin_x := x;
a_cos := 1;
cos_x := 1;
x := x * x;
REPEAT
a_sin := - a_sin * x / ((f + 1) * (f + 2));
a_cos := - a_cos * x / (f * (f + 1));
sin_x := sin_x + a_sin;
cos_x := cos_x + a_cos;
f := f + 2;
IF f > 30 THEN
EXIT;
END_IF;
UNTIL (ABS(a_sin) < 0.0000001) AND (f > 24)
END_REPEAT
// вычисляем для исходного аргумента
WHILE (n > 0) DO
sin_2x := 2 * sin_x * cos_x;
cos_2x := 1 - 2 * sin_x * sin_x;

sin_x := sin_2x;
cos_x := cos_2x;

n := n - 1;
END_WHILE

sin_enh := sin_x;
END_FUNCTION
Попробовал уйти от проблемы потери точности через формулу двойного аргумента - сначала несколькими делениями на 2 получить маленькое значение x, а потом для маленького x получить sin и cos и далее выполнить пересчёт к исходному аргументу.
Но тип REAL даёт всего 7-8 точных десятичных знаков и каждое умножение снижает точность на 1 разряд, т.е. все вычисления проходят на границе точности.
Т.е. и уменьшение аргумента к повышению точности до предельных 7 разрядов не привело.

Наверное, нужно попробовать сделать приведением аргумента к диапазону -Pi/4...+Pi/4 и там уже рядом условий вычислять или sin или cos от приведённого аргумента.

Рогов Алексей
06.02.2026, 07:40
Добрый день!

Алиса и с синусом готова помочь:

FUNCTION SinTaylorReal : REAL;
VAR_INPUT
x : REAL; (* Угол в радианах *)
tolerance: REAL; (* Точность, например, 1E-6 *)
END_VAR
VAR
result : REAL := 0.0; (* Текущая сумма ряда *)
term : REAL := 0.0; (* Текущий член ряда *)
x_power : REAL := 0.0; (* x^(2n+1) *)
factorial: REAL := 1.0; (* (2n+1)! *)
n : UDINT := 0; (* Номер члена ряда (целочисленный счётчик) *)
sign : REAL := 1.0; (* Знак члена: +1 или -1 *)
two_n_plus_1: UDINT; (* 2n + 1 *)
i, j : UDINT;
END_VAR

(* Нормализация угла: приводим x к [-2π, 2π] *)
WHILE ABS(x) > 2.0 * 3.1415926535 DO
IF x > 0.0 THEN
x := x - 2.0 * 3.1415926535;
ELSE
x := x + 2.0 * 3.1415926535;
END_IF
END_WHILE

(* Вычисление ряда Тейлора до достижения точности *)
WHILE TRUE DO
(* Вычисляем 2n + 1 *)
two_n_plus_1 := 2 * n + 1;

(* Вычисляем x^(2n+1) *)
x_power := 1.0;
FOR i := 1 TO two_n_plus_1 BY 1 DO
x_power := x_power * x;
END_FOR

(* Вычисляем (2n+1)! *)
factorial := 1.0;
FOR j := 1 TO two_n_plus_1 BY 1 DO
factorial := factorial * udint_to_real(j); (* Приводим UDINT к REAL *)
END_FOR

(* Текущий член ряда: (-1)^n * x^(2n+1) / (2n+1)! *)
term := sign * x_power / factorial;

(* Добавляем к результату *)
result := result + term;

(* Проверяем точность: если модуль члена < tolerance, завершаем *)
IF ABS(term) < tolerance THEN
EXIT;
END_IF

(* Переходим к следующему члену: n = n + 1, меняем знак *)
n := n + 1;
sign := -sign;
END_WHILE

SinTaylorReal := result;
END_FUNCTION

FPavel
06.02.2026, 08:30
Прямое вычисление факториала - быстро приведёт к переполнению разрядной сетки переменной.
Поэтому и используют реккурентное соотношение между соседними слагаемыми.

Но всё равно остаётся проблема точности при вычислениях с аргументами, превышающими 1,0-1,5, т.к. для первых слагаемых числитель (x^[2n]) растёт быстрее знаменателя ([2n]!), что приводит к сложению чисел очень с очень большой разницей, что усугубляется тем, что тип real способен хранить только 7-8 точных цифр (всего и целой и дробной частей).

Попытка снизить аргумент пересчётом по формуле удвоенного аргумента опять приводит к потере точности из-за увеличения количества операций умножения.

Пока я вижу, но не проверил кодом, решение в приведении аргумента к диапазону -Pi/2...+Pi/2 и вычислении sin или cos - вместо исходного sin.

Так что решение от Алисы можно забыть - проверьте 7 первых чисел результата вычислений с ответом Калькулятора для x=-0.227. Увидите, что результат даёт только 5 верных знаков.

Если есть желание - попробуйте сделать приведение к диапазону Pi/2.

Рогов Алексей
06.02.2026, 09:08
Странно, для x=-0.227 калькулятор выдаёт -0,225055503 Симулятор Овен Лоджика -0,2250555. Толеранс 1E-06 не забыли установить?

FPavel
06.02.2026, 09:13
Прошу прощения...
x=-0.227 это уже приведённое значение из узкого диапазона.

проверьте для
x=-0.227+2*Pi=6.056185307179586476925286766559

Тогда проявится

kondor3000
06.02.2026, 10:03
Точность падает при числах близких к 1, проверять надо 0,99 и -0,99

И самое главное, одна такая функция (от Алисы), при высокой точности (1000 итераций) делает цикл ПР близким к 72 мс, что ни в какие ворота не лезет https://owen.ru/forum/showthread.php?t=42448&p=479364&viewfull=1#post479364

Рогов Алексей
06.02.2026, 12:03
Формулу для горизонтальной бочки записывал в ПР 200 , значение высоты водяного столба вводил с экрана, - датчик пока не купили - тормозов не заметил, точность соответствует онлайн калькулятору. Это касательно обратных триг. функций. А Вам синус зачем, если не секрет?

capzap
06.02.2026, 12:16
Добрый день!

Алиса и с синусом готова помочь:


если просто написать дай функцию без анализа что она пишет то наверное будут претензии вот прокрученная второй раз с уточнением что она эксперт в промышленной атоматизации

Ваша функция реализует ряд Тейлора для синуса, но содержит критические недостатки для промышленного применения:
🔴 Проблемы:

Неэффективное вычисление степени и факториала
На каждой итерации заново вычисляются x^(2n+1) и (2n+1)! через вложенные циклы — это катастрофически медленно на ПЛК (каждая итерация требует ~2n операций умножения).
Переполнение факториала
Для 32-битного REAL (IEEE 754) факториал переполняется уже при (2n+1)! > 3.4&#215;10&#179;⁸ → n ≥ 11. При этом для точности 1E-6 достаточно 4–5 итераций.
Неточная нормализация угла
Цикл WHILE ABS(x) > 2π работает медленно для больших углов (например, при x = 1000 радиан потребуется ~160 итераций). Константа π задана с недостаточной точностью (9 знаков вместо 7–8 значащих для REAL).
Избыточная нормализация до [-2π, 2π]
Для синуса достаточно приведения к [-π, π] — это ускоряет сходимость ряда в 2 раза.
Оптимизированный вариант (рекуррентная формула)

FUNCTION SinTaylorOptimized : REAL
VAR_INPUT
x : REAL; // Угол в радианах
tolerance : REAL := 1E-6; // Точность (по умолчанию)
END_VAR
VAR
pi : REAL := 3.1415927; // Достаточно для 32-битного REAL
two_pi : REAL := 2.0 * pi;
term : REAL; // Текущий член ряда
x_sq : REAL; // x&#178; (вычисляется один раз)
n : UDINT := 1; // Счётчик итераций (начинаем с 1 для второго члена)
END_VAR

// === ШАГ 1: Нормализация к [-π, π] за О(1) ===
x := x - two_pi * TRUNC(x / two_pi); // Быстрое приведение через целую часть
IF x > pi THEN
x := x - two_pi;
ELSIF x < -pi THEN
x := x + two_pi;
END_IF;

// === ШАГ 2: Рекуррентное вычисление ряда ===
SinTaylorOptimized := x; // Первый член: x
term := x;
x_sq := x * x; // x&#178; вычисляем один раз

// Итерации: term_{k} = -term_{k-1} * x&#178; / ((2k)*(2k+1))
WHILE ABS(term) >= tolerance DO
term := -term * x_sq / REAL(2 * n) / REAL(2 * n + 1);
SinTaylorOptimized := SinTaylorOptimized + term;
n := n + 1;
END_WHILE;
END_FUNCTION
Ключевые улучшения:
Рекуррентная формула
termₙ = -termₙ₋₁ · x&#178; / ((2n)·(2n+1)) — исключает степень и факториал.
Нормализация за константное время
Через TRUNC(x / 2π) вместо цикла.
Минимизация операций
3 арифметические операции на итерацию против 2n в исходном коде.
Безопасность для ПЛК
Нет риска переполнения, стабильная работа с 32-битным
Важно для промышленного применения: Для критичных к скорости задач (цикл ПЛК < 10 мс) рекомендуется использовать аппаратную функцию SIN() из библиотеки ПЛК — она реализована через таблицы и полиномы Чебышёва и работает в 10–100 раз быстрее. Ряд Тейлора оправдан только при отсутствии встроенной функции или для учебных целей.

FPavel
06.02.2026, 12:23
Лично мне sin требуется при моделировании периодической помехи для проверки очередного регулятора.

Например,
https://owen.ru/forum/showthread.php?t=25067&p=474213&viewfull=1#post474213
https://owen.ru/forum/showthread.php?t=42441&p=479415&viewfull=1#post479415

Тогда можно до выхода на ПНР определиться с алгоритмом.

А точность - это принципиальный момент, т.к. 5 точных знаков получается без усилий, но есть, казалось бы некрасивые формулы без пояснений алгоритма, которые в тех же условиях дают 7-8 точных знаков.
Почему бы не научиться новому и не разобрать, как вычислять с повышенной точностью?

Вот я попробовал наивный метод вычисления ряда Тейлора, потом пересчётом аргумента с последующим пересчётом результата.
Теперь есть ещё идея по повышению точности - привести исходный x к диапазону 0...Pi/2 или (-Pi/4...+Pi/4) и вычислять sin или cos (что получиться после приведения) и тем самым повысить точность.

zjWlad
06.02.2026, 14:35
kondor3000.
Функция SIN_Rad для углов 90, 270 градусов (после пересчета в радианы) вместо верного результата выдает ноль. Одно из «магических» значений аргумента 1,5707964. При изменении последней цифры в любую сторону – все нормально. Может это только у меня. (OWEN Logic 2.6.347.0, на OWEN Logic 1.23 тоже самое)

1exan
06.02.2026, 14:37
kondor3000.
Функция SIN_Rad для углов 90, 270 градусов (после пересчета в радианы) вместо верного результата выдает ноль. Одно из «магических» значений аргумента 1,5707964. При изменении последней цифры в любую сторону – все нормально. Может это только у меня. (OWEN Logic 2.6.347.0, на OWEN Logic 1.23 тоже самое)

Магическое значение, очевидно - пи/2

zjWlad
06.02.2026, 14:49
Магическое значение, очевидно - пи/2

Да, но не только.

kondor3000
06.02.2026, 14:51
kondor3000.
Функция SIN_Rad для углов 90, 270 градусов (после пересчета в радианы) вместо верного результата выдает ноль. Одно из «магических» значений аргумента 1,5707964. При изменении последней цифры в любую сторону – все нормально. Может это только у меня. (OWEN Logic 2.6.347.0, на OWEN Logic 1.23 тоже самое)

У каждой функции есть свои ограничения, здесь простота и маленький цикл программы, https://owen.ru/forum/showthread.php?t=35489&page=49&p=397789&viewfull=1#post397789
В отличие от рядов Тейлора, в нескольких функциях, с огромным циклом программы (порядка 72 мс).
изначально некоторые функции использовались в астротаймере, где углы ограничены. https://owen.ru/forum/showthread.php?t=29532&page=2&p=448696#post448696

zjWlad
06.02.2026, 14:53
Магическое значение, очевидно - пи/2

Да, но оно не единственное.

FPavel
07.02.2026, 16:03
Взял у kondor3000 по ссылке https://owen.ru/forum/showthread.php?t=35489&p=397789&viewfull=1#post397789
У меня ощущение, что по алгоритму аргумент последовательно приводится к диапазону 0...2Pi, 0...Pi, 0...Pi/2, а потом по ряду Тейлора (Маклорена) вычисляется значение для фиксированного количества (пяти) слагаемых с изменением последовательности сложения для повышения точности.
Как отмечалось выше, для значений Pi/2 (90 градусов) и для (3/4)Pi (270 градусов) функция возвращает ошибочное значение 0,0 вместо точного 1,0.
Как отмечал выше kondor3000, функция предназначалась для конкретной задачи с узким диапазоном аргумента и ошибка не проявлялась.

function EXTRACT: bool; // Функция работает не правильно
var_input
X, N : udint;
end_var

Extract := (SHR(X,N) mod 2) > 0; // Функция работает правильно
// EXTRACT_:=(SHR(X,N) AND 1)=1 ; // Функция работает не правильно
end_function

function SIN_RAD: real ; //имя функции и тип данных выхода
var_input //объявление входных переменных
X: real ; //входная переменная с типом данных bool
end_var
var //объявление локальных переменных
Zn : real ;
Pi : real:=3.1415927 ;
a,b: real ;
end_var

Zn:=pow(-1,bool_to_real(EXTRACT(real_to_udint((abs(X))/Pi),0) XOR not (X>0)));
a:=(abs(X)/Pi - udint_to_real(real_to_udint(abs(X)/Pi)))*Pi ;
b:=(Pi-a) * (bool_to_real(a>1.5707964))+a* bool_to_real(not(a>=1.5707964)) ;
SIN_RAD:=((pow(b,9)/362880 + (((b-(pow(b,3)/6)) +pow(b,5)/120)- pow(b,7)/5040))-pow(b,11)/39916800)*Zn ;


end_function

Пробовал вычислить sin разными способами:


// вычисление синуса через ряд Маклорена (Тейлора)
FUNCTION sin_1_: REAL;

VAR_INPUT
x: REAL;
END_VAR

VAR
n: UDINT;
Pi: REAL := 3.1415926535897932384626433832795;
Pi_2: REAL := 6.2831853071795864769252867665590;
a, s, f: REAL;
sign: BOOL;
END_VAR

// приведение аргумента к диапазону 0...2*Pi
IF x < 0 THEN
n := REAL_TO_UDINT(ABS(x) / Pi_2) + 1;
x := x + UDINT_TO_REAL(n) * Pi_2;
END_IF;
IF (x > Pi_2) THEN
n := REAL_TO_UDINT(ABS(x) / Pi_2);
x := x - UDINT_TO_REAL(n) * Pi_2;
END_IF

f := 1;
a := x;
s := x;
x := x * x;
REPEAT
a := - a * x / ((f + 1) * (f + 2));
f := f + 2;
s := s + a;
IF f > 30 THEN
EXIT;
END_IF;
UNTIL (ABS(a) < 0.0000001) AND (f > 24)
END_REPEAT

sin_1_ := s;

END_FUNCTION

Пересчёт аргумента (неоднократное снижение в 2 раза) до приведения к диапазону (-1,5...+1,5), вычисление sin и cos при помощи ряда Тейлора, пересчёт результатов к исходному значению аргумента
Формула удвоения аргумента
sin(2x) = 2 sin(x) cos(x)
cos(2x) = 1 - [sin(x)]^2

// вычисление синуса через пересчёт аргумента к узкому диапазону, в котором доступна
// высокая точность вычислений, и последующим пересчётом результата для значения,
// соответствующего исходному аргументу
FUNCTION sin_2_: REAL;

VAR_INPUT
x: REAL;
END_VAR

VAR
Pi: REAL := 3.1415926535897932384626433832795;
Pi_x2: REAL := 6.2831853071795864769252867665590;
// Pi_2:real := 1.5707963267948966192313216916398;
// Pi_4:real := 0.78539816339744830961566084581988;
// переменные для вычислений по формуле двойного аргумента
n: UDINT;
sin_2x, cos_2x: REAL;
sin_x, cos_x: REAL;
// переменные для вычислений ряда Тейлора
f: REAL;
a_sin, a_cos: REAL;
END_VAR
// показательная функция [x^(2n+1)] в первых членах суммы ряда Тейлора
// растёт быстрее факториала [(2n+1)!], что приводит к потере точности
// буквально с первых слагаемых
// Решения:
// 1. приведение аргумента к диапазону 0...2*Pi - исходной области определения sin

IF x < 0 THEN
n := REAL_TO_UDINT(ABS(x) / Pi_x2) + 1;
x := x + UDINT_TO_REAL(n) * Pi_x2;
END_IF;
IF x > Pi_x2 THEN
n := REAL_TO_UDINT(ABS(x) / Pi_x2);
x := x - UDINT_TO_REAL(n) * Pi_x2;
END_IF

// приводим аргумент к приемлемым значениям для вычисления
n := 0;
WHILE (ABS(x) > 1.5) DO
x := x / 2.0;
n := n + 1;
END_WHILE
// вычисляем первое приближение через ряд Тейлора
f := 1;
a_sin := x;
sin_x := x;
a_cos := 1;
cos_x := 1;
x := x * x;
REPEAT
a_sin := - a_sin * x / ((f + 1) * (f + 2));
a_cos := - a_cos * x / (f * (f + 1));
sin_x := sin_x + a_sin;
cos_x := cos_x + a_cos;
f := f + 2;
IF f > 30 THEN
EXIT;
END_IF;
UNTIL (ABS(a_sin) < 0.0000001) AND (f > 24)
END_REPEAT
// вычисляем для исходного аргумента
WHILE (n > 0) DO
sin_2x := 2 * sin_x * cos_x;
cos_2x := 1 - 2 * sin_x * sin_x;

sin_x := sin_2x;
cos_x := cos_2x;

n := n - 1;
END_WHILE

sin_2_ := sin_x;

END_FUNCTION

По аналогии с предыдущим способом, но по готовой формуле
sin(5x) = 16 [sin(x)]^5 - 20 [sin(x)]^3 + 5 sin(x)

// вычисление синуса через пересчёт аргумента к узкому диапазону, в котором доступна
// высокая точность вычислений, и последующим пересчётом результата для значения,
// соответствующего исходному аргументу
// sin(2x) = 2 sin(x) cos(x)
// sin(3x) = 3 sin(x) - 4 [sin(x)]^3
// sin(4x) = cos(x) (4 sin(x) - 8 [sin(x)]^3)
// sin(5x) = 16 [sin(x)]^5 - 20 [sin(x)]^3 + 5 sin(x)
// sin(7x) = 7sin(x) - 56sin^3(x) + 112sin^5(x) - 64sin^7(x)
FUNCTION sin_3_: REAL;

VAR_INPUT
x: REAL;
END_VAR

VAR
Pi: REAL := 3.1415926535897932384626433832795;
Pi_x2: REAL := 6.2831853071795864769252867665590;
// Pi_2:real := 1.5707963267948966192313216916398;
// Pi_4:real := 0.78539816339744830961566084581988;
// переменные для вычислений по формуле двойного аргумента
n: UDINT;
sin_2x, cos_2x: REAL;
sin_x, cos_x: REAL;
// переменные для вычислений ряда Тейлора
f: REAL;
a_sin, a_cos: REAL;
END_VAR
// показательная функция [x^(2n+1)] в первых членах суммы ряда Тейлора
// растёт быстрее факториала [(2n+1)!], что приводит к потере точности
// буквально с первых слагаемых
// Решения:
// 1. приведение аргумента к диапазону 0...2*Pi - исходной области определения sin

IF x < 0 THEN
n := REAL_TO_UDINT(ABS(x) / Pi_x2) + 1;
x := x + UDINT_TO_REAL(n) * Pi_x2;
END_IF;
IF x > Pi_x2 THEN
n := REAL_TO_UDINT(ABS(x) / Pi_x2);
x := x - UDINT_TO_REAL(n) * Pi_x2;
END_IF

// приводим аргумент к приемлемым значениям для вычисления
// делим на 5
x := x / 5.0;
// вычисляем первое приближение через ряд Тейлора
f := 1;
a_sin := x;
sin_x := x;
a_cos := 1;
cos_x := 1;
x := x * x;
REPEAT
a_sin := - a_sin * x / ((f + 1) * (f + 2));
a_cos := - a_cos * x / (f * (f + 1));
sin_x := sin_x + a_sin;
cos_x := cos_x + a_cos;
f := f + 2;
IF f > 30 THEN
EXIT;
END_IF;
UNTIL (ABS(a_sin) < 0.0000001) AND (f > 24)
END_REPEAT
// вычисляем для исходного аргумента
sin_2x := sin_x * sin_x;
sin_x := sin_x * ((16*sin_2x - 20)*sin_2x +5);

sin_3_ := sin_x;

END_FUNCTION

Аналогично, но аргумент делится на 7
sin(7x) = 7sin(x) - 56sin^3(x) + 112sin^5(x) - 64sin^7(x)

// вычисление синуса через пересчёт аргумента к узкому диапазону, в котором доступна
// высокая точность вычислений, и последующим пересчётом результата для значения,
// соответствующего исходному аргументу
// sin(2x) = 2 sin(x) cos(x)
// sin(3x) = 3 sin(x) - 4 [sin(x)]^3
// sin(4x) = cos(x) (4 sin(x) - 8 [sin(x)]^3)
// sin(5x) = 16 [sin(x)]^5 - 20 [sin(x)]^3 + 5 sin(x)
// sin(7x) = 7sin(x) - 56sin^3(x) + 112sin^5(x) - 64sin^7(x)
FUNCTION sin_4_: REAL;

VAR_INPUT
x: REAL;
END_VAR

VAR
Pi: REAL := 3.1415926535897932384626433832795;
Pi_x2: REAL := 6.2831853071795864769252867665590;
// Pi_2:real := 1.5707963267948966192313216916398;
// Pi_4:real := 0.78539816339744830961566084581988;
// переменные для вычислений по формуле двойного аргумента
n: UDINT;
sin_2x, cos_2x: REAL;
sin_x, cos_x: REAL;
// переменные для вычислений ряда Тейлора
f: REAL;
a_sin, a_cos: REAL;
END_VAR
// показательная функция [x^(2n+1)] в первых членах суммы ряда Тейлора
// растёт быстрее факториала [(2n+1)!], что приводит к потере точности
// буквально с первых слагаемых
// Решения:
// 1. приведение аргумента к диапазону 0...2*Pi - исходной области определения sin
// 2. приведение аргумента к эквивалентному диапазону 0...+Pi,
// при этом меняется знак аргумента, который был больше Pi
// sin(t) = sin(-x+Pi) = sin(-x)cos(Pi) + sin(Pi)cos(-x) = -sin(-x) = sin(x)
// x = Pi - t
// 3. приведение аргумента к диапазону -Pi/2...+Pi/2
// sin(t) = sin(x+Pi/2)= sin(x)cos(Pi/2) + sin(Pi/2)cos(x) = -cos(x)

IF x < 0 THEN
n := REAL_TO_UDINT(ABS(x) / Pi_x2) + 1;
x := x + UDINT_TO_REAL(n) * Pi_x2;
END_IF;
IF x > Pi_x2 THEN
n := REAL_TO_UDINT(ABS(x) / Pi_x2);
x := x - UDINT_TO_REAL(n) * Pi_x2;
END_IF

// приводим аргумент к приемлемым значениям для вычисления
// делим на 7
x := x / 7.0;
// вычисляем первое приближение через ряд Тейлора
f := 1;
a_sin := x;
sin_x := x;
a_cos := 1;
cos_x := 1;
x := x * x;
REPEAT
a_sin := - a_sin * x / ((f + 1) * (f + 2));
a_cos := - a_cos * x / (f * (f + 1));
sin_x := sin_x + a_sin;
cos_x := cos_x + a_cos;
f := f + 2;
IF f > 30 THEN
EXIT;
END_IF;
UNTIL (ABS(a_sin) < 0.0000001) AND (f > 24)
END_REPEAT
// вычисляем для исходного аргумента
sin_2x := sin_x * sin_x;
// sin_x := sin_x * ((16*sin_2x - 20)*sin_2x +5);
// sin(7x) = 7sin(x) - 56sin^3(x) + 112sin^5(x) - 64sin^7(x)
sin_x := sin_x * (7 + sin_2x * ( - 56.0 + sin_2x * (112.0 - 64.0 * sin_2x)));

sin_4_ := sin_x;

END_FUNCTION

Вычисление синуса через ряд Маклорена (Тейлора), дополненное суммированием при помощи алгоритма Кэхэна (Kahan)

// вычисление синуса через ряд Маклорена (Тейлора)
// дополненное суммированием при помощи алгоритма Кэхэна (Kahan)
FUNCTION sin_5_: REAL;

VAR_INPUT
x: REAL;
END_VAR

VAR
n: UDINT;
Pi: REAL := 3.1415926535897932384626433832795;
Pi_x2: REAL := 6.2831853071795864769252867665590;
a, s, f: REAL; // числа для суммирования ряда Тейлора
c, y, t: REAL; // числа для суммирования алгоритмом Кэхэна
END_VAR

// приведение аргумента к диапазону 0...2*Pi
IF x < 0 THEN
n := REAL_TO_UDINT(ABS(x) / Pi_x2) + 1;
x := x + UDINT_TO_REAL(n) * Pi_x2;
END_IF;
IF x > Pi_x2 THEN
n := REAL_TO_UDINT(ABS(x) / Pi_x2);
x := x - UDINT_TO_REAL(n) * Pi_x2;
END_IF

IF x > Pi THEN
x := x - 0; // Pi_x2;
END_IF
// sin(x) = sin(Pi-x)
IF ABS(x) > ABS(Pi - x) THEN
x := Pi - x;
END_IF

// инициализация для алгоритма Кэхэна
c := 0;
// инициализация для ряда Тейлора
f := 1;
a := x;
s := x;
x := x * x;
REPEAT
a := - a * x / ((f + 1) * (f + 2)); // очередное слагаемое ряда

y := a - c; // сложение его с суммой по алгоритму Кэхэна
t := s + y;
c := (t - s) - y;

s := (s + a); // t; // сумму (s + a) заменяем на результат сложения по алгоритму
f := f + 2;
IF f > 50 THEN
EXIT;
END_IF;
UNTIL (ABS(a) < 0.00000001) AND (f > 24)
END_REPEAT

sin_5_ := s;

END_FUNCTION

Ещё пробовал выполнить приведение исходного аргумента к (0...Pi/2) или (-Pi/4...+Pi/4), но столкнулся с тем, что константы, кратные Pi, которые использую при этих приведениях, тоже имеют конечную точность представления в типе REAL и во время вычислений так же теряю точность, как если бы не выполнял их.
Поэтому и стал искать другие способы...

Наверное, остановлю изыскания, т.к. пока новых идей нет.

Для проверки использовал программу, которая по переключению от дискретного входа меняет аргумент с (-0,227) на его эквивалент (-0,227 + 2Pi)

По итогам моделирования приведу сводную таблицу для четырёх значений x, x+2*Pi, abs(x), abs(x+2*Pi)

x = -0.2270000
6.0561857
0.2270000
6.5101852

точное = -0.2250555
-0.2250555
0.2250555
0.2250555

SIN_RAD = -0.2250555
-0.2250550
0.2250555
0.2250555

sin_1_ = -0.2250548 - ряд Тейлора
-0.2250548
0.2250555
0.2250553

sin_2_ = -0.2250551 - пересчёт аргумента, ряд Тейлора, пересчёт результата
-0.2250551
0.2250555
0.2250553

sin_3_ = -0.2250549 - пересчёт аргумента деление на 5, формула sin(5x)
-0.2250549
0.2250555
0.2250553

sin_4_ = -0.2250543 - пересчёт аргумента деление на 7, формула sin(7x)
-0.2250543
0.2250555
0.2250552

sin_5_ = -0.2250551 - ряд Тейлора с алгоритмом сложения Кэхэна
-0.2250551
0.2250555
0.2250553

Думаю, что все ухищрения с уменьшением аргумента не приводят к повышению точности из-за сложения несравнимых слагаемых при обратном пересчёте результата.
Например, для sin(7x) = 7sin(x) - 56sin^3(x) + 112sin^5(x) - 64sin^7(x) видно, что в наихудшем случае происходит сложение чисел, сопоставимых с 112, что ухудшает точность в 7 знаке после запятой.

Для варианта с несколькими делениями на 2, происходят операции с числами, сопоставимыми с 1.

Ряд Тейлора с алгоритмом сложения Кэхэна не дал ожидаемых результатов из-за сложения сильно несопоставимых чисел - порядка 36 и 1 - разряды 6 и 7 после запятой сразу содержали мусор и мусором остались. Из-за учёта мелких слагаемых алгоритмом Кэхэна результат немного отличается от обычного Тейлора.

Вычисления алгоритмом SIN_RAD, возможно, более точны на диапазоне 0...Pi/2, но, не считая ошибок вычисления в двух точках (90 и 270 градусов), на всём диапазоне аргумента вычисляет с сопоставимой погрешностью - 6 знаков после запятой, против 5-6 у других методов - что не удивительно, ведь они все основаны на вычислении ряда Тейлора.

Для себя сделал выводы что из перебранных алгоритмов
- в целом результаты сопоставимы
- предпочту использовать или просто ряд Тейлора или с несколькими делениями аргумента на 2 с последующим пересчётом результата - за счёт простоты и скорости выполнения

kondor3000
07.02.2026, 17:21
Взял у kondor3000 по ссылке https://owen.ru/forum/showthread.php?t=35489&p=397789&viewfull=1#post397789
Для себя сделал выводы что из перебранных алгоритмов
- в целом результаты сопоставимы
- предпочту использовать или просто ряд Тейлора или с несколькими делениями аргумента на 2 с последующим пересчётом результата - за счёт простоты и скорости выполнения
Сделал проще, ввёл 2 точки, где не работало 1 и -1, зато вычисление намного быстрее, точнее и цикл маленький

function SIN_Rad: real ; //имя функции и тип данных выхода
var_input
X: real ; //входная переменная
end_var
var //объявление локальных переменных
Zn : real ;
Pi : real:=3.1415927 ;
a,b: real ;
end_var

Zn:=pow(-1,bool_to_real(EXTRACT(real_to_udint((abs(X))/Pi),0) XOR not (X>0)));
a:=(abs(X)/Pi - udint_to_real(real_to_udint(abs(X)/Pi)))*Pi ;
b:=(Pi-a) * (bool_to_real(a>1.5707964))+a* bool_to_real(not(a>=1.5707964)) ; // 1,5707964
if x=1.5707964 or x=7.853982 then
SIN_Rad:=1.0;
elsif x=-1.5707964 or x=4.712389 then
SIN_Rad:=-1.0;
else
SIN_Rad:=((pow(b,9)/362880 + (((b-(pow(b,3)/6)) +pow(b,5)/120)- pow(b,7)/5040))-pow(b,11)/39916800)*Zn ;
end_if
end_function

FPavel
07.02.2026, 18:56
Мне показалось, что этот алгоритм даёт не совсем точный результат для x=-0.227+2*Pi, т.е. не полного оборота. Именно поэтому и решил сказать о сопоставимости точности.
Результаты эксперимента для четырёх точек

x = -0.2270000
6.0561857 = -0.227 + 2*Pi
0.2270000 = |-0.227|
6.5101852 = |-0.227| + 2*Pi

точное = -0.2250555
-0.2250555
0.2250555
0.2250555

SIN_RAD = -0.2250555
-0.2250550
0.2250555
0.2250555
Справедливости ради, стоит отметить, что из-за ограничений разрядной сетки и погрешности при сложении с константой 2*Pi результат для полученного аргумента
sin(6.0561857 = -0.227 + 2*Pi)=-0,22505512, а не 0.22505550

Т.е. в последнем 7 разряде несовпадение с точным значением. Поэтому эксперимент показал, что точность не превышает 6 знаков.

Я не проверил, вполне возможно, на диапазоне 0...Pi/2 точность может быть выше. Т.к. для повышения точности при сложении переставлен порядок слагаемых.

Просто представьте, что для x=1.5 первое слагаемое будет 1,5, что сразу "убивает" надежду на 7 разряд после запятой.
SIN_Rad:=((pow(b,9)/362880 + (((b-(pow(b,3)/6)) +pow(b,5)/120)- pow(b,7)/5040))-pow(b,11)/39916800)*Zn ;

Скорость вычисления я тоже не проверял. Всё зависит от реализации компилятора.
Мне кажется, что 5 вызовов сторонней функции само по себе должно привнести затраты времени.
Далее, вероятно, функция pow(a, b) = exp(b*log(a)) с учётом знака - я просто не знаю, как иначе вычислить a^b с вещественными числами. Т.е. довольно затратные операции.

В моих реализациях есть циклы, это не прибавляет скорости, тоже накладные расходы.

Т.е. при сравнимой точности 5-6 знаков после запятой и скорости могут быть сопоставимыми - и делаю вывод о приблизительной равноценности реализации функции.

melky
07.02.2026, 19:31
Видел код Син. с использованием нескольких табличных значений арктангннса. Правда не на ST. Может адаптировать (портировать) его?
Честно, не знаю, насколько будет быстрее работать?

FPavel
07.02.2026, 21:41
Можно попробовать...

Мне просто не нравится код с неподходящим алгоритмом, особенно опубликованный в примерах - самый яркий это st функция для Pt1000 из компонентов.
При расчётах вызывается функция вычисления полинома (уже странно!)

............
f_PT1000:=f_Pol4((RtR0-1),4,0,D1,D2,D3,D4); //вызов функции "f_pol4"
.............
Смотрим содержимое функции

///<Description>Функция вычисления полинома четвертой степени</Description>
///<OutputDescription>Результат вычисления</OutputDescription>
///<Author>ОВЕН</Author>
///<GroupName>Аналоговые преобразования</GroupName>

function f_Pol4: Real; //функция вычисления полинома 4й степени

var_input

///<Description>Заданный корень</Description>
X : Real;

///<Description>Степень</Description>
exp: udint;

///<Description>Коэффициент D0</Description>
D0: Real;

///<Description>Коэффициент D1</Description>
D1: Real;

///<Description>Коэффициент D2</Description>
D2: Real;

///<Description>Коэффициент D3</Description>
D3: Real;

///<Description>Коэффициент D4</Description>
D4: Real;

end_var

var
i: udint;
d: array [0..4] of Real;
end_var

f_Pol4:=0;
d[0]:=d0;
d[1]:=d1;
d[2]:=d2;
d[3]:=d3;
d[4]:=d4;

for i := 0 to exp do
f_Pol4:=f_Pol4 + d[i]*pow(X,udint_to_real(i));
end_for

end_function

И это вместо простого вычисления по схеме Горнера

f_PT1000 := RtR0 * (D1 + RtR0 * (D2 + RtR0 * (D3 + RtR0 * D4)));
Т.е. простое действие обёрнуто в функцию, содержащую вместо нескольких арифметических действий:
- перепаковку входных данных в массив
- цикл, который из-за малого числа итераций можно развернуть
- вызов затратной функции pow(a, b)=exp(b*ln(a)) вместо одного умножения

А ведь на этот код Алиса смотрит! Стыдно же!

zjWlad
10.02.2026, 08:03
Сделал проще, ввёл 2 точки, где не работало 1 и -1, зато вычисление намного быстрее, точнее и цикл маленький

function SIN_Rad: real ; //имя функции и тип данных выхода
var_input
X: real ; //входная переменная
end_var
var //объявление локальных переменных
Zn : real ;
Pi : real:=3.1415927 ;
a,b: real ;
end_var

Zn:=pow(-1,bool_to_real(EXTRACT(real_to_udint((abs(X))/Pi),0) XOR not (X>0)));
a:=(abs(X)/Pi - udint_to_real(real_to_udint(abs(X)/Pi)))*Pi ;
b:=(Pi-a) * (bool_to_real(a>1.5707964))+a* bool_to_real(not(a>=1.5707964)) ; // 1,5707964
if x=1.5707964 or x=7.853982 then
SIN_Rad:=1.0;
elsif x=-1.5707964 or x=4.712389 then
SIN_Rad:=-1.0;
else
SIN_Rad:=((pow(b,9)/362880 + (((b-(pow(b,3)/6)) +pow(b,5)/120)- pow(b,7)/5040))-pow(b,11)/39916800)*Zn ;
end_if
end_function


Кстати, при последовательном вычислении членов ряда ошибка не возникает. Значение функций SIN_Rad и SIN_Rad2 практически совпадают. По данным fSUB разность 5.96E-8 отмечается лишь на некоторых углах (+/- 50, 245, 255 … - проверял через 5 градусов)). Извиняюсь за грубое редактирование (только для примера).


function SIN_Rad2: real ; //имя функции и тип данных выхода
var_input
X: real ; //входная переменная
end_var
var //объявление локальных переменных
Zn : real ;
Pi : real:=3.1415927 ;
a,b: real ;
i : udint; (* переменная цикла *)
end_var

Zn:=pow(-1,bool_to_real(EXTRACT(real_to_udint((abs(X))/Pi),0) XOR not (X>0)));
a:=(abs(X)/Pi - udint_to_real(real_to_udint(abs(X)/Pi)))*Pi ;
b:=(Pi-a) * (bool_to_real(a>1.5707964))+a* bool_to_real(not(a>=1.5707964)) ; // 1,5707964
(*
if x=1.5707964 or x=7.853982 then
SIN_Rad2:=1.0;
elsif x=-1.5707964 or x=4.712389 then
SIN_Rad2:=-1.0;
else
SIN_Rad2:=((pow(b,9)/362880 + (((b-(pow(b,3)/6)) +pow(b,5)/120)- pow(b,7)/5040))-pow(b,11)/39916800)*Zn ;
end_if
*)

// Вычисление степенного ряда Тейлора:
a:=b; (* 1-й член разложения *)
SIN_Rad2:= b; (* = 1-му члену разложения *)
b:=b*b; (* далее квадрат b *)
for i := 3 to 11 by 2 do
a:=a*b / udint_to_real(i * (i-1));(* очередной член разложения *)
SIN_Rad2:=a-SIN_Rad2;
end_for
SIN_Rad2:=-SIN_Rad2*Zn;

end_function

kondor3000
10.02.2026, 08:26
Кстати, при последовательном вычислении членов ряда ошибка не возникает. Значение функций SIN_Rad и SIN_Rad2 практически совпадают. По данным fSUB разность 5.96E-8 отмечается лишь на некоторых углах (+/- 50, 245, 255 … - проверял через 5 градусов)). Извиняюсь за грубое редактирование (только для примера).

Вас не смущает, что добавив цикл вы только усложнили функцию циклом, ничего не улучшив,
точность не лучше, на 90 и 270 градусах не работает, длительность цикла ПР выросла (по этой причине и отказался от рядов Тейлора). Какой смысл тогда?
Моя доработка хотя бы исправила работу на 90 и 270 градусах.

zjWlad
10.02.2026, 10:19
kondor3000.
Я действительно поспешил и ошибся в тестировании. Похоже в SIN_Rad ошибка спрятана в выражении:

b:=(Pi-a) * (bool_to_real(a>1.5707964))+a * bool_to_real(not(a>=1.5707964)) ; // 1,5707964
Именно оно обращается в ноль при 1,5707964.
Ну а пятикратный вызов простеньких выражений оформленный в виде цикла скорее всего не тяжелее пятикратного вызова pow()
( pow() во все времена была более тяжелой и часто менее точной чем арифметические операции, но возможно в Logic и не так).

zjWlad
10.02.2026, 12:47
kondor3000.
1 Похоже для устранения ошибки в SIN_Rad в выражении для b надо заменить сравнение «больше или равно»
на просто «больше», т.е. как то так:

b:=(Pi-a) * (bool_to_real(a>1.5707964))+a * bool_to_real(not(a>1.5707964)) ; // 1,5707964
2 В исправленной функции (из-за того что сравнение для исключения проводилось с входным аргументом
а не преобразованным значением) были исключены только четыре точки. А их гораздо больше, например,
минус 4,712389, минус 7,853982 и т.п. Можно конечно оговорить область определения, но …

Вы автор – Вам виднее.

kondor3000
10.02.2026, 14:30
kondor3000.
1 Похоже для устранения ошибки в SIN_Rad в выражении для b надо заменить сравнение «больше или равно»
на просто «больше», т.е. как то так:

b:=(Pi-a) * (bool_to_real(a>1.5707964))+a * bool_to_real(not(a>1.5707964)) ; // 1,5707964
2 В исправленной функции (из-за того что сравнение для исключения проводилось с входным аргументом
а не преобразованным значением) были исключены только четыре точки. А их гораздо больше, например,
минус 4,712389, минус 7,853982 и т.п. Можно конечно оговорить область определения, но …

Вы автор – Вам виднее.
А вот это хорошая мысль, достаточно убрать = и оставить > и всё работает правильно во всех точках.
И я не автор, всего лишь переписал на ST функции и астротаймер с форума.

WKD
04.03.2026, 09:15
Приветствую! Прошу помощи с написанием на ST алгоритма:
1. Алгоритм активен при активном входе "1"
2. При активации входа "2" (активация по переднему фронту) запускать алгоритм:
а) открываем выход "1" на время "т1"
б) закрываем выход "1", ждем время "т2"
в) открываем выход "2" на время "т1"
г) закрываем выход "2", ждем время "т2"
... и т.д. до последнего выхода
При повторной активации входа "2" цикл перебора выходов не должен прерываться! Выход из цикла только по прерыванию сигнала на вход "1".

kondor3000
04.03.2026, 10:00
Приветствую! Прошу помощи с написанием на ST алгоритма:
1. Алгоритм активен при активном входе "1"
2. При активации входа "2" (активация по переднему фронту) запускать алгоритм:
а) открываем выход "1" на время "т1"
б) закрываем выход "1", ждем время "т2"
в) открываем выход "2" на время "т1"
г) закрываем выход "2", ждем время "т2"
... и т.д. до последнего выхода
При повторной активации входа "2" цикл перебора выходов не должен прерываться! Выход из цикла только по прерыванию сигнала на вход "1".
Сколько всего выходов не написали, какое время тоже!
Вот пример, на 80% выполняет ваши задачи, Шаги Case_State https://owen.ru/forum/showthread.php?t=38239&page=43#424, выход сделать Битовой маской, для включения нужных выходов.
или отсюда Шаговик, тоже немного переделать https://owen.ru/forum/showthread.php?t=38239&page=11#105

WKD
04.03.2026, 10:46
Сколько всего выходов не написали, какое время тоже!

Значение времени в данном случае не принципиально, как и количество выходов. Главное сам алгоритм понять как должен работать. За примеры спасибо, буду изучать и думать.

EFrol
04.03.2026, 12:30
function_block func

var_input
Stop, Start : bool;
end_var

var_output
Q1, Q2, Q3, Q4, Q5 : bool;
end_var

var
tmr : SYS.TON;
Q : bool;
nQ : udint;
end_var

if Start and nQ = 0 then nQ := 1; Q := true; end_if // Пуск алгоритма
if Not Stop then nQ := 0; Q := false; end_if // Стоп алгоритма
if Q then tmr.T := T#1s; else tmr.T := T#2s; end_if // Выдача - 1s, пауза - 2s

tmr(I := nQ > 0); // Отсчёт времени
if tmr.Q then // Смена состояния выхода
Q := not Q; tmr(I := false);
if Q then // Смена выхода
nQ := nQ + 1; if nQ > 5 then nQ := 0; end_if
end_if
end_if

Q1 := Q and nQ = 1;
Q2 := Q and nQ = 2;
Q3 := Q and nQ = 3;
Q4 := Q and nQ = 4;
Q5 := Q and nQ = 5;

end_function_block

WKD
04.03.2026, 14:09
function_block func

var_input
Stop, Start : bool;
end_var

var_output
Q1, Q2, Q3, Q4, Q5 : bool;
end_var

var
tmr : SYS.TON;
Q : bool;
nQ : udint;
end_var

if Start and nQ = 0 then nQ := 1; Q := true; end_if // Пуск алгоритма
if Not Stop then nQ := 0; Q := false; end_if // Стоп алгоритма
if Q then tmr.T := T#1s; else tmr.T := T#2s; end_if // Выдача - 1s, пауза - 2s

tmr(I := nQ > 0); // Отсчёт времени
if tmr.Q then // Смена состояния выхода
Q := not Q; tmr(I := false);
if Q then // Смена выхода
nQ := nQ + 1; if nQ > 5 then nQ := 0; end_if
end_if
end_if

Q1 := Q and nQ = 1;
Q2 := Q and nQ = 2;
Q3 := Q and nQ = 3;
Q4 := Q and nQ = 4;
Q5 := Q and nQ = 5;

end_function_block


Благодарю! Очень красивое решение! Глядя на свой код в 100+ строк, понимаю что нужно расти.