Просмотр полной версии : CFC last value
Доброго времени суток. Появился вопрос по реализации, к сожалению не могу проверить по факту. Сам вопрос: как можно реализовать на CFC переменную которая помнит значение на 2 секунды ранее.
Например, у меня есть СИ8 в нем идет подсчет импульсов, но нужно еще реализовать выход на режим без расходомера. Думаю использовать значения СИ8 импульсов за промежуток в 2 сек. Зная цену импульса можно узнать текущее показание расхода. Но это все теория.
И вот встал вопрос по реализации как записать в переменную прошлое значение? Я попробовал сделать с помощью блоков BLINK SR и MOVE (EN/ENO), но это кажется не то.
Может кто сможет что нибудь подсказать?
Спасибо.
А как подсказывать то если не выложили свой проект. Обычно это делается с помощью таймера ton и селектора sel
Serhioromano
20.07.2017, 09:30
Ни думаю что ТОН тут справиться. Ведь речь идет о 2х секунадх назад. Это значит чно нужно хранить данные за последние 2 секунды. Нам нужно что то вроде базы данных для этого. Ведь речь о прошлом. Таймер туда не икак не посчитает.
Что первое приходи в голову, это массив структурированых данных, который хранит по одному значению на каждый цикл контроллер за последние 2 секунды. И для подсчета берет последее значение массва, а потом его удаляет, и дописывает новое текущее которое через 2 секунды станет последним.
Думаю такой блок будет проще написать в ST а потом его уже в CFC использовать.
Вот моя идея.
http://www.owen.ru/forum/attachment.php?attachmentid=32149&stc=1&d=1500531999
Значит тут 200 это как бы идея такая что если цикл ПЛК 10мс, то значит 2 секунды это 200 циклов. Значит мы как бы каждый раз будем добавлять по элементу, и выводить 200тый цыкл. Другими словами этот блок будет показывать данные 200 циклов назад.
Но я не уверен что время будет тут точно 2 секунды.
Для точного времени массив db должен быть из структуры которая хранит и время RTC в микросекундах. И уже по нему орентироваться, высчитывать сумму значений имеено в пределах 2х секунд.
А этот код это как идея как хранить массив как базу данных.
Может подойдут ФБ FT_TN8, FT_TN16 или FT_TN64 из библиотеки OSCAT?
http://www.owen.ru/forum/showthread.php?t=19268&p=152225&viewfull=1#post152225
Пример задержки сигнала с использованием этих ФБ
32150
32151
32152
У меня такая идея. Можно даже без сброса счетчика. После выхода на уставку сбросить и использовать уже как счетчик.
Ни думаю что ТОН тут справиться. Ведь речь идет о 2х секунадх назад. Это значит чно нужно хранить данные за последние 2 секунды. Нам нужно что то вроде базы данных для этого. Ведь речь о прошлом. Таймер туда не икак не посчитает.
Я предлагал таймер использовать не в качестве машины времени, а для отсчета времени, а хранение делать на SEL, без всяких массивов. Потому что, не стоит считать, что цикл длиться именно столько сколько установлено в минимальном времени цикла и гарантии, что в последнем массиве будет значение пришедшее 2 секунды назад, нет ни какой. За каждый цикл будет накапливаться некоторая ошибка, в отличии от таймера который ошибется только в последнем цикле.
Кроме того, ТС просил код в CFC, нука накидайте цикл FOR в графическом языке, чтоб это было просто для понимания
capzap, спасибо. И еще вопрос на счет переменных. Я вот получил переменную OLD теперь хочу вычесть с текущего значения значение OLD что бы получит количество импульсов за 2 секунды. Как мне лучше это сделать? Мой способ не подходит, во время нового цикла программы значения пересекаются и получается при вычитании соответственно 0.
таймер у меня выдает импульс на выходе, например у элемента DIV добавить EN/ENO, импульс подать на EN, вычесть из текущего значение прошлое, а с ENO подать на SEL чтоб сохранить. Главное при вставке нового элемента не забыть обновить порядок выполнения
Serhioromano
21.07.2017, 09:42
таймер у меня выдает импульс на выходе, например у элемента DIV добавить EN/ENO, импульс подать на EN, вычесть из текущего значение прошлое, а с ENO подать на SEL чтоб сохранить. Главное при вставке нового элемента не забыть обновить порядок выполнения
Твой код не только выдает данные 2 секунды назад но и каждые 2 секунды. Не получиться так получать данные каждый момент времени. Что бы каждый цикл прогрммы получать данные с задержкой 2 секунды, нужно хранить эти данные за 2 секунды. Иначе точные данные расчета скорости или чего том будут только в том цикле прогрммы когда TON.Q будет тру. А потом все будет не точно.
Может подойдут ФБ FT_TN8, FT_TN16 или FT_TN64 из библиотеки OSCAT?
Это вроде и то и не то. Эти блоки задерживают сигнал на время. А задержать сигнал не требуется. Как я понял требуется просто получить значение на в переменной 2 секунды назад. Потом по времени расчитать расход за 2 секунды. Например на счетчике 2 секунды назад было 100 а теперь 150, значит мы за 2 секунды прошли 50 чегото там, а значит что мы двигаемся со скоростью ХХХ в час.
Твой код не только выдает данные 2 секунды назад но и каждые 2 секунды. Не получиться так получать данные каждый момент времени. Что бы каждый цикл прогрммы получать данные с задержкой 2 секунды, нужно хранить эти данные за 2 секунды. Иначе точные данные расчета скорости или чего том будут только в том цикле прогрммы когда TON.Q будет тру. А потом все будет не точно.
Прочитайте задачу в первом посте и ответе соответствует ли мой подход ей, спрашивали о задержке на две секунды. Во вторых
Как я понял требуется просто получить значение на в переменной 2 секунды назадвот вроде как раз оно, тогда зачем Вы мне тут разъясняете про мгновенный расход в каждый момент времени
И я того же мнения
32171
Вроде и работает как надо, но периодически значение просидает или обнуляется. Сначала все в норме идет показывает значение с небольшой погрешностью, но иногда начинает выходить в 0 или показывать значение в несколько раз меньше чем было.
32198
32199
32200
Вроде и работает как надо, но периодически значение просидает или обнуляется. Сначала все в норме идет показывает значение с небольшой погрешностью, но иногда начинает выходить в 0 или показывать значение в несколько раз меньше чем было.
32198
32199
32200
Скорей всего это из-за того, что числа REAL приблизительные, всего 7...8 точных знаков.
А Вы используете для счетчика числа DINT, при преобразовании DINT_TO_REAL будет большая погрешность для больших чисел
Попробуйте так
1. Вот ФБ задержки для чисел DINT. Я его из FT_TN64 сделал, оскатовская библиотека больше не нужна
32208
FUNCTION_BLOCK Zad_DINT
VAR_INPUT
in : DINT;
T : TIME;
END_VAR
VAR_OUTPUT
out : DINT;
trig: BOOL;
END_VAR
VAR
length : INT := 64;
X : ARRAY[0..63] OF DINT;
cnt : INT;
last : TIME;
tx: TIME;
init: BOOL;
END_VAR
(* read system time *)
tx := TIME();
trig := FALSE;
IF NOT init THEN
x[cnt] := in;
init := TRUE;
last := tx;
ELSIF tx - last >= T / length THEN
IF cnt = length - 1 THEN cnt := 0; ELSE cnt := cnt + 1; END_IF;
Out := X[cnt];
x[cnt] := in;
last := tx;
trig := TRUE;
END_IF;
2. Преобразовывать DINT_TO_REAL нужно после вычитания "старых" значений из "новых"
32209
Скорей всего это из-за того, что числа REAL приблизительные, всего 7...8 точных знаков.
А Вы используете для счетчика числа DINT, при преобразовании DINT_TO_REAL будет большая погрешность для больших чисел
Попробуйте так
1. Вот ФБ задержки для чисел DINT. Я его из FT_TN64 сделал, оскатовская библиотека больше не нужна
32208
FUNCTION_BLOCK Zad_DINT
VAR_INPUT
in : DINT;
T : TIME;
END_VAR
VAR_OUTPUT
out : DINT;
trig: BOOL;
END_VAR
VAR
length : INT := 64;
X : ARRAY[0..63] OF DINT;
cnt : INT;
last : TIME;
tx: TIME;
init: BOOL;
END_VAR
(* read system time *)
tx := TIME();
trig := FALSE;
IF NOT init THEN
x[cnt] := in;
init := TRUE;
last := tx;
ELSIF tx - last >= T / length THEN
IF cnt = length - 1 THEN cnt := 0; ELSE cnt := cnt + 1; END_IF;
Out := X[cnt];
x[cnt] := in;
last := tx;
trig := TRUE;
END_IF;
2. Преобразовывать DINT_TO_REAL нужно после вычитания "старых" значений из "новых"
32209
а еще можно сделать одно внедрение из оскат и добавить в окно объявления VAR CONSTANT length : INT := 64; END_VAR, в обычном VAR убрать length и массив объявить как X : ARRAY[0..length] OF DINT; и в коде вместо условия cnt пропускать через модуль
Значения прыгают, но меньше. Думаю может это как то связано с периодом опроса. Теперь значения проседают в пределах 220-270
Значения прыгают, но меньше. Думаю может это как то связано с периодом опроса. Теперь значения проседают в пределах 220-270
Для этих значений
FUNCTION_BLOCK Zad_DINT
VAR_INPUT
in : DINT;
T : TIME;
END_VAR
VAR_OUTPUT
out : DINT;
trig: BOOL;
END_VAR
VAR
length : INT := 64;
X : ARRAY[0..63] OF DINT;
период опроса 2000/64 = 31,25 мс
Можно попробовать уменьшить дискретность выходного сигнала, например сделать
length : INT := 200;
X : ARRAY[0..199] OF DINT;
период опроса станет 2000/200 = 10 мс
В итоге попробовал разные значения и остановился все таки на
length : INT := 200;
X : ARRAY[0..199] OF DINT;
Но значения все равно в диапазоне изменяются. Решил просто это сгладить средним значением и поставил блок STATISTICS_REAL. Вывел наконец на блок PID. И он начал скакать, то выход минимум то максимум, хотя значение показывает +-2 или 3%.
В итоге попробовал разные значения и остановился все таки на
length : INT := 200;
X : ARRAY[0..199] OF DINT;
Но значения все равно в диапазоне изменяются. Решил просто это сгладить средним значением и поставил блок STATISTICS_REAL. Вывел наконец на блок PID. И он начал скакать, то выход минимум то максимум, хотя значение показывает +-2 или 3%.
регулятор гоняете в каждом циклк или в отдельной задаче с большим периодом?
Каждый цикл. Его лучше сделать через EN/ENO или я не правильно понимаю?
сделайте чтоб он выполнялся каждые 100мс, сравните результат
Подсчет расхода вообще не похож на то что у "эталона". Это первая проблема.
Вторая проблема на счет PID регулирования. Даже если выводить его по неправильному расходу на режим, то не получается. Выполнение каждые 100мс кроме блинка на EN/ENO (что не совсем то, как я понимаю)как еще можно сделать?
32214
по первой проблеме можно обратится к оскатовскому flow_meter
по второй в базовом документе КДС есть описание как создать несколько задач с разным временем выполнения
Подсчет расхода вообще не похож на то что у "эталона". Это первая проблема.
Вторая проблема на счет PID регулирования. Даже если выводить его по неправильному расходу на режим, то не получается. Выполнение каждые 100мс кроме блинка на EN/ENO (что не совсем то, как я понимаю)как еще можно сделать?
32214
Если коэффициенты PID взяты с потолка, то выполнение каждые 100мс не спасет.
Kp=1.2 ? А почему не 0.12 ?
И Tv=12 ? А почему не 120 ?
Я бы и Ymin сделал не 0, а -100. Соответственно и у LIN_TRAFO в этом случае д.б IN_MIN=-100
100ms спасет несколько от другого, например (http://www.owen.ru/forum/attachment.php?attachmentid=31236&d=1495173818).За каждый цикл, регулятор будет просчитывать "шумы" датчика и даже при идеальных коэффициентах стабильности не будет, если в регуляторе имеется "мертвая зона", то можно конечно и ей устранять подобные эффекты
Это Вы же предлагаете ПИД в другую программу поместить и с помощью глобальных переменных задать текущий расход в эту программу. Затем с помощью Task Manager (Конфигурация задач) задать в свойствах задач циклический тип и задать интервал в 100мс, правильно понял?
на счет flow metr не совсем понимаю, у меня обычный расчет (кол-во импульсов / цена импульса) * 3600 ну в моем случае 720 т.к. период измерения 5 сек. Я как раз брал промежуток в 5 сек кол-во импульсов.
Спасибо.
в симесах же обычно используют ОВ35 для вызова регуляторов там, в КДС задачи это нечто похожее на ОВ
ну а зачем изобретать велосипед, если кто то уже написал блок счетчика
Извините, не до конца понимаю на счет работы программы в интервале в 100мс. Тот способ который я описал выше ошибочный?
И еще вопрос на счет блока FLOW_METER. Я тяжело воспринимаю ST не могли бы помочь разобраться, а то как полез в эти дебри еще больше запутался.
Сам блок из OSCAT:
FUNCTION_BLOCK FLOW_METER
VAR_INPUT
VX : REAL;
E : BOOL;
RST : BOOL;
END_VAR
VAR_INPUT CONSTANT
PULSE_MODE : BOOL;
UPDATE_TIME : TIME := t#1s;
END_VAR
VAR_OUTPUT
F : REAL;
END_VAR
VAR_IN_OUT
X : REAL;
Y : UDINT;
END_VAR
VAR
tx, tl : TIME;
int1 : INTEGRATE;
init: BOOL;
e_last : BOOL;
tmp: INT;
x_last : REAL;
y_last : UDINT;
END_VAR
(*
version 1.0 23. jan. 2011
programmer hugo
tested by oscat
Flow meter measures flow according to gated time or pulses.
*)
IF NOT init THEN (* init on power up *)
init := TRUE;
tl := tx;
x_last := X;
y_last := Y;
int1.K := 2.7777777777777777E-4;
END_IF;
(* run integrator *)
int1(E := NOT (RST OR PULSE_MODE) AND E, X := VX, Y := X); (* gated operation *)
IF RST THEN (* reset *)
X := 0.0;
Y := 0;
tl := tx;
x_last := 0.0;
y_last := 0;
ELSIF E AND PULSE_MODE THEN (* check for pulse mode *)
IF NOT e_last THEN X := X + VX; END_IF;
END_IF;
e_last := E;
(* reduce X to be less than 1 and increase Y respectively *)
IF X > 1.0 THEN
tmp := FLOOR(X);
Y := Y + INT_TO_UDINT(tmp);
X := X - INT_TO_REAL(tmp);
END_IF;
(* calculate the current flow *)
tx := DWORD_TO_TIME(T_PLC_MS());
IF tx - tl >= UPDATE_TIME AND UPDATE_TIME > t#0s THEN
F := (UDINT_TO_REAL(Y - y_last) + X - x_last) / TIME_TO_REAL(tx - tl) * 3.6E6;
y_last := Y;
x_last := X;
tl := tx;
END_IF;
(* revision history
hm 23. jan. 2011 rev 1.0
original version
*)
я не понимаю зачем это нужно:
IF NOT init THEN (* init on power up *)
init := TRUE;
tl := tx;
x_last := X;
y_last := Y;
int1.K := 2.7777777777777777E-4;
END_IF;
Присвоение значений после сброса питания?!
Что за синтаксис на счет переменной int1.K := 2.7777777777777777E-4; ? Что такое .K ? И почему такое (2.7777777777777777E-4) значение у переменной?
и не понимаю эту часть:
tx := DWORD_TO_TIME(T_PLC_MS());
IF tx - tl >= UPDATE_TIME AND UPDATE_TIME > t#0s THEN
Что за время такое?
NOT init это инициализация при сттарте программы, так что скорее при подаче питания а не сбросе
int1 это видимо интеграл и следовательно в этом ПОУ переменная К, ей присваивается значение 0.0002777 вроде бы
T_PLC_MS() выдает результат количества миллисекунд в формате DWORD, её обратно переводят во время, издержки
NOT init это инициализация при сттарте программы, так что скорее при подаче питания а не сбросе
int1 это видимо интеграл и следовательно в этом ПОУ переменная К, ей присваивается значение 0.0002777 вроде бы
T_PLC_MS() выдает результат количества миллисекунд в формате DWORD, её обратно переводят во время, издержки
capzap, я правильно понимаю, что данный блок я могу использовать в своей программе изменив формулу расхода в строке F := (UDINT_TO_REAL(Y - y_last) + X - x_last) / TIME_TO_REAL(tx - tl) * 3.6E6; ?
И переменная UPDATE_TIME : TIME := t#1s; правильно понимаю, если изменю значение это и есть период обработки значений в блоке?
Возможно, надо проверять, эмуляция же работает
Powered by vBulletin® Version 4.2.3 Copyright © 2025 vBulletin Solutions, Inc. All rights reserved. Перевод: zCarot