系统仿真中一些问题的思考

系统仿真(system simulation)就是根据系统分析的目的,在分析系统各要素性质及其相互关系的基础上,建立能描述系统结构或行为过程的、且具有一定逻辑关系或数量关系的仿真模型,据此进行试验或定量分析,以获得正确决策所需的各种信息。

系统仿真与仿真游戏的区别

系统仿真与仿真游戏本质上没有区别,都是计算机程序对现实的模拟,所不同的是各自对仿真保真度(Simulation Fidelity)的要求不同。

仿真保真度(Simulation Fidelity)用于描述仿真精度,模拟真实对应物有多近似:

  • 低保真:对系统的最小模拟,接受输入产生输出
  • 中等保真:对刺激能自动响应,有限精度
  • 高保真:接近不可辨识或者尽可能地接近真实系统

通常系统仿真对仿真保真度的要求比仿真游戏要高。

计算步长与采样周期

采用计算机进行数值模拟或系统仿真时,经常需要采用数值解法求解模型方程。系统模型一般采用微分方程描述(也有其它形式),采用数值方法求解,就是采用迭代法逐步逼近。

计算步长

积分与微分是互逆。对一个曲线(包括直线)方程求积分,其实就是求曲线与横轴围成的面积。该面积可以用一系列间隔很小的面积块相加得到。这些小间隔的宽度就是计算步长。显然,纯粹从精度的角度考虑,步长越小越精确,因为近似面积更接近实际图形面积。

采样周期

采样周期是对一个实际信号测量时,相邻两次测量之间的时间间隔。有时候,采样周期和计算步长相似,但采样周期要考虑实际限制,且是时间单位,而计算步长不一定是时间单位,且相对自由些。两者在数值上没必然联系。对于同一问题,且都是时间量纲的话,采样周期大于等于计算步长,前者是后者的整数倍

系统仿真包含系统模型求解,也就是在每个采样周期内,要解出模型方程。控制系统仿真时在采样周期内要解出两个模型方程:控制器模型和系统模型。

一个采样周期内可对系统模型迭代求解一次或多次

计算步长和采样周期大小的选择

关于采样周期和计算步长的选择,一般考虑以下因素:

  • 从求解精度考虑,越小越好。

  • 从计算量考虑,越大越好。

采样周期与每秒帧数(Frames Per Second,FPS)

采样周期以秒为单位,则

$$FPS=\frac{1}{采样周期}$$

FPS是指每秒画面重绘的次数,用于衡量画面切换速度。FPS越大,则动画效果越平滑,当FPS小于20时,一般就能明显感受到画面的卡滞现象。

当FPS足够大(比如达到60),再增加帧数人眼也不会感受到明显的变化,反而相应地就要消耗更多资源(比如电影的胶片就需要更长了,或是电脑刷新画面需要消耗计算资源等等)。因此,选择一个适中的FPS即可。

NTSC标准的电视FPS是30,PAL标准的电视FPS是25,电影的FPS标准为24。

WebGL动画

WebGL是一种JavaScript API,用于在不使用插件的情况下在任何兼容的网页浏览器中呈现交互式2D和3D图形。但要产生WebGL动画,需要对运动的场景不停的采样,即不停地拍照。JavaScript的采样函数主要有setInterval方法和requestAnimationFrame方法。

setInterval方法

如果要设置特定的FPS(虽然严格来说,即使使用这种方法,JavaScript也不能保证帧数精确性),可以使用JavaScript DOM定义的方法:

1
setInterval(fn,mesc)

其中,fn是每过msec毫秒执行的函数,如果将fn定义为重绘画面的函数,就能实现动画效果。setInterval函数返回一个变量timer,如果需要停止重绘,需要使用clearInterval方法,并传入该变量timer。

requestAnimationFrame方法

大多数时候,我们并不在意多久重绘一次,这时候就适合用requestAnimationFrame方法了。它告诉浏览器在合适的时候调用指定函数,通常可能达到60FPS。

  • requestAnimationFrame同样有对应的cancelAnimationFrame取消动画
  • 和setInterval不同的是,由于requestAnimationFrame只请求一帧画面,因此,除了在init函数中需要调用,在被其调用的函数中需要再次调用requestAnimationFrame

使用stat.js记录FPS

stat.js是Three.js的作者Mr.Doob的另一个有用的JavaScript库。很多情况下,我们希望知道实时的FPS信息,从而更好地监测动画效果。这时候,stat.js就能提供一个很好的帮助,它占据屏幕中的一小块位置(如左上角),显示实时的FPS信息。

在HTML中引用stat.js:

1
<script type="text/javascript" src="//mrdoob.github.io/stats.js/build/stats.min.js"></script>

再使用如下代码监视实时FPS:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var stats = new Stats();
stats.showPanel( 1 ); // 0: fps, 1: ms, 2: mb, 3+: custom
document.body.appendChild( stats.dom );

function animate() {

stats.begin();

// monitored code goes here

stats.end();

requestAnimationFrame( animate );

}

requestAnimationFrame( animate );

参考链接

  1. 计算步长和采样周期,by 王永林.
  2. 离散和连续模拟之间的实际区别是什么?,by UF Game.
  3. 系统仿真,by 百度百科.
  4. 开源的物理引擎,by M. Jones.
  5. 数值分析,by wikipedia.
  6. three.js 入门详解(二),by Levi.
  7. WebGL,by wikipedia.
  8. stats.js, by mydoob.
  9. 详解JavaScript中的Event Loop(事件循环)机制,by 暮雨清秋.