fix: 统一选择远点命中 + FlightDuration 传递,喷气式通过
PlanUnitLane: ParabolicMotion.GetFlightTimes 选远点(离无人机近) FireEvent: 新增 FlightDuration 字段 MunitionEntity: 接收 flightDuration → _useTimeArrival,按时间到达 地基: FlightDuration = interceptShellTime(保持 InterceptCalculator 一致性) 空基: FlightDuration = ParabolicMotion 选出的远点 tof 238 全部通过
This commit is contained in:
parent
b4f9a4055c
commit
92d1131dc1
@ -108,6 +108,7 @@ namespace CounterDrone.Core.Algorithms
|
|||||||
public float TargetX, TargetY, TargetZ;
|
public float TargetX, TargetY, TargetZ;
|
||||||
public float MuzzleVelocity;
|
public float MuzzleVelocity;
|
||||||
public float LaunchAngle;
|
public float LaunchAngle;
|
||||||
|
public float FlightDuration;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ═══════════════════════════════════════════════
|
// ═══════════════════════════════════════════════
|
||||||
|
|||||||
@ -547,10 +547,15 @@ namespace CounterDrone.Core.Algorithms
|
|||||||
if (unit.Type == PlatformType.AirBased && heightDiff >= 0)
|
if (unit.Type == PlatformType.AirBased && heightDiff >= 0)
|
||||||
return (events, $"空基单元 {unit.Id}: 平台高度({unit.Position.Y:F0})≤目标高度({ty:F0}),无法重力下落");
|
return (events, $"空基单元 {unit.Id}: 平台高度({unit.Position.Y:F0})≤目标高度({ty:F0}),无法重力下落");
|
||||||
|
|
||||||
// 每发独立计算发射角(基于云团生成点,含风偏),验证弹道可达
|
// 每发独立计算发射角,选离无人机更近的命中点(更早拦截)
|
||||||
launchAngle = Kinematics.CalculateLaunchAngle(targetDist, mv, heightDiff);
|
launchAngle = Kinematics.CalculateLaunchAngle(targetDist, mv, heightDiff);
|
||||||
try { Kinematics.ComputeParabolicRange(mv, launchAngle, heightDiff); }
|
var motion = new ParabolicMotion(mv, launchAngle);
|
||||||
catch (ArgumentException) { return (events, $"目标超出弹道射程: dist={targetDist:F0}m"); }
|
var times = motion.GetFlightTimes(heightDiff);
|
||||||
|
if (times.Length == 0)
|
||||||
|
return (events, $"目标超出弹道射程: dist={targetDist:F0}m");
|
||||||
|
// 两个解时:远点更靠近无人机(较早拦截),优先选远点
|
||||||
|
float tof = times.Length == 2 ? times[1] : times[0];
|
||||||
|
float range = mv * (float)Math.Cos(launchAngle) * tof;
|
||||||
|
|
||||||
// 无人机到达穿越点的时间:基于探测边界,而非航路起点。
|
// 无人机到达穿越点的时间:基于探测边界,而非航路起点。
|
||||||
// planner 是参谋,只能基于探测信息规划。威胁从探测边界被发现,
|
// planner 是参谋,只能基于探测信息规划。威胁从探测边界被发现,
|
||||||
@ -565,11 +570,14 @@ namespace CounterDrone.Core.Algorithms
|
|||||||
|
|
||||||
float deliveryTime;
|
float deliveryTime;
|
||||||
if (unit.Type == PlatformType.AirBased)
|
if (unit.Type == PlatformType.AirBased)
|
||||||
deliveryTime = Kinematics.ComputeParabolicRange(mv, launchAngle, heightDiff).timeOfFlight;
|
deliveryTime = tof;
|
||||||
else if (interceptShellTime <= 0)
|
else if (interceptShellTime <= 0)
|
||||||
return (events, "拦截计算未得出有效飞行时间");
|
return (events, "拦截计算未得出有效飞行时间");
|
||||||
else
|
else
|
||||||
|
{
|
||||||
deliveryTime = interceptShellTime;
|
deliveryTime = interceptShellTime;
|
||||||
|
tof = interceptShellTime;
|
||||||
|
}
|
||||||
float fireTime = recommendedTiming - deliveryTime;
|
float fireTime = recommendedTiming - deliveryTime;
|
||||||
|
|
||||||
if (fireTime <= 0f)
|
if (fireTime <= 0f)
|
||||||
@ -584,6 +592,7 @@ namespace CounterDrone.Core.Algorithms
|
|||||||
TargetZ = cloudGenZ,
|
TargetZ = cloudGenZ,
|
||||||
MuzzleVelocity = mv,
|
MuzzleVelocity = mv,
|
||||||
LaunchAngle = launchAngle,
|
LaunchAngle = launchAngle,
|
||||||
|
FlightDuration = tof,
|
||||||
});
|
});
|
||||||
|
|
||||||
return (events, null);
|
return (events, null);
|
||||||
|
|||||||
@ -54,6 +54,7 @@ namespace CounterDrone.Core.Simulation
|
|||||||
private bool _hasExceededReleaseAltitude;
|
private bool _hasExceededReleaseAltitude;
|
||||||
// 发射点高于释放高度时,炮弹下降到达
|
// 发射点高于释放高度时,炮弹下降到达
|
||||||
private bool _arrivesDescending;
|
private bool _arrivesDescending;
|
||||||
|
private bool _useTimeArrival;
|
||||||
|
|
||||||
public MunitionEntity(string id, PlatformType launchMode, AerosolType aerosolType,
|
public MunitionEntity(string id, PlatformType launchMode, AerosolType aerosolType,
|
||||||
float startX, float startY, float startZ,
|
float startX, float startY, float startZ,
|
||||||
@ -61,6 +62,7 @@ namespace CounterDrone.Core.Simulation
|
|||||||
float muzzleVelocity, float releaseAltitude,
|
float muzzleVelocity, float releaseAltitude,
|
||||||
float launchTime,
|
float launchTime,
|
||||||
float? launchAngle = null,
|
float? launchAngle = null,
|
||||||
|
float flightDuration = 0,
|
||||||
float carrierVelX = 0f, float carrierVelY = 0f, float carrierVelZ = 0f)
|
float carrierVelX = 0f, float carrierVelY = 0f, float carrierVelZ = 0f)
|
||||||
{
|
{
|
||||||
Id = id;
|
Id = id;
|
||||||
@ -89,10 +91,15 @@ namespace CounterDrone.Core.Simulation
|
|||||||
float heightDiff = releaseAltitude - startY;
|
float heightDiff = releaseAltitude - startY;
|
||||||
|
|
||||||
LaunchAngle = launchAngle.Value;
|
LaunchAngle = launchAngle.Value;
|
||||||
var (_, tof) = Kinematics.ComputeParabolicRange(muzzleVelocity, LaunchAngle, heightDiff);
|
if (flightDuration > 0)
|
||||||
FlightDuration = tof;
|
{
|
||||||
_arrivesDescending = heightDiff < 0;
|
FlightDuration = flightDuration;
|
||||||
// 发射点高于释放高度 → 下降到达;否则上升到达
|
_useTimeArrival = true; // planner 指定了时间,按时间到达
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
(_, FlightDuration) = Kinematics.ComputeParabolicRange(muzzleVelocity, LaunchAngle, heightDiff);
|
||||||
|
}
|
||||||
_arrivesDescending = heightDiff < 0;
|
_arrivesDescending = heightDiff < 0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -112,7 +119,8 @@ namespace CounterDrone.Core.Simulation
|
|||||||
_startX, _startY, _startZ, LaunchAngle, Azimuth, MuzzleVelocity, _time);
|
_startX, _startY, _startZ, LaunchAngle, Azimuth, MuzzleVelocity, _time);
|
||||||
PosX = x; PosY = y; PosZ = z;
|
PosX = x; PosY = y; PosZ = z;
|
||||||
|
|
||||||
if (((y >= ReleaseAltitude && !_arrivesDescending) || (y <= ReleaseAltitude && _arrivesDescending)) && !_hasExceededReleaseAltitude)
|
if (_useTimeArrival ? _time >= FlightDuration :
|
||||||
|
((y >= ReleaseAltitude && !_arrivesDescending) || (y <= ReleaseAltitude && _arrivesDescending)))
|
||||||
{
|
{
|
||||||
_hasExceededReleaseAltitude = true;
|
_hasExceededReleaseAltitude = true;
|
||||||
float tPrev = _time - deltaTime;
|
float tPrev = _time - deltaTime;
|
||||||
|
|||||||
@ -220,7 +220,7 @@ namespace CounterDrone.Core.Simulation
|
|||||||
platform.AerosolType ?? Models.AerosolType.InertGas,
|
platform.AerosolType ?? Models.AerosolType.InertGas,
|
||||||
platform.PosX, platform.PosY, platform.PosZ,
|
platform.PosX, platform.PosY, platform.PosZ,
|
||||||
fe.TargetX, fe.TargetY, fe.TargetZ, fe.MuzzleVelocity, _disperseHeight,
|
fe.TargetX, fe.TargetY, fe.TargetZ, fe.MuzzleVelocity, _disperseHeight,
|
||||||
launchTime, fe.LaunchAngle);
|
launchTime, fe.LaunchAngle, fe.FlightDuration);
|
||||||
_munitions.Add(m);
|
_munitions.Add(m);
|
||||||
OnMunitionLaunched?.Invoke(m);
|
OnMunitionLaunched?.Invoke(m);
|
||||||
_frameEventPool.Add(new SimEvent { Type = SimEventType.MunitionLaunched, OccurredAt = launchTime, SourceId = platform.Id, Description = $"空基发射 {m.Id} @({platform.PosX:F0},{platform.PosY:F0},{platform.PosZ:F0})→({fe.TargetX:F0},{fe.TargetY:F0},{fe.TargetZ:F0})" });
|
_frameEventPool.Add(new SimEvent { Type = SimEventType.MunitionLaunched, OccurredAt = launchTime, SourceId = platform.Id, Description = $"空基发射 {m.Id} @({platform.PosX:F0},{platform.PosY:F0},{platform.PosZ:F0})→({fe.TargetX:F0},{fe.TargetY:F0},{fe.TargetZ:F0})" });
|
||||||
@ -233,7 +233,7 @@ namespace CounterDrone.Core.Simulation
|
|||||||
platform.AerosolType ?? Models.AerosolType.InertGas,
|
platform.AerosolType ?? Models.AerosolType.InertGas,
|
||||||
platform.PosX, platform.PosY, platform.PosZ,
|
platform.PosX, platform.PosY, platform.PosZ,
|
||||||
fe.TargetX, fe.TargetY, fe.TargetZ, fe.MuzzleVelocity, _disperseHeight,
|
fe.TargetX, fe.TargetY, fe.TargetZ, fe.MuzzleVelocity, _disperseHeight,
|
||||||
launchTime, fe.LaunchAngle);
|
launchTime, fe.LaunchAngle, fe.FlightDuration);
|
||||||
_munitions.Add(m);
|
_munitions.Add(m);
|
||||||
OnMunitionLaunched?.Invoke(m);
|
OnMunitionLaunched?.Invoke(m);
|
||||||
_frameEventPool.Add(new SimEvent { Type = SimEventType.MunitionLaunched, OccurredAt = launchTime, SourceId = platform.Id, Description = $"计划发射 {m.Id} @({platform.PosX:F0},{platform.PosY:F0},{platform.PosZ:F0})→({fe.TargetX:F0},{fe.TargetY:F0},{fe.TargetZ:F0})" });
|
_frameEventPool.Add(new SimEvent { Type = SimEventType.MunitionLaunched, OccurredAt = launchTime, SourceId = platform.Id, Description = $"计划发射 {m.Id} @({platform.PosX:F0},{platform.PosY:F0},{platform.PosZ:F0})→({fe.TargetX:F0},{fe.TargetY:F0},{fe.TargetZ:F0})" });
|
||||||
|
|||||||
@ -131,7 +131,7 @@ namespace CounterDrone.Core.Tests
|
|||||||
// 场景 4:喷气发动机 → 活性材料拦截
|
// 场景 4:喷气发动机 → 活性材料拦截
|
||||||
// ═══════════════════════════════════════════════
|
// ═══════════════════════════════════════════════
|
||||||
|
|
||||||
[Fact(Skip = "高弹道-上升段触发问题")]
|
[Fact]
|
||||||
public void Scenario_Jet_ActiveMaterialIntercept()
|
public void Scenario_Jet_ActiveMaterialIntercept()
|
||||||
{
|
{
|
||||||
var eng = RunPreset("喷气式拦截-活性材料");
|
var eng = RunPreset("喷气式拦截-活性材料");
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user