这里仿真了一个直行红绿灯路口。
假设有一条红绿灯路口的直行车道(假设只有一条,一条和多条相似),现在有一些车要过红绿灯,绿灯20s,黄灯5s,路口40m 这里采用网上五菱宏光s的加速度和刹车数据,零百14.3s左右,100码刹车42m,仪器显示加速度数值约为40km/h 我们假设均匀加减速,启动加速度取2m/s^2,刹车加速度取10m/s^2,设最大速度10m/s(36km/h),车长4.4m,这样最大刹车距离为5m
SimPy 是 Python 中一个流行的离散事件模拟框架。它允许用户使用 Python 编程语言进行事件驱动的模拟。SimPy 可以用于构建复杂的离散事件系统,如排队系统、库存系统等
详情请看代码如下:
import simpy
import random
import matplotlib.pyplot as plt
# 有一条红绿灯路口的直行车道(假设只有一条,一条和多条相似),现在有一些车要过红绿灯,绿灯20s,黄灯5s,路口40m
# 这里采用网上五菱宏光s的加速度和刹车数据,零百14.3s左右,100码刹车42m,仪器显示加速度数值约为40km/h
# 我们假设均匀加减速,启动加速度取2m/s^2,刹车加速度取10m/s^2,设最大速度10m/s(36km/h),车长4.4m,这样最大刹车距离为5m
# 最开始采用 每辆车只会在前面车启动1~3s后 启动,但是感觉像是一个一个上,慢慢改成现在的样子
class Traffic_Light(object):
def __init__(self, traffic_light_time, ):
# 0红1绿2黄
self.state = 0 # 开始红灯
self.time = 5 # 五秒后再变灯
self.traffic_light_time = traffic_light_time # 红绿灯时间
def change_light(self):
# 变灯过程
if self.state == 0:
self.state = 1
elif self.state == 1:
self.state = 2
else:
self.state = 0
self.time = self.traffic_light_time[self.state]
def getState(self): # 返回当前灯
return self.state
def run(self, env): # 开启红绿灯
self.env = env
while True:
yield env.timeout(self.time)
self.change_light() # 变灯
if self.state == 0:
print("红灯,==========时间:", env.now, "======================================")
elif self.state == 1:
print("绿灯,==========时间:", env.now, "======================================")
else:
print("黄灯,==========时间:", env.now, "======================================")
class Vehicle(object):
def __init__(self, env, delay, id, position_len, max_speed, acceleration): # 构造函数,
self.env = env # 车辆所处的环境
self.delay = delay # 比前车晚的启动时间
self.id = id
self.position_len = position_len # 到路口的距离,归零就结束
self.speed = max_speed # 当前速度
self.acceleration = acceleration # 加速度
self.ultimate_braking_distance = max_speed ** 2 / 2 / -acceleration[1] # 极限刹车距离
self.maximum_error = max_speed * time_particles # 最大误差,一个时间颗粒能跑最远距离
def run(self):
while True:
vi = vehicle.index(self)
now_a = 0
if vi > 0:
s = (self.position_len - vehicle[
vi - 1].position_len - self.ultimate_braking_distance - self.maximum_error)
if self.speed > vehicle[vi - 1].speed or s < 0: # 比前车快或者有点近了
# 通过与前车距离和速度差减速,留下最短刹车距离和误差做缓冲
if not s <= 0:
now_a = -(self.speed - vehicle[vi - 1].speed) ** 2 / 2 / s # 慢慢刹车
else:
now_a = -10
else:
now_a = self.acceleration[0]
else: # 是第一辆车
if traffic_light.getState() == 1: # 绿灯
now_a = self.acceleration[0] # 直接往前开
else: # 黄灯或者红灯 s = v^2/2a
if self.speed ** 2 / 2 / -acceleration[1] > self.position_len: # 刹不住的
now_a = self.acceleration[0] # 直接往前开
else:
if not self.position_len == 0:
now_a = -self.speed ** 2 / 2 / self.position_len # 慢慢刹车
else:
now_a = 0
if now_a > self.acceleration[0]:
now_a = self.acceleration[0]
if now_a < self.acceleration[1]:
print(self.id, "正在用脸停车,脸刹也止不住")
now_a = self.acceleration[1]
self.speed += now_a * time_particles # 微分思想,在短短时间内变速
if self.speed > max_speed: # 不允许超过最大速度
self.speed = max_speed
if self.speed <= 0:
self.speed = 0 # 负数减速到0
self.position_len -= self.speed * time_particles # 减少当前距离
print(self.id, "当前速度:", self.speed, "加速度:", now_a, "距离:", self.position_len, "时间:", env.now)
yield env.timeout(time_particles) # 等待一下再看看
if self.position_len <= -0.5: # 开过去了
self.firing = True
print(self.id, "已通过,时间:", env.now)
vehicle.remove(self)
break
def Vehicle_Appears(env, appears_time): # 随机时间出现车辆
all_vehicle = 0
while True:
yield env.timeout(random.uniform(appears_time[0], appears_time[1])) # 每隔随机时间出现一辆车
if len(vehicle) >= max_wait_len: # 车太多了,就不进来了
continue
vehicle.append(Vehicle(env, random.uniform(delay_time[0], delay_time[1]), all_vehicle, position_len, max_speed,
acceleration)) # 添加一个车辆
print("新车辆", all_vehicle, "到了,\t时间:", env.now) # 车辆启动
all_vehicle += 1
env.process(vehicle[-1].run()) # 车辆进入道路
def plt_Refresh(env):
while True:
plt.clf() # 清屏
plt.xlim(-2, position_len + 2)
plt.ylim(-1, 6)
# 绘图
plt.scatter(0, -0.5, 1000,
"r" if traffic_light.state == 0 else ("g" if traffic_light.state == 1 else "y")) # 红绿灯
for i in vehicle:
plt.scatter(i.position_len, i.id % 6, 50, coler[i.id % 6])
plt.text(i.position_len, i.id % 6 + 0.2, i.id, fontsize=12)
# 刷新图形
plt.draw()
plt.pause(time_particles / 10)# 不想真等几分钟
yield env.timeout(time_particles)
time_particles = 0.1 # 时间颗粒,车辆操作最小时间,大了不够细致,太小了运行太慢
delay_time = [0.5, 1.2] # 开车延时 后面通过各种实验和修改,废弃了这个方法
traffic_light_time = [10, 20, 5] # 红绿灯时间
appears_time = [1, 2] # 来车时间
run_time = 120 # 运行时间
position_len = 40 # 路口长度
max_speed = 10 # 最大速度
acceleration = [2, -10] # 加速度
max_wait_len = 5 # 最多5辆车排队
spacing = 6 # 等待中距离前车车头的距离
# 参数设置完毕
traffic_light = Traffic_Light(traffic_light_time) # 红绿灯
vehicle = [] # 汽车列表
# 绘图
plt.figure()
coler = ["r", "m", "y", "g", "c", "b", "k"] # 颜色
env = simpy.Environment() # 设置环境并启动模拟
env.process(traffic_light.run(env)) # 启动红绿灯
env.process(plt_Refresh(env))
env.process(Vehicle_Appears(env, appears_time)) # 开始来车
env.run(until=run_time) # 运行模拟
plt.show() # 遍历完成后不消失
结果如下:
仿真红绿灯单车道多行显示
虽然这里各个车(带数字的浮点)是分开的,但是这只是为了方便观察,可以将第123,124行的 i.id % 6 改为1
仿真红绿灯单车道单行显示