前言
上一篇使用几个简单的例子说明『模拟』的基本概念与SimPy基本用法,这一次我们仿效『大巨蛋紧急疏散模拟动画』,实作戏院售票流程的模拟动画。
图一. 戏院入场流程
记录模拟结果
首先改写上一篇的01_03_theater.py程式,将模拟结果写入 log,内容含4个栏位:
时间(Time Step):代表事件完成的时间,而非事件开始的时间,例如购票(purchase_ticket)是指购票完成的时间。观众代码:自动产生的序号。事件:包含到场(arrival)、购票完成(purchase_ticket)、验票完成且至小吃部(check_ticket_store_in)、验票完成直接就坐(check_ticket_wo_food)、离开小吃部(store_out)。处理时间:特定观众在个别事件的完成的时间。程式逻辑与01_03_theater.py大致相同,不另作解释,可参阅上一篇说明,执行方式如下:
python 01_04_theater_with_log.py
执行后会产生log档案:record.log。另外,售票口个数、验票口个数、小吃部销售员人数设定会记录在config.ini档案,以方便多个程式共用。产生动画
接着根据record.log产生动画,我採用PyGame套件,程式开发并没有想像中的简单,花了一天一夜才搞定,执行结果如下:
点选这里可以看到完整动画,也可以直接执行程式,指令如下:
python 01_05_gui.py
执行后会看到实际的模拟动画。同时会每隔10时间单位,储存一张截图。之后执行程式产生动画档案animated.gif。python make_gif.py
侦错与调校
由于程式逻辑複杂,而且有点凌乱,先不作说明,等未来整理出较完整的架构后,再作详细说明,有兴趣的读者可以在文末找到原始程式码。这里仅针对侦错及调校特别说明:
要调慢动画拨放速度,可修改第26行。play_speed = 60 # 60 frames per second
只播放一个观众的动画,藉以检查动画是否正确,可修改01_04_theater_with_log.py 第87~96行。 # 初始人数:1人 for moviegoer in range(1): env.process(go_to_movies(env, moviegoer, theater)) # 模拟 # while True: # yield env.timeout(arrival_interval) # 每隔0.2分钟有一观众到场 # moviegoer += 1 # env.process(go_to_movies(env, moviegoer, theater))
重新执行01_04_theater_with_log.py,产生record.log。
也可以修改config.ini档案的设定,调整资源(resoources),重新执行01_04_theater_with_log.py、01_05_gui.py,观看改善效果,以目前设定而言,小吃部会是戏院的瓶颈,可增加人力,以解决瓶颈。小结
视觉化可让使用者身历其境,有较深的感受,能从动画中观察出瓶颈,从而进行what-if分析,改善系统效能,如果只是呈现一些冰冷的统计数字,是很难让客户买单的,虽然需要花费很多心力,应该还是值得的。目前的动画非常粗糙,程式架构也缺乏通用性,未来希望能结合3D动画软体,呈现更好的使用者体验(UX)。之后将继续探讨Simpy更多的功能及应用,也希望有机会能实作专案,以印证所学,本篇的程式码放在GitHub,读者可自行下载。