PDA

Просмотр полной версии : Стек, динамический массив в ПЛК, Codesys



Frayl
29.05.2012, 13:00
Добрый день. Необходим совет.
Хочется считывать значения с датчика в динамический массив типа стек или очередь (в конец массива вставил новый элемент, с начала 1 удалил), для последующего усреднения. Как бы это аккуратно и безболезненно организовать?

lara197a
29.05.2012, 13:21
Через цикл FOR.
По команде, к примеру когда новое значение не равно старому, запускаете цикл и присваиваете значения от предпоследнего к последнему и...до верха.

capzap
29.05.2012, 14:33
Добрый день. Необходим совет.
Хочется считывать значения с датчика в динамический массив типа стек или очередь (в конец массива вставил новый элемент, с начала 1 удалил), для последующего усреднения. Как бы это аккуратно и безболезненно организовать?

Обращайтесь к библиотеке oscat, в папке Logic\memory есть реализации и стека и "певый вошел первый вышел"

Frayl
29.05.2012, 14:35
Рабочая схема. Только немного неудобно цикл в цикле делать. Вроде бы попроще нашел. Может пригодится кому (или покритикует).


PROGRAM PLC_PRG
VAR
ar:ARRAY[1..10]OF BYTE:=0,1,2,3,4,5,6,7,8,9;
i:BYTE:=10;
END_VAR
SysMemMove(dwDest:=ADR(ar[1]),dwSrc:=ADR(ar[2]), dwCount:=9);
ar[10]:=i;
i:=i+1;
IF i=255 THEN i:=0; END_IF;

capzap
29.05.2012, 14:37
а разве цикл в цикле работает на ПЛК?

Frayl
29.05.2012, 14:42
не пробовал. поэтому сделал без FOR

ksn33
29.05.2012, 15:00
а разве цикл в цикле работает на ПЛК?
писал, работает! приходилось и дважды цикл вкладывать на ПЛК100!

lazy
29.05.2012, 15:02
Если усреднение это простое среднее из 10 то необязательно чтобы в буфере (массиве) они были по порядку. В смысле среднее равно сумме значений в буфере поделенное на их количество. Если так то можно без копирования. Просто затирать в массиве самый "древний" результат.

PROGRAM PLC_PRG
VAR
ar:ARRAY[1..10]OF BYTE:=0,1,2,3,4,5,6,7,8,9;
nP: INT;
yNew: BYTE; (* новое значение чего то там *)
END_VAR

**********

nP:= nP + 1;
IF nP > 10 THEN
nP := 1;
END_IF;

ar[nP] := yNew;

Frayl
29.05.2012, 15:33
значения новые по времени и идут постоянно по времени опроса датчика. В конкретном случае тензодатчика. Усреднение для понижения шума и вибраций
предыдущий вариант понравился. Но величина массива нужна переменная. Памяти то можно выделять по переменной.

lazy
29.05.2012, 16:27
В таком случае цикл программы может "покрутиться" несколько раз в то время как значения с датчиков могут оставаться без изменений. Поэтому важно в массив "класть" действительно "новые" значения. Если память нужно выделять "динамически". Попробуйте SysMemAlloc. Но работать придется не с индексами массива а с "указателем" на выделенную память.

dwBuffer: POINTER TO BYTE (* буфер *)
dwPointer: POINTER TO BYTE; (* указатель на текщее значение в буфере *)
dwSize: DWORD; (* размер буфера *)
yNew: BYTE; (* новое!!! значение с датчиков *)
bInit: BOOL;

*****************

IF NOT bInit THEN

dwBuffer:= SysMemAlloc ( dwSize + 1 ); (* + 1 на всякий случай *)
dwPointer := dwBuffer;
bInit := TRUE;

ELSE

IF (* если пришло новое значение *) THEN

dwPointer^ := yNew;

