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


    来源: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 号长沙广播电视大学理工部)文孟飞 

  • 相关阅读:
    【iHMI43 液晶模块】【USB Mass storage 大容量存储设备 / 虚拟U盘代码包】
    [iBoard 电子学堂][第二卷 C程序设计语言 ]第二篇 数据类型与运算符
    【IAR EW STM8 1401】 破解方法
    [iBoard 电子学堂][第八卷 设计任意波发生器]第三篇 直接数字合成(DDS)原理
    发布《iCore》ARM + FPGA 双核心板
    [iBoard 电子学堂][第〇卷 电子基础 ]第三篇 单片微控制器、微处理器
    [iBoard 电子学堂][第二卷 C程序设计语言 ]第一篇 C语言简介
    【iCore双核心组合是开发板例程】【uCGUI 例程及代码包下载】
    发布《iBoard 电子学堂》基础例程之 8051 例程代码!
    【iBoard 电子学堂教程】【uCGUI 例程及代码包下载】
  • 原文地址:https://www.cnblogs.com/zouhao/p/6386712.html
Copyright © 2020-2023  润新知