C#实现 OPC历史数据存取研究

摘要:
本文遵循OPC历史数据规范,开发了历史数据提取程序,为工业过程历史数据分析软件提供了基础。本文分五个部分介绍了实施过程。2 OPC历史数据规范OPC历史数据服务器在逻辑意义上实现两个对象,每个对象包含一个或多个接口。服务器是需要连接的OPC历史数据服务器的集合//将您之前访问过的OPC历史数据库服务器分配给xpServer//错误处理}4地址空间地址空间由服务器的IOPCHDA控制_浏览器界面使客户端可以查找服务器中哪些项目具有历史数据。

来源:http://blog.csdn.net/gjack/article/details/5641794

 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 to 
analyze 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 NET 
API 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秒之间有表一所示的数据,表中及后文省略时间戳中的日期。 
表一  已有的历史数据(2004-1-29) 
时间戳  值 
原始数
据品质 
历史数
据品质 时间戳 值 原始数
据品质
历史数
据品质 
15:43:09 4.8 good Raw 15:43:174.7good Raw 
15:43:11 4.4 bad Raw 15:43:194.5good Raw 
15:43:13 4.9 good Raw 15:43:214.7good Raw 
15:43:15 4.5 good Raw     
15:43:23 起没有数据 
求平均值的聚合运算将原始数据品质为 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 
时间戳  值 
原始数据
品质 
历史数据
品质 
时间戳  值 原始数据
品质 
历史数据 
品质 
15:43:08 4.8 good Calculated15:43:081 good Calculated 
15:43:13 4.7 good Calculated15:43:163 good Calculated 
15:43:18 4.6 good Calculated15:43:242 good Calculated 
15:43:23  bad NoData 
 
15:43:320 good Calculated data-godown, joint-technology.Yang, Chun-hua (1965-), female, PHD tutor, taking on research on 
modeling and optimized controlling of complicated process, intelligent autocontrol system and 
installation, 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, Changsha 
University, 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]
 
通信地址: (410005   长沙市浏正街 126 号长沙广播电视大学理工部)文孟飞 

免责声明:文章转载自《C#实现 OPC历史数据存取研究》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇compose使用install和update安装package的区别图上的文章(割点和桥)下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

FFMPEG常用命令-格式转换-持续更新中

---恢复内容开始--- ffmpeg是一个强大的工具,在工作中各种格式转换,编码,提取视频中的帧需要用到,记录下工作中常用的一些ffmpeg命令,持续更新中... 将输入的infile视频文件通过avc编码成h264的视频流 ffmpeg -i infile.mp4 -an -vcodec libx264 -crf 23 outfile.h264 -i ...

TCP全连接队列和半连接队列已满之后的连接建立过程抓包分析[转]

最近项目需要做单机100万长连接与高并发的服务器,我们开发完服务器以后,通过自己搭的高速压测框架压测服务端的时候,发生了奇怪的现象,就是服务端莫名其妙的少接收了连接,造成了数据包的丢失,通过网上查资料,和自己的实践,下面是我做实验,抓包分析的过程如下: 总共5个连接 其中全连接队列somaxconn参数为1表示监听队列的总长度(实际可以完成somaxcon...

mysql 日期处理

mysql获取一个小时内的数据 (第一种方法)SELECT * FROM 表名 WHERE 字段名>NOW()-INTERVAL 2 HOUR; (第二种方法)SELECT * FROM 表名 WHERE 字段名 > DATE_SUB(NOW(), INTERVAL 60 MINUTE); 字符串型日期比对 select name,cdate ...

信息安全行业国家标准汇总,信息安全行业从业人员必看

1. GB/T 36618-2018 《信息安全技术 金融信息服务安全规范》 内容概述:该标准规定了金融信息服务提供商提供金融信息服务时的基本原则、服务过程要求、技术要求和管理要求。其中,技术要求部分主要涵盖基础设施安全、软件安全、网络安全、数据安全、运行安全、容灾和恢复六个方面。 2. GB/T 36619-2018 《信息安全技术 政务和公益机构域名命...

Elastic:在 Grok 中运用 custom pattern 来定义 pattern

我们先来看一下如下的一个日志: 157.97.192.70 2019 09 29 00:39:02.912 myserver Process 107673 Initializing 在上面的日志中,我们可以看到一个日期信息:2019 09 29 00:39:02.912。它是被空格字符串所分开,如果没有正确的 Grok pattern 来帮我们提取的话,我...

VIO系统的IMU与相机时间偏差标定

  视觉里程计(VIO)作为一种空间定位方法,广泛应用于VR/AR、无人驾驶和移动机器人,比如近年火热的苹果 AR-Kit和谷歌AR-Core都使用了VIO技术进行空间定位。通常,VIO系统忽略IMU与相机时间偏差,认为IMU和相机时间是同步和对齐的,然而由于硬件系统的触发延时、传输延时和没有准确同步时钟等问题,IMU和相机之间通常存在时间偏差,估计并纠正...