增加了Indicator基类,实现了红外测角仪的干扰处理

This commit is contained in:
Tian jianyong 2025-03-19 12:27:53 +08:00
parent 8a27dd5077
commit 7bf191a61d
36 changed files with 1895 additions and 409 deletions

View File

@ -1,10 +1,13 @@
---
description: 坐标系相关定义
description:
globs:
alwaysApply: false
alwaysApply: true
---
# 坐标系约定
- 采用右手坐标系
- Y 轴为垂直轴
# 运行命令
- 在运行命令前,先运行 pwd 命令,了解当前目录

View File

@ -18,10 +18,15 @@ namespace ThreatSource.Tests.Guidance
_testAdapter = new TestSimulationAdapter(_simulationManager);
_simulationManager.SetSimulationAdapter(_testAdapter);
var laserCodeConfig = new LaserCodeConfig();
var guidanceConfig = new LaserSemiActiveGuidanceConfig();
_guidanceSystem = new LaserSemiActiveGuidanceSystem(
"guidance1",
50, // maxAcceleration
3, // guidanceCoefficient
laserCodeConfig,
guidanceConfig,
_simulationManager
);
_guidanceSystem.ParentId = "missile1";
@ -54,8 +59,16 @@ namespace ThreatSource.Tests.Guidance
[Fact]
public void SetCodeMatchRequired_SetsRequirementCorrectly()
{
// Act
_guidanceSystem.SetCodeMatchRequired(true);
// 创建一个 LaserCodeConfig 对象
var laserCodeConfig = new LaserCodeConfig
{
IsCodeMatchRequired = true
};
// Act - 我们设置新的期望编码,包含配置信息
_guidanceSystem.SetExpectedLaserCode(LaserCodeType.PRF, 1234);
// 注意:无法直接测试内部状态,这个测试依赖于后续的功能测试
// Assert - We can't directly check the private field, but we can test the behavior
// This will be tested in the ProcessLaserIlluminationEvent test
@ -66,17 +79,19 @@ namespace ThreatSource.Tests.Guidance
{
// Arrange
_guidanceSystem.SetExpectedLaserCode(LaserCodeType.PRF, 1234);
_guidanceSystem.SetCodeMatchRequired(true);
var illuminationEvent = new LaserIlluminationStartEvent
{
LaserDesignatorId = "laser1",
TargetId = "target1",
IsCodeEnabled = true,
LaserCode = new LaserCode
LaserCodeConfig = new LaserCodeConfig
{
CodeType = LaserCodeType.PRF,
CodeValue = 1234
IsCodeEnabled = true,
Code = new LaserCode
{
CodeType = LaserCodeType.PRF,
CodeValue = 1234
}
}
};
@ -90,9 +105,9 @@ namespace ThreatSource.Tests.Guidance
var lastEvent = matchEvents[matchEvents.Count - 1];
Assert.Equal("missile1", lastEvent.MissileId);
Assert.Equal("laser1", lastEvent.DesignatorId);
Assert.NotNull(lastEvent.MatchedCode);
Assert.Equal(LaserCodeType.PRF, lastEvent.MatchedCode.CodeType);
Assert.Equal(1234, lastEvent.MatchedCode.CodeValue);
Assert.NotNull(lastEvent.MatchedCodeConfig);
Assert.Equal(LaserCodeType.PRF, lastEvent.MatchedCodeConfig.Code.CodeType);
Assert.Equal(1234, lastEvent.MatchedCodeConfig.Code.CodeValue);
}
[Fact]
@ -100,17 +115,19 @@ namespace ThreatSource.Tests.Guidance
{
// Arrange
_guidanceSystem.SetExpectedLaserCode(LaserCodeType.PRF, 1234);
_guidanceSystem.SetCodeMatchRequired(true);
var illuminationEvent = new LaserIlluminationStartEvent
{
LaserDesignatorId = "laser1",
TargetId = "target1",
IsCodeEnabled = true,
LaserCode = new LaserCode
LaserCodeConfig = new LaserCodeConfig
{
CodeType = LaserCodeType.PRF,
CodeValue = 5678 // Different code value
IsCodeEnabled = true,
Code = new LaserCode
{
CodeType = LaserCodeType.PRF,
CodeValue = 5678 // Different code value
}
}
};
@ -124,12 +141,12 @@ namespace ThreatSource.Tests.Guidance
var lastEvent = mismatchEvents[mismatchEvents.Count - 1];
Assert.Equal("missile1", lastEvent.MissileId);
Assert.Equal("laser1", lastEvent.DesignatorId);
Assert.NotNull(lastEvent.ExpectedCode);
Assert.Equal(LaserCodeType.PRF, lastEvent.ExpectedCode.CodeType);
Assert.Equal(1234, lastEvent.ExpectedCode.CodeValue);
Assert.NotNull(lastEvent.ReceivedCode);
Assert.Equal(LaserCodeType.PRF, lastEvent.ReceivedCode.CodeType);
Assert.Equal(5678, lastEvent.ReceivedCode.CodeValue);
Assert.NotNull(lastEvent.ExpectedCodeConfig);
Assert.Equal(LaserCodeType.PRF, lastEvent.ExpectedCodeConfig.Code.CodeType);
Assert.Equal(1234, lastEvent.ExpectedCodeConfig.Code.CodeValue);
Assert.NotNull(lastEvent.ReceivedCodeConfig);
Assert.Equal(LaserCodeType.PRF, lastEvent.ReceivedCodeConfig.Code.CodeType);
Assert.Equal(5678, lastEvent.ReceivedCodeConfig.Code.CodeValue);
}
[Fact]
@ -137,17 +154,19 @@ namespace ThreatSource.Tests.Guidance
{
// Arrange
_guidanceSystem.SetExpectedLaserCode(LaserCodeType.PRF, 1234);
_guidanceSystem.SetCodeMatchRequired(true);
var illuminationEvent = new LaserIlluminationStartEvent
{
LaserDesignatorId = "laser1",
TargetId = "target1",
IsCodeEnabled = true,
LaserCode = new LaserCode
LaserCodeConfig = new LaserCodeConfig
{
CodeType = LaserCodeType.PPM, // Different code type
CodeValue = 1234
IsCodeEnabled = true,
Code = new LaserCode
{
CodeType = LaserCodeType.PPM, // Different code type
CodeValue = 1234
}
}
};
@ -161,12 +180,12 @@ namespace ThreatSource.Tests.Guidance
var lastEvent = mismatchEvents[mismatchEvents.Count - 1];
Assert.Equal("missile1", lastEvent.MissileId);
Assert.Equal("laser1", lastEvent.DesignatorId);
Assert.NotNull(lastEvent.ExpectedCode);
Assert.Equal(LaserCodeType.PRF, lastEvent.ExpectedCode.CodeType);
Assert.Equal(1234, lastEvent.ExpectedCode.CodeValue);
Assert.NotNull(lastEvent.ReceivedCode);
Assert.Equal(LaserCodeType.PPM, lastEvent.ReceivedCode.CodeType);
Assert.Equal(1234, lastEvent.ReceivedCode.CodeValue);
Assert.NotNull(lastEvent.ExpectedCodeConfig);
Assert.Equal(LaserCodeType.PRF, lastEvent.ExpectedCodeConfig.Code.CodeType);
Assert.Equal(1234, lastEvent.ExpectedCodeConfig.Code.CodeValue);
Assert.NotNull(lastEvent.ReceivedCodeConfig);
Assert.Equal(LaserCodeType.PPM, lastEvent.ReceivedCodeConfig.Code.CodeType);
Assert.Equal(1234, lastEvent.ReceivedCodeConfig.Code.CodeValue);
}
[Fact]
@ -174,17 +193,19 @@ namespace ThreatSource.Tests.Guidance
{
// Arrange
_guidanceSystem.SetExpectedLaserCode(LaserCodeType.PRF, 1234);
_guidanceSystem.SetCodeMatchRequired(false); // Not required
var illuminationEvent = new LaserIlluminationStartEvent
{
LaserDesignatorId = "laser1",
TargetId = "target1",
IsCodeEnabled = false, // Code disabled
LaserCode = new LaserCode
LaserCodeConfig = new LaserCodeConfig
{
CodeType = LaserCodeType.PRF,
CodeValue = 5678 // Different code value
IsCodeEnabled = false, // Code disabled
Code = new LaserCode
{
CodeType = LaserCodeType.PRF,
CodeValue = 5678 // Different code value
}
}
};
@ -201,17 +222,19 @@ namespace ThreatSource.Tests.Guidance
{
// Arrange
_guidanceSystem.SetExpectedLaserCode(LaserCodeType.PRF, 1234);
_guidanceSystem.SetCodeMatchRequired(true);
var illuminationEvent = new LaserIlluminationUpdateEvent
{
LaserDesignatorId = "laser1",
TargetId = "target1",
IsCodeEnabled = true,
LaserCode = new LaserCode
LaserCodeConfig = new LaserCodeConfig
{
CodeType = LaserCodeType.PRF,
CodeValue = 1234
IsCodeEnabled = true,
Code = new LaserCode
{
CodeType = LaserCodeType.PRF,
CodeValue = 1234
}
}
};
@ -225,9 +248,9 @@ namespace ThreatSource.Tests.Guidance
var lastEvent = matchEvents[matchEvents.Count - 1];
Assert.Equal("missile1", lastEvent.MissileId);
Assert.Equal("laser1", lastEvent.DesignatorId);
Assert.NotNull(lastEvent.MatchedCode);
Assert.Equal(LaserCodeType.PRF, lastEvent.MatchedCode.CodeType);
Assert.Equal(1234, lastEvent.MatchedCode.CodeValue);
Assert.NotNull(lastEvent.MatchedCodeConfig);
Assert.Equal(LaserCodeType.PRF, lastEvent.MatchedCodeConfig.Code.CodeType);
Assert.Equal(1234, lastEvent.MatchedCodeConfig.Code.CodeValue);
}
}
}

View File

@ -24,22 +24,34 @@ namespace ThreatSource.Tests.Indicator
_config = new InfraredTrackerConfig
{
Id = "tracker1",
InitialPosition = new Vector3D(0, 0, 0),
InitialOrientation = new Orientation(0, 0, 0),
MaxTrackingRange = 10000,
FieldOfView = Math.PI / 3,
AngleMeasurementAccuracy = 0.001,
UpdateFrequency = 10
};
_tank = new Tank("target1", new Vector3D(100, 0, 0), 0, _simulationManager);
var tankInitialMotion = new InitialMotionParameters
{
Position = new Vector3D(100, 0, 0),
Orientation = new Orientation(0, 0, 0),
InitialSpeed = 0
};
_tank = new Tank("target1", tankInitialMotion, _simulationManager);
_simulationManager.RegisterEntity("target1", _tank);
var trackerInitialMotion = new InitialMotionParameters
{
Position = new Vector3D(0, 0, 0),
Orientation = new Orientation(0, 0, 0),
InitialSpeed = 0
};
_infraredTracker = new InfraredTracker(
"tracker1",
"target1",
_config,
trackerInitialMotion,
_simulationManager
);
_simulationManager.RegisterEntity("tracker1", _infraredTracker);
@ -107,14 +119,20 @@ namespace ThreatSource.Tests.Indicator
// 创建导弹配置
var missileConfig = new MissileProperties
{
Id = "missile1",
InitialPosition = new Vector3D(50, 0, 0),
MaxSpeed = 1000,
MaxAcceleration = 100,
ProportionalNavigationCoefficient = 3
};
var missileInitialMotion = new InitialMotionParameters
{
Position = new Vector3D(50, 0, 0),
Orientation = new Orientation(0, 0, 0),
InitialSpeed = 100
};
// 注册一个导弹实体
var missile = new InfraredCommandGuidedMissile(missileConfig, _simulationManager);
var missile = new InfraredCommandGuidedMissile("missile1", missileConfig, missileInitialMotion, _simulationManager);
_simulationManager.RegisterEntity("missile1", missile);
// 模拟导弹点亮红外热源
@ -191,12 +209,21 @@ namespace ThreatSource.Tests.Indicator
// Arrange
var missileProperties = new MissileProperties
{
Id = "missile1",
InitialPosition = new Vector3D(100, 0, 0),
InitialSpeed = 100,
MaxSpeed = 1000,
MaxFlightTime = 100,
MaxFlightDistance = 10000,
MaxAcceleration = 100,
Type = MissileType.InfraredCommandGuidance
};
var missile = new InfraredCommandGuidedMissile(missileProperties, _simulationManager);
var missileMotion = new InitialMotionParameters
{
Position = new Vector3D(100, 0, 0),
Orientation = new Orientation(0, 0, 0),
InitialSpeed = 100
};
var missile = new InfraredCommandGuidedMissile("missile1", missileProperties, missileMotion, _simulationManager);
_simulationManager.RegisterEntity("missile1", missile);
missile.Activate();

View File

@ -23,22 +23,34 @@ namespace ThreatSource.Tests.Indicator
_config = new LaserBeamRiderConfig
{
Id = "beamRider1",
InitialPosition = new Vector3D(0, 0, 0),
LaserPower = 1000,
ControlFieldDiameter = 5.0,
MaxGuidanceDistance = 5000
};
_tank = new Tank("target1", new Vector3D(100, 0, 0), 0, _simulationManager);
var tankInitialMotion = new InitialMotionParameters
{
Position = new Vector3D(100, 0, 0),
Orientation = new Orientation(0, 0, 0),
InitialSpeed = 0
};
_tank = new Tank("target1", tankInitialMotion, _simulationManager);
_simulationManager.RegisterEntity("target1", _tank);
var beamRiderInitialMotion = new InitialMotionParameters
{
Position = new Vector3D(0, 0, 0),
Orientation = new Orientation(0, 0, 0),
InitialSpeed = 0
};
_laserBeamRider = new LaserBeamRider(
"beamRider1",
"missile1",
"target1",
10,
"missile1",
_config,
beamRiderInitialMotion,
_simulationManager
);
_simulationManager.RegisterEntity("beamRider1", _laserBeamRider);

View File

