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