2025-03-09 16:53:01 +08:00
|
|
|
|
import random
|
|
|
|
|
import math
|
|
|
|
|
import matplotlib.pyplot as plt
|
|
|
|
|
import matplotlib.patches as patches
|
2025-03-11 16:40:20 +08:00
|
|
|
|
import yaml
|
2025-03-09 16:53:01 +08:00
|
|
|
|
# 固定随机种子,便于复现
|
|
|
|
|
random.seed(42)
|
|
|
|
|
|
2025-03-11 16:40:20 +08:00
|
|
|
|
num_iterations = 100000
|
|
|
|
|
|
2025-03-09 16:53:01 +08:00
|
|
|
|
# ---------------------------
|
|
|
|
|
# 参数设置
|
|
|
|
|
# ---------------------------
|
2025-03-11 16:40:20 +08:00
|
|
|
|
with open('params.yml', 'r', encoding='utf-8') as file:
|
|
|
|
|
params = yaml.safe_load(file)
|
|
|
|
|
|
|
|
|
|
H = params['H']
|
|
|
|
|
W = params['W']
|
|
|
|
|
k = params['num_cars']
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
flight_time_factor = params['flight_time_factor']
|
|
|
|
|
comp_time_factor = params['comp_time_factor']
|
|
|
|
|
trans_time_factor = params['trans_time_factor']
|
|
|
|
|
car_time_factor = params['car_time_factor']
|
|
|
|
|
bs_time_factor = params['bs_time_factor']
|
|
|
|
|
|
|
|
|
|
flight_energy_factor = params['flight_energy_factor']
|
|
|
|
|
comp_energy_factor = params['comp_energy_factor']
|
|
|
|
|
trans_energy_factor = params['trans_energy_factor']
|
|
|
|
|
battery_energy_capacity = params['battery_energy_capacity']
|
2025-03-09 16:53:01 +08:00
|
|
|
|
|
|
|
|
|
# ---------------------------
|
|
|
|
|
# 蒙特卡洛模拟,寻找最佳方案
|
|
|
|
|
# ---------------------------
|
|
|
|
|
best_T = float('inf')
|
|
|
|
|
best_solution = None
|
|
|
|
|
|
|
|
|
|
for iteration in range(num_iterations):
|
|
|
|
|
# 随机生成分区的行分段数与列分段数
|
|
|
|
|
R = random.randint(1, 5) # 行分段数
|
|
|
|
|
C = random.randint(1, 5) # 列分段数
|
|
|
|
|
|
|
|
|
|
# 生成随机的行、列分割边界
|
|
|
|
|
row_boundaries = sorted(random.sample(range(1, H), R - 1))
|
|
|
|
|
row_boundaries = [0] + row_boundaries + [H]
|
|
|
|
|
col_boundaries = sorted(random.sample(range(1, W), C - 1))
|
|
|
|
|
col_boundaries = [0] + col_boundaries + [W]
|
|
|
|
|
|
|
|
|
|
# ---------------------------
|
|
|
|
|
# 根据分割边界生成所有矩形任务
|
|
|
|
|
# ---------------------------
|
|
|
|
|
rectangles = []
|
|
|
|
|
valid_partition = True # 标记此分区是否满足所有约束
|
|
|
|
|
for i in range(len(row_boundaries) - 1):
|
|
|
|
|
for j in range(len(col_boundaries) - 1):
|
|
|
|
|
r1 = row_boundaries[i]
|
|
|
|
|
r2 = row_boundaries[i + 1]
|
|
|
|
|
c1 = col_boundaries[j]
|
|
|
|
|
c2 = col_boundaries[j + 1]
|
|
|
|
|
d = (r2 - r1) * (c2 - c1) # 任务的照片数量(矩形面积)
|
|
|
|
|
|
|
|
|
|
# 求解rho
|
|
|
|
|
rho_time_limit = (flight_time_factor - trans_time_factor) / \
|
2025-03-11 16:40:20 +08:00
|
|
|
|
(comp_time_factor - trans_time_factor)
|
|
|
|
|
rho_energy_limit = (battery_energy_capacity - flight_energy_factor * d - trans_energy_factor * d) / \
|
2025-03-09 16:53:01 +08:00
|
|
|
|
(comp_energy_factor * d - trans_energy_factor * d)
|
|
|
|
|
if rho_energy_limit < 0:
|
|
|
|
|
valid_partition = False
|
|
|
|
|
break
|
|
|
|
|
rho = min(rho_time_limit, rho_energy_limit)
|
|
|
|
|
flight_time = flight_time_factor * d
|
2025-03-11 16:40:20 +08:00
|
|
|
|
comp_time = comp_time_factor * rho * d
|
2025-03-09 16:53:01 +08:00
|
|
|
|
trans_time = trans_time_factor * (1 - rho) * d
|
2025-03-11 16:40:20 +08:00
|
|
|
|
bs_time = bs_time_factor * (1 - rho) * d
|
2025-03-09 16:53:01 +08:00
|
|
|
|
|
|
|
|
|
# 计算任务矩形中心,用于后续车辆移动时间计算
|
|
|
|
|
center_r = (r1 + r2) / 2.0
|
|
|
|
|
center_c = (c1 + c2) / 2.0
|
|
|
|
|
|
|
|
|
|
rectangles.append({
|
|
|
|
|
'r1': r1, 'r2': r2, 'c1': c1, 'c2': c2,
|
|
|
|
|
'd': d,
|
|
|
|
|
'rho': rho,
|
|
|
|
|
'flight_time': flight_time,
|
|
|
|
|
'comp_time': comp_time,
|
|
|
|
|
'trans_time': trans_time,
|
2025-03-11 16:40:20 +08:00
|
|
|
|
'bs_time': bs_time,
|
2025-03-09 16:53:01 +08:00
|
|
|
|
'center': (center_r, center_c)
|
|
|
|
|
})
|
|
|
|
|
if not valid_partition:
|
|
|
|
|
break
|
|
|
|
|
|
|
|
|
|
# 如果分区中存在任务不满足电池约束,则跳过该分区
|
|
|
|
|
if not valid_partition:
|
|
|
|
|
continue
|
|
|
|
|
|
|
|
|
|
# ---------------------------
|
|
|
|
|
# 随机将所有矩形任务分配给 k 个系统(车-机-巢)
|
|
|
|
|
# ---------------------------
|
|
|
|
|
system_tasks = {i: [] for i in range(k)}
|
|
|
|
|
for rect in rectangles:
|
|
|
|
|
system = random.randint(0, k - 1)
|
|
|
|
|
system_tasks[system].append(rect)
|
|
|
|
|
|
|
|
|
|
# ---------------------------
|
|
|
|
|
# 对于每个系统,计算该系统的总完成时间 T_k:
|
|
|
|
|
# T_k = 所有任务的飞行时间之和 + 车辆的移动时间
|
|
|
|
|
# 车辆移动时间:车辆从区域中心出发,依次经过各任务中心(顺序采用距离区域中心的启发式排序)
|
|
|
|
|
# ---------------------------
|
|
|
|
|
region_center = (H / 2.0, W / 2.0)
|
|
|
|
|
T_k_list = []
|
|
|
|
|
for i in range(k):
|
|
|
|
|
tasks = system_tasks[i]
|
|
|
|
|
tasks.sort(key=lambda r: math.hypot(r['center'][0] - region_center[0],
|
|
|
|
|
r['center'][1] - region_center[1]))
|
|
|
|
|
total_flight_time = sum(task['flight_time'] for task in tasks)
|
|
|
|
|
if tasks:
|
|
|
|
|
# 车辆从区域中心到第一个任务中心
|
|
|
|
|
car_time = math.hypot(tasks[0]['center'][0] - region_center[0],
|
2025-03-11 16:40:20 +08:00
|
|
|
|
tasks[0]['center'][1] - region_center[1]) * car_time_factor
|
2025-03-09 16:53:01 +08:00
|
|
|
|
# 依次经过任务中心
|
|
|
|
|
for j in range(1, len(tasks)):
|
|
|
|
|
prev_center = tasks[j - 1]['center']
|
|
|
|
|
curr_center = tasks[j]['center']
|
|
|
|
|
car_time += math.hypot(curr_center[0] - prev_center[0],
|
2025-03-11 16:40:20 +08:00
|
|
|
|
curr_center[1] - prev_center[1]) * car_time_factor
|
2025-03-09 16:53:01 +08:00
|
|
|
|
else:
|
|
|
|
|
car_time = 0
|
|
|
|
|
|
|
|
|
|
# 机巢的计算时间
|
2025-03-11 16:40:20 +08:00
|
|
|
|
total_bs_time = sum(task['bs_time'] for task in tasks)
|
2025-03-09 16:53:01 +08:00
|
|
|
|
T_k = max(total_flight_time + car_time, total_bs_time)
|
|
|
|
|
T_k_list.append(T_k)
|
|
|
|
|
|
|
|
|
|
T_max = max(T_k_list) # 整体目标 T 为各系统中最大的 T_k
|
|
|
|
|
|
|
|
|
|
# TODO 没有限制系统的总能耗
|
|
|
|
|
|
|
|
|
|
if T_max < best_T:
|
|
|
|
|
best_T = T_max
|
|
|
|
|
best_solution = {
|
|
|
|
|
'system_tasks': system_tasks,
|
|
|
|
|
'T_k_list': T_k_list,
|
|
|
|
|
'T_max': T_max,
|
|
|
|
|
'iteration': iteration,
|
|
|
|
|
'R': R,
|
|
|
|
|
'C': C,
|
|
|
|
|
'row_boundaries': row_boundaries,
|
|
|
|
|
'col_boundaries': col_boundaries
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# ---------------------------
|
|
|
|
|
# 输出最佳方案
|
|
|
|
|
# ---------------------------
|
|
|
|
|
if best_solution is not None:
|
|
|
|
|
print("最佳 T (各系统中最长的完成时间):", best_solution['T_max'])
|
|
|
|
|
for i in range(k):
|
|
|
|
|
num_tasks = len(best_solution['system_tasks'][i])
|
|
|
|
|
print(
|
|
|
|
|
f"系统 {i}: 完成时间 T = {best_solution['T_k_list'][i]}, 飞行任务数量: {num_tasks}")
|
|
|
|
|
else:
|
|
|
|
|
print("在给定的模拟次数内未找到满足所有约束的方案。")
|
|
|
|
|
|
|
|
|
|
# 在输出最佳方案后添加详细信息
|
|
|
|
|
if best_solution is not None:
|
|
|
|
|
print("\n各系统详细信息:")
|
|
|
|
|
region_center = (H / 2.0, W / 2.0)
|
|
|
|
|
|
|
|
|
|
for system_id, tasks in best_solution['system_tasks'].items():
|
|
|
|
|
print(f"\n系统 {system_id} 的任务详情:")
|
|
|
|
|
|
|
|
|
|
# 按距离区域中心的距离排序任务
|
|
|
|
|
tasks_sorted = sorted(tasks, key=lambda r: math.hypot(r['center'][0] - region_center[0],
|
|
|
|
|
r['center'][1] - region_center[1]))
|
|
|
|
|
|
|
|
|
|
if tasks_sorted:
|
|
|
|
|
print(
|
|
|
|
|
f"轨迹路线: 区域中心({region_center[0]:.1f}, {region_center[1]:.1f})", end="")
|
|
|
|
|
current_pos = region_center
|
|
|
|
|
total_car_time = 0
|
|
|
|
|
total_flight_time = 0
|
|
|
|
|
total_flight_energy = 0
|
|
|
|
|
total_comp_energy = 0
|
|
|
|
|
total_trans_energy = 0
|
|
|
|
|
|
|
|
|
|
for i, task in enumerate(tasks_sorted, 1):
|
|
|
|
|
# 计算车辆移动时间
|
|
|
|
|
car_time = math.hypot(task['center'][0] - current_pos[0],
|
2025-03-11 16:40:20 +08:00
|
|
|
|
task['center'][1] - current_pos[1]) * car_time_factor
|
2025-03-09 16:53:01 +08:00
|
|
|
|
total_car_time += car_time
|
|
|
|
|
|
|
|
|
|
# 更新当前位置
|
|
|
|
|
current_pos = task['center']
|
|
|
|
|
print(
|
|
|
|
|
f" -> 任务{i}({current_pos[0]:.1f}, {current_pos[1]:.1f})", end="")
|
|
|
|
|
|
|
|
|
|
# 累加各项数据
|
|
|
|
|
total_flight_time += task['flight_time']
|
|
|
|
|
total_flight_energy += flight_energy_factor * task['d']
|
|
|
|
|
total_comp_energy += comp_energy_factor * \
|
|
|
|
|
task['rho'] * task['d']
|
|
|
|
|
total_trans_energy += trans_energy_factor * \
|
|
|
|
|
(1 - task['rho']) * task['d']
|
|
|
|
|
|
|
|
|
|
print("\n")
|
|
|
|
|
print(f"任务数量: {len(tasks_sorted)}")
|
|
|
|
|
print(f"车辆总移动时间: {total_car_time:.2f} 秒")
|
|
|
|
|
print(f"无人机总飞行时间: {total_flight_time:.2f} 秒")
|
|
|
|
|
print(f"能耗统计:")
|
|
|
|
|
print(f" - 飞行能耗: {total_flight_energy:.2f} 分钟")
|
|
|
|
|
print(f" - 计算能耗: {total_comp_energy:.2f} 分钟")
|
|
|
|
|
print(f" - 传输能耗: {total_trans_energy:.2f} 分钟")
|
|
|
|
|
print(
|
|
|
|
|
f" - 总能耗: {(total_flight_energy + total_comp_energy + total_trans_energy):.2f} 分钟")
|
|
|
|
|
|
|
|
|
|
print("\n各任务详细信息:")
|
|
|
|
|
for i, task in enumerate(tasks_sorted, 1):
|
|
|
|
|
print(f"\n任务{i}:")
|
|
|
|
|
print(
|
|
|
|
|
f" 位置: ({task['center'][0]:.1f}, {task['center'][1]:.1f})")
|
|
|
|
|
print(f" 照片数量: {task['d']}")
|
|
|
|
|
print(f" 卸载比率(ρ): {task['rho']:.2f}")
|
|
|
|
|
print(f" 飞行时间: {task['flight_time']:.2f} 秒")
|
|
|
|
|
print(f" 计算时间: {task['comp_time']:.2f} 秒")
|
|
|
|
|
print(f" 传输时间: {task['trans_time']:.2f} 秒")
|
|
|
|
|
print(f" -- 飞行能耗: {task['d'] * flight_energy_factor:.2f} 分钟")
|
|
|
|
|
print(f" -- 计算能耗: {task['d'] * comp_energy_factor:.2f} 分钟")
|
|
|
|
|
print(f" -- 传输能耗: {task['d'] * trans_energy_factor:.2f} 分钟")
|
2025-03-11 16:40:20 +08:00
|
|
|
|
print(f" 基站计算时间: {task['bs_time']:.2f} 秒")
|
2025-03-09 16:53:01 +08:00
|
|
|
|
else:
|
|
|
|
|
print("该系统没有分配任务")
|
|
|
|
|
print("-" * 50)
|
|
|
|
|
|
|
|
|
|
if best_solution is not None:
|
|
|
|
|
plt.rcParams['font.family'] = ['sans-serif']
|
|
|
|
|
plt.rcParams['font.sans-serif'] = ['SimHei']
|
|
|
|
|
fig, ax = plt.subplots()
|
|
|
|
|
ax.set_xlim(0, W)
|
|
|
|
|
ax.set_ylim(0, H)
|
|
|
|
|
ax.set_title("区域划分与车-机-巢系统覆盖")
|
|
|
|
|
ax.set_xlabel("区域宽度")
|
|
|
|
|
ax.set_ylabel("区域高度")
|
|
|
|
|
|
|
|
|
|
# 定义若干颜色以区分不同系统(系统编号从0开始)
|
|
|
|
|
colors = ['red', 'blue', 'green', 'orange', 'purple', 'cyan', 'magenta']
|
|
|
|
|
|
|
|
|
|
# 绘制区域中心
|
|
|
|
|
region_center = (W / 2.0, H / 2.0) # 注意:x对应宽度,y对应高度
|
|
|
|
|
ax.plot(region_center[0], region_center[1],
|
|
|
|
|
'ko', markersize=8, label="区域中心")
|
|
|
|
|
|
|
|
|
|
# 绘制每个任务区域(矩形)及在矩形中心标注系统编号与卸载比率 ρ
|
|
|
|
|
for system_id, tasks in best_solution['system_tasks'].items():
|
|
|
|
|
# 重新按车辆行驶顺序排序(启发式:以任务中心距离区域中心的距离排序)
|
|
|
|
|
tasks_sorted = sorted(tasks, key=lambda task: math.hypot(
|
|
|
|
|
(task['c1'] + (task['c2'] - task['c1']) / 2.0) - region_center[0],
|
|
|
|
|
(task['r1'] + (task['r2'] - task['r1']) / 2.0) - region_center[1]
|
|
|
|
|
))
|
|
|
|
|
|
|
|
|
|
for i, task in enumerate(tasks_sorted, 1):
|
|
|
|
|
# 绘制矩形:左下角坐标为 (c1, r1),宽度为 (c2 - c1),高度为 (r2 - r1)
|
|
|
|
|
rect = patches.Rectangle((task['c1'], task['r1']),
|
|
|
|
|
task['c2'] - task['c1'],
|
|
|
|
|
task['r2'] - task['r1'],
|
|
|
|
|
linewidth=2,
|
|
|
|
|
edgecolor=colors[system_id % len(colors)],
|
|
|
|
|
facecolor='none')
|
|
|
|
|
ax.add_patch(rect)
|
|
|
|
|
# 计算矩形中心
|
|
|
|
|
center_x = task['c1'] + (task['c2'] - task['c1']) / 2.0
|
|
|
|
|
center_y = task['r1'] + (task['r2'] - task['r1']) / 2.0
|
|
|
|
|
# 在矩形中心标注:系统编号、执行顺序和卸载比率 ρ
|
|
|
|
|
ax.text(center_x, center_y, f"S{system_id}-{i}\nρ={task['rho']:.2f}",
|
|
|
|
|
color=colors[system_id % len(colors)],
|
|
|
|
|
ha='center', va='center', fontsize=10, fontweight='bold')
|
|
|
|
|
|
|
|
|
|
# 添加图例
|
|
|
|
|
ax.legend()
|
|
|
|
|
# 反转 y 轴使得行号从上到下递增(如需,可取消)
|
|
|
|
|
ax.invert_yaxis()
|
|
|
|
|
plt.show()
|
|
|
|
|
else:
|
|
|
|
|
print("没有找到满足约束条件的方案,无法进行可视化。")
|