@ -23,21 +23,33 @@ namespace ThreatSource.Tests.Indicator
_config = new LaserDesignatorConfig
{
Id = "laser1",
InitialPosition = new Vector3D(0, 0, 0),
LaserPower = 1000,
LaserDivergenceAngle = 0.001
};
_tank = new Tank("target1", new Vector3D(100, 0, 0), 0, _simulationManager);
var tankInitialMotion = new InitialMotionParameters
{
Position = new Vector3D(100, 0, 0),
Orientation = new Orientation(0, 0, 0),
InitialSpeed = 0
};
_tank = new Tank("target1", tankInitialMotion, _simulationManager);
_simulationManager.RegisterEntity("target1", _tank);
var designatorInitialMotion = new InitialMotionParameters
{
Position = new Vector3D(0, 0, 0),
Orientation = new Orientation(0, 0, 0),
InitialSpeed = 0
};
_laserDesignator = new LaserDesignator(
"laser1",
"target1",
"missile1",
10,
_config,
designatorInitialMotion,
_simulationManager
);
_simulationManager.RegisterEntity("laser1", _laserDesignator);
@ -50,7 +62,15 @@ namespace ThreatSource.Tests.Indicator
_laserDesignator.Activate();
// Act
_laserDesignator.SetLaserCode(LaserCodeType.PRF, 1234);
_laserDesignator.LaserCodeConfig = new LaserCodeConfig
{
IsCodeEnabled = true,
Code = new LaserCode
{
CodeType = LaserCodeType.PRF,
CodeValue = 1234
}
};
_laserDesignator.Update(0.1);
// Assert
@ -58,10 +78,10 @@ namespace ThreatSource.Tests.Indicator
Assert.NotEmpty(events);
var lastEvent = events[events.Count - 1];
Assert.True(lastEvent.IsCodeEnabled);
Assert.NotNull(lastEvent.LaserCode);
Assert.Equal(LaserCodeType.PRF, lastEvent.LaserCode.CodeType);
Assert.Equal(1234, lastEvent.LaserCode.CodeValue);
Assert.NotNull(lastEvent.LaserCodeConfig);
Assert.True(lastEvent.LaserCodeConfig.IsCodeEnabled);
Assert.Equal(LaserCodeType.PRF, lastEvent.LaserCodeConfig.Code.CodeType);
Assert.Equal(1234, lastEvent.LaserCodeConfig.Code.CodeValue);
}
[Fact]
@ -69,7 +89,15 @@ namespace ThreatSource.Tests.Indicator
{
// Arrange
_laserDesignator.Activate();
_laserDesignator.SetLaserCode(LaserCodeType.PPM, 5678);
_laserDesignator.LaserCodeConfig = new LaserCodeConfig
{
IsCodeEnabled = true,
Code = new LaserCode
{
CodeType = LaserCodeType.PPM,
CodeValue = 5678
}
};
// Act
_laserDesignator.AddCodeParameter("PulseWidth", 0.001);
@ -80,12 +108,12 @@ namespace ThreatSource.Tests.Indicator
Assert.NotEmpty(events);
var lastEvent = events[events.Count - 1];
Assert.True(lastEvent.IsCodeEnabled);
Assert.NotNull(lastEvent.LaserCode);
Assert.Equal(LaserCodeType.PPM, lastEvent.LaserCode.CodeType);
Assert.Equal(5678, lastEvent.LaserCode.CodeValue);
Assert.True(lastEvent.LaserCode.Parameters.ContainsKey("PulseWidth"));
Assert.Equal(0.001, lastEvent.LaserCode.Parameters["PulseWidth"]);
Assert.NotNull(lastEvent.LaserCodeConfig);
Assert.True(lastEvent.LaserCodeConfig.IsCodeEnabled);
Assert.Equal(LaserCodeType.PPM, lastEvent.LaserCodeConfig.Code.CodeType);
Assert.Equal(5678, lastEvent.LaserCodeConfig.Code.CodeValue);
Assert.True(lastEvent.LaserCodeConfig.Code.Parameters.ContainsKey("PulseWidth"));
Assert.Equal(0.001, lastEvent.LaserCodeConfig.Code.Parameters["PulseWidth"]);
}
[Fact]
@ -93,34 +121,52 @@ namespace ThreatSource.Tests.Indicator
{
// Arrange
_laserDesignator.Activate();
_laserDesignator.SetLaserCode(LaserCodeType.PRF, 1234);
_laserDesignator.LaserCodeConfig = new LaserCodeConfig
{
IsCodeEnabled = true,
Code = new LaserCode
{
CodeType = LaserCodeType.PRF,
CodeValue = 1234
}
};
// Act - Disable code
_laserDesignator.EnableCode(false);
_laserDesignator.LaserCodeConfig.IsCodeEnabled = false;
_laserDesignator.Update(0.1);
// Assert - Code should be disabled
var eventsAfterDisable = _testAdapter.GetPublishedEvents<LaserIlluminationUpdateEvent>();
Assert.NotEmpty(eventsAfterDisable);
var lastEventAfterDisable = eventsAfterDisable[eventsAfterDisable.Count - 1];
Assert.False(lastEventAfterDisable.IsCodeEnabled);
Assert.NotNull(lastEventAfterDisable.LaserCodeConfig);
Assert.False(lastEventAfterDisable.LaserCodeConfig.IsCodeEnabled);
// Act - Enable code again
_laserDesignator.EnableCode(true);
_laserDesignator.LaserCodeConfig.IsCodeEnabled = true;
_laserDesignator.Update(0.1);
// Assert - Code should be enabled
var eventsAfterEnable = _testAdapter.GetPublishedEvents<LaserIlluminationUpdateEvent>();
Assert.NotEmpty(eventsAfterEnable);
var lastEventAfterEnable = eventsAfterEnable[eventsAfterEnable.Count - 1];
Assert.True(lastEventAfterEnable.IsCodeEnabled);
Assert.NotNull(lastEventAfterEnable.LaserCodeConfig);
Assert.True(lastEventAfterEnable.LaserCodeConfig.IsCodeEnabled);
}
[Fact]
public void LaserIlluminationEvents_IncludeCodeInformation()
{
// Arrange
_laserDesignator.SetLaserCode(LaserCodeType.PRF, 1234);
_laserDesignator.LaserCodeConfig = new LaserCodeConfig
{
IsCodeEnabled = true,
Code = new LaserCode
{
CodeType = LaserCodeType.PRF,
CodeValue = 1234
}
};
// Act - Start illumination
_laserDesignator.Activate();
@ -129,10 +175,10 @@ namespace ThreatSource.Tests.Indicator
var startEvents = _testAdapter.GetPublishedEvents<LaserIlluminationStartEvent>();
Assert.NotEmpty(startEvents);
var startEvent = startEvents[startEvents.Count - 1];
Assert.True(startEvent.IsCodeEnabled);
Assert.NotNull(startEvent.LaserCode);
Assert.Equal(LaserCodeType.PRF, startEvent.LaserCode.CodeType);
Assert.Equal(1234, startEvent.LaserCode.CodeValue);
Assert.NotNull(startEvent.LaserCodeConfig);
Assert.True(startEvent.LaserCodeConfig.IsCodeEnabled);
Assert.Equal(LaserCodeType.PRF, startEvent.LaserCodeConfig.Code.CodeType);
Assert.Equal(1234, startEvent.LaserCodeConfig.Code.CodeValue);
// Act - Update illumination
_laserDesignator.Update(0.1);
@ -141,10 +187,10 @@ namespace ThreatSource.Tests.Indicator
var updateEvents = _testAdapter.GetPublishedEvents<LaserIlluminationUpdateEvent>();
Assert.NotEmpty(updateEvents);
var updateEvent = updateEvents[updateEvents.Count - 1];
Assert.True(updateEvent.IsCodeEnabled);
Assert.NotNull(updateEvent.LaserCode);
Assert.Equal(LaserCodeType.PRF, updateEvent.LaserCode.CodeType);
Assert.Equal(1234, updateEvent.LaserCode.CodeValue);
Assert.NotNull(updateEvent.LaserCodeConfig);
Assert.True(updateEvent.LaserCodeConfig.IsCodeEnabled);
Assert.Equal(LaserCodeType.PRF, updateEvent.LaserCodeConfig.Code.CodeType);
Assert.Equal(1234, updateEvent.LaserCodeConfig.Code.CodeValue);
}
}
}

View File

@ -23,21 +23,33 @@ namespace ThreatSource.Tests.Indicator
_config = new LaserDesignatorConfig
{
Id = "laser1",
InitialPosition = new Vector3D(0, 0, 0),
LaserPower = 1000,
LaserDivergenceAngle = 0.001
};
_tank = new Tank("target1", new Vector3D(100, 0, 0), 0, _simulationManager);
var tankInitialMotion = new InitialMotionParameters
{
Position = new Vector3D(100, 0, 0),
Orientation = new Orientation(0, 0, 0),
InitialSpeed = 0
};
_tank = new Tank("target1", tankInitialMotion, _simulationManager);
_simulationManager.RegisterEntity("target1", _tank);
var designatorInitialMotion = new InitialMotionParameters
{
Position = new Vector3D(0, 0, 0),
Orientation = new Orientation(0, 0, 0),
InitialSpeed = 0
};
_laserDesignator = new LaserDesignator(
"laser1",
"target1",
"missile1",
10,
_config,
designatorInitialMotion,
_simulationManager
);
_simulationManager.RegisterEntity("laser1", _laserDesignator);

View File

