ThreatSourceLibaray/ThreatSource/src/Guidance/LaserBeamRiderGuidanceSystem.cs

714 lines
26 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 System.Diagnostics;
using ThreatSource.Jamming;
using AirTransmission;
namespace ThreatSource.Guidance
{
/// <summary>
/// 激光驾束制导系统类,实现了基于激光束跟踪的制导功能
/// </summary>
/// <remarks>
/// 该类提供了激光驾束制导系统的核心功能:
/// - 激光束生成和控制
/// - 偏差检测和计算
/// - PID控制器
/// - 非线性增益控制
/// 用于实现高精度的制导控制
/// </remarks>
public class LaserBeamRiderGuidanceSystem : BasicGuidanceSystem
{
/// <summary>
/// 获取或设置激光源位置
/// </summary>
/// <remarks>
/// 记录激光发射源的三维位置
/// 用于计算导弹与激光束的相对位置
/// </remarks>
private Vector3D LaserSourcePosition { get; set; }
/// <summary>
/// 获取或设置激光方向
/// </summary>
/// <remarks>
/// 记录激光束的传播方向
/// 用于计算导弹与激光束的偏差
/// </remarks>
private Vector3D LaserDirection { get; set; }
/// <summary>
/// 获取或设置激光指示器激光功率,单位:瓦特
/// </summary>
/// <remarks>
/// 记录激光指示器的发射功率
/// 影响系统的探测距离和可靠性
/// </remarks>
public double LaserPower { get; set; }
/// <summary>
/// 最小可探测功率,单位:瓦特
/// </summary>
/// <remarks>
/// 定义了探测器的灵敏度阈值
/// 低于此值时无法有效探测
/// 典型值为1e-10瓦
/// </remarks>
private const double MinDetectablePower = 1e-10;
/// <summary>
/// 探测器直径,单位:米
/// </summary>
/// <remarks>
/// 定义了探测器的物理尺寸
/// 影响系统的接收能力
/// 典型值为0.03米
/// </remarks>
private const double DetectorDiameter = 0.03;
/// <summary>
/// 控制场直径,单位:米
/// </summary>
/// <remarks>
/// 定义了有效制导范围
/// 超出此范围将失去制导
/// 典型值为6米
/// </remarks>
private const double ControlFieldDiameter = 6.0;
/// <summary>
/// 上一次的误差向量
/// </summary>
/// <remarks>
/// 记录PID控制器的历史误差
/// 用于计算微分项
/// </remarks>
private Vector3D LastError = Vector3D.Zero;
/// <summary>
/// 获取上一次的制导加速度
/// </summary>
/// <remarks>
/// 记录历史制导指令
/// 用于实现低通滤波
/// </remarks>
public Vector3D LastGuidanceAcceleration { get; private set; }
/// <summary>
/// 偏航角偏差
/// </summary>
public double YawAngleOffset { get; private set; }
/// <summary>
/// 俯仰角偏差
/// </summary>
public double PitchAngleOffset { get; private set; }
/// <summary>
/// 积分误差向量
/// </summary>
/// <remarks>
/// 记录PID控制器的积分项
/// 用于消除稳态误差
/// </remarks>
private Vector3D IntegralError = Vector3D.Zero;
/// <summary>
/// 获取或设置激光照射状态
/// </summary>
/// <remarks>
/// 指示当前是否有激光照射
/// 影响系统的工作状态
/// </remarks>
private bool LaserIlluminationOn { get; set; }
/// <summary>
/// 获取或设置期望的激光编码配置
/// </summary>
/// <remarks>
/// 导弹期望接收的编码信息
/// 用于验证接收到的激光信号
/// </remarks>
private LaserCodeConfig? InternalLaserCodeConfig { get; set; }
/// <summary>
/// 获取或设置支持的编码类型列表
/// </summary>
/// <remarks>
/// 定义导弹支持的编码类型
/// 默认支持PRF、PPM和PWM编码
/// </remarks>
private List<LaserCodeType> supportedCodeTypes = new List<LaserCodeType>
{
LaserCodeType.PRF,
LaserCodeType.PPM,
LaserCodeType.PWM
};
/// <summary>
/// 系统配置参数
/// </summary>
private readonly LaserBeamRiderGuidanceSystemConfig config;
/// <summary>
/// 初始化激光驾束制导系统的新实例
/// </summary>
/// <param name="id">制导系统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 LaserBeamRiderGuidanceSystem(
string id,
double maxAcceleration,
double guidanceCoefficient,
LaserCodeConfig? laserCodeConfig,
LaserBeamRiderGuidanceSystemConfig guidanceConfig,
ISimulationManager simulationManager)
: base(id, maxAcceleration, guidanceCoefficient, simulationManager)
{
config = guidanceConfig;
LaserSourcePosition = Vector3D.Zero;
LaserDirection = Vector3D.Zero;
LaserPower = 0;
LaserIlluminationOn = false;
LastError = Vector3D.Zero;
IntegralError = Vector3D.Zero;
LastGuidanceAcceleration = Vector3D.Zero;
// 如果没有提供编码配置,创建默认配置
InternalLaserCodeConfig = laserCodeConfig ?? new LaserCodeConfig
{
Code = new LaserCode
{
CodeType = LaserCodeType.PPM,
CodeValue = 1234
},
IsCodeEnabled = true,
IsCodeMatchRequired = true
};
InitializeJamming(guidanceConfig.JammingResistanceThreshold, [JammingType.Laser]);
}
/// <summary>
/// 激活制导系统
/// </summary>
public override void Activate()
{
base.Activate();
// 在这里订阅事件,确保只订阅一次
SimulationManager.SubscribeToEvent<LaserJammingEvent>(OnLaserJamming);
SimulationManager.SubscribeToEvent<LaserBeamStartEvent>(OnLaserBeamStart);
SimulationManager.SubscribeToEvent<LaserBeamStopEvent>(OnLaserBeamStop);
}
/// <summary>
/// 停用制导系统
/// </summary>
public override void Deactivate()
{
base.Deactivate();
// 取消订阅事件
SimulationManager.UnsubscribeFromEvent<LaserJammingEvent>(OnLaserJamming);
SimulationManager.UnsubscribeFromEvent<LaserBeamStartEvent>(OnLaserBeamStart);
SimulationManager.UnsubscribeFromEvent<LaserBeamStopEvent>(OnLaserBeamStop);
}
/// <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="required">是否要求匹配</param>
/// <remarks>
/// 设置导弹是否严格要求激光编码匹配
/// true表示必须匹配false表示不要求匹配
/// </remarks>
public void SetCodeMatchRequired(bool required)
{
if (InternalLaserCodeConfig != null)
{
InternalLaserCodeConfig.IsCodeMatchRequired = required;
Debug.WriteLine($"激光驾束制导系统设置编码匹配要求:{required}");
}
}
/// <summary>
/// 检查激光编码是否匹配
/// </summary>
/// <param name="receivedConfig">接收到的激光编码配置</param>
/// <returns>如果匹配返回true否则返回false</returns>
/// <remarks>
/// 检查过程:
/// - 验证编码类型
/// - 验证编码值
/// - 验证额外参数
/// </remarks>
private bool CheckLaserCode(LaserCodeConfig? receivedConfig)
{
return InternalLaserCodeConfig?.CheckCodeMatch(receivedConfig) ?? false;
}
/// <summary>
/// 发布编码匹配事件
/// </summary>
/// <param name="designatorId">激光定位器ID</param>
/// <param name="matchedCodeConfig">匹配的编码配置</param>
private void PublishCodeMatchEvent(string? designatorId, LaserCodeConfig? matchedCodeConfig)
{
var matchEvent = new LaserCodeMatchEvent
{
MissileId = ParentId,
DesignatorId = designatorId,
MatchedCodeConfig = matchedCodeConfig
};
PublishEvent(matchEvent);
}
/// <summary>
/// 发布编码不匹配事件
/// </summary>
/// <param name="designatorId">激光定位器ID</param>
/// <param name="receivedCodeConfig">接收到的编码配置</param>
private void PublishCodeMismatchEvent(string? designatorId, LaserCodeConfig? receivedCodeConfig)
{
var mismatchEvent = new LaserCodeMismatchEvent
{
MissileId = ParentId,
DesignatorId = designatorId,
ExpectedCodeConfig = InternalLaserCodeConfig,
ReceivedCodeConfig = receivedCodeConfig
};
PublishEvent(mismatchEvent);
}
/// <summary>
/// 更新激光驾束仪参数
/// </summary>
/// <param name="sourcePosition">激光源位置,单位:米</param>
/// <param name="direction">激光方向向量</param>
/// <param name="laserPower">激光功率,单位:瓦特</param>
/// <remarks>
/// 更新过程:
/// - 激活激光照射
/// - 更新位置信息
/// - 更新方向信息
/// - 更新功率参数
/// </remarks>
public void UpdateLaserBeamRider(Vector3D sourcePosition, Vector3D direction, double laserPower)
{
LaserIlluminationOn = true;
LaserSourcePosition = sourcePosition;
LaserDirection = direction.Normalize();
LaserPower = laserPower;
}
/// <summary>
/// 关闭激光照射系统
/// </summary>
/// <remarks>
/// 关闭过程:
/// - 清除位置信息
/// - 清除方向信息
/// - 清除功率参数
/// - 停止制导
/// </remarks>
public void DeactivateLaserBeam()
{
LaserSourcePosition = Vector3D.Zero;
LaserDirection = Vector3D.Zero;
LaserPower = 0;
HasGuidance = false;
}
/// <summary>
/// 更新制导系统的状态和计算结果
/// </summary>
/// <param name="deltaTime">时间步长,单位:秒</param>
/// <param name="missilePosition">导弹位置,单位:米</param>
/// <param name="missileVelocity">导弹速度,单位:米/秒</param>
/// <remarks>
/// 更新过程:
/// - 检查激光照射状态
/// - 更新制导状态
/// - 计算制导指令
/// - 更新输出参数
/// </remarks>
public override void Update(double deltaTime, Vector3D missilePosition, Vector3D missileVelocity)
{
base.Update(deltaTime, missilePosition, missileVelocity);
if (!IsJammed)
{
if (LaserIlluminationOn)
{
UpdateGuidanceStatus();
if (HasGuidance)
{
CalculateGuidanceAcceleration(deltaTime);
}
else
{
GuidanceAcceleration = Vector3D.Zero;
}
}
else
{
HasGuidance = false;
GuidanceAcceleration = Vector3D.Zero;
}
}
else
{
HasGuidance = false;
GuidanceAcceleration = Vector3D.Zero;
}
}
/// <summary>
/// 更新制导系统状态
/// </summary>
/// <remarks>
/// 更新过程:
/// - 计算与激光束的距离
/// - 检查是否在控制场内
/// - 计算接收功率
/// - 判断是否满足制导条件
/// </remarks>
private void UpdateGuidanceStatus()
{
// 计算导弹到激光束的最短距离
Vector3D shortestDistanceVector = CalculateShortestDistanceToLaserBeam();
double shortestDistance = shortestDistanceVector.Magnitude();
// 检查导弹是否在控制场内
if (shortestDistance > config.ControlFieldDiameter / 2)
{
HasGuidance = false;
Trace.WriteLine($"激光驾束引导系统: 失去引导, 原因: 超出控制场范围, 距离: {shortestDistance}");
return;
}
Debug.WriteLine($"激光驾束引导系统: 在控制场内, 距离: {shortestDistance}");
// 计算导弹到激光源的距离
Vector3D missileToSource = LaserSourcePosition - Position;
double distance = missileToSource.Magnitude();
// 计算接收到的激光功率
double receivedPower = CalculateReceivedLaserPower(distance);
Debug.WriteLine($"激光驾束引导系统: 接收到的激光功率: {receivedPower:E} W");
if(receivedPower >= config.MinDetectablePower)
{
HasGuidance = true;
}
else
{
HasGuidance = false;
Trace.WriteLine($"激光驾束引导系统: 失去引导, 原因: 接收到的激光功率低于最小可探测功率,{LaserPower:E} W/{receivedPower:E} W");
}
}
/// <summary>
/// 计算接收到的激光功率
/// </summary>
/// <param name="distance">传播距离,单位:米</param>
/// <returns>接收到的激光功率,单位:瓦特</returns>
/// <remarks>
/// 计算过程:
/// - 使用距离球面公式计算功率密度
/// - 考虑探测器的有效接收面积
/// - 可选:考虑大气衰减
/// </remarks>
private double CalculateReceivedLaserPower(double distance)
{
// 使用距离球面公式计算功率密度
double powerDensity = LaserPower / (4 * Math.PI * Math.Pow(distance, 2));
// 计算探测器的有效接收面积
double detectorArea = Math.PI * Math.Pow(config.DetectorDiameter / 2, 2);
// 计算接收功率
double receivedPower = powerDensity * detectorArea;
// 考虑大气衰减(可选)
// 计算大气透过率如果当前天气为null则认为大气透过率为1.0
double atmosphericTransmittance = 1.0;
if(SimulationManager.CurrentWeather != null)
{
atmosphericTransmittance = AtmosphereDllWrapper.CalculateTransmittance(
distance,
RadiationType.Laser,
config.LaserWavelength,
SimulationManager.CurrentWeather);
}
receivedPower *= atmosphericTransmittance;
return receivedPower;
}
/// <summary>
/// 计算制导加速度
/// </summary>
/// <param name="deltaTime">时间步长,单位:秒</param>
/// <remarks>
/// 计算过程:
/// - 计算偏差向量
/// - 执行PID控制
/// - 应用非线性增益
/// - 计算横向加速度
/// - 计算前向加速度
/// - 合成最终制导指令
/// - 应用低通滤波
/// </remarks>
protected void CalculateGuidanceAcceleration(double deltaTime)
{
// 计算导弹到激光束的最短距离
Vector3D shortestDistanceVector = CalculateShortestDistanceToLaserBeam();
// PID控制
Vector3D error = shortestDistanceVector;
// 积分项
IntegralError += error * deltaTime;
// 微分项
Vector3D derivativeError = (error - LastError) / deltaTime;
// 计算PID输出
Vector3D pidOutput = error * config.ProportionalGain +
IntegralError * config.IntegralGain +
derivativeError * config.DerivativeGain;
// 非线性增益
double distance = shortestDistanceVector.Magnitude();
double nonLinearGain = Math.Tanh(distance / config.NonlinearGain);
// 计算横向加速度
Vector3D lateralAcceleration = pidOutput * nonLinearGain;
// 限制最大加速度
if (lateralAcceleration.Magnitude() > config.MaxGuidanceAcceleration)
{
lateralAcceleration = lateralAcceleration.Normalize() * config.MaxGuidanceAcceleration;
}
// 计算前向加速度
Vector3D forwardDirection = LaserDirection;
Vector3D currentDirection = Velocity.Normalize();
Vector3D rotationAxis = Vector3D.CrossProduct(currentDirection, forwardDirection);
double rotationAngle = Math.Acos(Vector3D.DotProduct(currentDirection, forwardDirection));
Vector3D forwardAcceleration = Vector3D.CrossProduct(rotationAxis, Velocity) * rotationAngle * ProportionalNavigationCoefficient;
// 合并横向和前向加速度
GuidanceAcceleration = lateralAcceleration + forwardAcceleration;
// 低通滤波
GuidanceAcceleration = GuidanceAcceleration * config.LowPassFilterCoefficient +
LastGuidanceAcceleration * (1 - config.LowPassFilterCoefficient);
// 更新上一次的误差和制导加速度
LastError = error;
LastGuidanceAcceleration = GuidanceAcceleration;
}
/// <summary>
/// 处理激光干扰事件
/// </summary>
/// <param name="evt">激光干扰事件</param>
private void OnLaserJamming(LaserJammingEvent evt)
{
// 创建干扰参数
var parameters = new JammingParameters
{
Type = JammingType.Laser,
Power = evt.JammingPower,
Direction = evt.JammingDirection,
SourcePosition = evt.JammingSourcePosition,
AngleRange = evt.JammingAngleRange,
Mode = evt.JammingMode,
Duration = evt.Duration
};
// 使用JammableComponent进行干扰判断
ApplyJamming(parameters);
Debug.WriteLine($"激光驾束制导系统干扰状态 - IsJammed: {IsJammed}, 干扰功率: {evt.JammingPower}W, 抗性阈值: {config.JammingResistanceThreshold}W");
}
/// <summary>
/// 处理系统被干扰的事件
/// </summary>
/// <param name="parameters">干扰参数</param>
protected override void HandleJammingApplied(JammingParameters parameters)
{
if (parameters.Type == JammingType.Laser)
{
Debug.WriteLine($"激光驾束制导系统受到激光干扰,功率:{parameters.Power}瓦特");
// 确保基类的处理逻辑被调用设置HasGuidance = false
base.HandleJammingApplied(parameters);
// 在强干扰下切换到搜索模式
if (LaserIlluminationOn)
{
LaserIlluminationOn = false;
HasGuidance = false;
}
}
}
/// <summary>
/// 处理系统干扰被清除的事件
/// </summary>
/// <param name="type">被清除的干扰类型</param>
protected override void HandleJammingCleared(JammingType type)
{
if (type == JammingType.Laser)
{
Debug.WriteLine("激光驾束制导系统干扰已清除");
// 确保基类的处理逻辑被调用
base.HandleJammingCleared(type);
}
}
/// <summary>
/// 获取制导系统的详细状态信息
/// </summary>
/// <returns>包含完整状态参数的字符串</returns>
/// <remarks>
/// 返回信息:
/// - 基本状态信息
/// - 制导参数
/// - 控制状态
/// 用于系统监控和调试
/// </remarks>
public override string GetStatus()
{
return base.GetStatus() + $"激光指示器功率: {LaserPower:E} W," + $" 激光照射状态: {LaserIlluminationOn}";
}
/// <summary>
/// 计算导弹到激光束的最短距离向量
/// </summary>
/// <returns>最短距离向量,单位:米</returns>
/// <remarks>
/// 计算过程:
/// - 计算导弹到激光源的向量
/// - 计算在激光方向上的投影
/// - 计算最近点位置
/// - 计算最短距离向量
/// </remarks>
private Vector3D CalculateShortestDistanceToLaserBeam()
{
// 计算导弹到激光源的向量
Vector3D missileToSource = LaserSourcePosition - Position;
// 计算导弹在激光方向上的投影长度
double projectionLength = Vector3D.DotProduct(missileToSource, LaserDirection);
// 计算激光束上最接近导弹的点
Vector3D closestPointOnBeam = LaserSourcePosition - LaserDirection * projectionLength;
// 计算导弹到激光束最近点的向量(即最短距离向量)
Vector3D shortestDistanceVector = closestPointOnBeam - Position;
return shortestDistanceVector;
}
/// <summary>
/// 处理激光波束开始事件
/// </summary>
/// <param name="evt">激光波束开始事件</param>
private void OnLaserBeamStart(LaserBeamStartEvent evt)
{
if (evt?.LaserBeamRiderId != null)
{
// 检查编码是否匹配
bool codeMatched = CheckLaserCode(evt.LaserCodeConfig);
if (!codeMatched)
{
// 发布编码不匹配事件
PublishCodeMismatchEvent(evt.LaserBeamRiderId, evt.LaserCodeConfig);
Debug.WriteLine("激光驾束制导系统接收到不匹配的激光编码,忽略信号");
HasGuidance = false;
LaserIlluminationOn = false;
return;
}
// 如果编码匹配,发布匹配事件
PublishCodeMatchEvent(evt.LaserBeamRiderId, evt.LaserCodeConfig);
// 更新激光波束参数
LaserPower = evt.BeamPower;
LaserIlluminationOn = true;
HasGuidance = true;
}
}
/// <summary>
/// 处理激光波束停止事件
/// </summary>
/// <param name="evt">激光波束停止事件</param>
private void OnLaserBeamStop(LaserBeamStopEvent evt)
{
LaserIlluminationOn = false;
HasGuidance = false;
}
}
}