diff --git a/docs/DCS点表需求模板.md b/docs/DCS点表需求模板.md new file mode 100644 index 0000000..0bf4992 --- /dev/null +++ b/docs/DCS点表需求模板.md @@ -0,0 +1,139 @@ +# DCS 点表需求模板(点位 / 量纲 / 采样率字段规范) + +> 对应 EPIC #2「[M1] 数据准备」子任务 **#16**(0.5d): +> 编制向客户 DCS 系统收集点位需求的标准化模板,字段规范对齐 +> PRD 5.1「① 边缘采集网关」CSV 字段规范与内核点位字典 schema +> (`core/edge-gateway/config/point_dict.example.csv`)。 +> +> 交付后由实施工程师按本模板收集客户点表 → 配置台导入校验 → +> 推送边缘网关加载只读采集(PRD 5.1 用户操作流程)。 + +--- + +## 1. 文档目的 + +在 M1 数据准备阶段,向客户(车间/仪表/自动化人员)收集 **DCS/PLC 点位需求**, +作为点位字典(`point_dict.csv`)的输入来源。本模板统一: + +- **点位**(point):需要采集的工艺测点(温度/压力/流量/液位/状态等); +- **量纲**(unit):每个测点的计量单位(℃/kPa/m³/h/%/Hz 等); +- **采样率**(sampleRate):每个测点的采集周期(毫秒)。 + +字段规范与平台内核**一一对应**,客户按模板填写后可直接导入校验,避免 +人工翻译造成的字段漂移。 + +--- + +## 2. DCS 系统对接信息(每套系统填写一份) + +| 字段 | 说明 | 示例 | +| --- | --- | --- | +| 系统名称 | DCS/PLC 系统名称 | 沸腾氯化车间和利时 DCS | +| 厂家/型号 | 设备厂家与系列 | 和利时 DCS / 西门子 S7-1200 | +| 软件版本 | 系统软件版本 | HOLLiAS-M 3.2 | +| 数据接口 | 支持的数据接口 | OPC UA / OPC DA / S7 协议 | +| OPC 服务器 | OPC 服务器地址(如可用) | opc.tcp://10.20.1.10:4840 | +| 网络隔离要求 | 采集网与办公网隔离方式 | 单向网闸 / 只读镜像(见 #27) | +| 对接负责人 | 客户侧接口人 | 王工(仪表科) | + +> 采集侧**严格只读、不反控**(PRD 5.1 验收:零控制指令下发), +> 网络拓扑隔离方案见子任务 #19「现场勘查采集网/工业环网/办公网拓扑与隔离策略」。 + +--- + +## 3. 点位需求表字段规范 + +客户按下表逐列填写(**表头与内核点位字典 CSV 完全一致**,可整表复制为 CSV): + +| 字段 | 类型 | 约束 | 说明 | 示例 | +| --- | --- | --- | --- | --- | +| device_id | string | 必填,唯一 | 设备编号(车间-设备) | CLF-01 | +| point_id | string | 必填,唯一 | 测点编号(设备.测点) | CLF-01.TEMP | +| name | string | 必填 | 测点中文名 | 炉温 | +| unit | enum | 必填 | 量纲(见 §4 量纲字典) | ℃ | +| dataType | enum | 必填 | float / int / bool | float | +| sampleRate | int | 必填,>0 | 采集周期(毫秒) | 1000 | +| qualityCode | bool | 默认 true | 是否启用质量码 | true | +| opcNode | string | 选填 | OPC UA 节点路径 / PLC 地址 | ns=2;s=CLF.Temp | +| protocol | enum | 必填 | opcua / s7 / modbus / weighing / energy / manual | opcua | + +**字段说明** + +- `device_id`:建议「车间/系统前缀 + 序号」,如 `CLF-01`(氯化炉 1#)、`S7-01`(PLC 站 1#); +- `point_id`:全局唯一,建议「`device_id.测点缩写`」,如 `CLF-01.TEMP`; +- `sampleRate`:按测点重要性分级填写(见 §5 采样率分级); +- `opcNode`:OPC UA 用节点路径(`ns=2;s=...`);S7 用数据块地址(`DB100.0.0`); + 称重/能源表用寄存器地址(`holding:40001`);人工录入(manual)可留空; +- `qualityCode`:开启质量码后,采集侧附带质量位(坏值/不确定值),平台按质量位过滤。 + +--- + +## 4. 量纲字典(unit 枚举) + +| 类别 | 允许值 | +| --- | --- | +| 温度 | ℃ | +| 压力 | kPa、MPa、Pa | +| 流量 | m³/h、t/h、L/min、m³/s | +| 液位/料位 | %、m、mm | +| 转速/频率 | rpm、Hz | +| 电气 | kW、kWh、A、V | +| 重量 | kg、t、g | +| 质量指标 | %、mmol/g(化验人工录入) | +| 状态 | bool(0/1、开/关) | + +> 不在上表的单位需在「备注」列说明并请平台配置台确认后再扩展。 + +--- + +## 5. 采样率分级建议(sampleRate) + +| 级别 | 周期 | 适用测点 | +| --- | --- | --- | +| 高速 | 100 ms | 关键工艺控制点(炉温、炉压) | +| 常规 | 1000 ms(1 Hz) | 一般工艺参数(流量、液位、转速)——PRD 5.1 验收基线:600 点位 1Hz | +| 低频 | 5000–10000 ms | 缓慢变化量(储罐液位、环境温度) | +| 化验/人工 | 60000 ms 或按批次 | 质量指标(交联度、交换容量、钛纯度)等人工录入或 LIMS 对接 | + +> 采样率需综合点位数量与链路容量评估:验收目标为 P99 ≤ 1.8s、丢失率 ≤ 0.02%(PRD 5.1), +> 点位过多时可先按「关键点位」子集接入,其余低频轮询。 + +--- + +## 6. 填表示例(Template-Ti 一期 · 氯化车间) + +| device_id | point_id | name | unit | dataType | sampleRate | qualityCode | opcNode | protocol | +| --- | --- | --- | --- | --- | --- | --- | --- | --- | +| CLF-01 | CLF-01.TEMP | 炉温 | ℃ | float | 1000 | true | ns=2;s=CLF.Temp | opcua | +| CLF-01 | CLF-01.PRES | 炉压 | kPa | float | 1000 | true | ns=2;s=CLF.Pres | opcua | +| CLF-01 | CLF-01.FEED | 进料量 | t/h | float | 1000 | true | ns=2;s=CLF.Feed | opcua | +| S7-01 | S7-01.PUMP_A | 泵A频率 | Hz | float | 1000 | true | DB100.0.0 | s7 | +| W-01 | W-01.WT | 称重值 | kg | float | 1000 | true | holding:40001 | weighing | +| E-01 | E-01.PWR | 电表功率 | kW | float | 1000 | true | holding:40010 | energy | +| LAB-01 | LAB-01.TI_PURITY | 钛纯度 | % | float | 60000 | true | —(人工录入) | manual | + +--- + +## 7. 填写规范与常见错误 + +| 规范 | 常见错误 | 处理 | +| --- | --- | --- | +| `point_id` 全局唯一 | 跨设备重复命名 | 配置台导入校验拒绝并提示 | +| `unit` 使用量纲字典 | 自定义单位(如 "度") | 归一化为 ℃ 或先申请扩展 | +| `sampleRate` 为大于 0 的整数 | 空值/0/小数 | 校验拒绝,按分级建议补填 | +| `device_id` 与现场标识一致 | 随意编号 | 与客户确认设备位号后再填 | +| 重复/冗余测点 | 同一物理量多张表重复 | 合并,保留唯一 `point_id` | +| 高危信号(联锁/停机) | 误标为普通测点 | 平台按「只读采集 + 告警」处理,严禁反控 | + +--- + +## 8. 交付与校验 + +1. 实施工程师向客户发出本模板(可与《数据准备清单》#18 同步发出); +2. 客户按 §2–§6 填写后回传(Excel/CSV 均可); +3. 配置台**导入校验**:设备/测点完整性、字段类型、单位枚举、采样率合法性; +4. 校验通过 → 生成点位字典 CSV → 推送边缘网关加载 → 启动只读采集; +5. 采集健康度(丢失率/P99)实时回传驾驶舱。 + +> 若客户点表延迟或字段不完整:先启用**缺省通用点位集**(EPIC #20)演示, +> 仅接入已确认点位(PRD 13 章数据依赖风险缓解策略)。 diff --git a/docs/_check_dcs_template.py b/docs/_check_dcs_template.py new file mode 100644 index 0000000..e9d22c3 --- /dev/null +++ b/docs/_check_dcs_template.py @@ -0,0 +1,79 @@ +# -*- coding: utf-8 -*- +"""DCS 点表需求模板(docs/DCS点表需求模板.md)与内核点位字典 schema 一致性检查。 + +检查项: +1. 文档 §3「点位需求表字段规范」表中的字段名(第一列)与内核 + `core/edge-gateway/config/point_dict.example.csv` 表头**完全一致**; +2. 文档中的量纲字典与填表示例单位均在内核示例出现过的类别内(人工抽查,仅告警); +3. 文档引用到的内核文件路径存在。 + +用法:python _check_dcs_template.py +""" +import csv +import os +import re +import sys + +HERE = os.path.dirname(os.path.abspath(__file__)) +REPO_ROOT = os.path.dirname(HERE) + +DOC_PATH = os.path.join(HERE, "DCS点表需求模板.md") +CSV_PATH = os.path.join(REPO_ROOT, "core", "edge-gateway", "config", + "point_dict.example.csv") + + +def doc_field_table_columns() -> list: + """抽取文档 §3 字段规范表的字段名(Markdown 表格第一列)。""" + lines = [ln.strip() for ln in open(DOC_PATH, "r", encoding="utf-8").readlines()] + fields = None + i = 0 + while i < len(lines): + line = lines[i] + if line.startswith("|") and line.strip("|").split("|")[0].strip() == "字段": + header_cells = [c.strip() for c in line.strip("|").split("|")] + if "类型" not in header_cells: # §3 特征:字段规范表含"类型"列 + i += 1 + continue + sep = lines[i + 1] if i + 1 < len(lines) else "" + if all(re.fullmatch(r":?-{3,}:?", c.strip()) + for c in sep.strip("|").split("|")): + j = i + 2 + rows = [] + while j < len(lines) and lines[j].startswith("|"): + cells = [c.strip() for c in lines[j].strip("|").split("|")] + if cells and cells[0]: + rows.append(cells[0]) + j += 1 + fields = rows + break + i += 1 + return fields or [] + + +def main() -> int: + failures = [] + + # 1) 文档字段规范与内核 CSV 表头一致 + with open(CSV_PATH, "r", encoding="utf-8") as fh: + csv_header = [c.strip() for c in next(csv.reader(fh))] + doc_fields = doc_field_table_columns() + if doc_fields != csv_header: + failures.append( + f"文档字段 {doc_fields} 与内核 CSV 表头 {csv_header} 不一致") + + # 2) 文档引用文件存在 + for ref in ("core/edge-gateway/config/point_dict.example.csv",): + if not os.path.isfile(os.path.join(REPO_ROOT, ref)): + failures.append(f"引用文件缺失:{ref}") + + if failures: + print("FAIL") + for f in failures: + print(" -", f) + return 1 + print(f"OK: 文档字段规范与内核 schema 一致({len(csv_header)} 列),引用完整") + return 0 + + +if __name__ == "__main__": + sys.exit(main())