@ -0,0 +1,307 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using ThreatSource.Indicator;
using ThreatSource.Jamming;
using ThreatSource.Simulation;
using ThreatSource.Tests.Simulation;
using ThreatSource.Utils;
using System;
using System.Collections.Generic;
namespace ThreatSource.Tests.Jamming
{
[TestClass]
public class InfraredJammingTests
{
private SimulationManager _simulationManager = null!;
private TestSimulationAdapter _testAdapter = null!;
private InfraredTracker _infraredTracker = null!;
[TestInitialize]
public void Setup()
{
// 初始化模拟管理器和测试适配器
_simulationManager = new SimulationManager();
_testAdapter = new TestSimulationAdapter(_simulationManager);
_simulationManager.SetSimulationAdapter(_testAdapter);
// 创建红外测角仪配置
var config = new InfraredTrackerConfig
{
MaxTrackingRange = 10000,
FieldOfView = Math.PI / 3,
AngleMeasurementAccuracy = 0.001,
UpdateFrequency = 10,
JammingResistanceThreshold = 0.05 // 设置干扰抗性阈值为50mW
};
// 初始化红外测角仪
var initialMotionParameters = new InitialMotionParameters
{
Position = new Vector3D(0, 0, 0),
Orientation = new Orientation(0, 0, 0),
InitialSpeed = 0
};
_infraredTracker = new InfraredTracker(
"tracker1",
"target1",
config,
initialMotionParameters,
_simulationManager
);
// 注册红外测角仪
_simulationManager.RegisterEntity("tracker1", _infraredTracker);
}
[TestMethod]
public void InfraredJamming_TargetsTracker_TrackerIsJammed()
{
// Arrange
_infraredTracker.Activate();
// 创建干扰事件
var jammingEvent = new InfraredJammingEvent
{
JammingPower = 200, // 高于阈值
WavelengthMin = 3,
WavelengthMax = 5,
JammingSourcePosition = new Vector3D(50, 0, 0),
JammingDirection = new Vector3D(-1, 0, 0), // 指向跟踪器
JammingAngleRange = Math.PI / 4, // 45度角
JammingMode = JammingMode.Noise,
Duration = null // 持续干扰
};
// Act
_simulationManager.PublishEvent(jammingEvent);
_infraredTracker.Update(0.1);
// Assert
Assert.IsTrue(_infraredTracker.IsJammed, "红外测角仪应该处于被干扰状态");
var status = _infraredTracker.GetStatus();
Assert.IsTrue(status.Contains("干扰状态: 受干扰"), "状态信息应该反映受干扰");
}
[TestMethod]
public void InfraredJamming_OutsideAngleRange_TrackerNotJammed()
{
// Arrange
_infraredTracker.Activate();
// 创建角度范围外的干扰事件
var jammingEvent = new InfraredJammingEvent
{
JammingPower = 200,
WavelengthMin = 3,
WavelengthMax = 5,
JammingSourcePosition = new Vector3D(0, 50, 0), // 位于上方
JammingDirection = new Vector3D(0, 0, 1), // 指向前方,不是指向跟踪器
JammingAngleRange = 0.1, // 很小的角度范围
JammingMode = JammingMode.Noise
};
// Act
_simulationManager.PublishEvent(jammingEvent);
_infraredTracker.Update(0.1);
// Assert
Assert.IsFalse(_infraredTracker.IsJammed, "测角仪不应该被干扰,因为干扰源不在角度范围内");
var status = _infraredTracker.GetStatus();
Assert.IsTrue(status.Contains("干扰状态: 正常"), "状态信息应该反映正常");
}
[TestMethod]
public void InfraredJamming_LowPower_TrackerNotJammed()
{
// Arrange
_infraredTracker.Activate();
// 创建低功率干扰事件
var jammingEvent = new InfraredJammingEvent
{
JammingPower = 10, // 低于阈值
WavelengthMin = 3,
WavelengthMax = 5,
JammingSourcePosition = new Vector3D(50, 0, 0),
JammingDirection = new Vector3D(-1, 0, 0),
JammingAngleRange = Math.PI / 4,
JammingMode = JammingMode.Noise
};
// Act
_simulationManager.PublishEvent(jammingEvent);
_infraredTracker.Update(0.1);
// Assert
Assert.IsFalse(_infraredTracker.IsJammed, "测角仪不应该被干扰,因为干扰功率低于阈值");
}
[TestMethod]
public void InfraredJamming_WrongWavelength_TrackerNotJammed()
{
// Arrange
_infraredTracker.Activate();
// 创建错误波长的干扰事件
var jammingEvent = new InfraredJammingEvent
{
JammingPower = 200,
WavelengthMin = 6, // 不在3-5μm或8-14μm范围
WavelengthMax = 7,
JammingSourcePosition = new Vector3D(50, 0, 0),
JammingDirection = new Vector3D(-1, 0, 0),
JammingAngleRange = Math.PI / 4,
JammingMode = JammingMode.Noise
};
// Act
_simulationManager.PublishEvent(jammingEvent);
_infraredTracker.Update(0.1);
// Assert
Assert.IsFalse(_infraredTracker.IsJammed, "测角仪不应该被干扰,因为波长不匹配");
}
[TestMethod]
public void InfraredJamming_DifferentTargetId_TrackerNotJammed()
{
// Arrange
_infraredTracker.Activate();
// 创建干扰事件
var jammingEvent = new InfraredJammingEvent
{
JammingPower = 200,
WavelengthMin = 3,
WavelengthMax = 5,
JammingSourcePosition = new Vector3D(50, 0, 0),
JammingDirection = new Vector3D(-1, 0, 0),
JammingAngleRange = Math.PI / 4,
JammingMode = JammingMode.Noise
};
// Act
_simulationManager.PublishEvent(jammingEvent);
_infraredTracker.Update(0.1);
// Assert
Assert.IsTrue(_infraredTracker.IsJammed, "测角仪应该被干扰,因为在干扰范围内");
}
[TestMethod]
public void InfraredJamming_ClearedAfterDuration_TrackerNotJammed()
{
// Arrange
_infraredTracker.Activate();
// 创建有限时间的干扰事件
var jammingEvent = new InfraredJammingEvent
{
JammingPower = 200,
WavelengthMin = 3,
WavelengthMax = 5,
JammingSourcePosition = new Vector3D(50, 0, 0),
JammingDirection = new Vector3D(-1, 0, 0),
JammingAngleRange = Math.PI / 4,
JammingMode = JammingMode.Noise,
Duration = 0.5 // 0.5秒后过期
};
// Act - 应用干扰
_simulationManager.PublishEvent(jammingEvent);
_infraredTracker.Update(0.1);
// Assert - 确认已被干扰
Assert.IsTrue(_infraredTracker.IsJammed, "红外测角仪应该处于被干扰状态");
// Act - 等待干扰过期
// 注意:这里我们需要模拟 JammingHandler 的更新,而不只是 InfraredTracker 的更新
// 通常在实际运行中JammingHandler 会在每帧更新时被调用
// 这里我们直接多次更新 InfraredTracker其内部会更新 JammingHandler
for (int i = 0; i < 10; i++)
{
_infraredTracker.Update(0.1); // 总共更新1秒超过干扰持续时间
}
// Assert - 确认干扰已清除
Assert.IsFalse(_infraredTracker.IsJammed, "干扰持续时间结束后,红外测角仪应该恢复正常");
}
[TestMethod]
public void InfraredJamming_ManualClear_TrackerNotJammed()
{
// Arrange
_infraredTracker.Activate();
// 创建持续干扰事件
var jammingEvent = new InfraredJammingEvent
{
JammingPower = 200,
WavelengthMin = 3,
WavelengthMax = 5,
JammingSourcePosition = new Vector3D(50, 0, 0),
JammingDirection = new Vector3D(-1, 0, 0),
JammingAngleRange = Math.PI / 4,
JammingMode = JammingMode.Noise,
Duration = null // 持续干扰
};
// Act - 应用干扰
_simulationManager.PublishEvent(jammingEvent);
_infraredTracker.Update(0.1);
// Assert - 确认已被干扰
Assert.IsTrue(_infraredTracker.IsJammed, "红外测角仪应该处于被干扰状态");
// Act - 手动清除干扰
_infraredTracker.ClearJamming(JammingType.Infrared);
_infraredTracker.Update(0.1);
// Assert - 确认干扰已清除
Assert.IsFalse(_infraredTracker.IsJammed, "手动清除后,红外测角仪应该恢复正常");
}
[TestMethod]
public void InfraredJamming_TrackingDisabledDuringJamming()
{
// 设置红外测角仪的目标和导弹ID使其进入跟踪状态
typeof(InfraredTracker).GetProperty("MissileId")?.SetValue(_infraredTracker, "missile1");
// Arrange
_infraredTracker.Activate();
// 创建干扰事件
var jammingEvent = new InfraredJammingEvent
{
JammingPower = 200,
WavelengthMin = 3,
WavelengthMax = 5,
JammingSourcePosition = new Vector3D(50, 0, 0),
JammingDirection = new Vector3D(-1, 0, 0),
JammingAngleRange = Math.PI / 4,
JammingMode = JammingMode.Noise
};
// 捕获发布的事件
List<SimulationEvent> publishedEvents = new List<SimulationEvent>();
_testAdapter.EventPublished += (sender, evt) => publishedEvents.Add(evt);
// Act - 没有干扰的情况下更新
_infraredTracker.Update(0.1);
// 记录发布的事件数量
int eventsBeforeJamming = publishedEvents.Count;
publishedEvents.Clear();
// Act - 应用干扰
_simulationManager.PublishEvent(jammingEvent);
_infraredTracker.Update(0.1);
// Assert
int eventsAfterJamming = publishedEvents.Count;
Assert.IsTrue(_infraredTracker.IsJammed, "红外测角仪应该处于被干扰状态");
Assert.AreEqual(0, eventsAfterJamming, "在干扰状态下不应该发送制导指令事件");
}
}
}

View File

@ -30,26 +30,52 @@ namespace ThreatSource.Tests.Jamming
_simulationManager.SetSimulationAdapter(_testAdapter);
// 创建目标
_tank = new Tank("tank1", new Vector3D(100, 0, 100), Math.PI/4, _simulationManager);
var tankInitialMotion = new InitialMotionParameters
{
Position = new Vector3D(100, 0, 100),
Orientation = new Orientation(Math.PI/4, 0, 0),
InitialSpeed = 0
};
_tank = new Tank("tank1", tankInitialMotion, _simulationManager);
_simulationManager.RegisterEntity("tank1", _tank);
_tank.Activate();
// 创建子弹
var properties = new MissileProperties
{
Id = "submunition1",
Mass = 10,
ExplosionRadius = 5,
MaxSpeed = 2000,
MaxFlightTime = 100,
MaxFlightDistance = 1000,
InitialPosition = new Vector3D(20, 150, 0),
InitialSpeed = 20,
InitialOrientation = new Orientation(0, -Math.PI/4, 0)
MaxAcceleration = 50,
ProportionalNavigationCoefficient = 3,
Mass = 10,
ExplosionRadius = 5,
HitProbability = 0.9,
Type = MissileType.TerminalSensitiveSubmunition
};
_submunition = new TerminalSensitiveSubmunition("tank1", properties, _simulationManager);
_simulationManager.RegisterEntity("submunition1", _submunition);
var submunitionInitialMotion = new InitialMotionParameters
{
Position = new Vector3D(20, 150, 0),
Orientation = new Orientation(0, -Math.PI/4, 0),
InitialSpeed = 20
};
var submunitionConfig = new TerminalSensitiveSubmunitionConfig
{
SeparationHeight = 400.0,
SeparationDistance = 1000.0,
SubmunitionSeparationAngle = 45.0
};
_submunition = new TerminalSensitiveSubmunition(
"tank1",
"submunition1",
properties,
submunitionInitialMotion,
submunitionConfig,
_simulationManager
);
// 初始化传感器
_infraredDetector = new InfraredDetector(_submunition, 500, InfraredBand.Short, 10);
@ -137,25 +163,52 @@ namespace ThreatSource.Tests.Jamming
public void TestSubmunitionHitDetection()
{
// 创建目标
var tank = new Tank("tank3", new Vector3D(0, 0, 0), 0, _simulationManager);
var tank3InitialMotion = new InitialMotionParameters
{
Position = new Vector3D(0, 0, 0),
Orientation = new Orientation(0, 0, 0),
InitialSpeed = 0
};
var tank = new Tank("tank3", tank3InitialMotion, _simulationManager);
_simulationManager.RegisterEntity("tank3", tank);
tank.Activate();
// 创建子弹
var properties = new MissileProperties
{
Id = "submunition3",
Mass = 10,
ExplosionRadius = 5,
MaxSpeed = 500,
MaxFlightTime = 100,
MaxFlightDistance = 1000,
InitialPosition = new Vector3D(0, 6, 0),
InitialSpeed = 10,
InitialOrientation = new Orientation(0, -Math.PI/2, 0)
MaxAcceleration = 50,
ProportionalNavigationCoefficient = 3,
Mass = 10,
ExplosionRadius = 5,
HitProbability = 0.9,
Type = MissileType.TerminalSensitiveSubmunition
};
var submunition = new TerminalSensitiveSubmunition("tank3", properties, _simulationManager);
var submunitionInitialMotion = new InitialMotionParameters
{
Position = new Vector3D(0, 6, 0),
Orientation = new Orientation(0, -Math.PI/2, 0),
InitialSpeed = 10
};
var submunitionConfig = new TerminalSensitiveSubmunitionConfig
{
SeparationHeight = 200.0,
SeparationDistance = 500.0,
SubmunitionSeparationAngle = 45.0
};
var submunition = new TerminalSensitiveSubmunition(
"tank3",
"submunition3",
properties,
submunitionInitialMotion,
submunitionConfig,
_simulationManager
);
_simulationManager.RegisterEntity("submunition3", submunition);
// 激活并发射子弹
@ -207,25 +260,48 @@ namespace ThreatSource.Tests.Jamming
public void TestDecelerationStageJamming()
{
// 创建目标
var tank = new Tank("tank5", new Vector3D(100, 0, 100), Math.PI/4, _simulationManager);
var tank5InitialMotion = new InitialMotionParameters
{
Position = new Vector3D(100, 0, 100),
Orientation = new Orientation(Math.PI/4, 0, 0),
InitialSpeed = 0
};
var tank = new Tank("tank5", tank5InitialMotion, _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)
Mass = 10,
ExplosionRadius = 5
};
var submunition = new TerminalSensitiveSubmunition("tank5", properties, _simulationManager);
var submunitionInitialMotion = new InitialMotionParameters
{
Position = new Vector3D(0, 400, 0),
Orientation = new Orientation(0, -Math.PI/4, 0),
InitialSpeed = 100
};
var submunitionConfig = new TerminalSensitiveSubmunitionConfig
{
SeparationHeight = 200.0,
SeparationDistance = 500.0,
SubmunitionSeparationAngle = 45.0
};
var submunition = new TerminalSensitiveSubmunition(
"tank5",
"submunition5",
properties,
submunitionInitialMotion,
submunitionConfig,
_simulationManager
);
_simulationManager.RegisterEntity("submunition5", submunition);
// 激活并发射子弹
@ -280,25 +356,48 @@ namespace ThreatSource.Tests.Jamming
public void TestParachuteDeploymentStageJamming()
{
// 创建目标
var tank = new Tank("tank6", new Vector3D(100, 0, 100), Math.PI/4, _simulationManager);
var tank6InitialMotion = new InitialMotionParameters
{
Position = new Vector3D(100, 0, 100),
Orientation = new Orientation(Math.PI/4, 0, 0),
InitialSpeed = 0
};
var tank = new Tank("tank6", tank6InitialMotion, _simulationManager);
_simulationManager.RegisterEntity("tank6", tank);
tank.Activate();
// 创建子弹初始高度设置为300米接近开伞高度
// 创建子弹初始高度设置为300米伞降阶段
var properties = new MissileProperties
{
Id = "submunition6",
Mass = 10,
ExplosionRadius = 5,
MaxSpeed = 500,
MaxFlightTime = 100,
MaxFlightDistance = 1000,
InitialPosition = new Vector3D(0, 300, 0),
InitialSpeed = 40, // 设置为减速阶段末速度
InitialOrientation = new Orientation(0, -Math.PI/2, 0) // 垂直向下
Mass = 10,
ExplosionRadius = 5
};
var submunition = new TerminalSensitiveSubmunition("tank6", properties, _simulationManager);
var submunitionInitialMotion = new InitialMotionParameters
{
Position = new Vector3D(0, 300, 0),
Orientation = new Orientation(0, -Math.PI/2, 0), // 垂直向下
InitialSpeed = 40 // 设置为减速阶段末速度
};
var submunitionConfig = new TerminalSensitiveSubmunitionConfig
{
SeparationHeight = 200.0,
SeparationDistance = 500.0,
SubmunitionSeparationAngle = 45.0
};
var submunition = new TerminalSensitiveSubmunition(
"tank6",
"submunition6",
properties,
submunitionInitialMotion,
submunitionConfig,
_simulationManager
);
_simulationManager.RegisterEntity("submunition6", submunition);
// 激活并发射子弹
@ -366,11 +465,6 @@ namespace ThreatSource.Tests.Jamming
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, "速度应该保持在开伞阶段的限制范围内");
}
@ -379,25 +473,48 @@ namespace ThreatSource.Tests.Jamming
public void TestStableScanStageJamming()
{
// 创建目标
var tank = new Tank("tank7", new Vector3D(100, 0, 100), Math.PI/4, _simulationManager);
var tank7InitialMotion = new InitialMotionParameters
{
Position = new Vector3D(100, 0, 100),
Orientation = new Orientation(Math.PI/4, 0, 0),
InitialSpeed = 0
};
var tank = new Tank("tank7", tank7InitialMotion, _simulationManager);
_simulationManager.RegisterEntity("tank7", tank);
tank.Activate();
// 创建子弹初始高度设置为200米稳定扫描高度
// 创建子弹初始高度设置为250米稳定扫描阶段
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) // 垂直向下
Mass = 10,
ExplosionRadius = 5
};
var submunition = new TerminalSensitiveSubmunition("tank7", properties, _simulationManager);
var submunitionInitialMotion = new InitialMotionParameters
{
Position = new Vector3D(0, 250, 0),
Orientation = new Orientation(0, -Math.PI/2, 0), // 垂直向下
InitialSpeed = 10 // 设置为垂直下降速度
};
var submunitionConfig = new TerminalSensitiveSubmunitionConfig
{
SeparationHeight = 200.0,
SeparationDistance = 500.0,
SubmunitionSeparationAngle = 45.0
};
var submunition = new TerminalSensitiveSubmunition(
"tank7",
"submunition7",
properties,
submunitionInitialMotion,
submunitionConfig,
_simulationManager
);
_simulationManager.RegisterEntity("submunition7", submunition);
// 激活并发射子弹
@ -499,25 +616,48 @@ namespace ThreatSource.Tests.Jamming
public void TestDetectionStageJamming()
{
// 创建目标
var tank = new Tank("tank8", new Vector3D( 30, 0, 30), Math.PI/4, _simulationManager);
var tank8InitialMotion = new InitialMotionParameters
{
Position = new Vector3D(100, 0, 100),
Orientation = new Orientation(Math.PI/4, 0, 0),
InitialSpeed = 0
};
var tank = new Tank("tank8", tank8InitialMotion, _simulationManager);
_simulationManager.RegisterEntity("tank8", tank);
tank.Activate();
// 创建子弹,初始位置设置在探测阶段范围内
// 创建子弹,初始高度设置为140米检测阶段
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)
Mass = 10,
ExplosionRadius = 5
};
var submunition = new TerminalSensitiveSubmunition("tank8", properties, _simulationManager);
var submunitionInitialMotion = new InitialMotionParameters
{
Position = new Vector3D(0, 140, 0),
Orientation = new Orientation(0, -Math.PI/2, 0),
InitialSpeed = 10
};
var submunitionConfig = new TerminalSensitiveSubmunitionConfig
{
SeparationHeight = 200.0,
SeparationDistance = 500.0,
SubmunitionSeparationAngle = 45.0
};
var submunition = new TerminalSensitiveSubmunition(
"tank8",
"submunition8",
properties,
submunitionInitialMotion,
submunitionConfig,
_simulationManager
);
_simulationManager.RegisterEntity("submunition8", submunition);
// 激活并发射子弹
@ -550,25 +690,48 @@ namespace ThreatSource.Tests.Jamming
public void TestAttackStageJamming()
{
// 创建目标
var tank = new Tank("tank_attack", new Vector3D(300, 0, 100), Math.PI/4, _simulationManager);
var tankAttackInitialMotion = new InitialMotionParameters
{
Position = new Vector3D(300, 0, 100),
Orientation = new Orientation(Math.PI/4, 0, 0),
InitialSpeed = 0
};
var tank = new Tank("tank_attack", tankAttackInitialMotion, _simulationManager);
_simulationManager.RegisterEntity("tank_attack", tank);
tank.Activate();
// 创建子弹,初始位置设置在传感器探测范围内
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度
Mass = 10,
ExplosionRadius = 5
};
var submunition = new TerminalSensitiveSubmunition("tank_attack", properties, _simulationManager);
var submunitionInitialMotion = new InitialMotionParameters
{
Position = new Vector3D(400, 200, 100), // 距离目标100米高度200米
Orientation = new Orientation(0, -Math.PI/6, 0), // 向下30度
InitialSpeed = 10
};
var submunitionConfig = new TerminalSensitiveSubmunitionConfig
{
SeparationHeight = 200.0,
SeparationDistance = 500.0,
SubmunitionSeparationAngle = 45.0
};
var submunition = new TerminalSensitiveSubmunition(
"tank_attack",
"submunition_attack",
properties,
submunitionInitialMotion,
submunitionConfig,
_simulationManager
);
_simulationManager.RegisterEntity("submunition_attack", submunition);
// 激活并发射子弹

