前言
模拟运行中状态,比较关键的是delay的模拟
同时还有对VAR的模拟 (对所有可能出现状态的模拟、对保持和变化两种状态的模拟,排除不会出现的情况)
为了模拟运行中的状态,需要提取VAR和delay的信息,上次主要是提取VAR,这次是提取了delay和其相关的VAR
提出一个关键概念:步长变量step
引入1个步长变量step1,可以保证状态一次不变
利用了Nusmv的步长特性(next语句的特点),step1 = 0: capability.var 能保证 capability.var在第一次next中不变。第一次next中step变为1,所以第二次next中 capability.var 可以正常变化。可以让nusmv状态转换变得更有序。步长变量也可用于比如出现某个状态,让step变化,作状态调整。
MODULE main
VAR
step1:{0,1};
capability.var:{state1,state2,state3};
ASSIGN
init(step1):= 0;
next(step1):= 1;
next(capability.var):=
case
step1 = 0: capability.var;
TRUE: state3;
esac;
一、模拟VAR
某个设备capability相关的VAR有3类:
- 设备的capability
- 该capability对应的上一状态
- 该capability对应的delay
对所有可能出现状态的模拟
不init三类变量 ,模拟了所有可能出现的状态,包括变化状态和不变状态
对保持和变化两种状态的模拟
capability保持不变(capability.var==lastvar),变化(capability.var!=lastvar)
排除不会出现的情况
代入现有规则看是否符合实际运行状态,如:bulb检测到有人移动,会on而不是off,有人移动和bulb on捆绑 ;如果smartplug等于off,那么连接smartplug 的设备一定是off,smartplug的开关状态和连接设备的开关状态绑定。所以python要提取出连smartplug的设备和类似情况
在smv中可以如下实现,未涉及timer应该在delay前进行:
对于smartplug
switch({on,off}属性)
smart.plug = off & step = :off
对于bulb这类
switch(bulb)
TAP前半部分 & step:off
capability.var、capability.lastvar需要在前两个next保持不变,为了避免变化而引起的其它变量改变,加入如下规则可实现
step1 = 0: capability.var;
step2 = 0: capability.var;
需要进一步考虑的点
TAP前半部分有timer作条件,VAR的修正是否在delay后执行,如何执行
oven heat且smoke!= detected:650
TAP规则里的隐含意义
二、模拟delay
方式一:Nusmv中VAR和delay init为所有取值范围 (不可行)
缺点1:会出现没有的状态,或者直接冲突的状态
缺点2:需要探索的空间太多
以iotinspector.smv为例,该smv中有60个VAR,根据上面对VAR的分类,实际设备capability相关的有60 / 3 = 20个
设备的capability的取值范围假设为10,那么该capability对应的上一状态的取值范围也为10,delay也假设取值范围为10
那么总共需要探索30的20次方,不现实
方式二:Python外部做判断、模拟 (不可行)
缺点:如果不在Nusmv里实现,判断的逻辑不好处理
Nusmv里有现成的next,最好在Nusmv里实现
方式三:引入步长变量,用于稳定状态、辅助修正
为了正确模拟运行,需要引入2个步长变量,保证状态两次不变以辅助修正
引入2个步长变量的原因:
delay的修正在第一个next。如果runin在第一个next就修正的话,会导致多倒计时,所以runin要等delay一个Next,在第二个next进行修正。step2在step1变了之后再变,可以保证状态两次不变
delay的nusmv编写
init(delay) = 0
delay的取值:只有0和上界值。0代表不工作(包括结束);上界值代表刚开始
next(delay)的编写
runind的取值。1,介于1和上界值,上界值。 1代表不工作(包括结束);介于1和上界值代表正在运行(其中上界值-2是个specification条件);上界值代表刚开始
runin参与实际的判断而不是delay,所以主要是修正runin
所以next(delay)为
- step1 = 0 & 满足条件(通常为变化):上界(刚开始)
- 之前出现过那个条件,如果状态为满足条件的保持:上界-2,或者python随机一个介于上下界的值
- 如果状态为保持,且为结束态: 1;因为是否结束是以runin作判断,所以确保runin=1
MODULE RUNIN(delay)
VAR
timer:0..500;
ASSIGN
init(timer):=0;
next(timer):=
case
delay=0:0;
timer=0 & delay>0: delay;
timer>0 & delay>0: timer - 1;
TRUE: timer;
esac;
MODULE main
VAR
step1:{0,1};
step2:{0,2};
capability.var:{state1,state2,state3};
capability.lastvar:{state1,state2,state3};
delay:0..500;
runin_delay: RUNIN(delay);
ASSIGN
init(step1):= 0;
next(step1):= 1;
init(step2):= 0;
next(step2):=
case
step1 = 0: step2;
step1 = 1: 2;
esac;
next(capability.var):=
case
step1 = 0: capability.var;
step2 = 0: capability.var;
TRUE: state3;
esac;
next(capability.lastvar):=
case
step1 = 0: capability.lastvar;
step2 = 0: capability.lastvar;
TRUE:capability.var;
init(delay): 0;
next(delay):=
case
step1 = 0 & capability.var=state1 & capability.var!=capability.lastvar: 400;
step1 = 0 & capability.var=state1 & capability.var==capability.lastvar: 398;
step2 = 0: delay;
capability.var=state1 & capability.var!=capability.lastvar: 400;
runin_delay.timer=1: 0;
TRUE: delay;
esac;
需要进一步考虑的点
如下的运行和结束不好区分:
step1 = 0 & capability.var=state1 & capability.var==capability.lastvar: 398;
step1 = 0 & capability.var=state1 & capability.var==capability.lastvar: 1;
可能的解决方法:通过python外部枚举后写入smv,枚举范围2的9次方:512,可行