From 9e1fe869a6c4a765b12a2c16db6d6d019c43685e Mon Sep 17 00:00:00 2001 From: tian <11429339@qq.com> Date: Sat, 13 Jun 2026 16:57:14 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E7=A9=BA=E5=9F=BA=E6=8A=95=E6=94=BE?= =?UTF-8?q?=E7=82=B9=E4=B8=8D=E8=A2=AB=E4=BC=A0=E9=80=81=E5=88=B0=E7=BB=88?= =?UTF-8?q?=E7=82=B9=E2=80=94=E2=80=94=E6=8F=92=E5=80=BC=E4=BD=8D=E7=BD=AE?= =?UTF-8?q?=E4=BF=9D=E7=95=99=E5=9C=A8=E6=8A=95=E6=94=BE=E7=82=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - PlatformEntity 投放条件触发时不设置PosX=targetX,保留插值位置 - 空基FireEvent.TargetX=云位,platform飞向云位,距目标driftDist时投放 - planner恢复laneBaseTime+stagger覆盖,保证云位连续间距均匀 - CommandFlyTo接收disperseHeight计算driftDist --- .../Algorithms/DefaultDefensePlanner.cs | 36 ++++++++++--------- .../Simulation/PlatformEntity.cs | 17 +++++---- .../Simulation/SimulationEngine.cs | 14 +++++++- 3 files changed, 44 insertions(+), 23 deletions(-) diff --git a/src/CounterDrone.Core/Algorithms/DefaultDefensePlanner.cs b/src/CounterDrone.Core/Algorithms/DefaultDefensePlanner.cs index cfd3c9b..e6e8b9e 100644 --- a/src/CounterDrone.Core/Algorithms/DefaultDefensePlanner.cs +++ b/src/CounterDrone.Core/Algorithms/DefaultDefensePlanner.cs @@ -147,6 +147,8 @@ namespace CounterDrone.Core.Algorithms // 逐单元分配:每个单元锁定一个 Y 车道 float spacing = 2f * turbulentRadius; int[] laneNeeded = new int[yLanes]; + float[] laneBaseTime = new float[yLanes]; + bool[] laneBaseSet = new bool[yLanes]; for (int l = 0; l < yLanes; l++) laneNeeded[l] = singleNeeded; int currentLane = 0; int roundsCollected = 0; @@ -167,6 +169,14 @@ namespace CounterDrone.Core.Algorithms if (toTake <= 0) continue; int yLane = currentLane; + var mid = ThreatMidpoint(threat); + // 车道第一个单元设基准时间,后续单元以此为准保证间距均匀 + if (!laneBaseSet[yLane]) + { + var refEvt = GenerateFireEventsAt(threat, c.Unit, c.AmmoType, ammo, env, 0, yLane, yLanes, formationWidth); + laneBaseTime[yLane] = refEvt[0].FireTime; + laneBaseSet[yLane] = true; + } float stagger = Kinematics.CloudCoverInterval(turbulentRadius * 2f, (float)threat.Target.TypicalSpeed, c.Unit.ChannelInterval); var fevents = new List(); @@ -175,9 +185,11 @@ namespace CounterDrone.Core.Algorithms { float offset = (eventIdx - (totalRoundsNeeded - 1) / 2f) * spacing; var fe = GenerateFireEventsAt(threat, c.Unit, c.AmmoType, ammo, env, offset, yLane, yLanes, formationWidth); - // 不覆盖 FireTime:GenerateFireEventsAt 已按偏移位置 + 单元飞行时间精确计算 + int baseRoundInLane = singleNeeded - laneNeeded[currentLane]; foreach (var e in fe) { + e.FireTime = laneBaseTime[yLane] + (baseRoundInLane + ch) * stagger; + e.TargetX = mid.X + offset; e.PlatformIndex = unitIdx * c.Unit.TotalChannels + ch; } fevents.AddRange(fe); @@ -394,7 +406,7 @@ namespace CounterDrone.Core.Algorithms { float avgSpeed = (float)threat.Target.TypicalSpeed / 3.6f; var (effectiveR, _, _) = ComputeEffectiveRadius(threat, ammo, env); - float spacing = effectiveR * 1.5f; + float spacing = 2f * effectiveR; float actualCoverage = spacing * (rounds - 1) + 2f * effectiveR; float actualExposure = actualCoverage / avgSpeed; @@ -441,29 +453,21 @@ namespace CounterDrone.Core.Algorithms float fireTime; if (unit.Type == PlatformType.AirBased) + { if (unit.ReleaseAltitude <= 0 || unit.CruiseSpeed <= 0) throw new InvalidOperationException($"空基单元 {unit.Id}: ReleaseAltitude={unit.ReleaseAltitude}, CruiseSpeed={unit.CruiseSpeed} 必须>0"); float releaseAlt = unit.ReleaseAltitude; float cruiseSpd = unit.CruiseSpeed; float fallTime = Kinematics.AirDropFallTime(releaseAlt, (float)threat.Target.TypicalAltitude); - // 投放点后移以抵消载具航速导致的漂移 - float flightDistToCloud = Kinematics.Distance3D( + // 载具飞向云端方向,漂移距离 = 巡航速度 × 落体时间 + float driftDist = cruiseSpd * fallTime; + float distToCloud = Kinematics.Distance3D( unit.Position.X, unit.Position.Y, unit.Position.Z, tx, releaseAlt, tz); - float flightTimeToCloud = flightDistToCloud / cruiseSpd; - // 载具飞行方向单位向量 - float dirX = (tx - unit.Position.X) / Math.Max(1f, flightDistToCloud); - float dirZ = (tz - unit.Position.Z) / Math.Max(1f, flightDistToCloud); - float driftX = cruiseSpd * fallTime * dirX; - float driftZ = cruiseSpd * fallTime * dirZ; - float releaseX = tx - driftX; - float releaseZ = tz - driftZ; - float flightDist = Kinematics.Distance3D( - unit.Position.X, unit.Position.Y, unit.Position.Z, - releaseX, releaseAlt, releaseZ); + // 投放点间距 = 总距离 - 漂移,投后弹药滑翔至预期云位 + float flightDist = Math.Max(0f, distToCloud - driftDist); float flightTime = flightDist / cruiseSpd; fireTime = recommendedTiming - flightTime - fallTime; - tx = releaseX; tz = releaseZ; } else { diff --git a/src/CounterDrone.Core/Simulation/PlatformEntity.cs b/src/CounterDrone.Core/Simulation/PlatformEntity.cs index 78d07ed..2a3001b 100644 --- a/src/CounterDrone.Core/Simulation/PlatformEntity.cs +++ b/src/CounterDrone.Core/Simulation/PlatformEntity.cs @@ -29,6 +29,7 @@ namespace CounterDrone.Core.Simulation private float _targetX, _targetY, _targetZ; private float _flightDistance; private float _flownDistance; + private float _driftDistance; /// 空基平台精确投放时刻(计算值) public float ExactReleaseTime => _exactReleaseTime; private float _exactReleaseTime; @@ -69,11 +70,13 @@ namespace CounterDrone.Core.Simulation float step = CruiseSpeed * deltaTime; _flownDistance += step; - if (_flownDistance >= _flightDistance || _flightDistance < 0.01f) + if (_flownDistance >= _flightDistance - _driftDistance - 0.01f || _flightDistance < 0.01f) { - PosX = _targetX; - PosY = _targetY; - PosZ = _targetZ; + // 在投放点(非终点),保留插值位置 + float rt = _flightDistance > 0.01f ? Math.Min(1f, _flownDistance / _flightDistance) : 1f; + PosX = PatrolX + (_targetX - PatrolX) * rt; + PosY = PatrolY + (_targetY - PatrolY) * rt; + PosZ = PatrolZ + (_targetZ - PatrolZ) * rt; State = PlatformState.ReadyToRelease; return; } @@ -85,7 +88,7 @@ namespace CounterDrone.Core.Simulation } /// 下令空基平台飞往投放点 - public void CommandFlyTo(float targetX, float targetY, float targetZ, float fireTime) + public void CommandFlyTo(float targetX, float targetY, float targetZ, float fireTime, float disperseHeight) { if (PlatformType != Models.PlatformType.AirBased) return; _targetX = targetX; @@ -97,7 +100,9 @@ namespace CounterDrone.Core.Simulation _flightDistance = (float)Math.Sqrt(dx * dx + dy * dy + dz * dz); _flownDistance = 0; float flightTime = CruiseSpeed > 0 ? _flightDistance / CruiseSpeed : 0f; - _exactReleaseTime = fireTime + flightTime; + float fallTime = Kinematics.AirDropFallTime(PosY, disperseHeight); + _driftDistance = CruiseSpeed * fallTime; + _exactReleaseTime = fireTime + Math.Max(0f, _flightDistance - _driftDistance) / CruiseSpeed; State = PlatformState.FlyingToTarget; } diff --git a/src/CounterDrone.Core/Simulation/SimulationEngine.cs b/src/CounterDrone.Core/Simulation/SimulationEngine.cs index fba8fe3..c293b1e 100644 --- a/src/CounterDrone.Core/Simulation/SimulationEngine.cs +++ b/src/CounterDrone.Core/Simulation/SimulationEngine.cs @@ -142,9 +142,19 @@ namespace CounterDrone.Core.Simulation { var result = _planner.Plan(fireUnits, threats, _scene); SetFireSchedule(result.Best.MergedSchedule); + // 诊断:输出 Planner 云团预期位置 + var lines = new List { "idx,fireTime,tx,ty,tz,mv" }; + for (int i = 0; i < _fireSchedule.Count; i++) + { + var f = _fireSchedule[i]; + lines.Add($"{i},{f.FireTime:F3},{f.TargetX:F1},{f.TargetY:F1},{f.TargetZ:F1},{f.MuzzleVelocity:F0}"); + } + System.IO.File.WriteAllLines(@"C:\Users\Tellme\Desktop\planner_targets.csv", lines); } } + // 初始化 cloud dump + System.IO.File.WriteAllText(@"C:\Users\Tellme\Desktop\cloud_actual.csv", "m.id,arrivalTime,px,py,pz,cloud.id,tx,ty,tz\n"); _frameDb = _frameStore.CreateOrOpen(_taskId); State = SimulationState.Running; } @@ -168,7 +178,7 @@ namespace CounterDrone.Core.Simulation if (platform.PlatformType == Models.PlatformType.AirBased && platform.Ready) { - platform.CommandFlyTo(fe.TargetX, platform.ReleaseAltitude, fe.TargetZ, fe.FireTime); + platform.CommandFlyTo(fe.TargetX, platform.ReleaseAltitude, fe.TargetZ, fe.FireTime, _disperseHeight); } else if (platform.Ready) { @@ -217,6 +227,8 @@ namespace CounterDrone.Core.Simulation _munitions.Remove(m); OnCloudGenerated?.Invoke(cloud); frameEvents.Add(new SimEvent { Type = SimEventType.CloudGenerated, OccurredAt = m.ArrivalTime, Description = "云团生成" }); + System.IO.File.AppendAllText(@"C:\Users\Tellme\Desktop\cloud_actual.csv", + $"{m.Id},{m.ArrivalTime:F3},{m.PosX:F1},{m.PosY:F1},{m.PosZ:F1},{cloud.Id},{m.TargetX:F1},{m.TargetY:F1},{m.TargetZ:F1}\n"); } }