View File

@ -3,6 +3,8 @@ using ThreatSource.Missile;
using ThreatSource.Simulation;
using ThreatSource.Utils;
using ThreatSource.Tests.Simulation;
using ThreatSource.Guidance;
using ThreatSource.Indicator;
namespace ThreatSource.Tests.Missile
{
@ -10,7 +12,7 @@ namespace ThreatSource.Tests.Missile
{
private readonly SimulationManager _simulationManager;
private readonly TestSimulationAdapter _testAdapter;
private readonly BaseMissile _missile;
private readonly LaserSemiActiveGuidedMissile _missile;
private readonly MissileProperties _properties;
public BaseMissileTests()
@ -21,10 +23,6 @@ namespace ThreatSource.Tests.Missile
_properties = new MissileProperties
{
Id = "missile1",
InitialPosition = new Vector3D(0, 0, 0),
InitialOrientation = new Orientation(0, 0, 0),
InitialSpeed = 100,
MaxSpeed = 1000,
MaxFlightTime = 100,
MaxFlightDistance = 10000,
@ -33,10 +31,45 @@ namespace ThreatSource.Tests.Missile
Mass = 100,
ExplosionRadius = 10,
HitProbability = 0.9,
Type = MissileType.StandardMissile
Type = MissileType.LaserSemiActiveGuidance
};
_missile = new BaseMissile(_properties, _simulationManager);
var missileInitialMotion = new InitialMotionParameters
{
Position = new Vector3D(0, 0, 0),
Orientation = new Orientation(0, 0, 0),
InitialSpeed = 100
};
var laserCodeConfig = new LaserCodeConfig
{
Code = new LaserCode
{
CodeType = LaserCodeType.PRF,
CodeValue = 1234
}
};
var guidanceConfig = new LaserSemiActiveGuidanceConfig
{
FieldOfViewAngle = 30,
LensDiameter = 0.1,
SensorDiameter = 0.03,
FocusedSpotDiameter = 0.006,
ReflectionCoefficient = 0.2,
TargetReflectiveArea = 1.0,
LockThreshold = 1e-12,
SpotOffsetSensitivity = 0.5
};
_missile = new LaserSemiActiveGuidedMissile(
"missile1",
_properties,
missileInitialMotion,
laserCodeConfig,
guidanceConfig,
_simulationManager
);
_simulationManager.RegisterEntity("missile1", _missile);
}

View File

@ -21,10 +21,6 @@ namespace ThreatSource.Tests.Missile
_properties = new MissileProperties
{
Id = "missile1",
InitialPosition = new Vector3D(0, 0, 0),
InitialOrientation = new Orientation(0, 0, 0),
InitialSpeed = 100,
MaxSpeed = 1000,
MaxFlightTime = 100,
MaxFlightDistance = 10000,
@ -36,7 +32,19 @@ namespace ThreatSource.Tests.Missile
Type = MissileType.InfraredCommandGuidance
};
_missile = new InfraredCommandGuidedMissile(_properties, _simulationManager);
var missileInitialMotion = new InitialMotionParameters
{
Position = new Vector3D(0, 0, 0),
Orientation = new Orientation(0, 0, 0),
InitialSpeed = 100
};
_missile = new InfraredCommandGuidedMissile(
"missile1",
_properties,
missileInitialMotion,
_simulationManager
);
_simulationManager.RegisterEntity("missile1", _missile);
}
@ -137,7 +145,7 @@ namespace ThreatSource.Tests.Missile
_missile.Fire();
_missile.Activate();
var maxDistance = _properties.MaxFlightDistance;
var timeToExceedDistance = maxDistance / _properties.InitialSpeed + 1;
var timeToExceedDistance = maxDistance / 100 + 1; // 使用已知的初始速度100
// Act
for (double time = 0; time < timeToExceedDistance; time += 0.1)

View File

@ -4,6 +4,7 @@ using ThreatSource.Simulation;
using ThreatSource.Utils;
using ThreatSource.Tests.Simulation;
using ThreatSource.Target;
using ThreatSource.Guidance;
namespace ThreatSource.Tests.Missile
{
@ -12,6 +13,7 @@ namespace ThreatSource.Tests.Missile
private readonly SimulationManager _simulationManager;
private readonly InfraredImagingTerminalGuidedMissile _missile;
private readonly MissileProperties _properties;
private readonly InitialMotionParameters _initialMotion;
public InfraredImagingTerminalGuidedMissileTests()
{
@ -19,10 +21,6 @@ namespace ThreatSource.Tests.Missile
_properties = new MissileProperties
{
Id = "missile1",
InitialPosition = new Vector3D(0, 0, 0),
InitialOrientation = new Orientation(0, 0, 0),
InitialSpeed = 100,
MaxSpeed = 1000,
MaxFlightTime = 100,
MaxFlightDistance = 10000,
@ -34,7 +32,30 @@ namespace ThreatSource.Tests.Missile
Type = MissileType.InfraredImagingTerminalGuidance
};
_missile = new InfraredImagingTerminalGuidedMissile(_properties, _simulationManager);
_initialMotion = new InitialMotionParameters
{
Position = new Vector3D(0, 0, 0),
Orientation = new Orientation(0, 0, 0),
InitialSpeed = 100
};
var guidanceConfig = new InfraredImagingGuidanceConfig
{
SearchFieldOfView = Math.PI / 15,
TrackFieldOfView = Math.PI / 60,
SearchRecognitionProbability = 0.6,
TrackRecognitionProbability = 0.8,
MaxDetectionRange = 5000
};
_missile = new InfraredImagingTerminalGuidedMissile(
"missile1",
TargetType.Tank,
_properties,
_initialMotion,
guidanceConfig,
_simulationManager
);
_simulationManager.RegisterEntity("missile1", _missile);
}
@ -79,7 +100,13 @@ namespace ThreatSource.Tests.Missile
}
// 7. 末制导阶段
var tank = new Tank("target1", new Vector3D(500, 0, 0), 0, _simulationManager);
var tankInitialMotion = new InitialMotionParameters
{
Position = new Vector3D(500, 0, 0),
Orientation = new Orientation(0, 0, 0),
InitialSpeed = 0
};
var tank = new Tank("target1", tankInitialMotion, _simulationManager);
_simulationManager.RegisterEntity("target1", tank);
tank.Activate();
@ -111,7 +138,7 @@ namespace ThreatSource.Tests.Missile
// Arrange
_missile.Fire();
var maxDistance = _properties.MaxFlightDistance;
var timeToExceedDistance = maxDistance / _properties.InitialSpeed + 1;
var timeToExceedDistance = maxDistance / 100 + 1; // 使用初始速度100
// Act
for (double time = 0; time < timeToExceedDistance; time += 0.1)
@ -190,9 +217,9 @@ namespace ThreatSource.Tests.Missile
_missile.Fire();
// Assert
Assert.Equal(_properties.InitialSpeed, _missile.Speed);
Assert.Equal(_properties.InitialPosition, _missile.Position);
Assert.Equal(_properties.InitialOrientation, _missile.Orientation);
Assert.Equal(_initialMotion.InitialSpeed, _missile.Speed);
Assert.Equal(_initialMotion.Position, _missile.Position);
Assert.Equal(_initialMotion.Orientation, _missile.Orientation);
}
}
}

View File

@ -3,6 +3,7 @@ using ThreatSource.Missile;
using ThreatSource.Simulation;
using ThreatSource.Utils;
using ThreatSource.Tests.Simulation;
using ThreatSource.Guidance;
namespace ThreatSource.Tests.Missile
{
@ -21,10 +22,6 @@ namespace ThreatSource.Tests.Missile
_properties = new MissileProperties
{
Id = "missile1",
InitialPosition = new Vector3D(0, 0, 0),
InitialOrientation = new Orientation(0, 0, 0),
InitialSpeed = 100,
MaxSpeed = 1000,
MaxFlightTime = 100,
MaxFlightDistance = 10000,
@ -36,7 +33,37 @@ namespace ThreatSource.Tests.Missile
Type = MissileType.LaserBeamRiderGuidance
};
_missile = new LaserBeamRiderMissile(_properties, _simulationManager);
var missileInitialMotion = new InitialMotionParameters
{
Position = new Vector3D(0, 0, 0),
Orientation = new Orientation(0, 0, 0),
InitialSpeed = 100
};
var laserCodeConfig = new LaserCodeConfig
{
Code = new LaserCode
{
CodeType = LaserCodeType.PRF,
CodeValue = 1234
}
};
var guidanceConfig = new LaserBeamRiderGuidanceSystemConfig
{
MaxGuidanceAcceleration = 50.0,
ControlFieldDiameter = 20.0,
DetectorDiameter = 0.1
};
_missile = new LaserBeamRiderMissile(
"missile1",
_properties,
missileInitialMotion,
laserCodeConfig,
guidanceConfig,
_simulationManager
);
_simulationManager.RegisterEntity("missile1", _missile);
}
@ -104,7 +131,7 @@ namespace ThreatSource.Tests.Missile
_missile.Fire();
_missile.Activate();
var maxDistance = _properties.MaxFlightDistance;
var timeToExceedDistance = maxDistance / _properties.InitialSpeed + 1;
var timeToExceedDistance = maxDistance / 100 + 1; // 使用初始速度100
// Act
for (double time = 0; time < timeToExceedDistance; time += 0.1)

View File

