# DefensePlanner 防御规划引擎 — 技术方案

- **版本**：V3
- **日期**：2026-06-13
- **状态**：已实现

---

## 1. 概述

DefensePlanner 是防御推荐模块的核心引擎。它接收**可用火力单元池**和**威胁编队列表**，综合考虑弹药匹配、空间可达性、时间约束、资源竞争，输出**最优分配方案**和**临界边际方案**。

**当前问题**：

- `DefaultDefenseAdvisor` 本质是"单威胁 → 单方案"的规则匹配器
- `Recommend()` 接收 `ThreatProfile`（不含火力单元信息），无法做资源分配
- `RecommendMultiGroup()` 接收 `List<FireUnit>`，但决策逻辑简单（先到先服务）
- 空基/地基平台类型通过 `PreferredPlatformType` 开关绕过，而非算法自主选择

**目标**：统一的规划入口，给定火力单元池和威胁列表，输出分配方案。

---

## 2. 输入模型

### 2.1 FireUnit（火力单元）

统一表达空基和地基平台，作为规划器的基本资产单元：

```csharp
class FireUnit {
    string Id;                         // 唯一标识
    PlatformType Type;                 // AirBased / GroundBased
    Vector3 Position;                  // 待命坐标（空基含巡航高度）
    // ── 发射装置 ──
    int GunCount;                      // 火炮数量（默认 1）
    int ChannelsPerGun;                // 每炮火力通道数（默认 1）
    int TotalChannels => GunCount * ChannelsPerGun;
    float ChannelInterval;             // 同通道连发最小间隔 s
    // ── 弹药 ──
    int TotalMunitions;                // 总载弹量
    List<AerosolType> AmmoTypes;       // 可装填的弹药类型
    float Cooldown;                    // 通道冷却时间 s
    float AmmoChangeTime;              // 更换弹种时间 s
    // ── 搜索跟踪 ──
    float RadarRange;                  // 雷达探测距离 m
    float EORange;                     // 光电探测距离 m
    float IRRange;                     // 红外探测距离 m
    // ── 空基 ──
    float CruiseSpeed;                 // 巡航速度 m/s
    float ReleaseAltitude;             // 投放高度 m
    // ── 地基 ──
    float MuzzleVelocity;              // 初速 m/s
}
```

### 2.2 DroneGroup（威胁编队）

```csharp
class DroneGroup {
    string GroupId;                    // 编队 ID
    TargetConfig Target;               // 类型、数量、动力、翼展、速度、高度
    List<Waypoint> Waypoints;          // 航路点
    float ArrivalTime;                 // 预计算：到达防御区域中点的时间 s
}
```

### 2.3 CombatScene（作战环境）

沿用现有的 `CombatScene`，提供风速、风向、天气等影响扩散模型计算的参数。

---

## 3. 输出模型

### 3.1 UnitAssignment（单元分配）

```csharp
class UnitAssignment {
    string FireUnitId;                 // 分配到的火力单元
    string DroneGroupId;               // 对抗的威胁编队
    AerosolType AmmoType;              // 装填的弹药类型
    int RoundsFired;                   // 本次发射几发
    float FirstFireTime;               // 首发发射时机 s
    List<FireEvent> FireEvents;        // 具体发射事件（含位置、时间）
}
```

### 3.2 DefensePlan（规划结果）

```csharp
class DefensePlan {
    List<UnitAssignment> Assignments;  // 分配方案
    List<FireEvent> MergedSchedule;    // 合并后的发射计划（排序）
    float OverallProbability;          // 总体拦截概率估计
    int ThreatsEngaged;                // 被分配方案的威胁数
    int ThreatsUnengaged;              // 无法分配方案的威胁数
    string Summary;                    // 人类可读概览
}
```

### 3.3 DefensePlanner 输出

```csharp
class PlannerResult {
    DefensePlan Best;                  // 最优方案
    DefensePlan Critical;              // 临界方案（刚好有效）
}
```

---

## 4. 内部流程（五步法）

