跳到主要内容

DataChangeFilter — 触发与死区过滤

概述

OPC UA Part 4 §7.17 DataChangeFilter 让客户端告诉服务端"什么时候才把数据 push 给我", 减少不必要的 Publish 流量:

  • Trigger — 触发条件 (Status / StatusValue / StatusValueTimestamp)
  • DeadbandType — 死区类型 (None / Absolute / Percent)
  • DeadbandValue — 死区数值

API

类 / 字段类别读写说明
DataChangeFilter过滤器配置 (init-only)
.Trigger属性读写DataChangeTrigger 枚举, 默认 StatusValue
.DeadbandType属性读写DeadbandType 枚举, 默认 None
.DeadbandValue属性读写double, 默认 0.0
sub.Add(nodeId, attr, samplingMs, mode, queueSize, discardOldest, filter)方法带 filter 的 MI 重载

相关结构:

public enum DataChangeTrigger
{
Status = 0, // 仅 StatusCode 变化时报告
StatusValue = 1, // StatusCode 或 Value 变化 (默认)
StatusValueTimestamp = 2 // StatusCode / Value / SourceTimestamp 任一变化
}

public enum DeadbandType
{
None = 0, // 无死区, 任何变化都报
Absolute = 1, // 绝对死区, |new - old| > DeadbandValue 才报
Percent = 2 // 百分比死区, |new - old| > EURange.Range × DeadbandValue / 100 才报
}

代码示例

using DarraOpcUa_Client;

using var ua = new DarraOpcUa("opc.tcp://localhost:4840");
ua.Connect();

using var sub = ua.CreateSubscription(publishingIntervalMs: 100);

// 1) 绝对死区 0.5 — 温度变化超过 0.5 度才上报
var filter1 = new DataChangeFilter
{
Trigger = DataChangeTrigger.StatusValue,
DeadbandType = DeadbandType.Absolute,
DeadbandValue = 0.5
};
uint mi1 = sub.Add("ns=2;s=Temp",
AttributeId.Value, samplingIntervalMs: 100,
mode: MonitoringMode.Reporting, queueSize: 1, discardOldest: true,
filter: filter1);

// 2) 百分比死区 2% — 流量在量程 2% 内不报
var filter2 = new DataChangeFilter
{
Trigger = DataChangeTrigger.StatusValueTimestamp,
DeadbandType = DeadbandType.Percent,
DeadbandValue = 2.0
};
uint mi2 = sub.Add("ns=2;s=Flow",
AttributeId.Value, 100,
MonitoringMode.Reporting, queueSize: 1, discardOldest: true,
filter: filter2);

// 3) 仅 Status 变化 — 看通讯链路状态翻转
var filter3 = new DataChangeFilter { Trigger = DataChangeTrigger.Status };
uint mi3 = sub.Add("ns=2;s=Comm.Status",
AttributeId.Value, 200, MonitoringMode.Reporting, 1, true, filter3);

sub.DataChanged += (s, e) =>
{
Console.WriteLine($"[mi={e.ClientHandle}] {e.Value.Value} ({e.Value.Status})");
};

实现说明

  • Stack 不支持自定义过滤器时, SDK graceful 降级:
    • 仍调底层 AddNode 注册 MI (filter 失效, 数据全量上报)
    • filter 缓存到本地 _miCache.FilterDef, 重连/重建时仍可还原
    • 推一条 Diagnostic 类别 Warn 事件让 UI 能感知
  • Percent 死区依赖目标节点有 EURange Property; 没有时服务端通常返回 BadFilterNotAllowed

最佳实践

  • 模拟量首选 Absolute 死区 — 工程单位直观, 例如 0.5°C / 0.1 bar
  • 大量程信号用 Percent — 量程 0-1000 的传感器写 1% 比写 10 直观
  • 数字量 (DI/DO) 不需要 filter — 状态翻转本来就稀疏
  • 死区不要太大 — 趋势曲线会失真, 经验值 0.1%-2%
  • filter 配 queueSize > 1 — 避免短脉冲被吞 (queueSize=10 + discardOldest=true 是常用)

跨语言对照

C#PythonJavaC++RustC
DataChangeFilterDataChangeFilterDataChangeFilterDataChangeFilterDataChangeFilterDarraUa_DataChangeFilter
DataChangeTriggerDataChangeTriggerDataChangeTriggerDataChangeTriggerDataChangeTriggerDarraUa_DataChangeTrigger
DeadbandTypeDeadbandTypeDeadbandTypeDeadbandTypeDeadbandTypeDarraUa_DeadbandType

下一步