Стартовая страница › Форумы › Понять, как работает ПО › Использование формул › Функции (формулы) для Rapid SCADA
- В этой теме 148 ответов, 16 участников, последнее обновление 1 месяц, 1 неделя назад сделано manjey73.
-
АвторСообщения
-
14.12.2016 в 10:11 #3862manjey73Участник17.12.2016 в 17:22 #3867manjey73Участник
Конечный вариант функции Toggle
Исходный код:
int[] toggleN = new int[1];
bool[] toggleB = new bool[1];
bool Toggle (double clk)
{
bool q = Val(CnlNum) > 0;
bool b = clk > 0;int res = Array.IndexOf(toggleN, CnlNum);
if (res == -1)
{
res = toggleN.Length;
Array.Resize(ref toggleN, res+1);
Array.Resize(ref toggleB, res+1);
toggleN[res] = CnlNum;
}bool edge = toggleB[res];
if (b && !edge) q = !q;
toggleB[res] = b;
return q;
}Вызов функции, Исп.формулу Toggle(Val(№ канала сигнала))
Другие переменные, кроме проверяемого канала не нужны.
17.12.2016 в 17:34 #3868manjey73УчастникНу и RS Trigger только с двумя входными переменными SET и Reset
bool RStrig (double set, double res)
{
bool s = set > 0;
bool r = res > 0;
bool q = r ? q = false : Val(CnlNum) > 0 || s;
return q ;
}Исп. формулу — RStrig(Val(№ канала set), Val(№ канала reset))
20.12.2016 в 15:33 #3869manjey73УчастникФункция масштабирования сигнала с плавающей точкой
Наименование — Scale_R
Исходный код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;
}Пример: Исп.формулу — Scaler(Val(№ канала измерения), 4,20,0.3,100.5)
4 — input min
20 — input max
0.3 — output min
100.5 — output max
Сигнал диапазона 4-20 будет масштабирован в диапазон 0.3 — 100.5Если in_min будет равен in_max то на выходе получим 0
Если больше, то на выходе будет output min.
Если сигнал будет выходить за пределы input min и input max то будут приняты данные значения и соответственно на выходе будет output min или output max соответственно.30.12.2016 в 11:42 #3971manjey73УчастникФункция возвращает количество тиков в миллисекундах.
Собственно функция стандартная из C#.Наименование — Ticks
Исходный кодpublic static long Ticks()
{
DateTime now = DateTime.Now;
long time = now.Ticks/10000;
return time;
}Пример смотреть ниже в следующей формуле (вызывается непосредственно из формулы)
30.12.2016 в 11:50 #3972manjey73УчастникФункция среднего плавающим окном, для работы требуется наличие Ticks
Наименование — Average
Исходный кодint [] aN = new int[1];
long [] at = new long[1];
float[] aD = new float[8];
double Average (double val, Int64 tx)
{
float q = Convert.ToSingle(val); float s=0; float a;
float [] ar = new float[8];
long t2 = Ticks();
int rd = 8;
int r = 1;
r = Array.IndexOf(aN, CnlNum);
if (r == -1)
{
r = aN.Length;
Array.Resize(ref aN, r+1);
Array.Resize(ref aD, r*rd);
Array.Resize(ref at, r+1);
aN[r] = CnlNum;
at[r] = Ticks();
aD[r*rd-8] = q;
}
long t1 = at[r];
long df = t2 — t1;
Array.Copy (aD, r*rd-8, ar, 0, 8);
if (df >= tx)
{
at[r] = Ticks();
for (int i = 7; i > 0; i—)
{
ar[i]= ar[i-1];
}
ar[0] = q;
}
int p = Array.IndexOf(ar, 0);
p-=1;
if (p<0) p=7;
for (int i = 0; i <= p; i++)
{
s = s + ar[i];
}
a = s / (p + 1);
Array.Copy (ar, 0, aD, r*rd-8, 8);
return a;
}Пример Дорасчетный, Исп.формулу — Average(Val(№ канала), фильтр)
где фильтр например = 500 — время в миллисекундах, после которого заносится значение в массив для измерения. Average(Val(310), 500)Можно сразу сделать округление значения, если необходимо, тогда формула будет выглядеть так Math.Round((Average(Val(309), 1000)),1)
p.s. Не знаю зачем делал, так, чтобы было переделал кем-то написанный макрос из Овен ПР200, с FBD на С#
13.01.2017 в 10:12 #4024MikhailМодератор// Словарь значений каналов Dictionary<int, double> CnlValDict = new Dictionary<int, double>(); // Получить значение канала double CnlValGet(int cnlNum) { double val; return CnlValDict.TryGetValue(cnlNum, out val) ? val : Val(); } // Установить значение канала double CnlValSet(int cnlNum) { CnlValDict[cnlNum] = Cmd; return double.NaN; }
// Вывод в лог void WriteToLog(string s) { using (System.IO.StreamWriter writer = new System.IO.StreamWriter(@"C:\SCADA\mylog.log", true, Encoding.UTF8)) { writer.WriteLine(s); } }
// Отправка команды для модуля ОВЕН double OWEN_Cmd(double cmdVal) { return cmdVal > 0 ? BitConverter.ToDouble(new byte[] { 0xFF, 0, 0, 0, 0, 0, 0, 0 }, 0) : 0; }
14.01.2017 в 12:59 #4060manjey73УчастникФункция сброса канала Дорасчетный ТИ в 0.
Например для сброса RS триггера от кнопки управления или подачи команды, после сброса триггера канал переводится в 0. Эдакий Rtrigger, импульс логической единицы.
Требуется наличие формулы CnlValGetSet постом выше от Михаила (первый код).Наименование — ResKey
Исходный кодdouble ResKey()
{
double val = CnlValGet(CnlNum);
bool key = Val(CnlNum) > 0;
if (key) CnlValDict[CnlNum] = 0;
return CnlValGet(CnlNum);
}Пример Дорасчетный, Исп.формулу — ResKey()
Устанавливать желательно после RS триггера.
Канал можно потом не отображать в таблице, команду управления вешать непосредственно на канал RS триггера.
Создаем канал управления, пишем в нем формулу CnlValSet(№ канала с формулой ResKey)
Номер канала управления прописываем в канале RS триггера.В табличном представлении пока необходимо использовать команду Стандартная, Откл-Вкл и использовать кнопку Включено.
Как поправят в очередном релизе команды, можно будет использовать команду Вкл с одной кнопкой. Ну или сделать по аналогии одну кнопку с надписью «Квитирование» например.В схеме не проверял.
01.04.2017 в 09:53 #5012MikhailМодераторПереставить байты для отправки стандартной команды по Модбас. Передаётся значение из 2 байт.
double SwapCmd() { ushort val = (ushort)Cmd; byte[] buf = BitConverter.GetBytes(val); return BitConverter.ToDouble(new byte[] { buf[1], buf[0], 0, 0, 0, 0, 0, 0 }, 0); }
19.05.2017 в 13:15 #5856manjey73УчастникИнвертирование bool переменной для обработки и записи. Например при использовании с Raspberry релейной платы, которая управляется через минус. (0 — реле включено, 1 — реле выключено). Чтобы в таблице показывалось наоборот 0-выкл, 1 -включено.
А так же, чтобы подавать команды Откл — Вкл так же наоборот.public double NotValue(double val) { bool boolVal = val > 0; return Convert.ToDouble(!boolVal); }
Во входном канале используем формулу NotValue(CnlVal), в канале управления соответственно NotValue(CmdVal)
25.05.2017 в 16:32 #5936manjey73УчастникФигово, что нельзя так же формулу прописать в Модуле Авт. управления……. ладно, погнали дальше…
Таймер задержки на включение Ton
int[] 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;
}Формула простая Ton(значение канала в double, время в миллисекундах)
Например в канале 152 используем формулу Ton(Val(150), 5000) — при появлении 1 на входном канале 150, появится единица на канале 152 (собственно сам Ton),Забыл, для работы нужна еще формула Ticks
31.05.2017 в 13:45 #5979manjey73УчастникЛучше в качестве выходного значения иметь переменную double, тогда формулы можны писать внутри других формул без дополнительных телодвижений, так как они прописываются в самой формуле. Например на примере Ton
Замените public bool Ton(double TonIn, long TonPT) на public double Ton(double TonIn, long TonPT) и вместо return q; пропишите return Convert.ToDouble(q);
Дальше — Гистерезис
int[] HysNum = new int[1];
bool[] Hys = new bool[1];
public double Hysteresis(double inCnl, double low, double high)
{
bool q = Val(CnlNum) > 0;
int res = Array.IndexOf(HysNum, CnlNum);
if (res == -1)
{
res = HysNum.Length;
Array.Resize(ref HysNum, res+1);
Array.Resize(ref Hys, res+1);
HysNum[res] = CnlNum;
Hys[res] = q;
}
if (inCnl < low) Hys[res] = true;
if (inCnl > high) Hys[res] = false;
return Convert.ToDouble(Hys[res]);
}Вызов формулы Hysteresis(Val(414),23.5,25.7) номер канала значения аналогового датчика например и нижний, верхний предел.
23.06.2017 в 13:17 #6277manjey73УчастникTOF — таймер с задержкой на выключение
int[] TofNum = new int[1];
long[] TofST = new long[1];
bool[] TofFlag = new bool[1];
public double Tof(double TofIn, long TofPT)
{
long ET = 0L;
bool q = Val(CnlNum) > 0;
bool tof_in = TofIn > 0;int res = Array.IndexOf(TofNum, CnlNum);
if (res == -1)
{
res = TofNum.Length;
Array.Resize(ref TofNum, res+1);
Array.Resize(ref TofST, res+1);
Array.Resize(ref TofFlag, res+1);
TofNum[res] = CnlNum;
}if (tof_in)
{
q = true;
TofFlag[res] = true;
TofST[res] = 0L;
ET = 0L;
}
else
{
if (TofFlag[res])
{
TofFlag[res] = false;
TofST[res] = Ticks();
ET = 0L;
}
else
{
if (q) ET = Ticks() — TofST[res];
}
if (ET >= TofPT) q = false;
}
return Convert.ToDouble(q);
}Вызов формулы Tof(Val(414),10000) номер контролируемого канала, время в миллисекундах.
Для работы требуется формула Ticks- Этот ответ был изменен 7 лет, 7 месяцев назад от manjey73.
23.06.2017 в 17:00 #6290manjey73УчастникFtrig — появление импульса (лог 1) в канале по спаду контролируемого сигнала
Можно отловить модулем автоматического управления, визуализация бывает не показывает.
———————————————int[] FtrigN = new int[1];
bool[] FtrigM = new bool[1];
double Ftrig (double clk)
{
bool q = Val(CnlNum) > 0;
bool c = clk > 0;
int res = Array.IndexOf(FtrigN, CnlNum);
if (res == -1)
{
res = FtrigN.Length;
Array.Resize(ref FtrigN, res+1);
Array.Resize(ref FtrigM, res+1);
FtrigN[res] = CnlNum;
FtrigM[res] = true;
}q = !c && !FtrigM[res];
FtrigM[res] = !c;
return Convert.ToDouble(q);
}Собственно применение, канал 187 — использование формулы — Ftrig(Val(186)) — 186 — номер контролируемого сигнала. Модулем ловим 187-й канал.
- Этот ответ был изменен 7 лет, 7 месяцев назад от manjey73.
30.06.2017 в 09:45 #6338manjey73УчастникTp — Таймер импульса заданной длительности, для работы требуется Ticks
__________________________________________________________
int[] TpNum = new int[1];
long[] TpST = new long[1];
bool[] TpFlag = new bool[1];
public double Tp(double TpIn, long TpPT)
{
long ET = 0L;
bool q = Val(CnlNum) > 0;
bool tp_in = TpIn > 0;int res = Array.IndexOf(TpNum, CnlNum);
if (res == -1)
{
res = TpNum.Length;
Array.Resize(ref TpNum, res+1);
Array.Resize(ref TpST, res+1);
Array.Resize(ref TpFlag, res+1);
TpNum[res] = CnlNum;
}if (!TpFlag[res])
{
if (tp_in)
{
TpFlag[res] = true;
TpST[res] = Ticks();
if (ET < TpPT) q = true;
}
}
else
{
if (q)
{
ET = Ticks() — TpST[res];
if (ET >= TpPT) q = false;
}
else
{
if(!tp_in)
{
TpFlag[res] = false;
ET = 0L;
}
}
}
return Convert.ToDouble(q);
}___________________________________________________________
Вызов формулы Tp(Val(414),10000) номер контролируемого канала 414, время в миллисекундах.
При появлении 1 в канале 414 включится выход таймера, по истечении 10 секунд выключится для данного примера. Таймер начинает работать по фронту сигнала, не требуется удержание 1 в контролируемом канале.з.ы. во всех таймерах время в мс задается переменной long, надо бы переделать на double и в long переводить уже внутри формулы. Упростит например запись в формулах, когда для множества таймеров одно и то же время PT, так как его можно брать из дополнительного канала.
сейчас приходится делать так Tp(Val(414),Convert.ToInt64(Val(1)))
в 1-й канал можно вводить время задержки командой. Так же можно на лету менять время, тоже оказалось полезным. -
АвторСообщения
- Вы должны авторизироваться для ответа в этой теме.