@ -26,10 +26,6 @@ namespace ThreatSource.Tests.Missile
_properties = new MissileProperties
{
Id = "missile1",
InitialPosition = new Vector3D(0, 0, 0),
InitialOrientation = new Orientation(0, 0, 0),
InitialSpeed = 100,
MaxSpeed = 1000,
MaxFlightTime = 100,
MaxFlightDistance = 10000,
@ -41,6 +37,13 @@ namespace ThreatSource.Tests.Missile
Type = MissileType.LaserSemiActiveGuidance
};
var missileInitialMotion = new InitialMotionParameters
{
Position = new Vector3D(0, 0, 0),
Orientation = new Orientation(0, 0, 0),
InitialSpeed = 100
};
// 创建并注册模拟的激光指示器位置在导弹后方100米处
_laserDesignator = new MockLaserDesignator("laser1", _simulationManager);
_laserDesignator.Position = new Vector3D(-100, 0, 0);
@ -52,21 +55,68 @@ namespace ThreatSource.Tests.Missile
_target.Position = new Vector3D(1000, 0, 0);
_testAdapter.AddTestEntity("target1", _target);
// 创建导弹并注册到仿真管理器
_missile = new LaserSemiActiveGuidedMissile(_properties, _simulationManager);
var laserCodeConfig = new LaserCodeConfig
{
Code = new LaserCode
{
CodeType = LaserCodeType.PRF,
CodeValue = 1234
}
};
var guidanceConfig = new LaserSemiActiveGuidanceConfig
{
FieldOfViewAngle = 30,
LensDiameter = 0.1,
SensorDiameter = 0.03,
FocusedSpotDiameter = 0.006,
ReflectionCoefficient = 0.2,
TargetReflectiveArea = 1.0,
LockThreshold = 1e-12,
SpotOffsetSensitivity = 0.5
};
_missile = new LaserSemiActiveGuidedMissile(
"missile1",
_properties,
missileInitialMotion,
laserCodeConfig,
guidanceConfig,
_simulationManager
);
_simulationManager.RegisterEntity("missile1", _missile);
// 创建独立的制导系统用于测试
var guidanceSystem = new LaserSemiActiveGuidanceSystem(
"guidance1",
_properties.MaxAcceleration,
_properties.ProportionalNavigationCoefficient,
laserCodeConfig,
guidanceConfig,
_simulationManager
);
guidanceSystem.ParentId = "missile1";
_simulationManager.RegisterEntity("guidance1", guidanceSystem);
}
private LaserSemiActiveGuidanceSystem GetGuidanceSystem()
{
return (_simulationManager.GetEntityById("guidance1") as LaserSemiActiveGuidanceSystem)!;
}
// 模拟的激光指示器类
private class MockLaserDesignator : LaserDesignator
{
public MockLaserDesignator(string id, ISimulationManager simulationManager)
: base(id, "target1", "missile1", 0, new LaserDesignatorConfig
: base(id, "target1", "missile1", new LaserDesignatorConfig
{
Id = id,
InitialPosition = new Vector3D(100, 0, 0),
LaserPower = 100,
LaserDivergenceAngle = 0.001
}, new InitialMotionParameters
{
Position = new Vector3D(100, 0, 0),
Orientation = new Orientation(0, 0, 0),
InitialSpeed = 0
}, simulationManager)
{
// 不需要额外设置属性,因为基类构造函数已经设置了
@ -77,7 +127,12 @@ namespace ThreatSource.Tests.Missile
private class MockTarget : Tank
{
public MockTarget(string id, ISimulationManager simulationManager)
: base(id, new Vector3D(1000, 0, 0), 10, simulationManager)
: base(id, new InitialMotionParameters
{
Position = new Vector3D(1000, 0, 0),
Orientation = new Orientation(0, 0, 0),
InitialSpeed = 0
}, simulationManager)
{
// 不需要额外设置属性,因为基类构造函数已经设置了
}
@ -89,9 +144,10 @@ namespace ThreatSource.Tests.Missile
// Arrange
_missile.Fire();
_missile.Activate();
var guidanceSystem = GetGuidanceSystem();
// Act
_missile.SetLaserCode(LaserCodeType.PRF, 1234);
guidanceSystem.SetExpectedLaserCode(LaserCodeType.PRF, 1234);
// Assert - We can't directly check the private field, but we can test the behavior
// This will be tested in the LaserIllumination test
@ -103,10 +159,11 @@ namespace ThreatSource.Tests.Missile
// Arrange
_missile.Fire();
_missile.Activate();
_missile.SetLaserCode(LaserCodeType.PPM, 5678);
var guidanceSystem = GetGuidanceSystem();
guidanceSystem.SetExpectedLaserCode(LaserCodeType.PPM, 5678);
// Act
_missile.AddLaserCodeParameter("PulseWidth", 0.001);
guidanceSystem.AddExpectedCodeParameter("PulseWidth", 0.001);
// Assert - We can't directly check the private field, but we can test the behavior
// This will be tested in the LaserIllumination test
@ -118,9 +175,18 @@ namespace ThreatSource.Tests.Missile
// Arrange
_missile.Fire();
_missile.Activate();
var guidanceSystem = GetGuidanceSystem();
// Act
_missile.SetCodeMatchRequired(true);
_missile.LaserCodeConfig = new LaserCodeConfig
{
IsCodeMatchRequired = true,
Code = new LaserCode
{
CodeType = LaserCodeType.PRF,
CodeValue = 1234
}
};
// Assert - We can't directly check the private field, but we can test the behavior
// This will be tested in the LaserIllumination test
@ -132,8 +198,9 @@ namespace ThreatSource.Tests.Missile
// Arrange
_missile.Fire();
_missile.Activate();
_missile.SetLaserCode(LaserCodeType.PRF, 1234);
_missile.SetCodeMatchRequired(true);
var guidanceSystem = GetGuidanceSystem();
guidanceSystem.SetExpectedLaserCode(LaserCodeType.PRF, 1234);
_missile.LaserCodeConfig.IsCodeMatchRequired = true;
_missile.Update(0.1); // Move past launch stage
// 设置激光指示器和目标位置,确保在视场角内
@ -176,8 +243,9 @@ namespace ThreatSource.Tests.Missile
// Arrange
_missile.Fire();
_missile.Activate();
_missile.SetLaserCode(LaserCodeType.PRF, 1234);
_missile.SetCodeMatchRequired(true);
var guidanceSystem = GetGuidanceSystem();
guidanceSystem.SetExpectedLaserCode(LaserCodeType.PRF, 1234);
_missile.LaserCodeConfig.IsCodeMatchRequired = true;
_missile.Update(0.1); // Move past launch stage
// 设置激光指示器和目标位置,确保在视场角内
@ -220,8 +288,9 @@ namespace ThreatSource.Tests.Missile
// Arrange
_missile.Fire();
_missile.Activate();
_missile.SetLaserCode(LaserCodeType.PRF, 1234);
_missile.SetCodeMatchRequired(false); // Not required
var guidanceSystem = GetGuidanceSystem();
guidanceSystem.SetExpectedLaserCode(LaserCodeType.PRF, 1234);
_missile.LaserCodeConfig.IsCodeMatchRequired = false; // Not required
_missile.Update(0.1); // Move past launch stage
// 设置激光指示器和目标位置,确保在视场角内
@ -262,8 +331,9 @@ namespace ThreatSource.Tests.Missile
// Arrange
_missile.Fire();
_missile.Activate();
_missile.SetLaserCode(LaserCodeType.PRF, 1234);
_missile.SetCodeMatchRequired(true); // Required
var guidanceSystem = GetGuidanceSystem();
guidanceSystem.SetExpectedLaserCode(LaserCodeType.PRF, 1234);
_missile.LaserCodeConfig.IsCodeMatchRequired = true; // Required
_missile.Update(0.1); // Move past launch stage
// Act - Send illumination with code disabled
@ -299,8 +369,9 @@ namespace ThreatSource.Tests.Missile
// Arrange
_missile.Fire();
_missile.Activate();
_missile.SetLaserCode(LaserCodeType.PRF, 1234);
_missile.SetCodeMatchRequired(true);
var guidanceSystem = GetGuidanceSystem();
guidanceSystem.SetExpectedLaserCode(LaserCodeType.PRF, 1234);
_missile.LaserCodeConfig.IsCodeMatchRequired = true;
_missile.Update(0.1); // Move past launch stage
// 设置激光指示器和目标位置,确保在视场角内

View File

@ -47,14 +47,10 @@ namespace ThreatSource.Tests.Missile
_properties = new MissileProperties
{
Id = "missile1",
InitialPosition = new Vector3D(0, 0, 0),
InitialOrientation = new Orientation(0, 0, 0),
InitialSpeed = 100,
MaxSpeed = 1000,
MaxFlightTime = 100,
MaxFlightDistance = 10000,
MaxAcceleration = 50,
MaxAcceleration = 50,
ProportionalNavigationCoefficient = 3,
Mass = 100,
ExplosionRadius = 10,
@ -62,24 +58,80 @@ namespace ThreatSource.Tests.Missile
Type = MissileType.LaserSemiActiveGuidance
};
// 创建并注册激光指示器位置在导弹后方100米处
_laserDesignator = new LaserDesignator("laser1", "target1", "missile1", 0, new LaserDesignatorConfig
var missileInitialMotion = new InitialMotionParameters
{
Position = new Vector3D(0, 0, 0),
Orientation = new Orientation(0, 0, 0),
InitialSpeed = 100
};
var laserDesignatorInitialMotion = new InitialMotionParameters
{
Position = new Vector3D(-100, 0, 0),
Orientation = new Orientation(0, 0, 0),
InitialSpeed = 0
};
// 创建并注册激光指示器位置在导弹后方100米处
var laserDesignatorConfig = new LaserDesignatorConfig
{
Id = "laser1",
InitialPosition = new Vector3D(-100, 0, 0),
LaserPower = 100,
LaserDivergenceAngle = 0.001
}, _simulationManager);
};
_laserDesignator = new LaserDesignator(
"laser1",
"target1",
"missile1",
laserDesignatorConfig,
laserDesignatorInitialMotion,
_simulationManager
);
_testAdapter.AddTestEntity("laser1", _laserDesignator);
_simulationManager.RegisterEntity("laser1", _laserDesignator);
// 创建并注册模拟的目标位置在导弹前方1000米处
_target = new MockTarget("target1", _simulationManager);
_target.Position = new Vector3D(1000, 0, 0);
var targetInitialMotion = new InitialMotionParameters
{
Position = new Vector3D(1000, 0, 0),
Orientation = new Orientation(0, 0, 0),
InitialSpeed = 0
};
_target = new MockTarget("target1", targetInitialMotion, _simulationManager);
_testAdapter.AddTestEntity("target1", _target);
// 创建激光代码配置
var laserCodeConfig = new LaserCodeConfig
{
Code = new LaserCode
{
CodeType = LaserCodeType.PRF,
CodeValue = 1234
}
};
// 创建导引系统配置
var guidanceConfig = new LaserSemiActiveGuidanceConfig
{
FieldOfViewAngle = 30,
LensDiameter = 0.1,
SensorDiameter = 0.03,
FocusedSpotDiameter = 0.006,
ReflectionCoefficient = 0.2,
TargetReflectiveArea = 1.0,
LockThreshold = 1e-12,
SpotOffsetSensitivity = 0.5
};
// 创建导弹并注册到仿真管理器
_missile = new LaserSemiActiveGuidedMissile(_properties, _simulationManager);
_missile = new LaserSemiActiveGuidedMissile(
"missile1",
_properties,
missileInitialMotion,
laserCodeConfig,
guidanceConfig,
_simulationManager
);
_testAdapter.AddTestEntity("missile1", _missile);
_simulationManager.RegisterEntity("missile1", _missile);
}
@ -87,8 +139,8 @@ namespace ThreatSource.Tests.Missile
// 模拟的目标类
private class MockTarget : Tank
{
public MockTarget(string id, ISimulationManager simulationManager)
: base(id, new Vector3D(1000, 0, 0), 10, simulationManager)
public MockTarget(string id, InitialMotionParameters initialMotionParameters, ISimulationManager simulationManager)
: base(id, initialMotionParameters, simulationManager)
{
// 不需要额外设置属性,因为基类构造函数已经设置了
}

View File

@ -21,10 +21,6 @@ namespace ThreatSource.Tests.Missile
_properties = new MissileProperties
{
Id = "missile1",
InitialPosition = new Vector3D(0, 0, 0),
InitialOrientation = new Orientation(0, 0, 0),
InitialSpeed = 100,
MaxSpeed = 1000,
MaxFlightTime = 100,
MaxFlightDistance = 10000,
@ -36,7 +32,42 @@ namespace ThreatSource.Tests.Missile
Type = MissileType.LaserSemiActiveGuidance
};
_missile = new LaserSemiActiveGuidedMissile(_properties, _simulationManager);
var missileInitialMotion = new InitialMotionParameters
{
Position = new Vector3D(0, 0, 0),
Orientation = new Orientation(0, 0, 0),
InitialSpeed = 100
};
var laserCodeConfig = new LaserCodeConfig
{
Code = new LaserCode
{
CodeType = LaserCodeType.PRF,
CodeValue = 1234
}
};
var guidanceConfig = new LaserSemiActiveGuidanceConfig
{
FieldOfViewAngle = 30,
LensDiameter = 0.1,
SensorDiameter = 0.03,
FocusedSpotDiameter = 0.006,
ReflectionCoefficient = 0.2,
TargetReflectiveArea = 1.0,
LockThreshold = 1e-12,
SpotOffsetSensitivity = 0.5
};
_missile = new LaserSemiActiveGuidedMissile(
"missile1",
_properties,
missileInitialMotion,
laserCodeConfig,
guidanceConfig,
_simulationManager
);
_simulationManager.RegisterEntity("missile1", _missile);
}
@ -104,7 +135,7 @@ namespace ThreatSource.Tests.Missile
_missile.Fire();
_missile.Activate();
var maxDistance = _properties.MaxFlightDistance;
var timeToExceedDistance = maxDistance / _properties.InitialSpeed + 1;
var timeToExceedDistance = maxDistance / 100 + 1; // 使用初始速度100
// Act
for (double time = 0; time < timeToExceedDistance; time += 0.1)

View File

@ -4,6 +4,7 @@ using ThreatSource.Simulation;
using ThreatSource.Utils;
using ThreatSource.Tests.Simulation;
using ThreatSource.Target;
using ThreatSource.Guidance;
namespace ThreatSource.Tests.Missile
{
@ -22,10 +23,6 @@ namespace ThreatSource.Tests.Missile
_properties = new MissileProperties
{
Id = "missile1",
InitialPosition = new Vector3D(0, 0, 0),
InitialOrientation = new Orientation(0, 0, 0),
InitialSpeed = 100,
MaxSpeed = 1000,
MaxFlightTime = 100,
MaxFlightDistance = 10000,
@ -37,7 +34,28 @@ namespace ThreatSource.Tests.Missile
Type = MissileType.MillimeterWaveTerminalGuidance
};
_missile = new MillimeterWaveTerminalGuidedMissile(_properties, _simulationManager);
var missileInitialMotion = new InitialMotionParameters
{
Position = new Vector3D(0, 0, 0),
Orientation = new Orientation(0, 0, 0),
InitialSpeed = 100
};
var guidanceConfig = new MillimeterWaveGuidanceConfig
{
FieldOfViewAngle = 30,
TransmitPower = 0.5,
AntennaGainDB = 25,
WaveFrequency = 94e9
};
_missile = new MillimeterWaveTerminalGuidedMissile(
"missile1",
_properties,
missileInitialMotion,
guidanceConfig,
_simulationManager
);
_simulationManager.RegisterEntity("missile1", _missile);
}
@ -56,7 +74,13 @@ namespace ThreatSource.Tests.Missile
public void Update_StageTransition_WorksCorrectly()
{
// Arrange
var tank = new Tank("target1", new Vector3D(1000, 0, 0), 0, _simulationManager);
var tankInitialMotion = new InitialMotionParameters
{
Position = new Vector3D(1000, 0, 0),
Orientation = new Orientation(0, 0, 0),
InitialSpeed = 0
};
var tank = new Tank("target1", tankInitialMotion, _simulationManager);
_simulationManager.RegisterEntity("target1", tank);
tank.Activate();
@ -112,7 +136,7 @@ namespace ThreatSource.Tests.Missile
_missile.Fire();
_missile.Activate();
var maxDistance = _properties.MaxFlightDistance;
var timeToExceedDistance = maxDistance / _properties.InitialSpeed + 1;
var timeToExceedDistance = maxDistance / 100 + 1; // 使用初始速度100
// Act
for (double time = 0; time < timeToExceedDistance; time += 0.1)

View File

@ -17,6 +17,7 @@ namespace ThreatSource.Tests.Missile
private readonly MissileProperties _properties;
private readonly MissileProperties _submunitionProperties;
private readonly Tank _tank;
private readonly InitialMotionParameters _missileInitialMotion;
public TerminalSensitiveMissileTests(ITestOutputHelper output)
{
@ -26,10 +27,16 @@ namespace ThreatSource.Tests.Missile
_simulationManager.SetSimulationAdapter(_testAdapter);
// 先创建并注册目标
var tankInitialMotion = new InitialMotionParameters
{
Position = new Vector3D(100, 0, 100),
Orientation = new Orientation(Math.PI/4, 0, 0), // 目标朝向45度
InitialSpeed = 0
};
_tank = new Tank(
"tank1",
new Vector3D(100, 0, 100),
Math.PI/4, // 目标朝向45度
tankInitialMotion,
_simulationManager
);
_simulationManager.RegisterEntity("tank1", _tank);
@ -37,10 +44,6 @@ namespace ThreatSource.Tests.Missile
_properties = new MissileProperties
{
Id = "missile1",
InitialPosition = new Vector3D(3000, 0, 100),
InitialOrientation = new Orientation(Math.PI, 0, 0),
InitialSpeed = 800,
MaxSpeed = 1000,
MaxFlightTime = 30,
MaxFlightDistance = 5000,
@ -54,6 +57,13 @@ namespace ThreatSource.Tests.Missile
Type = MissileType.TerminalSensitiveMissile
};
_missileInitialMotion = new InitialMotionParameters
{
Position = new Vector3D(3000, 0, 100),
Orientation = new Orientation(Math.PI, 0, 0),
InitialSpeed = 800
};
_submunitionProperties = new MissileProperties
{
MaxSpeed = 2000,
@ -68,7 +78,23 @@ namespace ThreatSource.Tests.Missile
Type = MissileType.TerminalSensitiveSubmunition
};
_missile = new TerminalSensitiveMissile("tank1", _properties, _submunitionProperties, 1, _simulationManager);
var submunitionConfig = new TerminalSensitiveSubmunitionConfig
{
SeparationHeight = 1000.0,
SeparationDistance = 1000.0,
SubmunitionSeparationAngle = 45.0
};
_missile = new TerminalSensitiveMissile(
"tank1",
"missile1",
_properties,
_missileInitialMotion,
_submunitionProperties,
1,
submunitionConfig,
_simulationManager
);
_simulationManager.RegisterEntity("missile1", _missile);
}

View File

@ -17,6 +17,7 @@ namespace ThreatSource.Tests.Missile
private readonly MissileProperties _properties;
private readonly Tank _tank;
private readonly ITestOutputHelper _output;
private readonly InitialMotionParameters _submunitionInitialMotion;
public TerminalSensitiveSubmunitionTests(ITestOutputHelper output)
{
@ -26,10 +27,16 @@ namespace ThreatSource.Tests.Missile
_simulationManager.SetSimulationAdapter(_testAdapter);
// 先创建并注册目标
var tankInitialMotion = new InitialMotionParameters
{
Position = new Vector3D(100, 0, 100), // 目标位置
Orientation = new Orientation(Math.PI/4, 0, 0), // 目标朝向45度
InitialSpeed = 0
};
_tank = new Tank(
"tank1",
new Vector3D(100, 0, 100), // 目标位置
Math.PI/4, // 目标朝向45度
tankInitialMotion,
_simulationManager
);
_simulationManager.RegisterEntity("tank1", _tank);
@ -38,10 +45,6 @@ namespace ThreatSource.Tests.Missile
// 子弹的初始配置
_properties = new MissileProperties
{
Id = "missile1_Sub_0",
InitialPosition = new Vector3D(1100, 400, 100), // 在目标前方1000米高度400米
InitialOrientation = new Orientation(0, -Math.PI/4, 0), // 向下45度
InitialSpeed = 200,
MaxSpeed = 2000,
MaxFlightTime = 50,
MaxFlightDistance = 1000,
@ -53,7 +56,28 @@ namespace ThreatSource.Tests.Missile
Type = MissileType.TerminalSensitiveMissile
};
_submunition = new TerminalSensitiveSubmunition("tank1", _properties, _simulationManager);
_submunitionInitialMotion = new InitialMotionParameters
{
Position = new Vector3D(1100, 400, 100), // 在目标前方1000米高度400米
Orientation = new Orientation(0, -Math.PI/4, 0), // 向下45度
InitialSpeed = 200
};
var submunitionConfig = new TerminalSensitiveSubmunitionConfig
{
SeparationHeight = 400.0,
SeparationDistance = 1000.0,
SubmunitionSeparationAngle = 45.0
};
_submunition = new TerminalSensitiveSubmunition(
"tank1",
"missile1_Sub_0",
_properties,
_submunitionInitialMotion,
submunitionConfig,
_simulationManager
);
_simulationManager.RegisterEntity("missile1_Sub_0", _submunition);
}
@ -61,8 +85,8 @@ namespace ThreatSource.Tests.Missile
public void Constructor_InitializesPropertiesCorrectly()
{
Assert.Equal("missile1_Sub_0", _submunition.Id);
Assert.Equal(_properties.InitialPosition, _submunition.Position);
Assert.Equal(_properties.InitialSpeed, _submunition.Speed);
Assert.Equal(_submunitionInitialMotion.Position, _submunition.Position);
Assert.Equal(_submunitionInitialMotion.InitialSpeed, _submunition.Speed);
Assert.False(_submunition.IsActive);
Assert.False(_submunition.IsGuidance);
}

View File

@ -22,6 +22,9 @@ namespace ThreatSource.Tests.Simulation
private double _currentTime = 0;
private readonly object _eventLock = new object();
// 添加事件声明
public event EventHandler<SimulationEvent>? EventPublished;
/// <summary>
/// 构造函数,初始化测试适配器
/// </summary>
@ -58,6 +61,8 @@ namespace ThreatSource.Tests.Simulation
{
simEvent.Timestamp = _currentTime; // 使用仿真时间作为时间戳
_publishedEvents.Add(simEvent);
// 触发事件
EventPublished?.Invoke(this, simEvent);
}
}

View File

@ -14,14 +14,31 @@ namespace ThreatSource.Tests.Target
public TankTests()
{
_simulationManager = new SimulationManager();
_tank = new Tank("tank1", new Vector3D(100, 0, 0), 10, _simulationManager);
// 创建初始运动参数
var initialMotionParameters = new InitialMotionParameters
{
Position = new Vector3D(100, 0, 0),
Orientation = new Orientation(0, 0, 0),
InitialSpeed = 10
};
// 使用新的构造函数创建坦克
_tank = new Tank("tank1", initialMotionParameters, _simulationManager);
}
[Fact]
public void Constructor_InitializesPropertiesCorrectly()
{
// Arrange & Act
var tank = new Tank("tank2", new Vector3D(200, 0, 0), 10, _simulationManager);
var initialMotionParameters = new InitialMotionParameters
{
Position = new Vector3D(200, 0, 0),
Orientation = new Orientation(0, 0, 0),
InitialSpeed = 10
};
var tank = new Tank("tank2", initialMotionParameters, _simulationManager);
// Assert
Assert.NotNull(tank);

View File

@ -1,7 +1,6 @@
using ThreatSource.Utils;
using ThreatSource.Simulation;
using System.Diagnostics;
using System.Collections.Generic;
namespace ThreatSource.Guidance
{

View File

@ -1,4 +1,5 @@
using ThreatSource.Utils;
using ThreatSource.Jamming;
namespace ThreatSource.Indicator
{
@ -10,9 +11,10 @@ namespace ThreatSource.Indicator
/// - 目标和导弹的关联
/// - 运行状态的获取
/// - 位置和姿态的管理
/// - 干扰处理能力
/// 是激光指示器、红外跟踪器等具体指示器的抽象基础
/// </remarks>
public interface IIndicator
public interface IIndicator : IJammable
{
/// <summary>
/// 获取或设置目标ID
@ -42,6 +44,7 @@ namespace ThreatSource.Indicator
/// - 指示器的工作状态
/// - 位置、速度和姿态信息
/// - 激活状态
/// - 干扰状态
/// </remarks>
IndicatorRunningState GetRunningState();
}
@ -55,6 +58,7 @@ namespace ThreatSource.Indicator
/// - 工作状态(类型和状态)
/// - 运动状态(位置、速度、姿态)
/// - 功能状态(是否激活)
/// - 干扰状态(是否被干扰)
/// 用于状态监控和控制决策
/// </remarks>
public struct IndicatorRunningState
@ -130,6 +134,15 @@ namespace ThreatSource.Indicator
/// true表示正在工作false表示待机
/// </remarks>
public bool IsActive { get; set; }
/// <summary>
/// 获取或设置指示器的干扰状态
/// </summary>
/// <remarks>
/// 表示指示器当前的干扰状态
/// 用于状态监控和干扰防护
/// </remarks>
public JammingState JammingState { get; set; }
}
/// <summary>
@ -178,4 +191,25 @@ namespace ThreatSource.Indicator
/// </summary>
Idle
}
/// <summary>
/// 干扰状态枚举,定义了指示器的干扰状态
/// </summary>
/// <remarks>
/// 包含两种基本状态:
/// - Normal正常状态未受到干扰
/// - Jammed干扰状态受到干扰影响
/// 用于干扰状态监控和防护
/// </remarks>
public enum JammingState
{
/// <summary>
/// 正常状态
/// </summary>
Normal,
/// <summary>
/// 干扰状态
/// </summary>
Jammed
}
}

View File

@ -0,0 +1,160 @@
using ThreatSource.Utils;
using ThreatSource.Jamming;
using ThreatSource.Simulation;
using System.Collections.Generic;
namespace ThreatSource.Indicator
{
/// <summary>
/// 指示器抽象基类实现IIndicator接口的基本功能
/// </summary>
/// <remarks>
/// 该类提供了指示器的通用实现:
/// - 位置和姿态管理
/// - 激活状态控制
/// - 干扰处理机制
/// 是具体指示器类的实现基础
/// </remarks>
public abstract class IndicatorBase : SimulationElement, IIndicator
{
/// <summary>
/// 干扰处理器
/// </summary>
/// <remarks>
/// 负责处理各类干扰对指示器的影响
/// 管理干扰状态和恢复
/// </remarks>
private protected JammingHandler? JammingHandler { get; set; }
/// <summary>
/// 获取设备支持的干扰类型
/// </summary>
/// <remarks>
/// 定义指示器可以被哪些类型的干扰影响
/// 子类需要重写此属性以指定支持的干扰类型
/// </remarks>
public abstract IEnumerable<JammingType> SupportedJammingTypes { get; }
/// <summary>
/// 获取设备当前是否处于被干扰状态
/// </summary>
/// <remarks>
/// true表示指示器当前受到干扰影响
/// false表示指示器正常工作
/// </remarks>
public bool IsJammed => JammingHandler?.IsJammed ?? false;
/// <summary>
/// 获取或设置目标ID
/// </summary>
public string? TargetId { get; protected set; }
/// <summary>
/// 获取或设置导弹ID
/// </summary>
public string? MissileId { get; protected set; }
/// <summary>
/// 初始化指示器基类的新实例
/// </summary>
/// <param name="id">指示器ID</param>
/// <param name="position">初始位置</param>
/// <param name="orientation">初始朝向</param>
/// <param name="initialSpeed">初始速度</param>
/// <param name="manager">仿真管理器实例</param>
/// <remarks>
/// 构造过程:
/// - 调用基类构造器
/// - 初始化基本属性
/// - 初始化干扰处理器
/// </remarks>
protected IndicatorBase(string id, Vector3D position, Orientation orientation, double initialSpeed, ISimulationManager manager)
: base(id, position, orientation, initialSpeed, manager)
{
InitializeJammingHandler();
}
/// <summary>
/// 初始化干扰处理器
/// </summary>
/// <remarks>
/// 子类需要重写此方法以初始化适合自身的干扰处理器
/// </remarks>
protected abstract void InitializeJammingHandler();
/// <summary>
/// 应用干扰
/// </summary>
/// <param name="parameters">干扰参数</param>
/// <remarks>
/// 处理对指示器的干扰影响
/// 只有支持的干扰类型才会被处理
/// </remarks>
public virtual void ApplyJamming(JammingParameters parameters)
{
if (SupportedJammingTypes.Contains(parameters.Type))
{
JammingHandler?.HandleJamming(parameters);
}
}
/// <summary>
/// 清除干扰
/// </summary>
/// <param name="type">要清除的干扰类型</param>
/// <remarks>
/// 移除特定类型的干扰影响
/// 恢复指示器的正常工作状态
/// </remarks>
public virtual void ClearJamming(JammingType type)
{
if (SupportedJammingTypes.Contains(type))
{
JammingHandler?.ClearJamming();
}
}
/// <summary>
/// 更新指示器状态
/// </summary>
/// <param name="deltaTime">时间步长,单位:秒</param>
/// <remarks>
/// 更新过程:
/// - 调用基类的更新方法
/// - 检查激活状态
/// - 更新干扰状态
/// - 处理指示器特定逻辑
/// </remarks>
public override void Update(double deltaTime)
{
if (IsActive)
{
JammingHandler?.Update(deltaTime);
UpdateIndicator(deltaTime);
}
}
/// <summary>
/// 更新指示器特定功能
/// </summary>
/// <param name="deltaTime">时间步长,单位:秒</param>
/// <remarks>
/// 子类需要重写此方法以实现特定的更新逻辑
/// 只有在未被干扰时才应执行正常的功能逻辑
/// </remarks>
protected virtual void UpdateIndicator(double deltaTime)
{
// 子类中实现具体的指示器更新逻辑
}
/// <summary>
/// 获取指示器运行状态
/// </summary>
/// <returns>包含指示器完整状态信息的结构体</returns>
/// <remarks>
/// 子类需要重写此方法以提供完整的状态信息
/// 包括位置、姿态、目标关联和干扰状态等
/// </remarks>
public abstract IndicatorRunningState GetRunningState();
}
}

View File

@ -1,6 +1,8 @@
using ThreatSource.Simulation;
using ThreatSource.Utils;
using ThreatSource.Missile;
using ThreatSource.Jamming;
using System.Diagnostics;
namespace ThreatSource.Indicator
{
@ -13,27 +15,23 @@ namespace ThreatSource.Indicator
/// - 角度测量和计算
/// - 制导指令生成
/// - 事件处理和状态管理
/// - 干扰防护处理
/// 通过测量目标的红外辐射实现对导弹的制导控制
/// </remarks>
public class InfraredTracker : SimulationElement, IIndicator
public class InfraredTracker : IndicatorBase
{
/// <summary>
/// 获取或设置当前跟踪的导弹ID
/// 获取设备支持的干扰类型
/// </summary>
/// <remarks>
/// 记录当前正在跟踪的导弹标识符
/// 用于导弹识别和制导控制
/// 红外测角仪支持的干扰类型:
/// - 红外干扰
/// - 激光干扰
/// </remarks>
public string? MissileId { get; private set; }
/// <summary>
/// 获取或设置目标ID
/// </summary>
/// <remarks>
/// 记录当前跟踪的目标标识符
/// 用于目标识别和状态更新
/// </remarks>
public string? TargetId { get; private set; }
public override IEnumerable<JammingType> SupportedJammingTypes => new[]
{
JammingType.Infrared
};
/// <summary>
/// 红外测角仪配置参数
@ -81,20 +79,33 @@ namespace ThreatSource.Indicator
}
/// <summary>
/// 更新红外测角仪状态
/// 初始化干扰处理器
/// </summary>
/// <remarks>
/// 创建适用于红外测角仪的干扰处理器
/// </remarks>
protected override void InitializeJammingHandler()
{
JammingHandler = new InfraredTrackerJammingHandler(this);
}
/// <summary>
/// 更新指示器特定功能
/// </summary>
/// <param name="deltaTime">时间步长,单位:秒</param>
/// <remarks>
/// 更新过程:
/// - 检查激活状态
/// 实现红外测角仪特定的更新逻辑
/// - 只有在未被干扰时才执行跟踪
/// - 更新跟踪状态
/// - 处理目标跟踪
/// </remarks>
public override void Update(double deltaTime)
protected override void UpdateIndicator(double deltaTime)
{
if (!IsActive) return;
UpdateTracking();
// 只有在未被干扰时才执行跟踪
if (!IsJammed)
{
UpdateTracking();
}
}
/// <summary>
@ -226,6 +237,7 @@ namespace ThreatSource.Indicator
base.Activate();
SimulationManager.SubscribeToEvent<InfraredGuidanceMissileLightEvent>(OnInfraredGuidanceMissileLight);
SimulationManager.SubscribeToEvent<InfraredGuidanceMissileLightOffEvent>(OnInfraredGuidanceMissileLightOff);
SimulationManager.SubscribeToEvent<InfraredJammingEvent>(OnInfraredJamming);
}
/// <summary>
@ -242,6 +254,88 @@ namespace ThreatSource.Indicator
base.Deactivate();
SimulationManager.UnsubscribeFromEvent<InfraredGuidanceMissileLightEvent>(OnInfraredGuidanceMissileLight);
SimulationManager.UnsubscribeFromEvent<InfraredGuidanceMissileLightOffEvent>(OnInfraredGuidanceMissileLightOff);
SimulationManager.UnsubscribeFromEvent<InfraredJammingEvent>(OnInfraredJamming);
}
/// <summary>
/// 处理红外干扰事件
/// </summary>
/// <param name="evt">红外干扰事件数据</param>
/// <remarks>
/// 处理过程:
/// - 计算干扰效果
/// - 应用干扰状态
/// </remarks>
private void OnInfraredJamming(InfraredJammingEvent evt)
{
// 计算干扰源与测角仪的相对位置
Vector3D relativePosition = evt.JammingSourcePosition - Position;
double distance = relativePosition.Magnitude();
// 计算干扰源与测角仪的相对方向
Vector3D jammingToTracker = relativePosition.Normalize();
// 计算干扰方向与干扰源到测角仪方向的夹角
// 注意:干扰源到测角仪的方向应该与干扰方向相反
double angle = Math.Acos(-Vector3D.DotProduct(evt.JammingDirection.Normalize(), jammingToTracker));
Debug.WriteLine($"干扰判断 - 距离: {distance:F2}米, 夹角: {angle * 180 / Math.PI:F2}度, 角度范围: {evt.JammingAngleRange * 180 / Math.PI:F2}度");
// 判断是否在干扰角度范围内
if (angle <= evt.JammingAngleRange)
{
// 计算距离衰减后的实际干扰功率
double attenuatedPower = evt.JammingPower / (distance * distance);
// 检查测角仪工作波段是否在干扰波长范围内
bool isWavelengthInRange = IsWavelengthInRange(evt.WavelengthMin, evt.WavelengthMax);
Debug.WriteLine($"干扰功率 - 原始: {evt.JammingPower:F2}W, 衰减后: {attenuatedPower:F2}W, 阈值: {config.JammingResistanceThreshold:F2}W");
Debug.WriteLine($"波长范围 - 干扰: {evt.WavelengthMin:F2}-{evt.WavelengthMax:F2}μm, 匹配: {isWavelengthInRange}");
// 如果功率足够且波长匹配,则应用干扰
if (attenuatedPower >= config.JammingResistanceThreshold && isWavelengthInRange)
{
Debug.WriteLine("应用干扰 - 条件满足,创建干扰参数");
// 创建干扰参数对象
var jammingParameters = new JammingParameters
{
Type = JammingType.Infrared,
Power = attenuatedPower,
Direction = evt.JammingDirection,
AngleRange = evt.JammingAngleRange,
Mode = evt.JammingMode,
Duration = evt.Duration
};
// 应用干扰
ApplyJamming(jammingParameters);
Debug.WriteLine($"干扰状态 - IsJammed: {IsJammed}");
}
else
{
Debug.WriteLine($"不满足干扰条件 - 功率不足或波长不匹配");
}
}
else
{
Debug.WriteLine($"不在干扰角度范围内");
}
}
/// <summary>
/// 检查干扰波长是否在测角仪工作波段范围内
/// </summary>
/// <param name="minWavelength">最小波长(微米)</param>
/// <param name="maxWavelength">最大波长(微米)</param>
/// <returns>如果波长范围有重叠则返回true</returns>
private static bool IsWavelengthInRange(double minWavelength, double maxWavelength)
{
// 假设红外测角仪的工作波段为3-5μm(中波红外)和8-14μm(长波红外)
// 这里应根据实际的红外测角仪配置来判断
return (minWavelength <= 5 && maxWavelength >= 3) || // 中波红外
(minWavelength <= 14 && maxWavelength >= 8); // 长波红外
}
/// <summary>
@ -255,7 +349,7 @@ namespace ThreatSource.Indicator
/// - 位置和姿态信息
/// - 激活状态
/// </remarks>
public IndicatorRunningState GetRunningState()
public override IndicatorRunningState GetRunningState()
{
return new IndicatorRunningState
{
@ -265,7 +359,8 @@ namespace ThreatSource.Indicator
State = IsTracking ? IndicatorState.Indicating : IndicatorState.Idle,
Position = Position,
Orientation = Orientation,
IsActive = IsActive
IsActive = IsActive,
JammingState = IsJammed ? JammingState.Jammed : JammingState.Normal
};
}
@ -277,9 +372,10 @@ namespace ThreatSource.Indicator
/// 返回信息包括:
/// - 基本标识信息
/// - 位置信息
/// - 跟踪状态
/// - 目标关联状态
/// - 工作状态
/// - 跟踪状态
/// - 干扰状态
/// </remarks>
public override string GetStatus()
{
@ -288,7 +384,8 @@ namespace ThreatSource.Indicator
$" 跟踪导弹: {MissileId ?? ""}\n" +
$" 目标: {TargetId ?? ""}\n" +
$" 状态: {(IsActive ? "" : "")}\n" +
$" 跟踪状态: {(IsTracking ? "" : "")}\n";
$" 跟踪状态: {(IsTracking ? "" : "")}\n" +
$" 干扰状态: {(IsJammed ? "" : "")}\n";
}
}
}

