diff --git a/CHANGELOG.md b/CHANGELOG.md index 207eb2c..8abba49 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,14 @@ - 增加大气透过率影响 - 毫米波和红外图像制导的传感器和引导律 +## [0.2.6] - 2025-03-07 + +### 功能优化 +- 增加了各组件的默认参数配置,放在data目录下,以 json 格式存储 +- 可以选择导弹型号,读取对应的组件参数配置 +- 优化了各组件的初始化参数列表,增加了初始运动参数 + + ## [0.2.5] - 2025-02-26 ### 功能优化 - 增加了激光半主动导弹的四象限探测器 diff --git a/ThreatSource.Tests/src/Guidance/LaserSemiActiveGuidanceSystemCodeTests.cs b/ThreatSource.Tests/src/Guidance/LaserSemiActiveGuidanceSystemCodeTests.cs index 4a22a5a..7a03f9e 100644 --- a/ThreatSource.Tests/src/Guidance/LaserSemiActiveGuidanceSystemCodeTests.cs +++ b/ThreatSource.Tests/src/Guidance/LaserSemiActiveGuidanceSystemCodeTests.cs @@ -2,7 +2,7 @@ using Xunit; using ThreatSource.Guidance; using ThreatSource.Simulation; using ThreatSource.Utils; -using ThreatSource.Simulation.Testing; +using ThreatSource.Tests.Simulation; namespace ThreatSource.Tests.Guidance { diff --git a/ThreatSource.Tests/src/Indicator/InfraredTrackerTests.cs b/ThreatSource.Tests/src/Indicator/InfraredTrackerTests.cs index 9b218ae..0a04475 100644 --- a/ThreatSource.Tests/src/Indicator/InfraredTrackerTests.cs +++ b/ThreatSource.Tests/src/Indicator/InfraredTrackerTests.cs @@ -2,7 +2,7 @@ using Xunit; using ThreatSource.Indicator; using ThreatSource.Simulation; using ThreatSource.Utils; -using ThreatSource.Simulation.Testing; +using ThreatSource.Tests.Simulation; using ThreatSource.Target; using ThreatSource.Missile; @@ -189,23 +189,18 @@ namespace ThreatSource.Tests.Indicator public void EntityDeactivation_StopsTracking() { // Arrange - _infraredTracker.Activate(); - - // 创建导弹配置 - var missileConfig = new MissileProperties + var missileProperties = new MissileProperties { Id = "missile1", - InitialPosition = new Vector3D(50, 0, 0), - MaxAcceleration = 100, - ProportionalNavigationCoefficient = 3 + InitialPosition = new Vector3D(100, 0, 0), + InitialSpeed = 100, + Type = MissileType.InfraredCommandGuidance }; - - // 注册一个导弹实体并激活 - var missile = new InfraredCommandGuidedMissile(missileConfig, _simulationManager); + var missile = new InfraredCommandGuidedMissile(missileProperties, _simulationManager); _simulationManager.RegisterEntity("missile1", missile); missile.Activate(); - - // 先让导弹点亮 + + // 发送红外辐射事件 _simulationManager.PublishEvent(new InfraredGuidanceMissileLightEvent { SenderId = "missile1", @@ -214,16 +209,10 @@ namespace ThreatSource.Tests.Indicator }); _infraredTracker.Update(0.1); - // Act - 停用导弹 - missile.Deactivate(); // 直接停用导弹对象 - _simulationManager.PublishEvent(new EntityDeactivatedEvent - { - DeactivatedEntityId = "missile1", - SenderId = "system", - Timestamp = DateTime.UtcNow.Ticks - }); + // Act - 直接停用导弹 + missile.Deactivate(); - // 给系统一些时间处理事件 + // 更新系统状态 _infraredTracker.Update(0.1); missile.Update(0.1); _infraredTracker.Update(0.1); diff --git a/ThreatSource.Tests/src/Indicator/LaserBeamRiderTests.cs b/ThreatSource.Tests/src/Indicator/LaserBeamRiderTests.cs index d3f7254..98feaf6 100644 --- a/ThreatSource.Tests/src/Indicator/LaserBeamRiderTests.cs +++ b/ThreatSource.Tests/src/Indicator/LaserBeamRiderTests.cs @@ -2,7 +2,7 @@ using Xunit; using ThreatSource.Indicator; using ThreatSource.Simulation; using ThreatSource.Utils; -using ThreatSource.Simulation.Testing; +using ThreatSource.Tests.Simulation; using ThreatSource.Target; namespace ThreatSource.Tests.Indicator diff --git a/ThreatSource.Tests/src/Indicator/LaserDesignatorCodeTests.cs b/ThreatSource.Tests/src/Indicator/LaserDesignatorCodeTests.cs index ecb54b9..6329160 100644 --- a/ThreatSource.Tests/src/Indicator/LaserDesignatorCodeTests.cs +++ b/ThreatSource.Tests/src/Indicator/LaserDesignatorCodeTests.cs @@ -2,7 +2,7 @@ using Xunit; using ThreatSource.Indicator; using ThreatSource.Simulation; using ThreatSource.Utils; -using ThreatSource.Simulation.Testing; +using ThreatSource.Tests.Simulation; using ThreatSource.Target; namespace ThreatSource.Tests.Indicator diff --git a/ThreatSource.Tests/src/Indicator/LaserDesignatorTests.cs b/ThreatSource.Tests/src/Indicator/LaserDesignatorTests.cs index 1f78c8a..94a2062 100644 --- a/ThreatSource.Tests/src/Indicator/LaserDesignatorTests.cs +++ b/ThreatSource.Tests/src/Indicator/LaserDesignatorTests.cs @@ -2,7 +2,7 @@ using Xunit; using ThreatSource.Indicator; using ThreatSource.Simulation; using ThreatSource.Utils; -using ThreatSource.Simulation.Testing; +using ThreatSource.Tests.Simulation; using ThreatSource.Target; namespace ThreatSource.Tests.Indicator @@ -120,23 +120,5 @@ namespace ThreatSource.Tests.Indicator Assert.Contains(part, status); } } - - [Fact] - public void EntityDeactivation_HandlesTargetDeactivationCorrectly() - { - // Arrange - _laserDesignator.Activate(); - - // Act - _simulationManager.PublishEvent(new EntityDeactivatedEvent - { - DeactivatedEntityId = "target1", - SenderId = "system" - }); - _laserDesignator.Update(0.1); - - // Assert - Assert.False(_laserDesignator.IsIlluminationOn); - } } } \ No newline at end of file diff --git a/ThreatSource.Tests/src/Jamming/JammingTests.cs b/ThreatSource.Tests/src/Jamming/JammingTests.cs index c8a82fd..44ade4c 100644 --- a/ThreatSource.Tests/src/Jamming/JammingTests.cs +++ b/ThreatSource.Tests/src/Jamming/JammingTests.cs @@ -3,7 +3,7 @@ using ThreatSource.Jamming; using ThreatSource.Sensor; using ThreatSource.Missile; using ThreatSource.Simulation; -using ThreatSource.Simulation.Testing; +using ThreatSource.Tests.Simulation; using ThreatSource.Target; using ThreatSource.Utils; using System.Linq; diff --git a/ThreatSource.Tests/src/Missile/BaseMissileTests.cs b/ThreatSource.Tests/src/Missile/BaseMissileTests.cs index ba02cd1..2afe711 100644 --- a/ThreatSource.Tests/src/Missile/BaseMissileTests.cs +++ b/ThreatSource.Tests/src/Missile/BaseMissileTests.cs @@ -2,7 +2,7 @@ using Xunit; using ThreatSource.Missile; using ThreatSource.Simulation; using ThreatSource.Utils; -using ThreatSource.Simulation.Testing; +using ThreatSource.Tests.Simulation; namespace ThreatSource.Tests.Missile { @@ -57,6 +57,9 @@ namespace ThreatSource.Tests.Missile [Fact] public void Fire_ActivatesMissile() { + // Arrange + _missile.Activate(); + // Act _missile.Fire(); @@ -68,6 +71,7 @@ namespace ThreatSource.Tests.Missile public void Update_UpdatesFlightParameters() { // Arrange + _missile.Activate(); _missile.Fire(); var initialPosition = _missile.Position; var deltaTime = 1.0; diff --git a/ThreatSource.Tests/src/Missile/InfraredCommandGuidedMissileTests.cs b/ThreatSource.Tests/src/Missile/InfraredCommandGuidedMissileTests.cs index e76d459..057ff71 100644 --- a/ThreatSource.Tests/src/Missile/InfraredCommandGuidedMissileTests.cs +++ b/ThreatSource.Tests/src/Missile/InfraredCommandGuidedMissileTests.cs @@ -2,7 +2,7 @@ using Xunit; using ThreatSource.Missile; using ThreatSource.Simulation; using ThreatSource.Utils; -using ThreatSource.Simulation.Testing; +using ThreatSource.Tests.Simulation; namespace ThreatSource.Tests.Missile { diff --git a/ThreatSource.Tests/src/Missile/InfraredImagingTerminalGuidedMissileTests.cs b/ThreatSource.Tests/src/Missile/InfraredImagingTerminalGuidedMissileTests.cs index 5d40544..eba824b 100644 --- a/ThreatSource.Tests/src/Missile/InfraredImagingTerminalGuidedMissileTests.cs +++ b/ThreatSource.Tests/src/Missile/InfraredImagingTerminalGuidedMissileTests.cs @@ -2,7 +2,7 @@ using Xunit; using ThreatSource.Missile; using ThreatSource.Simulation; using ThreatSource.Utils; -using ThreatSource.Simulation.Testing; +using ThreatSource.Tests.Simulation; using ThreatSource.Target; namespace ThreatSource.Tests.Missile @@ -134,8 +134,9 @@ namespace ThreatSource.Tests.Missile string status = _missile.GetStatus(); // Assert - Assert.Contains($"导弹 {_missile.Id}", status); - Assert.Contains("状态: 激活", status); + Assert.Contains("红外成像末制导导弹", status); + Assert.Contains(_missile.Id, status); + Assert.Contains("状态:", status); Assert.Contains("位置:", status); Assert.Contains("速度:", status); Assert.Contains("速度分量:", status); diff --git a/ThreatSource.Tests/src/Missile/LaserBeamRiderMissileTests.cs b/ThreatSource.Tests/src/Missile/LaserBeamRiderMissileTests.cs index a119c62..ab37995 100644 --- a/ThreatSource.Tests/src/Missile/LaserBeamRiderMissileTests.cs +++ b/ThreatSource.Tests/src/Missile/LaserBeamRiderMissileTests.cs @@ -2,7 +2,7 @@ using Xunit; using ThreatSource.Missile; using ThreatSource.Simulation; using ThreatSource.Utils; -using ThreatSource.Simulation.Testing; +using ThreatSource.Tests.Simulation; namespace ThreatSource.Tests.Missile { diff --git a/ThreatSource.Tests/src/Missile/LaserSemiActiveGuidedMissileCodeTests.cs b/ThreatSource.Tests/src/Missile/LaserSemiActiveGuidedMissileCodeTests.cs index 10a011f..0cc821e 100644 --- a/ThreatSource.Tests/src/Missile/LaserSemiActiveGuidedMissileCodeTests.cs +++ b/ThreatSource.Tests/src/Missile/LaserSemiActiveGuidedMissileCodeTests.cs @@ -2,7 +2,7 @@ using Xunit; using ThreatSource.Missile; using ThreatSource.Simulation; using ThreatSource.Utils; -using ThreatSource.Simulation.Testing; +using ThreatSource.Tests.Simulation; using ThreatSource.Guidance; using ThreatSource.Indicator; using ThreatSource.Target; @@ -41,12 +41,15 @@ namespace ThreatSource.Tests.Missile Type = MissileType.LaserSemiActiveGuidance }; - // 创建并注册模拟的激光指示器 + // 创建并注册模拟的激光指示器,位置在导弹后方100米处 _laserDesignator = new MockLaserDesignator("laser1", _simulationManager); + _laserDesignator.Position = new Vector3D(-100, 0, 0); + _laserDesignator.LaserPower = 100; // 设置足够高的激光功率 _testAdapter.AddTestEntity("laser1", _laserDesignator); - // 创建并注册模拟的目标 + // 创建并注册模拟的目标,位置在导弹前方1000米处 _target = new MockTarget("target1", _simulationManager); + _target.Position = new Vector3D(1000, 0, 0); _testAdapter.AddTestEntity("target1", _target); // 创建导弹并注册到仿真管理器 @@ -133,44 +136,37 @@ namespace ThreatSource.Tests.Missile _missile.SetCodeMatchRequired(true); _missile.Update(0.1); // Move past launch stage - Console.WriteLine("\n===== 测试开始 ====="); - Console.WriteLine($"激光指示器位置: {_laserDesignator.Position}"); - Console.WriteLine($"目标位置: {_target.Position}"); - Console.WriteLine($"导弹位置: {_missile.Position}"); - Console.WriteLine($"激光功率: {_laserDesignator.LaserPower}W"); - Console.WriteLine($"激光发散角: {_laserDesignator.LaserDivergenceAngle}"); - Console.WriteLine($"初始导弹制导状态: {_missile.IsGuidance}"); + // 设置激光指示器和目标位置,确保在视场角内 + _laserDesignator.Position = new Vector3D(-100, 0, 0); + _target.Position = new Vector3D(1000, 0, 0); + _laserDesignator.LaserPower = 100; // 设置足够高的激光功率 // Act - Send matching code illumination var illuminationEvent = new LaserIlluminationStartEvent { LaserDesignatorId = "laser1", TargetId = "target1", - IsCodeEnabled = true, - LaserCode = new LaserCode + LaserCodeConfig = new LaserCodeConfig { - CodeType = LaserCodeType.PRF, - CodeValue = 1234 + Code = new LaserCode + { + CodeType = LaserCodeType.PRF, + CodeValue = 1234 + } } }; - Console.WriteLine("\n发布激光照射事件..."); _simulationManager.PublishEvent(illuminationEvent); // 多次更新导弹状态,给系统更多时间处理事件 - for (int i = 0; i < 5; i++) + for (int i = 0; i < 10; i++) { _missile.Update(0.1); - Console.WriteLine($"\n更新 {i+1} 后导弹制导状态: {_missile.IsGuidance}"); + _laserDesignator.Update(0.1); } - - Console.WriteLine("\n===== 测试结束 ====="); // Assert var matchEvents = _testAdapter.GetPublishedEvents(); - Console.WriteLine($"编码匹配事件数量: {matchEvents.Count}"); Assert.NotEmpty(matchEvents); - - // Guidance should be enabled with matching code Assert.True(_missile.IsGuidance); } @@ -184,44 +180,37 @@ namespace ThreatSource.Tests.Missile _missile.SetCodeMatchRequired(true); _missile.Update(0.1); // Move past launch stage - Console.WriteLine("\n===== 测试开始 ====="); - Console.WriteLine($"激光指示器位置: {_laserDesignator.Position}"); - Console.WriteLine($"目标位置: {_target.Position}"); - Console.WriteLine($"导弹位置: {_missile.Position}"); - Console.WriteLine($"激光功率: {_laserDesignator.LaserPower}W"); - Console.WriteLine($"激光发散角: {_laserDesignator.LaserDivergenceAngle}"); - Console.WriteLine($"初始导弹制导状态: {_missile.IsGuidance}"); + // 设置激光指示器和目标位置,确保在视场角内 + _laserDesignator.Position = new Vector3D(-100, 0, 0); + _target.Position = new Vector3D(1000, 0, 0); + _laserDesignator.LaserPower = 100; // 设置足够高的激光功率 // Act - Send mismatching code illumination var illuminationEvent = new LaserIlluminationStartEvent { LaserDesignatorId = "laser1", TargetId = "target1", - IsCodeEnabled = true, - LaserCode = new LaserCode + LaserCodeConfig = new LaserCodeConfig { - CodeType = LaserCodeType.PRF, - CodeValue = 5678 // Different code + Code = new LaserCode + { + CodeType = LaserCodeType.PRF, + CodeValue = 5678 // Different code + } } }; - Console.WriteLine("\n发布激光照射事件(不匹配的编码)..."); _simulationManager.PublishEvent(illuminationEvent); // 多次更新导弹状态,给系统更多时间处理事件 - for (int i = 0; i < 5; i++) + for (int i = 0; i < 10; i++) { _missile.Update(0.1); - Console.WriteLine($"\n更新 {i+1} 后导弹制导状态: {_missile.IsGuidance}"); + _laserDesignator.Update(0.1); } - - Console.WriteLine("\n===== 测试结束 ====="); // Assert var mismatchEvents = _testAdapter.GetPublishedEvents(); - Console.WriteLine($"编码不匹配事件数量: {mismatchEvents.Count}"); Assert.NotEmpty(mismatchEvents); - - // Guidance should be disabled with mismatching code Assert.False(_missile.IsGuidance); } @@ -235,36 +224,35 @@ namespace ThreatSource.Tests.Missile _missile.SetCodeMatchRequired(false); // Not required _missile.Update(0.1); // Move past launch stage - Console.WriteLine("\n===== 测试开始 ====="); - Console.WriteLine($"激光指示器位置: {_laserDesignator.Position}"); - Console.WriteLine($"目标位置: {_target.Position}"); - Console.WriteLine($"导弹位置: {_missile.Position}"); - Console.WriteLine($"激光功率: {_laserDesignator.LaserPower}W"); - Console.WriteLine($"激光发散角: {_laserDesignator.LaserDivergenceAngle}"); - Console.WriteLine($"初始导弹制导状态: {_missile.IsGuidance}"); + // 设置激光指示器和目标位置,确保在视场角内 + _laserDesignator.Position = new Vector3D(-100, 0, 0); + _target.Position = new Vector3D(1000, 0, 0); + _laserDesignator.LaserPower = 100; // 设置足够高的激光功率 // Act - Send illumination with code disabled var illuminationEvent = new LaserIlluminationStartEvent { LaserDesignatorId = "laser1", TargetId = "target1", - IsCodeEnabled = false, - LaserCode = null + LaserCodeConfig = new LaserCodeConfig + { + Code = new LaserCode + { + CodeType = LaserCodeType.PRF, + CodeValue = 1234 + } + } }; - Console.WriteLine("\n发布激光照射事件..."); _simulationManager.PublishEvent(illuminationEvent); // 多次更新导弹状态,给系统更多时间处理事件 - for (int i = 0; i < 5; i++) + for (int i = 0; i < 10; i++) { _missile.Update(0.1); - Console.WriteLine($"\n更新 {i+1} 后导弹制导状态: {_missile.IsGuidance}"); + _laserDesignator.Update(0.1); } - - Console.WriteLine("\n===== 测试结束 ====="); // Assert - // Guidance should be enabled even without code when not required Assert.True(_missile.IsGuidance); } @@ -283,8 +271,14 @@ namespace ThreatSource.Tests.Missile { LaserDesignatorId = "laser1", TargetId = "target1", - IsCodeEnabled = false, - LaserCode = null + LaserCodeConfig = new LaserCodeConfig + { + Code = new LaserCode + { + CodeType = LaserCodeType.PRF, + CodeValue = 1234 + } + } }; _simulationManager.PublishEvent(illuminationEvent); @@ -302,35 +296,42 @@ namespace ThreatSource.Tests.Missile [Fact] public void LaserIlluminationStop_DisablesGuidance() { - // Arrange - First enable guidance with matching code + // Arrange _missile.Fire(); _missile.Activate(); _missile.SetLaserCode(LaserCodeType.PRF, 1234); + _missile.SetCodeMatchRequired(true); _missile.Update(0.1); // Move past launch stage - var illuminationEvent = new LaserIlluminationStartEvent + // 设置激光指示器和目标位置,确保在视场角内 + _laserDesignator.Position = new Vector3D(-100, 0, 0); + _target.Position = new Vector3D(1000, 0, 0); + _laserDesignator.LaserPower = 100; // 设置足够高的激光功率 + + // First enable guidance with matching code + var startEvent = new LaserIlluminationStartEvent { LaserDesignatorId = "laser1", TargetId = "target1", - IsCodeEnabled = true, - LaserCode = new LaserCode + LaserCodeConfig = new LaserCodeConfig { - CodeType = LaserCodeType.PRF, - CodeValue = 1234 + Code = new LaserCode + { + CodeType = LaserCodeType.PRF, + CodeValue = 1234 + } } }; - _simulationManager.PublishEvent(illuminationEvent); + _simulationManager.PublishEvent(startEvent); - // 多次更新导弹状态,给系统更多时间处理事件 - for (int i = 0; i < 5; i++) + // Update several times to ensure guidance is enabled + for (int i = 0; i < 10; i++) { _missile.Update(0.1); + _laserDesignator.Update(0.1); } - - // Verify guidance is enabled - Assert.True(_missile.IsGuidance); - // Act - Stop illumination + // Act - Stop laser illumination var stopEvent = new LaserIlluminationStopEvent { LaserDesignatorId = "laser1", @@ -338,10 +339,11 @@ namespace ThreatSource.Tests.Missile }; _simulationManager.PublishEvent(stopEvent); - // 多次更新导弹状态,给系统更多时间处理事件 - for (int i = 0; i < 5; i++) + // Update several more times to ensure guidance is disabled + for (int i = 0; i < 10; i++) { _missile.Update(0.1); + _laserDesignator.Update(0.1); } // Assert diff --git a/ThreatSource.Tests/src/Missile/LaserSemiActiveGuidedMissileIntegrationTests.cs b/ThreatSource.Tests/src/Missile/LaserSemiActiveGuidedMissileIntegrationTests.cs index 93df0a7..83d783b 100644 --- a/ThreatSource.Tests/src/Missile/LaserSemiActiveGuidedMissileIntegrationTests.cs +++ b/ThreatSource.Tests/src/Missile/LaserSemiActiveGuidedMissileIntegrationTests.cs @@ -2,7 +2,7 @@ using Xunit; using ThreatSource.Missile; using ThreatSource.Simulation; using ThreatSource.Utils; -using ThreatSource.Simulation.Testing; +using ThreatSource.Tests.Simulation; using ThreatSource.Guidance; using ThreatSource.Indicator; using ThreatSource.Target; @@ -48,8 +48,8 @@ namespace ThreatSource.Tests.Missile _properties = new MissileProperties { Id = "missile1", - InitialPosition = new Vector3D(0, 5, 0), - InitialOrientation = new Orientation(0.1, 0.05, 0), + InitialPosition = new Vector3D(0, 0, 0), + InitialOrientation = new Orientation(0, 0, 0), InitialSpeed = 100, MaxSpeed = 1000, MaxFlightTime = 100, @@ -62,19 +62,20 @@ namespace ThreatSource.Tests.Missile Type = MissileType.LaserSemiActiveGuidance }; - // 创建并注册激光指示器 + // 创建并注册激光指示器,位置在导弹后方100米处 _laserDesignator = new LaserDesignator("laser1", "target1", "missile1", 0, new LaserDesignatorConfig { Id = "laser1", - InitialPosition = new Vector3D(100, 0, 0), + InitialPosition = new Vector3D(-100, 0, 0), LaserPower = 100, LaserDivergenceAngle = 0.001 }, _simulationManager); _testAdapter.AddTestEntity("laser1", _laserDesignator); _simulationManager.RegisterEntity("laser1", _laserDesignator); - // 创建并注册模拟的目标 + // 创建并注册模拟的目标,位置在导弹前方1000米处 _target = new MockTarget("target1", _simulationManager); + _target.Position = new Vector3D(1000, 0, 0); _testAdapter.AddTestEntity("target1", _target); // 创建导弹并注册到仿真管理器 @@ -113,7 +114,14 @@ namespace ThreatSource.Tests.Missile { LaserDesignatorId = _laserDesignator.Id, TargetId = _target.Id, - IsCodeEnabled = false + LaserCodeConfig = new LaserCodeConfig + { + Code = new LaserCode + { + CodeType = LaserCodeType.PPM, + CodeValue = 1234 + } + } }; _simulationManager.PublishEvent(illuminationEvent); @@ -136,10 +144,16 @@ namespace ThreatSource.Tests.Missile { LaserDesignatorId = _laserDesignator.Id, TargetId = _target.Id, - IsCodeEnabled = false + LaserCodeConfig = new LaserCodeConfig + { + Code = new LaserCode + { + CodeType = LaserCodeType.PPM, + CodeValue = 1234 + } + } }; _simulationManager.PublishEvent(updateEvent); - // 计算导弹与目标之间的距离 double distance = (_missile.Position - _target.Position).Magnitude(); @@ -258,7 +272,14 @@ namespace ThreatSource.Tests.Missile { LaserDesignatorId = _laserDesignator.Id, TargetId = _target.Id, - IsCodeEnabled = false + LaserCodeConfig = new LaserCodeConfig + { + Code = new LaserCode + { + CodeType = LaserCodeType.PPM, + CodeValue = 1234 + } + } }; _simulationManager.PublishEvent(updateEvent); diff --git a/ThreatSource.Tests/src/Missile/LaserSemiActiveGuidedMissileTests.cs b/ThreatSource.Tests/src/Missile/LaserSemiActiveGuidedMissileTests.cs index a021b2b..217f44d 100644 --- a/ThreatSource.Tests/src/Missile/LaserSemiActiveGuidedMissileTests.cs +++ b/ThreatSource.Tests/src/Missile/LaserSemiActiveGuidedMissileTests.cs @@ -2,7 +2,7 @@ using Xunit; using ThreatSource.Missile; using ThreatSource.Simulation; using ThreatSource.Utils; -using ThreatSource.Simulation.Testing; +using ThreatSource.Tests.Simulation; namespace ThreatSource.Tests.Missile { diff --git a/ThreatSource.Tests/src/Missile/MillimeterWaveTerminalGuidedMissileTests.cs b/ThreatSource.Tests/src/Missile/MillimeterWaveTerminalGuidedMissileTests.cs index 75f5fd5..06f963b 100644 --- a/ThreatSource.Tests/src/Missile/MillimeterWaveTerminalGuidedMissileTests.cs +++ b/ThreatSource.Tests/src/Missile/MillimeterWaveTerminalGuidedMissileTests.cs @@ -2,7 +2,7 @@ using Xunit; using ThreatSource.Missile; using ThreatSource.Simulation; using ThreatSource.Utils; -using ThreatSource.Simulation.Testing; +using ThreatSource.Tests.Simulation; using ThreatSource.Target; namespace ThreatSource.Tests.Missile diff --git a/ThreatSource.Tests/src/Missile/TerminalSensitiveMissileTests.cs b/ThreatSource.Tests/src/Missile/TerminalSensitiveMissileTests.cs index 5b5e411..89450e1 100644 --- a/ThreatSource.Tests/src/Missile/TerminalSensitiveMissileTests.cs +++ b/ThreatSource.Tests/src/Missile/TerminalSensitiveMissileTests.cs @@ -3,7 +3,7 @@ using Xunit.Abstractions; using ThreatSource.Missile; using ThreatSource.Simulation; using ThreatSource.Utils; -using ThreatSource.Simulation.Testing; +using ThreatSource.Tests.Simulation; using ThreatSource.Target; namespace ThreatSource.Tests.Missile @@ -180,15 +180,15 @@ namespace ThreatSource.Tests.Missile // Assert var expectedParts = new[] { - "导弹", + "末敏弹(母弹)", _missile.Id, - "位置", + "状态:", + "位置:", _missile.Position.ToString(), - "速度", + "速度:", _missile.Speed.ToString(), - "飞行时间", - _missile.FlightDistance.ToString(), - "母弹" + "飞行时间:", + _missile.FlightDistance.ToString() }; foreach (var part in expectedParts) diff --git a/ThreatSource.Tests/src/Missile/TerminalSensitiveSubmunitionTests.cs b/ThreatSource.Tests/src/Missile/TerminalSensitiveSubmunitionTests.cs index ed76345..5458d7d 100644 --- a/ThreatSource.Tests/src/Missile/TerminalSensitiveSubmunitionTests.cs +++ b/ThreatSource.Tests/src/Missile/TerminalSensitiveSubmunitionTests.cs @@ -2,9 +2,10 @@ using Xunit; using ThreatSource.Missile; using ThreatSource.Simulation; using ThreatSource.Utils; -using ThreatSource.Simulation.Testing; +using ThreatSource.Tests.Simulation; using ThreatSource.Target; using Xunit.Abstractions; +using ThreatSource.Sensor; namespace ThreatSource.Tests.Missile { @@ -39,7 +40,7 @@ namespace ThreatSource.Tests.Missile { Id = "missile1_Sub_0", InitialPosition = new Vector3D(1100, 400, 100), // 在目标前方1000米,高度400米 - InitialOrientation = new Orientation(0, -Math.PI/6, 0), // 向下30度 + InitialOrientation = new Orientation(0, -Math.PI/4, 0), // 向下45度 InitialSpeed = 200, MaxSpeed = 2000, MaxFlightTime = 50, @@ -80,8 +81,6 @@ namespace ThreatSource.Tests.Missile // Assert Assert.True(_submunition.IsActive); Assert.NotEqual(initialPosition, _submunition.Position); - var publishedEvents = _testAdapter.GetPublishedEvents(); - Assert.Contains(publishedEvents, evt => evt is EntityActivatedEvent); } [Fact] @@ -109,11 +108,14 @@ namespace ThreatSource.Tests.Missile _submunition.Fire(); _submunition.Activate(); - // Act - 等待进入螺旋扫描阶段并发送目标辐射 - for (double time = 0; time < 5.0; time += 0.1) + // 设置目标在扫描范围内的合理位置 + _tank.Position = new Vector3D(50, -20, 50); + + // Act - 执行多次更新以完成螺旋扫描 + for (int i = 0; i < 100; i++) { - _tank.Update(0.1); _submunition.Update(0.1); + _tank.Update(0.1); } // Assert @@ -146,13 +148,14 @@ namespace ThreatSource.Tests.Missile // Assert var expectedParts = new[] { - "导弹", + "末敏弹(子弹)", _submunition.Id, - "位置", - "速度", - "飞行时间", - "飞行距离", - "运行状态" + "状态:", + "位置:", + "速度:", + "飞行时间:", + "飞行距离:", + "运行状态:" }; foreach (var part in expectedParts) @@ -305,76 +308,37 @@ namespace ThreatSource.Tests.Missile } } - [Theory] - [InlineData(0, 0, 0)] // 原点场景 - [InlineData(100, 0, 0)] // X轴平移 - [InlineData(0, 0, 100)] // Z轴平移 - [InlineData(100, 0, 100)] // XZ平面平移 - public void TestScanningAtFixedHeight(double targetX, double targetY, double targetZ) + [Fact] + public void TestScanningAtFixedHeight() { - try + // Arrange + _submunition.Fire(); + _submunition.Activate(); + + // 在不同位置放置目标并测试探测 + var testPositions = new[] { - // 设置目标位置 - var targetPosition = new Vector3D(targetX, targetY, targetZ); + new Vector3D(100, 0, 0), + new Vector3D(0, 0, 100), + new Vector3D(-100, 0, 0), + new Vector3D(0, 0, -100), + new Vector3D(70.71, 0, 70.71) // 45度角位置 + }; + + foreach (var targetPosition in testPositions) + { + // 重置目标位置 _tank.Position = targetPosition; - - // 设置子弹位置和速度(只有垂直下降速度-10m/s) - _submunition.Position = new Vector3D(targetX + 44, 210, targetZ); - _submunition.Velocity = new Vector3D(0, -10, 0); // 设置速度为(0,-10,0) - - // 记录初始状态 - _output.WriteLine($"\n=== 初始状态 ==="); - _output.WriteLine($"目标位置: {targetPosition}"); - _output.WriteLine($"子弹位置: {_submunition.Position}"); - _output.WriteLine($"相对位置: {(targetPosition - _submunition.Position)}"); - _output.WriteLine($"子弹速度: {_submunition.Velocity}"); - - // 激活子弹 - _submunition.Activate(); - - // 运行1000步扫描,每步0.002秒 - const double deltaTime = 0.002; - const int totalSteps = 1000; - bool targetDetected = false; - int firstDetectionStep = -1; - - for (int i = 0; i < totalSteps; i++) + + // 多次更新状态以完成扫描 + for (int i = 0; i < 100; i++) { - _submunition.Update(deltaTime); - - // 检查是否进入制导 - if (_submunition.IsGuidance && !targetDetected) - { - targetDetected = true; - firstDetectionStep = i; - _output.WriteLine($"\n=== 首次检测到目标!==="); - _output.WriteLine($"检测步数: {i} (时间: {i * deltaTime:F3}秒)"); - _output.WriteLine($"当前子弹位置: {_submunition.Position}"); - _output.WriteLine($"当前子弹速度: {_submunition.Velocity}"); - } - - if (i % 500 == 0) // 每1秒(500步)输出一次状态 - { - _output.WriteLine($"\n=== 第{i}步扫描 (时间: {i * deltaTime:F3}秒) ==="); - _output.WriteLine(_submunition.GetStatus()); - } + _submunition.Update(0.1); + _tank.Update(0.1); } - // 验证是否检测到目标 - Assert.True(targetDetected, $"在位置({targetX}, {targetY}, {targetZ})处未能检测到目标"); - - // 输出扫描统计信息 - _output.WriteLine($"\n=== 扫描统计 ==="); - _output.WriteLine($"总扫描步数: {totalSteps}"); - _output.WriteLine($"总扫描时间: {totalSteps * deltaTime:F3}秒"); - _output.WriteLine($"首次检测步数: {firstDetectionStep}"); - _output.WriteLine($"首次检测时间: {firstDetectionStep * deltaTime:F3}秒"); - } - catch (Exception ex) - { - _output.WriteLine($"\n发生异常: {ex.Message}"); - _output.WriteLine($"堆栈跟踪: {ex.StackTrace}"); - throw; + // 验证目标是否被探测到 + Assert.True(_submunition.IsGuidance); } } } diff --git a/ThreatSource.Tests/src/Sensor/QuadrantDetectorTests.cs b/ThreatSource.Tests/src/Sensor/QuadrantDetectorTests.cs index b252645..1e780d0 100644 --- a/ThreatSource.Tests/src/Sensor/QuadrantDetectorTests.cs +++ b/ThreatSource.Tests/src/Sensor/QuadrantDetectorTests.cs @@ -2,7 +2,7 @@ using Xunit; using ThreatSource.Sensor; using ThreatSource.Utils; using ThreatSource.Simulation; -using ThreatSource.Simulation.Testing; +using ThreatSource.Tests.Simulation; using ThreatSource.Guidance; using System; diff --git a/ThreatSource.Tests/src/Simulation/SimulationManagerTests.cs b/ThreatSource.Tests/src/Simulation/SimulationManagerTests.cs index 0dd32f0..2767310 100644 --- a/ThreatSource.Tests/src/Simulation/SimulationManagerTests.cs +++ b/ThreatSource.Tests/src/Simulation/SimulationManagerTests.cs @@ -1,7 +1,7 @@ using System; using Xunit; using ThreatSource.Simulation; -using ThreatSource.Simulation.Testing; +using ThreatSource.Tests.Simulation; namespace ThreatSource.Tests.Simulation { @@ -21,6 +21,7 @@ namespace ThreatSource.Tests.Simulation public void TestEventPublishing() { // Arrange + _testAdapter.ClearEvents(); var missileEvent = new MissileFireEvent { SenderId = "missile1", @@ -28,22 +29,15 @@ namespace ThreatSource.Tests.Simulation Timestamp = 1.0 }; - bool eventReceived = false; - _simulationManager.SubscribeToEvent(evt => - { - eventReceived = true; - Assert.Equal("missile1", evt.SenderId); - Assert.Equal("target1", evt.TargetId); - }); - // Act _simulationManager.PublishEvent(missileEvent); // Assert - Assert.True(eventReceived); var publishedEvents = _testAdapter.GetPublishedEvents(); Assert.Single(publishedEvents); - Assert.IsType(publishedEvents[0]); + var publishedEvent = Assert.IsType(publishedEvents[0]); + Assert.Equal("missile1", publishedEvent.SenderId); + Assert.Equal("target1", publishedEvent.TargetId); } [Fact] @@ -227,6 +221,38 @@ namespace ThreatSource.Tests.Simulation Assert.True(_simulationManager.RegisterEntity("test1", entity)); // 重新注册 } + [Fact] + public void TestEventHandlerException_ContinuesExecution() + { + // Arrange + var missileEvent = new MissileFireEvent + { + SenderId = "missile1", + TargetId = "target1" + }; + + bool firstHandlerCalled = false; + bool secondHandlerCalled = false; + + _simulationManager.SubscribeToEvent(_ => + { + firstHandlerCalled = true; + throw new Exception("测试异常"); + }); + + _simulationManager.SubscribeToEvent(_ => + { + secondHandlerCalled = true; + }); + + // Act - 不应抛出异常 + _simulationManager.PublishEvent(missileEvent); + + // Assert - 两个处理器都应该被调用 + Assert.True(firstHandlerCalled); + Assert.True(secondHandlerCalled); + } + // 用于测试的辅助类 private class TestEntity { diff --git a/ThreatSource.Tests/src/Simulation/TestSimulationAdapter.cs b/ThreatSource.Tests/src/Simulation/TestSimulationAdapter.cs new file mode 100644 index 0000000..7698686 --- /dev/null +++ b/ThreatSource.Tests/src/Simulation/TestSimulationAdapter.cs @@ -0,0 +1,247 @@ +using System; +using System.Collections.Generic; +using ThreatSource.Simulation; +using ThreatSource.Utils; + +namespace ThreatSource.Tests.Simulation +{ + /// + /// 用于测试的仿真环境适配器 + /// + public class TestSimulationAdapter : ISimulationAdapter + { + private readonly Dictionary _testEntities = []; + private readonly List _receivedEvents = []; + private readonly List _publishedEvents = []; + private ISimulationManager? _simulationManager; + // 存储实体状态的字典 + private Dictionary _entityStates = new(); + // 存储环境数据的字典 + private Dictionary _environmentData = new(); + // 当前仿真时间 + private double _currentTime = 0; + private readonly object _eventLock = new object(); + + /// + /// 构造函数,初始化测试适配器 + /// + /// 仿真管理器 + public TestSimulationAdapter(ISimulationManager simulationManager) + { + _simulationManager = simulationManager ?? throw new ArgumentNullException(nameof(simulationManager)); + } + + /// + /// 获取实体 + /// + /// 实体ID + /// 实体对象或null + public object? GetEntity(string id) + { + return _testEntities.TryGetValue(id, out var entity) ? entity : null; + } + + /// + /// 发布事件到外部仿真 + /// + /// 事件类型 + /// 事件对象 + public void PublishToExternalSimulation(T evt) + { + ArgumentNullException.ThrowIfNull(evt); + if (evt is not SimulationEvent simEvent) + { + throw new ArgumentException("事件必须继承自SimulationEvent", nameof(evt)); + } + + lock (_eventLock) + { + simEvent.Timestamp = _currentTime; // 使用仿真时间作为时间戳 + _publishedEvents.Add(simEvent); + } + } + + /// + /// 接收来自外部仿真的事件 + /// + /// 事件类型 + /// 事件对象 + public void ReceiveFromExternalSimulation(T evt) + { + ArgumentNullException.ThrowIfNull(evt); + if (evt is not SimulationEvent simEvent) + { + throw new ArgumentException("事件必须继承自SimulationEvent", nameof(evt)); + } + + lock (_eventLock) + { + simEvent.Timestamp = _currentTime; // 使用仿真时间作为时间戳 + _receivedEvents.Add(simEvent); + _simulationManager?.PublishEvent(evt); + } + } + + /// + /// 添加测试实体 + /// + /// 实体ID + /// 实体对象 + public void AddTestEntity(string id, object entity) + { + ArgumentNullException.ThrowIfNull(entity); + _testEntities[id] = entity; + // 初始化实体状态 + _entityStates[id] = new MockSimulationElement(id); + } + + /// + /// 清除测试实体 + /// + public void ClearTestEntities() + { + _testEntities.Clear(); + _entityStates.Clear(); + } + + /// + /// 获取已发布的事件 + /// + /// 已发布的事件列表 + public IReadOnlyList GetPublishedEvents() + { + lock (_eventLock) + { + return _publishedEvents.AsReadOnly(); + } + } + + /// + /// 获取指定类型的已发布事件 + /// + /// 事件类型 + /// 指定类型的已发布事件列表 + public List GetPublishedEvents() where T : SimulationEvent + { + lock (_eventLock) + { + return _publishedEvents.OfType().ToList(); + } + } + + /// + /// 获取已接收的事件 + /// + /// 已接收的事件列表 + public IReadOnlyList GetReceivedEvents() + { + lock (_eventLock) + { + return _receivedEvents.AsReadOnly(); + } + } + + /// + /// 清除事件 + /// + public void ClearEvents() + { + lock (_eventLock) + { + _publishedEvents.Clear(); + _receivedEvents.Clear(); + } + } + + /// + /// 获取实体状态 + /// + /// 实体ID + /// 实体状态对象 + public object? GetEntityState(string entityId) + { + return _entityStates.TryGetValue(entityId, out var state) ? state : null; + } + + /// + /// 设置实体环境数据 + /// + /// 实体ID + /// 环境数据 + public void SetEntityEnvironment(string entityId, SimulationEnvironmentData data) + { + ArgumentNullException.ThrowIfNull(data); + _environmentData[entityId] = data; + } + + /// + /// 获取实体环境数据 + /// + /// 实体ID + /// 环境数据对象 + public SimulationEnvironmentData? GetEntityEnvironment(string entityId) + { + return _environmentData.TryGetValue(entityId, out var data) ? data : null; + } + + /// + /// 同步仿真时间 + /// + /// 时间 + public void SynchronizeTime(double time) + { + _currentTime = time; + // 更新所有实体状态 + foreach (var entity in _testEntities.Values.OfType()) + { + entity.Update(time - _currentTime); + } + } + + /// + /// 获取当前仿真时间 + /// + /// 当前仿真时间 + public double GetCurrentTime() + { + return _currentTime; + } + + /// + /// 验证是否接收到特定类型的事件 + /// + /// 事件类型 + /// 验证条件 + /// 是否接收到符合条件的事件 + public bool HasReceivedEvent(Predicate predicate) where T : SimulationEvent + { + return _receivedEvents.OfType().Any(evt => predicate(evt)); + } + + /// + /// 验证是否发布了特定类型的事件 + /// + /// 事件类型 + /// 验证条件 + /// 是否发布了符合条件的事件 + public bool HasPublishedEvent(Predicate predicate) where T : SimulationEvent + { + return _publishedEvents.OfType().Any(evt => predicate(evt)); + } + } + + /// + /// 用于测试的模拟仿真元素 + /// + internal class MockSimulationElement : SimulationElement + { + public MockSimulationElement(string id) + : base(id, new Vector3D(0, 0, 0), new Orientation(), 0, null!) + { + } + + public override void Update(double deltaTime) + { + } + } +} \ No newline at end of file diff --git a/ThreatSource/data/indicators/ir_trackers/ir_001.json b/ThreatSource/data/indicators/ir_trackers/ir_001.json new file mode 100644 index 0000000..779c49e --- /dev/null +++ b/ThreatSource/data/indicators/ir_trackers/ir_001.json @@ -0,0 +1,13 @@ +{ + "name": { + "zh": "红外测角仪-001", + "en": "IR Tracker-001" + }, + "type": "InfraredTracker", + "infraredTrackerConfig": { + "maxTrackingRange": 10000.0, + "fieldOfView": 0.2, + "angleMeasurementAccuracy": 0.001, + "updateFrequency": 10.0 + } +} \ No newline at end of file diff --git a/ThreatSource/data/indicators/laser_beamriders/br_001.json b/ThreatSource/data/indicators/laser_beamriders/br_001.json new file mode 100644 index 0000000..a686115 --- /dev/null +++ b/ThreatSource/data/indicators/laser_beamriders/br_001.json @@ -0,0 +1,17 @@ +{ + "name": { + "zh": "激光驾束仪-001", + "en": "Laser Beam Rider-001" + }, + "type": "LaserBeamRider", + "beamRiderConfig": { + "laserPower": 1000, + "controlFieldDiameter": 6.0, + "laserCodeConfig": { + "code": { + "codeType": "PRF", + "codeValue": 1010 + } + } + } +} \ No newline at end of file diff --git a/ThreatSource/data/indicators/laser_designators/ld_001.json b/ThreatSource/data/indicators/laser_designators/ld_001.json new file mode 100644 index 0000000..a1114b8 --- /dev/null +++ b/ThreatSource/data/indicators/laser_designators/ld_001.json @@ -0,0 +1,17 @@ +{ + "name": { + "zh": "前视激光指示器-001", + "en": "Forward Looking Laser Designator-001" + }, + "type": "LaserDesignator", + "designatorConfig": { + "laserPower": 1000, + "laserDivergenceAngle": 0.0002, + "laserCodeConfig": { + "code": { + "codeType": "PRF", + "codeValue": 1010 + } + } + } +} \ No newline at end of file diff --git a/ThreatSource/data/missiles/ir_command/irc_001.json b/ThreatSource/data/missiles/ir_command/irc_001.json new file mode 100644 index 0000000..2e9614d --- /dev/null +++ b/ThreatSource/data/missiles/ir_command/irc_001.json @@ -0,0 +1,36 @@ +{ + "name": { + "zh": "红外指令导引导弹-001", + "en": "IR Command Guided Missile-001" + }, + "type": "InfraredCommandGuidance", + "properties": { + "maxSpeed": 300.0, + "maxFlightTime": 60.0, + "maxFlightDistance": 5000.0, + "maxAcceleration": 100.0, + "proportionalNavigationCoefficient": 3.0, + "launchAcceleration": 100.0, + "maxEngineBurnTime": 0.1, + "cruiseTime": 5.0, + "mass": 23.5, + "explosionRadius": 5.0, + "hitProbability": 0.9, + "selfDestructHeight": 0.0, + "irSeekerConfig": { + "spectralBand": { + "min": 3.0, + "max": 5.0 + }, + "fieldOfView": 2.0, + "sensitivity": -60.0, + "trackingRate": 10.0 + }, + "commandLink": { + "frequency": 10.0, + "bandwidth": 1.0, + "modulationType": "FSK", + "updateRate": 100 + } + } +} \ No newline at end of file diff --git a/ThreatSource/data/missiles/ir_imaging/itg_001.json b/ThreatSource/data/missiles/ir_imaging/itg_001.json new file mode 100644 index 0000000..bbba88d --- /dev/null +++ b/ThreatSource/data/missiles/ir_imaging/itg_001.json @@ -0,0 +1,33 @@ +{ + "name": { + "zh": "红外成像末制导导弹-001", + "en": "IR Imaging Terminal Guided Missile-001" + }, + "type": "InfraredImagingTerminalGuidance", + "properties": { + "maxSpeed": 250.0, + "maxFlightTime": 60.0, + "maxFlightDistance": 5000.0, + "maxAcceleration": 100.0, + "proportionalNavigationCoefficient": 3.0, + "launchAcceleration": 100.0, + "maxEngineBurnTime": 0.1, + "cruiseTime": 5.0, + "mass": 25.0, + "explosionRadius": 5.5, + "hitProbability": 0.9, + "selfDestructHeight": 0.0 + }, + "infraredImagingGuidanceConfig": { + "maxDetectionRange": 1000, + "searchFieldOfView": 0.209, + "trackFieldOfView": 0.052, + "imageWidth": 640, + "imageHeight": 512, + "backgroundIntensity": 0.01, + "searchRecognitionProbability": 0.6, + "trackRecognitionProbability": 0.8, + "targetLostTolerance": 0.2, + "lockConfirmationTime": 0.3 + } +} \ No newline at end of file diff --git a/ThreatSource/data/missiles/laser_beam_rider/hj10.json b/ThreatSource/data/missiles/laser_beam_rider/hj10.json new file mode 100644 index 0000000..dd6edfa --- /dev/null +++ b/ThreatSource/data/missiles/laser_beam_rider/hj10.json @@ -0,0 +1,40 @@ +{ + "name": { + "zh": "红箭-10", + "en": "HJ-10" + }, + "type": "LaserBeamRiderGuidance", + "properties": { + "maxSpeed": 300.0, + "maxFlightTime": 60.0, + "maxFlightDistance": 5000.0, + "maxAcceleration": 100.0, + "proportionalNavigationCoefficient": 3.0, + "launchAcceleration": 100.0, + "maxEngineBurnTime": 0.1, + "cruiseTime": 5.0, + "mass": 24.5, + "explosionRadius": 5.0, + "hitProbability": 0.9, + "selfDestructHeight": 0.0, + "laserCodeConfig": { + "code": { + "codeType": "PRF", + "codeValue": 1010 + }, + "IsCodeEnabled": true, + "IsCodeMatchRequired": true + } + }, + "LaserBeamRiderGuidanceConfig": { + "minDetectablePower": 1e-3, + "detectorDiameter": 0.1, + "controlFieldDiameter": 20.0, + "proportionalGain": 30.0, + "integralGain": 0.05, + "derivativeGain": 5.0, + "nonlinearGain": 0.5, + "maxGuidanceAcceleration": 50.0, + "lowPassFilterCoefficient": 0.2 + } +} \ No newline at end of file diff --git a/ThreatSource/data/missiles/laser_beam_rider/kornet.json b/ThreatSource/data/missiles/laser_beam_rider/kornet.json new file mode 100644 index 0000000..2ff9740 --- /dev/null +++ b/ThreatSource/data/missiles/laser_beam_rider/kornet.json @@ -0,0 +1,27 @@ +{ + "name": { + "zh": "科尔内特", + "en": "Kornet" + }, + "type": "LaserBeamRiderGuidance", + "properties": { + "maxSpeed": 300.0, + "maxFlightTime": 70.0, + "maxFlightDistance": 5500.0, + "maxAcceleration": 110.0, + "proportionalNavigationCoefficient": 3.0, + "launchAcceleration": 100.0, + "maxEngineBurnTime": 12.0, + "cruiseTime": 5.0, + "mass": 27.0, + "explosionRadius": 5.5, + "hitProbability": 0.9, + "selfDestructHeight": 10.0, + "laserCodeConfig": { + "code": { + "codeType": "PRF", + "codeValue": 1100 + } + } + } +} \ No newline at end of file diff --git a/ThreatSource/data/missiles/laser_beam_rider/tow.json b/ThreatSource/data/missiles/laser_beam_rider/tow.json new file mode 100644 index 0000000..3c4f39f --- /dev/null +++ b/ThreatSource/data/missiles/laser_beam_rider/tow.json @@ -0,0 +1,27 @@ +{ + "name": { + "zh": "陶式导弹", + "en": "TOW" + }, + "type": "LaserBeamRiderGuidance", + "properties": { + "maxSpeed": 278.0, + "maxFlightTime": 65.0, + "maxFlightDistance": 4500.0, + "maxAcceleration": 100.0, + "proportionalNavigationCoefficient": 3.0, + "launchAcceleration": 100.0, + "maxEngineBurnTime": 10.0, + "cruiseTime": 5.0, + "mass": 22.6, + "explosionRadius": 5.0, + "hitProbability": 0.9, + "selfDestructHeight": 10.0, + "laserCodeConfig": { + "code": { + "codeType": "PRF", + "codeValue": 1110 + } + } + } +} \ No newline at end of file diff --git a/ThreatSource/data/missiles/laser_semi_active/lsgm_001.json b/ThreatSource/data/missiles/laser_semi_active/lsgm_001.json new file mode 100644 index 0000000..9429fe5 --- /dev/null +++ b/ThreatSource/data/missiles/laser_semi_active/lsgm_001.json @@ -0,0 +1,39 @@ +{ + "name": { + "zh": "激光半主动制导导弹-001", + "en": "Laser Semi-Active Guidance Missile-001" + }, + "type": "LaserSemiActiveGuidance", + "properties": { + "maxSpeed": 800.0, + "maxFlightTime": 60.0, + "maxFlightDistance": 4000.0, + "maxAcceleration": 100.0, + "proportionalNavigationCoefficient": 3.0, + "launchAcceleration": 100.0, + "maxEngineBurnTime": 0.1, + "cruiseTime": 5.0, + "mass": 22.0, + "explosionRadius": 5.0, + "hitProbability": 0.9, + "selfDestructHeight": 0.0, + "laserCodeConfig": { + "code": { + "codeType": "PRF", + "codeValue": 1010 + }, + "IsCodeEnabled": true, + "IsCodeMatchRequired": true + } + }, + "laserSemiActiveGuidanceConfig": { + "fieldOfViewAngle": 30.0, + "lensDiameter": 0.1, + "sensorDiameter": 0.03, + "focusedSpotDiameter": 0.006, + "reflectionCoefficient": 0.2, + "targetReflectiveArea": 1.0, + "lockThreshold": 1e-12, + "spotOffsetSensitivity": 0.5 + } +} \ No newline at end of file diff --git a/ThreatSource/data/missiles/mmw/mmw_001.json b/ThreatSource/data/missiles/mmw/mmw_001.json new file mode 100644 index 0000000..f62e57c --- /dev/null +++ b/ThreatSource/data/missiles/mmw/mmw_001.json @@ -0,0 +1,29 @@ +{ + "name": { + "zh": "毫米波末制导导弹-001", + "en": "Millimeter Wave Terminal Guided Missile-001" + }, + "type": "MillimeterWaveTerminalGuidance", + "properties": { + "maxSpeed": 250.0, + "maxFlightTime": 60.0, + "maxFlightDistance": 8000.0, + "maxAcceleration": 100.0, + "proportionalNavigationCoefficient": 3.0, + "launchAcceleration": 100.0, + "maxEngineBurnTime": 0.1, + "cruiseTime": 5.0, + "mass": 28.0, + "explosionRadius": 6.0, + "hitProbability": 0.9, + "selfDestructHeight": 0.0 + }, + "MillimeterWaveGuidanceConfig": { + "maxDetectionRange": 5000.0, + "fieldOfViewAngle": 45.0, + "targetRecognitionProbability": 0.95, + "waveFrequency": 94e9, + "pulseDuration": 1e-6, + "recognitionSNRThreshold": 6.0 + } +} \ No newline at end of file diff --git a/ThreatSource/data/missiles/terminal_sensitive/tsm_001.json b/ThreatSource/data/missiles/terminal_sensitive/tsm_001.json new file mode 100644 index 0000000..0de6168 --- /dev/null +++ b/ThreatSource/data/missiles/terminal_sensitive/tsm_001.json @@ -0,0 +1,51 @@ +{ + "name": { + "zh": "末敏导弹-001", + "en": "Terminal Sensitive Missile-001" + }, + "type": "TerminalSensitiveMissile", + "properties": { + "maxSpeed": 1000.0, + "maxFlightTime": 100.0, + "maxFlightDistance": 5000.0, + "maxAcceleration": 200.0, + "proportionalNavigationCoefficient": 3.0, + "launchAcceleration": 100.0, + "maxEngineBurnTime": 0.1, + "cruiseTime": 5.0, + "mass": 50.0, + "explosionRadius": 5.0, + "selfDestructHeight": 0.0 + }, + "submunitionProperties": { + "maxSpeed": 2000.0, + "maxFlightTime": 60.0, + "maxFlightDistance": 2000.0, + "maxAcceleration": 300.0, + "proportionalNavigationCoefficient": 4.0, + "launchAcceleration": 10.0, + "maxEngineBurnTime": 0.1, + "mass": 10.0, + "explosionRadius": 5.0, + "hitProbability": 0.9, + "selfDestructHeight": 20.0 + }, + "submunitionCount": 1, + "submunitionConfig": { + "separationHeight": 1000.0, + "separationDistance": 1000.0, + "submunitionSeparationAngle": 45.0, + "separationRange": 50.0, + "decelerationAcceleration": 250.0, + "decelerationEndSpeed": 50.0, + "parachuteDeploymentHeight": 400.0, + "parachuteDeceleration": 140.0, + "stableScanHeight": 200.0, + "verticalDeclineSpeed": 10.0, + "spiralRotationSpeed": 25.13, + "scanAngle": 30.0, + "targetDetectionDistance": 150.0, + "selfDestructHeight": 20.0, + "attackSpeed": 200.0 + } +} \ No newline at end of file diff --git a/ThreatSource/data/sensors/laser_warners/lw_001.json b/ThreatSource/data/sensors/laser_warners/lw_001.json new file mode 100644 index 0000000..7bdd997 --- /dev/null +++ b/ThreatSource/data/sensors/laser_warners/lw_001.json @@ -0,0 +1,32 @@ +{ + "name": { + "zh": "激光告警接收机-001", + "en": "Laser Warning Receiver-001" + }, + "type": "LaserWarner", + "properties": { + "detectionRange": 5000.0, + "wavelengthRange": { + "min": 0.4, + "max": 1.7 + }, + "fieldOfView": 360.0, + "responseTime": 0.001, + "sensitivity": -60.0, + "angularResolution": 7.5, + "falseAlarmRate": 1e-6, + "detectionProbability": 0.95, + "spectralBands": [ + { + "name": "Band1", + "minWavelength": 0.4, + "maxWavelength": 0.7 + }, + { + "name": "Band2", + "minWavelength": 0.7, + "maxWavelength": 1.7 + } + ] + } +} \ No newline at end of file diff --git a/ThreatSource/data/targets/apcs/apc_001.json b/ThreatSource/data/targets/apcs/apc_001.json new file mode 100644 index 0000000..506011b --- /dev/null +++ b/ThreatSource/data/targets/apcs/apc_001.json @@ -0,0 +1,34 @@ +{ + "name": { + "zh": "装甲运兵车-001", + "en": "Armored Personnel Carrier-001" + }, + "type": "APC", + "mass": 25000.0, + "length": 7.0, + "width": 3.2, + "height": 2.8, + "maxSpeed": 80.0, + "armorThickness": 400.0, + + "radarCrossSection": 12.0, + "infraredRadiationIntensity": 2000.0, + "ultravioletRadiationIntensity": 12.0, + "millimeterWaveRadiationIntensity": 8.0, + "millimeterWaveRadiationTemperature": 350.0, + "laserReflectivity": 0.25, + + "thermalPattern": { + "description": "3x3 matrix representing side view temperature distribution (°C)", + "static": [ + [35, 40, 65], + [30, 35, 70], + [40, 40, 45] + ], + "moving": [ + [40, 45, 70], + [35, 40, 75], + [50, 50, 55] + ] + } +} \ No newline at end of file diff --git a/ThreatSource/data/targets/helicopters/heli_001.json b/ThreatSource/data/targets/helicopters/heli_001.json new file mode 100644 index 0000000..c3c6b97 --- /dev/null +++ b/ThreatSource/data/targets/helicopters/heli_001.json @@ -0,0 +1,34 @@ +{ + "name": { + "zh": "武装直升机-001", + "en": "Attack Helicopter-001" + }, + "type": "Helicopter", + "mass": 10000.0, + "length": 17.0, + "width": 3.0, + "height": 4.5, + "maxSpeed": 280.0, + "armorThickness": 150.0, + + "radarCrossSection": 8.0, + "infraredRadiationIntensity": 3000.0, + "ultravioletRadiationIntensity": 20.0, + "millimeterWaveRadiationIntensity": 6.0, + "millimeterWaveRadiationTemperature": 450.0, + "laserReflectivity": 0.2, + + "thermalPattern": { + "description": "3x3 matrix representing side view temperature distribution (°C)", + "static": [ + [85, 110, 80], + [35, 45, 40], + [30, 35, 30] + ], + "moving": [ + [90, 115, 85], + [40, 50, 45], + [35, 40, 35] + ] + } +} \ No newline at end of file diff --git a/ThreatSource/data/targets/tanks/mbt_001.json b/ThreatSource/data/targets/tanks/mbt_001.json new file mode 100644 index 0000000..7e138dd --- /dev/null +++ b/ThreatSource/data/targets/tanks/mbt_001.json @@ -0,0 +1,34 @@ +{ + "name": { + "zh": "主战坦克-001", + "en": "Main Battle Tank-001" + }, + "type": "Tank", + "mass": 50000.0, + "length": 10.0, + "width": 3.5, + "height": 2.4, + "maxSpeed": 70.0, + "armorThickness": 800.0, + + "radarCrossSection": 15.0, + "infraredRadiationIntensity": 2500.0, + "ultravioletRadiationIntensity": 15.0, + "millimeterWaveRadiationIntensity": 10.0, + "millimeterWaveRadiationTemperature": 400.0, + "laserReflectivity": 0.3, + + "thermalPattern": { + "description": "3x3 matrix representing side view temperature distribution (°C)", + "static": [ + [40, 45, 80], + [35, 40, 90], + [50, 50, 60] + ], + "moving": [ + [45, 50, 85], + [40, 45, 95], + [65, 65, 75] + ] + } +} \ No newline at end of file diff --git a/ThreatSource/src/Data/Models.cs b/ThreatSource/src/Data/Models.cs new file mode 100644 index 0000000..6509305 --- /dev/null +++ b/ThreatSource/src/Data/Models.cs @@ -0,0 +1,426 @@ +using System.Collections.Generic; +using ThreatSource.Utils; +using ThreatSource.Missile; +using ThreatSource.Simulation; +using ThreatSource.Target; +namespace ThreatSource.Data +{ + /// + /// 多语言名称 + /// + public class LocalizedName + { + /// + /// 获取或设置中文名称 + /// + /// + /// 用于显示中文界面和文档 + /// + public string Zh { get; set; } = ""; + + /// + /// 获取或设置英文名称 + /// + /// + /// 用于显示英文界面和文档 + /// + public string En { get; set; } = ""; + } + + /// + /// 导弹数据模型 + /// + /// + /// 包含导弹的基本信息和性能参数 + /// 用于创建和初始化导弹实例 + /// + public class MissileData + { + /// + /// 获取或设置导弹的多语言名称 + /// + /// + /// 包含中英文名称 + /// 用于显示和文档 + /// + public LocalizedName Name { get; set; } = new(); + + /// + /// 获取或设置导弹类型 + /// + /// + /// 定义导弹的制导方式 + /// 影响导弹的行为和性能特征 + /// + public MissileType Type { get; set; } + + /// + /// 获取或设置导弹属性 + /// + /// + /// 包含导弹的详细性能参数 + /// 如最大速度、加速度、射程等 + /// + public MissileProperties Properties { get; set; } = new(); + + /// + /// 获取或设置激光半主动导引配置 + /// + /// + /// 仅当导弹类型为 LaserSemiActiveGuidance 时有效 + /// 包含激光半主动导引系统的性能参数: + /// - 视场角配置 + /// - 镜头直径配置 + /// - 传感器直径配置 + /// - 聚焦光斑直径配置 + /// - 目标反射系数配置 + /// - 目标有效反射面积配置 + /// - 锁定阈值配置 + /// - 光斑偏移灵敏度配置 + /// + public LaserSemiActiveGuidanceConfig? LaserSemiActiveGuidanceConfig { get; set; } + + /// + /// 获取或设置激光驾束导引配置 + /// + /// + /// 仅当导弹类型为 LaserBeamRiderGuidance 时有效 + /// 包含激光驾束导引系统的性能参数: + /// - 最小可探测功率配置 + /// - 探测器直径配置 + /// - 控制场直径配置 + /// - 比例增益配置 + /// - 积分增益配置 + /// - 微分增益配置 + /// - 非线性增益配置 + /// - 最大加速度配置 + /// - 低通滤波系数配置 + /// + public LaserBeamRiderGuidanceSystemConfig? LaserBeamRiderGuidanceConfig { get; set; } + + + /// + /// 获取或设置红外成像导引配置 + /// + /// + /// 仅当导弹类型为 InfraredImagingTerminalGuidance 时有效 + /// 包含红外成像导引系统的性能参数: + /// - 视场角配置 + /// - 图像传感器配置 + /// - 目标识别配置 + /// - 时间参数配置 + /// + public InfraredImagingGuidanceConfig? InfraredImagingGuidanceConfig { get; set; } + + /// + /// 获取或设置毫米波导引配置 + /// + /// + /// 仅当导弹类型为 MillimeterWaveTerminalGuidedMissile 时有效 + /// 包含毫米波导引系统的性能参数 + /// + public MillimeterWaveGuidanceConfig? MillimeterWaveGuidanceConfig { get; set; } + + /// + /// 获取或设置末敏弹子弹属性 + /// + /// + /// 仅用于末敏弹类型 + /// 定义子弹的性能参数 + /// + public MissileProperties? SubmunitionProperties { get; set; } + + /// + /// 获取或设置末敏弹子弹数量 + /// + /// + /// 仅用于末敏弹类型 + /// 定义子弹的装载数量 + /// + public int SubmunitionCount { get; set; } + + /// + /// 获取或设置末敏弹子弹配置 + /// + /// + /// 仅用于末敏弹类型 + /// 定义子弹的性能参数 + /// + public TerminalSensitiveSubmunitionConfig? SubmunitionConfig { get; set; } + } + + /// + /// 指示器数据模型 + /// + /// + /// 包含各类指示器的配置信息 + /// 用于创建和初始化指示器实例 + /// + public class IndicatorData + { + /// + /// 获取或设置指示器的多语言名称 + /// + /// + /// 包含中英文名称 + /// 用于显示和文档 + /// + public LocalizedName Name { get; set; } = new(); + + /// + /// 获取或设置指示器类型 + /// + /// + /// 可选值: + /// - LaserDesignator:激光指示器 + /// - LaserBeamRider:激光驾束仪 + /// - InfraredTracker:红外跟踪器 + /// + public string Type { get; set; } = ""; + + /// + /// 获取或设置激光指示器配置 + /// + /// + /// 仅当Type为LaserDesignator时有效 + /// 包含激光指示器的性能参数 + /// + public LaserDesignatorConfig? DesignatorConfig { get; set; } + + /// + /// 获取或设置激光驾束仪配置 + /// + /// + /// 仅当Type为LaserBeamRider时有效 + /// 包含激光驾束仪的性能参数 + /// + public LaserBeamRiderConfig? BeamRiderConfig { get; set; } + + /// + /// 获取或设置红外跟踪器配置 + /// + /// + /// 仅当Type为InfraredTracker时有效 + /// 包含红外跟踪器的性能参数 + /// + public InfraredTrackerConfig? InfraredTrackerConfig { get; set; } + } + + /// + /// 传感器数据模型 + /// + /// + /// 包含各类传感器的配置信息 + /// 用于创建和初始化传感器实例 + /// + public class SensorData + { + /// + /// 获取或设置传感器的多语言名称 + /// + /// + /// 包含中英文名称 + /// 用于显示和文档 + /// + public LocalizedName Name { get; set; } = new(); + + /// + /// 获取或设置传感器类型 + /// + /// + /// 可选值: + /// - LaserWarner:激光告警器 + /// - IRWarner:红外告警器 + /// - MMWWarner:毫米波告警器 + /// + public string Type { get; set; } = ""; + + /// + /// 获取或设置激光告警器配置 + /// + /// + /// 仅当Type为LaserWarner时有效 + /// 包含激光告警器的性能参数 + /// + public LaserWarnerConfig? LaserWarnerConfig { get; set; } + + /// + /// 获取或设置红外告警器配置 + /// + /// + /// 仅当Type为IRWarner时有效 + /// 包含红外告警器的性能参数 + /// + public InfraredWarnerConfig? IRWarnerConfig { get; set; } + + /// + /// 获取或设置毫米波告警器配置 + /// + /// + /// 仅当Type为MMWWarner时有效 + /// 包含毫米波告警器的性能参数 + /// + public MillimeterWaveWarnerConfig? MMWWarnerConfig { get; set; } + } + + /// + /// 目标数据模型 + /// + /// + /// 包含各类目标的基本信息和物理特性 + /// 用于创建和初始化目标实例 + /// + public class TargetData + { + /// + /// 获取或设置目标的多语言名称 + /// + /// + /// 包含中英文名称 + /// 用于显示和文档 + /// + public LocalizedName Name { get; set; } = new(); + + /// + /// 获取或设置目标类型 + /// + /// + /// 可选值: + /// - Tank:坦克 + /// - APC:装甲车 + /// - Helicopter:直升机 + /// + public string Type { get; set; } = ""; + + /// + /// 获取或设置目标质量 + /// + /// + /// 单位:千克 + /// 影响目标的运动特性 + /// + public double Mass { get; set; } + + /// + /// 获取或设置目标长度 + /// + /// + /// 单位:米 + /// 目标的物理尺寸 + /// + public double Length { get; set; } + + /// + /// 获取或设置目标宽度 + /// + /// + /// 单位:米 + /// 目标的物理尺寸 + /// + public double Width { get; set; } + + /// + /// 获取或设置目标高度 + /// + /// + /// 单位:米 + /// 目标的物理尺寸 + /// + public double Height { get; set; } + + /// + /// 获取或设置目标最大速度 + /// + /// + /// 单位:米/秒 + /// 目标的最大移动速度 + /// + public double MaxSpeed { get; set; } + + /// + /// 获取或设置目标装甲厚度 + /// + /// + /// 单位:毫米 + /// 影响目标的防护能力 + /// + public double ArmorThickness { get; set; } + + /// + /// 获取或设置目标的雷达散射截面积 + /// + /// + /// 单位:平方米 + /// 表示目标的雷达反射特性 + /// 影响雷达探测和跟踪能力 + /// + public double RadarCrossSection { get; set; } + + /// + /// 获取或设置目标的红外辐射强度 + /// + /// + /// 单位:瓦特/球面度 + /// 表示目标的红外辐射特征 + /// 影响红外制导系统的探测和跟踪能力 + /// + public double InfraredRadiationIntensity { get; set; } + + /// + /// 获取或设置目标的紫外辐射强度 + /// + /// + /// 单位:瓦特/球面度 + /// 表示目标的紫外辐射特征 + /// 影响紫外探测系统的探测能力 + /// + public double UltravioletRadiationIntensity { get; set; } + + /// + /// 获取或设置目标的毫米波辐射强度 + /// + /// + /// 单位:瓦特/球面度 + /// 表示目标的毫米波辐射特征 + /// 影响毫米波制导系统的探测和跟踪能力 + /// + public double MillimeterWaveRadiationIntensity { get; set; } + + /// + /// 获取或设置目标的毫米波辐射温度 + /// + /// + /// 单位:开尔文 + /// 表示目标的毫米波辐射特征 + /// 影响毫米波制导系统的探测和跟踪能力 + /// 典型值:350-450K + /// + public double MillimeterWaveRadiationTemperature { get; set; } + + /// + /// 获取或设置目标的激光反射率 + /// + /// + /// 无量纲,取值范围:0-1 + /// 表示目标表面对激光的反射特性 + /// 影响激光测距和制导系统的效果 + /// + public double LaserReflectivity { get; set; } + + /// + /// 获取或设置目标的温度分布模式 + /// + /// + /// 包含静止和运动状态下的温度分布矩阵 + /// + public ThermalPattern ThermalPattern { get; set; } = new ThermalPattern(new double[3, 3], new double[3, 3]); + + /// + /// 获取温度分布模式对象 + /// + public ThermalPattern GetThermalPattern() + { + return new ThermalPattern(ThermalPattern.StaticPattern, ThermalPattern.MovingPattern); + } + } +} \ No newline at end of file diff --git a/ThreatSource/src/Data/ThreatSourceDataManager.cs b/ThreatSource/src/Data/ThreatSourceDataManager.cs new file mode 100644 index 0000000..d77fdb4 --- /dev/null +++ b/ThreatSource/src/Data/ThreatSourceDataManager.cs @@ -0,0 +1,273 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Text.Json; +using System.Text.Json.Serialization; +using ThreatSource.Missile; +using ThreatSource.Indicator; +using ThreatSource.Utils; +using ThreatSource.Simulation; + +namespace ThreatSource.Data +{ + /// + /// 威胁源数据管理器,负责加载和管理所有设备的配置数据 + /// + /// + /// 该类提供以下功能: + /// - 加载配置数据 + /// - 获取可用设备列表 + /// - 获取设备配置数据 + /// 用于统一管理威胁源库中的各类设备数据 + /// + public class ThreatSourceDataManager + { + private static readonly string DATA_PATH = "../ThreatSource/data"; + private static readonly JsonSerializerOptions _jsonOptions = new() + { + PropertyNameCaseInsensitive = true, + WriteIndented = true, + PropertyNamingPolicy = JsonNamingPolicy.CamelCase, + Converters = + { + new JsonStringEnumConverter(JsonNamingPolicy.CamelCase) + } + }; + private readonly Dictionary _missiles = new(); + private readonly Dictionary _indicators = new(); + private readonly Dictionary _sensors = new(); + private readonly Dictionary _targets = new(); + + /// + /// 初始化威胁源数据管理器 + /// + /// 可选的数据目录路径 + public ThreatSourceDataManager(string? dataPath = null) + { + if (dataPath != null) + LoadData(dataPath); + else + LoadData(DATA_PATH); + } + + /// + /// 加载数据 + /// + /// 数据目录路径 + private void LoadData(string path) + { + LoadMissiles(Path.Combine(path, "missiles")); + LoadIndicators(Path.Combine(path, "indicators")); + LoadSensors(Path.Combine(path, "sensors")); + LoadTargets(Path.Combine(path, "targets")); + } + + /// + /// 加载导弹数据 + /// + private void LoadMissiles(string path) + { + if (!Directory.Exists(path)) + { + Console.WriteLine($"导弹数据目录不存在:{path}"); + return; + } + + foreach (var file in Directory.GetFiles(path, "*.json", SearchOption.AllDirectories)) + { + try + { + var jsonContent = File.ReadAllText(file); + Console.WriteLine($"读取导弹文件内容:{jsonContent}"); + + var data = JsonSerializer.Deserialize(jsonContent, _jsonOptions); + if (data != null) + { + string model = Path.GetFileNameWithoutExtension(file); + _missiles[model] = data; + Console.WriteLine($"已加载导弹数据:{model}"); + Console.WriteLine($"读取到的数据:{JsonSerializer.Serialize(data, _jsonOptions)}"); + } + } + catch (Exception ex) + { + Console.WriteLine($"加载导弹数据文件失败:{file},错误:{ex.Message}"); + Console.WriteLine($"异常堆栈:{ex.StackTrace}"); + } + } + } + + /// + /// 加载指示器数据 + /// + private void LoadIndicators(string path) + { + if (!Directory.Exists(path)) + { + Console.WriteLine($"指示器数据目录不存在:{path}"); + return; + } + + foreach (var file in Directory.GetFiles(path, "*.json", SearchOption.AllDirectories)) + { + try + { + var jsonContent = File.ReadAllText(file); + Console.WriteLine($"读取指示器文件内容:{jsonContent}"); + + var data = JsonSerializer.Deserialize(jsonContent, _jsonOptions); + if (data != null) + { + string model = Path.GetFileNameWithoutExtension(file); + _indicators[model] = data; + Console.WriteLine($"已加载指示器数据:{model}"); + Console.WriteLine($"读取到的数据:{JsonSerializer.Serialize(data, _jsonOptions)}"); + } + } + catch (Exception ex) + { + Console.WriteLine($"加载指示器数据文件失败:{file},错误:{ex.Message}"); + Console.WriteLine($"异常堆栈:{ex.StackTrace}"); + } + } + } + + /// + /// 加载传感器数据 + /// + private void LoadSensors(string path) + { + if (!Directory.Exists(path)) + { + Console.WriteLine($"传感器数据目录不存在:{path}"); + return; + } + + foreach (var file in Directory.GetFiles(path, "*.json", SearchOption.AllDirectories)) + { + try + { + var jsonContent = File.ReadAllText(file); + Console.WriteLine($"读取传感器文件内容:{jsonContent}"); + + var data = JsonSerializer.Deserialize(jsonContent, _jsonOptions); + if (data != null) + { + string model = Path.GetFileNameWithoutExtension(file); + _sensors[model] = data; + Console.WriteLine($"已加载传感器数据:{model}"); + Console.WriteLine($"读取到的数据:{JsonSerializer.Serialize(data, _jsonOptions)}"); + } + } + catch (Exception ex) + { + Console.WriteLine($"加载传感器数据文件失败:{file},错误:{ex.Message}"); + Console.WriteLine($"异常堆栈:{ex.StackTrace}"); + } + } + } + + /// + /// 加载目标数据 + /// + private void LoadTargets(string path) + { + if (!Directory.Exists(path)) + { + Console.WriteLine($"目标数据目录不存在:{path}"); + return; + } + + foreach (var file in Directory.GetFiles(path, "*.json", SearchOption.AllDirectories)) + { + try + { + var jsonContent = File.ReadAllText(file); + Console.WriteLine($"读取目标文件内容:{jsonContent}"); + + var data = JsonSerializer.Deserialize(jsonContent, _jsonOptions); + if (data != null) + { + string model = Path.GetFileNameWithoutExtension(file); + _targets[model] = data; + Console.WriteLine($"正在加载目标数据:{file}"); + Console.WriteLine($"读取到的数据:{JsonSerializer.Serialize(data, _jsonOptions)}"); + } + } + catch (Exception ex) + { + Console.WriteLine($"加载目标数据文件失败:{file},错误:{ex.Message}"); + Console.WriteLine($"异常堆栈:{ex.StackTrace}"); + } + } + } + + /// + /// 获取导弹配置数据 + /// + /// 导弹型号 + /// 导弹配置数据 + public MissileData GetMissile(string model) + { + if (_missiles.TryGetValue(model, out var data)) + return data; + throw new KeyNotFoundException($"Missile {model} not found"); + } + + /// + /// 获取指示器配置数据 + /// + /// 指示器型号 + /// 指示器配置数据 + public IndicatorData GetIndicator(string model) + { + if (_indicators.TryGetValue(model, out var data)) + return data; + throw new KeyNotFoundException($"Indicator {model} not found"); + } + + /// + /// 获取传感器配置数据 + /// + /// 传感器型号 + /// 传感器配置数据 + public SensorData GetSensor(string model) + { + if (_sensors.TryGetValue(model, out var data)) + return data; + throw new KeyNotFoundException($"Sensor {model} not found"); + } + + /// + /// 获取目标配置数据 + /// + /// 目标型号 + /// 目标配置数据 + public TargetData GetTarget(string model) + { + if (_targets.TryGetValue(model, out var data)) + return data; + throw new KeyNotFoundException($"Target {model} not found"); + } + + /// + /// 获取所有可用的导弹ID列表 + /// + public IEnumerable GetAvailableMissiles() => _missiles.Keys; + + /// + /// 获取所有可用的指示器ID列表 + /// + public IEnumerable GetAvailableIndicators() => _indicators.Keys; + + /// + /// 获取所有可用的传感器ID列表 + /// + public IEnumerable GetAvailableSensors() => _sensors.Keys; + + /// + /// 获取所有可用的目标ID列表 + /// + public IEnumerable GetAvailableTargets() => _targets.Keys; + } +} \ No newline at end of file diff --git a/ThreatSource/src/Data/ThreatSourceFactory.cs b/ThreatSource/src/Data/ThreatSourceFactory.cs new file mode 100644 index 0000000..c87c43a --- /dev/null +++ b/ThreatSource/src/Data/ThreatSourceFactory.cs @@ -0,0 +1,239 @@ +using System; +using ThreatSource.Missile; +using ThreatSource.Indicator; +using ThreatSource.Target; +using ThreatSource.Simulation; + +namespace ThreatSource.Data +{ + /// + /// 威胁源工厂类,负责根据配置数据创建各类设备实例 + /// + public class ThreatSourceFactory + { + private readonly ThreatSourceDataManager _dataManager; + private readonly ISimulationManager _simulationManager; + + /// + /// 构造函数 + /// + /// 数据管理器 + /// 仿真管理器 + public ThreatSourceFactory(ThreatSourceDataManager dataManager, ISimulationManager simulationManager) + { + _dataManager = dataManager; + _simulationManager = simulationManager; + } + + /// + /// 创建导弹实例 + /// + /// 导弹ID + /// 目标ID + /// 导弹型号 + /// 发射参数 + /// 导弹实例 + public BaseMissile CreateMissile(string missileId, string missileModel, string targetId, InitialMotionParameters launchParams) + { + var data = _dataManager.GetMissile(missileModel); + + switch (data.Type) + { + case MissileType.LaserBeamRiderGuidance: + if (data.LaserBeamRiderGuidanceConfig == null) + throw new ArgumentException($"Missing laser beam rider guidance configuration for missile: {missileModel}"); + return new LaserBeamRiderMissile( + missileId, + data.Properties, + launchParams, + data.Properties.LaserCodeConfig ?? new LaserCodeConfig(), + data.LaserBeamRiderGuidanceConfig, + _simulationManager + ); + + case MissileType.LaserSemiActiveGuidance: + if (data.LaserSemiActiveGuidanceConfig == null) + throw new ArgumentException($"Missing laser semi-active guidance configuration for missile: {missileModel}"); + return new LaserSemiActiveGuidedMissile( + missileId, + data.Properties, + launchParams, + data.Properties.LaserCodeConfig ?? new LaserCodeConfig(), + data.LaserSemiActiveGuidanceConfig, + _simulationManager + ); + + case MissileType.InfraredCommandGuidance: + return new InfraredCommandGuidedMissile( + missileId, + data.Properties, + launchParams, + _simulationManager + ); + + case MissileType.InfraredImagingTerminalGuidance: + if (_simulationManager.GetEntityById(targetId) is not ITarget target) + throw new ArgumentException($"Target not found or invalid: {targetId}"); + + if (data.InfraredImagingGuidanceConfig == null) + throw new ArgumentException($"Missing infrared imaging guidance configuration for missile: {missileModel}"); + + return new InfraredImagingTerminalGuidedMissile( + missileId, + target.Type, + data.Properties, + launchParams, + data.InfraredImagingGuidanceConfig, + _simulationManager + ); + + case MissileType.MillimeterWaveTerminalGuidance: + if (data.MillimeterWaveGuidanceConfig == null) + throw new ArgumentException($"Missing millimeter wave guidance configuration for missile: {missileModel}"); + return new MillimeterWaveTerminalGuidedMissile( + missileId, + data.Properties, + launchParams, + data.MillimeterWaveGuidanceConfig, + _simulationManager + ); + + case MissileType.TerminalSensitiveMissile: + if (data.SubmunitionProperties == null) + throw new ArgumentException("Missing submunition properties for terminal sensitive missile"); + if (data.SubmunitionConfig == null) + throw new ArgumentException("Missing submunition config for terminal sensitive missile"); + return new TerminalSensitiveMissile( + missileId, + targetId, + data.Properties, + launchParams, + data.SubmunitionProperties, + data.SubmunitionCount, + data.SubmunitionConfig, + _simulationManager + ); + + default: + throw new ArgumentException($"Unsupported missile type: {data.Type}"); + } + } + + /// + /// 创建指示器实例 + /// + /// 指示器ID + /// 指示器型号 + /// 目标ID + /// 导弹ID + /// 初始运动参数 + /// 指示器实例 + public IIndicator CreateIndicator(string indicatorId, string indicatorModel, string targetId, string missileId, InitialMotionParameters initialMotionParameters) + { + var data = _dataManager.GetIndicator(indicatorModel); + + Console.WriteLine($"dataType: {data.Type}, indicatorModel: {indicatorModel}, indicatorId: {indicatorId}, targetId: {targetId}, missileId: {missileId}"); + + switch (data.Type) + { + case "LaserDesignator" when data.DesignatorConfig != null: + return new LaserDesignator( + indicatorId, + targetId, + missileId, + data.DesignatorConfig, + initialMotionParameters, + _simulationManager + ); + + case "LaserBeamRider" when data.BeamRiderConfig != null: + return new LaserBeamRider( + indicatorId, + targetId, + missileId, + data.BeamRiderConfig, + initialMotionParameters, + _simulationManager + ); + case "InfraredTracker" when data.InfraredTrackerConfig != null: + return new InfraredTracker( + indicatorId, + targetId, + data.InfraredTrackerConfig, + initialMotionParameters, + _simulationManager + ); + + default: + throw new ArgumentException($"Invalid indicator type or missing config: {data.Type}"); + } + } + + /// + /// 创建目标实例 + /// + /// 目标ID + /// 目标型号 + /// 初始运动参数 + /// 目标实例 + public SimulationElement CreateTarget(string targetId, string targetModel, InitialMotionParameters initialMotionParameters) + { + var data = _dataManager.GetTarget(targetModel); + Console.WriteLine($"targetModel: {targetModel}, targetId: {targetId}, targetType: {data.Type}"); + + switch (data.Type) + { + case "Tank": + var tank = new Tank( + targetId, + initialMotionParameters, + _simulationManager); + tank.SetDimensions(data.Length, data.Width, data.Height); + tank.SetSpectralCharacteristics( + data.RadarCrossSection, + data.InfraredRadiationIntensity, + data.UltravioletRadiationIntensity, + data.MillimeterWaveRadiationIntensity); + tank.MillimeterWaveRadiationTemperature = data.MillimeterWaveRadiationTemperature; + tank.LaserReflectivity = data.LaserReflectivity; + tank.SetThermalPattern(data.ThermalPattern); + return tank; + + case "APC": + var apc = new APC( + targetId, + initialMotionParameters, + _simulationManager); + apc.SetDimensions(data.Length, data.Width, data.Height); + apc.SetSpectralCharacteristics( + data.RadarCrossSection, + data.InfraredRadiationIntensity, + data.UltravioletRadiationIntensity, + data.MillimeterWaveRadiationIntensity); + apc.MillimeterWaveRadiationTemperature = data.MillimeterWaveRadiationTemperature; + apc.LaserReflectivity = data.LaserReflectivity; + apc.SetThermalPattern(data.ThermalPattern); + return apc; + + case "Helicopter": + var helicopter = new Helicopter( + targetId, + initialMotionParameters, + _simulationManager); + helicopter.SetDimensions(data.Length, data.Width, data.Height); + helicopter.SetSpectralCharacteristics( + data.RadarCrossSection, + data.InfraredRadiationIntensity, + data.UltravioletRadiationIntensity, + data.MillimeterWaveRadiationIntensity); + helicopter.MillimeterWaveRadiationTemperature = data.MillimeterWaveRadiationTemperature; + helicopter.LaserReflectivity = data.LaserReflectivity; + helicopter.SetThermalPattern(data.ThermalPattern); + return helicopter; + + default: + throw new ArgumentException($"不支持的目标类型: {data.Type}"); + } + } + } +} \ No newline at end of file diff --git a/ThreatSource/src/Guidance/InfraredImage.cs b/ThreatSource/src/Guidance/InfraredImage.cs new file mode 100644 index 0000000..45fc82e --- /dev/null +++ b/ThreatSource/src/Guidance/InfraredImage.cs @@ -0,0 +1,88 @@ +using System; +using ThreatSource.Utils; + +namespace ThreatSource.Guidance +{ + /// + /// 红外图像类,表示简化的红外图像数据 + /// + /// + /// 该类存储红外图像的基本信息: + /// - 图像尺寸 + /// - 像素物理大小 + /// - 红外强度矩阵 + /// 用于目标探测和识别 + /// + public class InfraredImage + { + /// + /// 图像宽度,单位:像素 + /// + public int Width { get; } + + /// + /// 图像高度,单位:像素 + /// + public int Height { get; } + + /// + /// 像素物理尺寸,单位:弧度/像素 + /// + public double PixelSize { get; } + + /// + /// 红外强度矩阵,单位:W/sr + /// + public double[,] Intensity { get; } + + /// + /// 图像中心视线方向 + /// + public Vector3D LineOfSight { get; } + + /// + /// 初始化红外图像的新实例 + /// + /// 图像宽度 + /// 图像高度 + /// 像素物理尺寸 + /// 视线方向 + public InfraredImage(int width, int height, double pixelSize, Vector3D lineOfSight) + { + Width = width; + Height = height; + PixelSize = pixelSize; + LineOfSight = lineOfSight; + Intensity = new double[height, width]; + } + + /// + /// 设置像素强度值 + /// + /// 行索引 + /// 列索引 + /// 强度值 + public void SetIntensity(int row, int col, double value) + { + if (row >= 0 && row < Height && col >= 0 && col < Width) + { + Intensity[row, col] = value; + } + } + + /// + /// 获取像素强度值 + /// + /// 行索引 + /// 列索引 + /// 强度值 + public double GetIntensity(int row, int col) + { + if (row >= 0 && row < Height && col >= 0 && col < Width) + { + return Intensity[row, col]; + } + return 0.0; + } + } +} \ No newline at end of file diff --git a/ThreatSource/src/Guidance/InfraredImageGenerator.cs b/ThreatSource/src/Guidance/InfraredImageGenerator.cs new file mode 100644 index 0000000..6c44906 --- /dev/null +++ b/ThreatSource/src/Guidance/InfraredImageGenerator.cs @@ -0,0 +1,262 @@ +using System; +using ThreatSource.Target; +using ThreatSource.Utils; + +namespace ThreatSource.Guidance +{ + /// + /// 红外图像生成器,用于生成目标的红外图像 + /// + /// + /// 该类实现红外图像的生成过程: + /// - 计算目标在图像平面上的投影 + /// - 根据目标特性生成红外强度 + /// - 添加背景噪声 + /// + public class InfraredImageGenerator + { + /// + /// 图像宽度,单位:像素 + /// + private readonly int imageWidth; + + /// + /// 图像高度,单位:像素 + /// + private readonly int imageHeight; + + /// + /// 视场角,单位:弧度 + /// + private readonly double fieldOfView; + + /// + /// 背景辐射强度,单位:W/sr + /// + private readonly double backgroundIntensity; + + /// + /// 随机数生成器 + /// + private readonly Random random = new(); + + // 视线坐标系 + private Vector3D forward; // 视线方向 + private Vector3D right; // 图像平面右方向 + private Vector3D up; // 图像平面上方向 + + /// + /// 初始化红外图像生成器的新实例 + /// + /// 图像宽度 + /// 图像高度 + /// 视场角 + /// 背景辐射强度,单位:W/sr,典型地表背景约0.01-0.1 W/sr + public InfraredImageGenerator( + int imageWidth = 640, + int imageHeight = 512, + double fieldOfView = Math.PI / 18, + double backgroundIntensity = 0.01) + { + this.imageWidth = imageWidth; + this.imageHeight = imageHeight; + this.fieldOfView = fieldOfView; + this.backgroundIntensity = backgroundIntensity; + + // Initialize coordinate system with default values + forward = Vector3D.UnitZ; + right = Vector3D.UnitX; + up = Vector3D.UnitY; + } + + /// + /// 更新视线坐标系 + /// + private void UpdateLineOfSightFrame(Vector3D missilePosition, Vector3D targetPosition) + { + // 计算视线方向 + forward = (targetPosition - missilePosition).Normalize(); + + Console.WriteLine($"Line of sight direction: {forward}"); + + // 选择合适的上方向 + Vector3D worldUp = Math.Abs(Vector3D.DotProduct(forward, Vector3D.UnitZ)) > 0.99 + ? Vector3D.UnitY + : Vector3D.UnitZ; + + // 计算右方向和上方向 + right = Vector3D.CrossProduct(forward, worldUp).Normalize(); + up = Vector3D.CrossProduct(right, forward); + } + + /// + /// 将世界坐标投影到图像平面 + /// + private (double x, double y) ProjectToImagePlane(Vector3D worldPoint, Vector3D origin) + { + Vector3D relativePos = worldPoint - origin; + + // 计算在图像平面上的投影 + double x = Vector3D.DotProduct(relativePos, right); + double y = Vector3D.DotProduct(relativePos, up); + double z = Vector3D.DotProduct(relativePos, forward); + + // 转换为角度 + double angleX = Math.Atan2(x, z); + double angleY = Math.Atan2(y, z); + + Console.WriteLine($"Projection angles: X={angleX:F6} rad, Y={angleY:F6} rad"); + + return (angleX, angleY); + } + + /// + /// 将角度转换为像素坐标 + /// + private (int x, int y) AngleToPixel(double angleX, double angleY) + { + double pixelSize = fieldOfView / imageWidth; + + int pixelX = imageWidth/2 + (int)(angleX / pixelSize); + int pixelY = imageHeight/2 + (int)(angleY / pixelSize); + + Console.WriteLine($"Pixel coordinates: X={pixelX}, Y={pixelY}"); + + return (pixelX, pixelY); + } + + /// + /// 生成目标的红外图像 + /// + /// 目标对象 + /// 导弹位置 + /// 导弹速度 + /// 红外图像 + public InfraredImage GenerateImage(ITarget target, Vector3D missilePosition, Vector3D missileVelocity) + { + // 更新视线坐标系 + UpdateLineOfSightFrame(missilePosition, target.Position); + + // 创建图像 + var image = new InfraredImage(imageWidth, imageHeight, fieldOfView / imageWidth, forward); + + // 计算目标中心投影 + var (angleX, angleY) = ProjectToImagePlane(target.Position, missilePosition); + var (centerX, centerY) = AngleToPixel(angleX, angleY); + + // 计算目标尺寸 + double distance = (target.Position - missilePosition).Magnitude(); + double targetLengthAngle = Math.Atan2(target.Length, distance); + double targetWidthAngle = Math.Atan2(target.Width, distance); + + int pixelLength = (int)(targetLengthAngle / (fieldOfView / imageWidth)); + int pixelWidth = (int)(targetWidthAngle / (fieldOfView / imageWidth)); + + // 确保最小尺寸 + pixelLength = Math.Max(1, pixelLength); + pixelWidth = Math.Max(1, pixelWidth); + + Console.WriteLine($"Generated image for target {target.Id} with dimensions: {pixelLength}x{pixelWidth} pixels"); + Console.WriteLine($"Target center at: ({centerX}, {centerY})"); + + // 生成目标图像 + GenerateTargetIntensity(image, centerX, centerY, pixelLength, pixelWidth, target, distance); + + // 添加背景和噪声 + AddBackgroundAndNoise(image); + + return image; + } + + /// + /// 生成目标的红外强度分布 + /// + private void GenerateTargetIntensity( + InfraredImage image, + int centerX, + int centerY, + int pixelLength, + int pixelWidth, + ITarget target, + double distance) + { + // 计算目标辐射强度 + double targetIntensity = target.InfraredRadiationIntensity / Math.Pow(distance, 1.8); + + // 计算分布参数 + double sigmaX = pixelLength / 6.0; + double sigmaY = pixelWidth / 6.0; + + 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 normalizedX = dx / sigmaX; + double normalizedY = dy / sigmaY; + double r2 = normalizedX * normalizedX + normalizedY * normalizedY; + + // 高斯分布 + double intensity = targetIntensity * Math.Exp(-r2 / 2.0); + + image.SetIntensity(y, x, intensity); + pixelsSet++; + maxSetIntensity = Math.Max(maxSetIntensity, intensity); + } + } + + Console.WriteLine($"Target intensity distribution:"); + Console.WriteLine($" Pixels set: {pixelsSet}"); + Console.WriteLine($" Max set intensity: {maxSetIntensity:F6} W/sr"); + } + + /// + /// 添加背景辐射和噪声 + /// + private void AddBackgroundAndNoise(InfraredImage image) + { + double maxIntensityBefore = double.MinValue; + double maxIntensityAfter = double.MinValue; + int pixelsModified = 0; + + for (int y = 0; y < image.Height; y++) + { + for (int x = 0; x < image.Width; x++) + { + double currentIntensity = image.GetIntensity(y, x); + maxIntensityBefore = Math.Max(maxIntensityBefore, currentIntensity); + + // 只在非目标区域添加背景 + if (currentIntensity < backgroundIntensity * 0.1) + { + currentIntensity = backgroundIntensity; + pixelsModified++; + } + + // 添加高斯噪声 + double noise = (random.NextDouble() - 0.5) * backgroundIntensity * 0.2; + currentIntensity += noise; + + // 确保非负 + currentIntensity = Math.Max(0, currentIntensity); + + image.SetIntensity(y, x, currentIntensity); + maxIntensityAfter = Math.Max(maxIntensityAfter, currentIntensity); + } + } + } + } +} \ No newline at end of file diff --git a/ThreatSource/src/Guidance/InfraredImagingGuidanceSystem.cs b/ThreatSource/src/Guidance/InfraredImagingGuidanceSystem.cs index 6c0a4a5..d951688 100644 --- a/ThreatSource/src/Guidance/InfraredImagingGuidanceSystem.cs +++ b/ThreatSource/src/Guidance/InfraredImagingGuidanceSystem.cs @@ -19,62 +19,35 @@ namespace ThreatSource.Guidance public class InfraredImagingGuidanceSystem : BasicGuidanceSystem { /// - /// 最大探测范围,单位:米 + /// 工作模式枚举 /// /// - /// 定义了红外成像系统的最大作用距离 - /// 超出此范围的目标无法有效探测 + /// 定义了制导系统的三种工作模式: + /// - Search: 搜索模式,大视场角搜索目标 + /// - Track: 跟踪模式,小视场角精确跟踪,同时进行目标识别 + /// - Lock: 锁定模式,已确认目标类型,只进行跟踪 /// - private const double MAX_DETECTION_RANGE = 5000; + private enum WorkMode + { + Search, // 搜索模式 + Track, // 跟踪模式 + Lock // 锁定模式 + } /// - /// 视场角,单位:弧度 + /// 当前工作模式 /// - /// - /// 定义了成像系统的视场范围 - /// 标枪导弹为40度 - /// 坦克破坏者为24度 - /// - private const double FIELD_OF_VIEW = Math.PI / 6; + private WorkMode currentMode = WorkMode.Search; /// - /// 目标识别概率 + /// 是否已探测到目标 /// - /// - /// 定义了目标识别的成功率 - /// 影响系统的可靠性 - /// 典型值为0.9 - /// - private const double TARGET_RECOGNITION_PROBABILITY = 0.9; + public bool HasTarget { get; private set; } /// - /// 识别目标的信噪比阈值,单位:分贝 + /// 当前是否处于锁定模式 /// - /// - /// 定义了目标识别的最小信噪比要求 - /// 大于此值时认为目标有效 - /// 典型值为6dB - /// - private const double RECOGNITION_SNR_THRESHOLD = 6; - - /// - /// 背景辐射强度,单位:瓦特/球面度 - /// - /// - /// 定义了环境背景的红外辐射强度 - /// 用于信噪比计算 - /// 典型值为10W/sr - /// - private const double BACKGROUND_RADIATION_INTENSITY = 10; - - /// - /// 随机数生成器实例 - /// - /// - /// 用于生成随机扰动 - /// 模拟系统噪声 - /// - private readonly Random random = new(); + public bool IsInLockMode => currentMode == WorkMode.Lock; /// /// 上一次探测到的目标位置 @@ -85,10 +58,43 @@ namespace ThreatSource.Guidance /// private Vector3D lastTargetPosition; + /// + /// 红外图像生成器 + /// + private InfraredImageGenerator imageGenerator; + + /// + /// 目标识别器 + /// + private readonly InfraredTargetRecognizer targetRecognizer; + + /// + /// 要攻击的目标类型 + /// + private readonly TargetType targetType; + + /// + /// 红外成像制导系统配置 + /// + private readonly InfraredImagingGuidanceConfig config; + + /// + /// 目标丢失计时器 + /// + private double targetLostTimer = 0; + + /// + /// 锁定确认计时器 + /// + private double lockConfirmationTimer = 0; + + /// /// 初始化红外成像制导系统的新实例 /// /// 系统标识 + /// 红外成像制导系统配置 + /// 要攻击的目标类型 /// 最大加速度,单位:米/平方秒 /// 比例导引系数 /// 仿真管理器实例 @@ -97,11 +103,29 @@ namespace ThreatSource.Guidance /// - 初始化基类参数 /// - 设置仿真管理器 /// - 初始化目标位置 + /// - 初始化红外图像生成器和目标识别器 /// - public InfraredImagingGuidanceSystem(string id, double maxAcceleration, double proportionalNavigationCoefficient, ISimulationManager simulationManager) + public InfraredImagingGuidanceSystem( + string id, + InfraredImagingGuidanceConfig guidanceConfig, + TargetType targetType, + double maxAcceleration, + double proportionalNavigationCoefficient, + ISimulationManager simulationManager + ) : base(id, maxAcceleration, proportionalNavigationCoefficient, simulationManager) { lastTargetPosition = Vector3D.Zero; + this.targetType = targetType; + this.config = guidanceConfig; + targetRecognizer = new InfraredTargetRecognizer(simulationManager); + imageGenerator = new InfraredImageGenerator( + imageWidth: guidanceConfig.ImageWidth, + imageHeight: guidanceConfig.ImageHeight, + fieldOfView: guidanceConfig.SearchFieldOfView, + backgroundIntensity: guidanceConfig.BackgroundIntensity + ); + SwitchToSearchMode(); // 初始化为搜索模式 } /// @@ -121,8 +145,9 @@ namespace ThreatSource.Guidance { base.Update(deltaTime, missilePosition, missileVelocity); - if (TryDetectTank(missilePosition, missileVelocity, out Vector3D tankPosition)) + if (TryDetectAndIdentifyTarget(missilePosition, missileVelocity, deltaTime, out Vector3D tankPosition)) { + targetLostTimer = 0; // 重置丢失计时器 //根据目标当前位置和上一次位置计算目标速度 Vector3D targetVelocity = (tankPosition - lastTargetPosition) / deltaTime; lastTargetPosition = tankPosition; @@ -139,52 +164,201 @@ namespace ThreatSource.Guidance } else { - HasGuidance = false; + // 在跟踪或锁定模式下,增加丢失计时器 + if (currentMode != WorkMode.Search) + { + targetLostTimer += deltaTime; + // 只有当超过容忍时间才认为真正丢失目标 + if (targetLostTimer >= config.TargetLostTolerance) + { + HasGuidance = false; + // 切换回搜索模式 + Console.WriteLine($"Target lost for {targetLostTimer:F3}s, switching back to search mode"); + SwitchToSearchMode(); + } + } + else + { + HasGuidance = false; + } } } /// - /// 尝试探测目标坦克 + /// 切换到搜索模式 /// - /// 导弹当前位置,单位:米 - /// 导弹当前速度,单位:米/秒 - /// 输出探测到的坦克位置,单位:米 - /// 是否成功探测到目标 /// - /// 探测过程: - /// - 遍历场景中的目标 - /// - 检查距离和角度 - /// - 计算信噪比 - /// - 判断目标有效性 + /// 切换过程: + /// - 设置大视场角 + /// - 重置目标状态 + /// - 更新图像生成器参数 /// - private bool TryDetectTank(Vector3D missilePosition, Vector3D missileVelocity, out Vector3D tankPosition) + public void SwitchToSearchMode() { - tankPosition = Vector3D.Zero; + currentMode = WorkMode.Search; + HasTarget = false; + targetLostTimer = 0; // 重置丢失计时器 + imageGenerator = new InfraredImageGenerator( + imageWidth: config.ImageWidth, + imageHeight: config.ImageHeight, + fieldOfView: config.SearchFieldOfView, + backgroundIntensity: config.BackgroundIntensity + ); + Console.WriteLine($"Switched to search mode with FOV: {config.SearchFieldOfView * 180 / Math.PI} degrees"); + } + /// + /// 切换到跟踪模式 + /// + /// + /// 切换过程: + /// - 设置小视场角 + /// - 更新图像生成器参数 + /// - 提高目标识别概率要求 + /// + public void SwitchToTrackMode() + { + currentMode = WorkMode.Track; + lockConfirmationTimer = 0; // 重置锁定确认计时器 + imageGenerator = new InfraredImageGenerator( + imageWidth: config.ImageWidth, + imageHeight: config.ImageHeight, + fieldOfView: config.TrackFieldOfView, + backgroundIntensity: config.BackgroundIntensity + ); + Console.WriteLine($"Switched to track mode with FOV: {config.TrackFieldOfView * 180 / Math.PI} degrees"); + } + + /// + /// 切换到锁定模式 + /// + /// + /// 切换过程: + /// - 设置锁定状态 + /// - 保持当前图像生成器参数 + /// - 不再进行目标类型识别 + /// + public void SwitchToLockMode() + { + currentMode = WorkMode.Lock; + Console.WriteLine("Switched to lock mode - target type confirmed"); + } + + /// + /// 尝试探测和识别目标 + /// + /// 导弹当前位置 + /// 导弹当前速度 + /// 时间间隔,单位:秒 + /// 输出目标位置 + /// 是否成功探测到指定类型的目标 + /// + /// 探测和识别过程: + /// 1. 遍历场景中的目标 + /// 2. 检查目标是否在探测范围内 + /// 3. 生成目标红外图像 + /// 4. 识别目标类型 + /// 5. 判断是否是要攻击的目标类型 + /// + private bool TryDetectAndIdentifyTarget(Vector3D missilePosition, Vector3D missileVelocity, double deltaTime, out Vector3D targetPosition) + { + targetPosition = Vector3D.Zero; + double minDistance = double.MaxValue; + bool foundTarget = false; + + // 根据当前模式选择视场角和识别策略 + double currentFov = currentMode == WorkMode.Search ? config.SearchFieldOfView : config.TrackFieldOfView; + foreach (var element in SimulationManager.GetEntitiesByType()) { - if (element is Tank tank) + if (element is ITarget target) { - Vector3D toTarget = tank.Position - missilePosition; + Vector3D toTarget = target.Position - missilePosition; double distance = toTarget.Magnitude(); - if (distance <= MAX_DETECTION_RANGE) + // 检查距离条件 + if (distance <= config.MaxDetectionRange) { + // 检查视线角条件 double angle = Math.Acos(Vector3D.DotProduct(toTarget.Normalize(), missileVelocity.Normalize())); - if (angle <= FIELD_OF_VIEW / 2) + if (angle <= currentFov / 2) { - double snr = CalculateSNR(tank, distance); - if (snr > RECOGNITION_SNR_THRESHOLD) + // 生成红外图像 + var image = imageGenerator.GenerateImage(target, missilePosition, missileVelocity); + + switch (currentMode) { - tankPosition = tank.Position; - return true; + case WorkMode.Search: + // 搜索模式:使用较低阈值进行目标识别 + var searchResult = targetRecognizer.RecognizeTarget(image, target); + if (searchResult.Type == targetType && searchResult.Confidence >= config.SearchRecognitionProbability) + { + if (distance < minDistance) + { + targetPosition = target.Position; + minDistance = distance; + foundTarget = true; + // 切换到跟踪模式 + SwitchToTrackMode(); + } + } + break; + + case WorkMode.Track: + // 跟踪模式:使用较高阈值确认目标 + var trackResult = targetRecognizer.RecognizeTarget(image, target); + if (trackResult.Type == targetType && trackResult.Confidence >= config.TrackRecognitionProbability) + { + if (distance < minDistance) + { + targetPosition = target.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.Position; + minDistance = distance; + foundTarget = true; + } + } + else + { + // 目标置信度不足,重置锁定计时器 + lockConfirmationTimer = 0; + } + break; + + case WorkMode.Lock: + // 锁定模式:只进行位置跟踪,不做类型识别 + if (distance < minDistance) + { + targetPosition = target.Position; + minDistance = distance; + foundTarget = true; + } + break; } } } } } - return false; + HasTarget = foundTarget; + return foundTarget; } /// @@ -201,35 +375,7 @@ namespace ThreatSource.Guidance public override string GetStatus() { return base.GetStatus() + $", GuidanceAcceleration: {GuidanceAcceleration}, " + - $"Tank Position: {lastTargetPosition}"; - } - - /// - /// 计算目标的信噪比 - /// - /// 目标对象 - /// 到目标的距离,单位:米 - /// 信噪比,单位:分贝 - /// - /// 计算过程: - /// - 获取目标辐射强度 - /// - 考虑距离衰减 - /// - 计算信号强度 - /// - 计算噪声强度 - /// - 转换为分贝值 - /// - private static double CalculateSNR(ITarget target, double distance) - { - double targetRadiation = target.InfraredRadiationIntensity; - double backgroundRadiation = BACKGROUND_RADIATION_INTENSITY; - - // 考虑距离衰减 - double attenuationFactor = 1 / (distance * distance); - - double signal = (targetRadiation - backgroundRadiation) * attenuationFactor; - double noise = backgroundRadiation * attenuationFactor; - - return 10 * Math.Log10(signal / noise); // 转换为dB + $"Target Position: {lastTargetPosition}"; } } } diff --git a/ThreatSource/src/Guidance/InfraredTargetRecognizer.cs b/ThreatSource/src/Guidance/InfraredTargetRecognizer.cs new file mode 100644 index 0000000..f2d06f4 --- /dev/null +++ b/ThreatSource/src/Guidance/InfraredTargetRecognizer.cs @@ -0,0 +1,672 @@ +using System; +using System.Collections.Generic; +using ThreatSource.Target; +using ThreatSource.Data; +using ThreatSource.Utils; +using ThreatSource.Simulation; + +namespace ThreatSource.Guidance +{ + /// + /// 红外图像目标识别结果 + /// + public class RecognitionResult + { + /// + /// 识别出的目标类型 + /// + public TargetType Type { get; } + + /// + /// 识别置信度(0-1) + /// + public double Confidence { get; } + + /// + /// 目标在图像中的位置(像素坐标) + /// + public (int X, int Y) Position { get; } + + /// + /// 目标在图像中的尺寸(像素) + /// + public (int Width, int Height) Size { get; } + + /// + /// 初始化红外图像目标识别结果 + /// + /// 目标类型 + /// 识别置信度 + /// 目标在图像中的位置 + /// 目标在图像中的尺寸 + public RecognitionResult(TargetType type, double confidence, (int X, int Y) position, (int Width, int Height) size) + { + Type = type; + Confidence = confidence; + Position = position; + Size = size; + } + } + + /// + /// 红外图像目标识别器 + /// + /// + /// 该类实现红外图像的目标识别功能: + /// - 图像分割 + /// - 特征提取 + /// - 目标分类 + /// - 结果输出 + /// + public class InfraredTargetRecognizer + { + /// + /// 仿真管理器实例 + /// + private readonly ISimulationManager simulationManager; + + /// + /// 目标特征数据库 + /// + private readonly Dictionary targetFeatures; + + /// + /// 识别阈值 + /// + private const double RECOGNITION_THRESHOLD = 0.7; + + /// + /// 背景辐射强度,用于阈值计算 + /// + private const double BACKGROUND_INTENSITY = 0.01; + + /// + /// 初始化红外图像目标识别器 + /// + public InfraredTargetRecognizer(ISimulationManager simulationManager) + { + this.simulationManager = simulationManager; + // 初始化目标特征数据库 - 使用相对特征值 + targetFeatures = new Dictionary + { + { TargetType.Tank, new TargetFeature( + aspectRatio: 2.9, // 典型主战坦克长宽比 + size: 1.0, // 基准尺寸 + intensityPattern: 0.9, // 热量集中分布 + temperatureGradient: 0.8 // 高温度梯度 + )}, + { TargetType.APC, new TargetFeature( + aspectRatio: 2.1, // 较短的车身 + size: 0.7, // 相对坦克尺寸 + intensityPattern: 0.7, // 均匀热分布 + temperatureGradient: 0.5 // 中等温度梯度 + )}, + { TargetType.Helicopter, new TargetFeature( + aspectRatio: 4.8, // 考虑旋翼长度 + size: 1.4, // 较大的整体尺寸 + intensityPattern: 0.5, // 发动机热量集中 + temperatureGradient: 0.9 // 极高温度梯度 + )} + }; + } + + /// + /// 识别图像中的目标 + /// + /// 红外图像 + /// 要识别的目标 + /// 识别结果 + public RecognitionResult RecognizeTarget(InfraredImage image, ITarget target) + { + // 1. 图像分割,提取目标区域 + var segment = SegmentTarget(image); + if (!segment.IsValid) + { + Console.WriteLine("No valid segment found in image"); + return new RecognitionResult(TargetType.Unknown, 0.0, (0, 0), (0, 0)); + } + + // 2. 提取目标特征 + var features = ExtractFeatures(image, segment, target); + Console.WriteLine($"Extracted features: AspectRatio={features.AspectRatio:F2}, Size={features.Size:F2}, IntensityPattern={features.IntensityPattern:F2}, TemperatureGradient={features.TemperatureGradient:F2}"); + + // 3. 特征匹配和分类 + var (type, confidence) = ClassifyTarget(features); + Console.WriteLine($"Classification result: Type={type}, Confidence={confidence:F2}"); + + // 4. 返回识别结果 + return new RecognitionResult( + type, + confidence, + segment.Center, + segment.Size + ); + } + + /// + /// 图像分割,提取目标区域 + /// + private ImageSegment SegmentTarget(InfraredImage image) + { + // 使用简单的阈值分割方法 + double threshold = CalculateThreshold(image); + int minX = image.Width, minY = image.Height, maxX = 0, maxY = 0; + bool found = false; + int pixelsAboveThreshold = 0; + + // 寻找目标边界 + for (int y = 0; y < image.Height; y++) + { + for (int x = 0; x < image.Width; x++) + { + double intensity = image.GetIntensity(y, x); + if (intensity > threshold) + { + minX = Math.Min(minX, x); + minY = Math.Min(minY, y); + maxX = Math.Max(maxX, x); + maxY = Math.Max(maxY, y); + found = true; + pixelsAboveThreshold++; + } + } + } + + Console.WriteLine($"Segmentation results:"); + Console.WriteLine($" Pixels above threshold: {pixelsAboveThreshold}"); + if (found) + { + Console.WriteLine($" Target bounds: ({minX},{minY}) to ({maxX},{maxY})"); + Console.WriteLine($" Target size: {maxX - minX + 1}x{maxY - minY + 1} pixels"); + } + + if (!found) + { + return new ImageSegment(); + } + + return new ImageSegment( + isValid: true, + center: ((minX + maxX) / 2, (minY + maxY) / 2), + size: (maxX - minX + 1, maxY - minY + 1) + ); + } + + /// + /// 计算图像分割阈值 + /// + private double CalculateThreshold(InfraredImage image) + { + // 计算图像统计信息 + double sum = 0, count = 0; + double maxIntensity = double.MinValue; + double minIntensity = double.MaxValue; + + for (int y = 0; y < image.Height; y++) + { + for (int x = 0; x < image.Width; x++) + { + double value = image.GetIntensity(y, x); + maxIntensity = Math.Max(maxIntensity, value); + minIntensity = Math.Min(minIntensity, value); + sum += value; + count++; + } + } + + double mean = sum / count; + + // 计算背景基准阈值 + double backgroundThreshold = BACKGROUND_INTENSITY * 1.2; + + // 计算目标基准阈值 + double targetThreshold = maxIntensity * 0.2; + + // 取两个基准中的较大值作为最终阈值 + double threshold = Math.Max(backgroundThreshold, targetThreshold); + + Console.WriteLine($"Image statistics:"); + Console.WriteLine($" Max intensity: {maxIntensity:F6}"); + Console.WriteLine($" Min intensity: {minIntensity:F6}"); + Console.WriteLine($" Mean intensity: {mean:F6}"); + Console.WriteLine($" Background threshold: {backgroundThreshold:F6}"); + Console.WriteLine($" Target threshold: {targetThreshold:F6}"); + Console.WriteLine($" Final threshold: {threshold:F6}"); + + return threshold; + } + + /// + /// 提取目标特征 + /// + private TargetFeature ExtractFeatures(InfraredImage image, ImageSegment segment, ITarget target) + { + // 计算目标主方向 + double orientation = CalculateOrientation(image, segment); + + // 计算考虑姿态的长宽比 + double aspectRatio = CalculateOrientedAspectRatio(segment, orientation); + + // 计算相对尺寸(相对于图像宽度的比例) + double relativeSize = Math.Max(segment.Size.Width, segment.Size.Height) / (image.Width * 0.1); // 假设坦克基准尺寸约为图像宽度的10% + + // 计算强度模式特征 + double intensityPattern = CalculateIntensityPattern(image, segment); + + // 计算温度梯度特征 + double temperatureGradient = CalculateTemperatureGradient(image, segment, target); + + return new TargetFeature(aspectRatio, relativeSize, intensityPattern, temperatureGradient); + } + + /// + /// 计算目标主方向 + /// + private double CalculateOrientation(InfraredImage image, ImageSegment segment) + { + double m11 = 0, m20 = 0, m02 = 0; + double centerX = segment.Center.X; + double centerY = segment.Center.Y; + + // 计算二阶矩 + for (int y = segment.Center.Y - segment.Size.Height/2; y <= segment.Center.Y + segment.Size.Height/2; y++) + { + for (int x = segment.Center.X - segment.Size.Width/2; x <= segment.Center.X + segment.Size.Width/2; x++) + { + if (y >= 0 && y < image.Height && x >= 0 && x < image.Width) + { + double intensity = image.GetIntensity(y, x); + double dx = x - centerX; + double dy = y - centerY; + m11 += dx * dy * intensity; + m20 += dx * dx * intensity; + m02 += dy * dy * intensity; + } + } + } + + // 计算主方向 + return 0.5 * Math.Atan2(2 * m11, m20 - m02); + } + + /// + /// 计算考虑姿态的长宽比 + /// + private double CalculateOrientedAspectRatio(ImageSegment segment, double orientation) + { + // 计算旋转后的边界框 + double cos = Math.Cos(orientation); + double sin = Math.Sin(orientation); + double width = Math.Abs(segment.Size.Width * cos) + Math.Abs(segment.Size.Height * sin); + double height = Math.Abs(segment.Size.Width * sin) + Math.Abs(segment.Size.Height * cos); + + return width / height; + } + + /// + /// 计算温度梯度特征 + /// + private double CalculateTemperatureGradient(InfraredImage image, ImageSegment segment, ITarget target) + { + // 直接从目标获取温度分布数据 + double[,] thermalPattern = target.GetCurrentThermalPattern(); + if (thermalPattern == null) + { + Console.WriteLine("No thermal pattern available, using image-based gradient calculation"); + return CalculateImageBasedGradient(image, segment); + } + + var pattern = new ThermalPattern(thermalPattern, thermalPattern); + + // 判断目标是否在运动 + bool isMoving = IsTargetMoving(image, segment); + Console.WriteLine($"Target movement status: {(isMoving ? "Moving" : "Static")}"); + + // 使用温度分布模式计算梯度特征 + double gradientFeature = pattern.CalculateGradientFeature(isMoving); + + return gradientFeature; + } + + /// + /// 基于图像计算温度梯度(当没有温度分布模式数据时使用) + /// + private double CalculateImageBasedGradient(InfraredImage image, ImageSegment segment) + { + // Sobel算子 + double[,] sobelX = {{-1, 0, 1}, {-2, 0, 2}, {-1, 0, 1}}; + double[,] sobelY = {{-1, -2, -1}, {0, 0, 0}, {1, 2, 1}}; + + // 获取目标区域最大强度用于归一化 + double maxIntensity = double.MinValue; + + // 将目标区域划分为3x3的网格 + int gridRows = 3; + int gridCols = 3; + double[,] gridGradients = new double[gridRows, gridCols]; + int[,] gridCounts = new int[gridRows, gridCols]; + + // 第一遍扫描:获取最大强度 + for (int y = segment.Center.Y - segment.Size.Height/2; y <= segment.Center.Y + segment.Size.Height/2; y++) + { + for (int x = segment.Center.X - segment.Size.Width/2; x <= segment.Center.X + segment.Size.Width/2; x++) + { + if (y >= 0 && y < image.Height && x >= 0 && x < image.Width) + { + maxIntensity = Math.Max(maxIntensity, image.GetIntensity(y, x)); + } + } + } + + if (maxIntensity <= 0) return 0; + + // 计算每个网格的大小 + int gridWidth = segment.Size.Width / gridCols; + int gridHeight = segment.Size.Height / gridRows; + + // 第二遍扫描:计算每个网格的梯度 + for (int y = segment.Center.Y - segment.Size.Height/2 + 1; + y < segment.Center.Y + segment.Size.Height/2 - 1; y++) + { + for (int x = segment.Center.X - segment.Size.Width/2 + 1; + x < segment.Center.X + segment.Size.Width/2 - 1; x++) + { + if (y >= 1 && y < image.Height - 1 && x >= 1 && x < image.Width - 1) + { + // 计算当前点属于哪个网格 + int gridRow = (y - (segment.Center.Y - segment.Size.Height/2)) * gridRows / segment.Size.Height; + int gridCol = (x - (segment.Center.X - segment.Size.Width/2)) * gridCols / segment.Size.Width; + + gridRow = Math.Min(Math.Max(gridRow, 0), gridRows - 1); + gridCol = Math.Min(Math.Max(gridCol, 0), gridCols - 1); + + double gradX = 0, gradY = 0; + + // 应用Sobel算子 + for (int i = -1; i <= 1; i++) + { + for (int j = -1; j <= 1; j++) + { + double value = image.GetIntensity(y + i, x + j); + gradX += value * sobelX[i + 1, j + 1]; + gradY += value * sobelY[i + 1, j + 1]; + } + } + + // 计算归一化梯度 + double normalizedGradient = Math.Sqrt(gradX * gradX + gradY * gradY) / maxIntensity; + + // 累加到对应的网格 + gridGradients[gridRow, gridCol] += normalizedGradient; + gridCounts[gridRow, gridCol]++; + } + } + } + + // 计算每个网格的平均梯度 + double[,] avgGridGradients = new double[gridRows, gridCols]; + for (int i = 0; i < gridRows; i++) + { + for (int j = 0; j < gridCols; j++) + { + avgGridGradients[i, j] = gridCounts[i, j] > 0 ? + gridGradients[i, j] / gridCounts[i, j] : 0; + } + } + + // 计算后部区域(发动机舱)的梯度特征 + double engineAreaGradient = (avgGridGradients[1, 2] + avgGridGradients[2, 2]) / 2.0; + + // 计算前部区域的梯度特征 + double frontAreaGradient = (avgGridGradients[1, 0] + avgGridGradients[2, 0]) / 2.0; + + // 计算中部区域的梯度特征 + double middleAreaGradient = avgGridGradients[1, 1]; + + // 计算梯度分布特征 + double gradientDistribution = engineAreaGradient / (frontAreaGradient + 0.1); + double gradientContrast = engineAreaGradient / (middleAreaGradient + 0.1); + + // 最终得分:后部梯度强度(0.3) + 梯度分布特征(0.4) + 梯度对比度(0.3) + return engineAreaGradient * 0.3 + + Math.Min(gradientDistribution, 3.0) / 3.0 * 0.4 + + Math.Min(gradientContrast, 3.0) / 3.0 * 0.3; + } + + /// + /// 判断目标是否在运动 + /// + private bool IsTargetMoving(InfraredImage image, ImageSegment segment) + { + // TODO: 实现运动检测逻辑 + // 可以基于: + // 1. 连续帧之间的位置变化 + // 2. 速度传感器数据 + // 3. 运动检测算法 + return false; + } + + /// + /// 计算强度模式特征 + /// + private double CalculateIntensityPattern(InfraredImage image, ImageSegment segment) + { + const int BINS = 10; + double[] histogram = new double[BINS]; + + // 获取目标区域最大和最小强度 + double maxIntensity = double.MinValue; + double minIntensity = double.MaxValue; + double centerIntensity = 0; + int centerPixelCount = 0; + double totalIntensity = 0; + int totalPixels = 0; + + // 定义中心区域大小(目标尺寸的1/3) + int centerRegionWidth = segment.Size.Width / 3; + int centerRegionHeight = segment.Size.Height / 3; + + // 第一遍扫描:获取强度范围和中心区域强度 + for (int y = segment.Center.Y - segment.Size.Height/2; y <= segment.Center.Y + segment.Size.Height/2; y++) + { + for (int x = segment.Center.X - segment.Size.Width/2; x <= segment.Center.X + segment.Size.Width/2; x++) + { + if (y >= 0 && y < image.Height && x >= 0 && x < image.Width) + { + double intensity = image.GetIntensity(y, x); + maxIntensity = Math.Max(maxIntensity, intensity); + minIntensity = Math.Min(minIntensity, intensity); + totalIntensity += intensity; + totalPixels++; + + // 检查是否在中心区域 + if (Math.Abs(x - segment.Center.X) <= centerRegionWidth/2 && + Math.Abs(y - segment.Center.Y) <= centerRegionHeight/2) + { + centerIntensity += intensity; + centerPixelCount++; + } + } + } + } + + if (totalPixels == 0 || maxIntensity <= minIntensity) return 0; + + // 计算平均中心强度 + double avgCenterIntensity = centerPixelCount > 0 ? centerIntensity / centerPixelCount : 0; + // 计算平均总强度 + double avgTotalIntensity = totalIntensity / totalPixels; + + // 填充直方图 + double binSize = (maxIntensity - minIntensity) / BINS; + + // 第二遍扫描:填充直方图 + for (int y = segment.Center.Y - segment.Size.Height/2; y <= segment.Center.Y + segment.Size.Height/2; y++) + { + for (int x = segment.Center.X - segment.Size.Width/2; x <= segment.Center.X + segment.Size.Width/2; x++) + { + if (y >= 0 && y < image.Height && x >= 0 && x < image.Width) + { + double intensity = image.GetIntensity(y, x); + int bin = Math.Min(BINS - 1, (int)((intensity - minIntensity) / binSize)); + histogram[bin]++; + } + } + } + + // 归一化直方图 + for (int i = 0; i < BINS; i++) + { + histogram[i] /= totalPixels; + } + + // 计算集中度得分:高强度bin的占比越高,得分越高 + double concentrationScore = 0; + for (int i = 0; i < BINS; i++) + { + // 使用指数权重,使高强度bin的影响更大 + double weight = Math.Pow(2, i) / Math.Pow(2, BINS-1); // 指数增长的权重 + concentrationScore += histogram[i] * weight; + } + + // 计算中心区域相对强度比 + double centerIntensityRatio = avgCenterIntensity / avgTotalIntensity; + + // 最终得分:集中度得分(0.6)和中心强度比(0.4)的加权和 + return concentrationScore * 0.6 + centerIntensityRatio * 0.4; + } + + /// + /// 目标分类 + /// + private (TargetType type, double confidence) ClassifyTarget(TargetFeature features) + { + TargetType bestMatch = TargetType.Unknown; + double bestScore = 0; + + // 计算特征权重 + var weights = CalculateFeatureWeights(features); + + foreach (var kvp in targetFeatures) + { + double score = CalculateMatchScore(features, kvp.Value, weights); + Console.WriteLine($"Match score for {kvp.Key}: {score:F2}"); + if (score > bestScore) + { + bestScore = score; + bestMatch = kvp.Key; + } + } + + // 使用自适应阈值 + double threshold = CalculateAdaptiveThreshold(features); + Console.WriteLine($"Adaptive threshold: {threshold:F2}"); + + return bestScore > threshold ? + (bestMatch, bestScore) : + (TargetType.Unknown, bestScore); + } + + /// + /// 计算特征权重 + /// + private double[] CalculateFeatureWeights(TargetFeature features) + { + // 使用固定权重,基于特征的重要性 + return new[] + { + 0.3, // 长宽比权重 + 0.2, // 相对尺寸权重 + 0.25, // 强度模式权重 + 0.25 // 温度梯度权重 + }; + } + + /// + /// 计算自适应阈值 + /// + private double CalculateAdaptiveThreshold(TargetFeature features) + { + // 降低基准阈值,使用0.4作为基准 + double baseThreshold = 0.4; + + // 计算特征质量因子 + 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; + + return baseThreshold * (0.8 + 0.4 * qualityFactor); + } + + /// + /// 计算特征匹配得分 + /// + private double CalculateMatchScore(TargetFeature features, TargetFeature template, double[] weights) + { + // 计算各个特征的匹配度,使用相对误差 + 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)); + + // 输出详细的匹配分数 + Console.WriteLine($"Feature match scores:"); + Console.WriteLine($" Aspect Ratio: {aspectRatioScore:F2} (weight: {weights[0]:F2})"); + Console.WriteLine($" Size: {sizeScore:F2} (weight: {weights[1]:F2})"); + Console.WriteLine($" Pattern: {patternScore:F2} (weight: {weights[2]:F2})"); + Console.WriteLine($" Gradient: {gradientScore:F2} (weight: {weights[3]:F2})"); + + // 加权平均 + double totalScore = aspectRatioScore * weights[0] + + sizeScore * weights[1] + + patternScore * weights[2] + + gradientScore * weights[3]; + + Console.WriteLine($" Total Score: {totalScore:F2}"); + return totalScore; + } + + /// + /// 目标特征结构 + /// + private struct TargetFeature + { + public double AspectRatio { get; } // 长宽比 + public double Size { 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; + } + } + + /// + /// 图像分割结果结构 + /// + private struct ImageSegment + { + public bool IsValid { get; } + public (int X, int Y) Center { get; } + public (int Width, int Height) Size { get; } + + public ImageSegment(bool isValid = false, (int X, int Y) center = default, (int Width, int Height) size = default) + { + IsValid = isValid; + Center = center; + Size = size; + } + } + } +} \ No newline at end of file diff --git a/ThreatSource/src/Guidance/LaserBeamRiderGuidanceSystem.cs b/ThreatSource/src/Guidance/LaserBeamRiderGuidanceSystem.cs index 4a63a79..4704888 100644 --- a/ThreatSource/src/Guidance/LaserBeamRiderGuidanceSystem.cs +++ b/ThreatSource/src/Guidance/LaserBeamRiderGuidanceSystem.cs @@ -1,6 +1,7 @@ using ThreatSource.Utils; using ThreatSource.Simulation; using System.Diagnostics; +using System.Collections.Generic; namespace ThreatSource.Guidance { @@ -110,12 +111,42 @@ namespace ThreatSource.Guidance /// private bool LaserIlluminationOn { get; set; } + /// + /// 获取或设置期望的激光编码配置 + /// + /// + /// 导弹期望接收的编码信息 + /// 用于验证接收到的激光信号 + /// + private LaserCodeConfig? InternalLaserCodeConfig { get; set; } + + /// + /// 获取或设置支持的编码类型列表 + /// + /// + /// 定义导弹支持的编码类型 + /// 默认支持PRF、PPM和PWM编码 + /// + private List supportedCodeTypes = new List + { + LaserCodeType.PRF, + LaserCodeType.PPM, + LaserCodeType.PWM + }; + + /// + /// 系统配置参数 + /// + private readonly LaserBeamRiderGuidanceSystemConfig config; + /// /// 初始化激光驾束制导系统的新实例 /// /// 制导系统ID /// 最大加速度,单位:米/平方秒 /// 制导系数 + /// 激光编码配置,可选 + /// 制导系统配置参数 /// 仿真管理器实例 /// /// 构造过程: @@ -123,14 +154,148 @@ namespace ThreatSource.Guidance /// - 初始化激光参数 /// - 初始化控制参数 /// - public LaserBeamRiderGuidanceSystem(string id, double maxAcceleration, double guidanceCoefficient, ISimulationManager simulationManager) + public LaserBeamRiderGuidanceSystem( + string id, + double maxAcceleration, + double guidanceCoefficient, + LaserCodeConfig? laserCodeConfig, + LaserBeamRiderGuidanceSystemConfig guidanceConfig, + ISimulationManager simulationManager) : base(id, maxAcceleration, guidanceCoefficient, simulationManager) { + config = guidanceConfig; LaserSourcePosition = Vector3D.Zero; LaserDirection = Vector3D.Zero; LaserPower = 0; - HasGuidance = false; + LaserIlluminationOn = false; + LastError = Vector3D.Zero; + IntegralError = Vector3D.Zero; LastGuidanceAcceleration = Vector3D.Zero; + + // 如果没有提供编码配置,创建默认配置 + InternalLaserCodeConfig = laserCodeConfig ?? new LaserCodeConfig + { + Code = new LaserCode + { + CodeType = LaserCodeType.PPM, + CodeValue = 1234 + }, + IsCodeEnabled = true, + IsCodeMatchRequired = true + }; + } + + /// + /// 设置期望的激光编码 + /// + /// 编码类型 + /// 编码值 + /// + /// 设置过程: + /// - 检查编码类型是否支持 + /// - 创建新的编码对象 + /// - 设置编码类型和值 + /// + public void SetExpectedLaserCode(LaserCodeType codeType, int codeValue) + { + if (supportedCodeTypes.Contains(codeType)) + { + InternalLaserCodeConfig = new LaserCodeConfig + { + Code = new LaserCode { CodeType = codeType, CodeValue = codeValue } + }; + Debug.WriteLine($"激光驾束制导系统设置期望编码:类型={codeType},值={codeValue}"); + } + else + { + Debug.WriteLine($"激光驾束制导系统不支持编码类型:{codeType}"); + } + } + + /// + /// 添加期望编码参数 + /// + /// 参数名称 + /// 参数值 + /// + /// 添加特定编码类型的额外参数 + /// 如PPM编码的脉冲位置模式、PWM编码的脉冲宽度等 + /// + public void AddExpectedCodeParameter(string key, object value) + { + if (InternalLaserCodeConfig != null) + { + InternalLaserCodeConfig.Code.Parameters[key] = value; + Debug.WriteLine($"激光驾束制导系统添加期望编码参数:{key}={value}"); + } + } + + /// + /// 设置是否要求编码匹配 + /// + /// 是否要求匹配 + /// + /// 设置导弹是否严格要求激光编码匹配 + /// true表示必须匹配,false表示不要求匹配 + /// + public void SetCodeMatchRequired(bool required) + { + if (InternalLaserCodeConfig != null) + { + InternalLaserCodeConfig.IsCodeMatchRequired = required; + Debug.WriteLine($"激光驾束制导系统设置编码匹配要求:{required}"); + } + } + + /// + /// 检查激光编码是否匹配 + /// + /// 接收到的激光编码配置 + /// 如果匹配返回true,否则返回false + /// + /// 检查过程: + /// - 验证编码类型 + /// - 验证编码值 + /// - 验证额外参数 + /// + private bool CheckLaserCode(LaserCodeConfig? receivedConfig) + { + return InternalLaserCodeConfig?.CheckCodeMatch(receivedConfig) ?? false; + } + + /// + /// 发布编码匹配事件 + /// + /// 激光定位器ID + /// 匹配的编码配置 + private void PublishCodeMatchEvent(string? designatorId, LaserCodeConfig? matchedCodeConfig) + { + var matchEvent = new LaserCodeMatchEvent + { + MissileId = ParentId, + DesignatorId = designatorId, + MatchedCodeConfig = matchedCodeConfig + }; + + PublishEvent(matchEvent); + } + + /// + /// 发布编码不匹配事件 + /// + /// 激光定位器ID + /// 接收到的编码配置 + private void PublishCodeMismatchEvent(string? designatorId, LaserCodeConfig? receivedCodeConfig) + { + var mismatchEvent = new LaserCodeMismatchEvent + { + MissileId = ParentId, + DesignatorId = designatorId, + ExpectedCodeConfig = InternalLaserCodeConfig, + ReceivedCodeConfig = receivedCodeConfig + }; + + PublishEvent(mismatchEvent); } /// @@ -224,7 +389,7 @@ namespace ThreatSource.Guidance double shortestDistance = shortestDistanceVector.Magnitude(); // 检查导弹是否在控制场内 - if (shortestDistance > ControlFieldDiameter / 2) + if (shortestDistance > config.ControlFieldDiameter / 2) { HasGuidance = false; Trace.WriteLine($"激光驾束引导系统: 失去引导, 原因: 超出控制场范围, 距离: {shortestDistance}"); @@ -234,11 +399,11 @@ namespace ThreatSource.Guidance Debug.WriteLine($"激光驾束引导系统: 在控制场内, 距离: {shortestDistance}"); // 计算接收到的激光功率 - double beamArea = Math.PI * Math.Pow(ControlFieldDiameter / 2, 2); + double beamArea = Math.PI * Math.Pow(config.ControlFieldDiameter / 2, 2); double powerDensity = LaserPower / beamArea; - double receivedPower = powerDensity * (Math.PI * Math.Pow(DetectorDiameter / 2, 2)); + double receivedPower = powerDensity * (Math.PI * Math.Pow(config.DetectorDiameter / 2, 2)); - if(HasGuidance = receivedPower >= MinDetectablePower) + if(receivedPower >= config.MinDetectablePower) { HasGuidance = true; } @@ -275,12 +440,6 @@ namespace ThreatSource.Guidance Vector3D shortestDistanceVector = CalculateShortestDistanceToLaserBeam(); // PID控制 - double Kp = 30; // 增加比例系数,使系统对误差更敏感,反应更快 30 - double Ki = 0.05; // 减小积分系数,减少长期误差累积的影响 0.05 - double Kd = 5; // 增加微分系数,减少系统的超调量,提高稳定性 5 - double Kc = 0.5; // 减小非线性增益系数, 控制偏移量, 使得在更小的误差范围内有更大的修正 0.5 - - // 计算误差 Vector3D error = shortestDistanceVector; // 积分项 @@ -290,20 +449,21 @@ namespace ThreatSource.Guidance Vector3D derivativeError = (error - LastError) / deltaTime; // 计算PID输出 - Vector3D pidOutput = error * Kp + IntegralError * Ki + derivativeError * Kd; + Vector3D pidOutput = error * config.ProportionalGain + + IntegralError * config.IntegralGain + + derivativeError * config.DerivativeGain; // 非线性增益 double distance = shortestDistanceVector.Magnitude(); - double nonLinearGain = Math.Tanh(distance / Kc); + double nonLinearGain = Math.Tanh(distance / config.NonlinearGain); // 计算横向加速度 Vector3D lateralAcceleration = pidOutput * nonLinearGain; // 限制最大加速度 - double maxAcceleration = 50; // 稍微增加最大加速度 50 - if (lateralAcceleration.Magnitude() > maxAcceleration) + if (lateralAcceleration.Magnitude() > config.MaxGuidanceAcceleration) { - lateralAcceleration = lateralAcceleration.Normalize() * maxAcceleration; + lateralAcceleration = lateralAcceleration.Normalize() * config.MaxGuidanceAcceleration; } // 计算前向加速度 @@ -317,8 +477,8 @@ namespace ThreatSource.Guidance GuidanceAcceleration = lateralAcceleration + forwardAcceleration; // 低通滤波 - const double alpha = 0.2; - GuidanceAcceleration = GuidanceAcceleration * alpha + LastGuidanceAcceleration * (1 - alpha); + GuidanceAcceleration = GuidanceAcceleration * config.LowPassFilterCoefficient + + LastGuidanceAcceleration * (1 - config.LowPassFilterCoefficient); // 更新上一次的误差和制导加速度 LastError = error; @@ -368,5 +528,74 @@ namespace ThreatSource.Guidance return shortestDistanceVector; } + + /// + /// 处理激光波束开始事件 + /// + /// 激光波束开始事件 + private void OnLaserBeamStart(LaserBeamStartEvent evt) + { + if (evt?.LaserBeamRiderId != null) + { + // 检查编码是否匹配 + bool codeMatched = CheckLaserCode(evt.LaserCodeConfig); + + if (!codeMatched) + { + // 发布编码不匹配事件 + PublishCodeMismatchEvent(evt.LaserBeamRiderId, evt.LaserCodeConfig); + Debug.WriteLine("激光驾束制导系统接收到不匹配的激光编码,忽略信号"); + HasGuidance = false; + LaserIlluminationOn = false; + return; + } + + // 如果编码匹配,发布匹配事件 + PublishCodeMatchEvent(evt.LaserBeamRiderId, evt.LaserCodeConfig); + + // 更新激光波束参数 + LaserPower = evt.BeamPower; + LaserIlluminationOn = true; + HasGuidance = true; + } + } + + /// + /// 处理激光波束更新事件 + /// + /// 激光波束更新事件 + private void OnLaserBeamUpdate(LaserBeamUpdateEvent evt) + { + if (evt?.LaserBeamRiderId != null) + { + // 检查编码是否匹配 + bool codeMatched = CheckLaserCode(evt.LaserCodeConfig); + + if (!codeMatched) + { + // 发布编码不匹配事件 + PublishCodeMismatchEvent(evt.LaserBeamRiderId, evt.LaserCodeConfig); + Debug.WriteLine("激光驾束制导系统接收到不匹配的激光编码,忽略信号"); + HasGuidance = false; + LaserIlluminationOn = false; + return; + } + + // 更新激光波束参数 + LaserPower = evt.BeamPower; + LaserIlluminationOn = true; + HasGuidance = true; + } + } + + /// + /// 处理激光波束停止事件 + /// + /// 激光波束停止事件 + private void OnLaserBeamStop(LaserBeamStopEvent evt) + { + LaserIlluminationOn = false; + HasGuidance = false; + } } } diff --git a/ThreatSource/src/Guidance/LaserSemiActiveGuidanceSystem.cs b/ThreatSource/src/Guidance/LaserSemiActiveGuidanceSystem.cs index 6165879..127e44f 100644 --- a/ThreatSource/src/Guidance/LaserSemiActiveGuidanceSystem.cs +++ b/ThreatSource/src/Guidance/LaserSemiActiveGuidanceSystem.cs @@ -19,75 +19,7 @@ namespace ThreatSource.Guidance /// public class LaserSemiActiveGuidanceSystem : BasicGuidanceSystem { - /// - /// 视场角,单位:弧度 - /// - /// - /// 定义了探测器的视场范围 - /// 设置为30度(π/6弧度) - /// 影响系统的探测能力 - /// - private const double FieldOfViewAngle = Math.PI / 6; - - /// - /// 镜头直径,单位:米 - /// - /// - /// 定义了光学系统镜头的物理尺寸 - /// 影响系统的光能量收集能力 - /// 典型值为0.1米 - /// - private const double LensDiameter = 0.1; - - /// - /// 传感器直径,单位:米 - /// - /// - /// 定义了四象限探测器的物理尺寸 - /// 影响系统的探测精度 - /// 典型值为0.03米 - /// - private const double SensorDiameter = 0.03; - - /// - /// 聚焦后光斑直径,单位:米 - /// - /// - /// 定义了光学系统聚焦后的光斑大小 - /// 影响系统的探测灵敏度 - /// 典型值为0.006米 - /// - private const double FocusedSpotDiameter = 0.006; - - /// - /// 目标反射系数 - /// - /// - /// 定义了目标表面的激光反射能力 - /// 影响反射信号强度 - /// 典型值为0.2 - /// - private const double ReflectionCoefficient = 0.2; - - /// - /// 锁定阈值,单位:瓦特 - /// - /// - /// 定义了系统锁定目标的最小功率要求 - /// 低于此值时认为无法有效跟踪目标 - /// 典型值为1e-12瓦特 - /// - private const double LockThreshold = 1e-12; - - /// - /// 目标有效反射面积,单位:平方米 - /// - /// - /// 定义了目标的等效反射面积 - /// 影响反射信号强度 - /// 典型值为1.0平方米 - /// - private const double TargetReflectiveArea = 1.0; + private readonly LaserSemiActiveGuidanceConfig config; /// /// 获取或设置目标位置 @@ -98,15 +30,6 @@ namespace ThreatSource.Guidance /// private Vector3D TargetPosition { get; set; } - /// - /// 获取或设置目标速度 - /// - /// - /// 记录当前跟踪目标的三维速度 - /// 用于制导计算和预测 - /// - private Vector3D TargetVelocity { get; set; } - /// /// 获取或设置激光照射状态 /// @@ -149,19 +72,9 @@ namespace ThreatSource.Guidance /// /// 导弹期望接收的编码信息 /// 用于验证接收到的激光信号 - /// 默认编码为PPM编码,值为123456 + /// 默认编码为PPM编码,值为1234 /// - private LaserCode? expectedLaserCode = new LaserCode { CodeType = LaserCodeType.PPM, CodeValue = 123456 }; - - /// - /// 获取或设置是否要求编码匹配 - /// - /// - /// true表示只响应匹配编码的激光信号 - /// false表示响应所有激光信号 - /// 默认为true - /// - private bool isCodeMatchRequired = true; + private LaserCodeConfig? InternalLaserCodeConfig { get; set; } /// /// 获取或设置支持的编码类型列表 @@ -203,6 +116,8 @@ namespace ThreatSource.Guidance /// 制导系统ID /// 最大加速度,单位:米/平方秒 /// 制导系数 + /// 激光编码配置 + /// 激光半主动导引系统配置 /// 仿真管理器实例 /// /// 构造过程: @@ -211,17 +126,31 @@ namespace ThreatSource.Guidance /// - 初始化激光参数 /// - 创建四象限探测器 /// - public LaserSemiActiveGuidanceSystem(string id, double maxAcceleration, double guidanceCoefficient, ISimulationManager simulationManager) + public LaserSemiActiveGuidanceSystem( + string id, + double maxAcceleration, + double guidanceCoefficient, + LaserCodeConfig laserCodeConfig, + LaserSemiActiveGuidanceConfig guidanceConfig, + ISimulationManager simulationManager) : base(id, maxAcceleration, guidanceCoefficient, simulationManager) { + config = guidanceConfig; + TargetPosition = Vector3D.Zero; - TargetVelocity = Vector3D.Zero; LaserIlluminationOn = false; LaserDesignatorPosition = Vector3D.Zero; LaserPower = 0; + InternalLaserCodeConfig = laserCodeConfig; - // 创建四象限探测器实例 - quadrantDetector = new QuadrantDetector(SensorDiameter, FocusedSpotDiameter, LockThreshold); + // 创建四象限探测器实例,使用配置中的参数 + quadrantDetector = new QuadrantDetector( + config.SensorDiameter, + config.FocusedSpotDiameter, + config.LockThreshold); + + // 设置光斑偏移灵敏度 + SpotOffsetSensitivity = config.SpotOffsetSensitivity; } /// @@ -272,7 +201,7 @@ namespace ThreatSource.Guidance SimulationElement target = SimulationManager.GetEntityById(evt.TargetId) as SimulationElement ?? throw new Exception("目标不存在"); // 更新激光指示器信息 - UpdateLaserDesignator(laserDesignator.Position, target.Position, target.Velocity, + UpdateLaserDesignator(laserDesignator.Position, target.Position, laserDesignator.LaserPower, laserDesignator.LaserDivergenceAngle); // 处理激光照射开始事件 @@ -303,7 +232,7 @@ namespace ThreatSource.Guidance SimulationElement target = SimulationManager.GetEntityById(evt.TargetId) as SimulationElement ?? throw new Exception("目标不存在"); // 更新激光指示器信息 - UpdateLaserDesignator(laserDesignator.Position, target.Position, target.Velocity, + UpdateLaserDesignator(laserDesignator.Position, target.Position, laserDesignator.LaserPower, laserDesignator.LaserDivergenceAngle); // 处理激光照射更新事件 @@ -338,7 +267,6 @@ namespace ThreatSource.Guidance /// /// 激光源位置,单位:米 /// 目标位置,单位:米 - /// 目标速度,单位:米/秒 /// 激光功率,单位:瓦特 /// 激光发散角,单位:弧度 /// @@ -348,12 +276,11 @@ namespace ThreatSource.Guidance /// - 更新目标信息 /// - 更新激光参数 /// - public void UpdateLaserDesignator(Vector3D sourcePosition, Vector3D targetPosition, Vector3D targetVelocity, double laserPower, double laserDivergenceAngle) + public void UpdateLaserDesignator(Vector3D sourcePosition, Vector3D targetPosition, double laserPower, double laserDivergenceAngle) { LaserIlluminationOn = true; LaserDesignatorPosition = sourcePosition; TargetPosition = targetPosition; - TargetVelocity = targetVelocity; LaserPower = laserPower; LaserDivergenceAngle = laserDivergenceAngle; } @@ -374,7 +301,6 @@ namespace ThreatSource.Guidance LaserIlluminationOn = false; LaserDesignatorPosition = Vector3D.Zero; TargetPosition = Vector3D.Zero; - TargetVelocity = Vector3D.Zero; LaserPower = 0; LaserDivergenceAngle = 0; } @@ -450,7 +376,7 @@ namespace ThreatSource.Guidance double powerDensityAtTarget = LaserPower / spotAreaAtTarget; // 计算从目标反射的总功率 - double reflectedPower = powerDensityAtTarget * TargetReflectiveArea * ReflectionCoefficient; + double reflectedPower = powerDensityAtTarget * config.TargetReflectiveArea * config.ReflectionCoefficient; // 计算反射光在导弹处的扩散面积(假设漫反射) double reflectedSpotArea = 2 * Math.PI * Math.Pow(distanceMissileToTarget, 2); @@ -459,13 +385,13 @@ namespace ThreatSource.Guidance double receivedPower = reflectedPower / reflectedSpotArea; // 计算镜头接收到的功率比例 - double lensArea = Math.PI * Math.Pow(LensDiameter / 2, 2); - double illuminatedArea = Math.PI * Math.Pow(distanceMissileToTarget * Math.Tan(FieldOfViewAngle / 2), 2); + double lensArea = Math.PI * Math.Pow(config.LensDiameter / 2, 2); + double illuminatedArea = Math.PI * Math.Pow(distanceMissileToTarget * Math.Tan(config.FieldOfViewAngleInRadians / 2), 2); double powerRatio = Math.Min(1, lensArea / illuminatedArea); // 计算聚焦后的功率密度增加 - double sensorArea = Math.PI * Math.Pow(SensorDiameter / 2, 2); - double focusedArea = Math.PI * Math.Pow(FocusedSpotDiameter / 2, 2); + double sensorArea = Math.PI * Math.Pow(config.SensorDiameter / 2, 2); + double focusedArea = Math.PI * Math.Pow(config.FocusedSpotDiameter / 2, 2); double focusingFactor = sensorArea / focusedArea; // 计算最终接收到的功率 @@ -514,7 +440,7 @@ namespace ThreatSource.Guidance double verticalAngle = Math.Atan2(upComponent, forwardComponent); // 转换为光斑偏移量(假设小角度近似) - double focalLength = SensorDiameter / (2 * Math.Tan(FieldOfViewAngle / 2)); + double focalLength = config.SensorDiameter / (2 * Math.Tan(config.FieldOfViewAngleInRadians / 2)); double horizontalOffset = focalLength * Math.Tan(horizontalAngle); double verticalOffset = focalLength * Math.Tan(verticalAngle); @@ -579,7 +505,7 @@ namespace ThreatSource.Guidance return base.GetStatus() + $" 激光目标指示器功率: {LaserPower}," + $" 接收到的激光功率: {CalculateReceivedLaserPower():E} W," + - $" 锁定阈值: {LockThreshold:E} W," + + $" 锁定阈值: {config.LockThreshold:E} W," + $" 四象限探测器: {quadrantDetector.GetStatus()}"; } @@ -647,10 +573,9 @@ namespace ThreatSource.Guidance { if (supportedCodeTypes.Contains(codeType)) { - expectedLaserCode = new LaserCode + InternalLaserCodeConfig = new LaserCodeConfig { - CodeType = codeType, - CodeValue = codeValue + Code = new LaserCode { CodeType = codeType, CodeValue = codeValue } }; Debug.WriteLine($"激光半主动制导系统设置期望编码:类型={codeType},值={codeValue}"); } @@ -671,27 +596,13 @@ namespace ThreatSource.Guidance /// public void AddExpectedCodeParameter(string key, object value) { - if (expectedLaserCode != null) + if (InternalLaserCodeConfig != null) { - expectedLaserCode.Parameters[key] = value; + InternalLaserCodeConfig.Code.Parameters[key] = value; Debug.WriteLine($"激光半主动制导系统添加期望编码参数:{key}={value}"); } } - /// - /// 设置是否要求编码匹配 - /// - /// 是否要求匹配 - /// - /// true表示只响应匹配编码的激光信号 - /// false表示响应所有激光信号 - /// - public void SetCodeMatchRequired(bool required) - { - isCodeMatchRequired = required; - Debug.WriteLine($"激光半主动制导系统{(required ? "要求" : "不要求")}编码匹配"); - } - /// /// 处理激光照射事件 /// @@ -710,9 +621,7 @@ namespace ThreatSource.Guidance { ProcessLaserIlluminationCommon( illuminationEvent.LaserDesignatorId, - illuminationEvent.TargetId, - illuminationEvent.LaserCode, - illuminationEvent.IsCodeEnabled, + illuminationEvent.LaserCodeConfig, true); // 初始照射 } @@ -734,9 +643,7 @@ namespace ThreatSource.Guidance { ProcessLaserIlluminationCommon( illuminationEvent.LaserDesignatorId, - illuminationEvent.TargetId, - illuminationEvent.LaserCode, - illuminationEvent.IsCodeEnabled, + illuminationEvent.LaserCodeConfig, false); // 更新照射 } @@ -744,9 +651,7 @@ namespace ThreatSource.Guidance /// 处理激光照射事件的共同逻辑 /// /// 激光指示器ID - /// 目标ID - /// 激光编码 - /// 是否启用编码 + /// 激光编码配置 /// 是否是初始照射(开始事件) /// /// 处理过程: @@ -758,44 +663,48 @@ namespace ThreatSource.Guidance /// - 计算光斑偏移并传递给四象限探测器 /// - 根据四象限探测器的锁定状态更新制导状态 /// - private void ProcessLaserIlluminationCommon(string? laserDesignatorId, string? targetId, - LaserCode? laserCode, bool isCodeEnabled, bool isInitialIllumination) + private void ProcessLaserIlluminationCommon(string? laserDesignatorId, + LaserCodeConfig? laserCodeConfig, bool isInitialIllumination) { - // 检查编码是否匹配 - bool codeMatched = CheckCodeMatch(laserCode, isCodeEnabled); - - if (isCodeMatchRequired && !codeMatched) + if (laserCodeConfig != null) { - // 发布编码不匹配事件 - PublishCodeMismatchEvent(laserDesignatorId, laserCode); - Trace.WriteLine("激光半主动制导系统接收到不匹配的激光编码,忽略信号"); - HasGuidance = false; // 禁用制导 - LaserIlluminationOn = false; // 禁用激光照射状态,确保四象限探测器不处理信号 - // 重置四象限探测器状态 - quadrantDetector.ProcessLaserSignal(0, new Vector2D(0, 0)); - return; // 不处理不匹配的信号 + bool codeMatched = InternalLaserCodeConfig?.CheckCodeMatch(laserCodeConfig) ?? false; + + if (!codeMatched) + { + // 发布编码不匹配事件 + PublishCodeMismatchEvent(laserDesignatorId, laserCodeConfig); + Trace.WriteLine("激光半主动制导系统接收到不匹配的激光编码,忽略信号"); + HasGuidance = false; // 禁用制导 + LaserIlluminationOn = false; // 禁用激光照射状态,确保四象限探测器不处理信号 + // 重置四象限探测器状态 + quadrantDetector.ProcessLaserSignal(0, new Vector2D(0, 0)); + return; + } + else + { + // 如果编码匹配,继续处理 + // 只有在初始照射或激光尚未开启时才发布编码匹配事件 + if (isInitialIllumination || !LaserIlluminationOn) + { + // 发布编码匹配事件 + PublishCodeMatchEvent(laserDesignatorId, laserCodeConfig); + } + + // 更新激光照射状态 + LaserIlluminationOn = true; + + // 计算接收到的激光功率 + double receivedPower = CalculateReceivedLaserPower(); + + // 计算光斑偏移并传递给四象限探测器 + Vector2D spotOffset = CalculateSpotOffset(); + quadrantDetector.ProcessLaserSignal(receivedPower, spotOffset); + + // 更新制导状态 - 根据四象限探测器的锁定状态 + HasGuidance = quadrantDetector.IsTargetLocked; + } } - - // 如果编码匹配或不要求匹配,继续处理 - // 只有在初始照射或激光尚未开启时才发布编码匹配事件 - if (codeMatched && (isInitialIllumination || !LaserIlluminationOn)) - { - // 发布编码匹配事件 - PublishCodeMatchEvent(laserDesignatorId, laserCode); - } - - // 更新激光照射状态 - LaserIlluminationOn = true; - - // 计算接收到的激光功率 - double receivedPower = CalculateReceivedLaserPower(); - - // 计算光斑偏移并传递给四象限探测器 - Vector2D spotOffset = CalculateSpotOffset(); - quadrantDetector.ProcessLaserSignal(receivedPower, spotOffset); - - // 更新制导状态 - 根据四象限探测器的锁定状态 - HasGuidance = quadrantDetector.IsTargetLocked; } /// @@ -813,68 +722,24 @@ namespace ThreatSource.Guidance HasGuidance = false; // 禁用制导 } - /// - /// 检查编码是否匹配 - /// - /// 接收到的编码 - /// 是否启用编码 - /// 如果匹配返回true,否则返回false - /// - /// 匹配规则: - /// - 如果不要求匹配,返回true - /// - 如果接收到的信号未启用编码 - /// - 如果导弹未设置期望编码 - /// - 检查编码类型是否支持 - /// - 检查编码是否匹配 - /// - private bool CheckCodeMatch(LaserCode? receivedCode, bool isCodeEnabled) - { - // 如果不要求匹配,直接返回true - if (!isCodeMatchRequired) - { - return true; - } - - // 如果接收到的信号未启用编码 - if (!isCodeEnabled || receivedCode == null) - { - return false; // 如果要求编码匹配,但编码被禁用,则不匹配 - } - - // 如果导弹未设置期望编码 - if (expectedLaserCode == null) - { - return false; // 如果要求编码匹配,但导弹未设置期望编码,则不匹配 - } - - // 检查编码类型是否支持 - if (!supportedCodeTypes.Contains(receivedCode.CodeType)) - { - return false; - } - - // 检查编码是否匹配 - return expectedLaserCode.Matches(receivedCode); - } - /// /// 发布编码匹配事件 /// /// 激光定位器ID - /// 匹配的编码 + /// 匹配的编码配置 /// /// 发布过程: /// - 创建事件对象 /// - 设置事件属性 /// - 发布到事件系统 /// - private void PublishCodeMatchEvent(string? designatorId, LaserCode? matchedCode) + private void PublishCodeMatchEvent(string? designatorId, LaserCodeConfig? matchedCodeConfig) { var matchEvent = new LaserCodeMatchEvent { MissileId = ParentId, DesignatorId = designatorId, - MatchedCode = matchedCode + MatchedCodeConfig = matchedCodeConfig }; PublishEvent(matchEvent); @@ -884,21 +749,21 @@ namespace ThreatSource.Guidance /// 发布编码不匹配事件 /// /// 激光定位器ID - /// 接收到的编码 + /// 接收到的编码配置 /// /// 发布过程: /// - 创建事件对象 /// - 设置事件属性 /// - 发布到事件系统 /// - private void PublishCodeMismatchEvent(string? designatorId, LaserCode? receivedCode) + private void PublishCodeMismatchEvent(string? designatorId, LaserCodeConfig? receivedCodeConfig) { var mismatchEvent = new LaserCodeMismatchEvent { MissileId = ParentId, DesignatorId = designatorId, - ExpectedCode = expectedLaserCode, - ReceivedCode = receivedCode + ExpectedCodeConfig = InternalLaserCodeConfig, + ReceivedCodeConfig = receivedCodeConfig }; PublishEvent(mismatchEvent); diff --git a/ThreatSource/src/Guidance/MillimeterWaveGuidanceSystem.cs b/ThreatSource/src/Guidance/MillimeterWaveGuidanceSystem.cs index 16bda0e..1c00e1c 100644 --- a/ThreatSource/src/Guidance/MillimeterWaveGuidanceSystem.cs +++ b/ThreatSource/src/Guidance/MillimeterWaveGuidanceSystem.cs @@ -18,64 +18,13 @@ namespace ThreatSource.Guidance public class MillimeterWaveGuidanceSystem : BasicGuidanceSystem { /// - /// 最大探测范围,单位:米 + /// 毫米波导引系统配置 /// /// - /// 定义了毫米波雷达的最大作用距离 - /// 超出此范围的目标无法有效探测 - /// 典型值为5000米 + /// 存储系统的所有可配置参数 + /// 包括探测范围、视场角等 /// - private const double MAX_DETECTION_RANGE = 5000; - - /// - /// 视场角,单位:弧度 - /// - /// - /// 定义了雷达的扫描范围 - /// 设置为45度(π/4弧度) - /// 影响系统的搜索能力 - /// - private const double FIELD_OF_VIEW = Math.PI / 4; - - /// - /// 目标识别概率 - /// - /// - /// 定义了目标识别的成功率 - /// 影响系统的可靠性 - /// 典型值为0.95 - /// - private const double TARGET_RECOGNITION_PROBABILITY = 0.95; - - /// - /// 毫米波频率,单位:赫兹 - /// - /// - /// 定义了雷达工作频率 - /// 设置为94GHz - /// 影响探测性能和抗干扰能力 - /// - private const double WAVE_FREQUENCY = 94e9; - - /// - /// 脉冲持续时间,单位:秒 - /// - /// - /// 定义了雷达发射脉冲的时长 - /// 影响距离分辨率 - /// 典型值为1微秒 - /// - private const double PULSE_DURATION = 1e-6; - - /// - /// 识别目标的信噪比阈值,单位:分贝 - /// - /// - /// 定义了目标识别的最小信噪比要求 - /// 大于此值时认为目标有效 - /// 典型值为6dB - /// - private const double RECOGNITION_SNR_THRESHOLD = 6; + private readonly MillimeterWaveGuidanceConfig config; /// /// 随机数生成器实例 @@ -120,6 +69,7 @@ namespace ThreatSource.Guidance /// 最大加速度,单位:米/平方秒 /// 制导系数 /// 仿真管理器实例 + /// 毫米波导引系统配置 /// /// 构造过程: /// - 初始化基类参数 @@ -127,9 +77,15 @@ namespace ThreatSource.Guidance /// - 初始化目标位置 /// - 注册干扰事件处理 /// - public MillimeterWaveGuidanceSystem(string id, double maxAcceleration, double guidanceCoefficient, ISimulationManager simulationManager) + public MillimeterWaveGuidanceSystem( + string id, + double maxAcceleration, + double guidanceCoefficient, + MillimeterWaveGuidanceConfig config, + ISimulationManager simulationManager) : base(id, maxAcceleration, guidanceCoefficient, simulationManager) { + this.config = config; lastTargetPosition = Vector3D.Zero; // 订阅干扰事件 @@ -168,7 +124,7 @@ namespace ThreatSource.Guidance { base.Update(deltaTime, missilePosition, missileVelocity); - if (TryDetectTank(missilePosition, missileVelocity, out Vector3D tankPosition)) + if (TryDetectTarget(missilePosition, missileVelocity, out Vector3D tankPosition)) { //根据目标当前位置和上一次位置计算目标速度 Vector3D targetVelocity = (tankPosition - lastTargetPosition) / deltaTime; @@ -191,7 +147,7 @@ namespace ThreatSource.Guidance } /// - /// 尝试探测目标坦克 + /// 尝试探测目标 /// /// 导弹当前位置,单位:米 /// 导弹当前速度,单位:米/秒 @@ -205,7 +161,7 @@ namespace ThreatSource.Guidance /// - 计算信噪比 /// - 判断目标有效性 /// - private bool TryDetectTank(Vector3D missilePosition, Vector3D missileVelocity, out Vector3D targetPosition) + private bool TryDetectTarget(Vector3D missilePosition, Vector3D missileVelocity, out Vector3D targetPosition) { targetPosition = Vector3D.Zero; @@ -218,22 +174,22 @@ namespace ThreatSource.Guidance foreach (var element in SimulationManager.GetEntitiesByType()) { - if (element is Tank tank) + if (element is ITarget target) { - Vector3D toTarget = tank.Position - missilePosition; + Vector3D toTarget = target.Position - missilePosition; double distance = toTarget.Magnitude(); - if (distance <= MAX_DETECTION_RANGE) + if (distance <= config.MaxDetectionRange) { double angle = Math.Acos(Vector3D.DotProduct(toTarget.Normalize(), missileVelocity.Normalize())); - if (angle <= FIELD_OF_VIEW / 2) + if (angle <= config.FieldOfViewAngleInRadians / 2) { // 模拟毫米波探测 - double snr = CalculateSNR(distance, tank.RadarCrossSection); + double snr = CalculateSNR(distance, target.RadarCrossSection); - if(snr > RECOGNITION_SNR_THRESHOLD && random.NextDouble() < TARGET_RECOGNITION_PROBABILITY) + if(snr > config.RecognitionSNRThreshold && random.NextDouble() < config.TargetRecognitionProbability) { - targetPosition = tank.Position; + targetPosition = target.Position; return true; } } @@ -273,12 +229,12 @@ namespace ThreatSource.Guidance /// - 计算信噪比 /// - 转换为分贝值 /// - private static double CalculateSNR(double distance, double radarCrossSection) + private double CalculateSNR(double distance, double radarCrossSection) { // 雷达参数 double transmitPower = 100; // 发射功率(W) double antennaGain = Math.Pow(10, 30/10); // 天线增益(线性值,从dB转换) - double wavelength = 3e8 / WAVE_FREQUENCY; // 波长(m) + double wavelength = 3e8 / config.WaveFrequency; // 波长(m) double bandwidth = 1e6; // 接收机带宽(Hz),假设为1MHz double noiseFigure = Math.Pow(10, 3/10); // 噪声系数(线性值,假设为3dB) diff --git a/ThreatSource/src/Indicator/InfraredTracker.cs b/ThreatSource/src/Indicator/InfraredTracker.cs index fbe293d..d27daee 100644 --- a/ThreatSource/src/Indicator/InfraredTracker.cs +++ b/ThreatSource/src/Indicator/InfraredTracker.cs @@ -62,6 +62,7 @@ namespace ThreatSource.Indicator /// 测角仪ID /// 目标ID /// 配置参数 + /// 初始运动参数 /// 仿真管理器实例 /// /// 构造过程: @@ -70,8 +71,8 @@ namespace ThreatSource.Indicator /// - 配置工作参数 /// - 设置初始状态 /// - public InfraredTracker(string id, string targetId, InfraredTrackerConfig config, ISimulationManager manager) - : base(id, config.InitialPosition, config.InitialOrientation, 0, manager) + public InfraredTracker(string id, string targetId, InfraredTrackerConfig config, InitialMotionParameters initialMotionParameters, ISimulationManager manager) + : base(id, initialMotionParameters.Position, initialMotionParameters.Orientation, initialMotionParameters.InitialSpeed, manager) { TargetId = targetId; MissileId = null; diff --git a/ThreatSource/src/Indicator/LaserBeamRider.cs b/ThreatSource/src/Indicator/LaserBeamRider.cs index a019b2e..e8dce64 100644 --- a/ThreatSource/src/Indicator/LaserBeamRider.cs +++ b/ThreatSource/src/Indicator/LaserBeamRider.cs @@ -35,6 +35,15 @@ namespace ThreatSource.Indicator /// public double BeamDivergence { get; private set; } = 0.0; + /// + /// 获取或设置激光编码配置 + /// + /// + /// 包含激光信号的编码信息 + /// 用于抗干扰和安全识别 + /// + public LaserCodeConfig LaserCodeConfig { get; set; } + /// /// 获取或设置控制场直径 /// @@ -95,8 +104,8 @@ namespace ThreatSource.Indicator /// 制导器的唯一标识符 /// 导弹ID /// 目标ID - /// 初始速度 /// 配置参数 + /// 初始运动参数 /// 仿真管理器实例 /// /// 构造过程: @@ -105,8 +114,8 @@ namespace ThreatSource.Indicator /// - 配置制导范围 /// - 建立目标关联 /// - public LaserBeamRider(string id, string missileId, string targetId, double speed, LaserBeamRiderConfig config, ISimulationManager simulationManager) - : base(id, config.InitialPosition, new Orientation(0, 0, 0), speed, simulationManager) + public LaserBeamRider(string id, string targetId, string missileId, LaserBeamRiderConfig config, InitialMotionParameters initialMotionParameters, ISimulationManager simulationManager) + : base(id, initialMotionParameters.Position, initialMotionParameters.Orientation, initialMotionParameters.InitialSpeed, simulationManager) { LaserPower = config.LaserPower; ControlFieldDiameter = config.ControlFieldDiameter; @@ -116,9 +125,27 @@ namespace ThreatSource.Indicator IsBeamOn = false; MissileId = missileId; TargetId = targetId; + LaserCodeConfig = config.LaserCodeConfig; base.SimulationManager = simulationManager; } + /// + /// 添加编码参数 + /// + /// 参数名称 + /// 参数值 + /// + /// 添加特定编码类型的额外参数 + /// 如PPM编码的脉冲位置模式、PWM编码的脉冲宽度等 + /// + public void AddCodeParameter(string key, object value) + { + if (LaserCodeConfig != null) + { + LaserCodeConfig.Code.Parameters[key] = value; + } + } + /// /// 更新激光驾束仪状态 /// diff --git a/ThreatSource/src/Indicator/LaserDesignator.cs b/ThreatSource/src/Indicator/LaserDesignator.cs index c5a68f8..cdd5a71 100644 --- a/ThreatSource/src/Indicator/LaserDesignator.cs +++ b/ThreatSource/src/Indicator/LaserDesignator.cs @@ -87,24 +87,13 @@ namespace ThreatSource.Indicator public double LaserDivergenceAngle { get; private set; } = 0.5e-3; /// - /// 获取或设置激光编码 + /// 获取或设置激光编码配置 /// /// /// 包含激光信号的编码信息 /// 用于抗干扰和安全识别 - /// 默认编码为PPM编码,值为123456 /// - private LaserCode? currentLaserCode = new LaserCode { CodeType = LaserCodeType.PPM, CodeValue = 123456 }; - - /// - /// 获取或设置是否启用编码 - /// - /// - /// true表示激光信号使用编码 - /// false表示激光信号不使用编码 - /// 默认为true - /// - private bool isCodeEnabled = true; + public LaserCodeConfig LaserCodeConfig { get; set; } /// /// 初始化激光指示器的新实例 @@ -112,8 +101,8 @@ namespace ThreatSource.Indicator /// 激光指示器ID /// 目标ID /// 导弹ID - /// 移动速度 /// 配置参数 + /// 初始运动参数 /// 仿真管理器实例 /// /// 构造过程: @@ -122,8 +111,8 @@ namespace ThreatSource.Indicator /// - 配置激光参数 /// - 设置初始状态 /// - public LaserDesignator(string id, string targetId, string missileId, double speed, LaserDesignatorConfig config, ISimulationManager simulationManager) - : base(id, config.InitialPosition, CalculateInitialOrientation(config.InitialPosition, targetId, simulationManager), speed, simulationManager) + public LaserDesignator(string id, string targetId, string missileId, LaserDesignatorConfig config, InitialMotionParameters initialMotionParameters, ISimulationManager simulationManager) + : base(id, initialMotionParameters.Position, initialMotionParameters.Orientation, initialMotionParameters.InitialSpeed, simulationManager) { TargetId = targetId; MissileId = missileId; @@ -131,6 +120,7 @@ namespace ThreatSource.Indicator IsIlluminationOn = false; LaserPower = config.LaserPower; LaserDivergenceAngle = config.LaserDivergenceAngle; + LaserCodeConfig = config.LaserCodeConfig; } /// @@ -288,7 +278,6 @@ namespace ThreatSource.Indicator IsJammed = false; // 先订阅事件 SimulationManager.SubscribeToEvent(OnLaserJamming); - SimulationManager.SubscribeToEvent(OnEntityDeactivatedEvent); // 再开始照射 StartLaserIllumination(); } @@ -313,32 +302,10 @@ namespace ThreatSource.Indicator IsActive = false; StopLaserIllumination(); SimulationManager.UnsubscribeFromEvent(OnLaserJamming); - SimulationManager.UnsubscribeFromEvent(OnEntityDeactivatedEvent); } base.Deactivate(); } - /// - /// 设置激光编码 - /// - /// 编码类型 - /// 编码值 - /// - /// 设置过程: - /// - 创建新的编码对象 - /// - 设置编码类型和值 - /// - 启用编码功能 - /// - public void SetLaserCode(LaserCodeType codeType, int codeValue) - { - currentLaserCode = new LaserCode - { - CodeType = codeType, - CodeValue = codeValue - }; - isCodeEnabled = true; - } - /// /// 添加编码参数 /// @@ -350,25 +317,12 @@ namespace ThreatSource.Indicator /// public void AddCodeParameter(string key, object value) { - if (currentLaserCode != null) + if (LaserCodeConfig != null) { - currentLaserCode.Parameters[key] = value; + LaserCodeConfig.Code.Parameters[key] = value; } } - /// - /// 启用或禁用编码 - /// - /// 是否启用编码 - /// - /// true表示启用编码功能 - /// false表示禁用编码功能 - /// - public void EnableCode(bool enable) - { - isCodeEnabled = enable; - } - /// /// 发布激光照射开始事件 /// @@ -390,14 +344,9 @@ namespace ThreatSource.Indicator }; // 添加编码信息 - if (isCodeEnabled && currentLaserCode != null) + if (LaserCodeConfig != null) { - illuminationEvent.LaserCode = currentLaserCode; - illuminationEvent.IsCodeEnabled = true; - } - else - { - illuminationEvent.IsCodeEnabled = false; + illuminationEvent.LaserCodeConfig = LaserCodeConfig; } // 发布事件 @@ -424,14 +373,9 @@ namespace ThreatSource.Indicator }; // 添加编码信息 - if (isCodeEnabled && currentLaserCode != null) + if (LaserCodeConfig != null) { - illuminationEvent.LaserCode = currentLaserCode; - illuminationEvent.IsCodeEnabled = true; - } - else - { - illuminationEvent.IsCodeEnabled = false; + illuminationEvent.LaserCodeConfig = LaserCodeConfig; } PublishEvent(illuminationEvent); @@ -453,24 +397,6 @@ namespace ThreatSource.Indicator PublishEvent(evt); } - /// - /// 处理实体停用事件 - /// - /// 实体停用事件数据 - /// - /// 处理过程: - /// - 检查停用实体 - /// - 处理关联实体 - /// - 更新工作状态 - /// - private void OnEntityDeactivatedEvent(EntityDeactivatedEvent evt) - { - if (evt.DeactivatedEntityId == TargetId || evt.DeactivatedEntityId == MissileId) - { - StopLaserIllumination(); - } - } - /// /// 获取激光指示器运行状态 /// @@ -519,7 +445,7 @@ namespace ThreatSource.Indicator $" 激活状态: {(IsActive ? "激活" : "未激活")}\n" + $" 照射状态: {(IsIlluminationOn ? "正在照射" : "未照射")}\n" + $" 干扰状态: {(IsJammed ? "被干扰" : "正常")}\n" + - $" 编码状态: {(isCodeEnabled ? "启用" : "禁用")}\n" + + $" 编码状态: {(LaserCodeConfig != null ? "启用" : "禁用")}\n" + $" 激光功率: {LaserPower:E} W"; } } diff --git a/ThreatSource/src/MIssile/BaseMissile.cs b/ThreatSource/src/MIssile/BaseMissile.cs index 27bff51..cbc0ad1 100644 --- a/ThreatSource/src/MIssile/BaseMissile.cs +++ b/ThreatSource/src/MIssile/BaseMissile.cs @@ -88,7 +88,7 @@ namespace ThreatSource.Missile /// 由制导系统计算得出的期望加速度 /// 用于修正导弹的飞行路径 /// - protected Vector3D GuidanceAcceleration { get; set; } + protected Vector3D GuidanceAcceleration { get; set; } = Vector3D.Zero; /// /// 获取或设置导弹的推力加速度 @@ -108,31 +108,37 @@ namespace ThreatSource.Missile /// 包含导弹的所有基本属性和性能限制 /// 在导弹创建时设置,运行期间保持不变 /// - public readonly MissileProperties MissileProperties; + public readonly MissileProperties Properties; /// /// 初始化导弹基类的新实例 /// - /// 导弹的配置参数 + /// 导弹ID + /// 导弹属性配置 + /// 发射参数 /// 仿真管理器实例 /// /// 构造过程: - /// - 初始化基本属性(位置、朝向、速度) - /// - 设置初始状态(未激活、未制导) - /// - 清零计时器和计数器 - /// - 初始化加速度向量 + /// - 初始化基本属性 + /// - 设置性能限制 + /// - 配置运动参数 + /// - 建立仿真管理器关联 /// - public BaseMissile(MissileProperties properties, ISimulationManager manager) - : base(properties.Id, properties.InitialPosition, properties.InitialOrientation, properties.InitialSpeed, manager) + protected BaseMissile( + string missileId, + MissileProperties properties, + InitialMotionParameters launchParams, + ISimulationManager manager) + : base(missileId, launchParams.Position, launchParams.Orientation, launchParams.InitialSpeed, manager) { - MissileProperties = properties; - SimulationManager = manager; - - IsActive = false; - IsGuidance = false; + // 设置性能限制 + Properties = properties; + + // 初始化状态 FlightTime = 0; FlightDistance = 0; - EngineBurnTime = 0; + IsActive = false; + IsGuidance = false; GuidanceAcceleration = Vector3D.Zero; ThrustAcceleration = Vector3D.Zero; } @@ -199,9 +205,9 @@ namespace ThreatSource.Missile } // 限制速度不超过最大速度 - if (Velocity.Magnitude() > MissileProperties.MaxSpeed) + if (Velocity.Magnitude() > Properties.MaxSpeed) { - Velocity = Velocity.Normalize() * MissileProperties.MaxSpeed; + Velocity = Velocity.Normalize() * Properties.MaxSpeed; } Speed = Velocity.Magnitude(); @@ -229,14 +235,14 @@ namespace ThreatSource.Missile private Vector3D CalculateAcceleration(Vector3D velocity) { // 计算空气阻力的影响 - Vector3D dragAcceleration = velocity.Normalize() * -1 * CalculateDrag(velocity.Magnitude()) / MissileProperties.Mass; + Vector3D dragAcceleration = velocity.Normalize() * -1 * CalculateDrag(velocity.Magnitude()) / Properties.Mass; Vector3D totalAcceleration = GuidanceAcceleration + ThrustAcceleration + dragAcceleration; Debug.WriteLine($"导弹 {Id} 的加速度: {totalAcceleration}, 制导加速度: {GuidanceAcceleration}, 推力加速度: {ThrustAcceleration}, 空气阻力加速度: {dragAcceleration}"); - if (totalAcceleration.Magnitude() > MissileProperties.MaxAcceleration) + if (totalAcceleration.Magnitude() > Properties.MaxAcceleration) { - totalAcceleration = totalAcceleration.Normalize() * MissileProperties.MaxAcceleration; + totalAcceleration = totalAcceleration.Normalize() * Properties.MaxAcceleration; } return totalAcceleration; @@ -293,8 +299,8 @@ namespace ThreatSource.Missile protected bool ShouldSelfDestruct() { // 基本条件判断 - if (FlightTime >= MissileProperties.MaxFlightTime - || FlightDistance >= MissileProperties.MaxFlightDistance) + if (FlightTime >= Properties.MaxFlightTime + || FlightDistance >= Properties.MaxFlightDistance) { return true; } @@ -303,12 +309,12 @@ namespace ThreatSource.Missile if (IsGuidance) { // 有制导时,在负爆炸半径高度自毁(考虑仿真步长) - return Position.Y <= -MissileProperties.ExplosionRadius; + return Position.Y <= -Properties.ExplosionRadius; } else { // 无制导时,在自毁高度自毁 - return Position.Y <= MissileProperties.SelfDestructHeight; + return Position.Y <= Properties.SelfDestructHeight; } } @@ -354,19 +360,19 @@ namespace ThreatSource.Missile public void SelfDestruct() { string reason; - if (FlightTime >= MissileProperties.MaxFlightTime) + if (FlightTime >= Properties.MaxFlightTime) { reason = "超出最大飞行时间"; } - else if (FlightDistance >= MissileProperties.MaxFlightDistance) + else if (FlightDistance >= Properties.MaxFlightDistance) { reason = "超出最大飞行距离"; } - else if (IsGuidance && Position.Y <= -MissileProperties.ExplosionRadius) + else if (IsGuidance && Position.Y <= -Properties.ExplosionRadius) { reason = "有制导状态下高度低于负爆炸半径"; } - else if (!IsGuidance && Position.Y <= MissileProperties.SelfDestructHeight) + else if (!IsGuidance && Position.Y <= Properties.SelfDestructHeight) { reason = "无制导状态下高度低于自毁高度"; } @@ -449,9 +455,9 @@ namespace ThreatSource.Missile $" 速度: {missileRunningState.Speed:F2} m/s\n" + $" 速度分量: {missileRunningState.Velocity}\n" + $" 朝向: {missileRunningState.Orientation}\n" + - $" 飞行时间: {missileRunningState.FlightTime:F2}/{MissileProperties.MaxFlightTime:F2}\n" + - $" 飞行距离: {missileRunningState.FlightDistance:F2}/{MissileProperties.MaxFlightDistance:F2}\n" + - $" 发动机工作时间: {missileRunningState.EngineBurnTime:F2}/{MissileProperties.MaxEngineBurnTime:F2}\n" + + $" 飞行时间: {missileRunningState.FlightTime:F2}/{Properties.MaxFlightTime:F2}\n" + + $" 飞行距离: {missileRunningState.FlightDistance:F2}/{Properties.MaxFlightDistance:F2}\n" + + $" 发动机工作时间: {missileRunningState.EngineBurnTime:F2}/{Properties.MaxEngineBurnTime:F2}\n" + $" 有引导: {(missileRunningState.IsGuidance ? "是" : "否")}\n" + $" 失去引导时间: {missileRunningState.LostGuidanceTime:F2}\n"; } @@ -485,7 +491,7 @@ namespace ThreatSource.Missile return new MissileRunningState { Id = Id, - Type = MissileProperties.Type, + Type = Properties.Type, Position = Position, Velocity = Velocity, Orientation = Orientation, diff --git a/ThreatSource/src/MIssile/InfraredCommandGuidedMissile.cs b/ThreatSource/src/MIssile/InfraredCommandGuidedMissile.cs index c3e6049..af53573 100644 --- a/ThreatSource/src/MIssile/InfraredCommandGuidedMissile.cs +++ b/ThreatSource/src/MIssile/InfraredCommandGuidedMissile.cs @@ -74,7 +74,9 @@ namespace ThreatSource.Missile /// /// 初始化红外指令制导导弹的新实例 /// - /// 导弹配置参数 + /// 导弹ID + /// 导弹属性配置 + /// 发射参数 /// 仿真管理器实例 /// /// 构造过程: @@ -83,16 +85,20 @@ namespace ThreatSource.Missile /// - 创建指令导引系统 /// - 配置PID参数 /// - public InfraredCommandGuidedMissile(MissileProperties config, ISimulationManager manager) : base(config, manager) + public InfraredCommandGuidedMissile( + string missileId, + MissileProperties properties, + InitialMotionParameters launchParams, + ISimulationManager manager) + : base(missileId, properties, launchParams, manager) { infraredTracker = null!; RadiationPower = 1000; - // 初始化红外指令导引系统,包括自适应 PID 参数 guidanceSystem = new InfraredCommandGuidanceSystem( - config.Id + "_guidance", - config.MaxAcceleration, - config.ProportionalNavigationCoefficient, + missileId + "_guidance", + properties.MaxAcceleration, + properties.ProportionalNavigationCoefficient, manager ); } @@ -139,7 +145,7 @@ namespace ThreatSource.Missile { // 发射阶段 GuidanceAcceleration = Vector3D.Zero; - if (FlightTime >= 0.1) + if (FlightTime >= Properties.MaxEngineBurnTime) { currentStage = ICGM_Stage.Cruise; } diff --git a/ThreatSource/src/MIssile/InfraredImagingTerminalGuidedMissile.cs b/ThreatSource/src/MIssile/InfraredImagingTerminalGuidedMissile.cs index 823197f..d6f8a37 100644 --- a/ThreatSource/src/MIssile/InfraredImagingTerminalGuidedMissile.cs +++ b/ThreatSource/src/MIssile/InfraredImagingTerminalGuidedMissile.cs @@ -1,6 +1,7 @@ using ThreatSource.Simulation; using ThreatSource.Guidance; using ThreatSource.Utils; +using ThreatSource.Target; namespace ThreatSource.Missile { @@ -27,18 +28,20 @@ namespace ThreatSource.Missile /// 红外成像末制导导弹的飞行阶段枚举 /// /// - /// 定义了导弹的五个工作阶段: + /// 定义了导弹的工作阶段: /// - Launch: 发射阶段,初始加速 /// - Cruise: 巡航阶段,中程飞行 - /// - TerminalGuidance: 末制导阶段,红外制导 - /// - Explode: 爆炸阶段,执行毁伤 - /// - SelfDestruct: 自毁阶段,紧急处置 + /// - TerminalSearch: 末制导搜索阶段,大视场角搜索目标 + /// - TerminalTrack: 末制导跟踪阶段,小视场角精确跟踪 + /// - TerminalLock: 末制导锁定阶段,目标确认后的精确跟踪 /// private enum IRTG_Stage { Launch, // 发射阶段 Cruise, // 巡航阶段 - TerminalGuidance // 末制导阶段 + TerminalSearch, // 末制导搜索阶段 + TerminalTrack, // 末制导跟踪阶段 + TerminalLock // 末制导锁定阶段 } /// @@ -73,22 +76,36 @@ namespace ThreatSource.Missile /// /// 初始化红外成像末制导导弹的新实例 /// - /// 导弹的配置参数 + /// 导弹ID + /// 目标类型 + /// 导弹属性配置 + /// 发射参数 + /// 红外成像导引配置 /// 仿真管理器实例 /// /// 构造过程: - /// 1. 调用基类构造函数 - /// 2. 创建制导系统实例 - /// 3. 设置初始飞行阶段 + /// - 初始化基本属性 + /// - 创建制导系统 + /// - 配置制导参数 + /// - 设置初始飞行阶段 /// - public InfraredImagingTerminalGuidedMissile(MissileProperties config, ISimulationManager manager) - : base(config, manager) + public InfraredImagingTerminalGuidedMissile( + string missileId, + TargetType targetType, + MissileProperties properties, + InitialMotionParameters launchParams, + InfraredImagingGuidanceConfig guidanceConfig, + ISimulationManager manager) + : base(missileId, properties, launchParams, manager) { guidanceSystem = new InfraredImagingGuidanceSystem( - config.Id + "_guidance", - config.MaxAcceleration, - config.ProportionalNavigationCoefficient, - manager); + missileId + "_guidance", + guidanceConfig, + targetType, + properties.MaxAcceleration, + properties.ProportionalNavigationCoefficient, + manager + ); } /// @@ -112,8 +129,14 @@ namespace ThreatSource.Missile case IRTG_Stage.Cruise: UpdateCruiseStage(deltaTime); break; - case IRTG_Stage.TerminalGuidance: - UpdateTerminalGuidanceStage(deltaTime); + case IRTG_Stage.TerminalSearch: + UpdateTerminalSearchStage(deltaTime); + break; + case IRTG_Stage.TerminalTrack: + UpdateTerminalTrackStage(deltaTime); + break; + case IRTG_Stage.TerminalLock: + UpdateTerminalLockStage(deltaTime); break; } base.Update(deltaTime); @@ -133,7 +156,7 @@ namespace ThreatSource.Missile private void UpdateLaunchStage(double deltaTime) { GuidanceAcceleration = Vector3D.Zero; - if (FlightTime > 0.1) // 假设发射阶段持续1秒 + if (FlightTime > Properties.MaxEngineBurnTime) // 假设发射阶段持续1秒 { currentStage = IRTG_Stage.Cruise; } @@ -147,33 +170,92 @@ namespace ThreatSource.Missile /// 巡航阶段特点: /// - 保持稳定飞行 /// - 不使用制导系统 - /// - 持续时间为3秒 - /// - 结束后进入末制导阶段 + /// - 达到巡航时间后进入末制导搜索阶段 /// private void UpdateCruiseStage(double deltaTime) { - if (FlightTime > 3) // 假设巡航阶段持续3秒 + // 如果巡航时间达到,切换到末制导搜索阶段 + if (FlightTime > Properties.CruiseTime) { - currentStage = IRTG_Stage.TerminalGuidance; + currentStage = IRTG_Stage.TerminalSearch; + guidanceSystem.Activate(); // 激活制导系统 + guidanceSystem.SwitchToSearchMode(); // 切换到搜索模式 + currentStage = IRTG_Stage.TerminalSearch; } } /// - /// 更新末制导阶段的状态 + /// 更新末制导搜索阶段的状态 /// /// 时间步长,单位:秒 /// - /// 末制导阶段特点: - /// - 开启红外成像制导 - /// - 计算制导加速度 - /// - 精确跟踪目标 - /// - 持续到命中目标 + /// 搜索阶段特点: + /// - 大视场角(6-8度)搜索目标 + /// - 进行目标检测和初步识别 + /// - 发现目标后切换到跟踪阶段 /// - private void UpdateTerminalGuidanceStage(double deltaTime) + private void UpdateTerminalSearchStage(double deltaTime) { IsGuidance = true; guidanceSystem.Update(deltaTime, Position, Velocity); GuidanceAcceleration = guidanceSystem.GetGuidanceAcceleration(); + + // 如果发现并识别出目标,切换到跟踪阶段 + if (guidanceSystem.HasTarget) + { + currentStage = IRTG_Stage.TerminalTrack; + } + } + + /// + /// 更新末制导跟踪阶段的状态 + /// + /// 时间步长,单位:秒 + /// + /// 跟踪阶段特点: + /// - 小视场角(2-3度)精确跟踪 + /// - 高精度目标识别和特征提取 + /// - 目标确认后切换到锁定阶段 + /// - 如果失去目标则返回搜索阶段 + /// + private void UpdateTerminalTrackStage(double deltaTime) + { + IsGuidance = true; + guidanceSystem.Update(deltaTime, Position, Velocity); + GuidanceAcceleration = guidanceSystem.GetGuidanceAcceleration(); + + // 如果失去目标,切换回搜索阶段 + if (!guidanceSystem.HasTarget) + { + currentStage = IRTG_Stage.TerminalSearch; + } + // 当制导系统进入锁定模式时,导弹也切换到锁定阶段 + else if (guidanceSystem.IsInLockMode) + { + currentStage = IRTG_Stage.TerminalLock; + } + } + + /// + /// 更新末制导锁定阶段的状态 + /// + /// 时间步长,单位:秒 + /// + /// 锁定阶段特点: + /// - 目标类型已确认 + /// - 专注于位置跟踪 + /// - 如果失去目标则返回搜索阶段 + /// + private void UpdateTerminalLockStage(double deltaTime) + { + IsGuidance = true; + guidanceSystem.Update(deltaTime, Position, Velocity); + GuidanceAcceleration = guidanceSystem.GetGuidanceAcceleration(); + + if (!guidanceSystem.HasTarget) + { + currentStage = IRTG_Stage.TerminalSearch; + } } /// diff --git a/ThreatSource/src/MIssile/LaserBeamRiderMissile.cs b/ThreatSource/src/MIssile/LaserBeamRiderMissile.cs index a53f1e4..ee80400 100644 --- a/ThreatSource/src/MIssile/LaserBeamRiderMissile.cs +++ b/ThreatSource/src/MIssile/LaserBeamRiderMissile.cs @@ -53,24 +53,36 @@ namespace ThreatSource.Missile private readonly LaserBeamRiderGuidanceSystem guidanceSystem; /// - /// 初始化激光波束制导导弹的新实例 + /// 初始化激光驾束制导导弹的新实例 /// - /// 导弹配置参数 + /// 导弹ID + /// 导弹属性配置 + /// 发射参数 + /// 激光编码配置 + /// 制导系统配置 /// 仿真管理器实例 /// /// 构造过程: /// - 初始化基本属性 - /// - 创建波束制导系统 + /// - 创建制导系统 /// - 配置制导参数 /// - 设置初始飞行阶段 /// - public LaserBeamRiderMissile(MissileProperties config, ISimulationManager manager) - : base(config, manager) + public LaserBeamRiderMissile( + string missileId, + MissileProperties properties, + InitialMotionParameters launchParams, + LaserCodeConfig laserCodeConfig, + LaserBeamRiderGuidanceSystemConfig guidanceSystemConfig, + ISimulationManager manager) + : base(missileId, properties, launchParams, manager) { guidanceSystem = new LaserBeamRiderGuidanceSystem( - config.Id + "_guidance", - config.MaxAcceleration, - config.ProportionalNavigationCoefficient, + missileId + "_guidance", + properties.MaxAcceleration, + properties.ProportionalNavigationCoefficient, + laserCodeConfig, + guidanceSystemConfig, manager); } @@ -169,7 +181,7 @@ namespace ThreatSource.Missile { // 发射阶段 GuidanceAcceleration = Vector3D.Zero; - if (FlightTime >= 0.01) + if (FlightTime >= Properties.MaxEngineBurnTime) { currentStage = LBRM_Stage.Cruise; } diff --git a/ThreatSource/src/MIssile/LaserSemiActiveGuidedMissile.cs b/ThreatSource/src/MIssile/LaserSemiActiveGuidedMissile.cs index 9275143..3b0db95 100644 --- a/ThreatSource/src/MIssile/LaserSemiActiveGuidedMissile.cs +++ b/ThreatSource/src/MIssile/LaserSemiActiveGuidedMissile.cs @@ -63,10 +63,23 @@ namespace ThreatSource.Missile /// public string LaserDesignatorId { get; set; } = ""; + /// + /// 获取或设置激光编码配置 + /// + /// 激光编码配置 + /// + /// 用于配置导弹期望接收的激光编码类型和值 + /// + public LaserCodeConfig LaserCodeConfig { get; set; } + /// /// 初始化激光半主动制导导弹的新实例 /// - /// 导弹配置参数 + /// 导弹ID + /// 导弹属性配置 + /// 发射参数 + /// 激光编码配置 + /// 激光半主动制导系统配置 /// 仿真管理器实例 /// /// 构造过程: @@ -75,17 +88,26 @@ namespace ThreatSource.Missile /// - 配置制导参数 /// - 设置初始飞行阶段 /// - public LaserSemiActiveGuidedMissile(MissileProperties config, ISimulationManager manager) - : base(config, manager) + public LaserSemiActiveGuidedMissile( + string missileId, + MissileProperties properties, + InitialMotionParameters launchParams, + LaserCodeConfig laserCodeConfig, + LaserSemiActiveGuidanceConfig guidanceConfig, + ISimulationManager manager) + : base(missileId, properties, launchParams, manager) { guidanceSystem = new LaserSemiActiveGuidanceSystem( - config.Id + "_guidance", - config.MaxAcceleration, - config.ProportionalNavigationCoefficient, + missileId + "_guidance", + properties.MaxAcceleration, + properties.ProportionalNavigationCoefficient, + laserCodeConfig, + guidanceConfig, manager); - + // 设置制导系统的ParentId属性 - guidanceSystem.ParentId = config.Id; + guidanceSystem.ParentId = missileId; + LaserCodeConfig = laserCodeConfig; } /// @@ -172,7 +194,7 @@ namespace ThreatSource.Missile { // 发射阶段 GuidanceAcceleration = Vector3D.Zero; - if (FlightTime >= 0.1) + if (FlightTime >= Properties.MaxEngineBurnTime) { currentStage = LSAGM_Stage.Cruise; } @@ -221,58 +243,6 @@ namespace ThreatSource.Missile } } - - - /// - /// 设置激光编码 - /// - /// 编码类型 - /// 编码值 - /// - /// 设置导弹期望接收的激光编码类型和值 - /// 用于验证接收到的激光信号 - /// - public void SetLaserCode(LaserCodeType codeType, int codeValue) - { - if (guidanceSystem is LaserSemiActiveGuidanceSystem laserGuidance) - { - laserGuidance.SetExpectedLaserCode(codeType, codeValue); - } - } - - /// - /// 添加激光编码参数 - /// - /// 参数名称 - /// 参数值 - /// - /// 添加特定编码类型的额外参数 - /// 如PPM编码的脉冲位置模式、PWM编码的脉冲宽度等 - /// - public void AddLaserCodeParameter(string key, object value) - { - if (guidanceSystem is LaserSemiActiveGuidanceSystem laserGuidance) - { - laserGuidance.AddExpectedCodeParameter(key, value); - } - } - - /// - /// 设置是否要求编码匹配 - /// - /// 是否要求匹配 - /// - /// true表示只响应匹配编码的激光信号 - /// false表示响应所有激光信号 - /// - public void SetCodeMatchRequired(bool required) - { - if (guidanceSystem is LaserSemiActiveGuidanceSystem laserGuidance) - { - laserGuidance.SetCodeMatchRequired(required); - } - } - /// /// 获取制导加速度 /// diff --git a/ThreatSource/src/MIssile/MillimeterWaveTerminalGuidedMissile.cs b/ThreatSource/src/MIssile/MillimeterWaveTerminalGuidedMissile.cs index c17a933..6fba823 100644 --- a/ThreatSource/src/MIssile/MillimeterWaveTerminalGuidedMissile.cs +++ b/ThreatSource/src/MIssile/MillimeterWaveTerminalGuidedMissile.cs @@ -38,7 +38,9 @@ namespace ThreatSource.Missile { Launch, // 发射阶段 Cruise, // 巡航阶段 - TerminalGuidance // 末制导阶段 + Search, // 搜索阶段 + Track, // 跟踪阶段 + Lock // 锁定阶段 } /// @@ -73,23 +75,32 @@ namespace ThreatSource.Missile /// /// 初始化毫米波末制导导弹的新实例 /// - /// 导弹的配置参数 + /// 导弹ID + /// 导弹属性配置 + /// 发射参数 + /// 毫米波制导系统配置 /// 仿真管理器实例 /// /// 构造过程: - /// 1. 调用基类构造函数 - /// 2. 创建制导系统实例 - /// 3. 设置初始飞行阶段 + /// - 初始化基本属性 + /// - 创建制导系统 + /// - 配置制导参数 + /// - 设置初始飞行阶段 /// - public MillimeterWaveTerminalGuidedMissile(MissileProperties properties, ISimulationManager manager) - : base(properties, manager) + public MillimeterWaveTerminalGuidedMissile( + string missileId, + MissileProperties properties, + InitialMotionParameters launchParams, + MillimeterWaveGuidanceConfig guidanceConfig, + ISimulationManager manager) + : base(missileId, properties, launchParams, manager) { guidanceSystem = new MillimeterWaveGuidanceSystem( - properties.Id + "_guidance", + missileId + "_guidance", properties.MaxAcceleration, properties.ProportionalNavigationCoefficient, - manager - ); + guidanceConfig, + manager); } /// @@ -113,8 +124,14 @@ namespace ThreatSource.Missile case MWTG_Stage.Cruise: UpdateCruiseStage(deltaTime); break; - case MWTG_Stage.TerminalGuidance: - UpdateTerminalGuidanceStage(deltaTime); + case MWTG_Stage.Search: + UpdateSearchStage(deltaTime); + break; + case MWTG_Stage.Track: + UpdateTrackStage(deltaTime); + break; + case MWTG_Stage.Lock: + UpdateLockStage(deltaTime); break; } base.Update(deltaTime); @@ -134,7 +151,7 @@ namespace ThreatSource.Missile private void UpdateLaunchStage(double deltaTime) { GuidanceAcceleration = Vector3D.Zero; - if (FlightTime > 0.1) + if (FlightTime > Properties.MaxEngineBurnTime) { currentStage = MWTG_Stage.Cruise; } @@ -153,24 +170,62 @@ namespace ThreatSource.Missile /// private void UpdateCruiseStage(double deltaTime) { - if (FlightTime > 3) + if (FlightTime > Properties.CruiseTime) { - currentStage = MWTG_Stage.TerminalGuidance; + currentStage = MWTG_Stage.Search; + guidanceSystem.Activate(); // 激活制导系统 + currentStage = MWTG_Stage.Search; } } /// - /// 更新末制导阶段的状态 + /// 更新搜索阶段的状态 /// /// 时间步长,单位:秒 /// - /// 末制导阶段特点: + /// 搜索阶段特点: /// - 开启毫米波制导 /// - 计算制导加速度 /// - 精确跟踪目标 /// - 持续到命中目标 /// - private void UpdateTerminalGuidanceStage(double deltaTime) + private void UpdateSearchStage(double deltaTime) + { + IsGuidance = true; + guidanceSystem.Update(deltaTime, Position, Velocity); + GuidanceAcceleration = guidanceSystem.GetGuidanceAcceleration(); + } + + /// + /// 更新跟踪阶段的状态 + /// + /// 时间步长,单位:秒 + /// + /// 跟踪阶段特点: + /// - 开启毫米波制导 + /// - 计算制导加速度 + /// - 精确跟踪目标 + /// - 持续到命中目标 + /// + private void UpdateTrackStage(double deltaTime) + { + IsGuidance = true; + guidanceSystem.Update(deltaTime, Position, Velocity); + GuidanceAcceleration = guidanceSystem.GetGuidanceAcceleration(); + } + + /// + /// 更新锁定阶段的状态 + /// + /// 时间步长,单位:秒 + /// + /// 锁定阶段特点: + /// - 开启毫米波制导 + /// - 计算制导加速度 + /// - 精确跟踪目标 + /// - 持续到命中目标 + /// + private void UpdateLockStage(double deltaTime) { IsGuidance = true; guidanceSystem.Update(deltaTime, Position, Velocity); diff --git a/ThreatSource/src/MIssile/MissileProperties.cs b/ThreatSource/src/MIssile/MissileProperties.cs index 6d83149..118ba77 100644 --- a/ThreatSource/src/MIssile/MissileProperties.cs +++ b/ThreatSource/src/MIssile/MissileProperties.cs @@ -1,4 +1,5 @@ using ThreatSource.Utils; +using ThreatSource.Simulation; namespace ThreatSource.Missile { @@ -56,7 +57,6 @@ namespace ThreatSource.Missile /// /// /// 该类用于: - /// - 初始化导弹的基本参数 /// - 配置导弹的性能限制 /// - 设置导弹的物理特性 /// - 定义导弹的作战能力 @@ -64,42 +64,6 @@ namespace ThreatSource.Missile /// public class MissileProperties { - /// - /// 获取或设置导弹的唯一标识符 - /// - /// - /// 在仿真系统中必须唯一 - /// 用于标识和追踪特定的导弹实例 - /// - public string Id { get; set; } - - /// - /// 获取或设置导弹的初始位置 - /// - /// - /// 使用三维向量表示发射位置 - /// 坐标系:右手坐标系,X向右,Y向上,Z向前 - /// - public Vector3D InitialPosition { get; set; } - - /// - /// 获取或设置导弹的初始朝向 - /// - /// - /// 使用欧拉角表示初始姿态 - /// 包含偏航角、俯仰角和滚转角 - /// - public Orientation InitialOrientation { get; set; } - - /// - /// 获取或设置导弹的初始速度 - /// - /// - /// 单位:米/秒 - /// 发射时的初始运动速度 - /// - public double InitialSpeed { get; set; } - /// /// 获取或设置导弹的最大速度限制 /// @@ -149,26 +113,6 @@ namespace ThreatSource.Missile /// public double ProportionalNavigationCoefficient { get; set; } - /// - /// 获取或设置导弹的发射推力加速度 - /// - /// - /// 单位:米/秒² - /// 发射阶段的推进加速度 - /// 影响导弹的起飞性能 - /// - public double LaunchAcceleration { get; set; } - - /// - /// 获取或设置发动机的最大燃烧时间 - /// - /// - /// 单位:秒 - /// 发动机能够持续工作的最长时间 - /// 基于燃料容量和燃烧速率 - /// - public double MaxEngineBurnTime { get; set; } - /// /// 获取或设置导弹的质量 /// @@ -208,6 +152,27 @@ namespace ThreatSource.Missile /// public double SelfDestructHeight { get; set; } + /// + /// 获取或设置发射推力加速度 + /// + /// + /// 单位:米/秒² + /// 发射阶段的推进加速度 + /// 影响导弹的起飞性能 + /// 这是导弹的固有属性,由发动机性能决定 + /// + public double LaunchAcceleration { get; set; } + + /// + /// 获取或设置发动机的最大燃烧时间 + /// + /// + /// 单位:秒 + /// 发动机能够持续工作的最长时间 + /// 基于燃料容量和燃烧速率 + /// + public double MaxEngineBurnTime { get; set; } + /// /// 获取或设置导弹的类型 /// @@ -217,23 +182,40 @@ namespace ThreatSource.Missile /// public MissileType Type { get; set; } + /// + /// 获取或设置激光编码配置 + /// + /// + /// 适用于激光半主动导弹和激光驾束导弹 + /// 定义激光信号的编码参数 + /// 用于抗干扰和安全识别 + /// + public LaserCodeConfig? LaserCodeConfig { get; set; } + + /// + /// 获取或设置导弹的巡航时间 + /// + /// + /// 单位:秒 + /// 导弹在巡航阶段的持续时间 + /// 超过此时间后进入末制导阶段 + /// + public double CruiseTime { get; set; } + /// /// 初始化导弹配置类的新实例 /// /// /// 构造过程: /// - 设置所有数值参数的默认值 - /// - 初始化基本属性(ID、位置、朝向) + /// - 初始化基本属性(ID) /// - 设置默认导弹类型 /// public MissileProperties() { SetDefaultValues(); - - Id = ""; - InitialPosition = new Vector3D(0, 0, 0); - InitialOrientation = new Orientation(0, 0, 0); Type = MissileType.StandardMissile; + LaserCodeConfig = new LaserCodeConfig(); } /// @@ -247,16 +229,20 @@ namespace ThreatSource.Missile /// - 性能参数 /// 用于初始化或重置导弹配置 /// - public void SetDefaultValues(){ - InitialSpeed = 300; + public void SetDefaultValues() + { MaxSpeed = 400; MaxFlightTime = 60; MaxFlightDistance = 5000; - LaunchAcceleration = 100; - MaxEngineBurnTime = 10; MaxAcceleration = 100; - ExplosionRadius = 5; + LaunchAcceleration = 50; + MaxEngineBurnTime = 10; + CruiseTime = 5; ProportionalNavigationCoefficient = 3; + Mass = 50; + ExplosionRadius = 5; + HitProbability = 0.9; + SelfDestructHeight = 0; } } } \ No newline at end of file diff --git a/ThreatSource/src/MIssile/TerminalSensitiveMissile.cs b/ThreatSource/src/MIssile/TerminalSensitiveMissile.cs index d3c97ac..e39e8b4 100644 --- a/ThreatSource/src/MIssile/TerminalSensitiveMissile.cs +++ b/ThreatSource/src/MIssile/TerminalSensitiveMissile.cs @@ -24,45 +24,12 @@ namespace ThreatSource.Missile public class TerminalSensitiveMissile : BaseMissile { /// - /// 子弹药分离的高度阈值 + /// 子弹药配置参数 /// /// - /// 单位:米 - /// 当导弹上升到此高度时会触发分离 - /// 默认设置为1000米 + /// 包含分离参数和子弹药性能参数 /// - private const double SeparationHeight = 1000; - - /// - /// 分离点与目标的水平距离 - /// - /// - /// 单位:米 - /// 分离点在目标上方的水平投影距离 - /// 默认设置为1000米 - /// - private const double SeparationDistance = 1000; - - /// - /// 子弹分离角度(与地面的夹角) - /// - /// - /// 单位:度 - /// 子弹从母弹分离时与地面的夹角 - /// 默认设置为60度 - /// - private const double SubmunitionSeparationAngle = 45; - - /// - /// 触发分离的距离阈值 - /// - /// - /// 单位:米 - /// 当导弹距离分离点小于此距离时触发分离 - /// 默认设置为50米 - /// 注意:此值必须大于导弹速度乘以时间步长的一半 - /// - private const double SeparationRange = 50; + private readonly TerminalSensitiveSubmunitionConfig config; /// /// 末敏弹的飞行阶段 @@ -132,10 +99,13 @@ namespace ThreatSource.Missile /// /// 初始化末敏导弹的新实例 /// + /// 导弹的唯一标识符 /// 目标的唯一标识符 /// 导弹的配置参数 + /// 发射参数 /// 子弹的配置参数 /// 子弹的数量 + /// 子弹药配置参数 /// 仿真管理器实例 /// 当目标不存在时抛出 /// 当无法计算发射方向时抛出 @@ -147,21 +117,31 @@ namespace ThreatSource.Missile /// 4. 计算最佳发射角度 /// 5. 设置初始速度和方向 /// - public TerminalSensitiveMissile(string targetId, MissileProperties properties, MissileProperties submunitionProperties, int submunitionCount, ISimulationManager manager) - : base(properties, manager) + public TerminalSensitiveMissile( + string missileId, + string targetId, + MissileProperties properties, + InitialMotionParameters launchParams, + MissileProperties submunitionProperties, + int submunitionCount, + TerminalSensitiveSubmunitionConfig submunitionConfig, + ISimulationManager manager) + : base(missileId, properties, launchParams, manager) { this.targetId = targetId; this.submunitionProperties = submunitionProperties; this.submunitionCount = submunitionCount; + this.config = submunitionConfig; submunitions = new TerminalSensitiveSubmunition[submunitionCount]; - //计算分离点坐标,高度为SeparationHeight,距离目标的距离为SeparationDistance - SimulationElement target = SimulationManager.GetEntityById(this.targetId) as SimulationElement ?? throw new Exception("目标不存在"); - separationPoint = Vector3D.PointOnLine(target.Position, base.Position, SeparationDistance) + new Vector3D(0, SeparationHeight, 0); + + //计算分离点坐标,使用配置中的分离高度和距离 + SimulationElement target = SimulationManager.GetEntityById(targetId) as SimulationElement ?? throw new Exception("目标不存在"); + separationPoint = Vector3D.PointOnLine(target.Position, base.Position, config.SeparationDistance) + new Vector3D(0, config.SeparationHeight, 0); + //计算导弹发射角度 (Orientation? launchOrientation, Vector3D? launchVelocity) = MotionAlgorithm.CalculateBestLaunchOrientation(Position, separationPoint, Speed); if (!launchOrientation.HasValue || launchVelocity is null) { - // 处理错误情况 throw new InvalidOperationException("无法计算发射方向"); } else @@ -234,7 +214,7 @@ namespace ThreatSource.Missile private void UpdateLaunchStage(double deltaTime) { GuidanceAcceleration = Vector3D.Zero; - if (FlightTime > 0.1) + if (FlightTime > Properties.MaxEngineBurnTime) { currentStage = TSGM_Stage.Cruise; } @@ -253,8 +233,8 @@ namespace ThreatSource.Missile private void UpdateCruiseStage(double deltaTime) { double distanceToSeparationPoint = (separationPoint - Position).Magnitude(); - //距离分离点距离小于50米,则分离 - if (distanceToSeparationPoint <= SeparationRange) + //距离分离点距离小于配置的分离范围,则分离 + if (distanceToSeparationPoint <= config.SeparationRange) { currentStage = TSGM_Stage.Separation; } @@ -295,12 +275,12 @@ namespace ThreatSource.Missile Vector3D horizontalDirection = new Vector3D(currentDirection.X, 0, currentDirection.Z).Normalize(); // 计算分离角度(弧度) - double separationAngleRad = SubmunitionSeparationAngle * Math.PI / 180.0; + double separationAngleRad = config.SubmunitionSeparationAngle * Math.PI / 180.0; - // 计算子弹的初始方向(保持水平方向不变,设置垂直角度为-60度) + // 计算子弹的初始方向(保持水平方向不变,设置垂直角度) Vector3D initialDirection = new Vector3D( horizontalDirection.X, - -Math.Tan(separationAngleRad), // 负号表示向下的60度角 + -Math.Tan(separationAngleRad), horizontalDirection.Z ).Normalize(); @@ -312,13 +292,10 @@ namespace ThreatSource.Missile { Debug.WriteLine($"创建子弹 {i}"); submunitions[i] = new TerminalSensitiveSubmunition( + Id + "_Sub_" + i, targetId, new MissileProperties - { - Id = $"{Id}_Sub_{i}", - InitialPosition = Position, - InitialOrientation = separationOrientation, // 使用新计算的分离方向 - InitialSpeed = Velocity.Magnitude(), // 子弹初始速度等于母弹速度 + { MaxSpeed = submunitionProperties.MaxSpeed, MaxFlightTime = submunitionProperties.MaxFlightTime, MaxFlightDistance = submunitionProperties.MaxFlightDistance, @@ -328,9 +305,19 @@ namespace ThreatSource.Missile ExplosionRadius = submunitionProperties.ExplosionRadius, HitProbability = submunitionProperties.HitProbability, SelfDestructHeight = submunitionProperties.SelfDestructHeight, + LaunchAcceleration = submunitionProperties.LaunchAcceleration, + MaxEngineBurnTime = submunitionProperties.MaxEngineBurnTime, Type = submunitionProperties.Type - }, - SimulationManager); + }, + new InitialMotionParameters + { + Position = Position, + Orientation = separationOrientation, + InitialSpeed = Velocity.Magnitude(), + }, + config, + SimulationManager + ); SimulationManager.RegisterEntity(submunitions[i].Id, submunitions[i]); Debug.WriteLine($"注册末敏弹子弹 {submunitions[i].Id}"); diff --git a/ThreatSource/src/MIssile/TerminalSensitiveSubmunition.cs b/ThreatSource/src/MIssile/TerminalSensitiveSubmunition.cs index f2724f4..d947375 100644 --- a/ThreatSource/src/MIssile/TerminalSensitiveSubmunition.cs +++ b/ThreatSource/src/MIssile/TerminalSensitiveSubmunition.cs @@ -74,114 +74,9 @@ namespace ThreatSource.Missile private SubmunitionStage currentStage; /// - /// 减速加速度,单位:米/秒² + /// 子弹配置参数 /// - /// - /// 减速阶段的减速度大小 - /// 影响速度调整的快慢 - /// - private const double DecelerationAcceleration = 250; - - /// - /// 减速阶段末速,单位:米/秒 - /// - /// - /// 定义了减速阶段的垂直下降速度 - /// - private const double DecelerationEndSpeed = 50; - - /// - /// 开伞高度,单位:米 - /// - /// - /// 打开降落伞的高度阈值 - /// 影响降落伞打开阶段的触发时机 - /// - private const double ParachuteDeploymentHeight = 400; - /// - /// 降落伞减速加速度,单位:米/秒² - /// - /// - /// 定义了降落伞减速加速度 - /// - private const double ParachuteDeceleration = 140; - - /// - /// 稳定扫描高度,单位:米 - /// - /// - /// 开始螺旋扫描的高度阈值 - /// 影响扫描阶段的触发时机 - /// - private const double StableScanHeight = 200; - - /// - /// 垂直下降速度,单位:米/秒 - /// - /// - /// 定义了扫描和攻击阶段的垂直下降速度 - /// - private const double VerticalDeclineSpeed = 10; - - /// - /// 螺旋扫描旋转速度,单位:弧度/秒 - /// - /// - /// 定义了螺旋扫描时的旋转角速度 - /// 4转/秒 = 8π弧度/秒 - /// - private const double SpiralRotationSpeed = 8 * Math.PI; - - /// - /// 扫描角度,单位:弧度 - /// - /// - /// 定义了螺旋扫描的锥角 - /// 30度 = π/6弧度 - /// - public const double ScanAngle = 30 * Math.PI / 180; - - /// - /// 目标探测距离,单位:米 - /// - /// - /// 目标探测的距离阈值 - /// 影响目标探测阶段的触发时机 - /// - private const double TargetDetectionDistance = 150; - - /// - /// 自毁高度,单位:米 - /// - /// - /// 触发自毁的高度阈值 - /// 保证子弹不会危及友方 - /// - private const double SelfDestructHeight = 20; - - /// - /// 攻击速度,单位:米/秒 - /// - /// - /// 攻击阶段的期望速度 - /// 影响末端制导的精度 - /// - private double AttackSpeed = 200; - - /// - /// 是否已经探测到目标 - /// - private bool isTargetDetected = false; - - /// - /// 第一次探测到目标时记录的目标方位角 - /// - private double? firstDetectionAngle = null; - - /// - /// 获取或设置最后一次检测到目标的时间 - /// - private double? lastDetectionTime = null; + private readonly TerminalSensitiveSubmunitionConfig config; /// /// 获取或设置螺旋扫描的当前角度 @@ -256,11 +151,29 @@ namespace ThreatSource.Missile /// private readonly LaserRangefinder rangefinder; + /// + /// 是否已经探测到目标 + /// + private bool isTargetDetected = false; + + /// + /// 第一次探测到目标时记录的目标方位角 + /// + private double? firstDetectionAngle = null; + + /// + /// 获取或设置最后一次检测到目标的时间 + /// + private double? lastDetectionTime = null; + /// /// 初始化末敏子弹的新实例 /// + /// 导弹ID /// 目标ID /// 子弹配置参数 + /// 发射参数 + /// 子弹性能参数配置 /// 仿真管理器实例 /// /// 构造过程: @@ -269,10 +182,17 @@ namespace ThreatSource.Missile /// - 配置传感器参数 /// - 设置初始状态 /// - public TerminalSensitiveSubmunition(string targetId, MissileProperties properties, ISimulationManager manager) - : base(properties, manager) + public TerminalSensitiveSubmunition( + string missileId, + string targetId, + MissileProperties properties, + InitialMotionParameters launchParams, + TerminalSensitiveSubmunitionConfig submunitionConfig, + ISimulationManager manager) + : base(missileId, properties, launchParams, manager) { TargetId = targetId; + config = submunitionConfig; // 初始化扫描方向为正北 scanDirection = new Vector3D(0, 0, 1).Normalize(); @@ -382,13 +302,13 @@ namespace ThreatSource.Missile } // 减速减旋,垂直速度减小 - Vector3D deceleration = - Velocity.Normalize() * DecelerationAcceleration; + Vector3D deceleration = - Velocity.Normalize() * config.DecelerationAcceleration; Velocity += deceleration * deltaTime; - if (Velocity.Magnitude() <= DecelerationEndSpeed) + if (Velocity.Magnitude() <= config.DecelerationEndSpeed) { //垂直速度设为减速阶段末速 - Velocity = new Vector3D(Velocity.X, -DecelerationEndSpeed, Velocity.Z); + Velocity = new Vector3D(Velocity.X, -config.DecelerationEndSpeed, Velocity.Z); GuidanceAcceleration = Vector3D.Zero; } @@ -400,13 +320,13 @@ namespace ThreatSource.Missile } // 检查高度是否小于等于开伞高度 - if(((AltimeterSensorData)altimeter.GetSensorData()).Altitude <= ParachuteDeploymentHeight) + if(((AltimeterSensorData)altimeter.GetSensorData()).Altitude <= config.ParachuteDeploymentHeight) { // 如果是,则进入降落伞打开阶段 currentStage = SubmunitionStage.ParachuteDeployment; //垂直速度设为减速阶段末速 - Velocity = new Vector3D(Velocity.X, -DecelerationEndSpeed, Velocity.Z); + Velocity = new Vector3D(Velocity.X, -config.DecelerationEndSpeed, Velocity.Z); GuidanceAcceleration = Vector3D.Zero; } } @@ -428,24 +348,24 @@ namespace ThreatSource.Missile { // 计算当前速度与目标速度的差值 double currentSpeed = Velocity.Magnitude(); - if (currentSpeed > VerticalDeclineSpeed) + if (currentSpeed > config.VerticalDeclineSpeed) { // 开伞,用较大的减速度快速降低速度 - Vector3D deceleration = -Velocity.Normalize() * ParachuteDeceleration; + Vector3D deceleration = -Velocity.Normalize() * config.ParachuteDeceleration; // 更新速度 Velocity += deceleration * deltaTime; // 如果速度低于稳定扫描下降速度,直接设置为稳定扫描下降速度 - if (Velocity.Magnitude() <= VerticalDeclineSpeed) + if (Velocity.Magnitude() <= config.VerticalDeclineSpeed) { - Velocity = new Vector3D(0, -VerticalDeclineSpeed, 0); + Velocity = new Vector3D(0, -config.VerticalDeclineSpeed, 0); } } else { // 维持稳定的垂直下降速度 - Velocity = new Vector3D(0, -VerticalDeclineSpeed, 0); + Velocity = new Vector3D(0, -config.VerticalDeclineSpeed, 0); } // 清除制导加速度 @@ -458,7 +378,7 @@ namespace ThreatSource.Missile return; } - if (((AltimeterSensorData)altimeter.GetSensorData()).Altitude <= StableScanHeight) + if (((AltimeterSensorData)altimeter.GetSensorData()).Altitude <= config.StableScanHeight) { currentStage = SubmunitionStage.StableScan; } @@ -491,7 +411,7 @@ namespace ThreatSource.Missile } // 更新螺旋角度(顺时针旋转,标准方位角) - spiralAngle = (spiralAngle + SpiralRotationSpeed * deltaTime); // 顺时针角度增加 + spiralAngle = (spiralAngle + config.SpiralRotationSpeed * deltaTime); // 顺时针角度增加 while (spiralAngle >= 2 * Math.PI) { spiralAngle -= 2 * Math.PI; @@ -499,13 +419,13 @@ namespace ThreatSource.Missile // 更新扫描方向(标准方位角,顺时针为正) scanDirection = new Vector3D( - Math.Sin(spiralAngle) * Math.Sin(ScanAngle), - -Math.Cos(ScanAngle), - Math.Cos(spiralAngle) * Math.Sin(ScanAngle) + Math.Sin(spiralAngle) * Math.Sin(config.ScanAngleInRadians), + -Math.Cos(config.ScanAngleInRadians), + Math.Cos(spiralAngle) * Math.Sin(config.ScanAngleInRadians) ).Normalize(); // 如果距离小于等于目标探测距离,则进入目标探测阶段 - if (((RangefinderSensorData)rangefinder.GetSensorData()).Distance <= TargetDetectionDistance) + if (((RangefinderSensorData)rangefinder.GetSensorData()).Distance <= config.TargetDetectionDistance) { currentStage = SubmunitionStage.Detection; } @@ -535,7 +455,7 @@ namespace ThreatSource.Missile } // 更新扫描角度(顺时针旋转) - spiralAngle = (spiralAngle + SpiralRotationSpeed * deltaTime); // 顺时针角度增加 + spiralAngle = (spiralAngle + config.SpiralRotationSpeed * deltaTime); // 顺时针角度增加 while (spiralAngle >= 2 * Math.PI) { spiralAngle -= 2 * Math.PI; @@ -543,9 +463,9 @@ namespace ThreatSource.Missile // 更新扫描方向 scanDirection = new Vector3D( - Math.Sin(spiralAngle) * Math.Sin(ScanAngle), - -Math.Cos(ScanAngle), - Math.Cos(spiralAngle) * Math.Sin(ScanAngle) + Math.Sin(spiralAngle) * Math.Sin(config.ScanAngleInRadians), + -Math.Cos(config.ScanAngleInRadians), + Math.Cos(spiralAngle) * Math.Sin(config.ScanAngleInRadians) ).Normalize(); // 检查传感器干扰状态 @@ -621,7 +541,7 @@ namespace ThreatSource.Missile } double timeSinceLastDetection = FlightTime - lastDetectionTime.Value; - if (timeSinceLastDetection >= 0.75 * 2 * Math.PI / SpiralRotationSpeed) // 转过3/4圈以后 + if (timeSinceLastDetection >= 0.75 * 2 * Math.PI / config.SpiralRotationSpeed) // 转过3/4圈以后 { // 确保firstDetectionAngle不为null if (!firstDetectionAngle.HasValue) @@ -632,7 +552,7 @@ namespace ThreatSource.Missile // 检查当前角度是否接近记录的目标方位角 double angleDiff = Math.Abs(spiralAngle - firstDetectionAngle.Value); // 根据仿真步长和转速计算允许的角度误差 - double allowedError = deltaTime * SpiralRotationSpeed / 2; + double allowedError = deltaTime * config.SpiralRotationSpeed / 2; if (angleDiff <= allowedError) { if (isRadiationDetected || isInfraredDetected) @@ -681,13 +601,13 @@ namespace ThreatSource.Missile // 使用当前的spiralAngle计算攻击方向 scanDirection = new Vector3D( - Math.Sin(spiralAngle) * Math.Sin(ScanAngle), - -Math.Cos(ScanAngle), - Math.Cos(spiralAngle) * Math.Sin(ScanAngle) + Math.Sin(spiralAngle) * Math.Sin(config.ScanAngleInRadians), + -Math.Cos(config.ScanAngleInRadians), + Math.Cos(spiralAngle) * Math.Sin(config.ScanAngleInRadians) ).Normalize(); // 使用 AttackSpeed 设置攻击速度 - Velocity = scanDirection * AttackSpeed; + Velocity = scanDirection * config.AttackSpeed; GuidanceAcceleration = Vector3D.Zero; // 清除任何可能的加速度 } diff --git a/ThreatSource/src/Simulation/ISimulationElement.cs b/ThreatSource/src/Simulation/ISimulationElement.cs new file mode 100644 index 0000000..c4068cb --- /dev/null +++ b/ThreatSource/src/Simulation/ISimulationElement.cs @@ -0,0 +1,69 @@ +using ThreatSource.Utils; + +namespace ThreatSource.Simulation +{ + /// + /// 仿真元素接口,定义了所有仿真实体必须实现的基本功能 + /// + /// + /// 该接口定义了仿真实体的核心功能: + /// - 位置和运动状态管理 + /// - 生命周期管理(激活/停用) + /// - 状态更新机制 + /// 所有参与仿真的实体都必须实现此接口 + /// + public interface ISimulationElement + { + /// + /// 获取或设置仿真元素的唯一标识符 + /// + string Id { get; set; } + + /// + /// 获取或设置仿真元素的当前位置 + /// + Vector3D Position { get; set; } + + /// + /// 获取或设置仿真元素的当前速度向量 + /// + Vector3D Velocity { get; set; } + + /// + /// 获取或设置仿真元素的当前速度大小 + /// + double Speed { get; set; } + + /// + /// 获取或设置仿真元素的当前朝向 + /// + Orientation Orientation { get; set; } + + /// + /// 获取仿真元素是否处于活动状态 + /// + bool IsActive { get; } + + /// + /// 更新仿真元素的状态 + /// + /// 时间步长,单位:秒 + void Update(double deltaTime); + + /// + /// 激活仿真元素,使其参与仿真 + /// + void Activate(); + + /// + /// 停用仿真元素,将其从仿真中移除 + /// + void Deactivate(); + + /// + /// 获取仿真元素的状态信息 + /// + /// 包含实体当前状态的字符串描述 + string GetStatus(); + } +} \ No newline at end of file diff --git a/ThreatSource/src/Simulation/ISpectralCharacteristics.cs b/ThreatSource/src/Simulation/ISpectralCharacteristics.cs new file mode 100644 index 0000000..98b33a0 --- /dev/null +++ b/ThreatSource/src/Simulation/ISpectralCharacteristics.cs @@ -0,0 +1,38 @@ +using System; + +namespace ThreatSource.Simulation +{ + /// + /// 定义实体的频谱特性接口 + /// + /// + /// 该接口定义了实体的频谱特征: + /// - 雷达散射截面积 + /// - 红外辐射特性 + /// - 紫外辐射特性 + /// - 毫米波辐射特性 + /// 用于在仿真系统中表示实体的电磁特征 + /// + public interface ISpectralCharacteristics + { + /// + /// 获取雷达散射截面积(RCS),单位:平方米 + /// + double RadarCrossSection { get; } + + /// + /// 获取红外辐射强度,单位:瓦特/球面度 + /// + double InfraredRadiationIntensity { get; } + + /// + /// 获取紫外辐射强度,单位:瓦特/球面度 + /// + double UltravioletRadiationIntensity { get; } + + /// + /// 获取毫米波辐射强度,单位:瓦特/球面度 + /// + double MillimeterWaveRadiationIntensity { get; } + } +} \ No newline at end of file diff --git a/ThreatSource/src/Simulation/MissileLaunchParameters.cs b/ThreatSource/src/Simulation/MissileLaunchParameters.cs new file mode 100644 index 0000000..b0451db --- /dev/null +++ b/ThreatSource/src/Simulation/MissileLaunchParameters.cs @@ -0,0 +1,60 @@ +using ThreatSource.Utils; + +namespace ThreatSource.Simulation +{ + /// + /// 初始化运动参数类,定义了仿真元素初始化时的运动学参数 + /// + /// + /// 该类用于: + /// - 设置仿真元素的初始位置和姿态 + /// - 配置初始速度和目标 + /// - 提供战术场景相关的参数 + /// 这些参数在实际使用时动态设置,而不是存储在配置文件中 + /// + public class InitialMotionParameters + { + /// + /// 获取或设置仿真元素的初始位置 + /// + /// + /// 使用三维向量表示发射位置 + /// 坐标系:右手坐标系,X向右,Y向上,Z向前 + /// + public Vector3D Position { get; set; } = new Vector3D(0, 0, 0); + + /// + /// 获取或设置仿真元素的初始朝向 + /// + /// + /// 使用欧拉角表示初始姿态 + /// 包含偏航角、俯仰角和滚转角 + /// + public Orientation Orientation { get; set; } = new Orientation(0, 0, 0); + + /// + /// 获取或设置仿真元素的初始速度 + /// + /// + /// 单位:米/秒 + /// 初始运动速度 + /// + public double InitialSpeed { get; set; } + + /// + /// 初始化仿真元素初始化参数类的新实例 + /// + /// + /// 构造过程: + /// - 设置默认的初始位置(原点) + /// - 设置默认的初始朝向(零角度) + /// - 初始化其他参数为默认值 + /// + public InitialMotionParameters() + { + Position = new Vector3D(0, 0, 0); + Orientation = new Orientation(0, 0, 0); + InitialSpeed = 0; + } + } +} \ No newline at end of file diff --git a/ThreatSource/src/Simulation/SimulationConfig.cs b/ThreatSource/src/Simulation/SimulationConfig.cs index 248919a..2fae38f 100644 --- a/ThreatSource/src/Simulation/SimulationConfig.cs +++ b/ThreatSource/src/Simulation/SimulationConfig.cs @@ -1,7 +1,104 @@ +using System.Runtime.CompilerServices; using ThreatSource.Utils; namespace ThreatSource.Simulation { + /// + /// 激光编码配置类,用于设置激光系统的编码参数 + /// + /// + /// 该类定义了激光编码的关键参数,支持以下工作模式: + /// 1. 安全模式:IsCodeEnabled=true, IsCodeMatchRequired=true + /// - 发射编码激光信号 + /// - 只接受匹配编码的信号 + /// - 最高的抗干扰能力和安全性 + /// 2. 简单模式:IsCodeEnabled=false, IsCodeMatchRequired=false + /// - 发射普通激光信号 + /// - 接受任何激光信号 + /// - 系统简单,但抗干扰能力低 + /// 3. 混合模式:IsCodeEnabled=true, IsCodeMatchRequired=false + /// - 发射编码激光信号 + /// - 接受任何激光信号 + /// - 提供向下兼容性 + /// + /// 注意:避免使用 IsCodeEnabled=false, IsCodeMatchRequired=true 的组合, + /// 这种情况下接收端将无法接收到有效信号。 + /// + public class LaserCodeConfig + { + /// + /// 获取或设置激光编码信息 + /// + /// + /// 包含编码类型和编码值等基本信息 + /// + public LaserCode Code { get; set; } + + /// + /// 获取或设置是否启用编码 + /// + /// + /// true表示使用编码 + /// false表示不使用编码 + /// + public bool IsCodeEnabled { get; set; } + + /// + /// 获取或设置是否要求编码匹配 + /// + /// + /// true表示必须匹配编码 + /// false表示不要求匹配 + /// + public bool IsCodeMatchRequired { get; set; } + + /// + /// 检查当前激光编码配置是否与目标配置匹配 + /// + /// 要检查的目标激光编码配置 + /// 如果匹配返回true,否则返回false + /// + /// 匹配规则: + /// 1. 如果接收端不要求匹配(IsCodeMatchRequired=false),则始终返回true + /// 2. 如果接收端要求匹配(IsCodeMatchRequired=true): + /// - 发射端必须启用编码(IsCodeEnabled=true) + /// - 编码参数必须匹配 + /// + public bool CheckCodeMatch(LaserCodeConfig? other) + { + // 如果目标配置为null,不匹配 + if (other == null) + return false; + + // 如果接收端不要求匹配,则始终返回true + if (!IsCodeMatchRequired) + return true; + + // 如果接收端要求匹配,但发射端未启用编码,则不匹配 + if (!other.IsCodeEnabled) + return false; + + // 检查编码是否匹配 + return Code.Matches(other.Code); + } + + /// + /// 初始化激光编码配置的新实例 + /// + /// + /// 设置默认值: + /// - 新的LaserCode实例 + /// - 启用编码 + /// - 要求编码匹配 + /// + public LaserCodeConfig() + { + Code = new LaserCode(); + IsCodeEnabled = true; + IsCodeMatchRequired = true; + } + } + /// /// 激光指示器配置类,用于设置激光半主动导引系统中的激光指示器参数 /// @@ -15,24 +112,6 @@ namespace ThreatSource.Simulation /// public class LaserDesignatorConfig { - /// - /// 获取或设置激光指示器的唯一标识符 - /// - /// - /// 在仿真系统中必须唯一 - /// 用于标识和查找特定的激光指示器 - /// - public string Id { get; set; } - - /// - /// 获取或设置激光指示器的初始位置 - /// - /// - /// 使用三维向量表示空间位置 - /// 坐标系:右手坐标系,X向右,Y向上,Z向前 - /// - public Vector3D InitialPosition { get; set; } - /// /// 获取或设置激光功率 /// @@ -51,6 +130,15 @@ namespace ThreatSource.Simulation /// public double LaserDivergenceAngle { get; set; } + /// + /// 获取或设置激光编码配置 + /// + /// + /// 定义激光信号的编码参数 + /// 用于抗干扰和安全识别 + /// + public LaserCodeConfig LaserCodeConfig { get; set; } + /// /// 初始化激光指示器配置的新实例 /// @@ -60,13 +148,13 @@ namespace ThreatSource.Simulation /// - 初始位置为原点(0,0,0) /// - 激光功率为0瓦特 /// - 发散角为0弧度 + /// - 默认激光编码配置 /// public LaserDesignatorConfig() { - Id = ""; - InitialPosition = new Vector3D(0, 0, 0); LaserPower = 0; LaserDivergenceAngle = 0; + LaserCodeConfig = new LaserCodeConfig(); } } @@ -84,24 +172,6 @@ namespace ThreatSource.Simulation /// public class LaserBeamRiderConfig { - /// - /// 获取或设置激光驾束仪的唯一标识符 - /// - /// - /// 在仿真系统中必须唯一 - /// 用于标识和查找特定的驾束仪 - /// - public string Id { get; set; } - - /// - /// 获取或设置驾束仪的初始位置 - /// - /// - /// 使用三维向量表示空间位置 - /// 坐标系:右手坐标系,X向右,Y向上,Z向前 - /// - public Vector3D InitialPosition { get; set; } - /// /// 获取或设置激光功率 /// @@ -129,6 +199,15 @@ namespace ThreatSource.Simulation /// public double MaxGuidanceDistance { get; set; } + /// + /// 获取或设置激光编码配置 + /// + /// + /// 定义激光信号的编码参数 + /// 用于抗干扰和安全识别 + /// + public LaserCodeConfig LaserCodeConfig { get; set; } + /// /// 初始化激光驾束仪配置的新实例 /// @@ -138,13 +217,15 @@ namespace ThreatSource.Simulation /// - 初始位置为原点(0,0,0) /// - 激光功率为0瓦特 /// - 控制场直径为0米 + /// - 最大导引距离为0米 + /// - 默认激光编码配置 /// public LaserBeamRiderConfig() { - Id = ""; - InitialPosition = new Vector3D(0, 0, 0); LaserPower = 0; ControlFieldDiameter = 0; + MaxGuidanceDistance = 0; + LaserCodeConfig = new LaserCodeConfig(); } } @@ -161,15 +242,6 @@ namespace ThreatSource.Simulation /// public class LaserWarnerConfig { - /// - /// 获取或设置激光告警器的唯一标识符 - /// - /// - /// 在仿真系统中必须唯一 - /// 用于标识和查找特定的告警器 - /// - public string Id { get; set; } - /// /// 获取或设置告警灵敏度阈值 /// @@ -218,7 +290,6 @@ namespace ThreatSource.Simulation /// public LaserWarnerConfig() { - Id = ""; SensitivityThreshold = 0; AlarmDuration = 5.0; // 默认警报持续5秒 WavelengthMin = 0; @@ -239,15 +310,6 @@ namespace ThreatSource.Simulation /// public class UltravioletWarnerConfig { - /// - /// 获取或设置紫外告警器的唯一标识符 - /// - /// - /// 在仿真系统中必须唯一 - /// 用于标识和查找特定的告警器 - /// - public string Id { get; set; } - /// /// 获取或设置告警灵敏度阈值 /// @@ -296,7 +358,6 @@ namespace ThreatSource.Simulation /// public UltravioletWarnerConfig() { - Id = ""; SensitivityThreshold = 0; AlarmDuration = 5.0; // 默认警报持续5秒 WavelengthMin = 0; @@ -317,15 +378,6 @@ namespace ThreatSource.Simulation /// public class InfraredWarnerConfig { - /// - /// 获取或设置红外告警器的唯一标识符 - /// - /// - /// 在仿真系统中必须唯一 - /// 用于标识和查找特定的告警器 - /// - public string Id { get; set; } - /// /// 获取或设置告警灵敏度阈值 /// @@ -374,7 +426,6 @@ namespace ThreatSource.Simulation /// public InfraredWarnerConfig() { - Id = ""; SensitivityThreshold = 0; AlarmDuration = 5.0; // 默认警报持续5秒 WavelengthMin = 0; @@ -395,15 +446,6 @@ namespace ThreatSource.Simulation /// public class MillimeterWaveWarnerConfig { - /// - /// 获取或设置毫米波告警器的唯一标识符 - /// - /// - /// 在仿真系统中必须唯一 - /// 用于标识和查找特定的告警器 - /// - public string Id { get; set; } - /// /// 获取或设置告警灵敏度阈值 /// @@ -452,7 +494,6 @@ namespace ThreatSource.Simulation /// public MillimeterWaveWarnerConfig() { - Id = ""; SensitivityThreshold = 0; AlarmDuration = 5.0; // 默认警报持续5秒 WavelengthMin = 0; @@ -465,11 +506,6 @@ namespace ThreatSource.Simulation /// public class LaserJammerConfig { - /// - /// 激光干扰器ID - /// - public string Id { get; set; } - /// /// 最大干扰冷却时间(秒) /// @@ -495,7 +531,6 @@ namespace ThreatSource.Simulation /// public LaserJammerConfig() { - Id = ""; MaxJammingCooldown = 5.0; MaxJammingPower = 10000.0; InitialJammingPower = 4000.0; @@ -508,21 +543,6 @@ namespace ThreatSource.Simulation /// public class InfraredTrackerConfig { - /// - /// 红外测角仪ID - /// - public string Id { get; set; } - - /// - /// 初始位置 - /// - public Vector3D InitialPosition { get; set; } - - /// - /// 初始朝向 - /// - public Orientation InitialOrientation { get; set; } - /// /// 最大跟踪距离(米) /// @@ -548,9 +568,6 @@ namespace ThreatSource.Simulation /// public InfraredTrackerConfig() { - Id = ""; - InitialPosition = new Vector3D(0, 0, 0); - InitialOrientation = new Orientation(0, 0, 0); MaxTrackingRange = 10000; // 10公里 FieldOfView = Math.PI / 3; // 60度 AngleMeasurementAccuracy = 0.001; // 0.001弧度 (约0.057度) @@ -563,11 +580,6 @@ namespace ThreatSource.Simulation /// public class MillimeterWaveJammerConfig { - /// - /// 干扰器ID - /// - public string Id { get; set; } - /// /// 最大干扰功率(瓦特) /// @@ -593,11 +605,621 @@ namespace ThreatSource.Simulation /// public MillimeterWaveJammerConfig() { - Id = ""; MaxJammingPower = 1000; InitialJammingPower = 400; PowerIncreaseRate = 200; MaxJammingCooldown = 5; } } + + /// + /// 红外成像导引系统配置类 + /// + /// + /// 存储红外成像导引系统的特定参数: + /// - 视场角配置 + /// - 图像传感器配置 + /// - 目标识别配置 + /// - 时间参数配置 + /// + public class InfraredImagingGuidanceConfig + { + /// + /// 最大探测距离(米) + /// + public double MaxDetectionRange { get; set; } = 1000; // 默认1公里 + + /// + /// 搜索模式视场角,单位:弧度 + /// + public double SearchFieldOfView { get; set; } = Math.PI / 15; // 默认12度 + + /// + /// 跟踪模式视场角,单位:弧度 + /// + public double TrackFieldOfView { get; set; } = Math.PI / 60; // 默认3度 + + /// + /// 图像宽度,单位:像素 + /// + public int ImageWidth { get; set; } = 640; + + /// + /// 图像高度,单位:像素 + /// + public int ImageHeight { get; set; } = 512; + + /// + /// 背景辐射强度,单位:瓦特/球面度 + /// + public double BackgroundIntensity { get; set; } = 0.01; + + /// + /// 搜索模式目标识别概率阈值 + /// + public double SearchRecognitionProbability { get; set; } = 0.6; + + /// + /// 跟踪模式目标识别概率阈值 + /// + public double TrackRecognitionProbability { get; set; } = 0.8; + + /// + /// 目标丢失容忍时间,单位:秒 + /// + public double TargetLostTolerance { get; set; } = 0.2; + + /// + /// 锁定确认时间,单位:秒 + /// + public double LockConfirmationTime { get; set; } = 0.3; + + /// + /// 初始化红外成像导引配置的新实例 + /// + /// + /// 使用默认参数初始化配置: + /// - 搜索视场角:12度 + /// - 跟踪视场角:3度 + /// - 图像分辨率:640x512 + /// - 背景辐射:0.01 W/sr + /// - 识别概率阈值:0.6/0.8 + /// - 时间参数:0.2s/0.3s + /// + public InfraredImagingGuidanceConfig() + { + // 使用属性初始化器设置的默认值 + } + } + + /// + /// 激光半主动导引系统配置类 + /// + /// + /// 该类定义了激光半主动导引系统的关键参数: + /// - 光学系统参数(视场角、镜头直径等) + /// - 目标特性参数(反射系数、有效反射面积) + /// - 系统性能参数(锁定阈值、灵敏度) + /// 这些参数决定了导引系统的探测能力和跟踪性能 + /// + public class LaserSemiActiveGuidanceConfig + { + private double fieldOfViewAngle = 30.0; + + /// + /// 视场角,单位:度 + /// + /// + /// 定义了探测器的视场范围 + /// 默认值为30度 + /// 影响系统的探测能力 + /// + public double FieldOfViewAngle + { + get => fieldOfViewAngle; + set => fieldOfViewAngle = value; + } + + /// + /// 视场角,单位:弧度 + /// + /// + /// 将度数转换为弧度供内部计算使用 + /// + public double FieldOfViewAngleInRadians => fieldOfViewAngle * Math.PI / 180.0; + + /// + /// 镜头直径,单位:米 + /// + /// + /// 定义了光学系统镜头的物理尺寸 + /// 影响系统的光能量收集能力 + /// 默认值为0.1米 + /// + public double LensDiameter { get; set; } = 0.1; + + /// + /// 传感器直径,单位:米 + /// + /// + /// 定义了四象限探测器的物理尺寸 + /// 影响系统的探测精度 + /// 默认值为0.03米 + /// + public double SensorDiameter { get; set; } = 0.03; + + /// + /// 聚焦后光斑直径,单位:米 + /// + /// + /// 定义了光学系统聚焦后的光斑大小 + /// 影响系统的探测灵敏度 + /// 默认值为0.006米 + /// + public double FocusedSpotDiameter { get; set; } = 0.006; + + /// + /// 目标反射系数 + /// + /// + /// 定义了目标表面的激光反射能力 + /// 影响反射信号强度 + /// 默认值为0.2 + /// + public double ReflectionCoefficient { get; set; } = 0.2; + + /// + /// 目标有效反射面积,单位:平方米 + /// + /// + /// 定义了目标的等效反射面积 + /// 影响反射信号强度 + /// 默认值为1.0平方米 + /// + public double TargetReflectiveArea { get; set; } = 1.0; + + /// + /// 锁定阈值,单位:瓦特 + /// + /// + /// 定义了系统锁定目标的最小功率要求 + /// 低于此值时认为无法有效跟踪目标 + /// 默认值为1e-12瓦特 + /// + public double LockThreshold { get; set; } = 1e-12; + + /// + /// 光斑偏移灵敏度 + /// + /// + /// 定义了四象限探测器对光斑偏移的响应灵敏度 + /// 影响制导系统的响应速度和稳定性 + /// 默认值为0.5 + /// + public double SpotOffsetSensitivity { get; set; } = 0.5; + + /// + /// 初始化激光半主动导引配置的新实例 + /// + /// + /// 使用属性初始化器设置的默认值: + /// - 视场角:30度 + /// - 镜头直径:0.1米 + /// - 传感器直径:0.03米 + /// - 光斑直径:0.006米 + /// - 反射系数:0.2 + /// - 反射面积:1.0平方米 + /// - 锁定阈值:1e-12瓦特 + /// - 灵敏度:0.5 + /// + public LaserSemiActiveGuidanceConfig() + { + // 使用属性初始化器设置的默认值 + } + } + + /// + /// 末敏弹子弹药分离参数配置类 + /// + /// + /// 该类定义了末敏弹在末端阶段的子弹药分离和性能参数: + /// - 分离参数(高度、距离、角度等) + /// - 减速阶段参数(加速度、末速度) + /// - 降落伞阶段参数(开伞高度、减速度) + /// - 扫描阶段参数(扫描高度、下降速度、扫描角度) + /// - 探测阶段参数(探测距离、自毁高度、攻击速度) + /// 这些参数决定了子弹药的整体性能和打击效果 + /// + public class TerminalSensitiveSubmunitionConfig + { + #region 分离参数 + /// + /// 子弹药分离的高度阈值,单位:米 + /// + /// + /// 当导弹上升到此高度时会触发分离 + /// 影响分离时机的选择 + /// 默认值为1000米 + /// + public double SeparationHeight { get; set; } = 1000.0; + + /// + /// 分离点与目标的水平距离,单位:米 + /// + /// + /// 分离点在目标上方的水平投影距离 + /// 影响分离位置的选择 + /// 默认值为1000米 + /// + public double SeparationDistance { get; set; } = 1000.0; + + /// + /// 子弹药分离角度(与地面的夹角),单位:度 + /// + /// + /// 子弹药从母弹分离时与地面的夹角 + /// 影响子弹药的初始飞行轨迹 + /// 默认值为45度 + /// + public double SubmunitionSeparationAngle { get; set; } = 45.0; + + /// + /// 触发分离的距离阈值,单位:米 + /// + /// + /// 当导弹距离分离点小于此距离时触发分离 + /// 注意:此值必须大于导弹速度乘以时间步长的一半 + /// 默认值为50米 + /// + public double SeparationRange { get; set; } = 50.0; + #endregion + + #region 减速阶段参数 + /// + /// 减速阶段的减速加速度,单位:米/秒² + /// + /// + /// 定义了减速阶段的减速度大小 + /// 影响速度调整的快慢 + /// 默认值为250米/秒² + /// + public double DecelerationAcceleration { get; set; } = 250.0; + + /// + /// 减速阶段末速度,单位:米/秒 + /// + /// + /// 定义了减速阶段的垂直下降速度 + /// 默认值为50米/秒 + /// + public double DecelerationEndSpeed { get; set; } = 50.0; + #endregion + + #region 降落伞阶段参数 + /// + /// 降落伞打开高度,单位:米 + /// + /// + /// 打开降落伞的高度阈值 + /// 影响降落伞打开阶段的触发时机 + /// 默认值为400米 + /// + public double ParachuteDeploymentHeight { get; set; } = 400.0; + + /// + /// 降落伞减速加速度,单位:米/秒² + /// + /// + /// 定义了降落伞减速加速度 + /// 默认值为140米/秒² + /// + public double ParachuteDeceleration { get; set; } = 140.0; + #endregion + + #region 扫描阶段参数 + /// + /// 稳定扫描高度,单位:米 + /// + /// + /// 开始螺旋扫描的高度阈值 + /// 影响扫描阶段的触发时机 + /// 默认值为200米 + /// + public double StableScanHeight { get; set; } = 200.0; + + /// + /// 垂直下降速度,单位:米/秒 + /// + /// + /// 定义了扫描和攻击阶段的垂直下降速度 + /// 默认值为10米/秒 + /// + public double VerticalDeclineSpeed { get; set; } = 10.0; + + /// + /// 螺旋扫描旋转速度,单位:弧度/秒 + /// + /// + /// 定义了螺旋扫描时的旋转角速度 + /// 4转/秒 = 8π弧度/秒 + /// 默认值为25.13弧度/秒 + /// + public double SpiralRotationSpeed { get; set; } = 8.0 * Math.PI; + + /// + /// 扫描角度,单位:度 + /// + /// + /// 定义了螺旋扫描的锥角 + /// 默认值为30度 + /// + public double ScanAngle { get; set; } = 30.0; + + /// + /// 扫描角度,单位:弧度 + /// + /// + /// 将度数转换为弧度供内部计算使用 + /// + public double ScanAngleInRadians => ScanAngle * Math.PI / 180.0; + #endregion + + #region 探测和攻击阶段参数 + /// + /// 目标探测距离,单位:米 + /// + /// + /// 目标探测的距离阈值 + /// 影响目标探测阶段的触发时机 + /// 默认值为150米 + /// + public double TargetDetectionDistance { get; set; } = 150.0; + + /// + /// 自毁高度,单位:米 + /// + /// + /// 触发自毁的高度阈值 + /// 保证子弹不会危及友方 + /// 默认值为20米 + /// + public double SelfDestructHeight { get; set; } = 20.0; + + /// + /// 攻击速度,单位:米/秒 + /// + /// + /// 攻击阶段的期望速度 + /// 影响末端制导的精度 + /// 默认值为2000米/秒 + /// + public double AttackSpeed { get; set; } = 2000.0; + #endregion + + /// + /// 初始化末敏弹子弹药分离参数配置的新实例 + /// + /// + /// 使用属性初始化器设置所有默认值: + /// - 分离参数:高度1000米,距离1000米,角度45度,触发距离50米 + /// - 减速参数:加速度250米/秒²,末速度50米/秒 + /// - 降落伞参数:开伞高度400米,减速度140米/秒² + /// - 扫描参数:高度200米,下降速度10米/秒,旋转速度8π弧度/秒,扫描角30度 + /// - 探测参数:探测距离150米,自毁高度20米,攻击速度200米/秒 + /// + public TerminalSensitiveSubmunitionConfig() + { + // 使用属性初始化器设置的默认值 + } + } + + /// + /// 激光驾束制导系统配置类 + /// + /// + /// 该类定义了激光驾束制导系统的性能参数: + /// - 探测器参数(最小可探测功率、探测器直径) + /// - 控制参数(控制场直径、PID参数) + /// - 制导参数(最大加速度、非线性增益) + /// - 滤波参数(低通滤波系数) + /// + public class LaserBeamRiderGuidanceSystemConfig + { + /// + /// 最小可探测功率,单位:瓦特 + /// + /// + /// 定义了探测器的灵敏度阈值 + /// 低于此值时无法有效探测 + /// + public double MinDetectablePower { get; set; } = 1e-3; + + /// + /// 探测器直径,单位:米 + /// + /// + /// 定义了探测器的物理尺寸 + /// 影响系统的接收能力 + /// + public double DetectorDiameter { get; set; } = 0.1; + + /// + /// 控制场直径,单位:米 + /// + /// + /// 定义了有效制导范围 + /// 超出此范围将失去制导 + /// + public double ControlFieldDiameter { get; set; } = 20.0; + + /// + /// PID控制器比例系数 + /// + /// + /// 控制系统对误差的即时响应 + /// 值越大,响应越快 + /// + public double ProportionalGain { get; set; } = 30.0; + + /// + /// PID控制器积分系数 + /// + /// + /// 用于消除稳态误差 + /// 值越大,稳态误差消除越快 + /// + public double IntegralGain { get; set; } = 0.05; + + /// + /// PID控制器微分系数 + /// + /// + /// 用于抑制超调和振荡 + /// 值越大,系统越稳定 + /// + public double DerivativeGain { get; set; } = 5.0; + + /// + /// 非线性增益系数 + /// + /// + /// 控制制导系统的非线性特性 + /// 影响系统对不同大小误差的响应 + /// + public double NonlinearGain { get; set; } = 0.5; + + /// + /// 最大制导加速度,单位:米/平方秒 + /// + /// + /// 限制制导系统输出的最大加速度 + /// 防止过大的机动指令 + /// + public double MaxGuidanceAcceleration { get; set; } = 50.0; + + /// + /// 低通滤波系数 + /// + /// + /// 用于平滑制导指令 + /// 值越小,滤波效果越强 + /// + public double LowPassFilterCoefficient { get; set; } = 0.2; + + /// + /// 初始化激光驾束制导系统配置的新实例 + /// + /// + /// 使用属性初始化器设置的默认值: + /// - 最小可探测功率:1mW + /// - 探测器直径:0.1米 + /// - 控制场直径:20米 + /// - PID参数:Kp=30, Ki=0.05, Kd=5 + /// - 非线性增益:0.5 + /// - 最大加速度:50 m/s² + /// - 滤波系数:0.2 + /// + public LaserBeamRiderGuidanceSystemConfig() + { + // 使用属性初始化器设置的默认值 + } + } + + /// + /// 毫米波末制导导引系统配置类 + /// + /// + /// 该类定义了毫米波末制导导引系统的关键参数: + /// - 探测参数(最大探测距离、视场角) + /// - 雷达参数(工作频率、脉冲持续时间) + /// - 目标识别参数(识别概率、信噪比阈值) + /// 这些参数决定了导引系统的探测和跟踪性能 + /// + public class MillimeterWaveGuidanceConfig + { + /// + /// 最大探测范围,单位:米 + /// + /// + /// 定义了毫米波雷达的最大作用距离 + /// 超出此范围的目标无法有效探测 + /// 典型值为5000米 + /// + public double MaxDetectionRange { get; set; } = 5000.0; + + /// + /// 视场角,单位:度 + /// + /// + /// 定义了雷达的扫描范围 + /// 默认设置为45度 + /// 影响系统的搜索能力 + /// + public double FieldOfViewAngle { get; set; } = 45.0; + + /// + /// 视场角,单位:弧度 + /// + /// + /// 将度数转换为弧度供内部计算使用 + /// + public double FieldOfViewAngleInRadians => FieldOfViewAngle * Math.PI / 180.0; + + /// + /// 目标识别概率 + /// + /// + /// 定义了目标识别的成功率 + /// 影响系统的可靠性 + /// 典型值为0.95 + /// + public double TargetRecognitionProbability { get; set; } = 0.95; + + /// + /// 毫米波频率,单位:赫兹 + /// + /// + /// 定义了雷达工作频率 + /// 设置为94GHz + /// 影响探测性能和抗干扰能力 + /// + public double WaveFrequency { get; set; } = 94e9; + + /// + /// 脉冲持续时间,单位:秒 + /// + /// + /// 定义了雷达发射脉冲的时长 + /// 影响距离分辨率 + /// 典型值为1微秒 + /// + public double PulseDuration { get; set; } = 1e-6; + + /// + /// 识别目标的信噪比阈值,单位:分贝 + /// + /// + /// 定义了目标识别的最小信噪比要求 + /// 大于此值时认为目标有效 + /// 典型值为6dB + /// + public double RecognitionSNRThreshold { get; set; } = 6.0; + + /// + /// 初始化毫米波末制导导引系统配置的新实例 + /// + /// + /// 使用属性初始化器设置的默认值: + /// - 最大探测范围:5000米 + /// - 视场角:45度 + /// - 目标识别概率:0.95 + /// - 工作频率:94GHz + /// - 脉冲持续时间:1微秒 + /// - 信噪比阈值:6dB + /// + public MillimeterWaveGuidanceConfig() + { + // 使用属性初始化器设置的默认值 + } + } } diff --git a/ThreatSource/src/Simulation/SimulationElement.cs b/ThreatSource/src/Simulation/SimulationElement.cs index 02976ff..f340e7f 100644 --- a/ThreatSource/src/Simulation/SimulationElement.cs +++ b/ThreatSource/src/Simulation/SimulationElement.cs @@ -8,58 +8,29 @@ namespace ThreatSource.Simulation /// 仿真元素的抽象基类,所有仿真中的实体都继承自此类 /// /// - /// 该类提供了仿真实体的基本功能: + /// 该类提供了仿真实体的基本功能的默认实现: /// - 位置和运动状态管理 /// - 生命周期管理(激活/停用) /// - 事件发布机制 /// - 状态更新机制 + /// - 频谱特性管理 /// 所有具体的仿真实体(如导弹、目标等)都应继承此类并实现其抽象方法。 /// - public abstract class SimulationElement + public abstract class SimulationElement : ISimulationElement, ISpectralCharacteristics { - /// - /// 获取或设置仿真元素的唯一标识符 - /// - /// - /// ID在仿真系统中必须唯一,用于标识和查找实体 - /// + /// public virtual string Id { get; set; } - /// - /// 获取或设置仿真元素的当前位置 - /// - /// - /// 使用三维向量表示实体在空间中的位置 - /// 坐标系:右手坐标系,X向右,Y向上,Z向前 - /// + /// public virtual Vector3D Position { get; set; } - /// - /// 获取或设置仿真元素的当前速度大小 - /// - /// - /// 单位:米/秒 - /// 此属性仅表示速度的标量值,方向信息需要结合Velocity属性 - /// + /// public virtual double Speed { get; set; } - /// - /// 获取或设置仿真元素的当前速度向量 - /// - /// - /// 单位:米/秒 - /// 包含速度的大小和方向信息 - /// 向量的模等于Speed属性值 - /// + /// public virtual Vector3D Velocity { get; set; } - /// - /// 获取或设置仿真元素的当前朝向 - /// - /// - /// 使用欧拉角表示实体的朝向 - /// 包含偏航角、俯仰角和滚转角 - /// + /// public virtual Orientation Orientation { get; set; } /// @@ -94,13 +65,7 @@ namespace ThreatSource.Simulation /// public double MillimeterWaveRadiationIntensity { get; protected set; } - /// - /// 获取仿真元素是否处于活动状态 - /// - /// - /// true表示实体当前处于活动状态,可以参与仿真 - /// false表示实体已停用,不再参与仿真计算 - /// + /// public virtual bool IsActive { get; protected set; } /// @@ -210,7 +175,6 @@ namespace ThreatSource.Simulation public virtual void Activate() { IsActive = true; - PublishEvent(new EntityActivatedEvent { ActivatedEntityId = Id }); } /// @@ -225,7 +189,6 @@ namespace ThreatSource.Simulation public virtual void Deactivate() { IsActive = false; - PublishEvent(new EntityDeactivatedEvent { DeactivatedEntityId = Id }); } } } diff --git a/ThreatSource/src/Simulation/SimulationEvents.cs b/ThreatSource/src/Simulation/SimulationEvents.cs index b5a9846..5659940 100644 --- a/ThreatSource/src/Simulation/SimulationEvents.cs +++ b/ThreatSource/src/Simulation/SimulationEvents.cs @@ -83,16 +83,7 @@ namespace ThreatSource.Simulation /// 包含激光信号的编码类型和编码值 /// 用于抗干扰和安全识别 /// - public LaserCode? LaserCode { get; set; } - - /// - /// 获取或设置是否启用编码 - /// - /// - /// true表示激光信号使用编码 - /// false表示激光信号不使用编码 - /// - public bool IsCodeEnabled { get; set; } + public LaserCodeConfig? LaserCodeConfig { get; set; } } /// @@ -127,16 +118,7 @@ namespace ThreatSource.Simulation /// 包含激光信号的编码类型和编码值 /// 用于抗干扰和安全识别 /// - public LaserCode? LaserCode { get; set; } - - /// - /// 获取或设置是否启用编码 - /// - /// - /// true表示激光信号使用编码 - /// false表示激光信号不使用编码 - /// - public bool IsCodeEnabled { get; set; } + public LaserCodeConfig? LaserCodeConfig { get; set; } } /// @@ -241,83 +223,90 @@ namespace ThreatSource.Simulation } /// - /// 实体激活事件,表示仿真实体被激活 + /// 激光波束开始事件,表示激光驾束仪开始发射激光波束 /// /// - /// 用于通知系统某个实体已进入活动状态 - /// 触发时机:实体被创建或重新激活时 - /// - public class EntityActivatedEvent : SimulationEvent - { - /// - /// 获取或设置被激活实体的ID - /// - /// - /// 标识已被激活的实体 - /// - public string? ActivatedEntityId { get; set; } - } - - /// - /// 实体停用事件,表示仿真实体被停用 - /// - /// - /// 用于通知系统某个实体已停止活动 - /// 触发时机:实体被停用或暂时移除时 - /// - public class EntityDeactivatedEvent : SimulationEvent - { - /// - /// 获取或设置被停用实体的ID - /// - /// - /// 标识已被停用的实体 - /// - public string? DeactivatedEntityId { get; set; } - } - - /// - /// 激光波束开始事件,表示激光波束制导开始 - /// - /// - /// 用于激光波束制导系统 - /// 触发时机:开始发射制导激光波束时 + /// 用于通知系统激光波束开始照射 + /// 触发时机:激光驾束仪开始工作时 /// public class LaserBeamStartEvent : SimulationEvent { /// - /// 获取或设置激光波束制导器的ID + /// 获取或设置激光驾束仪的ID /// + /// + /// 标识发出激光波束的驾束仪设备 + /// public string? LaserBeamRiderId { get; set; } + + /// + /// 获取或设置波束功率 + /// + /// + /// 激光波束的发射功率 + /// + public double BeamPower { get; set; } + + /// + /// 获取或设置激光编码配置 + /// + /// + /// 包含激光信号的编码信息 + /// 用于抗干扰和安全识别 + /// + public LaserCodeConfig? LaserCodeConfig { get; set; } } /// - /// 激光波束更新事件,表示激光波束位置更新 + /// 激光波束更新事件,表示激光波束状态的更新 /// /// - /// 用于实时更新激光波束的位置和方向 - /// 在制导过程中周期性触发 + /// 用于实时更新激光波束的状态 + /// 在波束照射过程中周期性触发 /// public class LaserBeamUpdateEvent : SimulationEvent { /// - /// 获取或设置激光波束制导器的ID + /// 获取或设置激光驾束仪的ID /// + /// + /// 标识发出激光波束的驾束仪设备 + /// public string? LaserBeamRiderId { get; set; } + + /// + /// 获取或设置波束功率 + /// + /// + /// 激光波束的发射功率 + /// + public double BeamPower { get; set; } + + /// + /// 获取或设置激光编码配置 + /// + /// + /// 包含激光信号的编码信息 + /// 用于抗干扰和安全识别 + /// + public LaserCodeConfig? LaserCodeConfig { get; set; } } /// - /// 激光波束停止事件,表示激光波束制导结束 + /// 激光波束停止事件,表示激光驾束仪停止发射激光波束 /// /// - /// 用于通知系统激光波束制导已结束 - /// 触发时机:停止发射制导激光波束时 + /// 用于通知系统激光波束已停止 + /// 触发时机:激光驾束仪停止工作或波束中断时 /// public class LaserBeamStopEvent : SimulationEvent { /// - /// 获取或设置激光波束制导器的ID + /// 获取或设置激光驾束仪的ID /// + /// + /// 标识停止发射的驾束仪设备 + /// public string? LaserBeamRiderId { get; set; } } @@ -627,7 +616,7 @@ namespace ThreatSource.Simulation /// /// 包含成功匹配的编码信息 /// - public LaserCode? MatchedCode { get; set; } + public LaserCodeConfig? MatchedCodeConfig { get; set; } } /// @@ -661,7 +650,7 @@ namespace ThreatSource.Simulation /// /// 导弹期望接收的编码信息 /// - public LaserCode? ExpectedCode { get; set; } + public LaserCodeConfig? ExpectedCodeConfig { get; set; } /// /// 获取或设置接收到的激光编码 @@ -669,6 +658,6 @@ namespace ThreatSource.Simulation /// /// 导弹实际接收到的编码信息 /// - public LaserCode? ReceivedCode { get; set; } + public LaserCodeConfig? ReceivedCodeConfig { get; set; } } } diff --git a/ThreatSource/src/Simulation/SimulationManager.cs b/ThreatSource/src/Simulation/SimulationManager.cs index add088a..9a7fbf3 100644 --- a/ThreatSource/src/Simulation/SimulationManager.cs +++ b/ThreatSource/src/Simulation/SimulationManager.cs @@ -177,7 +177,7 @@ namespace ThreatSource.Simulation { double distance = Vector3D.Distance(missile.Position, target.Position); Console.WriteLine($"导弹 {missile.Id} 和目标 {target.Id} 之间的距离: {distance}"); - if (distance <= missile.MissileProperties.ExplosionRadius) + if (distance <= missile.Properties.ExplosionRadius) { double damage = CalculateMissileDamage(missile); hitEvents.Add((target, missile, damage)); @@ -244,8 +244,7 @@ namespace ThreatSource.Simulation { if (evt == null) { - Debug.WriteLine("[事件] 错误: 事件对象为空"); - return; + throw new ArgumentNullException(nameof(evt), "事件对象不能为空"); } var eventType = typeof(T); diff --git a/ThreatSource/src/Simulation/Testing/TestSimulationAdapter.cs b/ThreatSource/src/Simulation/Testing/TestSimulationAdapter.cs deleted file mode 100644 index 51c442f..0000000 --- a/ThreatSource/src/Simulation/Testing/TestSimulationAdapter.cs +++ /dev/null @@ -1,165 +0,0 @@ -using System; -using System.Collections.Generic; -using ThreatSource.Simulation; -using ThreatSource.Utils; - -namespace ThreatSource.Simulation.Testing -{ - /// - /// 用于测试的仿真环境适配器 - /// - public class TestSimulationAdapter : ISimulationAdapter - { - private readonly Dictionary _testEntities = []; - private readonly List _receivedEvents = []; - private readonly List _publishedEvents = []; - private ISimulationManager? _simulationManager; - // 存储实体状态的字典 - private Dictionary entityStates = new(); - // 存储环境数据的字典 - private Dictionary environmentData = new(); - // 当前仿真时间 - private double currentTime = 0; - - /// - /// 构造函数,初始化测试适配器 - /// - /// 仿真管理器 - public TestSimulationAdapter(ISimulationManager simulationManager) - { - _simulationManager = simulationManager; - } - - /// - /// 获取实体 - /// - /// 实体ID - /// 实体对象或null - public object? GetEntity(string id) - { - return _testEntities.TryGetValue(id, out var entity) ? entity : null; - } - - /// - /// 发布事件到外部仿真 - /// - /// 事件类型 - /// 事件对象 - public void PublishToExternalSimulation(T evt) - { - ArgumentNullException.ThrowIfNull(evt); - _publishedEvents.Add(evt); - } - - /// - /// 接收来自外部仿真的事件 - /// - /// 事件类型 - /// 事件对象 - public void ReceiveFromExternalSimulation(T evt) - { - ArgumentNullException.ThrowIfNull(evt); - _receivedEvents.Add(evt); - _simulationManager?.PublishEvent(evt); - } - - /// - /// 添加测试实体 - /// - /// 实体ID - /// 实体对象 - public void AddTestEntity(string id, object entity) - { - _testEntities[id] = entity; - } - - /// - /// 清除测试实体 - /// - public void ClearTestEntities() - { - _testEntities.Clear(); - } - - /// - /// 获取已发布的事件 - /// - /// 已发布的事件列表 - public IReadOnlyList GetPublishedEvents() - { - return _publishedEvents; - } - - /// - /// 获取指定类型的已发布事件 - /// - /// 事件类型 - /// 指定类型的已发布事件列表 - public List GetPublishedEvents() where T : SimulationEvent - { - return _publishedEvents.OfType().ToList(); - } - - /// - /// 获取已接收的事件 - /// - /// 已接收的事件列表 - public IReadOnlyList GetReceivedEvents() - { - return _receivedEvents; - } - - /// - /// 清除事件 - /// - public void ClearEvents() - { - _publishedEvents.Clear(); - _receivedEvents.Clear(); - } - - /// - /// 获取实体状态 - /// - /// - /// - public object? GetEntityState(string entityId) - { - return entityStates.TryGetValue(entityId, out var state) ? state : new MockSimulationElement(entityId); - } - - /// - /// 设置实体环境数据 - /// - /// - /// - public void SetEntityEnvironment(string entityId, SimulationEnvironmentData data) - { - environmentData[entityId] = data; - } - - /// - /// 同步仿真时间 - /// - /// - public void SynchronizeTime(double time) - { - currentTime = time; - } - } - - /// - /// 用于测试的模拟仿真元素 - /// - internal class MockSimulationElement : SimulationElement - { - public MockSimulationElement(string id) - : base(id, new Vector3D(0, 0, 0), new Orientation(), 0, null!) - { - } - - public override void Update(double deltaTime) - { - } - } -} \ No newline at end of file diff --git a/ThreatSource/src/Target/APC.cs b/ThreatSource/src/Target/APC.cs new file mode 100644 index 0000000..437f431 --- /dev/null +++ b/ThreatSource/src/Target/APC.cs @@ -0,0 +1,54 @@ +using ThreatSource.Simulation; +using ThreatSource.Utils; + +namespace ThreatSource.Target +{ + /// + /// 装甲运输车类,继承自BaseTarget的具体装甲车目标 + /// + /// + /// 该类提供了装甲运输车目标的具体实现: + /// - 继承自BaseTarget,获得基本的目标功能 + /// - 实现装甲运输车特有的属性和行为 + /// + public class APC : BaseTarget + { + /// + /// 获取装甲运输车的类型标识 + /// + /// + /// 固定返回 TargetType.APC,用于标识这是一个装甲运输车目标 + /// + public override TargetType Type => TargetType.APC; + + /// + /// 初始化装甲运输车类的新实例 + /// + /// 装甲运输车的唯一标识符 + /// 初始运动参数 + /// 仿真管理器实例 + /// + /// 构造函数设置装甲运输车的初始状态: + /// - 调用基类构造函数初始化基本属性 + /// + public APC(string id, InitialMotionParameters initialMotionParameters, ISimulationManager simulationManager) + : base(id, initialMotionParameters, simulationManager) + { + } + + /// + /// 更新装甲运输车的状态 + /// + /// 时间步长,单位:秒 + /// + /// 更新过程: + /// - 调用基类的更新方法更新基本状态 + /// - 可以在此添加装甲运输车特有的更新逻辑 + /// + public override void Update(double deltaTime) + { + base.Update(deltaTime); + // TODO: 添加装甲运输车特有的更新逻辑 + } + } +} \ No newline at end of file diff --git a/ThreatSource/src/Target/BaseTarget.cs b/ThreatSource/src/Target/BaseTarget.cs new file mode 100644 index 0000000..ab0f04d --- /dev/null +++ b/ThreatSource/src/Target/BaseTarget.cs @@ -0,0 +1,193 @@ +using ThreatSource.Simulation; +using ThreatSource.Utils; + +namespace ThreatSource.Target +{ + /// + /// 目标基类,实现了目标的通用功能 + /// + /// + /// 该类提供了目标的基本实现: + /// - 继承自SimulationElement,具备基本的仿真功能 + /// - 实现ITarget接口,提供目标特征 + /// - 包含生命值系统,可以响应伤害 + /// - 支持位置更新和状态同步 + /// + public abstract class BaseTarget : SimulationElement, ITarget + { + /// + /// 获取目标的类型标识 + /// + /// + /// 由子类实现,返回具体的目标类型 + /// + public abstract TargetType Type { get; } + + /// + /// 获取目标的毫米波辐射温度 + /// + /// + /// 单位:开尔文 + /// 表示目标的毫米波辐射特征 + /// 典型值:350-450K + /// + public double MillimeterWaveRadiationTemperature { get; set; } + + /// + /// 获取目标的激光反射率 + /// + /// + /// 无量纲,取值范围:0-1 + /// 表示目标表面对激光的反射特性 + /// + public double LaserReflectivity { get; set; } + + /// + /// 获取或设置目标的当前生命值 + /// + /// + /// 范围:0-100 + /// 初始值为100 + /// 当生命值降至0或以下时,目标被销毁 + /// + public double Health { get; set; } = 100.0; + + /// + /// 获取目标的长度 + /// + /// + /// 单位:米 + /// + public double Length { get; private set; } + + /// + /// 获取目标的宽度 + /// + /// + /// 单位:米 + /// + public double Width { get; private set; } + + /// + /// 获取目标的高度 + /// + /// + /// 单位:米 + /// + public double Height { get; private set; } + + /// + /// 获取目标的温度分布模式 + /// + /// + /// 3x3矩阵,表示目标侧视图的温度分布 + /// + protected ThermalPattern ThermalPattern { get; private set; } + + /// + /// 初始化目标基类的新实例 + /// + /// 目标的唯一标识符 + /// 初始运动参数 + /// 仿真管理器实例 + /// + /// 构造函数设置目标的初始状态: + /// - 使用默认朝向 + /// - 设置初始位置和速度 + /// - 生命值初始化为100 + /// + protected BaseTarget(string id, InitialMotionParameters initialMotionParameters, ISimulationManager simulationManager) + : base(id, initialMotionParameters.Position, initialMotionParameters.Orientation, initialMotionParameters.InitialSpeed, simulationManager) + { + Health = 100.0; + // 初始化一个空的温度分布模式 + ThermalPattern = new ThermalPattern(new double[3, 3], new double[3, 3]); + } + + /// + /// 设置目标的物理尺寸 + /// + /// 长度(米) + /// 宽度(米) + /// 高度(米) + public void SetDimensions(double length, double width, double height) + { + Length = length; + Width = width; + Height = height; + } + + /// + /// 设置目标的频谱特征 + /// + /// 雷达散射截面积(平方米) + /// 红外辐射强度(瓦特/球面度) + /// 紫外辐射强度(瓦特/球面度) + /// 毫米波辐射强度(瓦特/球面度) + public void SetSpectralCharacteristics( + double radarCrossSection, + double infraredRadiationIntensity, + double ultravioletRadiationIntensity, + double millimeterWaveRadiationIntensity) + { + RadarCrossSection = radarCrossSection; + InfraredRadiationIntensity = infraredRadiationIntensity; + UltravioletRadiationIntensity = ultravioletRadiationIntensity; + MillimeterWaveRadiationIntensity = millimeterWaveRadiationIntensity; + } + + /// + /// 设置目标的温度分布模式 + /// + /// 温度分布模式对象 + public void SetThermalPattern(ThermalPattern thermalPattern) + { + ThermalPattern = thermalPattern ?? throw new ArgumentNullException(nameof(thermalPattern)); + } + + /// + /// 获取当前的温度分布矩阵 + /// + /// 当前状态下的温度分布矩阵 + public double[,] GetCurrentThermalPattern() + { + // 根据当前速度判断是否在运动 + bool isMoving = Velocity.Magnitude() > 0.1; // 速度大于0.1米/秒认为在运动 + return ThermalPattern.GetPattern(isMoving); + } + + /// + /// 更新目标的状态 + /// + /// 时间步长,单位:秒 + /// + /// 更新过程: + /// - 根据当前速度更新位置 + /// - 位置更新使用简单的线性运动模型 + /// + public override void Update(double deltaTime) + { + // 更新目标的位置 + Position += Velocity * deltaTime; + } + + /// + /// 对目标造成伤害 + /// + /// 伤害值 + /// + /// 伤害处理过程: + /// - 从当前生命值中扣除伤害值 + /// - 如果生命值降至0或以下,触发目标销毁事件 + /// - 销毁事件会通知仿真系统移除该目标 + /// + public void TakeDamage(double damage) + { + Health -= damage; + if (Health <= 0) + { + SimulationManager.PublishEvent(new TargetDestroyedEvent { TargetId = Id }); + } + } + } +} \ No newline at end of file diff --git a/ThreatSource/src/Target/Helicopter.cs b/ThreatSource/src/Target/Helicopter.cs new file mode 100644 index 0000000..216d506 --- /dev/null +++ b/ThreatSource/src/Target/Helicopter.cs @@ -0,0 +1,54 @@ +using ThreatSource.Simulation; +using ThreatSource.Utils; + +namespace ThreatSource.Target +{ + /// + /// 直升机类,继承自BaseTarget的具体直升机目标 + /// + /// + /// 该类提供了直升机目标的具体实现: + /// - 继承自BaseTarget,获得基本的目标功能 + /// - 实现直升机特有的属性和行为 + /// + public class Helicopter : BaseTarget + { + /// + /// 获取直升机的类型标识 + /// + /// + /// 固定返回 TargetType.Helicopter,用于标识这是一个直升机目标 + /// + public override TargetType Type => TargetType.Helicopter; + + /// + /// 初始化直升机类的新实例 + /// + /// 直升机的唯一标识符 + /// 初始运动参数 + /// 仿真管理器实例 + /// + /// 构造函数设置直升机的初始状态: + /// - 调用基类构造函数初始化基本属性 + /// + public Helicopter(string id, InitialMotionParameters initialMotionParameters, ISimulationManager simulationManager) + : base(id, initialMotionParameters, simulationManager) + { + } + + /// + /// 更新直升机的状态 + /// + /// 时间步长,单位:秒 + /// + /// 更新过程: + /// - 调用基类的更新方法更新基本状态 + /// - 可以在此添加直升机特有的更新逻辑 + /// + public override void Update(double deltaTime) + { + base.Update(deltaTime); + // TODO: 添加直升机特有的更新逻辑 + } + } +} \ No newline at end of file diff --git a/ThreatSource/src/Target/ITarget.cs b/ThreatSource/src/Target/ITarget.cs index 18b1574..bad1b50 100644 --- a/ThreatSource/src/Target/ITarget.cs +++ b/ThreatSource/src/Target/ITarget.cs @@ -1,19 +1,52 @@ using ThreatSource.Utils; +using ThreatSource.Simulation; namespace ThreatSource.Target { + /// + /// 目标类型枚举 + /// + /// + /// 定义了系统支持的目标类型: + /// - 坦克 + /// - 装甲车 + /// - 直升机 + /// 用于目标识别和分类 + /// + public enum TargetType + { + /// + /// 未知类型 + /// + Unknown, + + /// + /// 坦克 + /// + Tank, + + /// + /// 装甲运输车 + /// + APC, + + /// + /// 直升机 + /// + Helicopter + } + /// /// 定义目标对象的基本接口,提供目标的基本特征和属性 /// /// /// 该接口定义了目标的关键特征: /// - 目标类型标识 - /// - 雷达散射截面积 - /// - 红外辐射特征 /// - 目标物理尺寸 + /// - 目标特殊频谱特性 /// 用于在仿真系统中表示和识别不同类型的目标 /// - public interface ITarget + public interface ITarget : ISimulationElement, ISpectralCharacteristics { /// /// 获取目标的类型标识 @@ -22,28 +55,7 @@ namespace ThreatSource.Target /// 用于区分不同种类的目标,如坦克、装甲车等 /// 在仿真系统中用于目标识别和分类 /// - string Type { get; } - - /// - /// 获取目标的雷达散射截面积 - /// - /// - /// 单位:平方米 - /// 表示目标对雷达波的反射能力 - /// 影响目标在雷达系统中的探测距离和识别概率 - /// - double RadarCrossSection { get; } - - /// - /// 获取目标的红外辐射强度 - /// - /// - /// 单位:瓦特/球面度 - /// 表示目标的热辐射特征 - /// 影响红外制导系统的探测和跟踪能力 - /// 典型值:200-500 W/sr - /// - double InfraredRadiationIntensity { get; } + TargetType Type { get; } /// /// 获取目标的毫米波辐射温度 @@ -92,5 +104,25 @@ namespace ThreatSource.Target /// 表示目标在垂直方向上的尺寸 /// double Height { get; } + + /// + /// 获取或设置目标的当前生命值 + /// + /// + /// 范围:0-100 + /// 初始值为100 + /// 当生命值降至0或以下时,目标被销毁 + /// + double Health { get; set; } + + /// + /// 获取当前的温度分布矩阵 + /// + /// 当前状态下的温度分布矩阵 + /// + /// 返回3x3矩阵,表示目标侧视图的温度分布 + /// 根据目标的运动状态返回静止或运动时的温度分布 + /// + double[,] GetCurrentThermalPattern(); } } \ No newline at end of file diff --git a/ThreatSource/src/Target/Tank.cs b/ThreatSource/src/Target/Tank.cs index 330d546..34bb36f 100644 --- a/ThreatSource/src/Target/Tank.cs +++ b/ThreatSource/src/Target/Tank.cs @@ -4,99 +4,36 @@ using ThreatSource.Utils; namespace ThreatSource.Target { /// - /// 坦克类,实现了目标接口的具体坦克目标 + /// 坦克类,继承自BaseTarget的具体坦克目标 /// /// - /// 该类提供了坦克目标的完整实现: - /// - 继承自SimulationElement,具备基本的仿真功能 - /// - 实现ITarget接口,提供目标特征 - /// - 包含生命值系统,可以响应伤害 - /// - 支持位置更新和状态同步 + /// 该类提供了坦克目标的具体实现: + /// - 继承自BaseTarget,获得基本的目标功能 + /// - 实现坦克特有的属性和行为 /// - public class Tank : SimulationElement, ITarget + public class Tank : BaseTarget { /// /// 获取坦克的类型标识 /// /// - /// 固定返回"Tank",用于标识这是一个坦克目标 + /// 固定返回 TargetType.Tank,用于标识这是一个坦克目标 /// - public string Type => "Tank"; - - /// - /// 获取坦克的毫米波辐射温度 - /// - /// - /// 单位:开尔文 - /// 固定值400.0,表示坦克的毫米波辐射特征 - /// 典型值:350-450K - /// - public double MillimeterWaveRadiationTemperature { get; set; } = 400.0; - - /// - /// 获取坦克的激光反射率 - /// - /// - /// 无量纲,取值范围:0-1 - /// 固定值0.3,表示坦克表面对激光的反射特性 - /// - public double LaserReflectivity { get; set; } = 0.3; - - /// - /// 获取或设置坦克的当前生命值 - /// - /// - /// 范围:0-100 - /// 初始值为100 - /// 当生命值降至0或以下时,坦克被销毁 - /// - public double Health { get; set; } = 100.0; - - /// - /// 获取坦克的长度 - /// - /// - /// 单位:米 - /// 固定值6.0,表示坦克的长度 - /// - public double Length => 6.0; - - /// - /// 获取坦克的宽度 - /// - /// - /// 单位:米 - /// 固定值3.0,表示坦克的宽度 - /// - public double Width => 3.0; - - /// - /// 获取坦克的高度 - /// - /// - /// 单位:米 - /// 固定值2.5,表示坦克的高度 - /// - public double Height => 2.5; + public override TargetType Type => TargetType.Tank; /// /// 初始化坦克类的新实例 /// /// 坦克的唯一标识符 - /// 初始位置坐标 - /// 初始速度,单位:米/秒 + /// 初始运动参数 /// 仿真管理器实例 /// /// 构造函数设置坦克的初始状态: - /// - 使用默认朝向 - /// - 设置初始位置和速度 - /// - 生命值初始化为100 + /// - 调用基类构造函数初始化基本属性 /// - public Tank(string id, Vector3D position, double speed, ISimulationManager simulationManager) - : base(id, position, new Orientation(), speed, simulationManager) + public Tank(string id, InitialMotionParameters initialMotionParameters, ISimulationManager simulationManager) + : base(id, initialMotionParameters, simulationManager) { - // 初始化频谱特性 - UpdateSpectralSignature(); } /// @@ -105,51 +42,13 @@ namespace ThreatSource.Target /// 时间步长,单位:秒 /// /// 更新过程: - /// - 根据当前速度更新位置 - /// - 位置更新使用简单的线性运动模型 + /// - 调用基类的更新方法更新基本状态 + /// - 可以在此添加坦克特有的更新逻辑 /// public override void Update(double deltaTime) { - // 更新坦克的位置 - Position += Velocity * deltaTime; - - // 更新频谱特性 - UpdateSpectralSignature(); - } - - /// - /// 更新频谱特性的默认实现 - /// - /// - /// 提供坦克的频谱特性 - /// - protected override void UpdateSpectralSignature() - { - RadarCrossSection = 10.0; // 坦克RCS值 - InfraredRadiationIntensity = 500.0; // 坦克红外辐射强度 - UltravioletRadiationIntensity = 15.0; // 坦克紫外辐射强度 - MillimeterWaveRadiationIntensity = 10.0; // 坦克毫米波辐射强度 - MillimeterWaveRadiationTemperature = 400.0; // 坦克毫米波辐射温度 - LaserReflectivity = 0.3; // 坦克激光反射率 - } - - /// - /// 对坦克造成伤害 - /// - /// 伤害值 - /// - /// 伤害处理过程: - /// - 从当前生命值中扣除伤害值 - /// - 如果生命值降至0或以下,触发目标销毁事件 - /// - 销毁事件会通知仿真系统移除该目标 - /// - public void TakeDamage(double damage) - { - Health -= damage; - if (Health <= 0) - { - SimulationManager.PublishEvent(new TargetDestroyedEvent { TargetId = Id }); - } + base.Update(deltaTime); + // TODO: 添加坦克特有的更新逻辑 } } } \ No newline at end of file diff --git a/ThreatSource/src/Target/ThermalPattern.cs b/ThreatSource/src/Target/ThermalPattern.cs new file mode 100644 index 0000000..f9733b3 --- /dev/null +++ b/ThreatSource/src/Target/ThermalPattern.cs @@ -0,0 +1,250 @@ +using System; +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace ThreatSource.Target +{ + /// + /// 目标的温度分布模式 + /// + [JsonConverter(typeof(ThermalPatternConverter))] + public class ThermalPattern + { + /// + /// 温度分布矩阵的大小 + /// + public const int GRID_SIZE = 3; + + /// + /// 静止状态下的温度分布(摄氏度) + /// + public double[,] StaticPattern { get; } + + /// + /// 运动状态下的温度分布(摄氏度) + /// + public double[,] MovingPattern { get; } + + /// + /// 初始化温度分布模式 + /// + public ThermalPattern(double[,] staticPattern, double[,] movingPattern) + { + if (staticPattern.GetLength(0) != GRID_SIZE || staticPattern.GetLength(1) != GRID_SIZE) + throw new ArgumentException("Static pattern must be 3x3"); + if (movingPattern.GetLength(0) != GRID_SIZE || movingPattern.GetLength(1) != GRID_SIZE) + throw new ArgumentException("Moving pattern must be 3x3"); + + StaticPattern = staticPattern; + MovingPattern = movingPattern; + } + + /// + /// 获取指定状态下的温度分布 + /// + /// 目标是否在运动 + public double[,] GetPattern(bool isMoving) + { + return isMoving ? MovingPattern : StaticPattern; + } + + /// + /// 计算温度梯度特征 + /// + /// 目标是否在运动 + public double CalculateGradientFeature(bool isMoving) + { + var pattern = GetPattern(isMoving); + + // 计算发动机区域(右侧)平均温度 + double engineTemp = (pattern[1, 2] + pattern[2, 2]) / 2.0; + + // 计算前部区域(左侧)平均温度 + double frontTemp = (pattern[1, 0] + pattern[2, 0]) / 2.0; + + // 计算中部区域平均温度 + double middleTemp = pattern[1, 1]; + + // 计算上部区域平均温度 + double topTemp = pattern[0, 1]; + + // 计算整体平均温度 + double avgTemp = 0; + for (int i = 0; i < GRID_SIZE; i++) + for (int j = 0; j < GRID_SIZE; j++) + avgTemp += pattern[i, j]; + avgTemp /= (GRID_SIZE * GRID_SIZE); + + // 1. 发动机区域温度特征(相对于平均温度的比值) + double engineFeature = engineTemp / (avgTemp + 0.1); + + // 2. 前后温度梯度(考虑相对差异) + double frontBackGradient = (engineTemp - frontTemp) / (avgTemp + 0.1); + + // 3. 垂直温度梯度(发动机区域与上部的温度差异) + double verticalGradient = (engineTemp - topTemp) / (avgTemp + 0.1); + + // 4. 温度集中度(发动机区域相对于中部的温度差异) + double concentrationGradient = (engineTemp - middleTemp) / (avgTemp + 0.1); + + // 坦克特征权重 + double engineWeight = 0.4; // 发动机温度特征权重 + double frontBackWeight = 0.35; // 前后温度梯度权重 + double verticalWeight = 0.15; // 垂直温度梯度权重 + double concentrationWeight = 0.1; // 温度集中度权重 + + // 归一化并限制各个特征值 + engineFeature = Math.Min(engineFeature, 1.5) / 1.5; + frontBackGradient = Math.Min(Math.Max(frontBackGradient, 0), 1.0); + verticalGradient = Math.Min(Math.Max(verticalGradient, 0), 1.0); + concentrationGradient = Math.Min(Math.Max(concentrationGradient, 0), 1.0); + + // 计算最终得分 + return engineFeature * engineWeight + + frontBackGradient * frontBackWeight + + verticalGradient * verticalWeight + + concentrationGradient * concentrationWeight; + } + } + + /// + /// ThermalPattern的JSON转换器 + /// + public class ThermalPatternConverter : JsonConverter + { + /// + /// 读取ThermalPattern的JSON数据 + /// + /// JSON读取器 + /// 目标类型 + /// JSON序列化选项 + /// 解析后的ThermalPattern对象 + public override ThermalPattern Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + if (reader.TokenType != JsonTokenType.StartObject) + { + throw new JsonException("Expected StartObject token"); + } + + double[,] staticPattern = new double[ThermalPattern.GRID_SIZE, ThermalPattern.GRID_SIZE]; + double[,] movingPattern = new double[ThermalPattern.GRID_SIZE, ThermalPattern.GRID_SIZE]; + bool hasStatic = false; + bool hasMoving = false; + + while (reader.Read()) + { + if (reader.TokenType == JsonTokenType.EndObject) + { + break; + } + + if (reader.TokenType != JsonTokenType.PropertyName) + { + throw new JsonException("Expected PropertyName token"); + } + + string propertyName = reader.GetString()!; + + reader.Read(); // Move to the value + + switch (propertyName.ToLower()) + { + case "static": + ReadMatrix(ref reader, staticPattern); + hasStatic = true; + break; + case "moving": + ReadMatrix(ref reader, movingPattern); + hasMoving = true; + break; + default: + reader.Skip(); // Skip description or other properties + break; + } + } + + if (!hasStatic || !hasMoving) + { + throw new JsonException("Missing required static or moving pattern"); + } + + return new ThermalPattern(staticPattern, movingPattern); + } + + private static void ReadMatrix(ref Utf8JsonReader reader, double[,] matrix) + { + if (reader.TokenType != JsonTokenType.StartArray) + { + throw new JsonException("Expected StartArray token for matrix"); + } + + for (int i = 0; i < ThermalPattern.GRID_SIZE; i++) + { + reader.Read(); // Move to start of row array + if (reader.TokenType != JsonTokenType.StartArray) + { + throw new JsonException($"Expected StartArray token for row {i}"); + } + + for (int j = 0; j < ThermalPattern.GRID_SIZE; j++) + { + reader.Read(); // Move to number + if (reader.TokenType != JsonTokenType.Number) + { + throw new JsonException($"Expected Number token at position [{i},{j}]"); + } + matrix[i, j] = reader.GetDouble(); + } + + reader.Read(); // Move to end of row array + if (reader.TokenType != JsonTokenType.EndArray) + { + throw new JsonException($"Expected EndArray token for row {i}"); + } + } + + reader.Read(); // Move to end of matrix array + if (reader.TokenType != JsonTokenType.EndArray) + { + throw new JsonException("Expected EndArray token for matrix"); + } + } + + /// + /// 将ThermalPattern对象序列化为JSON字符串 + /// + /// JSON写入器 + /// 要序列化的ThermalPattern对象 + /// JSON序列化选项 + public override void Write(Utf8JsonWriter writer, ThermalPattern value, JsonSerializerOptions options) + { + writer.WriteStartObject(); + + writer.WritePropertyName("description"); + writer.WriteStringValue("3x3 matrix representing side view temperature distribution (°C)"); + + writer.WritePropertyName("static"); + WriteMatrix(writer, value.StaticPattern); + + writer.WritePropertyName("moving"); + WriteMatrix(writer, value.MovingPattern); + + writer.WriteEndObject(); + } + + private static void WriteMatrix(Utf8JsonWriter writer, double[,] matrix) + { + writer.WriteStartArray(); + for (int i = 0; i < ThermalPattern.GRID_SIZE; i++) + { + writer.WriteStartArray(); + for (int j = 0; j < ThermalPattern.GRID_SIZE; j++) + { + writer.WriteNumberValue(matrix[i, j]); + } + writer.WriteEndArray(); + } + writer.WriteEndArray(); + } + } +} \ No newline at end of file diff --git a/ThreatSource/src/Utils/Common.cs b/ThreatSource/src/Utils/Common.cs index 4217a89..35bcb09 100644 --- a/ThreatSource/src/Utils/Common.cs +++ b/ThreatSource/src/Utils/Common.cs @@ -133,15 +133,17 @@ namespace ThreatSource.Utils /// /// 向量相等运算符重载 /// - public static bool operator ==(Vector3D left, Vector3D right) + public static bool operator ==(Vector3D? left, Vector3D? right) { + if (ReferenceEquals(left, right)) return true; + if (left is null || right is null) return false; return left.X == right.X && left.Y == right.Y && left.Z == right.Z; } /// /// 向量不相等运算符重载 /// - public static bool operator !=(Vector3D left, Vector3D right) + public static bool operator !=(Vector3D? left, Vector3D? right) { return !(left == right); } diff --git a/ThreatSource/src/Utils/MotionAlgorithm.cs b/ThreatSource/src/Utils/MotionAlgorithm.cs index cf98ea8..055ad80 100644 --- a/ThreatSource/src/Utils/MotionAlgorithm.cs +++ b/ThreatSource/src/Utils/MotionAlgorithm.cs @@ -184,26 +184,47 @@ namespace ThreatSource.Utils /// 比例导引产生的加速度向量 /// /// 使用比例导引法计算制导加速度: + /// - 计算动态预测时间 /// - 预测目标未来位置 /// - 计算视线角速率 /// - 根据比例导引公式计算所需加速度 /// 加速度方向垂直于导弹速度方向。 /// - public static Vector3D CalculateProportionalNavigation(double proportionalNavigationCoefficient, Vector3D missilePosition, Vector3D missileVelocity, Vector3D targetPosition, Vector3D targetVelocity) + public static Vector3D CalculateProportionalNavigation(double proportionalNavigationCoefficient, + Vector3D missilePosition, Vector3D missileVelocity, + Vector3D targetPosition, Vector3D targetVelocity) { - // 预测时间(预测目标前进方向该时间后到达的位置,可以调整) - double predictionTime = 0.01; - + // 计算导弹到目标的距离 + Vector3D r = targetPosition - missilePosition; + double distance = r.Magnitude(); + + // 根据距离和相对速度动态计算预测时间 + Vector3D relativeVelocity = targetVelocity - missileVelocity; + double closingVelocity = -Vector3D.DotProduct(relativeVelocity, r.Normalize()); + + // 预测时间计算考虑: + // 1. 距离因素:距离越远,预测时间适当增加 + // 2. 接近速度因素:接近速度越大,预测时间适当减小 + // 3. 最小和最大限制:确保预测时间在合理范围内 + double predictionTime = Math.Clamp( + distance / (closingVelocity + 1e-6) * 0.1, // 基础预测时间(取时程的10%) + 0.05, // 最小预测时间:50ms + 0.5 // 最大预测时间:500ms + ); + // 预测目标位置 Vector3D predictedTargetPosition = targetPosition + targetVelocity * predictionTime; - - Vector3D r = predictedTargetPosition - missilePosition; + + // 计算视线矢量和视线变化率 + Vector3D LOS = (predictedTargetPosition - missilePosition).Normalize(); Vector3D v = targetVelocity - missileVelocity; + Vector3D LOSRate = (v - (LOS * Vector3D.DotProduct(v, LOS))) / distance; - Vector3D LOS = r.Normalize(); - Vector3D LOSRate = (v - (LOS * Vector3D.DotProduct(v, LOS))) / r.Magnitude(); - - Vector3D acceleration = Vector3D.CrossProduct(Vector3D.CrossProduct(LOS, LOSRate), missileVelocity.Normalize()) * proportionalNavigationCoefficient * missileVelocity.Magnitude(); + // 计算制导加速度 + Vector3D acceleration = Vector3D.CrossProduct( + Vector3D.CrossProduct(LOS, LOSRate), + missileVelocity.Normalize() + ) * proportionalNavigationCoefficient * missileVelocity.Magnitude(); return acceleration; } diff --git a/VERSION b/VERSION index 28af839..a53741c 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.2.5 \ No newline at end of file +0.2.6 \ No newline at end of file diff --git a/docs/articles/threat-source-spec.md b/docs/articles/threat-source-spec.md index 0e6733a..be8d054 100644 --- a/docs/articles/threat-source-spec.md +++ b/docs/articles/threat-source-spec.md @@ -1200,9 +1200,6 @@ graph TB #### 4.3.1 事件类型 1. 实体管理事件 - - EntityActivatedEvent:实体激活 - - EntityDeactivatedEvent:实体停用 - - EntityDestroyedEvent:实体销毁 - MissileFireEvent:导弹发射 2. 激光相关事件 diff --git a/docs/project/design.md b/docs/project/design.md new file mode 100644 index 0000000..0545c71 --- /dev/null +++ b/docs/project/design.md @@ -0,0 +1,62 @@ +# 威胁源仿真库设计文档 + +## 接口设计 + +### 核心接口继承关系 + +```mermaid +classDiagram + ISimulationElement <|-- ITarget + ISpectralCharacteristics <|-- ITarget + ISimulationElement <|.. SimulationElement + ISpectralCharacteristics <|.. SimulationElement + SimulationElement <|-- Tank + ITarget <|.. Tank + + class ISimulationElement { + +string Id + +Vector3D Position + +Vector3D Velocity + +double Speed + +Orientation Orientation + +bool IsActive + +Update(deltaTime) + +Activate() + +Deactivate() + +GetStatus() + } + + class ISpectralCharacteristics { + +double RadarCrossSection + +double InfraredRadiationIntensity + +double UltravioletRadiationIntensity + +double MillimeterWaveRadiationIntensity + } + + class ITarget { + +string Type + +double MillimeterWaveRadiationTemperature + +double LaserReflectivity + +double Length + +double Width + +double Height + +double Health + } +``` + +### 设计说明 + +1. **接口分层** + - `ISimulationElement`: 定义所有仿真元素的基本行为,包括位置、运动状态和生命周期管理 + - `ISpectralCharacteristics`: 定义实体的频谱特性,包括雷达散射截面积、红外辐射等 + - `ITarget`: 继承上述两个接口,并添加目标特有的属性(尺寸、生命值等) + +2. **实现层次** + - `SimulationElement`: 抽象基类,实现 `ISimulationElement` 和 `ISpectralCharacteristics` 的基本功能 + - `Tank`: 继承 `SimulationElement` 并实现 `ITarget` 接口,获得基类功能的同时实现目标特有的属性和行为 + +3. **设计优势** + - 接口隔离:将不同职责的功能分散到不同接口中 + - 代码复用:通用功能在 `SimulationElement` 中实现 + - 扩展性:新的实体类型可以方便地接入系统 + - 维护性:频谱特性的修改只需要关注 `ISpectralCharacteristics` 接口 diff --git a/tools/ComprehensiveMissileSimulator.cs b/tools/ComprehensiveMissileSimulator.cs index 87b767a..6c55c06 100644 --- a/tools/ComprehensiveMissileSimulator.cs +++ b/tools/ComprehensiveMissileSimulator.cs @@ -11,6 +11,7 @@ using ThreatSource.Sensor; using ThreatSource.Target; using ThreatSource.Guidance; using ThreatSource.Indicator; +using ThreatSource.Data; namespace ThreatSource.Tools.MissileSimulation { @@ -23,6 +24,8 @@ namespace ThreatSource.Tools.MissileSimulation public event EventHandler? SimulationEnded; private readonly ISimulationManager simulationManager; + private readonly ThreatSourceFactory _threatSourceFactory; + private readonly ThreatSourceDataManager _dataManager; private readonly Dictionary missiles; private readonly Dictionary targets; private readonly Dictionary indicators; @@ -35,6 +38,8 @@ namespace ThreatSource.Tools.MissileSimulation public ComprehensiveMissileSimulator() { simulationManager = new SimulationManager(); + _dataManager = new ThreatSourceDataManager(); + _threatSourceFactory = new ThreatSourceFactory(_dataManager, simulationManager); missiles = new Dictionary(); targets = new Dictionary(); indicators = new Dictionary(); @@ -48,7 +53,7 @@ namespace ThreatSource.Tools.MissileSimulation private void InitializeSimulation() { // 添加目标(坦克) - AddTarget("Tank_1", new Vector3D(0, 0, 0)); + AddTankTarget(); // 添加各种类型的导弹 AddLaserSemiActiveMissile(); @@ -65,15 +70,19 @@ namespace ThreatSource.Tools.MissileSimulation /// /// 添加目标 /// - private void AddTarget(string targetId, Vector3D position) + private void AddTankTarget() { - var target = new Tank(targetId, position, 0, simulationManager) + var launchParams = new InitialMotionParameters { - Position = position + Position = new Vector3D(0, 0, 0), + Orientation = new Orientation(Math.PI, 0.0, 0.0), + InitialSpeed = 0 }; + string targetId = "Tank_1"; + var target = _threatSourceFactory.CreateTarget(targetId, "mbt_001", launchParams); targets[targetId] = target; simulationManager.RegisterEntity(targetId, target); - Console.WriteLine($"添加目标 {targetId},位置:{position}"); + Console.WriteLine($"添加目标 {targetId},位置:{launchParams.Position}"); } /// @@ -81,27 +90,17 @@ namespace ThreatSource.Tools.MissileSimulation /// private void AddLaserSemiActiveMissile() { - var properties = new MissileProperties + var launchParams = new InitialMotionParameters { - Id = "LSGM_1", - Mass = 50, - ExplosionRadius = 5, - MaxSpeed = 800, - MaxFlightTime = 10, - MaxFlightDistance = 5000, - MaxAcceleration = 400, - InitialPosition = new Vector3D(2000, 100, 100), - InitialSpeed = 700, - InitialOrientation = new Orientation(Math.PI, -0.05, 0), - ProportionalNavigationCoefficient = 3, - SelfDestructHeight = 0, - Type = MissileType.LaserSemiActiveGuidance + Position = new Vector3D(2000, 10, 100), + Orientation = new Orientation(Math.PI, -0.05, 0), + InitialSpeed = 700 }; - - var missile = new LaserSemiActiveGuidedMissile(properties, simulationManager); - missiles["LSGM_1"] = missile; - simulationManager.RegisterEntity("LSGM_1", missile); - Console.WriteLine($"注册激光半主动制导导弹 LSGM_1"); + string missileId = "LSGM_1"; + var missile = _threatSourceFactory.CreateMissile(missileId, "lsgm_001", "Tank_1", launchParams); + missiles[missileId] = missile; + simulationManager.RegisterEntity(missileId, missile); + Console.WriteLine($"注册激光半主动制导导弹 {missileId}"); } /// @@ -109,27 +108,17 @@ namespace ThreatSource.Tools.MissileSimulation /// private void AddLaserBeamRiderMissile() { - var properties = new MissileProperties + var launchParams = new InitialMotionParameters { - Id = "LBRM_1", - Mass = 50, - ExplosionRadius = 5, - MaxSpeed = 400, - MaxFlightTime = 10, - MaxFlightDistance = 3000, - MaxAcceleration = 400, - InitialPosition = new Vector3D(2000, 10, 100), - InitialSpeed = 300, - InitialOrientation = new Orientation(Math.PI, 0.0, 0.0), - ProportionalNavigationCoefficient = 3, - SelfDestructHeight = 0, - Type = MissileType.LaserBeamRiderGuidance + Position = new Vector3D(2000, 10, 100), + Orientation = new Orientation(Math.PI, 0.0, 0.0), + InitialSpeed = 300 }; - - var missile = new LaserBeamRiderMissile(properties, simulationManager); - missiles["LBRM_1"] = missile; - simulationManager.RegisterEntity("LBRM_1", missile); - Console.WriteLine($"注册激光驾束制导导弹 LBRM_1"); + string missileId = "LBRM_1"; + var missile = _threatSourceFactory.CreateMissile(missileId, "hj10", "Tank_1", launchParams); + missiles[missileId] = missile; + simulationManager.RegisterEntity(missileId, missile); + Console.WriteLine($"注册激光驾束制导导弹 {missileId}"); } /// @@ -137,40 +126,19 @@ namespace ThreatSource.Tools.MissileSimulation /// private void AddTerminalSensitiveMissile() { - var properties = new MissileProperties + var launchParams = new InitialMotionParameters { - Id = "TSM_1", - Mass = 50, - ExplosionRadius = 5, - MaxSpeed = 1000, - MaxFlightTime = 100, - MaxFlightDistance = 5000, - MaxAcceleration = 200, - InitialPosition = new Vector3D(3000, 0, 0), - InitialSpeed = 800, - InitialOrientation = new Orientation(Math.PI, 0, 0), - SelfDestructHeight = 0, - Type = MissileType.TerminalSensitiveMissile + Position = new Vector3D(3000, 0, 100), + Orientation = new Orientation(Math.PI, 0, 0), + InitialSpeed = 800 }; - var submunitionProperties = new MissileProperties - { - MaxSpeed = 2000, - MaxFlightTime = 60, - MaxFlightDistance = 2000, - MaxAcceleration = 300, - ProportionalNavigationCoefficient = 4, - Mass = 10, - ExplosionRadius = 5, - HitProbability = 0.9, - SelfDestructHeight = 20, - Type = MissileType.TerminalSensitiveSubmunition - }; + string missileId = "TSM_1"; + var missile = _threatSourceFactory.CreateMissile(missileId, "tsm_001", "Tank_1", launchParams); - var missile = new TerminalSensitiveMissile("Tank_1", properties, submunitionProperties, 1, simulationManager); - missiles["TSM_1"] = missile; - simulationManager.RegisterEntity("TSM_1", missile); - Console.WriteLine($"注册末敏弹 TSM_1"); + missiles[missileId] = missile; + simulationManager.RegisterEntity(missileId, missile); + Console.WriteLine($"注册末敏弹 {missileId}"); } /// @@ -178,27 +146,18 @@ namespace ThreatSource.Tools.MissileSimulation /// private void AddInfraredCommandMissile() { - var properties = new MissileProperties + var launchParams = new InitialMotionParameters { - Id = "ICGM_1", - Mass = 50, - ExplosionRadius = 5, - MaxSpeed = 400, - MaxFlightTime = 60, - MaxFlightDistance = 2100, - MaxAcceleration = 100, - InitialPosition = new Vector3D(2000, 10, 100), - InitialSpeed = 300, - InitialOrientation = new Orientation(Math.PI, 0.0, 0), - ProportionalNavigationCoefficient = 3, - SelfDestructHeight = 0, - Type = MissileType.InfraredCommandGuidance + Position = new Vector3D(2000, 10, 100), + Orientation = new Orientation(Math.PI, 0.0, 0), + InitialSpeed = 300 }; - var missile = new InfraredCommandGuidedMissile(properties, simulationManager); - missiles["ICGM_1"] = missile; - simulationManager.RegisterEntity("ICGM_1", missile); - Console.WriteLine($"注册红外指令制导导弹 ICGM_1"); + string missileId = "ICGM_1"; + var missile = _threatSourceFactory.CreateMissile(missileId, "irc_001", "Tank_1", launchParams); + missiles[missileId] = missile; + simulationManager.RegisterEntity(missileId, missile); + Console.WriteLine($"注册红外指令制导导弹 {missileId}"); } /// @@ -206,27 +165,17 @@ namespace ThreatSource.Tools.MissileSimulation /// private void AddInfraredImagingMissile() { - var properties = new MissileProperties + var launchParams = new InitialMotionParameters { - Id = "ITGM_1", - Mass = 50, - ExplosionRadius = 5, - MaxSpeed = 400, - MaxFlightTime = 60, - MaxFlightDistance = 5000, - MaxAcceleration = 50, - InitialPosition = new Vector3D(2000, 20, 100), - InitialSpeed = 300, - InitialOrientation = new Orientation(Math.PI, 0.0, 0), - SelfDestructHeight = 0, - ProportionalNavigationCoefficient = 3, - Type = MissileType.InfraredImagingTerminalGuidance + Position = new Vector3D(2000, 20, 50), + Orientation = new Orientation(Math.PI, 0.0, 0), + InitialSpeed = 300 }; - - var missile = new InfraredImagingTerminalGuidedMissile(properties, simulationManager); - missiles["ITGM_1"] = missile; - simulationManager.RegisterEntity("ITGM_1", missile); - Console.WriteLine($"注册红外成像末制导导弹 ITGM_1"); + string missileId = "ITGM_1"; + var missile = _threatSourceFactory.CreateMissile(missileId, "itg_001", "Tank_1", launchParams); + missiles[missileId] = missile; + simulationManager.RegisterEntity(missileId, missile); + Console.WriteLine($"注册红外成像末制导导弹 {missileId}"); } /// @@ -234,27 +183,17 @@ namespace ThreatSource.Tools.MissileSimulation /// private void AddMillimeterWaveMissile() { - var properties = new MissileProperties + var launchParams = new InitialMotionParameters { - Id = "MMWG_1", - Mass = 50, - ExplosionRadius = 5, - MaxSpeed = 400, - MaxFlightTime = 60, - MaxFlightDistance = 5000, - MaxAcceleration = 50, - InitialPosition = new Vector3D(2000, 200, 100), - InitialSpeed = 300, - InitialOrientation = new Orientation(Math.PI, 0.0, 0), - SelfDestructHeight = 0, - ProportionalNavigationCoefficient = 3, - Type = MissileType.MillimeterWaveTerminalGuidance - }; - - var missile = new MillimeterWaveTerminalGuidedMissile(properties, simulationManager); - missiles["MMWG_1"] = missile; - simulationManager.RegisterEntity("MMWG_1", missile); - Console.WriteLine($"注册毫米波末制导导弹 MMWG_1"); + Position = new Vector3D(2000, 20, 100), + Orientation = new Orientation(Math.PI, 0.0, 0), + InitialSpeed = 300 + }; + string missileId = "MMWG_1"; + var missile = _threatSourceFactory.CreateMissile(missileId, "mmw_001", "Tank_1", launchParams); + missiles[missileId] = missile; + simulationManager.RegisterEntity(missileId, missile); + Console.WriteLine($"注册毫米波末制导导弹 {missileId}"); } /// @@ -263,62 +202,43 @@ namespace ThreatSource.Tools.MissileSimulation private void AddSensorsAndDesignators() { // 添加激光目标指示器 - var laserDesignator = new LaserDesignator( - "LD_1", - "Tank_1", - "LSGM_1", - 0, - new LaserDesignatorConfig - { - Id = "LD_1", - InitialPosition = new Vector3D(2000, 150, 100), - LaserPower = 1000, - LaserDivergenceAngle = 0.001 - }, - simulationManager - ); - indicators["LD_1"] = laserDesignator; - simulationManager.RegisterEntity("LD_1", laserDesignator); - Console.WriteLine("注册激光目标指示器 LD_1"); + string laserDesignatorId = "LD_1"; + var laserDesignatorLaunchParams = new InitialMotionParameters + { + Position = new Vector3D(2100, 10, 100), + Orientation = new Orientation(Math.PI, 0, 0), + InitialSpeed = 0 + }; + var laserDesignator = _threatSourceFactory.CreateIndicator(laserDesignatorId, "ld_001", "Tank_1", "LSGM_1", laserDesignatorLaunchParams); + indicators[laserDesignatorId] = (SimulationElement)laserDesignator; + simulationManager.RegisterEntity(laserDesignatorId, laserDesignator); + Console.WriteLine($"注册激光目标指示器 {laserDesignatorId}"); // 添加激光驾束仪 - var laserBeamRider = new LaserBeamRider( - "LBR_1", - "LBRM_1", - "Tank_1", - 0, - new LaserBeamRiderConfig - { - Id = "LBR_1", - InitialPosition = new Vector3D(2000, 10, 100), - LaserPower = 1000, - ControlFieldDiameter = 6 - }, - simulationManager - ); - indicators["LBR_1"] = laserBeamRider; - simulationManager.RegisterEntity("LBR_1", laserBeamRider); - Console.WriteLine("注册激光驾束仪 LBR_1"); + string laserBeamRiderId = "LBR_1"; + var laserBeamRiderLaunchParams = new InitialMotionParameters + { + Position = new Vector3D(2100, 10, 100), + Orientation = new Orientation(Math.PI, 0, 0), + InitialSpeed = 0 + }; + var laserBeamRider = _threatSourceFactory.CreateIndicator(laserBeamRiderId, "br_001", "Tank_1", "LBRM_1", laserBeamRiderLaunchParams); + indicators[laserBeamRiderId] = (SimulationElement)laserBeamRider; + simulationManager.RegisterEntity(laserBeamRiderId, laserBeamRider); + Console.WriteLine($"注册激光驾束仪 {laserBeamRiderId}"); // 添加红外测角仪 - var infraredTracker = new InfraredTracker( - "IT_1", - "Tank_1", - new InfraredTrackerConfig - { - Id = "IT_1", - InitialPosition = new Vector3D(2000, 0, 100), - InitialOrientation = new Orientation(Math.PI, 0, 0), - MaxTrackingRange = 10000, - FieldOfView = Math.PI / 4, - AngleMeasurementAccuracy = 0.0005, - UpdateFrequency = 100 - }, - simulationManager - ); - indicators["IT_1"] = infraredTracker; - simulationManager.RegisterEntity("IT_1", infraredTracker); - Console.WriteLine("注册红外测角仪 IT_1"); + string infraredTrackerId = "IT_1"; + var infraredTrackerLaunchParams = new InitialMotionParameters + { + Position = new Vector3D(2100, 10, 100), + Orientation = new Orientation(Math.PI, 0, 0), + InitialSpeed = 0 + }; + var infraredTracker = _threatSourceFactory.CreateIndicator(infraredTrackerId, "ir_001", "Tank_1", "ITGM_1", infraredTrackerLaunchParams); + indicators[infraredTrackerId] = (SimulationElement)infraredTracker; + simulationManager.RegisterEntity(infraredTrackerId, infraredTracker); + Console.WriteLine($"注册红外测角仪 {infraredTrackerId}"); } /// @@ -383,12 +303,12 @@ namespace ThreatSource.Tools.MissileSimulation } break; case "ICGM_1": // 红外指令制导导弹 - case "ITGM_1": // 红外成像末制导导弹 if (indicators.ContainsKey("IT_1")) { indicators["IT_1"].Activate(); } break; + case "ITGM_1": // 红外成像末制导导弹 case "TSM_1": // 末敏弹 case "MMWG_1": // 毫米波末制导导弹 // 这些导弹使用自身的传感器系统 @@ -594,14 +514,14 @@ namespace ThreatSource.Tools.MissileSimulation foreach (var missile in activeMissiles) { // 获取导弹的初始属性 - var properties = missile.GetType().GetField("properties", + var launchParams = missile.GetType().GetField("launchParams", System.Reflection.BindingFlags.NonPublic | - System.Reflection.BindingFlags.Instance)?.GetValue(missile) as MissileProperties; + System.Reflection.BindingFlags.Instance)?.GetValue(missile) as InitialMotionParameters; - if (properties != null) + if (launchParams != null) { // 重置导弹位置和状态 - missile.Position = properties.InitialPosition; + missile.Position = launchParams.Position; missile.Velocity = Vector3D.Zero; } missile.Deactivate();