IEC 61850 报告系列(一):报告控制块标准原理——从轮询到推送的演进

核心目标:建立对 IEC 61850 Report 机制的完整理论认知,理解报告控制块(RCB)的属性全集、触发模型与缓冲语义,能读懂标准条文并指导工程实践。

前置依赖:主系列 Part 2(信息模型:LD/LN/DO/DA/DataSet)、Part 3 §3.2.5(Report 机制基础)。

本专题定位:主系列 Part 3 已讲清"Report 是什么、怎么交互",本专题回答"为什么这样设计、属性全集如何、缓冲区状态机如何运转、出了问题怎么从原理层面定位"。


1.1 为什么需要 Report:C/S 模型的推送补丁

1.1.1 轮询的三大痛点

IEC 61850 的站控层通信基于 MMS 的 Client/Server 模型。最朴素的数据获取方式是轮询(Polling) :Client 周期性地向 Server 发起 Read 请求,拉取关心的数据对象当前值。这种方式在概念上简单,但在电力监控场景下存在三大痛点:

  1. 延迟不可控 :事件发生到下一次轮询之间存在随机间隔。若轮询周期为 T,事件平均感知延迟为 T/2,最坏情况为 T。对于保护跳闸这类事件,秒级延迟是不可接受的。
  2. 带宽浪费严重:绝大多数轮询返回的是"未变化"的冗余数据。假设一个 IED 有 500 个数据点,每秒轮询一次,即使只有 1 个点变化,仍有 499 个点的报文是无效负载。
  3. Server 负载高 :每次 Read 请求都需要 Server 解析对象引用、查找数据树、编码响应。高频轮询会显著占用 IED 的 CPU 资源,挤压保护逻辑的执行预算。

1.1.2 Report 的设计哲学

Report 机制是 IEC 61850 为 C/S 模型打的"推送补丁":事件驱动 + 服务端主动推送。Server 监视数据对象的变化,当满足预设的触发条件时,主动构造 Report 报文推送给已订阅的 Client。
#mermaid-svg-Q1xh2t2JI0dUK8GM{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-Q1xh2t2JI0dUK8GM .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-Q1xh2t2JI0dUK8GM .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-Q1xh2t2JI0dUK8GM .error-icon{fill:#552222;}#mermaid-svg-Q1xh2t2JI0dUK8GM .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-Q1xh2t2JI0dUK8GM .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-Q1xh2t2JI0dUK8GM .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-Q1xh2t2JI0dUK8GM .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-Q1xh2t2JI0dUK8GM .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-Q1xh2t2JI0dUK8GM .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-Q1xh2t2JI0dUK8GM .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-Q1xh2t2JI0dUK8GM .marker{fill:#333333;stroke:#333333;}#mermaid-svg-Q1xh2t2JI0dUK8GM .marker.cross{stroke:#333333;}#mermaid-svg-Q1xh2t2JI0dUK8GM svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-Q1xh2t2JI0dUK8GM p{margin:0;}#mermaid-svg-Q1xh2t2JI0dUK8GM .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-Q1xh2t2JI0dUK8GM .cluster-label text{fill:#333;}#mermaid-svg-Q1xh2t2JI0dUK8GM .cluster-label span{color:#333;}#mermaid-svg-Q1xh2t2JI0dUK8GM .cluster-label span p{background-color:transparent;}#mermaid-svg-Q1xh2t2JI0dUK8GM .label text,#mermaid-svg-Q1xh2t2JI0dUK8GM span{fill:#333;color:#333;}#mermaid-svg-Q1xh2t2JI0dUK8GM .node rect,#mermaid-svg-Q1xh2t2JI0dUK8GM .node circle,#mermaid-svg-Q1xh2t2JI0dUK8GM .node ellipse,#mermaid-svg-Q1xh2t2JI0dUK8GM .node polygon,#mermaid-svg-Q1xh2t2JI0dUK8GM .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-Q1xh2t2JI0dUK8GM .rough-node .label text,#mermaid-svg-Q1xh2t2JI0dUK8GM .node .label text,#mermaid-svg-Q1xh2t2JI0dUK8GM .image-shape .label,#mermaid-svg-Q1xh2t2JI0dUK8GM .icon-shape .label{text-anchor:middle;}#mermaid-svg-Q1xh2t2JI0dUK8GM .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-Q1xh2t2JI0dUK8GM .rough-node .label,#mermaid-svg-Q1xh2t2JI0dUK8GM .node .label,#mermaid-svg-Q1xh2t2JI0dUK8GM .image-shape .label,#mermaid-svg-Q1xh2t2JI0dUK8GM .icon-shape .label{text-align:center;}#mermaid-svg-Q1xh2t2JI0dUK8GM .node.clickable{cursor:pointer;}#mermaid-svg-Q1xh2t2JI0dUK8GM .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-Q1xh2t2JI0dUK8GM .arrowheadPath{fill:#333333;}#mermaid-svg-Q1xh2t2JI0dUK8GM .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-Q1xh2t2JI0dUK8GM .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-Q1xh2t2JI0dUK8GM .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Q1xh2t2JI0dUK8GM .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-Q1xh2t2JI0dUK8GM .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Q1xh2t2JI0dUK8GM .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-Q1xh2t2JI0dUK8GM .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-Q1xh2t2JI0dUK8GM .cluster text{fill:#333;}#mermaid-svg-Q1xh2t2JI0dUK8GM .cluster span{color:#333;}#mermaid-svg-Q1xh2t2JI0dUK8GM div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-Q1xh2t2JI0dUK8GM .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-Q1xh2t2JI0dUK8GM rect.text{fill:none;stroke-width:0;}#mermaid-svg-Q1xh2t2JI0dUK8GM .icon-shape,#mermaid-svg-Q1xh2t2JI0dUK8GM .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Q1xh2t2JI0dUK8GM .icon-shape p,#mermaid-svg-Q1xh2t2JI0dUK8GM .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-Q1xh2t2JI0dUK8GM .icon-shape .label rect,#mermaid-svg-Q1xh2t2JI0dUK8GM .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Q1xh2t2JI0dUK8GM .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-Q1xh2t2JI0dUK8GM .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-Q1xh2t2JI0dUK8GM :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 报告模式(Report)
事件持续产生
Client 一次订阅
Server 监视触发条件
满足条件时推送 Report

(仅含变化的数据)
轮询模式(Polling)
Client 周期发起 Read
Server 返回全部数据

(含大量未变化值)
Client 过滤变化

1.1.3 Report 在服务映射中的位置

Report 是 ACSI(Abstract Communication Service Interface,IEC 61850-7-2)定义的抽象服务,通过 SCSM(Specific Communication Service Mapping,IEC 61850-8-1)映射到 MMS 的 informationReport 服务:

复制代码
ACSI 层(IEC 61850-7-2)
  └─ Report 服务(抽象定义)
       ↓ SCSM 映射