```
输入：List<FireUnit> + List<DroneGroup> + CombatScene
  │
  ▼
Step 1 — 威胁排序
  │  威胁指数 = 速度系数 × 目标类型系数（可扩展重量、载弹量等）
  │  综合优先级 = 威胁指数 / (到达时间 + 1)
  │  同到达时间下高威胁优先
  │
  ▼
Step 2 — 弹药匹配
  │  PowerType → AerosolType（规则表）
  │  输出：每个威胁需要的弹药类型
  │
  ▼
Step 3 — 候选生成
  │  对每个(威胁, 火力单元)组合：
  │    ① 弹药兼容性检查
  │    ② 空间可达性（地基：弹道射程；空基：飞行距离）
  │    ③ 时间窗口计算（最早/最晚拦截时机）
  │  输出：List<InterceptCandidate>
  │
  ▼
Step 4 — 分配求解
  │  贪心策略（v1，后续可升级回溯/匈牙利）：
  │    按威胁优先级遍历
  │    → 选最早可拦截的兼容单元
  │    → 弹药必须精确匹配，不降级（ActiveMaterial 不能替代 InertGas）
  │    → 标记单元占用（冷却 + 换弹 + 飞行时间）
  │    → 弹药耗尽则移除
  │
  ▼
Step 5 — 时序生成
  │  对每个分配：
  │    地基：FireTime = 最佳交汇时刻 − 炮弹飞行时间
  │    空基：FireTime = 最佳交汇时刻 − 平台飞行时间 − 弹药下落时间
  │  合并排序 → MergedFireSchedule
  │
  ▼
输出：PlannerResult { Best, Critical }
```

---

## 5. 关键算法详设

### 5.1 威胁排序

**威胁指数** = 速度系数 × 目标类型系数（后续可扩展重量、载弹量等要素）

| 目标类型 | 类型系数 | 理由 |
|----------|:------:|------|
| 高速目标（300km/h+） | 4 | 最快突防 |
| 喷气式 | 3 | 高温发动机，毁伤窗口短 |
| 固定翼 | 2 | 速度中等 |
| 活塞式 | 2 | 速度中等 |
| 旋翼 | 1 | 慢速 |
| 电推 | 1 | 慢速，无热源 |

速度系数 = TypicalSpeed / 60（以 60 km/h 为基准归一化）

**综合优先级** = 威胁指数 / (ArrivalTime + 1)，按降序排列。同到达时间下高威胁优先。

### 5.2 InterceptCandidate（拦截候选）

```csharp
class InterceptCandidate {
    FireUnit Unit;
    AerosolType AmmoType;
    float EarliestTime;    // 最早可拦截时刻（仿真秒）
    float LatestTime;      // 最晚可拦截时刻
    float Coverage;        // 有效覆盖时长
    float KillProbability; // 预计杀伤概率
}
```

**候选生成逻辑**：

对于给定的威胁编队和火力单元：

1. **弹药兼容性**：`Unit.AmmoTypes` 包含威胁需要的弹药类型
2. **地基可达性**：计算目标与部署点的水平距离，校验 `MuzzleVelocity` 射程
3. **空基可达性**：计算飞行距离，`飞行时间 = distance(巡逻点, 投放点) / CruiseSpeed`
4. **时间窗口**：
   - 威胁到达防御区域的时间段 `[tEnter, tExit]`
   - 单元可拦截的时间段 = 威胁窗口 ∩（单元可用时间 + 弹药飞行时间）
   - 空基额外加平台飞行时间
5. **覆盖率**：基于云团有效半径、持续时间、无人机速度的综合估计

### 5.3 贪心分配算法

```
pending = threats.OrderBy(t => t.ArrivalTime)
available = fireUnits.Clone()

timeNow = 0
assignments = []

for each threat in pending:
    candidates = GenerateCandidates(threat, available, timeNow)
    if candidates.isEmpty:
        threats.Unengaged++
        continue

    best = candidates.OrderBy(c => c.EarliestTime)
                     .ThenByDescending(c => c.KillProbability)
                     .First()

    assignment = Commit(best, threat)
    assignments.Add(assignment)

    // 更新单元状态
    unit = best.Unit
    unit.TotalMunitions -= assignment.RoundsFired
    timeNow = max(timeNow, assignment.LastFireTime + unit.Cooldown)
```

### 5.4 临界方案（Critical Plan）

临界方案 = 刚好达到可接受下限概率（默认 50%）的最小配置：
- 从最优方案的分配列表出发
- 逐次减少每个单元分配的弹药数
- 直到整体拦截概率刚好跌破 50%
- 上一轮（≥50% 的最小配置）即为临界方案

> 作用：给操作员一个置信区间——最优 vs 临界，展示"再少就不够了"的底线。

### 5.5 多编队合并

```
Step 4 的贪心算法天然支持多威胁：
  - 按优先级顺序处理
  - 前一威胁占用的单元在后续威胁中不可用（直到冷却/换弹完成）
  - 弹药消耗全局追踪
```

---

## 6. 接口设计

### 6.1 规划器接口

```csharp
public interface IDefensePlanner
{
    /// <summary>为给定火力单元池和威胁列表生成规划方案</summary>
    PlannerResult Plan(List<FireUnit> fireUnits, List<DroneGroup> threats, CombatScene environment);
}
```

### 6.2 兼容现有接口

