FireEvent移入Algorithms, Advisor生成FireSchedule, 引擎/测试零对齐逻辑, 129测试通过
This commit is contained in:
parent
98e16ea720
commit
e3486e5bdf
@ -3,7 +3,7 @@ using CounterDrone.Core.Models;
|
||||
|
||||
namespace CounterDrone.Core.Algorithms
|
||||
{
|
||||
/// <summary>威胁画像 — 防御推荐算法的输入</summary>
|
||||
/// <summary>威胁画像</summary>
|
||||
public class ThreatProfile
|
||||
{
|
||||
public CombatScene Environment { get; set; } = new();
|
||||
@ -26,19 +26,15 @@ namespace CounterDrone.Core.Algorithms
|
||||
public AerosolType RecommendedAerosolType { get; set; }
|
||||
public string AerosolRationale { get; set; } = string.Empty;
|
||||
public CloudDispersal RecommendedCloud { get; set; } = new();
|
||||
/// <summary>多轮次云团列表(含主云团)</summary>
|
||||
public List<CloudDispersal> CloudSalvo { get; set; } = new();
|
||||
|
||||
/// <summary>齐射参数:弹药数,由算法填充</summary>
|
||||
public int SalvoRounds { get; set; } = 1;
|
||||
/// <summary>齐射参数:云团间隔(m),由算法填充</summary>
|
||||
public float SalvoSpacing { get; set; }
|
||||
|
||||
public List<RecommendedPlatform> Platforms { get; set; } = new();
|
||||
public List<RecommendedDetection> Detections { get; set; } = new();
|
||||
|
||||
public float InterceptProbability { get; set; }
|
||||
public string SummaryRationale { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>由推荐方案生成的发射计划,仿真器直接执行</summary>
|
||||
public List<FireEvent> FireSchedule { get; set; } = new();
|
||||
}
|
||||
|
||||
public class RecommendedPlatform
|
||||
@ -80,4 +76,13 @@ namespace CounterDrone.Core.Algorithms
|
||||
public string ColorHex { get; set; } = "#FFFFFF";
|
||||
public float SizeMultiplier { get; set; } = 1.0f;
|
||||
}
|
||||
|
||||
/// <summary>发射计划中的单次事件(算法生成 → 引擎执行)</summary>
|
||||
public class FireEvent
|
||||
{
|
||||
public float FireTime;
|
||||
public int PlatformIndex;
|
||||
public float TargetX, TargetY, TargetZ;
|
||||
public float MuzzleVelocity;
|
||||
}
|
||||
}
|
||||
|
||||
@ -105,6 +105,22 @@ namespace CounterDrone.Core.Algorithms
|
||||
var expansionTime = (float)Math.Pow((effectiveR - r0) / k, 2);
|
||||
var recommendedTiming = halfTime - expansionTime;
|
||||
|
||||
// 生成发射计划
|
||||
var fireSchedule = new List<FireEvent>();
|
||||
for (int i = 0; i < roundsNeeded; i++)
|
||||
{
|
||||
var offset = (i - (roundsNeeded - 1) / 2f) * spacing;
|
||||
fireSchedule.Add(new FireEvent
|
||||
{
|
||||
FireTime = recommendedTiming,
|
||||
PlatformIndex = i % roundsNeeded,
|
||||
TargetX = mid.X + offset,
|
||||
TargetY = mid.Y,
|
||||
TargetZ = mid.Z,
|
||||
MuzzleVelocity = 800f,
|
||||
});
|
||||
}
|
||||
|
||||
var bestCloud = new CloudDispersal
|
||||
{
|
||||
AerosolType = (int)aerosolType,
|
||||
@ -117,8 +133,6 @@ namespace CounterDrone.Core.Algorithms
|
||||
Source = "Algorithm",
|
||||
PositionMode = (int)PositionMode.AlgorithmRecommended,
|
||||
RecommendedTiming = recommendedTiming,
|
||||
SalvoRounds = roundsNeeded,
|
||||
SalvoSpacing = spacing,
|
||||
};
|
||||
|
||||
// 平台部署:假设齐射(同时发射),每门炮打一发后冷却 5s
|
||||
@ -142,8 +156,7 @@ namespace CounterDrone.Core.Algorithms
|
||||
RecommendedAerosolType = aerosolType,
|
||||
AerosolRationale = rationale,
|
||||
RecommendedCloud = bestCloud,
|
||||
SalvoRounds = roundsNeeded,
|
||||
SalvoSpacing = spacing,
|
||||
FireSchedule = fireSchedule,
|
||||
Platforms = platforms,
|
||||
Detections = new List<RecommendedDetection>
|
||||
{
|
||||
|
||||
@ -45,10 +45,5 @@ namespace CounterDrone.Core.Models
|
||||
public double? CriticalPosY { get; set; }
|
||||
public double? CriticalPosZ { get; set; }
|
||||
public double? CriticalTiming { get; set; }
|
||||
|
||||
/// <summary>齐射弹药数(推荐算法填充)</summary>
|
||||
public int SalvoRounds { get; set; }
|
||||
/// <summary>云团间隔(m)(推荐算法填充)</summary>
|
||||
public double SalvoSpacing { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@ -9,14 +9,6 @@ using SQLite;
|
||||
|
||||
namespace CounterDrone.Core.Simulation
|
||||
{
|
||||
public class FireEvent
|
||||
{
|
||||
public float FireTime;
|
||||
public int PlatformIndex;
|
||||
public float TargetX, TargetY, TargetZ;
|
||||
public float MuzzleVelocity;
|
||||
}
|
||||
|
||||
/// <summary>仿真引擎 — 纯执行器,接收发射计划按时间表执行</summary>
|
||||
public class SimulationEngine
|
||||
{
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using CounterDrone.Core.Algorithms;
|
||||
using CounterDrone.Core.Models;
|
||||
using Xunit;
|
||||
|
||||
namespace CounterDrone.Core.Tests
|
||||
{
|
||||
/// <summary>验证三阶段扩散模型下推荐算法的参数合理性</summary>
|
||||
public class DispersionAdvisorRealityTests
|
||||
{
|
||||
private ThreatProfile CreatePistonThreat(float speed = 200, float length = 20000)
|
||||
@ -33,24 +33,15 @@ namespace CounterDrone.Core.Tests
|
||||
var advisor = new DefaultDefenseAdvisor(DefaultAmmunition.GetAll());
|
||||
var rec = advisor.Recommend(CreatePistonThreat());
|
||||
|
||||
// 基本断言
|
||||
Assert.Equal(AerosolType.InertGas, rec.Best.RecommendedAerosolType);
|
||||
Assert.True(rec.Best.SalvoRounds >= 1, $"齐射数={rec.Best.SalvoRounds},应≥1");
|
||||
Assert.True(rec.Best.SalvoSpacing > 0, $"间隔={rec.Best.SalvoSpacing}m,应>0");
|
||||
Assert.True(rec.Best.RecommendedCloud.RecommendedTiming > 0,
|
||||
$"推荐时机={rec.Best.RecommendedCloud.RecommendedTiming}s,应>0");
|
||||
Assert.NotEmpty(rec.Best.FireSchedule);
|
||||
Assert.True(rec.Best.FireSchedule.Count >= 1, $"齐射数={rec.Best.FireSchedule.Count},应≥1");
|
||||
|
||||
// 检查膨胀时间
|
||||
var ammo = DefaultAmmunition.GetByType(AerosolType.InertGas);
|
||||
var r0 = 3.3f * System.Math.Pow(ammo.BurstChargeKg, 0.32);
|
||||
var k = ammo.TurbulentExpansionK;
|
||||
var halfTime = 20000f / (200f / 3.6f) / 2f;
|
||||
var effectiveR = r0 + k * System.Math.Sqrt(System.Math.Min(halfTime, 30));
|
||||
if (halfTime > 30) effectiveR += k * System.Math.Sqrt(halfTime - 30) * 0.3f;
|
||||
|
||||
// 膨胀应在合理范围
|
||||
Assert.True(effectiveR > 10, $"有效半径={effectiveR:F1}m,应>10m(初始{r0:F1}m)");
|
||||
Assert.True(effectiveR < 200, $"有效半径={effectiveR:F1}m,应<200m");
|
||||
// 发射计划中的云团位置应在航路范围内且沿航路展开
|
||||
var positions = rec.Best.FireSchedule.Select(f => f.TargetX).OrderBy(x => x).ToList();
|
||||
Assert.True(positions.First() > 0, "第一个云团应在航路起点之后");
|
||||
Assert.True(positions.Last() < 20000, "最后一个云团应在航路终点之前");
|
||||
Assert.True(positions.Last() - positions.First() > 10, "云团应沿航路展开");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@ -62,7 +53,6 @@ namespace CounterDrone.Core.Tests
|
||||
var timing = rec.Best.RecommendedCloud.RecommendedTiming!.Value;
|
||||
var halfTime = 20000f / (200f / 3.6f) / 2f;
|
||||
|
||||
// 推荐时机应明显早于无人机到达中点(因为有飞行时间和膨胀时间)
|
||||
Assert.True(timing < halfTime - 5,
|
||||
$"推荐时机={timing:F1}s 应早于中点={halfTime:F1}s(预留飞行+膨胀时间)");
|
||||
}
|
||||
|
||||
@ -21,6 +21,7 @@ namespace CounterDrone.Core.Tests
|
||||
private readonly FrameDataStore _frameStore;
|
||||
private readonly SQLiteConnection _mainDb;
|
||||
private List<AmmunitionSpec> _ammoCatalog;
|
||||
private List<FireEvent> _lastFireSchedule;
|
||||
private string _taskId = string.Empty;
|
||||
|
||||
public FullPipelineTests()
|
||||
@ -73,42 +74,7 @@ namespace CounterDrone.Core.Tests
|
||||
/// <summary>从推荐方案的时机参数生成发射计划</summary>
|
||||
private List<FireEvent> BuildFireSchedule(TaskFullConfig detail)
|
||||
{
|
||||
var schedule = new List<FireEvent>();
|
||||
var cloud = detail.Cloud;
|
||||
|
||||
if (!cloud.RecommendedTiming.HasValue || cloud.RecommendedTiming.Value <= 0)
|
||||
return schedule;
|
||||
|
||||
var platforms = detail.Equipment
|
||||
.Where(e => e.EquipmentRole == (int)EquipmentRole.LaunchPlatform)
|
||||
.ToList();
|
||||
if (platforms.Count == 0) return schedule;
|
||||
|
||||
// 齐射展开:按推荐间隔沿航路排列云团位置
|
||||
var spacing = (float)cloud.SalvoSpacing;
|
||||
if (spacing <= 0) spacing = 50f;
|
||||
var releaseAlt = (float)cloud.DisperseHeight;
|
||||
if (releaseAlt < 10) releaseAlt = 300f;
|
||||
|
||||
for (int i = 0; i < platforms.Count; i++)
|
||||
{
|
||||
var p = platforms[i];
|
||||
var mv = (float)(p.MuzzleVelocity ?? 800);
|
||||
var offset = (i - (platforms.Count - 1) / 2f) * spacing;
|
||||
var tx = (float)cloud.PositionX + offset; var ty = (float)cloud.PositionY; var tz = (float)cloud.PositionZ;
|
||||
var dx = tx - (float)p.PositionX; var dz = tz - (float)p.PositionZ;
|
||||
var dist = (float)Math.Sqrt(dx * dx + dz * dz);
|
||||
var angle = Kinematics.CalculateLaunchAngle(dist, mv, releaseAlt);
|
||||
var sinA = (float)Math.Sin(angle);
|
||||
var tUp = mv * sinA / 9.81f;
|
||||
var peakH = mv * mv * sinA * sinA / (2f * 9.81f);
|
||||
var dropH = Math.Max(0, peakH - releaseAlt);
|
||||
var ft = tUp + (float)Math.Sqrt(2f * dropH / 9.81f);
|
||||
var fireTime = (float)cloud.RecommendedTiming!.Value - ft;
|
||||
if (fireTime < 0) fireTime = 0.1f;
|
||||
schedule.Add(new FireEvent { FireTime = fireTime, PlatformIndex = i, TargetX = tx, TargetY = ty, TargetZ = tz, MuzzleVelocity = mv });
|
||||
}
|
||||
return schedule;
|
||||
return _lastFireSchedule ?? new List<FireEvent>();
|
||||
}
|
||||
|
||||
/// <summary>将 DefenseAdvisor 推荐方案写入想定</summary>
|
||||
@ -152,6 +118,7 @@ namespace CounterDrone.Core.Tests
|
||||
MuzzleVelocity = p.MuzzleVelocity,
|
||||
});
|
||||
_scenario.SaveDeployment(_taskId, equips);
|
||||
_lastFireSchedule = rec.Best.FireSchedule;
|
||||
|
||||
return rec;
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user