MMS 层(IEC 61850-8-1)
  └─ informationReport 服务
       ↓ BER 编码
MMS PDU(ConfirmedRequestPDU,opcode = informationReport)

关键区别 :普通的 Read/Write 是 Client 发起的请求-响应模式;而 informationReportServer 主动发起的,Client 不需要为每条报告单独发请求。这是 Report 能实现"推送"语义的根本所在。

1.1.4 轮询 vs Report 的量化对比

以一个监控 200 个数据点的场景为例,假设事件发生频率为 1 次/秒:

指标 轮询(T=1s) Report(事件触发)
事件平均感知延迟 500ms < 50ms(含 bufTime)
每秒报文数(Client↔Server) 2(1 请求 + 1 响应) 1(仅推送)
每秒有效数据负载 200 点 × 全量编码 1 点 × 增量编码
Server CPU 占用 高(持续处理 Read) 低(仅事件时编码)
网络带宽占用 高(固定) 低(按需)

结论:在事件驱动的监控场景中,Report 在延迟、带宽、负载三个维度全面优于轮询。轮询仅适合"必须周期获取全量快照"的少数场景(如完整性校验),而 Report 是主力机制。


1.2 报告控制块(RCB)属性全集

Report 机制的核心管理对象是报告控制块(Report Control Block, RCB)。RCB 是一个特殊的逻辑节点对象,承载了 Report 行为的全部可配置参数。Client 通过读写 RCB 的属性来订阅、配置、控制报告流。

1.2.1 RCB 的两类实例:BRCB 与 URCB

IEC 61850 定义了两类 RCB,对应两种报告语义:

类型 全称 FC 命名前缀 缓冲语义 典型场景
BRCB Buffered Report Control Block BR BR 事件入缓冲区,ACK 前保留,断线可补发 保护事件、告警(不可丢失)
URCB Unbuffered Report Control Block RP RP 不缓冲,发送即丢弃,断线丢失 测量值周期上报(可容忍丢包)

