完善了红外成像制导的搜索和跟踪机制(滑动窗口),修改了特征提取和目标识别算法
This commit is contained in:
parent
f6ff47f2b4
commit
a780126d32
@ -11,10 +11,10 @@ MaxSpeed = 250.0
|
||||
MaxFlightTime = 60.0
|
||||
MaxFlightDistance = 5000.0
|
||||
MaxAcceleration = 100.0
|
||||
ProportionalNavigationCoefficient = 3.0
|
||||
ProportionalNavigationCoefficient = 4.0
|
||||
LaunchAcceleration = 100.0
|
||||
MaxEngineBurnTime = 2.5
|
||||
CruiseTime = 5.0 # 假设这是第一阶段(MMW)的巡航时间或总巡航时间的一部分
|
||||
CruiseTime = 5.0
|
||||
Mass = 25.0
|
||||
ExplosionRadius = 5.5
|
||||
HitProbability = 0.9
|
||||
@ -33,9 +33,9 @@ GuidanceSystemType = "MillimeterWaveTerminalGuidance" # 必须与C#工厂中的
|
||||
ActivationTrigger = "OnLaunch" # 激活触发器:OnLaunch, AfterFlightTime, DistanceToTargetThreshold, PreviousStageComplete
|
||||
ActivationValue = 0.0 # 触发器关联值 (例如:飞行时间秒数,距离米数)
|
||||
Priority = 0 # 优先级 (例如:0为最高)
|
||||
MaxTimeToAcquireGuidanceSeconds = 5.0 # 新增:获取制导的最大时间
|
||||
MinTimeWithGuidanceBeforeSwitchSeconds = 0.2 # 新增:稳定跟踪0.2秒后切换(因为毫米波跟踪不稳定)
|
||||
ContinueChainOnFailure = true # 新增:失败后继续尝试下一个
|
||||
MaxTimeToAcquireGuidanceSeconds = 5.0 # 获取制导的最大时间
|
||||
MinTimeWithGuidanceBeforeSwitchSeconds = 0.2 # 稳定跟踪0.2秒后切换(因为毫米波跟踪不稳定)
|
||||
ContinueChainOnFailure = true # 失败后继续尝试下一个
|
||||
|
||||
# 第二个制导阶段:红外成像末制导
|
||||
[[Properties.GuidanceSuite]]
|
||||
@ -44,35 +44,35 @@ GuidanceSystemType = "InfraredImagingTerminalGuidance" # 必须与C#工厂中的
|
||||
ActivationTrigger = "PreviousStageComplete" # 例如:在飞行一段时间后切换 (或者 PreviousStageComplete)
|
||||
ActivationValue = 10.0 # 例如:飞行10秒后激活红外阶段 (如果 CruiseTime 是 5s,这里可能需要调整)
|
||||
Priority = 1 # 优先级低于毫米波
|
||||
MaxTimeToAcquireGuidanceSeconds = 5.0 # 新增:获取制导的最大时间
|
||||
MinTimeWithGuidanceBeforeSwitchSeconds = 60.0 # 新增:设置为MaxFlightTime,使其持续制导
|
||||
ContinueChainOnFailure = false # 新增:这是最后一个,失败也无需继续
|
||||
MaxTimeToAcquireGuidanceSeconds = 5.0 # 获取制导的最大时间
|
||||
MinTimeWithGuidanceBeforeSwitchSeconds = 60.0 # 设置为MaxFlightTime,使其持续制导
|
||||
ContinueChainOnFailure = false # 这是最后一个,失败也无需继续
|
||||
|
||||
# --- 各制导模式的详细配置 ---
|
||||
[InfraredImagingGuidanceConfig]
|
||||
MaxDetectionRange = 1000.0 # 最大探测距离 (米), JSON中为1000,对应C#默认为1000.0
|
||||
SearchFieldOfView = 0.209 # 搜索视场角 (弧度), JSON中为0.209, C#默认为 PI/15 ≈ 0.2094
|
||||
TrackFieldOfView = 0.052 # 跟踪视场角 (弧度), JSON中为0.052, C#默认为 PI/60 ≈ 0.0523
|
||||
MaxDetectionRange = 1000.0 # 最大探测距离 (米)
|
||||
SearchFieldOfView = 12.0 # 搜索视场角 (度)
|
||||
TrackFieldOfView = 6.0 # 跟踪视场角 (度)
|
||||
ImageWidth = 640 # 图像宽度 (像素)
|
||||
ImageHeight = 512 # 图像高度 (像素)
|
||||
BackgroundIntensity = 1.0e-4 # 背景辐射强度 (瓦特/球面度), JSON中为1e-4, C#默认为0.01
|
||||
ImageHeight = 480 # 图像高度 (像素)
|
||||
BackgroundIntensity = 1.0e-4 # 背景辐射强度 (瓦特/球面度)
|
||||
SearchRecognitionProbability = 0.6 # 搜索模式目标识别概率阈值
|
||||
TrackRecognitionProbability = 0.8 # 跟踪模式目标识别概率阈值
|
||||
TargetLostTolerance = 0.2 # 目标丢失容忍时间 (秒)
|
||||
LockConfirmationTime = 0.3 # 锁定确认时间 (秒)
|
||||
TargetLostTolerance = 0.3 # 目标丢失容忍时间 (秒)
|
||||
LockConfirmationTime = 0.5 # 锁定确认时间 (秒)
|
||||
JammingResistanceThreshold = 1.0e-5 # 干扰抗性阈值 (瓦特)
|
||||
Wavelength = 3.0 # 波长 (微米), C#中属性名为Wavelength, JSON中为waveLength
|
||||
Wavelength = 3.0 # 波长 (微米)
|
||||
|
||||
[MillimeterWaveGuidanceConfig]
|
||||
MaxDetectionRange = 5000.0 # 最大探测距离 (米)
|
||||
FieldOfViewAngle = 45.0 # 视场角 (度)
|
||||
TargetRecognitionProbability = 0.95 # 目标识别概率
|
||||
WaveFrequency = 9.4e10 # 波频率 (赫兹, JSON中为94e9)
|
||||
WaveFrequency = 9.4e10 # 波频率 (赫兹)
|
||||
PulseDuration = 1.0e-6 # 脉冲持续时间 (秒)
|
||||
|
||||
SearchBeamWidth = 5.0 # 搜索波束宽度 (度)
|
||||
TrackBeamWidth = 2.5 # 跟踪波束宽度 (度)
|
||||
LockBeamWidth = 1.0 # 锁定波束宽度 (度)
|
||||
TrackBeamWidth = 3.0 # 跟踪波束宽度 (度)
|
||||
LockBeamWidth = 2.0 # 锁定波束宽度 (度)
|
||||
|
||||
ScanAngularSpeedDeg = 360.0 # 扫描角速度 (度/秒)
|
||||
ScanRadiusGrowthRateDeg = 22.5 # 扫描半径增长率 (度)
|
||||
@ -83,7 +83,7 @@ LockSNRThreshold = -10.0 # 锁定信噪比阈值 (分贝)
|
||||
TargetLostTolerance = 0.2 # 目标丢失容忍时间 (秒)
|
||||
LockConfirmationTime = 0.3 # 锁定确认时间 (秒)
|
||||
|
||||
PulseRepetitionFrequency = 1.0e-4 # 脉冲重复频率 (秒, JSON中为1e-4,通常PRT单位是秒,PRF是Hz。这里JSON的注释可能不准确,按数值和C#模型属性名推断,这里应为PulseRepetitionTime,即脉冲重复间隔)
|
||||
PulseRepetitionFrequency = 1.0e-4 # 脉冲重复间隔 (秒)
|
||||
TransmitPower = 0.3 # 发射功率 (瓦特)
|
||||
|
||||
DopplerVelocityResolution = 1.0 # 多普勒速度分辨率 (米/秒)
|
||||
@ -92,7 +92,7 @@ MaxMeasurableVelocity = 1000.0 # 最大可测量速度 (米/秒)
|
||||
AntennaGainDB = 23.0 # 天线增益 (分贝)
|
||||
NoiseFigureDB = 7.0 # 噪声系数 (分贝)
|
||||
SystemLossDB = 6.0 # 系统损耗 (分贝)
|
||||
MonopulseSensitivity = 1.0 # 单脉冲灵敏度 (单位取决于具体实现,JSON中为1)
|
||||
MonopulseSensitivity = 1.0 # 单脉冲灵敏度
|
||||
|
||||
YawControlEffectiveness = 120.0 # 偏航控制有效性 (度/秒^2 或类似单位)
|
||||
PitchControlEffectiveness = 150.0 # 俯仰控制有效性 (度/秒^2 或类似单位)
|
||||
|
||||
@ -11,7 +11,7 @@ MaxSpeed = 250.0
|
||||
MaxFlightTime = 60.0
|
||||
MaxFlightDistance = 5000.0
|
||||
MaxAcceleration = 100.0
|
||||
ProportionalNavigationCoefficient = 3.0
|
||||
ProportionalNavigationCoefficient = 4.0
|
||||
LaunchAcceleration = 100.0
|
||||
MaxEngineBurnTime = 2.5
|
||||
CruiseTime = 5.0
|
||||
@ -24,14 +24,14 @@ UltravioletRadiationIntensity = 100.0 # 紫外辐射强度 (瓦特/球面度)
|
||||
|
||||
[InfraredImagingGuidanceConfig]
|
||||
MaxDetectionRange = 1000.0 # 最大探测距离 (米), JSON中为1000,对应C#默认为1000.0
|
||||
SearchFieldOfView = 0.209 # 搜索视场角 (弧度), JSON中为0.209, C#默认为 PI/15 ≈ 0.2094
|
||||
TrackFieldOfView = 0.052 # 跟踪视场角 (弧度), JSON中为0.052, C#默认为 PI/60 ≈ 0.0523
|
||||
SearchFieldOfView = 12.0 # 搜索视场角 (度), 对应C#默认为12.0度
|
||||
TrackFieldOfView = 6.0 # 跟踪视场角 (度), 对应C#默认为3.0度
|
||||
ImageWidth = 640 # 图像宽度 (像素)
|
||||
ImageHeight = 512 # 图像高度 (像素)
|
||||
ImageHeight = 480 # 图像高度 (像素)
|
||||
BackgroundIntensity = 1.0e-4 # 背景辐射强度 (瓦特/球面度), JSON中为1e-4, C#默认为0.01
|
||||
SearchRecognitionProbability = 0.6 # 搜索模式目标识别概率阈值
|
||||
TrackRecognitionProbability = 0.8 # 跟踪模式目标识别概率阈值
|
||||
TargetLostTolerance = 0.2 # 目标丢失容忍时间 (秒)
|
||||
LockConfirmationTime = 0.3 # 锁定确认时间 (秒)
|
||||
TargetLostTolerance = 0.3 # 目标丢失容忍时间 (秒)
|
||||
LockConfirmationTime = 0.5 # 锁定确认时间 (秒)
|
||||
JammingResistanceThreshold = 1.0e-5 # 干扰抗性阈值 (瓦特)
|
||||
Wavelength = 3.0 # 波长 (微米), C#中属性名为Wavelength, JSON中为waveLength
|
||||
@ -11,7 +11,7 @@ MaxSpeed = 250.0 # 最大速度 (米/秒)
|
||||
MaxFlightTime = 60.0 # 最大飞行时间 (秒)
|
||||
MaxFlightDistance = 8000.0 # 最大飞行距离 (米)
|
||||
MaxAcceleration = 100.0 # 最大加速度 (米/秒^2)
|
||||
ProportionalNavigationCoefficient = 3.0 # 比例导引系数
|
||||
ProportionalNavigationCoefficient = 4.0 # 比例导引系数
|
||||
LaunchAcceleration = 100.0 # 发射加速度 (米/秒^2)
|
||||
MaxEngineBurnTime = 2.5 # 最大发动机燃烧时间 (秒)
|
||||
CruiseTime = 4.0 # 巡航时间 (秒)
|
||||
@ -29,9 +29,9 @@ TargetRecognitionProbability = 0.95 # 目标识别概率
|
||||
WaveFrequency = 9.4e10 # 波频率 (赫兹, JSON中为94e9)
|
||||
PulseDuration = 1.0e-6 # 脉冲持续时间 (秒)
|
||||
|
||||
SearchBeamWidth = 4.0 # 搜索波束宽度 (度)
|
||||
TrackBeamWidth = 2.0 # 跟踪波束宽度 (度)
|
||||
LockBeamWidth = 1.0 # 锁定波束宽度 (度)
|
||||
SearchBeamWidth = 5.0 # 搜索波束宽度 (度)
|
||||
TrackBeamWidth = 3.0 # 跟踪波束宽度 (度)
|
||||
LockBeamWidth = 2.0 # 锁定波束宽度 (度)
|
||||
|
||||
ScanAngularSpeedDeg = 360.0 # 扫描角速度 (度/秒)
|
||||
ScanRadiusGrowthRateDeg = 22.5 # 扫描半径增长率 (度)
|
||||
|
||||
@ -3,6 +3,9 @@ using ThreatSource.Equipment;
|
||||
using ThreatSource.Utils;
|
||||
using ThreatSource.Jammer;
|
||||
using System.Diagnostics;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System;
|
||||
|
||||
namespace ThreatSource.Guidance
|
||||
{
|
||||
@ -55,11 +58,6 @@ namespace ThreatSource.Guidance
|
||||
/// </summary>
|
||||
public bool HasTarget { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 当前是否处于锁定模式
|
||||
/// </summary>
|
||||
public bool IsInLockMode => currentMode == WorkMode.Lock;
|
||||
|
||||
/// <summary>
|
||||
/// 上一次探测到的目标位置 (使用可空类型)
|
||||
/// </summary>
|
||||
@ -67,7 +65,7 @@ namespace ThreatSource.Guidance
|
||||
/// 记录目标的历史位置
|
||||
/// 用于计算目标速度
|
||||
/// </remarks>
|
||||
private Vector3D? LastTargetPosition { get; set; } // Changed to nullable Vector3D?
|
||||
private Vector3D? LastTargetPosition { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 红外图像生成器
|
||||
@ -89,16 +87,41 @@ namespace ThreatSource.Guidance
|
||||
/// </summary>
|
||||
private readonly InfraredImagingGuidanceConfig config;
|
||||
|
||||
/// <summary>
|
||||
/// 目标丢失计时器
|
||||
/// </summary>
|
||||
private double targetLostTimer = 0;
|
||||
|
||||
/// <summary>
|
||||
/// 锁定确认计时器
|
||||
/// </summary>
|
||||
private double lockConfirmationTimer = 0;
|
||||
|
||||
/// <summary>
|
||||
/// 当前正在跟踪或已锁定的目标ID
|
||||
/// </summary>
|
||||
private string? _currentlyTrackedTargetId;
|
||||
|
||||
/// <summary>
|
||||
/// Search模式下当前关注的候选目标ID
|
||||
/// </summary>
|
||||
private string? _searchModeFocusCandidateId;
|
||||
|
||||
/// <summary>
|
||||
/// 当前活动模式 (搜索焦点或跟踪稳定) 的识别历史队列
|
||||
/// </summary>
|
||||
private Queue<bool> _activeRecognitionHistory = new();
|
||||
|
||||
/// <summary>
|
||||
/// 识别历史窗口大小 (搜索和跟踪阶段共用)
|
||||
/// </summary>
|
||||
private const int COMMON_RECOGNITION_WINDOW_SIZE = 10;
|
||||
|
||||
/// <summary>
|
||||
/// 识别成功率阈值 (搜索切换和跟踪稳定性判断共用, 例如80%)
|
||||
/// </summary>
|
||||
private const double COMMON_RECOGNITION_SUCCESS_RATE_THRESHOLD = 0.8;
|
||||
|
||||
/// <summary>
|
||||
/// 锁定模式下目标丢失计时器
|
||||
/// </summary>
|
||||
private double _lockModeTargetLostTimer = 0;
|
||||
|
||||
/// <summary>
|
||||
/// 初始化红外成像制导系统的新实例
|
||||
/// </summary>
|
||||
@ -135,7 +158,7 @@ namespace ThreatSource.Guidance
|
||||
imageGenerator = new InfraredImageGenerator(
|
||||
imageWidth: guidanceConfig.ImageWidth,
|
||||
imageHeight: guidanceConfig.ImageHeight,
|
||||
fieldOfView: guidanceConfig.SearchFieldOfView,
|
||||
fieldOfView: guidanceConfig.SearchFieldOfView * Math.PI / 180.0,
|
||||
backgroundIntensity: guidanceConfig.BackgroundIntensity,
|
||||
wavelength: guidanceConfig.Wavelength
|
||||
);
|
||||
@ -219,15 +242,24 @@ namespace ThreatSource.Guidance
|
||||
public override void Update(double deltaTime)
|
||||
{
|
||||
base.Update(deltaTime);
|
||||
if (!IsBlockingJammed)
|
||||
bool targetFoundAndIdentifiedThisFrame = false;
|
||||
Vector3D currentTargetPosition = Vector3D.Zero; // 初始化
|
||||
|
||||
if (IsBlockingJammed)
|
||||
{
|
||||
if (TryDetectAndIdentifyTarget(KState.Position, KState.Velocity, deltaTime, out Vector3D currentTargetPosition))
|
||||
targetFoundAndIdentifiedThisFrame = false;
|
||||
Debug.WriteLine($"[IR IMAGING] 系统被阻塞干扰,无法探测目标。当前模式: {currentMode}");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (TryDetectAndIdentifyTarget(KState.Position, KState.Velocity, deltaTime, out currentTargetPosition))
|
||||
{
|
||||
targetLostTimer = 0; // 重置丢失计时器
|
||||
Vector3D? currentTargetVelocity = null; // Initialize as nullable
|
||||
targetFoundAndIdentifiedThisFrame = true;
|
||||
// 目标成功探测/跟踪/锁定
|
||||
Vector3D? currentTargetVelocity = null;
|
||||
if(LastTargetPosition != null && deltaTime > 0)
|
||||
{
|
||||
currentTargetVelocity = (currentTargetPosition - LastTargetPosition) / deltaTime;
|
||||
currentTargetVelocity = (currentTargetPosition - LastTargetPosition.Value) / deltaTime; // 使用 .Value
|
||||
}
|
||||
|
||||
LastTargetPosition = currentTargetPosition;
|
||||
@ -236,43 +268,64 @@ namespace ThreatSource.Guidance
|
||||
ProportionalNavigationCoefficient,
|
||||
KState.Position,
|
||||
KState.Velocity,
|
||||
currentTargetPosition, // Non-nullable from out parameter
|
||||
currentTargetVelocity ?? Vector3D.Zero // Provide default if null
|
||||
currentTargetPosition,
|
||||
currentTargetVelocity ?? Vector3D.Zero
|
||||
);
|
||||
// 限制最大加速度
|
||||
|
||||
if (GuidanceAcceleration.Magnitude() > MaxAcceleration)
|
||||
{
|
||||
GuidanceAcceleration = GuidanceAcceleration.Normalize() * MaxAcceleration;
|
||||
}
|
||||
|
||||
HasGuidance = true;
|
||||
|
||||
if (currentMode == WorkMode.Lock)
|
||||
{
|
||||
_lockModeTargetLostTimer = 0; // 目标在锁定模式下重新确认,重置计时器
|
||||
}
|
||||
}
|
||||
else
|
||||
else // TryDetectAndIdentifyTarget 返回 false (目标未找到/不稳定)
|
||||
{
|
||||
// 在跟踪或锁定模式下,增加丢失计时器
|
||||
if (currentMode != WorkMode.Search)
|
||||
{
|
||||
targetLostTimer += deltaTime;
|
||||
// 只有当超过容忍时间才认为真正丢失目标
|
||||
if (targetLostTimer >= config.TargetLostTolerance)
|
||||
{
|
||||
HasGuidance = false;
|
||||
// 切换回搜索模式
|
||||
Debug.WriteLine($"目标丢失 {targetLostTimer:F3}s, 切换回搜索模式");
|
||||
SwitchToSearchMode();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
HasGuidance = false;
|
||||
}
|
||||
targetFoundAndIdentifiedThisFrame = false;
|
||||
// 不更新 LastTargetPosition
|
||||
Debug.WriteLine($"[IR IMAGING] TryDetectAndIdentifyTarget 返回 false。当前模式: {currentMode}");
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
// 处理目标未识别/丢失的后果
|
||||
if (!targetFoundAndIdentifiedThisFrame)
|
||||
{
|
||||
GuidanceAcceleration = Vector3D.Zero;
|
||||
HasGuidance = false;
|
||||
|
||||
// 模式切换逻辑
|
||||
if (currentMode == WorkMode.Track)
|
||||
{
|
||||
Debug.WriteLine($"[IR IMAGING] 目标在 Track 模式下丢失/不稳定 (或受干扰),立即切换回搜索模式。");
|
||||
SwitchToSearchMode();
|
||||
}
|
||||
else if (currentMode == WorkMode.Lock)
|
||||
{
|
||||
if (IsBlockingJammed)
|
||||
{
|
||||
Debug.WriteLine($"[IR IMAGING] 因阻塞干扰,在 Lock 模式下丢失目标,立即切换回搜索模式。");
|
||||
SwitchToSearchMode();
|
||||
}
|
||||
else
|
||||
{
|
||||
_lockModeTargetLostTimer += deltaTime;
|
||||
Debug.WriteLine($"[IR IMAGING] 目标在 Lock 模式下丢失。计时器: {_lockModeTargetLostTimer:F2}s / {config.TargetLostTolerance:F2}s");
|
||||
if (_lockModeTargetLostTimer >= config.TargetLostTolerance)
|
||||
{
|
||||
Debug.WriteLine($"[IR IMAGING] Lock 模式目标丢失超过容限,切换回搜索模式。");
|
||||
SwitchToSearchMode();
|
||||
}
|
||||
// else 容限未到,保持在 Lock 模式,但 HasGuidance 已为 false
|
||||
}
|
||||
}
|
||||
// 如果在Search模式下目标丢失,通常意味着本帧未找到任何满足条件的目标,
|
||||
// TryDetectAndIdentifyTarget内部逻辑会处理是否重置焦点等,此处无需额外操作
|
||||
}
|
||||
// 如果 targetFoundAndIdentifiedThisFrame 为 true,则制导参数已设置,模式状态由 TryDetectAndIdentifyTarget 内部逻辑(如切换到Track/Lock)或 Update 稍早部分(重置Lock模式计时器)处理
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -288,18 +341,22 @@ namespace ThreatSource.Guidance
|
||||
{
|
||||
currentMode = WorkMode.Search;
|
||||
HasTarget = false;
|
||||
targetLostTimer = 0; // 重置丢失计时器
|
||||
LastTargetPosition = null; // Add reset to null
|
||||
// targetLostTimer = 0; // 已移除
|
||||
LastTargetPosition = null;
|
||||
_currentlyTrackedTargetId = null;
|
||||
_searchModeFocusCandidateId = null;
|
||||
_activeRecognitionHistory.Clear();
|
||||
_lockModeTargetLostTimer = 0; // 清理状态
|
||||
|
||||
// 创建图像生成器
|
||||
imageGenerator = new InfraredImageGenerator(
|
||||
imageWidth: config.ImageWidth,
|
||||
imageHeight: config.ImageHeight,
|
||||
fieldOfView: config.SearchFieldOfView,
|
||||
fieldOfView: config.SearchFieldOfView * Math.PI / 180.0,
|
||||
backgroundIntensity: config.BackgroundIntensity,
|
||||
wavelength: config.Wavelength
|
||||
);
|
||||
Debug.WriteLine($"切换到搜索模式, 视场角: {config.SearchFieldOfView * 180 / Math.PI} 度");
|
||||
Debug.WriteLine($"切换到搜索模式, 视场角: {config.SearchFieldOfView} 度");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -315,16 +372,22 @@ namespace ThreatSource.Guidance
|
||||
{
|
||||
currentMode = WorkMode.Track;
|
||||
lockConfirmationTimer = 0; // 重置锁定确认计时器
|
||||
// _lockModeTargetLostTimer 在切换到Track时不需要重置,因为它特定于Lock模式,
|
||||
// 并且在从Lock切换到Search,再可能到Track时,应由SwitchToSearchMode清理。
|
||||
|
||||
// 清理搜索阶段的状态
|
||||
_searchModeFocusCandidateId = null;
|
||||
_activeRecognitionHistory.Clear(); // Track模式应从零开始积累历史
|
||||
|
||||
// 创建图像生成器
|
||||
// 创建图像生成器 (通常视场角会变化)
|
||||
imageGenerator = new InfraredImageGenerator(
|
||||
imageWidth: config.ImageWidth,
|
||||
imageHeight: config.ImageHeight,
|
||||
fieldOfView: config.TrackFieldOfView,
|
||||
fieldOfView: config.TrackFieldOfView * Math.PI / 180.0,
|
||||
backgroundIntensity: config.BackgroundIntensity,
|
||||
wavelength: config.Wavelength
|
||||
);
|
||||
Debug.WriteLine($"切换到跟踪模式, 视场角: {config.TrackFieldOfView * 180 / Math.PI} 度");
|
||||
Debug.WriteLine($"切换到跟踪模式, 视场角: {config.TrackFieldOfView} 度");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -339,6 +402,7 @@ namespace ThreatSource.Guidance
|
||||
public void SwitchToLockMode()
|
||||
{
|
||||
currentMode = WorkMode.Lock;
|
||||
_lockModeTargetLostTimer = 0; // 进入锁定模式时重置计时器
|
||||
Debug.WriteLine("切换到锁定模式 - 目标类型确认");
|
||||
}
|
||||
|
||||
@ -362,208 +426,331 @@ namespace ThreatSource.Guidance
|
||||
{
|
||||
targetPosition = Vector3D.Zero;
|
||||
double minDistance = double.MaxValue;
|
||||
bool foundTarget = false;
|
||||
bool foundThisFrame = false;
|
||||
bool currentFrameDirectRecognitionSuccess = false; // 新增:用于记录当前帧的直接识别/探测成功状态
|
||||
|
||||
// 根据当前模式选择视场角和识别策略
|
||||
double currentFov = currentMode == WorkMode.Search ? config.SearchFieldOfView : config.TrackFieldOfView;
|
||||
double searchFovRadians = config.SearchFieldOfView * Math.PI / 180.0;
|
||||
double trackFovRadians = config.TrackFieldOfView * Math.PI / 180.0;
|
||||
double currentFovRadians = currentMode == WorkMode.Search ? searchFovRadians : trackFovRadians;
|
||||
|
||||
foreach (var element in SimulationManager.GetEntitiesByType<SimulationElement>())
|
||||
{
|
||||
if (element is BaseEquipment target)
|
||||
if (element is BaseEquipment currentEntity)
|
||||
{
|
||||
Vector3D toTarget = target.KState.Position - missilePosition;
|
||||
double distance = toTarget.Magnitude();
|
||||
Vector3D toTarget = currentEntity.KState.Position - missilePosition;
|
||||
double distanceToCurrentEntity = toTarget.Magnitude();
|
||||
|
||||
// 检查距离条件
|
||||
if (distance <= config.MaxDetectionRange)
|
||||
// 调用新的统一烟幕评估方法
|
||||
var smokeImpact = EvaluateSmokeImpact(missilePosition, currentEntity);
|
||||
bool isGeometricallyObscuredBySmoke = smokeImpact.IsGeometricallyObscured;
|
||||
double liveTransmittanceForImage = smokeImpact.OverallTransmittance; // 重命名以避免与旧变量名冲突
|
||||
|
||||
// 根据当前模式调整FOV检查,并将烟幕几何遮挡作为主要过滤条件之一
|
||||
bool passesBasicChecks = false;
|
||||
if (currentMode == WorkMode.Search)
|
||||
{
|
||||
// 检查视线角条件
|
||||
double angle = Math.Acos(Vector3D.DotProduct(toTarget.Normalize(), missileVelocity.Normalize()));
|
||||
if (angle <= currentFov / 2)
|
||||
passesBasicChecks = distanceToCurrentEntity <= config.MaxDetectionRange &&
|
||||
Math.Acos(Vector3D.DotProduct(toTarget.Normalize(), missileVelocity.Normalize())) <= (searchFovRadians / 2) &&
|
||||
!isGeometricallyObscuredBySmoke;
|
||||
}
|
||||
else if (currentMode == WorkMode.Track || currentMode == WorkMode.Lock)
|
||||
{ // Track 和 Lock 模式使用 TrackFieldOfView
|
||||
passesBasicChecks = distanceToCurrentEntity <= config.MaxDetectionRange &&
|
||||
Math.Acos(Vector3D.DotProduct(toTarget.Normalize(), missileVelocity.Normalize())) <= (trackFovRadians / 2) &&
|
||||
!isGeometricallyObscuredBySmoke;
|
||||
}
|
||||
|
||||
if (passesBasicChecks)
|
||||
{
|
||||
switch (currentMode)
|
||||
{
|
||||
// 在生成红外图像前,检查目标是否被烟幕几何遮挡
|
||||
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);
|
||||
case WorkMode.Search:
|
||||
// 几何和主要烟幕检查已在上方 passesBasicChecks 中完成
|
||||
// if (distanceToCurrentEntity > config.MaxDetectionRange || ... || CheckIfTargetObscuredBySmoke(...))
|
||||
// 上述条件已由 passesBasicChecks 处理
|
||||
|
||||
switch (currentMode)
|
||||
{
|
||||
case WorkMode.Search:
|
||||
// 搜索模式:使用较低阈值进行目标识别
|
||||
var searchResult = targetRecognizer.RecognizeTarget(image, target);
|
||||
if (searchResult.Type == targetType && searchResult.Confidence >= config.SearchRecognitionProbability)
|
||||
if (currentEntity.Id == _searchModeFocusCandidateId && !passesBasicChecks)
|
||||
{
|
||||
// 如果是焦点目标,但它不再满足基本条件 (例如,进入了烟幕或飞出FOV)
|
||||
_searchModeFocusCandidateId = null;
|
||||
_activeRecognitionHistory.Clear();
|
||||
continue; // 跳过此不合格的焦点实体
|
||||
}
|
||||
|
||||
if (!passesBasicChecks) { continue; } // 如果任何实体不通过基本检查,直接跳过
|
||||
|
||||
// 确定或确认焦点目标
|
||||
if (_searchModeFocusCandidateId == null)
|
||||
{
|
||||
_searchModeFocusCandidateId = currentEntity.Id;
|
||||
_activeRecognitionHistory.Clear();
|
||||
}
|
||||
else if (currentEntity.Id != _searchModeFocusCandidateId)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// 此处意味着 currentEntity.Id == _searchModeFocusCandidateId,处理焦点目标
|
||||
// double liveSmokeTransmittance = CalculateLiveSmokeTransmittance(missilePosition, currentEntity.KState.Position);
|
||||
var image = imageGenerator.GenerateImage(currentEntity, missilePosition, liveTransmittanceForImage, SimulationManager);
|
||||
var searchResult = targetRecognizer.RecognizeTarget(image, currentEntity);
|
||||
|
||||
bool currentRecognitionSuccessInSearch = (searchResult.Type == targetType && searchResult.Confidence >= config.SearchRecognitionProbability);
|
||||
currentFrameDirectRecognitionSuccess = currentRecognitionSuccessInSearch; // 赋值给提升作用域的变量
|
||||
_activeRecognitionHistory.Enqueue(currentRecognitionSuccessInSearch);
|
||||
while (_activeRecognitionHistory.Count > COMMON_RECOGNITION_WINDOW_SIZE)
|
||||
{
|
||||
_activeRecognitionHistory.Dequeue();
|
||||
}
|
||||
|
||||
// 只有当窗口填满时才做决策
|
||||
if (_activeRecognitionHistory.Count == COMMON_RECOGNITION_WINDOW_SIZE)
|
||||
{
|
||||
double successRate = (double)_activeRecognitionHistory.Count(s => s) / COMMON_RECOGNITION_WINDOW_SIZE;
|
||||
if (successRate >= COMMON_RECOGNITION_SUCCESS_RATE_THRESHOLD)
|
||||
{
|
||||
if (distance < minDistance)
|
||||
Vector3D toTargetForTrackCheck = currentEntity.KState.Position - missilePosition;
|
||||
double angleToTargetForTrackCheck = Math.Acos(Vector3D.DotProduct(toTargetForTrackCheck.Normalize(), missileVelocity.Normalize()));
|
||||
|
||||
if (angleToTargetForTrackCheck <= (trackFovRadians / 2))
|
||||
{
|
||||
targetPosition = target.KState.Position;
|
||||
minDistance = distance;
|
||||
foundTarget = true;
|
||||
// 切换到跟踪模式
|
||||
_currentlyTrackedTargetId = _searchModeFocusCandidateId;
|
||||
targetPosition = currentEntity.KState.Position;
|
||||
minDistance = distanceToCurrentEntity;
|
||||
foundThisFrame = true;
|
||||
Debug.WriteLine($"[IR IMAGING SEARCH] 目标 {_searchModeFocusCandidateId} 滑动窗口达标 (率: {successRate:P2}) 且在Track FOV内. 切换到Track模式。");
|
||||
SwitchToTrackMode();
|
||||
break; // 跳出 foreach, 完成搜索并切换
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case WorkMode.Track:
|
||||
// 跟踪模式:使用较高阈值确认目标
|
||||
var trackResult = targetRecognizer.RecognizeTarget(image, target);
|
||||
if (trackResult.Type == targetType && trackResult.Confidence >= config.TrackRecognitionProbability)
|
||||
{
|
||||
if (distance < minDistance)
|
||||
else
|
||||
{
|
||||
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;
|
||||
_searchModeFocusCandidateId = null;
|
||||
_activeRecognitionHistory.Clear();
|
||||
foundThisFrame = false; // 仅对当前焦点而言,未通过最终检查
|
||||
Debug.WriteLine($"[IR IMAGING SEARCH] 目标 {currentEntity.Id} 滑动窗口达标,但不满足Track FOV. 清除焦点,继续搜索。");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// 目标置信度不足,重置锁定计时器
|
||||
lockConfirmationTimer = 0;
|
||||
_searchModeFocusCandidateId = null;
|
||||
_activeRecognitionHistory.Clear();
|
||||
foundThisFrame = false; // 明确当前焦点未通过滑动窗口
|
||||
Debug.WriteLine($"[IR IMAGING SEARCH] 目标 {currentEntity.Id} 滑动窗口未达标 (率: {successRate:P2}). 清除焦点,继续搜索。");
|
||||
}
|
||||
break;
|
||||
}
|
||||
else // 窗口未满,foundThisFrame取决于本帧的直接识别结果,但不做模式切换
|
||||
{
|
||||
foundThisFrame = currentRecognitionSuccessInSearch;
|
||||
if (currentRecognitionSuccessInSearch) targetPosition = currentEntity.KState.Position; // 如果本帧识别到,更新临时位置
|
||||
Debug.WriteLine($"[IR IMAGING SEARCH] 目标 {_searchModeFocusCandidateId} 正在收集数据,窗口 ({_activeRecognitionHistory.Count}/{COMMON_RECOGNITION_WINDOW_SIZE}). 本帧识别: {currentRecognitionSuccessInSearch}");
|
||||
}
|
||||
break; // Search case 的 break
|
||||
|
||||
case WorkMode.Lock:
|
||||
// 锁定模式:只进行位置跟踪,不做类型识别
|
||||
if (distance < minDistance)
|
||||
case WorkMode.Track:
|
||||
if (_currentlyTrackedTargetId != null && currentEntity.Id == _currentlyTrackedTargetId)
|
||||
{
|
||||
bool actualRecognitionSuccessInTrack = false; // 重命名,避免与search模式的变量混淆
|
||||
if (!passesBasicChecks)
|
||||
{
|
||||
targetPosition = target.KState.Position;
|
||||
minDistance = distance;
|
||||
foundTarget = true;
|
||||
actualRecognitionSuccessInTrack = false;
|
||||
Debug.WriteLine($"[IR IMAGING TRACK] 目标 {_currentlyTrackedTargetId} 未通过基本检查. 本帧失败。");
|
||||
}
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
var image_track = imageGenerator.GenerateImage(currentEntity, missilePosition, liveTransmittanceForImage, SimulationManager);
|
||||
var trackResult = targetRecognizer.RecognizeTarget(image_track, currentEntity);
|
||||
bool recognitionSucceededThisFrame = trackResult.Type == targetType && trackResult.Confidence >= config.TrackRecognitionProbability;
|
||||
|
||||
if (recognitionSucceededThisFrame)
|
||||
{
|
||||
actualRecognitionSuccessInTrack = true;
|
||||
Debug.WriteLine($"[IR IMAGING TRACK] 目标 {_currentlyTrackedTargetId} 本帧识别成功 (置信度 {trackResult.Confidence:P2})。");
|
||||
}
|
||||
else
|
||||
{
|
||||
actualRecognitionSuccessInTrack = false;
|
||||
Debug.WriteLine($"[IR IMAGING TRACK] 目标 {_currentlyTrackedTargetId} 本帧识别失败 (置信度: {trackResult.Confidence:P2})。");
|
||||
}
|
||||
}
|
||||
currentFrameDirectRecognitionSuccess = actualRecognitionSuccessInTrack; // 赋值给提升作用域的变量
|
||||
|
||||
_activeRecognitionHistory.Enqueue(actualRecognitionSuccessInTrack); // 使用 track 模式下的直接识别结果
|
||||
while (_activeRecognitionHistory.Count > COMMON_RECOGNITION_WINDOW_SIZE)
|
||||
{
|
||||
_activeRecognitionHistory.Dequeue();
|
||||
}
|
||||
|
||||
if (_activeRecognitionHistory.Count == COMMON_RECOGNITION_WINDOW_SIZE)
|
||||
{
|
||||
double trackSuccessRate = (double)_activeRecognitionHistory.Count(s => s) / COMMON_RECOGNITION_WINDOW_SIZE;
|
||||
if (trackSuccessRate >= COMMON_RECOGNITION_SUCCESS_RATE_THRESHOLD)
|
||||
{
|
||||
foundThisFrame = true;
|
||||
if (actualRecognitionSuccessInTrack)
|
||||
{
|
||||
targetPosition = currentEntity.KState.Position;
|
||||
minDistance = distanceToCurrentEntity;
|
||||
}
|
||||
else if (LastTargetPosition.HasValue) // 滑动窗口稳定,但本帧识别失败,使用上一位置
|
||||
{
|
||||
targetPosition = LastTargetPosition.Value;
|
||||
// minDistance 不更新,因为这是基于旧位置的
|
||||
Debug.WriteLine($"[IR IMAGING TRACK] 滑动窗口稳定,但本帧识别失败。使用LastTargetPosition: {targetPosition}");
|
||||
}
|
||||
Debug.WriteLine($"[IR IMAGING TRACK] 目标 {_currentlyTrackedTargetId} 滑动窗口稳定 (成功率 {trackSuccessRate:P2})。foundThisFrame = true。");
|
||||
}
|
||||
else
|
||||
{
|
||||
foundThisFrame = false;
|
||||
Debug.WriteLine($"[IR IMAGING TRACK] 目标 {_currentlyTrackedTargetId} 滑动窗口不稳定 (成功率 {trackSuccessRate:P2})。foundThisFrame = false。");
|
||||
}
|
||||
}
|
||||
else // 滑动窗口未满
|
||||
{
|
||||
foundThisFrame = passesBasicChecks;
|
||||
if (passesBasicChecks)
|
||||
{
|
||||
if (actualRecognitionSuccessInTrack) // 如果本帧具体识别也成功了
|
||||
{
|
||||
targetPosition = currentEntity.KState.Position;
|
||||
minDistance = distanceToCurrentEntity;
|
||||
}
|
||||
else if (LastTargetPosition.HasValue) // 基本检查通过,本帧识别失败,使用上一位置
|
||||
{
|
||||
targetPosition = LastTargetPosition.Value;
|
||||
// minDistance 不更新
|
||||
Debug.WriteLine($"[IR IMAGING TRACK] 滑动窗口未满,本帧识别失败。使用LastTargetPosition: {targetPosition}");
|
||||
}
|
||||
}
|
||||
Debug.WriteLine($"[IR IMAGING TRACK] 目标 {_currentlyTrackedTargetId} 正在收集数据,窗口 ({_activeRecognitionHistory.Count}/{COMMON_RECOGNITION_WINDOW_SIZE}). 本帧passesBasicChecks:{passesBasicChecks}, 本帧识别:{actualRecognitionSuccessInTrack}. foundThisFrame set to {foundThisFrame}");
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case WorkMode.Lock:
|
||||
if (_currentlyTrackedTargetId != null && currentEntity.Id == _currentlyTrackedTargetId)
|
||||
{
|
||||
if (!passesBasicChecks)
|
||||
{
|
||||
foundThisFrame = false;
|
||||
currentFrameDirectRecognitionSuccess = false;
|
||||
Debug.WriteLine($"[IR IMAGING LOCK] 锁定目标 {_currentlyTrackedTargetId} 未通过基本检查 (FOV, 范围, 烟幕几何遮挡)。");
|
||||
}
|
||||
else
|
||||
{
|
||||
targetPosition = currentEntity.KState.Position;
|
||||
minDistance = distanceToCurrentEntity;
|
||||
foundThisFrame = true;
|
||||
currentFrameDirectRecognitionSuccess = true; // Lock模式下通过基础检查即认为本帧直接探测成功
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
HasTarget = foundTarget;
|
||||
return foundTarget;
|
||||
if (currentMode == WorkMode.Track)
|
||||
{
|
||||
if (foundThisFrame && currentFrameDirectRecognitionSuccess)
|
||||
{
|
||||
lockConfirmationTimer += deltaTime;
|
||||
Debug.WriteLine($"[IR IMAGING TRACK] 目标 {_currentlyTrackedTargetId} 跟踪中,累积锁定确认时间: {lockConfirmationTimer:F2}s / {config.LockConfirmationTime:F2}s");
|
||||
if (lockConfirmationTimer >= config.LockConfirmationTime)
|
||||
{
|
||||
SwitchToLockMode();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
lockConfirmationTimer = 0;
|
||||
Debug.WriteLine($"[IR IMAGING TRACK] 目标 {_currentlyTrackedTargetId} 跟踪条件不满足 (foundThisFrame:{foundThisFrame} 或本帧直接识别失败:{currentFrameDirectRecognitionSuccess}),重置锁定确认计时器。");
|
||||
}
|
||||
}
|
||||
else if (currentMode == WorkMode.Lock)
|
||||
{
|
||||
if (!foundThisFrame)
|
||||
{
|
||||
// 在Lock模式下,如果 TryDetectAndIdentifyTarget 返回 false (即 foundThisFrame 为 false),
|
||||
// _currentlyTrackedTargetId 暂时不清除,而是由 Update 方法中的 _lockModeTargetLostTimer 机制来决定何时因超时而真正丢失目标并切换模式。
|
||||
// 此时 _currentlyTrackedTargetId 仍然保留,以便在容限时间内如果目标重现,可以继续锁定。
|
||||
Debug.WriteLine($"[IR IMAGING LOCK] 锁定目标 {_currentlyTrackedTargetId} 在本帧未被找到。等待容限超时...");
|
||||
}
|
||||
}
|
||||
|
||||
HasTarget = foundThisFrame; // HasTarget 反映的是本帧是否成功探测/识别/跟踪到目标
|
||||
return foundThisFrame; // 返回本帧的探测/跟踪状态
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 检查目标是否被烟幕完全遮挡
|
||||
/// </summary>
|
||||
/// <param name="observerPosition">观察者位置(导弹)</param>
|
||||
/// <param name="target">目标</param>
|
||||
/// <returns>如果目标被烟幕遮挡超过阈值,返回true</returns>
|
||||
private bool CheckIfTargetObscuredBySmoke(Vector3D observerPosition, BaseEquipment target)
|
||||
private (bool IsGeometricallyObscured, double OverallTransmittance) EvaluateSmokeImpact(Vector3D observerPosition, BaseEquipment target)
|
||||
{
|
||||
// 获取所有活动的烟幕弹
|
||||
var smokeGrenades = SimulationManager.GetEntitiesByType<SmokeGrenade>()
|
||||
.Where(sg => sg.IsActive && sg.config != null)
|
||||
.ToList();
|
||||
|
||||
if (smokeGrenades.Count == 0)
|
||||
double overallTransmittance = 1.0;
|
||||
bool isGeometricallyObscured = false;
|
||||
|
||||
var activeSmokeGrenades = SimulationManager.GetEntitiesByType<SmokeGrenade>()
|
||||
.Where(sg => sg.IsActive && sg.config != null)
|
||||
.ToList();
|
||||
|
||||
if (!activeSmokeGrenades.Any())
|
||||
{
|
||||
return false; // 没有活动的烟幕
|
||||
return (false, 1.0); // 没有活动的烟幕,无遮挡,全透过
|
||||
}
|
||||
|
||||
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)
|
||||
// 1. 几何遮挡检查
|
||||
if (!isGeometricallyObscured)
|
||||
{
|
||||
return 0.0;
|
||||
try
|
||||
{
|
||||
Vector3D smokeDims;
|
||||
if (smokeGrenade.config.SmokeType == SmokeScreenType.Cloud)
|
||||
{
|
||||
smokeDims = new Vector3D(smokeGrenade.config.CloudDiameter, smokeGrenade.config.Thickness, smokeGrenade.config.CloudDiameter);
|
||||
}
|
||||
else // Wall
|
||||
{
|
||||
smokeDims = new Vector3D(smokeGrenade.config.Thickness, smokeGrenade.config.WallHeight, smokeGrenade.config.WallWidth);
|
||||
}
|
||||
|
||||
double overlapRatio = ObscurationUtils.CalculateProjectedOverlapRatio(
|
||||
observerPosition,
|
||||
smokeGrenade.KState.Position, smokeDims, smokeGrenade.KState.Orientation,
|
||||
targetCenter, targetDims, targetOrient
|
||||
);
|
||||
|
||||
if (overlapRatio >= ObscurationThreshold)
|
||||
{
|
||||
isGeometricallyObscured = true;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.WriteLine($"[红外成像制导系统 Eval] 计算烟幕几何遮挡时出错: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
// 2. 透过率计算
|
||||
if (smokeGrenade.IsJamming)
|
||||
{
|
||||
double transmittanceForThisSmoke = smokeGrenade.GetSmokeTransmittanceOnLine(observerPosition, targetCenter, config.Wavelength);
|
||||
overallTransmittance *= transmittanceForThisSmoke;
|
||||
}
|
||||
}
|
||||
return Math.Max(0.0, totalTransmittance); //确保不为负
|
||||
|
||||
if (overallTransmittance < 0.001)
|
||||
{
|
||||
overallTransmittance = 0.0;
|
||||
}
|
||||
|
||||
return (isGeometricallyObscured, Math.Max(0.0, overallTransmittance));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -578,8 +765,11 @@ namespace ThreatSource.Guidance
|
||||
{
|
||||
var statusInfo = base.GetStatusInfo();
|
||||
string lastPosStr = LastTargetPosition.HasValue ? LastTargetPosition.Value.ToString() : "null";
|
||||
statusInfo.ExtendedProperties["Mode"] = currentMode.ToString();
|
||||
statusInfo.ExtendedProperties["lastPosStr"] = lastPosStr;
|
||||
statusInfo.ExtendedProperties["HasTarget"] = HasTarget.ToString();
|
||||
return statusInfo;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -61,6 +61,31 @@ namespace ThreatSource.Guidance
|
||||
/// </summary>
|
||||
private readonly Dictionary<EquipmentType, TargetFeature> targetFeatures;
|
||||
|
||||
/// <summary>
|
||||
/// 目标图像最小宽度阈值
|
||||
/// </summary>
|
||||
private const int MIN_WIDTH_THRESHOLD = 10;
|
||||
|
||||
/// <summary>
|
||||
/// 目标图像最小高度阈值
|
||||
/// </summary>
|
||||
private const int MIN_HEIGHT_THRESHOLD = 5;
|
||||
|
||||
/// <summary>
|
||||
/// Blob最大面积占比阈值
|
||||
/// </summary>
|
||||
private const double BLOB_MAX_AREA_RATIO_THRESHOLD = 0.75;
|
||||
|
||||
/// <summary>
|
||||
/// Blob最小面积阈值
|
||||
/// </summary>
|
||||
private const int BLOB_MIN_AREA_THRESHOLD = 10;
|
||||
|
||||
/// <summary>
|
||||
/// 烟幕覆盖率阈值
|
||||
/// </summary>
|
||||
private const double SMOKE_COVERAGE_THRESHOLD = 0.75;
|
||||
|
||||
/// <summary>
|
||||
/// 初始化红外图像目标识别器
|
||||
/// </summary>
|
||||
@ -71,19 +96,16 @@ namespace ThreatSource.Guidance
|
||||
{
|
||||
{ EquipmentType.Tank, new TargetFeature(
|
||||
aspectRatio: 2.9, // 典型主战坦克长宽比
|
||||
size: 1.0, // 基准尺寸
|
||||
intensityPattern: 0.5, // 热量集中分布
|
||||
temperatureGradient: 0.3 // 高温度梯度
|
||||
)},
|
||||
{ EquipmentType.APC, new TargetFeature(
|
||||
aspectRatio: 2.1, // 较短的车身
|
||||
size: 0.7, // 相对坦克尺寸
|
||||
intensityPattern: 0.8, // 均匀热分布
|
||||
temperatureGradient: 0.8 // 中等温度梯度
|
||||
)},
|
||||
{ EquipmentType.Helicopter, new TargetFeature(
|
||||
aspectRatio: 4.8, // 考虑旋翼长度
|
||||
size: 1.4, // 较大的整体尺寸
|
||||
intensityPattern: 0.8, // 发动机热量集中
|
||||
temperatureGradient: 0.8 // 较低的温度梯度
|
||||
)}
|
||||
@ -107,17 +129,15 @@ namespace ThreatSource.Guidance
|
||||
}
|
||||
|
||||
// 检查目标区域尺寸是否足够大
|
||||
int minRequiredWidth = 10;
|
||||
int minRequiredHeight = 5;
|
||||
if (segment.Size.Width < minRequiredWidth && segment.Size.Height < minRequiredHeight)
|
||||
if (segment.Size.Width < MIN_WIDTH_THRESHOLD && segment.Size.Height < MIN_HEIGHT_THRESHOLD)
|
||||
{
|
||||
Debug.WriteLine($"目标区域过小: {segment.Size.Width}x{segment.Size.Height} 像素,低于最小要求 {minRequiredWidth}x{minRequiredHeight}");
|
||||
Debug.WriteLine($"目标区域过小: {segment.Size.Width}x{segment.Size.Height} 像素,低于最小要求 {MIN_WIDTH_THRESHOLD}x{MIN_HEIGHT_THRESHOLD}");
|
||||
return new RecognitionResult(EquipmentType.Unknown, 0.0, segment.Center, segment.Size);
|
||||
}
|
||||
|
||||
// 提取目标特征
|
||||
var features = ExtractFeatures(image, segment, target);
|
||||
Debug.WriteLine($"提取的特征: 长宽比={features.AspectRatio:F2}, 尺寸={features.Size:F2}, 强度模式={features.IntensityPattern:F2}, 温度梯度={features.TemperatureGradient:F2}");
|
||||
Debug.WriteLine($"提取的特征: 长宽比={features.AspectRatio:F2}, 强度模式={features.IntensityPattern:F2}, 温度梯度={features.TemperatureGradient:F2}");
|
||||
|
||||
// 特征匹配和分类
|
||||
var (type, confidence) = ClassifyTarget(features);
|
||||
@ -157,7 +177,7 @@ namespace ThreatSource.Guidance
|
||||
var currentBlob = new Blob
|
||||
{
|
||||
Label = blobs.Count + 1,
|
||||
Pixels = new List<(int x, int y)>(),
|
||||
Pixels = [],
|
||||
MinX = x, MinY = y, MaxX = x, MaxY = y
|
||||
};
|
||||
|
||||
@ -201,17 +221,15 @@ namespace ThreatSource.Guidance
|
||||
Debug.WriteLine($"发现 {blobs.Count} 个 Blobs");
|
||||
|
||||
// 2. 过滤 Blobs
|
||||
List<Blob> filteredBlobs = new List<Blob>();
|
||||
int minArea = 10; // 最小面积阈值 (过滤噪声)
|
||||
int maxArea = (int)(width * height * 0.25); // 最大面积阈值 (过滤背景或巨大干扰, 25%)
|
||||
const double SMOKE_COVERAGE_THRESHOLD = 0.75; // 烟幕覆盖率阈值
|
||||
List<Blob> filteredBlobs = [];
|
||||
int maxArea = (int)(width * height * BLOB_MAX_AREA_RATIO_THRESHOLD); // 最大面积阈值 (过滤背景或巨大干扰, 25%)
|
||||
|
||||
foreach (var blob in blobs)
|
||||
{
|
||||
// 检查面积
|
||||
if (blob.Area < minArea || blob.Area > maxArea)
|
||||
if (blob.Area < BLOB_MIN_AREA_THRESHOLD || blob.Area > maxArea)
|
||||
{
|
||||
Debug.WriteLine($" Blob {blob.Label} 因面积 ({blob.Area}) 不符被过滤 (允许范围: {minArea}-{maxArea})");
|
||||
Debug.WriteLine($" Blob {blob.Label} 因面积 ({blob.Area}) 不符被过滤 (允许范围: {BLOB_MIN_AREA_THRESHOLD}-{maxArea})");
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -342,7 +360,7 @@ namespace ThreatSource.Guidance
|
||||
// 计算温度梯度特征
|
||||
double temperatureGradient = CalculateTemperatureGradient(image, segment, target);
|
||||
|
||||
return new TargetFeature(aspectRatio, relativeSize, intensityPattern, temperatureGradient);
|
||||
return new TargetFeature(aspectRatio, intensityPattern, temperatureGradient);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -644,21 +662,14 @@ namespace ThreatSource.Guidance
|
||||
private double[] CalculateFeatureWeights(TargetFeature features)
|
||||
{
|
||||
// 使用固定权重,基于特征的重要性
|
||||
// **重新平衡权重:降低梯度权重,提升形状和尺寸权重**
|
||||
return
|
||||
[
|
||||
0.30, // 长宽比权重 (原 0.15, 最初 0.3)
|
||||
0.20, // 相对尺寸权重 (原 0.15, 最初 0.2)
|
||||
0.25, // 强度模式权重 (原 0.20, 最初 0.25)
|
||||
0.25 // 温度梯度权重 (原 0.50, 最初 0.25)
|
||||
// 总和为 1.00
|
||||
];
|
||||
// 长宽比: 0.4, 强度模式: 0.3, 温度梯度: 0.3
|
||||
return [0.4, 0.3, 0.3];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 计算自适应阈值
|
||||
/// </summary>
|
||||
private double CalculateAdaptiveThreshold(TargetFeature features)
|
||||
private static double CalculateAdaptiveThreshold(TargetFeature features)
|
||||
{
|
||||
// 降低基准阈值,使用0.4作为基准
|
||||
double baseThreshold = 0.4;
|
||||
@ -666,10 +677,9 @@ namespace ThreatSource.Guidance
|
||||
// 计算特征质量因子
|
||||
double qualityFactor = (
|
||||
Math.Min(1.0, features.AspectRatio / 5.0) + // 长宽比质量(最大考虑5.0)
|
||||
Math.Min(1.0, features.Size / 1.5) + // 相对尺寸质量(最大考虑1.5)
|
||||
features.IntensityPattern + // 强度模式质量
|
||||
features.TemperatureGradient // 温度梯度质量
|
||||
) / 4.0;
|
||||
) / 3.0;
|
||||
|
||||
return baseThreshold * (0.8 + 0.4 * qualityFactor);
|
||||
}
|
||||
@ -681,22 +691,19 @@ namespace ThreatSource.Guidance
|
||||
{
|
||||
// 计算各个特征的匹配度,使用相对误差
|
||||
double aspectRatioScore = 1 - Math.Min(1, Math.Abs(features.AspectRatio - template.AspectRatio) / Math.Max(features.AspectRatio, template.AspectRatio));
|
||||
double sizeScore = 1 - Math.Min(1, Math.Abs(features.Size - template.Size) / Math.Max(features.Size, template.Size));
|
||||
double patternScore = 1 - Math.Min(1, Math.Abs(features.IntensityPattern - template.IntensityPattern));
|
||||
double gradientScore = 1 - Math.Min(1, Math.Abs(features.TemperatureGradient - template.TemperatureGradient));
|
||||
|
||||
// 输出详细的匹配分数
|
||||
Debug.WriteLine($"特征匹配得分:");
|
||||
Debug.WriteLine($" 长宽比: {aspectRatioScore:F2} (权重: {weights[0]:F2})");
|
||||
Debug.WriteLine($" 尺寸: {sizeScore:F2} (权重: {weights[1]:F2})");
|
||||
Debug.WriteLine($" 模式: {patternScore:F2} (权重: {weights[2]:F2})");
|
||||
Debug.WriteLine($" 梯度: {gradientScore:F2} (权重: {weights[3]:F2})");
|
||||
Debug.WriteLine($" 模式: {patternScore:F2} (权重: {weights[1]:F2})");
|
||||
Debug.WriteLine($" 梯度: {gradientScore:F2} (权重: {weights[2]:F2})");
|
||||
|
||||
// 加权平均
|
||||
double totalScore = aspectRatioScore * weights[0] +
|
||||
sizeScore * weights[1] +
|
||||
patternScore * weights[2] +
|
||||
gradientScore * weights[3];
|
||||
patternScore * weights[1] +
|
||||
gradientScore * weights[2];
|
||||
|
||||
Debug.WriteLine($" 总得分: {totalScore:F2}");
|
||||
return totalScore;
|
||||
@ -707,19 +714,16 @@ namespace ThreatSource.Guidance
|
||||
/// </summary>
|
||||
private struct TargetFeature
|
||||
{
|
||||
public double AspectRatio { get; } // 长宽比
|
||||
public double Size { get; } // 特征尺寸
|
||||
public double IntensityPattern { get; } // 强度模式特征
|
||||
public double TemperatureGradient { get; } // 温度梯度特征
|
||||
public double AspectRatio { get; }
|
||||
public double IntensityPattern { get; }
|
||||
public double TemperatureGradient { get; }
|
||||
|
||||
public TargetFeature(
|
||||
double aspectRatio,
|
||||
double size,
|
||||
double intensityPattern,
|
||||
double temperatureGradient)
|
||||
{
|
||||
AspectRatio = aspectRatio;
|
||||
Size = size;
|
||||
IntensityPattern = intensityPattern;
|
||||
TemperatureGradient = temperatureGradient;
|
||||
}
|
||||
|
||||
@ -119,7 +119,10 @@ namespace ThreatSource.Guidance
|
||||
/// </summary>
|
||||
private double MaxScanRadius => config.FieldOfViewAngle * Math.PI / 180.0 / 2;
|
||||
|
||||
private const double SpeedOfLight = 299792458.0; // m/s
|
||||
/// <summary>
|
||||
/// 光速,单位:m/s
|
||||
/// </summary>
|
||||
private const double LIGHT_SPEED = 299792458.0; // 光速 m/s
|
||||
|
||||
/// <summary>
|
||||
/// Swerling模型实例
|
||||
@ -332,7 +335,7 @@ namespace ThreatSource.Guidance
|
||||
}
|
||||
|
||||
// 更新扫描周期计时器
|
||||
if (scanCycleTimer < 360 / config.ScanAngularSpeedDeg)
|
||||
if (scanCycleTimer < config.FieldOfViewAngle / config.ScanAngularSpeedDeg)
|
||||
{
|
||||
scanCycleTimer += deltaTime;
|
||||
}
|
||||
@ -625,7 +628,6 @@ namespace ThreatSource.Guidance
|
||||
|
||||
// 采用Swerling模型计算RCS
|
||||
rcsLinear = swerlingRcsModel.GetRealtimeRcs(target.Id, target.Properties.Type, motionState, rcsLinear, false);
|
||||
|
||||
Debug.WriteLine($"[RCS获取-Swerling模型] Target {target.Id}: RCS_Linear: {rcsLinear} ");
|
||||
|
||||
double snr_dB = CalculateSNR(distance, rcsLinear, liveSmokeTransmittance);
|
||||
@ -775,9 +777,9 @@ namespace ThreatSource.Guidance
|
||||
double antennaGain = Math.Pow(10, config.AntennaGainDB/10);
|
||||
|
||||
// 波长,单位:米 (m),用于雷达方程核心计算
|
||||
double wavelength_m = SpeedOfLight / config.WaveFrequency;
|
||||
double wavelength_m = LIGHT_SPEED / config.WaveFrequency;
|
||||
// 波长,单位:微米 (µm),用于需要微米单位的函数调用
|
||||
double wavelength_um = SpeedOfLight / config.WaveFrequency * 1e6;
|
||||
double wavelength_um = LIGHT_SPEED / config.WaveFrequency * 1e6;
|
||||
|
||||
double bandwidth = 1.0 / config.PulseDuration;
|
||||
double noiseFigure = Math.Pow(10, config.NoiseFigureDB/10);
|
||||
@ -853,7 +855,7 @@ namespace ThreatSource.Guidance
|
||||
return 1.0;
|
||||
}
|
||||
|
||||
double wavelength_um = SpeedOfLight / config.WaveFrequency * 1e6;
|
||||
double wavelength_um = LIGHT_SPEED / config.WaveFrequency * 1e6;
|
||||
|
||||
if (wavelength_um <= 0) {
|
||||
Trace.TraceInformation("[毫米波制导] 计算波长为米时无效. 假设没有烟幕影响.");
|
||||
|
||||
@ -37,11 +37,9 @@ namespace ThreatSource.Missile
|
||||
/// </remarks>
|
||||
private enum IRTG_Stage
|
||||
{
|
||||
Launch, // 发射阶段
|
||||
Cruise, // 巡航阶段
|
||||
TerminalSearch, // 末制导搜索阶段
|
||||
TerminalTrack, // 末制导跟踪阶段
|
||||
TerminalLock // 末制导锁定阶段
|
||||
Launch, // 发射阶段
|
||||
Cruise, // 巡航阶段
|
||||
Terminal // 末制导
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -130,14 +128,8 @@ namespace ThreatSource.Missile
|
||||
case IRTG_Stage.Cruise:
|
||||
UpdateCruiseStage(deltaTime);
|
||||
break;
|
||||
case IRTG_Stage.TerminalSearch:
|
||||
UpdateTerminalSearchStage(deltaTime);
|
||||
break;
|
||||
case IRTG_Stage.TerminalTrack:
|
||||
UpdateTerminalTrackStage(deltaTime);
|
||||
break;
|
||||
case IRTG_Stage.TerminalLock:
|
||||
UpdateTerminalLockStage(deltaTime);
|
||||
case IRTG_Stage.Terminal:
|
||||
UpdateTerminalStage(deltaTime);
|
||||
break;
|
||||
}
|
||||
base.Update(deltaTime);
|
||||
@ -157,7 +149,7 @@ namespace ThreatSource.Missile
|
||||
private void UpdateLaunchStage(double deltaTime)
|
||||
{
|
||||
GuidanceAcceleration = Vector3D.Zero;
|
||||
if (FlightTime > Properties.MaxEngineBurnTime) // 假设发射阶段持续1秒
|
||||
if (FlightTime > Properties.MaxEngineBurnTime)
|
||||
{
|
||||
currentStage = IRTG_Stage.Cruise;
|
||||
}
|
||||
@ -178,10 +170,8 @@ namespace ThreatSource.Missile
|
||||
// 如果巡航时间达到,切换到末制导搜索阶段
|
||||
if (FlightTime > Properties.CruiseTime)
|
||||
{
|
||||
currentStage = IRTG_Stage.TerminalSearch;
|
||||
guidanceSystem.Activate(); // 激活制导系统
|
||||
guidanceSystem.SwitchToSearchMode(); // 切换到搜索模式
|
||||
currentStage = IRTG_Stage.TerminalSearch;
|
||||
currentStage = IRTG_Stage.Terminal;
|
||||
guidanceSystem.Activate();
|
||||
}
|
||||
}
|
||||
|
||||
@ -190,72 +180,16 @@ namespace ThreatSource.Missile
|
||||
/// </summary>
|
||||
/// <param name="deltaTime">时间步长,单位:秒</param>
|
||||
/// <remarks>
|
||||
/// 搜索阶段特点:
|
||||
/// - 大视场角(6-8度)搜索目标
|
||||
/// - 进行目标检测和初步识别
|
||||
/// - 发现目标后切换到跟踪阶段
|
||||
/// 末制导阶段特点:
|
||||
/// - 完全依赖导航系统的工作模式
|
||||
/// - 根据导航系统状态更新制导
|
||||
/// - 持续到命中目标
|
||||
/// </remarks>
|
||||
private void UpdateTerminalSearchStage(double deltaTime)
|
||||
private void UpdateTerminalStage(double deltaTime)
|
||||
{
|
||||
guidanceSystem.Update(deltaTime);
|
||||
GuidanceAcceleration = guidanceSystem.GetGuidanceAcceleration();
|
||||
IsGuidance = guidanceSystem.HasGuidance;
|
||||
|
||||
// 如果发现并识别出目标,切换到跟踪阶段
|
||||
if (guidanceSystem.HasTarget)
|
||||
{
|
||||
currentStage = IRTG_Stage.TerminalTrack;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更新末制导跟踪阶段的状态
|
||||
/// </summary>
|
||||
/// <param name="deltaTime">时间步长,单位:秒</param>
|
||||
/// <remarks>
|
||||
/// 跟踪阶段特点:
|
||||
/// - 小视场角(2-3度)精确跟踪
|
||||
/// - 高精度目标识别和特征提取
|
||||
/// - 目标确认后切换到锁定阶段
|
||||
/// - 如果失去目标则返回搜索阶段
|
||||
/// </remarks>
|
||||
private void UpdateTerminalTrackStage(double deltaTime)
|
||||
{
|
||||
guidanceSystem.Update(deltaTime);
|
||||
GuidanceAcceleration = guidanceSystem.GetGuidanceAcceleration();
|
||||
IsGuidance = guidanceSystem.HasGuidance;
|
||||
|
||||
// 如果失去目标,切换回搜索阶段
|
||||
if (!guidanceSystem.HasTarget)
|
||||
{
|
||||
currentStage = IRTG_Stage.TerminalSearch;
|
||||
}
|
||||
// 当制导系统进入锁定模式时,导弹也切换到锁定阶段
|
||||
else if (guidanceSystem.IsInLockMode)
|
||||
{
|
||||
currentStage = IRTG_Stage.TerminalLock;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更新末制导锁定阶段的状态
|
||||
/// </summary>
|
||||
/// <param name="deltaTime">时间步长,单位:秒</param>
|
||||
/// <remarks>
|
||||
/// 锁定阶段特点:
|
||||
/// - 目标类型已确认
|
||||
/// - 专注于位置跟踪
|
||||
/// - 如果失去目标则返回搜索阶段
|
||||
/// </remarks>
|
||||
private void UpdateTerminalLockStage(double deltaTime)
|
||||
{
|
||||
guidanceSystem.Update(deltaTime);
|
||||
GuidanceAcceleration = guidanceSystem.GetGuidanceAcceleration();
|
||||
IsGuidance = guidanceSystem.HasGuidance;
|
||||
if (!guidanceSystem.HasTarget)
|
||||
{
|
||||
currentStage = IRTG_Stage.TerminalSearch;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@ -494,14 +494,14 @@ namespace ThreatSource.Simulation
|
||||
public double MaxDetectionRange { get; set; } = 1000; // 默认1公里
|
||||
|
||||
/// <summary>
|
||||
/// 搜索模式视场角,单位:弧度
|
||||
/// 搜索模式视场角,单位:度
|
||||
/// </summary>
|
||||
public double SearchFieldOfView { get; set; } = Math.PI / 15; // 默认12度
|
||||
public double SearchFieldOfView { get; set; } = 12.0; // 默认12度
|
||||
|
||||
/// <summary>
|
||||
/// 跟踪模式视场角,单位:弧度
|
||||
/// 跟踪模式视场角,单位:度
|
||||
/// </summary>
|
||||
public double TrackFieldOfView { get; set; } = Math.PI / 60; // 默认3度
|
||||
public double TrackFieldOfView { get; set; } = 3.0; // 默认3度
|
||||
|
||||
/// <summary>
|
||||
/// 图像宽度,单位:像素
|
||||
@ -567,6 +567,8 @@ namespace ThreatSource.Simulation
|
||||
public InfraredImagingGuidanceConfig()
|
||||
{
|
||||
// 使用属性初始化器设置的默认值
|
||||
// SearchFieldOfView 默认 12.0 度
|
||||
// TrackFieldOfView 默认 3.0 度
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1105,7 +1105,7 @@ namespace ThreatSource.Tools.MissileSimulation
|
||||
double simulationTime = simulationManager.CurrentTime;
|
||||
var weather = simulationManager.CurrentWeather;
|
||||
|
||||
Console.WriteLine($"\n========== 模拟状态 (时间: {simulationTime:F1}s)==========");
|
||||
Console.WriteLine($"\n========== 模拟状态 (时间: {simulationTime:F3}s)==========");
|
||||
|
||||
// 天气状态
|
||||
Console.WriteLine("\n--- 天气状态 ---");
|
||||
|
||||
Loading…
Reference in New Issue
Block a user