`DefaultDefenseAdvisor` 改造为 `DefaultDefensePlanner`：

```csharp
public class DefaultDefensePlanner : IDefensePlanner
{
    private readonly List<AmmunitionSpec> _ammoCatalog;

    public DefaultDefensePlanner(List<AmmunitionSpec> ammoCatalog) { ... }

    public PlannerResult Plan(List<FireUnit> fireUnits, List<DroneGroup> threats, CombatScene env)
    {
        // Step 1-5
    }

    // 内部方法
    private List<DroneGroup> Prioritize(List<DroneGroup> threats) { ... }
    private AerosolType MatchAmmo(PowerType power) { ... }
    private List<InterceptCandidate> GenerateCandidates(DroneGroup threat, List<FireUnit> units, float now) { ... }
    private DefensePlan Solve(List<DroneGroup> threats, List<FireUnit> units) { ... }
    private DefensePlan DeriveCritical(DefensePlan best) { ... }
}
```

### 6.3 接口迁移（已完成）

| 旧接口 | 新接口 | 状态 |
|--------|--------|------|
| `IDefenseAdvisor.Recommend(ThreatProfile)` | `IDefensePlanner.Plan(fireUnits, threats, env)` | ✅ 已替换 |
| `IDefenseAdvisor.GetDefenseRecommendation(taskId)` | 不再需要 | ✅ 已删除 |
| `DefaultDefenseAdvisor.RecommendMultiGroup()` | Planner 原生支持多编队 | ✅ 已删除 |

---

## 7. 数据流改造（已实现）

```
SimulationEngine.Initialize(taskId)
  │
  │  // 引擎内部组装
  ├── BuildFireUnits(config)     → List<FireUnit>
  ├── BuildDroneGroups(config)   → List<DroneGroup>
  └── _scene (CombatScene)
  │
  ▼
IDefensePlanner.Plan(fireUnits, threats, scene)
  │
  ▼
PlannerResult.Best.MergedSchedule
  │
  ▼
引擎 Tick() 按发射计划执行
```

> 引擎是 Planner 的唯一调用者。测试和 UI 代码不再直接接触 Planner。

---

## 8. 实现状态

### ✅ 已实现

- `IDefensePlanner` + `DefaultDefensePlanner`（五步流水线）
- `FireUnit` 通道模型（GunCount/ChannelsPerGun/ChannelInterval/搜索跟踪设备）
- 贪心分配 + 物理间隔错发 + 按目标点独立计时
- 空基/地基弹道统一处理
- `SimulationEngine` 内部调用 Planner 自动生成发射计划
- `DefaultFireUnits` 4 种模板
- 报告显示 per-unit 发射数和火力单元列
- 所有硬编码默认值和静默 fallback 已删除

### ❌ 已删除

- `IDefenseAdvisor` / `DefaultDefenseAdvisor` / `RecommendMultiGroup`
- `ThreatProfile` / `DefenseSolution` / `DefenseRecommendation` / `MultiGroupRecommendation`（AlgorithmTypes 中保留但未使用）
- `Models.SimEvent`（死代码）
- 所有 `?.` + 任意默认值模式

### 🔒 不变

- `Kinematics` / `GaussianPuffDispersion` / `DamageModelRouter`
- 所有 Repository 和数据模型（EquipmentDeployment 新增 GunCount/ChannelsPerGun/ChannelInterval）
- `ScenarioService` 接口

---

## 9. 风险与应对

| 风险 | 影响 | 应对 |
|------|------|------|
| 贪心算法局部最优，整体非最优 | 部分威胁可能被跳过 | 后续可升级为匈牙利算法或回溯搜索；贪心结果对大多数场景足够 |
| 覆盖率估算依赖简化模型 | 拦截概率不精确 | 使用现有的 `GaussianPuffDispersion` + `Kinematics`，与仿真引擎一致 |
| 空基/地基混合分配复杂 | 边界情况遗漏 | Step 3 候选生成对每种平台类型独立计算，Step 4 统一排序；单元测试覆盖典型混合场景 |

---

## 10. 已决策事项

| # | 议题 | 决策 |
|---|------|------|
| 1 | 威胁排序 | 综合威胁指数：类型系数（高速4/喷气3/固定翼2/活塞2/旋翼1/电推1）× 速度系数（km/h ÷ 60），除以到达时间。可扩展重量、载弹量等要素 |
| 2 | 临界方案 | 概率阈值定义：刚好 ≥ 50% 的最小资源配置 |
| 3 | 分配算法 | v1 贪心；后续按需升级回溯搜索或匈牙利算法 |
| 4 | Failover | 不做降级。弹药必须精确匹配（ActiveMaterial 不能替代 InertGas） |
