From 5f76e5b067ba93d3705cb4137499947c71d9de75 Mon Sep 17 00:00:00 2001
From: Tian jianyong <11429339@qq.com>
Date: Thu, 22 May 2025 21:20:31 +0800
Subject: [PATCH] =?UTF-8?q?=E9=87=87=E7=94=A8=E6=BB=91=E5=8A=A8=E7=AA=97?=
=?UTF-8?q?=E5=8F=A3=E5=92=8C=E9=A2=84=E7=83=AD=E5=B8=A7=E6=9C=BA=E5=88=B6?=
=?UTF-8?q?=E5=AE=8C=E5=96=84=E4=BA=86=E6=AF=AB=E7=B1=B3=E6=B3=A2=E5=AF=BC?=
=?UTF-8?q?=E5=BC=95=E7=B3=BB=E7=BB=9F?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../data/missiles/composite/cg_001.toml | 18 +-
.../data/missiles/ir_imaging/itg_001.toml | 14 +-
ThreatSource/data/missiles/mmw/mmw_001.toml | 14 +-
.../Guidance/InfraredImagingGuidanceSystem.cs | 503 ++++++++----------
.../Guidance/MillimeterWaveGuidanceSystem.cs | 391 +++++++-------
.../src/MIssile/CompositeGuidedMissile.cs | 2 +-
.../InfraredImagingTerminalGuidedMissile.cs | 2 +-
.../MillimeterWaveTerminalGuidedMissile.cs | 2 +-
8 files changed, 449 insertions(+), 497 deletions(-)
diff --git a/ThreatSource/data/missiles/composite/cg_001.toml b/ThreatSource/data/missiles/composite/cg_001.toml
index 87227bb..13f5475 100644
--- a/ThreatSource/data/missiles/composite/cg_001.toml
+++ b/ThreatSource/data/missiles/composite/cg_001.toml
@@ -14,9 +14,9 @@ MaxAcceleration = 100.0
ProportionalNavigationCoefficient = 4.0
LaunchAcceleration = 100.0
MaxEngineBurnTime = 2.5
-CruiseTime = 5.0
+CruiseTime = 4.0
Mass = 25.0
-ExplosionRadius = 5.5
+ExplosionRadius = 5.0
HitProbability = 0.9
SelfDestructHeight = 0.0
InfraredRadiationIntensity = 96.0 # 红外辐射强度 (瓦特/球面度)
@@ -69,31 +69,23 @@ FieldOfViewAngle = 45.0 # 视场角 (度)
TargetRecognitionProbability = 0.95 # 目标识别概率
WaveFrequency = 9.4e10 # 波频率 (赫兹)
PulseDuration = 1.0e-6 # 脉冲持续时间 (秒)
-
SearchBeamWidth = 5.0 # 搜索波束宽度 (度)
-TrackBeamWidth = 3.0 # 跟踪波束宽度 (度)
-LockBeamWidth = 2.0 # 锁定波束宽度 (度)
-
+TrackBeamWidth = 4.0 # 跟踪波束宽度 (度)
+LockBeamWidth = 3.0 # 锁定波束宽度 (度)
ScanAngularSpeedDeg = 360.0 # 扫描角速度 (度/秒)
ScanRadiusGrowthRateDeg = 22.5 # 扫描半径增长率 (度)
-
RecognitionSNRThreshold = -25.0 # 识别信噪比阈值 (分贝)
LockSNRThreshold = -10.0 # 锁定信噪比阈值 (分贝)
-
TargetLostTolerance = 0.2 # 目标丢失容忍时间 (秒)
-LockConfirmationTime = 0.3 # 锁定确认时间 (秒)
-
+LockConfirmationTime = 0.3 # 锁定确认时间 (秒)
PulseRepetitionFrequency = 1.0e-4 # 脉冲重复间隔 (秒)
TransmitPower = 0.3 # 发射功率 (瓦特)
-
DopplerVelocityResolution = 1.0 # 多普勒速度分辨率 (米/秒)
MaxMeasurableVelocity = 1000.0 # 最大可测量速度 (米/秒)
-
AntennaGainDB = 23.0 # 天线增益 (分贝)
NoiseFigureDB = 7.0 # 噪声系数 (分贝)
SystemLossDB = 6.0 # 系统损耗 (分贝)
MonopulseSensitivity = 1.0 # 单脉冲灵敏度
-
YawControlEffectiveness = 120.0 # 偏航控制有效性 (度/秒^2 或类似单位)
PitchControlEffectiveness = 150.0 # 俯仰控制有效性 (度/秒^2 或类似单位)
JammingResistanceThreshold = 1.0e-5 # 干扰抗性阈值 (瓦特)
\ No newline at end of file
diff --git a/ThreatSource/data/missiles/ir_imaging/itg_001.toml b/ThreatSource/data/missiles/ir_imaging/itg_001.toml
index bab81e3..009cc69 100644
--- a/ThreatSource/data/missiles/ir_imaging/itg_001.toml
+++ b/ThreatSource/data/missiles/ir_imaging/itg_001.toml
@@ -14,24 +14,24 @@ MaxAcceleration = 100.0
ProportionalNavigationCoefficient = 4.0
LaunchAcceleration = 100.0
MaxEngineBurnTime = 2.5
-CruiseTime = 5.0
+CruiseTime = 4.0
Mass = 25.0
-ExplosionRadius = 5.5
+ExplosionRadius = 5.0
HitProbability = 0.9
SelfDestructHeight = 0.0
InfraredRadiationIntensity = 96.0 # 红外辐射强度 (瓦特/球面度)
UltravioletRadiationIntensity = 100.0 # 紫外辐射强度 (瓦特/球面度)
[InfraredImagingGuidanceConfig]
-MaxDetectionRange = 1000.0 # 最大探测距离 (米), JSON中为1000,对应C#默认为1000.0
-SearchFieldOfView = 12.0 # 搜索视场角 (度), 对应C#默认为12.0度
-TrackFieldOfView = 6.0 # 跟踪视场角 (度), 对应C#默认为3.0度
+MaxDetectionRange = 1000.0 # 最大探测距离 (米), 默认为1000.0
+SearchFieldOfView = 12.0 # 搜索视场角 (度), 默认为12.0度
+TrackFieldOfView = 6.0 # 跟踪视场角 (度), 默认为3.0度
ImageWidth = 640 # 图像宽度 (像素)
ImageHeight = 480 # 图像高度 (像素)
-BackgroundIntensity = 1.0e-4 # 背景辐射强度 (瓦特/球面度), JSON中为1e-4, C#默认为0.01
+BackgroundIntensity = 1.0e-4 # 背景辐射强度 (瓦特/球面度), 默认为1e-4
SearchRecognitionProbability = 0.6 # 搜索模式目标识别概率阈值
TrackRecognitionProbability = 0.8 # 跟踪模式目标识别概率阈值
TargetLostTolerance = 0.3 # 目标丢失容忍时间 (秒)
LockConfirmationTime = 0.5 # 锁定确认时间 (秒)
JammingResistanceThreshold = 1.0e-5 # 干扰抗性阈值 (瓦特)
-Wavelength = 3.0 # 波长 (微米), C#中属性名为Wavelength, JSON中为waveLength
\ No newline at end of file
+Wavelength = 3.0 # 波长 (微米)
\ 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 ff00ce9..f2352f3 100644
--- a/ThreatSource/data/missiles/mmw/mmw_001.toml
+++ b/ThreatSource/data/missiles/mmw/mmw_001.toml
@@ -28,31 +28,23 @@ FieldOfViewAngle = 45.0 # 视场角 (度)
TargetRecognitionProbability = 0.95 # 目标识别概率
WaveFrequency = 9.4e10 # 波频率 (赫兹, JSON中为94e9)
PulseDuration = 1.0e-6 # 脉冲持续时间 (秒)
-
SearchBeamWidth = 5.0 # 搜索波束宽度 (度)
-TrackBeamWidth = 3.0 # 跟踪波束宽度 (度)
-LockBeamWidth = 2.0 # 锁定波束宽度 (度)
-
+TrackBeamWidth = 4.0 # 跟踪波束宽度 (度)
+LockBeamWidth = 3.0 # 锁定波束宽度 (度)
ScanAngularSpeedDeg = 360.0 # 扫描角速度 (度/秒)
ScanRadiusGrowthRateDeg = 22.5 # 扫描半径增长率 (度)
-
RecognitionSNRThreshold = -25.0 # 识别信噪比阈值 (分贝)
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 # 多普勒速度分辨率 (米/秒)
MaxMeasurableVelocity = 1000.0 # 最大可测量速度 (米/秒)
-
AntennaGainDB = 23.0 # 天线增益 (分贝)
NoiseFigureDB = 7.0 # 噪声系数 (分贝)
SystemLossDB = 6.0 # 系统损耗 (分贝)
MonopulseSensitivity = 1.0 # 单脉冲灵敏度 (单位取决于具体实现,JSON中为1)
-
YawControlEffectiveness = 120.0 # 偏航控制有效性 (度/秒^2 或类似单位)
PitchControlEffectiveness = 150.0 # 俯仰控制有效性 (度/秒^2 或类似单位)
JammingResistanceThreshold = 1.0e-5 # 干扰抗性阈值 (瓦特)
\ No newline at end of file
diff --git a/ThreatSource/src/Guidance/InfraredImagingGuidanceSystem.cs b/ThreatSource/src/Guidance/InfraredImagingGuidanceSystem.cs
index b4ce3b6..6f54906 100644
--- a/ThreatSource/src/Guidance/InfraredImagingGuidanceSystem.cs
+++ b/ThreatSource/src/Guidance/InfraredImagingGuidanceSystem.cs
@@ -95,17 +95,17 @@ namespace ThreatSource.Guidance
///
/// 当前正在跟踪或已锁定的目标ID
///
- private string? _currentlyTrackedTargetId;
+ private string? currentlyTrackedTargetId;
///
/// Search模式下当前关注的候选目标ID
///
- private string? _searchModeFocusCandidateId;
+ private string? searchModeFocusCandidateId;
///
/// 当前活动模式 (搜索焦点或跟踪稳定) 的识别历史队列
///
- private Queue _activeRecognitionHistory = new();
+ private readonly Queue activeRecognitionHistory = new();
///
/// 识别历史窗口大小 (搜索和跟踪阶段共用)
@@ -120,7 +120,7 @@ namespace ThreatSource.Guidance
///
/// 锁定模式下目标丢失计时器
///
- private double _lockModeTargetLostTimer = 0;
+ private double lockModeTargetLostTimer = 0;
///
/// 初始化红外成像制导系统的新实例
@@ -222,7 +222,7 @@ namespace ThreatSource.Guidance
public override void Deactivate()
{
base.Deactivate();
- LastTargetPosition = null; // Add reset to null
+ LastTargetPosition = null;
HasTarget = false;
HasGuidance = false;
GuidanceAcceleration = Vector3D.Zero;
@@ -241,91 +241,78 @@ namespace ThreatSource.Guidance
///
public override void Update(double deltaTime)
{
+ bool tryDetectSucceeded = false;
+
base.Update(deltaTime);
- bool targetFoundAndIdentifiedThisFrame = false;
- Vector3D currentTargetPosition = Vector3D.Zero; // 初始化
if (IsBlockingJammed)
{
- targetFoundAndIdentifiedThisFrame = false;
Debug.WriteLine($"[IR IMAGING] 系统被阻塞干扰,无法探测目标。当前模式: {currentMode}");
}
else
{
- if (TryDetectAndIdentifyTarget(KState.Position, KState.Velocity, deltaTime, out currentTargetPosition))
+ if (TryDetectAndIdentifyTarget(KState.Position, KState.Velocity, deltaTime, out Vector3D detectedTargetPosition))
{
- targetFoundAndIdentifiedThisFrame = true;
- // 目标成功探测/跟踪/锁定
+ tryDetectSucceeded = true;
+
Vector3D? currentTargetVelocity = null;
- if(LastTargetPosition != null && deltaTime > 0)
- {
- currentTargetVelocity = (currentTargetPosition - LastTargetPosition.Value) / deltaTime; // 使用 .Value
+ if (LastTargetPosition != null && deltaTime > 0) {
+ currentTargetVelocity = (detectedTargetPosition - LastTargetPosition.Value) / deltaTime;
}
-
- LastTargetPosition = currentTargetPosition;
+ LastTargetPosition = detectedTargetPosition;
GuidanceAcceleration = MotionAlgorithm.CalculateProportionalNavigation(
- ProportionalNavigationCoefficient,
- KState.Position,
- KState.Velocity,
- currentTargetPosition,
- currentTargetVelocity ?? Vector3D.Zero
+ ProportionalNavigationCoefficient, KState.Position, KState.Velocity,
+ detectedTargetPosition, currentTargetVelocity ?? Vector3D.Zero
);
-
- if (GuidanceAcceleration.Magnitude() > MaxAcceleration)
- {
+
+ if (GuidanceAcceleration.Magnitude() > MaxAcceleration) {
GuidanceAcceleration = GuidanceAcceleration.Normalize() * MaxAcceleration;
}
HasGuidance = true;
- if (currentMode == WorkMode.Lock)
- {
- _lockModeTargetLostTimer = 0; // 目标在锁定模式下重新确认,重置计时器
+ if (currentMode == WorkMode.Lock) {
+ lockModeTargetLostTimer = 0;
}
}
- else // TryDetectAndIdentifyTarget 返回 false (目标未找到/不稳定)
+ else
{
- targetFoundAndIdentifiedThisFrame = false;
- // 不更新 LastTargetPosition
Debug.WriteLine($"[IR IMAGING] TryDetectAndIdentifyTarget 返回 false。当前模式: {currentMode}");
}
}
- // 处理目标未识别/丢失的后果
- if (!targetFoundAndIdentifiedThisFrame)
+ if (!tryDetectSucceeded)
{
GuidanceAcceleration = Vector3D.Zero;
HasGuidance = false;
- // 模式切换逻辑
- if (currentMode == WorkMode.Track)
- {
+ 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
- }
+ else if (currentMode == WorkMode.Lock) {
+ HandleLockModeTargetLoss(deltaTime);
+ }
+ }
+ }
+
+ private void HandleLockModeTargetLoss(double deltaTime)
+ {
+ 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();
}
- // 如果在Search模式下目标丢失,通常意味着本帧未找到任何满足条件的目标,
- // TryDetectAndIdentifyTarget内部逻辑会处理是否重置焦点等,此处无需额外操作
}
- // 如果 targetFoundAndIdentifiedThisFrame 为 true,则制导参数已设置,模式状态由 TryDetectAndIdentifyTarget 内部逻辑(如切换到Track/Lock)或 Update 稍早部分(重置Lock模式计时器)处理
}
///
@@ -341,12 +328,11 @@ namespace ThreatSource.Guidance
{
currentMode = WorkMode.Search;
HasTarget = false;
- // targetLostTimer = 0; // 已移除
LastTargetPosition = null;
- _currentlyTrackedTargetId = null;
- _searchModeFocusCandidateId = null;
- _activeRecognitionHistory.Clear();
- _lockModeTargetLostTimer = 0; // 清理状态
+ currentlyTrackedTargetId = null;
+ searchModeFocusCandidateId = null;
+ activeRecognitionHistory.Clear();
+ lockModeTargetLostTimer = 0;
// 创建图像生成器
imageGenerator = new InfraredImageGenerator(
@@ -371,13 +357,11 @@ namespace ThreatSource.Guidance
public void SwitchToTrackMode()
{
currentMode = WorkMode.Track;
- lockConfirmationTimer = 0; // 重置锁定确认计时器
- // _lockModeTargetLostTimer 在切换到Track时不需要重置,因为它特定于Lock模式,
- // 并且在从Lock切换到Search,再可能到Track时,应由SwitchToSearchMode清理。
+ lockConfirmationTimer = 0;
// 清理搜索阶段的状态
- _searchModeFocusCandidateId = null;
- _activeRecognitionHistory.Clear(); // Track模式应从零开始积累历史
+ searchModeFocusCandidateId = null;
+ activeRecognitionHistory.Clear();
// 创建图像生成器 (通常视场角会变化)
imageGenerator = new InfraredImageGenerator(
@@ -402,7 +386,7 @@ namespace ThreatSource.Guidance
public void SwitchToLockMode()
{
currentMode = WorkMode.Lock;
- _lockModeTargetLostTimer = 0; // 进入锁定模式时重置计时器
+ lockModeTargetLostTimer = 0;
Debug.WriteLine("切换到锁定模式 - 目标类型确认");
}
@@ -425,14 +409,12 @@ namespace ThreatSource.Guidance
private bool TryDetectAndIdentifyTarget(Vector3D missilePosition, Vector3D missileVelocity, double deltaTime, out Vector3D targetPosition)
{
targetPosition = Vector3D.Zero;
- double minDistance = double.MaxValue;
bool foundThisFrame = false;
- bool currentFrameDirectRecognitionSuccess = false; // 新增:用于记录当前帧的直接识别/探测成功状态
+ bool isRecognizedThisFrame = false;
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 currentEntity)
@@ -440,224 +422,182 @@ namespace ThreatSource.Guidance
Vector3D toTarget = currentEntity.KState.Position - missilePosition;
double distanceToCurrentEntity = toTarget.Magnitude();
- // 调用新的统一烟幕评估方法
- var smokeImpact = EvaluateSmokeImpact(missilePosition, currentEntity);
- bool isGeometricallyObscuredBySmoke = smokeImpact.IsGeometricallyObscured;
- double liveTransmittanceForImage = smokeImpact.OverallTransmittance; // 重命名以避免与旧变量名冲突
+ var (isGeometricallyObscured, overallTransmittance) = EvaluateSmokeImpact(missilePosition, currentEntity);
- // 根据当前模式调整FOV检查,并将烟幕几何遮挡作为主要过滤条件之一
- bool passesBasicChecks = false;
- if (currentMode == WorkMode.Search)
- {
- 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;
- }
+ bool isWithinFovAndRange;
+ double relevantFovRadians = currentMode == WorkMode.Search ? searchFovRadians : trackFovRadians;
- if (passesBasicChecks)
+ isWithinFovAndRange = distanceToCurrentEntity <= config.MaxDetectionRange &&
+ Math.Acos(Vector3D.DotProduct(toTarget.Normalize(), missileVelocity.Normalize())) <= (relevantFovRadians / 2);
+
+ if (!isWithinFovAndRange || isGeometricallyObscured)
{
- switch (currentMode)
+ // 如果是 Search 模式下的焦点目标,但它不再满足基本条件,则清除焦点
+ if (currentMode == WorkMode.Search && currentEntity.Id == searchModeFocusCandidateId)
{
- case WorkMode.Search:
- // 几何和主要烟幕检查已在上方 passesBasicChecks 中完成
- // if (distanceToCurrentEntity > config.MaxDetectionRange || ... || CheckIfTargetObscuredBySmoke(...))
- // 上述条件已由 passesBasicChecks 处理
-
- 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)
- {
- Vector3D toTargetForTrackCheck = currentEntity.KState.Position - missilePosition;
- double angleToTargetForTrackCheck = Math.Acos(Vector3D.DotProduct(toTargetForTrackCheck.Normalize(), missileVelocity.Normalize()));
-
- if (angleToTargetForTrackCheck <= (trackFovRadians / 2))
- {
- _currentlyTrackedTargetId = _searchModeFocusCandidateId;
- targetPosition = currentEntity.KState.Position;
- minDistance = distanceToCurrentEntity;
- foundThisFrame = true;
- Debug.WriteLine($"[IR IMAGING SEARCH] 目标 {_searchModeFocusCandidateId} 滑动窗口达标 (率: {successRate:P2}) 且在Track FOV内. 切换到Track模式。");
- SwitchToTrackMode();
- break; // 跳出 foreach, 完成搜索并切换
- }
- else
- {
- _searchModeFocusCandidateId = null;
- _activeRecognitionHistory.Clear();
- foundThisFrame = false; // 仅对当前焦点而言,未通过最终检查
- Debug.WriteLine($"[IR IMAGING SEARCH] 目标 {currentEntity.Id} 滑动窗口达标,但不满足Track FOV. 清除焦点,继续搜索。");
- }
- }
- else
- {
- _searchModeFocusCandidateId = null;
- _activeRecognitionHistory.Clear();
- foundThisFrame = false; // 明确当前焦点未通过滑动窗口
- Debug.WriteLine($"[IR IMAGING SEARCH] 目标 {currentEntity.Id} 滑动窗口未达标 (率: {successRate:P2}). 清除焦点,继续搜索。");
- }
- }
- 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.Track:
- if (_currentlyTrackedTargetId != null && currentEntity.Id == _currentlyTrackedTargetId)
- {
- bool actualRecognitionSuccessInTrack = false; // 重命名,避免与search模式的变量混淆
- if (!passesBasicChecks)
- {
- actualRecognitionSuccessInTrack = false;
- Debug.WriteLine($"[IR IMAGING TRACK] 目标 {_currentlyTrackedTargetId} 未通过基本检查. 本帧失败。");
- }
- 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;
+ searchModeFocusCandidateId = null;
+ activeRecognitionHistory.Clear();
+ Debug.WriteLine($"[IR IMAGING SEARCH] 焦点目标 {currentEntity.Id} 不再满足基本条件,清除焦点。");
}
+ continue; // 不满足基本FOV、距离或被烟幕遮挡,处理下一个实体
+ }
+
+ switch (currentMode)
+ {
+ case WorkMode.Search:
+ // 处理焦点
+ if (searchModeFocusCandidateId == null)
+ {
+ searchModeFocusCandidateId = currentEntity.Id;
+ activeRecognitionHistory.Clear();
+ Debug.WriteLine($"[IR IMAGING SEARCH] 选取新的焦点目标: {searchModeFocusCandidateId}");
+ }
+ else if (currentEntity.Id != searchModeFocusCandidateId)
+ {
+ continue; // 不是当前选定的焦点目标,跳过
+ }
+
+ // 当前是焦点目标,且通过了基本检查
+ var image = imageGenerator.GenerateImage(currentEntity, missilePosition, overallTransmittance, SimulationManager);
+ var searchResult = targetRecognizer.RecognizeTarget(image, currentEntity);
+
+ isRecognizedThisFrame = (searchResult.Type == targetType && searchResult.Confidence >= config.SearchRecognitionProbability);
+ activeRecognitionHistory.Enqueue(isRecognizedThisFrame);
+ 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)
+ {
+ // 检查是否也在Track模式的FOV内 (因为search FOV可能比track FOV宽)
+ double angleToTargetForTrackCheck = Math.Acos(Vector3D.DotProduct(toTarget.Normalize(), missileVelocity.Normalize()));
+ if (angleToTargetForTrackCheck <= (trackFovRadians / 2))
+ {
+ currentlyTrackedTargetId = searchModeFocusCandidateId;
+ targetPosition = currentEntity.KState.Position;
+ foundThisFrame = true;
+ Debug.WriteLine($"[IR IMAGING SEARCH] 目标 {searchModeFocusCandidateId} 滑动窗口达标 (率: {successRate:P2}) 且在Track FOV内. 切换到Track模式。");
+ SwitchToTrackMode();
+ }
+ else
+ {
+ searchModeFocusCandidateId = null; // 不在Track FOV内,放弃此焦点
+ activeRecognitionHistory.Clear();
+ foundThisFrame = false;
+ Debug.WriteLine($"[IR IMAGING SEARCH] 目标 {currentEntity.Id} 滑动窗口达标,但不满足切换到Track模式的FOV条件. 清除焦点。");
+ }
+ }
+ else
+ {
+ searchModeFocusCandidateId = null; // 滑动窗口未达标,放弃此焦点
+ activeRecognitionHistory.Clear();
+ foundThisFrame = false;
+ Debug.WriteLine($"[IR IMAGING SEARCH] 目标 {currentEntity.Id} 滑动窗口未达标 (率: {successRate:P2}). 清除焦点。");
+ }
+ }
+ else // 窗口未满
+ {
+ foundThisFrame = isRecognizedThisFrame; // foundThisFrame反映本帧直接识别结果
+ if (isRecognizedThisFrame) targetPosition = currentEntity.KState.Position;
+ Debug.WriteLine($"[IR IMAGING SEARCH] 目标 {searchModeFocusCandidateId} 正在收集数据,窗口 ({activeRecognitionHistory.Count}/{COMMON_RECOGNITION_WINDOW_SIZE}). 本帧识别: {isRecognizedThisFrame}");
+ }
+ break;
+
+ case WorkMode.Track:
+ if (currentlyTrackedTargetId == null || currentEntity.Id != currentlyTrackedTargetId)
+ {
+ continue; // 不是当前正在跟踪的目标
+ }
+
+ // 当前是跟踪目标,且已通过外层基本检查
+ var image_track = imageGenerator.GenerateImage(currentEntity, missilePosition, overallTransmittance, SimulationManager);
+ var trackResult = targetRecognizer.RecognizeTarget(image_track, currentEntity);
+ isRecognizedThisFrame = trackResult.Type == targetType && trackResult.Confidence >= config.TrackRecognitionProbability;
+
+ if (isRecognizedThisFrame)
+ {
+ Debug.WriteLine($"[IR IMAGING TRACK] 目标 {currentlyTrackedTargetId} 本帧识别成功 (置信度 {trackResult.Confidence:P2})。");
+ }
+ else
+ {
+ Debug.WriteLine($"[IR IMAGING TRACK] 目标 {currentlyTrackedTargetId} 本帧识别失败 (置信度: {trackResult.Confidence:P2})。");
+ }
+
+ activeRecognitionHistory.Enqueue(isRecognizedThisFrame);
+ 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 (isRecognizedThisFrame)
+ {
+ targetPosition = currentEntity.KState.Position;
+ }
+ else if (LastTargetPosition.HasValue)
+ {
+ targetPosition = LastTargetPosition.Value;
+ 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 = isRecognizedThisFrame;
+ if (isRecognizedThisFrame)
+ {
+ targetPosition = currentEntity.KState.Position;
+ }
+ else if (LastTargetPosition.HasValue)
+ {
+ targetPosition = LastTargetPosition.Value;
+ Debug.WriteLine($"[IR IMAGING TRACK] 滑动窗口未满,本帧识别失败。使用LastTargetPosition: {targetPosition}");
+ }
+ Debug.WriteLine($"[IR IMAGING TRACK] 目标 {currentlyTrackedTargetId} 正在收集数据,窗口 ({activeRecognitionHistory.Count}/{COMMON_RECOGNITION_WINDOW_SIZE}). 本帧识别:{isRecognizedThisFrame}. foundThisFrame set to {foundThisFrame}");
+ }
+ break;
+
+ case WorkMode.Lock:
+ if (currentlyTrackedTargetId == null || currentEntity.Id != currentlyTrackedTargetId)
+ {
+ continue;
+ }
+ targetPosition = currentEntity.KState.Position;
+ foundThisFrame = true;
+ isRecognizedThisFrame = true;
+ Debug.WriteLine($"[IR IMAGING LOCK] 锁定目标 {currentlyTrackedTargetId} 通过基本检查。");
+ break;
+ }
+
+ // 如果在Search模式下成功切换到Track,或者在Track/Lock模式下处理了目标(无论成功与否),则不再继续遍历此帧中的其他实体
+ if (foundThisFrame || currentMode != WorkMode.Search || (currentMode == WorkMode.Search && currentlyTrackedTargetId != null) )
+ {
+ break;
}
}
}
if (currentMode == WorkMode.Track)
{
- if (foundThisFrame && currentFrameDirectRecognitionSuccess)
+ if (foundThisFrame && isRecognizedThisFrame)
{
lockConfirmationTimer += deltaTime;
- Debug.WriteLine($"[IR IMAGING TRACK] 目标 {_currentlyTrackedTargetId} 跟踪中,累积锁定确认时间: {lockConfirmationTimer:F2}s / {config.LockConfirmationTime:F2}s");
+ Debug.WriteLine($"[IR IMAGING TRACK] 目标 {currentlyTrackedTargetId} 跟踪中,累积锁定确认时间: {lockConfirmationTimer:F2}s / {config.LockConfirmationTime:F2}s");
if (lockConfirmationTimer >= config.LockConfirmationTime)
{
SwitchToLockMode();
@@ -666,22 +606,19 @@ namespace ThreatSource.Guidance
else
{
lockConfirmationTimer = 0;
- Debug.WriteLine($"[IR IMAGING TRACK] 目标 {_currentlyTrackedTargetId} 跟踪条件不满足 (foundThisFrame:{foundThisFrame} 或本帧直接识别失败:{currentFrameDirectRecognitionSuccess}),重置锁定确认计时器。");
+ Debug.WriteLine($"[IR IMAGING TRACK] 目标 {currentlyTrackedTargetId} 跟踪条件不满足 (foundThisFrame:{foundThisFrame} 或本帧直接识别失败:{isRecognizedThisFrame}),重置锁定确认计时器。");
}
}
else if (currentMode == WorkMode.Lock)
{
if (!foundThisFrame)
{
- // 在Lock模式下,如果 TryDetectAndIdentifyTarget 返回 false (即 foundThisFrame 为 false),
- // _currentlyTrackedTargetId 暂时不清除,而是由 Update 方法中的 _lockModeTargetLostTimer 机制来决定何时因超时而真正丢失目标并切换模式。
- // 此时 _currentlyTrackedTargetId 仍然保留,以便在容限时间内如果目标重现,可以继续锁定。
- Debug.WriteLine($"[IR IMAGING LOCK] 锁定目标 {_currentlyTrackedTargetId} 在本帧未被找到。等待容限超时...");
+ Debug.WriteLine($"[IR IMAGING LOCK] 锁定目标 {currentlyTrackedTargetId} 在本帧未被找到。等待容限超时...");
}
}
- HasTarget = foundThisFrame; // HasTarget 反映的是本帧是否成功探测/识别/跟踪到目标
- return foundThisFrame; // 返回本帧的探测/跟踪状态
+ HasTarget = foundThisFrame;
+ return foundThisFrame;
}
private (bool IsGeometricallyObscured, double OverallTransmittance) EvaluateSmokeImpact(Vector3D observerPosition, BaseEquipment target)
diff --git a/ThreatSource/src/Guidance/MillimeterWaveGuidanceSystem.cs b/ThreatSource/src/Guidance/MillimeterWaveGuidanceSystem.cs
index c82782d..6b1d492 100644
--- a/ThreatSource/src/Guidance/MillimeterWaveGuidanceSystem.cs
+++ b/ThreatSource/src/Guidance/MillimeterWaveGuidanceSystem.cs
@@ -66,15 +66,6 @@ namespace ThreatSource.Guidance
///
private Vector3D? LastTargetVelocity { get; set; }
- ///
- /// 目标丢失计时器
- ///
- ///
- /// 记录目标丢失的时间
- /// 用于切换到搜索模式
- ///
- private double targetLostTimer = 0;
-
///
/// 锁定确认计时器
///
@@ -94,6 +85,26 @@ namespace ThreatSource.Guidance
///
private WorkMode currentMode = WorkMode.Search;
+ ///
+ /// 当前正在跟踪或已锁定的目标ID (由Search模式切换时设置)
+ ///
+ private string? currentlyTrackedTargetId;
+
+ ///
+ /// 当前活动模式 (Search焦点、Track、Lock) 的探测历史队列
+ ///
+ private readonly Queue activeDetectionHistory = new();
+
+ ///
+ /// Search到Track模式切换的滑动窗口大小
+ ///
+ private const int COMMON_DETECTION_WINDOW_SIZE = 10;
+
+ ///
+ /// Search到Track模式切换的成功率阈值
+ ///
+ private const double COMMON_DETECTION_SUCCESS_RATE_THRESHOLD = 0.8;
+
///
/// 是否有目标
///
@@ -129,6 +140,11 @@ namespace ThreatSource.Guidance
///
private readonly SwerlingRcsModel swerlingRcsModel;
+ private int _framesInTrackMode = 0;
+ private const int MIN_FRAMES_FOR_TRACK_STABILITY_CHECK = 5;
+
+ private double lastDetailSnrForDecision; // 新增类成员存储SNR供决策
+
///
/// 初始化毫米波制导系统的新实例
///
@@ -169,12 +185,15 @@ namespace ThreatSource.Guidance
currentMode = WorkMode.Search;
HasTarget = false;
HasGuidance = false;
- targetLostTimer = 0;
lockConfirmationTimer = 0;
currentScanAngle = 0;
currentScanRadius = config.SearchBeamWidth * Math.PI / 720.0; // 从半个波束宽度的一半开始
LastTargetPosition = null;
LastTargetVelocity = null;
+
+ activeDetectionHistory.Clear();
+ currentlyTrackedTargetId = null;
+
Trace.TraceInformation($"切换到搜索模式,波束宽度: {config.SearchBeamWidth}度");
}
@@ -186,6 +205,10 @@ namespace ThreatSource.Guidance
currentMode = WorkMode.Track;
lockConfirmationTimer = 0;
HasGuidance = true;
+
+ activeDetectionHistory.Clear();
+ _framesInTrackMode = 0; // 重置计数器
+
Trace.TraceInformation($"切换到跟踪模式,波束宽度: {config.TrackBeamWidth}度");
}
@@ -207,7 +230,6 @@ namespace ThreatSource.Guidance
if (!IsActive)
{
IsActive = true;
- // 在这里订阅事件,确保只订阅一次
SimulationManager.SubscribeToEvent(HandleJammingEvent);
}
base.Activate();
@@ -243,7 +265,6 @@ namespace ThreatSource.Guidance
if (parameters.Type == JammingType.MillimeterWave)
{
Debug.WriteLine($"[MMW_GUIDANCE] 受到毫米波干扰,功率:{parameters.Power} W。切换到搜索模式。", "Jamming");
- // 干扰时切换到搜索模式
if (currentMode != WorkMode.Search)
{
SwitchToSearchMode();
@@ -252,7 +273,6 @@ namespace ThreatSource.Guidance
else if (parameters.Type == JammingType.SmokeGrenade)
{
Debug.WriteLine($"[MMW_GUIDANCE] 受到烟幕干扰影响。Jammer ID: {parameters.JammerId}", "Jamming");
- // 烟幕主要通过影响SNR体现,不直接触发模式切换
}
}
@@ -267,11 +287,9 @@ namespace ThreatSource.Guidance
if (parameters.Type == JammingType.MillimeterWave)
{
Debug.WriteLine($"[MMW_GUIDANCE] 毫米波干扰已清除。", "Jamming");
- // 干扰清除后是否需要切换模式?取决于当前是否有目标。Update 会处理。
}
else if (parameters.Type == JammingType.SmokeGrenade)
{
- // _currentSmokeTransmittance = 1.0; // Field removed, no longer needed here
Debug.WriteLine($"[MMW_GUIDANCE] 烟幕干扰解除。Jammer ID: {parameters.JammerId}", "Jamming");
}
}
@@ -283,17 +301,13 @@ namespace ThreatSource.Guidance
/// 如果应该处理则返回 true,否则返回 false
protected override bool ShouldHandleJamming(JammingParameters parameters)
{
- // 首先调用基类检查是否支持该干扰类型
if (!base.ShouldHandleJamming(parameters))
{
return false;
}
- // 对毫米波干扰添加波长检查
if (parameters.Type == JammingType.MillimeterWave)
{
- // 检查波长是否与工作波长匹配 (单位: 毫米 mm)
- // 计算配置波长 (单位: mm), 直接使用光速值 3e8 m/s
const double speedOfLight = 3e8;
double configWavelength_mm = speedOfLight / config.WaveFrequency * 1000.0; // m/s / Hz * 1000 = mm
@@ -304,7 +318,6 @@ namespace ThreatSource.Guidance
}
}
- // 如果是支持的非毫米波干扰 (例如烟幕) 或通过了毫米波检查,则返回 true
return true;
}
@@ -467,69 +480,52 @@ namespace ThreatSource.Guidance
///
public override void Update(double deltaTime)
{
- base.Update(deltaTime); // 更新基类状态和干扰状态
+ base.Update(deltaTime);
- // 在执行核心逻辑前检查阻塞性干扰状态
if (IsBlockingJammed)
{
- // 如果被阻塞性干扰,确保处于搜索模式并且没有制导
- if (currentMode != WorkMode.Search)
- {
- SwitchToSearchMode();
- }
- HasGuidance = false;
+ if (currentMode != WorkMode.Search) SwitchToSearchMode();
+ this.HasTarget = false;
GuidanceAcceleration = Vector3D.Zero;
+ HasGuidance = false;
return;
}
- // 更新扫描参数
UpdateConicalScan(deltaTime);
-
- if (TryDetectAndTrackTarget(KState.Position, KState.Velocity, deltaTime, out Vector3D currentTargetPosition))
+
+ TryDetectAndTrackTarget(KState.Position, KState.Velocity, deltaTime, out Vector3D currentTargetPositionFromDetector);
+
+ HasGuidance = HasTarget;
+
+ if (HasGuidance)
{
- targetLostTimer = 0;
Vector3D? currentTargetVelocity = null;
- if (LastTargetPosition != null && deltaTime > 0)
+ if (LastTargetPosition.HasValue && deltaTime > 0 && currentTargetPositionFromDetector != Vector3D.Zero)
{
- currentTargetVelocity = (currentTargetPosition - LastTargetPosition) / deltaTime;
+ currentTargetVelocity = (currentTargetPositionFromDetector - LastTargetPosition.Value) / deltaTime;
}
-
- LastTargetPosition = currentTargetPosition;
- LastTargetVelocity = currentTargetVelocity;
+ LastTargetVelocity = currentTargetVelocity;
GuidanceAcceleration = MotionAlgorithm.CalculateProportionalNavigation(
ProportionalNavigationCoefficient,
KState.Position,
KState.Velocity,
- currentTargetPosition,
- currentTargetVelocity ?? Vector3D.Zero
+ currentTargetPositionFromDetector,
+ LastTargetVelocity ?? Vector3D.Zero
);
if (GuidanceAcceleration.Magnitude() > MaxAcceleration)
{
GuidanceAcceleration = GuidanceAcceleration.Normalize() * MaxAcceleration;
}
-
Debug.WriteLine($"制导加速度: {GuidanceAcceleration}");
- HasGuidance = true;
}
- else
+ else
{
- if (currentMode != WorkMode.Search)
- {
- targetLostTimer += deltaTime;
- if (targetLostTimer >= config.TargetLostTolerance)
- {
- HasGuidance = false;
- Trace.TraceInformation($"目标丢失 {targetLostTimer:F3}秒,切换回搜索模式");
- SwitchToSearchMode();
- }
- }
- else
- {
- HasGuidance = false;
- }
+ GuidanceAcceleration = Vector3D.Zero;
+ LastTargetVelocity = null;
}
+ HasGuidance = HasTarget;
}
///
@@ -551,178 +547,209 @@ namespace ThreatSource.Guidance
private bool TryDetectAndTrackTarget(Vector3D missilePosition, Vector3D missileVelocity, double deltaTime, out Vector3D targetPosition)
{
targetPosition = Vector3D.Zero;
- double minDistance = double.MaxValue;
- bool foundTarget = false;
- double currentSNR_dB = double.MinValue;
foreach (var element in SimulationManager.GetEntitiesByType())
{
- if (element is BaseEquipment target && target.Id != MissileId && target.IsActive)
+ if (!(element is BaseEquipment target && target.Id != MissileId && target.IsActive))
{
- Vector3D toTarget = target.KState.Position - missilePosition;
- double distance = toTarget.Magnitude();
+ continue; // 卫语句: 跳过自身或无效目标
+ }
- if (distance <= config.MaxDetectionRange && distance > 0)
+ Vector3D toTarget = target.KState.Position - missilePosition;
+ double distance = toTarget.Magnitude();
+
+ // 卫语句: 超出最大探测距离或距离无效
+ if (!(distance <= config.MaxDetectionRange && distance > 0))
+ {
+ if ((currentMode == WorkMode.Track || currentMode == WorkMode.Lock) && target.Id == currentlyTrackedTargetId)
{
- double liveSmokeTransmittance = CalculateLiveSmokeTransmittance(missilePosition, target.KState.Position);
-
- // --- 开始RCS获取逻辑 ---
- double rcsDbSm = RcsPattern.DEFAULT_RCS_DBSM;
- double rcsLinear;
-
- Vector3D targetForward = Vector3D.Zero;
- Vector3D targetRight = Vector3D.Zero;
- Vector3D targetUp = Vector3D.Zero;
- Vector3D observerVector = Vector3D.Zero;
- bool isTargetOrientationValid = false;
- MotionStateType motionState = MotionStateType.Static;
+ Debug.WriteLine($"[MMW {currentMode.ToString().ToUpper()}] 当前跟踪目标 {currentlyTrackedTargetId} 超出最大探测距离 ({distance:F0}m > {config.MaxDetectionRange:F0}m) 或距离无效。");
+ }
+ else
+ {
+ continue;
+ }
+ }
- if (target.KState != null)
+ double liveSmokeTransmittance = CalculateLiveSmokeTransmittance(missilePosition, target.KState.Position);
+ double rcsDbSm = RcsPattern.DEFAULT_RCS_DBSM;
+ double rcsLinear;
+ Vector3D targetForward = Vector3D.Zero;
+ Vector3D targetRight = Vector3D.Zero;
+ Vector3D targetUp = Vector3D.Zero;
+ bool isTargetOrientationValid = false;
+ MotionStateType motionState = MotionStateType.Static;
+
+ if (target.KState != null)
+ {
+ targetForward = target.KState.Orientation.ToVector().Normalize();
+ if (targetForward.MagnitudeSquared() > 1e-10)
+ {
+ Vector3D worldUpRef = Vector3D.UnitY;
+ if (Math.Abs(Vector3D.DotProduct(targetForward, worldUpRef)) > 0.99) worldUpRef = Vector3D.UnitZ;
+ targetRight = Vector3D.CrossProduct(targetForward, worldUpRef).Normalize();
+ if (targetRight.MagnitudeSquared() > 1e-10)
{
- targetForward = target.KState.Orientation.ToVector().Normalize();
- if (targetForward.MagnitudeSquared() > 1e-10) // 确保从Orientation得到的Forward有效
- {
- Vector3D worldUpRef = Vector3D.UnitY;
- if (Math.Abs(Vector3D.DotProduct(targetForward, worldUpRef)) > 0.99) // 目标几乎垂直运动
- {
- worldUpRef = Vector3D.UnitZ;
- }
- targetRight = Vector3D.CrossProduct(targetForward, worldUpRef).Normalize();
- if (targetRight.MagnitudeSquared() > 1e-10) // 确保Right向量有效
- {
- targetUp = Vector3D.CrossProduct(targetRight, targetForward).Normalize();
- if (targetUp.MagnitudeSquared() > 1e-10) // 确保Up向量有效
- {
- isTargetOrientationValid = true;
- }
- }
- }
- if(target.KState.Speed >0.1)
- {
- motionState = MotionStateType.ConstantVelocity;
- }
+ targetUp = Vector3D.CrossProduct(targetRight, targetForward).Normalize();
+ if (targetUp.MagnitudeSquared() > 1e-10) isTargetOrientationValid = true;
+ }
+ }
+ if (target.KState.Speed > 0.1) motionState = MotionStateType.ConstantVelocity;
+ }
+ if (!isTargetOrientationValid) Debug.WriteLine($"[MMW_GUIDANCE] Target {target.Id}: 方向无效或 KState 为 null. 使用默认RCS.");
+
+ if (target.Properties.RcsPattern != null)
+ {
+ if (isTargetOrientationValid) rcsDbSm = target.Properties.RcsPattern.GetRcsValueDbSm(missilePosition - target.KState!.Position, targetForward, targetUp, targetRight);
+ }
+ else Debug.WriteLine($"[MMW_GUIDANCE] Target {target.Id}: 没有 RcsPattern 对象. 使用默认RCS.");
+
+ rcsLinear = Math.Pow(10, rcsDbSm / 10.0);
+ Debug.WriteLine($"[MMW_GUIDANCE] 目标 {target.Id}: 原始RCS: {rcsLinear:F2} dBsm.");
+ bool isNewScanPeriodForRcs = currentMode == WorkMode.Track || currentMode == WorkMode.Lock;
+ rcsLinear = swerlingRcsModel.GetRealtimeRcs(target.Id, target.Properties.Type, motionState, rcsLinear, isNewScanPeriodForRcs);
+ Debug.WriteLine($"[MMW_GUIDANCE] 目标 {target.Id}: 实时RCS: {rcsLinear:F2} dBsm.");
+ double localSnrDb = CalculateSNR(distance, rcsLinear, liveSmokeTransmittance);
+
+ switch (currentMode)
+ {
+ case WorkMode.Search:
+ if (IsTargetInBeam(missileVelocity, toTarget) && localSnrDb >= config.RecognitionSNRThreshold)
+ {
+ Debug.WriteLine($"[MMW SEARCH] TryDetect发现目标: {target.Id}, SNR: {localSnrDb:F2} dB.");
+ targetPosition = target.KState!.Position;
+ UpdateStateAndPotentiallySwitchMode(true, localSnrDb, target.Id, targetPosition, deltaTime);
+ return true;
+ }
+ break;
+
+ case WorkMode.Track:
+ if (currentlyTrackedTargetId == null || target.Id != currentlyTrackedTargetId)
+ {
+ continue;
}
- if (!isTargetOrientationValid)
- {
- Debug.WriteLine($"[MMW_GUIDANCE] Target {target.Id}: 方向无效或 KState 为 null. 使用默认RCS ({RcsPattern.DEFAULT_RCS_DBSM} dBsm) 进行线性转换.");
- }
+ bool currentFrameSuccessForTrack = IsTargetInBeam(missileVelocity, toTarget) && localSnrDb >= config.RecognitionSNRThreshold;
+ activeDetectionHistory.Enqueue(currentFrameSuccessForTrack);
+ while (activeDetectionHistory.Count > COMMON_DETECTION_WINDOW_SIZE) activeDetectionHistory.Dequeue();
+
+ Debug.WriteLine($"[MMW TRACK] TryDetect目标 {currentlyTrackedTargetId} 本帧探测: {currentFrameSuccessForTrack}, SNR: {localSnrDb:F2} dB. 窗口 ({activeDetectionHistory.Count}/{COMMON_DETECTION_WINDOW_SIZE}), 预热帧: {_framesInTrackMode}/{MIN_FRAMES_FOR_TRACK_STABILITY_CHECK}.");
- if (target.Properties.RcsPattern != null)
+ bool trackOverallSuccess;
+ if (_framesInTrackMode < MIN_FRAMES_FOR_TRACK_STABILITY_CHECK)
{
- if (isTargetOrientationValid)
- {
- observerVector = missilePosition - target.KState!.Position; // 从目标指向导弹 (观察者)
- Debug.WriteLine($"[RCS获取] Target {target.Id}: observerVector: {observerVector}, targetForward: {targetForward}, targetUp: {targetUp}, targetRight: {targetRight}");
- rcsDbSm = target.Properties.RcsPattern.GetRcsValueDbSm(observerVector, targetForward, targetUp, targetRight);
- }
+ _framesInTrackMode++;
+ trackOverallSuccess = true;
}
else
{
- Debug.WriteLine($"[MMW_GUIDANCE] Target {target.Id}: 没有 RcsPattern 对象. 使用默认RCS ({RcsPattern.DEFAULT_RCS_DBSM} dBsm) 进行线性转换.");
+ if (activeDetectionHistory.Count == COMMON_DETECTION_WINDOW_SIZE)
+ {
+ double successRate = (double)activeDetectionHistory.Count(s => s) / COMMON_DETECTION_WINDOW_SIZE;
+ trackOverallSuccess = successRate >= COMMON_DETECTION_SUCCESS_RATE_THRESHOLD;
+ if(trackOverallSuccess) Debug.WriteLine($"[MMW TRACK] TryDetect目标 {currentlyTrackedTargetId} 滑动窗口稳定 (率: {successRate:P2}).");
+ else Debug.WriteLine($"[MMW TRACK] TryDetect目标 {currentlyTrackedTargetId} 滑动窗口不稳定 (率: {successRate:P2}).");
+ }
+ else
+ {
+ trackOverallSuccess = currentFrameSuccessForTrack;
+ Debug.WriteLine($"[MMW TRACK] TryDetect目标 {currentlyTrackedTargetId} 预热期后窗口未满. trackOverallSuccess = currentFrameSuccessForTrack ({currentFrameSuccessForTrack}).");
+ }
}
+
+ targetPosition = trackOverallSuccess ?
+ (currentFrameSuccessForTrack ? target.KState!.Position : (LastTargetPosition ?? Vector3D.Zero)) :
+ Vector3D.Zero;
+ UpdateStateAndPotentiallySwitchMode(trackOverallSuccess, localSnrDb, currentlyTrackedTargetId, targetPosition, deltaTime);
+ return trackOverallSuccess;
- // 单位转换 (dBsm -> 平方米)
- rcsLinear = Math.Pow(10, rcsDbSm / 10.0);
- Debug.WriteLine($"[RCS获取] Target {target.Id}: RCS_dBsm: {rcsDbSm}, RCS_Linear: {rcsLinear}, ");
-
- // 采用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);
-
- if (currentMode == WorkMode.Search)
+ case WorkMode.Lock:
+ if (currentlyTrackedTargetId == null || target.Id != currentlyTrackedTargetId)
{
- if (IsTargetInBeam(missileVelocity, toTarget) && snr_dB >= config.RecognitionSNRThreshold)
- {
- if (distance < minDistance)
- {
- targetPosition = target.KState!.Position;
- minDistance = distance;
- foundTarget = true;
- currentSNR_dB = snr_dB;
- }
- }
+ continue;
}
- else if (currentMode == WorkMode.Track || currentMode == WorkMode.Lock)
- {
- bool isPotentiallyTrackedTarget = true;
- if (LastTargetPosition != null)
- {
- double proximityThreshold = (target.Properties.Length > 0) ? target.Properties.Length * 5.0 : 100.0;
- isPotentiallyTrackedTarget = Vector3D.Distance(target.KState!.Position, LastTargetPosition.Value) < proximityThreshold;
- }
- if (IsTargetInBeam(missileVelocity, toTarget) && isPotentiallyTrackedTarget)
- {
- double requiredSNR_dB = (currentMode == WorkMode.Track) ?
- config.RecognitionSNRThreshold : config.LockSNRThreshold;
-
- if (snr_dB >= requiredSNR_dB)
- {
- targetPosition = target.KState!.Position;
- foundTarget = true;
- currentSNR_dB = snr_dB;
- break;
- }
- }
+ bool currentFrameSuccessForLock = IsTargetInBeam(missileVelocity, toTarget) && localSnrDb >= config.LockSNRThreshold;
+ activeDetectionHistory.Enqueue(currentFrameSuccessForLock);
+ while (activeDetectionHistory.Count > COMMON_DETECTION_WINDOW_SIZE) activeDetectionHistory.Dequeue();
+
+ Debug.WriteLine($"[MMW LOCK] TryDetect目标 {currentlyTrackedTargetId} 本帧探测: {currentFrameSuccessForLock}, SNR: {localSnrDb:F2} dB. 窗口 ({activeDetectionHistory.Count}/{COMMON_DETECTION_WINDOW_SIZE}).");
+
+ bool lockOverallSuccess;
+ if (activeDetectionHistory.Count == COMMON_DETECTION_WINDOW_SIZE)
+ {
+ double successRate = (double)activeDetectionHistory.Count(s => s) / COMMON_DETECTION_WINDOW_SIZE;
+ lockOverallSuccess = successRate >= COMMON_DETECTION_SUCCESS_RATE_THRESHOLD;
+ if(lockOverallSuccess) Debug.WriteLine($"[MMW LOCK] TryDetect目标 {currentlyTrackedTargetId} 滑动窗口稳定 (率: {successRate:P2}).");
+ else Debug.WriteLine($"[MMW LOCK] TryDetect目标 {currentlyTrackedTargetId} 滑动窗口不稳定 (率: {successRate:P2}).");
}
- }
+ else
+ {
+ lockOverallSuccess = currentFrameSuccessForLock;
+ Debug.WriteLine($"[MMW LOCK] TryDetect目标 {currentlyTrackedTargetId} 窗口未满. lockOverallSuccess = currentFrameSuccessForLock ({currentFrameSuccessForLock}).");
+ }
+
+ targetPosition = lockOverallSuccess ?
+ (currentFrameSuccessForLock ? target.KState!.Position : (LastTargetPosition ?? Vector3D.Zero)) :
+ Vector3D.Zero;
+ UpdateStateAndPotentiallySwitchMode(lockOverallSuccess, localSnrDb, currentlyTrackedTargetId, targetPosition, deltaTime);
+ return lockOverallSuccess;
}
}
- UpdateSystemState(foundTarget, currentSNR_dB, deltaTime);
- HasTarget = foundTarget;
- return foundTarget;
+ Debug.WriteLine($"[MMW {currentMode.ToString().ToUpper()}] TryDetect循环结束,未在switch中返回。");
+ UpdateStateAndPotentiallySwitchMode(false, double.MinValue, currentlyTrackedTargetId, Vector3D.Zero, deltaTime);
+ targetPosition = Vector3D.Zero;
+ return false;
}
- ///
- /// 更新系统状态
- ///
- private void UpdateSystemState(bool hasTarget, double snr, double deltaTime)
+ private void UpdateStateAndPotentiallySwitchMode(bool frameSuccess, double snr, string? newOrCurrentTargetId, Vector3D newOrCurrentPosition, double deltaTime)
{
- if (!hasTarget)
+ HasTarget = frameSuccess;
+ lastDetailSnrForDecision = snr;
+
+ if (frameSuccess && newOrCurrentPosition != Vector3D.Zero)
{
- targetLostTimer += deltaTime;
- if (targetLostTimer >= config.TargetLostTolerance)
+ LastTargetPosition = newOrCurrentPosition;
+ }
+
+ if (!frameSuccess)
+ {
+ if (currentMode == WorkMode.Track || currentMode == WorkMode.Lock)
{
+ Debug.WriteLine($"[MMW {currentMode.ToString().ToUpper()}] UpdateState判定目标丢失/不稳定 (frameSuccess=false),切换到搜索模式。");
SwitchToSearchMode();
}
return;
}
- targetLostTimer = 0;
-
switch (currentMode)
{
case WorkMode.Search:
- if (snr >= config.RecognitionSNRThreshold)
+ if (newOrCurrentTargetId != null)
{
+ currentlyTrackedTargetId = newOrCurrentTargetId;
+ Debug.WriteLine($"[MMW SEARCH] UpdateState确认目标 {newOrCurrentTargetId},准备切换到Track。");
SwitchToTrackMode();
}
+ else
+ {
+ Debug.WriteLine("[MMW SEARCH] Warning: UpdateState收到Search成功但无TargetId。");
+ }
break;
case WorkMode.Track:
- if (snr >= config.LockSNRThreshold)
+ lockConfirmationTimer += deltaTime;
+ Debug.WriteLine($"[MMW TRACK] UpdateState目标 {currentlyTrackedTargetId} 跟踪稳定. Lock确认计时: {lockConfirmationTimer:F2}s / {config.LockConfirmationTime:F2}s. SNR决策值: {snr:F2}dB");
+ if (lockConfirmationTimer >= config.LockConfirmationTime)
{
- lockConfirmationTimer += deltaTime;
- if (lockConfirmationTimer >= config.LockConfirmationTime)
- {
- SwitchToLockMode();
- }
- }
- else
- {
- lockConfirmationTimer = 0;
+ Debug.WriteLine($"[MMW TRACK] UpdateState达到锁定持续时间. 切换到Lock模式.");
+ SwitchToLockMode();
}
break;
case WorkMode.Lock:
- if (snr < config.LockSNRThreshold)
- {
- SwitchToTrackMode();
- }
+ Debug.WriteLine($"[MMW LOCK] UpdateState目标 {currentlyTrackedTargetId} 锁定稳定. SNR决策值: {snr:F2}dB");
break;
}
}
@@ -877,3 +904,7 @@ namespace ThreatSource.Guidance
}
}
+
+
+
+
diff --git a/ThreatSource/src/MIssile/CompositeGuidedMissile.cs b/ThreatSource/src/MIssile/CompositeGuidedMissile.cs
index 341a057..dd32b17 100644
--- a/ThreatSource/src/MIssile/CompositeGuidedMissile.cs
+++ b/ThreatSource/src/MIssile/CompositeGuidedMissile.cs
@@ -431,7 +431,7 @@ namespace ThreatSource.Missile
///
protected virtual void UpdateCruiseStage(double deltaTime)
{
- if (FlightTime >= Properties.CruiseTime)
+ if (FlightTime >= Properties.CruiseTime + Properties.MaxEngineBurnTime)
{
currentFlightStage = CompositeFlightStage.Terminal;
}
diff --git a/ThreatSource/src/MIssile/InfraredImagingTerminalGuidedMissile.cs b/ThreatSource/src/MIssile/InfraredImagingTerminalGuidedMissile.cs
index 286b3c8..85e8be2 100644
--- a/ThreatSource/src/MIssile/InfraredImagingTerminalGuidedMissile.cs
+++ b/ThreatSource/src/MIssile/InfraredImagingTerminalGuidedMissile.cs
@@ -168,7 +168,7 @@ namespace ThreatSource.Missile
private void UpdateCruiseStage(double deltaTime)
{
// 如果巡航时间达到,切换到末制导搜索阶段
- if (FlightTime > Properties.CruiseTime)
+ if (FlightTime > Properties.CruiseTime + Properties.MaxEngineBurnTime)
{
currentStage = IRTG_Stage.Terminal;
guidanceSystem.Activate();
diff --git a/ThreatSource/src/MIssile/MillimeterWaveTerminalGuidedMissile.cs b/ThreatSource/src/MIssile/MillimeterWaveTerminalGuidedMissile.cs
index daff4f4..a1177b4 100644
--- a/ThreatSource/src/MIssile/MillimeterWaveTerminalGuidedMissile.cs
+++ b/ThreatSource/src/MIssile/MillimeterWaveTerminalGuidedMissile.cs
@@ -161,7 +161,7 @@ namespace ThreatSource.Missile
///
private void UpdateCruiseStage(double deltaTime)
{
- if (FlightTime > Properties.CruiseTime)
+ if (FlightTime > Properties.CruiseTime + Properties.MaxEngineBurnTime)
{
currentStage = MWTG_Stage.Terminal;
guidanceSystem.Activate(); // 激活制导系统