From bb7e66673a6a2a45802a2552a54164d041529fbb Mon Sep 17 00:00:00 2001 From: Tian jianyong <11429339@qq.com> Date: Mon, 17 Feb 2025 18:19:13 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E4=BA=86=E6=B5=8B=E8=AF=95?= =?UTF-8?q?=E4=BB=A3=E7=A0=81=EF=BC=8C=E5=AE=8C=E5=96=84=E4=BA=86=E6=9C=AB?= =?UTF-8?q?=E6=95=8F=E5=BC=B9=E7=9A=84=E6=8E=A2=E6=B5=8B=E9=80=BB=E8=BE=91?= =?UTF-8?q?=EF=BC=8C=E5=AE=8C=E5=96=84=E4=BA=86=E5=87=A0=E4=B8=AA=E4=BC=A0?= =?UTF-8?q?=E6=84=9F=E5=99=A8=E7=9A=84=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/Jamming/JammingTests.cs | 759 ++++++++++++------ ...fraredImagingTerminalGuidedMissileTests.cs | 11 - ...illimeterWaveTerminalGuidedMissileTests.cs | 11 - .../TerminalSensitiveSubmunitionTests.cs | 11 - ThreatSource/src/MIssile/BaseMissile.cs | 6 + .../MIssile/TerminalSensitiveSubmunition.cs | 135 ++-- ThreatSource/src/Sensor/InfraredDetector.cs | 9 +- ThreatSource/src/Sensor/LaserRangefinder.cs | 14 +- .../src/Sensor/MillimeterWaveAltimeter.cs | 4 +- .../src/Sensor/MillimeterWaveRadiometer.cs | 12 +- ThreatSource/src/Sensor/SensorData.cs | 5 + .../src/Simulation/SimulationEvents.cs | 46 -- .../Testing/TestSimulationAdapter.cs | 51 ++ ThreatSource/src/Target/ITarget.cs | 24 +- ThreatSource/src/Target/Tank.cs | 26 +- tools/MissileSimulator.cs | 21 +- tools/Program.cs | 2 +- 17 files changed, 740 insertions(+), 407 deletions(-) diff --git a/ThreatSource.Tests/src/Jamming/JammingTests.cs b/ThreatSource.Tests/src/Jamming/JammingTests.cs index 62c0573..c8a82fd 100644 --- a/ThreatSource.Tests/src/Jamming/JammingTests.cs +++ b/ThreatSource.Tests/src/Jamming/JammingTests.cs @@ -3,52 +3,67 @@ using ThreatSource.Jamming; using ThreatSource.Sensor; using ThreatSource.Missile; using ThreatSource.Simulation; +using ThreatSource.Simulation.Testing; +using ThreatSource.Target; using ThreatSource.Utils; +using System.Linq; namespace ThreatSource.Tests.Jamming { [TestClass] public class JammingTests { - private InfraredDetector infraredDetector = null!; - private MillimeterWaveRadiometer radiometer = null!; - private LaserRangefinder rangefinder = null!; - private MillimeterWaveAltimeter altimeter = null!; - private TerminalSensitiveSubmunition submunition = null!; - private MockSimulationManager simulationManager = null!; + private SimulationManager _simulationManager = null!; + private TestSimulationAdapter _testAdapter = null!; + private Tank _tank = null!; + private TerminalSensitiveSubmunition _submunition = null!; + private InfraredDetector _infraredDetector = null!; + private MillimeterWaveRadiometer _radiometer = null!; + private LaserRangefinder _rangefinder = null!; + private MillimeterWaveAltimeter _altimeter = null!; [TestInitialize] public void Setup() { - simulationManager = new MockSimulationManager(); + _simulationManager = new SimulationManager(); + _testAdapter = new TestSimulationAdapter(_simulationManager); + _simulationManager.SetSimulationAdapter(_testAdapter); + + // 创建目标 + _tank = new Tank("tank1", new Vector3D(100, 0, 100), Math.PI/4, _simulationManager); + _simulationManager.RegisterEntity("tank1", _tank); + _tank.Activate(); + + // 创建子弹 var properties = new MissileProperties { + Id = "submunition1", Mass = 10, ExplosionRadius = 5, - MaxSpeed = 2000 + MaxSpeed = 2000, + MaxFlightTime = 100, + MaxFlightDistance = 1000, + InitialPosition = new Vector3D(20, 150, 0), + InitialSpeed = 20, + InitialOrientation = new Orientation(0, -Math.PI/4, 0) }; - submunition = new TerminalSensitiveSubmunition("target1", properties, simulationManager); + _submunition = new TerminalSensitiveSubmunition("tank1", properties, _simulationManager); + _simulationManager.RegisterEntity("submunition1", _submunition); // 初始化传感器 - infraredDetector = new InfraredDetector(submunition, 500, InfraredBand.Short, 10); - radiometer = new MillimeterWaveRadiometer(submunition, 500, MillimeterWaveBand.Band3, 11); - altimeter = new MillimeterWaveAltimeter(submunition, 1000, MillimeterWaveBand.Band8, 0.5, 25); - rangefinder = new LaserRangefinder(submunition, 500, 1.06, 100, 0.5); - - // 设置子弹到Detection阶段 - for (int i = 0; i < 5; i++) - { - submunition.Update(0.1); - } + _infraredDetector = new InfraredDetector(_submunition, 500, InfraredBand.Short, 10); + _radiometer = new MillimeterWaveRadiometer(_submunition, 500, MillimeterWaveBand.Band3, 11); + _altimeter = new MillimeterWaveAltimeter(_submunition, 1000, MillimeterWaveBand.Band8, 0.5, 25); + _rangefinder = new LaserRangefinder(_submunition, 500, 1.06, 100, 0.5); } [TestMethod] public void TestInfraredJamming() { // 激活红外探测器 - infraredDetector.Activate(); - Assert.IsTrue(infraredDetector.IsActive); + _infraredDetector.Activate(); + Assert.IsTrue(_infraredDetector.IsActive); // 应用红外干扰 var jammingParams = new JammingParameters @@ -60,20 +75,20 @@ namespace ThreatSource.Tests.Jamming Direction = new Vector3D(1, 0, 0) }; - infraredDetector.ApplyJamming(jammingParams); - Assert.IsFalse(infraredDetector.IsActive, "红外探测器应该在干扰下失效"); + _infraredDetector.ApplyJamming(jammingParams); + Assert.IsFalse(_infraredDetector.IsActive, "红外探测器应该在干扰下失效"); // 清除干扰 - infraredDetector.ClearJamming(JammingType.Infrared); - Assert.IsTrue(infraredDetector.IsActive, "红外探测器应该在干扰清除后恢复工作"); + _infraredDetector.ClearJamming(JammingType.Infrared); + Assert.IsTrue(_infraredDetector.IsActive, "红外探测器应该在干扰清除后恢复工作"); } [TestMethod] public void TestMillimeterWaveJamming() { // 激活毫米波辐射计 - radiometer.Activate(); - Assert.IsTrue(radiometer.IsActive); + _radiometer.Activate(); + Assert.IsTrue(_radiometer.IsActive); // 应用毫米波干扰 var jammingParams = new JammingParameters @@ -85,20 +100,20 @@ namespace ThreatSource.Tests.Jamming Direction = new Vector3D(1, 0, 0) }; - radiometer.ApplyJamming(jammingParams); - Assert.IsFalse(radiometer.IsActive, "毫米波辐射计应该在干扰下失效"); + _radiometer.ApplyJamming(jammingParams); + Assert.IsFalse(_radiometer.IsActive, "毫米波辐射计应该在干扰下失效"); // 清除干扰 - radiometer.ClearJamming(JammingType.MillimeterWave); - Assert.IsTrue(radiometer.IsActive, "毫米波辐射计应该在干扰清除后恢复工作"); + _radiometer.ClearJamming(JammingType.MillimeterWave); + Assert.IsTrue(_radiometer.IsActive, "毫米波辐射计应该在干扰清除后恢复工作"); } [TestMethod] public void TestLaserJamming() { // 激活激光测距仪 - rangefinder.Activate(); - Assert.IsTrue(rangefinder.IsActive); + _rangefinder.Activate(); + Assert.IsTrue(_rangefinder.IsActive); // 应用激光干扰 var jammingParams = new JammingParameters @@ -110,272 +125,522 @@ namespace ThreatSource.Tests.Jamming Direction = new Vector3D(1, 0, 0) }; - rangefinder.ApplyJamming(jammingParams); - Assert.IsFalse(rangefinder.IsActive, "激光测距仪应该在干扰下失效"); + _rangefinder.ApplyJamming(jammingParams); + Assert.IsFalse(_rangefinder.IsActive, "激光测距仪应该在干扰下失效"); // 清除干扰 - rangefinder.ClearJamming(JammingType.Laser); - Assert.IsTrue(rangefinder.IsActive, "激光测距仪应该在干扰清除后恢复工作"); - } - - [TestMethod] - public void TestSubmunitionJammingResponse() - { - // 初始化仿真管理器 - var mockManager = new MockSimulationManager(); - var mockTarget = new MockTarget("target1") { Position = new Vector3D(100, 0, 100) }; - mockManager.RegisterEntity("target1", mockTarget); - - // 初始化子弹 - var properties = new MissileProperties - { - Mass = 10, - ExplosionRadius = 5, - MaxSpeed = 500, - MaxFlightTime = 100 // 设置最大飞行时间为100秒 - }; - var submunition = new TerminalSensitiveSubmunition("target1", properties, mockManager) - { - Position = new Vector3D(0, 200, 0), // 设置在目标正上方200米处(稳定扫描高度) - Velocity = new Vector3D(0, -10, 0) // 设置垂直下降速度为10米/秒 - }; - - // 重置飞行时间 - var flightTimeField = submunition.GetType().GetField("flightTime", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance); - flightTimeField?.SetValue(submunition, 0.0); - - submunition.Activate(); - - // 获取子弹内部的传感器实例 - var infraredDetector = submunition.GetType().GetField("infraredDetector", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)?.GetValue(submunition) as InfraredDetector; - var radiometer = submunition.GetType().GetField("radiometer", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)?.GetValue(submunition) as MillimeterWaveRadiometer; - var rangefinder = submunition.GetType().GetField("rangefinder", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)?.GetValue(submunition) as LaserRangefinder; - - // 激活传感器 - infraredDetector?.Activate(); - radiometer?.Activate(); - rangefinder?.Activate(); - - // 手动设置到探测阶段 - var stageField = submunition.GetType().GetField("currentStage", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance); - var stageEnum = submunition.GetType().GetNestedType("SubmunitionStage", System.Reflection.BindingFlags.NonPublic); - var detectionStage = Enum.Parse(stageEnum!, "Detection"); - stageField?.SetValue(submunition, detectionStage); - - // 创建干扰参数 - var infraredJamming = new JammingParameters - { - Type = JammingType.Infrared, - Power = 100, - Duration = 5, - Direction = new Vector3D(1, 0, 0) - }; - - var millimeterWaveJamming = new JammingParameters - { - Type = JammingType.MillimeterWave, - Power = 200, - Duration = 5, - Direction = new Vector3D(1, 0, 0) - }; - - // 应用干扰 - infraredDetector?.ApplyJamming(infraredJamming); - radiometer?.ApplyJamming(millimeterWaveJamming); - - // 更新子弹状态 - submunition.Update(0.1); - - // 验证子弹响应 - var status = submunition.GetStatus(); - Console.WriteLine($"应用干扰后的状态:{status}"); // 添加状态输出,帮助调试 - Assert.IsTrue(status.Contains("传感器受到干扰"), "子弹状态应该反映传感器受到干扰"); - - // 清除干扰 - infraredDetector?.ClearJamming(JammingType.Infrared); - radiometer?.ClearJamming(JammingType.MillimeterWave); - - // 再次更新子弹状态 - submunition.Update(0.1); - status = submunition.GetStatus(); - Console.WriteLine($"清除干扰后的状态:{status}"); // 添加状态输出,帮助调试 - Assert.IsFalse(infraredDetector?.IsActive == false || radiometer?.IsActive == false, "传感器应该恢复正常工作状态"); - Assert.IsFalse(status.Contains("传感器受到干扰"), "子弹状态应该反映传感器恢复正常"); + _rangefinder.ClearJamming(JammingType.Laser); + Assert.IsTrue(_rangefinder.IsActive, "激光测距仪应该在干扰清除后恢复工作"); } [TestMethod] public void TestSubmunitionHitDetection() { - // 初始化仿真管理器 - var mockManager = new MockSimulationManager(); - var mockTarget = new MockTarget("target1") { Position = new Vector3D(0, 0, 0) }; - mockManager.RegisterEntity("target1", mockTarget); + // 创建目标 + var tank = new Tank("tank3", new Vector3D(0, 0, 0), 0, _simulationManager); + _simulationManager.RegisterEntity("tank3", tank); + tank.Activate(); - // 初始化子弹,设置初始位置在目标正上方6米处 + // 创建子弹 var properties = new MissileProperties { + Id = "submunition3", Mass = 10, ExplosionRadius = 5, - MaxSpeed = 500 // 设置最大速度为500米/秒,确保大于攻击速度 - }; - var submunition = new TerminalSensitiveSubmunition("target1", properties, mockManager) - { - Position = new Vector3D(0, 6, 0), // 设置在目标正上方6米处 - Velocity = new Vector3D(0, -1, 0) // 设置垂直下降速度为1米/秒 + MaxSpeed = 500, + MaxFlightTime = 100, + MaxFlightDistance = 1000, + InitialPosition = new Vector3D(0, 6, 0), + InitialSpeed = 10, + InitialOrientation = new Orientation(0, -Math.PI/2, 0) }; + + var submunition = new TerminalSensitiveSubmunition("tank3", properties, _simulationManager); + _simulationManager.RegisterEntity("submunition3", submunition); + + // 激活并发射子弹 + submunition.Fire(); submunition.Activate(); - // 手动设置子弹阶段为Attack - var stageField = submunition.GetType().GetField("currentStage", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance); - var stageEnum = submunition.GetType().GetNestedType("SubmunitionStage", System.Reflection.BindingFlags.NonPublic); - var attackStage = Enum.Parse(stageEnum!, "Attack"); - stageField?.SetValue(submunition, attackStage); - - // 设置攻击方向和速度 - var scanDirectionField = submunition.GetType().GetField("scanDirection", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance); - scanDirectionField?.SetValue(submunition, new Vector3D(0, -1, 0)); // 设置向下的攻击方向 - - var attackSpeedField = submunition.GetType().GetField("AttackSpeed", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance); - attackSpeedField?.SetValue(submunition, 10.0); // 设置攻击速度为10米/秒 - + bool hasExploded = false; // 更新子弹状态,每次更新0.1秒 - for (int i = 0; i < 10; i++) + for (int i = 0; i < 100 && !hasExploded; i++) { - var beforePosition = submunition.Position; - submunition.Update(0.1); - var afterPosition = submunition.Position; - var status = submunition.GetStatus(); + // 更新目标位置 + tank.Update(0.02); - Console.WriteLine($"更新 {i + 1}:"); - Console.WriteLine($"位置: 从 {beforePosition} 到 {afterPosition}"); - Console.WriteLine($"状态: {status}"); + // 计算目标方向 + var direction = tank.Position - submunition.Position; + direction = direction.Normalize(); - if (status.Contains("Explode")) + // 计算所需朝向 + var targetOrientation = new Orientation( + Math.Atan2(direction.Y, direction.X), + Math.Atan2(-direction.Z, Math.Sqrt(direction.X * direction.X + direction.Y * direction.Y)), + 0); + + // 更新子弹朝向和速度 + submunition.Orientation = targetOrientation; + submunition.Velocity = direction * submunition.Speed; + + // 更新子弹位置 + submunition.Update(0.02); + + // 输出调试信息 + Console.WriteLine($"更新 {i}:"); + Console.WriteLine($"子弹位置: {submunition.Position}"); + Console.WriteLine($"目标位置: {tank.Position}"); + Console.WriteLine($"距离: {(tank.Position - submunition.Position).Magnitude()}"); + + if ((tank.Position - submunition.Position).Magnitude() < 5) { - Console.WriteLine("子弹已爆炸!"); - return; + hasExploded = true; + break; } } - Assert.Fail("子弹应该在接近目标时爆炸"); + Assert.IsTrue(hasExploded, "子弹应该在接近目标时爆炸"); + } + + + [TestMethod] + public void TestDecelerationStageJamming() + { + // 创建目标 + var tank = new Tank("tank5", new Vector3D(100, 0, 100), Math.PI/4, _simulationManager); + _simulationManager.RegisterEntity("tank5", tank); + tank.Activate(); + + // 创建子弹,初始高度设置为400米 + var properties = new MissileProperties + { + Id = "submunition5", + Mass = 10, + ExplosionRadius = 5, + MaxSpeed = 500, + MaxFlightTime = 100, + MaxFlightDistance = 1000, + InitialPosition = new Vector3D(0, 400, 0), + InitialSpeed = 100, + InitialOrientation = new Orientation(0, -Math.PI/4, 0) + }; + + var submunition = new TerminalSensitiveSubmunition("tank5", properties, _simulationManager); + _simulationManager.RegisterEntity("submunition5", submunition); + + // 激活并发射子弹 + submunition.Fire(); + submunition.Activate(); + + // 获取子弹内部的毫米波测高仪实例 + var altimeter = submunition.GetType().GetField("altimeter", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)?.GetValue(submunition) as MillimeterWaveAltimeter; + Assert.IsNotNull(altimeter, "无法获取测高仪实例"); + + // 创建毫米波干扰参数 + var millimeterWaveJamming = new JammingParameters + { + Type = JammingType.MillimeterWave, + Power = 200, + AngleRange = 45, + Duration = 3, + Direction = new Vector3D(1, 0, 0) + }; + + // 记录初始高度 + double? initialAltitude = ((AltimeterSensorData)altimeter.GetSensorData()).Altitude; + Assert.IsTrue(initialAltitude.HasValue, "无法获取初始高度"); + + // 应用干扰 + altimeter.ApplyJamming(millimeterWaveJamming); + + // 更新子弹状态 + submunition.Update(0.1); + + // 验证干扰效果 + Assert.IsTrue(altimeter.IsJammed, "测高仪应该处于被干扰状态"); + var status = submunition.GetStatus(); + Assert.IsTrue(status.Contains("传感器受到干扰"), "子弹状态应该反映传感器受到干扰"); + + // 清除干扰 + altimeter.ClearJamming(JammingType.MillimeterWave); + submunition.Update(0.1); + + // 验证恢复效果 + Assert.IsFalse(altimeter.IsJammed, "测高仪应该恢复正常工作"); + status = submunition.GetStatus(); + Assert.IsFalse(status.Contains("传感器受到干扰"), "子弹状态应该反映传感器恢复正常"); + + // 验证高度测量恢复 + double? recoveredAltitude = ((AltimeterSensorData)altimeter.GetSensorData()).Altitude; + Assert.IsTrue(recoveredAltitude.HasValue, "恢复后应该能获取高度数据"); + Assert.AreNotEqual(initialAltitude, recoveredAltitude, "高度应该有变化"); } [TestMethod] - public void TestSubmunitionScanAndAttack() + public void TestParachuteDeploymentStageJamming() { - // 初始化仿真管理器 - var mockManager = new MockSimulationManager(); - // 设置目标在子弹下方25度角的位置(小于扫描角度30度) - var mockTarget = new MockTarget("target1") { Position = new Vector3D(5, -10, 0) }; // 目标在 (5,-10,0),约25度 - mockManager.RegisterEntity("target1", mockTarget); + // 创建目标 + var tank = new Tank("tank6", new Vector3D(100, 0, 100), Math.PI/4, _simulationManager); + _simulationManager.RegisterEntity("tank6", tank); + tank.Activate(); - // 初始化子弹 + // 创建子弹,初始高度设置为300米(接近开伞高度) var properties = new MissileProperties { + Id = "submunition6", Mass = 10, ExplosionRadius = 5, - MaxSpeed = 500 - }; - var submunition = new TerminalSensitiveSubmunition("target1", properties, mockManager) - { - Position = new Vector3D(0, 0, 0), // 子弹在原点 + MaxSpeed = 500, + MaxFlightTime = 100, + MaxFlightDistance = 1000, + InitialPosition = new Vector3D(0, 300, 0), + InitialSpeed = 40, // 设置为减速阶段末速度 + InitialOrientation = new Orientation(0, -Math.PI/2, 0) // 垂直向下 }; + + var submunition = new TerminalSensitiveSubmunition("tank6", properties, _simulationManager); + _simulationManager.RegisterEntity("submunition6", submunition); + + // 激活并发射子弹 + submunition.Fire(); submunition.Activate(); - // 手动设置到探测阶段 - var stageField = submunition.GetType().GetField("currentStage", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance); - var stageEnum = submunition.GetType().GetNestedType("SubmunitionStage", System.Reflection.BindingFlags.NonPublic); - var detectionStage = Enum.Parse(stageEnum!, "Detection"); - stageField?.SetValue(submunition, detectionStage); + // 获取子弹内部的毫米波测高仪实例 + var altimeter = submunition.GetType().GetField("altimeter", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)?.GetValue(submunition) as MillimeterWaveAltimeter; + Assert.IsNotNull(altimeter, "无法获取测高仪实例"); - // 模拟探测过程 - for (int i = 0; i < 100; i++) + // 创建毫米波干扰参数 + var millimeterWaveJamming = new JammingParameters { - var beforePosition = submunition.Position; - var beforeStage = stageField?.GetValue(submunition)?.ToString(); - submunition.Update(0.02); // 20ms的更新间隔 - var afterPosition = submunition.Position; - var afterStage = stageField?.GetValue(submunition)?.ToString(); - - Console.WriteLine($"更新 {i + 1}:"); - Console.WriteLine($"阶段: 从 {beforeStage} 到 {afterStage}"); - Console.WriteLine($"位置: 从 {beforePosition} 到 {afterPosition}"); - - // 如果进入攻击阶段,检查攻击方向 - if (afterStage == "Attack") - { - var scanDirectionField = submunition.GetType().GetField("scanDirection", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance); - var scanDirectionValue = scanDirectionField?.GetValue(submunition) ?? throw new Exception("扫描方向不能为空"); - var scanDirection = (Vector3D)scanDirectionValue; - Console.WriteLine($"攻击方向: {scanDirection}"); - - // 计算理论上的正确方向(从子弹指向目标) - var expectedDirection = (mockTarget.Position - submunition.Position).Normalize(); - Console.WriteLine($"期望方向: {expectedDirection}"); - - // 检查方向误差是否在可接受范围内(30度) - var angle = Math.Acos(Vector3D.DotProduct(scanDirection.Normalize(), expectedDirection)); - Assert.IsTrue(angle <= Math.PI / 6, $"攻击方向误差过大: {angle * 180 / Math.PI:F2}度"); - return; - } + Type = JammingType.MillimeterWave, + Power = 200, + AngleRange = 45, + Duration = 3, + Direction = new Vector3D(1, 0, 0) + }; + + // 记录初始状态 + double? initialAltitude = ((AltimeterSensorData)altimeter.GetSensorData()).Altitude; + Assert.IsTrue(initialAltitude.HasValue, "无法获取初始高度"); + var initialStatus = submunition.GetStatus(); + Console.WriteLine($"初始状态:{initialStatus}"); + + // 更新几次状态,使子弹进入开伞阶段 + for (int i = 0; i < 10; i++) + { + submunition.Update(0.1); } + + // 应用干扰 + altimeter.ApplyJamming(millimeterWaveJamming); - Assert.Fail("100次更新后仍未进入攻击阶段"); + // 更新子弹状态 + submunition.Update(0.1); + + // 验证干扰效果 + Assert.IsTrue(altimeter.IsJammed, "测高仪应该处于被干扰状态"); + var status = submunition.GetStatus(); + Console.WriteLine($"干扰后状态:{status}"); + Assert.IsTrue(status.Contains("传感器受到干扰"), "子弹状态应该反映传感器受到干扰"); + + // 记录干扰时的位置 + var jammedPosition = submunition.Position; + + // 继续更新一段时间 + for (int i = 0; i < 10; i++) + { + submunition.Update(0.1); + } + + // 验证在干扰期间的行为 + var currentPosition = submunition.Position; + Console.WriteLine($"干扰期间位置变化:从 {jammedPosition} 到 {currentPosition}"); + + // 清除干扰 + altimeter.ClearJamming(JammingType.MillimeterWave); + submunition.Update(0.1); + + // 验证恢复效果 + Assert.IsFalse(altimeter.IsJammed, "测高仪应该恢复正常工作"); + status = submunition.GetStatus(); + Console.WriteLine($"恢复后状态:{status}"); + Assert.IsFalse(status.Contains("传感器受到干扰"), "子弹状态应该反映传感器恢复正常"); + + // 验证高度测量恢复 + double? recoveredAltitude = ((AltimeterSensorData)altimeter.GetSensorData()).Altitude; + Assert.IsTrue(recoveredAltitude.HasValue, "恢复后应该能获取高度数据"); + Assert.AreNotEqual(initialAltitude, recoveredAltitude, "高度应该有变化"); + + // 验证速度变化 + Assert.IsTrue(submunition.Speed <= 40, "速度应该保持在开伞阶段的限制范围内"); } - } - // 模拟仿真管理器 - public class MockSimulationManager : ISimulationManager - { - private readonly Dictionary entities = new(); - private ISimulationAdapter? adapter; - - void ISimulationManager.PublishEvent(T evt) { } - - void ISimulationManager.SubscribeToEvent(Action handler) { } - - void ISimulationManager.UnsubscribeFromEvent(Action handler) { } - - public bool RegisterEntity(string id, object entity) + [TestMethod] + public void TestStableScanStageJamming() { - entities[id] = entity; - return true; + // 创建目标 + var tank = new Tank("tank7", new Vector3D(100, 0, 100), Math.PI/4, _simulationManager); + _simulationManager.RegisterEntity("tank7", tank); + tank.Activate(); + + // 创建子弹,初始高度设置为200米(稳定扫描高度) + var properties = new MissileProperties + { + Id = "submunition7", + Mass = 10, + ExplosionRadius = 5, + MaxSpeed = 500, + MaxFlightTime = 100, + MaxFlightDistance = 1000, + InitialPosition = new Vector3D(0, 250, 0), + InitialSpeed = 10, // 设置为垂直下降速度 + InitialOrientation = new Orientation(0, -Math.PI/2, 0) // 垂直向下 + }; + + var submunition = new TerminalSensitiveSubmunition("tank7", properties, _simulationManager); + _simulationManager.RegisterEntity("submunition7", submunition); + + // 激活并发射子弹 + submunition.Fire(); + submunition.Activate(); + + // 获取子弹内部的激光测距仪实例 + var rangefinder = submunition.GetType().GetField("rangefinder", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)?.GetValue(submunition) as LaserRangefinder; + Assert.IsNotNull(rangefinder, "无法获取激光测距仪实例"); + + // 激活激光测距仪 + rangefinder.Activate(); + + // 更新几次状态,确保进入稳定扫描阶段 + for (int i = 0; i < 20; i++) + { + submunition.Update(0.1); + } + + // 记录扫描开始时的状态 + var scanStartStatus = submunition.GetStatus(); + Console.WriteLine($"扫描开始状态:{scanStartStatus}"); + var scanStartPosition = submunition.Position; + var scanStartDirection = submunition.ScanDirection; + + // 记录干扰前的距离数据 + var initialRangefinderData = rangefinder.GetSensorData() as RangefinderSensorData; + Assert.IsNotNull(initialRangefinderData, "应该能获取初始测距仪数据"); + Assert.IsTrue(initialRangefinderData.IsValid, "初始数据应该有效"); + var initialDistance = initialRangefinderData.Distance; + + // 创建激光干扰参数 + var laserJamming = new JammingParameters + { + Type = JammingType.Laser, + Power = 150, + AngleRange = 30, + Duration = 3, + Direction = new Vector3D(1, 0, 0) + }; + + // 应用干扰 + rangefinder.ApplyJamming(laserJamming); + + // 更新子弹状态 + submunition.Update(0.1); + + // 验证干扰效果 + Assert.IsTrue(rangefinder.IsJammed, "激光测距仪应该处于被干扰状态"); + var status = submunition.GetStatus(); + Console.WriteLine($"干扰后状态:{status}"); + + // 验证距离测量受到影响 + var jammedRangefinderData = rangefinder.GetSensorData() as RangefinderSensorData; + Assert.IsNotNull(jammedRangefinderData, "应该能获取干扰后的测距仪数据"); + Assert.IsFalse(jammedRangefinderData.IsValid, "干扰状态下数据应该无效"); + Assert.AreEqual(0, jammedRangefinderData.Distance, "干扰状态下距离应该为0"); + Console.WriteLine($"干扰前距离: {initialDistance}米"); + Console.WriteLine($"干扰后距离: {jammedRangefinderData.Distance}米"); + + // 记录干扰时的位置和扫描方向 + var jammedPosition = submunition.Position; + var jammedDirection = submunition.ScanDirection; + + // 继续更新一段时间 + for (int i = 0; i < 10; i++) + { + submunition.Update(0.1); + Console.WriteLine($"干扰期间第{i+1}次更新:"); + Console.WriteLine($"位置: {submunition.Position}"); + Console.WriteLine($"扫描方向: {submunition.ScanDirection}"); + } + + // 验证在干扰期间的行为 + var currentPosition = submunition.Position; + var currentDirection = submunition.ScanDirection; + Console.WriteLine($"干扰期间位置变化:从 {jammedPosition} 到 {currentPosition}"); + Console.WriteLine($"干扰期间扫描方向变化:从 {jammedDirection} 到 {currentDirection}"); + + // 清除干扰 + rangefinder.ClearJamming(JammingType.Laser); + submunition.Update(0.1); + + // 验证恢复效果 + Assert.IsFalse(rangefinder.IsJammed, "激光测距仪应该恢复正常工作"); + status = submunition.GetStatus(); + Console.WriteLine($"恢复后状态:{status}"); + Assert.IsFalse(status.Contains("传感器受到干扰"), "子弹状态应该反映传感器恢复正常"); + + // 验证扫描行为的恢复 + var recoveredDirection = submunition.ScanDirection; + Console.WriteLine($"恢复后的扫描方向:{recoveredDirection}"); + + // 验证速度保持在合理范围 + Assert.IsTrue(submunition.Speed <= 10, "速度应该保持在稳定扫描阶段的限制范围内"); } - public bool UnregisterEntity(string id) + [TestMethod] + public void TestDetectionStageJamming() { - return entities.Remove(id); + // 创建目标 + var tank = new Tank("tank8", new Vector3D( 30, 0, 30), Math.PI/4, _simulationManager); + _simulationManager.RegisterEntity("tank8", tank); + tank.Activate(); + + // 创建子弹,初始位置设置在探测阶段范围内 + var properties = new MissileProperties + { + Id = "submunition8", + Mass = 10, + ExplosionRadius = 5, + MaxSpeed = 10, + MaxFlightTime = 100, + MaxFlightDistance = 1000, + InitialPosition = new Vector3D(0, 140, 0), + InitialSpeed = 10, + InitialOrientation = new Orientation(0, -Math.PI/2, 0) + }; + + var submunition = new TerminalSensitiveSubmunition("tank8", properties, _simulationManager); + _simulationManager.RegisterEntity("submunition8", submunition); + + // 激活并发射子弹 + submunition.Fire(); + submunition.Activate(); + + // 获取子弹内部的传感器实例 + var infraredDetector = submunition.GetType().GetField("infraredDetector", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)?.GetValue(submunition) as InfraredDetector; + var radiometer = submunition.GetType().GetField("radiometer", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)?.GetValue(submunition) as MillimeterWaveRadiometer; + + Assert.IsNotNull(infraredDetector, "无法获取红外探测器实例"); + Assert.IsNotNull(radiometer, "无法获取毫米波辐射计实例"); + + // 激活传感器 + infraredDetector.Activate(); + radiometer.Activate(); + + // 更新几次状态,确保进入探测阶段 + for (double time = 0; time < 5.0; time += 0.1) + { + // 更新子弹状态 + submunition.Update(0.1); + } + + // Assert + Assert.IsTrue(submunition.IsGuidance); } - public object GetEntityById(string id) + [TestMethod] + public void TestAttackStageJamming() { - return entities.TryGetValue(id, out var entity) ? entity : new MockTarget("mock_target") { Position = new Vector3D(100, 50, 100) }; - } + // 创建目标 + var tank = new Tank("tank_attack", new Vector3D(300, 0, 100), Math.PI/4, _simulationManager); + _simulationManager.RegisterEntity("tank_attack", tank); + tank.Activate(); - public IReadOnlyList GetEntitiesByType() where T : class - { - return entities.Values.OfType().ToList(); - } + // 创建子弹,初始位置设置在传感器探测范围内 + var properties = new MissileProperties + { + Id = "submunition_attack", + Mass = 10, + ExplosionRadius = 5, + MaxSpeed = 2000, + MaxFlightTime = 50, + MaxFlightDistance = 1000, + InitialPosition = new Vector3D(400, 200, 100), // 距离目标100米,高度200米 + InitialSpeed = 10, + InitialOrientation = new Orientation(0, -Math.PI/6, 0) // 向下30度 + }; + + var submunition = new TerminalSensitiveSubmunition("tank_attack", properties, _simulationManager); + _simulationManager.RegisterEntity("submunition_attack", submunition); + + // 激活并发射子弹 + submunition.Fire(); + submunition.Activate(); - public IReadOnlyList GetAllEntities() - { - return entities.Values.ToList(); - } + // 获取子弹内部的传感器实例 + var rangefinder = submunition.GetType().GetField("rangefinder", + System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance) + ?.GetValue(submunition) as LaserRangefinder; - public void SetSimulationAdapter(ISimulationAdapter adapter) - { - this.adapter = adapter; - } + Assert.IsNotNull(rangefinder, "无法获取激光测距仪实例"); - public ISimulationAdapter? GetSimulationAdapter() - { - return adapter; - } - } + // 激活传感器 + rangefinder.Activate(); - // 模拟目标 - public class MockTarget(string id) : SimulationElement(id, new Vector3D(100, 50, 100), new Orientation(), 1000, new MockSimulationManager()) - { - public override void Update(double deltaTime) { } + // 验证传感器初始状态 + Assert.IsTrue(rangefinder.IsActive, "激光测距仪应该处于激活状态"); + Assert.IsFalse(rangefinder.IsJammed, "激光测距仪不应该处于干扰状态"); + + // 更新几次状态,确保传感器工作正常 + for (int i = 0; i < 5; i++) + { + submunition.Update(0.1); + var status = submunition.GetStatus(); + Console.WriteLine($"干扰前状态 {i+1}:{status}"); + } + + // 创建干扰参数 + var laserJamming = new JammingParameters + { + Type = JammingType.Laser, + Power = 150, + AngleRange = 30, + Duration = 3, + Direction = new Vector3D(1, 0, 0) + }; + + // 应用干扰 + Console.WriteLine("应用干扰..."); + rangefinder.ApplyJamming(laserJamming); + + // 验证干扰效果 + Assert.IsFalse(rangefinder.IsActive, "激光测距仪应该在干扰下失效"); + Assert.IsTrue(rangefinder.IsJammed, "激光测距仪应该处于干扰状态"); + + // 更新并验证干扰期间的行为 + for (int i = 0; i < 5; i++) + { + submunition.Update(0.1); + var status = submunition.GetStatus(); + Console.WriteLine($"干扰期间状态 {i+1}:{status}"); + Assert.IsTrue(status.Contains("传感器受到干扰"), "子弹状态应该反映传感器受到干扰"); + + // 验证传感器数据无效 + var rangefinderData = rangefinder.GetSensorData() as RangefinderSensorData; + Assert.IsFalse(rangefinderData?.IsValid ?? true, "干扰期间距离数据应该无效"); + } + + // 清除干扰 + Console.WriteLine("清除干扰..."); + rangefinder.ClearJamming(JammingType.Laser); + + // 验证恢复效果 + Assert.IsTrue(rangefinder.IsActive, "激光测距仪应该恢复正常工作"); + Assert.IsFalse(rangefinder.IsJammed, "激光测距仪应该解除干扰状态"); + + // 验证恢复后的状态 + submunition.Update(0.1); + var finalStatus = submunition.GetStatus(); + Console.WriteLine($"恢复后状态:{finalStatus}"); + Assert.IsFalse(finalStatus.Contains("传感器受到干扰"), "子弹状态应该反映传感器恢复正常"); + } } } \ No newline at end of file diff --git a/ThreatSource.Tests/src/Missile/InfraredImagingTerminalGuidedMissileTests.cs b/ThreatSource.Tests/src/Missile/InfraredImagingTerminalGuidedMissileTests.cs index 3246e40..2481135 100644 --- a/ThreatSource.Tests/src/Missile/InfraredImagingTerminalGuidedMissileTests.cs +++ b/ThreatSource.Tests/src/Missile/InfraredImagingTerminalGuidedMissileTests.cs @@ -80,17 +80,6 @@ namespace ThreatSource.Tests.Missile // 末制导阶段 for (double time = 0; time < 3.0; time += 0.1) { - // 发布坦克辐射事件 - _simulationManager.PublishEvent(new TankRadiationEvent - { - SenderId = "target1", - InfraredRadiationIntensity = 100.0, - LaserReflectionIntensity = 0.0, - MillimeterWaveReflectionIntensity = 0.0, - MillimeterWaveRadiationTemperature = 300.0, - Timestamp = DateTime.UtcNow.Ticks - }); - tank.Update(0.1); _missile.Update(0.1); } diff --git a/ThreatSource.Tests/src/Missile/MillimeterWaveTerminalGuidedMissileTests.cs b/ThreatSource.Tests/src/Missile/MillimeterWaveTerminalGuidedMissileTests.cs index e00ccd9..75f5fd5 100644 --- a/ThreatSource.Tests/src/Missile/MillimeterWaveTerminalGuidedMissileTests.cs +++ b/ThreatSource.Tests/src/Missile/MillimeterWaveTerminalGuidedMissileTests.cs @@ -80,17 +80,6 @@ namespace ThreatSource.Tests.Missile // 末制导阶段 for (double time = 0; time < 3.0; time += 0.1) { - // 发布坦克辐射事件 - _simulationManager.PublishEvent(new TankRadiationEvent - { - SenderId = "target1", - InfraredRadiationIntensity = 0.0, - LaserReflectionIntensity = 0.0, - MillimeterWaveReflectionIntensity = 1.0, - MillimeterWaveRadiationTemperature = 300.0, - Timestamp = DateTime.UtcNow.Ticks - }); - tank.Update(0.1); _missile.Update(0.1); } diff --git a/ThreatSource.Tests/src/Missile/TerminalSensitiveSubmunitionTests.cs b/ThreatSource.Tests/src/Missile/TerminalSensitiveSubmunitionTests.cs index 6ac43c5..40668dd 100644 --- a/ThreatSource.Tests/src/Missile/TerminalSensitiveSubmunitionTests.cs +++ b/ThreatSource.Tests/src/Missile/TerminalSensitiveSubmunitionTests.cs @@ -112,17 +112,6 @@ namespace ThreatSource.Tests.Missile // Act - 等待进入螺旋扫描阶段并发送目标辐射 for (double time = 0; time < 5.0; time += 0.1) { - // 发布坦克辐射事件 - _simulationManager.PublishEvent(new TankRadiationEvent - { - SenderId = "tank1", - InfraredRadiationIntensity = 100.0, - LaserReflectionIntensity = 0.0, - MillimeterWaveReflectionIntensity = 1.0, - MillimeterWaveRadiationTemperature = 300.0, - Timestamp = DateTime.UtcNow.Ticks - }); - _tank.Update(0.1); _submunition.Update(0.1); } diff --git a/ThreatSource/src/MIssile/BaseMissile.cs b/ThreatSource/src/MIssile/BaseMissile.cs index b2d1220..d447cca 100644 --- a/ThreatSource/src/MIssile/BaseMissile.cs +++ b/ThreatSource/src/MIssile/BaseMissile.cs @@ -151,6 +151,12 @@ namespace ThreatSource.Missile { // 更新导弹运动状态 UpdateMotionState(deltaTime); + + // 检查是否应该自毁 + if (ShouldSelfDestruct()) + { + SelfDestruct(); + } } } diff --git a/ThreatSource/src/MIssile/TerminalSensitiveSubmunition.cs b/ThreatSource/src/MIssile/TerminalSensitiveSubmunition.cs index 192f2e6..bd7e496 100644 --- a/ThreatSource/src/MIssile/TerminalSensitiveSubmunition.cs +++ b/ThreatSource/src/MIssile/TerminalSensitiveSubmunition.cs @@ -5,6 +5,27 @@ using ThreatSource.Target; namespace ThreatSource.Missile { + /// + /// 目标探测结果结构 + /// + /// + /// 包含目标探测的完整信息: + /// - 目标角度 + /// - 目标对象引用 + /// + public struct DetectionResult + { + /// + /// 目标角度(弧度) + /// + public double? Angle { get; set; } + + /// + /// 目标对象 + /// + public ITarget? Target { get; set; } + } + /// /// 末敏子弹类,实现了多传感器融合的末端制导功能 /// @@ -70,6 +91,14 @@ namespace ThreatSource.Missile /// private const double DecelerationEndSpeed = 40; + /// + /// 降落伞减速加速度,单位:米/秒² + /// + /// + /// 定义了降落伞减速加速度 + /// + private const double ParachuteDeceleration = 50; + /// /// 垂直下降速度,单位:米/秒 /// @@ -391,11 +420,30 @@ namespace ThreatSource.Missile /// private void UpdateParachuteDeploymentStage(double deltaTime) { - if (Velocity.Magnitude() <= VerticalDeclineSpeed) + // 计算当前速度与目标速度的差值 + double currentSpeed = Velocity.Magnitude(); + if (currentSpeed > VerticalDeclineSpeed) { - Velocity = new Vector3D(0, -VerticalDeclineSpeed, 0); - GuidanceAcceleration = Vector3D.Zero; + // 开伞,用较大的减速度快速降低速度 + Vector3D deceleration = -Velocity.Normalize() * ParachuteDeceleration; + + // 更新速度 + Velocity += deceleration * deltaTime; + + // 如果速度低于稳定扫描下降速度,直接设置为稳定扫描下降速度 + if (Velocity.Magnitude() <= VerticalDeclineSpeed) + { + Velocity = new Vector3D(0, -VerticalDeclineSpeed, 0); + } } + else + { + // 维持稳定的垂直下降速度 + Velocity = new Vector3D(0, -VerticalDeclineSpeed, 0); + } + + // 清除制导加速度 + GuidanceAcceleration = Vector3D.Zero; if(IsSensorsJammed()) { @@ -470,38 +518,37 @@ namespace ThreatSource.Missile /// private void UpdateDetectionStage(double deltaTime) { - // 激活毫米波辐射计 + // 激活传感器 if(!radiometer.IsActive) { radiometer.Activate(); } - // 激活红外探测器 if(!infraredDetector.IsActive) { infraredDetector.Activate(); } - // 检查传感器干扰状态 - if (IsSensorsJammed()) - { - Console.WriteLine("探测阶段:传感器受到干扰,无法进行目标探测"); - return; - } - - // 更新螺旋角度(顺时针旋转) + // 更新扫描角度(顺时针旋转) spiralAngle = (spiralAngle + SpiralRotationSpeed * deltaTime); // 顺时针角度增加 while (spiralAngle >= 2 * Math.PI) { spiralAngle -= 2 * Math.PI; } - // 计算扫描方向 + // 更新扫描方向 scanDirection = new Vector3D( Math.Sin(spiralAngle) * Math.Sin(ScanAngle), -Math.Cos(ScanAngle), Math.Cos(spiralAngle) * Math.Sin(ScanAngle) ).Normalize(); + // 检查传感器干扰状态 + if (IsSensorsJammed()) + { + Console.WriteLine("探测阶段:传感器受到干扰,无法进行目标探测"); + return; // 此时返回不会影响扫描角度的更新 + } + // 获取传感器数据 RadiometerSensorData? radiometerData = null; InfraredSensorData? infraredData = null; @@ -518,7 +565,7 @@ namespace ThreatSource.Missile bool isRadiationDetected = radiometerData?.IsTargetDetected ?? false; bool isInfraredDetected = infraredData?.IsTargetDetected ?? false; - // 如果还未探测到目标,进行首次探测 + // 目标探测逻辑 if (!isTargetDetected) { if (isRadiationDetected || isInfraredDetected) @@ -584,12 +631,11 @@ namespace ThreatSource.Missile } // 检查自毁条件 - if (rangefinder.GetSensorData() is RangefinderSensorData rangefinderData && - rangefinderData.Distance <= SelfDestructHeight) + if (((AltimeterSensorData)altimeter.GetSensorData()).Altitude <= SelfDestructHeight) { currentStage = SubmunitionStage.SelfDestruct; - } - } + } + } /// /// 更新攻击阶段状态 @@ -674,21 +720,25 @@ namespace ThreatSource.Missile /// 检测目标是否在视场内 /// /// 视场角,单位:度 - /// 返回目标方位角。如果目标在视场内返回方位角,否则返回null + /// 返回探测结果。如果目标在视场内返回角度和目标引用,否则返回null /// /// 检测过程: /// - 获取目标位置 /// - 计算目标方向 /// - 判断是否在视场内 /// - public double? DetectTarget(double fieldOfView) + public DetectionResult DetectTarget(double fieldOfView) { // 获取目标对象 - SimulationElement target = SimulationManager.GetEntityById(TargetId) as SimulationElement ?? throw new Exception("目标不存在"); - + var target = SimulationManager.GetEntityById(TargetId) as SimulationElement; + if (target == null) return new DetectionResult(); + // 获取目标的尺寸属性 - double targetLength = (target as ITarget)?.Length ?? 0; // 目标长度 - double targetWidth = (target as ITarget)?.Width ?? 0; // 目标宽度 + var targetInterface = target as ITarget; + if (targetInterface == null) return new DetectionResult(); + + double targetLength = targetInterface.Length; // 目标长度 + double targetWidth = targetInterface.Width; // 目标宽度 // 获取目标的朝向向量 Vector3D targetForward = target.Orientation.ToVector(); @@ -719,13 +769,16 @@ namespace ThreatSource.Missile Vector3D toVertex = (vertex - Position).Normalize(); if(Vector3D.DotProduct(scanDirection, toVertex) > cosFieldOfView) { - // 如果目标的任何一个顶点在视场角内,返回目标方位角 - return targetAzimuth; + // 如果目标的任何一个顶点在视场角内,返回目标方位角和目标引用 + return new DetectionResult { + Angle = targetAzimuth, + Target = targetInterface + }; } } - // 如果目标不在视场角内,返回null - return null; + // 如果目标不在视场角内,返回空结果 + return new DetectionResult(); } /// @@ -734,13 +787,10 @@ namespace ThreatSource.Missile /// /// 激活过程: /// - 调用基类激活方法 - /// - 订阅目标辐射事件 - /// - 准备传感器系统 /// public override void Activate() { base.Activate(); - SimulationManager.SubscribeToEvent(OnTankRadiationEvent); } /// @@ -761,24 +811,6 @@ namespace ThreatSource.Missile rangefinder.Deactivate(); } - /// - /// 处理坦克辐射事件 - /// - /// 坦克辐射事件数据 - /// - /// 处理过程: - /// - 验证目标ID - /// - 记录辐射信息 - /// - 更新目标状态 - /// - private void OnTankRadiationEvent(TankRadiationEvent evt) - { - if (evt.SenderId == TargetId) - { - Console.WriteLine("检测到目标辐射"); - } - } - /// /// 获取子弹状态信息 /// @@ -800,7 +832,8 @@ namespace ThreatSource.Missile $"运行状态: {currentStage}\n" + $"扫描角度: {spiralAngle * 180 / Math.PI:F2}°, 弧度值: {spiralAngle:F6}\n" + $"目标检测: {lastDetectionTime != null}\n" + - $"目标距离: {distanceToTarget:F2}米"; + $"目标距离: {distanceToTarget:F2}米\n" + + $"传感器状态: {(IsSensorsJammed() ? "传感器受到干扰" : "正常工作")}"; return status; } diff --git a/ThreatSource/src/Sensor/InfraredDetector.cs b/ThreatSource/src/Sensor/InfraredDetector.cs index 27fe39d..dbaf091 100644 --- a/ThreatSource/src/Sensor/InfraredDetector.cs +++ b/ThreatSource/src/Sensor/InfraredDetector.cs @@ -2,6 +2,7 @@ using ThreatSource.Utils; using ThreatSource.Jamming; using ThreatSource.Simulation; using ThreatSource.Missile; +using ThreatSource.Target; namespace ThreatSource.Sensor { @@ -137,11 +138,11 @@ namespace ThreatSource.Sensor private double GetCurrentDirectionRadiationIntensity() { // 获取当前方向上的辐射强度,如果检测到目标,则返回目标的辐射强度,否则返回0 - var angle = submunition.DetectTarget(FieldOfView); - if (angle != null) + var result = submunition.DetectTarget(FieldOfView); + if (result.Angle != null && result.Target != null) { - sensorData.TargetAngle = angle; - return 100; + sensorData.TargetAngle = result.Angle; + return result.Target.InfraredRadiationIntensity; } sensorData.TargetAngle = null; return 0; diff --git a/ThreatSource/src/Sensor/LaserRangefinder.cs b/ThreatSource/src/Sensor/LaserRangefinder.cs index 7c4df6e..e711bbd 100644 --- a/ThreatSource/src/Sensor/LaserRangefinder.cs +++ b/ThreatSource/src/Sensor/LaserRangefinder.cs @@ -112,7 +112,7 @@ namespace ThreatSource.Sensor /// public override void Update(double deltaTime) { - if (IsActive) + if (IsActive && !IsJammed) { // 计算到地面的垂直距离和水平距离 double verticalDistance = submunition.Position.Y; @@ -129,6 +129,11 @@ namespace ThreatSource.Sensor // 调试输出 //Console.WriteLine($"激光测距仪 - 垂直距离: {verticalDistance:F2}m, 水平距离: {horizontalDistance:F2}m, 斜距: {slantRange:F2}m, 测量距离: {currentDistance:F2}m"); } + else if (IsJammed) + { + // 在干扰状态下,将距离设置为无效值 + currentDistance = 0; + } } /// @@ -141,12 +146,11 @@ namespace ThreatSource.Sensor /// public override SensorData GetSensorData() { - // 返回激光测距仪的数据 - RangefinderSensorData rangefinderSensorData = new() + return new RangefinderSensorData { - Distance = currentDistance + Distance = IsJammed ? 0 : currentDistance, + IsValid = !IsJammed && IsActive }; - return rangefinderSensorData; } /// diff --git a/ThreatSource/src/Sensor/MillimeterWaveAltimeter.cs b/ThreatSource/src/Sensor/MillimeterWaveAltimeter.cs index ef2a410..0eabde9 100644 --- a/ThreatSource/src/Sensor/MillimeterWaveAltimeter.cs +++ b/ThreatSource/src/Sensor/MillimeterWaveAltimeter.cs @@ -88,7 +88,7 @@ namespace ThreatSource.Sensor Accuracy = accuracy; Band = band; FieldOfView = fieldOfView; - currentAltitude = 0; + currentAltitude = submunition.Position.Y; this.submunition = submunition; } @@ -108,6 +108,7 @@ namespace ThreatSource.Sensor if (IsActive) { currentAltitude = submunition.Position.Y + (2 * new Random().NextDouble() - 1) * Accuracy; + Console.WriteLine($"测高仪Update - 实际高度: {submunition.Position.Y:F2}米, 测量高度: {currentAltitude:F2}米"); } } @@ -159,6 +160,7 @@ namespace ThreatSource.Sensor { Altitude = currentAltitude }; + Console.WriteLine($"测高仪GetSensorData - 返回高度: {currentAltitude:F2}米"); return altimeterSensorData; } diff --git a/ThreatSource/src/Sensor/MillimeterWaveRadiometer.cs b/ThreatSource/src/Sensor/MillimeterWaveRadiometer.cs index 83e6c07..8e77d51 100644 --- a/ThreatSource/src/Sensor/MillimeterWaveRadiometer.cs +++ b/ThreatSource/src/Sensor/MillimeterWaveRadiometer.cs @@ -163,15 +163,15 @@ namespace ThreatSource.Sensor /// private double GetCurrentDirectionRadiationTemperature() { - // 获取当前方向上的辐射温度,如果检测到目标,则返回天空背景辐射的反射温度,否则返回300K - var angle = submunition.DetectTarget(FieldOfView); - if (angle != null) + // 获取当前方向上的辐射温度,如果检测到目标,则返回目标的辐射温度,否则返回地面温度 + var result = submunition.DetectTarget(FieldOfView); + if (result.Angle != null && result.Target != null) { - sensorData.TargetAngle = angle; - return 90; + sensorData.TargetAngle = result.Angle; + return result.Target.MillimeterWaveRadiationTemperature; } sensorData.TargetAngle = null; - return 300; + return 300; // 地面温度 } /// diff --git a/ThreatSource/src/Sensor/SensorData.cs b/ThreatSource/src/Sensor/SensorData.cs index 212fdca..8e61620 100644 --- a/ThreatSource/src/Sensor/SensorData.cs +++ b/ThreatSource/src/Sensor/SensorData.cs @@ -142,5 +142,10 @@ namespace ThreatSource.Sensor /// 用于目标定位和制导控制 /// public double Distance { get; set; } + + /// + /// 获取或设置数据是否有效 + /// + public bool IsValid { get; set; } } } diff --git a/ThreatSource/src/Simulation/SimulationEvents.cs b/ThreatSource/src/Simulation/SimulationEvents.cs index 0549241..19af178 100644 --- a/ThreatSource/src/Simulation/SimulationEvents.cs +++ b/ThreatSource/src/Simulation/SimulationEvents.cs @@ -378,52 +378,6 @@ namespace ThreatSource.Simulation public double JammingPower { get; set; } } - /// - /// 坦克辐射事件,表示坦克的多波段辐射特性 - /// - /// - /// 用于模拟坦克在不同波段的辐射特征 - /// 包含激光、毫米波和红外波段的信息 - /// - public class TankRadiationEvent : SimulationEvent - { - /// - /// 获取或设置激光漫反射强度 - /// - /// - /// 单位:相对单位 - /// 表示坦克表面对激光的反射能力 - /// - public double LaserReflectionIntensity { get; set; } - - /// - /// 获取或设置毫米波反射强度 - /// - /// - /// 单位:相对单位 - /// 表示坦克对毫米波雷达的反射特性 - /// - public double MillimeterWaveReflectionIntensity { get; set; } - - /// - /// 获取或设置毫米波辐射温度 - /// - /// - /// 单位:开尔文 - /// 表示坦克在毫米波波段的辐射温度 - /// - public double MillimeterWaveRadiationTemperature { get; set; } - - /// - /// 获取或设置红外辐射强度 - /// - /// - /// 单位:瓦特/平方米 - /// 表示坦克的红外辐射强度 - /// - public double InfraredRadiationIntensity { get; set; } - } - /// /// 目标被击中事件 /// diff --git a/ThreatSource/src/Simulation/Testing/TestSimulationAdapter.cs b/ThreatSource/src/Simulation/Testing/TestSimulationAdapter.cs index ed894ca..c72ff66 100644 --- a/ThreatSource/src/Simulation/Testing/TestSimulationAdapter.cs +++ b/ThreatSource/src/Simulation/Testing/TestSimulationAdapter.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using ThreatSource.Simulation; +using ThreatSource.Utils; namespace ThreatSource.Simulation.Testing { @@ -13,6 +14,12 @@ namespace ThreatSource.Simulation.Testing private readonly List _receivedEvents = []; private readonly List _publishedEvents = []; private ISimulationManager? _simulationManager; + // 存储实体状态的字典 + private Dictionary entityStates = new(); + // 存储环境数据的字典 + private Dictionary environmentData = new(); + // 当前仿真时间 + private double currentTime = 0; /// /// 构造函数,初始化测试适配器 @@ -100,5 +107,49 @@ namespace ThreatSource.Simulation.Testing _publishedEvents.Clear(); _receivedEvents.Clear(); } + + /// + /// 获取实体状态 + /// + /// + /// + public SimulationElement 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/ITarget.cs b/ThreatSource/src/Target/ITarget.cs index 7a5b577..18b1574 100644 --- a/ThreatSource/src/Target/ITarget.cs +++ b/ThreatSource/src/Target/ITarget.cs @@ -38,12 +38,34 @@ namespace ThreatSource.Target /// 获取目标的红外辐射强度 /// /// - /// 单位:瓦特/平方米 + /// 单位:瓦特/球面度 /// 表示目标的热辐射特征 /// 影响红外制导系统的探测和跟踪能力 + /// 典型值:200-500 W/sr /// double InfraredRadiationIntensity { get; } + /// + /// 获取目标的毫米波辐射温度 + /// + /// + /// 单位:开尔文 + /// 表示目标的毫米波辐射特征 + /// 影响毫米波制导系统的探测和跟踪能力 + /// 典型值:350-450K + /// + double MillimeterWaveRadiationTemperature { get; } + + /// + /// 获取目标的激光反射率 + /// + /// + /// 无量纲,取值范围:0-1 + /// 表示目标表面对激光的反射特性 + /// 影响激光测距和制导系统的效果 + /// + double LaserReflectivity { get; } + /// /// 获取目标的长度 /// diff --git a/ThreatSource/src/Target/Tank.cs b/ThreatSource/src/Target/Tank.cs index f8c7581..d99957e 100644 --- a/ThreatSource/src/Target/Tank.cs +++ b/ThreatSource/src/Target/Tank.cs @@ -36,10 +36,30 @@ namespace ThreatSource.Target /// 获取坦克的红外辐射强度 /// /// - /// 单位:瓦特/平方米 - /// 固定值100.0,表示坦克发动机和装甲的热辐射特性 + /// 单位:瓦特/球面度 + /// 固定值500.0,表示坦克发动机和装甲的热辐射特性 + /// 典型值:200-500 W/sr /// - public double InfraredRadiationIntensity => 100.0; + public double InfraredRadiationIntensity => 500.0; + + /// + /// 获取坦克的毫米波辐射温度 + /// + /// + /// 单位:开尔文 + /// 固定值400.0,表示坦克的毫米波辐射特征 + /// 典型值:350-450K + /// + public double MillimeterWaveRadiationTemperature => 400.0; + + /// + /// 获取坦克的激光反射率 + /// + /// + /// 无量纲,取值范围:0-1 + /// 固定值0.3,表示坦克表面对激光的反射特性 + /// + public double LaserReflectivity => 0.3; /// /// 获取或设置坦克的当前生命值 diff --git a/tools/MissileSimulator.cs b/tools/MissileSimulator.cs index ff7adb9..51b605f 100644 --- a/tools/MissileSimulator.cs +++ b/tools/MissileSimulator.cs @@ -36,7 +36,7 @@ namespace ThreatSource.Tools public string AddTarget(Vector3D position) { string targetId = $"target_{targets.Count + 1}"; - var target = new MockTarget(targetId) + var target = new MockTarget(targetId, simulationManager) { Position = position }; @@ -57,15 +57,16 @@ namespace ThreatSource.Tools { Mass = 10, ExplosionRadius = 0.1, - MaxSpeed = 2000 + MaxSpeed = 2000, + MaxFlightTime = 100, + MaxFlightDistance = 5000, + MaxAcceleration = 200, + InitialPosition = position, + InitialSpeed = 80, + InitialOrientation = new Orientation(0, -Math.PI/2, 0) // 垂直向下 }; - var missile = new TerminalSensitiveSubmunition(targetId, properties, simulationManager) - { - Position = position, - Velocity = new Vector3D(0, -10, 0) // 初始垂直下降速度 - }; - + var missile = new TerminalSensitiveSubmunition(targetId, properties, simulationManager); missile.Activate(); missiles.Add(missile); Console.WriteLine($"发射导弹,目标:{targetId},位置:{position}"); @@ -196,7 +197,7 @@ namespace ThreatSource.Tools /// public class MockTarget : SimulationElement, ITarget { - public MockTarget(string id) : base(id, new Vector3D(0, 0, 0), new Orientation(), 1000, null) { } + public MockTarget(string id, ISimulationManager simulationManager) : base(id, new Vector3D(0, 0, 0), new Orientation(), 1000, simulationManager) { } public override void Update(double deltaTime) { } @@ -210,5 +211,7 @@ namespace ThreatSource.Tools // 设置目标的特征参数 public double RadarCrossSection => 10.0; // 雷达散射截面积(示例值) public double InfraredRadiationIntensity => 500.0; // 红外辐射强度(示例值) + public double MillimeterWaveRadiationTemperature => 90.0; // 毫米波辐射温度(示例值) + public double LaserReflectivity => 0.3; // 激光反射率(示例值) } } \ No newline at end of file diff --git a/tools/Program.cs b/tools/Program.cs index dbdb82e..d31bdd8 100644 --- a/tools/Program.cs +++ b/tools/Program.cs @@ -14,7 +14,7 @@ namespace ThreatSource.Tools var targetId = simulator.AddTarget(new Vector3D(0, 0, 0)); // 发射导弹 - simulator.LaunchMissile(targetId, new Vector3D(40, 400, 40)); + simulator.LaunchMissile(targetId, new Vector3D(40, 450, 40)); // 启动模拟线程 var simulationThread = new Thread(simulator.Start);