avatar

元胞自动机

内容来自:

https://www.zhihu.com/question/21929655

演化规则(二维)

  1. 活细胞周围的细胞数小于2个或多于3个则死亡;

  2. 活细胞周围有2或3个细胞可以继续存活;

  3. 死细胞周围恰好有3个细胞则会复活。

在交通领域的应用

  • 经典的NaSch模型,模拟了车辆在一维高速公路上的行驶状态

v2-b2257119ede75ba235cbd938d0736004_hd

  • 将CA模型推广到二维,可以仿真换道的行人流或车流

v2-8f6ba0eead51c46ed921d33884c1cbf6_hd

  • 通过设置更复杂的规则,可以用元胞自动机仿真更真实的情况。例如在对向行走的行人流情境下,元胞们会仿真行人的排队特性,从而避免冲突相撞。v2-332188684ca16eb388779eb1af2789a9_hd

Python代码

NaSch模型

  • 老规矩,先调包,并创建一个图像
import matplotlib as mpl
import matplotlib.pyplot as plt
import random
# 创建图像
fig = plt.figure(figsize=(10,1))
  • 设置模型的参数,相当于一个遥控器,哪里不对点哪里~
# 模型参数设置
numofcell = 20 # 道路长度
numofcar = 12 # 空间中的车辆数
max_time = 100 # 设置最大时间步
max_speed = 5 # 允许的车辆最大速度
p_slowdown = 0.3 # 随机慢化概率
pause_time = 0.1 # 刷新时间(每一帧持续的时间)
cell_size = 15 # 元胞的大小
  • 定义一个函数来构建一维空间,空间的长度就是道路长度,相当于用一系列和X轴或Y轴平行的直线,绘制一排小网格,每个小网格的中心,相当于(i,0),其中,i=1,2,…,numofcell
# 函数:构建一维空间
def Plot_Space():
for i in range(1, numofcell): plt.plot([i-0.5, i-0.5], [-0.5, 0.5], '-k', linewidth = 0.5)
plt.axis([-0.5, numofcell-0.5, -0.5, 0.5])
plt.xticks([]);plt.yticks([])

img)img

  • 定义一个函数来获取和前车的距离,从而避免两车相撞。在这里采用了周期性边界,即从道路末端驶出的小车会重新回到起点,相当于一个环路。
# 函数:获取和前车的距离
def get_empty_front(link, numofcell, indexofcell):
link2 = link * 2 # 周期性边界
num = 0; i = 1
while (link2[indexofcell + i]) == None:
num += 1; i += 1
return num
  • 在道路空间中随机生成numofcar个初始元胞,并赋予随机的初始速度(不大于已经设置好的最大速度)。道路被车辆占有的状态储存在列表link中,若元胞中没有车辆,则link对应的位置为“None”;若元胞中有车,link对应的位置储存车辆的速度。(可以开开脑洞,大胆地尝试不同初始状态噢)
# 随机生成初始元胞
Plot_Space()
link = [None] * numofcell
num = 0
while num != numofcar:
sj = random.randint(0, numofcell - 1)
if link[sj] == None:
link[sj] = random.randint(0, 5)
num += 1
  • 在0~max_time的时间步内,进行NaSch模型的演化,模型演化的四个步骤:

加速:若还没到速度最大值,速度就加1

减速:如果速度值大于前方的空元胞数,有撞车风险,则减速至前方的空元胞数目

随机慢化:司机以p_slowdown的概率随机踩刹车,使速度减1

位置更新:新的位置为当前位置+当前速度,同时更新所有车辆的位置

# NaSch模型
for t in range(0, max_time):
for cell in range(0, numofcell):
if link[cell] != None:
# 加速
link[cell] = min(link[cell] + 1, max_speed)
# 减速
link[cell] = min(link[cell], get_empty_front(link, numofcell, cell))
# 随机慢化
if random.random() <= p_slowdown:
link[cell] = max(link[cell] - 1, 0)
# 位置更新
nlink = [None] * numofcell
for cell in range(0, numofcell):
if link[cell] != None:
new_index = cell + link[cell]
if new_index >= numofcell:
new_index -= numofcell
nlink[new_index] = link[cell]
link = nlink
  • 绘制当前时间步车辆位置的图像,注意这里有缩进,说明上一段NaSch模型演化代码中的for循环还没有结束呦~
x1 = []
for i in range(0,len(link)):
if link[i] != None:
x1.append(i)
Plot_Space()
plt.plot(x1, [0] * numofcar, 'sk', markersize=cell_size)
plt.xlabel('timestep:' + str(t))
  • 让图片动起来(同样注意缩进),plt.pause()函数让当前的图像维持pause_time长的时间,随后plt.cla()函数将整个图像擦除。下一个时间步,继续绘制图像,保留一段时间,并擦除,再绘制图像……就能源源不断地产生动画啦!你学会了吗?
plt.pause(pause_time)
plt.cla()

终于写完代码啦,RUN一下!

仔细看,拥堵带也会跳鬼步舞,逐渐向后传播的。

v2-3b6878489f851d07be894b5fb569886d_hd

操控我的“遥控器”,给它一个初始状态,就可以开启“阅兵模式”啦,你猜我是怎么做到的?

img

给我开“瞬移”挂,只要动的足够快,你就分不清我到底是往左跑还是往右跑

v2-3b6878489f851d07be894b5fb569886d_hd


内容参考http://wulixb.iphy.ac.cn/fileWLXB/journal/article/wlxb/2001/3/PDF/w20010315.pdf

如果说上车到出发需要一个时间单位

1 2 3 4 5(乘车点) 6
o o o o
Author: Michelle19l
Link: https://gitee.com/michelle19l/michelle19l/2020/07/10/建模/元胞自动机/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
Donate
  • 微信
    微信
  • 支付寶
    支付寶