Lanchester方程的离散模型及Python代码实现
利用差分的方法将连续域的Lanchester方程离散化,以得到战争双方的兵力损耗情况。
下面对间瞄火力的Lanchester方程、平方律的Lanchester方程和考虑了信息对抗因素的Lanchester方程进行离散化,并给出了对应的离散方程。
(1)间瞄火力的Lanchester方程
公式
离散化后的公式如下:
\[\left\{\begin{matrix} R(k+1) = R(k) - a_lB(k)R(k) \\ B(k+1) = B(k) - b_lB(k)R(k) \end{matrix}\right. \tag{1}\]参数说明
- $R(k)$、$B(k)$ 分别表示红、蓝双方在 $k$ 的兵力情况,此处取初值为 $R_0=8000$、$B_0=10000$ ;
- $b_l$ 、$a_l$分别表示红、蓝双方战斗单位的作战效能,此处取 $b_l=0.00001$ 、$a_l=0.00002$。(一定要注意这里!$b_l$ 、$a_l$ 的位置是反的!不是按照顺序给了红、蓝双方,这篇论文在引言和第1.2节中的定义有冲突,为写公式不出错,我采用了作者第1.2节的写法。)
Python 代码实现
定义了一个LinearLaw()
函数来实现间瞄火力的Lanchester方程,代码如下。
def LinearLaw(R, B, b_l, a_l, t):
R.append(R[t] - a_l * B[t] * R[t])
B.append(B[t] - b_l * B[t] * R[t])
return R, B
这里有个判断哪一方交战胜利的等式,如果红、蓝双方兵力满足下面等式 \(R_0b_l>B_0a_l\) 则说明红方必将获胜。代码如下
elif mode == "LinearLaw": # 根据间瞄火力的胜负条件做比较
if R0 * b > B0 * a:
print("红方将【取得胜利】!")
else:
print("蓝方将【取得胜利】!")
仿真结果如下图所示,源代码将在文章的末尾给出。
(2)平方律的Lanchester方程
公式
离散化后的公式如下:
\[\left\{\begin{matrix} R(k+1) = R(t) - a_sB(t) \\ B(k+1) = B(k) - b_sR(t) \end{matrix}\right. \tag{2}\]参数说明
- $R(k)$、$B(k)$ 分别表示红、蓝双方在 $k$ 的兵力情况,此处取初值为 $R_0=8000$、$B_0=10000$ ;
- $b_s$ 、$a_s$分别表示红、蓝双方战斗单位在单位时间内平均毁伤对方战斗成员的数量,此处取 $b_s=0.1$ 、$a_s=0.2$。(一定要注意这里!$b_s$ 、$a_s$ 的位置是反的!不是按照顺序给了红、蓝双方,这篇论文在引言和第1.2节中的定义有冲突,为写公式不出错,我采用了作者第1.2节的写法。)
Python 代码实现
定义了一个SquareLaw()
函数来实现平方律的Lanchester方程,代码如下。
def SquareLaw(R, B, b_s, a_s, t):
R.append(R[t] - a_s * B[t])
B.append(B[t] - b_s * R[t])
return R, B
这里有个判断哪一方交战胜利的等式,如果红、蓝双方兵力满足下面等式
\[R_0^2b_l>B_0^2a_l\]则说明红方必将获胜。代码如下
R0_square = R0 ** 2 # 红方兵力的平方
B0_square = B0 ** 2 # 蓝方兵力的平方
if R0_square * b > B0_square * a: # 根据平方律的胜负条件做比较
print("红方将【取得胜利】!")
else:
print("蓝方将【取得胜利】!")
仿真结果如下图所示,源代码将在文章的末尾给出。
(3)信息对抗因素的Lanchester方程
公式
离散化后的公式如下:
\[\left\{\begin{matrix} R(k+1) = R(t) - (1-f_r)s_bb_sB(k)\varepsilon_b - (1-(1-f_r)s_b)b_lB(k)R(k)\varepsilon_b\\ B(k+1) = B(k) - (1-f_b)s_ra_sR(k)\varepsilon_r - (1-(1-f_b)s_r)a_lB(k)R(k)\varepsilon_r \end{matrix}\right. \tag{3}\]注意:这篇论文给出的公式是错的,在计算 $B(k+1)$ 时,下面的等式最后一项括号里面的符号应为$(1-(1-\boldsymbol{f_b})s_r)$,而非原文中的$(1-(1-\boldsymbol{f_r})s_r)$。
参数说明
- $R(k)$、$B(k)$ 分别表示红、蓝双方在 $k$ 的兵力情况,此处取初值为 $R_0=8000$、$B_0=10000$ ;
- $b_l$ 、$a_l$分别表示红、蓝双方战斗单位的作战效能,此处取 $b_l=0.00001$ 、$a_l=0.00002$;
- $b_s$ 、$a_s$分别表示红、蓝双方战斗单位在单位时间内平均毁伤对方战斗成员的数量,此处取 $b_s=0.1$ 、$a_s=0.2$;
- $f_r$、$f_b$ 为红、蓝双方的伪装能力系数,此处取 $f_r=0.6$、$f_b=0.2$;
- $s_r$、$s_b$ 为红、蓝双方的侦察能力,此处取 $s_r=0.6$、$s_b=0.2$ ;
- $\varepsilon_r$、$\varepsilon_b$ 为红、蓝双方的信息作战能力系数,此处取 $\varepsilon_r=4$、$\varepsilon_b=4$ 。
Python 代码实现
定义了一个MoLanMdl()
函数来实现间瞄火力的Lanchester方程,代码如下。
def MoLanMdl(R, B, b_s, a_s, b_l, a_l, f_r, s_r, f_b, s_b, e_r, e_b, t):
rValue = R[t] - (1-f_r)*s_b*b_s*B[t]*e_b - (1-(1-f_r)*s_b)*b_l*B[t]*R[t]*e_b
bValue = B[t] - (1-f_b)*s_r*a_s*R[t]*e_r - (1-(1-f_b)*s_r)*a_l*B[t]*R[t]*e_r
R.append(rValue)
B.append(bValue)
return R, B
这里没给双方交战胜利的判断条件。
仿真结果如下图所示,源代码将在文章的末尾给出。
Python 代码
源码如下
# encoding: utf-8
"""
#-------------------------------------------------------------------#
# Lei Lie's Python Code #
#-------------------------------------------------------------------#
# @Project Name : Python代码 #
# @File Name : mainZhanDonghui.py #
# @Programmer : Lei Lie #
# @Start Date : 2021/5/11 #
# @Last Update : 2021/5/11 #
#-------------------------------------------------------------------#
# Function: #
# 论文《现代化战争条件下的兰切斯特战斗模型》的代码复现 #
#-------------------------------------------------------------------#
"""
import numpy as np
import matplotlib.pyplot as plt
def predict(R0, B0, b, a, mode):
print("——————————————————————————————————————————————")
print("战斗过程预测结果为:")
if mode == "SquareLaw":
R0_square = R0 ** 2 # 红方兵力的平方
B0_square = B0 ** 2 # 蓝方兵力的平方
if R0_square * b > B0_square * a: # 根据平方律的胜负条件做比较
print("红方将【取得胜利】!")
else:
print("蓝方将【取得胜利】!")
elif mode == "LinearLaw":
if R0 * b > B0 * a:
print("红方将【取得胜利】!")
else:
print("蓝方将【取得胜利】!")
def finalTroops(r, b):
print("红方剩余兵力为【", r, "】")
print("蓝方剩余兵力为【", b, "】")
def SquareLaw(R, B, b_s, a_s, t):
R.append(R[t] - a_s * B[t])
B.append(B[t] - b_s * R[t])
return R, B
def LinearLaw(R, B, b_l, a_l, t):
R.append(R[t] - a_l * B[t] * R[t])
B.append(B[t] - b_l * B[t] * R[t])
return R, B
def MoLanMdl(R, B, b_s, a_s, b_l, a_l, f_r, s_r, f_b, s_b, e_r, e_b, t):
rValue = R[t] - (1-f_r)*s_b*b_s*B[t]*e_b - (1-(1-f_r)*s_b)*b_l*B[t]*R[t]*e_b
bValue = B[t] - (1-f_b)*s_r*a_s*R[t]*e_r - (1-(1-f_b)*s_r)*a_l*B[t]*R[t]*e_r
R.append(rValue)
B.append(bValue)
return R, B
if __name__ == '__main__':
# 初始参数
R0 = 8000 # 红方兵力
B0 = 10000 # 蓝方兵力
b_l = 0.00001 # 红方战斗单位作战效能
a_l = 0.00002 # 蓝方战斗单位作战效能
b_s = 0.2 # 红方战斗单位在单位时间平均毁伤对方战斗成员的数量
a_s = 0.1 # 蓝方战斗单位在单位时间平均毁伤对方战斗成员的数量
R = [R0, ] # 用于记录红方兵力变化的列表
B = [B0, ] # 用于记录蓝方病理变化的列表
T = 100 # 仿真总步长
dt = 1 # 时间间隔
# mode = "SquareLaw"
# mode = "LinearLaw"
mode = "ModernizedLanchesterModel"
if mode == "SquareLaw": # 采用平方律的战斗过程
# 预测战斗进程
predict(R0, B0, b_s, a_s, mode)
for t in np.arange(0, T, dt):
SquareLaw(R, B, b_s, a_s, t)
if R[-1] < 1e-6 or B[-1] < 1e-6:
break
elif mode == "LinearLaw": # 采用线性律的战斗过程
predict(R0, B0, b_l, a_l, mode)
for t in np.arange(0, T, dt):
LinearLaw(R, B, b_l, a_l, t)
if R[-1] < 1e-6 or B[-1] < 1e-6:
break
elif mode == "ModernizedLanchesterModel":
# 初始化参数
f_r = 0.6 # 红方的伪装能力系数
s_r = 0.6 # 红方的侦察能力
f_b = 0.2 # 蓝方的伪装能力系数
s_b = 0.2 # 蓝方的侦察能力
epsilon_r = 4 # 红方信息作战能力系数
epsilon_b = 4 # 蓝方信息作战能力系数
for t in np.arange(0, T, dt):
MoLanMdl(R, B, b_s, a_s, b_l, a_l, f_r, s_r, f_b, s_b, epsilon_r, epsilon_b, t)
if R[-1] < 1e-6 or B[-1] < 1e-6:
break
print("——————————————————————————————————————————————")
print("战斗过程预测结果为:")
if R[-1] > B[-1]:
print("红方将【取得胜利】!")
else:
print("蓝方将【取得胜利】!")
print("——————————————————————————————————————————————")
finalTroops(R[-1], B[-1]) # 打印红、蓝双方最终剩余兵力
print("——————————————————————————————————————————————")
'''画图'''
tPlot = np.arange(0, len(R) * dt, dt)
plt.figure(1)
plt.plot(tPlot, R, '--r', label='Attribution of red forces')
plt.plot(tPlot, B, 'b', label='Attribution of blue forces')
plt.xlabel("Time (round)")
plt.ylabel("The number of forces")
# plt.xlim(0, len(R) * dt)
# plt.ylim(0, B0 + 0.5)
plt.title("Lanchester Model Simulation"+" ("+mode+")")
plt.legend()
plt.show()
代码解释
(1)模式选择
# mode = "SquareLaw"
# mode = "LinearLaw"
mode = "ModernizedLanchesterModel"
这三行代码用来选择要仿真的模式。
mode = "SquareLaw"
即仿真验证平方律的Lanchester方程。
mode = "LinearLaw"
即仿真验证间瞄火力的Lanchester方程。
mode = "ModernizedLanchesterModel"
即仿真验证现代战争模式下的Lanchester方程
(2)进行仿真
if mode == "SquareLaw": # 采用平方律的战斗过程
# 预测战斗进程
predict(R0, B0, b_s, a_s, mode)
for t in np.arange(0, T, dt):
SquareLaw(R, B, b_s, a_s, t)
if R[-1] < 1e-6 or B[-1] < 1e-6:
break
elif mode == "LinearLaw": # 采用线性律的战斗过程
predict(R0, B0, b_l, a_l, mode)
for t in np.arange(0, T, dt):
LinearLaw(R, B, b_l, a_l, t)
if R[-1] < 1e-6 or B[-1] < 1e-6:
break
elif mode == "ModernizedLanchesterModel":
# 初始化参数
f_r = 0.6 # 红方的伪装能力系数
s_r = 0.6 # 红方的侦察能力
f_b = 0.2 # 蓝方的伪装能力系数
s_b = 0.2 # 蓝方的侦察能力
epsilon_r = 4 # 红方信息作战能力系数
epsilon_b = 4 # 蓝方信息作战能力系数
for t in np.arange(0, T, dt):
MoLanMdl(R, B, b_s, a_s, b_l, a_l, f_r, s_r, f_b, s_b, epsilon_r, epsilon_b, t)
if R[-1] < 1e-6 or B[-1] < 1e-6:
break
这里的三个if()
判断就是用来判断执行何种模式的Lanchester方程仿真验证的。
总结
- 这篇论文没有给出如何将连续域的Lanchester方程转换为离散域的差分方程,得研究一下如何将微分方程转换成差分方程的方法。
- 不过,微分方程转换成离散方程再用代码来进行仿真验证,就不用费心费力地去算微分方程的解了,值得学习一下思路。