| New file |
| | |
| | | package com.zy.asrs.utils; |
| | | |
| | | import java.util.*; |
| | | import java.util.concurrent.atomic.AtomicReference; |
| | | |
| | | import lombok.Data; |
| | | |
| | | public class SchedulingCarUtil { |
| | | |
| | | private static final Map<Integer, Double> STATION_PRIORITIES = |
| | | Collections.unmodifiableMap(new HashMap<Integer, Double>() {{ |
| | | put(5101, 0.8); |
| | | put(5120, 0.9); |
| | | // ... |
| | | }}); |
| | | private static final Map<String, Double> AREA_WEIGHTS = |
| | | Collections.unmodifiableMap(new HashMap<String, Double>() {{ |
| | | put("A", 1.2); |
| | | put("B", 1.0); |
| | | put("C", 0.8); |
| | | // ... |
| | | }}); |
| | | |
| | | // 常量配置 |
| | | private static final double WAIT_THRESHOLD = 120.0; // 等待临界点(秒) |
| | | private static final double MAX_DISTANCE = 1000.0; // 轨道最大长度 |
| | | private static final double DIST_PENALTY = -0.5; // 最低距离系数 |
| | | |
| | | // 新增线性增长阈值和系数 |
| | | private static final double LINEAR_THRESHOLD = 300.0; // 线性增长起点(秒) |
| | | private static final double LINEAR_FACTOR = 0.0083; // 线性增长系数(≈0.5/60) |
| | | |
| | | private static final double LOAD_THRESHOLD = 0.7; |
| | | private static final double ADJUSTMENT_STEP = 0.01; |
| | | |
| | | // 权重参数 (可动态调整) |
| | | private double baseWeight = 0.40; |
| | | private double waitWeight = 0.35; |
| | | private double distWeight = 0.25; |
| | | |
| | | private static final double[] EXP_CACHE = new double[1800]; // 缓存0~1800秒(30分钟) |
| | | static { |
| | | for (int i = 0; i < EXP_CACHE.length; i++) { |
| | | EXP_CACHE[i] = 0.8 * (1 - Math.exp(-0.02 * i)); |
| | | } |
| | | } |
| | | |
| | | // 预计算常量 |
| | | private static final double EXP_BASE = 0.5; |
| | | private static final double EXP_FACTOR = 3.0; |
| | | |
| | | private static class Weights { |
| | | double base = 0.40, wait = 0.35, dist = 0.25; |
| | | } |
| | | private final AtomicReference<Weights> weightsRef = new AtomicReference<>(new Weights()); |
| | | |
| | | // // 复用对象(线程安全) |
| | | // private final ThreadLocal<Double> distanceCache = ThreadLocal.withInitial(() -> 0.0); |
| | | /** |
| | | * 计算任务综合优先级 |
| | | * @param task 当前任务对象 |
| | | * @param agv 当前小车对象 |
| | | * @return 综合优先级得分(0.0 - 1.0 ~ ∞) |
| | | */ |
| | | public double calculatePriority(Task task, AGV agv) { |
| | | // 1. 站点基础优先级计算 |
| | | double stationPriority = calculateStationPriority(task.getStationId()); |
| | | |
| | | // 2. 任务等待时间优先级 |
| | | double waitPriority = calculateWaitPriority(task.getWaitSeconds()); |
| | | |
| | | // 3. 小车距离优先级 |
| | | double distancePriority = calculateDistancePriority( |
| | | agv.getPosition(), |
| | | task.getTargetPosition() |
| | | ); |
| | | |
| | | applyDynamicWeightAdjustment(); |
| | | |
| | | return (stationPriority * baseWeight) |
| | | + (waitPriority * waitWeight) |
| | | + (distancePriority * distWeight); |
| | | } |
| | | |
| | | private void applyDynamicWeightAdjustment() { |
| | | Weights current = weightsRef.get(); |
| | | Weights updated = new Weights(); |
| | | |
| | | double loadFactor = SystemMonitor.getLoadFactor(); |
| | | if (loadFactor > LOAD_THRESHOLD) { |
| | | waitWeight = Math.min(0.55, waitWeight + ADJUSTMENT_STEP); |
| | | distWeight = Math.max(0.10, distWeight - ADJUSTMENT_STEP/2); |
| | | } else if (loadFactor < LOAD_THRESHOLD - 0.05) { |
| | | // 负载降低时逐步恢复权重 |
| | | waitWeight = Math.max(0.35, waitWeight - ADJUSTMENT_STEP); |
| | | distWeight = Math.min(0.25, distWeight + ADJUSTMENT_STEP/2); |
| | | } |
| | | |
| | | weightsRef.compareAndSet(current, updated); // CAS更新 |
| | | } |
| | | |
| | | /** |
| | | * 站点基础优先级(固定值+区域权重) |
| | | */ |
| | | private double calculateStationPriority(int stationId) { |
| | | double basePriority = STATION_PRIORITIES.getOrDefault(stationId, 0.5); |
| | | String area = "A"; |
| | | return basePriority * AREA_WEIGHTS.getOrDefault(area, 1.0); |
| | | } |
| | | |
| | | /** |
| | | * 等待时间优先级(非线性增长) |
| | | */ |
| | | private double calculateWaitPriority(double waitSeconds) { |
| | | // if (waitSeconds <= WAIT_THRESHOLD) { |
| | | // return 0.2; // 基础值 |
| | | // } |
| | | // // 等待超时后的指数增长(无峰值上限) |
| | | // return Math.min(1.0, 0.2 + 0.8 * (1 - Math.exp(-0.02*(waitSeconds-WAIT_THRESHOLD)))); |
| | | |
| | | if (waitSeconds <= WAIT_THRESHOLD) { |
| | | return 0.2; // 基础值 |
| | | } |
| | | |
| | | double exceedSeconds = waitSeconds - WAIT_THRESHOLD; |
| | | double expPart = (exceedSeconds < EXP_CACHE.length) ? |
| | | EXP_CACHE[(int) exceedSeconds] : |
| | | 0.8 * (1 - Math.exp(-0.02 * exceedSeconds)); |
| | | |
| | | // double exceedSeconds = waitSeconds - WAIT_THRESHOLD; |
| | | // // 指数增长阶段(0~300秒) |
| | | // double expPart = 0.8 * (1 - Math.exp(-0.02 * exceedSeconds)); |
| | | |
| | | // 线性增长阶段(300秒后) |
| | | double linearPart = (exceedSeconds > LINEAR_THRESHOLD) ? |
| | | LINEAR_FACTOR * (exceedSeconds - LINEAR_THRESHOLD) : 0; |
| | | |
| | | return 0.2 + expPart + linearPart; // 突破1.0上限 |
| | | } |
| | | |
| | | /** |
| | | * 小车距离优先级(含负向调节) |
| | | */ |
| | | private double calculateDistancePriority(double agvPos, double stationPos) { |
| | | // 计算轨道有效距离(考虑单向移动) |
| | | double distance = calculateEffectiveDistance(agvPos, stationPos); |
| | | // |
| | | // double distance = distanceCache.get(); |
| | | // if (distance == 0.0) { // 0表示未计算 |
| | | // distance = calculateEffectiveDistance(agvPos, stationPos); |
| | | // distanceCache.set(distance); |
| | | // } |
| | | |
| | | // 非线性衰减公式(近距离奖励,远距离惩罚) |
| | | double ratio = distance / MAX_DISTANCE; |
| | | // return Math.max(DIST_PENALTY, 0.5 * (Math.pow(0.5, ratio * 3) - 0.5)); |
| | | double exponentValue = Math.pow(EXP_BASE, ratio * EXP_FACTOR); |
| | | return Math.max(DIST_PENALTY, 0.5 * (exponentValue - 0.5)); |
| | | } |
| | | |
| | | /** |
| | | * 计算有效距离(单方向轨道逻辑) |
| | | */ |
| | | private double calculateEffectiveDistance(double agvPos, double stationPos) { |
| | | // 单向轨道场景:若小车已过站点,需绕行至终点再返回起点 |
| | | // if (agvPos > stationPos) { |
| | | // return (MAX_DISTANCE - agvPos) + stationPos; |
| | | // } |
| | | // return stationPos - agvPos; |
| | | return (stationPos - agvPos + MAX_DISTANCE) % MAX_DISTANCE; |
| | | } |
| | | } |
| | | |
| | | @Data |
| | | class Task { |
| | | private int taskId; |
| | | private int stationId; |
| | | private double targetPosition; |
| | | private long createTime; // 任务创建时间戳 |
| | | private static final long THIRTY_DAYS_MS = 30L * 24 * 60 * 60 * 1000; |
| | | |
| | | public double getWaitSeconds() { |
| | | long elapsed = (System.currentTimeMillis() - createTime) ; |
| | | // 固定为30天 |
| | | return (elapsed > THIRTY_DAYS_MS) ? (THIRTY_DAYS_MS / 1000.0) : (elapsed / 1000.0); |
| | | } |
| | | } |
| | | |
| | | @Data |
| | | class AGV { |
| | | private int agvId; |
| | | private double position; // 当前轨道位置(0-MAX_DISTANCE) |
| | | } |
| | | |
| | | // 系统监控类(示例) |
| | | @Data |
| | | class SystemMonitor { |
| | | public static double getLoadFactor() { |
| | | // 实际实现中读取系统负载率 |
| | | return 0.1; |
| | | // return LoadHolder.cachedLoad; // 定时更新,非实时读取 |
| | | } |
| | | // private static class LoadHolder { |
| | | // static double cachedLoad = 0.1; |
| | | // static { ScheduledExecutorService.scheduleAtFixedRate(() -> |
| | | // cachedLoad = realTimeLoad(), 5, 5, TimeUnit.SECONDS); } |
| | | // } |
| | | } |