View File

@ -2,6 +2,8 @@ using ThreatSource.Simulation;
using System;
using ThreatSource.Utils;
using System.Diagnostics;
using ThreatSource.Jamming;
using System.Collections.Generic;
namespace ThreatSource.Indicator
{
@ -15,8 +17,31 @@ namespace ThreatSource.Indicator
/// - 实时更新波束位置和方向
/// - 发布波束状态事件
/// </remarks>
public class LaserBeamRider : SimulationElement, IIndicator
public class LaserBeamRider : IndicatorBase
{
/// <summary>
/// 获取设备支持的干扰类型
/// </summary>
/// <remarks>
/// 定义波束制导器可以被哪些类型的干扰影响
/// </remarks>
public override IEnumerable<JammingType> SupportedJammingTypes => new[]
{
JammingType.Laser,
JammingType.RadioFrequency
};
/// <summary>
/// 初始化干扰处理器
/// </summary>
/// <remarks>
/// 创建适用于激光波束制导器的干扰处理器
/// </remarks>
protected override void InitializeJammingHandler()
{
JammingHandler = new LaserBeamRiderJammingHandler(this);
}
/// <summary>
/// 获取或设置激光功率
/// </summary>
@ -80,24 +105,6 @@ namespace ThreatSource.Indicator
/// </remarks>
public bool IsBeamOn { get; private set; }
/// <summary>
/// 获取当前制导的导弹ID
/// </summary>
/// <remarks>
/// 记录正在接受制导的导弹标识符
/// 如果为null表示当前没有制导目标
/// </remarks>
public string? MissileId { get; private set; }
/// <summary>
/// 获取目标ID
/// </summary>
/// <remarks>
/// 记录当前跟踪的目标标识符
/// 如果为null表示当前没有跟踪目标
/// </remarks>
public string? TargetId { get; private set; }
/// <summary>
/// 初始化激光波束制导器的新实例
/// </summary>
@ -302,17 +309,18 @@ namespace ThreatSource.Indicator
}
/// <summary>
/// 获取激光驾束仪运行状态
/// 获取指示器运行状态
/// </summary>
/// <returns>包含完整状态信息的结构体</returns>
/// <returns>包含指示器完整状态信息的结构体</returns>
/// <remarks>
/// 返回信息包括:
/// - 目标和导弹ID
/// - 设备类型和工作状态
/// - 位置和朝向信息
/// - 目标和导弹关联状态
/// - 工作类型和状态
/// - 位置和姿态信息
/// - 激活状态
/// - 干扰状态
/// </remarks>
public IndicatorRunningState GetRunningState()
public override IndicatorRunningState GetRunningState()
{
return new IndicatorRunningState
{
@ -322,7 +330,8 @@ namespace ThreatSource.Indicator
State = IsBeamOn ? IndicatorState.Indicating : IndicatorState.Idle,
Position = Position,
Orientation = Orientation,
IsActive = IsActive
IsActive = IsActive,
JammingState = IsJammed ? JammingState.Jammed : JammingState.Normal
};
}

View File

@ -2,6 +2,8 @@ using ThreatSource.Simulation;
using System;
using ThreatSource.Utils;
using System.Diagnostics;
using ThreatSource.Jamming;
using System.Collections.Generic;
namespace ThreatSource.Indicator
{
@ -16,25 +18,30 @@ namespace ThreatSource.Indicator
/// - 状态监控
/// 通过激光照射目标实现半主动激光制导
/// </remarks>
public class LaserDesignator : SimulationElement, IIndicator
public class LaserDesignator : IndicatorBase
{
/// <summary>
/// 获取或设置目标ID
/// 获取设备支持的干扰类型
/// </summary>
/// <remarks>
/// 记录当前照射的目标标识符
/// 用于目标识别和状态更新
/// 定义激光指示器可以被哪些类型的干扰影响
/// </remarks>
public string? TargetId { get; private set; }
public override IEnumerable<JammingType> SupportedJammingTypes => new[]
{
JammingType.Laser,
JammingType.RadioFrequency
};
/// <summary>
/// 获取或设置导弹ID
/// 初始化干扰处理器
/// </summary>
/// <remarks>
/// 记录当前关联的导弹标识符
/// 用于导弹制导控制
/// 创建适用于激光指示器的干扰处理器
/// </remarks>
public string? MissileId { get; private set; }
protected override void InitializeJammingHandler()
{
JammingHandler = new LaserDesignatorJammingHandler(this);
}
/// <summary>
/// 获取或设置干扰阈值,单位:分贝
@ -45,16 +52,6 @@ namespace ThreatSource.Indicator
/// </remarks>
public double JammingThreshold { get; private set; } = 0.0;
/// <summary>
/// 获取或设置是否被干扰状态
/// </summary>
/// <remarks>
/// true表示当前受到有效干扰
/// false表示工作正常
/// 影响激光照射的有效性
/// </remarks>
public bool IsJammed { get; private set; } = false;
/// <summary>
/// 获取或设置是否正在照射状态
/// </summary>
@ -244,7 +241,14 @@ namespace ThreatSource.Indicator
if (!IsJammed)
{
Debug.WriteLine($"激光目标指示器 {Id} 被干扰,停止工作");
IsJammed = true;
// 应用干扰
var parameters = new JammingParameters
{
Type = JammingType.Laser,
Power = evt.JammingPower,
Direction = new Vector3D(1, 0, 0) // 简化处理
};
ApplyJamming(parameters);
StopLaserIllumination();
}
}
@ -253,7 +257,8 @@ namespace ThreatSource.Indicator
if (IsJammed)
{
Debug.WriteLine($"激光目标指示器 {Id} 干扰解除,恢复工作");
IsJammed = false;
// 清除干扰
ClearJamming(JammingType.Laser);
}
}
}
@ -275,7 +280,6 @@ namespace ThreatSource.Indicator
if (!IsActive)
{
IsActive = true;
IsJammed = false;
// 先订阅事件
SimulationManager.SubscribeToEvent<LaserJammingEvent>(OnLaserJamming);
// 再开始照射
@ -398,7 +402,7 @@ namespace ThreatSource.Indicator
}
/// <summary>
/// 获取激光指示器运行状态
/// 获取指示器运行状态
/// </summary>
/// <returns>包含指示器完整状态信息的结构体</returns>
/// <remarks>
@ -407,8 +411,9 @@ namespace ThreatSource.Indicator
/// - 工作类型和状态
/// - 位置和姿态信息
/// - 激活状态
/// - 干扰状态
/// </remarks>
public IndicatorRunningState GetRunningState()
public override IndicatorRunningState GetRunningState()
{
return new IndicatorRunningState
{
@ -418,7 +423,8 @@ namespace ThreatSource.Indicator
State = IsIlluminationOn ? IndicatorState.Indicating : IndicatorState.Idle,
Position = Position,
Orientation = Orientation,
IsActive = IsActive
IsActive = IsActive,
JammingState = IsJammed ? JammingState.Jammed : JammingState.Normal
};
}

