ThreatSourceLibaray/ThreatSource/src/Guidance/LaserSemiActiveGuidanceSystem.cs

861 lines
36 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 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); //确保不为负
}
}
}