import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
from scipy.spatial.distance import euclidean
from shapely.geometry import Polygon, Point, LineString
import random
from datetime import datetime
import os
import math
# -------------------------- 从Excel读取任务参数 --------------------------
EXCEL_PATH = "output.xlsx"
try:
task_df = pd.read_excel(EXCEL_PATH)
required_columns = [
"任务类别", "任务持续时间", "跟踪距离",
"移动任务", "航速", "航向",
"点位X轴坐标", "点位Y轴坐标", "时间" # 新增需求:增加任务开始时间列
]
missing_cols = [col for col in required_columns if col not in task_df.columns]
if missing_cols:
raise ValueError(f"Excel文件缺少必需列:{', '.join(missing_cols)},请检查列名是否匹配模板")
# 读取所有任务参数
TASK_TYPES = task_df["任务类别"].tolist()
TASK_DURATIONS = task_df["任务持续时间"].astype(float).tolist()
TASK_TRACKING_DIST = task_df["跟踪距离"].astype(float).tolist()
MOVING_TASKS = task_df["移动任务"].astype(bool).tolist()
MOVING_SPEEDS = task_df["航速"].astype(float).tolist()
MOVING_COURSES = task_df["航向"].astype(float).tolist()
TASK_LOCATIONS = list(zip(
task_df["点位X轴坐标"].astype(float).tolist(),
task_df["点位Y轴坐标"].astype(float).tolist()
))
TASK_LOCATIONS = [(round(x, 2), round(y, 2)) for x, y in TASK_LOCATIONS]
TASK_START_TIMES = task_df["时间"].astype(float).tolist() # 新增:任务开始时间
TOTAL_TASKS_FROM_EXCEL = len(TASK_TYPES)
# 筛选必须执行的任务(S1, S2, S3)和可选任务(S4)
REQUIRED_TASK_IDS = [
idx for idx, task_type in enumerate(TASK_TYPES)
if task_type in ['S1', 'S2', 'S3']
]
OPTIONAL_TASK_IDS = [
idx for idx, task_type in enumerate(TASK_TYPES)
if task_type == 'S4'
]
print(f"成功从Excel读取{TOTAL_TASKS_FROM_EXCEL}个任务的参数")
print(f"必须执行的任务(S1,S2,S3)ID:{REQUIRED_TASK_IDS}")
print(f"可选执行的任务(S4)ID:{OPTIONAL_TASK_IDS}")
if not REQUIRED_TASK_IDS:
print("警告:未检测到必须执行的任务(S1,S2,S3)")
except FileNotFoundError:
raise FileNotFoundError(f"未找到Excel文件:{EXCEL_PATH},请检查文件路径是否正确")
except Exception as e:
raise Exception(f"读取Excel失败:{str(e)}")
# -------------------------- 基础参数设置 --------------------------
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False # 解决负号显示问题
SHIP_SPEEDS = [20, 24, 26, 30] # 节
SHIP_START_POINTS = [(187, 175), (169, 112), (50, 88), (73, 214)] # 4艘舰艇初始位置
EXIT_POLYGON = Polygon([(194.0, 177.6), (173.4, 106.9), (42.5, 81.2),
(68.1, 220.7), (144.6, 211.5)])
Cruise_line = [(187.05, 175.1), (168.65, 112.1), (50, 88.75), (73, 214.05), (142.45, 205.75)]
cruise_polygon = Polygon(Cruise_line)
cruise_boundary = LineString(cruise_polygon.exterior.coords)
SHIP_Handling_radius = [5, 3, 1, 1] # 处置半径
SHIP_Handling_amount = [6, 5, 3, 2] # 处置数量
# 周期检查点(ABCD点) - 新增需求
CHECK_POINTS = {
'A': (187.05, 175.1),
'B': (168.65, 112.1),
'C': (50, 88.75),
'D': (73, 214.05)
}
CHECK_POINT_ORDER = ['A', 'B', 'C', 'D'] # 检查点顺序
CYCLE_DURATION = 12 # 约束周期:12小时
# 任务优先级和响应时间约束 - 新增需求
TASK_PRIORITIES = {
'S1': 1, # 最高优先级
'S2': 2,
'S3': 3,
'S4': 4 # 最低优先级
}
MAX_RESPONSE_TIMES = {
'S1': 5, # 小时
'S2': 6,
'S3': 6,
'S4': 24
}
# 算法参数
KNOTS_TO_KMH = 1
NAUTICAL_TO_KM = 1
PENALTY_FACTOR = 0.5 # 约束不满足时的适应度惩罚系数
# 舰艇航迹配置(颜色、线型、标记,4艘舰艇各不同)
SHIP_TRAJECTORY_CONFIG = [
{"color": "#1f77b4", "line_style": "-", "init_marker": "D", "task_marker": "o", "label": "舰艇1"},
{"color": "#ff7f0e", "line_style": "--", "init_marker": "D", "task_marker": "s", "label": "舰艇2"},
{"color": "#2ca02c", "line_style": "-.", "init_marker": "D", "task_marker": "^", "label": "舰艇3"},
{"color": "#d62728", "line_style": ":", "init_marker": "D", "task_marker": "p", "label": "舰艇4"}
]
# == == == == == 新增:周期检查点约束辅助函数 == == == == ==
def get_time_cycles(total_time):
"""获取所有时间周期"""
if total_time <= 0:
return []
cycle_count = int(np.ceil(total_time / CYCLE_DURATION))
return [[cycle * CYCLE_DURATION, (cycle + 1) * CYCLE_DURATION]
for cycle in range(cycle_count)]
def check_checkpoint_constraint(ship_tasks, total_time):
"""检查每12小时必须经过ABCD点的约束"""
cycles = get_time_cycles(total_time)
constraint_result = {
"总周期数": len(cycles),
"周期详情": [f"{cycle[0]}-{cycle[1]}h" for cycle in cycles],
"舰艇检查点检查": {}
}
unmet_count = 0
for ship_idx in range(len(ship_tasks)):
ship_task_history = []
# 收集舰艇的所有位置和时间点
for task in ship_tasks[ship_idx]:
ship_task_history.append({
"时间": task["舰艇出发出发时刻(小时)"],
"位置": task["舰艇出发坐标(x,y)"]
})
ship_task_history.append({
"时间": task["处置任务开始时刻(小时)"],
"位置": task["处置置任务开始坐标(x,y)"]
})
ship_task_history.append({
"时间": task["处置任务结束时刻(小时)"],
"位置": task["处置任务结束坐标(x,y)"]
})
# 按时间排序
ship_task_history.sort(key=lambda x: x["时间"])
cycle_check = []
for cycle_idx, (cycle_start, cycle_end) in enumerate(cycles):
# 检查该周期内是否经过所有检查点
visited_checkpoints = set()
# 检查任务历史中的点
for record in ship_task_history:
if cycle_start <= record["时间"] < cycle_end:
pos = record["位置"]
# 检查是否接近任何检查点(考虑一定的误差范围)
for cp_name, cp_pos in CHECK_POINTS.items():
distance = calc_distance(pos, cp_pos)
if distance < 0.5: # 0.5单位范围内视为经过
visited_checkpoints.add(cp_name)
# 检查是否经过所有检查点
if visited_checkpoints == set(CHECK_POINT_ORDER):
cycle_check.append(f"周期{cycle_idx + 1}({cycle_start}-{cycle_end}h):已经过所有检查点✅")
else:
missing_points = set(CHECK_POINT_ORDER) - visited_checkpoints
cycle_check.append(f"周期{cycle_idx + 1}({cycle_start}-{cycle_end}h):缺少检查点{missing_points}❌")
unmet_count += 1
constraint_result["舰艇检查点检查"][f"舰艇{ship_idx + 1}"] = cycle_check
constraint_result["约束状态"] = f"共{unmet_count}个(舰艇-周期)对未满足检查点约束"
return constraint_result, unmet_count
# == == == == == 新增:任务中断中断管理 == == == == ==
class TaskInterruptManager:
"""任务中断管理器"""
@staticmethod
def check_pending_tasks(current_time, ship_positions, ship_available_times):
"""
检查是否有需要立即处理的高优先级任务
返回需要中断当前任务的新任务ID列表
"""
pending_tasks = []
for task_id in range(TOTAL_TASKS_FROM_EXCEL):
task_type = TASK_TYPES[task_id]
task_start_time = TASK_START_TIMES[task_id]
# 如果任务已经超过最大响应时间,需要立即处理
if current_time > task_start_time + MAX_RESPONSE_TIMES[task_type]:
# 检查是否有舰艇可以更快到达
for ship_idx in range(len(ship_positions)):
if ship_available_times[ship_idx] <= current_time:
# 计算舰艇到达任务点的时间
target_pos = get_target_position(task_id, current_time)
distance = calc_distance(ship_positions[ship_idx], target_pos)
travel_time = calc_travel_time(SHIP_SPEEDS[ship_idx], distance)
# 如果能在剩余响应时间内到达,则需要处理
if travel_time <= MAX_RESPONSE_TIMES[task_type]:
pending_tasks.append({
"task_id": task_id,
"task_type": task_type,
"priority": TASK_PRIORITIES[task_type],
"ship_idx": ship_idx,
"urgency": (current_time - task_start_time) / MAX_RESPONSE_TIMES[task_type]
})
# 按优先级和紧急程度排序
pending_tasks.sort(key=lambda x: (x["priority"], x["urgency"]), reverse=True)
return pending_tasks
@staticmethod
def can_interrupt(current_task, new_task):
"""
判断是否可以中断当前任务以执行新任务
当前任务是S4且新任务优先级更高时可以中断
"""
if current_task is None:
return True
if current_task["任务类型"] == 'S4' and TASK_PRIORITIES[new_task["task_type"]] < TASK_PRIORITIES['S4']:
return True
return False
# == == == == == 原有辅助函数(保持不变) == == == == ==
def calc_course(from_pos, to_pos):
dx = to_pos[0] - from_pos[0]
dy = to_pos[1] - from_pos[1]
if dx == 0 and dy == 0:
return 0.0
math_angle = np.arctan2(dy, dx)
course = (90 - np.degrees(math_angle)) % 360
return round(course, 2)
def get_closest_cruise_point(end_pos):
end_point = Point(end_pos)
proj_dist = cruise_boundary.project(end_point)
closest_point = cruise_boundary.interpolate(proj_dist)
closest_pos = (round(closest_point.x, 2), round(closest_point.y, 2))
boundary_vertices = list(cruise_boundary.coords)[:-1]
min_x = min(v[0] for v in boundary_vertices)
max_x = max(v[0] for v in boundary_vertices)
min_y = min(v[1] for v in boundary_vertices)
max_y = max(v[1] for v in boundary_vertices)
cx, cy = closest_pos
if not (min_x - 1e-6 <= cx <= max_x + 1e-6 and min_y - 1e-6 <= cy <= max_y + 1e-6):
vertex_dists = [euclidean(end_pos, v) for v in boundary_vertices]
closest_idx = np.argmin(vertex_dists)
closest_pos = boundary_vertices[closest_idx]
return closest_pos
def calc_end_course_to_cruise(end_pos):
closest_pos = get_closest_cruise_point(end_pos)
return calc_course(end_pos, closest_pos)
def get_target_position(task_id, t):
if not MOVING_TASKS[task_id]:
return TASK_LOCATIONS[task_id]
x0, y0 = TASK_LOCATIONS[task_id]
speed_kmh = MOVING_SPEEDS[task_id] * KNOTS_TO_KMH
course_rad = np.deg2rad(MOVING_COURSES[task_id])
dx = speed_kmh * t * np.sin(course_rad)
dy = speed_kmh * t * np.cos(course_rad)
return (round(x0 + dx, 2), round(y0 + dy, 2))
def is_target_exited(task_id, t):
if not MOVING_TASKS[task_id]:
return False
pos = get_target_position(task_id, t)
return not EXIT_POLYGON.contains(Point(pos))
def calc_distance(pos1, pos2):
return round(euclidean(pos1, pos2), 2)
def calc_travel_time(ship_speed, distance):
if distance == 0:
return 0.0
speed_kmh = ship_speed * KNOTS_TO_KMH
return round(distance / speed_kmh, 2)
def calc_time_in_polygon(init_point, speed, direction_angle, polygon_vertices):
"""
计算移动点从多边形外进入、再离开的总时间(简化验证版)
:param init_point: 初始点坐标(元组):(x0, y0)
:param speed: 移动速度(正数)
:param direction_angle: 移动方向角(度,与x轴正方向夹角)
:param polygon_vertices: 多边形顶点列表:[(x1,y1), ..., (xn,yn)]
:return: 总时间,无有效交点时返回0
"""
# 提取初始坐标
init_x, init_y = init_point
# 1. 初始化多边形和轨迹
polygon = Polygon(polygon_vertices)
theta = math.radians(450 - direction_angle)
vx = speed * math.cos(theta)
vy = speed * math.sin(theta)
# 生成足够长的轨迹线段
end_x = init_x + vx * 1e6
end_y = init_y + vy * 1e6
trajectory = LineString([(init_x, init_y), (end_x, end_y)])
# 2. 计算轨迹与多边形边界的交点
intersection = trajectory.intersection(polygon.boundary)
if intersection.is_empty:
return 0.0 # 无交点
# 3. 提取并排序交点(按到初始点的距离)
if intersection.geom_type == "Point":
intersections = [intersection]
elif intersection.geom_type == "MultiPoint":
intersections = list(intersection.geoms)
else:
return 0.0 # 非点类型交点视为无效
# 按轨迹顺序排序(确保进入点在前,离开点在后)
intersections.sort(key=lambda p: math.hypot(p.x - init_x, p.y - init_y))
# 4. 取前两个交点计算距离(假设存在两个有效交点)
if len(intersections) < 2:
leave_point = intersections[0]
distance = math.hypot(leave_point.x - init_x, leave_point.y - init_y)
else:
enter_point, leave_point = intersections[0], intersections[1]
distance = math.hypot(init_x - leave_point.x, init_y - leave_point.y)
return round(distance / speed, 6)
# == == == == == 优先级调度算法核心 == == == == ==
class PriorityScheduler:
def __init__(self, num_ships=4):
self.num_ships = num_ships
self.total_tasks = TOTAL_TASKS_FROM_EXCEL
self.required_tasks = REQUIRED_TASK_IDS.copy()
self.optional_tasks = OPTIONAL_TASK_IDS.copy()
self.interrupt_manager = TaskInterruptManager()
print(f"任务划分:必须执行任务{self.required_tasks},可选执行任务{self.optional_tasks}")
print(f"任务优先级:S1(1) > S2(2) > S3(3) > S4(4)")
print(f"最大响应时间:S1({MAX_RESPONSE_TIMES['S1']}h)、S2({MAX_RESPONSE_TIMES['S2']}h)、"
f"S3({MAX_RESPONSE_TIMES['S3']}h)、S4({MAX_RESPONSE_TIMES['S4']}h)")
print(f"周期检查点:每{CYCLE_DURATION}小时必须经过{CHECK_POINT_ORDER}点")
def schedule_tasks(self):
"""
基于优先级的任务调度算法
1. 按时间顺序处理任务
2. 高优先级任务优先分配
3. 支持任务中断
4. 满足响应时间约束
5. 满足周期检查点约束
"""
# 舰艇状态初始化
ship_states = []
for i in range(self.num_ships):
ship_states.append({
"position": SHIP_START_POINTS[i],
"available_time": 0.0,
"current_task": None, # 当前执行的任务(可能被中断)
"completed_tasks": [],
"interrupted_tasks": [],
"checkpoint_history": []
})
# 任务执行记录
task_execution_records = [[] for _ in range(self.num_ships)]
required_tasks_completed = set()
optional_tasks_completed = set()
current_time = 0.0
max_simulation_time = 100.0 # 最大模拟时间
# 创建任务事件队列(按开始时间排序)
task_events = []
for task_id in range(TOTAL_TASKS_FROM_EXCEL):
task_events.append({
"task_id": task_id,
"task_type": TASK_TYPES[task_id],
"priority": TASK_PRIORITIES[TASK_TYPES[task_id]],
"start_time": TASK_START_TIMES[task_id],
"is_required": task_id in self.required_tasks
})
# 按开始时间和优先级排序
task_events.sort(key=lambda x: (x["start_time"], x["priority"]))
# 主调度循环
while current_time < max_simulation_time:
# 1. 检查是否有需要立即处理的紧急任务(响应时间即将超时)
pending_tasks = self.interrupt_manager.check_pending_tasks(
current_time,
[state["position"] for state in ship_states],
[state["available_time"] for state in ship_states]
)
# 2. 处理紧急任务
for pending_task in pending_tasks:
self.handle_emergency_task(pending_task, current_time, ship_states,
task_execution_records, required_tasks_completed, optional_tasks_completed)
# 3. 处理新到达的任务
new_tasks = [event for event in task_events
if event["start_time"] <= current_time and
event["task_id"] not in required_tasks_completed and
event["task_id"] not in optional_tasks_completed and
not any(state["current_task"] and state["current_task"]["任务编号"] == event["task_id"]
for state in ship_states)]
# 按优先级排序新任务
new_tasks.sort(key=lambda x: (x["priority"], x["start_time"]))
# 分配新任务
for task_event in new_tasks:
# 为任务找到最合适的舰艇
best_ship_idx = self.find_best_ship_for_task(task_event["task_id"], current_time, ship_states)
if best_ship_idx is not None:
# 检查是否需要中断当前任务
if ship_states[best_ship_idx]["current_task"] is not None:
current_task = ship_states[best_ship_idx]["current_task"]
if self.interrupt_manager.can_interrupt(current_task, task_event):
# 中断当前任务
self.interrupt_current_task(best_ship_idx, current_time, ship_states,
task_execution_records)
# 分配新任务
if ship_states[best_ship_idx]["current_task"] is None:
self.assign_task(best_ship_idx, task_event["task_id"], current_time, ship_states,
task_execution_records, required_tasks_completed, optional_tasks_completed)
# 4. 检查周期性检查点
self.check_periodic_checkpoints(current_time, ship_states)
# 5. 更新时间
next_event_time = self.get_next_event_time(ship_states, task_events, current_time, max_simulation_time)
if next_event_time == current_time:
break # 没有更多事件
# 6. 处理在时间推进过程中完成的任务
self.process_completed_tasks(current_time, next_event_time, ship_states, task_execution_records,
required_tasks_completed, optional_tasks_completed)
current_time = next_event_time
# 计算调度结果指标
metrics = self.calculate_metrics(required_tasks_completed, optional_tasks_completed,
task_execution_records, current_time)
return task_execution_records, metrics
def handle_emergency_task(self, emergency_task, current_time, ship_states,
task_execution_records, required_tasks_completed, optional_tasks_completed):
"""处理紧急任务"""
ship_idx = emergency_task["ship_idx"]
task_id = emergency_task["task_id"]
# 如果舰艇正在执行任务,检查是否可以中断
if ship_states[ship_idx]["current_task"] is not None:
current_task = ship_states[ship_idx]["current_task"]
if self.interrupt_manager.can_interrupt(current_task, emergency_task):
# 中断当前任务
self.interrupt_current_task(ship_idx, current_time, ship_states, task_execution_records)
# 分配紧急任务
if ship_states[ship_idx]["current_task"] is None:
self.assign_task(ship_idx, task_id, current_time, ship_states,
task_execution_records, required_tasks_completed, optional_tasks_completed)
def interrupt_current_task(self, ship_idx, current_time, ship_states, task_execution_records):
"""中断当前任务"""
current_task = ship_states[ship_idx]["current_task"]
if current_task is None:
return
# 更新任务状态
current_task["任务状态"] = "已中断"
current_task["实际结束时刻(小时)"] = current_time
current_task["已完成时间比例"] = (current_time - current_task["处置任务开始时刻(小时)"]) / current_task[
"任务耗时(小时)"]
# 记录中断的任务
ship_states[ship_idx]["interrupted_tasks"].append(current_task)
# 更新舰艇状态
ship_states[ship_idx]["current_task"] = None
ship_states[ship_idx]["available_time"] = current_time
def find_best_ship_for_task(self, task_id, current_time, ship_states):
"""为任务找到最合适的舰艇"""
task_type = TASK_TYPES[task_id]
task_start_time = TASK_START_TIMES[task_id]
best_ship_idx = None
best_score = float('inf')
for ship_idx in range(self.num_ships):
state = ship_states[ship_idx]
# 如果舰艇不可用,跳过
if state["available_time"] > current_time + MAX_RESPONSE_TIMES[task_type]:
continue
# 计算舰艇到达任务点的时间
target_pos = get_target_position(task_id, max(current_time, state["available_time"]))
distance = calc_distance(state["position"], target_pos)
travel_time = calc_travel_time(SHIP_SPEEDS[ship_idx], distance)
# 计算响应时间
actual_start_time = max(current_time, state["available_time"]) + travel_time
response_time = actual_start_time - task_start_time
# 如果超过最大响应时间,跳过
if response_time > MAX_RESPONSE_TIMES[task_type]:
continue
# 计算评分(考虑响应时间、舰艇优先级等)
score = response_time * TASK_PRIORITIES[task_type]
if score < best_score:
best_score = score
best_ship_idx = ship_idx
return best_ship_idx
def assign_task(self, ship_idx, task_id, current_time, ship_states,
task_execution_records, required_tasks_completed, optional_tasks_completed):
"""分配任务给舰艇"""
state = ship_states[ship_idx]
task_type = TASK_TYPES[task_id]
task_start_time = TASK_START_TIMES[task_id]
# 计算出发时间(舰艇可用时间和任务开始时间的最大值)
depart_time = max(current_time, state["available_time"], task_start_time)
# 计算航行时间和任务开始时间
ship_speed = SHIP_SPEEDS[ship_idx]
depart_pos = state["position"]
target_pos = get_target_position(task_id, depart_time)
distance = calc_distance(depart_pos, target_pos)
travel_time = calc_travel_time(ship_speed, distance)
task_start_time_actual = depart_time + travel_time
# 计算响应时间
response_time = task_start_time_actual - task_start_time
# 如果超过最大响应时间,不分配(仅对必须执行的任务)
if task_type in ['S1', 'S2', 'S3'] and response_time > MAX_RESPONSE_TIMES[task_type]:
return False
# 计算任务执行时间
if task_type in ['S2', 'S3']:
# S2/S3任务需要跟踪目标移动
travel_dist = calc_distance(depart_pos, TASK_LOCATIONS[task_id])
travel_time = calc_travel_time(ship_speed, travel_dist)
# 计算追踪时间(目标移动指定距离所需时间)
tracking_time = TASK_TRACKING_DIST[task_id] / MOVING_SPEEDS[task_id]
# 任务开始时间 = 出发时间 + 航行时间
task_start_time_actual = depart_time + travel_time
exit_time = calc_time_in_polygon(target_pos, MOVING_SPEEDS[task_id],
MOVING_COURSES[task_id], EXIT_POLYGON)
# 任务结束时间 = 开始时间 + 追踪时间
task_end_time = task_start_time_actual + exit_time - travel_time
# 到达任务点位置
task_start_pos = get_target_position(task_id, task_start_time_actual)
# 任务结束位置 = 目标在结束时刻的位置
task_end_pos = get_target_position(task_id, task_end_time)
# 任务总耗时
task_duration = exit_time - task_start_time_actual
else:
# S1/S4任务
task_duration = TASK_DURATIONS[task_id]
task_end_time = task_start_time_actual + task_duration
task_start_pos = target_pos
task_end_pos = get_target_position(task_id, task_end_time)
# 创建任务详情
task_detail = {
"舰艇编号": ship_idx + 1,
"任务编号": task_id,
"任务类型": task_type,
"任务优先级": TASK_PRIORITIES[task_type],
"最大响应时间": MAX_RESPONSE_TIMES[task_type],
"实际响应时间": round(response_time, 2),
"舰艇速度(节)": ship_speed,
"舰艇出发时刻(小时)": round(depart_time, 2),
"舰艇出发坐标(x,y)": depart_pos,
"舰艇出发航向(°)": calc_course(depart_pos, task_start_pos),
"处置任务开始时刻(小时)": round(task_start_time_actual, 2),
"处置任务开始坐标(x,y)": task_start_pos,
"处置任务结束时刻(小时)": round(task_end_time, 2),
"处置任务结束坐标(x,y)": task_end_pos,
"任务结束后航向(°)": None,
"任务耗时(小时)": round(task_duration, 2),
"任务状态": "执行中"
}
# 更新舰艇状态
state["current_task"] = task_detail
state["available_time"] = task_end_time
# 添加到执行记录
task_execution_records[ship_idx].append(task_detail)
return True
def check_periodic_checkpoints(self, current_time, ship_states):
"""检查周期性检查点"""
# 检查是否需要前往检查点
for ship_idx in range(self.num_ships):
state = ship_states[ship_idx]
# 如果舰艇当前没有任务且不在检查点附近
if state["current_task"] is None:
current_cycle = int(current_time / CYCLE_DURATION)
next_checkpoint_time = (current_cycle + 1) * CYCLE_DURATION
# 检查是否需要前往下一个检查点
time_until_next_checkpoint = next_checkpoint_time - current_time
if time_until_next_checkpoint < 1.0: # 1小时内需要到达检查点
# 找到最近的检查点
closest_cp = None
min_distance = float('inf')
for cp_name, cp_pos in CHECK_POINTS.items():
distance = calc_distance(state["position"], cp_pos)
if distance < min_distance:
min_distance = distance
closest_cp = cp_name
# 如果距离检查点较远,规划前往检查点的任务
if min_distance > 1.0: # 距离超过1单位
travel_time = calc_travel_time(SHIP_SPEEDS[ship_idx], min_distance)
if travel_time <= time_until_next_checkpoint:
# 创建前往检查点的任务
checkpoint_task = {
"舰艇编号": ship_idx + 1,
"任务编号": -1, # 特殊任务编号
"任务类型": "检查点任务",
"任务优先级": 5, # 低于所有其他任务
"最大响应时间": time_until_next_checkpoint,
"实际响应时间": 0,
"舰艇速度(节)": SHIP_SPEEDS[ship_idx],
"舰艇出发时刻(小时)": round(current_time, 2),
"舰艇出发坐标(x,y)": state["position"],
"舰艇出发航向(°)": calc_course(state["position"], CHECK_POINTS[closest_cp]),
"处置任务开始时刻(小时)": round(current_time, 2),
"处置任务开始坐标(x,y)": state["position"],
"处置任务结束时刻(小时)": round(current_time + travel_time, 2),
"处置任务结束坐标(x,y)": CHECK_POINTS[closest_cp],
"任务结束后航向(°)": None,
"任务耗时(小时)": round(travel_time, 2),
"任务状态": "执行中"
}
# 更新舰艇状态
state["current_task"] = checkpoint_task
state["available_time"] = current_time + travel_time
def get_next_event_time(self, ship_states, task_events, current_time, max_simulation_time):
"""获取下一个事件的时间"""
# 舰艇可用时间
ship_available_times = [state["available_time"] for state in ship_states]
# 未处理任务的开始时间
unprocessed_task_times = []
for event in task_events:
task_id = event["task_id"]
# 检查任务是否已经完成或正在执行
task_completed = any(task_id in state["completed_tasks"] for state in ship_states)
task_running = any(state["current_task"] and state["current_task"]["任务编号"] == task_id
for state in ship_states)
if not task_completed and not task_running and event["start_time"] > current_time:
unprocessed_task_times.append(event["start_time"])
# 周期检查点时间
next_cycle_start = ((int(current_time / CYCLE_DURATION) + 1) * CYCLE_DURATION)
# 所有可能的事件时间
all_event_times = ship_available_times + unprocessed_task_times + [next_cycle_start, max_simulation_time]
# 找到最近的事件时间
next_event_time = min([t for t in all_event_times if t > current_time])
return next_event_time
def process_completed_tasks(self, current_time, next_event_time, ship_states, task_execution_records,
required_tasks_completed, optional_tasks_completed):
"""处理在时间推进过程中完成的任务"""
for ship_idx in range(self.num_ships):
state = ship_states[ship_idx]
# 如果舰艇有当前任务且任务在这个时间段内完成
if state["current_task"] is not None:
task_end_time = state["current_task"]["处置任务结束时刻(小时)"]
if current_time < task_end_time <= next_event_time:
# 任务完成
current_task = state["current_task"]
current_task["任务状态"] = "已完成"
# 更新任务完成状态
task_id = current_task["任务编号"]
if task_id != -1: # 不是检查点任务
task_type = TASK_TYPES[task_id]
if task_type in ['S1', 'S2', 'S3']:
required_tasks_completed.add(task_id)
elif task_type == 'S4':
optional_tasks_completed.add(task_id)
# 记录完成的任务
state["completed_tasks"].append(task_id)
# 更新舰艇状态
state["position"] = current_task["处置任务结束坐标(x,y)"]
state["current_task"] = None
state["available_time"] = task_end_time
def calculate_metrics(self, required_tasks_completed, optional_tasks_completed,
task_execution_records, total_time):
"""计算调度结果指标"""
# 1. 必须执行的任务是否全部完成
required_all_completed = len(required_tasks_completed) == len(self.required_tasks)
# 2. S4任务完成数量
s4_completed = len([t for t in optional_tasks_completed if TASK_TYPES[t] == 'S4'])
# 3. 检查约束
checkpoint_constraint_result, unmet_checkpoint_count = check_checkpoint_constraint(task_execution_records,
total_time)
# 4. 响应时间约束检查
response_time_violations = 0
for task_id in required_tasks_completed:
task_type = TASK_TYPES[task_id]
task_start_time = TASK_START_TIMES[task_id]
# 找到任务的执行记录
for ship_tasks in task_execution_records:
for task in ship_tasks:
if task["任务编号"] == task_id:
actual_start_time = task["处置任务开始时刻(小时)"]
response_time = actual_start_time - task_start_time
if response_time > MAX_RESPONSE_TIMES[task_type]:
response_time_violations += 1
break
else:
continue
break
# 5. 计算适应度(S4任务完成数量)
if not required_all_completed:
fitness = 0.0
else:
# 基础适应度 = S4任务完成数量
base_fitness = s4_completed
# 约束惩罚
constraint_penalty = (PENALTY_FACTOR ** (unmet_checkpoint_count + response_time_violations))
# 最终适应度
fitness = base_fitness * constraint_penalty
return {
"fitness": fitness,
"s4_completed": s4_completed,
"required_completed": len(required_tasks_completed),
"required_total": len(self.required_tasks),
"checkpoint_violations": unmet_checkpoint_count,
"response_time_violations": response_time_violations,
"total_time": total_time,
"checkpoint_constraint_result": checkpoint_constraint_result
}
def decode_schedule(self, task_execution_records):
"""解码调度计划,生成详细的任务执行记录"""
# 完成所有任务后更新航向
for ship_idx in range(self.num_ships):
tasks = task_execution_records[ship_idx]
num_tasks = len(tasks)
for i in range(num_tasks):
current_task = tasks[i]
current_end_pos = current_task["处置任务结束坐标(x,y)"]
if i == num_tasks - 1:
end_course = calc_end_course_to_cruise(current_end_pos)
else:
next_task = tasks[i + 1]
if next_task["任务编号"] == -1: # 检查点任务
end_course = calc_course(current_end_pos, next_task["处置任务开始坐标(x,y)"])
else:
next_task_id = next_task["任务编号"]
next_depart_time = current_task["处置任务结束时刻(小时)"]
next_task_start_pos = get_target_position(next_task_id, next_depart_time) if MOVING_TASKS[
next_task_id] else TASK_LOCATIONS[next_task_id]
end_course = calc_course(current_end_pos, next_task_start_pos)
current_task["任务结束后航向(°)"] = end_course
return task_execution_records
# == == == == == 主程序== == == == ==
if __name__ == "__main__":
# 创建优先级调度器
scheduler = PriorityScheduler(num_ships=4)
# 执行调度
print("\n开始优先级调度...")
ship_tasks, metrics = scheduler.schedule_tasks()
# 解码调度计划
ship_tasks = scheduler.decode_schedule(ship_tasks)
# 统计任务完成情况
required_completed = metrics["required_completed"]
required_total = metrics["required_total"]
s4_completed = metrics["s4_completed"]
s4_total = len(OPTIONAL_TASK_IDS)
# 输出结果
print("\n" + "=" * 80)
print("优先级调度完成!")
print(f"Excel总任务数: {TOTAL_TASKS_FROM_EXCEL}")
print(f"必须执行任务(S1,S2,S3):{required_completed}/{required_total}")
print(f"可选执行任务(S4):{s4_completed}/{s4_total}")
print(f"最佳适应度: {metrics['fitness']:.2f}")
print(f"检查点约束违反次数: {metrics['checkpoint_violations']}")
print(f"响应时间约束违反次数: {metrics['response_time_violations']}")
print(f"总完成时间: {metrics['total_time']:.2f} 小时")
print("=" * 80)
# 输出检查点约束详细结果
print("\n【周期检查点约束检查结果】")
if metrics["checkpoint_constraint_result"]:
for key, value in metrics["checkpoint_constraint_result"].items():
if isinstance(value, dict):
print(f" {key}:")
for task_key, task_value in value.items():
print(f" {task_key}:")
for item in task_value:
print(f" - {item}")
else:
print(f" {key}: {value}")
print("=" * 80)
# 导出Excel
all_tasks = []
for ship in ship_tasks:
all_tasks.extend(ship)
if all_tasks:
df = pd.DataFrame(all_tasks)
column_order = [
"舰艇编号", "任务编号", "任务类型", "任务优先级",
"最大响应时间", "实际响应时间", "舰艇速度(节)",
"舰艇出发时刻(小时)", "舰艇出发坐标(x,y)", "舰艇出发航向(°)",
"处置任务开始时刻(小时)", "处置任务开始坐标(x,y)",
"处置任务结束时刻(小时)", "处置任务结束坐标(x,y)",
"任务结束后航向(°)", "任务耗时(小时)", "任务状态"
]
# 确保所有列都存在
for col in column_order:
if col not in df.columns:
df[col] = None
df = df[column_order]
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
excel_filename = f"优先级调度舰艇任务分配详情_{timestamp}.xlsx"
try:
with pd.ExcelWriter(excel_filename, engine="openpyxl") as writer:
# 任务分配详情
df.to_excel(writer, sheet_name="任务分配详情", index=False)
# 任务完成统计
stats_data = [
{"统计项目": "总任务数", "数值": TOTAL_TASKS_FROM_EXCEL},
{"统计项目": "必须执行任务数(S1,S2,S3)", "数值": len(REQUIRED_TASK_IDS)},
{"统计项目": "必须执行任务完成数", "数值": required_completed},
{"统计项目": "可选任务数(S4)", "数值": len(OPTIONAL_TASK_IDS)},
{"统计项目": "可选任务完成数(S4)", "数值": s4_completed},
{"统计项目": "S4任务完成率",
"数值": f"{s4_completed / len(OPTIONAL_TASK_IDS) * 100:.1f}%" if OPTIONAL_TASK_IDS else "0%"},
{"统计项目": "总完成时间(小时)", "数值": round(metrics["total_time"], 2)},
{"统计项目": "检查点约束违反次数", "数值": metrics["checkpoint_violations"]},
{"统计项目": "响应时间约束违反次数", "数值": metrics["response_time_violations"]}
]
stats_df = pd.DataFrame(stats_data)
stats_df.to_excel(writer, sheet_name="任务完成统计", index=False)
# 检查点约束结果
if metrics["checkpoint_constraint_result"]:
constraint_data = []
for key, value in metrics["checkpoint_constraint_result"].items():
if isinstance(value, list) and key == "周期详情":
for i, cycle in enumerate(value):
constraint_data.append(
{"约束项": "周期详情", "周期序号": i + 1, "周期范围": cycle, "备注": ""})
elif isinstance(value, dict) and key == "舰艇检查点检查":
for ship_key, ship_cycles in value.items():
for cycle_idx, cycle_check in enumerate(ship_cycles):
cycle_range = metrics["checkpoint_constraint_result"]["周期详情"][cycle_idx]
status = "已满足" if "✅" in cycle_check else "未满足"
constraint_data.append({
"约束项": ship_key,
"周期序号": cycle_idx + 1,
"周期范围": cycle_range,
"约束状态": status,
"详细信息": cycle_check.split(":")[1]
})
else:
constraint_data.append(
{"约束项": key, "周期序号": "", "周期范围": "", "约束状态": "", "详细信息": value})
constraint_df = pd.DataFrame(constraint_data)
constraint_df.to_excel(writer, sheet_name="检查点约束结果", index=False)
print(f"\nExcel表格已生成:{excel_filename}")
print(f"文件路径:{os.path.abspath(excel_filename)}")
print(f"表格包含3个工作表:")
print(f" 1. 任务分配详情:所有任务的执行信息")
print(f" 2. 任务完成统计:任务完成情况汇总")
print(f" 3. 检查点约束结果:周期检查点约束的详细检查结果")
except Exception as e:
print(f"\n导出Excel失败:{str(e)}")
print("请确保已安装依赖库:pip install pandas openpyxl shapely")
# 绘制任务执行甘特图
plt.figure(figsize=(15, 8))
colors = {'S1': '#ff4444', 'S2': '#ff8800', 'S3': '#ffcc00', 'S4': '#00cc44', '检查点任务': '#8888ff'}
y_positions = range(1, len(ship_tasks) + 1)
for i, (ship_idx, tasks) in enumerate(zip(y_positions, ship_tasks)):
for task in tasks:
start_time = task["处置任务开始时刻(小时)"]
duration = task["任务耗时(小时)"]
task_type = task["任务类型"]
task_id = task["任务编号"]
# 检查点任务特殊处理
if task_type == "检查点任务":
label = "检查点"
else:
label = f'{task_type}-{task_id}' if task_id != -1 else "检查点"
plt.barh(ship_idx, duration, left=start_time,
color=colors.get(task_type, '#888888'), alpha=0.7, height=0.6)
# 添加任务标签
plt.text(start_time + duration / 2, ship_idx,
label,
ha='center', va='center', fontsize=8, fontweight='bold')
# 添加检查点垂直线
cycles = get_time_cycles(metrics["total_time"])
for cycle_start, cycle_end in cycles:
plt.axvline(x=cycle_start, color='gray', linestyle='--', alpha=0.5)
plt.text(cycle_start, len(ship_tasks) + 0.5, f'周期{int(cycle_start / 12) + 1}开始',
rotation=90, ha='center', va='bottom', fontsize=8, color='gray')
plt.yticks(y_positions, [f'舰艇{i}' for i in range(1, len(ship_tasks) + 1)])
plt.xlabel('时间(小时)')
plt.ylabel('舰艇编号')
plt.title('舰艇任务执行甘特图')
plt.grid(True, alpha=0.3)
# 添加图例
legend_elements = [plt.Rectangle((0, 0), 1, 1, color=color, alpha=0.7, label=task_type)
for task_type, color in colors.items()]
plt.legend(handles=legend_elements, loc='upper right')
plt.tight_layout()
plt.savefig(f'task_gantt_chart_{timestamp}.png', dpi=300, bbox_inches='tight')
plt.close()
print(f"任务执行甘特图已保存:task_gantt_chart_{timestamp}.png")
print("\n所有结果文件已生成完成!")
纠正上述代码
最新发布