View File

@ -29,4 +29,61 @@ namespace ThreatSource.Jamming
/// <param name="type">要清除的干扰类型</param>
void ClearJamming(JammingType type);
}
/// <summary>
/// 干扰模式枚举
/// </summary>
public enum JammingMode
{
/// <summary>
/// 噪声干扰
/// </summary>
Noise,
/// <summary>
/// 欺骗干扰
/// </summary>
Deception,
/// <summary>
/// 阻塞干扰
/// </summary>
Blocking,
/// <summary>
/// 扫频干扰
/// </summary>
Sweep
}
/// <summary>
/// 干扰类型枚举
/// </summary>
public enum JammingType
{
/// <summary>
/// 红外干扰
/// </summary>
Infrared,
/// <summary>
/// 毫米波干扰
/// </summary>
MillimeterWave,
/// <summary>
/// 激光干扰
/// </summary>
Laser,
/// <summary>
/// 射频干扰
/// </summary>
RadioFrequency,
/// <summary>
/// GPS干扰
/// </summary>
GPS
}
}

View File

@ -0,0 +1,63 @@
using ThreatSource.Indicator;
using System.Diagnostics;
namespace ThreatSource.Jamming
{
/// <summary>
/// 红外测角仪干扰处理器
/// </summary>
/// <remarks>
/// 处理红外测角仪的干扰效果:
/// - 降低跟踪精度
/// - 影响目标识别
/// - 干扰制导指令
/// </remarks>
public class InfraredTrackerJammingHandler : JammingHandler
{
private readonly InfraredTracker tracker;
/// <summary>
/// 初始化红外测角仪干扰处理器的新实例
/// </summary>
/// <param name="tracker">要处理的红外测角仪</param>
public InfraredTrackerJammingHandler(InfraredTracker tracker)
{
this.tracker = tracker;
}
/// <summary>
/// 当干扰被应用时调用
/// </summary>
/// <param name="parameters">干扰参数</param>
/// <remarks>
/// 实现干扰效果:
/// - 暂停跟踪功能
/// - 降低测量精度
/// - 影响目标识别
/// </remarks>
protected override void OnJammingApplied(JammingParameters parameters)
{
// 实现红外测角仪的干扰效果
// 可以根据干扰类型实现不同的干扰效果
if (parameters.Type == JammingType.Infrared)
{
Debug.WriteLine($"红外测角仪受到红外干扰,功率:{parameters.Power}瓦特");
}
}
/// <summary>
/// 当干扰被清除时调用
/// </summary>
/// <param name="parameters">被清除的干扰参数</param>
/// <remarks>
/// 恢复设备功能:
/// - 恢复跟踪能力
/// - 恢复正常精度
/// - 重新开始工作
/// </remarks>
protected override void OnJammingCleared(JammingParameters? parameters)
{
Debug.WriteLine("红外测角仪干扰已清除");
}
}
}

