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.
76 lines
3.3 KiB
C#
76 lines
3.3 KiB
C#
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);
|
||
}
|
||
}
|
||
}
|