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;