From a97cb6a9092e0bb138f65e7c9a49500292b05549 Mon Sep 17 00:00:00 2001 From: Tian jianyong <11429339@qq.com> Date: Tue, 7 Jan 2025 02:58:28 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E4=BA=86detectionAngle?= =?UTF-8?q?=E7=9A=84=20bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/Jamming/JammingTests.cs | 145 +++++++++++-- .../src/MIssile/TerminalSensitiveMissile.cs | 10 +- .../MIssile/TerminalSensitiveSubmunition.cs | 96 ++++++--- ThreatSource/src/Sensor/LaserRangefinder.cs | 18 +- .../Testing/TestSimulationAdapter.cs | 6 +- src/tools/MissileSimulator.cs | 23 ++ src/tools/Program.cs | 75 +++++++ tools/MissileSimulator.cs | 203 ++++++++++++++++++ tools/Program.cs | 75 +++++++ tools/ThreatSource.Tools.csproj | 14 ++ 10 files changed, 614 insertions(+), 51 deletions(-) create mode 100644 src/tools/MissileSimulator.cs create mode 100644 src/tools/Program.cs create mode 100644 tools/MissileSimulator.cs create mode 100644 tools/Program.cs create mode 100644 tools/ThreatSource.Tools.csproj diff --git a/ThreatSource.Tests/src/Jamming/JammingTests.cs b/ThreatSource.Tests/src/Jamming/JammingTests.cs index b230f74..62c0573 100644 --- a/ThreatSource.Tests/src/Jamming/JammingTests.cs +++ b/ThreatSource.Tests/src/Jamming/JammingTests.cs @@ -126,18 +126,24 @@ namespace ThreatSource.Tests.Jamming var mockTarget = new MockTarget("target1") { Position = new Vector3D(100, 0, 100) }; mockManager.RegisterEntity("target1", mockTarget); - // 初始化子弹,设置初始位置在目标正上方120米处(刚好进入探测距离) + // 初始化子弹 var properties = new MissileProperties { Mass = 10, ExplosionRadius = 5, - MaxSpeed = 2000 + MaxSpeed = 500, + MaxFlightTime = 100 // 设置最大飞行时间为100秒 }; var submunition = new TerminalSensitiveSubmunition("target1", properties, mockManager) { - Position = new Vector3D(100, 120, 100), // 设置在目标正上方120米处 + 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(); // 获取子弹内部的传感器实例 @@ -150,15 +156,7 @@ namespace ThreatSource.Tests.Jamming radiometer?.Activate(); rangefinder?.Activate(); - // 更新子弹状态,让它进入Detection阶段 - for (int i = 0; i < 3; i++) - { - submunition.Update(0.1); - var currentStatus = submunition.GetStatus(); - Console.WriteLine($"更新 {i + 1} 后的状态:{currentStatus}"); // 添加状态输出,帮助调试 - } - - // 手动设置子弹阶段为Detection + // 手动设置到探测阶段 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"); @@ -204,6 +202,126 @@ namespace ThreatSource.Tests.Jamming Assert.IsFalse(infraredDetector?.IsActive == false || radiometer?.IsActive == false, "传感器应该恢复正常工作状态"); Assert.IsFalse(status.Contains("传感器受到干扰"), "子弹状态应该反映传感器恢复正常"); } + + [TestMethod] + public void TestSubmunitionHitDetection() + { + // 初始化仿真管理器 + var mockManager = new MockSimulationManager(); + var mockTarget = new MockTarget("target1") { Position = new Vector3D(0, 0, 0) }; + mockManager.RegisterEntity("target1", mockTarget); + + // 初始化子弹,设置初始位置在目标正上方6米处 + var properties = new MissileProperties + { + 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米/秒 + }; + 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米/秒 + + // 更新子弹状态,每次更新0.1秒 + for (int i = 0; i < 10; i++) + { + var beforePosition = submunition.Position; + submunition.Update(0.1); + var afterPosition = submunition.Position; + var status = submunition.GetStatus(); + + Console.WriteLine($"更新 {i + 1}:"); + Console.WriteLine($"位置: 从 {beforePosition} 到 {afterPosition}"); + Console.WriteLine($"状态: {status}"); + + if (status.Contains("Explode")) + { + Console.WriteLine("子弹已爆炸!"); + return; + } + } + + Assert.Fail("子弹应该在接近目标时爆炸"); + } + + [TestMethod] + public void TestSubmunitionScanAndAttack() + { + // 初始化仿真管理器 + 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 properties = new MissileProperties + { + Mass = 10, + ExplosionRadius = 5, + MaxSpeed = 500 + }; + var submunition = new TerminalSensitiveSubmunition("target1", properties, mockManager) + { + Position = new Vector3D(0, 0, 0), // 子弹在原点 + }; + 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); + + // 模拟探测过程 + for (int i = 0; i < 100; i++) + { + 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; + } + } + + Assert.Fail("100次更新后仍未进入攻击阶段"); + } } // 模拟仿真管理器 @@ -256,9 +374,8 @@ namespace ThreatSource.Tests.Jamming } // 模拟目标 - public class MockTarget : SimulationElement + public class MockTarget(string id) : SimulationElement(id, new Vector3D(100, 50, 100), new Orientation(), 1000, new MockSimulationManager()) { - public MockTarget(string id) : base(id, new Vector3D(100, 50, 100), new Orientation(), 1000, null) { } public override void Update(double deltaTime) { } } } \ No newline at end of file diff --git a/ThreatSource/src/MIssile/TerminalSensitiveMissile.cs b/ThreatSource/src/MIssile/TerminalSensitiveMissile.cs index 042513e..4543908 100644 --- a/ThreatSource/src/MIssile/TerminalSensitiveMissile.cs +++ b/ThreatSource/src/MIssile/TerminalSensitiveMissile.cs @@ -248,12 +248,12 @@ namespace ThreatSource.Missile { Id = $"{Id}_Sub_{i}", InitialPosition = Position, - InitialOrientation = orientationToTarget, - InitialSpeed = 200, // 子弹初始速度 + InitialOrientation = Orientation, // 子弹初始方向等于母弹方向 + InitialSpeed = Velocity.Magnitude(), // 子弹初始速度等于母弹速度 MaxSpeed = 2000, - MaxFlightTime = 50, - MaxFlightDistance = 1000, - MaxAcceleration = 50, + MaxFlightTime = 100, + MaxFlightDistance = 2000, + MaxAcceleration = 1000, ProportionalNavigationCoefficient = 3, Mass = 10, ExplosionRadius = MissileProperties.ExplosionRadius, diff --git a/ThreatSource/src/MIssile/TerminalSensitiveSubmunition.cs b/ThreatSource/src/MIssile/TerminalSensitiveSubmunition.cs index 5c64ff6..ea2668a 100644 --- a/ThreatSource/src/MIssile/TerminalSensitiveSubmunition.cs +++ b/ThreatSource/src/MIssile/TerminalSensitiveSubmunition.cs @@ -138,7 +138,7 @@ namespace ThreatSource.Missile /// 攻击阶段的期望速度 /// 影响末端制导的精度 /// - private const double AttackSpeed = 500; + private double AttackSpeed = 200; /// /// 获取或设置最后一次检测到目标的时间 @@ -416,16 +416,6 @@ namespace ThreatSource.Missile /// private void UpdateStableScanStage(double deltaTime) { - if(!radiometer.IsActive) - { - // 激活毫米波辐射计 - radiometer.Activate(); - } - if(!infraredDetector.IsActive) - { - // 激活红外探测器 - infraredDetector.Activate(); - } if(!rangefinder.IsActive) { // 激活激光测距仪 @@ -439,6 +429,29 @@ namespace ThreatSource.Missile return; } + // 更新螺旋角度 + double oldSpiralAngle = spiralAngle; + spiralAngle = (spiralAngle + SpiralRotationSpeed * deltaTime) % (2 * Math.PI); + Console.WriteLine($"[ANGLE] 螺旋角更新: {oldSpiralAngle * 180 / Math.PI:F2}°({oldSpiralAngle:F6}) -> {spiralAngle * 180 / Math.PI:F2}°({spiralAngle:F6})"); + + // 计算水平速度分量 + double horizontalSpeed = VerticalDeclineSpeed * Math.Tan(ScanAngle); + Vector3D horizontalVelocity = new( + Math.Cos(spiralAngle) * horizontalSpeed, + 0, + Math.Sin(spiralAngle) * horizontalSpeed + ); + + // 更新速度,执行螺旋运动 + Velocity = new(horizontalVelocity.X, -VerticalDeclineSpeed, horizontalVelocity.Z); + + // 更新扫描方向(虽然这时候不开启探测器,但保持方向更新) + scanDirection = new( + Math.Cos(spiralAngle) * Math.Sin(ScanAngle), + -Math.Cos(ScanAngle), + Math.Sin(spiralAngle) * Math.Sin(ScanAngle) + ); + // 如果距离小于等于目标探测距离,则进入目标探测阶段 if (((RangefinderSensorData)rangefinder.GetSensorData()).Distance <= TargetDetectionDistance) { @@ -459,6 +472,17 @@ namespace ThreatSource.Missile /// private void UpdateDetectionStage(double deltaTime) { + // 激活毫米波辐射计 + if(!radiometer.IsActive) + { + radiometer.Activate(); + } + // 激活红外探测器 + if(!infraredDetector.IsActive) + { + infraredDetector.Activate(); + } + // 检查传感器干扰状态 if (IsSensorsJammed()) { @@ -467,7 +491,12 @@ namespace ThreatSource.Missile } // 更新螺旋角度 + double oldSpiralAngle = spiralAngle; spiralAngle = (spiralAngle + SpiralRotationSpeed * deltaTime) % (2 * Math.PI); + if (lastDetectionTime != null) + { + Console.WriteLine($"[DEBUG] 螺旋角更新: {oldSpiralAngle * 180 / Math.PI:F2}° -> {spiralAngle * 180 / Math.PI:F2}°"); + } // 计算水平速度分量 double horizontalSpeed = VerticalDeclineSpeed * Math.Tan(ScanAngle); @@ -492,15 +521,15 @@ namespace ThreatSource.Missile if (isRadiationDetected || isInfraredDetected) { - double currentTime = DateTime.Now.Ticks; + double currentTime = FlightTime; if (lastDetectionTime == null) { lastDetectionTime = currentTime; + Console.WriteLine($"[DEBUG] 首次探测到目标:"); } else { double timeSinceLastDetection = currentTime - lastDetectionTime.Value; - // 重新检测到目标的时间大于等于螺旋周期的90%,则二次确认目标 if (timeSinceLastDetection >= 0.9 * 2 * Math.PI / SpiralRotationSpeed) { Console.WriteLine($"目标确认,进入攻击阶段。距离上次检测时间:{timeSinceLastDetection:F2}秒"); @@ -524,25 +553,38 @@ namespace ThreatSource.Missile /// 时间步长,单位:秒 /// /// 攻击阶段处理: - /// - 获取目标位置 - /// - 计算攻击速度 + /// - 使用当前的螺旋角和锥角计算攻击方向 + /// - 使用扫描方向作为攻击方向,弹丸没有传感器,只进行弹道运动 /// - 更新速度和位置 - /// - 检查命中条件 + /// - 检查命中条件:使用纯几何计算 /// private void UpdateAttackStage(double deltaTime) { - // 攻击逻辑 - SimulationElement target = SimulationManager.GetEntityById(TargetId) as SimulationElement ?? throw new Exception("目标不存在"); - Vector3D targetPosition = target.Position; + // 使用当前的螺旋角和锥角计算攻击方向 + scanDirection = new Vector3D( + Math.Cos(spiralAngle) * Math.Sin(ScanAngle), + -Math.Cos(ScanAngle), + Math.Sin(spiralAngle) * Math.Sin(ScanAngle) + ).Normalize(); - // 计算攻击速度,攻击角度为最后的扫描方向 + // 使用 AttackSpeed 设置攻击速度 Velocity = scanDirection * AttackSpeed; - Position += Velocity * deltaTime; + IsGuidance = false; // 明确声明这是无制导的直线运动 + GuidanceAcceleration = Vector3D.Zero; // 清除任何可能的加速度 - // 检查命中条件 - if ((targetPosition - Position).Magnitude() <= MissileProperties.ExplosionRadius) + // 检查命中条件:使用纯几何计算 + SimulationElement target = SimulationManager.GetEntityById(TargetId) as SimulationElement ?? throw new Exception("目标不存在"); + if ((target.Position - Position).Magnitude() <= MissileProperties.ExplosionRadius) { currentStage = SubmunitionStage.Explode; + return; + } + + // 检查自毁条件 + if (Position.Y <= 0) + { + currentStage = SubmunitionStage.SelfDestruct; + return; } } @@ -659,12 +701,14 @@ namespace ThreatSource.Missile /// public override string GetStatus() { - var status = $"{base.GetStatus()}\n运行状态: {currentStage}\n检测角度: {detectionAngle * 180 / Math.PI:F2}°\n螺旋角度: {spiralAngle * 180 / Math.PI:F2}°\n目标检测: {lastDetectionTime != null}"; + var status = $"{base.GetStatus()}\n" + + $"运行状态: {currentStage}\n" + + $"扫描角度: {spiralAngle * 180 / Math.PI:F2}°, 弧度值: {spiralAngle:F6}\n" + + $"目标检测: {lastDetectionTime != null}"; - // 使用IsSensorsJammed方法检查当前阶段所需传感器的状态 if (IsSensorsJammed()) { - status += "\n传感器受到干扰"; + status += "\n传感器状态: 受到干扰"; } return status; diff --git a/ThreatSource/src/Sensor/LaserRangefinder.cs b/ThreatSource/src/Sensor/LaserRangefinder.cs index 77478bd..18b14aa 100644 --- a/ThreatSource/src/Sensor/LaserRangefinder.cs +++ b/ThreatSource/src/Sensor/LaserRangefinder.cs @@ -95,6 +95,8 @@ namespace ThreatSource.Sensor WaveLength = waveLength; PulseRate = pulseRate; Accuracy = accuracy; + // 初始化距离为最大量程 + currentDistance = maxRange; } /// @@ -110,12 +112,22 @@ namespace ThreatSource.Sensor /// public override void Update(double deltaTime) { - // 激光测距仪的更新逻辑,考虑测量精度 if (IsActive) { - // 计算斜向距离:高度/cos(扫描角度) - double slantRange = submunition.Position.Y / Math.Cos(TerminalSensitiveSubmunition.ScanAngle); + // 计算到地面的垂直距离和水平距离 + double verticalDistance = submunition.Position.Y; + double horizontalDistance = Math.Sqrt( + submunition.Position.X * submunition.Position.X + + submunition.Position.Z * submunition.Position.Z); + + // 计算实际的斜距 + double slantRange = Math.Sqrt(verticalDistance * verticalDistance + horizontalDistance * horizontalDistance); + + // 添加测量精度引入的随机误差 currentDistance = slantRange + (2 * new Random().NextDouble() - 1) * Accuracy; + + // 调试输出 + Console.WriteLine($"激光测距仪 - 垂直距离: {verticalDistance:F2}m, 水平距离: {horizontalDistance:F2}m, 斜距: {slantRange:F2}m, 测量距离: {currentDistance:F2}m"); } } diff --git a/ThreatSource/src/Simulation/Testing/TestSimulationAdapter.cs b/ThreatSource/src/Simulation/Testing/TestSimulationAdapter.cs index 59f6692..ed894ca 100644 --- a/ThreatSource/src/Simulation/Testing/TestSimulationAdapter.cs +++ b/ThreatSource/src/Simulation/Testing/TestSimulationAdapter.cs @@ -9,9 +9,9 @@ namespace ThreatSource.Simulation.Testing /// public class TestSimulationAdapter : ISimulationAdapter { - private readonly Dictionary _testEntities = new(); - private readonly List _receivedEvents = new(); - private readonly List _publishedEvents = new(); + private readonly Dictionary _testEntities = []; + private readonly List _receivedEvents = []; + private readonly List _publishedEvents = []; private ISimulationManager? _simulationManager; /// diff --git a/src/tools/MissileSimulator.cs b/src/tools/MissileSimulator.cs new file mode 100644 index 0000000..b5c1d68 --- /dev/null +++ b/src/tools/MissileSimulator.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Numerics; + +public class MissileSimulator +{ + private List missiles = new List(); + private SimulationManager simulationManager; + private double InitialHeight; + + public void LaunchMissile(Vector3 target) + { + var missile = new TerminalSensitiveSubmunition + { + Position = new Vector3(target.X, target.Y, InitialHeight), + Velocity = new Vector3(0, 0, 0), + Target = target + }; + + missiles.Add(missile); + simulationManager.AddElement(missile); + } +} \ No newline at end of file diff --git a/src/tools/Program.cs b/src/tools/Program.cs new file mode 100644 index 0000000..45ff55b --- /dev/null +++ b/src/tools/Program.cs @@ -0,0 +1,75 @@ +using ThreatSource.Utils; +using ThreatSource.Jamming; + +namespace ThreatSource.Tools +{ + class Program + { + static void Main(string[] args) + { + Console.WriteLine("末敏子弹模拟程序启动..."); + var simulator = new MissileSimulator(); + + // 添加目标 + var targetId = simulator.AddTarget(new Vector3D(100, 0, 100)); + + // 发射导弹 + simulator.LaunchMissile(targetId, new Vector3D(100, 400, 100)); + + // 启动模拟线程 + var simulationThread = new Thread(simulator.Start); + simulationThread.Start(); + + // 等待用户输入命令 + while (true) + { + Console.WriteLine("\n请输入命令(help查看帮助):"); + var command = Console.ReadLine()?.ToLower(); + + switch (command) + { + case "help": + ShowHelp(); + break; + case "ir": + simulator.ApplyJamming(JammingType.Infrared, 100, 5, new Vector3D(0, 0, 0)); + break; + case "mw": + simulator.ApplyJamming(JammingType.MillimeterWave, 200, 5, new Vector3D(0, 0, 0)); + break; + case "laser": + simulator.ApplyJamming(JammingType.Laser, 150, 5, new Vector3D(0, 0, 0)); + break; + case "clear ir": + simulator.ClearJamming(JammingType.Infrared); + break; + case "clear mw": + simulator.ClearJamming(JammingType.MillimeterWave); + break; + case "clear laser": + simulator.ClearJamming(JammingType.Laser); + break; + case "exit": + simulator.Stop(); + return; + default: + Console.WriteLine("未知命令,请输入help查看帮助"); + break; + } + } + } + + static void ShowHelp() + { + Console.WriteLine("可用命令:"); + Console.WriteLine(" help - 显示帮助信息"); + Console.WriteLine(" ir - 应用红外干扰"); + Console.WriteLine(" mw - 应用毫米波干扰"); + Console.WriteLine(" laser - 应用激光干扰"); + Console.WriteLine(" clear ir - 清除红外干扰"); + Console.WriteLine(" clear mw - 清除毫米波干扰"); + Console.WriteLine(" clear laser - 清除激光干扰"); + Console.WriteLine(" exit - 退出程序"); + } + } +} \ No newline at end of file diff --git a/tools/MissileSimulator.cs b/tools/MissileSimulator.cs new file mode 100644 index 0000000..fe8e43d --- /dev/null +++ b/tools/MissileSimulator.cs @@ -0,0 +1,203 @@ +using ThreatSource.Missile; +using ThreatSource.Simulation; +using ThreatSource.Utils; +using ThreatSource.Jamming; +using ThreatSource.Sensor; + +namespace ThreatSource.Tools +{ + /// + /// 导弹模拟程序 + /// + public class MissileSimulator + { + private readonly ISimulationManager simulationManager; + private readonly List missiles; + private readonly List targets; + private bool isRunning; + private readonly double timeStep = 0.005; // 时间步长,单位:秒 + + /// + /// 初始化导弹模拟器 + /// + public MissileSimulator() + { + simulationManager = new SimulationManager(); + missiles = new List(); + targets = new List(); + isRunning = false; + } + + /// + /// 添加目标 + /// + /// 目标位置 + /// 目标ID + public string AddTarget(Vector3D position) + { + string targetId = $"target_{targets.Count + 1}"; + var target = new MockTarget(targetId) + { + Position = position + }; + targets.Add(target); + simulationManager.RegisterEntity(targetId, target); + Console.WriteLine($"添加目标 {targetId},位置:{position}"); + return targetId; + } + + /// + /// 发射导弹 + /// + /// 目标ID + /// 发射位置 + public void LaunchMissile(string targetId, Vector3D position) + { + var properties = new MissileProperties + { + Mass = 10, + ExplosionRadius = 5, + MaxSpeed = 2000 + }; + + var missile = new TerminalSensitiveSubmunition(targetId, properties, simulationManager) + { + Position = position, + Velocity = new Vector3D(0, -10, 0) // 初始垂直下降速度 + }; + + missile.Activate(); + missiles.Add(missile); + Console.WriteLine($"发射导弹,目标:{targetId},位置:{position}"); + } + + /// + /// 应用干扰 + /// + /// 干扰类型 + /// 干扰功率 + /// 持续时间 + /// 干扰源位置 + public void ApplyJamming(JammingType type, double power, double duration, Vector3D position) + { + var jammingParams = new JammingParameters + { + Type = type, + Power = power, + Duration = duration, + Direction = new Vector3D(1, 0, 0) + }; + + foreach (var missile in missiles) + { + // 获取导弹内部的传感器 + var infraredDetector = missile.GetType().GetField("infraredDetector", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)?.GetValue(missile) as InfraredDetector; + var radiometer = missile.GetType().GetField("radiometer", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)?.GetValue(missile) as MillimeterWaveRadiometer; + var rangefinder = missile.GetType().GetField("rangefinder", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)?.GetValue(missile) as LaserRangefinder; + var altimeter = missile.GetType().GetField("altimeter", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)?.GetValue(missile) as MillimeterWaveAltimeter; + + switch (type) + { + case JammingType.Infrared: + infraredDetector?.ApplyJamming(jammingParams); + break; + case JammingType.MillimeterWave: + radiometer?.ApplyJamming(jammingParams); + altimeter?.ApplyJamming(jammingParams); + break; + case JammingType.Laser: + rangefinder?.ApplyJamming(jammingParams); + break; + } + } + + Console.WriteLine($"应用{type}干扰,功率:{power}瓦特,持续时间:{duration}秒,位置:{position}"); + } + + /// + /// 清除干扰 + /// + /// 干扰类型 + public void ClearJamming(JammingType type) + { + foreach (var missile in missiles) + { + // 获取导弹内部的传感器 + var infraredDetector = missile.GetType().GetField("infraredDetector", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)?.GetValue(missile) as InfraredDetector; + var radiometer = missile.GetType().GetField("radiometer", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)?.GetValue(missile) as MillimeterWaveRadiometer; + var rangefinder = missile.GetType().GetField("rangefinder", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)?.GetValue(missile) as LaserRangefinder; + var altimeter = missile.GetType().GetField("altimeter", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)?.GetValue(missile) as MillimeterWaveAltimeter; + + switch (type) + { + case JammingType.Infrared: + infraredDetector?.ClearJamming(type); + break; + case JammingType.MillimeterWave: + radiometer?.ClearJamming(type); + altimeter?.ClearJamming(type); + break; + case JammingType.Laser: + rangefinder?.ClearJamming(type); + break; + } + } + + Console.WriteLine($"清除{type}干扰"); + } + + /// + /// 开始模拟 + /// + public void Start() + { + isRunning = true; + Console.WriteLine("开始模拟..."); + + while (isRunning) + { + // 更新所有实体 + foreach (var missile in missiles.ToList()) + { + missile.Update(timeStep); + Console.WriteLine($"\n导弹状态:\n{missile.GetStatus()}"); + } + + foreach (var target in targets) + { + target.Update(timeStep); + } + + // 移除已经爆炸或自毁的导弹 + missiles.RemoveAll(m => m.GetType().GetField("currentStage", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)?.GetValue(m)?.ToString() is "Explode" or "SelfDestruct"); + + // 如果所有导弹都已经结束,停止模拟 + if (!missiles.Any()) + { + Stop(); + } + + Thread.Sleep((int)(timeStep * 1000)); // 按照时间步长暂停 + } + } + + /// + /// 停止模拟 + /// + public void Stop() + { + isRunning = false; + Console.WriteLine("模拟结束"); + } + } + + /// + /// 模拟目标类 + /// + public class MockTarget : SimulationElement + { + public MockTarget(string id) : base(id, new Vector3D(0, 0, 0), new Orientation(), 1000, null) { } + + public override void Update(double deltaTime) { } + } +} \ No newline at end of file diff --git a/tools/Program.cs b/tools/Program.cs new file mode 100644 index 0000000..d2698d1 --- /dev/null +++ b/tools/Program.cs @@ -0,0 +1,75 @@ +using ThreatSource.Utils; +using ThreatSource.Jamming; + +namespace ThreatSource.Tools +{ + class Program + { + static void Main(string[] args) + { + Console.WriteLine("末敏子弹模拟程序启动..."); + var simulator = new MissileSimulator(); + + // 添加目标 + var targetId = simulator.AddTarget(new Vector3D(0, 0, 0)); + + // 发射导弹 + simulator.LaunchMissile(targetId, new Vector3D(50, 400, 50)); + + // 启动模拟线程 + var simulationThread = new Thread(simulator.Start); + simulationThread.Start(); + + // 等待用户输入命令 + while (true) + { + Console.WriteLine("\n请输入命令(help查看帮助):"); + var command = Console.ReadLine()?.ToLower(); + + switch (command) + { + case "help": + ShowHelp(); + break; + case "ir": + simulator.ApplyJamming(JammingType.Infrared, 100, 5, new Vector3D(0, 0, 0)); + break; + case "mw": + simulator.ApplyJamming(JammingType.MillimeterWave, 200, 5, new Vector3D(0, 0, 0)); + break; + case "laser": + simulator.ApplyJamming(JammingType.Laser, 150, 5, new Vector3D(0, 0, 0)); + break; + case "clear ir": + simulator.ClearJamming(JammingType.Infrared); + break; + case "clear mw": + simulator.ClearJamming(JammingType.MillimeterWave); + break; + case "clear laser": + simulator.ClearJamming(JammingType.Laser); + break; + case "exit": + simulator.Stop(); + return; + default: + Console.WriteLine("未知命令,请输入help查看帮助"); + break; + } + } + } + + static void ShowHelp() + { + Console.WriteLine("可用命令:"); + Console.WriteLine(" help - 显示帮助信息"); + Console.WriteLine(" ir - 应用红外干扰"); + Console.WriteLine(" mw - 应用毫米波干扰"); + Console.WriteLine(" laser - 应用激光干扰"); + Console.WriteLine(" clear ir - 清除红外干扰"); + Console.WriteLine(" clear mw - 清除毫米波干扰"); + Console.WriteLine(" clear laser - 清除激光干扰"); + Console.WriteLine(" exit - 退出程序"); + } + } +} \ No newline at end of file diff --git a/tools/ThreatSource.Tools.csproj b/tools/ThreatSource.Tools.csproj new file mode 100644 index 0000000..197e1de --- /dev/null +++ b/tools/ThreatSource.Tools.csproj @@ -0,0 +1,14 @@ + + + + Exe + net8.0 + enable + enable + + + + + + +