2. 报警泛滥基线指标计算与可视化
指标口径与计算逻辑
基线计算的第一步不是写代码,而是把 EEMUA 191 与 ISA 18.2 的指标口径固定下来,否则同一份数据在不同人手里会算出不同结果。本例采用以下约定:
- 统计窗口:以 1 小时为基本统计粒度,按 24 小时汇总日均值;所有时间均为平台本地时间,且已在前一例完成时间对齐。
- 报警率(Alarm Rate):窗口内新产生的报警条数 ÷ 窗口小时数,单位「条/小时/操作员」。只统计首次进入报警状态的记录,重复刷新不计入。
- 峰值率(Peak Rate):所有 1 小时窗口中报警率的最大值,用于识别短时冲击。
- 持续报警数(Standing Alarms):在统计时刻仍处于激活状态、且已持续超过 1 小时的报警数量(按报警点去重,不按条数)。
- 抖动报警数(Chattering Alarms):在 1 小时内同一报警点激活次数 ≥ 3 次的报警点数量。
EEMUA 191 给出的可接受区间为:平均报警率 ≤ 6 条/小时/操作员(可接受),峰值率 ≤ 12 条/小时;ISA 18.2 进一步建议 10 分钟窗口内 ≤ 10 条。本例以「平均率 ≤ 6、峰值率 ≤ 12、持续报警 ≤ 10、抖动报警 ≤ 5」作为基线判定的四条阈值线。
从标准化数据到指标:一段可运行的实现
假设前一例输出的标准化数据为 alarms.csv,字段包括 tag(报警点标识)、priority、system(工艺系统)、ts_active(激活时间)、ts_clear(恢复时间,未恢复为空)。下面用 Python 完成四项指标计算与基线报告生成。
import pandas as pd
import numpy as np
# 1. 读取并规整
df = pd.read_csv("alarms.csv", parse_dates=["ts_active", "ts_clear"])
df = df.dropna(subset=["ts_active"]).sort_values("ts_active").reset_index(drop=True)
# 2. 报警率:按小时统计新产生报警条数
df["hour"] = df["ts_active"].dt.floor("h")
hourly = df.groupby("hour").size().rename("count")
# 补齐无报警的小时,避免均值被低估
full_idx = pd.date_range(hourly.index.min(), hourly.index.max(), freq="h")
hourly = hourly.reindex(full_idx, fill_value=0)
avg_rate = hourly.mean() # 平均报警率(条/小时)
peak_rate = hourly.max() # 峰值率
peak_hour = hourly.idxmax() # 峰值出现时段
# 3. 持续报警:统计时刻仍激活且持续 > 1h 的报警点(去重)
now = df["ts_active"].max()
active = df[df["ts_clear"].isna() | (df["ts_clear"] > now)]
standing = active[active["ts_active"] < now - pd.Timedelta(hours=1)]
standing_count = standing["tag"].nunique()
# 4. 抖动报警:1 小时内同一 tag 激活 >= 3 次
df["hour"] = df["ts_active"].dt.floor("h")
chatter = (df.groupby(["tag", "hour"]).size()
.reset_index(name="n")
.query("n >= 3"))
chatter_count = chatter["tag"].nunique()
# 5. 基线报告
report = pd.DataFrame({
"指标": ["平均报警率", "峰值率", "持续报警数", "抖动报警数"],
"计算值": [round(avg_rate, 2), peak_rate, standing_count, chatter_count],
"阈值": [6, 12, 10, 5],
})
report["判定"] = np.where(report["计算值"] > report["阈值"], "超限", "正常")
print(report.to_string(index=False))
print(f"峰值时段: {peak_hour}")
这段代码的关键点在于:补齐空小时(否则平均率会被高估)、持续报警按 tag 去重(同一报警点反复刷新不应重复计数)、抖动按 tag+小时分组(保证「1 小时内 ≥ 3 次」的口径)。运行后得到一张四行判定表,并输出峰值时段,用于下一步定位泛滥时段。
基线可视化:把「超限」落到时间轴上
仅有汇总数字不足以定位问题。下图把 24 小时报警率曲线、四条阈值线、峰值时段与持续/抖动报警的分布放在同一视图中,使「哪几个小时泛滥、由哪类指标驱动」一目了然。
图中可以读出三条结论:其一,04:00–07:00 出现连续三个小时的报警率超过平均阈值,其中 05:00 达到 14 条/小时,突破峰值阈值 12,是本次基线中最明确的泛滥时段;其二,持续报警数 13 个超过阈值 10,说明存在一批长期未恢复的报警点,需要结合设备清单进一步定位;其三,抖动报警数 4 个在阈值内,暂不构成主要矛盾。这三条结论直接决定后续治理的优先级:先处理 05:00 前后的短时冲击源,再清理持续报警。
基线报告的结构与判读
把上述计算与可视化固化为一份可复用的基线报告,建议包含以下字段,便于跨班次、跨平台对比:
| 字段 | 示例值 | 判读要点 |
|---|---|---|
| 统计窗口 | 2024-03-12 00:00–24:00 | 必须与数据对齐后的本地时间一致 |
| 平均报警率 | 5.8 条/h | ≤ 6 为可接受,接近阈值需关注趋势 |
| 峰值率 / 时段 | 14 条/h @ 05:00 | > 12 即超限,需定位冲击源 |
| 持续报警数 | 13 个 | > 10 需输出按设备分组的清单 |
| 抖动报警数 | 4 个 | > 5 需检查死区与滤波设置 |
| 泛滥时段 | 04:00–07:00 | 连续超限小时段,作为治理切入点 |