From 17eb9826b55634b3a1454aeb58a7bad03566a50a Mon Sep 17 00:00:00 2001
From: Tian jianyong <11429339@qq.com>
Date: Mon, 19 May 2025 16:35:37 +0800
Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E4=BA=86=E5=AF=BC=E5=BC=B9?=
=?UTF-8?q?=E7=9A=84=E7=BA=A2=E5=A4=96=E5=92=8C=E7=B4=AB=E5=A4=96=E8=BE=90?=
=?UTF-8?q?=E5=B0=84=E5=BC=BA=E5=BA=A6=E5=B1=9E=E6=80=A7?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
CHANGELOG.md | 1 +
ThreatSource.Tests/SwerlingRcsModelTests.cs | 388 ++++++++++++++++++
.../data/missiles/composite/cg_001.toml | 2 +
.../data/missiles/ir_command/irc_001.toml | 2 +
.../data/missiles/ir_imaging/itg_001.toml | 2 +
.../data/missiles/laser_beam_rider/hj10.toml | 2 +
.../missiles/laser_semi_active/lsgm_001.toml | 2 +
ThreatSource/data/missiles/mmw/mmw_001.toml | 2 +
ThreatSource/src/Equipment/BaseEquipment.cs | 24 +-
.../Guidance/LaserSemiActiveGuidanceSystem.cs | 2 -
ThreatSource/src/Indicator/BaseIndicator.cs | 2 +-
ThreatSource/src/Jammer/BaseJammer.cs | 2 +-
ThreatSource/src/MIssile/BaseMissile.cs | 45 +-
ThreatSource/src/MIssile/MissileProperties.cs | 44 +-
ThreatSource/src/Sensor/BaseSensor.cs | 2 +-
15 files changed, 484 insertions(+), 38 deletions(-)
create mode 100644 ThreatSource.Tests/SwerlingRcsModelTests.cs
diff --git a/CHANGELOG.md b/CHANGELOG.md
index c9a5cd2..1685e51 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -19,6 +19,7 @@
- 增加了SwerlingRCS回波模型
- 在毫米波制导中使用SwerlingRCS回波模型获取目标RCS
- 增加了扫描周期计时器,用于控制RCS的更新
+- 增加了导弹的红外和紫外辐射强度属性
## [1.1.19] - 2025-05-18
- 增加了装备的RCS特征矩阵
diff --git a/ThreatSource.Tests/SwerlingRcsModelTests.cs b/ThreatSource.Tests/SwerlingRcsModelTests.cs
new file mode 100644
index 0000000..9c06ba0
--- /dev/null
+++ b/ThreatSource.Tests/SwerlingRcsModelTests.cs
@@ -0,0 +1,388 @@
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using ThreatSource.Utils;
+using ThreatSource.Equipment;
+
+namespace ThreatSource.Tests
+{
+ [TestClass]
+ public class SwerlingRcsModelTests
+ {
+ private const double DefaultAverageRcs = 10.0; // 默认平均RCS值,单位:平方米
+ private const string TargetId1 = "target_tank_001"; // 测试用目标ID 1
+ private const string TargetId2 = "target_heli_002"; // 测试用目标ID 2
+ private const int TestSeed = 12345; // 测试用随机数种子
+
+ ///
+ /// 测试:默认构造函数应成功初始化。
+ ///
+ [TestMethod]
+ public void Constructor_DefaultSeed_InitializesSuccessfully()
+ {
+ // 准备 (Arrange)
+ SwerlingRcsModel model;
+
+ // 操作 (Act)
+ model = new SwerlingRcsModel();
+
+ // 断言 (Assert)
+ Assert.IsNotNull(model, "使用默认种子构造模型实例不应为null。");
+ }
+
+ ///
+ /// 测试:带特定种子的构造函数应成功初始化。
+ ///
+ [TestMethod]
+ public void Constructor_WithSpecificSeed_InitializesSuccessfully()
+ {
+ // 准备 (Arrange)
+ SwerlingRcsModel model;
+
+ // 操作 (Act)
+ model = new SwerlingRcsModel(TestSeed);
+
+ // 断言 (Assert)
+ Assert.IsNotNull(model, "使用特定种子构造模型实例不应为null。");
+ }
+
+ ///
+ /// 测试:当目标是坦克且静止时,其RCS行为应类似Swerling I (慢起伏,使用缓存)。
+ ///
+ [TestMethod]
+ public void GetRealtimeRcs_Tank_Static_BehavesAsSwerlingI()
+ {
+ // 准备 (Arrange)
+ var model = new SwerlingRcsModel(TestSeed);
+
+ // 操作 (Act)
+ // 第一次调用,isNewScanPeriod为false但由于是首次,应采样并缓存
+ double rcs1 = model.GetRealtimeRcs(TargetId1, EquipmentType.Tank, MotionStateType.Static, DefaultAverageRcs, false);
+ // 第二次调用,isNewScanPeriod为false,应从缓存获取
+ double rcs2 = model.GetRealtimeRcs(TargetId1, EquipmentType.Tank, MotionStateType.Static, DefaultAverageRcs, false);
+
+ // 断言 (Assert)
+ Assert.AreEqual(rcs1, rcs2, "对于Swerling I模型 (Tank, Static),在同一扫描周期内(isNewScanPeriod=false),RCS值应从缓存读取且保持不变。");
+ Assert.IsTrue(rcs1 > 0, "RCS值应大于0。");
+ }
+
+ ///
+ /// 测试:当目标是直升机且静止时,其RCS行为应类似Swerling II (快起伏,不使用缓存)。
+ ///
+ [TestMethod]
+ public void GetRealtimeRcs_Helicopter_Static_BehavesAsSwerlingII()
+ {
+ // 准备 (Arrange)
+ var model = new SwerlingRcsModel(TestSeed);
+
+ // 操作 (Act)
+ double rcs1 = model.GetRealtimeRcs(TargetId1, EquipmentType.Helicopter, MotionStateType.Static, DefaultAverageRcs, false);
+ double rcs2 = model.GetRealtimeRcs(TargetId1, EquipmentType.Helicopter, MotionStateType.Static, DefaultAverageRcs, false);
+
+ // 断言 (Assert)
+ // 对于快起伏,即使ID相同,种子固定情况下,连续调用也应基于随机数序列产生可预测的不同值
+ // 注意:这里比较的是"不同",但因为种子固定,这两个值本身是确定的。
+ // 如果需要严格验证"不同",可以比较两者差的绝对值大于某个小量,但更简单的做法是验证它们不相等。
+ Assert.AreNotEqual(rcs1, rcs2, "对于Swerling II模型 (Helicopter, Static),连续调用RCS值理论上应不同(因为是快起伏,每次都重新采样)。");
+ Assert.IsTrue(rcs1 > 0, "第一个RCS值应大于0。");
+ Assert.IsTrue(rcs2 > 0, "第二个RCS值应大于0。");
+ }
+
+
+ ///
+ /// 测试:当目标是坦克且机动时,其RCS行为应类似Swerling III (慢起伏,使用缓存)。
+ ///
+ [TestMethod]
+ public void GetRealtimeRcs_Tank_Maneuvering_BehavesAsSwerlingIII()
+ {
+ // 准备 (Arrange)
+ var model = new SwerlingRcsModel(TestSeed);
+
+ // 操作 (Act)
+ double rcs1 = model.GetRealtimeRcs(TargetId1, EquipmentType.Tank, MotionStateType.Maneuvering, DefaultAverageRcs, false);
+ double rcs2 = model.GetRealtimeRcs(TargetId1, EquipmentType.Tank, MotionStateType.Maneuvering, DefaultAverageRcs, false);
+
+ // 断言 (Assert)
+ Assert.AreEqual(rcs1, rcs2, "对于Swerling III模型 (Tank, Maneuvering),在同一扫描周期内,RCS值应从缓存读取且保持不变。");
+ Assert.IsTrue(rcs1 > 0, "RCS值应大于0。");
+ }
+
+ ///
+ /// 测试:当目标是直升机且机动时,其RCS行为应类似Swerling IV (快起伏,不使用缓存)。
+ ///
+ [TestMethod]
+ public void GetRealtimeRcs_Helicopter_Maneuvering_BehavesAsSwerlingIV()
+ {
+ // 准备 (Arrange)
+ var model = new SwerlingRcsModel(TestSeed);
+
+ // 操作 (Act)
+ double rcs1 = model.GetRealtimeRcs(TargetId1, EquipmentType.Helicopter, MotionStateType.Maneuvering, DefaultAverageRcs, false);
+ double rcs2 = model.GetRealtimeRcs(TargetId1, EquipmentType.Helicopter, MotionStateType.Maneuvering, DefaultAverageRcs, false);
+
+ // 断言 (Assert)
+ Assert.AreNotEqual(rcs1, rcs2, "对于Swerling IV模型 (Helicopter, Maneuvering),连续调用RCS值应不同。");
+ Assert.IsTrue(rcs1 > 0, "第一个RCS值应大于0。");
+ Assert.IsTrue(rcs2 > 0, "第二个RCS值应大于0。");
+ }
+
+ ///
+ /// 测试:当目标是坦克且匀速运动时,其RCS行为应类似Swerling I (慢起伏,使用缓存)。
+ ///
+ [TestMethod]
+ public void GetRealtimeRcs_Tank_ConstantVelocity_BehavesAsSwerlingI()
+ {
+ // 准备 (Arrange)
+ var model = new SwerlingRcsModel(TestSeed);
+
+ // 操作 (Act)
+ double rcs1 = model.GetRealtimeRcs(TargetId1, EquipmentType.Tank, MotionStateType.ConstantVelocity, DefaultAverageRcs, false);
+ double rcs2 = model.GetRealtimeRcs(TargetId1, EquipmentType.Tank, MotionStateType.ConstantVelocity, DefaultAverageRcs, false);
+
+ // 断言 (Assert)
+ Assert.AreEqual(rcs1, rcs2, "对于Swerling I模型 (Tank, ConstantVelocity),在同一扫描周期内,RCS值应从缓存读取且保持不变。");
+ Assert.IsTrue(rcs1 > 0, "RCS值应大于0。");
+ }
+
+ ///
+ /// 测试:当目标是直升机且匀速运动时,其RCS行为应类似Swerling II (快起伏,不使用缓存)。
+ ///
+ [TestMethod]
+ public void GetRealtimeRcs_Helicopter_ConstantVelocity_BehavesAsSwerlingII()
+ {
+ // 准备 (Arrange)
+ var model = new SwerlingRcsModel(TestSeed);
+
+ // 操作 (Act)
+ double rcs1 = model.GetRealtimeRcs(TargetId1, EquipmentType.Helicopter, MotionStateType.ConstantVelocity, DefaultAverageRcs, false);
+ double rcs2 = model.GetRealtimeRcs(TargetId1, EquipmentType.Helicopter, MotionStateType.ConstantVelocity, DefaultAverageRcs, false);
+
+ // 断言 (Assert)
+ Assert.AreNotEqual(rcs1, rcs2, "对于Swerling II模型 (Helicopter, ConstantVelocity),连续调用RCS值应不同。");
+ Assert.IsTrue(rcs1 > 0, "第一个RCS值应大于0。");
+ Assert.IsTrue(rcs2 > 0, "第二个RCS值应大于0。");
+ }
+
+ ///
+ /// 测试:当目标类型未知时,应默认为Swerling I行为。
+ ///
+ [TestMethod]
+ public void GetRealtimeRcs_UnknownEquipment_BehavesAsSwerlingI()
+ {
+ // 准备 (Arrange)
+ var model = new SwerlingRcsModel(TestSeed);
+
+ // 操作 (Act)
+ double rcs1 = model.GetRealtimeRcs(TargetId1, EquipmentType.Unknown, MotionStateType.Static, DefaultAverageRcs, false);
+ double rcs2 = model.GetRealtimeRcs(TargetId1, EquipmentType.Unknown, MotionStateType.Static, DefaultAverageRcs, false);
+
+ // 断言 (Assert)
+ Assert.AreEqual(rcs1, rcs2, "对于未知装备类型,应默认为Swerling I行为,RCS值在同一扫描周期内应保持不变。");
+ Assert.IsTrue(rcs1 > 0, "RCS值应大于0。");
+ }
+
+
+ ///
+ /// 测试:慢起伏模型在同一扫描周期内(isNewScanPeriod=false)应返回缓存的RCS值。
+ ///
+ [TestMethod]
+ public void GetRealtimeRcs_SlowFluctuation_SameScanPeriod_ReturnsCachedValue()
+ {
+ // 准备 (Arrange)
+ var model = new SwerlingRcsModel(TestSeed);
+ // 首次调用,isNewScanPeriod 为 true 或 false 都会导致采样和缓存 (对于Swerling I)
+ double initialRcs = model.GetRealtimeRcs(TargetId1, EquipmentType.Tank, MotionStateType.Static, DefaultAverageRcs, true);
+
+ // 操作 (Act)
+ // 后续调用,isNewScanPeriod 为 false
+ double cachedRcs = model.GetRealtimeRcs(TargetId1, EquipmentType.Tank, MotionStateType.Static, DefaultAverageRcs, false);
+
+ // 断言 (Assert)
+ Assert.AreEqual(initialRcs, cachedRcs, "慢起伏模型在同一扫描周期内应返回相同的缓存RCS值。");
+ }
+
+ ///
+ /// 测试:慢起伏模型在新扫描周期开始时(isNewScanPeriod=true)应更新并返回新的缓存RCS值。
+ ///
+ [TestMethod]
+ public void GetRealtimeRcs_SlowFluctuation_NewScanPeriod_UpdatesAndReturnsNewCachedValue()
+ {
+ // 准备 (Arrange)
+ var model = new SwerlingRcsModel(TestSeed); // 使用固定种子
+ double rcsScan1 = model.GetRealtimeRcs(TargetId1, EquipmentType.Tank, MotionStateType.Static, DefaultAverageRcs, false);
+
+ // 操作 (Act)
+ // 新扫描周期开始
+ double rcsScan2PeriodStart = model.GetRealtimeRcs(TargetId1, EquipmentType.Tank, MotionStateType.Static, DefaultAverageRcs, true);
+ // 在新扫描周期内再次获取,应与周期开始时相同
+ double rcsScan2SamePeriod = model.GetRealtimeRcs(TargetId1, EquipmentType.Tank, MotionStateType.Static, DefaultAverageRcs, false);
+
+ // 断言 (Assert)
+ // 由于种子固定,rcsScan1 和 rcsScan2PeriodStart 应该不同(因为重新采样了)
+ // 但对于不同的随机数序列,它们也可能偶然相同,所以这个断言不是绝对的,更多的是检查行为
+ // 更可靠的测试是验证 rcsScan2PeriodStart 和 rcsScan2SamePeriod 相同
+ Assert.AreNotEqual(rcsScan1, rcsScan2PeriodStart, "新扫描周期开始时,RCS值应重新采样,与旧周期的值不同(高概率)。");
+ Assert.AreEqual(rcsScan2PeriodStart, rcsScan2SamePeriod, "在新扫描周期内,后续获取的RCS值应与周期开始时采样并缓存的值相同。");
+ Assert.IsTrue(rcsScan1 > 0, "第一个扫描周期的RCS值应大于0。");
+ Assert.IsTrue(rcsScan2PeriodStart > 0, "第二个扫描周期开始的RCS值应大于0。");
+ }
+
+ ///
+ /// 测试:当平均RCS为0时,GetRealtimeRcs应返回0。
+ ///
+ [TestMethod]
+ public void GetRealtimeRcs_AverageRcsZero_ReturnsZero()
+ {
+ // 准备 (Arrange)
+ var model = new SwerlingRcsModel();
+
+ // 操作 (Act)
+ double rcsS1 = model.GetRealtimeRcs(TargetId1, EquipmentType.Tank, MotionStateType.Static, 0.0, false);
+ double rcsS2 = model.GetRealtimeRcs(TargetId1, EquipmentType.Helicopter, MotionStateType.Static, 0.0, false);
+ double rcsS3 = model.GetRealtimeRcs(TargetId1, EquipmentType.Tank, MotionStateType.Maneuvering, 0.0, false);
+ double rcsS4 = model.GetRealtimeRcs(TargetId1, EquipmentType.Helicopter, MotionStateType.Maneuvering, 0.0, false);
+
+ // 断言 (Assert)
+ Assert.AreEqual(0.0, rcsS1, "Swerling I,平均RCS为0时,应返回0。");
+ Assert.AreEqual(0.0, rcsS2, "Swerling II,平均RCS为0时,应返回0。");
+ Assert.AreEqual(0.0, rcsS3, "Swerling III,平均RCS为0时,应返回0。");
+ Assert.AreEqual(0.0, rcsS4, "Swerling IV,平均RCS为0时,应返回0。");
+ }
+
+ ///
+ /// 测试:当平均RCS为负数时,GetRealtimeRcs应返回0。
+ ///
+ [TestMethod]
+ public void GetRealtimeRcs_AverageRcsNegative_ReturnsZero()
+ {
+ // 准备 (Arrange)
+ var model = new SwerlingRcsModel();
+
+ // 操作 (Act)
+ double rcs = model.GetRealtimeRcs(TargetId1, EquipmentType.Tank, MotionStateType.Static, -5.0, false);
+
+ // 断言 (Assert)
+ Assert.AreEqual(0.0, rcs, "平均RCS为负数时,应返回0。");
+ }
+
+ ///
+ /// 测试:对于Swerling I模型,如果targetId为null,应抛出ArgumentNullException。
+ ///
+ [TestMethod]
+ [ExpectedException(typeof(ArgumentNullException))]
+ public void GetRealtimeRcs_SwerlingI_NullTargetId_ThrowsArgumentNullException()
+ {
+ // 准备 (Arrange)
+ var model = new SwerlingRcsModel();
+
+ // 操作 (Act)
+ model.GetRealtimeRcs(null!, EquipmentType.Tank, MotionStateType.Static, DefaultAverageRcs, false);
+ }
+
+ ///
+ /// 测试:对于Swerling I模型,如果targetId为空字符串,应抛出ArgumentNullException。
+ ///
+ [TestMethod]
+ [ExpectedException(typeof(ArgumentNullException))]
+ public void GetRealtimeRcs_SwerlingI_EmptyTargetId_ThrowsArgumentNullException()
+ {
+ // 准备 (Arrange)
+ var model = new SwerlingRcsModel();
+
+ // 操作 (Act)
+ model.GetRealtimeRcs(string.Empty, EquipmentType.Tank, MotionStateType.Static, DefaultAverageRcs, false);
+ }
+
+ ///
+ /// 测试:对于Swerling III模型,如果targetId为null,应抛出ArgumentNullException。
+ ///
+ [TestMethod]
+ [ExpectedException(typeof(ArgumentNullException))]
+ public void GetRealtimeRcs_SwerlingIII_NullTargetId_ThrowsArgumentNullException()
+ {
+ // 准备 (Arrange)
+ var model = new SwerlingRcsModel();
+
+ // 操作 (Act)
+ model.GetRealtimeRcs(null!, EquipmentType.Tank, MotionStateType.Maneuvering, DefaultAverageRcs, false);
+ }
+
+
+ ///
+ /// 测试:ClearCachedRcs应清除特定目标的缓存,导致下次调用重新采样。
+ ///
+ [TestMethod]
+ public void ClearCachedRcs_SlowFluctuation_ForcesNewSampleForSpecificTarget()
+ {
+ // 准备 (Arrange)
+ var model = new SwerlingRcsModel(TestSeed);
+ double rcs1Target1 = model.GetRealtimeRcs(TargetId1, EquipmentType.Tank, MotionStateType.Static, DefaultAverageRcs, false);
+ double rcs1Target2 = model.GetRealtimeRcs(TargetId2, EquipmentType.Tank, MotionStateType.Static, DefaultAverageRcs, false); // 另一个目标以验证其缓存不受影响
+
+ // 操作 (Act)
+ model.ClearCachedRcs(TargetId1); // 清除TargetId1的缓存
+ double rcs2Target1 = model.GetRealtimeRcs(TargetId1, EquipmentType.Tank, MotionStateType.Static, DefaultAverageRcs, false); // 重新获取TargetId1的RCS
+ double rcs2Target2 = model.GetRealtimeRcs(TargetId2, EquipmentType.Tank, MotionStateType.Static, DefaultAverageRcs, false); // 再次获取TargetId2的RCS
+
+ // 断言 (Assert)
+ Assert.AreNotEqual(rcs1Target1, rcs2Target1, "清除缓存后,TargetId1的RCS值应重新采样而不同(高概率)。");
+ Assert.AreEqual(rcs1Target2, rcs2Target2, "清除TargetId1的缓存不应影响TargetId2的缓存值。");
+ Assert.IsTrue(rcs1Target1 > 0);
+ Assert.IsTrue(rcs2Target1 > 0);
+ }
+
+ ///
+ /// 测试:ClearAllCachedRcs应清除所有目标的缓存,导致下次所有慢起伏目标调用都重新采样。
+ ///
+ [TestMethod]
+ public void ClearAllCachedRcs_SlowFluctuation_ForcesNewSamplesForAllTargets()
+ {
+ // 准备 (Arrange)
+ var model = new SwerlingRcsModel(TestSeed);
+ double rcs1Target1 = model.GetRealtimeRcs(TargetId1, EquipmentType.Tank, MotionStateType.Static, DefaultAverageRcs, false);
+ double rcs1Target2 = model.GetRealtimeRcs(TargetId2, EquipmentType.Tank, MotionStateType.Static, DefaultAverageRcs, false);
+
+ // 操作 (Act)
+ model.ClearAllCachedRcs(); // 清除所有缓存
+ double rcs2Target1 = model.GetRealtimeRcs(TargetId1, EquipmentType.Tank, MotionStateType.Static, DefaultAverageRcs, false);
+ double rcs2Target2 = model.GetRealtimeRcs(TargetId2, EquipmentType.Tank, MotionStateType.Static, DefaultAverageRcs, false);
+
+ // 断言 (Assert)
+ Assert.AreNotEqual(rcs1Target1, rcs2Target1, "清除所有缓存后,TargetId1的RCS值应重新采样而不同(高概率)。");
+ Assert.AreNotEqual(rcs1Target2, rcs2Target2, "清除所有缓存后,TargetId2的RCS值应重新采样而不同(高概率)。");
+ Assert.IsTrue(rcs1Target1 > 0);
+ Assert.IsTrue(rcs1Target2 > 0);
+ Assert.IsTrue(rcs2Target1 > 0);
+ Assert.IsTrue(rcs2Target2 > 0);
+ }
+
+ ///
+ /// 测试:使用相同种子的两个SwerlingRcsModel实例应产生可复现的RCS序列。
+ ///
+ [TestMethod]
+ public void GetRealtimeRcs_WithSameSeed_GeneratesReproducibleSequence()
+ {
+ // 准备 (Arrange)
+ var model1 = new SwerlingRcsModel(TestSeed);
+ var model2 = new SwerlingRcsModel(TestSeed);
+
+ // 操作 (Act) & 断言 (Assert)
+ // 以Swerling II (快起伏) 为例,因为它不依赖缓存和isNewScanPeriod
+ for (int i = 0; i < 10; i++)
+ {
+ double rcsM1 = model1.GetRealtimeRcs(TargetId1, EquipmentType.Helicopter, MotionStateType.Static, DefaultAverageRcs, false);
+ double rcsM2 = model2.GetRealtimeRcs(TargetId1, EquipmentType.Helicopter, MotionStateType.Static, DefaultAverageRcs, false);
+ Assert.AreEqual(rcsM1, rcsM2, $"在第 {i+1} 次调用时,使用相同种子的两个模型产生的RCS值应相同。");
+ Assert.IsTrue(rcsM1 > 0, $"Model1, 调用 {i+1}, RCS 值应大于0。");
+ }
+
+ // 测试Swerling I (慢起伏)
+ double rcsS1M1_Initial = model1.GetRealtimeRcs(TargetId2, EquipmentType.Tank, MotionStateType.Static, DefaultAverageRcs, true);
+ double rcsS1M2_Initial = model2.GetRealtimeRcs(TargetId2, EquipmentType.Tank, MotionStateType.Static, DefaultAverageRcs, true);
+ Assert.AreEqual(rcsS1M1_Initial, rcsS1M2_Initial, "Swerling I,相同种子,首次调用(isNewScanPeriod=true),RCS值应相同。");
+
+ double rcsS1M1_Cached = model1.GetRealtimeRcs(TargetId2, EquipmentType.Tank, MotionStateType.Static, DefaultAverageRcs, false);
+ double rcsS1M2_Cached = model2.GetRealtimeRcs(TargetId2, EquipmentType.Tank, MotionStateType.Static, DefaultAverageRcs, false);
+ Assert.AreEqual(rcsS1M1_Cached, rcsS1M2_Cached, "Swerling I,相同种子,后续调用(isNewScanPeriod=false),缓存的RCS值应相同。");
+ Assert.AreEqual(rcsS1M1_Initial, rcsS1M1_Cached, "Swerling I,Model1,后续调用应返回首次缓存的值。");
+ }
+ }
+}
\ No newline at end of file
diff --git a/ThreatSource/data/missiles/composite/cg_001.toml b/ThreatSource/data/missiles/composite/cg_001.toml
index 5da05e5..fb8c5b3 100644
--- a/ThreatSource/data/missiles/composite/cg_001.toml
+++ b/ThreatSource/data/missiles/composite/cg_001.toml
@@ -19,6 +19,8 @@ Mass = 25.0
ExplosionRadius = 5.5
HitProbability = 0.9
SelfDestructHeight = 0.0
+InfraredRadiationIntensity = 96.0 # 红外辐射强度 (瓦特/球面度)
+UltravioletRadiationIntensity = 100.0 # 紫外辐射强度 (瓦特/球面度)
# --- 复合制导特定属性 ---
CompositeWorkMode = "Serial" # 工作模式:Serial (串行) 或 Parallel (并行)
# FusionStrategy = "UseHighestPriority" # 仅在并行模式下相关
diff --git a/ThreatSource/data/missiles/ir_command/irc_001.toml b/ThreatSource/data/missiles/ir_command/irc_001.toml
index fec61cd..0cd0ea8 100644
--- a/ThreatSource/data/missiles/ir_command/irc_001.toml
+++ b/ThreatSource/data/missiles/ir_command/irc_001.toml
@@ -19,6 +19,8 @@ Mass = 23.5 # 质量 (千克)
ExplosionRadius = 5.0 # 爆炸半径 (米)
HitProbability = 0.9 # 命中概率
SelfDestructHeight = 0.0 # 自毁高度 (米)
+InfraredRadiationIntensity = 96.0 # 红外辐射强度 (瓦特/球面度)
+UltravioletRadiationIntensity = 100.0 # 紫外辐射强度 (瓦特/球面度)
# TrackerSensitivity, CommandLatency, IrSignature 在JSON中为null,此处省略
[InfraredCommandGuidanceConfig]
diff --git a/ThreatSource/data/missiles/ir_imaging/itg_001.toml b/ThreatSource/data/missiles/ir_imaging/itg_001.toml
index 2205993..bc8c951 100644
--- a/ThreatSource/data/missiles/ir_imaging/itg_001.toml
+++ b/ThreatSource/data/missiles/ir_imaging/itg_001.toml
@@ -19,6 +19,8 @@ Mass = 25.0
ExplosionRadius = 5.5
HitProbability = 0.9
SelfDestructHeight = 0.0
+InfraredRadiationIntensity = 96.0 # 红外辐射强度 (瓦特/球面度)
+UltravioletRadiationIntensity = 100.0 # 紫外辐射强度 (瓦特/球面度)
[InfraredImagingGuidanceConfig]
MaxDetectionRange = 1000.0 # 最大探测距离 (米), JSON中为1000,对应C#默认为1000.0
diff --git a/ThreatSource/data/missiles/laser_beam_rider/hj10.toml b/ThreatSource/data/missiles/laser_beam_rider/hj10.toml
index 376e97d..62b7aa6 100644
--- a/ThreatSource/data/missiles/laser_beam_rider/hj10.toml
+++ b/ThreatSource/data/missiles/laser_beam_rider/hj10.toml
@@ -19,6 +19,8 @@ Mass = 24.5 # 质量 (千克)
ExplosionRadius = 5.0 # 爆炸半径 (米)
HitProbability = 0.9 # 命中概率
SelfDestructHeight = 0.0 # 自毁高度 (米)
+InfraredRadiationIntensity = 96.0 # 红外辐射强度 (瓦特/球面度)
+UltravioletRadiationIntensity = 100.0 # 紫外辐射强度 (瓦特/球面度)
[Properties.LaserCodeConfig] # 激光编码配置
IsCodeEnabled = true # 是否启用编码
diff --git a/ThreatSource/data/missiles/laser_semi_active/lsgm_001.toml b/ThreatSource/data/missiles/laser_semi_active/lsgm_001.toml
index 58b752b..b27f9f3 100644
--- a/ThreatSource/data/missiles/laser_semi_active/lsgm_001.toml
+++ b/ThreatSource/data/missiles/laser_semi_active/lsgm_001.toml
@@ -20,6 +20,8 @@ Mass = 22.0 # 导弹质量 (kg)
ExplosionRadius = 5.0 # 爆炸半径 (米)
HitProbability = 0.9 # 固有命中概率 (0.0 到 1.0)
SelfDestructHeight = 0.0 # 离地自毁高度 (米)
+InfraredRadiationIntensity = 96.0 # 红外辐射强度 (瓦特/球面度)
+UltravioletRadiationIntensity = 100.0 # 紫外辐射强度 (瓦特/球面度)
[Properties.LaserCodeConfig] # properties内部的激光编码配置
IsCodeEnabled = true # 激光编码系统是否启用?
diff --git a/ThreatSource/data/missiles/mmw/mmw_001.toml b/ThreatSource/data/missiles/mmw/mmw_001.toml
index f499e7e..8982a9b 100644
--- a/ThreatSource/data/missiles/mmw/mmw_001.toml
+++ b/ThreatSource/data/missiles/mmw/mmw_001.toml
@@ -19,6 +19,8 @@ Mass = 28.0 # 质量 (千克)
ExplosionRadius = 5.0 # 爆炸半径 (米)
HitProbability = 0.9 # 命中概率
SelfDestructHeight = 0.0 # 自毁高度 (米)
+InfraredRadiationIntensity = 96.0 # 红外辐射强度 (瓦特/球面度)
+UltravioletRadiationIntensity = 100.0 # 紫外辐射强度 (瓦特/球面度)
[MillimeterWaveGuidanceConfig]
MaxDetectionRange = 5000.0 # 最大探测距离 (米)
diff --git a/ThreatSource/src/Equipment/BaseEquipment.cs b/ThreatSource/src/Equipment/BaseEquipment.cs
index ed8cdad..eeff7d8 100644
--- a/ThreatSource/src/Equipment/BaseEquipment.cs
+++ b/ThreatSource/src/Equipment/BaseEquipment.cs
@@ -1,3 +1,4 @@
+using System.Reflection;
using ThreatSource.Simulation;
namespace ThreatSource.Equipment
@@ -104,15 +105,22 @@ namespace ThreatSource.Equipment
{
// 获取基础状态信息
var statusInfo = base.GetStatusInfo();
-
+
// 添加装备特有属性
- statusInfo.ExtendedProperties["Health"] = Health;
- statusInfo.ExtendedProperties["Length"] = Properties.Length;
- statusInfo.ExtendedProperties["Width"] = Properties.Width;
- statusInfo.ExtendedProperties["Height"] = Properties.Height;
- statusInfo.ExtendedProperties["InfraredRadiationIntensity"] = Properties.InfraredRadiationIntensity;
- statusInfo.ExtendedProperties["MillimeterWaveRadiationIntensity"] = Properties.MillimeterWaveRadiationIntensity;
- statusInfo.ExtendedProperties["UltravioletRadiationIntensity"] = Properties.UltravioletRadiationIntensity;
+ if (Properties != null)
+ {
+ var propertiesType = Properties.GetType();
+ var props = propertiesType.GetProperties(BindingFlags.Public | BindingFlags.Instance);
+
+ foreach (var prop in props)
+ {
+ if (prop.CanRead) // 确保属性是可读的
+ {
+ object? propValue = prop.GetValue(Properties);
+ statusInfo.ExtendedProperties[prop.Name] = propValue ?? string.Empty;
+ }
+ }
+ }
return statusInfo;
}
diff --git a/ThreatSource/src/Guidance/LaserSemiActiveGuidanceSystem.cs b/ThreatSource/src/Guidance/LaserSemiActiveGuidanceSystem.cs
index a315214..7a4da81 100644
--- a/ThreatSource/src/Guidance/LaserSemiActiveGuidanceSystem.cs
+++ b/ThreatSource/src/Guidance/LaserSemiActiveGuidanceSystem.cs
@@ -478,8 +478,6 @@ namespace ThreatSource.Guidance
// 将合成激光信号传递给四象限探测器
quadrantDetector.ProcessLaserSignal(ReceivedLaserPower, spotOffset);
-
- Debug.WriteLine($"处理激光信号: 总功率={ReceivedLaserPower:E}W, 目标位置={TargetPosition}");
}
catch (Exception ex)
{
diff --git a/ThreatSource/src/Indicator/BaseIndicator.cs b/ThreatSource/src/Indicator/BaseIndicator.cs
index 611017d..c6ce07c 100644
--- a/ThreatSource/src/Indicator/BaseIndicator.cs
+++ b/ThreatSource/src/Indicator/BaseIndicator.cs
@@ -245,7 +245,7 @@ namespace ThreatSource.Indicator
// 获取基类状态信息
var statusInfo = base.GetStatusInfo();
- // 添加制导系统特有属性
+ // 添加指示器特有属性
statusInfo.ExtendedProperties["TargetId"] = TargetId ?? "";
statusInfo.ExtendedProperties["MissileId"] = MissileId ?? "";
statusInfo.ExtendedProperties["lastKnownTargetPosition"] = _lastKnownTargetPosition ?? Vector3D.Zero;
diff --git a/ThreatSource/src/Jammer/BaseJammer.cs b/ThreatSource/src/Jammer/BaseJammer.cs
index a1c0620..70ef87d 100644
--- a/ThreatSource/src/Jammer/BaseJammer.cs
+++ b/ThreatSource/src/Jammer/BaseJammer.cs
@@ -223,7 +223,7 @@ namespace ThreatSource.Jammer
// 获取基类状态信息
var statusInfo = base.GetStatusInfo();
- // 添加制导系统特有属性
+ // 添加干扰器特有属性
statusInfo.ExtendedProperties["JammingType"] = JammingType;
statusInfo.ExtendedProperties["State"] = State;
statusInfo.ExtendedProperties["IsJamming"] = IsJamming;
diff --git a/ThreatSource/src/MIssile/BaseMissile.cs b/ThreatSource/src/MIssile/BaseMissile.cs
index 30ae5bb..9b59c57 100644
--- a/ThreatSource/src/MIssile/BaseMissile.cs
+++ b/ThreatSource/src/MIssile/BaseMissile.cs
@@ -1,6 +1,7 @@
using System.Diagnostics;
using ThreatSource.Simulation;
using ThreatSource.Utils;
+using System.Reflection;
namespace ThreatSource.Missile
{
@@ -456,22 +457,38 @@ namespace ThreatSource.Missile
// 获取基础状态信息
var statusInfo = base.GetStatusInfo();
- // 添加导弹固有属性(通过MissileProperties)
- statusInfo.ExtendedProperties["Type"] = Properties.Type;
- statusInfo.ExtendedProperties["MaxSpeed"] = Properties.MaxSpeed;
- statusInfo.ExtendedProperties["MaxAcceleration"] = Properties.MaxAcceleration;
- statusInfo.ExtendedProperties["MaxRange"] = Properties.MaxFlightDistance;
- statusInfo.ExtendedProperties["MaxFlightTime"] = Properties.MaxFlightTime;
- statusInfo.ExtendedProperties["ExplosionRadius"] = Properties.ExplosionRadius;
- statusInfo.ExtendedProperties["Mass"] = Properties.Mass;
+ // 使用反射动态添加来自 this.Properties 的导弹固有属性
+ if (Properties != null)
+ {
+ var propertiesType = Properties.GetType();
+ var props = propertiesType.GetProperties(BindingFlags.Public | BindingFlags.Instance);
+
+ foreach (var prop in props)
+ {
+ if (prop.CanRead)
+ {
+ // 复合制导导弹才有复合制导系统参数
+ if ((prop.Name == nameof(MissileProperties.GuidanceSuite) ||
+ prop.Name == nameof(MissileProperties.CompositeWorkMode) ||
+ prop.Name == nameof(MissileProperties.FusionStrategy)) &&
+ Properties.Type != MissileType.CompositeGuidance)
+ {
+ continue;
+ }
+
+ object? propValue = prop.GetValue(Properties);
+ statusInfo.ExtendedProperties[prop.Name] = propValue ?? string.Empty;
+ }
+ }
+ }
- // 添加导弹运行时状态
- statusInfo.ExtendedProperties["FlightTime"] = FlightTime;
- statusInfo.ExtendedProperties["FlightDistance"] = FlightDistance;
- statusInfo.ExtendedProperties["EngineBurnTime"] = EngineBurnTime;
- statusInfo.ExtendedProperties["IsGuidance"] = IsGuidance;
+ // 添加 BaseMissile 类的运行时状态参数
+ statusInfo.ExtendedProperties["FlightTime"] = FlightTime;
+ statusInfo.ExtendedProperties["FlightDistance"] = FlightDistance;
+ statusInfo.ExtendedProperties["EngineBurnTime"] = EngineBurnTime;
+ statusInfo.ExtendedProperties["IsGuidance"] = IsGuidance;
statusInfo.ExtendedProperties["LostGuidanceTime"] = LostGuidanceTime;
- statusInfo.ExtendedProperties["GuidanceAcceleration"] = GuidanceAcceleration;
+ statusInfo.ExtendedProperties["GuidanceAcceleration"] = GuidanceAcceleration;
return statusInfo;
}
diff --git a/ThreatSource/src/MIssile/MissileProperties.cs b/ThreatSource/src/MIssile/MissileProperties.cs
index 3979de2..eef1e0a 100644
--- a/ThreatSource/src/MIssile/MissileProperties.cs
+++ b/ThreatSource/src/MIssile/MissileProperties.cs
@@ -209,6 +209,15 @@ namespace ThreatSource.Missile
///
public class MissileProperties
{
+ ///
+ /// 获取或设置导弹的类型
+ ///
+ ///
+ /// 决定导弹的制导方式和行为特征
+ /// 影响导弹的性能参数和作战能力
+ ///
+ public MissileType Type { get; set; }
+
///
/// 获取或设置导弹的最大速度限制
///
@@ -319,13 +328,22 @@ namespace ThreatSource.Missile
public double MaxEngineBurnTime { get; set; }
///
- /// 获取或设置导弹的类型
+ /// 获取或设置红外辐射强度
///
///
- /// 决定导弹的制导方式和行为特征
- /// 影响导弹的性能参数和作战能力
+ /// 单位:瓦特/球面度
+ /// 表示导弹在红外波段的发射功率
///
- public MissileType Type { get; set; }
+ public double InfraredRadiationIntensity { get; set; }
+
+ ///
+ /// 获取或设置紫外辐射强度
+ ///
+ ///
+ /// 单位:瓦特/球面度
+ /// 表示导弹在紫外波段的发射功率
+ ///
+ public double UltravioletRadiationIntensity { get; set; }
///
/// 获取或设置激光编码配置
@@ -357,13 +375,13 @@ namespace ThreatSource.Missile
/// 复合制导模式下,多个制导系统的工作方式。默认为串行。
/// 仅当 Type 为 CompositeGuidance 时有效。
///
- public CompositeWorkType CompositeWorkMode { get; set; } = CompositeWorkType.Serial;
+ public CompositeWorkType CompositeWorkMode { get; set; }
///
/// 并行工作模式下的指令融合策略。默认为使用最高优先级的指令。
/// 仅当 Type 为 CompositeGuidance 且 CompositeWorkMode 为 Parallel 时有效。
///
- public CommandFusionStrategy FusionStrategy { get; set; } = CommandFusionStrategy.UseHighestPriority;
+ public CommandFusionStrategy FusionStrategy { get; set; }
///
/// 初始化导弹配置类的新实例
@@ -377,8 +395,6 @@ namespace ThreatSource.Missile
public MissileProperties()
{
SetDefaultValues();
- Type = MissileType.StandardMissile;
- LaserCodeConfig = new LaserCodeConfig();
GuidanceSuite = [];
}
@@ -395,6 +411,7 @@ namespace ThreatSource.Missile
///
public void SetDefaultValues()
{
+ Type = MissileType.StandardMissile;
MaxSpeed = 400;
MaxFlightTime = 60;
MaxFlightDistance = 5000;
@@ -407,11 +424,16 @@ namespace ThreatSource.Missile
ExplosionRadius = 5;
HitProbability = 0.9;
SelfDestructHeight = 0;
+ InfraredRadiationIntensity = 100.0;
+ UltravioletRadiationIntensity = 100.0;
+ LaserCodeConfig = new LaserCodeConfig();
// 重置复合制导相关属性的默认值
- CompositeWorkMode = CompositeWorkType.Serial;
- FusionStrategy = CommandFusionStrategy.UseHighestPriority;
- if (GuidanceSuite != null) GuidanceSuite.Clear(); else GuidanceSuite = new List();
+ if(Type == MissileType.CompositeGuidance)
+ {
+ CompositeWorkMode = CompositeWorkType.Serial;
+ FusionStrategy = CommandFusionStrategy.UseHighestPriority;
+ }
}
}
}
\ No newline at end of file
diff --git a/ThreatSource/src/Sensor/BaseSensor.cs b/ThreatSource/src/Sensor/BaseSensor.cs
index c10e9d8..c98aada 100644
--- a/ThreatSource/src/Sensor/BaseSensor.cs
+++ b/ThreatSource/src/Sensor/BaseSensor.cs
@@ -303,7 +303,7 @@ namespace ThreatSource.Sensor
// 获取基础状态信息
var statusInfo = base.GetStatusInfo();
- // 添加传感器状态
+ // 添加传感器特有状态信息
statusInfo.ExtendedProperties["IsJammed"] = IsJammed.ToString();
statusInfo.ExtendedProperties["IsBlockingJammed"] = IsBlockingJammed.ToString();
statusInfo.ExtendedProperties["SensorData"] = GetSensorData().ToString() ?? "无数据";