From a780126d3277a3626c092e7f69a5b2aecc25ffdd Mon Sep 17 00:00:00 2001
From: Tian jianyong <11429339@qq.com>
Date: Wed, 21 May 2025 01:23:58 +0800
Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E5=96=84=E4=BA=86=E7=BA=A2=E5=A4=96?=
=?UTF-8?q?=E6=88=90=E5=83=8F=E5=88=B6=E5=AF=BC=E7=9A=84=E6=90=9C=E7=B4=A2?=
=?UTF-8?q?=E5=92=8C=E8=B7=9F=E8=B8=AA=E6=9C=BA=E5=88=B6=EF=BC=88=E6=BB=91?=
=?UTF-8?q?=E5=8A=A8=E7=AA=97=E5=8F=A3=EF=BC=89=EF=BC=8C=E4=BF=AE=E6=94=B9?=
=?UTF-8?q?=E4=BA=86=E7=89=B9=E5=BE=81=E6=8F=90=E5=8F=96=E5=92=8C=E7=9B=AE?=
=?UTF-8?q?=E6=A0=87=E8=AF=86=E5=88=AB=E7=AE=97=E6=B3=95?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../data/missiles/composite/cg_001.toml | 42 +-
.../data/missiles/ir_imaging/itg_001.toml | 12 +-
ThreatSource/data/missiles/mmw/mmw_001.toml | 8 +-
.../Guidance/InfraredImagingGuidanceSystem.cs | 602 ++++++++++++------
.../src/Guidance/InfraredTargetRecognizer.cs | 86 +--
.../Guidance/MillimeterWaveGuidanceSystem.cs | 14 +-
.../InfraredImagingTerminalGuidedMissile.cs | 92 +--
.../src/Simulation/SimulationConfig.cs | 10 +-
tools/ComprehensiveMissileSimulator.cs | 2 +-
9 files changed, 500 insertions(+), 368 deletions(-)
diff --git a/ThreatSource/data/missiles/composite/cg_001.toml b/ThreatSource/data/missiles/composite/cg_001.toml
index fb8c5b3..87227bb 100644
--- a/ThreatSource/data/missiles/composite/cg_001.toml
+++ b/ThreatSource/data/missiles/composite/cg_001.toml
@@ -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 或类似单位)
diff --git a/ThreatSource/data/missiles/ir_imaging/itg_001.toml b/ThreatSource/data/missiles/ir_imaging/itg_001.toml
index bc8c951..bab81e3 100644
--- a/ThreatSource/data/missiles/ir_imaging/itg_001.toml
+++ b/ThreatSource/data/missiles/ir_imaging/itg_001.toml
@@ -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
\ No newline at end of file
diff --git a/ThreatSource/data/missiles/mmw/mmw_001.toml b/ThreatSource/data/missiles/mmw/mmw_001.toml
index 8982a9b..ff00ce9 100644
--- a/ThreatSource/data/missiles/mmw/mmw_001.toml
+++ b/ThreatSource/data/missiles/mmw/mmw_001.toml
@@ -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 # 扫描半径增长率 (度)
diff --git a/ThreatSource/src/Guidance/InfraredImagingGuidanceSystem.cs b/ThreatSource/src/Guidance/InfraredImagingGuidanceSystem.cs
index c5b08ba..b4ce3b6 100644
--- a/ThreatSource/src/Guidance/InfraredImagingGuidanceSystem.cs
+++ b/ThreatSource/src/Guidance/InfraredImagingGuidanceSystem.cs
@@ -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
///
public bool HasTarget { get; private set; }
- ///
- /// 当前是否处于锁定模式
- ///
- public bool IsInLockMode => currentMode == WorkMode.Lock;
-
///
/// 上一次探测到的目标位置 (使用可空类型)
///
@@ -67,7 +65,7 @@ namespace ThreatSource.Guidance
/// 记录目标的历史位置
/// 用于计算目标速度
///
- private Vector3D? LastTargetPosition { get; set; } // Changed to nullable Vector3D?
+ private Vector3D? LastTargetPosition { get; set; }
///
/// 红外图像生成器
@@ -89,16 +87,41 @@ namespace ThreatSource.Guidance
///
private readonly InfraredImagingGuidanceConfig config;
- ///
- /// 目标丢失计时器
- ///
- private double targetLostTimer = 0;
-
///
/// 锁定确认计时器
///
private double lockConfirmationTimer = 0;
+ ///
+ /// 当前正在跟踪或已锁定的目标ID
+ ///
+ private string? _currentlyTrackedTargetId;
+
+ ///
+ /// Search模式下当前关注的候选目标ID
+ ///
+ private string? _searchModeFocusCandidateId;
+
+ ///
+ /// 当前活动模式 (搜索焦点或跟踪稳定) 的识别历史队列
+ ///
+ private Queue _activeRecognitionHistory = new();
+
+ ///
+ /// 识别历史窗口大小 (搜索和跟踪阶段共用)
+ ///
+ private const int COMMON_RECOGNITION_WINDOW_SIZE = 10;
+
+ ///
+ /// 识别成功率阈值 (搜索切换和跟踪稳定性判断共用, 例如80%)
+ ///
+ private const double COMMON_RECOGNITION_SUCCESS_RATE_THRESHOLD = 0.8;
+
+ ///
+ /// 锁定模式下目标丢失计时器
+ ///
+ private double _lockModeTargetLostTimer = 0;
+
///
/// 初始化红外成像制导系统的新实例
///
@@ -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模式计时器)处理
}
///
@@ -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} 度");
}
///
@@ -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} 度");
}
///
@@ -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())
{
- 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; // 返回本帧的探测/跟踪状态
}
- ///
- /// 检查目标是否被烟幕完全遮挡
- ///
- /// 观察者位置(导弹)
- /// 目标
- /// 如果目标被烟幕遮挡超过阈值,返回true
- private bool CheckIfTargetObscuredBySmoke(Vector3D observerPosition, BaseEquipment target)
+ private (bool IsGeometricallyObscured, double OverallTransmittance) EvaluateSmokeImpact(Vector3D observerPosition, BaseEquipment target)
{
- // 获取所有活动的烟幕弹
- var smokeGrenades = SimulationManager.GetEntitiesByType()
- .Where(sg => sg.IsActive && sg.config != null)
- .ToList();
-
- if (smokeGrenades.Count == 0)
+ double overallTransmittance = 1.0;
+ bool isGeometricallyObscured = false;
+
+ var activeSmokeGrenades = SimulationManager.GetEntitiesByType()
+ .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; // 没有烟幕能有效遮挡目标
- }
-
- ///
- /// 计算给定观察点和目标点之间的总烟幕透过率
- ///
- /// 观察者位置
- /// 目标位置
- /// 总透过率 (0.0 到 1.0)
- private double CalculateLiveSmokeTransmittance(Vector3D observerPosition, Vector3D targetEndPosition)
- {
- double totalTransmittance = 1.0;
- var activeSmokeGrenades = SimulationManager.GetEntitiesByType()
- .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));
}
///
@@ -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;
}
}
}
+
diff --git a/ThreatSource/src/Guidance/InfraredTargetRecognizer.cs b/ThreatSource/src/Guidance/InfraredTargetRecognizer.cs
index 143e699..71dbc1c 100644
--- a/ThreatSource/src/Guidance/InfraredTargetRecognizer.cs
+++ b/ThreatSource/src/Guidance/InfraredTargetRecognizer.cs
@@ -61,6 +61,31 @@ namespace ThreatSource.Guidance
///
private readonly Dictionary targetFeatures;
+ ///
+ /// 目标图像最小宽度阈值
+ ///
+ private const int MIN_WIDTH_THRESHOLD = 10;
+
+ ///
+ /// 目标图像最小高度阈值
+ ///
+ private const int MIN_HEIGHT_THRESHOLD = 5;
+
+ ///
+ /// Blob最大面积占比阈值
+ ///
+ private const double BLOB_MAX_AREA_RATIO_THRESHOLD = 0.75;
+
+ ///
+ /// Blob最小面积阈值
+ ///
+ private const int BLOB_MIN_AREA_THRESHOLD = 10;
+
+ ///
+ /// 烟幕覆盖率阈值
+ ///
+ private const double SMOKE_COVERAGE_THRESHOLD = 0.75;
+
///
/// 初始化红外图像目标识别器
///
@@ -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 filteredBlobs = new List();
- int minArea = 10; // 最小面积阈值 (过滤噪声)
- int maxArea = (int)(width * height * 0.25); // 最大面积阈值 (过滤背景或巨大干扰, 25%)
- const double SMOKE_COVERAGE_THRESHOLD = 0.75; // 烟幕覆盖率阈值
+ List 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);
}
///
@@ -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];
}
///
/// 计算自适应阈值
///
- 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
///
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;
}
diff --git a/ThreatSource/src/Guidance/MillimeterWaveGuidanceSystem.cs b/ThreatSource/src/Guidance/MillimeterWaveGuidanceSystem.cs
index 9467a3c..c82782d 100644
--- a/ThreatSource/src/Guidance/MillimeterWaveGuidanceSystem.cs
+++ b/ThreatSource/src/Guidance/MillimeterWaveGuidanceSystem.cs
@@ -119,7 +119,10 @@ namespace ThreatSource.Guidance
///
private double MaxScanRadius => config.FieldOfViewAngle * Math.PI / 180.0 / 2;
- private const double SpeedOfLight = 299792458.0; // m/s
+ ///
+ /// 光速,单位:m/s
+ ///
+ private const double LIGHT_SPEED = 299792458.0; // 光速 m/s
///
/// 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("[毫米波制导] 计算波长为米时无效. 假设没有烟幕影响.");
diff --git a/ThreatSource/src/MIssile/InfraredImagingTerminalGuidedMissile.cs b/ThreatSource/src/MIssile/InfraredImagingTerminalGuidedMissile.cs
index ee5d6d6..286b3c8 100644
--- a/ThreatSource/src/MIssile/InfraredImagingTerminalGuidedMissile.cs
+++ b/ThreatSource/src/MIssile/InfraredImagingTerminalGuidedMissile.cs
@@ -37,11 +37,9 @@ namespace ThreatSource.Missile
///
private enum IRTG_Stage
{
- Launch, // 发射阶段
- Cruise, // 巡航阶段
- TerminalSearch, // 末制导搜索阶段
- TerminalTrack, // 末制导跟踪阶段
- TerminalLock // 末制导锁定阶段
+ Launch, // 发射阶段
+ Cruise, // 巡航阶段
+ Terminal // 末制导
}
///
@@ -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
///
/// 时间步长,单位:秒
///
- /// 搜索阶段特点:
- /// - 大视场角(6-8度)搜索目标
- /// - 进行目标检测和初步识别
- /// - 发现目标后切换到跟踪阶段
+ /// 末制导阶段特点:
+ /// - 完全依赖导航系统的工作模式
+ /// - 根据导航系统状态更新制导
+ /// - 持续到命中目标
///
- 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;
- }
- }
-
- ///
- /// 更新末制导跟踪阶段的状态
- ///
- /// 时间步长,单位:秒
- ///
- /// 跟踪阶段特点:
- /// - 小视场角(2-3度)精确跟踪
- /// - 高精度目标识别和特征提取
- /// - 目标确认后切换到锁定阶段
- /// - 如果失去目标则返回搜索阶段
- ///
- 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;
- }
- }
-
- ///
- /// 更新末制导锁定阶段的状态
- ///
- /// 时间步长,单位:秒
- ///
- /// 锁定阶段特点:
- /// - 目标类型已确认
- /// - 专注于位置跟踪
- /// - 如果失去目标则返回搜索阶段
- ///
- private void UpdateTerminalLockStage(double deltaTime)
- {
- guidanceSystem.Update(deltaTime);
- GuidanceAcceleration = guidanceSystem.GetGuidanceAcceleration();
- IsGuidance = guidanceSystem.HasGuidance;
- if (!guidanceSystem.HasTarget)
- {
- currentStage = IRTG_Stage.TerminalSearch;
- }
}
///
diff --git a/ThreatSource/src/Simulation/SimulationConfig.cs b/ThreatSource/src/Simulation/SimulationConfig.cs
index 850885e..b99105c 100644
--- a/ThreatSource/src/Simulation/SimulationConfig.cs
+++ b/ThreatSource/src/Simulation/SimulationConfig.cs
@@ -494,14 +494,14 @@ namespace ThreatSource.Simulation
public double MaxDetectionRange { get; set; } = 1000; // 默认1公里
///
- /// 搜索模式视场角,单位:弧度
+ /// 搜索模式视场角,单位:度
///
- public double SearchFieldOfView { get; set; } = Math.PI / 15; // 默认12度
+ public double SearchFieldOfView { get; set; } = 12.0; // 默认12度
///
- /// 跟踪模式视场角,单位:弧度
+ /// 跟踪模式视场角,单位:度
///
- public double TrackFieldOfView { get; set; } = Math.PI / 60; // 默认3度
+ public double TrackFieldOfView { get; set; } = 3.0; // 默认3度
///
/// 图像宽度,单位:像素
@@ -567,6 +567,8 @@ namespace ThreatSource.Simulation
public InfraredImagingGuidanceConfig()
{
// 使用属性初始化器设置的默认值
+ // SearchFieldOfView 默认 12.0 度
+ // TrackFieldOfView 默认 3.0 度
}
}
diff --git a/tools/ComprehensiveMissileSimulator.cs b/tools/ComprehensiveMissileSimulator.cs
index a165e84..e81f425 100644
--- a/tools/ComprehensiveMissileSimulator.cs
+++ b/tools/ComprehensiveMissileSimulator.cs
@@ -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--- 天气状态 ---");