Plant Sim中CLUIP瓶颈工位时长统计的代码异常问题
Plant Simulation中基于CLUIP的瓶颈工位识别问题解决方案
问题背景
在Plant Simulation环境中,通过SimTalk代码基于**当前最长连续运行时长(CLUIP)**识别瓶颈工位并统计其持续时长,存在两个核心问题:
- 工位循环检查顺序导致当前瓶颈之前的工位被短暂误判为瓶颈,
cluip_table无法统计真实瓶颈时长; - 事件控制器频繁调用代码,触发
Drain.CLUIP属性更新过于频繁,导致cluip_table的时长累加值远超仿真总时长。
解决方案
问题1:工位循环顺序误判修复
原代码遍历工位时,每找到更长的时长就立即更新瓶颈并记录时间戳,导致遍历过程中的临时“最长值”被误当作真实瓶颈。修复逻辑:
- 先完整遍历所有工位,确定全局最长和次长CLUIP,再统一更新瓶颈状态,避免遍历过程的临时值干扰;
- 仅当新候选瓶颈与当前瓶颈存在明确差异时,才触发状态切换。
问题2:属性频繁更新导致的时长累加错误修复
原代码每次事件控制器调用都更新Drain.CLUIP,导致属性变化事件频繁触发,重复累加时长。修复逻辑:
- 仅当真实发生瓶颈切换时,才更新
Drain.CLUIP并触发时长统计; - 在瓶颈切换时,先完成前一个瓶颈的时长计算,再记录新瓶颈的起始时间,避免重复累加。
修改后的完整代码
事件控制器调用代码
-- param attribute: string, oldValue: time param newValue: time -- Variables to store the results var current_longest_active_time, current_second_longest_active_time : time var BN_station, ShiftingBN_station, current_station: object var current_duration: time var prev_BN_station: object -- 记录上一轮的瓶颈工位 -- 1. 更新所有工位的当前活跃时长 for var i := 1 to shifting_table.YdimIndex loop current_station := shifting_table["station_object", i] if shifting_table["state_inactive", current_station] = true then shifting_table["current_inactive_period", current_station] := newValue - shifting_table["end_active_period", current_station] shifting_table["current_active_period", current_station] := 0 else shifting_table["current_active_period", current_station] := newValue - shifting_table["start_active_period", current_station] end next -- 2. 完整遍历所有工位,确定全局最长和次长CLUIP current_longest_active_time := 0 current_second_longest_active_time := 0 BN_station := void ShiftingBN_station := void for var i:=1 to shifting_table.YdimIndex loop current_station := shifting_table["station_object", i] current_duration := shifting_table["current_active_period", current_station] if current_duration > current_longest_active_time then current_second_longest_active_time := current_longest_active_time ShiftingBN_station := BN_station current_longest_active_time := current_duration BN_station := current_station elseif current_duration > current_second_longest_active_time then current_second_longest_active_time := current_duration ShiftingBN_station := current_station end next -- 3. 仅在瓶颈切换时更新统计和属性 prev_BN_station := shifting_table["current_bn", 7] if BN_station <> prev_BN_station then -- 计算上一个瓶颈的持续时长 if prev_BN_station <> void then cluip_table["end_cluip", prev_BN_station] := EventController.simtime cluip_table["cluip_duration", prev_BN_station] := cluip_table["cluip_duration", prev_BN_station] + (cluip_table["end_cluip", prev_BN_station] - cluip_table["start_cluip", prev_BN_station]) end -- 记录新瓶颈的起始时间 if BN_station <> void then cluip_table["start_cluip", BN_station] := EventController.simtime end -- 仅在切换时更新CLUIP属性 Drain.CLUIP := BN_station end -- 更新状态表 shifting_table["current_longest_active_time", 7] := current_longest_active_time shifting_table["current_bn", 7] := BN_station shifting_table["current_second_longest_active_time", 7] := current_second_longest_active_time shifting_table["current_shifting_bn", 7] := ShiftingBN_station
移除原CLUIP属性变化触发代码
原第二段(CLUIP属性变化时调用)的代码可直接删除,因为时长统计逻辑已整合到瓶颈切换判断中,避免重复触发累加。
关键修改说明
- 全局遍历确定瓶颈:先遍历所有工位找到真实的最长CLUIP,再统一更新瓶颈状态,彻底解决顺序导致的误判;
- 瓶颈切换才更新属性:仅当新瓶颈与上一轮不同时,才更新
Drain.CLUIP,避免频繁触发属性变化事件; - 统一时长统计时机:在瓶颈切换时一次性完成前一个瓶颈的时长计算,避免多次累加同一时间段。
内容的提问来源于stack exchange,提问作者Jerald
相关产品推荐
相关产品推荐

