目录
1 基本概念
1.1 历史数据服务器类型
1.2 数据源
1.3 对象和接口概述
1.4 所需接口定义
1.5 可选接口定义
1.6 定义
1.7 边界值和时域
2 HDA聚合
2.1 生成间隔
2.2 数据类型
2.3 数据质量
3 聚合示例
3.1 示例数据
3.2 内插(INTERPOLATIVE)
3.3 时间加权平均(TIMEAVERAGE)
3.4 平均值(AVERAGE)
3.5 计数(COUNT)
3.6 实际时间最小值(MINIMUM ACTUAL TIME)
3.7 最小值(MINIMUM)
3.8 实际时间最大值(MAXIMUM ACTUAL TIME)
3.9 最大值(MAXIMUM)
3.10 首值(START)
3.11 末值(END)
3.12 持续良好时间(DURATION GOOD)
3.13 持续坏值时间(DURATION BAD)
1 基本概念
目前,大多数历史数据系统都使用自己的专有接口对外提供数据服务,不能与任何其他系统互操作。OPC HDA规范旨在提供历史数据访问的标准接口,促进用C和C++开发用于历史数据访问的OPC服务器/客户端应用程序。规范中描述的接口的体系结构和设计旨在支持其他语言的OPC服务器的开发。
OPC HDA规范与其他OPC规范之间存在松散的绑定。此OPC规范不是从另一个OPC规范派生而来,也不是从其继承接口。
OPC HDA规范的接口提供时间序列历史数据。如果需要实时数据,则应使用OPC DA接口。
OPC HDA规范描述了OPC COM对象及其由OPC历史服务器实现的接口。OPC客户端可以连接到一个或多个供应商提供的OPC历史服务器。供应商也可以提供其他OPC服务器。下图说明了可能的OPC供应商服务器配置:
任何供应商,甚至是不提供服务器的供应商,都可以提供客户端。客户端应该能够与任何服务器一起工作。如果需要另一个OPC服务器(如数据访问服务器)才能实现全部功能,则客户端仍应能够在没有其他OPC服务器的情况下对历史数据进行操作。
1.1 历史数据服务器类型
1)简单的趋势数据服务器。这些服务器只提供简单的原始数据存储。(数据通常是可从OPC数据访问服务器获得的数据类型,通常以元组[时间、数值、质量]的形式提供)。
2)复杂的数据压缩和分析服务器。这些服务器提供数据压缩以及原始数据存储。它们能够提供汇总数据或数据分析功能,如平均值、最小值和最大值等。它们可以支持数据更新和更新历史。它们可以支持注释的存储以及实际的历史数据存储。
这些不同的服务器都包含在OPC HDA规范的可选接口中。如果服务器不支持一组功能,则不需要实现该功能组的可选接口。
1.2 数据源
OPC历史数据服务器提供了一种访问一组历史数据源的方式。可用的源类型是服务器实现的一个函数。
服务器可以实现为独立的OPC历史数据服务器,从OPC数据访问服务器或另一数据源收集数据。它也可能是一组分层在现有专有历史数据服务器之上的接口。引用OPC历史数据服务器的客户端可能是简单的趋势包,只需要给定时间范围内的值,也可能是需要多种格式数据的复杂报告。
1.3 对象和接口概述
OPC历史数据服务器对象提供从历史服务器读取数据和向历史服务器写入数据的能力。所有COM对象都是通过接口访问的。客户端只能看到接口。下图概述了OPC对象及其接口。请注意,有些接口是可选的(如[]所示)。
下图为Historian Server模型。
浏览器接口为客户端提供了一种查看历史记录的地址空间的方法。预期该地址空间对于一些服务器可能是分层的,而对于其他服务器可能是平面的。此接口旨在支持分层视图,其中平面地址空间表示为单层分层视图。浏览器接口在大多数大型历史数据服务器中是必不可少的,它允许客户端以简单的图形方式查看地址空间。
OPC Historian Client应用程序必须实现回调接口以支持关闭请求。客户端还可以实现用于服务器可以提供的各种异步连接的接口。如果客户端希望使用(而服务器提供)特定的异步接口,则客户端必须实现匹配的回调。
下图为Historian Client模型。
关闭请求是允许OPC历史数据服务器干净关闭所必需的。当HDA服务器访问时,客户端应释放服务器提供的内存(请参阅自定义接口内存部分)并终止所有连接。
1.4 所需接口定义
OPC HDA服务器开发人员必须实现所需接口的所有方法,并且必须实现所述方法的所有功能。OPC历史客户端通过调用OPC所需接口的功能与OPC历史数据服务器通信。对于所需接口上的可选方法,OPC历史数据服务器可能会返回E_NOTIMPL。
1.5 可选接口定义
OPC HDA服务器开发人员可以实现可选接口的功能。当OPC HDA服务器支持可选接口时,必须实现该可选接口中的所有功能,即使该功能仅返回E_NOTIMPL。希望使用可选接口功能的OPC历史客户端将向OPC HDA服务器查询可选接口。客户端必须设计为不要求存在此可选接口。
1.6 定义
OPC HDA规范中使用的以下术语和概念通常在 historian中使用,但可以由不同的供应商定义,以具有略微不同的定义。以下列出了本规范中使用的定义。
1)Attribute(属性): 特定项目可能与其关联的附加限定符。例如,“项目值”属性可能具有与其关联的以下属性:“数据类型”(VT_R4)、“阶梯式”(0)和“存档”(1)。,即“项目值”返回一个4字节的实数,该值可以显示为插值(斜线),并且数据正在存档。
2)Aggregate(绑定值): 汇总数据值的方法。常见的聚合包括均匀时间范围内的平均值、时间范围内最小值和时间范围内最大值。这些聚合是在检索数据的过程中执行的。
3)Annotations (总计): 操作员或用户输入的与项目相关联的注释,通常在给定的时间点。此时不必存储值。
4)Bounding Values(绑定值): 客户端在请求某个时间范围内的原始数据时需要绑定值来确定入口点和出口点。如果原始数据值存在于入口或出口点,则即使它是数据请求的一部分,也会将其视为边界值。如果入口点或出口点不存在原始数据值,则范围之外的下一个数据点被视为边界值。
5)Interpolated Data(插值数据): 从存档中的数据派生而来,但没有存储值的数据。这可以从所请求的时间戳两侧的两个存储的数据点线性导出,也可以通过更复杂的方法从档案中的数据外推。
6)Item Handles: ItemHandle可以是客户端值或服务器值。所有者使用它来加快对项目的访问。其数据类型为OPCHandle(DWORD)。
如果客户端打算使用OPC HDA接口的任何异步功能,则预期客户端将为客户端句柄分配一个唯一值。但是,服务器不应该对客户端句柄做出任何假设,客户端也不应该对服务器句柄做出任何假定。项句柄的唯一性取决于实现。
7)Item ID: 字符串,它是对服务器地址空间中数据项的唯一引用。
8)Modified values(修改的值): 存储在历史记录中后更改的值。实验室数据输入值不是修改后的值,但如果用户更正了实验室值,则原始值将被视为修改值,并将在请求修改值时返回。假设所有接口上的所有方法都基于指定时间戳处指定项的当前值或最新值。对修改值的请求用于访问已被取代的值。
9)Properties(属性): 在Automation接口中,属性是指示其操作方式的历史服务器的属性。
10)Raw Data(原始数据): 存储在历史记录中的数据。数据可以被压缩,也可以是为项目收集的所有数据,这取决于保存项目值时调用的历史记录和存储规则。
11)Start Time / End Time(开始时间/结束时间): 限制历史请求的时间,用于定义请求的时域。对于所有请求,位于时域末尾的值不包括在域中,因此,为连续的、连续的时域发出的请求将只包括存档中的每个值一次。
12)Time Domain(时域): 特定请求或特定响应所覆盖的时间间隔。通常,如果开始时间早于结束时间,则时域被认为从开始时间开始,并在结束时间之前结束;如果结束时间早于开始时间,则时域仍然从开始时间开始,并在结束时间之前结束,对于特定的请求和响应,时间“向后运行”。在这两种情况下,任何正好落在时域结束时间的值都不包括在域中。
请注意,FILETIME中可以合法表示的所有时间戳都是有效的时间戳,并且服务器可能不会返回E_INVALIDARG,因为时间戳超出了服务器拥有数据的范围。服务器应该能够优雅地处理越界的时间戳,并向客户端返回正确的错误代码和值,例如OPC_S_NODATA或OPCHDA_NOBOUND。
1.7 边界值和时域
时域包括开始时间和结束时间之间的所有值,以及正好落在开始时间上的任何值,但不包括正好落在结束时间上的任意值。因此,对于不请求边界值的情况,如果从1:00到1:05,然后从1:05到1:10请求数据,则正好在1:05存在的值将被包括在第二请求中,但不包括在第一请求中。
假设历史记录的值存储在5:00、5:02、5:03、5:05和5:06,从RAW数据调用返回的数据由下表给出。在表中,FIRST代表一个值为VT_EMPTY、指定StartTime的时间戳和质量为OPCHDA_NOBOUND的元组。LAST代表一个值为VT_EMPTY、指定EndTime的时间戳和质量为OPCHDA_NOBOUND的元组。
2 HDA聚合
以下说明HDA聚合的要求和性能。其目的是使HDA聚合标准化,以便HDA客户端能够可靠地预测聚合计算的结果并理解其含义。如果用户需要聚合中的自定义功能,则应将这些聚合编写为自定义聚合。
标准聚合必须尽可能一致,这意味着每个聚合的行为必须与输入参数、原始数据和边界条件相似的其他聚合的行为相似。在可能的情况下,总量应以类似的方式处理投入和先决条件。本节分为两个部分。第一小节涉及所有聚合共同的聚合特性和行为。其余小节涉及特定于聚合的聚合的特性和行为。
本篇介绍通用特征。
2.1 生成间隔
要读取聚合,OPC客户端必须指定三个时间参数:
- start time (开始)
- end time (结束)
-重新采样间隔 resample interval (Int)
OPC服务器必须使用这三个参数生成一系列时间间隔,然后计算每个时间间隔的聚合值。本节指定了在给定三个参数的情况下生成的时间间隔。在表中,我们将Range定义为|结束-开始|。
2.2 数据类型
以下所有聚合仅适用于数字数据类型,即整数或实数/浮点数。不支持日期、字符串、数组等。
然而,在某些情况下,OPC服务器可能具有非数字类型的项目类型(即“VT_BSTR”),但该项目实际上代表一个数字值。因此,每个聚合都必须尝试使用VariantChangeType将项值转换为数字类型。必须对原始历史记录列表中的每个项目执行此操作。
如果某个区间中的任何项目未能转换,则不应在聚合计算中使用该项目,并且聚合的质量应不确定/低于标准。如果未能在一个时间间隔内转换所有项,则聚合占位符应返回坏质量OPCHDA_CONVERSION。
2.3 数据质量
所有聚合都应在计算中省略错误的数据值。如果忽略任何值,则聚合质量应不确定/低于标准。
在某些情况下,会存在不确定的值(即既不好也不坏)。是否从聚合调用中省略这些值将取决于服务器。服务器文档必须清楚地说明服务器将如何处理不确定的值。如果在合计计算中使用了不确定值,则这些区间的质量应为不确定/低于标准。
3 聚合示例
3.1 示例数据
1)聚合数据例子——Historian 1
2)聚合数据例子——Historian 2
Historian 1
1)不确定的值包含在聚合调用中。
2)数据点之间使用线性插值。
3)在末端边界条件下使用阶跃外推法
Historian 2
1)不确定的值被视为质量差,并且不包括在聚合调用中。
2)数据点之间使用线性插值。
3)在末端边界条件下使用阶跃外推法
3.2 内插(INTERPOLATIVE)
为了使插值聚合返回有意义的数据,在边界条件下必须有好的值。出于讨论的目的,我们将使用“好”和“不好”这两个术语。正如在“质量”部分中所讨论的,“不好”表示的是依赖于服务器的。对于一些服务器来说,不好只代表坏数据,而对于其他服务器来说,它代表坏的和不确定的数据。
当在边界条件下遇到不好的值时,必须遵守以下规则:
如果请求时间的值不好,则聚合会在请求时间的两侧寻找好的数据,以便执行直线插值。
如果没有终点(即未来时间),则该值应根据之前的良好值在时间上向前外推。在这种情况下,质量将低于正常水平。
总量不应在时间上向后推断。如果没有起始绑定,则应返回OPCHDANO_DATA。拖尾值不应及时向前拉。
插值方法,阶梯式(即保持最后值)或线性直线插值,将取决于服务器。服务器文档必须清楚地说明所使用的方法。
如果为了找到最接近的良好值而跳过任何非良好值,则聚合将是不确定的/低于正常值
所有间隔聚合返回间隔开始的时间戳。除非另有说明,否则质量是好的,具有内插性。
案例1:正在请求具有良好边界值的数据。
Start: Jan-01-2002 12:00:10 End: Jan-01-2002 12:00:20 Interval: 00:00:05
案例2:请求具有良好边界值的数据,但间隔中的数据不正确
Start: Jan-01-2002 12:00:35 End: Jan-01-2002 12:01:00 Interval: 00:00:05
案例3:正在请求没有良好结束边界值的数据。
Start: Jan-01-2002 12:01:20 End: Jan-01-2002 12:01:40 Interval: 00:00:05
案例4:请求没有良好起始边界值的数据。
Start: Jan-01-2002 12:00:00 End: Jan-01-2002 12:00:20 Interval: 00:00:05
3.3 时间加权平均(TIMEAVERAGE)
时间加权平均聚合使用如上面插值部分所述的插值来找到区间开始和结束处的点的值。在间隔中的每个原始值之间绘制一条直线。线下的面积除以区间的长度得到平均值。
示例:
输入:
Start: Jan-01-2002 12:00:10
End: Jan-01-2002 12:00:15
Interval: 00:00:05
结果:
点1=12:00:10时为10的良好原始值
点2=12:00:15时的插值15,使用12:00:10和12:00:20时的边界值。
线下面积为62.5(1/2b*h+b*h)。间隔为5秒
时间平均值=面积/间隔=12.5
如果区间的任何原始值都不好,则会忽略它们,并且聚合
该区间的质量是不确定的/低于标准的。
所有间隔聚合返回间隔开始的时间戳。
案例1:请求具有良好边界值的数据
Start: Jan-01-2002 12:00:10 End: Jan-01-2002 12:00:20 Interval: 00:00:05
案例2:正在请求具有良好边界值的数据,但间隔中的数据不正确。
Start: Jan-01-2002 12:00:35 End: Jan-01-2002 12:01:00 Interval: 00:00:05
案例3:正在请求没有良好结束边界值的数据。
Start: Jan-01-2002 12:01:20 End: Jan-01-2002 12:01:40 Interval: 00:00:05
在边界处使用阶跃外推法。服务器可以选择根据先前的斜率推断数据。
案例4:请求没有良好起始边界值的数据。
Start: Jan-01-2002 12:00:00 End: Jan-01-2002 12:00:20 Interval: 00:00:05
3.4 平均值(AVERAGE)
平均聚合将给定间隔内所有良好原始数据的值相加,然后将总和除以良好值的数量。如果在计算中忽略任何不好的值,则聚合质量将是不确定的/低于标准的。
如果某个间隔不存在好的数据,则该间隔的聚合质量将很差,即OPCHDA_NODATA。
所有间隔聚合返回间隔开始的时间戳。
案例1:正在请求具有良好边界值的数据。
Start: Jan-01-2002 12:00:10 End: Jan-01-2002 12:00:20 Interval: 00:00:05
案例2:正在请求具有良好边界值的数据,但间隔中的数据不正确。
Start: Jan-01-2002 12:00:35 End: Jan-01-2002 12:01:00 Interval: 00:00:05
案例3:正在请求没有良好结束边界值的数据。
Start: Jan-01-2002 12:01:20 End: Jan-01-2002 12:01:40 Interval: 00:00:05
案例4:请求没有良好起始边界值的数据。
Start: Jan-01-2002 12:00:00 End: Jan-01-2002 12:00:20 Interval: 00:00:05
3.5 计数(COUNT)
此聚合检索一个间隔内所有原始值的计数。如果一个或多个原始值不合格,则它们不包括在计数中,并且聚合质量不确定/低于标准。如果在一个时间间隔内不存在好的数据,则计数为零。
所有间隔聚合返回间隔开始的时间戳。
案例1:正在请求具有良好边界值的数据。
Start: Jan-01-2002 12:00:10 End: Jan-01-2002 12:00:20 Interval: 00:00:05
案例2:正在请求间隔中数据不确定的数据。
Start: Jan-01-2002 12:00:50 End: Jan-01-2002 12:01:30 Interval: 00:00:00
*一些服务器可能会选择将不确定的数据视为坏数据,因此结果为3。
3.6 实际时间最小值(MINIMUM ACTUAL TIME)
实际时间最小值聚合检索间隔[s,e)内的最小良好原始值,并返回该值以及该值出现的时间戳。请注意,如果相同的最小值存在于多个时间戳中,则检索最旧的时间戳中。如果非良好值低于良好最小值,则聚合的质量将不确定/低于正常值。
除非另有说明,否则质量良好,原始。如果间隔中没有值,则不会返回带有间隔开始时间戳的数据。
案例1: 正在请求具有良好边界值的数据。
Start: Jan-01-2002 12:00:10 End: Jan-01-2002 12:00:20 Interval: 00:00:05
案例2:请求具有良好边界值的数据,但间隔中的数据不正确
案例3: 正在请求没有良好结束边界值的数据。
案例4: 请求没有良好起始边界值的数据。
Start: Jan-01-2002 12:00:00 End: Jan-01-2002 12:00:20 Interval: 00:00:05
案例5: 部分间隔
3.7 最小值(MINIMUM)
最小值聚合与最小值实际时间(MINIMUM ACTUAL TIME)相同,只是聚合的时间戳始终是每个间隔的开始时间。
最小值聚合检索间隔[s,e)内的最小良好原始值,并返回该值以及对应间隔的开始时间戳。请注意,如果相同的最小值存在于多个时间戳中,则检索最旧的时间戳中。如果非良好值低于良好最小值,则聚合的质量将不确定/低于正常值。
除非另有说明,否则质量良好,原始。如果间隔中没有值,则不会返回带有间隔开始时间戳的数据。
案例1:请求具有良好边界值的数据。
案例2:请求具有良好边界值的数据,但间隔中的数据不正确。
案例3:请求没有好的结束边界值的数据。
Start: Jan-01-2002 12:01:20 End: Jan-01-2002 12:01:40 Interval: 00:00:05
案例4:请求没有良好起始边界值的数据。
案例5:部分间隔
3.8 实际时间最大值(MAXIMUM ACTUAL TIME)
最大值聚合检索间隔[s,e)内的最大良好原始值,并返回该值以及对应的开始时间戳。请注意,如果相同的最大值存在于多个时间戳中,则检索最旧的时间戳中。如果非良好值高于良好最大值,则聚合的质量将不确定/低于正常值。
除非另有说明,否则质量良好,原始。如果间隔中没有值,则不会返回带有间隔开始时间戳的数据。
案例1:正在请求具有良好边界值的数据。
案例2:正在请求没有良好结束边界值的数据。
案例3:请求没有良好起始边界值的数据。
案例4:部分间隔
3.9 最大值(MAXIMUM)
最大值聚合检索间隔[s,e)内的最大良好原始值,并返回该值以及对应间隔的开始时间戳。请注意,如果相同的最大值存在于多个时间戳中,则检索最旧的时间戳中。如果非良好值高于良好最大值,则聚合的质量将不确定/低于正常值。
除非另有说明,否则质量良好,原始。如果间隔中没有值,则不会返回带有间隔开始时间戳的数据。
案例1:正在请求具有良好边界值的数据。
案例2:正在请求具有良好边界值的数据,但间隔中的数据不正确。
案例3:正在请求没有良好结束边界值的数据。
案例4:请求没有良好起始边界值的数据。
案例5:部分间隔
3.10 首值(START)
首值聚合检索区间[s,e)内的第一个原始值,并返回该值以及该值出现的时间戳。如果该值不好,则聚合的质量将不确定/低于正常水平。
案例1:请求具有良好边界值的数据
案例2:正在请求具有良好边界值的数据,但间隔中的数据不正确。
案例3:部分间隔
3.11 末值(END)
末值聚合检索区间[s,e)内的最后一个原始值,并返回该值以及该值出现的时间戳。如果该值不好,则聚合的质量将不确定/低于正常水平。
案例1:请求具有良好边界值的数据。
案例2:正在请求具有良好边界值的数据,但间隔中的数据不正确。
案例3:部分间隔
3.12 持续良好时间(DURATION GOOD)
持续良好时间聚合查看区间的边界值的质量,以确定区间开始时的质量。如果不存在边界值,则假定在间隔开始时质量不好。此合计仅考虑真正的良好价值。不确定的数值不适合计算该合计值。
每当在一个区间内从头到尾遇到质量为q的原始值x时,质量被认为是q,直到遇到下一个值y,此时质量变为y,依此类推。
时间以秒为单位返回。任何返回值都不会是不确定的或低于标准的。每个间隔的聚合都会返回间隔开始的时间戳。素质很好,经过深思熟虑。
案例1:正在请求具有良好边界值的数据。
案例2:正在请求具有良好边界值的数据,但间隔中的数据不正确。
案例3:正在请求没有良好结束边界值的数据。
案例4:请求没有良好起始边界值的数据
案例5:请求没有良好起始边界值的数据
案例6:请求间隔中数据不确定的数据
*不确定的数据不应被视为良好数据
3.13 持续坏值时间(DURATION BAD)
持续时间坏聚合查看间隔的边界值的质量,以确定间隔开始时的质量。如果不存在边界值,则假定在间隔开始时质量不好。此合计仅考虑真正的坏值。不确定的数值在计算该合计时并不被认为是坏的。
每当在一个区间内从头到尾遇到质量为q的原始值x时,质量被认为是q,直到遇到下一个值y,此时质量变为y,依此类推。
时间以秒为单位返回。任何返回值都不会是不确定的或低于标准的。每个间隔的聚合都会返回间隔开始的时间戳。
持续时间坏不是简单的间隔减去持续时间好,因为间隔数据不确定。
案例1:请求具有良好边界值的数据
案例2:请求具有良好边界值的数据,但间隔中的数据不正确
案例3:请求间隔中数据不确定的数据