跳到主要内容

边缘预处理

概述

云端带宽昂贵、延迟不可控, 现场决策又要求毫秒级响应, 所以原始数据不应直接上云。DarraRT 在 PLC 侧与 Service 侧共同实现边缘预处理: 过滤噪声、聚合降频、死区压缩、规则决策, 让本地先处理 90% 的事, 只把关键信息发到云端或 MES。

典型带宽压缩比: 原始 10Hz × 500 点 = 5000 点/s, 经过死区 + 1 分钟均值后, 降到约 8 点/s, 流量节省 600 倍

适用场景

场景原始输入边缘处理输出
温度监控10Hz 采样Kalman 去噪 + 死区1Hz 上云
振动分析1kHz ADCFFT + 均值 + P951 分钟汇总
计件生产光电脉冲防抖 + 累加每班次/每小时产量
报警判定温度/压力规则引擎本地停机 + 推送
预测维护电流/扭矩滑动窗特征特征向量上云

架构图

┌──────────────────── PLC ─────────────────────┐
│ OB1 (10ms) │
│ ├── 采集 → MW 区 │
│ ├── 过滤 (Kalman / 中值 / 低通) │
│ ├── 规则引擎 (IF-THEN 快速决策) │
│ └── 写回控制输出 │
│ │
│ OB20 (1s 周期中断) │
│ ├── 聚合 (avg / min / max / P95) │
│ ├── 死区判定 (与上次发送值比较) │
│ └── 写入 DB_Upload │
└────────────────────┬──────────────────────────┘
│ 共享内存
┌──────────▼───────────┐
│ Service 网关 │
│ (调度 / 压缩 / 重试) │
└──────────┬───────────┘
▼ MQTT / HTTP
云平台

前置条件

  • PLC 项目启用 OB20 周期中断 (默认 100ms, 支持降到 10ms)
  • 变量表中目标变量标注 Archive = True
  • Service 端开启 EdgeProcessor 模块

详细步骤

1. 过滤: Kalman 去噪

工业现场的传感器读数往往带高斯白噪声, Kalman 滤波在已知过程方差 Q观测方差 R 的情况下给出最优估计。

FUNCTION_BLOCK FB_Kalman1D
VAR_INPUT
rawValue : REAL;
Q : REAL := 0.001; // 过程噪声
R : REAL := 0.5; // 观测噪声
END_VAR
VAR_OUTPUT
filtered : REAL;
END_VAR
VAR
xEst : REAL; // 状态估计
pEst : REAL := 1.0; // 估计方差
k : REAL; // 卡尔曼增益
initDone : BOOL;
END_VAR

IF NOT initDone THEN
xEst := rawValue;
initDone := TRUE;
END_IF;

// 预测: x = x (假设常值模型), p = p + Q
pEst := pEst + Q;

// 更新
k := pEst / (pEst + R);
xEst := xEst + k * (rawValue - xEst);
pEst := (1.0 - k) * pEst;

filtered := xEst;

其他滤波器选型:

滤波适用缺点
中值滤波 (5/7 点)尖峰毛刺延迟半个窗口
低通 IIR (α=0.1)平滑缓变信号响应滞后
滑动均值固定噪声窗口内激烈变化会被抹平
Kalman最优 (已知模型)调参复杂

2. 聚合: 窗口统计

OB20 每秒计算一次上一窗口的 min / max / avg / P95。

FUNCTION_BLOCK FB_WindowStats
VAR_INPUT
newSample : REAL;
windowSize : INT := 600; // 600 个样本 = 1min@10Hz
END_VAR
VAR_OUTPUT
avg : REAL;
min : REAL;
max : REAL;
p95 : REAL;
END_VAR
VAR
buf : ARRAY[0..999] OF REAL;
idx : INT;
count : INT;
END_VAR

buf[idx] := newSample;
idx := (idx + 1) MOD windowSize;
IF count < windowSize THEN count := count + 1; END_IF;

// 仅在窗口满时计算
IF count = windowSize THEN
// ... 遍历 buf 求 min/max/avg/p95 (省略)
END_IF;

3. 压缩: 死区 / 摆动门

死区算法: 只有当新值相对上次发送值的绝对变化超过阈值, 才发送。

IF ABS(newValue - lastSent) > deadband THEN
uploadValue := newValue;
lastSent := newValue;
uploadFlag := TRUE;
END_IF;

更精细的摆动门 (Swing Door) 算法能保证重建误差 < epsilon, 压缩率比死区高 2-5 倍, 详见 Historian 章节。

4. 本地决策: 规则引擎

规则引擎把"IF...THEN" 抽象成可配置表, 非程序员也能改。

# rules.yaml
rules:
- id: overtemp_stop
when: "DB1.temperature > 80"
then:
- action: set_var
path: Q0.0
value: FALSE
- action: alarm
level: fatal
message: "超温紧急停机 T={{DB1.temperature}}℃"
cooldown_s: 60

- id: pressure_warn
when: "DB1.pressure > 1.5 and DB1.pressure < 1.8"
then:
- action: log
level: warn
message: "压力接近上限"

- id: predictive_wear
when: "stats.current.p95 > 12.0 and stats.current.avg > 9.0"
then:
- action: mqtt_publish
topic: factory/line1/alert/wear
payload: '{"current_p95": {{stats.current.p95}}}'

规则引擎在 Service 中解析并挂到 PLC 的变量订阅上, 本身不进入 PLC 扫描周期, 以免影响确定性。 确实需要进入扫描周期的硬停机规则 (如超温), 应该作为 SCL 代码写进 OB1, 规则引擎只做软告警和数据面决策。

5. OB1 / OB20 周期配合

// OB1 (10ms 周期, 决定性高)
temp_raw := IO_Read_AI(1);
temp_filtered := FB_Kalman1D(rawValue := temp_raw);

// 硬规则: 必须在 OB1 立即响应
IF temp_filtered > 85.0 THEN
Q_Heater := FALSE;
StartAlarm(ALARM_OVERTEMP);
END_IF;

// OB20 (1s 周期中断, 不影响 OB1)
stats := FB_WindowStats(newSample := temp_filtered);
IF ABS(stats.avg - lastSentTemp) > 0.5 THEN
DB_Upload.temp_avg := stats.avg;
DB_Upload.temp_p95 := stats.p95;
DB_Upload.ts := SystemTime_Ms();
lastSentTemp := stats.avg;
END_IF;

参数调优表

参数默认调优依据
Kalman Q0.001信号越平稳越小
Kalman R传感器方差查数据手册
滑动窗大小600 (@10Hz=1min)按报表周期
死区阈值精度的 2 倍满足统计需求即可
OB20 周期1000 ms高频 10-100ms, 低频可 5000
规则冷却60 s防止频繁触发

排错

现象原因措施
OB1 超时在 OB1 跑聚合了把聚合挪到 OB20
云端数据抖动大死区太小 / 滤波弱加大死区或换 Kalman
报警漏触发规则在软引擎, 扫描周期没进硬停机改成 SCL 代码进 OB1
P95 一直 0窗口没填满count = windowSize 才有值

高级技巧

  1. 自适应死区: 值越大死区越大, 按量程的 0.1% 动态调整
  2. 特征工程: 滑动窗输出 mean/std/kurtosis/fft_peak 给云端 ML 模型用
  3. 多级聚合: 1s → 1min → 1h, 逐级降采样上云, 本地保留高分辨率
  4. 事件驱动: 状态变化才发, 稳态不发
  5. 时间对齐: 所有聚合窗以整秒/整分对齐, 方便跨点合并

相关文档