跨平台 VOCs 色谱工作站重构开发文档(边缘节点 + 云平台)
目标与约束
本次重构目标是将现有 Windows 工作站升级为跨平台(Linux/macOS/Windows)可运行的“边缘节点工作站”,并为后续云平台化做准备。
约束与已确认前提:
- 采集层:与色谱仪的连接使用网口协议(TCP),无需依赖 Windows 专有驱动。
- 报表层:不需要复刻原系统的 Word/Excel 互操作与复杂报表,允许使用新语言重新实现简单报表。
- 算法一致性:重构版本需要严格参考现有 Windows 版本的分析逻辑。对关键输出(RT/面积/峰高/峰数/定量结果),需在约定的误差阈值内与基线一致,并通过固定数据集的对照测试持续回归。
- UI:不复刻原 WinForms/DevExpress 界面;只需实现谱图展示与标定/套峰交互达到同等效果。
- 技术选型:分析内核使用 Go;未来要支持云平台化(方法下发、结果上报、云端重算)。
现有版本流程复盘(用于迁移对照)
现有版本已经实现“TCP 采集 → 实时显示 → 自动保存 → 停止后分析并打开谱图”的闭环链路。关键路径如下:
- 启动 TCP Server:
FormMain.StartTcpServer(),创建采集端口25001与相关端口502/503。 - 采集数据接收与解析:
TcpServerSocket.OneDataReceive()→AnalyseReceivedData()。 - 开始/停止采集:UI 发送 cmd 22/23;应答
Answer150/146将Signal.simple=true进入采集态;Answer147触发StoptAllGather()保存。 - 实时曲线:采集包处理过程中调用
Signal.AddDots(...)增长点列;ChromAcqCtrl.timer_0_Tick定时Refresh()触发绘制。 - 落盘与分析:
TcpServerSocket.Save(...)构建Chromatogram,调用Chromatogram.Process(...)完成积分/结果计算,然后落盘.sda;若启用StopAutoAlalyse则自动打开谱图窗体。
迁移策略:保留“采集→显示→周期结束保存→分析→标注结果”的用户体验,但在新架构中拆分为独立模块与统一数据契约。
总体架构(边缘节点 + 可云化)
边缘节点建议按“采集 / 分析 / UI”三层解耦,可部署为多进程或同进程多模块:
- 采集服务(TCP Ingest)
- 连接色谱仪(TCP),协议解析、重连、心跳。
- 将原始数据流切片为“一个测量周期”的谱图记录。
- 本地落盘:同步生成 XML + JSON。
- 对外发布:向本地 UI 推送实时点列/周期结束事件(WebSocket/IPC)。
- 分析内核(Analyzer Core,Go)
- 输入:谱图记录(trace)+ 方法(method)。
- 输出:分析结果(result)。
- 对外形式:
- 库模式(in-process):低延迟。
- 服务模式(out-of-process):HTTP/gRPC,利于云化与多 UI。
- UI
- Realtime Monitor:实时展示、选择方法、周期结束自动分析并标注结果。
- Method Editor:离线打开谱图、标定套峰、保存方法版本。
数据标准与文件格式(XML + JSON)
谱图 XML(已存在行业标准)
示例结构:
约定:
- X 轴生成规则(统一):
dt = TimeSpan / Datas.Count(单位秒)- 第
Seq=i点时间:t[i] = i * dt
Pollutants允许为空,表示未标定。
JSON(推荐的通用格式)
JSON 与 XML 同源,建议将点序列展开为数组以提升性能:
说明:
code是环保因子编码(如a05002),name是因子名称(如“总烃/甲烷”)。- 结果换算系数(如 k/b)不与“因子编码/名称”混用,单独放在 method 的 quant 区。
方法(标定)与套峰分析
业务流程
- 标定(Method Editor):
- 打开历史谱图(XML/JSON)。
- 对每个污染物(因子)框选套峰窗口:
StartTime/EndTime。 - 配置漂移鲁棒参数(padding、对齐策略)与基线策略。
- 保存为方法文件(JSON + XML),并做版本化(method_id/version)。
- 实时分析(Realtime Monitor):
- 采集服务持续输出实时点列;UI 实时绘制。
- 每个周期结束后自动:
- 写入 trace(XML/JSON)。
- 使用已选择的方法调用分析内核生成 result。
- UI 将污染物窗口与结果(RT/面积/高度/状态)叠加标注。
漂移补偿(“套峰加峰宽”)
目的:周期性测量时 RT 小漂移导致窗口切峰不准。
机制建议同时具备:
- 窗口扩展:左右各加
paddingS,扩大积分范围。 - 窗口对齐:在扩展窗口内找峰顶(peakmax),并可选将窗口中心向峰顶对齐(限制最大平移量)。
默认推荐:alignMode=peakmax + 适度 paddingS。
目标积分(Targeted Integration)算法最小闭环
对每个污染物(code)执行:
- 取窗口:
[startS-paddingS, endS+paddingS](裁剪到[0, timeSpan])。 - 峰顶:窗口内取最大值点(正峰)或按配置支持负峰。
- 基线:默认用窗口两端点连线(linear_endpoints);可选 robust_endpoints。
- 面积:对
max(0, y-baseline)做梯形积分;高度:峰顶相对基线高度;RT:峰顶时间。 - 缺峰判定:
max_height < threshold→not_detected。
该模式与“全谱自动检峰”解耦,适合云端批处理与现场稳定运行。
模块拆分与职责
边缘节点
采集服务
- 输入:TCP 数据流(仪器协议)。
- 输出:实时点列推送;周期 trace(XML/JSON)落盘;周期结束事件;可选上报云端。
分析服务/库(Go)
- 输入:trace + method。
- 输出:result(JSON,必要时可输出 XML)。
Realtime Monitor UI
- 实时曲线;选择 method;周期结束自动分析;叠加标注;本地基本操作(开始/停止、导出、上传、告警)。
方法编辑器(可与边缘 UI 同壳不同模块,也可独立应用)
Method Editor UI
- 打开历史谱图;框选污染物套峰;配置 padding/align/baseline;保存方法版本。
API(本地与云端统一)
建议将分析内核以 HTTP/gRPC 暴露,便于边缘与云统一:
POST /trace:上传 trace(JSON)。POST /method:上传/发布 method(JSON)。POST /analyze:入参 trace + method_id/version 或 method 内容,返回 result。GET /result?...:查询结果。
边缘可选择:
- 本地分析后只上报 result(节省云算力)。
- 或上传 trace 由云端统一分析(便于集中升级算法)。
MODBUS(标准 Modbus/TCP,实现寄存器地址映射)
目标:对外提供标准 Modbus/TCP(MBAP 头 + Function Code),外部系统仅需按“寄存器地址”读取/写入。
关键约定:
- 连接:TCP 端口建议默认
1502(Linux 下避免绑定 502 的权限问题),支持配置为502。 - 多仪器:使用 Modbus/TCP 的
Unit Identifier(MBAP Header 里的 UnitId,1 字节)选择仪器实例;单仪器可固定UnitId=1。 - 通道分段:按
base = channelIndex * 10000的方式做寄存器分段(0/1/2/3 通道分别在 0/10000/20000/30000 段)。 - StationId:Holding Register
801~812(共 12 寄存器,24 ASCII),每寄存器 2 字节,顺序见 docs/DEVICE_ID_STATIONID.md。
寄存器映射建议(MVP):
- Coils(01/05/15):状态位与控制位(地址沿用现有定义,便于对照)
10000:控温状态(读)10001:分析/采集中状态(读)10002..10005:通道 0..3 采集态(读)10006:点火状态 1(读)10007:点火状态 2(读)10008:事件状态 bit1(读)- 对应“写入控制”统一用 05/15 写 coil,边缘节点再映射为主站下行命令(如 16/17、18/19、22/23、20 等)
- Holding Registers(03/06/16):关键只做“读寄存器”
base + 0..7:设备/通道描述(16 字节 ASCII)base + 8..15:状态文本(16 字节 ASCII)base + 16..21:采集时间yyMMddHHmmss(12 字节 ASCII)base + 22:检测器标识detMark(uint16)base + 24:进样次数injNo(uint16)base + 25:峰数peakCount(uint16)base + 26..27:炉温/加热值 1(float32,2 寄存器)base + 28..29:炉温/加热值 2(float32,2 寄存器)base + 801..812:StationId(24 ASCII,12 寄存器)- 峰表建议从
base + 1000开始(每峰 40 寄存器,最多 20 峰,预留扩展)
浮点端序(必须写死并文档化):
- 建议默认:寄存器高字在前(Big-Endian word order),每寄存器内部高字节在前(标准 Modbus 习惯)。
- 如现场 PLC/采集卡需要 swap,可在边缘节点提供“字序/端序”配置项,但对外文档仍只给出默认。
分析内核(已确认:Go)
- 已确认:分析内核使用 Go。
- MVP 统一用 Go 实现 Collector/Edge API/Analyzer/Telemetry(减少语言栈数量)。
- Analyzer 对外接口固定为 HTTP(可预留 gRPC),便于解耦 UI/采集与分析实现,并支撑云端重算与回归测试基线对照。
版本治理与审计
- 方法文件必须版本化:
method_id + version。 - 结果必须引用方法版本:result 内写明
method_id/version。 - trace + method 可重放得到同结果(强调确定性与可复现)。
可交付里程碑(一步一步完成并测试)
每一步都必须满足:能运行、可观测(日志/指标/可复现输入输出)、有自动化测试(至少 golden fixtures)。
Step 0:契约固化(Schema + Fixtures)
- 产出:
voc-trace.v1 / voc-method.v1 / voc-result.v1的 JSON Schema + 3~5 份示例数据(含缺峰/漂移/噪声场景) - 测试:Schema 校验 + 示例反序列化/序列化一致性测试
Step 1:Analyzer v1(离线可测 + 对齐 Win 基线)
- 产出:
- Analyzer(Go)提供
POST /analyze - 基线导出器:从现有 Windows 版本(C# 引擎)对同一份 trace+method 导出“基线结果 JSON”
- 对照器:新 Analyzer 输出与“基线结果 JSON”自动对比(误差阈值、差异报告)
- Analyzer(Go)提供
- 测试:
- golden test:对固定 trace+method 的结果 JSON 做回归
- 基线一致性测试:RT/面积/峰高/峰数/定量等关键字段在约定误差阈值内与基线一致
- 确定性测试:同输入多次输出一致(字段级稳定)
Step 2:Collector v1(用“仪器模拟器”先跑通)
- 产出:
- GCKC 协议最小实现(接收点列、周期切片、落盘 trace JSON/XML、WebSocket 推送)
- 仪器模拟器:可模拟“主板连接 + 连续上报点列 + 周期结束事件”
- 测试:
- 协议编解码 golden bytes
- 模拟器集成测试:collector 能稳定跑 N 个周期不丢包
- 可视化冒烟:UI 打开后能看到“设备在线/心跳”状态(先用最简页面也可)
Step 3:Realtime Monitor UI MVP
- 产出:实时曲线 + 方法选择 + 周期结束自动分析 + 结果叠加标注
- 测试:
- 端到端集成测试(模拟器→collector→analyzer→ui 可完成一个周期闭环)
- 冒烟验收用例(必须可重复执行):
- 打开界面后能自动发现设备在线
- 点击“开始/停止”后主站命令下发与应答状态正确
- 实时曲线连续滚动、采样点数持续增长、Y 轴自动缩放不抖动
- 周期结束自动保存 trace,并自动触发 analyze,结果能叠加显示
Step 4:Modbus/TCP(标准协议)
- 产出:标准 Modbus/TCP Server(03/01/05/15 等)+ 寄存器映射(含 StationId 801~812)
- 测试:Modbus 客户端脚本集成测试(读写地址/边界/异常码);与模拟器联动验证状态位与结果字段更新
Step 5:Telemetry(MQTT→EMQX→ES)与运维反控
- 产出:结果增量上报、心跳、告警;运维反控命令链路(云→边缘→主站下行命令)
- 测试:离线消息回放 + 断网重连/补发策略测试;权限与审计测试(仅运维命令可达)
