CounterDroneBackend/src/CounterDrone.Core/Algorithms/DefaultDefenseAdvisor.cs

189 lines
7.5 KiB
C#
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.

using System;
using System.Collections.Generic;
using System.Linq;
using CounterDrone.Core.Models;
namespace CounterDrone.Core.Algorithms
{
public class DefaultDefenseAdvisor : IDefenseAdvisor
{
private readonly List<AmmunitionSpec> _ammoCatalog;
public DefaultDefenseAdvisor(List<AmmunitionSpec> ammoCatalog)
{
_ammoCatalog = ammoCatalog ?? new List<AmmunitionSpec>();
}
private static readonly Dictionary<PowerType, AerosolType> MatchTable = new()
{
{ PowerType.Electric, AerosolType.InertGas },
{ PowerType.Piston, AerosolType.InertGas },
{ PowerType.Jet, AerosolType.ActiveMaterial },
};
public DefenseRecommendation Recommend(ThreatProfile threat)
{
var result = new DefenseRecommendation
{
Best = new DefenseSolution(),
Critical = new DefenseSolution(),
};
// ===== 输入校验 =====
if (threat.Targets.Count == 0)
{
result.Best.SummaryRationale = "失败:未配置威胁目标";
return result;
}
if (threat.Waypoints.Count < 2)
{
result.Best.SummaryRationale = "失败:需要至少两个航路点";
return result;
}
var target = threat.Targets[0];
if (target.TypicalSpeed <= 0)
{
result.Best.SummaryRationale = "失败:目标速度为 0";
return result;
}
// ===== Step A气溶胶选型 =====
var powerType = (PowerType)target.PowerType;
var aerosolType = MatchTable.TryGetValue(powerType, out var match)
? match : AerosolType.InertGas;
var ammo = _ammoCatalog.FirstOrDefault(a => a.AerosolType == (int)aerosolType);
if (ammo == null)
{
result.Best.SummaryRationale = $"失败:弹药库中未找到 {aerosolType} 类型的弹药规格";
return result;
}
var rationale = powerType switch
{
PowerType.Electric or PowerType.Piston =>
$"{powerType}发动机依赖氧气,推荐惰性气体窒息方案",
PowerType.Jet =>
$"{powerType}发动机高温表面可触发活性材料爆燃反应",
_ => "默认推荐惰性气体方案",
};
// ===== Step B时空交汇优化 =====
var start = ToV3(threat.Waypoints[0]);
var end = ToV3(threat.Waypoints[^1]);
var mid = new Vector3((start.X + end.X) / 2f, (start.Y + end.Y) / 2f, (start.Z + end.Z) / 2f);
var routeLength = start.DistanceTo(end);
var avgSpeed = (float)target.TypicalSpeed / 3.6f;
var totalFlightTime = routeLength / avgSpeed;
if (routeLength < 100)
{
result.Best.SummaryRationale = "失败:航路太短(<100m";
return result;
}
// 弹药参数
var initialR = (float)ammo.InitialRadius;
var maxDur = (float)ammo.MaxDuration;
// 无人机穿过单个云团的时间
var crossTime = (2f * initialR) / avgSpeed;
var neededExposure = aerosolType == AerosolType.ActiveMaterial ? 2f : 6f;
var spacing = initialR * 1.5f; // 云团间隔
// 有效覆盖距离 = 间距×(N-1) + 直径,需 ≥ 所需暴露时间 × 速度
var requiredCoverage = neededExposure * avgSpeed;
var roundsNeeded = Math.Max(1,
(int)Math.Ceiling((requiredCoverage - 2f * initialR) / spacing) + 1);
// 实际有效暴露时间
var actualCoverage = spacing * (roundsNeeded - 1) + 2f * initialR;
var actualExposure = actualCoverage / avgSpeed;
var prob = Math.Min(0.95f, actualExposure / neededExposure);
// 多轮次云团:沿航路等距分布
var cloudSalvo = new List<CloudDispersal>();
for (int i = 0; i < roundsNeeded; i++)
{
var offset = (i - (roundsNeeded - 1) / 2f) * spacing;
cloudSalvo.Add(new CloudDispersal
{
AerosolType = (int)aerosolType,
PositionX = mid.X + offset,
PositionY = mid.Y,
PositionZ = mid.Z,
DisperseHeight = (float)target.TypicalAltitude,
TriggerMode = (int)TriggerMode.Time,
Duration = (int)maxDur,
InitialScale = ammo.InitialVolume,
ReleaseMode = (int)ReleaseMode.Single,
Source = "Algorithm",
PositionMode = (int)PositionMode.AlgorithmRecommended,
RecommendedTiming = totalFlightTime / 2f,
});
}
// 平台部署:假设齐射(同时发射),每门炮打一发后冷却 5s
// 需要 roundsNeeded 门炮同时发射
var gunCount = roundsNeeded;
var platforms = new List<RecommendedPlatform>();
for (int i = 0; i < gunCount; i++)
platforms.Add(new RecommendedPlatform
{
Type = PlatformType.GroundBased,
Position = new Vector3(mid.X + i * 50, 0, 50),
Quantity = 1,
MunitionCount = 1,
CoverageVolume = (float)ammo.InitialVolume,
Cooldown = 5f,
MuzzleVelocity = 800f,
});
result.Best = new DefenseSolution
{
RecommendedAerosolType = aerosolType,
AerosolRationale = rationale,
RecommendedCloud = cloudSalvo[0],
CloudSalvo = cloudSalvo,
Platforms = platforms,
Detections = new List<RecommendedDetection>
{
new RecommendedDetection
{
Position = new Vector3(mid.X, mid.Y, 0),
DetectionRadius = Math.Max(3000f, routeLength * 0.4f),
Quantity = 1,
}
},
InterceptProbability = prob,
SummaryRationale = $"{aerosolType}方案,{roundsNeeded}发,预计拦截概率 {prob:P0}",
};
result.Critical = new DefenseSolution
{
RecommendedAerosolType = aerosolType,
RecommendedCloud = new CloudDispersal
{
AerosolType = (int)aerosolType,
PositionX = start.X + (end.X - start.X) * 0.25f,
PositionY = start.Y,
PositionZ = start.Z,
DisperseHeight = (float)target.TypicalAltitude,
Duration = (int)maxDur,
Source = "Algorithm",
PositionMode = (int)PositionMode.AlgorithmRecommended,
RecommendedTiming = totalFlightTime * 0.25f,
},
Platforms = platforms,
InterceptProbability = prob * 0.3f,
SummaryRationale = $"临界方案:拦截概率仅 {prob * 0.3f:P0}",
};
return result;
}
private static Vector3 ToV3(Waypoint wp) => new((float)wp.PosX, (float)wp.PosY, (float)wp.PosZ);
}
}