ThreatSourceLibaray/ThreatSource/src/MIssile/BaseMissile.cs

743 lines
27 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.Diagnostics;
using ThreatSource.Simulation;
using ThreatSource.Utils;
using System.Reflection;
namespace ThreatSource.Missile
{
/// <summary>
/// 导弹基类,实现了导弹的基本功能和状态管理
/// </summary>
/// <remarks>
/// 该类提供了导弹的核心功能:
/// - 运动状态计算和更新
/// - 制导系统管理
/// - 发动机控制
/// - 自毁和爆炸处理
/// - 状态监控和事件处理
/// 所有具体的导弹类型都继承自此基类
/// </remarks>
public class BaseMissile : SimulationElement, IMissile
{
/// <summary>
/// 获取导弹的当前飞行时间
/// </summary>
/// <value>飞行时间,单位:秒</value>
/// <remarks>
/// 从发射时刻开始计时
/// 用于控制导弹的生命周期
/// </remarks>
public double FlightTime { get; protected set; }
/// <summary>
/// 获取导弹的当前飞行距离
/// </summary>
/// <value>飞行距离,单位:米</value>
/// <remarks>
/// 从发射点到当前位置的累计飞行距离
/// 用于判断是否超出最大射程
/// </remarks>
public double FlightDistance { get; protected set; }
/// <summary>
/// 获取发动机的当前燃烧时间
/// </summary>
/// <value>发动机燃烧时间,单位:秒</value>
/// <remarks>
/// 发动机工作的累计时间
/// 用于控制推力变化和燃料消耗
/// </remarks>
public double EngineBurnTime { get; protected set; }
/// <summary>
/// 获取导弹是否处于制导状态
/// </summary>
/// <value>true表示导弹当前在制导false表示导弹处于非制导状态</value>
/// <remarks>
/// 影响导弹的运动学计算方法
/// 制导状态下使用制导律计算加速度
/// 非制导状态下使用弹道方程计算运动
/// </remarks>
public bool IsGuidance { get; protected set; }
/// <summary>
/// 获取或设置前一个制导状态
/// </summary>
/// <value>上一个时间步的制导状态</value>
/// <remarks>
/// 用于检测制导状态变化
/// 当IsGuidance与此值不同时表示制导状态发生了变化
/// </remarks>
protected bool PreviousIsGuidance { get; set; } = false;
/// <summary>
/// 获取或设置导弹的最后已知速度向量
/// </summary>
/// <value>三维速度向量</value>
/// <remarks>
/// 用于在失去制导时保持导弹的运动状态
/// 作为弹道计算的参考数据
/// </remarks>
protected Vector3D LastKnownVelocity = Vector3D.Zero;
/// <summary>
/// 获取或设置导弹的制导加速度
/// </summary>
/// <value>三维加速度向量,单位:米/秒²</value>
/// <remarks>
/// 由制导系统计算得出的期望加速度
/// 用于修正导弹的飞行路径
/// </remarks>
protected Vector3D GuidanceAcceleration { get; set; } = Vector3D.Zero;
/// <summary>
/// 获取或设置导弹的推力加速度
/// </summary>
/// <value>三维加速度向量,单位:米/秒²</value>
/// <remarks>
/// 由发动机产生的推进加速度
/// 影响导弹的速度变化
/// </remarks>
protected Vector3D ThrustAcceleration { get; set; }
/// <summary>
/// 获取或设置导弹的升力加速度
/// </summary>
/// <value>三维加速度向量,单位:米/秒²</value>
/// <remarks>
/// 由升力产生的加速度
/// 影响导弹的垂直运动
/// </remarks>
protected Vector3D LiftAcceleration { get; set; }
/// <summary>
/// 重力加速度(北京标准值)
/// </summary>
private static readonly Vector3D GravityAcceleration = new(0, -PhysicalConstants.BeijingGravity, 0);
/// <summary>
/// 获取导弹的固定配置参数
/// </summary>
/// <value>导弹属性配置对象</value>
/// <remarks>
/// 包含导弹的所有基本属性和性能限制
/// 在导弹创建时设置,运行期间保持不变
/// </remarks>
public readonly MissileProperties Properties;
/// <summary>
/// 标准导弹三段式飞行阶段
/// </summary>
public enum MissileFlightStage
{
/// <summary>
/// 发射阶段
/// </summary>
Launch,
/// <summary>
/// 巡航阶段
/// </summary>
Cruise,
/// <summary>
/// 制导阶段
/// </summary>
Guidance
}
/// <summary>
/// 当前飞行阶段
/// </summary>
protected MissileFlightStage currentStage = MissileFlightStage.Launch;
/// <summary>
/// 初始化导弹基类的新实例
/// </summary>
/// <param name="missileId">导弹ID</param>
/// <param name="properties">导弹属性配置</param>
/// <param name="kinematicState">发射参数</param>
/// <param name="manager">仿真管理器实例</param>
/// <remarks>
/// 构造过程:
/// - 初始化基本属性
/// - 设置性能限制
/// - 配置运动参数
/// - 建立仿真管理器关联
/// </remarks>
protected BaseMissile(
string missileId,
MissileProperties properties,
KinematicState kinematicState,
ISimulationManager manager)
: base(missileId, kinematicState, manager)
{
// 设置性能限制
Properties = properties;
// 初始化状态
EngineBurnTime = 0;
FlightTime = 0;
FlightDistance = 0;
IsActive = false;
IsGuidance = false;
GuidanceAcceleration = Vector3D.Zero;
LiftAcceleration = Vector3D.Zero;
// 计算初始推力加速度
Vector3D launchDirection = kinematicState.Orientation.ToVector().Normalize();
ThrustAcceleration = launchDirection * properties.LaunchAcceleration;
}
/// <summary>
/// 判断是否为末敏弹类型
/// </summary>
protected bool IsTerminalSensitiveType()
{
return Properties.Type == MissileType.TerminalSensitiveSubmunition;
}
/// <summary>
/// 供末敏弹等特殊导弹重写的自定义阶段更新方法
/// </summary>
protected virtual void UpdateCustomStages(double deltaTime) { }
/// <summary>
/// 更新导弹的状态
/// </summary>
/// <param name="deltaTime">时间步长,单位:秒</param>
/// <remarks>
/// 更新过程:
/// - 检查导弹是否处于活动状态
/// - 更新导弹的运动状态
/// - 更新计时器和计数器
/// </remarks>
public override void Update(double deltaTime)
{
if (!IsActive) return;
// 末敏弹等特殊类型走自定义流程
if (!IsTerminalSensitiveType())
{
// 标准三段式流程
switch (currentStage)
{
case MissileFlightStage.Launch:
OnLaunchStage(deltaTime);
break;
case MissileFlightStage.Cruise:
OnCruiseStage(deltaTime);
break;
case MissileFlightStage.Guidance:
OnGuidanceStage(deltaTime);
break;
}
}
// 公共运动学与生命周期管理
UpdateMotionState(deltaTime);
if (ShouldSelfDestruct())
{
SelfDestruct();
}
// 检测制导状态变化并发布相应事件
CheckGuidanceStatusChange();
}
/// <summary>
/// 发射阶段默认实现
/// </summary>
protected virtual void OnLaunchStage(double deltaTime)
{
// 发射阶段不使用制导
GuidanceAcceleration = Vector3D.Zero;
// 计算升力加速度。在发射阶段,升力加速度和攻角相关
LiftAcceleration = LiftModel.CalculateLiftAcceleration(KState.Orientation.Pitch * 180 / Math.PI);
// 发射阶段结束,进入巡航阶段
if (FlightTime >= Properties.MaxEngineBurnTime)
{
currentStage = MissileFlightStage.Cruise;
}
}
/// <summary>
/// 巡航阶段默认实现
/// </summary>
protected virtual void OnCruiseStage(double deltaTime)
{
// 巡航阶段不使用制导
GuidanceAcceleration = Vector3D.Zero;
// 调整速度方向为水平飞行
if (Math.Abs(KState.Velocity.Y) > 0.1) // 如果有明显的垂直速度分量
{
// 保持水平速度大小,消除垂直分量
double horizontalSpeed = Math.Sqrt(KState.Velocity.X * KState.Velocity.X + KState.Velocity.Z * KState.Velocity.Z);
if (horizontalSpeed > 0.1) // 确保有水平速度
{
Vector3D horizontalDirection = new Vector3D(KState.Velocity.X, 0, KState.Velocity.Z).Normalize();
KState.Velocity = horizontalDirection * KState.Speed;
}
}
// 设置巡航攻角(相对于水平面)
double cruiseAttackAngleRad = Properties.CruiseAttackAngle * Math.PI / 180.0;
KState.Orientation = new Orientation(KState.Orientation.Yaw, cruiseAttackAngleRad, KState.Orientation.Roll);
// 计算升力加速度:在巡航阶段,基于攻角计算升力
LiftAcceleration = LiftModel.CalculateLiftAcceleration(Properties.CruiseAttackAngle);
// 巡航阶段结束,进入制导阶段
if (FlightTime >= Properties.MaxEngineBurnTime + Properties.CruiseTime)
{
currentStage = MissileFlightStage.Guidance;
}
}
/// <summary>
/// 制导阶段默认实现
/// </summary>
protected virtual void OnGuidanceStage(double deltaTime)
{
// 计算升力加速度。在制导阶段,升力加速度和攻角相关;
LiftAcceleration = LiftModel.CalculateLiftAcceleration(KState.Orientation.Pitch * 180 / Math.PI);
}
/// <summary>
/// 更新导弹的运动状态
/// </summary>
/// <param name="deltaTime">时间步长,单位:秒</param>
/// <remarks>
/// 更新过程:
/// - 计算包含风影响的合加速度
/// - 根据制导状态选择运动更新方法
/// - 更新导弹的位置和速度
/// </remarks>
protected virtual void UpdateMotionState(double deltaTime)
{
// 检查发动机是否仍在提供推力
if (ThrustAcceleration != Vector3D.Zero)
{
EngineBurnTime += deltaTime; // 累加燃烧时间
if (EngineBurnTime >= Properties.MaxEngineBurnTime || KState.Speed >= Properties.MaxSpeed)
{
string reason = EngineBurnTime >= Properties.MaxEngineBurnTime ?
$"达到最大燃烧时间({Properties.MaxEngineBurnTime}s)" :
$"达到最大速度({KState.Speed:F2}m/s >= {Properties.MaxSpeed}m/s)";
Debug.WriteLine($"导弹 {Id}: 发动机推力已于飞行时间 {FlightTime:F2}s 关闭。原因: {reason}");
ThrustAcceleration = Vector3D.Zero; // 关闭推力
}
}
// 计算包含风影响的合加速度
Vector3D acceleration = CalculateAcceleration(KState.Velocity);
if (IsGuidance)
{
// 制导条件下,使用四阶龙格-库塔方法更新导弹的位置和速度
(KState.Position, KState.Velocity) = MotionAlgorithm.RungeKutta4(deltaTime, KState.Position, KState.Velocity, acceleration);
}
else
{
// 无制导条件下,使用运动学方程更新导弹的位置和速度
(KState.Position, KState.Velocity) = MotionAlgorithm.CalculateBallisticMotion(KState.Position, KState.Velocity, acceleration, deltaTime);
}
// 在制导阶段,根据是否获得制导来调整导弹朝向
if(currentStage == MissileFlightStage.Guidance)
{
if (!IsGuidance)
{
// 导引头搜索阶段:保持水平飞行,导弹朝向向下一个固定角度进行搜索
// 不改变速度向量,让导引头在下视角范围内搜索目标
double seekingAngleRad = Properties.GuidanceSeekingAngle * Math.PI / 180.0;
KState.Orientation = new Orientation(KState.Orientation.Yaw, -seekingAngleRad, KState.Orientation.Roll);
}
// 如果IsGuidance为true制导系统会通过GuidanceAcceleration自动调整导弹的飞行轨迹和朝向
}
// 限制速度不超过最大速度
if (KState.Speed > Properties.MaxSpeed)
{
KState.Speed = Properties.MaxSpeed;
}
// 添加高斯噪声(测试用,用于测试运动中概率的影响)
// Position = MotionAlgorithm.AddRandomPerturbation(Position);
// Velocity = MotionAlgorithm.AddRandomPerturbation(Velocity);
FlightTime += deltaTime;
FlightDistance += KState.Speed * deltaTime;
}
/// <summary>
/// 计算导弹的合加速度
/// </summary>
/// <param name="velocity">当前速度向量</param>
/// <returns>合加速度向量</returns>
/// <remarks>
/// 计算过程:
/// - 获取当前风速向量
/// - 计算空气阻力加速度(已考虑风)
/// - 合成总加速度(制导加速度 + 推力加速度 + 空气阻力加速度 + 重力加速度)
/// - 限制合加速度不超过最大值
/// </remarks>
private Vector3D CalculateAcceleration(Vector3D velocity)
{
// 获取当前风速向量
Vector3D windVector = GetWindVectorFromWeather();
// 计算空气阻力加速度(考虑风的影响)
Vector3D dragAcceleration = MotionAlgorithm.CalculateDragAcceleration(velocity, windVector, Properties.Mass);
// 合成总加速度(制导加速度 + 推力加速度 + 空气阻力加速度 + 升力加速度 + 重力加速度)
Vector3D totalAcceleration = GuidanceAcceleration + ThrustAcceleration + dragAcceleration + LiftAcceleration + GravityAcceleration;
Debug.WriteLine($"导弹 {Id} 的加速度: {totalAcceleration}, 制导: {GuidanceAcceleration}, " +
$"推力: {ThrustAcceleration}, 空阻(含风): {dragAcceleration}, 升力: {LiftAcceleration}, 重力: {GravityAcceleration}");
if (totalAcceleration.Magnitude() > Properties.MaxAcceleration)
{
totalAcceleration = totalAcceleration.Normalize() * Properties.MaxAcceleration;
}
return totalAcceleration;
}
/// <summary>
/// 从天气系统获取当前的风速向量
/// </summary>
/// <returns>风速向量,单位:米/秒</returns>
protected Vector3D GetWindVectorFromWeather()
{
var weather = SimulationManager.CurrentWeather;
if (weather == null)
return Vector3D.Zero;
return MotionAlgorithm.CalculateWindVector(weather.WindSpeed, weather.WindDirection);
}
/// <summary>
/// 发射导弹
/// </summary>
/// <remarks>
/// 发射过程:
/// - 开始计时和计数
/// - 启动发动机
/// - 初始化运动状态
/// </remarks>
public virtual void Fire()
{
// 子类可以重写此方法来处理发射时的特殊逻辑
}
/// <summary>
/// 检查是否应该自毁
/// </summary>
/// <returns>true表示需要自毁false表示可以继续飞行</returns>
/// <remarks>
/// 自毁条件:
/// - 超出最大飞行时间
/// - 超出最大飞行距离
/// - 有制导时:高度低于负爆炸半径(考虑仿真步长)
/// - 无制导时:高度低于安全阈值
/// </remarks>
protected bool ShouldSelfDestruct()
{
// 基本条件判断
if (FlightTime >= Properties.MaxFlightTime
|| FlightDistance >= Properties.MaxFlightDistance)
{
return true;
}
// 根据制导状态判断自毁高度
if (IsGuidance)
{
// 有制导时,在负爆炸半径高度自毁(考虑仿真步长)
return KState.Position.Y <= -Properties.ExplosionRadius;
}
else
{
// 无制导时,在自毁高度自毁
return KState.Position.Y <= Properties.SelfDestructHeight;
}
}
/// <summary>
/// 导弹爆炸
/// </summary>
/// <remarks>
/// 爆炸过程:
/// - 停止导弹运动
/// - 触发爆炸效果
/// - 发布爆炸事件
/// - 结束导弹任务
/// </remarks>
public virtual void Explode()
{
OnExplode();
Deactivate();
}
/// <summary>
/// 爆炸后处理
/// </summary>
/// <remarks>
/// 爆炸后处理:
/// - 设置导弹状态为非活动
/// - 触发爆炸事件
/// </remarks>
protected virtual void OnExplode()
{
// 发布导弹爆炸事件
var explodeEvent = new MissileExplodeEvent
{
SenderId = Id,
Position = KState.Position,
ExplosionRadius = Properties.ExplosionRadius,
TargetId = null // 这里可以根据需要设置目标ID通常在子类中重写
};
SimulationManager.PublishEvent(explodeEvent);
// 子类可以重写此方法来处理爆炸时的特殊逻辑
}
/// <summary>
/// 导弹自毁
/// </summary>
/// <remarks>
/// 自毁过程:
/// - 记录自毁原因
/// - 停止导弹运动
/// - 触发自毁效果
/// - 结束导弹任务
/// </remarks>
public void SelfDestruct()
{
string reason;
if (FlightTime >= Properties.MaxFlightTime)
{
reason = "超出最大飞行时间";
}
else if (FlightDistance >= Properties.MaxFlightDistance)
{
reason = "超出最大飞行距离";
}
else if (IsGuidance && KState.Position.Y <= -Properties.ExplosionRadius)
{
reason = "有制导状态下高度低于负爆炸半径";
}
else if (!IsGuidance && KState.Position.Y <= Properties.SelfDestructHeight)
{
reason = "无制导状态下高度低于自毁高度";
}
else
{
reason = "未知原因触发自毁";
}
Trace.TraceInformation($"导弹 {Id} 自毁。原因: {reason}");
// 发布导弹自毁事件
var selfDestructEvent = new MissileSelfDestructEvent
{
SenderId = Id,
Reason = reason,
Position = KState.Position
};
SimulationManager.PublishEvent(selfDestructEvent);
OnSelfDestruct();
Deactivate();
}
/// <summary>
/// 自毁后处理
/// </summary>
/// <remarks>
/// 自毁后处理:
/// - 设置导弹状态为非活动
/// - 触发自毁事件
/// </remarks>
protected virtual void OnSelfDestruct()
{
// 子类可以重写此方法来处理自毁时的特殊逻辑
}
/// <summary>
/// 激活导弹
/// </summary>
/// <remarks>
/// 激活过程:
/// - 调用基类激活方法
/// - 订阅目标命中事件
/// </remarks>
public override void Activate()
{
base.Activate();
SimulationManager.SubscribeToEvent<TargetHitEvent>(OnTargetHitEvent);
}
/// <summary>
/// 停用导弹
/// </summary>
/// <remarks>
/// 停用过程:
/// - 调用基类停用方法
/// - 取消订阅目标命中事件
/// </remarks>
public override void Deactivate()
{
base.Deactivate();
SimulationManager.UnsubscribeFromEvent<TargetHitEvent>(OnTargetHitEvent);
}
private void OnTargetHitEvent(TargetHitEvent eventData)
{
if (eventData.MissileId == Id)
{
Explode();
}
}
/// <summary>
/// 获取导弹状态信息
/// </summary>
/// <returns>导弹状态信息</returns>
/// <remarks>
/// 返回信息包括:
/// - 基本状态信息
/// - 导弹固有属性
/// - 导弹运行时状态
/// </remarks>
public override ElementStatusInfo GetStatusInfo()
{
// 获取基础状态信息
var statusInfo = base.GetStatusInfo();
// 使用反射动态添加来自 this.Properties 的导弹固有属性
if (Properties != null)
{
var propertiesType = Properties.GetType();
var props = propertiesType.GetProperties(BindingFlags.Public | BindingFlags.Instance);
foreach (var prop in props)
{
if (prop.CanRead)
{
object? propValue = prop.GetValue(Properties);
if (propValue != null)
{
statusInfo.ExtendedProperties[prop.Name] = propValue;
}
}
}
}
// 添加 BaseMissile 类的运行时状态参数
statusInfo.ExtendedProperties["FlightTime"] = FlightTime;
statusInfo.ExtendedProperties["FlightDistance"] = FlightDistance;
statusInfo.ExtendedProperties["EngineBurnTime"] = EngineBurnTime;
statusInfo.ExtendedProperties["CurrentStage"] = currentStage.ToString();
statusInfo.ExtendedProperties["IsGuidance"] = IsGuidance;
statusInfo.ExtendedProperties["GuidanceAcceleration"] = GuidanceAcceleration;
return statusInfo;
}
/// <summary>
/// 检测制导状态变化并发布相应事件
/// </summary>
/// <remarks>
/// 检测过程:
/// - 比较当前制导状态与前一个状态
/// - 如果状态发生变化,发布相应的制导获得或失去事件
/// - 更新前一个状态记录
/// </remarks>
protected virtual void CheckGuidanceStatusChange()
{
if (IsGuidance != PreviousIsGuidance)
{
if (IsGuidance)
{
// 获得制导
var guidanceAcquiredEvent = new MissileGuidanceAcquiredEvent
{
SenderId = Id,
GuidanceType = GetCurrentGuidanceType(),
GuidanceSystemId = GetCurrentGuidanceSystemId()
};
SimulationManager.PublishEvent(guidanceAcquiredEvent);
Trace.TraceInformation($"导弹 {Id} 获得制导");
}
else
{
// 失去制导
var guidanceLostEvent = new MissileGuidanceLostEvent
{
SenderId = Id,
Reason = GetGuidanceLostReason(),
GuidanceType = GetCurrentGuidanceType(),
};
SimulationManager.PublishEvent(guidanceLostEvent);
Trace.TraceInformation($"导弹 {Id} 失去制导,原因: {guidanceLostEvent.Reason}");
}
// 更新前一个状态
PreviousIsGuidance = IsGuidance;
}
}
/// <summary>
/// 获取当前制导类型描述
/// </summary>
/// <returns>制导类型字符串</returns>
/// <remarks>
/// 子类可以重写此方法以提供更具体的制导类型信息
/// 基类默认根据导弹类型返回通用描述
/// </remarks>
protected virtual string GetCurrentGuidanceType()
{
return Properties.Type switch
{
MissileType.LaserSemiActiveGuidance => "激光半主动制导",
MissileType.LaserBeamRiderGuidance => "激光驾束制导",
MissileType.InfraredImagingTerminalGuidance => "红外成像制导",
MissileType.InfraredCommandGuidance => "红外指令制导",
MissileType.MillimeterWaveTerminalGuidance => "毫米波制导",
MissileType.CompositeGuidance => "复合制导",
_ => "未知制导类型"
};
}
/// <summary>
/// 获取当前制导系统ID
/// </summary>
/// <returns>制导系统ID基类返回null</returns>
/// <remarks>
/// 子类可以重写此方法以提供具体的制导系统ID
/// </remarks>
protected virtual string? GetCurrentGuidanceSystemId()
{
return null;
}
/// <summary>
/// 获取失去制导的原因
/// </summary>
/// <returns>失去制导的原因描述</returns>
/// <remarks>
/// 子类可以重写此方法以提供更具体的失去制导原因
/// 基类默认返回通用描述
/// </remarks>
protected virtual string GetGuidanceLostReason()
{
return "制导系统失效或信号中断";
}
}
}