CounterDroneBackend/docs/design/technical/DefensePlanner-技术方案.md
tian 56d345189e refactor: 编组概念拆分为批次(WaveId)+火力单元(FireUnit)
Breaking: Group表/枚举/Service/Repository移除; GroupId->WaveId; DroneGroup->DroneWave; DroneGroupId->DroneWaveId; GroupManager删除

Docs: CHANGELOG 0.7.0; 总体架构 V10; DefensePlanner V4; 实施计划 V1.4; 对接文档 V1.2

Tests: 204/204 pass
2026-06-15 15:13:48 +08:00

370 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# DefensePlanner 防御规划引擎 — 技术方案
- **版本**V4
- **日期**2026-06-15
- **状态**:已实现
---
## 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 DroneWave威胁批次
```csharp
class DroneWave {
string WaveId; // 批次 ID
TargetConfig Target; // 类型、数量、动力、翼展、速度、高度
List<Waypoint> Waypoints; // 航路点
float ArrivalTime; // 预计算:到达防御区域中点的时间 s
}
```
### 2.3 CombatScene作战环境
沿用现有的 `CombatScene`,提供风速、风向、天气等影响扩散模型计算的参数。
---
## 3. 输出模型
### 3.1 UnitAssignment单元分配
```csharp
class UnitAssignment {
string FireUnitId; // 分配到的火力单元
string DroneWaveId; // 对抗的威胁批次
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<DroneWave> + 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<DroneWave> 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<DroneWave> threats, CombatScene env)
{
// Step 1-5
}
// 内部方法
private List<DroneWave> Prioritize(List<DroneWave> threats) { ... }
private AerosolType MatchAmmo(PowerType power) { ... }
private List<InterceptCandidate> GenerateCandidates(DroneWave threat, List<FireUnit> units, float now) { ... }
private DefensePlan Solve(List<DroneWave> 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>
├── BuildDroneWaves(config) → List<DroneWave>
└── _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 |