Стартовая страница › Форумы › Понять, как работает ПО › Формулы › Функции (формулы) для Rapid SCADA
- В этой теме 149 ответов, 17 участников, последнее обновление 1 год, 3 месяца назад сделано
Oleg.
-
АвторСообщения
-
30.06.2017 в 09:50 #6341
manjey73УчастникR_Trig появление импульса (лог 1) в канале по фронту (переход от 0 к 1) контролируемого сигнала
Можно отловить модулем автоматического управления, визуализация бывает не показывает.________________________________________________________________
int[] RtrigN = new int[1];
bool[] RtrigM = new bool[1];
double Rtrig (double clk)
{
bool q = Val(CnlNum) > 0;
bool c = clk > 0;
int res = Array.IndexOf(RtrigN, CnlNum);
if (res == -1)
{
res = RtrigN.Length;
Array.Resize(ref RtrigN, res+1);
Array.Resize(ref RtrigM, res+1);
RtrigN[res] = CnlNum;
RtrigM[res] = false;
}q = c && !RtrigM[res];
RtrigM[res] = c;
return Convert.ToDouble(q);
}
_________________________________________________________________Запись в формуле аналогично F_trig
Собственно применение, канал 187 — использование формулы — Rtrig(Val(186)) — 186 — номер контролируемого сигнала. Модулем ловим 187-й канал.
-
Ответ изменён 8 лет, 12 месяцев назад пользователем
manjey73.
17.07.2017 в 09:56 #6650
djbond07УчастникДобрый день, manjey73! Попытался протестировать формулу TON, и вот что обнаружилось:
1. ScadaServer Ругается на длинное тире в этой записи
if (!q) ET = Ticks() — TonST[res];
Изменил на обычный «-«, ошибка пропала. Это же относится к формуле TOF.
А так формула работает, спасибо большое!17.07.2017 в 12:43 #6655
manjey73УчастникВозможно длинное тире подставилось при копировании формулы сюда на страницу.
Так как формулы вставляю как придется (в смысле из разных текстовых редакторов)Да, посмотрел, у меня в формуле короткое тире и это ошибка из-за копи паст произошла.
Как писал выше, я стараюсь все входные и выходные переменные преобразовать в/из double внутри формул, тогда легче применять формулы непосредственно в SCADA. Что позволяет в используемой в канале формуле не писать таких вещей как Convert.ToInt64(vvv) и так далее. Уж лучше пусть конвертирование будет внутри формулы, если оно необходимо.
-
Ответ изменён 8 лет, 11 месяцев назад пользователем
manjey73.
17.07.2017 в 12:49 #6657
manjey73УчастникТакая же ошибка есть и в TP
18.07.2017 в 16:34 #6671
MikhailМодераторС тире движок форума чудит.
Вы имеете возможность вставлять код в теги <pre></pre>?19.07.2017 в 16:38 #6686
manjey73УчастникФормулы для организации энергонезависимых переменных (запись и чтение из файла).
Retainstring pathRet = @"/home/pi/scada/ScadaServer/Config/retain.txt"; Dictionary<int, double> DictRet = new Dictionary<int, double>(); public double Retain (double ret) { DictRet[CnlNum] = ret; return ret; }Для применения на Windows в случае организации записи файла текущих данных current.dat на виртуальный диск для SSD дисков указать путь в формуле на соответствующий диск. Пример: string pathRet = @»e:\Retain\retain.txt»;
Ну или любая существующая папка, которую вы сделаете для указанного файла.
Наличие папок не проверяется, только наличие файла.Пример применения формулы в базе входных каналов. Retain(Val(150))
В канале управления может стоять SetVal(150, Cmd)В самом младшем входном канале применяется формула Load_Retain
Запись в канале LoadRet()bool initRet = false; double LoadRet() { if (!initRet) { if (System.IO.File.Exists(pathRet)) { string[] RetLoad = System.IO.File.ReadAllLines(pathRet, Encoding.UTF8); for (int i = 0; i < RetLoad.Length; i++) { SetVal(Convert.ToInt32(RetLoad[i].Substring(RetLoad[i].IndexOf("[")+1, RetLoad[i].IndexOf(", ")-(RetLoad[i].IndexOf("[")+1)),10),Convert.ToDouble(RetLoad[i].Substring(RetLoad[i].IndexOf(", ")+2,RetLoad[i].IndexOf("]")-(RetLoad[i].IndexOf(", ")+2)))); } initRet = true; } } return Convert.ToDouble(initRet); }Выполняется один раз при старте сервера
В самом последнем канале используется формула Save_Retain
Запись в формуле канала SaveRet()double SaveRet() { string[] RetSave = new string[DictRet.Count]; bool eq = false; for (int i = 0; i < DictRet.Count; i++) { RetSave[i] = Convert.ToString(System.Linq.Enumerable.ElementAt(DictRet, i)); } if (!System.IO.File.Exists(pathRet)) { System.IO.File.WriteAllLines(pathRet, RetSave, Encoding.UTF8); return 0; } else { string[] RetOld = System.IO.File.ReadAllLines(pathRet, Encoding.UTF8); eq = System.Linq.Enumerable.SequenceEqual(RetOld, RetSave); if (!eq) { System.IO.File.WriteAllLines(pathRet, RetSave, Encoding.UTF8); } } return Convert.ToDouble(eq); }Путь на Raspberry указываете свой в первой формуле.
Пример файла retain.txt[450, 23]
[451, 51]
[452, 51,5]
[453, 46]Первая цифра — номер канала, вторая — значение канала.
Запись файла происходит при изменении переменной, указанной как Retain.
Так же можно инициализировать необходимые переменные при запуске сервера.-
Ответ изменён 8 лет, 11 месяцев назад пользователем
manjey73.
19.07.2017 в 16:52 #6692
manjey73УчастникПример для Windows
string pathRet = @"e:\Retain\retain.txt";Для меняющих переменных в процессе работы, но которым надо сделать сохранение лучше добавить наверное еще таймер и записывать не чаще х минут. Мне так кажется.
Для конфигурационных переменных, которые меняются редко, можно использовать как есть.-
Ответ изменён 8 лет, 11 месяцев назад пользователем
manjey73.
20.07.2017 в 16:29 #6711
MikhailМодераторИдея по поводу хранения формул:
Завести проект на Visual Studio, писать формулы внутри этого проекта и выложить проект на GitHub. Я могу поделиться проектом-заготовкой, которая имеет заглушки для стандартных формул Rapid SCADA.
Смысл идеи — чтобы формулы точно не потерялись. А сюда выкладывать ссылки на них.20.07.2017 в 21:41 #6718
manjey73УчастникСкиньте тогда шаблон, можно будет выложить по аналогии с OpenKP.
А то я первоначальные формулы пару раз переписывал, ну и вообще видоизменял.-
Ответ изменён 8 лет, 11 месяцев назад пользователем
manjey73.
21.07.2017 в 19:41 #6721
MikhailМодераторМне нужно подготовить проект для общего использования. Как выложу, напишу в эту тему.
26.07.2017 в 16:33 #6758
MikhailМодераторПроект для тестирования формул https://github.com/RapidScada/scada/tree/develop/ScadaServer/FormulaTester
Обратите внимание, что он на данный момент в ветке develop. Примеры в коде говорят сами за себя. Используется функционал для запуска юнит-тестов Visual Studio.22.02.2018 в 23:42 #8554KoliaMor
УчастникТаймер, по аналогии TON, TOF. Только на выходе выдает время включения. Отдельный вход сброса TimRst().
// Tim int[] TimNum = new int[1]; long[] TimST = new long[1]; long[] TimAcc = new long[1]; bool[] TimFlag = new bool[1]; public double Tim(double TimIn, int mode) { bool Tim_in = TimIn > 0; int res = Array.IndexOf(TimNum, CnlNum); if (res == -1) { res = TimNum.Length; Array.Resize(ref TimNum, res+1); Array.Resize(ref TimST, res+1); Array.Resize(ref TimAcc, res+1); Array.Resize(ref TimFlag, res+1); TimNum[res] = CnlNum; } if (!Tim_in) { TimFlag[res] = false; TimST[res] = 0L; if((mode&1)==0) TimAcc[res] = 0L; } else { if (!TimFlag[res]) { TimFlag[res] = true; TimST[res] = Ticks(); } else { TimAcc[res] += Ticks() - TimST[res]; TimST[res] = Ticks(); } } if((mode&2)==0) { long Ret = ((mode&4)==0) ? TimAcc[res] : TimAcc[res]/1000; double Div = Math.Pow(10, (mode&0x70)>>4); return Convert.ToDouble(Ret)/Div; } else { DateTime RetTim = new DateTime(2018, 1, 1, 0, 0, 0); return EncodeDate(RetTim.AddMilliseconds(TimAcc[res])); } } public double TimRst(double InRst,int Chanel) { int res = Array.IndexOf(TimNum, Chanel); if (res != -1) { if(InRst!=0)TimAcc[res] = 0L; } return 0; } // Example : // 130, ДТИ, Фл = Tim(Val(101),0x05), Фт = D // 101 - включение // 131, ДТИ, Фл = TimRst(Val(102),130) // 102 - сброс (для (mode&1) > 0) // mode bits: // 0: 0 - без сохранения, 1 - с сохранением, сброс по Фл.TimRst -> при пропадании входа // 1: 0 - вывод double, 1 - вывод TimeData в формате double // 2: 0 - вывод double в мсек, 1 - вывод double в сек // 3: не используется // 4-6: делитель числа double: 0 - на 1, 1 на 10, 2 на 100 и т.д. до 10^7 // 7: не используется // Example : Tim(Val(101),0x30) - вывод времени в мс в формате D.DDD, время не сохраняется-
Ответ изменён 8 лет, 4 месяца назад пользователем
KoliaMor.
24.02.2018 в 13:06 #8559
MikhailМодераторспасибо
27.05.2021 в 16:30 #19617sakhalin_Cat
Участникспасибо
12.02.2024 в 13:11 #31025Algomus
УчастникПрошу помощи. Моих навыков не хватает. Как эту формулу превратить в генератор импульсов в один цикл.
Таймер задержки на включение Tonint[] TonNum = new int[1];
long[] TonST = new long[1];
bool[] TonFlag = new bool[1];
public bool Ton(double TonIn, long TonPT)
{
long ET = 0L;
bool q = Val(CnlNum) > 0;
bool ton_in = TonIn > 0;int res = Array.IndexOf(TonNum, CnlNum);
if (res == -1)
{
res = TonNum.Length;
Array.Resize(ref TonNum, res+1);
Array.Resize(ref TonST, res+1);
Array.Resize(ref TonFlag, res+1);
TonNum[res] = CnlNum;
}if (!ton_in)
{
q = false;
TonFlag[res] = false;
TonST[res] = 0L;
}
else
{
if (!TonFlag[res])
{
TonFlag[res] = true;
TonST[res] = Ticks();
}
else
{
if (!q) ET = Ticks() — TonST[res];
}
if (ET >= TonPT) q = true;
}
return q;
}-
Ответ изменён 2 года, 4 месяца назад пользователем
Algomus.
-
Ответ изменён 8 лет, 12 месяцев назад пользователем
-
АвторСообщения
- Для ответа в этой теме необходимо авторизоваться.