本文章基于作者先前的文章“城市轨道行车组织运行时刻表自动化生成---使用python代码实现”在基础上进行列车乘务员自动化排班的功能,使得代码更加智能。喜欢文章给作者点点赞把!
- 一、客流量计算
1.定义早高峰小时客流量:设定早高峰时段的小时客流量为43000人。
2.时间段比例:根据不同时间段的比例,计算每个时间段的客流量。
- 二、列车编组和容量
1.列车编组:每列列车由6辆车组成。
2.车辆定员:每辆车的定员为310人,因此每列列车的总定员为6 * 310人。
- 三、 区间运行时间和停站时间
2.上行方向运行时间:各区间的运行时间已定义。
3.下行方向运行时间:各区间的运行时间已定义。
4.停站时间:各站的停站时间分别定义了上行和下行方向的停站时间。
5.折返时间:列车折返所需的时间。
6.进场和出场时间:列车进场和出场所需的时间。
- 四、满载率和列车数量计算
7.满载率:通过随机函数为每个时间段生成一个满载率,特别是在高峰时段(如06:30和16:30),满载率较高。
8.列车数量:根据每个时间段的客流量和满载率,计算所需的列车数量。
- 五、列车循环时间计算
上行时间:计算上行方向总运行时间和停站时间的总和。
下行时间:计算下行方向总运行时间和停站时间的总和。
循环时间:包括上行时间、下行时间、折返时间、进场时间和出场时间。
- 六、列车运行图生成
起始时间:设定列车的起始运行时间为05:00。
列车池:记录每列车的下一次可用时间。
列车运行时刻表:根据计算出的列车数量和运行间隔时间,为每个时间段生成列车的具体运行时刻表,包括各站的到达和出发时间,以及满载率。
- 七、 乘务员排班表生成
1.乘务员列表:定义50名乘务员。
2.乘务员池:使用字典记录每名乘务员的下一次可用时间、累计工作时间和当天工作时间。
3.乘务员分配:
3.1. 每当一列列车需要分配乘务员时,从乘务员池中选择一名当前时间可用且当天工作时间未超过8小时的乘务员进行分配。
3.2. 乘务员的工作时间分配有以下特点:
3.2.1 每次工作时间不超过2小时。
3.2.2每2小时工作时间后有30分钟的休息时间(如果连续工作达到2小时)。
4.乘务员排班记录:记录乘务员的工作开始时间和结束时间。
代码部分:
import numpy as np
import pandas as pd
from datetime import datetime, timedelta
import random
# 定义早高峰小时客流量
peak_hour_passenger_flow = 43000
# 表1中的客流量比例
time_period_proportions = [
0.08, 0.43, 1, 0.76, 0.51, 0.41, 0.47, 0.59, 0.64, 0.64,
0.69, 0.73, 0.88, 0.62, 0.39, 0.31, 0.26, 0.20, 0.08,
]
# 定义时间段(起始时间)
time_periods = [
"05:00", "05:30", "06:30", "07:30", "08:30", "09:30", "10:30", "11:30", "12:30",
"13:30", "14:30", "15:30", "16:30", "17:30", "18:30", "19:30", "20:30", "21:30", "22:30"
]
# 计算每个时间段的客流量
passenger_flow = [round(peak_hour_passenger_flow * proportion) for proportion in time_period_proportions]
# 列车编组和车辆定员
train_capacity = 6 * 310 # 6辆车,每辆车310人
# 定义区间运行时间和停站时间
section_times_up = [222, 250, 232, 175, 180, 210, 265] # 上行方向停站时间(单位:秒)
section_times_down = [215, 245, 240, 182, 212, 300, 250] # 下行方向停站时间(单位:秒)
stop_times_up = [40, 30, 50, 30, 30, 50, 30, 40] # 各站停站时间(上行方向,单位:秒)
stop_times_down = [40, 30, 50, 30, 30, 50, 30, 40] # 各站停站时间(下行方向,单位:秒)
turnaround_time = 200 # 折返时间(单位:秒)
entry_time = 260 # 进场时间(单位:秒)
exit_time = 270 # 出场时间(单位:秒)
stations = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H']
# 满载率计算,加入随机性
def get_full_load_rate(period):
if time_periods[period] in ["06:30", "16:30"]:
return np.random.uniform(1.1, 1.2)
else:
return np.random.uniform(0.7, 0.9)
full_load_rates = [get_full_load_rate(i) for i in range(len(time_periods))]
# 计算各时间段的列车数量,加入随机性
train_numbers = [
np.ceil((passenger_flow[i] * np.random.uniform(0.9, 1.1)) / (train_capacity * full_load_rates[i])).astype(int)
for i in range(len(passenger_flow))
]
# 计算列车运行间隔时间(单位:秒)
time_intervals = [1800 if i == 0 or i == len(time_periods) - 1 else 3600 for i in range(len(time_periods))] # 修改后的每个时间段总时间
departure_intervals = [int(np.ceil(time_intervals[i] / train_numbers[i])) for i in range(len(train_numbers))]
# 计算一列列车的循环时间(包括上行、下行、折返和停站时间)
def calculate_cycle_time():
up_time = sum(section_times_up) + sum(stop_times_up)
down_time = sum(section_times_down) + sum(stop_times_down)
return up_time + down_time + 2 * turnaround_time + entry_time + exit_time
cycle_time_seconds = calculate_cycle_time()
cycle_time = timedelta(seconds=cycle_time_seconds) # 转换为timedelta对象
# 生成列车运行图和乘务员排班表
timetable = []
crew_schedule = []
train_id = 1
# 起始时间
start_time = datetime.strptime("05:00", "%H:%M")
# 列车池,记录每列车的下一次可用时间
train_pool = []
# 创建乘务员列表
crew_members = [f"乘{i+1}" for i in range(50)]
# 乘务员池,记录每个乘务员的下一次可用时间和累计工作时间
crew_pool = {member: (start_time, timedelta(0), timedelta(0)) for member in crew_members} # (下一次可用时间, 累计工作时间, 当天工作时间)
for period in range(len(time_periods)):
departure_time = start_time + timedelta(seconds=sum(time_intervals[:period]))
current_train_numbers = train_numbers[period]
active_trains = []
for _ in range(current_train_numbers):
# 检查列车池中是否有可用列车
if train_pool and train_pool[0][1] <= departure_time:
# 复用已有列车
train_no, available_time = train_pool.pop(0)
else:
# 创建新列车
train_no = f"01{train_id:03d}"
train_id += 1
active_trains.append(train_no)
for train_no in active_trains:
# 初始化时间
current_time = departure_time
# 分配乘务员
for crew_member, (available_time, total_work_time, daily_work_time) in crew_pool.items():
if available_time <= current_time and daily_work_time < timedelta(hours=8):
work_time = min(cycle_time, timedelta(hours=2) - (total_work_time % timedelta(hours=2))) # 每次工作时间不超过2小时
rest_time = timedelta(minutes=30) if (total_work_time + work_time) % timedelta(hours=2) == timedelta(0) else timedelta(0)
crew_pool[crew_member] = (current_time + work_time + rest_time, total_work_time + work_time, daily_work_time + work_time)
break
crew_schedule.append([crew_member, train_no, current_time.strftime("%H:%M:%S"), (current_time + work_time).strftime("%H:%M:%S")])
# 上行方向运行
for i, station in enumerate(stations):
if i == 0:
# 进场时间
current_time += timedelta(seconds=entry_time)
else:
# 区间运行时间
current_time += timedelta(seconds=section_times_up[i - 1])
# 记录到达时间
arrive_time = current_time
# 停站时间
current_time += timedelta(seconds=stop_times_up[i])
# 记录出发时间
depart_time = current_time
# 添加到时刻表
timetable.append([train_no, station, arrive_time.strftime("%H:%M:%S"), depart_time.strftime("%H:%M:%S"), round(full_load_rates[period], 2)])
# 折返时间
current_time += timedelta(seconds=turnaround_time)
# 下行方向运行
for i, station in enumerate(reversed(stations)):
if i == 0:
# 出发时间
current_time += timedelta(seconds=0)
else:
# 区间运行时间
current_time += timedelta(seconds=section_times_down[i - 1])
# 记录到达时间
arrive_time = current_time
# 停站时间
current_time += timedelta(seconds=stop_times_down[i])
# 记录出发时间
depart_time = current_time
# 添加到时刻表
timetable.append([train_no, station, arrive_time.strftime("%H:%M:%S"), depart_time.strftime("%H:%M:%S"), round(full_load_rates[period], 2)])
# 出场时间
current_time += timedelta(seconds=exit_time)
# 更新列车池
next_available_time = current_time + timedelta(seconds=turnaround_time)
train_pool.append((train_no, next_available_time))
train_pool.sort(key=lambda x: x[1])
# 调整下一列车的发车时间,避免重叠
departure_time += timedelta(seconds=departure_intervals[period])
# 创建DataFrame并保存到Excel文件
df_timetable = pd.DataFrame(timetable, columns=["列车号", "站点名称", "到达时间", "出发时间", "满载率"])
df_crew_schedule = pd.DataFrame(crew_schedule, columns=["乘务员", "列车号", "工作开始时间", "工作结束时间"])
# 保存为Excel文件到D盘
file_path_timetable = "D:/train_timetable_randomized.xlsx"
file_path_crew_schedule = "D:/crew_schedule.xlsx"
df_timetable.to_excel(file_path_timetable, index=False)
df_crew_schedule.to_excel(file_path_crew_schedule, index=False)
print(f"列车运行图已生成并保存为 {file_path_timetable} 文件。")
print(f"乘务员排班表已生成并保存为 {file_path_crew_schedule} 文件。")