From 6e990f65a442c520c68bfcf06e361b489bd287c9 Mon Sep 17 00:00:00 2001 From: Tian jianyong <11429339@qq.com> Date: Tue, 22 Apr 2025 16:27:15 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E4=BA=86=E7=83=9F=E5=B9=95?= =?UTF-8?q?=E5=AF=B9=E6=AF=AB=E7=B1=B3=E6=B3=A2=E5=88=B6=E5=AF=BC=E5=AF=BC?= =?UTF-8?q?=E5=BC=B9=E7=9A=84=E5=BD=B1=E5=93=8D=EF=BC=8C=E5=AE=8C=E5=96=84?= =?UTF-8?q?=E4=BA=86=E4=B8=80=E4=BA=9B=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 4 + .../src/Indicator/LaserBeamRiderTests.cs | 21 +- .../src/Jamming/LaserBeamRiderJammingTests.cs | 2 +- ...SemiActiveGuidedMissileIntegrationTests.cs | 376 ------------------ .../Guidance/InfraredCommandGuidanceSystem.cs | 56 ++- .../src/Guidance/InfraredImageGenerator.cs | 64 --- .../Guidance/InfraredImagingGuidanceSystem.cs | 75 +++- .../src/Guidance/InfraredTargetRecognizer.cs | 24 +- .../Guidance/LaserBeamRiderGuidanceSystem.cs | 109 ++--- .../Guidance/LaserSemiActiveGuidanceSystem.cs | 34 +- .../Guidance/MillimeterWaveGuidanceSystem.cs | 153 +++++-- ThreatSource/src/Indicator/LaserBeamRider.cs | 7 +- .../src/MIssile/LaserBeamRiderMissile.cs | 27 +- .../src/Simulation/SimulationEvents.cs | 37 +- VERSION | 2 +- tools/ComprehensiveMissileSimulator.cs | 14 +- 16 files changed, 311 insertions(+), 694 deletions(-) delete mode 100644 ThreatSource.Tests/src/Missile/LaserSemiActiveGuidedMissileIntegrationTests.cs diff --git a/CHANGELOG.md b/CHANGELOG.md index 0700469..78d627c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,10 @@ - 毫米波跟踪和锁定阶段采用脉冲多普勒制导、目标 RCS 特征矩阵 - 多种发射弹道模式:低平弹道、高抛弹道、俯冲弹道 - 双模、多模制导 +- 烟幕弹对毫米波末制导、末敏弹、激光目标指示器、激光驾束仪、红外指令制导指令发射端的干扰 + +## [0.2.12] - 2025-04-18 +- 改进了红外成像制导的目标识别和烟幕弹干扰算法 ## [0.2.11] - 2025-04-14 - 增加了激光诱偏目标的干扰功能 diff --git a/ThreatSource.Tests/src/Indicator/LaserBeamRiderTests.cs b/ThreatSource.Tests/src/Indicator/LaserBeamRiderTests.cs index 3f3ec61..39c340b 100644 --- a/ThreatSource.Tests/src/Indicator/LaserBeamRiderTests.cs +++ b/ThreatSource.Tests/src/Indicator/LaserBeamRiderTests.cs @@ -60,6 +60,7 @@ namespace ThreatSource.Tests.Indicator _simulationManager ); _simulationManager.RegisterEntity("beamRider1", _laserBeamRider); + _simulationManager.RegisterEntity("target1", _tank); } [Fact] @@ -78,14 +79,20 @@ namespace ThreatSource.Tests.Indicator [Fact] public void Activate_SetsCorrectState() { + // Arrange + _testAdapter.ClearEvents(); // 确保开始时事件列表是空的 + // Act _laserBeamRider.Activate(); // Assert Assert.True(_laserBeamRider.IsActive); Assert.True(_laserBeamRider.IsBeamOn); - var publishedEvents = _testAdapter.GetPublishedEvents(); - Assert.Contains(publishedEvents, evt => evt is LaserBeamStartEvent); + var publishedEvents = _testAdapter.GetPublishedEvents(); // 获取 Activate 产生的事件 + // 注意: Activate 可能发布 LaserBeamStartEvent 和 IndicatorActivatedEvent + Assert.Contains(publishedEvents, evt => evt is LaserBeamEvent); // 确认发布了 LaserBeamEvent + // 可以选择性地添加对 IndicatorActivatedEvent 的检查 + // Assert.Contains(publishedEvents, evt => evt is IndicatorActivatedEvent); } [Fact] @@ -93,6 +100,7 @@ namespace ThreatSource.Tests.Indicator { // Arrange _laserBeamRider.Activate(); + _testAdapter.ClearEvents(); // 清除 Activate 产生的事件 // Act _laserBeamRider.Deactivate(); @@ -100,7 +108,8 @@ namespace ThreatSource.Tests.Indicator // Assert Assert.False(_laserBeamRider.IsActive); Assert.False(_laserBeamRider.IsBeamOn); - var publishedEvents = _testAdapter.GetPublishedEvents(); + var publishedEvents = _testAdapter.GetPublishedEvents(); // 获取 Deactivate 产生的事件 + // 注意: Deactivate 可能发布 LaserBeamStopEvent 和 IndicatorDeactivatedEvent Assert.Contains(publishedEvents, evt => evt is LaserBeamStopEvent); } @@ -109,14 +118,14 @@ namespace ThreatSource.Tests.Indicator { // Arrange _laserBeamRider.Activate(); - _testAdapter.GetPublishedEvents(); // 清除之前的事件 + _testAdapter.ClearEvents(); // 清除 Activate 产生的事件 // Act _laserBeamRider.Update(0.1); // Assert - var publishedEvents = _testAdapter.GetPublishedEvents(); - Assert.Contains(publishedEvents, evt => evt is LaserBeamUpdateEvent); + var publishedEvents = _testAdapter.GetPublishedEvents(); // 获取 Update 产生的事件 + Assert.Contains(publishedEvents, evt => evt is LaserBeamEvent); // 用户确认 Update 发布 LaserBeamEvent } [Fact] diff --git a/ThreatSource.Tests/src/Jamming/LaserBeamRiderJammingTests.cs b/ThreatSource.Tests/src/Jamming/LaserBeamRiderJammingTests.cs index de9a561..1fff7ce 100644 --- a/ThreatSource.Tests/src/Jamming/LaserBeamRiderJammingTests.cs +++ b/ThreatSource.Tests/src/Jamming/LaserBeamRiderJammingTests.cs @@ -144,7 +144,7 @@ namespace ThreatSource.Tests.Jamming // Assert - 干扰清除后激光束应该恢复 Assert.IsFalse(_laserBeamRider.IsJammed, "干扰已清除,激光驾束仪应该恢复正常"); Assert.IsTrue(_laserBeamRider.IsBeamOn, "干扰清除后激光束应该重新开启"); - Assert.IsTrue(publishedEvents.Any(evt => evt is LaserBeamStartEvent), "应该发布激光束开始事件"); + Assert.IsTrue(publishedEvents.Any(evt => evt is LaserBeamEvent), "应该发布激光束开始事件"); } [TestMethod] diff --git a/ThreatSource.Tests/src/Missile/LaserSemiActiveGuidedMissileIntegrationTests.cs b/ThreatSource.Tests/src/Missile/LaserSemiActiveGuidedMissileIntegrationTests.cs deleted file mode 100644 index c8683ba..0000000 --- a/ThreatSource.Tests/src/Missile/LaserSemiActiveGuidedMissileIntegrationTests.cs +++ /dev/null @@ -1,376 +0,0 @@ -using Xunit; -using ThreatSource.Missile; -using ThreatSource.Simulation; -using ThreatSource.Utils; -using ThreatSource.Tests.Simulation; -using ThreatSource.Guidance; -using ThreatSource.Indicator; -using ThreatSource.Equipment; -using ThreatSource.Sensor; -using System; -using System.Reflection; - -namespace ThreatSource.Tests.Missile -{ - /// - /// 激光半主动导弹集成测试类 - /// - /// - /// 该测试类验证激光半主动导弹的整体性能: - /// - 验证导弹能否在正常条件下命中目标 - /// - 验证导弹在低功率条件下的行为 - /// - 验证导弹在干扰环境下的表现 - /// - public class LaserSemiActiveGuidedMissileIntegrationTests - { - private readonly SimulationManager _simulationManager; - private readonly TestSimulationAdapter _testAdapter; - private readonly LaserSemiActiveGuidedMissile _missile; - private readonly MissileProperties _properties; - private readonly LaserDesignator _laserDesignator; - private readonly MockTarget _target; - - // 定义命中距离阈值(米) - private const double HIT_THRESHOLD = 10.0; - - // 定义最大模拟时间(秒) - private const double MAX_SIMULATION_TIME = 30.0; - - // 定义模拟时间步长(秒) - private const double TIME_STEP = 0.025; - - public LaserSemiActiveGuidedMissileIntegrationTests() - { - _simulationManager = new SimulationManager(); - _testAdapter = new TestSimulationAdapter(_simulationManager); - _simulationManager.SetSimulationAdapter(_testAdapter); - - _properties = new MissileProperties - { - MaxSpeed = 1000, - MaxFlightTime = 100, - MaxFlightDistance = 10000, - MaxAcceleration = 50, - ProportionalNavigationCoefficient = 3, - Mass = 100, - ExplosionRadius = 10, - HitProbability = 0.9, - Type = MissileType.LaserSemiActiveGuidance - }; - - var missileInitialMotion = new MotionParameters - { - Position = new Vector3D(0, 0, 0), - Orientation = new Orientation(0, 0, 0), - InitialSpeed = 100 - }; - - var laserDesignatorInitialMotion = new MotionParameters - { - Position = new Vector3D(-100, 0, 0), - Orientation = new Orientation(0, 0, 0), - InitialSpeed = 0 - }; - - // 创建并注册激光指示器,位置在导弹后方100米处 - var laserDesignatorConfig = new LaserDesignatorConfig - { - LaserPower = 100, - LaserDivergenceAngle = 0.001, - LaserWavelength = 1.06 - }; - - _laserDesignator = new LaserDesignator( - "laser1", - "target1", - "missile1", - laserDesignatorConfig, - laserDesignatorInitialMotion, - _simulationManager - ); - _testAdapter.AddTestEntity("laser1", _laserDesignator); - _simulationManager.RegisterEntity("laser1", _laserDesignator); - - // 创建并注册模拟的目标,位置在导弹前方1000米处 - var targetInitialMotion = new MotionParameters - { - Position = new Vector3D(1000, 0, 0), - Orientation = new Orientation(0, 0, 0), - InitialSpeed = 0 - }; - _target = new MockTarget("target1", targetInitialMotion, _simulationManager); - _testAdapter.AddTestEntity("target1", _target); - - // 创建激光代码配置 - var laserCodeConfig = new LaserCodeConfig - { - Code = new LaserCode - { - CodeType = LaserCodeType.PRF, - CodeValue = 1234 - } - }; - - // 创建导引系统配置 - var guidanceConfig = new LaserSemiActiveGuidanceConfig - { - FieldOfViewAngle = 30, - LensDiameter = 0.1, - SensorDiameter = 0.03, - FocusedSpotDiameter = 0.006, - ReflectionCoefficient = 0.2, - TargetReflectiveArea = 1.0, - LockThreshold = 1e-12, - SpotOffsetSensitivity = 0.5 - }; - - // 创建导弹并注册到仿真管理器 - _missile = new LaserSemiActiveGuidedMissile( - "missile1", - _properties, - missileInitialMotion, - laserCodeConfig, - guidanceConfig, - _simulationManager - ); - _testAdapter.AddTestEntity("missile1", _missile); - _simulationManager.RegisterEntity("missile1", _missile); - } - - // 模拟的目标类 - private class MockTarget : Tank - { - public MockTarget(string id, MotionParameters motionParameters, ISimulationManager simulationManager) - : base(id, new EquipmentProperties(), motionParameters, simulationManager) - { - // 不需要额外设置属性,因为基类构造函数已经设置了 - } - } - - /// - /// 模拟导弹飞行过程,直到命中目标或超时 - /// - /// 激光功率 - /// 导弹与目标之间的最小距离 - private double SimulateMissileFlight(double laserPower) - { - _laserDesignator.LaserPower = laserPower; - - // 激活激光指示器(如果尚未激活) - if (!_laserDesignator.IsActive) - { - _laserDesignator.Activate(); // Activate方法内部会启动激光照射 - } - - // 手动创建并发布激光照射开始事件,确保事件被正确传递到制导系统 - var illuminationEvent = new LaserIlluminationUpdateEvent - { - LaserDesignatorId = _laserDesignator.Id, - TargetId = _target.Id, - LaserCodeConfig = new LaserCodeConfig - { - Code = new LaserCode - { - CodeType = LaserCodeType.PPM, - CodeValue = 1234 - } - } - }; - _simulationManager.PublishEvent(illuminationEvent); - - // 发射导弹 - _missile.Fire(); - _missile.Activate(); - - double minDistance = double.MaxValue; - double simulationTime = 0; - - // 模拟导弹飞行,直到命中目标或超时 - while (simulationTime < MAX_SIMULATION_TIME) - { - // 更新导弹状态 - _missile.Update(TIME_STEP); - _laserDesignator.Update(TIME_STEP); // Update方法内部会发布激光照射更新事件 - - // 手动发布激光照射更新事件,确保事件被正确传递到制导系统 - var updateEvent = new LaserIlluminationUpdateEvent - { - LaserDesignatorId = _laserDesignator.Id, - TargetId = _target.Id, - LaserCodeConfig = new LaserCodeConfig - { - Code = new LaserCode - { - CodeType = LaserCodeType.PPM, - CodeValue = 1234 - } - } - }; - _simulationManager.PublishEvent(updateEvent); - // 计算导弹与目标之间的距离 - double distance = (_missile.Position - _target.Position).Magnitude(); - - // 更新最小距离 - minDistance = Math.Min(minDistance, distance); - - // 如果导弹已经命中目标,则结束模拟 - if (distance <= HIT_THRESHOLD) - { - Console.WriteLine($"导弹命中目标!时间:{simulationTime:F1}秒,距离:{distance:F2}米"); - break; - } - - // 获取导弹状态 - string status = _missile.GetStatus(); - bool isExploded = status.Contains("爆炸阶段"); - bool isSelfDestructed = status.Contains("自毁阶段"); - - // 如果导弹已经爆炸或自毁,则结束模拟 - if (isExploded || isSelfDestructed) - { - Console.WriteLine($"导弹已{(isExploded ? "爆炸" : "自毁")}!时间:{simulationTime:F1}秒,距离:{distance:F2}米"); - break; - } - - // 更新模拟时间 - simulationTime += TIME_STEP; - } - - // 停用激光指示器,这会自动停止激光照射 - _laserDesignator.Deactivate(); - - if (simulationTime >= MAX_SIMULATION_TIME) - { - Console.WriteLine($"模拟超时!最小距离:{minDistance:F2}米"); - } - - return minDistance; - } - - [Fact] - public void Missile_NormalConditions_HitsTarget() - { - // 使用正常激光功率模拟导弹飞行 - double minDistance = SimulateMissileFlight(100.0); - - // 断言导弹能够命中目标 - Assert.True(minDistance <= HIT_THRESHOLD, $"导弹未能命中目标,最小距离:{minDistance:F2}米"); - } - - [Fact] - public void Missile_LowLaserPower_FailsToHitTarget() - { - // 使用低于锁定阈值的激光功率模拟导弹飞行 - // 根据计算,锁定阈值对应的激光功率约为0.159瓦特,使用其一半的值 - double minDistance = SimulateMissileFlight(0.079); - - // 由于导弹初始方向已偏离目标,在低功率条件下应无法校正轨道 - // 断言导弹无法命中目标 - Assert.True(minDistance > HIT_THRESHOLD, $"导弹在低功率条件下仍然命中了目标,最小距离:{minDistance:F2}米"); - } - - [Fact] - public void Missile_NoLaserPower_FailsToHitTarget() - { - // 使用零激光功率模拟导弹飞行 - double minDistance = SimulateMissileFlight(0.0); - - // 输出最小距离 - Console.WriteLine($"导弹在无激光信号条件下与目标的最小距离:{minDistance:F2}米"); - - // 由于导弹初始方向已偏离目标,在无激光信号条件下应无法校正轨道 - // 断言导弹无法命中目标 - Assert.True(minDistance > HIT_THRESHOLD, $"导弹在无激光信号条件下仍然命中了目标,最小距离:{minDistance:F2}米"); - } - - [Fact] - public void Missile_IntermittentLaserPower_StillHitsTarget() - { - // 设置初始激光功率 - _laserDesignator.LaserPower = 100.0; - - // 确保激光指示器处于激活状态 - if (!_laserDesignator.IsActive) - { - _laserDesignator.Activate(); - } - - // 发射导弹 - _missile.Fire(); - _missile.Activate(); - - double minDistance = double.MaxValue; - double simulationTime = 0; - - // 模拟导弹飞行,激光功率间歇性变化 - while (simulationTime < MAX_SIMULATION_TIME) - { - // 每2秒切换一次激光功率 - if ((int)(simulationTime / 2) % 2 == 0) - { - _laserDesignator.LaserPower = 100.0; // 高功率 - } - else - { - // 使用低于锁定阈值的激光功率(约为0.159瓦特的一半) - _laserDesignator.LaserPower = 0.079; - } - - // 更新导弹状态 - _missile.Update(TIME_STEP); - _laserDesignator.Update(TIME_STEP); - - // 手动发布激光照射更新事件,确保事件被正确传递到制导系统 - var updateEvent = new LaserIlluminationUpdateEvent - { - LaserDesignatorId = _laserDesignator.Id, - TargetId = _target.Id, - LaserCodeConfig = new LaserCodeConfig - { - Code = new LaserCode - { - CodeType = LaserCodeType.PPM, - CodeValue = 1234 - } - } - }; - _simulationManager.PublishEvent(updateEvent); - - // 计算导弹与目标之间的距离 - double distance = (_missile.Position - _target.Position).Magnitude(); - - // 更新最小距离 - minDistance = Math.Min(minDistance, distance); - - // 如果导弹已经命中目标,则结束模拟 - if (distance <= HIT_THRESHOLD) - { - Console.WriteLine($"导弹命中目标!时间:{simulationTime:F1}秒,距离:{distance:F2}米"); - break; - } - - // 获取导弹状态 - string status = _missile.GetStatus(); - bool isExploded = status.Contains("爆炸阶段"); - bool isSelfDestructed = status.Contains("自毁阶段"); - - // 如果导弹已经爆炸或自毁,则结束模拟 - if (isExploded || isSelfDestructed) - { - Console.WriteLine($"导弹已{(isExploded ? "爆炸" : "自毁")}!时间:{simulationTime:F1}秒,距离:{distance:F2}米"); - break; - } - - // 更新模拟时间 - simulationTime += TIME_STEP; - } - - // 停用激光指示器 - _laserDesignator.Deactivate(); - - // 即使在间歇性激光照射下,导弹仍应能够命中目标 - // 断言导弹能够在间歇性激光照射下命中目标 - Assert.True(minDistance <= HIT_THRESHOLD, $"导弹在间歇性激光照射下未能命中目标,最小距离:{minDistance:F2}米"); - } - } -} \ No newline at end of file diff --git a/ThreatSource/src/Guidance/InfraredCommandGuidanceSystem.cs b/ThreatSource/src/Guidance/InfraredCommandGuidanceSystem.cs index 8a22a79..07985ae 100644 --- a/ThreatSource/src/Guidance/InfraredCommandGuidanceSystem.cs +++ b/ThreatSource/src/Guidance/InfraredCommandGuidanceSystem.cs @@ -18,31 +18,31 @@ namespace ThreatSource.Guidance public class InfraredCommandGuidanceSystem : BasicGuidanceSystem { /// - /// 跟踪器到导弹的方向向量 + /// 跟踪器到导弹的方向向量 (使用可空类型) /// /// /// 记录上一次接收到的跟踪器指向导弹的方向 /// 用于计算导弹的相对位置 /// - private Vector3D lastTrackerToMissileVector; + private Vector3D? lastTrackerToMissileVector { get; set; } /// - /// 跟踪器到目标的方向向量 + /// 跟踪器到目标的方向向量 (使用可空类型) /// /// /// 记录上一次接收到的跟踪器指向目标的方向 /// 用于计算目标的相对位置 /// - private Vector3D lastTrackerToTargetVector; + private Vector3D? lastTrackerToTargetVector { get; set; } /// - /// 上一次的期望飞行方向 + /// 上一次的期望飞行方向 (使用可空类型) /// /// /// 记录上一次计算的期望飞行方向 /// 用于计算转向速率 /// - private Vector3D lastDesiredDirection; + private Vector3D? lastDesiredDirection { get; set; } /// /// 当前转向速率,单位:弧度/秒 @@ -90,9 +90,6 @@ namespace ThreatSource.Guidance public InfraredCommandGuidanceSystem(string id, InfraredCommandGuidanceConfig guidanceConfig, double maxAcceleration, double guidanceCoefficient, ISimulationManager simulationManager) : base(id, maxAcceleration, guidanceCoefficient, simulationManager) { - lastTrackerToMissileVector = Vector3D.Zero; - lastTrackerToTargetVector = Vector3D.Zero; - lastDesiredDirection = Vector3D.Zero; turnRate = 0; InitializeJamming(guidanceConfig.JammingResistanceThreshold, [JammingType.Infrared]); } @@ -120,12 +117,20 @@ namespace ThreatSource.Guidance else { GuidanceAcceleration = Vector3D.Zero; + lastTrackerToMissileVector = null; + lastTrackerToTargetVector = null; + lastDesiredDirection = null; + turnRate = 0; } } else { HasGuidance = false; GuidanceAcceleration = Vector3D.Zero; + lastTrackerToMissileVector = null; + lastTrackerToTargetVector = null; + lastDesiredDirection = null; + turnRate = 0; } } @@ -161,29 +166,34 @@ namespace ThreatSource.Guidance /// protected void CalculateGuidanceAcceleration(double deltaTime) { - // 计算期望飞行方向(从导弹指向目标) + if (lastTrackerToMissileVector == null || lastTrackerToTargetVector == null) + { + GuidanceAcceleration = Vector3D.Zero; + HasGuidance = false; + return; + } + Vector3D currentDesiredDirection = (lastTrackerToTargetVector - lastTrackerToMissileVector).Normalize(); - // 计算当前飞行方向 Vector3D currentDirection = Velocity.Normalize(); - // 更新转向速率 - if (lastDesiredDirection != Vector3D.Zero) + + if (lastDesiredDirection != null && deltaTime > 0) { double instantTurnRate = Vector3D.CrossProduct(lastDesiredDirection, currentDesiredDirection).Magnitude() / deltaTime; turnRate = turnRate * (1 - TurnRateSmoothingFactor) + instantTurnRate * TurnRateSmoothingFactor; } + else + { + turnRate = 0; + } - // 计算带有提前量的期望方向 Vector3D leadDirection = Vector3D.CrossProduct(currentDesiredDirection, Vector3D.CrossProduct(currentDesiredDirection, currentDirection).Normalize()); Vector3D desiredDirectionWithLead = (currentDesiredDirection + leadDirection * turnRate * LeadTimeFactor).Normalize(); - // 计算转向轴 Vector3D turnAxis = Vector3D.CrossProduct(currentDirection, desiredDirectionWithLead).Normalize(); - // 计算所需转向角度 double turnAngle = Vector3D.AngleBetween(currentDirection, desiredDirectionWithLead); - // 计算制导加速度 double accelerationMagnitude = ProportionalNavigationCoefficient * turnAngle * Velocity.Magnitude(); GuidanceAcceleration = Vector3D.CrossProduct(turnAxis, currentDirection) * accelerationMagnitude; - // 限制最大加速度 + if (GuidanceAcceleration.Magnitude() > MaxAcceleration) { GuidanceAcceleration = GuidanceAcceleration.Normalize() * MaxAcceleration; @@ -205,9 +215,15 @@ namespace ThreatSource.Guidance /// public override string GetStatus() { + string angleStr = "null"; + if (lastTrackerToTargetVector != null && lastTrackerToMissileVector != null) + { + angleStr = Vector3D.AngleBetween(lastTrackerToTargetVector, lastTrackerToMissileVector).ToString("F3"); + } + return base.GetStatus() + - $" 转向角度: {Vector3D.AngleBetween(lastTrackerToTargetVector, lastTrackerToMissileVector)} 弧度," + - $" 转向速率: {turnRate} 弧度/秒"; + $" 转向角度: {angleStr} 弧度," + + $" 转向速率: {turnRate:F3} 弧度/秒"; } } } diff --git a/ThreatSource/src/Guidance/InfraredImageGenerator.cs b/ThreatSource/src/Guidance/InfraredImageGenerator.cs index 8477d35..f64ec68 100644 --- a/ThreatSource/src/Guidance/InfraredImageGenerator.cs +++ b/ThreatSource/src/Guidance/InfraredImageGenerator.cs @@ -372,8 +372,6 @@ namespace ThreatSource.Guidance if (thermalPattern == null) { Console.WriteLine($"警告: 目标 {target.Id} 未提供 ThermalPattern,无法生成基于模式的强度。"); - // Fallback or return? For now, let's just log and potentially result in a black target area. - // Alternatively, could fallback to the old Gaussian model here. return; } @@ -453,68 +451,6 @@ namespace ThreatSource.Guidance } Console.WriteLine($"目标基于ThermalPattern强度分布: 像素设置: {pixelsSet}, 最大强度: {maxSetIntensity:F6} W/sr"); - - // --- 结束: 使用 ThermalPattern 重构 --- - - /* --- 保留旧的高斯模型代码以供参考 --- - // 计算目标自身应有的辐射强度(未被遮挡时) - double targetBaseIntensity = target.Properties.InfraredRadiationIntensity * transmittance / Math.Pow(distance, 1.8); - - // 计算高斯分布参数 - double sigmaX = pixelLength / 6.0; // 标准差设为长度/宽度的1/6,覆盖约99.7%范围 - double sigmaY = pixelWidth / 6.0; - - // 避免除以零 - sigmaX = Math.Max(sigmaX, 1e-6); - sigmaY = Math.Max(sigmaY, 1e-6); - - int halfLength = pixelLength / 2; - int halfWidth = pixelWidth / 2; - - int pixelsSet = 0; - double maxSetIntensity = 0; - - // 设置强度分布 - for (int dy = -halfWidth; dy <= halfWidth; dy++) - { - int y = centerY + dy; - if (y < 0 || y >= image.Height) continue; - - for (int dx = -halfLength; dx <= halfLength; dx++) - { - int x = centerX + dx; - if (x < 0 || x >= image.Width) continue; - - double finalIntensity; - double smokeIntensity = smokeIntensityLayer[y, x]; - - if (smokeIntensity >= 0) // 检查此像素是否被遮蔽烟幕覆盖 - { - // 如果被覆盖,使用烟幕的强度 - finalIntensity = smokeIntensity; - } - else - { - // 如果未被覆盖,计算目标的强度 - // 计算归一化距离 (相对于高斯分布中心) - double normalizedX = dx / sigmaX; - double normalizedY = dy / sigmaY; - double r2 = normalizedX * normalizedX + normalizedY * normalizedY; - - // 计算高斯分布下的目标强度 - finalIntensity = targetBaseIntensity * Math.Exp(-r2 / 2.0); - // Console.WriteLine($"像素 ({x},{y}) 未被烟幕覆盖,使用目标强度: {finalIntensity:F6}"); - } - - // 设置最终计算出的强度到图像 - image.SetIntensity(y, x, finalIntensity); - pixelsSet++; - maxSetIntensity = Math.Max(maxSetIntensity, finalIntensity); - } - } - - Console.WriteLine($"目标/烟幕强度分布: 像素设置: {pixelsSet}, 最大强度: {maxSetIntensity:F6} W/sr"); - */ } /// diff --git a/ThreatSource/src/Guidance/InfraredImagingGuidanceSystem.cs b/ThreatSource/src/Guidance/InfraredImagingGuidanceSystem.cs index f5e3485..3c08125 100644 --- a/ThreatSource/src/Guidance/InfraredImagingGuidanceSystem.cs +++ b/ThreatSource/src/Guidance/InfraredImagingGuidanceSystem.cs @@ -53,13 +53,13 @@ namespace ThreatSource.Guidance public bool IsInLockMode => currentMode == WorkMode.Lock; /// - /// 上一次探测到的目标位置 + /// 上一次探测到的目标位置 (使用可空类型) /// /// /// 记录目标的历史位置 /// 用于计算目标速度 /// - private Vector3D lastTargetPosition; + private Vector3D? lastTargetPosition { get; set; } // Changed to nullable Vector3D? /// /// 红外图像生成器 @@ -123,10 +123,9 @@ namespace ThreatSource.Guidance ) : base(id, maxAcceleration, proportionalNavigationCoefficient, simulationManager) { - lastTargetPosition = Vector3D.Zero; this.targetType = targetType; config = guidanceConfig; - targetRecognizer = new InfraredTargetRecognizer(simulationManager); + targetRecognizer = new InfraredTargetRecognizer(); // 首先创建图像生成器 imageGenerator = new InfraredImageGenerator( @@ -192,8 +191,24 @@ namespace ThreatSource.Guidance { if (SimulationManager.GetEntityById(parameters.JammerId) is SmokeGrenade smokeGrenade) { - // 计算烟幕衰减 - SmokeAttenuation = smokeGrenade.GetSmokeTransmittanceOnLine(Position, lastTargetPosition, config.WaveLength); + // Check lastTargetPosition != null before using it + if (lastTargetPosition != null) + { + // 计算烟幕衰减 (这里存储衰减系数,1.0表示无衰减) + SmokeAttenuation = smokeGrenade.GetSmokeTransmittanceOnLine(Position, lastTargetPosition, config.WaveLength); + Debug.WriteLine($"[烟幕干扰应用 IR] 视线透过率/衰减系数: {SmokeAttenuation:F3}"); + } + else + { + // 目标尚未有效跟踪,无法计算特定视线衰减,假定无衰减 + SmokeAttenuation = 1.0; + Debug.WriteLine("[烟幕干扰应用 IR] 目标位置无效,暂不计算烟幕衰减。"); + } + } + else + { + // 未找到烟幕弹,假定无衰减 + SmokeAttenuation = 1.0; } } } @@ -211,6 +226,16 @@ namespace ThreatSource.Guidance base.HandleJammingCleared(type); // 干扰清除后的恢复逻辑 } + else if (type == JammingType.SmokeScreen) + { + SmokeAttenuation = 1.0; // Reset smoke attenuation + Debug.WriteLine("[烟幕干扰清除 IR]"); + base.HandleJammingCleared(type); + } + else + { + base.HandleJammingCleared(type); + } } /// @@ -234,6 +259,13 @@ namespace ThreatSource.Guidance base.Deactivate(); SimulationManager.UnsubscribeFromEvent(OnInfraredJamming); SimulationManager.UnsubscribeFromEvent(OnSmokeScreen); + lastTargetPosition = null; // Add reset to null + HasTarget = false; + HasGuidance = false; + GuidanceAcceleration = Vector3D.Zero; + // Optionally reset timers? + // targetLostTimer = 0; + // lockConfirmationTimer = 0; } /// @@ -289,15 +321,28 @@ namespace ThreatSource.Guidance base.Update(deltaTime, missilePosition, missileVelocity); if (!IsHardJammed) { - if (TryDetectAndIdentifyTarget(missilePosition, missileVelocity, deltaTime, out Vector3D tankPosition)) + if (TryDetectAndIdentifyTarget(missilePosition, missileVelocity, deltaTime, out Vector3D currentTargetPosition)) { targetLostTimer = 0; // 重置丢失计时器 - //根据目标当前位置和上一次位置计算目标速度 - Vector3D targetVelocity = (tankPosition - lastTargetPosition) / deltaTime; - lastTargetPosition = tankPosition; + Vector3D? currentTargetVelocity = null; // Initialize as nullable + // Check lastTargetPosition != null before calculating velocity + if(lastTargetPosition != null && deltaTime > 0) + { + // Remove cast, use lastTargetPosition directly + currentTargetVelocity = (currentTargetPosition - lastTargetPosition) / deltaTime; + } + + // Update last known position (assign non-nullable to nullable) + lastTargetPosition = currentTargetPosition; - // 使用比例控制算法 - GuidanceAcceleration = MotionAlgorithm.CalculateProportionalNavigation(ProportionalNavigationCoefficient, missilePosition, missileVelocity, tankPosition, targetVelocity); + // Use proportional navigation, provide default if velocity is null + GuidanceAcceleration = MotionAlgorithm.CalculateProportionalNavigation( + ProportionalNavigationCoefficient, + missilePosition, + missileVelocity, + currentTargetPosition, // Non-nullable from out parameter + currentTargetVelocity ?? Vector3D.Zero // Provide default if null + ); // 限制最大加速度 if (GuidanceAcceleration.Magnitude() > MaxAcceleration) { @@ -330,6 +375,7 @@ namespace ThreatSource.Guidance else { GuidanceAcceleration = Vector3D.Zero; + HasGuidance = false; } } @@ -347,6 +393,7 @@ namespace ThreatSource.Guidance currentMode = WorkMode.Search; HasTarget = false; targetLostTimer = 0; // 重置丢失计时器 + lastTargetPosition = null; // Add reset to null // 创建图像生成器 imageGenerator = new InfraredImageGenerator( @@ -529,8 +576,10 @@ namespace ThreatSource.Guidance /// public override string GetStatus() { + // Check for null before calling ToString() + string lastPosStr = lastTargetPosition != null ? lastTargetPosition.ToString() : "null"; return base.GetStatus() + $", GuidanceAcceleration: {GuidanceAcceleration}, " + - $"Target Position: {lastTargetPosition}"; + $"Target Position: {lastPosStr}"; } } } diff --git a/ThreatSource/src/Guidance/InfraredTargetRecognizer.cs b/ThreatSource/src/Guidance/InfraredTargetRecognizer.cs index 1b50632..8a0dacb 100644 --- a/ThreatSource/src/Guidance/InfraredTargetRecognizer.cs +++ b/ThreatSource/src/Guidance/InfraredTargetRecognizer.cs @@ -58,32 +58,16 @@ namespace ThreatSource.Guidance /// public class InfraredTargetRecognizer { - /// - /// 仿真管理器实例 - /// - private readonly ISimulationManager simulationManager; - /// /// 目标特征数据库 /// private readonly Dictionary targetFeatures; - /// - /// 识别阈值 - /// - private const double RECOGNITION_THRESHOLD = 0.7; - - /// - /// 背景辐射强度,用于阈值计算 - /// - private const double BACKGROUND_INTENSITY = 0.0001; - /// /// 初始化红外图像目标识别器 /// - public InfraredTargetRecognizer(ISimulationManager simulationManager) + public InfraredTargetRecognizer() { - this.simulationManager = simulationManager; // 初始化目标特征数据库 - 使用相对特征值 targetFeatures = new Dictionary { @@ -324,13 +308,10 @@ namespace ThreatSource.Guidance double mean = sum / count; // --- 修改为基于动态范围的阈值计算 --- - double thresholdFactor = 0.05; // 基于动态范围的因子 (初始值设为0.15, 从 0.05 改为 0.01) + double thresholdFactor = 0.05; // 基于动态范围的因子 double dynamicRange = maxIntensity - minIntensity; double threshold = minIntensity + dynamicRange * thresholdFactor; - // 添加一个小的偏移量,以确保阈值严格大于最小强度,避免将所有背景像素包含进来 - // double epsilon = 1e-9; - // threshold = Math.Max(threshold, minIntensity + epsilon); // 确保阈值至少比最小值大一点点 Console.WriteLine($"图像统计:"); Console.WriteLine($" 最大强度: {maxIntensity:F6}"); @@ -339,7 +320,6 @@ namespace ThreatSource.Guidance Console.WriteLine($" 动态范围: {dynamicRange:F6}"); Console.WriteLine($" 动态阈值因子: {thresholdFactor:P1}"); Console.WriteLine($" 最终阈值: {threshold:F6}"); - // --- 结束修改 --- return threshold; } diff --git a/ThreatSource/src/Guidance/LaserBeamRiderGuidanceSystem.cs b/ThreatSource/src/Guidance/LaserBeamRiderGuidanceSystem.cs index dab1ca0..0e1339d 100644 --- a/ThreatSource/src/Guidance/LaserBeamRiderGuidanceSystem.cs +++ b/ThreatSource/src/Guidance/LaserBeamRiderGuidanceSystem.cs @@ -20,22 +20,22 @@ namespace ThreatSource.Guidance public class LaserBeamRiderGuidanceSystem : BasicGuidanceSystem { /// - /// 获取或设置激光源位置 + /// 获取或设置激光源位置 (使用可空类型) /// /// /// 记录激光发射源的三维位置 /// 用于计算导弹与激光束的相对位置 /// - private Vector3D LaserSourcePosition { get; set; } + private Vector3D? LaserSourcePosition { get; set; } /// - /// 获取或设置激光方向 + /// 获取或设置激光方向 (使用可空类型) /// /// /// 记录激光束的传播方向 /// 用于计算导弹与激光束的偏差 /// - private Vector3D LaserDirection { get; set; } + private Vector3D? LaserDirection { get; set; } /// /// 获取或设置激光指示器激光功率,单位:瓦特 @@ -46,36 +46,6 @@ namespace ThreatSource.Guidance /// public double LaserPower { get; set; } - /// - /// 最小可探测功率,单位:瓦特 - /// - /// - /// 定义了探测器的灵敏度阈值 - /// 低于此值时无法有效探测 - /// 典型值为1e-10瓦 - /// - private const double MinDetectablePower = 1e-10; - - /// - /// 探测器直径,单位:米 - /// - /// - /// 定义了探测器的物理尺寸 - /// 影响系统的接收能力 - /// 典型值为0.03米 - /// - private const double DetectorDiameter = 0.03; - - /// - /// 控制场直径,单位:米 - /// - /// - /// 定义了有效制导范围 - /// 超出此范围将失去制导 - /// 典型值为6米 - /// - private const double ControlFieldDiameter = 6.0; - /// /// 上一次的误差向量 /// @@ -175,8 +145,6 @@ namespace ThreatSource.Guidance : base(id, maxAcceleration, guidanceCoefficient, simulationManager) { config = guidanceConfig; - LaserSourcePosition = Vector3D.Zero; - LaserDirection = Vector3D.Zero; LaserPower = 0; LaserIlluminationOn = false; LastError = Vector3D.Zero; @@ -205,7 +173,7 @@ namespace ThreatSource.Guidance base.Activate(); // 在这里订阅事件,确保只订阅一次 SimulationManager.SubscribeToEvent(OnLaserJamming); - SimulationManager.SubscribeToEvent(OnLaserBeamStart); + SimulationManager.SubscribeToEvent(OnLaserBeamStart); SimulationManager.SubscribeToEvent(OnLaserBeamStop); } @@ -217,7 +185,7 @@ namespace ThreatSource.Guidance base.Deactivate(); // 取消订阅事件 SimulationManager.UnsubscribeFromEvent(OnLaserJamming); - SimulationManager.UnsubscribeFromEvent(OnLaserBeamStart); + SimulationManager.UnsubscribeFromEvent(OnLaserBeamStart); SimulationManager.UnsubscribeFromEvent(OnLaserBeamStop); } @@ -350,10 +318,11 @@ namespace ThreatSource.Guidance /// public void DeactivateLaserBeam() { - LaserSourcePosition = Vector3D.Zero; - LaserDirection = Vector3D.Zero; + LaserSourcePosition = null; + LaserDirection = null; LaserPower = 0; HasGuidance = false; + LaserIlluminationOn = false; } /// @@ -411,11 +380,16 @@ namespace ThreatSource.Guidance /// private void UpdateGuidanceStatus() { - // 计算导弹到激光束的最短距离 + if (LaserSourcePosition == null) + { + HasGuidance = false; + Trace.WriteLine($"激光驾束引导系统: 失去引导, 原因: 激光源位置未知"); + return; + } + Vector3D shortestDistanceVector = CalculateShortestDistanceToLaserBeam(); double shortestDistance = shortestDistanceVector.Magnitude(); - // 检查导弹是否在控制场内 if (shortestDistance > config.ControlFieldDiameter / 2) { HasGuidance = false; @@ -425,11 +399,9 @@ namespace ThreatSource.Guidance Debug.WriteLine($"激光驾束引导系统: 在控制场内, 距离: {shortestDistance}"); - // 计算导弹到激光源的距离 Vector3D missileToSource = LaserSourcePosition - Position; double distance = missileToSource.Magnitude(); - // 计算接收到的激光功率 double receivedPower = CalculateReceivedLaserPower(distance); Debug.WriteLine($"激光驾束引导系统: 接收到的激光功率: {receivedPower:E} W"); @@ -498,53 +470,48 @@ namespace ThreatSource.Guidance /// - 合成最终制导指令 /// - 应用低通滤波 /// - protected void CalculateGuidanceAcceleration(double deltaTime) + protected void CalculateGuidanceAcceleration(double deltaTime) { - // 计算导弹到激光束的最短距离 + if (LaserDirection == null) + { + GuidanceAcceleration = Vector3D.Zero; + LastError = Vector3D.Zero; + IntegralError = Vector3D.Zero; + return; + } + Vector3D shortestDistanceVector = CalculateShortestDistanceToLaserBeam(); - // PID控制 Vector3D error = shortestDistanceVector; - // 积分项 IntegralError += error * deltaTime; - // 微分项 Vector3D derivativeError = (error - LastError) / deltaTime; - // 计算PID输出 Vector3D pidOutput = error * config.ProportionalGain + IntegralError * config.IntegralGain + derivativeError * config.DerivativeGain; - // 非线性增益 double distance = shortestDistanceVector.Magnitude(); double nonLinearGain = Math.Tanh(distance / config.NonlinearGain); - // 计算横向加速度 Vector3D lateralAcceleration = pidOutput * nonLinearGain; - // 限制最大加速度 if (lateralAcceleration.Magnitude() > config.MaxGuidanceAcceleration) { lateralAcceleration = lateralAcceleration.Normalize() * config.MaxGuidanceAcceleration; } - // 计算前向加速度 Vector3D forwardDirection = LaserDirection; Vector3D currentDirection = Velocity.Normalize(); Vector3D rotationAxis = Vector3D.CrossProduct(currentDirection, forwardDirection); double rotationAngle = Math.Acos(Vector3D.DotProduct(currentDirection, forwardDirection)); Vector3D forwardAcceleration = Vector3D.CrossProduct(rotationAxis, Velocity) * rotationAngle * ProportionalNavigationCoefficient; - // 合并横向和前向加速度 GuidanceAcceleration = lateralAcceleration + forwardAcceleration; - - // 低通滤波 GuidanceAcceleration = GuidanceAcceleration * config.LowPassFilterCoefficient + LastGuidanceAcceleration * (1 - config.LowPassFilterCoefficient); - // 更新上一次的误差和制导加速度 LastError = error; LastGuidanceAcceleration = GuidanceAcceleration; } @@ -572,7 +539,6 @@ namespace ThreatSource.Guidance Debug.WriteLine($"激光驾束制导系统干扰状态 - IsJammed: {IsJammed}, 干扰功率: {evt.JammingPower}W, 抗性阈值: {config.JammingResistanceThreshold}W"); } - /// /// 处理系统被干扰的事件 /// @@ -621,7 +587,10 @@ namespace ThreatSource.Guidance /// public override string GetStatus() { - return base.GetStatus() + $"激光指示器功率: {LaserPower:E} W," + $" 激光照射状态: {LaserIlluminationOn}"; + string sourcePosStr = LaserSourcePosition != null ? LaserSourcePosition.ToString() : "null"; + string directionStr = LaserDirection != null ? LaserDirection.ToString() : "null"; + return base.GetStatus() + $", SourcePos: {sourcePosStr}, Direction: {directionStr}, " + + $"LaserPower: {LaserPower:E} W, Illumination: {LaserIlluminationOn}"; } /// @@ -637,16 +606,14 @@ namespace ThreatSource.Guidance /// private Vector3D CalculateShortestDistanceToLaserBeam() { - // 计算导弹到激光源的向量 + if (LaserSourcePosition == null || LaserDirection == null) + { + return Vector3D.Zero; + } + Vector3D missileToSource = LaserSourcePosition - Position; - - // 计算导弹在激光方向上的投影长度 double projectionLength = Vector3D.DotProduct(missileToSource, LaserDirection); - - // 计算激光束上最接近导弹的点 Vector3D closestPointOnBeam = LaserSourcePosition - LaserDirection * projectionLength; - - // 计算导弹到激光束最近点的向量(即最短距离向量) Vector3D shortestDistanceVector = closestPointOnBeam - Position; return shortestDistanceVector; @@ -656,22 +623,22 @@ namespace ThreatSource.Guidance /// 处理激光波束开始事件 /// /// 激光波束开始事件 - private void OnLaserBeamStart(LaserBeamStartEvent evt) + private void OnLaserBeamStart(LaserBeamEvent evt) { if(evt?.LaserBeamRiderId != null && evt.LaserCodeConfig != null) { if(evt.LaserCodeConfig.IsCodeEnabled) { - // 检查编码是否匹配 bool codeMatched = CheckLaserCode(evt.LaserCodeConfig); if (!codeMatched) { - // 发布编码不匹配事件 PublishCodeMismatchEvent(evt.LaserBeamRiderId, evt.LaserCodeConfig); Debug.WriteLine("激光驾束制导系统接收到不匹配的激光编码,忽略信号"); HasGuidance = false; LaserIlluminationOn = false; + LaserSourcePosition = null; + LaserDirection = null; return; } } @@ -691,6 +658,8 @@ namespace ThreatSource.Guidance { LaserIlluminationOn = false; HasGuidance = false; + LaserSourcePosition = null; + LaserDirection = null; } } } diff --git a/ThreatSource/src/Guidance/LaserSemiActiveGuidanceSystem.cs b/ThreatSource/src/Guidance/LaserSemiActiveGuidanceSystem.cs index 433e5e9..3e8120f 100644 --- a/ThreatSource/src/Guidance/LaserSemiActiveGuidanceSystem.cs +++ b/ThreatSource/src/Guidance/LaserSemiActiveGuidanceSystem.cs @@ -24,13 +24,13 @@ namespace ThreatSource.Guidance private readonly LaserSemiActiveGuidanceConfig config; /// - /// 获取或设置目标位置 + /// 获取或设置目标位置 (使用可空类型) /// /// /// 记录当前跟踪目标的三维位置 /// 用于制导计算 /// - private Vector3D TargetPosition { get; set; } + private Vector3D? TargetPosition { get; set; } /// /// 获取或设置接收到的激光功率 @@ -150,7 +150,6 @@ namespace ThreatSource.Guidance { config = guidanceConfig; - TargetPosition = Vector3D.Zero; LaserIlluminationOn = false; InternalLaserCodeConfig = laserCodeConfig; @@ -217,6 +216,7 @@ namespace ThreatSource.Guidance // 取消订阅诱偏目标照射事件 SimulationManager.UnsubscribeFromEvent(OnLaserDecoy); SimulationManager.UnsubscribeFromEvent(OnLaserDecoyStop); + TargetPosition = null; } /// @@ -261,6 +261,7 @@ namespace ThreatSource.Guidance LaserIlluminationOn = false; HasGuidance = false; // 禁用制导 PreviousGuidanceAcceleration = Vector3D.Zero; // 重置历史加速度 + TargetPosition = null; } /// @@ -320,7 +321,7 @@ namespace ThreatSource.Guidance if (IsHardJammed) { // 清除目标信息 - TargetPosition = Vector3D.Zero; + TargetPosition = null; LaserIlluminationOn = false; // 记录干扰信息 Trace.WriteLine($"激光半主动制导系统被硬干扰 - 功率: {evt.JammingPower}W, 位置: {evt.JammingSourcePosition}, 方向: {evt.JammingDirection}"); @@ -381,11 +382,24 @@ namespace ThreatSource.Guidance { if (SimulationManager.GetEntityById(parameters.JammerId) is SmokeGrenade smokeGrenade) { - // 计算烟幕衰减 - if (LaserIlluminationOn) + // 检查目标位置是否有效,并且激光照射是否开启 (烟幕只影响接收到的信号) + if (TargetPosition != null && LaserIlluminationOn) { + // 计算烟幕衰减 (1.0 表示无衰减) SmokeAttenuation = smokeGrenade.GetSmokeTransmittanceOnLine(Position, TargetPosition, config.LaserWavelength); + Console.WriteLine($"[烟幕干扰应用 Laser] 视线透过率/衰减系数: {SmokeAttenuation:F3}"); } + else + { + // 目标无效或激光未照射,暂不计算特定视线衰减 + SmokeAttenuation = 1.0; + Console.WriteLine("[烟幕干扰应用 Laser] 目标位置无效或激光未照射,暂不计算烟幕衰减。"); + } + } + else + { + // 未找到烟幕弹,假定无衰减 + SmokeAttenuation = 1.0; } } } @@ -623,7 +637,13 @@ namespace ThreatSource.Guidance /// private Vector2D CalculateSpotOffset() { - // 计算理想指向方向(从导弹到目标) + // Check TargetPosition != null before using it + if (TargetPosition == null) + { + return Vector2D.Zero; + } + + // No cast needed, just use TargetPosition directly Vector3D idealDirection = (TargetPosition - Position).Normalize(); // 计算当前导弹前向方向 diff --git a/ThreatSource/src/Guidance/MillimeterWaveGuidanceSystem.cs b/ThreatSource/src/Guidance/MillimeterWaveGuidanceSystem.cs index 3ba381f..f06eb97 100644 --- a/ThreatSource/src/Guidance/MillimeterWaveGuidanceSystem.cs +++ b/ThreatSource/src/Guidance/MillimeterWaveGuidanceSystem.cs @@ -1,4 +1,3 @@ - using ThreatSource.Utils; using ThreatSource.Equipment; using System.Diagnostics; @@ -51,22 +50,22 @@ namespace ThreatSource.Guidance private readonly Random random = new(); /// - /// 上一次探测到的目标位置 + /// 上一次探测到的目标位置 (使用可空类型) /// /// /// 记录目标的历史位置 /// 用于计算目标速度 /// - private Vector3D lastTargetPosition; + private Vector3D? lastTargetPosition { get; set; } /// - /// 上一次探测到的目标速度 + /// 上一次探测到的目标速度 (使用可空类型) /// /// /// 记录目标的历史速度 /// 用于计算目标速度 /// - private Vector3D lastTargetVelocity; + private Vector3D? lastTargetVelocity { get; set; } /// /// 目标丢失计时器 @@ -134,6 +133,10 @@ namespace ThreatSource.Guidance /// private double maxScanRadius => config.FieldOfViewAngle * Math.PI / 180.0 / 2; + /// + /// 当前视线的烟幕透过率 (0.0 - 1.0) + /// + private double _currentSmokeTransmittance = 1.0; /// @@ -161,10 +164,7 @@ namespace ThreatSource.Guidance : base(id, maxAcceleration, guidanceCoefficient, simulationManager) { this.config = config; - lastTargetPosition = Vector3D.Zero; - lastTargetVelocity = Vector3D.Zero; - - InitializeJamming(config.JammingResistanceThreshold, [JammingType.MillimeterWave]); + InitializeJamming(config.JammingResistanceThreshold, [JammingType.MillimeterWave, JammingType.SmokeScreen]); SwitchToSearchMode(); // 初始化为搜索模式 } @@ -180,6 +180,8 @@ namespace ThreatSource.Guidance lockConfirmationTimer = 0; currentScanAngle = 0; currentScanRadius = config.SearchBeamWidth * Math.PI / 720.0; // 从半个波束宽度的一半开始 + lastTargetPosition = null; + lastTargetVelocity = null; Trace.WriteLine($"切换到搜索模式,波束宽度: {config.SearchBeamWidth}度"); } @@ -214,7 +216,9 @@ namespace ThreatSource.Guidance IsActive = true; // 在这里订阅事件,确保只订阅一次 SimulationManager.SubscribeToEvent(OnMillimeterWaveJamming); - } + // 添加对烟幕事件的订阅 + SimulationManager.SubscribeToEvent(OnSmokeScreen); + } base.Activate(); SwitchToSearchMode(); } @@ -228,11 +232,15 @@ namespace ThreatSource.Guidance { IsActive = false; SimulationManager.UnsubscribeFromEvent(OnMillimeterWaveJamming); + // 添加取消对烟幕事件的订阅 + SimulationManager.UnsubscribeFromEvent(OnSmokeScreen); } base.Deactivate(); HasTarget = false; HasGuidance = false; GuidanceAcceleration = Vector3D.Zero; + lastTargetPosition = null; + lastTargetVelocity = null; } /// @@ -265,22 +273,77 @@ namespace ThreatSource.Guidance Debug.WriteLine($"毫米波导引头系统干扰状态 - IsJammed: {IsJammed}, 干扰功率: {evt.JammingPower}W, 抗性阈值: {config.JammingResistanceThreshold}W"); } + /// + /// 处理烟幕事件,触发干扰应用 + /// + /// 烟幕事件 + private void OnSmokeScreen(SmokeScreenEvent evt) + { + if (evt != null && evt.SmokeGrenadeId != null) + { + // 获取烟幕弹实例以创建干扰参数 + if (SimulationManager.GetEntityById(evt.SmokeGrenadeId) is SmokeGrenade smokeGrenade) + { + var parameters = new JammingParameters + { + Type = JammingType.SmokeScreen, + JammerId = smokeGrenade.Id, + SourcePosition = smokeGrenade.Position, + Direction = smokeGrenade.Orientation.ToVector(), + Mode = JammingMode.Obscuration // 表明是遮蔽干扰 + // JammableComponent可能需要其他烟幕属性,如果需要则从smokeGrenade.CurrentParameters获取 + }; + // 应用干扰效果,这将调用HandleJammingApplied + ApplyJamming(parameters); + } + } + } + /// /// 处理系统被干扰的事件 /// /// 干扰参数 protected override void HandleJammingApplied(JammingParameters parameters) { + // 1. 让基类处理通用硬干扰逻辑 (如果不是SmokeScreen, 会设置 IsHardJammed 和 HasGuidance = false) + base.HandleJammingApplied(parameters); + + // 2. 处理特定于毫米波的硬干扰响应 if (parameters.Type == JammingType.MillimeterWave) - { - Debug.WriteLine($"毫米波导引头系统受到毫米波干扰,功率:{parameters.Power}瓦特"); - // 确保基类的处理逻辑被调用,设置HasGuidance = false - base.HandleJammingApplied(parameters); + { + Debug.WriteLine($"毫米波导引头系统受到毫米波干扰,功率:{parameters.Power}瓦特"); + // 在硬干扰下切换到搜索模式 (即使基类已设置HasGuidance=false, 仍可切换模式) + if (currentMode != WorkMode.Search) + { + SwitchToSearchMode(); + } } - // 在强干扰下切换到搜索模式 - if (currentMode != WorkMode.Search) + // 3. 处理烟幕干扰 (计算透过率,不直接影响 IsHardJammed 或 HasGuidance) + else if (parameters.Type == JammingType.SmokeScreen) { - SwitchToSearchMode(); + if (SimulationManager.GetEntityById(parameters.JammerId) is SmokeGrenade smokeGrenade) + { + // Check lastTargetPosition != null before using it + if (lastTargetPosition != null) + { + // 计算波长 + double wavelength = 3e8 / config.WaveFrequency; + // 计算视线透过率 + _currentSmokeTransmittance = smokeGrenade.GetSmokeTransmittanceOnLine(Position, lastTargetPosition, wavelength); + Debug.WriteLine($"[烟幕干扰应用 MMW] 视线透过率: {_currentSmokeTransmittance:F3}"); + } + else + { + // 目标尚未有效跟踪,无法计算特定视线衰减,假定无衰减 + _currentSmokeTransmittance = 1.0; + Debug.WriteLine("[烟幕干扰应用 MMW] 目标位置无效,暂不计算烟幕衰减。"); + } + } + else + { + // 未找到烟幕弹,假定无衰减 + _currentSmokeTransmittance = 1.0; + } } } @@ -290,11 +353,21 @@ namespace ThreatSource.Guidance /// 被清除的干扰类型 protected override void HandleJammingCleared(JammingType type) { - if (type == JammingType.MillimeterWave) + // 1. 处理特定于烟幕的清除逻辑 + if (type == JammingType.SmokeScreen) { - Debug.WriteLine("毫米波导引头系统干扰被清除"); - base.HandleJammingCleared(type); + _currentSmokeTransmittance = 1.0; // 重置透过率 + Debug.WriteLine("[烟幕干扰清除 MMW]"); } + else if (type == JammingType.MillimeterWave) + { + Debug.WriteLine("毫米波导引头系统干扰被清除"); + // 毫米波硬干扰清除的具体行为由基类处理 + } + + // 2. 最后调用基类方法处理通用清除逻辑 + // 基类会检查是否所有干扰都已清除,并相应地更新 IsHardJammed 和 HasGuidance + base.HandleJammingCleared(type); } /// @@ -452,25 +525,28 @@ namespace ThreatSource.Guidance base.Update(deltaTime, missilePosition, missileVelocity); - if (!IsJammed) + if (!IsHardJammed) { - if (TryDetectAndTrackTarget(missilePosition, missileVelocity, deltaTime, out Vector3D targetPosition)) + if (TryDetectAndTrackTarget(missilePosition, missileVelocity, deltaTime, out Vector3D currentTargetPosition)) { targetLostTimer = 0; - Vector3D targetVelocity = (targetPosition - lastTargetPosition) / deltaTime; - lastTargetPosition = targetPosition; - lastTargetVelocity = targetVelocity; + Vector3D? currentTargetVelocity = null; + if (lastTargetPosition != null && deltaTime > 0) + { + currentTargetVelocity = (currentTargetPosition - lastTargetPosition) / deltaTime; + } + + lastTargetPosition = currentTargetPosition; + lastTargetVelocity = currentTargetVelocity; - // 使用比例导引计算制导加速度 GuidanceAcceleration = MotionAlgorithm.CalculateProportionalNavigation( ProportionalNavigationCoefficient, missilePosition, missileVelocity, - targetPosition, - targetVelocity + currentTargetPosition, + currentTargetVelocity ?? Vector3D.Zero ); - // 限制最大加速度 if (GuidanceAcceleration.Magnitude() > MaxAcceleration) { GuidanceAcceleration = GuidanceAcceleration.Normalize() * MaxAcceleration; @@ -484,7 +560,6 @@ namespace ThreatSource.Guidance if (currentMode != WorkMode.Search) { targetLostTimer += deltaTime; - // 如果目标丢失时间达到阈值,切换回搜索模式 if (targetLostTimer >= config.TargetLostTolerance) { HasGuidance = false; @@ -528,7 +603,6 @@ namespace ThreatSource.Guidance bool foundTarget = false; double currentSNR = double.MinValue; - // 如果被干扰,直接返回false if (isJammed) { Trace.WriteLine($"毫米波导引头受到干扰,干扰功率: {jammingPower:F2}W"); @@ -545,13 +619,11 @@ namespace ThreatSource.Guidance if (distance <= config.MaxDetectionRange) { - // 计算信噪比 double snr = CalculateSNR(distance, target.Properties.RadarCrossSection); Console.WriteLine($"信噪比: {snr:F2}dB"); if (currentMode == WorkMode.Search) { - // 在搜索模式下进行波束判断 if (IsTargetInBeam(missileVelocity, toTarget) && snr >= config.RecognitionSNRThreshold) { targetPosition = target.Position; @@ -562,11 +634,10 @@ namespace ThreatSource.Guidance } else if (currentMode == WorkMode.Track || currentMode == WorkMode.Lock) { - // 波束内判断 if (IsTargetInBeam(missileVelocity, toTarget) && + lastTargetPosition != null && Vector3D.Distance(target.Position, lastTargetPosition) < 100.0) { - // 在跟踪模式下,SNR至少要达到识别阈值 double requiredSNR = (currentMode == WorkMode.Track) ? config.RecognitionSNRThreshold : config.LockSNRThreshold; @@ -588,9 +659,7 @@ namespace ThreatSource.Guidance } } - // 根据当前模式和探测结果更新系统状态 UpdateSystemState(foundTarget, currentSNR, deltaTime); - HasTarget = foundTarget; return foundTarget; } @@ -657,10 +726,13 @@ namespace ThreatSource.Guidance /// public override string GetStatus() { + string lastPosStr = lastTargetPosition != null ? lastTargetPosition.ToString() : "null"; + string lastVelStr = lastTargetVelocity != null ? lastTargetVelocity.ToString() : "null"; + return base.GetStatus() + $"\n当前模式: {currentMode}" + - $"\n目标位置: {lastTargetPosition}" + - $"\n目标速度: {lastTargetVelocity}" + + $"\n最后目标位置: {lastPosStr}" + + $"\n最后目标速度: {lastVelStr}" + $"\n是否有目标: {HasTarget}"; } @@ -713,6 +785,9 @@ namespace ThreatSource.Guidance signalPower *= atmosphericTransmittance; + // 应用当前生效的烟幕衰减 (通过存储的透过率) + signalPower *= _currentSmokeTransmittance; + // 计算噪声功率 double noisePower = k * T0 * bandwidth * noiseFigure; diff --git a/ThreatSource/src/Indicator/LaserBeamRider.cs b/ThreatSource/src/Indicator/LaserBeamRider.cs index 1d787f4..b9795ea 100644 --- a/ThreatSource/src/Indicator/LaserBeamRider.cs +++ b/ThreatSource/src/Indicator/LaserBeamRider.cs @@ -182,6 +182,7 @@ namespace ThreatSource.Indicator Vector3D targetPosition = target.Position; LaserDirection = (targetPosition - Position).Normalize(); Debug.WriteLine($"激光驾束仪 {Id} 更新激光指向: {LaserDirection}"); + PublishLaserBeamEvent(); } } } @@ -287,7 +288,7 @@ namespace ThreatSource.Indicator { LaserDirection = (target.Position - Position).Normalize(); IsBeamOn = true; - PublishLaserBeamStartEvent(); + PublishLaserBeamEvent(); } } } @@ -318,9 +319,9 @@ namespace ThreatSource.Indicator /// 通知仿真系统激光波束开始工作 /// 包含制导器ID等关键信息 /// - private void PublishLaserBeamStartEvent() + private void PublishLaserBeamEvent() { - PublishEvent(new LaserBeamStartEvent + PublishEvent(new LaserBeamEvent { LaserBeamRiderId = Id }); diff --git a/ThreatSource/src/MIssile/LaserBeamRiderMissile.cs b/ThreatSource/src/MIssile/LaserBeamRiderMissile.cs index 4a40a2f..473fdb2 100644 --- a/ThreatSource/src/MIssile/LaserBeamRiderMissile.cs +++ b/ThreatSource/src/MIssile/LaserBeamRiderMissile.cs @@ -96,26 +96,7 @@ namespace ThreatSource.Missile /// - 更新波束参数 /// - 开始波束跟踪 /// - private void OnLaserBeamStart(LaserBeamStartEvent evt) - { - if (evt?.LaserBeamRiderId != null) - { - LaserBeamRider laserBeamRider = SimulationManager.GetEntityById(evt.LaserBeamRiderId) as LaserBeamRider ?? throw new Exception("激光驾束仪不存在"); - guidanceSystem?.UpdateLaserBeamRider(laserBeamRider.Position, laserBeamRider.LaserDirection, laserBeamRider.LaserPower); - } - } - - /// - /// 处理激光束更新事件 - /// - /// 激光束更新事件数据 - /// - /// 处理过程: - /// - 验证激光驾束仪 - /// - 更新波束位置和方向 - /// - 更新制导参数 - /// - private void OnLaserBeamUpdate(LaserBeamUpdateEvent evt) + private void OnLaserBeamEvent(LaserBeamEvent evt) { if (evt?.LaserBeamRiderId != null) { @@ -235,9 +216,8 @@ namespace ThreatSource.Missile // 激活制导系统 guidanceSystem.Activate(); // 订阅激光波束事件 - SimulationManager.SubscribeToEvent(OnLaserBeamStart); + SimulationManager.SubscribeToEvent(OnLaserBeamEvent); SimulationManager.SubscribeToEvent(OnLaserBeamStop); - SimulationManager.SubscribeToEvent(OnLaserBeamUpdate); } /// @@ -255,9 +235,8 @@ namespace ThreatSource.Missile // 停用制导系统 guidanceSystem.Deactivate(); // 取消订阅波束事件 - SimulationManager.UnsubscribeFromEvent(OnLaserBeamStart); + SimulationManager.UnsubscribeFromEvent(OnLaserBeamEvent); SimulationManager.UnsubscribeFromEvent(OnLaserBeamStop); - SimulationManager.UnsubscribeFromEvent(OnLaserBeamUpdate); } /// diff --git a/ThreatSource/src/Simulation/SimulationEvents.cs b/ThreatSource/src/Simulation/SimulationEvents.cs index b3968d7..7779079 100644 --- a/ThreatSource/src/Simulation/SimulationEvents.cs +++ b/ThreatSource/src/Simulation/SimulationEvents.cs @@ -242,42 +242,7 @@ namespace ThreatSource.Simulation /// 用于通知系统激光波束开始照射 /// 触发时机:激光驾束仪开始工作时 /// - public class LaserBeamStartEvent : SimulationEvent - { - /// - /// 获取或设置激光驾束仪的ID - /// - /// - /// 标识发出激光波束的驾束仪设备 - /// - public string? LaserBeamRiderId { get; set; } - - /// - /// 获取或设置波束功率 - /// - /// - /// 激光波束的发射功率 - /// - public double BeamPower { get; set; } - - /// - /// 获取或设置激光编码配置 - /// - /// - /// 包含激光信号的编码信息 - /// 用于抗干扰和安全识别 - /// - public LaserCodeConfig? LaserCodeConfig { get; set; } - } - - /// - /// 激光波束更新事件,表示激光波束状态的更新 - /// - /// - /// 用于实时更新激光波束的状态 - /// 在波束照射过程中周期性触发 - /// - public class LaserBeamUpdateEvent : SimulationEvent + public class LaserBeamEvent : SimulationEvent { /// /// 获取或设置激光驾束仪的ID diff --git a/VERSION b/VERSION index f8112eb..25cd22b 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.2.11 \ No newline at end of file +0.2.12 \ No newline at end of file diff --git a/tools/ComprehensiveMissileSimulator.cs b/tools/ComprehensiveMissileSimulator.cs index dfcc38e..e1d664a 100644 --- a/tools/ComprehensiveMissileSimulator.cs +++ b/tools/ComprehensiveMissileSimulator.cs @@ -250,7 +250,7 @@ namespace ThreatSource.Tools.MissileSimulation { var motionParameters = new MotionParameters { - Position = new Vector3D(2000, 1, 50), + Position = new Vector3D(2000, 1, 30), Orientation = new Orientation(Math.PI, 0.02, 0), InitialSpeed = 300 }; @@ -268,7 +268,7 @@ namespace ThreatSource.Tools.MissileSimulation { var motionParameters = new MotionParameters { - Position = new Vector3D(3000, 1, 20), + Position = new Vector3D(2000, 1, 20), Orientation = new Orientation(Math.PI, 0.01, 0), InitialSpeed = 300 }; @@ -383,16 +383,6 @@ namespace ThreatSource.Tools.MissileSimulation indicators["LD_1"].Activate(); } Console.WriteLine($"干扰器数量 {jammers.Count}"); - // if (jammers.ContainsKey("LDY_1")) - // { - // jammers["LDY_1"].Activate(); - // Console.WriteLine($"激活激光诱偏目标 {jammers["LDY_1"].Id}"); - // } - if (jammers.ContainsKey("SG_1")) - { - //jammers["SG_1"].Activate(); - Console.WriteLine($"激活烟幕弹 {jammers["SG_1"].Id}"); - } break; case "LBRM_1": // 激光驾束制导导弹 if (indicators.ContainsKey("LBR_1"))