docs: DefensePlanner 技术方案定稿

- 五步流水线:威胁排序→弹药匹配→候选生成→贪心分配→时序生成
- 统一输入:List<FireUnit> + List<DroneGroup> + CombatScene
- 输出:PlannerResult { Best, Critical }
- 威胁排序:类型系数×速度系数 / 到达时间
- 临界方案:刚好≥50%概率的最小配置
- 弹药精确匹配,不降级;贪心 v1,后续可升级
This commit is contained in:
tian 2026-06-12 18:12:41 +08:00
parent 0a3c444a4b
commit 1e07bcc535

View File

@ -0,0 +1,363 @@
# DefensePlanner 防御规划引擎 — 技术方案
- **版本**V2
- **日期**2026-06-12
- **状态**:已定稿
---
## 1. 概述
DefensePlanner 是防御推荐模块的核心引擎。它接收**可用火力单元池**和**威胁编队列表**,综合考虑弹药匹配、空间可达性、时间约束、资源竞争,输出**最优分配方案**和**临界边际方案**。
**当前问题**
- `DefaultDefenseAdvisor` 本质是"单威胁 → 单方案"的规则匹配器
- `Recommend()` 接收 `ThreatProfile`(不含火力单元信息),无法做资源分配
- `RecommendMultiGroup()` 接收 `List<FireUnit>`,但决策逻辑简单(先到先服务)
- 空基/地基平台类型通过 `PreferredPlatformType` 开关绕过,而非算法自主选择
**目标**:统一的规划入口,给定火力单元池和威胁列表,输出分配方案。
---
## 2. 输入模型
### 2.1 FireUnit火力单元
统一表达空基和地基平台,作为规划器的基本资产单元:
```csharp
class FireUnit {
string Id; // 唯一标识
PlatformType Type; // AirBased / GroundBased
Vector3 Position; // 待命坐标(空基含巡航高度)
float CruiseSpeed; // 空基巡航速度 m/s地基 = 0
float ReleaseAltitude; // 空基投放高度 m
float MuzzleVelocity; // 地基初速 m/s
int TotalMunitions; // 总载弹量(一次部署的总弹药数)
List<AerosolType> AmmoTypes; // 可装填的弹药类型(支持多弹种)
float Cooldown; // 同弹种连发间隔 s
float AmmoChangeTime; // 更换弹种所需时间 s
}
```
> 与当前 `FireUnit``AlgorithmTypes.cs`)的区别:新增 `Type`、`CruiseSpeed`、`ReleaseAltitude`、`MuzzleVelocity`、`TotalMunitions`、`AmmoTypes`(重命名自 `AvailableAmmo`)。
### 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)` | ScenarioService 调用 Planner | 保持 |
| `DefaultDefenseAdvisor.RecommendMultiGroup()` | Planner 原生支持多编队 | 删除 |
---
## 7. 数据流改造
```
ScenarioService.GetTaskDetail(taskId)
│ // 组装输入
├── 收集 EquipmentDeployment → List<FireUnit>
├── 收集 TargetConfig + RoutePlan + Waypoint → List<DroneGroup>
└── CombatScene
IDefensePlanner.Plan(fireUnits, threats, env)
PlannerResult
├── DefensePlan.Best
│ ├── Assignments → 写入 EquipmentDeployment更新 PlatformType/AerosolType/MunitionCount 等)
│ └── MergedSchedule → 传给 SimulationEngine.SetFireSchedule()
└── DefensePlan.Critical
└── Assignments → 存入 CloudDispersal 的 Critical* 字段
```
---
## 8. 与现有代码的关系
### 保留
- `Kinematics` 弹道/运动学工具类(被 Step 3/5 调用)
- `GaussianPuffDispersion` 扩散模型(被 Step 3 调用计算覆盖率)
- `DamageModelRouter` 毁伤模型(不影响规划)
- `FireEvent` / `FireSchedule`Step 5 输出)
- `AmmunitionSpec` 弹药参数(弹药匹配和覆盖率计算)
### 修改
- `DefaultDefenseAdvisor` → 改名为 `DefaultDefensePlanner`,实现 `IDefensePlanner`
- `AlgorithmTypes.FireUnit` → 扩展字段Type, CruiseSpeed, ReleaseAltitude, MuzzleVelocity, TotalMunitions
- `AlgorithmTypes.ThreatProfile` → 简化或废弃,输入直接使用 `DroneGroup` 列表
- `AlgorithmTypes.DefenseRecommendation` → 替换为 `PlannerResult`
### 删除
- `AlgorithmTypes.DroneGroup.GetArrivalTime()` → 移入规划器
- `AlgorithmTypes.DefenseSolution` → 替换为 `DefensePlan`
- `IDefenseAdvisor` → 替换为 `IDefensePlanner`
- `AlgorithmFactory``IDefenseAdvisor` 注册 → 改为 `IDefensePlanner`
### 不变
- `SimulationEngine` — 不感知 Planner只接收 `FireSchedule`
- `ScenarioService` — 接口不变,内部调用 Planner
- 所有 Repository、数据模型EquipmentDeployment 等)— 不需要改
---
## 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 |