| 本篇完成什么 按批次关联工艺曲线与累计量,用一组数字算出公辅单耗,并说明清洗过程记录能够证明什么。 |
一批产品从夜班跨到早班,蒸汽表按零点出日报,灌装产量却按工单结算。把两列直接相除,就会把不同时间窗口的数据算成“本批单耗”。先定义批次开始和结束,再选择同一边界内的产量与消耗。
本文用 Rapid SCADA v6 的通道和归档作为数据基础。批次台账、资源分摊和质量判定需要业务记录与统计实现;本文的数字是算例,不提供清洗工艺处方或食品安全达标判定。
1. 通道和批次记录各存什么
| 数据 | 建议内容 | 作用 |
|---|---|---|
| 工艺实时通道 | 温度、压力、流量、阀位、设备状态及质量 | 监视和曲线追溯 |
| 公辅累计通道 | 蒸汽累计、水累计、电量累计 | 区间消耗计算 |
| 批次主记录 | 批次ID、工单、产品、设备、开始/结束时间 | 定义统计边界 |
| 产量/质检记录 | 总产量、合格产量、复检与修订版本 | 确定单耗分母和质量来源 |
| 清洗步骤记录 | 回路、步骤、开始/结束、参数与配方版本 | 还原实际过程 |
批次ID不是从画面标题推断出来的。开始、结束和切换事件来自已约定的PLC/生产系统接口,并具有去重身份。重复收到“批次结束”,不应重复创建一份消耗。
工段可以按糖化、发酵、清洗、灌装组织对象和编号,但同一物理温度或公辅表计不应被多份复制通道各自统计。共享资源用分摊规则处理,不能为让画面整齐就重复计量。
2. 确认批次边界后再取归档
以批次 B001 为例:开始时间22:00,次日02:00结束。业务统计窗口是这4小时,而不是某一天的00:00到24:00。
为每个计量点取得边界附近符合规则的累计示值,并记录实际采样时间。如果边界没有有效点,是取设备冻结值、使用允许误差内的邻近点,还是估算,需要明确规则;不能把前一小时的旧值无说明地当成批次起点。
源数据使用 UTC 保存时,批次业务时间先按约定时区转换。跨零点不应该被拆成两个不完整批次,除非项目本身要求按班次另外分摊。
3. 用同一批次的数据计算单耗
假设该批次蒸汽累计起止值为1200.0和1224.0 t,合格产品80.0 t,总产量82.0 t:
本批已计量蒸汽消耗 = 1224.0 - 1200.0 = 24.0 t 按合格产量计算单耗 = 24.0 / 80.0 = 0.300 t/t 按总产量计算单耗 = 24.0 / 82.0 ≈ 0.293 t/t两个结果都能算出,但指标名称和用途不同。报表必须写出分母,不把它们都叫“本批蒸汽单耗”。合格产量为0或尚未终结时,应显示不可计算/暂结状态,不输出0单耗。
累计表跨批次清零、换表或倍率变化时,按计量段拆分;不能简单用期末减期初得到负数后取绝对值。历史补回或质检修订后,重算同一批次并保留版本。
4. 用两张业务表把 B001 算到可重复查询
为了让读者能从数据得到结果,下面给出一个完整的 SQLite 示例。它使用独立业务表,不是 Rapid SCADA 的内置归档表名。生产中先用目标归档服务/API读取并保留源记录,再按经过验证的规则写入业务库;批次与产量来自相应生产记录。不要直接修改平台归档文件。
batch定义统计边界与合格产量,meter保存指定计量点累计值、质量及计量段。segment在换表、倍率变化或确认清零时切换,不能只按自然日生成。主键(meter_id,ts)防止同一读数重复插入,但有修订冲突时还要由上游版本规则决定保留哪条。
保存以下内容为batch.sql,在支持窗口函数的 SQLite 3.25及以上执行sqlite3 :memory: < batch.sql。窗口函数语法可查 SQLite 官方文档。
CREATETABLEbatch(idTEXTPRIMARYKEY,start_sINTEGERNOTNULL,end_sINTEGERNOTNULL,good_tREALNOTNULLCHECK(good_t>=0),CHECK(end_s>start_s));CREATETABLEmeter(meter_idTEXTNOTNULL,tsINTEGERNOTNULL,value_tREALNOTNULL,goodINTEGERNOTNULLCHECK(goodIN(0,1)),segmentTEXTNOTNULL,PRIMARYKEY(meter_id,ts));-- 固定 UTC 时刻,对应北京时间 2026-01-01 22:00 至次日 02:00。INSERTINTObatchVALUES('B001',1767276000,1767290400,80.0);INSERTINTOmeterVALUES('steam-main',1767275940,1199.8,1,'meter-A-v1'),('steam-main',1767276000,1200.0,1,'meter-A-v1'),('steam-main',1767283200,1212.0,1,'meter-A-v1'),('steam-main',1767290400,1224.0,1,'meter-A-v1');CREATEVIEWbatch_resultASWITHchosenAS(SELECTb.*,m.ts,m.value_t,m.good,m.segment,row_number()OVER(PARTITIONBYb.idORDERBYm.ts)ASn,lag(m.value_t)OVER(PARTITIONBYb.idORDERBYm.ts)ASprevFROMbatch bJOINmeter mONm.meter_id='steam-main'ANDm.tsBETWEENb.start_sANDb.end_s),checkedAS(SELECTid,max(start_s)ASt0,max(end_s)ASt1,max(good_t)ASgood_t,min(ts)ASfirst_ts,max(ts)ASlast_ts,count(*)ASpoints,count(DISTINCTsegment)ASsegments,min(good)ASall_good,sum(CASEWHENn>1ANDvalue_t<prevTHEN1ELSE0END)ASfalls,max(CASEWHENts=start_sTHENvalue_tEND)ASv0,max(CASEWHENts=end_sTHENvalue_tEND)ASv1FROMchosenGROUPBYid),validatedAS(SELECT*,CASEWHENfirst_ts=t0ANDlast_ts=t1ANDpoints>=2ANDall_good=1ANDsegments=1ANDfalls=0THEN1ELSE0ENDASvalidFROMchecked)SELECTb.id,CASEWHENv.valid=1THENv.v1-v.v0ENDASsteam_t,CASEWHENv.valid=1ANDb.good_t>0THEN(v.v1-v.v0)/b.good_tENDASunit_t_t,CASEWHENv.validISNOT1THEN'REVIEW'WHENb.good_t<=0THEN'NO_DENOMINATOR'ELSE'READY'ENDASstateFROMbatch bLEFTJOINvalidated vONv.id=b.id;SELECTid,steam_t,round(unit_t_t,3)ASunit_t_t,stateFROMbatch_result;应输出B001|24.0|0.3|READY。示例用UTC秒数固定了北京时间22:00–次日02:00的四小时窗口;零点中间读数1212参与单调性检查,不会将批次切成两天。开始前一分钟的1199.8也不会被误取为起点。
这条查询有意采用严格边界:首尾都必须有有效的、属于同一计量段的读数,窗口内不能出现坏质量或累计下降。缺任意一项便返回REVIEW,同时把消耗和单耗留空;分母为0则返回NO_DENOMINATOR。没有读数的批次也保留一行待核结果,不从报表里消失。
严格边界并不要求所有现场都刚好在整秒采到冻结值。实际项目可使用设备冻结接口,或经确认的邻近点/插值策略,但必须记录真实源时间、偏差、算法和质量。不能伪造一个“恰好等于批次开始”的测量时间,让SQL检查表面通过。
用四次故障注入看查询是否会给假数
在独立测试库逐项修改后重查batch_result,每次恢复初始样本再测试下一项:
| 注入 | 预期 |
|---|---|
| 删除开始时间1767276000的读数 | REVIEW,不是拿前一分钟替代 |
| 将中间读数1212改为1190 | 检出累计下降,REVIEW |
| 中间读数质量设为0 | REVIEW,不能删除坏点后照常报合格 |
| 中间读数计量段改为meter-B-v1 | REVIEW,先处理换表或清零分段 |
| 合格产量改为0 | 仍可保留24 t消耗,单耗为空 |
两个边界示值恢复得很高,不能反证中途一定没有清零。脚本只能检查已保存读数和分段元数据;如果上游丢掉了复位事件,算法无法凭空恢复,需补采事件或人工确认,并保留“证据不足”。
重复结束事件和质检晚到怎样避免重复累计
本例结果是查询视图:同一个B001查十次仍是24 t,不会累加成240 t。批次结束接口应按批次ID和来源事件身份幂等落库,历史修订按同一业务键重算。报表发布版本再单独保存,不能每次刷新都创建新“消耗事实”。
例如在上面脚本之后建立版本快照:
CREATETABLEbatch_report(batch_idTEXTNOTNULL,revisionINTEGERNOTNULL,steam_tREAL,good_tREALNOTNULL,unit_t_tREAL,stateTEXTNOTNULL,source_revisionTEXTNOTNULL,PRIMARYKEY(batch_id,revision));INSERTINTObatch_reportSELECTr.id,1,r.steam_t,b.good_t,r.unit_t_t,r.state,'demo-source-v1'FROMbatch_result rJOINbatch bONb.id=r.id;SELECT*FROMbatch_report;若同一版本再插入,主键应拒绝重复,由业务层读取已有快照并比较来源,不能通过另起一条消耗绕过去。质检修订时更新经过授权的生产记录,重新计算后发布revision2,保留revision1的分母和结果;列表使用最新有效版本,审计仍可查看旧版。
以上SQL已在本地SQLite内存库执行,并测试缺边界、坏质量、累计下降、计量段变化、无数据和零分母。这里验证的是统计与幂等的数据结构,不代表已经接入真实生产系统或完成质量放行。
5. 共享公辅不能自动归给某一罐
如果一块蒸汽总表同时供两条生产线,它只证明两条线在该时间窗内合计消耗。没有分项表或经确认的分摊依据,就不能把总表差值分别写成两条线各自的实测消耗。
可以选择分项计量,或定义按运行时间、有效产量等分摊的业务方法。采用分摊时保存权重、覆盖对象、算法版本,并标明“分摊值”。若按60%和40%分摊24 t,则结果14.4 t与9.6 t;两者之和应仍为24 t。
公辅表计的实际时间边界、计量点和数据质量,与分摊方法一起保留,避免把统计估算展示成直接仪表测量。
6. CIP 记录应还原步骤与时间
清洗页面显示一次“温度已达到”,不能证明整个要求时段都满足条件。过程记录至少关联回路、步骤、配方版本、开始/结束时间、相关参数及其有效质量。
若项目要求某条件连续满足指定时间,统计应按真实时间区间核验,并对中断、无效采样、步骤跳转和人工干预留痕。具体温度、浓度、流速和持续时间由经过确认的工艺要求提供,本文不给统一参数。
SCADA 曲线和记录用于追溯,清洗合格与产品放行仍需对应的质量流程。把图表上的一条线改成绿色,不会补齐缺失的过程证据。
7. 一次验收应覆盖这些异常
| 测试 | 检查结果 |
|---|---|
| B001跨零点 | 仍按同一批次22:00–02:00统计 |
| 蒸汽差值24 t、合格产量80 t | 单耗0.300 t/t,原始读数可查 |
| 共享24 t按60/40分摊 | 14.4+9.6=24,明确标识分摊 |
| 结束事件重复 | 不重复增加批次消耗 |
| 累计量中途清零 | 分段重算或待核,不产生负消耗 |
| 质检结果晚到 | 暂结转终结,有修订时间和版本 |
| CIP关键步骤数据缺失 | 标记证据不完整,不自动判合格 |
排障先看批次ID、时间窗和表计覆盖范围,再看累计量质量和分母来源。只有这些口径一致,工段曲线、批次报表与公辅单耗才能互相核对。
官网:Rapid SCADA 中文站