diff --git a/src/CounterDrone.Core/Algorithms/CloudExpansionModel.cs b/src/CounterDrone.Core/Algorithms/CloudExpansionModel.cs index b35c34e..86aa15a 100644 --- a/src/CounterDrone.Core/Algorithms/CloudExpansionModel.cs +++ b/src/CounterDrone.Core/Algorithms/CloudExpansionModel.cs @@ -49,6 +49,26 @@ namespace CounterDrone.Core.Algorithms return volume > 0.001f ? (float)_ammo.SourceStrength / volume : (float)_ammo.CoreDensity; } + /// 达到指定浓度所需时间(密度随膨胀下降,较晚时间密度更低) + /// 浓度首次低于threshold的时间(s),如果不会低于则返回MaxDuration + public float TimeToDensity(float threshold) + { + // 密度 ≈ SourceStrength / (4/3 π R³),随R增大而下降 + // 求R使得密度=threshold: R³ = SourceStrength / (threshold * 4π/3) + float src = (float)_ammo.SourceStrength; + float volume = src / Math.Max(threshold, 0.000001f); + float r = (float)Math.Pow(volume * 3f / (4f * (float)Math.PI), 1f / 3f); + return TimeToReach(r); + } + + /// 覆盖指定距离需要的云团数量(间距=2R) + public int RoundsNeeded(float requiredCoverage) + { + float R = RadiusAt(30f); + float spacing = 2f * R; + return Math.Max(1, (int)Math.Ceiling(requiredCoverage / spacing)); + } + /// 达到指定半径所需时间 (s) public float TimeToReach(float radius) { diff --git a/src/CounterDrone.Core/Algorithms/DefaultDefensePlanner.cs b/src/CounterDrone.Core/Algorithms/DefaultDefensePlanner.cs index 41d3861..cfcdcff 100644 --- a/src/CounterDrone.Core/Algorithms/DefaultDefensePlanner.cs +++ b/src/CounterDrone.Core/Algorithms/DefaultDefensePlanner.cs @@ -361,16 +361,12 @@ namespace CounterDrone.Core.Algorithms private int CalcRoundsNeeded(DroneGroup threat, AmmunitionSpec ammo, CombatScene env, bool isAirBased, float turbulentRadius) { + var cloudModel = new CloudExpansionModel(ammo, env); float avgSpeed = (float)threat.Target.TypicalSpeed / 3.6f; - float spacing = 2f * turbulentRadius; - var aerosolType = (AerosolType)ammo.AerosolType; float neededExposure = aerosolType == AerosolType.ActiveMaterial ? 2f : 6f; - float singleCoverage = neededExposure * avgSpeed; - float requiredCoverage = singleCoverage; - - return Math.Max(1, - (int)Math.Ceiling(requiredCoverage / spacing)); + float requiredCoverage = neededExposure * avgSpeed; + return cloudModel.RoundsNeeded(requiredCoverage); } private float ComputeInterceptProbability(DroneGroup threat, @@ -399,7 +395,8 @@ namespace CounterDrone.Core.Algorithms var events = new List(); var mid = ThreatMidpoint(threat); - var (effectiveR, expansionTime, _) = ComputeEffectiveRadius(threat, ammo, env); + var cloudModel = new CloudExpansionModel(ammo, env); + float expansionTime = cloudModel.TimeToReach(cloudModel.RadiusAt(30f)); // 编队 Y 偏移:按车道分布 float laneSpacingZ = yLanes > 1 ? formationWidth / (yLanes - 1) : 0f; @@ -407,7 +404,7 @@ namespace CounterDrone.Core.Algorithms float tx = mid.X + targetOffset; - // 按目标点位置计算无人机到达时间,非中点 + // 无人机到达目标点时间 float droneSpeed = (float)threat.Target.TypicalSpeed / 3.6f; if (droneSpeed <= 0) return events; float startX = (float)threat.Waypoints[0].PosX; @@ -420,7 +417,6 @@ namespace CounterDrone.Core.Algorithms distToTx = Math.Max(0, Math.Min(totalDist, distToTx)); float txArrival = distToTx / droneSpeed; float recommendedTiming = txArrival - expansionTime; - // 来不及:无人机到达时云团未形成 → 跳过此目标点 if (recommendedTiming <= 0f) return events; float fireTime;