CounterDroneBackend/src/CounterDrone.Core/Algorithms/CloudExpansionModel.cs
tian 3b8fb4ee86 refactor: code cleanup - warnings, dead code, naming
Warnings (9 to 0): events declared nullable, _cache nullable, IDamageModel param nullable.

Dead code removed: DefaultFormations class + FormationTemplate; AlgorithmTypes legacy types (ThreatProfile/DefenseRecommendation/DefenseSolution/MultiGroupRecommendation/RecommendedPlatform/RecommendedDetection); DroneEntity CurrentWaypointIndex/FormationOffsetX/Y/ApplyFormationOffset/wind params; Vector3 operators+Length+DistanceTo; CloudExpansionModel Phase2Duration/TimeToDensity; Kinematics EstimatedShellTime/GaussianConcentration; InterceptCandidate write-only fields (CoverageDuration/FlightTime/ShellFlightTime); ParticleParams EmitRate/ColorHex.

Naming: DefaultDefensePlanner -> DefensePlanner (only impl of IDefensePlanner); inCloudTime -> inCloudDistance (returns meters not seconds); DamageAssessment class summary fixed; wind comments clarified (drone wind removed vs cloud wind active).

Tests: 191 pass, 0 warnings.
2026-06-14 15:52:05 +08:00

76 lines
3.3 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System;
using CounterDrone.Core.Models;
namespace CounterDrone.Core.Algorithms
{
/// <summary>云团膨胀模型——根据弹药和环境参数计算各阶段半径、密度、膨胀时间</summary>
public class CloudExpansionModel
{
private readonly AmmunitionSpec _ammo;
private readonly CombatScene _env;
public CloudExpansionModel(AmmunitionSpec ammo, CombatScene env)
{
_ammo = ammo;
_env = env;
}
/// <summary>Phase 1 爆轰初始半径 (m)</summary>
public float InitialRadius => 3.3f * (float)Math.Pow(Math.Max(0.01, (float)_ammo.BurstChargeKg), 0.32f);
/// <summary>Phase 2 结束时的有效半径30s 湍流膨胀)</summary>
public float TurbulentRadius => RadiusAt(30f);
/// <summary>湍流膨胀系数 k</summary>
public float TurbulentExpansionK => (float)_ammo.TurbulentExpansionK;
/// <summary>指定时刻湍流膨胀半径 R(t) = R₀ + k√t</summary>
public float RadiusAt(float elapsedSeconds)
{
if (elapsedSeconds <= 0) return InitialRadius;
bool inPhase3 = elapsedSeconds > 30f;
if (!inPhase3)
return InitialRadius + TurbulentExpansionK * (float)Math.Sqrt(elapsedSeconds);
// Phase 3: 高斯扩散
float windSpeed = (float)_env.WindSpeed;
float x = Math.Max(1f, windSpeed * (elapsedSeconds - 30f));
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;
if (peakC <= effConc) return InitialRadius + TurbulentExpansionK * (float)Math.Sqrt(30f);
float sigma = (sY + sZ) / 2f;
float rPhase2 = InitialRadius + TurbulentExpansionK * (float)Math.Sqrt(30f);
return rPhase2 + sigma * (float)Math.Sqrt(2f * Math.Log(peakC / effConc));
}
/// <summary>指定时刻中心浓度</summary>
public float DensityAt(float elapsedSeconds)
{
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;
}
/// <summary>覆盖指定距离需要的云团数量</summary>
/// <param name="requiredCoverage">需要覆盖的距离 (m)</param>
/// <param name="spacing">相邻云团中心间距 (m),默认=2R(相切)。重叠时由调用方传入更小值。</param>
public int RoundsNeeded(float requiredCoverage, float? spacing = null)
{
float s = spacing ?? 2f * TurbulentRadius;
return Math.Max(1, (int)Math.Ceiling(requiredCoverage / s));
}
/// <summary>达到指定半径所需时间 (s)</summary>
public float TimeToReach(float radius)
{
float r0 = InitialRadius;
if (radius <= r0) return 0;
float k = TurbulentExpansionK;
return (radius - r0) * (radius - r0) / (k * k);
}
}
}