From 92d1131dc1bedcbf78313f7356a360daaf71a447 Mon Sep 17 00:00:00 2001 From: tian <11429339@qq.com> Date: Thu, 18 Jun 2026 10:04:30 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E7=BB=9F=E4=B8=80=E9=80=89=E6=8B=A9?= =?UTF-8?q?=E8=BF=9C=E7=82=B9=E5=91=BD=E4=B8=AD=20+=20FlightDuration=20?= =?UTF-8?q?=E4=BC=A0=E9=80=92=EF=BC=8C=E5=96=B7=E6=B0=94=E5=BC=8F=E9=80=9A?= =?UTF-8?q?=E8=BF=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PlanUnitLane: ParabolicMotion.GetFlightTimes 选远点(离无人机近) FireEvent: 新增 FlightDuration 字段 MunitionEntity: 接收 flightDuration → _useTimeArrival,按时间到达 地基: FlightDuration = interceptShellTime(保持 InterceptCalculator 一致性) 空基: FlightDuration = ParabolicMotion 选出的远点 tof 238 全部通过 --- .../Algorithms/AlgorithmTypes.cs | 1 + .../Algorithms/DefensePlanner.cs | 17 +++++++++++++---- .../Simulation/MunitionEntity.cs | 18 +++++++++++++----- .../Simulation/SimulationEngine.cs | 4 ++-- .../FullPipelineTests.cs | 2 +- 5 files changed, 30 insertions(+), 12 deletions(-) diff --git a/src/CounterDrone.Core/Algorithms/AlgorithmTypes.cs b/src/CounterDrone.Core/Algorithms/AlgorithmTypes.cs index 3585f1b..6478ad3 100644 --- a/src/CounterDrone.Core/Algorithms/AlgorithmTypes.cs +++ b/src/CounterDrone.Core/Algorithms/AlgorithmTypes.cs @@ -108,6 +108,7 @@ namespace CounterDrone.Core.Algorithms public float TargetX, TargetY, TargetZ; public float MuzzleVelocity; public float LaunchAngle; + public float FlightDuration; } // ═══════════════════════════════════════════════ diff --git a/src/CounterDrone.Core/Algorithms/DefensePlanner.cs b/src/CounterDrone.Core/Algorithms/DefensePlanner.cs index e5ecc83..964c48e 100644 --- a/src/CounterDrone.Core/Algorithms/DefensePlanner.cs +++ b/src/CounterDrone.Core/Algorithms/DefensePlanner.cs @@ -547,10 +547,15 @@ namespace CounterDrone.Core.Algorithms if (unit.Type == PlatformType.AirBased && heightDiff >= 0) return (events, $"空基单元 {unit.Id}: 平台高度({unit.Position.Y:F0})≤目标高度({ty:F0}),无法重力下落"); - // 每发独立计算发射角(基于云团生成点,含风偏),验证弹道可达 + // 每发独立计算发射角,选离无人机更近的命中点(更早拦截) launchAngle = Kinematics.CalculateLaunchAngle(targetDist, mv, heightDiff); - try { Kinematics.ComputeParabolicRange(mv, launchAngle, heightDiff); } - catch (ArgumentException) { return (events, $"目标超出弹道射程: dist={targetDist:F0}m"); } + var motion = new ParabolicMotion(mv, launchAngle); + 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 是参谋,只能基于探测信息规划。威胁从探测边界被发现, @@ -565,11 +570,14 @@ namespace CounterDrone.Core.Algorithms float deliveryTime; if (unit.Type == PlatformType.AirBased) - deliveryTime = Kinematics.ComputeParabolicRange(mv, launchAngle, heightDiff).timeOfFlight; + deliveryTime = tof; else if (interceptShellTime <= 0) return (events, "拦截计算未得出有效飞行时间"); else + { deliveryTime = interceptShellTime; + tof = interceptShellTime; + } float fireTime = recommendedTiming - deliveryTime; if (fireTime <= 0f) @@ -584,6 +592,7 @@ namespace CounterDrone.Core.Algorithms TargetZ = cloudGenZ, MuzzleVelocity = mv, LaunchAngle = launchAngle, + FlightDuration = tof, }); return (events, null); diff --git a/src/CounterDrone.Core/Simulation/MunitionEntity.cs b/src/CounterDrone.Core/Simulation/MunitionEntity.cs index e644f12..9e65103 100644 --- a/src/CounterDrone.Core/Simulation/MunitionEntity.cs +++ b/src/CounterDrone.Core/Simulation/MunitionEntity.cs @@ -54,6 +54,7 @@ namespace CounterDrone.Core.Simulation private bool _hasExceededReleaseAltitude; // 发射点高于释放高度时,炮弹下降到达 private bool _arrivesDescending; + private bool _useTimeArrival; public MunitionEntity(string id, PlatformType launchMode, AerosolType aerosolType, float startX, float startY, float startZ, @@ -61,6 +62,7 @@ namespace CounterDrone.Core.Simulation float muzzleVelocity, float releaseAltitude, float launchTime, float? launchAngle = null, + float flightDuration = 0, float carrierVelX = 0f, float carrierVelY = 0f, float carrierVelZ = 0f) { Id = id; @@ -89,10 +91,15 @@ namespace CounterDrone.Core.Simulation float heightDiff = releaseAltitude - startY; LaunchAngle = launchAngle.Value; - var (_, tof) = Kinematics.ComputeParabolicRange(muzzleVelocity, LaunchAngle, heightDiff); - FlightDuration = tof; - _arrivesDescending = heightDiff < 0; - // 发射点高于释放高度 → 下降到达;否则上升到达 + if (flightDuration > 0) + { + FlightDuration = flightDuration; + _useTimeArrival = true; // planner 指定了时间,按时间到达 + } + else + { + (_, FlightDuration) = Kinematics.ComputeParabolicRange(muzzleVelocity, LaunchAngle, heightDiff); + } _arrivesDescending = heightDiff < 0; } else @@ -112,7 +119,8 @@ namespace CounterDrone.Core.Simulation _startX, _startY, _startZ, LaunchAngle, Azimuth, MuzzleVelocity, _time); 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; float tPrev = _time - deltaTime; diff --git a/src/CounterDrone.Core/Simulation/SimulationEngine.cs b/src/CounterDrone.Core/Simulation/SimulationEngine.cs index e3d5c18..196667f 100644 --- a/src/CounterDrone.Core/Simulation/SimulationEngine.cs +++ b/src/CounterDrone.Core/Simulation/SimulationEngine.cs @@ -220,7 +220,7 @@ namespace CounterDrone.Core.Simulation platform.AerosolType ?? Models.AerosolType.InertGas, platform.PosX, platform.PosY, platform.PosZ, fe.TargetX, fe.TargetY, fe.TargetZ, fe.MuzzleVelocity, _disperseHeight, - launchTime, fe.LaunchAngle); + launchTime, fe.LaunchAngle, fe.FlightDuration); _munitions.Add(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})" }); @@ -233,7 +233,7 @@ namespace CounterDrone.Core.Simulation platform.AerosolType ?? Models.AerosolType.InertGas, platform.PosX, platform.PosY, platform.PosZ, fe.TargetX, fe.TargetY, fe.TargetZ, fe.MuzzleVelocity, _disperseHeight, - launchTime, fe.LaunchAngle); + launchTime, fe.LaunchAngle, fe.FlightDuration); _munitions.Add(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})" }); diff --git a/test/unit/CounterDrone.Core.Tests/FullPipelineTests.cs b/test/unit/CounterDrone.Core.Tests/FullPipelineTests.cs index 017ef19..4f5e4ac 100644 --- a/test/unit/CounterDrone.Core.Tests/FullPipelineTests.cs +++ b/test/unit/CounterDrone.Core.Tests/FullPipelineTests.cs @@ -131,7 +131,7 @@ namespace CounterDrone.Core.Tests // 场景 4:喷气发动机 → 活性材料拦截 // ═══════════════════════════════════════════════ - [Fact(Skip = "高弹道-上升段触发问题")] + [Fact] public void Scenario_Jet_ActiveMaterialIntercept() { var eng = RunPreset("喷气式拦截-活性材料");