命名规则:RCB 挂载在 LD 的 LLN0 下,ObjectReference 格式为:

  • URCB:LD/LLN0.RP.<name>(如 PROT/LLN0.RP.urcbStat
  • BRCB:LD/LLN0.BR.<name>(如 PROT/LLN0.BR.brcbTrip

注意 FC 与命名前缀的对应:URCB 用 RP,BRCB 用 BR。这是区分两类 RCB 的关键标识。

1.2.2 RCB 属性速查表

下表汇总了 IEC 61850-7-2 定义、IEC 61850-8-1 映射的 RCB 全部属性。标注 M 表示该类 RCB 必须支持,--- 表示不适用。

属性 全称 BRCB URCB 含义 数据类型
RptID Report Identifier M M 报告标识,区分不同报告流 VisibleString
RptEna Report Enable M M 使能标志,true=开始上报 BOOLEAN
Resv Reserved M M 保留标志,客户端独占 BOOLEAN
DatSet DataSet Reference M M 关联的数据集引用 ObjectReference
ConfRev Configuration Revision M M 配置版本号,DatSet 变更时递增 INT32U
OptFlds Option Fields M M 报告包含的可选字段位图 PACKED LIST
BufTm Buffer Time M --- 缓冲聚合时间(ms) INT32U
SqNum Sequence Number M M 序列号 INT8U/INT16U
TrgOps Trigger Options M M 触发条件位图 PACKED LIST
IntgPd Integrity Period M M 完整性周期(ms) INT32U
GI General Interrogation M M 总召唤标志 BOOLEAN
PurgeBuf Purge Buffer M --- 清除缓冲区 BOOLEAN
EntryID Entry Identifier M --- 缓冲区条目标识 OCTET STRING
TimeofEntry Time of Entry M --- 条目入缓冲区时间 UtcTime
Owner Owner --- M 当前占用者标识 OCTET STRING

1.2.3 BRCB vs URCB 属性差异图

#mermaid-svg-j0KSVM3bfijQTn2H{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-j0KSVM3bfijQTn2H .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-j0KSVM3bfijQTn2H .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-j0KSVM3bfijQTn2H .error-icon{fill:#552222;}#mermaid-svg-j0KSVM3bfijQTn2H .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-j0KSVM3bfijQTn2H .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-j0KSVM3bfijQTn2H .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-j0KSVM3bfijQTn2H .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-j0KSVM3bfijQTn2H .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-j0KSVM3bfijQTn2H .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-j0KSVM3bfijQTn2H .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-j0KSVM3bfijQTn2H .marker{fill:#333333;stroke:#333333;}#mermaid-svg-j0KSVM3bfijQTn2H .marker.cross{stroke:#333333;}#mermaid-svg-j0KSVM3bfijQTn2H svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-j0KSVM3bfijQTn2H p{margin:0;}#mermaid-svg-j0KSVM3bfijQTn2H .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-j0KSVM3bfijQTn2H .cluster-label text{fill:#333;}#mermaid-svg-j0KSVM3bfijQTn2H .cluster-label span{color:#333;}#mermaid-svg-j0KSVM3bfijQTn2H .cluster-label span p{background-color:transparent;}#mermaid-svg-j0KSVM3bfijQTn2H .label text,#mermaid-svg-j0KSVM3bfijQTn2H span{fill:#333;color:#333;}#mermaid-svg-j0KSVM3bfijQTn2H .node rect,#mermaid-svg-j0KSVM3bfijQTn2H .node circle,#mermaid-svg-j0KSVM3bfijQTn2H .node ellipse,#mermaid-svg-j0KSVM3bfijQTn2H .node polygon,#mermaid-svg-j0KSVM3bfijQTn2H .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-j0KSVM3bfijQTn2H .rough-node .label text,#mermaid-svg-j0KSVM3bfijQTn2H .node .label text,#mermaid-svg-j0KSVM3bfijQTn2H .image-shape .label,#mermaid-svg-j0KSVM3bfijQTn2H .icon-shape .label{text-anchor:middle;}#mermaid-svg-j0KSVM3bfijQTn2H .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-j0KSVM3bfijQTn2H .rough-node .label,#mermaid-svg-j0KSVM3bfijQTn2H .node .label,#mermaid-svg-j0KSVM3bfijQTn2H .image-shape .label,#mermaid-svg-j0KSVM3bfijQTn2H .icon-shape .label{text-align:center;}#mermaid-svg-j0KSVM3bfijQTn2H .node.clickable{cursor:pointer;}#mermaid-svg-j0KSVM3bfijQTn2H .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-j0KSVM3bfijQTn2H .arrowheadPath{fill:#333333;}#mermaid-svg-j0KSVM3bfijQTn2H .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-j0KSVM3bfijQTn2H .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-j0KSVM3bfijQTn2H .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-j0KSVM3bfijQTn2H .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-j0KSVM3bfijQTn2H .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-j0KSVM3bfijQTn2H .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-j0KSVM3bfijQTn2H .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-j0KSVM3bfijQTn2H .cluster text{fill:#333;}#mermaid-svg-j0KSVM3bfijQTn2H .cluster span{color:#333;}#mermaid-svg-j0KSVM3bfijQTn2H div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-j0KSVM3bfijQTn2H .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-j0KSVM3bfijQTn2H rect.text{fill:none;stroke-width:0;}#mermaid-svg-j0KSVM3bfijQTn2H .icon-shape,#mermaid-svg-j0KSVM3bfijQTn2H .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-j0KSVM3bfijQTn2H .icon-shape p,#mermaid-svg-j0KSVM3bfijQTn2H .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-j0KSVM3bfijQTn2H .icon-shape .label rect,#mermaid-svg-j0KSVM3bfijQTn2H .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-j0KSVM3bfijQTn2H .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-j0KSVM3bfijQTn2H .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-j0KSVM3bfijQTn2H :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} URCB 独有(独占语义)
Owner

当前占用者标识
BRCB 独有(缓冲语义)
BufTm

缓冲聚合时间
PurgeBuf

清除缓冲区
EntryID

条目标识
TimeofEntry

入缓冲时间
共有属性(BRCB + URCB)
RptID / RptEna / Resv

DatSet / ConfRev / OptFlds

SqNum / TrgOps / IntgPd / GI

1.2.4 关键属性语义详解

RptID(报告标识)

  • 字符串类型,用于在 Client 端区分来自不同 RCB 的报告流。
  • 典型取值为 RCB 的 ObjectReference(如 PROT/LLN0.BR.brcbTrip),但标准不强制。
  • 一个 Client 可同时订阅多个 RCB,回调中靠 RptID 分发。

RptEna(使能标志)

  • false(默认):RCB 处于禁用态,不产生任何报告。
  • true:RCB 使能,开始监视触发条件并上报。
  • Client 订阅的核心动作就是 Write RptEna = true;取消订阅则 Write RptEna = false

Resv(保留标志)

  • 用于实现 Client 独占。Resv = true 表示该 RCB 被某个 Client 保留,其他 Client 修改其属性会被拒绝。
  • BRCB 中 Resv 控制配置修改权;URCB 中 ResvOwner 共同实现独占。

DatSet(数据集引用)

  • 指向 RCB 关联的 DataSet(数据集)。Report 上报的内容就是 DatSet 成员的值。
  • 引用格式:LD/LLN0.dsName(如 PROT/LLN0.dsTrip)。
  • DatSet 变更(成员增删、顺序变化)会导致 ConfRev 递增。

ConfRev(配置版本)

  • 32 位无符号整数。每当 DatSet 成员发生变化时,Server 自动将 ConfRev 加 1。
  • Client 收到报告时应检查 ConfRev 是否与订阅时一致,不一致说明配置已变更,需重新订阅。
  • 详见 §1.6。

OptFlds(可选字段)

  • 位图类型,控制 Report 报文中包含哪些可选字段(sqNum、timeStamp、reasonForInclusion 等)。
  • 详见 §1.4。

BufTm(缓冲时间)

  • 仅 BRCB 有。单位毫秒。
  • 作用:事件触发后不立即发送,而是在 BufTm 时间窗口内聚合多个事件,窗口结束时一并发送。
  • 设计意图:高频事件场景下减少报文数量。例如断路器分合过程中位置抖动,BufTm 可聚合为单条报告。
  • 0 表示不聚合,事件立即发送。

SqNum(序列号)

  • 报告的顺序编号,用于 Client 检测丢包与乱序。
  • BRCB:SqNum 在缓冲区内严格递增,Client ACK 后 Server 可清理对应条目。
  • URCB:SqNum 每条报告独立递增,无 ACK 机制。
  • 标准允许 INT8U(0-255)或 INT16U(0-65535),由实现决定。溢出后回绕到 0。

TrgOps(触发条件)

  • 位图类型,定义哪些条件触发报告。详见 §1.3。

IntgPd(完整性周期)

  • 单位毫秒。周期性全量上报 DatSet 所有成员当前值,与触发条件独立。
  • 0 表示禁用完整性周期。
  • 典型值:测量值场景 1000-5000ms,状态量场景 60000ms。

GI(总召唤)

  • 布尔标志。Client 写 GI = true 触发一次性的全量上报(DatSet 全部成员当前值)。
  • IntgPd 的区别:GI 是一次性手动触发,IntgPd 是周期性自动触发。
  • GI 触发的报告中,所有成员的 reason-for-inclusion 都标记为"integrity"。

PurgeBuf(清除缓冲区)

  • 仅 BRCB 有 。Client 写 PurgeBuf = true 清空缓冲区中尚未发送/未 ACK 的条目。
  • 使用场景:Client 重连后不想要历史积压事件,主动清空。
  • 风险:清空后缓冲区内的事件永久丢失,需谨慎使用。

EntryID(条目标识)

  • 仅 BRCB 有。8 字节 OCTET STRING,唯一标识缓冲区中的每个条目。
  • 核心用途:Client 断线重连后,基于最后收到的 EntryID 请求 Server 从该点续传。
  • 详见 §1.5。

TimeofEntry(入缓冲时间)

  • 仅 BRCB 有。事件入缓冲区的 UTC 时间戳,精度到毫秒。
  • 与报告发送时间不同:事件可能在缓冲区中等待一段时间(受 BufTm 或网络断开影响)才被发送。

Owner(占用者)

  • 仅 URCB 有。OCTET STRING,记录当前独占该 URCB 的 Client 标识(通常是 Client 的 IP + 端口或会话 ID)。
  • URCB 是单订阅者模型,同一时刻只能有一个 Client 持有 Owner。
  • BRCB 支持多订阅者,故无 Owner 属性。

1.3 触发模型深度解析

触发模型决定了"什么情况下 Server 会产生一条报告"。IEC 61850-7-2 §14.5 定义了四种触发条件,它们之间是逻辑或关系:任一条件满足即触发。

1.3.1 四种触发条件

触发条件 名称 控制位 语义 典型场景
dchg Data Change TrgOps.dchg 数据值发生变化 断路器位置变化、保护动作
qchg Quality Change TrgOps.qchg 数据品质位变化 数据从 good 变 invalid
dupd Data Update TrgOps.dupd 数据被更新(值可能未变) 周期性状态刷新、设定值写入
IntgPd Integrity IntgPd > 0 周期性全量上报 测量值定期刷新、心跳监视

注意 :前三种(dchg/qchg/dupd)由 TrgOps 位图控制,是事件触发的;第四种(IntgPd)由 IntgPd 属性的值控制(非零即启用),是周期触发的,与 TrgOps 位图独立。

1.3.2 TrgOps 位图编码

TrgOps 是一个位图(BIT STRING),标准定义的位如下:

Bit 名称 含义
bit 0 reserved 保留
bit 1 dchg 数据变化触发
bit 2 qchg 品质变化触发
bit 3 dupd 数据更新触发
bit 4 period 完整性周期触发(对应 IntgPd)

常见组合

  • dchg + qchg(0b00110 = 6):保护事件、状态变化(最常用)
  • dchg + qchg + dupd(0b01110 = 14):故障录波、全量捕获
  • period(0b10000 = 16):纯周期上报,无事件触发
  • dchg + qchg + period(0b10110 = 22):事件 + 周期心跳(推荐配置)
    陷阱TrgOps.periodIntgPd 的关系容易混淆。period 位控制"是否启用完整性周期上报",而 IntgPd 的值决定"周期多长"。两者必须同时配置才生效:period=trueIntgPd > 0。若只设 IntgPdperiod=false,不会产生周期报告。

1.3.3 触发决策流程

当 Server 端某个 DA 的值或品质发生变化时,触发决策流程如下:
#mermaid-svg-5kKFGrzXVQSTMEBO{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-5kKFGrzXVQSTMEBO .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-5kKFGrzXVQSTMEBO .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-5kKFGrzXVQSTMEBO .error-icon{fill:#552222;}#mermaid-svg-5kKFGrzXVQSTMEBO .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-5kKFGrzXVQSTMEBO .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-5kKFGrzXVQSTMEBO .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-5kKFGrzXVQSTMEBO .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-5kKFGrzXVQSTMEBO .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-5kKFGrzXVQSTMEBO .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-5kKFGrzXVQSTMEBO .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-5kKFGrzXVQSTMEBO .marker{fill:#333333;stroke:#333333;}#mermaid-svg-5kKFGrzXVQSTMEBO .marker.cross{stroke:#333333;}#mermaid-svg-5kKFGrzXVQSTMEBO svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-5kKFGrzXVQSTMEBO p{margin:0;}#mermaid-svg-5kKFGrzXVQSTMEBO .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-5kKFGrzXVQSTMEBO .cluster-label text{fill:#333;}#mermaid-svg-5kKFGrzXVQSTMEBO .cluster-label span{color:#333;}#mermaid-svg-5kKFGrzXVQSTMEBO .cluster-label span p{background-color:transparent;}#mermaid-svg-5kKFGrzXVQSTMEBO .label text,#mermaid-svg-5kKFGrzXVQSTMEBO span{fill:#333;color:#333;}#mermaid-svg-5kKFGrzXVQSTMEBO .node rect,#mermaid-svg-5kKFGrzXVQSTMEBO .node circle,#mermaid-svg-5kKFGrzXVQSTMEBO .node ellipse,#mermaid-svg-5kKFGrzXVQSTMEBO .node polygon,#mermaid-svg-5kKFGrzXVQSTMEBO .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-5kKFGrzXVQSTMEBO .rough-node .label text,#mermaid-svg-5kKFGrzXVQSTMEBO .node .label text,#mermaid-svg-5kKFGrzXVQSTMEBO .image-shape .label,#mermaid-svg-5kKFGrzXVQSTMEBO .icon-shape .label{text-anchor:middle;}#mermaid-svg-5kKFGrzXVQSTMEBO .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-5kKFGrzXVQSTMEBO .rough-node .label,#mermaid-svg-5kKFGrzXVQSTMEBO .node .label,#mermaid-svg-5kKFGrzXVQSTMEBO .image-shape .label,#mermaid-svg-5kKFGrzXVQSTMEBO .icon-shape .label{text-align:center;}#mermaid-svg-5kKFGrzXVQSTMEBO .node.clickable{cursor:pointer;}#mermaid-svg-5kKFGrzXVQSTMEBO .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-5kKFGrzXVQSTMEBO .arrowheadPath{fill:#333333;}#mermaid-svg-5kKFGrzXVQSTMEBO .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-5kKFGrzXVQSTMEBO .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-5kKFGrzXVQSTMEBO .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-5kKFGrzXVQSTMEBO .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-5kKFGrzXVQSTMEBO .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-5kKFGrzXVQSTMEBO .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-5kKFGrzXVQSTMEBO .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-5kKFGrzXVQSTMEBO .cluster text{fill:#333;}#mermaid-svg-5kKFGrzXVQSTMEBO .cluster span{color:#333;}#mermaid-svg-5kKFGrzXVQSTMEBO div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-5kKFGrzXVQSTMEBO .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-5kKFGrzXVQSTMEBO rect.text{fill:none;stroke-width:0;}#mermaid-svg-5kKFGrzXVQSTMEBO .icon-shape,#mermaid-svg-5kKFGrzXVQSTMEBO .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-5kKFGrzXVQSTMEBO .icon-shape p,#mermaid-svg-5kKFGrzXVQSTMEBO .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-5kKFGrzXVQSTMEBO .icon-shape .label rect,#mermaid-svg-5kKFGrzXVQSTMEBO .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-5kKFGrzXVQSTMEBO .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-5kKFGrzXVQSTMEBO .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-5kKFGrzXVQSTMEBO :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 否





DA 值/品质发生变化
RCB 是否使能?

RptEna == true
变化类型是否匹配

TrgOps 位图?
是 BRCB 且

BufTm > 0?
加入当前 BufTm 窗口

等待聚合
事件入缓冲区

分配 EntryID + SqNum
立即构造并发送 Report
BufTm 到期时

聚合发送 Report
丢弃,不触发

1.3.4 GI(总召唤)

GI 是一种特殊的触发方式,由 Client 主动发起:

  • Client 写 RCB.GI = true
  • Server 收到后,立即构造一条报告,包含 DatSet 全部成员的当前值。
  • GI 报告中所有成员的 reason-for-inclusion 标记为"integrity"(与 IntgPd 触发的报告相同)。
  • GI 是一次性的,写一次触发一条报告;不会持续。

典型应用:Client 上线后立即调用 GI,获取 IED 当前全量状态,之后依赖事件触发接收增量变化。

1.3.5 dchg 与 dupd 的微妙区别

dchgdupd 都涉及"数据变化",但语义不同,容易混淆:

对比项 dchg(Data Change) dupd(Data Update)
触发条件 实际发生变化 值被写入/更新(无论是否变化)
默认触发位 离散量(BOOLEAN/ENUM)默认 dchg 模拟量(MV/ASG)默认 dupd
典型 CDC SPC/DPC/ENC/ACT MV/ASG/WYE
应用场景 开关变位、保护动作 设定值修改、测量值刷新

CDC 与默认触发位的对应关系(IEC 61850-7-3):

CDC 类别 默认 dchg 默认 qchg 默认 dupd
SPC(单点控制) ---
DPC(双点控制) ---
ENC(枚举控制) ---
ACT(保护动作) ---
MV(测量值) ---
ASG(模拟设定) --- ---
WYE(三相量) ---

实践建议

  • 状态量(开关、保护动作)用 dchg,确保只在真正变位时上报。
  • 模拟量(测量值、设定值)用 dupd,因为模拟量"变化"的判定需要死区,而 dupd 不做值比较,每次更新都触发。若需死区控制,应在 DA 的 db(deadband)属性或 Server 端逻辑中实现。
  • qchg 几乎总是应该启用,因为品质变化(如通信中断导致 invalid)是重要的运维信号。

1.4 OptFlds(可选字段)详解

Report 报文的结构分为"必选部分"和"可选部分"。必选部分包括 RptID、DatSet 引用、Inclusion-bitstring、listOfAccessResult;可选部分由 OptFlds 位图控制。Client 可根据应用需求选择包含哪些可选字段。

1.4.1 OptFlds 位图定义

Bit 字段 含义 报文体积影响
0 sqNum 序列号 +1~2 字节
1 timeStamp 报告时间戳 +8 字节(UTCTime)
2 reasonForInclusion 每个成员的触发原因 +N 字节(N=成员数)
3 dataSetName 数据集名称 +10~30 字节
4 dataRef 每个成员的对象引用 +N×20 字节
5 bufferOverflow 缓冲区溢出标志 +1 字节
6 entryID 缓冲区条目标识 +8 字节
7 confRev 配置版本号 +4 字节

1.4.2 OptFlds 组合场景表

不同应用场景对报告内容的需求不同,推荐配置如下:

应用场景 推荐 OptFlds 理由
监控后台 sqNum + timeStamp + dataRef + dataSetName 需要时间戳和对象引用用于画面刷新,dataRef 帮助定位数据点
事件记录系统 sqNum + timeStamp + reasonForInclusion + entryID 需要触发原因用于事件分类,entryID 用于断线续传
故障录波 全字段 录波需要完整上下文,不吝啬带宽
网关转发 sqNum + timeStamp + reasonCode 转发到其他协议(如 IEC 104)需要触发原因做映射
轻量遥测 sqNum + timeStamp 仅需值和时间,最小化报文

1.4.3 OptFlds 对报文体积的影响估算

以一个 20 成员的 DatSet 为例,估算不同 OptFlds 配置下的报告体积:

OptFlds 配置 固定开销 每成员开销 20 成员总开销 估算总字节数
最小(无可选字段) ~30B ~10B 200B ~230B
sqNum + timeStamp ~38B ~10B 200B ~238B
+ dataRef ~38B ~30B 600B ~638B
+ reasonForInclusion ~38B ~32B 640B ~678B
全字段 ~50B ~35B 700B ~750B

结论dataRef 是体积增长的主要因素(每成员增加约 20 字节的对象引用字符串)。对于大 DatSet(>50 成员),应谨慎启用 dataRef,可改用 dataSetName + 成员索引的方式在 Client 端还原引用。


1.5 缓冲报告的状态机

BRCB 的核心价值在于缓冲区机制:事件入缓冲区后,即使 Client 暂时断开,事件也不会丢失,网络恢复后可补发。理解缓冲区的状态机是掌握 BRCB 的关键。

1.5.1 BRCB 缓冲区生命周期

#mermaid-svg-aPfNQ933TSuZBWyt{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-aPfNQ933TSuZBWyt .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-aPfNQ933TSuZBWyt .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-aPfNQ933TSuZBWyt .error-icon{fill:#552222;}#mermaid-svg-aPfNQ933TSuZBWyt .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-aPfNQ933TSuZBWyt .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-aPfNQ933TSuZBWyt .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-aPfNQ933TSuZBWyt .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-aPfNQ933TSuZBWyt .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-aPfNQ933TSuZBWyt .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-aPfNQ933TSuZBWyt .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-aPfNQ933TSuZBWyt .marker{fill:#333333;stroke:#333333;}#mermaid-svg-aPfNQ933TSuZBWyt .marker.cross{stroke:#333333;}#mermaid-svg-aPfNQ933TSuZBWyt svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-aPfNQ933TSuZBWyt p{margin:0;}#mermaid-svg-aPfNQ933TSuZBWyt defs #statediagram-barbEnd{fill:#333333;stroke:#333333;}#mermaid-svg-aPfNQ933TSuZBWyt g.stateGroup text{fill:#9370DB;stroke:none;font-size:10px;}#mermaid-svg-aPfNQ933TSuZBWyt g.stateGroup text{fill:#333;stroke:none;font-size:10px;}#mermaid-svg-aPfNQ933TSuZBWyt g.stateGroup .state-title{font-weight:bolder;fill:#131300;}#mermaid-svg-aPfNQ933TSuZBWyt g.stateGroup rect{fill:#ECECFF;stroke:#9370DB;}#mermaid-svg-aPfNQ933TSuZBWyt g.stateGroup line{stroke:#333333;stroke-width:1;}#mermaid-svg-aPfNQ933TSuZBWyt .transition{stroke:#333333;stroke-width:1;fill:none;}#mermaid-svg-aPfNQ933TSuZBWyt .stateGroup .composit{fill:white;border-bottom:1px;}#mermaid-svg-aPfNQ933TSuZBWyt .stateGroup .alt-composit{fill:#e0e0e0;border-bottom:1px;}#mermaid-svg-aPfNQ933TSuZBWyt .state-note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-aPfNQ933TSuZBWyt .state-note text{fill:black;stroke:none;font-size:10px;}#mermaid-svg-aPfNQ933TSuZBWyt .stateLabel .box{stroke:none;stroke-width:0;fill:#ECECFF;opacity:0.5;}#mermaid-svg-aPfNQ933TSuZBWyt .edgeLabel .label rect{fill:#ECECFF;opacity:0.5;}#mermaid-svg-aPfNQ933TSuZBWyt .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-aPfNQ933TSuZBWyt .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-aPfNQ933TSuZBWyt .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-aPfNQ933TSuZBWyt .edgeLabel .label text{fill:#333;}#mermaid-svg-aPfNQ933TSuZBWyt .label div .edgeLabel{color:#333;}#mermaid-svg-aPfNQ933TSuZBWyt .stateLabel text{fill:#131300;font-size:10px;font-weight:bold;}#mermaid-svg-aPfNQ933TSuZBWyt .node circle.state-start{fill:#333333;stroke:#333333;}#mermaid-svg-aPfNQ933TSuZBWyt .node .fork-join{fill:#333333;stroke:#333333;}#mermaid-svg-aPfNQ933TSuZBWyt .node circle.state-end{fill:#9370DB;stroke:white;stroke-width:1.5;}#mermaid-svg-aPfNQ933TSuZBWyt .end-state-inner{fill:white;stroke-width:1.5;}#mermaid-svg-aPfNQ933TSuZBWyt .node rect{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-aPfNQ933TSuZBWyt .node polygon{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-aPfNQ933TSuZBWyt #statediagram-barbEnd{fill:#333333;}#mermaid-svg-aPfNQ933TSuZBWyt .statediagram-cluster rect{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-aPfNQ933TSuZBWyt .cluster-label,#mermaid-svg-aPfNQ933TSuZBWyt .nodeLabel{color:#131300;}#mermaid-svg-aPfNQ933TSuZBWyt .statediagram-cluster rect.outer{rx:5px;ry:5px;}#mermaid-svg-aPfNQ933TSuZBWyt .statediagram-state .divider{stroke:#9370DB;}#mermaid-svg-aPfNQ933TSuZBWyt .statediagram-state .title-state{rx:5px;ry:5px;}#mermaid-svg-aPfNQ933TSuZBWyt .statediagram-cluster.statediagram-cluster .inner{fill:white;}#mermaid-svg-aPfNQ933TSuZBWyt .statediagram-cluster.statediagram-cluster-alt .inner{fill:#f0f0f0;}#mermaid-svg-aPfNQ933TSuZBWyt .statediagram-cluster .inner{rx:0;ry:0;}#mermaid-svg-aPfNQ933TSuZBWyt .statediagram-state rect.basic{rx:5px;ry:5px;}#mermaid-svg-aPfNQ933TSuZBWyt .statediagram-state rect.divider{stroke-dasharray:10,10;fill:#f0f0f0;}#mermaid-svg-aPfNQ933TSuZBWyt .note-edge{stroke-dasharray:5;}#mermaid-svg-aPfNQ933TSuZBWyt .statediagram-note rect{fill:#fff5ad;stroke:#aaaa33;stroke-width:1px;rx:0;ry:0;}#mermaid-svg-aPfNQ933TSuZBWyt .statediagram-note rect{fill:#fff5ad;stroke:#aaaa33;stroke-width:1px;rx:0;ry:0;}#mermaid-svg-aPfNQ933TSuZBWyt .statediagram-note text{fill:black;}#mermaid-svg-aPfNQ933TSuZBWyt .statediagram-note .nodeLabel{color:black;}#mermaid-svg-aPfNQ933TSuZBWyt .statediagram .edgeLabel{color:red;}#mermaid-svg-aPfNQ933TSuZBWyt #dependencyStart,#mermaid-svg-aPfNQ933TSuZBWyt #dependencyEnd{fill:#333333;stroke:#333333;stroke-width:1;}#mermaid-svg-aPfNQ933TSuZBWyt .statediagramTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-aPfNQ933TSuZBWyt :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} RptEna = false
Client 写 RptEna = true
Client 写 RptEna = false
禁用态
使能态
事件触发
BufTm 到期 或 立即发送
报告已发送
收到 Client ACK
新事件到达(未 ACK 的保留)
缓冲区满
空闲
缓冲中
发送中
等待ACK
溢出
覆盖最旧条目
设置_bufOvfl_标志

1.5.2 状态详解

禁用态(RptEna = false)

  • RCB 不监视任何触发条件,不产生报告。
  • 缓冲区为空(若之前有数据,使能时是否清空取决于实现,标准未强制)。
  • Client 通过 Write RptEna = true 切换到使能态。

使能态 - 空闲

  • RCB 正在监视触发条件,但缓冲区中无待发送事件。
  • IntgPd 计时器运行中,到期时触发完整性报告。

使能态 - 缓冲中

  • 事件已入缓冲区,分配了 EntryID 和 SqNum。
  • BufTm > 0,等待 BufTm 窗口聚合更多事件。
  • BufTm = 0,立即转入发送中。

使能态 - 发送中

  • Server 构造 Report 报文并通过 MMS informationReport 发送。
  • 报告发送后,条目仍保留在缓冲区,等待 Client ACK。

使能态 - 等待ACK

  • 报告已发送,等待 Client 的确认。
  • Client 通过写 RCB.AckRcv(或等价机制)确认已收到的 SqNum。
  • 收到 ACK 后,Server 可清理缓冲区中 SqNum ≤ ACK 值的条目。

溢出

  • 缓冲区容量达到上限(由实现决定,libiec61850 默认 100 条,可编译期调整)。
  • 行为:覆盖最旧的未 ACK 条目,并设置 bufOvfl 标志。
  • 后续报告中 OptFlds.bufferOverflow = true,通知 Client 发生过溢出。

1.5.3 SqNum 的循环与溢出处理

SqNum 的取值范围由实现决定:

  • INT8U(0-255):适用于低频事件场景,缓冲区容量通常 ≤ 256。
  • INT16U(0-65535):适用于高频事件场景,缓冲区容量可更大。

SqNum 递增到上限后回绕到 0:

复制代码
SqNum 序列:... 253 → 254 → 255 → 0 → 1 → 2 ...

Client 端处理:检测 SqNum 连续性时需考虑回绕。例如收到 255 后期望 0,若收到 1 则说明丢失了 0 号报告。推荐的检测算法:

复制代码
expected = (last_sqnum + 1) % MAX_SQNUM
if received_sqnum != expected:
    gap = (received_sqnum - expected + MAX_SQNUM) % MAX_SQNUM
    报告丢失 gap 个报告

1.5.4 EntryID 与断线续传

EntryID 是 BRCB 缓冲区中每个条目的唯一标识(8 字节 OCTET STRING)。它的核心价值在于支持断线续传

  1. Client 订阅 BRCB,正常接收报告,记录每条报告的 EntryID
  2. 网络断开,Client 与 Server 失去连接。
  3. Server 端事件继续产生,入缓冲区(缓冲区未满则保留)。
  4. 网络恢复,Client 重连。
  5. Client 写 RCB.EntryID = <最后收到的 EntryID>,请求 Server 从该点之后补发。
  6. Server 查找缓冲区,将 EntryID 之后的所有条目依次补发给 Client。

Server (BRCB) Client Server (BRCB) Client #mermaid-svg-qtL31ZoSfcYeiNT7{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-qtL31ZoSfcYeiNT7 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-qtL31ZoSfcYeiNT7 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-qtL31ZoSfcYeiNT7 .error-icon{fill:#552222;}#mermaid-svg-qtL31ZoSfcYeiNT7 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-qtL31ZoSfcYeiNT7 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-qtL31ZoSfcYeiNT7 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-qtL31ZoSfcYeiNT7 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-qtL31ZoSfcYeiNT7 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-qtL31ZoSfcYeiNT7 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-qtL31ZoSfcYeiNT7 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-qtL31ZoSfcYeiNT7 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-qtL31ZoSfcYeiNT7 .marker.cross{stroke:#333333;}#mermaid-svg-qtL31ZoSfcYeiNT7 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-qtL31ZoSfcYeiNT7 p{margin:0;}#mermaid-svg-qtL31ZoSfcYeiNT7 .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-qtL31ZoSfcYeiNT7 text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-qtL31ZoSfcYeiNT7 .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-qtL31ZoSfcYeiNT7 .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-qtL31ZoSfcYeiNT7 .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-qtL31ZoSfcYeiNT7 .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-qtL31ZoSfcYeiNT7 #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-qtL31ZoSfcYeiNT7 .sequenceNumber{fill:white;}#mermaid-svg-qtL31ZoSfcYeiNT7 #sequencenumber{fill:#333;}#mermaid-svg-qtL31ZoSfcYeiNT7 #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-qtL31ZoSfcYeiNT7 .messageText{fill:#333;stroke:none;}#mermaid-svg-qtL31ZoSfcYeiNT7 .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-qtL31ZoSfcYeiNT7 .labelText,#mermaid-svg-qtL31ZoSfcYeiNT7 .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-qtL31ZoSfcYeiNT7 .loopText,#mermaid-svg-qtL31ZoSfcYeiNT7 .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-qtL31ZoSfcYeiNT7 .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-qtL31ZoSfcYeiNT7 .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-qtL31ZoSfcYeiNT7 .noteText,#mermaid-svg-qtL31ZoSfcYeiNT7 .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-qtL31ZoSfcYeiNT7 .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-qtL31ZoSfcYeiNT7 .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-qtL31ZoSfcYeiNT7 .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-qtL31ZoSfcYeiNT7 .actorPopupMenu{position:absolute;}#mermaid-svg-qtL31ZoSfcYeiNT7 .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-qtL31ZoSfcYeiNT7 .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-qtL31ZoSfcYeiNT7 .actor-man circle,#mermaid-svg-qtL31ZoSfcYeiNT7 line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-qtL31ZoSfcYeiNT7 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 正常订阅阶段 记录最后 EntryID=0x02 网络断开 事件继续入缓冲区EntryID=0x03, 0x04, 0x05 网络恢复 完整收到所有积压事件 Write RptEna = trueReport (EntryID=0x01, SqNum=1)Report (EntryID=0x02, SqNum=2)Write RptEna = true(重新使能)Write EntryID = 0x02(请求续传点)Report (EntryID=0x03, SqNum=3)Report (EntryID=0x04, SqNum=4)Report (EntryID=0x05, SqNum=5)

关键点:EntryID 续传依赖缓冲区中条目未被覆盖。若断线期间事件过多导致缓冲区溢出,最旧的条目会被覆盖,此时 Client 请求的 EntryID 可能已不存在,Server 会返回错误或从当前最旧条目开始补发(具体行为由实现决定)。

1.5.5 PurgeBuf 的使用场景与风险

PurgeBuf(仅 BRCB)用于主动清空缓冲区:

  • 使用场景
    • Client 重连后不关心历史积压事件,只要实时数据 → 清空后重新开始。
    • 测试场景下重置缓冲区状态。
  • 风险
    • 清空操作不可逆,缓冲区内所有未发送/未 ACK 的事件永久丢失
    • 若多个 Client 订阅同一 BRCB,PurgeBuf 会影响所有订阅者。
  • 建议:生产环境慎用,仅在明确不需要历史数据时使用。更安全的做法是基于 EntryID 续传。

1.5.6 缓冲区溢出(BufferOverflow)

当事件产生速率超过 Client ACK 速率,或缓冲区过小时,会发生溢出。溢出的语义与处理:

  • 溢出行为:环形缓冲区覆盖最旧的未 ACK 条目,新事件继续入队。
  • 标志通知 :溢出发生后,下一条报告的 OptFlds.bufferOverflow 位置 1(前提是 OptFlds 中启用了该位)。
  • Client 感知 :Client 收到 bufOvfl = true 的报告时,应:
    1. 记录溢出事件,产生告警。
    2. 检查 SqNum 跳变,估算丢失的报告数量。
    3. 决定是否触发 GI 重新获取全量状态(弥补丢失数据)。
    4. 评估是否需要增大缓冲区或拆分高频数据到独立 RCB。

预防措施

  • 高频事件(如测量值抖动)不应与低频关键事件(如保护跳闸)共用同一 BRCB,否则高频事件可能挤占缓冲区导致关键事件被覆盖。
  • 监控 ACK 延迟,确保 Client 处理报告的速度跟得上 Server 产生事件的速度。

1.6 ConfRev(配置版本)机制

1.6.1 为什么需要 ConfRev

ConfRev(Configuration Revision)是 RCB 的配置版本号,用于解决"DatSet 变更导致 Client 误读"的问题。

考虑以下场景:

  1. Client 订阅了 brcbTrip,关联 dsTrip(成员:PTOC1.Op.generalXCBR1.Pos.stVal)。
  2. Client 在本地维护了"Inclusion-bitstring 第 0 位 = PTOC1.Op.general,第 1 位 = XCBR1.Pos.stVal"的映射。
  3. 运维人员修改 SCL,在 dsTrip 头部插入了一个新成员 PTOC1.Str.general
  4. 现在 Inclusion-bitstring 的第 0 位变成了 PTOC1.Str.general,第 1 位变成了 PTOC1.Op.general
  5. 若 Client 不感知此变更,仍按旧映射解读,就会把保护启动信号误认为跳闸信号------严重的安全事故

ConfRev 就是为防止这类问题而设计的:每次 DatSet 成员变更,ConfRev 递增,Client 检测到变化后强制重新同步配置。

1.6.2 ConfRev 递增规则

Server 在以下情况下将 ConfRev 加 1:

变更类型 ConfRev 是否递增 说明
DatSet 增加成员 成员列表变化
DatSet 删除成员 成员列表变化
DatSet 成员顺序变化 Inclusion-bitstring 位映射变化
DatSet 成员引用不变但值变化 值变化由报告本身承载
RCB 的 TrgOps/OptFlds 变化 这些是 RCB 自身属性,非 DatSet 配置
RCB 的 IntgPd/BufTm 变化 同上

注意:ConfRev 只反映 DatSet 成员列表的变更,不反映 RCB 自身参数的变更。后者由 Client 主动管理(修改前需 disable,修改后 enable)。

1.6.3 Client 检测 ConfRev 变化的处理流程

#mermaid-svg-NDulo8mpR2Eltxyv{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-NDulo8mpR2Eltxyv .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-NDulo8mpR2Eltxyv .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-NDulo8mpR2Eltxyv .error-icon{fill:#552222;}#mermaid-svg-NDulo8mpR2Eltxyv .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-NDulo8mpR2Eltxyv .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-NDulo8mpR2Eltxyv .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-NDulo8mpR2Eltxyv .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-NDulo8mpR2Eltxyv .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-NDulo8mpR2Eltxyv .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-NDulo8mpR2Eltxyv .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-NDulo8mpR2Eltxyv .marker{fill:#333333;stroke:#333333;}#mermaid-svg-NDulo8mpR2Eltxyv .marker.cross{stroke:#333333;}#mermaid-svg-NDulo8mpR2Eltxyv svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-NDulo8mpR2Eltxyv p{margin:0;}#mermaid-svg-NDulo8mpR2Eltxyv .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-NDulo8mpR2Eltxyv .cluster-label text{fill:#333;}#mermaid-svg-NDulo8mpR2Eltxyv .cluster-label span{color:#333;}#mermaid-svg-NDulo8mpR2Eltxyv .cluster-label span p{background-color:transparent;}#mermaid-svg-NDulo8mpR2Eltxyv .label text,#mermaid-svg-NDulo8mpR2Eltxyv span{fill:#333;color:#333;}#mermaid-svg-NDulo8mpR2Eltxyv .node rect,#mermaid-svg-NDulo8mpR2Eltxyv .node circle,#mermaid-svg-NDulo8mpR2Eltxyv .node ellipse,#mermaid-svg-NDulo8mpR2Eltxyv .node polygon,#mermaid-svg-NDulo8mpR2Eltxyv .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-NDulo8mpR2Eltxyv .rough-node .label text,#mermaid-svg-NDulo8mpR2Eltxyv .node .label text,#mermaid-svg-NDulo8mpR2Eltxyv .image-shape .label,#mermaid-svg-NDulo8mpR2Eltxyv .icon-shape .label{text-anchor:middle;}#mermaid-svg-NDulo8mpR2Eltxyv .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-NDulo8mpR2Eltxyv .rough-node .label,#mermaid-svg-NDulo8mpR2Eltxyv .node .label,#mermaid-svg-NDulo8mpR2Eltxyv .image-shape .label,#mermaid-svg-NDulo8mpR2Eltxyv .icon-shape .label{text-align:center;}#mermaid-svg-NDulo8mpR2Eltxyv .node.clickable{cursor:pointer;}#mermaid-svg-NDulo8mpR2Eltxyv .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-NDulo8mpR2Eltxyv .arrowheadPath{fill:#333333;}#mermaid-svg-NDulo8mpR2Eltxyv .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-NDulo8mpR2Eltxyv .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-NDulo8mpR2Eltxyv .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-NDulo8mpR2Eltxyv .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-NDulo8mpR2Eltxyv .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-NDulo8mpR2Eltxyv .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-NDulo8mpR2Eltxyv .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-NDulo8mpR2Eltxyv .cluster text{fill:#333;}#mermaid-svg-NDulo8mpR2Eltxyv .cluster span{color:#333;}#mermaid-svg-NDulo8mpR2Eltxyv div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-NDulo8mpR2Eltxyv .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-NDulo8mpR2Eltxyv rect.text{fill:none;stroke-width:0;}#mermaid-svg-NDulo8mpR2Eltxyv .icon-shape,#mermaid-svg-NDulo8mpR2Eltxyv .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-NDulo8mpR2Eltxyv .icon-shape p,#mermaid-svg-NDulo8mpR2Eltxyv .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-NDulo8mpR2Eltxyv .icon-shape .label rect,#mermaid-svg-NDulo8mpR2Eltxyv .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-NDulo8mpR2Eltxyv .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-NDulo8mpR2Eltxyv .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-NDulo8mpR2Eltxyv :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 是

Client 收到 Report
report.conf_rev ==

本地记录的 conf_rev?
正常处理报告
ConfRev 变更!

本地映射可能失效
Write RptEna = false

禁用 RCB
重新读取 DatSet 成员列表

更新本地 Inclusion-bitstring 映射
更新本地 conf_rev
Write RptEna = true

重新使能
Write GI = true

触发总召唤获取全量状态

1.6.4 ConfRev 不一致时的告警与重订阅

当 Client 检测到 ConfRev 变化时,推荐的处理流程:

  1. 告警:记录"RCB 配置变更"事件,通知运维人员。
  2. 禁用 RCBWrite RptEna = false,停止报告流。
  3. 重新读取配置
    • 读取 RCB.ConfRev 获取最新版本号。
    • 读取 RCB.DatSet 获取关联的数据集引用。
    • 调用 GetDataSetDirectory 读取 DatSet 成员列表。
    • 更新本地的"Inclusion-bitstring 位 ↔ 成员引用"映射表。
  4. 更新本地 ConfRev:将本地记录同步为最新值。
  5. 重新使能Write RptEna = true
  6. 触发 GIWrite GI = true,获取全量当前值,弥补配置变更期间可能遗漏的数据。

最佳实践:健壮的 Client 应在每条报告回调中检查 ConfRev,将其作为报告处理的"前置校验"。忽略 ConfRev 检查是导致现场误报/漏报的常见根因。


1.7 小结

本专题从理论层面完整剖析了 IEC 61850 Report 机制的核心------报告控制块(RCB):

  1. Report 的价值:以事件驱动 + 服务端推送,解决轮询模式的延迟、带宽、负载三大痛点。
  2. RCB 属性全集:BRCB 与 URCB 两类实例,15 个属性,理解每个属性的语义是配置与排障的基础。
  3. 触发模型:dchg/qchg/dupd/IntgPd 四种触发条件的或关系,TrgOps 位图编码,dchg 与 dupd 的 CDC 对应。
  4. OptFlds:8 个可选字段的位图控制,不同场景的推荐组合与体积估算。
  5. 缓冲区状态机:BRCB 的禁用/使能/缓冲/发送/等待ACK/溢出六态流转,SqNum 回绕,EntryID 断线续传,PurgeBuf 风险,溢出处理。
  6. ConfRev 机制:DatSet 变更的版本保护,Client 检测不一致时的重订阅流程。

下期预告

IEC 61850 报告系列(二):Report 报文逐字段剖析 将从理论走向报文:

  • Report 在 MMS 协议栈中的位置与 informationReport 的 ASN.1 定义
  • 真实 Report 报文的十六进制逐字段标注
  • Inclusion-bitstring 机制与 listOfAccessResult 的对齐
  • Wireshark 抓取与分析 Report 的实战流程
  • 四种触发场景的报文对比与异常报文识别

参考标准

  • IEC 61850-7-2 §14: Report 服务与 RCB 属性定义
  • IEC 61850-7-2 §14.5: 触发条件(TrgOps)定义
  • IEC 61850-8-1: SCSM 映射到 MMS informationReport
  • IEC 61850-7-3: CDC 与默认触发位的对应关系

交叉引用

  • 主系列 Part 3 §3.2.5:Report 机制基础(本专题的深化基础)
  • 主系列 Part 4 §4.4:ReportControl 配置(专题 3 将工程化展开)
  • 专题 3:SCL 中的 ReportControl 配置------工程化设计
  • 专题 4:基于 pyiec61850-ng 的代码实现