861 lines
36 KiB
C#
861 lines
36 KiB
C#
using ThreatSource.Utils;
|
||
using ThreatSource.Simulation;
|
||
using ThreatSource.Sensor;
|
||
using ThreatSource.Indicator;
|
||
using ThreatSource.Jammer;
|
||
using System.Diagnostics;
|
||
using AirTransmission;
|
||
|
||
namespace ThreatSource.Guidance
|
||
{
|
||
/// <summary>
|
||
/// 激光半主动制导系统类,实现了基于激光照射的目标跟踪和制导功能
|
||
/// </summary>
|
||
/// <remarks>
|
||
/// 该类提供了激光半主动制导系统的核心功能:
|
||
/// - 激光目标照射
|
||
/// - 反射光探测
|
||
/// - 信号处理
|
||
/// - 比例导引控制
|
||
/// 用于实现精确制导打击
|
||
/// </remarks>
|
||
public class LaserSemiActiveGuidanceSystem : BaseGuidanceSystem
|
||
{
|
||
private readonly LaserSemiActiveGuidanceConfig config;
|
||
|
||
/// <summary>
|
||
/// 获取设备支持的阻塞干扰类型
|
||
/// </summary>
|
||
public override IEnumerable<JammingType> SupportedBlockingJammingTypes => [JammingType.Laser];
|
||
|
||
/// <summary>
|
||
/// 获取设备支持的干扰类型
|
||
/// </summary>
|
||
public override IEnumerable<JammingType> SupportedJammingTypes => [JammingType.Laser, JammingType.SmokeGrenade, JammingType.LaserDecoy];
|
||
|
||
/// <summary>
|
||
/// 获取或设置目标位置 (使用可空类型)
|
||
/// </summary>
|
||
/// <remarks>
|
||
/// 记录当前跟踪目标的三维位置
|
||
/// 用于制导计算
|
||
/// </remarks>
|
||
private Vector3D? TargetPosition { get; set; }
|
||
|
||
/// <summary>
|
||
/// 获取或设置接收到的激光功率
|
||
/// </summary>
|
||
/// <remarks>
|
||
/// 记录接收到的激光功率
|
||
/// 用于制导计算
|
||
/// </remarks>
|
||
private double ReceivedLaserPower { get; set; }
|
||
|
||
/// <summary>
|
||
/// 获取或设置激光照射状态
|
||
/// </summary>
|
||
/// <remarks>
|
||
/// 指示当前是否有激光照射目标
|
||
/// 影响系统的工作状态
|
||
/// </remarks>
|
||
private bool LaserIlluminationOn { get; set; }
|
||
|
||
/// <summary>
|
||
/// 获取或设置期望的激光编码
|
||
/// </summary>
|
||
/// <remarks>
|
||
/// 导弹期望接收的编码信息
|
||
/// 用于验证接收到的激光信号
|
||
/// 默认编码为PPM编码,值为1234
|
||
/// </remarks>
|
||
private LaserCodeConfig? InternalLaserCodeConfig { get; set; }
|
||
|
||
/// <summary>
|
||
/// 获取或设置支持的编码类型列表
|
||
/// </summary>
|
||
/// <remarks>
|
||
/// 定义导弹支持的编码类型
|
||
/// 默认支持PRF、PPM和PWM编码
|
||
/// </remarks>
|
||
private readonly List<LaserCodeType> supportedCodeTypes =
|
||
[
|
||
LaserCodeType.PRF,
|
||
LaserCodeType.PPM,
|
||
LaserCodeType.PWM
|
||
];
|
||
|
||
/// <summary>
|
||
/// 四象限探测器实例
|
||
/// </summary>
|
||
/// <remarks>
|
||
/// 用于精确测量光斑位置
|
||
/// 计算目标方向误差
|
||
/// 提供高精度制导信号
|
||
/// </remarks>
|
||
private readonly QuadrantDetector quadrantDetector;
|
||
|
||
/// <summary>
|
||
/// 获取或设置光斑偏移灵敏度
|
||
/// </summary>
|
||
/// <remarks>
|
||
/// 定义了四象限探测器对光斑偏移的响应灵敏度
|
||
/// 影响制导系统的响应速度和稳定性
|
||
/// 典型值为0.05
|
||
/// </remarks>
|
||
private double SpotOffsetSensitivity { get; set; } = 0.05;
|
||
|
||
/// <summary>
|
||
/// 上一次的制导加速度,用于平滑处理
|
||
/// </summary>
|
||
/// <remarks>
|
||
/// 用于实现加速度平滑处理
|
||
/// 减少加速度突变,使导弹飞行更稳定
|
||
/// </remarks>
|
||
private Vector3D PreviousGuidanceAcceleration { get; set; } = Vector3D.Zero;
|
||
|
||
/// <summary>
|
||
/// 加速度平滑系数
|
||
/// </summary>
|
||
/// <remarks>
|
||
/// 范围(0,1],值越小平滑效果越强
|
||
/// 影响加速度的平滑程度
|
||
/// </remarks>
|
||
private const double AccelerationSmoothingFactor = 0.5;
|
||
|
||
/// <summary>
|
||
/// 激光目标列表,包括真实目标和诱偏目标
|
||
/// </summary>
|
||
private readonly List<(SimulationElement Target, Vector3D SpotPosition, SimulationElement Source)> laserTargets = [];
|
||
|
||
/// <summary>
|
||
/// 初始化激光半主动制导系统的新实例
|
||
/// </summary>
|
||
/// <param name="id">制导系统ID</param>
|
||
/// <param name="missileId">导弹ID</param>
|
||
/// <param name="maxAcceleration">最大加速度,单位:米/平方秒</param>
|
||
/// <param name="guidanceCoefficient">制导系数</param>
|
||
/// <param name="laserCodeConfig">激光编码配置</param>
|
||
/// <param name="guidanceConfig">激光半主动导引系统配置</param>
|
||
/// <param name="simulationManager">仿真管理器实例</param>
|
||
/// <remarks>
|
||
/// 构造过程:
|
||
/// - 初始化基类参数
|
||
/// - 初始化目标信息
|
||
/// - 初始化激光参数
|
||
/// - 创建四象限探测器
|
||
/// - 加载干扰阈值配置
|
||
/// </remarks>
|
||
public LaserSemiActiveGuidanceSystem(
|
||
string id,
|
||
string missileId,
|
||
double maxAcceleration,
|
||
double guidanceCoefficient,
|
||
LaserCodeConfig laserCodeConfig,
|
||
LaserSemiActiveGuidanceConfig guidanceConfig,
|
||
ISimulationManager simulationManager)
|
||
: base(id, missileId, maxAcceleration, guidanceCoefficient, simulationManager)
|
||
{
|
||
config = guidanceConfig;
|
||
|
||
LaserIlluminationOn = false;
|
||
InternalLaserCodeConfig = laserCodeConfig;
|
||
|
||
// 创建四象限探测器实例,使用配置中的参数
|
||
quadrantDetector = new QuadrantDetector(
|
||
config.SensorDiameter,
|
||
config.FocusedSpotDiameter,
|
||
config.LockThreshold);
|
||
|
||
// 设置光斑偏移灵敏度
|
||
SpotOffsetSensitivity = config.SpotOffsetSensitivity;
|
||
|
||
// 初始化加速度平滑处理
|
||
PreviousGuidanceAcceleration = Vector3D.Zero;
|
||
|
||
InitializeJamming(guidanceConfig.JammingResistanceThreshold, SupportedJammingTypes, SupportedBlockingJammingTypes);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 激活制导系统
|
||
/// </summary>
|
||
/// <remarks>
|
||
/// 激活过程:
|
||
/// - 调用基类激活
|
||
/// - 订阅激光照射事件
|
||
/// - 订阅激光干扰事件
|
||
/// </remarks>
|
||
public override void Activate()
|
||
{
|
||
base.Activate();
|
||
// 订阅激光照射事件
|
||
SimulationManager.SubscribeToEvent<LaserIlluminationUpdateEvent>(OnLaserIlluminationUpdate);
|
||
SimulationManager.SubscribeToEvent<LaserIlluminationStopEvent>(OnLaserIlluminationStop);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 停用制导系统
|
||
/// </summary>
|
||
/// <remarks>
|
||
/// 停用过程:
|
||
/// - 调用基类停用
|
||
/// - 取消订阅激光照射事件
|
||
/// </remarks>
|
||
public override void Deactivate()
|
||
{
|
||
base.Deactivate();
|
||
// 取消订阅激光照射事件
|
||
SimulationManager.UnsubscribeFromEvent<LaserIlluminationUpdateEvent>(OnLaserIlluminationUpdate);
|
||
SimulationManager.UnsubscribeFromEvent<LaserIlluminationStopEvent>(OnLaserIlluminationStop);
|
||
|
||
TargetPosition = null;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 处理激光照射更新事件 (恢复编码检查)
|
||
/// </summary>
|
||
/// <param name="evt">激光照射更新事件</param>
|
||
private void OnLaserIlluminationUpdate(LaserIlluminationUpdateEvent evt)
|
||
{
|
||
if (evt?.LaserDesignatorId == null || evt?.TargetId == null || evt?.SpotPosition == null)
|
||
{
|
||
Trace.TraceInformation("接收到无效的激光照射更新事件");
|
||
return;
|
||
}
|
||
|
||
// 1. 检查编码 (如果需要)
|
||
if (InternalLaserCodeConfig != null && InternalLaserCodeConfig.IsCodeMatchRequired)
|
||
{
|
||
if (!CheckLaserCode(evt.LaserCodeConfig)) // 使用辅助方法检查编码
|
||
{
|
||
PublishCodeMismatchEvent(evt.LaserDesignatorId, evt.LaserCodeConfig);
|
||
Trace.TraceInformation($"[LASER_SEMI_ACTIVE] {Id} 接收到编码不匹配的激光照射事件,忽略。预期: {InternalLaserCodeConfig}, 收到: {evt.LaserCodeConfig}");
|
||
// 编码不匹配,不处理此事件,也不设置 LaserIlluminationOn
|
||
return;
|
||
}
|
||
Debug.WriteLine($"[LASER_SEMI_ACTIVE] {Id} 激光编码匹配。");
|
||
}
|
||
else
|
||
{
|
||
Debug.WriteLine($"[LASER_SEMI_ACTIVE] {Id} 未配置编码检查或不要求匹配。");
|
||
}
|
||
|
||
// 2. 编码匹配或无需检查,处理事件
|
||
Debug.WriteLine($"[LASER_SEMI_ACTIVE] 处理激光照射更新事件: 指示器ID: {evt.LaserDesignatorId}, 目标ID: {evt.TargetId}");
|
||
try
|
||
{
|
||
LaserDesignator laserDesignator = SimulationManager.GetEntityById(evt.LaserDesignatorId) as LaserDesignator ?? throw new Exception("激光指示器不存在");
|
||
SimulationElement target = SimulationManager.GetEntityById(evt.TargetId) as SimulationElement ?? throw new Exception("目标不存在");
|
||
|
||
int existingIndex = laserTargets.FindIndex(t => t.Target.Id == target.Id);
|
||
if (existingIndex != -1)
|
||
{
|
||
laserTargets.RemoveAt(existingIndex);
|
||
}
|
||
laserTargets.Add((target, evt.SpotPosition.Value, laserDesignator));
|
||
|
||
// 只要收到有效事件就认为照射开启 (有效性由后续SNR判断)
|
||
LaserIlluminationOn = true;
|
||
// HasGuidance 的设置由 Update 方法根据 SNR 和其他条件决定
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
Trace.TraceError($"处理激光照射更新事件时出错: {ex.Message}");
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 处理激光照射停止事件
|
||
/// </summary>
|
||
/// <param name="evt">激光照射停止事件</param>
|
||
private void OnLaserIlluminationStop(LaserIlluminationStopEvent evt)
|
||
{
|
||
if (evt?.TargetId != null)
|
||
{
|
||
// 移除特定目标
|
||
laserTargets.RemoveAll(t => t.Target.Id == evt.TargetId);
|
||
// 如果没有其他照射目标,则关闭照射状态
|
||
if (!laserTargets.Any())
|
||
{
|
||
LaserIlluminationOn = false;
|
||
HasGuidance = false;
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 处理系统被干扰的事件
|
||
/// </summary>
|
||
/// <param name="parameters">干扰参数</param>
|
||
protected override void HandleJammingApplied(JammingParameters parameters)
|
||
{
|
||
base.HandleJammingApplied(parameters);
|
||
|
||
if (parameters.Type == JammingType.Laser)
|
||
{
|
||
Debug.WriteLine($"[LASER_SEMI_ACTIVE] 受到激光干扰。", "Jamming");
|
||
TargetPosition = null; // 丢失目标位置
|
||
LaserIlluminationOn = false; // 无法确认照射状态
|
||
}
|
||
else if (parameters.Type == JammingType.SmokeGrenade)
|
||
{
|
||
Debug.WriteLine($"[LASER_SEMI_ACTIVE] 烟幕干扰应用,JammerId: {parameters.JammerId}", "Jamming");
|
||
}
|
||
else if (parameters.Type == JammingType.LaserDecoy)
|
||
{
|
||
Debug.WriteLine($"[LASER_SEMI_ACTIVE] 受到激光诱偏干扰。JammerId: {parameters.JammerId}, SourceId: {parameters.SourceId}");
|
||
if (parameters.JammerId != null && parameters.SourceId != null)
|
||
{
|
||
LaserDecoy decoyTarget = SimulationManager.GetEntityById(parameters.JammerId) as LaserDecoy ?? throw new Exception("诱偏目标不存在");
|
||
SimulationElement decoySource = SimulationManager.GetEntityById(parameters.SourceId) as SimulationElement ?? throw new Exception("诱偏源不存在");
|
||
// 添加激光目标
|
||
if (!laserTargets.Any(t => t.Target.Id == decoyTarget.Id))
|
||
{
|
||
laserTargets.Add((decoyTarget, decoyTarget.KState.Position, decoySource));
|
||
Debug.WriteLine($"[LASER_SEMI_ACTIVE] 诱偏目标添加到激光目标列表。当前激光目标数量: {laserTargets.Count}");
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 处理系统干扰被清除的事件
|
||
/// </summary>
|
||
/// <param name="parameters">干扰参数</param>
|
||
protected override void HandleJammingCleared(JammingParameters parameters)
|
||
{
|
||
base.HandleJammingCleared(parameters);
|
||
|
||
if (parameters.Type == JammingType.Laser)
|
||
{
|
||
Debug.WriteLine($"[LASER_SEMI_ACTIVE] 激光干扰已清除。", "Jamming");
|
||
}
|
||
else if (parameters.Type == JammingType.SmokeGrenade)
|
||
{
|
||
Debug.WriteLine($"[LASER_SEMI_ACTIVE] 烟幕干扰已清除,JammerId: {parameters.JammerId}", "Jamming");
|
||
}
|
||
else if (parameters.Type == JammingType.LaserDecoy)
|
||
{
|
||
if (parameters.JammerId != null)
|
||
{
|
||
laserTargets.RemoveAll(t => t.Target.Id == parameters.JammerId);
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 判断是否应该处理传入的干扰参数(激光干扰需要额外检查波长和编码)
|
||
/// </summary>
|
||
/// <param name="parameters">干扰参数</param>
|
||
/// <returns>如果应该处理则返回 true,否则返回 false</returns>
|
||
protected override bool ShouldHandleJamming(JammingParameters parameters)
|
||
{
|
||
// 首先调用基类检查是否支持该干扰类型
|
||
if (!base.ShouldHandleJamming(parameters))
|
||
{
|
||
return false;
|
||
}
|
||
|
||
// 对激光干扰添加波长检查
|
||
if (parameters.Type == JammingType.Laser || parameters.Type == JammingType.LaserDecoy)
|
||
{
|
||
// 1. 检查波长
|
||
if (Math.Abs((parameters.Wavelength ?? 0) - config.Wavelength) > 1e-6)
|
||
{
|
||
Debug.WriteLine($"[LASER_SEMI_ACTIVE] {Id} 忽略激光干扰:波长 {parameters.Wavelength}um 与期望波长 {config.Wavelength}um 不匹配。", "Jamming");
|
||
return false;
|
||
}
|
||
}
|
||
|
||
// 如果是支持的非激光干扰 (例如烟幕) 或通过了激光检查,则返回 true
|
||
return true;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 更新制导系统的状态和计算结果
|
||
/// </summary>
|
||
/// <param name="deltaTime">时间步长,单位:秒</param>
|
||
public override void Update(double deltaTime)
|
||
{
|
||
base.Update(deltaTime);
|
||
|
||
// 处理接收到的所有激光信号
|
||
ProcessLaserTargets();
|
||
|
||
if (LaserIlluminationOn && !IsBlockingJammed)
|
||
{
|
||
// 更新制导状态
|
||
HasGuidance = quadrantDetector.IsTargetLocked;
|
||
|
||
if (HasGuidance)
|
||
{
|
||
CalculateGuidanceAcceleration(deltaTime);
|
||
}
|
||
else
|
||
{
|
||
GuidanceAcceleration = Vector3D.Zero;
|
||
PreviousGuidanceAcceleration = Vector3D.Zero; // 重置历史加速度
|
||
}
|
||
}
|
||
else
|
||
{
|
||
HasGuidance = false;
|
||
GuidanceAcceleration = Vector3D.Zero;
|
||
PreviousGuidanceAcceleration = Vector3D.Zero; // 重置历史加速度
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 处理接收到的所有激光目标
|
||
/// </summary>
|
||
/// <remarks>
|
||
/// 基于接收到的激光目标计算合成光斑位置
|
||
/// </remarks>
|
||
private void ProcessLaserTargets()
|
||
{
|
||
try
|
||
{
|
||
Debug.WriteLine($"处理激光信号: 激光目标数量={laserTargets.Count}");
|
||
|
||
// 如果没有激光源,返回
|
||
if (laserTargets.Count == 0)
|
||
{
|
||
LaserIlluminationOn = false;
|
||
return;
|
||
}
|
||
|
||
// 计算所有激光源的总接收功率和加权位置
|
||
ReceivedLaserPower = 0.0;
|
||
Vector3D weightedPosition = Vector3D.Zero;
|
||
|
||
foreach (var target in laserTargets)
|
||
{
|
||
// 计算角度偏差,判断是否在视野范围内
|
||
double angleDeviation = CalculateAngleDeviation(target.SpotPosition);
|
||
if (angleDeviation > config.FieldOfViewAngleInRadians / 2)
|
||
{
|
||
Debug.WriteLine($"处理激光信号: 目标超出视野范围,目标ID: {target.Target.Id}, 角度偏差: {angleDeviation:F2}弧度, 视野范围: {config.FieldOfViewAngleInRadians:F2}弧度");
|
||
continue; // 目标超出视野范围
|
||
}
|
||
|
||
double receivedPower = 0;
|
||
if (target.Target is LaserDecoy decoy)
|
||
{
|
||
// 计算接收功率
|
||
receivedPower = CalculateReceivedPower(target.Source.KState.Position, target.SpotPosition, decoy.config.Power, decoy.config.DivergenceAngle);
|
||
Debug.WriteLine($"处理激光信号: 诱偏目标接收功率={receivedPower:E}W, 诱偏目标ID: {target.Target.Id}, 诱偏目标位置: {target.SpotPosition}");
|
||
}
|
||
else if (target.Source is LaserDesignator laserDesignator)
|
||
{
|
||
// 计算接收功率
|
||
receivedPower = CalculateReceivedPower(target.Source.KState.Position, target.SpotPosition, laserDesignator.config.Power, laserDesignator.config.DivergenceAngle);
|
||
Debug.WriteLine($"处理激光信号: 真实目标接收功率={receivedPower:E}W, 真实目标ID: {target.Target.Id}, 真实目标位置: {target.SpotPosition}");
|
||
}
|
||
|
||
// 累加功率
|
||
ReceivedLaserPower += receivedPower;
|
||
|
||
// 加权位置
|
||
weightedPosition += target.SpotPosition * receivedPower;
|
||
Debug.WriteLine($"处理激光信号: 累加功率={ReceivedLaserPower:E}W, 加权位置={weightedPosition}");
|
||
}
|
||
|
||
// 如果总功率为0,表示没有在视野范围内的激光源
|
||
if (ReceivedLaserPower <= 0)
|
||
{
|
||
LaserIlluminationOn = false;
|
||
return;
|
||
}
|
||
|
||
// 计算加权平均位置
|
||
TargetPosition = weightedPosition / ReceivedLaserPower;
|
||
|
||
Debug.WriteLine($"处理激光信号: 总功率={ReceivedLaserPower:E}W, 加权平均目标位置={TargetPosition}");
|
||
|
||
// 更新激光照射参数
|
||
LaserIlluminationOn = true;
|
||
// 计算光斑偏移
|
||
Vector2D spotOffset = CalculateSpotOffset();
|
||
|
||
// 将合成激光信号传递给四象限探测器
|
||
quadrantDetector.ProcessLaserSignal(ReceivedLaserPower, spotOffset);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
Trace.TraceError($"处理激光信号时出错: {ex.Message}");
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 计算从特定位置接收到的激光功率
|
||
/// </summary>
|
||
/// <param name="sourcePos">激光源位置</param>
|
||
/// <param name="targetPos">目标位置</param>
|
||
/// <param name="laserPower">激光功率</param>
|
||
/// <param name="laserDivergenceAngle">激光发散角</param>
|
||
/// <returns>接收到的激光功率,单位:瓦特</returns>
|
||
private double CalculateReceivedPower(Vector3D sourcePos, Vector3D targetPos, double laserPower, double laserDivergenceAngle)
|
||
{
|
||
// --- 路径1: 指示器 (source) 到目标 (target) ---
|
||
double distanceSourceToTarget = (sourcePos - targetPos).Magnitude();
|
||
double smokeTransmittance_S2T = CalculateLiveSmokeTransmittanceForPath(sourcePos, targetPos);
|
||
double atmTransmittance_S2T = 1.0;
|
||
if (SimulationManager.CurrentWeather != null)
|
||
{
|
||
atmTransmittance_S2T = AtmosphereDllWrapper.CalculateTransmittance(
|
||
distanceSourceToTarget, RadiationType.Laser, config.Wavelength, SimulationManager.CurrentWeather);
|
||
}
|
||
double totalTransmittance_S2T = smokeTransmittance_S2T * atmTransmittance_S2T;
|
||
|
||
// 功率密度在目标表面
|
||
double spotAreaAtTarget = Math.PI * Math.Pow(distanceSourceToTarget * Math.Tan(laserDivergenceAngle), 2);
|
||
if (spotAreaAtTarget < 1e-9) spotAreaAtTarget = 1e-9; // 防止除零
|
||
double powerDensityOnTargetSurface = laserPower * config.TransmitterEfficiency * totalTransmittance_S2T / spotAreaAtTarget;
|
||
|
||
// 目标反射的总功率
|
||
double totalPowerReflectedByTarget = powerDensityOnTargetSurface * config.TargetReflectiveArea * config.ReflectionCoefficient;
|
||
|
||
// --- 路径2: 目标 (target) 到导弹 (missile) ---
|
||
double distanceTargetToMissile = (targetPos - KState.Position).Magnitude();
|
||
if (distanceTargetToMissile < 1e-9) distanceTargetToMissile = 1e-9; // 防止除零
|
||
double smokeTransmittance_T2M = CalculateLiveSmokeTransmittanceForPath(targetPos, KState.Position);
|
||
double atmTransmittance_T2M = 1.0;
|
||
if (SimulationManager.CurrentWeather != null)
|
||
{
|
||
atmTransmittance_T2M = AtmosphereDllWrapper.CalculateTransmittance(
|
||
distanceTargetToMissile, RadiationType.Laser, config.Wavelength, SimulationManager.CurrentWeather);
|
||
}
|
||
double totalTransmittance_T2M = smokeTransmittance_T2M * atmTransmittance_T2M;
|
||
|
||
// 导弹接收孔径处的功率密度 (来自目标反射,假设朗伯体)
|
||
// 反射功率在2*PI立体角内分布(朗伯反射体)
|
||
// 功率密度 = 总反射功率 / (2 * PI * R^2)
|
||
// 在此步骤应用路径2的透过率,因为它影响从目标到导弹的信号强度
|
||
double powerDensityAtMissileAperture = totalPowerReflectedByTarget * totalTransmittance_T2M / (2 * Math.PI * Math.Pow(distanceTargetToMissile, 2));
|
||
|
||
// 导弹最终接收到的功率
|
||
double lensArea = Math.PI * Math.Pow(config.LensDiameter / 2, 2);
|
||
double finalReceivedPower = powerDensityAtMissileAperture * lensArea * config.ReceiverEfficiency;
|
||
|
||
Debug.WriteLine($"激光功率计算: S2T D={distanceSourceToTarget:F1}m (Path1 T={totalTransmittance_S2T:F3}), " +
|
||
$"T2M D={distanceTargetToMissile:F1}m (Path2 T={totalTransmittance_T2M:F3}), " +
|
||
$"最终功率={finalReceivedPower:E}W");
|
||
|
||
return finalReceivedPower;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 计算目标的角度偏差
|
||
/// </summary>
|
||
/// <param name="targetPos">目标位置</param>
|
||
/// <returns>角度偏差,单位:弧度</returns>
|
||
/// <remarks>
|
||
/// 计算目标方向与导弹当前朝向的夹角
|
||
/// </remarks>
|
||
private double CalculateAngleDeviation(Vector3D targetPos)
|
||
{
|
||
// 计算目标方向
|
||
Vector3D targetDirection = (targetPos - KState.Position).Normalize();
|
||
|
||
// 计算当前导弹朝向
|
||
Vector3D missileDirection = KState.Velocity.Normalize();
|
||
|
||
// 计算夹角
|
||
double dotProduct = Vector3D.DotProduct(targetDirection, missileDirection);
|
||
dotProduct = Math.Max(-1.0, Math.Min(1.0, dotProduct)); // 确保在[-1,1]范围内
|
||
|
||
return Math.Acos(dotProduct);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 计算光斑偏移量
|
||
/// </summary>
|
||
/// <returns>光斑中心相对于探测器中心的偏移量,单位:米</returns>
|
||
/// <remarks>
|
||
/// 计算过程:
|
||
/// - 计算理想指向方向
|
||
/// - 计算当前指向方向
|
||
/// - 计算角度偏差
|
||
/// - 转换为光斑偏移量
|
||
/// </remarks>
|
||
private Vector2D CalculateSpotOffset()
|
||
{
|
||
// Check TargetPosition != null before using it
|
||
if (TargetPosition == null)
|
||
{
|
||
return Vector2D.Zero;
|
||
}
|
||
|
||
// No cast needed, just use TargetPosition directly
|
||
Vector3D idealDirection = (TargetPosition.Value - KState.Position).Normalize();
|
||
|
||
// 计算当前导弹前向方向
|
||
Vector3D currentDirection = KState.Velocity.Normalize();
|
||
|
||
// 计算右向量和上向量
|
||
Vector3D right = Vector3D.CrossProduct(Vector3D.UnitY, currentDirection).Normalize();
|
||
Vector3D up = Vector3D.CrossProduct(currentDirection, right).Normalize();
|
||
|
||
// 计算理想方向在当前坐标系中的投影
|
||
double forwardComponent = Vector3D.DotProduct(idealDirection, currentDirection);
|
||
double rightComponent = Vector3D.DotProduct(idealDirection, right);
|
||
double upComponent = Vector3D.DotProduct(idealDirection, up);
|
||
|
||
// 确保前向分量为正(目标在前方)
|
||
if (forwardComponent <= 0)
|
||
{
|
||
// 目标在后方,无法探测
|
||
return new Vector2D(0, 0);
|
||
}
|
||
|
||
// 计算角度偏差
|
||
double horizontalAngle = Math.Atan2(rightComponent, forwardComponent);
|
||
double verticalAngle = Math.Atan2(upComponent, forwardComponent);
|
||
|
||
// 转换为光斑偏移量(假设小角度近似)
|
||
double focalLength = config.SensorDiameter / (2 * Math.Tan(config.FieldOfViewAngleInRadians / 2));
|
||
double horizontalOffset = focalLength * Math.Tan(horizontalAngle);
|
||
double verticalOffset = focalLength * Math.Tan(verticalAngle);
|
||
|
||
return new Vector2D(horizontalOffset, verticalOffset);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 计算制导加速度
|
||
/// </summary>
|
||
/// <param name="deltaTime">时间步长,单位:秒</param>
|
||
/// <remarks>
|
||
/// 计算过程:
|
||
/// - 使用四象限探测器获取目标方向
|
||
/// - 计算比例导引加速度
|
||
/// - 限制最大加速度
|
||
/// - 应用加速度平滑处理
|
||
/// </remarks>
|
||
protected void CalculateGuidanceAcceleration(double deltaTime)
|
||
{
|
||
// 获取当前导弹指向方向
|
||
Vector3D currentDirection = KState.Velocity.Normalize();
|
||
|
||
// 使用四象限探测器获取修正后的目标方向
|
||
Vector3D targetDirection = quadrantDetector.GetTargetDirection(currentDirection, SpotOffsetSensitivity);
|
||
|
||
// 计算方向差异向量
|
||
Vector3D directionDifference = targetDirection - currentDirection;
|
||
|
||
// 确保差异向量与当前速度垂直(只保留横向分量)
|
||
Vector3D guidanceDirection = directionDifference - currentDirection * Vector3D.DotProduct(directionDifference, currentDirection);
|
||
|
||
// 如果差异太小,可以适当放大
|
||
if (guidanceDirection.Magnitude() < 0.01)
|
||
{
|
||
guidanceDirection = guidanceDirection.Normalize() * 0.01;
|
||
}
|
||
|
||
// 计算新的制导加速度,与速度垂直
|
||
Vector3D newGuidanceAcceleration = guidanceDirection * ProportionalNavigationCoefficient * KState.Velocity.Magnitude();
|
||
|
||
// 限制最大加速度
|
||
double maxAcceleration = MaxAcceleration;
|
||
if (newGuidanceAcceleration.Magnitude() > maxAcceleration)
|
||
{
|
||
newGuidanceAcceleration = newGuidanceAcceleration.Normalize() * maxAcceleration;
|
||
}
|
||
|
||
// 应用加速度平滑处理
|
||
GuidanceAcceleration = PreviousGuidanceAcceleration * (1 - AccelerationSmoothingFactor) +
|
||
newGuidanceAcceleration * AccelerationSmoothingFactor;
|
||
|
||
// 保存当前加速度用于下次平滑计算
|
||
PreviousGuidanceAcceleration = GuidanceAcceleration;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取制导系统的详细状态信息
|
||
/// </summary>
|
||
/// <returns>包含完整状态参数的ElementStatusInfo对象</returns>
|
||
/// <remarks>
|
||
/// 特有的返回信息:
|
||
/// - 接收功率数据
|
||
/// - 锁定阈值
|
||
/// - 四象限探测器状态
|
||
/// 用于系统监控和调试
|
||
/// </remarks>
|
||
public override ElementStatusInfo GetStatusInfo()
|
||
{
|
||
var statusInfo = base.GetStatusInfo();
|
||
|
||
statusInfo.ExtendedProperties["ReceivedLaserPower"] = ReceivedLaserPower.ToString("E") + " W";
|
||
statusInfo.ExtendedProperties["LockThreshold"] = config.LockThreshold.ToString("E") + " W";
|
||
statusInfo.ExtendedProperties["QuadrantDetectorStatus"] = quadrantDetector.GetStatus();
|
||
|
||
return statusInfo;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取四象限探测器的水平误差
|
||
/// </summary>
|
||
/// <returns>水平误差值,范围[-1, 1]</returns>
|
||
/// <remarks>
|
||
/// 正值表示右侧偏移,负值表示左侧偏移
|
||
/// </remarks>
|
||
public double GetHorizontalError()
|
||
{
|
||
return quadrantDetector.HorizontalError;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取四象限探测器的垂直误差
|
||
/// </summary>
|
||
/// <returns>垂直误差值,范围[-1, 1]</returns>
|
||
/// <remarks>
|
||
/// 正值表示上方偏移,负值表示下方偏移
|
||
/// </remarks>
|
||
public double GetVerticalError()
|
||
{
|
||
return quadrantDetector.VerticalError;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 设置光斑偏移灵敏度
|
||
/// </summary>
|
||
/// <param name="sensitivity">灵敏度值</param>
|
||
/// <remarks>
|
||
/// 灵敏度值越高,制导系统对光斑偏移的响应越强烈
|
||
/// 典型值范围:0.1-1.0
|
||
/// </remarks>
|
||
public void SetSpotOffsetSensitivity(double sensitivity)
|
||
{
|
||
SpotOffsetSensitivity = sensitivity;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取四象限探测器的锁定状态
|
||
/// </summary>
|
||
/// <returns>如果四象限探测器锁定目标则返回true,否则返回false</returns>
|
||
/// <remarks>
|
||
/// 用于外部系统监控四象限探测器的工作状态
|
||
/// </remarks>
|
||
public bool IsQuadrantDetectorLocked()
|
||
{
|
||
return quadrantDetector.IsTargetLocked;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 设置期望的激光编码
|
||
/// </summary>
|
||
/// <param name="codeType">编码类型</param>
|
||
/// <param name="codeValue">编码值</param>
|
||
/// <remarks>
|
||
/// 设置过程:
|
||
/// - 检查编码类型是否支持
|
||
/// - 创建新的编码对象
|
||
/// - 设置编码类型和值
|
||
/// </remarks>
|
||
public void SetExpectedLaserCode(LaserCodeType codeType, int codeValue)
|
||
{
|
||
if (supportedCodeTypes.Contains(codeType))
|
||
{
|
||
InternalLaserCodeConfig = new LaserCodeConfig
|
||
{
|
||
Code = new LaserCode { CodeType = codeType, CodeValue = codeValue }
|
||
};
|
||
Debug.WriteLine($"激光半主动制导系统设置期望编码:类型={codeType},值={codeValue}");
|
||
}
|
||
else
|
||
{
|
||
Debug.WriteLine($"激光半主动制导系统不支持编码类型:{codeType}");
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 添加期望编码参数
|
||
/// </summary>
|
||
/// <param name="key">参数名称</param>
|
||
/// <param name="value">参数值</param>
|
||
/// <remarks>
|
||
/// 添加特定编码类型的额外参数
|
||
/// 如PPM编码的脉冲位置模式、PWM编码的脉冲宽度等
|
||
/// </remarks>
|
||
public void AddExpectedCodeParameter(string key, object value)
|
||
{
|
||
if (InternalLaserCodeConfig != null)
|
||
{
|
||
InternalLaserCodeConfig.Code.Parameters[key] = value;
|
||
Debug.WriteLine($"激光半主动制导系统添加期望编码参数:{key}={value}");
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 检查激光编码是否匹配
|
||
/// </summary>
|
||
/// <param name="receivedConfig">接收到的激光编码配置</param>
|
||
/// <returns>如果匹配返回true,否则返回false</returns>
|
||
private bool CheckLaserCode(LaserCodeConfig? receivedConfig)
|
||
{
|
||
// 如果内部配置为空,或接收到的配置为空,或内部配置不需要检查,则视为匹配(或忽略)
|
||
if (InternalLaserCodeConfig == null || receivedConfig == null || !InternalLaserCodeConfig.IsCodeMatchRequired)
|
||
{
|
||
return true;
|
||
}
|
||
// 调用内部配置的匹配逻辑
|
||
return InternalLaserCodeConfig.CheckCodeMatch(receivedConfig);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 发布编码不匹配事件
|
||
/// </summary>
|
||
/// <param name="designatorId">激光定位器ID</param>
|
||
/// <param name="receivedCodeConfig">接收到的编码配置</param>
|
||
/// <remarks>
|
||
/// 发布过程:
|
||
/// - 创建事件对象
|
||
/// - 设置事件属性
|
||
/// - 发布到事件系统
|
||
/// </remarks>
|
||
private void PublishCodeMismatchEvent(string? designatorId, LaserCodeConfig? receivedCodeConfig)
|
||
{
|
||
var mismatchEvent = new LaserCodeMismatchEvent
|
||
{
|
||
MissileId = MissileId,
|
||
DesignatorId = designatorId,
|
||
ExpectedCodeConfig = InternalLaserCodeConfig,
|
||
ReceivedCodeConfig = receivedCodeConfig
|
||
};
|
||
|
||
PublishEvent(mismatchEvent); // 使用基类的 PublishEvent
|
||
}
|
||
|
||
/// <summary>
|
||
/// 计算给定路径上的总烟幕透过率
|
||
/// </summary>
|
||
/// <param name="pathStart">路径起点</param>
|
||
/// <param name="pathEnd">路径终点</param>
|
||
/// <returns>总透过率 (0.0 到 1.0)</returns>
|
||
private double CalculateLiveSmokeTransmittanceForPath(Vector3D pathStart, Vector3D pathEnd)
|
||
{
|
||
double totalTransmittance = 1.0;
|
||
var activeSmokeGrenades = SimulationManager.GetEntitiesByType<SmokeGrenade>()
|
||
.Where(sg => sg.IsActive && sg.config != null && sg.IsJamming) // 确保烟幕弹已激活并正在干扰
|
||
.ToList();
|
||
|
||
if (!activeSmokeGrenades.Any())
|
||
{
|
||
return 1.0; // 没有活动的、正在干扰的烟幕,无衰减
|
||
}
|
||
|
||
foreach (var smokeGrenade in activeSmokeGrenades)
|
||
{
|
||
// 调用 SmokeGrenade 实例的方法来计算其对视线的透过率
|
||
double transmittanceForThisSmoke = smokeGrenade.GetSmokeTransmittanceOnLine(pathStart, pathEnd, config.Wavelength);
|
||
totalTransmittance *= transmittanceForThisSmoke; // 叠加衰减效应(透过率相乘)
|
||
|
||
// 如果透过率已经很低,可以提前退出以优化
|
||
if (totalTransmittance < 0.005)
|
||
{
|
||
return 0.0;
|
||
}
|
||
}
|
||
return Math.Max(0.0, totalTransmittance); //确保不为负
|
||
}
|
||
}
|
||
}
|