View File

@ -15,6 +15,11 @@ namespace ThreatSource.Jamming
/// </summary>
protected JammingParameters? CurrentJamming { get; private set; }
/// <summary>
/// 累积的干扰时间
/// </summary>
private double _elapsedTime;
/// <summary>
/// 更新干扰状态
/// </summary>
@ -23,9 +28,9 @@ namespace ThreatSource.Jamming
{
if (IsJammed && CurrentJamming?.Duration != null)
{
_elapsedTime += deltaTime;
// 检查是否超时
var elapsed = (DateTime.Now - CurrentJamming.StartTime).TotalSeconds;
if (elapsed >= CurrentJamming.Duration)
if (_elapsedTime >= CurrentJamming.Duration)
{
ClearJamming();
}
@ -38,7 +43,7 @@ namespace ThreatSource.Jamming
/// <param name="parameters">干扰参数</param>
public virtual void HandleJamming(JammingParameters parameters)
{
parameters.StartTime = DateTime.Now;
_elapsedTime = 0;
IsJammed = true;
CurrentJamming = parameters;
OnJammingApplied(parameters);
@ -52,6 +57,7 @@ namespace ThreatSource.Jamming
if (IsJammed)
{
IsJammed = false;
_elapsedTime = 0;
var oldJamming = CurrentJamming;
CurrentJamming = null;
OnJammingCleared(oldJamming);

View File

@ -1,28 +0,0 @@
namespace ThreatSource.Jamming
{
/// <summary>
/// 干扰模式枚举
/// </summary>
public enum JammingMode
{
/// <summary>
/// 噪声干扰
/// </summary>
Noise,
/// <summary>
/// 欺骗干扰
/// </summary>
Deception,
/// <summary>
/// 阻塞干扰
/// </summary>
Blocking,
/// <summary>
/// 扫频干扰
/// </summary>
Sweep
}
}

View File

@ -1,33 +0,0 @@
namespace ThreatSource.Jamming
{
/// <summary>
/// 干扰类型枚举
/// </summary>
public enum JammingType
{
/// <summary>
/// 红外干扰
/// </summary>
Infrared,
/// <summary>
/// 毫米波干扰
/// </summary>
MillimeterWave,
/// <summary>
/// 激光干扰
/// </summary>
Laser,
/// <summary>
/// 射频干扰
/// </summary>
RadioFrequency,
/// <summary>
/// GPS干扰
/// </summary>
GPS
}
}

View File

@ -0,0 +1,64 @@
using ThreatSource.Indicator;
namespace ThreatSource.Jamming
{
/// <summary>
/// 激光波束制导器干扰处理器
/// </summary>
/// <remarks>
/// 处理激光波束制导器的干扰效果:
/// - 降低制导精度
/// - 干扰制导信号
/// - 影响制导效果
/// </remarks>
public class LaserBeamRiderJammingHandler : JammingHandler
{
private readonly LaserBeamRider beamRider;
/// <summary>
/// 初始化激光波束制导器干扰处理器的新实例
/// </summary>
/// <param name="beamRider">要处理的激光波束制导器</param>
public LaserBeamRiderJammingHandler(LaserBeamRider beamRider)
{
this.beamRider = beamRider;
}
/// <summary>
/// 当干扰被应用时调用
/// </summary>
/// <param name="parameters">干扰参数</param>
/// <remarks>
/// 实现干扰效果:
/// - 暂停制导功能
/// - 降低制导精度
/// - 影响波束稳定性
/// </remarks>
protected override void OnJammingApplied(JammingParameters parameters)
{
// 实现激光波束制导器的干扰效果
// 根据干扰类型实现不同的干扰效果
if (parameters.Type == JammingType.Laser)
{
// 激光干扰效果
// 这里可以添加具体的干扰实现
}
}
/// <summary>
/// 当干扰被清除时调用
/// </summary>
/// <param name="parameters">被清除的干扰参数</param>
/// <remarks>
/// 恢复设备功能:
/// - 恢复制导能力
/// - 恢复波束稳定性
/// - 重新开始工作
/// </remarks>
protected override void OnJammingCleared(JammingParameters? parameters)
{
// 恢复激光波束制导器的功能
// 这里可以添加恢复功能的实现
}
}
}

View File

@ -0,0 +1,64 @@
using ThreatSource.Indicator;
namespace ThreatSource.Jamming
{
/// <summary>
/// 激光指示器干扰处理器
/// </summary>
/// <remarks>
/// 处理激光指示器的干扰效果:
/// - 降低照射精度
/// - 干扰激光信号
/// - 影响制导效果
/// </remarks>
public class LaserDesignatorJammingHandler : JammingHandler
{
private readonly LaserDesignator designator;
/// <summary>
/// 初始化激光指示器干扰处理器的新实例
/// </summary>
/// <param name="designator">要处理的激光指示器</param>
public LaserDesignatorJammingHandler(LaserDesignator designator)
{
this.designator = designator;
}
/// <summary>
/// 当干扰被应用时调用
/// </summary>
/// <param name="parameters">干扰参数</param>
/// <remarks>
/// 实现干扰效果:
/// - 暂停照射功能
/// - 降低照射精度
/// - 影响激光稳定性
/// </remarks>
protected override void OnJammingApplied(JammingParameters parameters)
{
// 实现激光指示器的干扰效果
// 根据干扰类型实现不同的干扰效果
if (parameters.Type == JammingType.Laser)
{
// 激光干扰效果
// 这里可以添加具体的干扰实现
}
}
/// <summary>
/// 当干扰被清除时调用
/// </summary>
/// <param name="parameters">被清除的干扰参数</param>
/// <remarks>
/// 恢复设备功能:
/// - 恢复照射能力
/// - 恢复激光稳定性
/// - 重新开始工作
/// </remarks>
protected override void OnJammingCleared(JammingParameters? parameters)
{
// 恢复激光指示器的功能
// 这里可以添加恢复功能的实现
}
}
}

View File

@ -88,7 +88,7 @@ namespace ThreatSource.Sensor
/// <summary>
/// 干扰处理器
/// </summary>
private protected JammingHandler? JammingHandler { get; set; }
protected virtual JammingHandler? JammingHandler { get; set; }
/// <summary>
/// 获取设备支持的干扰类型

View File

@ -563,6 +563,15 @@ namespace ThreatSource.Simulation
/// </summary>
public double UpdateFrequency { get; set; }
/// <summary>
/// 干扰抗性阈值(瓦特)
/// </summary>
/// <remarks>
/// 定义了红外测角仪抵抗干扰的能力
/// 当实际干扰功率超过此阈值时,测角仪将受到干扰
/// </remarks>
public double JammingResistanceThreshold { get; set; }
/// <summary>
/// 构造函数,设置默认值
/// </summary>
@ -572,6 +581,7 @@ namespace ThreatSource.Simulation
FieldOfView = Math.PI / 3; // 60度
AngleMeasurementAccuracy = 0.001; // 0.001弧度 (约0.057度)
UpdateFrequency = 10; // 10赫兹
JammingResistanceThreshold = 50; // 50瓦特
}
}

View File

@ -1,4 +1,5 @@
using ThreatSource.Utils;
using ThreatSource.Jamming;
namespace ThreatSource.Simulation
{
@ -564,11 +565,6 @@ namespace ThreatSource.Simulation
/// </summary>
public class InfraredJammingEvent : SimulationEvent
{
/// <summary>
/// 目标ID
/// </summary>
public string? TargetId { get; set; }
/// <summary>
/// 干扰功率(瓦特)
/// </summary>
@ -583,6 +579,50 @@ namespace ThreatSource.Simulation
/// 最大波长(微米)
/// </summary>
public double WavelengthMax { get; set; }
/// <summary>
/// 干扰源位置
/// </summary>
/// <remarks>
/// 干扰设备在三维空间中的位置
/// 用于计算干扰效果衰减
/// </remarks>
public Vector3D JammingSourcePosition { get; set; } = Vector3D.Zero;
/// <summary>
/// 干扰方向
/// </summary>
/// <remarks>
/// 干扰波束的主方向向量
/// 单位向量
/// </remarks>
public Vector3D JammingDirection { get; set; } = Vector3D.UnitX;
/// <summary>
/// 干扰角度范围(弧度)
/// </summary>
/// <remarks>
/// 定义了干扰波束的发散角度
/// 影响干扰的覆盖范围
/// </remarks>
public double JammingAngleRange { get; set; } = 0.5;
/// <summary>
/// 干扰模式
/// </summary>
/// <remarks>
/// 定义干扰的工作模式
/// 影响干扰的效果类型
/// </remarks>
public JammingMode JammingMode { get; set; } = JammingMode.Noise;
/// <summary>
/// 干扰持续时间(秒)
/// </summary>
/// <remarks>
/// null表示持续干扰直到显式清除
/// </remarks>
public double? Duration { get; set; }
}
/// <summary>