<< Click to Display Table of Contents >> Navigation: Проект в MasterSCADA 4D > Рекомендации по созданию проектов > Формирование отчета с помощью ФБ READ_ARCHIVE_DATA |
Содержание статьи:
1.Общее описание
2.Постановка задачи
3.Генерация архивного значения
4.READ_ARCHIVE_DATA
5.Массив структур типа SYSTEM_*_PARAM
6.Таблица данных. Условное выделение ячеек
7.Выгрузка данных в .CSV файл с помощью ФБ StringToFile
На большинстве контроллеров формирование отчетов, с использованием стандартного редактора отчетов, технически невозможно, поэтому если стоит задача отобразить архивные данные в табличном виде на контроллере, то придется использовать ФБ READ_ARCHIVE_DATA (далее RAD) с выводом результата в графический элемент Таблица данных и записью в сторонний .csv файл. Этот пример может быть также полезен для дополнительного освоения MasterSCADA 4D в других прикладных задачах.
Сгенерировать архивные значения параметра объекта, при этом формируя недостоверный признак качества. Отобразить этот параметр на графике, выделив аварийный диапазон значений. Использовать начало и конец отображаемого интервала тренда для формирования массивов значений, признаков качества и меток времени с помощью RAD. Полученные массивы собрать в единый массив структур и вывести его на таблицу данных. В таблице выделить ячейки с аварийными значениями, а также строку с недостоверным признаком качества. Также этот массив нужно записать в сторонний .csv файл.
В проекте есть архивируемый параметр типа SYSTEM_LREAL_PARAM с настройками архивирования по умолчанию. Нужно задать значения полей Value, SourceTime и StatusCode.
Делаем это с помощью генераторов сигналов из библиотеки OSCAT:
Т.е. значение меняется произвольно от 0 до 100 раз в 1 секунду, метка времена формируется с помощью функции GET_UTC_TIME, а признак качества будет недостоверным в течении 2 секунд.
У параметра установим настройки шкалы AI, будем использовать верхний и нижний аварийные значения:
Нужно обработать полученные архивные данные, отобразить эти данные в табличном виде и экспортировать эти данные. Для решения такой задачи обычно используется стандартный редактор отчетов, но на контроллерах сформировать их нельзя. В таком случае можно воспользоваться графическим элементом Тренд. На стартовое окно из палитры нужно вытащить тренд и архивный параметр перетащить на график.
Получим результат:
Тренд позволяет вывести архивные значения за отображаемый интервал, экспортировать эти данные в .csv, а с помощью легенды тренда можно получить максимальное и минимальное значения за отображаемый период.
Если на данном этапе для вас и заказчика проблема решена - то можно смело дальше не читать. Но если: тренд вообще не предполагался, выводимая таблица слишком маленькая и без выделения всех ячеек, в таблице нет признака качества, обработок в легенде недостаточно и вообще требуется построить аналог периодического отчета, а не отчета по изменению - приступаем к следующему пункту.
ФБ READ_ARCHIVE_DATA позволяет получить массив значений, массив меток времени и массив признаков качества за определенный промежуток времени, а также выполнить обработку архивируемых значений за интервал.
Вид блока в редакторе FBD:
В нашем примере начало и конец будем брать из графика, так как тренд может возвращать по исходящей связи значения интервала и конца:
Здесь мы это делаем для удобства, в вашем проекте будут свои начало и конец для RAD. Тренд не возвращает свойство Начало, поэтому его мы посчитаем отдельно в программе:
Далее нужно задать параметр, по которому будем производить запрос в базу. Для этого нужно задать входную переменную Item. Это можно сделать вручную, узнав id архивного параметра в служебных свойствах, либо создать входную переменную программы Ссылка типа REF_TO (этот тип возвращает id элемента, с которым связан), связать с архивным параметром и ножкой Item ФБ RAD:
Далее определим, как обрабатывать архивные значения параметров с помощью входа Aggregate. По умолчанию вход имеет значение Sampling. В таком случае после вызова ФБ вернется массив архивных значений без какой-либо обработки, т.е. результатом будет та же таблица, которую формирует тренд, или отчет по изменению. Но если стоит задача провести обработку архивных значений за небольшие интервалы, т.е. построить периодический отчет, то нужно поменять значения входа Aggregate и Interval.
У нас есть архивные значения за большой промежуток времени, например, расход электричества за год, и нужно посчитать среднее потребление в месяц. В таком случае выбирается значение входа Aggregate - Average, а интервал 1 месяц, разница между Begin и End будет составлять один год. Результатом будет массив из 12 значений, и каждое значение будет среднее за интервал в 1 месяц, т.е. система автоматически просуммирует все значения и поделит на число таких значений. Тут важно еще следить за входом Bound, чтобы учитывать значения на границах интервалов. В примере мы с вами посмотрим все возможные обработки, поэтому Aggregate будем менять с помощью выпадающего списка на окне.
После вызова этого ФБ с помощью задания True входа Run (на окне обычной кнопкой) получим нужные нам массивы, а также количество элементов в этих массивах:
Далее с массивами можно делать любые операции. В частности, если текущих обработок недостаточно и у вас свои уникальные расчеты, то далее нужно писать свой ФБ, который бы производил эти вычисления с полученными данными. Нам также нужно это сделать, нам нужно собрать массив значений, меток времени и признаков качества в единый массив структур, так как источником данных для таблицы является именно массив структур.
В локальную библиотеку добавим ФБ на языке ST. Входными переменными будут динамические массивы типа LREAL, DT и UDINT, так как количество значений, возвращаемых RAD, разное после каждого вызова ФБ:
Также входной переменной будет число элементов массива, а результатом ФБ - массив структур типа SYSTEM_LREAL_PARAM:
Тело программы:
OutArray := CREATE_ARRAY(INIT:= Переменная_2, SIZE:= Count); //каждый раз создаем новый массив с новой длиной
for i := 1 to Count do
OutArray[i].Value := InputArrayData[i]; //простое присвоение
OutArray[i].SourceTime := InputArrayDate[i];
OutArray[i].StatusCode := InputArrayStatusCode[i];
END_FOR;
И экземпляр этого ФБ используемой в основной программе:
OutArray будем использовать в качестве источника для таблицы данных.
На окно вытащим графический элементТаблица данных и установим связь свойства Источник данных этой таблицы с параметром типа динамический массив структур SYSTEM_LREAL_PARAM:
Дважды совершим клик по таблице и в редакторе таблицы зададим столбцы:
Необходимо выделить в таблице те ячейки, которые не попали в нормальный диапазон 10..90, а также выделить строки, соответствующие плохому признаку качества. Для начала перейдем в стиль строки и зададим точечную конвертацию по StatusCode:
Затем в стиле ячейки создадим стиль Авария, в котором по значениям Value будем менять цвет текста и его жирность:
Вернемся в редактор столбцов таблицы и для столбца Value установим стиль ячеек Авария:
В результате в среде исполнения вы сможете задать обработку аварийных значений на схеме, а также выделить нужные значения в таблице данных:
В примере выше есть один большой недостаток - эту таблицу не экспортировать и не распечатать, на момент написания этого документа такая задача еще стоит в очереди на разработку. Но есть способ записать массив структур в сторонний .csv с помощью ФБ StringToFile. Создадим программу:
count := UPPER_BOUND(ARR:= Результат, DIM:= 1);
a_1 := Результат[1].Value;
b_1 := Результат[count].Value;
if a_1 <> a and b_1 <> b THEN
Переменная_7 := Переменная_8;
a := Результат[1].Value;
b := Результат[count].Value;
ELSIF a = a_1 and b = b_1 and i <> count THEN
for i := 1 to count do
Переменная_1 := CONCAT(IN1:= LREAL_TO_STRING(Результат[i].Value) , IN2:= Переменная_2);
Переменная_4 := CONCAT(IN1:= DT_TO_STRING(Результат[i].SourceTime), IN2:= Переменная_2);
Переменная_5 := CONCAT(IN1:= UDINT_TO_STRING(Результат[i].StatusCode), IN2:= "");
Переменная_6 := CONCAT(IN1:= CONCAT(IN1:= CONCAT(IN1:= Переменная_1, IN2:= Переменная_4) , IN2:=Переменная_5 ) , IN2:=Переменная_3 );
Переменная_7 := CONCAT(IN1:= Переменная_7, IN2:= Переменная_6);
END_FOR;
END_IF;
StringToFile_1(Input:= Переменная_7, FileName:="C:\Users\User\Desktop\43.csv" , Write:= Запись);
count := UPPER_BOUND(ARR:= Результат, DIM:= 1); - получаем количество элементов массива структур
a_1 := Результат[1].Value; - получаем первый элемент массива структур
b_1 := Результат[count].Value; - получаем последний элемент массива структур
Эти значения нам нужны для того, чтобы затем обнулять результат записи в файл.
if a_1 <> a and b_1 <> b THEN
Переменная_7 := Переменная_8;
a := Результат[1].Value;
b := Результат[count].Value;
Переменная_8 - пустая строка, Переменная_7 - результат, который надо записать в csv файл. Поэтому если мы поменяли интервал, то предыдущий результат надо обнулить.
ELSIF a = a_1 and b = b_1 and i <> count THEN - если же интервал не менялся, то можно задать значение переменной типа STRING
for i := 1 to count do
Переменная_1 := CONCAT(IN1:= LREAL_TO_STRING(Результат[i].Value) , IN2:= Переменная_2);
Переменная_4 := CONCAT(IN1:= DT_TO_STRING(Результат[i].SourceTime), IN2:= Переменная_2);
Переменная_5 := CONCAT(IN1:= UDINT_TO_STRING(Результат[i].StatusCode), IN2:= "");
Переменная_6 := CONCAT(IN1:= CONCAT(IN1:= CONCAT(IN1:= Переменная_1, IN2:= Переменная_4) , IN2:=Переменная_5 ) , IN2:=Переменная_3 );
Переменная_7 := CONCAT(IN1:= Переменная_7, IN2:= Переменная_6);
END_FOR;
END_IF;
Потому что разделителем между столбцами в csv является точка с запятой “;”, а переходом на следующую строку перевод каретки. Поэтому в цикле мы каждый раз приклеиваем сначала к Value значение SourceTime через точку с запятой, затем к этой новой строке приклеиваем значение признака качества, а уже потом к строке целиком добавляем перевод каретки. И так каждый элемент массива.
StringToFile_1(Input:= Переменная_7, FileName:="C:\Users\User\Desktop\43.csv" , Write:= Запись);
Это вызов ФБ SrtingToFile - на вход идет стринговое представление массива структур, далее нужно обязательно указать путь к файлу, куда пишем значения.
В результате получим: