某天然气公司的生产信息平台,是一个生产运行关键数据统计和展示的平台,其中的装置关键参数合格率、设备运行状态、振动设备报警监测这三部分,由紫金桥实时数据库提供数据。
客户在功能上要求是这样的:
1、装置关键参数合格率,报警上下限值要从指定的关系数据库表中读取,该表由工艺人员根据需要修改报警上下限的限值,紫金桥软件根据此限值计算装置关键参数的合格率,计算完成后,再存入关系数据库指定的表中。
2、设备运行状态,实时值由信息平台实时读取,历史值要定时存入关系数据库指定的表中。
3、设备振动报警监测,实时值由信息平台实时读取,不需要存储历史值。
设备运行状态以及设备振动监测的实时数据是通过开放OPC Server接口,由对方直接实时采集,装置关键参数的合格率以及设备运行状态历史两部分的数据,是通过紫金桥实时数据库软件,将历史数据写入到SQL Server数据库中,再由生产信息平台系统从SQL Server中按照需要读取。
系统使用的软件版本:紫金桥实时数据库软件V6.5。
功能窗口截图如下,由于该窗口不需要展示,故未做任何美化:
各部分功能说明:
1-报警时间统计组件,用于统计位号的累计报警时间,以便计算合格率。
2-设备状态实时报表,实时显示设备状态值,通过脚本将对应位号的值存储到数据库中。
3-位号的报警上下限值报表,从关系数据库读取参数的报警限值。
4-手动读取合格率报警限值按钮,点击后读取关系数据库的报警限值。
5-查看当天已经写入数据的报表,用来查看数据库中已经写入的数据。
6-查看设备状态/合格率数据按钮。点击按钮分别查看最近一天的设备状态或者合格率数据。
窗口最下方的部分即5、6两块实际上不是功能必须的,只是方便开发者自己查看远程数据库中的数据是否成功存储。
本文主要介绍“装置关键参数合格率”这部分的功能,“设备运行状态”部分大同小异,“设备振动监测”部分不需要向关系数据库存储数据,所以这两部分不再过多叙述。接下来开始说明关键参数合格率功能部分:
1、窗口中新增报警时间统计组件,命名为Alarm1,在组件中添加需要进行统计的位号,设置位号使用自身报警限值。
2、点组态中,新增‘报表关系数据源点’,连接要读取数据的关系数据库。
3、窗口中新增自由报表,关系数据库连接里面,连接新建的报表关系数据源点,并将报表命名。本案例中,该报表名为Fr1 。
4、建立表模板。
使用紫金桥软件预定义的SQL函数向关系数据库插入数据,首先要按照固定表结构在关系数据库先创建表, SQL函数无法直接生成表,而是需要一个给定的模板,按照模板进行表的创建,这就需要事先定义好一个表模板。
下图是合格率数据表要使用的表模板,要创建的表一共有4个字段,分别是‘日期、位号名、值、权重’,对应的字段名分别是‘UpdateTime、TagName、TagValue、TagLevel’,权重这个字段是客户要求的。
合格率表模版
创建表使用函数SQLCreateTable(),这里定义一个窗口整型变量w_cID,供SQL函数使用。关于紫金桥实时数据库预定义的SQL函数的用法,请读者自行查看帮助,这里不再详述。
一旦数据表创建完毕,表模板就不再需要了。基于此原因,最开始的数据表是使用按钮创建的,创建完毕后,按钮就删除了,所以窗口中没有创建数据表的脚本。
5、建立绑定表。
数据表创建完毕后,接下来就是向表内插入数据了。要向关系数据库表内插入数据,需要使用紫金桥实时数据库的‘绑定表’,绑定表里的字段名设置要和表模版里的字段完全一致,否则插入数据时会失败。
另外,需要建立4个中间变量(图中变量名部分),分别对应数据表的4个字段,供绑定表使用,具体用法在后面脚本部分会详细介绍。
合格率绑定表
6、脚本。
由于紫金桥实时数据库6.5版软件里,窗口周期执行脚本的周期不能大于15分钟,所以为了实现需要的功能,定义以下整型窗口变量:w_cID、w_t1、w_t2、w_t3、w_t4、w_TBegin,具体使用在后面的脚本中说明。
进入窗口:
进入窗口后,执行下面脚本,前三行是给w_t1、w_t2、w_t3赋值为次日零点的时间;第五行w_TBegin赋值为当日零点的时间,是报警统计组件执行统计的起始时间;第六行连接数据存储所使用的数据库,由于连接字符涉及到客户信息,所以这里去掉了,读者可以自己查看帮助中关于紫金桥软件内置SQL函数的用法,里面有关于连接数据库的详细说明。w_t4赋值为次日上午8:30分的时间,设备状态数据存储脚本使用,与合格率数据存储无关。w
_t1 = LongTime(StrLeft(StrTime($Curtime,0),10) + " 00:00:00") + 86400;
w_t2 = w_t1;
w_t3 = w_t1;
w_t4 = LongTime(StrLeft(StrTime($Curtime,0),10) + " 08:30:00") + 86400;
w_TBegin = LongTime(StrLeft(StrTime($Curtime,0),10) + " 00:00:00");
SQLConnect(w_cID,"此部分是数据库服务器连接字符串,不便公开");
周期执行:
首先,每天凌晨前5分钟,从关系数据库读取关键参数的报警限值到报表Fr1中。由于报警限值由工艺人员维护,可能根据工艺需要有修改,所以每天计算合格率之前要重新读取。脚本如下:
if $Curtime >= w_t1-300 && $Curtime < w_t1-240 then
w_t1 = $Curtime + 86400;
#Fr1.SqlSelectCmd("select 位号,指标级别,下限,上限 from TM_装置关键控制参数");
Delay(1500);
for i = 1 to #Fr1.RowCount()+1
#本地.SetDataStr(#Fr1.Txt(1,i)+".EU",#Fr1.Txt(2,i));
#本地.SetDataReal(#Fr1.Txt(1,i)+".EULO",#Fr1.Val(3,i));
#本地.SetDataReal(#Fr1.Txt(1,i)+".EUHI",#Fr1.Val(4,i));
#next
#本地.RegUpdate();
endif
脚本第1行是判断本段脚本执行的时间,当系统时间处于零点前5分钟至前4分钟这段时间内,开始执行脚本;
第2行是将变量w_t1的值增加一天的时间,以便下次执行的时间是在下一天的同一时间;
第3行是报表Fr1从关系数据库的表中读取报警限值;
第4行是延迟时间,以便报表Fr1能够完全读取表中的数据;
第5~9行循环,将报表Fr1中的报警限值以及权重设置到对应的位号,第6行是设置权重,第7行是设置报警下限,第8行是设置报警上限;
第10行,刷新第6、7、8行操作以后的点的信息。
读取报警限值后,接下来就是根据报警限值计算位号的合格率了。下面这段脚本是判断系统时间在零点前4分钟至3分钟之间,开始执行,同样把变量w_t2的值增加一天,即与w_t1相同,然后开始报警组件进行报警时间的统计,统计的时间是一天,即86400秒。
if $Curtime >= w_t2-240 && $Curtime < w_t2-180 then
#w_t2 = w_t1;
#Alarm1.Start(w_TBegin,86400,1);
endif
在报警统计组件完成统计后,接下来就需要将统计的数据提取出来,然后计算,再把计算结果存入数据库的表中了。
if $Curtime > w_t3-60 && $Curtime <= w_t3 then
w_t3 = w_t1;
for i = 0 to #Alarm1.GetTagCount()
Bind_TagValue = 1 - (#Alarm1.GetCellHi(0,i) + #Alarm1.GetCellLow(0,i))/86400;
Bind_TagName = #Alarm1.GetTag(i) + ".PV";
Bind_StrTime = StrTime($Curtime,1);
for j = 0 to #Fr1.RowCount()
if #Alarm1.GetTag(i) == #Fr1.Txt(1,j+1) then
Bind_TagLevel = #Fr1.Txt(2,j+1)
endif
next
SQLInsert(w_cID,"XHQ_HGL","XHQ_BindHGL");
next
endif
这部分脚本就是向数据库表内写入数据了。
第1行仍然是判断时间,当时间达到零点前一分钟时,开始执行脚本,首先还是将时间变量w_t3增加一天,与w_t1相同;
第3~13行循环,将报警组件中所有位号的值逐个进行计算,然后存入数据库的表中。
第4行是把报警组件第i列的位号报警上限时间和报警下限时间求和,然后除以一天的时间,得到不合格率,再用1减去不合格率得到合格率的数值,赋给绑定表使用的变量;
第5行是把报警组件第i列的位号赋给绑定表变量;
第6行是把当前时间赋给绑定表变量;
第7~11行,是在报表Fr1中查找当前第i列位号的权重,然后赋给绑定表变量;
第12行,4个绑定表变量都已经赋值,此行使用紫金桥软件的SQL函数,将绑定表变量的值插入到关系数据库表中。
至此,完成报警组件第i列的一个循环,直至报警组件中所有位号的合格率统计值都插入数据表后,循环完成。
退出窗口:
这里只有一行脚本,就是当退出窗口时,断开与关系数据库的连接。
SQLDisconnect(w_cID);
整个脚本的关键,就是周期执行部分,这里使用了一个小技巧,由于紫金桥实时数据库6.5版,周期执行脚本的周期不能大于15分钟,所以这里使用一个整型变量,通过该变量的值与系统当前时间比较,只有符合条件才能执行脚本,否则不执行,这就保证了脚本只在每天指定的零点附近执行。
另外,为了保证每一部分的脚本能够完全执行完毕,并且不在时间上有交叉冲突,所以设置3个不同的时间变量,并且在不交叉的时间执行。而且通过这样的方法,不会影响其他需要频繁执行的周期脚本正常运行。
总结:
本例中使用了报表关系数据源点与自由报表相结合,读取关系数据库表中的数据,这样的好处是操作简单,不需要写过多脚本,但是无法向数据库表中写入数据。
又使用了紫金桥实时数据库软件预定义的SQL函数,向关系数据库中写入数据。SQL函数的优点是功能全面,几乎能够完成对关系数据库表的所有操作,包括查询、插入、删除、建表、删表等等;缺点就是操作相对自由报表和报表关系数据源点的结合要繁琐一些,需要建立表模版、绑定表,还要手动写一些脚本等。