From fe4e754cc423d7a937a02383b8cfe1979b2da84e Mon Sep 17 00:00:00 2001 From: weixin_46229132 Date: Wed, 12 Mar 2025 11:33:35 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0greedy=E6=B1=82=E8=A7=A3?= =?UTF-8?q?=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- PPO/env.py | 27 +++--- greedy_solver.py | 237 +++++++++++++++++++++++++++++++++++++++++++++++ mtkl_sovler.py | 5 +- 3 files changed, 257 insertions(+), 12 deletions(-) create mode 100644 greedy_solver.py diff --git a/PPO/env.py b/PPO/env.py index 9e124e6..102511c 100644 --- a/PPO/env.py +++ b/PPO/env.py @@ -61,7 +61,7 @@ class PartitionMazeEnv(gym.Env): # 路径规划阶段相关变量 self.MAX_STEPS = 50 # 迷宫走法步数上限 - self.BASE_LINE = 2750.0 # 基准时间,通过greedy或者蒙特卡洛计算出来 + self.BASE_LINE = 3400.0 # 基准时间,通过greedy或者蒙特卡洛计算出来 self.step_count = 0 self.rectangles = {} self.car_pos = [[0.5, 0.5] for _ in range(self.num_cars)] @@ -139,6 +139,7 @@ class PartitionMazeEnv(gym.Env): bs_time = self.bs_time_factor * (1 - rho) * d self.rectangles[(i, j)] = { + 'center': ((h_boundaries[i] + h_boundaries[i+1]) * self.H / 2, (v_boundaries[j+1] - v_boundaries[j]) * self.W / 2), 'flight_time': flight_time, 'bs_time': bs_time, 'is_visited': False @@ -243,6 +244,8 @@ class PartitionMazeEnv(gym.Env): # 区域覆盖完毕,根据轨迹计算各车队的执行时间 T = max([self._compute_motorcade_time(idx) for idx in range(self.num_cars)]) + print(T) + print(self.car_traj) reward += -(T - self.BASE_LINE) elif done and self.step_count >= self.MAX_STEPS: reward += -100 @@ -257,21 +260,23 @@ class PartitionMazeEnv(gym.Env): # 计算车的移动时间,首先在轨迹的首尾添加上大区域中心 car_time = 0 - self.car_traj[idx].append([0.5, 0.5]) - self.car_traj[idx].insert(0, [0.5, 0.5]) + # self.car_traj[idx].append([0.5, 0.5]) + # self.car_traj[idx].insert(0, [0.5, 0.5]) for i in range(len(self.car_traj[idx]) - 1): first_point = self.car_traj[idx][i] second_point = self.car_traj[idx][i + 1] - car_time += math.dist(first_point, second_point) * \ - self.H * self.W * self.car_time_factor + car_time += math.dist(self.rectangles[tuple(first_point)]['center'], self.rectangles[tuple(second_point)]['center']) * \ + self.car_time_factor + car_time + math.dist(self.rectangles[tuple(self.car_traj[idx][0])]['center'], [self.H, self.W]) + car_time + math.dist(self.rectangles[tuple(self.car_traj[idx][-1])]['center'], [self.H, self.W]) return max(float(car_time) + flight_time, bs_time) def render(self): - if self.phase == 0: - print("Phase 0: Partitioning.") - print(f"Partition step: {self.partition_step}") + if self.phase == 1: + print("Phase 1: Initialize maze environment.") print(f"Partition values so far: {self.partition_values}") - elif self.phase == 1: - print("Phase 1: Path planning (maze).") - print(f"Step count: {self.step_count}") + print(f"Motorcade positon: {self.car_pos}") + elif self.phase == 2: + print("Phase 2: Play maze.") + print(f'Motorcade trajectory: {self.car_traj}') diff --git a/greedy_solver.py b/greedy_solver.py new file mode 100644 index 0000000..682ff34 --- /dev/null +++ b/greedy_solver.py @@ -0,0 +1,237 @@ +import math +import yaml +import matplotlib.pyplot as plt +import matplotlib.patches as patches +import numpy as np + +def calculate_max_photos_per_flight(params): + """计算每次飞行能拍摄的最大照片数量 + 基于以下约束: + 1. 电池能量约束 + 2. 计算+传输时间 = 飞行时间 + """ + # 从参数中提取时间和能量因子 + flight_time_factor = params['flight_time_factor'] + comp_time_factor = params['comp_time_factor'] + trans_time_factor = params['trans_time_factor'] + battery_energy_capacity = params['battery_energy_capacity'] + flight_energy_factor = params['flight_energy_factor'] + comp_energy_factor = params['comp_energy_factor'] + trans_energy_factor = params['trans_energy_factor'] + + # 基于时间约束求解rho:飞行时间 = 计算时间 + 传输时间 + # flight_time_factor * d = comp_time_factor * rho * d + trans_time_factor * (1-rho) * d + rho_time = (flight_time_factor - trans_time_factor) / (comp_time_factor - trans_time_factor) + + # 基于能量约束求解最大照片数d + # battery_energy_capacity = flight_energy_factor * d + comp_energy_factor * rho * d + trans_energy_factor * (1-rho) * d + energy_per_photo = (flight_energy_factor + + comp_energy_factor * rho_time + + trans_energy_factor * (1 - rho_time)) + + max_photos = math.floor(battery_energy_capacity / energy_per_photo) + + return max_photos, rho_time + +def solve_greedy(params): + """使用贪心算法求解任务分配问题""" + H = params['H'] + W = params['W'] + k = params['num_cars'] # 系统数量 + car_time_factor = params['car_time_factor'] + bs_time_factor = params['bs_time_factor'] + flight_time_factor = params['flight_time_factor'] + + # 计算每次飞行能拍摄的最大照片数 + photos_per_flight, rho = calculate_max_photos_per_flight(params) + print(f"贪心无人机计算的情况下,每次飞行能拍摄的最大照片数: {photos_per_flight}") + print(f"卸载率 rho: {rho:.3f}") + + # 用较小的边长来划分网格 + min_side = min(H, W) + next_side = photos_per_flight // min_side + + # 初始化任务分配列表 + tasks = [[] for _ in range(k)] + + if min_side == H: + grid_h = min_side + grid_w = next_side + num_rows = 1 + num_cols = round(W / grid_w) + + current_col = 0 + for i in range(math.ceil(num_cols / k)): + for j in range(k): + tasks[j].append((0, current_col)) + current_col += 1 + if current_col == num_cols: + break + else: + grid_w = min_side + grid_h = next_side + num_cols = 1 + num_rows = round(H / grid_h) + + current_row = 0 + for i in range(math.ceil(num_rows / k)): + for j in range(k): + tasks[j].append((current_row, 0)) + current_row += 1 + if current_row == num_rows: + break + + print(f"网格大小: {grid_w}x{grid_h}") + print(f"网格数量: {num_rows}x{num_cols}") + print(f"任务分配情况: {tasks}") + + # 计算区域中心点 + center_x = W / 2 + center_y = H / 2 + + # 为每个系统计算完成时间 + system_times = [] + for i in range(k): + if not tasks[i]: # 如果该系统没有分配任务 + system_times.append(0) + continue + + # 生成该系统负责的网格中心坐标 + grids = [] + for row, col in tasks[i]: + if min_side == H: + # 如果H是较小边,那么row=0,col递增 + # TODO 最后一个网格的中心点不能这么算 + grid_center_x = (col + 0.5) * grid_w + grid_center_y = (row + 0.5) * grid_h + else: + # 如果W是较小边,那么col=0,row递增 + grid_center_x = (col + 0.5) * grid_w + grid_center_y = (row + 0.5) * grid_h + grids.append((grid_center_x, grid_center_y)) + + # 计算车辆路径长度(从中心点出发) + car_distance = math.hypot(center_x - grids[0][0], center_y - grids[0][1]) # 从中心到第一个网格 + for j in range(len(grids)-1): + car_distance += math.hypot(grids[j+1][0] - grids[j][0], + grids[j+1][1] - grids[j][1]) # 网格间距离 + car_distance += math.hypot(grids[-1][0] - center_x, + grids[-1][1] - center_y) # 从最后一个网格回到中心 + + # 计算时间 + num_photos = len(grids) * photos_per_flight # 该系统需要拍摄的总照片数 + flight_time = flight_time_factor * num_photos # 飞行时间 + car_time = car_time_factor * car_distance # 车辆移动时间 + bs_time = bs_time_factor * (1 - rho) * num_photos # 基站计算时间 + + total_time = max(flight_time + car_time, bs_time) + system_times.append(total_time) + + print(f"\n系统 {i} 详细信息:") + print(f"负责的网格数: {len(grids)}") + print(f"总照片数: {num_photos}") + print(f"车辆移动距离: {car_distance:.2f}") + print(f"飞行时间: {flight_time:.2f}") + print(f"车辆时间: {car_time:.2f}") + print(f"基站时间: {bs_time:.2f}") + print(f"总完成时间: {total_time:.2f}") + + # 找出最大完成时间 + max_time = max(system_times) + print(f"\n最大完成时间: {max_time:.2f}") + + # 准备返回结果 + result = { + 'max_time': max_time, + 'system_times': system_times, + 'photos_per_flight': photos_per_flight, + 'grid_w': grid_w, + 'grid_h': grid_h, + 'num_rows': num_rows, + 'num_cols': num_cols, + 'tasks': tasks, + 'rho': rho + } + + return result + +def plot_results(params, result): + """可视化结果""" + H = params['H'] + W = params['W'] + k = params['num_cars'] + + plt.rcParams['font.family'] = ['sans-serif'] + plt.rcParams['font.sans-serif'] = ['SimHei'] + + # 创建图形 + fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(15, 5)) + + # 1. 绘制系统完成时间对比 + ax1.bar(range(k), result['system_times']) + ax1.set_title('各系统完成时间对比') + ax1.set_xlabel('系统编号') + ax1.set_ylabel('完成时间(秒)') + + # 2. 绘制网格划分示意图 + ax2.set_xlim(0, W) + ax2.set_ylim(0, H) + + # 为不同系统的网格使用不同颜色 + colors = plt.cm.rainbow(np.linspace(0, 1, k)) + + # 绘制网格和系统分配 + grid_w = result['grid_w'] + grid_h = result['grid_h'] + tasks = result['tasks'] + + # 绘制每个系统的网格 + for system_idx, system_tasks in enumerate(tasks): + for row, col in system_tasks: + rect = patches.Rectangle( + (col * grid_w, row * grid_h), + grid_w, grid_h, + linewidth=1, + edgecolor='black', + facecolor=colors[system_idx], + alpha=0.3 + ) + ax2.add_patch(rect) + + # 在网格中心添加系统编号 + center_x = (col + 0.5) * grid_w + center_y = (row + 0.5) * grid_h + ax2.text(center_x, center_y, str(system_idx), + ha='center', va='center') + + # 添加中心点标记 + ax2.plot(W/2, H/2, 'r*', markersize=15, label='区域中心') + ax2.legend() + + ax2.set_title('网格划分和系统分配示意图') + ax2.set_xlabel('宽度') + ax2.set_ylabel('高度') + + plt.tight_layout() + plt.show() + +def main(): + # 读取参数 + with open('params.yml', 'r', encoding='utf-8') as file: + params = yaml.safe_load(file) + + # 求解 + result = solve_greedy(params) + + # 输出结果 + print("\n求解结果:") + print(f"最大完成时间: {result['max_time']:.2f} 秒") + print("\n各系统完成时间:") + for i, time in enumerate(result['system_times']): + print(f"系统 {i}: {time:.2f} 秒") + + # 可视化 + plot_results(params, result) + +if __name__ == "__main__": + main() diff --git a/mtkl_sovler.py b/mtkl_sovler.py index 6a766c0..d746e91 100644 --- a/mtkl_sovler.py +++ b/mtkl_sovler.py @@ -6,7 +6,7 @@ import yaml # 固定随机种子,便于复现 random.seed(42) -num_iterations = 100000 +num_iterations = 1000000 # --------------------------- # 参数设置 @@ -125,6 +125,9 @@ for iteration in range(num_iterations): curr_center = tasks[j]['center'] car_time += math.hypot(curr_center[0] - prev_center[0], curr_center[1] - prev_center[1]) * car_time_factor + # 回到区域中心 + car_time += math.hypot(curr_center[0] - region_center[0], + curr_center[1] - prev_center[1]) * car_time_factor else: car_time = 0