dwPointer := dwPointer + 1;
IF dwPointer > dwBuffer + dwSize THEN
dwPointer := dwBuffer;
END_IF;

END_IF;

END_IF;

как то так. но нужно протестить. ) в кодесисе не запускал.
А можно заранее объявить массив размером с наибольший разумный буфер. Но пользоваться лишь его частью. Типа динамически ))

lara197a
29.05.2012, 17:13
Да все там проще, я к примеру писал структуру(если много значений), из нее делал массив.
Далее так
IF VAR1 THEN (команда сдвига)
FOR Cn:= 30 TO 0 BY-1 DO ( к примеру архив на месяц от 31 до 0-текущей даты)
ARRAY[cn+1]:= ARRAY[cn];
END_FOR
END_IF

Yegor
30.05.2012, 06:17
Господа, от перестановки слагаемых сумма не изменяется. Зачем двигать весь массив, если можно сдвинуть новое значение? Просто записывайте очередной элемент на место того, который надо удалить. Для этого всего-навсего нужен счётчик входящих элементов. Псевдокод:
count := count + 1;
array[count MOD size_of_array] := value;

(* Считаем среднее по массиву *)Для пущей аккуратности и безболезненности за размер массива в цикле усреднения можно брать минимум между счётчиком и, собственно, размером массива.

Валенок
30.05.2012, 10:40
Зачем двигать весь массив, если можно сдвинуть новое значение?
Про это уже ответили :

..
PROGRAM PLC_PRG
VAR
ar:ARRAY[1..10]OF BYTE:=0,1,2,3,4,5,6,7,8,9;
nP: INT;
yNew: BYTE; (* новое значение чего то там *)
END_VAR
**********
nP:= nP + 1;
IF nP > 10 THEN
nP := 1;
END_IF;

ar[nP] := yNew;



..в цикле усреднения..
А этот цикл зачем ?

Yegor
30.05.2012, 10:43
Про это уже ответилиВерно, не удосужился дочитать.
А этот цикл зачем ?
для последующего усреднения

Валенок
30.05.2012, 10:52
А без цикла никак ?

Yegor
30.05.2012, 11:04
С накапливающейся ошибкой — как.

Валенок
30.05.2012, 11:10
Да все так же


PROGRAM PLC_PRG
VAR
ar:ARRAY[1..10]OF BYTE:=0,1,2,3,4,5,6,7,8,9;
nP: INT;
yNew: BYTE; (* новое значение чего то там *)
average:.... (усредненное значение) := ????
END_VAR

**********

nP:= nP + 1;
IF nP > 10 THEN
nP := 1;
END_IF;
average:=average+(yNew-ar[nP])/10;
ar[nP] := yNew;

Yegor
30.05.2012, 11:18
Вот оно и есть. Прогрессирующая потеря точности.

Валенок
30.05.2012, 11:22
А где прогрессирует ?
Всегда среднее последних 10-ти

PS
Для наглядности :
summ := summ -ar[nP] + yNew; (*ушел самый старый, на смену новый*)
averagwe:=summ / 10;

Yegor
30.05.2012, 11:31
В арифметических операциях с плавающей запятой не гарантируется точность результата. Эту неточность вы накапливаете в average.

Frayl
30.05.2012, 12:01
ну а что делать. среднее нужно всё-равно

capzap
30.05.2012, 12:20
В арифметических операциях с плавающей запятой не гарантируется точность результата. Эту неточность вы накапливаете в average.

а какая точность может быть у средней, Вы же сами принудительно загрубляете используя усреднение. В этом случае надо ставить ОРС сервер с режимом HDA чтоб всегда знать в какое время какая точная температура была и по этим же данным рисовать (суточный, часовой не важно) график для наглядности

Frayl
30.05.2012, 12:34
у меня дозатор

Валенок
30.05.2012, 12:36
В арифметических операциях с плавающей запятой не гарантируется точность результата. Эту неточность вы накапливаете в average.



