ThreatSourceLibaray/ThreatSource/src/Guidance/InfraredImagingGuidanceSystem.cs

586 lines
25 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.Simulation;
using ThreatSource.Equipment;
using ThreatSource.Utils;
using ThreatSource.Jammer;
using System.Diagnostics;
namespace ThreatSource.Guidance
{
/// <summary>
/// 红外成像引导系统类,实现了基于红外图像的目标探测和跟踪功能
/// </summary>
/// <remarks>
/// 该类提供了红外成像制导系统的核心功能:
/// - 目标自动探测
/// - 图像识别处理
/// - 信噪比计算
/// - 比例导引控制
/// 用于实现自主寻的制导
/// </remarks>
public class InfraredImagingGuidanceSystem : BaseGuidanceSystem
{
/// <summary>
/// 工作模式枚举
/// </summary>
/// <remarks>
/// 定义了制导系统的三种工作模式:
/// - Search: 搜索模式,大视场角搜索目标
/// - Track: 跟踪模式,小视场角精确跟踪,同时进行目标识别
/// - Lock: 锁定模式,已确认目标类型,只进行跟踪
/// </remarks>
private enum WorkMode
{
Search, // 搜索模式
Track, // 跟踪模式
Lock // 锁定模式
}
/// <summary>
/// 当前工作模式
/// </summary>
private WorkMode currentMode = WorkMode.Search;
/// <summary>
/// 获取设备支持的阻塞干扰类型
/// </summary>
public override IEnumerable<JammingType> SupportedBlockingJammingTypes => [JammingType.Infrared];
/// <summary>
/// 获取设备支持的干扰类型
/// </summary>
public override IEnumerable<JammingType> SupportedJammingTypes => [JammingType.Infrared, JammingType.SmokeGrenade];
/// <summary>
/// 是否已探测到目标
/// </summary>
public bool HasTarget { get; private set; }
/// <summary>
/// 当前是否处于锁定模式
/// </summary>
public bool IsInLockMode => currentMode == WorkMode.Lock;
/// <summary>
/// 上一次探测到的目标位置 (使用可空类型)
/// </summary>
/// <remarks>
/// 记录目标的历史位置
/// 用于计算目标速度
/// </remarks>
private Vector3D? LastTargetPosition { get; set; } // Changed to nullable Vector3D?
/// <summary>
/// 红外图像生成器
/// </summary>
private InfraredImageGenerator imageGenerator;
/// <summary>
/// 目标识别器
/// </summary>
private readonly InfraredTargetRecognizer targetRecognizer;
/// <summary>
/// 要攻击的目标类型
/// </summary>
private readonly EquipmentType targetType;
/// <summary>
/// 红外成像制导系统配置
/// </summary>
private readonly InfraredImagingGuidanceConfig config;
/// <summary>
/// 目标丢失计时器
/// </summary>
private double targetLostTimer = 0;
/// <summary>
/// 锁定确认计时器
/// </summary>
private double lockConfirmationTimer = 0;
/// <summary>
/// 初始化红外成像制导系统的新实例
/// </summary>
/// <param name="id">系统标识</param>
/// <param name="missileId">导弹ID</param>
/// <param name="guidanceConfig">红外成像制导系统配置</param>
/// <param name="targetType">要攻击的目标类型</param>
/// <param name="maxAcceleration">最大加速度,单位:米/平方秒</param>
/// <param name="proportionalNavigationCoefficient">比例导引系数</param>
/// <param name="simulationManager">仿真管理器实例</param>
/// <remarks>
/// 构造过程:
/// - 初始化基类参数
/// - 设置仿真管理器
/// - 初始化目标位置
/// - 初始化红外图像生成器和目标识别器
/// </remarks>
public InfraredImagingGuidanceSystem(
string id,
string missileId,
InfraredImagingGuidanceConfig guidanceConfig,
EquipmentType targetType,
double maxAcceleration,
double proportionalNavigationCoefficient,
ISimulationManager simulationManager
)
: base(id, missileId, maxAcceleration, proportionalNavigationCoefficient, simulationManager)
{
this.targetType = targetType;
config = guidanceConfig;
targetRecognizer = new InfraredTargetRecognizer();
// 首先创建图像生成器
imageGenerator = new InfraredImageGenerator(
imageWidth: guidanceConfig.ImageWidth,
imageHeight: guidanceConfig.ImageHeight,
fieldOfView: guidanceConfig.SearchFieldOfView,
backgroundIntensity: guidanceConfig.BackgroundIntensity,
wavelength: guidanceConfig.Wavelength
);
InitializeJamming(guidanceConfig.JammingResistanceThreshold, SupportedJammingTypes, SupportedBlockingJammingTypes);
SwitchToSearchMode(); // 初始化为搜索模式
}
/// <summary>
/// 处理系统被干扰的事件
/// </summary>
/// <param name="parameters">干扰参数</param>
protected override void HandleJammingApplied(JammingParameters parameters)
{
base.HandleJammingApplied(parameters);
if (parameters.Type == JammingType.Infrared)
{
Debug.WriteLine($"红外引导系统受到红外干扰,功率:{parameters.Power}瓦特");
if (currentMode != WorkMode.Search)
{
SwitchToSearchMode();
}
}
else if (parameters.Type == JammingType.SmokeGrenade)
{
Debug.WriteLine($"[IR IMAGING] 烟幕干扰事件 {parameters.JammerId} 应用。", "Jamming");
}
}
/// <summary>
/// 处理系统干扰被清除的事件
/// </summary>
/// <param name="parameters">干扰参数</param>
protected override void HandleJammingCleared(JammingParameters parameters)
{
base.HandleJammingCleared(parameters);
if (parameters.Type == JammingType.Infrared)
{
Debug.WriteLine("红外引导系统干扰已清除");
// 干扰清除后的恢复逻辑
}
else if (parameters.Type == JammingType.SmokeGrenade)
{
Debug.WriteLine($"[IR IMAGING] 烟幕干扰事件 {parameters.JammerId} 清除。", "Jamming");
}
}
/// <summary>
/// 激活引导系统
/// </summary>
public override void Activate()
{
base.Activate();
}
/// <summary>
/// 停用引导系统
/// </summary>
public override void Deactivate()
{
base.Deactivate();
LastTargetPosition = null; // Add reset to null
HasTarget = false;
HasGuidance = false;
GuidanceAcceleration = Vector3D.Zero;
}
/// <summary>
/// 更新引导系统的状态和计算结果
/// </summary>
/// <param name="deltaTime">自上次更新以来的时间间隔,单位:秒</param>
/// <remarks>
/// 更新过程:
/// - 探测目标位置
/// - 计算目标速度
/// - 生成制导指令
/// - 限制最大加速度
/// </remarks>
public override void Update(double deltaTime)
{
base.Update(deltaTime);
if (!IsBlockingJammed)
{
if (TryDetectAndIdentifyTarget(KState.Position, KState.Velocity, deltaTime, out Vector3D currentTargetPosition))
{
targetLostTimer = 0; // 重置丢失计时器
Vector3D? currentTargetVelocity = null; // Initialize as nullable
if(LastTargetPosition != null && deltaTime > 0)
{
currentTargetVelocity = (currentTargetPosition - LastTargetPosition) / deltaTime;
}
LastTargetPosition = currentTargetPosition;
GuidanceAcceleration = MotionAlgorithm.CalculateProportionalNavigation(
ProportionalNavigationCoefficient,
KState.Position,
KState.Velocity,
currentTargetPosition, // Non-nullable from out parameter
currentTargetVelocity ?? Vector3D.Zero // Provide default if null
);
// 限制最大加速度
if (GuidanceAcceleration.Magnitude() > MaxAcceleration)
{
GuidanceAcceleration = GuidanceAcceleration.Normalize() * MaxAcceleration;
}
HasGuidance = true;
}
else
{
// 在跟踪或锁定模式下,增加丢失计时器
if (currentMode != WorkMode.Search)
{
targetLostTimer += deltaTime;
// 只有当超过容忍时间才认为真正丢失目标
if (targetLostTimer >= config.TargetLostTolerance)
{
HasGuidance = false;
// 切换回搜索模式
Debug.WriteLine($"目标丢失 {targetLostTimer:F3}s, 切换回搜索模式");
SwitchToSearchMode();
}
}
else
{
HasGuidance = false;
}
}
}
else
{
GuidanceAcceleration = Vector3D.Zero;
HasGuidance = false;
}
}
/// <summary>
/// 切换到搜索模式
/// </summary>
/// <remarks>
/// 切换过程:
/// - 设置大视场角
/// - 重置目标状态
/// - 更新图像生成器参数
/// </remarks>
public void SwitchToSearchMode()
{
currentMode = WorkMode.Search;
HasTarget = false;
targetLostTimer = 0; // 重置丢失计时器
LastTargetPosition = null; // Add reset to null
// 创建图像生成器
imageGenerator = new InfraredImageGenerator(
imageWidth: config.ImageWidth,
imageHeight: config.ImageHeight,
fieldOfView: config.SearchFieldOfView,
backgroundIntensity: config.BackgroundIntensity,
wavelength: config.Wavelength
);
Debug.WriteLine($"切换到搜索模式, 视场角: {config.SearchFieldOfView * 180 / Math.PI} 度");
}
/// <summary>
/// 切换到跟踪模式
/// </summary>
/// <remarks>
/// 切换过程:
/// - 设置小视场角
/// - 更新图像生成器参数
/// - 提高目标识别概率要求
/// </remarks>
public void SwitchToTrackMode()
{
currentMode = WorkMode.Track;
lockConfirmationTimer = 0; // 重置锁定确认计时器
// 创建图像生成器
imageGenerator = new InfraredImageGenerator(
imageWidth: config.ImageWidth,
imageHeight: config.ImageHeight,
fieldOfView: config.TrackFieldOfView,
backgroundIntensity: config.BackgroundIntensity,
wavelength: config.Wavelength
);
Debug.WriteLine($"切换到跟踪模式, 视场角: {config.TrackFieldOfView * 180 / Math.PI} 度");
}
/// <summary>
/// 切换到锁定模式
/// </summary>
/// <remarks>
/// 切换过程:
/// - 设置锁定状态
/// - 保持当前图像生成器参数
/// - 不再进行目标类型识别
/// </remarks>
public void SwitchToLockMode()
{
currentMode = WorkMode.Lock;
Debug.WriteLine("切换到锁定模式 - 目标类型确认");
}
/// <summary>
/// 尝试探测和识别目标
/// </summary>
/// <param name="missilePosition">导弹当前位置</param>
/// <param name="missileVelocity">导弹当前速度</param>
/// <param name="deltaTime">时间间隔,单位:秒</param>
/// <param name="targetPosition">输出目标位置</param>
/// <returns>是否成功探测到指定类型的目标</returns>
/// <remarks>
/// 探测和识别过程:
/// 1. 遍历场景中的目标
/// 2. 检查目标是否在探测范围内
/// 3. 生成目标红外图像
/// 4. 识别目标类型
/// 5. 判断是否是要攻击的目标类型
/// </remarks>
private bool TryDetectAndIdentifyTarget(Vector3D missilePosition, Vector3D missileVelocity, double deltaTime, out Vector3D targetPosition)
{
targetPosition = Vector3D.Zero;
double minDistance = double.MaxValue;
bool foundTarget = false;
// 根据当前模式选择视场角和识别策略
double currentFov = currentMode == WorkMode.Search ? config.SearchFieldOfView : config.TrackFieldOfView;
foreach (var element in SimulationManager.GetEntitiesByType<SimulationElement>())
{
if (element is BaseEquipment target)
{
Vector3D toTarget = target.KState.Position - missilePosition;
double distance = toTarget.Magnitude();
// 检查距离条件
if (distance <= config.MaxDetectionRange)
{
// 检查视线角条件
double angle = Math.Acos(Vector3D.DotProduct(toTarget.Normalize(), missileVelocity.Normalize()));
if (angle <= currentFov / 2)
{
// 在生成红外图像前,检查目标是否被烟幕几何遮挡
bool isTargetGeometricallyObscured = CheckIfTargetObscuredBySmoke(missilePosition, target);
if (isTargetGeometricallyObscured)
{
Debug.WriteLine($"[红外成像制导系统] 目标 {target.Id} 被烟幕几何遮挡,跳过图像生成");
continue; // 如果目标被完全遮挡,跳过此目标
}
// 实时计算当前目标到导弹之间的烟幕透过率
double liveSmokeTransmittance = CalculateLiveSmokeTransmittance(missilePosition, target.KState.Position);
// 生成红外图像
var image = imageGenerator.GenerateImage(target, missilePosition, liveSmokeTransmittance, SimulationManager);
switch (currentMode)
{
case WorkMode.Search:
// 搜索模式:使用较低阈值进行目标识别
var searchResult = targetRecognizer.RecognizeTarget(image, target);
if (searchResult.Type == targetType && searchResult.Confidence >= config.SearchRecognitionProbability)
{
if (distance < minDistance)
{
targetPosition = target.KState.Position;
minDistance = distance;
foundTarget = true;
// 切换到跟踪模式
SwitchToTrackMode();
}
}
break;
case WorkMode.Track:
// 跟踪模式:使用较高阈值确认目标
var trackResult = targetRecognizer.RecognizeTarget(image, target);
if (trackResult.Type == targetType && trackResult.Confidence >= config.TrackRecognitionProbability)
{
if (distance < minDistance)
{
targetPosition = target.KState.Position;
minDistance = distance;
foundTarget = true;
// 增加锁定确认时间
lockConfirmationTimer += deltaTime;
if (lockConfirmationTimer >= config.LockConfirmationTime)
{
// 持续高置信度跟踪足够时间后,切换到锁定模式
SwitchToLockMode();
}
}
}
else if (trackResult.Type == targetType && trackResult.Confidence >= config.SearchRecognitionProbability)
{
// 如果置信度达到搜索阈值但未达到跟踪阈值,重置锁定计时器
lockConfirmationTimer = 0;
if (distance < minDistance)
{
targetPosition = target.KState.Position;
minDistance = distance;
foundTarget = true;
}
}
else
{
// 目标置信度不足,重置锁定计时器
lockConfirmationTimer = 0;
}
break;
case WorkMode.Lock:
// 锁定模式:只进行位置跟踪,不做类型识别
if (distance < minDistance)
{
targetPosition = target.KState.Position;
minDistance = distance;
foundTarget = true;
}
break;
}
}
}
}
}
HasTarget = foundTarget;
return foundTarget;
}
/// <summary>
/// 检查目标是否被烟幕完全遮挡
/// </summary>
/// <param name="observerPosition">观察者位置(导弹)</param>
/// <param name="target">目标</param>
/// <returns>如果目标被烟幕遮挡超过阈值返回true</returns>
private bool CheckIfTargetObscuredBySmoke(Vector3D observerPosition, BaseEquipment target)
{
// 获取所有活动的烟幕弹
var smokeGrenades = SimulationManager.GetEntitiesByType<SmokeGrenade>()
.Where(sg => sg.IsActive && sg.config != null)
.ToList();
if (smokeGrenades.Count == 0)
{
return false; // 没有活动的烟幕
}
const double ObscurationThreshold = 0.8; // 80%遮挡视为完全遮挡
Vector3D targetCenter = target.KState.Position;
Orientation targetOrient = target.KState.Orientation;
Vector3D targetDims = new(target.Properties.Width, target.Properties.Height, target.Properties.Length);
foreach (var smoke in smokeGrenades)
{
try
{
// 对于墙状烟幕,定义其尺寸和方向
Vector3D smokeDims;
if (smoke.config.SmokeType == SmokeScreenType.Cloud)
{
smokeDims = new Vector3D(smoke.config.CloudDiameter, smoke.config.Thickness, smoke.config.CloudDiameter);
}
else // Wall
{
smokeDims = new Vector3D(smoke.config.Thickness, smoke.config.WallHeight, smoke.config.WallWidth);
}
// 使用ObscurationUtils计算烟幕对目标的遮挡比例
double overlapRatio = ObscurationUtils.CalculateProjectedOverlapRatio(
observerPosition, // 观察者位置(导弹)
smoke.KState.Position, smokeDims, smoke.KState.Orientation, // 烟幕数据(前景)
targetCenter, targetDims, targetOrient // 目标数据(背景)
);
Debug.WriteLine($"[红外成像制导系统] 目标 {target.Id} 被烟幕 {smoke.Id} 遮挡比例: {overlapRatio:P2}");
// 如果任何一个烟幕的遮挡比例超过阈值,则认为目标被遮挡
if (overlapRatio >= ObscurationThreshold)
{
Debug.WriteLine($"[红外成像制导系统] 目标 {target.Id} 被烟幕 {smoke.Id} 遮挡超过阈值 {ObscurationThreshold:P0},视为完全遮挡");
return true;
}
}
catch (Exception ex)
{
Debug.WriteLine($"[红外成像制导系统] 计算烟幕遮挡时出错: {ex.Message}");
}
}
return false; // 没有烟幕能有效遮挡目标
}
/// <summary>
/// 计算给定观察点和目标点之间的总烟幕透过率
/// </summary>
/// <param name="observerPosition">观察者位置</param>
/// <param name="targetEndPosition">目标位置</param>
/// <returns>总透过率 (0.0 到 1.0)</returns>
private double CalculateLiveSmokeTransmittance(Vector3D observerPosition, Vector3D targetEndPosition)
{
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(observerPosition, targetEndPosition, config.Wavelength);
totalTransmittance *= transmittanceForThisSmoke; // 叠加衰减效应(透过率相乘)
// 如果透过率已经很低,可以提前退出以优化
if (totalTransmittance < 0.001)
{
return 0.0;
}
}
return Math.Max(0.0, totalTransmittance); //确保不为负
}
/// <summary>
/// 获取红外图像制导系统的详细状态信息
/// </summary>
/// <returns>包含完整状态参数的字符串</returns>
/// <remarks>
/// 特有的返回信息:
/// - 上次发现的目标位置
/// </remarks>
public override ElementStatusInfo GetStatusInfo()
{
var statusInfo = base.GetStatusInfo();
string lastPosStr = LastTargetPosition.HasValue ? LastTargetPosition.Value.ToString() : "null";
statusInfo.ExtendedProperties["lastPosStr"] = lastPosStr;
return statusInfo;
}
}
}