python 利用simpy工具包设计一个仿真应用

这里仿真了一个直行红绿灯路口。

假设有一条红绿灯路口的直行车道(假设只有一条,一条和多条相似),现在有一些车要过红绿灯,绿灯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

仿真红绿灯单车道单行显示

猜你喜欢

转载自blog.csdn.net/weixin_58196051/article/details/134188932