diff --git a/ThreatSource.Tests/src/Missile/TerminalSensitiveSubmunitionTests.cs b/ThreatSource.Tests/src/Missile/TerminalSensitiveSubmunitionTests.cs index 40668dd..ed76345 100644 --- a/ThreatSource.Tests/src/Missile/TerminalSensitiveSubmunitionTests.cs +++ b/ThreatSource.Tests/src/Missile/TerminalSensitiveSubmunitionTests.cs @@ -236,5 +236,146 @@ namespace ThreatSource.Tests.Missile _output.WriteLine($"修正后的水平方向: {horizontalCorrectedDirection}"); _output.WriteLine($"修正后的水平夹角: {correctedHorizontalAngle:F2}°"); } + + [Theory] + [InlineData(0, 0, 0, 44, 76.5, 0)] // 原点场景 + [InlineData(100, 0, 0, 144, 76.5, 0)] // X轴平移 + [InlineData(0, 0, 100, 44, 76.5, 100)] // Z轴平移 + [InlineData(100, 0, 100, 144, 76.5, 100)] // XZ平面平移 + public void TestTargetDetectionAtDifferentPositions( + double targetX, double targetY, double targetZ, + double submunitionX, double submunitionY, double submunitionZ) + { + try + { + // 设置目标位置 + var targetPosition = new Vector3D(targetX, targetY, targetZ); + _tank.Position = targetPosition; + + // 设置子弹位置 + var submunitionPosition = new Vector3D(submunitionX, submunitionY, submunitionZ); + _submunition.Position = submunitionPosition; + + // 计算从子弹到目标的向量 + var toTarget = (targetPosition - submunitionPosition).Normalize(); + + // 设置子弹的扫描方向直接指向目标 + var scanDirection = toTarget; + var field = typeof(TerminalSensitiveSubmunition) + .GetField("scanDirection", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance); + + if (field == null) + { + _output.WriteLine("无法找到scanDirection字段"); + Assert.Fail("无法找到scanDirection字段"); + return; + } + + field.SetValue(_submunition, scanDirection); + + // 执行目标检测 + var detectionResult = _submunition.DetectTarget(30); // 30度视场角 + + // 输出测试信息 + _output.WriteLine($"\n=== 测试场景 ==="); + _output.WriteLine($"目标位置: ({targetX}, {targetY}, {targetZ})"); + _output.WriteLine($"子弹位置: ({submunitionX}, {submunitionY}, {submunitionZ})"); + _output.WriteLine($"相对位置向量: {toTarget}"); + _output.WriteLine($"扫描方向: {scanDirection}"); + _output.WriteLine($"检测结果: {(detectionResult.Target != null ? "已检测到目标" : "未检测到目标")}"); + + if (detectionResult.Target != null) + { + _output.WriteLine($"目标方位角: {detectionResult.Angle * 180 / Math.PI:F2}度"); + } + else + { + _output.WriteLine("警告:未检测到目标!"); + } + + // 验证检测结果 + Assert.True(detectionResult.Target != null, $"在位置({targetX}, {targetY}, {targetZ})处未能检测到目标"); + Assert.True(detectionResult.Angle.HasValue, "检测结果中没有方位角信息"); + } + catch (Exception ex) + { + _output.WriteLine($"\n发生异常: {ex.Message}"); + _output.WriteLine($"堆栈跟踪: {ex.StackTrace}"); + throw; + } + } + + [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) + { + try + { + // 设置目标位置 + var targetPosition = new Vector3D(targetX, targetY, targetZ); + _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++) + { + _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()); + } + } + + // 验证是否检测到目标 + 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; + } + } } } \ No newline at end of file diff --git a/ThreatSource/src/MIssile/TerminalSensitiveMissile.cs b/ThreatSource/src/MIssile/TerminalSensitiveMissile.cs index 4543908..c36deb7 100644 --- a/ThreatSource/src/MIssile/TerminalSensitiveMissile.cs +++ b/ThreatSource/src/MIssile/TerminalSensitiveMissile.cs @@ -43,6 +43,16 @@ namespace ThreatSource.Missile /// private const double SeparationDistance = 1000; + /// + /// 子弹分离角度(与地面的夹角) + /// + /// + /// 单位:度 + /// 子弹从母弹分离时与地面的夹角 + /// 默认设置为60度 + /// + private const double SubmunitionSeparationAngle = 45; + /// /// 触发分离的距离阈值 /// @@ -225,19 +235,32 @@ namespace ThreatSource.Missile Console.WriteLine($"开始分离,当前位置:{Position},分离点:{separationPoint}"); Debug.WriteLine($"开始分离,当前位置:{Position},分离点:{separationPoint}"); - // 获取目标位置 - SimulationElement target = SimulationManager.GetEntityById(TargetId) as SimulationElement ?? throw new Exception("目标不存在"); - Vector3D targetPosition = target.Position; - Console.WriteLine($"目标位置:{targetPosition}"); - Debug.WriteLine($"目标位置:{targetPosition}"); + // 获取母弹当前的方向向量 + Vector3D currentDirection = Orientation.ToVector(); - // 计算子弹朝向目标的方向 - Vector3D directionToTarget = (targetPosition - this.Position).Normalize(); - Orientation orientationToTarget = Orientation.FromVector(directionToTarget); - Console.WriteLine($"子弹朝向:{directionToTarget}"); - Debug.WriteLine($"子弹朝向:{directionToTarget}"); + // 计算水平方向(保持母弹的水平方向分量) + Vector3D horizontalDirection = new Vector3D(currentDirection.X, 0, currentDirection.Z).Normalize(); - // 创建并释子弹 + // 计算分离角度(弧度) + double separationAngleRad = SubmunitionSeparationAngle * Math.PI / 180.0; + + // 计算子弹的初始方向(保持水平方向不变,设置垂直角度为-60度) + Vector3D initialDirection = new Vector3D( + horizontalDirection.X, + -Math.Tan(separationAngleRad), // 负号表示向下的60度角 + horizontalDirection.Z + ).Normalize(); + + // 根据新方向创建朝向 + Orientation separationOrientation = Orientation.FromVector(initialDirection); + Console.WriteLine($"母弹当前方向:{currentDirection}"); + Console.WriteLine($"子弹分离角度:{SubmunitionSeparationAngle}度(向下)"); + Console.WriteLine($"子弹初始方向:{initialDirection}"); + Debug.WriteLine($"母弹当前方向:{currentDirection}"); + Debug.WriteLine($"子弹分离角度:{SubmunitionSeparationAngle}度(向下)"); + Debug.WriteLine($"子弹初始方向:{initialDirection}"); + + // 创建并释放子弹 for (int i = 0; i < SubmunitionCount; i++) { Console.WriteLine($"创建子弹 {i}"); @@ -248,7 +271,7 @@ namespace ThreatSource.Missile { Id = $"{Id}_Sub_{i}", InitialPosition = Position, - InitialOrientation = Orientation, // 子弹初始方向等于母弹方向 + InitialOrientation = separationOrientation, // 使用新计算的分离方向 InitialSpeed = Velocity.Magnitude(), // 子弹初始速度等于母弹速度 MaxSpeed = 2000, MaxFlightTime = 100, diff --git a/ThreatSource/src/MIssile/TerminalSensitiveSubmunition.cs b/ThreatSource/src/MIssile/TerminalSensitiveSubmunition.cs index 76a7c0d..5ac1f4f 100644 --- a/ThreatSource/src/MIssile/TerminalSensitiveSubmunition.cs +++ b/ThreatSource/src/MIssile/TerminalSensitiveSubmunition.cs @@ -75,13 +75,13 @@ namespace ThreatSource.Missile private SubmunitionStage currentStage; /// - /// 螺旋扫描旋转速度,单位:弧度/秒 + /// 减速加速度,单位:米/秒² /// /// - /// 定义了螺旋扫描时的旋转角速度 - /// 4转/秒 = 8π弧度/秒 + /// 减速阶段的减速度大小 + /// 影响速度调整的快慢 /// - private const double SpiralRotationSpeed = 8 * Math.PI; + private const double DecelerationAcceleration = 250; /// /// 减速阶段末速,单位:米/秒 @@ -89,15 +89,32 @@ namespace ThreatSource.Missile /// /// 定义了减速阶段的垂直下降速度 /// - private const double DecelerationEndSpeed = 40; + private const double DecelerationEndSpeed = 50; + /// + /// 开伞高度,单位:米 + /// + /// + /// 打开降落伞的高度阈值 + /// 影响降落伞打开阶段的触发时机 + /// + private const double ParachuteDeploymentHeight = 400; /// /// 降落伞减速加速度,单位:米/秒² /// /// /// 定义了降落伞减速加速度 /// - private const double ParachuteDeceleration = 50; + private const double ParachuteDeceleration = 140; + + /// + /// 稳定扫描高度,单位:米 + /// + /// + /// 开始螺旋扫描的高度阈值 + /// 影响扫描阶段的触发时机 + /// + private const double StableScanHeight = 200; /// /// 垂直下降速度,单位:米/秒 @@ -107,6 +124,15 @@ namespace ThreatSource.Missile /// private const double VerticalDeclineSpeed = 10; + /// + /// 螺旋扫描旋转速度,单位:弧度/秒 + /// + /// + /// 定义了螺旋扫描时的旋转角速度 + /// 4转/秒 = 8π弧度/秒 + /// + private const double SpiralRotationSpeed = 8 * Math.PI; + /// /// 扫描角度,单位:弧度 /// @@ -116,33 +142,6 @@ namespace ThreatSource.Missile /// public const double ScanAngle = 30 * Math.PI / 180; - /// - /// 开伞高度,单位:米 - /// - /// - /// 打开降落伞的高度阈值 - /// 影响降落伞打开阶段的触发时机 - /// - private const double ParachuteDeploymentHeight = 400; - - /// - /// 减速加速度,单位:米/秒² - /// - /// - /// 减速阶段的减速度大小 - /// 影响速度调整的快慢 - /// - private const double DecelerationAcceleration = 50; - - /// - /// 稳定扫描高度,单位:米 - /// - /// - /// 开始螺旋扫描的高度阈值 - /// 影响扫描阶段的触发时机 - /// - private const double StableScanHeight = 200; - /// /// 目标探测距离,单位:米 /// @@ -386,7 +385,8 @@ namespace ThreatSource.Missile if (Velocity.Magnitude() <= DecelerationEndSpeed) { - Velocity = new Vector3D(0, -DecelerationEndSpeed, 0); + //垂直速度设为减速阶段末速 + Velocity = new Vector3D(Velocity.X, -DecelerationEndSpeed, Velocity.Z); GuidanceAcceleration = Vector3D.Zero; } @@ -402,6 +402,10 @@ namespace ThreatSource.Missile { // 如果是,则进入降落伞打开阶段 currentStage = SubmunitionStage.ParachuteDeployment; + + //垂直速度设为减速阶段末速 + Velocity = new Vector3D(Velocity.X, -DecelerationEndSpeed, Velocity.Z); + GuidanceAcceleration = Vector3D.Zero; } } @@ -850,6 +854,7 @@ namespace ThreatSource.Missile $"运行状态: {currentStage}\n" + $"扫描角度: {spiralAngle * 180 / Math.PI:F2}°, 弧度值: {spiralAngle:F6}\n" + $"目标检测: {lastDetectionTime != null}\n" + + $"目标位置: {target.Position}\n" + $"目标距离: {distanceToTarget:F2}米\n" + $"传感器状态: {(IsSensorsJammed() ? "传感器受到干扰" : "正常工作")}"; diff --git a/tools/ComprehensiveMissileSimulator.cs b/tools/ComprehensiveMissileSimulator.cs new file mode 100644 index 0000000..d4e8c57 --- /dev/null +++ b/tools/ComprehensiveMissileSimulator.cs @@ -0,0 +1,546 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using System.Linq; +using ThreatSource.Missile; +using ThreatSource.Simulation; +using ThreatSource.Utils; +using ThreatSource.Jamming; +using ThreatSource.Sensor; +using ThreatSource.Target; +using ThreatSource.Guidance; +using ThreatSource.Indicator; + +namespace ThreatSource.Tools.MissileSimulation +{ + /// + /// 综合导弹模拟器 - 支持6种不同类型的导弹模拟 + /// + public class ComprehensiveMissileSimulator + { + // 定义仿真结束事件 + public event EventHandler? SimulationEnded; + + private readonly ISimulationManager simulationManager; + private readonly Dictionary missiles; + private readonly Dictionary targets; + private readonly Dictionary sensors; + private Dictionary missileActiveStatus; + private bool isRunning; + private readonly double timeStep = 0.002; // 时间步长,单位:秒 + + /// + /// 初始化综合导弹模拟器 + /// + public ComprehensiveMissileSimulator() + { + simulationManager = new SimulationManager(); + missiles = new Dictionary(); + targets = new Dictionary(); + sensors = new Dictionary(); + missileActiveStatus = new Dictionary(); + isRunning = false; + InitializeSimulation(); + } + + /// + /// 初始化仿真环境 + /// + private void InitializeSimulation() + { + // 添加目标(坦克) + AddTarget("Tank_1", new Vector3D(0, 0, 0)); + + // 添加各种类型的导弹 + AddLaserSemiActiveMissile(); + AddLaserBeamRiderMissile(); + AddTerminalSensitiveMissile(); + AddInfraredCommandMissile(); + AddInfraredImagingMissile(); + AddMillimeterWaveMissile(); + + // 添加各种传感器和指示器 + AddSensorsAndDesignators(); + + // 初始化所有导弹的激活状态为false + foreach (var missile in missiles.Keys) + { + missileActiveStatus[missile] = false; + missiles[missile].Activate(); // 激活导弹,但不会更新状态 + } + } + + /// + /// 添加目标 + /// + private void AddTarget(string targetId, Vector3D position) + { + var target = new Tank(targetId, position, 0, simulationManager) + { + Position = position + }; + targets[targetId] = target; + simulationManager.RegisterEntity(targetId, target); + Console.WriteLine($"添加目标 {targetId},位置:{position}"); + } + + /// + /// 添加激光半主动制导导弹 + /// + private void AddLaserSemiActiveMissile() + { + var properties = new MissileProperties + { + 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.1, 0), + Type = MissileType.LaserSemiActiveGuidance + }; + + var missile = new LaserSemiActiveGuidedMissile(properties, simulationManager); + missiles["LSGM_1"] = missile; + } + + /// + /// 添加激光驾束制导导弹 + /// + private void AddLaserBeamRiderMissile() + { + var properties = new MissileProperties + { + 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), + Type = MissileType.LaserBeamRiderGuidance + }; + + var missile = new LaserBeamRiderMissile(properties, simulationManager); + missiles["LBRM_1"] = missile; + } + + /// + /// 添加末敏弹 + /// + private void AddTerminalSensitiveMissile() + { + var properties = new MissileProperties + { + 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), + Type = MissileType.TerminalSensitiveMissile + }; + + var missile = new TerminalSensitiveMissile("Tank_1", properties, simulationManager); + missiles["TSM_1"] = missile; + } + + /// + /// 添加红外指令制导导弹 + /// + private void AddInfraredCommandMissile() + { + var properties = new MissileProperties + { + Id = "ICGM_1", + Mass = 50, + ExplosionRadius = 5, + MaxSpeed = 400, + MaxFlightTime = 60, + MaxFlightDistance = 5000, + MaxAcceleration = 100, + InitialPosition = new Vector3D(2000, 10, 100), + InitialSpeed = 300, + InitialOrientation = new Orientation(Math.PI, 0.0, 0), + Type = MissileType.InfraredCommandGuidance + }; + + var missile = new InfraredCommandGuidedMissile(properties, simulationManager); + missiles["ICGM_1"] = missile; + } + + /// + /// 添加红外成像末制导导弹 + /// + private void AddInfraredImagingMissile() + { + var properties = new MissileProperties + { + 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), + Type = MissileType.InfraredImagingTerminalGuidance + }; + + var missile = new InfraredImagingTerminalGuidedMissile(properties, simulationManager); + missiles["ITGM_1"] = missile; + } + + /// + /// 添加毫米波末制导导弹 + /// + private void AddMillimeterWaveMissile() + { + var properties = new MissileProperties + { + 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), + Type = MissileType.MillimeterWaveTerminalGuidance + }; + + var missile = new MillimeterWaveTerminalGuidedMissile(properties, simulationManager); + missiles["MMWG_1"] = missile; + } + + /// + /// 添加传感器和指示器 + /// + 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 = 1e6, + LaserDivergenceAngle = 0.01 + }, + simulationManager + ); + sensors["LD_1"] = laserDesignator; + + // 添加激光驾束仪 + 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 + ); + sensors["LBR_1"] = laserBeamRider; + + // 添加红外测角仪 + 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 + ); + sensors["IT_1"] = infraredTracker; + } + + /// + /// 选择要激活的导弹 + /// + public void SelectMissile(string missileId) + { + if (!missiles.ContainsKey(missileId)) + { + Console.WriteLine($"错误:找不到导弹 {missileId}"); + return; + } + + // 重置所有导弹的激活状态 + foreach (var id in missiles.Keys) + { + missileActiveStatus[id] = false; + } + + // 激活选中的导弹 + missileActiveStatus[missileId] = true; + Console.WriteLine($"已选择导弹:{missileId}"); + + // 激活相关的传感器和指示器 + ActivateRelatedSensors(missileId); + } + + /// + /// 激活与导弹相关的传感器和指示器 + /// + private void ActivateRelatedSensors(string missileId) + { + // 停用所有传感器 + foreach (var sensor in sensors.Values) + { + sensor.Deactivate(); + } + + // 根据导弹类型激活相应的传感器 + switch (missileId) + { + case "LSGM_1": // 激光半主动制导导弹 + if (sensors.ContainsKey("LD_1")) + { + sensors["LD_1"].Activate(); + } + break; + case "LBRM_1": // 激光驾束制导导弹 + if (sensors.ContainsKey("LBR_1")) + { + sensors["LBR_1"].Activate(); + } + break; + case "ICGM_1": // 红外指令制导导弹 + case "ITGM_1": // 红外成像末制导导弹 + if (sensors.ContainsKey("IT_1")) + { + sensors["IT_1"].Activate(); + } + break; + case "TSM_1": // 末敏弹 + case "MMWG_1": // 毫米波末制导导弹 + // 这些导弹使用自身的传感器系统 + break; + } + } + + /// + /// 应用干扰 + /// + 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.Values) + { + if (missile is BaseMissile actualMissile) + { + // 获取导弹内部的传感器 + var infraredDetector = actualMissile.GetType().GetField("infraredDetector", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)?.GetValue(actualMissile) as InfraredDetector; + var radiometer = actualMissile.GetType().GetField("radiometer", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)?.GetValue(actualMissile) as MillimeterWaveRadiometer; + var rangefinder = actualMissile.GetType().GetField("rangefinder", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)?.GetValue(actualMissile) as LaserRangefinder; + var altimeter = actualMissile.GetType().GetField("altimeter", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)?.GetValue(actualMissile) 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; + } + } + } + } + + /// + /// 清除干扰 + /// + public void ClearJamming(JammingType type) + { + var jammingParams = new JammingParameters + { + Type = type, + Power = 0, + Duration = 0, + Direction = new Vector3D(1, 0, 0) + }; + + foreach (var missile in missiles.Values) + { + if (missile is BaseMissile actualMissile) + { + // 获取导弹内部的传感器 + var infraredDetector = actualMissile.GetType().GetField("infraredDetector", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)?.GetValue(actualMissile) as InfraredDetector; + var radiometer = actualMissile.GetType().GetField("radiometer", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)?.GetValue(actualMissile) as MillimeterWaveRadiometer; + var rangefinder = actualMissile.GetType().GetField("rangefinder", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)?.GetValue(actualMissile) as LaserRangefinder; + var altimeter = actualMissile.GetType().GetField("altimeter", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)?.GetValue(actualMissile) 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; + } + } + } + } + + /// + /// 开始模拟 + /// + public void Start() + { + isRunning = true; + bool hasActiveEntities = true; + Console.WriteLine("开始综合导弹模拟..."); + + while (isRunning) + { + hasActiveEntities = false; + // 更新所有导弹 + foreach (var missile in missiles.Values) + { + if (missile.IsActive && missileActiveStatus[missile.Id]) + { + hasActiveEntities = true; + missile.Update(timeStep); + Console.WriteLine($"\n导弹状态:\n{missile.GetStatus()}"); + } + } + + // 获取并更新所有子弹 + var allEntities = simulationManager.GetAllEntities(); + foreach (var entity in allEntities) + { + if (entity is TerminalSensitiveSubmunition submunition && submunition.IsActive) + { + hasActiveEntities = true; + submunition.Update(timeStep); + Console.WriteLine($"\n子弹状态:\n{submunition.GetStatus()}"); + } + } + + // 如果没有活动的导弹和子弹,退出模拟 + if (!hasActiveEntities) + { + isRunning = false; + // 触发仿真结束事件 + SimulationEnded?.Invoke(this, EventArgs.Empty); + break; + } + + foreach (var target in targets.Values) + { + target.Update(timeStep); + } + + foreach (var sensor in sensors.Values) + { + if (sensor.IsActive) + { + sensor.Update(timeStep); + } + } + + Thread.Sleep((int)(timeStep * 1000)); + } + } + + /// + /// 停止模拟 + /// + public void Stop() + { + isRunning = false; + Console.WriteLine("模拟结束"); + } + + /// + /// 获取当前活动的传感器列表 + /// + public (string Id, string Name, bool IsActive)[] GetActiveSensors() + { + return sensors.Select(s => ( + s.Value.Id, + GetSensorDisplayName(s.Value), + s.Value.IsActive + )).ToArray(); + } + + /// + /// 获取传感器的显示名称 + /// + private string GetSensorDisplayName(SimulationElement sensor) + { + return sensor switch + { + LaserDesignator _ => "激光目标指示器", + LaserBeamRider _ => "激光驾束仪", + InfraredTracker _ => "红外测角仪", + _ => sensor.Id + }; + } + + /// + /// 切换传感器的激活状态 + /// + public void ToggleSensor(string sensorId) + { + if (sensors.TryGetValue(sensorId, out var sensor)) + { + if (sensor.IsActive) + sensor.Deactivate(); + else + sensor.Activate(); + + Console.WriteLine($"传感器 {GetSensorDisplayName(sensor)} 已{(sensor.IsActive ? "激活" : "停用")}"); + } + } + } +} \ No newline at end of file diff --git a/tools/MissileSimulator.cs b/tools/MissileSimulator.cs deleted file mode 100644 index 51b605f..0000000 --- a/tools/MissileSimulator.cs +++ /dev/null @@ -1,217 +0,0 @@ -using ThreatSource.Missile; -using ThreatSource.Simulation; -using ThreatSource.Utils; -using ThreatSource.Jamming; -using ThreatSource.Sensor; -using ThreatSource.Target; -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.0025; // 时间步长,单位:秒 - - /// - /// 初始化导弹模拟器 - /// - 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, simulationManager) - { - 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 = 0.1, - 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); - 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, ITarget - { - public MockTarget(string id, ISimulationManager simulationManager) : base(id, new Vector3D(0, 0, 0), new Orientation(), 1000, simulationManager) { } - - public override void Update(double deltaTime) { } - - public string Type => "Tank"; - - // 设置目标的物理尺寸 - public double Length => 6.0; // 长度 6 米 - public double Width => 3.0; // 宽度 3 米 - public double Height => 2.5; // 高度 2.5 米 - - // 设置目标的特征参数 - 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 d31bdd8..21b34c6 100644 --- a/tools/Program.cs +++ b/tools/Program.cs @@ -1,75 +1,206 @@ using ThreatSource.Utils; using ThreatSource.Jamming; +using System; +using System.Threading; -namespace ThreatSource.Tools +namespace ThreatSource.Tools.MissileSimulation { 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(40, 450, 40)); - - // 启动模拟线程 - var simulationThread = new Thread(simulator.Start); - simulationThread.Start(); - - // 等待用户输入命令 + Console.WriteLine("综合导弹模拟程序启动..."); + var simulator = new ComprehensiveMissileSimulator(); + + // 标记是否收到仿真结束事件 + var simulationEndedEvent = new ManualResetEvent(false); + + // 订阅仿真结束事件 + simulator.SimulationEnded += (sender, e) => { + simulationEndedEvent.Set(); + }; + while (true) { - Console.WriteLine("\n请输入命令(help查看帮助):"); - var command = Console.ReadLine()?.ToLower(); - - switch (command) + // 显示主菜单,如果返回false则退出程序 + if (!ShowMainMenu(simulator)) { - 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; + break; } + + // 重置事件状态 + simulationEndedEvent.Reset(); + + // 开始仿真 + var simulationThread = new Thread(simulator.Start); + simulationThread.Start(); + + // 等待退出命令 + Console.WriteLine("\n仿真已开始运行。输入 'exit' 退出程序。"); + bool exitProgram = false; + while (true) + { + if (Console.KeyAvailable) + { + var input = Console.ReadLine()?.ToLower(); + if (input == "exit") + { + simulator.Stop(); + exitProgram = true; + break; + } + } + + // 检查仿真是否结束 + if (simulationEndedEvent.WaitOne(100)) // 等待100ms + { + break; + } + } + + if (exitProgram) + { + break; + } + + // 等待仿真线程完全结束 + simulationThread.Join(); + + // 显示分隔线和新的仿真选项 + Console.WriteLine("\n" + new string('=', 50)); + Console.WriteLine("当前导弹仿真结束,准备开始新的仿真..."); + Console.WriteLine(new string('=', 50) + "\n"); + } + + Console.WriteLine("\n程序已退出。"); + } + + static bool ShowMainMenu(ComprehensiveMissileSimulator simulator) + { + Console.WriteLine("=== 导弹仿真系统主菜单 ===\n"); + + // 第一步:选择导弹 + if (!SelectMissile(simulator)) + return false; + + // 第二步:配置传感器 + if (!ConfigureSensors(simulator)) + return false; + + // 第三步:配置干扰 + if (!ConfigureJamming(simulator)) + return false; + + return true; + } + + static bool SelectMissile(ComprehensiveMissileSimulator simulator) + { + var missiles = new[] + { + ("LSGM_1", "激光半主动制导导弹"), + ("LBRM_1", "激光驾束制导导弹"), + ("TSM_1", "末敏弹"), + ("ICGM_1", "红外指令制导导弹"), + ("ITGM_1", "红外成像末制导导弹"), + ("MMWG_1", "毫米波末制导导弹") + }; + + while (true) + { + Console.WriteLine("\n第一步:请选择导弹类型:"); + for (int i = 0; i < missiles.Length; i++) + { + Console.WriteLine($" {i + 1}. {missiles[i].Item2}"); + } + Console.WriteLine(" exit. 退出程序"); + + var input = Console.ReadLine()?.ToLower(); + if (input == "exit") + return false; + + if (int.TryParse(input, out int choice) && + choice >= 1 && choice <= missiles.Length) + { + simulator.SelectMissile(missiles[choice - 1].Item1); + return true; + } + Console.WriteLine("无效选择,请重试"); } } - - static void ShowHelp() + + static bool ConfigureSensors(ComprehensiveMissileSimulator simulator) { - 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 - 退出程序"); + while (true) + { + Console.WriteLine("\n第二步:配置传感器和指示器"); + Console.WriteLine("当前传感器状态:"); + var sensors = simulator.GetActiveSensors(); + for (int i = 0; i < sensors.Length; i++) + { + Console.WriteLine($" {i + 1}. {sensors[i].Name} [{(sensors[i].IsActive ? "激活" : "未激活")}]"); + } + Console.WriteLine(" 0. 继续下一步"); + Console.WriteLine(" exit. 退出程序"); + + var input = Console.ReadLine()?.ToLower(); + if (input == "exit") + return false; + + if (int.TryParse(input, out int choice)) + { + if (choice == 0) return true; + if (choice >= 1 && choice <= sensors.Length) + { + simulator.ToggleSensor(sensors[choice - 1].Id); + continue; + } + } + Console.WriteLine("无效选择,请重试"); + } + } + + static bool ConfigureJamming(ComprehensiveMissileSimulator simulator) + { + var jammingTypes = new[] + { + (JammingType.Infrared, "红外干扰"), + (JammingType.MillimeterWave, "毫米波干扰"), + (JammingType.Laser, "激光干扰") + }; + + var jammingStatus = new bool[jammingTypes.Length]; + + while (true) + { + Console.WriteLine("\n第三步:配置干扰方式"); + Console.WriteLine("当前干扰状态:"); + for (int i = 0; i < jammingTypes.Length; i++) + { + Console.WriteLine($" {i + 1}. {jammingTypes[i].Item2} [{(jammingStatus[i] ? "激活" : "未激活")}]"); + } + Console.WriteLine(" 0. 开始仿真"); + Console.WriteLine(" exit. 退出程序"); + + var input = Console.ReadLine()?.ToLower(); + if (input == "exit") + return false; + + if (int.TryParse(input, out int choice)) + { + if (choice == 0) return true; + if (choice >= 1 && choice <= jammingTypes.Length) + { + jammingStatus[choice - 1] = !jammingStatus[choice - 1]; + if (jammingStatus[choice - 1]) + simulator.ApplyJamming(jammingTypes[choice - 1].Item1, 100, 5, new Vector3D(0, 0, 0)); + else + simulator.ClearJamming(jammingTypes[choice - 1].Item1); + continue; + } + } + Console.WriteLine("无效选择,请重试"); + } } } } \ No newline at end of file