From da4e8d5c6399e67f7ac70de93d6445400a44bacb Mon Sep 17 00:00:00 2001 From: tian <11429339@qq.com> Date: Wed, 17 Jun 2026 11:30:56 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20=E7=A7=BB=E9=99=A4=E9=9A=90?= =?UTF-8?q?=E8=97=8F=20Math.Max=20=E5=9B=9E=E9=80=80=EF=BC=8C=E6=94=B9?= =?UTF-8?q?=E4=B8=BA=E6=98=BE=E5=BC=8F=E9=AA=8C=E8=AF=81=E6=88=96=E6=95=B0?= =?UTF-8?q?=E5=80=BC=20epsilon?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit GaussianPuffDispersion: - BurstChargeKg ≤ 0 → 抛异常,不再用 Math.Max(0.01, ...) 掩护 - Phase3 扩散距离 x ≤ 0 → 跳过,不再用 Math.Max(1f, ...) - Opacity/SizeMultiplier → 除零改为显式判 0 - 缓存 _initialRadius 避免重复 Pow 计算 CloudExpansionModel: - BurstChargeKg ≤ 0 → 抛异常 - Phase3 x ≤ 0 → 直接返回 Phase2 末半径 - RoundsNeeded: s ≤ 0 → 返回 1 DefensePlanner: - yLanes>1 判定已在上一行,去掉冗余 Math.Max(1, ...) InterceptCalculator: - 保留 +0.001f epsilon(确保 ts>0),但不作为隐藏回退 - 改用显式加偏移替代 Math.Max(0.001f, ...) DetectionCalculator.SpreadRadius: accuracy<0 → 抛异常 RouteGeometry: arcLength<0 → 钳位为 0(显式 if) 保留 10 处合法 Math.Max(取两值中较大者或几何钳位) --- .../Algorithms/CloudExpansionModel.cs | 32 +++++++++++-------- .../Algorithms/DefensePlanner.cs | 2 +- .../Algorithms/DetectionCalculator.cs | 4 ++- .../Algorithms/GaussianPuffDispersion.cs | 24 +++++++------- .../Algorithms/InterceptCalculator.cs | 3 +- .../Algorithms/RouteGeometry.cs | 3 +- 6 files changed, 39 insertions(+), 29 deletions(-) diff --git a/src/CounterDrone.Core/Algorithms/CloudExpansionModel.cs b/src/CounterDrone.Core/Algorithms/CloudExpansionModel.cs index 6c95bba..c1cd96b 100644 --- a/src/CounterDrone.Core/Algorithms/CloudExpansionModel.cs +++ b/src/CounterDrone.Core/Algorithms/CloudExpansionModel.cs @@ -8,15 +8,21 @@ namespace CounterDrone.Core.Algorithms { private readonly AmmunitionSpec _ammo; private readonly CombatScene _env; + private readonly float _initialRadius; public CloudExpansionModel(AmmunitionSpec ammo, CombatScene env) { _ammo = ammo; _env = env; + + var w = (float)ammo.BurstChargeKg; + if (w <= 0) + throw new ArgumentException($"BurstChargeKg 必须 > 0,实际: {w}", nameof(ammo)); + _initialRadius = 3.3f * (float)Math.Pow(w, 0.32); } /// Phase 1 爆轰初始半径 (m) - public float InitialRadius => 3.3f * (float)Math.Pow(Math.Max(0.01, (float)_ammo.BurstChargeKg), 0.32f); + public float InitialRadius => _initialRadius; /// Phase 2 结束时的有效半径 public float TurbulentRadius => RadiusAt(Phase2Duration); @@ -29,21 +35,22 @@ namespace CounterDrone.Core.Algorithms /// 指定时刻湍流膨胀半径 R(t) = R₀ + k√t public float RadiusAt(float elapsedSeconds) { - if (elapsedSeconds <= 0) return InitialRadius; + if (elapsedSeconds <= 0) return _initialRadius; float p2 = Phase2Duration; bool inPhase3 = elapsedSeconds > p2; if (!inPhase3) - return InitialRadius + TurbulentExpansionK * (float)Math.Sqrt(elapsedSeconds); + return _initialRadius + TurbulentExpansionK * (float)Math.Sqrt(elapsedSeconds); // Phase 3: 高斯扩散 float windSpeed = (float)_env.WindSpeed; - float x = Math.Max(1f, windSpeed * (elapsedSeconds - p2)); + float x = windSpeed * (elapsedSeconds - p2); + if (x <= 0) return _initialRadius + TurbulentExpansionK * (float)Math.Sqrt(p2); var cls = Kinematics.GetStabilityClass((WeatherType)_env.WeatherType, windSpeed); float sY = Kinematics.SigmaY(cls, x); float sZ = Kinematics.SigmaZ(cls, x); float peakC = Kinematics.GaussianPeakConcentration((float)_ammo.SourceStrength, sY, sZ); float effConc = (float)_ammo.EffectiveConcentration; - float rPhase2 = InitialRadius + TurbulentExpansionK * (float)Math.Sqrt(p2); + float rPhase2 = _initialRadius + TurbulentExpansionK * (float)Math.Sqrt(p2); if (peakC <= effConc) return rPhase2; float sigma = (sY + sZ) / 2f; return rPhase2 + sigma * (float)Math.Sqrt(2f * Math.Log(peakC / effConc)); @@ -54,26 +61,25 @@ namespace CounterDrone.Core.Algorithms { float r = RadiusAt(elapsedSeconds); float volume = (4f / 3f) * (float)Math.PI * r * r * r; - return volume > 0.001f ? (float)_ammo.SourceStrength / volume : (float)_ammo.CoreDensity; + if (volume <= 0.001f) return (float)_ammo.CoreDensity; + return (float)_ammo.SourceStrength / volume; } - /// 覆盖指定距离需要的云团数量 - /// 需要覆盖的距离 (m) - /// 相邻云团中心间距 (m),默认=2R(相切)。重叠时由调用方传入更小值。 public int RoundsNeeded(float requiredCoverage, float? spacing = null) { float s = spacing ?? 2f * TurbulentRadius; - return Math.Max(1, (int)Math.Ceiling(requiredCoverage / s)); + if (s <= 0) return 1; + int n = (int)Math.Ceiling(requiredCoverage / s); + return n < 1 ? 1 : n; } /// 达到指定半径所需时间 (s) public float TimeToReach(float radius) { - float r0 = InitialRadius; - if (radius <= r0) return 0; + if (radius <= _initialRadius) return 0; float k = TurbulentExpansionK; - return (radius - r0) * (radius - r0) / (k * k); + return (radius - _initialRadius) * (radius - _initialRadius) / (k * k); } } } diff --git a/src/CounterDrone.Core/Algorithms/DefensePlanner.cs b/src/CounterDrone.Core/Algorithms/DefensePlanner.cs index a022b87..5a6d60f 100644 --- a/src/CounterDrone.Core/Algorithms/DefensePlanner.cs +++ b/src/CounterDrone.Core/Algorithms/DefensePlanner.cs @@ -527,7 +527,7 @@ namespace CounterDrone.Core.Algorithms // 法向 = 切向旋转 90°,用 RouteGeometry.TangentAt 取穿越点处航路方向 var (tanX, tanZ) = RouteGeometry.TangentAt(wps, crossArc); float normalX = -tanZ, normalZ = tanX; // 切向逆时针 90° = 左侧法向 - float laneSpacing = yLanes > 1 ? formationWidth / Math.Max(1, yLanes - 1) : 0f; + float laneSpacing = yLanes > 1 ? formationWidth / (yLanes - 1) : 0f; float laneOffset = yLane * laneSpacing; // 穿越点 = 航路上 crossArc 处 + 横向车道偏移 diff --git a/src/CounterDrone.Core/Algorithms/DetectionCalculator.cs b/src/CounterDrone.Core/Algorithms/DetectionCalculator.cs index 8c1e972..820113e 100644 --- a/src/CounterDrone.Core/Algorithms/DetectionCalculator.cs +++ b/src/CounterDrone.Core/Algorithms/DetectionCalculator.cs @@ -137,7 +137,9 @@ namespace CounterDrone.Core.Algorithms /// 当前模型:散布半径 = 精度值(如精度 100m → 散布 ±100m)。 public static float SpreadRadius(float accuracy) { - return Math.Max(0f, accuracy); + if (accuracy < 0) + throw new ArgumentException($"accuracy 必须 ≥ 0,实际: {accuracy}", nameof(accuracy)); + return accuracy; } } diff --git a/src/CounterDrone.Core/Algorithms/GaussianPuffDispersion.cs b/src/CounterDrone.Core/Algorithms/GaussianPuffDispersion.cs index 4c47e30..09ed683 100644 --- a/src/CounterDrone.Core/Algorithms/GaussianPuffDispersion.cs +++ b/src/CounterDrone.Core/Algorithms/GaussianPuffDispersion.cs @@ -19,11 +19,11 @@ namespace CounterDrone.Core.Algorithms private Vector3 _center; private Vector3 _windVelocity; private bool _inPhase3; + private float _initialRadius; public Vector3 Center => _center; public float Radius => _currentRadius; public float CoreDensity => _currentDensity; - /// 云团中心峰值浓度(无人机穿过位置) public float PeakDensity { get; private set; } public float EffectiveRadius => _currentRadius; public ParticleParams Particles { get; } = new(); @@ -38,9 +38,11 @@ namespace CounterDrone.Core.Algorithms _elapsed = 0f; _inPhase3 = false; - // Phase 1: 爆轰膨胀 → 初始半径 var w = (float)ammo.BurstChargeKg; - _currentRadius = 3.3f * (float)Math.Pow(Math.Max(0.01, w), 0.32); + if (w <= 0) + throw new ArgumentException($"BurstChargeKg 必须 > 0,实际: {w}", nameof(ammo)); + _initialRadius = 3.3f * (float)Math.Pow(w, 0.32); + _currentRadius = _initialRadius; _currentDensity = (float)ammo.CoreDensity; PeakDensity = (float)ammo.CoreDensity; _center = releasePos; @@ -59,7 +61,6 @@ namespace CounterDrone.Core.Algorithms var (vx, vy, vz) = Kinematics.WindToVector(windDir, windSpeed); _windVelocity = new Vector3(vx, vy, vz); - // 判断阶段切换 if (!_inPhase3 && _elapsed >= 30f) _inPhase3 = true; @@ -67,8 +68,7 @@ namespace CounterDrone.Core.Algorithms { // Phase 2: 湍流扩散 R(t) = R₀ + k × √t var k = (float)_ammo.TurbulentExpansionK; - _currentRadius = 3.3f * (float)Math.Pow(Math.Max(0.01, (float)_ammo.BurstChargeKg), 0.32) - + k * (float)Math.Sqrt(_elapsed); + _currentRadius = _initialRadius + k * (float)Math.Sqrt(_elapsed); // 密度 = 源强 / 体积 var volume = (4f / 3f) * (float)Math.PI * _currentRadius * _currentRadius * _currentRadius; _currentDensity = volume > 0.001f ? (float)_ammo.SourceStrength / volume : 0f; @@ -76,12 +76,12 @@ namespace CounterDrone.Core.Algorithms else { // Phase 3: 高斯扩散 - var x = Math.Max(1f, windSpeed * (_elapsed - 30f)); + float x = windSpeed * (_elapsed - 30f); + if (x <= 0) return; // 尚未进入有效扩散距离 var cls = Kinematics.GetStabilityClass((WeatherType)_env.WeatherType, windSpeed); var sY = Kinematics.SigmaY(cls, x); var sZ = Kinematics.SigmaZ(cls, x); _currentDensity = Kinematics.GaussianPeakConcentration((float)_ammo.SourceStrength, sY, sZ); - // 有效半径从浓度反推 var effConc = (float)_ammo.EffectiveConcentration; if (_currentDensity > effConc) { @@ -95,11 +95,11 @@ namespace CounterDrone.Core.Algorithms _center.Y += _windVelocity.Y * deltaTime; _center.Z += _windVelocity.Z * deltaTime; - // 粒子参数 - Particles.Opacity = Math.Max(0.1f, _currentDensity / (float)_ammo.CoreDensity); - Particles.SizeMultiplier = _currentRadius / Math.Max(0.5f, 3.3f * (float)Math.Pow(Math.Max(0.01, (float)_ammo.BurstChargeKg), 0.32)); + // 粒子参数(仅用于可视化,不参与物理计算) + float coreDensity = (float)_ammo.CoreDensity; + Particles.Opacity = coreDensity > 0 ? _currentDensity / coreDensity : 0f; + Particles.SizeMultiplier = _initialRadius > 0 ? _currentRadius / _initialRadius : 0f; - // 消散 if (_elapsed >= (float)_ammo.MaxDuration || _currentRadius >= (float)_ammo.MaxRadius) { IsDissipated = true; diff --git a/src/CounterDrone.Core/Algorithms/InterceptCalculator.cs b/src/CounterDrone.Core/Algorithms/InterceptCalculator.cs index e8a3a52..82b92d5 100644 --- a/src/CounterDrone.Core/Algorithms/InterceptCalculator.cs +++ b/src/CounterDrone.Core/Algorithms/InterceptCalculator.cs @@ -75,7 +75,8 @@ namespace CounterDrone.Core.Algorithms return MathF.Atan2(sinA, cosA); } - float lo = detectArc + Math.Max(0.001f, vd * reactionTime + 0.001f); + // +0.001f 确保 ts > 0,否则 F() 返回 MaxValue 导致搜索失败 + float lo = detectArc + vd * reactionTime + 0.001f; if (lo >= totalArc) return (0, 0, 0); float fLo = F(lo); diff --git a/src/CounterDrone.Core/Algorithms/RouteGeometry.cs b/src/CounterDrone.Core/Algorithms/RouteGeometry.cs index 5dae24c..bc1a2db 100644 --- a/src/CounterDrone.Core/Algorithms/RouteGeometry.cs +++ b/src/CounterDrone.Core/Algorithms/RouteGeometry.cs @@ -108,7 +108,8 @@ namespace CounterDrone.Core.Algorithms { if (wps == null || wps.Count < 2) return (1f, 0f); - float remaining = Math.Max(0f, arcLength); + if (arcLength < 0) arcLength = 0; + float remaining = arcLength; for (int i = 0; i < wps.Count - 1; i++) { float dx = (float)wps[i + 1].PosX - (float)wps[i].PosX;