完善了红外成像制导的搜索和跟踪机制(滑动窗口),修改了特征提取和目标识别算法

This commit is contained in:
Tian jianyong 2025-05-21 01:23:58 +08:00
parent f6ff47f2b4
commit a780126d32
9 changed files with 500 additions and 368 deletions

View File

@ -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 或类似单位)

View File

@ -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

View File

@ -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 # 扫描半径增长率 (度)

View File

@ -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;
}
}
}

View File

@ -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;
}

View File

@ -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("[毫米波制导] 计算波长为米时无效. 假设没有烟幕影响.");

View File

@ -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>

View File

@ -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 度
}
}

View File

@ -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--- 天气状态 ---");