C#实现OPC 历史数据存取研究
Research of Accessing the OPC Historical Data by Using C#
文孟飞[1],何海江[2],阳春华[3]
WEN meng-fei[1], HE hai-jiang[2], YANG chun-hua[3]
(1、长沙广播电视大学;2、长沙大学计算机中心;3、中南大学信息科学与工程学院)
摘要:在OPC.NET COM 包装器和OPC.NET API 的基础上,用C#实现一个实例,从OPC历史数据服务器抽取数据,对数据聚合运算。结果表明,该技术能应用于工业过程数据仓库,综合分析自动化系统所产生的历史数据,取得了满意的效果。
关键词:OPC 历史数据;工业过程;.NET
中图分类号:TP312 文献标识码:A
Abstract: One application coded by C# on the basis of OPC.NET COM Wrapper and OPC.NET
API is realized,it can be used to extract and aggregate data from the OPC historical data server.
The results show its good performance when used in the industrial process data warehouse toanalyze synthetically the historical data produced by the automation system.
Key Words: OPC historical data; industrial process;.NET
1 前言
目前工业界面临激烈的全球竞争,企业为了生存,需要各种分析和决策去占领和控制市场。为提高竞争力,许多企业使用DCS、SCADA、PLC 等自动化设备和软件,来实现生产过程自动化[1]。现在大多数这一类工业企业都保存了大量的过程数据,但由于这些自动化系统属于不同的厂商,数据往往分散在异构的计算机或控制系统上,各个自动化系统所拥有的历史数据都只能为本身使用,不能统一的存储、调用和管理,造成数据资源的极大浪费,许多问题因无法得到足够的数据进行综合分析而难以得到合理快捷的解决。本文遵循OPC 历史数据规范,开发了一个历史数据抽取的程序,为工业过程历史数据分析软件提供基础,文章分五个部分介绍实现过程。
2 OPC 历史数据规范
OPC 历史数据服务器实现两个逻辑意义上的对象,每个对象包含一个或多个接口。IOPCHDA_Server、IOPCHDA_SyncRead 和IOPCHDA_Browser(后文简称HDA 项)是这两个逻辑对象包含的重要接口。历史数据客户端软件根据功能要求,获取对应的接口,再调用接口,从服务器获得所需要的数据。
3 服务器的枚举和连接
OPC基金会[2]对会员提供了OpcRcw动态链接库、OPC NET COM 包装器和OPC NETAPI 1.1版本,前两者完成了COM编排过程中遇到的包括数据类型转换、接口实现、参数传递等复杂的技术工作,后者将OPC复杂的规范封装成简单易用的C#类。本文在此两种技术的基础上,建立客户端软件,与OPC历史数据服务器交换数据。遵照Visual Studio.NET的要求,引用组OpcNetApi.dll和OpcNetCom.dll,在程序中使用using,加入这些命名空间[3]。
下面的代码用来浏览某台计算机上已安装的历史数据服务器。
Opc.IDiscovery m_discovery = new OpcCom.ServerEnumerator();
Opc.Server[] servers = m_discovery.GetAvailableServers(Specification.COM_HDA_10, host,
null);// COM_HDA_10历史数据1.0版本,host为计算机名,null表示不需要任何网络安全认证。
servers即为需要连接的OPC历史数据服务器的集合。找到服务器xpServer后,可建立与该服务
器的连接。
Opc.Hda.Server xpServer=null;//定义历史数据服务器
…//将从前文游览到的某一个OPC历史数据服务器赋给xpServer。
Try{
本课题得到国家自然科学基金(60574030)资助。
…//将从前文浏览到的某一个OPC历史数据服务器赋给xpServer。
try{
xpServer.Connect();//建立连接。
…
}
catch (Exception f){//捕获错误,提高软件的健壮性,后文的代码都省略这一段。
…//错误处理
}
4 地址空间
地址空间由服务器的IOPCHDA_Browser接口提供,客户端由此可查找到服务器中哪些项拥有历史数据。与数据存取规范相同,OPC历史数据服务器提供两种方式的地址空间:平直型(Flat)、层次型(Hierarchical)。要在.NET中激活COM对象,需要通过RCW(运行库可调用包装)在托管的.NET代码和未托管的COM代码之间生成一个代理[4],手工编排COM中的接口定义语言。IOPCHDA_Browser接口的编排方法如下。
[Guid("1F1217B1-DEE0-11d2-A5E5-000086339399)"],//接口IOPCHDA_Browser的GUID
InterfaceType( ComInterfaceType.InterfaceIsIUnknown )]
internal interface IOPCHDA_Browser{
void GetEnum([in]int dwBrowseType, [out]Intptr ppIEnumString );
void ChangeBrowsePosition([in]int dwBrowseDirection,
[in, MarshalAs(UnmanagedType.LPWStr)]string szString );
void GetItemID ([in, MarshalAs(UnmanagedType.LPWStr)]string szNode,
[out]Intptr pszItemID);
void GetBranchPosition ( [out]Intptr pszBranchPos );
}
用IOPCHDA_Browser中的方法递归调用,可搜索地址空间。
5 HDA 项的历史数据
OPC NET 组件使用两种方法读HDA 项的数据,一是通过Trend,一是直接操作HDA 项。
先介绍Trend 方法,Trend 是HDA 项的集合,相当于数据存取规范中的组Group。客户端创建
Trend 后,再将HDA 项加入其中,对Trend 进行ReadRaw(读原始数据)、ReadProcessed(读聚合数据)等操作,则Trend 内所有HDA 项的相应操作完成。如下方法可创建一个Trend。
Trend trend = new Trend(m_server); //在服务器m_server中创建Trend。
trend.Name = "分配台"; //Trend名不进行聚合运算,修改此值后,可对其实行各种聚合运算。
trend.AggregateID = AggregateID.NOAGGREGATE;
trend.StartTime = new Time(new DateTime(2002,10,12,15,43,08,0));//起始时间
trend.EndTime = new Time(new DateTime(2002,11,12,15,44,28,0)); //终止时间
trend.MaxValues = 0;//一次最多读值个数,0表示读时间段内所有数据。
trend.IncludeBounds = false;//不包括边界。
m_server.Trends.Add(trend); //将trend添加到服务器m_server中。
在名为“分配台”的Trend中增加三个HDA项。
Item[] items = new Item[3]; //Item为HDA项的类,创建一个数组。
for( int i=0;i<3;i++ ) {
items[i] = new Item();
items[i].ItemName = m_strItemName[i]; //m_strItemName在地址空间内找到的HDA项名。
items[i].ItemPath = null;//该HDA项没有路径。
items[i].ClientHandle = Guid.NewGuid().ToString(); //生成客户端句柄。
}
IdentifiedResult[] results= m_server.CreateItems(items);//在m_server创建HDA项。
if (results != null){ //创建成功
foreach (IdentifiedResult item in results){
if (item.ResultID.Succeeded()){
trend.Items.Add(new Item(item)); //***将HDA项加入到trend中。
} } }
完成前述工作后,一条语句m_results = trend.ReadRaw()即可完成读操作,并将结果存放
在类型为ItemValueCollection[]的数组m_results中。下面的代码在视图中显示第一个HDA项
的结果。
ItemValueCollection i_r_s = m_results[0];
foreach (ItemValue iValue in i_r_s) {
string strTime = Opc.Convert.ToString(iValue.Timestamp);//时间戳
string strValue = Opc.Convert.ToString(iValue.Value); //值
string strQuality = Opc.Convert.ToString(iValue.Quality); //原始的数据品质
//将枚举型的历史数据品质转换为字符串。
string strHdaQuality = Opc.Convert.ToString(iValue.HistorianQuality);
……
}
第二种方法直接操作HDA项则不涉及到Trend的操作。先在历史数据服务器中创建HDA项,成功后再将这些HDA项放到一个Item数组中。具体代码除两个变化外与Trend操作第二段相同,增加两个变量Item[] m_readItems =null; j=0;将用*标记的一句替换为m_readItems[j++] =new Item(item);读操作变为:
Opc.Hda.Time start = new Time(new DateTime(2002,10,12,15,43,08,0)); //起始时间
Opc.Hda.Time end = new Time(new DateTime(2002,10,12,15,44,28,0)); //终止时间
m_results = m_server.ReadRaw(start,end,0,false,m_readItems); //读所有数据,不包括边
界值历史数据服务器在2002年10月12日15时43分0秒到15时45分0秒之间有43:03、43:08、
43:13、43:18、43:23…44:23、44:28…44:58这些时间的历史数据。前文代码中的MaxValues
和IncludeBounds为0和true时,则返回的数据包括43:08、43:13…44:23、44:28;IncludeBounds
为false时,左边界值43:08返回,右边界值44:28则没有;MaxValues和IncludeBounds为3和true时,则返回的数据只有三个43:08、43:13、43:18。
6 平均值和记数
同样,组件使用Trend和直接操作两种方法读HDA项的聚合值,包括求平均值、总和、方差、插值等,文章以求平均值和记数为例。Trend方法和前文相同,创建Trend后,再将HDA项加入其中,对Trend进行聚合运算。下面的代码直接操作HDA项,不用到Trend,求平均值。
Opc.Hda.Time start = new Time(new DateTime(2002,10,27,15,43,08,0)); //起始时间
Opc.Hda.Time end = new Time(new DateTime(2002,10,27,15,43,27,0)); //终止时间
foreach(Item item in m_readItems)
item.AggregateID = AggregateID.AVERAGE;//求平均值,COUNT为记数。
m_results = m_server.ReadProcessed(start,end,5,m_readItems);//时间间隔为5秒。
返回的结果m_results 使用前述方法显示。历史数据服务器的某一HDA 项在2002 年10 月27 日15 时43 分08 秒到15 时43 分27 秒之间有表一所示的数据,表中及后文省略时间戳中的日期。
求平均值的聚合运算将原始数据品质为good 的数据求和,再除以数据个数,返回结果的时间戳为每一个时间段的起始。前述的执行结果返回四个值,15:43:08 到15:43:12 这5 秒钟(时间间隔)内有两个值,15:43:11 的值不参与计算,因为其原始数据品质为bad,则平均值为4.8,时间戳为15:43:08;15:43:13 到15:43:17 这5 秒钟内有三个值,平均值=(4.9+4.5+4.7)/3=4.7;15:43:18 到15:43:22 这5 秒钟内有两个值,平均值=(4.5+4.7)/2=4.6;15:43:23 到15:43:27 内没有数据。最终显示表二所示的结果:
记数是统计时间段内原始数据品质为good 的数据个数,将代码中的AggregateID.AVERAGE 改为AggregateID. COUNT 时,则表二变成表三。
7 结束语
实例在Windows XP 专业版,.NET 框架1.1,Visual Studio.NET 2003 下调试通过,在实际应用中运行良好。工业过程的数据抽取是一个十分复杂的过程,遇到不提供OPC 历史数据服务器的自动化系统,则要求厂商提供文件或数据库表的格式,即算得到格式,工作量比文章介绍的方法大得多。本文作者创新点是实现了在.net 环境下使用OPC 规范获取历史数据,为工业过程历史数据分析软件提供基础。
参考文献
[1] 日本横河公司电子文档.1B30_09.pdf
[2] OPC Foundation·OPC Historical Data Access Specification V1.20 [EB]·2003.12
[3] 何海江.C#程序与基于COM 的OPC 数据存取服务器交换数据研究[J].微计算机信息,2004,20(10):112-113
[4] Microsoft·MSDN 2003
作者简介:文孟飞,男,1975 年生,硕士,讲师,主要研究方向为计算机应用技术、智能系统、自动
控制.E-mail:wmfdcf@126.com..何海江,男,1970 年生,硕士,副教授,主要研究方向为数据仓库、
组件技术.阳春华,女,1965 年生,博士,教授,博士生导师,主要研究领域为复杂过程建模与优化
控制、智能自动控制系统与装置以及实时系统容错调度技术。
Author Brief introduction :Wen, Meng-fei (1975-), male, M.A. in computer applied technology,docent. taking on research on computer applied technology, intelligence-system,e-mail:wmfdcf@126.com. He, Hai-jiang (1970-), male, adjunct professor, taking on research on data-godown, joint-technology.Yang, Chun-hua (1965-), female, PHD tutor, taking on research onmodeling and optimized controlling of complicated process, intelligent autocontrol system andinstallation, and real-time attemper technology of systematic fault tolerance.
(1、长沙广播电视大学 长沙 410005;2、长沙大学计算机中心 长沙 410003; 3、中南大学信息科学与工程学院 长沙 410083)文孟飞[1],何海江[2],阳春华[3]
(1、Shangsha Radio & TV Unversity, Changsha, 410005; 2、Computer Teaching Center, ChangshaUniversity, Changsha, 410003; 3、College of Information Science and Engineering, Central South University, Changsha, 410083) WEN meng-fei[1], HE hai-jiang[2], YANG chun-hua[3]