一个“when”语句由两部分组成。第一部分是条件表达式,它表明事件发生的时刻。在本例中,事件将在“当高度
h 首次降至 0 以下时”发生。当语句的第二部分是事件发生时所要执行的操作。在本例中,v 的值通过
reinit 操作符重新初始化。reinit 操作符允许我们为一个状态指定一个新的初始条件。从概念上讲,你可以将
reinit 想象成是在模拟过程中插入的一个初始方程。但它只改变一个变量,并且总是明确地设置(也就是说,它不如初始方程那样灵活)。在这种情况下,reinit
语句将把 v 的值重新初始化为与碰撞前 v 的值相反的方向,并按因子 e 进行缩放。
为了解决这个问题,我们必须引入一定的滞后效应(死区)。在这种情况下,这意味着一旦条件
h<0 成立,我们必须先远离该条件“足够远”之后,才能再次允许该事件发生。换句话说,只要
h 小于零,事件就会发生。但在我们再次触发该事件之前,我们要求 h 必须首先大于某个值
。换句话说,并非仅仅 h 变为大于零就足够了,而是必须大于 (其中
是由求解器通过检查各种缩放因子来确定的)。
在之前的模拟中存在这样一个问题:每次球弹起时,h 的峰值都会略微降低一点。这里所说的峰值是指球再次开始下落时的
h 值。最终,h 的峰值不足以超过
的临界值。这也就意味着当语句永远不会触发,而重新初始化语句也永远不会再次重置 v。因此,球会无限期地处于自由落体状态。
modelStableBouncingBall"The 'classic' bouncing ball model with numerical tolerances"typeHeight=Real(unit="m");typeVelocity=Real(unit="m/s");parameterReale=0.8"Coefficient of restitution";parameterHeighth0=1.0"Initial height";constantHeighteps=1e-3"Small height";Booleandone"Flag when to turn off gravity";Heighth"Height";Velocityv(start=0.0,fixed=true)"Velocity";initialequationh=h0;done=false;equationv=der(h);der(v)=ifdonethen0else-9.81;when{h<0,h<-eps}thendone=h<-eps;reinit(v,-e*(ifh<-epsthen0elsepre(v)));endwhen;endStableBouncingBall;