利用AnyLogic软件搭建多智能体模型验证Lanchester方程线性律和平方律
写在前面
这篇文档是一篇备忘文档。记录了我使用AnyLogic搭建智能体群,并用其验证Lanchester方程线性律和平方律的过程。Lanchester方程是一种数学解析模型,用以模拟对战过程中交战双方作战能力的损耗情况,它分为线性律和平方律。
线性律的表达式为
{ dydt=−α,dxdt=−β(1) \left \{ \begin{matrix} \frac{\text{d}y}{\text{d}t}=-\alpha,\\ \frac{\text{d}x}{\text{d}t}=-\beta \end{matrix} \right. \tag{1} { dtdy=−α,dtdx=−β(1)
式中,x(t)x(t)x(t) 和 y(t)y(t)y(t) 分别是红、蓝方在 ttt 时刻的作战能力,α\alphaα 和 β\betaβ 分别是红方对蓝方的损耗系数和蓝方对红方的损耗系数。损耗系数为单位时间内一方可摧毁另一方多少作战能力的意思。线性律适用于描述冷兵器对抗的作战过程,对抗双方贴身肉搏,一对一捉对拼杀。
平方律的表达式为
{ dydt=−αx,dxdt=−βy(2) \left \{ \begin{matrix} \frac{\text{d}y}{\text{d}t}=-\alpha x, \\ \frac{\text{d}x}{\text{d}t}=-\beta y \end{matrix} \right. \tag{2} { dtdy=−αx,dtdx=−βy(2)
式中,x(t)x(t)x(t) 、 y(t)y(t)y(t) 、α\alphaα 和 β\betaβ 的意义与式(1) 一致。平方律适用于描述火器对抗的作战过程,对抗双方远距离点火力射击,也能体现现代战争中集中优势兵力原则对于作战过程的影响。
也有学者使用Lanchester方程对历史战例进行分析,取得了比较好的效果。此外,许多实时策略游戏(例如星际争霸2)、战棋游戏(例如火焰之纹章)、兵棋游戏(例如红龙)等不同单位之间的损耗过程也参考了Lanchester方程进行设置,所以Lanchester方程应用的十分广泛。
借鉴上面的现状,我在想,有没有一种方式可以用来验证一下Lanchester方程的正确性。真要进行一场战斗是不可能了,因为这样代价太大了,而且也不是我们普通人可以实施的方案。所以呢,为了得到作战数据,采用了仿真手段进行作战过程的模拟,看看能不能从这里面得到一些有用的结论。
加上AnyLogic这个软件在仿真界比较常见,也比较权威、专业,许多学者用它来做多智能体模型、系统动力学分析,应用领域十分广泛,有供应链和物流、制造业、市场和竞争、项目和资产管理、社会和生态动力学、国防等领域。因此,我选用AnyLogic搭建多智能体模型,用以验证Lanchester方程线性律和平方律。
这篇教程里面已经默认读者在电脑上安装了AnyLogic。没有安装的读者可以去AnyLogic官网申请个人学习版。
1. 创建新模型
点击左上角“文件”,再点击“新建”,最后点击“模型”。

新建模型,模型名字根据自己喜好起,位置放在一个自己之后比较好找的位置,模型时间单位选秒(或者其他单位均可)。设置完毕后,点击“完成”。

这样一个模型界面就建立好了,如果没有出意外的话,会看到下面这样的画面。

2. 创建场景
这里说的场景是指在Main里面的场景,分为三个部分,
- 规定好智能体移动的范围,相当于一个平台;
- 把智能体画出来;
- 添加智能体需要的参数和变量,以及需要导出的参数变量。
这里需要用到“面板”中的“演示”里面的各种形状,包括:
- 折线
- 矩形
- 直线
经过一番画图和添加参数,会得到下面这样的场景。

图片中的1、2、3和上面写到序号1、2、3相对应。1对应的就是平台,这里我设置的尺寸是600*600,设置参数的步骤在第3节说。
2对应的是智能体,红色小箭头就代表了智能体,可以用折线画出来;红色箭头后面只有一点点大的红色小点可以用矩形画出来,后面用来产生动画效果的轨迹;红色箭头右下角的黄色几何图形代表该智能体的瞄准方向,可以用直线和矩形画出来。
3对应的是智能体需要的参数和变量,在下一节会详细讲怎么添加以及设置参数。
在这里说一下3中有个红色的方块和蓝色的方块,这两个方块可以用矩形画出来,是用来设置智能体的颜色的,它们的设置如下:


3. 添加场景参数
这里分了如下几种类型的参数:
- 参数;
- 变量;
- 数据集;
- excel文件;
- 事件;
- 函数;
- 智能体群。
3.1 参数
按照如下顺序把参数添加进场景中:“面板”——>“智能体”——>“智能体组件”——>“参数”,鼠标左键单击就可以把参数拖拽进场景中了,设置参数名称、类型和默认值在“属性”栏中设置。鼠标左键单击参数图标左边的小圆圈就可以了(注意:点文字是没有用的),像下图一样设置参数。

这里给出所有用到的参数的名称、类型和默认值。下面这些参数用于智能体combatSatSwarm的参数设置。
| 名称 | 类型 | 默认值 | 名称 | 类型 | 默认值 |
|---|---|---|---|---|---|
| dt | double | 1 | sensorRange | double | 150 |
| height | double | 600 | collisionRange | double | 5 |
| width | double | 600 | deathRangeD | double | 100∗100^*100∗ |
| swarmSizeRD | double | 500 | deathRangeK | double | 10∗10^*10∗ |
| swarmSizeRK | double | 500 | minimumSpeed | 速度(米每秒) | 2 |
| swarmSizeBD | double | 170 | maximumSpeed | 速度(米每秒) | 5 |
| swarmSizeBK | double | 170 | turnAngle | double | 0.23 |
| hitPointRD | double | 1 | acceleration | double | 0.05 |
| hitPointRK | double | 1 | deathConstant | double | 0.23109 |
| hitPointBD | double | 10 | attackConstant | double | 1.69 |
| hitPointBK | double | 10 | retreatConstant | double | 1.0 |
注:数字上标带有*号说明该数据作过修改,按照上述参数设置不能得到有效仿真结果。
3.2 变量
按照如下顺序把变量添加进场景中:“面板”——>“智能体”——>“智能体组件”——>“变量”,操作与添加参数的操作一样,鼠标左键单击拖拽进场景中即可,同样在“属性”栏中设置名称和类型,初始值不用设置。

这里给出所有用到的变量的名称、类型。下面4种变量用于记录对抗过程中4种不同类型兵种的数量变化。
| 名称 | 类型 | 名称 | 类型 |
|---|---|---|---|
| forceRDVar | double | forceRKVar | double |
| forceBDVar | double | forceBKVar | double |
3.3 数据集
按照如下顺序把数据集添加进场景中:“面板”——>“分析”——>“数据”——>“数据集”,操作与添加参数的操作一样,鼠标左键单击拖拽进场景中即可,有两个数据集,(1)forceRed和(2)forceBlue。它们的属性按照下面的图片设置。这两个数据集用于存储红方和蓝方的兵力数量变化情况,接下来会导出至excel文件中。
forceRed的属性如下。

forceBlue的属性如下。

3.4 excel文件
按照如下步骤设置:
- 在电脑上某一位置新建一个excel文件,这里为了方便,我把excel文件创建在了AnyLogic模型文件夹里,命名为
data.xlsx; - 按照如下顺序把excel文件添加进场景中:“面板”——>“连接”——>“连接”——>“Excel文件”,操作与添加参数的操作一样,鼠标左键单击拖拽进场景中即可;
- 在属性栏中,先设置好“名称”,再在“浏览”中找到刚才新建的excel文件,点击“确定”即可。

这样就把新建好的excel文件链接到AnyLogic模型中了。后面会通过代码把模型中储存的数据导出至外部的excel文件中,会在第3.7节中说明。
3.5 事件
按照如下顺序把事件添加进场景中:“面板”——>“智能体”——>“智能体组件”——>“事件”,操作与添加参数的操作一样,鼠标左键单击拖拽进场景中即可。
这里我设置了两个事件,step和collectData,代码写在“属性”栏的“行动”中,下面一一说明,每行代码的意义我会详细注释在代码旁边,这里使用的语言是JAVA。
事件: step
功能说明: 用于执行智能体的移动
引用函数:
size() - BIF
get() - BIF
step()
--------------------------------------
for (int i = 0; i < combatSatSwarms.size(); i++) {
// 遍历所有combatSatSwarms个体
combatSatSwarms.get(i).step(); // 每个个体都执行一遍step()函数,让它们动起来
}
注:BIF 即 Build in Function 内置函数。
step()函数是智能体群combatSatSwarm的内置函数,在第5章会介绍。

事件step的属性按照上图设置,类型选择到时,模式选择循环,复发时间(即循环时间)为1秒,即1秒触发1次step事件。
事件: collectData
功能说明: 用于收集红方和蓝方兵力数量变化数据
引用函数:
size() - BIF
get() - BIF
add() - BIF
--------------------------------------
for (int i = 0; i < combatSatSwarms.size(); i++) {
// 遍历所有combatSatSwarms个体
if(combatSatSwarms.get(i).color==rectRed.getFillColor()){
// 判断这个个体的颜色是否为红色
if(combatSatSwarms.get(i).type==RD){
// 判断这个个体的类型是否为RD
forceRDVar += 1; // 如果是RD,则本循环中 forceRDVar 加1
}
else if(combatSatSwarms.get(i).type==RK){
// 判断这个个体的类型是否为RK
forceRKVar += 1; // 如果是RK,则本循环中 forceRKVar 加1
}
}
else if(combatSatSwarms.get(i).color==rectBlue.getFillColor()){
// 判断这个个体的颜色是否为蓝色
if(combatSatSwarms.get(i).type==BD){
// 判断这个个体的类型是否为BD
forceBDVar += 1; // 如果是BD,则本循环中 forceBDVar 加1
}
else if(combatSatSwarms.get(i).type==BK){
// 判断这个个体的类型是否为BK
forceBKVar += 1; // 如果是BK,则本循环中 forceBKVar 加1
}
}
}
forceRed.add(forceRDVar,forceRKVar); // 向数据集 forceRed 添加参数
forceBlue.add(forceBDVar,forceBKVar); // 向数据集 forceBlue 添加参数
// 把变量清零,为下次事件触发时记录数据做准备
forceRDVar = 0;
forceRKVar = 0;
forceBDVar = 0;
forceBKVar = 0;

事件collectData的属性按照上图设置,类型选择到时,模式选择循环,复发时间(即循环时间)为1秒,即1秒触发1次collectData事件。
3.6 函数
按照如下顺序把函数添加进场景中:“面板”——>“智能体”——>“智能体组件”——>“函数”,操作与添加参数的操作一样,鼠标左键单击拖拽进场景中即可。
函数只有1个,injectTeam,用于在对抗初始时刻添加红方和蓝方的兵力。
同样地,
- 要写代码,写在“属性栏”里面的“函数体”中;
- 记得添加参数,参数即为函数的输入。
Function: injectTeam()
Input:
1. color [Color]
2. type [TypeOption]
3. minX [double]
4. w [double]
5. minY [

本文详细介绍了如何使用AnyLogic软件构建多智能体模型,通过模拟红蓝双方的对抗,验证Lanchester方程的线性律和平方律,通过仿真数据验证战争理论模型的实际效果。
最低0.47元/天 解锁文章
1402

被折叠的 条评论
为什么被折叠?



