3. SCADA实时数据采集与数据库接入

SCADA 系统的数据采集层,本质上是把现场设备中不断变化的物理量,转换成数据库能够长期存储、查询和分析的结构化记录。这个过程涉及三个关键决策:用什么协议把数据取回来、以多快的频率取、取回来之后分别写进哪一类数据库。三者互相牵制——协议决定单次采集的时延与可寻址范围,采集频率决定数据量与实时库压力,而实时库与关系库的边界划分则决定后续查询、报表与历史追溯的成本。

一、三类主流协议的解析差异

OPC UA、Modbus、IEC 60870-5-104 在数据模型、寻址方式和传输语义上差异明显,直接决定了采集程序的写法。

OPC UA 是面向对象的地址空间模型。每个变量由 NodeId 唯一标识,例如 ns=2;s=Boiler1.Temp,其中 ns=2 是命名空间索引,s= 表示字符串型标识符。客户端通过订阅(Subscription)机制注册感兴趣的点位,并设置 PublishingInterval(发布周期)和 SamplingInterval(采样周期)。服务端只在数据变化超过 Deadband(死区)时才推送,因此 OPC UA 天然适合“变化上报”型采集,而不是盲目轮询。读取时返回的 StatusCode 必须判断,Good 才写入数据库,Bad 或 Uncertain 应记录质量戳而非直接丢弃。

Modbus 是典型的寄存器寻址模型,没有语义,只有地址。常见四类区域:线圈(0x)、离散输入(1x)、输入寄存器(3x)、保持寄存器(4x)。例如读取保持寄存器 40001 起始的 10 个寄存器,功能码 03,从站地址 1,报文为 01 03 00 00 00 0A C5 CD。Modbus 是主从轮询,必须由采集端主动发起,因此采集频率直接等于轮询周期。浮点数需要两个寄存器拼接,且存在大小端(ABCD/CDAB/BADC/DCBA)问题,配置错误会得到完全错误的数值,这是现场最常见的接入故障之一。

IEC 104 用于电力调度,采用 ASDU(应用服务数据单元)结构,通过类型标识区分遥测(M_ME_NC_1,短浮点)、遥信(M_SP_NA_1,单点)、遥控等。它支持总召唤(C_IC_NA_1)和变化上送(COS),并带有传送原因(COT)字段,如 3 表示突发、20 表示响应总召唤。IEC 104 的时标是 CP56Time2a 七字节格式,接入时必须正确解析,否则历史曲线时间轴会整体偏移。

三类协议采集链路与数据落库边界 现场设备 / 控制器 PLC / 变频器 Modbus TCP/RTU DCS / 智能仪表 OPC UA Server 保护 / 测控装置 IEC 60870-5-104 电表 / 环境传感器 Modbus RTU 485 边缘网关 协议转换 / 缓存 采集服务(Collector) OPC UA 客户端 Subscription + Deadband StatusCode 质量判断 Modbus 轮询器 功能码 03/04 批量读 字节序 ABCD/CDAB 解析 IEC 104 客户端 总召唤 + COS 变化上送 CP56Time2a 时标解析 统一数据模型 点位ID / 值 / 质量戳 采集时间 / 源时间 实时库(内存/时序) 当前值 + 短周期历史 秒级~分钟级 高频写入、低延迟读 保留 7~30 天 面向画面刷新 / 报警 典型:Redis / InfluxDB 关系库(业务/归档) 点位台账 + 统计结果 分钟/小时/日聚合 低频写入、复杂查询 长期保留(年) 面向报表 / 能耗分析 典型:PostgreSQL / MySQL 高频直写 聚合后写入 边界划分原则 ① 秒级原始值 → 实时库 ② 分钟聚合值 → 关系库 ③ 点位台账 → 关系库 ④ 报警事件 → 关系库 ⑤ 画面刷新 → 读实时库 ⑥ 报表统计 → 读关系库 ⑦ 质量戳必须随值存储 ⑧ 时间戳统一 UTC 存储 ⑨ 死区过滤减少写入量 ⑩ 断线补传避免数据空洞 避免: 高频原始值直写关系库 导致表膨胀与查询变慢

