仿真时间推进
仿真中的时间推进是指在仿真过程中,通过什么方法推进仿真时间。
时间推进法的分类
常见的仿真时间推进方法有三大类:
- 事件调度法:事件调度法是一种基于事件的仿真方法,它通过对仿真系统中各个事件进行排序,按照事件发生的先后顺序依次推进时间执行活动,进而实现仿真。
- 固定增量推进法:固定增量推进法是指在仿真过程中,固定一个时间增量。在设定起始时间后,在起始时间的基础上根据时间的增量来对时间进行推进仿真。
- 活动事件扫描法:针对不确定性较强的系统,通过扫描系统中发生的事件并执行相应的活动实现时间推进。感觉实现起来比较难(容易出现时间推进不准(有误差)的问题,可能是我的水平不够😥)
实例
事件调度法
事件调度法是一种基于事件的仿真方法,它通过对仿真系统中各个事件进行排序,按照事件发生的先后顺序来进行仿真。在仿真过程中,仿真系统根据当前仿真时间和剩余事件,将时间推进到下一个事件,执行相应的活动。
事件调度法主要分为以下3个主要步骤,这3个步骤也是控制事件调度法的主控程序的主要步骤:
- 时间扫描:确定下一事件发生时间并将仿真时钟推进到该时刻
- 事件辨识:正确地辨识当前要发生的事件
- 事件执行:正确地执行当前发生的事件
事件调度法基本原理流程图如下:
事件调度法在MicroCityWeb中的具体实现参见 离散事件仿真和程序控制 - 协程
固定增量推进法
固定增量推进法是指在仿真过程中,从起始时间开始,每次推进一个固定步长的时间。在每个步长内,若无事件发生,则仿真钟再推进一个单位时间T;若在该步内有若干个事件发生,则依次执行,且认为这些事件均发生在该步的结束时刻。
例题
代码流程示例
while scene.render() do
t = t + dt
if t % cycle ~= work_time then
d = d + v * dt
print("出发后", t, "小时")
else
print("出发后", t, "小时,休息")
end
car:setpos(CastToLine(d)) --直线轨迹
os.sleep(200)
end
此为代码主要流程,无法直接使用
自动化仓库仿真思路的最后一部分提到了改进空间,实现了全局的仿真钟,最终实现了时间推进法。最终还实现了非固定增量推进,详细见下文介绍。
自动化仓库仿真向主导时钟推进法的改变
具体来说,只在原来的基础上做了如下改动:
- 删除大部分与事件调度法有关的
os.sleep()
。由于仿真流程比较简单,保留了与装卸货有关的事件调度法,优化资源占用。 - 设置全局仿真时钟,将
Agv:Move()
函数的思路从“固定步长执行任务并刷新场景”的改为“监测仿真时钟时长变化,根据时长变化执行任务并刷新场景” - 新增仿真速度调整。
从以上的改动可以看出,仿真的核心从事件任务转向了仿真时钟。其中,场景刷新的部分使用了 os.clock()
实现。
非固定增量推进法
下面是一个有关于时间推进法和 os.clock()
函数的简单的示例,修改自MicroCityWeb中内置的方块旋转案例。其中,os.clock()
用于计算CPU运行时间,以此实现仿真时间与真实世界时间成一定比例。而具体的比例可以通过 simspeed
(仿真速度)进行调整。
local obj = scene.addobj('box')
-- 初始位置
local x = 1
local y = 1
local z = 0
local rx, ry = 0.1, 0.1 -- x方向和y方向的旋转速度
local simspeed = 10 -- 仿真速度
local t = 0 -- 全局仿真时钟
local t0 = os.clock() -- 记录仿真开始的时间
while scene.render() do
local dt = os.clock() - t0 -- 计算自上次记录时间以来的时间差
t = t + dt -- 仿真时钟走过相应时间差长度的时间
-- 设置方块此刻的旋转位置
x = x + rx * dt * simspeed
y = y + ry * dt * simspeed
obj:setrot(x, y, z)
t0 = os.clock() -- 记录仿真时间
end
相关说明
- 当仿真速度
simspeed
为1时,表示仿真时钟与真实世界时钟的速度相同。simspeed
可以视作加速倍率。 dt
表示两次记录时间之间的时间差,仿真中的时间步进根据dt*simspeed
计算得到。相关信息
需要注意的是,时间增量
dt
的数值在每个循环周期一般都不相同,dt
的具体大小一般取决于电脑的运算能力提示
有时两次记录时间之间没有太多耗时的操作,计算得到的
dt
可能为0。一般两次时间记录之间存在一个scene.render()
,这样一般能够保证两次采样的时间之间能够计算得到一个不为0的时间差值。
对于 MicroCity Web,非固定增量的时间推进法还可以参考 Gallery 部分绘制一个时钟的案例,比较详细地介绍了如何控制时钟的指针,以及如何根据当前时间来控制指针的位置。