tahovig/poc-emstime
GitHub: tahovig/poc-emstime
面向亚秒级电网时间序列数据的 Python 机器学习管线,用于检测卫星时钟和 GPS 时序故障异常。
Stars: 0 | Forks: 0
# poc-emstime — 电网时间异常检测
一个针对亚秒级电网时间序列数据的 Python ML pipeline。接收真实的 micro-PMU (µPMU) 同步相量数据,合成带有标签的时间故障异常(GPS 抖动、信号丢失、时钟步进偏移、时间质量标志损坏),构建滚动/间隙感知特征,并使用 Isolation Forest 异常检测器根据注入的 ground truth 进行评分。
这是支持从软件工程转向网络安全工程的一系列作品集项目中的第四个(参见 `poc-osint`、`poc-logids`、`poc-scada`)。长期目标:将此应用于电网时间同步基础设施的卫星时钟(GPS)异常检测。当前阶段仅包含数据和模型——有关完整背景,请参阅 `CLAUDE.md`;有关数据集来源和 schema,请参阅 `data/README.md`。
## 状态
阶段 1(数据 + 模型,无应用/报告层)已完成:`ingest.py`、`faults.py`、`features.py`、`model.py`、`evaluate.py`、`pipeline.py`,17 个单元测试 + 1 个集成测试,全部通过。已针对约 1.13 小时的真实 LBNL µPMU 数据进行了验证(参见下方的结果),而不仅仅是合成测试数据。
## 设置
```
cd code
python3 -m venv poc-emstime-venv
source poc-emstime-venv/bin/activate
pip install -e ".[dev]"
pytest
```
真实数据未提交(`data/raw/` 已被 gitignore,文件大小达数百 MB)。请使用 `data/fetch.sh ` 获取——有关文件列表和确认的 schema,请参见 `data/README.md`。
## 结果(真实数据)
针对约 1.13 小时真实的 LBNL `a6_bus1` 数据(以 120Hz 频率的 487,640 行:真实的 `L1MAG` 电压幅值 + 真实的 `LSTATE` 作为 TQ 列)运行了 `pipeline.run()`,并分别注入了每种类型的故障。每种故障类型的检测率(recall):
| fault type | detected |
|---------------------|----------|
| `timestamp_jitter` | 100% |
| `tq_corruption` | 100% |
| `dropout` | 0% |
| `clock_step` | 0% |
总体:precision 0.12%,recall 60%,F1 0.25%(`contamination=0.01` 标记了所有 487,640 行数据中约 1% 的行——大多数标记是数据中真实的电气事件,而不是属于注入故障的那约 16 行,因此针对*此*合成 ground truth 的 precision 预计会很低;这并不意味着那些其他被标记的行在现实中是误报)。
**两个真实的发现,尚未通过调参掩盖:**
1. **IsolationForest 默认的行二次采样使得罕见故障几乎不可见。** sklearn 默认的 `max_samples='auto'` 将每棵树的训练二次样本限制在 256 行。面对 487,640 行数据,一个 3-4 行的故障被分入任何给定树的二次样本的几率不到 1/500——因此几乎没有树学会围绕它进行分割。即使对于距离基线约 400 个标准差的 TQ 标志损坏,这也同样成立。通过在 `model.py` 中将 `max_samples` 提高到完整数据集证实了这一点,该操作将 `timestamp_jitter`/`tq_corruption` 的检测率从 0% 提升到了 100%。按原样无法扩展到完整的多日数据集(100 棵树 x 数百万行)——未来的工作应改用分层/加权采样。
2. **`dropout` 和 `clock_step` 仍然未被检测到——已找到根本原因,但尚未修复。** `ffill_limit` 下方的短间隙仍然会在值列中留下真实的 `NaN`,这些 `NaN` 会传播到每个滚动特征的接下来 `window - 1` 行中(`rolling(10)` 会触及它之前的 9 行)。随后,`dropna(subset=feature_cols)` 会直接删除这些行——包括间隙证据(`Time_Delta_ms` 飙升至标称值的约 5 倍)最明显的那一行。异常是真实且巨大的,但在模型看到它之前就被删除了。修复此问题(例如,将 `Time_Delta_ms` 从滚动 NaN 驱动的删除中排除,或者在重建索引/`Was_Filled` 的行上评估间隙检测,而不是依赖 `dropna` 的幸存行)被规划为后续工作,此处未进行修补以避免夸大上述数字。
标签:Apex, PKINIT, Python, 安全规则引擎, 工控安全, 异常检测, 数据管道, 无后门, 时间序列分析, 机器学习, 软件工程, 逆向工具