二、采集频率设计

采集频率不是越高越好。频率由三个因素共同决定:工艺变化速度、控制/报警响应要求、以及数据库写入能力。经验上,温度、液位等慢变量 1~5 秒一次即可;电流、功率等电气量 200 ms~1 s;开关量变位需要毫秒级捕获,但应采用“变化上送”而非高频轮询。

以 1000 个模拟量点位为例,若每点每秒采集一次,实时库写入速率为 1000 点/秒,一天约 8640 万条记录。若改为 5 秒一次并启用死区过滤(如温度死区 0.2℃),实际写入量通常可下降 60%~80%。关系库则不应接收这个量级,而应通过定时任务把实时库数据按分钟聚合后写入,例如每分钟计算平均值、最大值、最小值,一天仅 1440 条/点。

采集周期与发布周期要匹配:OPC UA 的 SamplingInterval 应小于等于 PublishingInterval,否则会出现“采样了但没发布”的无效配置。Modbus 轮询周期必须大于单次报文往返时间,否则会堆积超时。

三、实时库与关系库的边界划分

边界划分的核心判断标准是“访问模式”,而不是“数据新旧”。实时库面向高频写入、按时间点快速读取、保留期短;关系库面向结构化查询、聚合统计、长期归档。具体可遵循以下分工:

  • 实时库:当前值快照、秒级原始历史、报警状态、画面刷新数据源。保留 7~30 天,超期自动降采样或删除。
  • 关系库:点位台账(点位 ID、名称、单位、量程、所属设备)、分钟/小时/日聚合值、报警事件记录、操作日志、报表配置。长期保留。

一个常见错误是把所有原始秒级数据直接写入关系库。以 PostgreSQL 为例,单表日增千万行后,即使有索引,按时间范围查询也会明显变慢,且磁盘增长迅速。正确做法是实时库承担高频写入,关系库只接收聚合结果和业务数据。

四、数据接入实战示例

假设需要接入一台锅炉的 3 个点位:炉温(Modbus 保持寄存器 40001,浮点 ABCD)、压力(OPC UA NodeId ns=2;s=Boiler1.Press)、运行状态(IEC 104 遥信,信息体地址 0x4001)。采集周期统一设为 1 秒,死区:温度 0.2℃,压力 0.01 MPa。

Modbus 读取报文构造:从站 1,功能码 03,起始地址 0,数量 2,得到 4 字节后按 ABCD 解析为 float。OPC UA 建立 Subscription,PublishingInterval=1000ms,SamplingInterval=500ms,MonitoredItem 设置 Deadband=0.01。IEC 104 启动后先发总召唤,收到 COT=20 的响应后进入变化上送模式。

采集服务把三个点位统一为如下结构写入实时库:

{
  "point_id": "BOILER1_TEMP",
  "value": 186.4,
  "quality": "Good",
  "ts_source": "2025-03-11T08:15:22.000Z",
  "ts_collect": "2025-03-11T08:15:22.180Z"
}

随后由聚合任务每分钟从实时库读取,计算 avg/max/min 写入关系库表 boiler_1min。判断接入是否成功的依据:实时库中点位值随现场变化而更新、质量戳为 Good、关系库分钟表在整分钟后出现对应记录、时间戳无整体偏移。若发现数值明显异常(如温度 1.8e38),优先检查 Modbus 字节序;若时间戳偏移 8 小时,检查 IEC 104 时标是否按 UTC 解析。

接入调试阶段建议先关闭死区过滤,确认原始值正确后再启用,否则死区会掩盖字节序或量程错误。同时应记录每个点位的源时间与采集时间,便于排查网络延迟与设备时钟偏差。

完成上述配置后,SCADA 的数据链路即形成“协议采集 → 统一模型 → 实时库高频写入 → 聚合任务 → 关系库长期存储”的闭环。后续的画面刷新、报警判断、能耗报表都建立在这条链路之上,因此协议解析的正确性、采集频率的合理性、以及两库边界的清晰度,直接决定整个能源管理系统的稳定性与可维护性。