Ai - не рандом, диапазон ограничен, колебания между несколькими соседями незначительна, значит експонента одинакова, и сложения/вычитания мантис - почти по правилам целых чисел.
Разрядность Ai - далеко не все 24 бита. Накапливаться нечему

При больших переживаниях по этому поводу всегда можно складывать типа :
var
sum10000 : dword;

sum10000 := sum10000 + real_to_dword( yNew -ar[nP] ) * 10000;
average := av10000 / 10 / 10000.0;

Real-вычисления в циклах - зародыш ватчдога



а какая точность может быть у средней, Вы же сами принудительно загрубляете
:) Тормознул

Валенок
30.05.2012, 12:39
у меня дозатор
Дозируем управлением по 4-20мА ?

Frayl
30.05.2012, 13:03
Тензодатчик с мв110.ТД.
Другой вопрос возник.
Как в панель СП270 записать биты? Считать можно.
То есть я создаю Universal Modbus Device для панели. Панель работает в режиме Slave.
Создаю 8 bit output module и управляющие биты. Далее, так как в режиме слейв доступна только память PSW у панели, кидаю туда эти биты, а на панели в непрерывном режиме копирую в область битов соответствующие регистры с PSW. Вопрос только в том, что биты не доходят.

Yegor
30.05.2012, 13:07
а какая точность может быть у средней, Вы же сами принудительно загрубляете используя усреднениеУсреднение этот как раз метод уточнения. А неточность, про которую говорю я, это постоянная составляющая.
експонента одинаковаОт −1E9 до 1E9, если верить параметрам Min FV / Max FV. И речь об аналоговых входах не шла вроде.

Спорить дальше не буду. Даже отчасти согласен — можно считать кумулятивно и периодически пересчитывать в цикле для пущей уверенности.

Валенок
30.05.2012, 13:31
От −1E9 до 1E9, если верить параметрам Min FV / Max FV.
−1E9 до 1E9 - бывают, а соседние E отличаются друг от друга максимум на 1. Мы же реальные значения рассматриваем, а не математику, вот 1e-9. Бац : 1e9

И речь об аналоговых входах не шла вроде.
Откуда в ПЛК может появится real ? :)

Yegor
30.05.2012, 13:42
От его не менее мозговитых и зачастую сумасшедших друзей, присылающих что-то вроде давления в вакуумной камере в паскалях по цифровому интерфейсу. Да-да, знаю: давление не меняется моментально и т.д.

Валенок
30.05.2012, 14:27
Ну да. А друзья давление откуда взяли ? Из тумбочки ?

Yegor
30.05.2012, 14:38
С потолка.

Frayl
30.05.2012, 14:38
Простите, что отвлекаю вас от увлекательнейшей(для меня)(нет серьезно увлекательной) беседы, просто уведомляю что с битами, массивами и усреднением разобрался.

capzap
30.05.2012, 14:49
на панели в непрерывном режиме копирую в область битов соответствующие регистры с PSW. Вопрос только в том, что биты не доходят.

А пробовали выводить на экран сам регистр, в нем значение соответствует отправляемомому, не забыли что байты(а вместе с ними и биты) в регистре могут переварачиваться

Frayl
30.05.2012, 14:51
да, помню. Разобрался уже - через систему 3 функциональных областей организовал обмен битами)

Frayl
01.06.2012, 13:52
кому интересно: можно обойтись одним набором битов для кнопок на панели (когда та в режиме слейв работает). Делать просто реверс бита по нажатию на кнопку и 1 функциональную область с непрерывной передачей бита в область PSW. И соответственно ловить эту ячейку памяти с ПЛК.

ProZorg_tm
09.12.2017, 15:26
Простите, что отвлекаю вас от увлекательнейшей(для меня)(нет серьезно увлекательной) беседы, просто уведомляю что с битами, массивами и усреднением разобрался.

можно код ?