From 6e990f65a442c520c68bfcf06e361b489bd287c9 Mon Sep 17 00:00:00 2001
From: Tian jianyong <11429339@qq.com>
Date: Tue, 22 Apr 2025 16:27:15 +0800
Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E4=BA=86=E7=83=9F=E5=B9=95?=
=?UTF-8?q?=E5=AF=B9=E6=AF=AB=E7=B1=B3=E6=B3=A2=E5=88=B6=E5=AF=BC=E5=AF=BC?=
=?UTF-8?q?=E5=BC=B9=E7=9A=84=E5=BD=B1=E5=93=8D=EF=BC=8C=E5=AE=8C=E5=96=84?=
=?UTF-8?q?=E4=BA=86=E4=B8=80=E4=BA=9B=E6=B5=8B=E8=AF=95?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
CHANGELOG.md | 4 +
.../src/Indicator/LaserBeamRiderTests.cs | 21 +-
.../src/Jamming/LaserBeamRiderJammingTests.cs | 2 +-
...SemiActiveGuidedMissileIntegrationTests.cs | 376 ------------------
.../Guidance/InfraredCommandGuidanceSystem.cs | 56 ++-
.../src/Guidance/InfraredImageGenerator.cs | 64 ---
.../Guidance/InfraredImagingGuidanceSystem.cs | 75 +++-
.../src/Guidance/InfraredTargetRecognizer.cs | 24 +-
.../Guidance/LaserBeamRiderGuidanceSystem.cs | 109 ++---
.../Guidance/LaserSemiActiveGuidanceSystem.cs | 34 +-
.../Guidance/MillimeterWaveGuidanceSystem.cs | 153 +++++--
ThreatSource/src/Indicator/LaserBeamRider.cs | 7 +-
.../src/MIssile/LaserBeamRiderMissile.cs | 27 +-
.../src/Simulation/SimulationEvents.cs | 37 +-
VERSION | 2 +-
tools/ComprehensiveMissileSimulator.cs | 14 +-
16 files changed, 311 insertions(+), 694 deletions(-)
delete mode 100644 ThreatSource.Tests/src/Missile/LaserSemiActiveGuidedMissileIntegrationTests.cs
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 0700469..78d627c 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -15,6 +15,10 @@
- 毫米波跟踪和锁定阶段采用脉冲多普勒制导、目标 RCS 特征矩阵
- 多种发射弹道模式:低平弹道、高抛弹道、俯冲弹道
- 双模、多模制导
+- 烟幕弹对毫米波末制导、末敏弹、激光目标指示器、激光驾束仪、红外指令制导指令发射端的干扰
+
+## [0.2.12] - 2025-04-18
+- 改进了红外成像制导的目标识别和烟幕弹干扰算法
## [0.2.11] - 2025-04-14
- 增加了激光诱偏目标的干扰功能
diff --git a/ThreatSource.Tests/src/Indicator/LaserBeamRiderTests.cs b/ThreatSource.Tests/src/Indicator/LaserBeamRiderTests.cs
index 3f3ec61..39c340b 100644
--- a/ThreatSource.Tests/src/Indicator/LaserBeamRiderTests.cs
+++ b/ThreatSource.Tests/src/Indicator/LaserBeamRiderTests.cs
@@ -60,6 +60,7 @@ namespace ThreatSource.Tests.Indicator
_simulationManager
);
_simulationManager.RegisterEntity("beamRider1", _laserBeamRider);
+ _simulationManager.RegisterEntity("target1", _tank);
}
[Fact]
@@ -78,14 +79,20 @@ namespace ThreatSource.Tests.Indicator
[Fact]
public void Activate_SetsCorrectState()
{
+ // Arrange
+ _testAdapter.ClearEvents(); // 确保开始时事件列表是空的
+
// Act
_laserBeamRider.Activate();
// Assert
Assert.True(_laserBeamRider.IsActive);
Assert.True(_laserBeamRider.IsBeamOn);
- var publishedEvents = _testAdapter.GetPublishedEvents();
- Assert.Contains(publishedEvents, evt => evt is LaserBeamStartEvent);
+ var publishedEvents = _testAdapter.GetPublishedEvents(); // 获取 Activate 产生的事件
+ // 注意: Activate 可能发布 LaserBeamStartEvent 和 IndicatorActivatedEvent
+ Assert.Contains(publishedEvents, evt => evt is LaserBeamEvent); // 确认发布了 LaserBeamEvent
+ // 可以选择性地添加对 IndicatorActivatedEvent 的检查
+ // Assert.Contains(publishedEvents, evt => evt is IndicatorActivatedEvent);
}
[Fact]
@@ -93,6 +100,7 @@ namespace ThreatSource.Tests.Indicator
{
// Arrange
_laserBeamRider.Activate();
+ _testAdapter.ClearEvents(); // 清除 Activate 产生的事件
// Act
_laserBeamRider.Deactivate();
@@ -100,7 +108,8 @@ namespace ThreatSource.Tests.Indicator
// Assert
Assert.False(_laserBeamRider.IsActive);
Assert.False(_laserBeamRider.IsBeamOn);
- var publishedEvents = _testAdapter.GetPublishedEvents();
+ var publishedEvents = _testAdapter.GetPublishedEvents(); // 获取 Deactivate 产生的事件
+ // 注意: Deactivate 可能发布 LaserBeamStopEvent 和 IndicatorDeactivatedEvent
Assert.Contains(publishedEvents, evt => evt is LaserBeamStopEvent);
}
@@ -109,14 +118,14 @@ namespace ThreatSource.Tests.Indicator
{
// Arrange
_laserBeamRider.Activate();
- _testAdapter.GetPublishedEvents(); // 清除之前的事件
+ _testAdapter.ClearEvents(); // 清除 Activate 产生的事件
// Act
_laserBeamRider.Update(0.1);
// Assert
- var publishedEvents = _testAdapter.GetPublishedEvents();
- Assert.Contains(publishedEvents, evt => evt is LaserBeamUpdateEvent);
+ var publishedEvents = _testAdapter.GetPublishedEvents(); // 获取 Update 产生的事件
+ Assert.Contains(publishedEvents, evt => evt is LaserBeamEvent); // 用户确认 Update 发布 LaserBeamEvent
}
[Fact]
diff --git a/ThreatSource.Tests/src/Jamming/LaserBeamRiderJammingTests.cs b/ThreatSource.Tests/src/Jamming/LaserBeamRiderJammingTests.cs
index de9a561..1fff7ce 100644
--- a/ThreatSource.Tests/src/Jamming/LaserBeamRiderJammingTests.cs
+++ b/ThreatSource.Tests/src/Jamming/LaserBeamRiderJammingTests.cs
@@ -144,7 +144,7 @@ namespace ThreatSource.Tests.Jamming
// Assert - 干扰清除后激光束应该恢复
Assert.IsFalse(_laserBeamRider.IsJammed, "干扰已清除,激光驾束仪应该恢复正常");
Assert.IsTrue(_laserBeamRider.IsBeamOn, "干扰清除后激光束应该重新开启");
- Assert.IsTrue(publishedEvents.Any(evt => evt is LaserBeamStartEvent), "应该发布激光束开始事件");
+ Assert.IsTrue(publishedEvents.Any(evt => evt is LaserBeamEvent), "应该发布激光束开始事件");
}
[TestMethod]
diff --git a/ThreatSource.Tests/src/Missile/LaserSemiActiveGuidedMissileIntegrationTests.cs b/ThreatSource.Tests/src/Missile/LaserSemiActiveGuidedMissileIntegrationTests.cs
deleted file mode 100644
index c8683ba..0000000
--- a/ThreatSource.Tests/src/Missile/LaserSemiActiveGuidedMissileIntegrationTests.cs
+++ /dev/null
@@ -1,376 +0,0 @@
-using Xunit;
-using ThreatSource.Missile;
-using ThreatSource.Simulation;
-using ThreatSource.Utils;
-using ThreatSource.Tests.Simulation;
-using ThreatSource.Guidance;
-using ThreatSource.Indicator;
-using ThreatSource.Equipment;
-using ThreatSource.Sensor;
-using System;
-using System.Reflection;
-
-namespace ThreatSource.Tests.Missile
-{
- ///
- /// 激光半主动导弹集成测试类
- ///
- ///
- /// 该测试类验证激光半主动导弹的整体性能:
- /// - 验证导弹能否在正常条件下命中目标
- /// - 验证导弹在低功率条件下的行为
- /// - 验证导弹在干扰环境下的表现
- ///
- public class LaserSemiActiveGuidedMissileIntegrationTests
- {
- private readonly SimulationManager _simulationManager;
- private readonly TestSimulationAdapter _testAdapter;
- private readonly LaserSemiActiveGuidedMissile _missile;
- private readonly MissileProperties _properties;
- private readonly LaserDesignator _laserDesignator;
- private readonly MockTarget _target;
-
- // 定义命中距离阈值(米)
- private const double HIT_THRESHOLD = 10.0;
-
- // 定义最大模拟时间(秒)
- private const double MAX_SIMULATION_TIME = 30.0;
-
- // 定义模拟时间步长(秒)
- private const double TIME_STEP = 0.025;
-
- public LaserSemiActiveGuidedMissileIntegrationTests()
- {
- _simulationManager = new SimulationManager();
- _testAdapter = new TestSimulationAdapter(_simulationManager);
- _simulationManager.SetSimulationAdapter(_testAdapter);
-
- _properties = new MissileProperties
- {
- MaxSpeed = 1000,
- MaxFlightTime = 100,
- MaxFlightDistance = 10000,
- MaxAcceleration = 50,
- ProportionalNavigationCoefficient = 3,
- Mass = 100,
- ExplosionRadius = 10,
- HitProbability = 0.9,
- Type = MissileType.LaserSemiActiveGuidance
- };
-
- var missileInitialMotion = new MotionParameters
- {
- Position = new Vector3D(0, 0, 0),
- Orientation = new Orientation(0, 0, 0),
- InitialSpeed = 100
- };
-
- var laserDesignatorInitialMotion = new MotionParameters
- {
- Position = new Vector3D(-100, 0, 0),
- Orientation = new Orientation(0, 0, 0),
- InitialSpeed = 0
- };
-
- // 创建并注册激光指示器,位置在导弹后方100米处
- var laserDesignatorConfig = new LaserDesignatorConfig
- {
- LaserPower = 100,
- LaserDivergenceAngle = 0.001,
- LaserWavelength = 1.06
- };
-
- _laserDesignator = new LaserDesignator(
- "laser1",
- "target1",
- "missile1",
- laserDesignatorConfig,
- laserDesignatorInitialMotion,
- _simulationManager
- );
- _testAdapter.AddTestEntity("laser1", _laserDesignator);
- _simulationManager.RegisterEntity("laser1", _laserDesignator);
-
- // 创建并注册模拟的目标,位置在导弹前方1000米处
- var targetInitialMotion = new MotionParameters
- {
- 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(
- "missile1",
- _properties,
- missileInitialMotion,
- laserCodeConfig,
- guidanceConfig,
- _simulationManager
- );
- _testAdapter.AddTestEntity("missile1", _missile);
- _simulationManager.RegisterEntity("missile1", _missile);
- }
-
- // 模拟的目标类
- private class MockTarget : Tank
- {
- public MockTarget(string id, MotionParameters motionParameters, ISimulationManager simulationManager)
- : base(id, new EquipmentProperties(), motionParameters, simulationManager)
- {
- // 不需要额外设置属性,因为基类构造函数已经设置了
- }
- }
-
- ///
- /// 模拟导弹飞行过程,直到命中目标或超时
- ///
- /// 激光功率
- /// 导弹与目标之间的最小距离
- private double SimulateMissileFlight(double laserPower)
- {
- _laserDesignator.LaserPower = laserPower;
-
- // 激活激光指示器(如果尚未激活)
- if (!_laserDesignator.IsActive)
- {
- _laserDesignator.Activate(); // Activate方法内部会启动激光照射
- }
-
- // 手动创建并发布激光照射开始事件,确保事件被正确传递到制导系统
- var illuminationEvent = new LaserIlluminationUpdateEvent
- {
- LaserDesignatorId = _laserDesignator.Id,
- TargetId = _target.Id,
- LaserCodeConfig = new LaserCodeConfig
- {
- Code = new LaserCode
- {
- CodeType = LaserCodeType.PPM,
- CodeValue = 1234
- }
- }
- };
- _simulationManager.PublishEvent(illuminationEvent);
-
- // 发射导弹
- _missile.Fire();
- _missile.Activate();
-
- double minDistance = double.MaxValue;
- double simulationTime = 0;
-
- // 模拟导弹飞行,直到命中目标或超时
- while (simulationTime < MAX_SIMULATION_TIME)
- {
- // 更新导弹状态
- _missile.Update(TIME_STEP);
- _laserDesignator.Update(TIME_STEP); // Update方法内部会发布激光照射更新事件
-
- // 手动发布激光照射更新事件,确保事件被正确传递到制导系统
- var updateEvent = new LaserIlluminationUpdateEvent
- {
- LaserDesignatorId = _laserDesignator.Id,
- TargetId = _target.Id,
- LaserCodeConfig = new LaserCodeConfig
- {
- Code = new LaserCode
- {
- CodeType = LaserCodeType.PPM,
- CodeValue = 1234
- }
- }
- };
- _simulationManager.PublishEvent(updateEvent);
- // 计算导弹与目标之间的距离
- double distance = (_missile.Position - _target.Position).Magnitude();
-
- // 更新最小距离
- minDistance = Math.Min(minDistance, distance);
-
- // 如果导弹已经命中目标,则结束模拟
- if (distance <= HIT_THRESHOLD)
- {
- Console.WriteLine($"导弹命中目标!时间:{simulationTime:F1}秒,距离:{distance:F2}米");
- break;
- }
-
- // 获取导弹状态
- string status = _missile.GetStatus();
- bool isExploded = status.Contains("爆炸阶段");
- bool isSelfDestructed = status.Contains("自毁阶段");
-
- // 如果导弹已经爆炸或自毁,则结束模拟
- if (isExploded || isSelfDestructed)
- {
- Console.WriteLine($"导弹已{(isExploded ? "爆炸" : "自毁")}!时间:{simulationTime:F1}秒,距离:{distance:F2}米");
- break;
- }
-
- // 更新模拟时间
- simulationTime += TIME_STEP;
- }
-
- // 停用激光指示器,这会自动停止激光照射
- _laserDesignator.Deactivate();
-
- if (simulationTime >= MAX_SIMULATION_TIME)
- {
- Console.WriteLine($"模拟超时!最小距离:{minDistance:F2}米");
- }
-
- return minDistance;
- }
-
- [Fact]
- public void Missile_NormalConditions_HitsTarget()
- {
- // 使用正常激光功率模拟导弹飞行
- double minDistance = SimulateMissileFlight(100.0);
-
- // 断言导弹能够命中目标
- Assert.True(minDistance <= HIT_THRESHOLD, $"导弹未能命中目标,最小距离:{minDistance:F2}米");
- }
-
- [Fact]
- public void Missile_LowLaserPower_FailsToHitTarget()
- {
- // 使用低于锁定阈值的激光功率模拟导弹飞行
- // 根据计算,锁定阈值对应的激光功率约为0.159瓦特,使用其一半的值
- double minDistance = SimulateMissileFlight(0.079);
-
- // 由于导弹初始方向已偏离目标,在低功率条件下应无法校正轨道
- // 断言导弹无法命中目标
- Assert.True(minDistance > HIT_THRESHOLD, $"导弹在低功率条件下仍然命中了目标,最小距离:{minDistance:F2}米");
- }
-
- [Fact]
- public void Missile_NoLaserPower_FailsToHitTarget()
- {
- // 使用零激光功率模拟导弹飞行
- double minDistance = SimulateMissileFlight(0.0);
-
- // 输出最小距离
- Console.WriteLine($"导弹在无激光信号条件下与目标的最小距离:{minDistance:F2}米");
-
- // 由于导弹初始方向已偏离目标,在无激光信号条件下应无法校正轨道
- // 断言导弹无法命中目标
- Assert.True(minDistance > HIT_THRESHOLD, $"导弹在无激光信号条件下仍然命中了目标,最小距离:{minDistance:F2}米");
- }
-
- [Fact]
- public void Missile_IntermittentLaserPower_StillHitsTarget()
- {
- // 设置初始激光功率
- _laserDesignator.LaserPower = 100.0;
-
- // 确保激光指示器处于激活状态
- if (!_laserDesignator.IsActive)
- {
- _laserDesignator.Activate();
- }
-
- // 发射导弹
- _missile.Fire();
- _missile.Activate();
-
- double minDistance = double.MaxValue;
- double simulationTime = 0;
-
- // 模拟导弹飞行,激光功率间歇性变化
- while (simulationTime < MAX_SIMULATION_TIME)
- {
- // 每2秒切换一次激光功率
- if ((int)(simulationTime / 2) % 2 == 0)
- {
- _laserDesignator.LaserPower = 100.0; // 高功率
- }
- else
- {
- // 使用低于锁定阈值的激光功率(约为0.159瓦特的一半)
- _laserDesignator.LaserPower = 0.079;
- }
-
- // 更新导弹状态
- _missile.Update(TIME_STEP);
- _laserDesignator.Update(TIME_STEP);
-
- // 手动发布激光照射更新事件,确保事件被正确传递到制导系统
- var updateEvent = new LaserIlluminationUpdateEvent
- {
- LaserDesignatorId = _laserDesignator.Id,
- TargetId = _target.Id,
- LaserCodeConfig = new LaserCodeConfig
- {
- Code = new LaserCode
- {
- CodeType = LaserCodeType.PPM,
- CodeValue = 1234
- }
- }
- };
- _simulationManager.PublishEvent(updateEvent);
-
- // 计算导弹与目标之间的距离
- double distance = (_missile.Position - _target.Position).Magnitude();
-
- // 更新最小距离
- minDistance = Math.Min(minDistance, distance);
-
- // 如果导弹已经命中目标,则结束模拟
- if (distance <= HIT_THRESHOLD)
- {
- Console.WriteLine($"导弹命中目标!时间:{simulationTime:F1}秒,距离:{distance:F2}米");
- break;
- }
-
- // 获取导弹状态
- string status = _missile.GetStatus();
- bool isExploded = status.Contains("爆炸阶段");
- bool isSelfDestructed = status.Contains("自毁阶段");
-
- // 如果导弹已经爆炸或自毁,则结束模拟
- if (isExploded || isSelfDestructed)
- {
- Console.WriteLine($"导弹已{(isExploded ? "爆炸" : "自毁")}!时间:{simulationTime:F1}秒,距离:{distance:F2}米");
- break;
- }
-
- // 更新模拟时间
- simulationTime += TIME_STEP;
- }
-
- // 停用激光指示器
- _laserDesignator.Deactivate();
-
- // 即使在间歇性激光照射下,导弹仍应能够命中目标
- // 断言导弹能够在间歇性激光照射下命中目标
- Assert.True(minDistance <= HIT_THRESHOLD, $"导弹在间歇性激光照射下未能命中目标,最小距离:{minDistance:F2}米");
- }
- }
-}
\ No newline at end of file
diff --git a/ThreatSource/src/Guidance/InfraredCommandGuidanceSystem.cs b/ThreatSource/src/Guidance/InfraredCommandGuidanceSystem.cs
index 8a22a79..07985ae 100644
--- a/ThreatSource/src/Guidance/InfraredCommandGuidanceSystem.cs
+++ b/ThreatSource/src/Guidance/InfraredCommandGuidanceSystem.cs
@@ -18,31 +18,31 @@ namespace ThreatSource.Guidance
public class InfraredCommandGuidanceSystem : BasicGuidanceSystem
{
///
- /// 跟踪器到导弹的方向向量
+ /// 跟踪器到导弹的方向向量 (使用可空类型)
///
///
/// 记录上一次接收到的跟踪器指向导弹的方向
/// 用于计算导弹的相对位置
///
- private Vector3D lastTrackerToMissileVector;
+ private Vector3D? lastTrackerToMissileVector { get; set; }
///
- /// 跟踪器到目标的方向向量
+ /// 跟踪器到目标的方向向量 (使用可空类型)
///
///
/// 记录上一次接收到的跟踪器指向目标的方向
/// 用于计算目标的相对位置
///
- private Vector3D lastTrackerToTargetVector;
+ private Vector3D? lastTrackerToTargetVector { get; set; }
///
- /// 上一次的期望飞行方向
+ /// 上一次的期望飞行方向 (使用可空类型)
///
///
/// 记录上一次计算的期望飞行方向
/// 用于计算转向速率
///
- private Vector3D lastDesiredDirection;
+ private Vector3D? lastDesiredDirection { get; set; }
///
/// 当前转向速率,单位:弧度/秒
@@ -90,9 +90,6 @@ namespace ThreatSource.Guidance
public InfraredCommandGuidanceSystem(string id, InfraredCommandGuidanceConfig guidanceConfig, double maxAcceleration, double guidanceCoefficient, ISimulationManager simulationManager)
: base(id, maxAcceleration, guidanceCoefficient, simulationManager)
{
- lastTrackerToMissileVector = Vector3D.Zero;
- lastTrackerToTargetVector = Vector3D.Zero;
- lastDesiredDirection = Vector3D.Zero;
turnRate = 0;
InitializeJamming(guidanceConfig.JammingResistanceThreshold, [JammingType.Infrared]);
}
@@ -120,12 +117,20 @@ namespace ThreatSource.Guidance
else
{
GuidanceAcceleration = Vector3D.Zero;
+ lastTrackerToMissileVector = null;
+ lastTrackerToTargetVector = null;
+ lastDesiredDirection = null;
+ turnRate = 0;
}
}
else
{
HasGuidance = false;
GuidanceAcceleration = Vector3D.Zero;
+ lastTrackerToMissileVector = null;
+ lastTrackerToTargetVector = null;
+ lastDesiredDirection = null;
+ turnRate = 0;
}
}
@@ -161,29 +166,34 @@ namespace ThreatSource.Guidance
///
protected void CalculateGuidanceAcceleration(double deltaTime)
{
- // 计算期望飞行方向(从导弹指向目标)
+ if (lastTrackerToMissileVector == null || lastTrackerToTargetVector == null)
+ {
+ GuidanceAcceleration = Vector3D.Zero;
+ HasGuidance = false;
+ return;
+ }
+
Vector3D currentDesiredDirection = (lastTrackerToTargetVector - lastTrackerToMissileVector).Normalize();
- // 计算当前飞行方向
Vector3D currentDirection = Velocity.Normalize();
- // 更新转向速率
- if (lastDesiredDirection != Vector3D.Zero)
+
+ if (lastDesiredDirection != null && deltaTime > 0)
{
double instantTurnRate = Vector3D.CrossProduct(lastDesiredDirection, currentDesiredDirection).Magnitude() / deltaTime;
turnRate = turnRate * (1 - TurnRateSmoothingFactor) + instantTurnRate * TurnRateSmoothingFactor;
}
+ else
+ {
+ turnRate = 0;
+ }
- // 计算带有提前量的期望方向
Vector3D leadDirection = Vector3D.CrossProduct(currentDesiredDirection, Vector3D.CrossProduct(currentDesiredDirection, currentDirection).Normalize());
Vector3D desiredDirectionWithLead = (currentDesiredDirection + leadDirection * turnRate * LeadTimeFactor).Normalize();
- // 计算转向轴
Vector3D turnAxis = Vector3D.CrossProduct(currentDirection, desiredDirectionWithLead).Normalize();
- // 计算所需转向角度
double turnAngle = Vector3D.AngleBetween(currentDirection, desiredDirectionWithLead);
- // 计算制导加速度
double accelerationMagnitude = ProportionalNavigationCoefficient * turnAngle * Velocity.Magnitude();
GuidanceAcceleration = Vector3D.CrossProduct(turnAxis, currentDirection) * accelerationMagnitude;
- // 限制最大加速度
+
if (GuidanceAcceleration.Magnitude() > MaxAcceleration)
{
GuidanceAcceleration = GuidanceAcceleration.Normalize() * MaxAcceleration;
@@ -205,9 +215,15 @@ namespace ThreatSource.Guidance
///
public override string GetStatus()
{
+ string angleStr = "null";
+ if (lastTrackerToTargetVector != null && lastTrackerToMissileVector != null)
+ {
+ angleStr = Vector3D.AngleBetween(lastTrackerToTargetVector, lastTrackerToMissileVector).ToString("F3");
+ }
+
return base.GetStatus() +
- $" 转向角度: {Vector3D.AngleBetween(lastTrackerToTargetVector, lastTrackerToMissileVector)} 弧度," +
- $" 转向速率: {turnRate} 弧度/秒";
+ $" 转向角度: {angleStr} 弧度," +
+ $" 转向速率: {turnRate:F3} 弧度/秒";
}
}
}
diff --git a/ThreatSource/src/Guidance/InfraredImageGenerator.cs b/ThreatSource/src/Guidance/InfraredImageGenerator.cs
index 8477d35..f64ec68 100644
--- a/ThreatSource/src/Guidance/InfraredImageGenerator.cs
+++ b/ThreatSource/src/Guidance/InfraredImageGenerator.cs
@@ -372,8 +372,6 @@ namespace ThreatSource.Guidance
if (thermalPattern == null)
{
Console.WriteLine($"警告: 目标 {target.Id} 未提供 ThermalPattern,无法生成基于模式的强度。");
- // Fallback or return? For now, let's just log and potentially result in a black target area.
- // Alternatively, could fallback to the old Gaussian model here.
return;
}
@@ -453,68 +451,6 @@ namespace ThreatSource.Guidance
}
Console.WriteLine($"目标基于ThermalPattern强度分布: 像素设置: {pixelsSet}, 最大强度: {maxSetIntensity:F6} W/sr");
-
- // --- 结束: 使用 ThermalPattern 重构 ---
-
- /* --- 保留旧的高斯模型代码以供参考 ---
- // 计算目标自身应有的辐射强度(未被遮挡时)
- double targetBaseIntensity = target.Properties.InfraredRadiationIntensity * transmittance / Math.Pow(distance, 1.8);
-
- // 计算高斯分布参数
- double sigmaX = pixelLength / 6.0; // 标准差设为长度/宽度的1/6,覆盖约99.7%范围
- double sigmaY = pixelWidth / 6.0;
-
- // 避免除以零
- sigmaX = Math.Max(sigmaX, 1e-6);
- sigmaY = Math.Max(sigmaY, 1e-6);
-
- int halfLength = pixelLength / 2;
- int halfWidth = pixelWidth / 2;
-
- int pixelsSet = 0;
- double maxSetIntensity = 0;
-
- // 设置强度分布
- for (int dy = -halfWidth; dy <= halfWidth; dy++)
- {
- int y = centerY + dy;
- if (y < 0 || y >= image.Height) continue;
-
- for (int dx = -halfLength; dx <= halfLength; dx++)
- {
- int x = centerX + dx;
- if (x < 0 || x >= image.Width) continue;
-
- double finalIntensity;
- double smokeIntensity = smokeIntensityLayer[y, x];
-
- if (smokeIntensity >= 0) // 检查此像素是否被遮蔽烟幕覆盖
- {
- // 如果被覆盖,使用烟幕的强度
- finalIntensity = smokeIntensity;
- }
- else
- {
- // 如果未被覆盖,计算目标的强度
- // 计算归一化距离 (相对于高斯分布中心)
- double normalizedX = dx / sigmaX;
- double normalizedY = dy / sigmaY;
- double r2 = normalizedX * normalizedX + normalizedY * normalizedY;
-
- // 计算高斯分布下的目标强度
- finalIntensity = targetBaseIntensity * Math.Exp(-r2 / 2.0);
- // Console.WriteLine($"像素 ({x},{y}) 未被烟幕覆盖,使用目标强度: {finalIntensity:F6}");
- }
-
- // 设置最终计算出的强度到图像
- image.SetIntensity(y, x, finalIntensity);
- pixelsSet++;
- maxSetIntensity = Math.Max(maxSetIntensity, finalIntensity);
- }
- }
-
- Console.WriteLine($"目标/烟幕强度分布: 像素设置: {pixelsSet}, 最大强度: {maxSetIntensity:F6} W/sr");
- */
}
///
diff --git a/ThreatSource/src/Guidance/InfraredImagingGuidanceSystem.cs b/ThreatSource/src/Guidance/InfraredImagingGuidanceSystem.cs
index f5e3485..3c08125 100644
--- a/ThreatSource/src/Guidance/InfraredImagingGuidanceSystem.cs
+++ b/ThreatSource/src/Guidance/InfraredImagingGuidanceSystem.cs
@@ -53,13 +53,13 @@ namespace ThreatSource.Guidance
public bool IsInLockMode => currentMode == WorkMode.Lock;
///
- /// 上一次探测到的目标位置
+ /// 上一次探测到的目标位置 (使用可空类型)
///
///
/// 记录目标的历史位置
/// 用于计算目标速度
///
- private Vector3D lastTargetPosition;
+ private Vector3D? lastTargetPosition { get; set; } // Changed to nullable Vector3D?
///
/// 红外图像生成器
@@ -123,10 +123,9 @@ namespace ThreatSource.Guidance
)
: base(id, maxAcceleration, proportionalNavigationCoefficient, simulationManager)
{
- lastTargetPosition = Vector3D.Zero;
this.targetType = targetType;
config = guidanceConfig;
- targetRecognizer = new InfraredTargetRecognizer(simulationManager);
+ targetRecognizer = new InfraredTargetRecognizer();
// 首先创建图像生成器
imageGenerator = new InfraredImageGenerator(
@@ -192,8 +191,24 @@ namespace ThreatSource.Guidance
{
if (SimulationManager.GetEntityById(parameters.JammerId) is SmokeGrenade smokeGrenade)
{
- // 计算烟幕衰减
- SmokeAttenuation = smokeGrenade.GetSmokeTransmittanceOnLine(Position, lastTargetPosition, config.WaveLength);
+ // Check lastTargetPosition != null before using it
+ if (lastTargetPosition != null)
+ {
+ // 计算烟幕衰减 (这里存储衰减系数,1.0表示无衰减)
+ SmokeAttenuation = smokeGrenade.GetSmokeTransmittanceOnLine(Position, lastTargetPosition, config.WaveLength);
+ Debug.WriteLine($"[烟幕干扰应用 IR] 视线透过率/衰减系数: {SmokeAttenuation:F3}");
+ }
+ else
+ {
+ // 目标尚未有效跟踪,无法计算特定视线衰减,假定无衰减
+ SmokeAttenuation = 1.0;
+ Debug.WriteLine("[烟幕干扰应用 IR] 目标位置无效,暂不计算烟幕衰减。");
+ }
+ }
+ else
+ {
+ // 未找到烟幕弹,假定无衰减
+ SmokeAttenuation = 1.0;
}
}
}
@@ -211,6 +226,16 @@ namespace ThreatSource.Guidance
base.HandleJammingCleared(type);
// 干扰清除后的恢复逻辑
}
+ else if (type == JammingType.SmokeScreen)
+ {
+ SmokeAttenuation = 1.0; // Reset smoke attenuation
+ Debug.WriteLine("[烟幕干扰清除 IR]");
+ base.HandleJammingCleared(type);
+ }
+ else
+ {
+ base.HandleJammingCleared(type);
+ }
}
///
@@ -234,6 +259,13 @@ namespace ThreatSource.Guidance
base.Deactivate();
SimulationManager.UnsubscribeFromEvent(OnInfraredJamming);
SimulationManager.UnsubscribeFromEvent(OnSmokeScreen);
+ lastTargetPosition = null; // Add reset to null
+ HasTarget = false;
+ HasGuidance = false;
+ GuidanceAcceleration = Vector3D.Zero;
+ // Optionally reset timers?
+ // targetLostTimer = 0;
+ // lockConfirmationTimer = 0;
}
///
@@ -289,15 +321,28 @@ namespace ThreatSource.Guidance
base.Update(deltaTime, missilePosition, missileVelocity);
if (!IsHardJammed)
{
- if (TryDetectAndIdentifyTarget(missilePosition, missileVelocity, deltaTime, out Vector3D tankPosition))
+ if (TryDetectAndIdentifyTarget(missilePosition, missileVelocity, deltaTime, out Vector3D currentTargetPosition))
{
targetLostTimer = 0; // 重置丢失计时器
- //根据目标当前位置和上一次位置计算目标速度
- Vector3D targetVelocity = (tankPosition - lastTargetPosition) / deltaTime;
- lastTargetPosition = tankPosition;
+ Vector3D? currentTargetVelocity = null; // Initialize as nullable
+ // Check lastTargetPosition != null before calculating velocity
+ if(lastTargetPosition != null && deltaTime > 0)
+ {
+ // Remove cast, use lastTargetPosition directly
+ currentTargetVelocity = (currentTargetPosition - lastTargetPosition) / deltaTime;
+ }
+
+ // Update last known position (assign non-nullable to nullable)
+ lastTargetPosition = currentTargetPosition;
- // 使用比例控制算法
- GuidanceAcceleration = MotionAlgorithm.CalculateProportionalNavigation(ProportionalNavigationCoefficient, missilePosition, missileVelocity, tankPosition, targetVelocity);
+ // Use proportional navigation, provide default if velocity is null
+ GuidanceAcceleration = MotionAlgorithm.CalculateProportionalNavigation(
+ ProportionalNavigationCoefficient,
+ missilePosition,
+ missileVelocity,
+ currentTargetPosition, // Non-nullable from out parameter
+ currentTargetVelocity ?? Vector3D.Zero // Provide default if null
+ );
// 限制最大加速度
if (GuidanceAcceleration.Magnitude() > MaxAcceleration)
{
@@ -330,6 +375,7 @@ namespace ThreatSource.Guidance
else
{
GuidanceAcceleration = Vector3D.Zero;
+ HasGuidance = false;
}
}
@@ -347,6 +393,7 @@ namespace ThreatSource.Guidance
currentMode = WorkMode.Search;
HasTarget = false;
targetLostTimer = 0; // 重置丢失计时器
+ lastTargetPosition = null; // Add reset to null
// 创建图像生成器
imageGenerator = new InfraredImageGenerator(
@@ -529,8 +576,10 @@ namespace ThreatSource.Guidance
///
public override string GetStatus()
{
+ // Check for null before calling ToString()
+ string lastPosStr = lastTargetPosition != null ? lastTargetPosition.ToString() : "null";
return base.GetStatus() + $", GuidanceAcceleration: {GuidanceAcceleration}, " +
- $"Target Position: {lastTargetPosition}";
+ $"Target Position: {lastPosStr}";
}
}
}
diff --git a/ThreatSource/src/Guidance/InfraredTargetRecognizer.cs b/ThreatSource/src/Guidance/InfraredTargetRecognizer.cs
index 1b50632..8a0dacb 100644
--- a/ThreatSource/src/Guidance/InfraredTargetRecognizer.cs
+++ b/ThreatSource/src/Guidance/InfraredTargetRecognizer.cs
@@ -58,32 +58,16 @@ namespace ThreatSource.Guidance
///
public class InfraredTargetRecognizer
{
- ///
- /// 仿真管理器实例
- ///
- private readonly ISimulationManager simulationManager;
-
///
/// 目标特征数据库
///
private readonly Dictionary targetFeatures;
- ///
- /// 识别阈值
- ///
- private const double RECOGNITION_THRESHOLD = 0.7;
-
- ///
- /// 背景辐射强度,用于阈值计算
- ///
- private const double BACKGROUND_INTENSITY = 0.0001;
-
///
/// 初始化红外图像目标识别器
///
- public InfraredTargetRecognizer(ISimulationManager simulationManager)
+ public InfraredTargetRecognizer()
{
- this.simulationManager = simulationManager;
// 初始化目标特征数据库 - 使用相对特征值
targetFeatures = new Dictionary
{
@@ -324,13 +308,10 @@ namespace ThreatSource.Guidance
double mean = sum / count;
// --- 修改为基于动态范围的阈值计算 ---
- double thresholdFactor = 0.05; // 基于动态范围的因子 (初始值设为0.15, 从 0.05 改为 0.01)
+ double thresholdFactor = 0.05; // 基于动态范围的因子
double dynamicRange = maxIntensity - minIntensity;
double threshold = minIntensity + dynamicRange * thresholdFactor;
- // 添加一个小的偏移量,以确保阈值严格大于最小强度,避免将所有背景像素包含进来
- // double epsilon = 1e-9;
- // threshold = Math.Max(threshold, minIntensity + epsilon); // 确保阈值至少比最小值大一点点
Console.WriteLine($"图像统计:");
Console.WriteLine($" 最大强度: {maxIntensity:F6}");
@@ -339,7 +320,6 @@ namespace ThreatSource.Guidance
Console.WriteLine($" 动态范围: {dynamicRange:F6}");
Console.WriteLine($" 动态阈值因子: {thresholdFactor:P1}");
Console.WriteLine($" 最终阈值: {threshold:F6}");
- // --- 结束修改 ---
return threshold;
}
diff --git a/ThreatSource/src/Guidance/LaserBeamRiderGuidanceSystem.cs b/ThreatSource/src/Guidance/LaserBeamRiderGuidanceSystem.cs
index dab1ca0..0e1339d 100644
--- a/ThreatSource/src/Guidance/LaserBeamRiderGuidanceSystem.cs
+++ b/ThreatSource/src/Guidance/LaserBeamRiderGuidanceSystem.cs
@@ -20,22 +20,22 @@ namespace ThreatSource.Guidance
public class LaserBeamRiderGuidanceSystem : BasicGuidanceSystem
{
///
- /// 获取或设置激光源位置
+ /// 获取或设置激光源位置 (使用可空类型)
///
///
/// 记录激光发射源的三维位置
/// 用于计算导弹与激光束的相对位置
///
- private Vector3D LaserSourcePosition { get; set; }
+ private Vector3D? LaserSourcePosition { get; set; }
///
- /// 获取或设置激光方向
+ /// 获取或设置激光方向 (使用可空类型)
///
///
/// 记录激光束的传播方向
/// 用于计算导弹与激光束的偏差
///
- private Vector3D LaserDirection { get; set; }
+ private Vector3D? LaserDirection { get; set; }
///
/// 获取或设置激光指示器激光功率,单位:瓦特
@@ -46,36 +46,6 @@ namespace ThreatSource.Guidance
///
public double LaserPower { get; set; }
- ///
- /// 最小可探测功率,单位:瓦特
- ///
- ///
- /// 定义了探测器的灵敏度阈值
- /// 低于此值时无法有效探测
- /// 典型值为1e-10瓦
- ///
- private const double MinDetectablePower = 1e-10;
-
- ///
- /// 探测器直径,单位:米
- ///
- ///
- /// 定义了探测器的物理尺寸
- /// 影响系统的接收能力
- /// 典型值为0.03米
- ///
- private const double DetectorDiameter = 0.03;
-
- ///
- /// 控制场直径,单位:米
- ///
- ///
- /// 定义了有效制导范围
- /// 超出此范围将失去制导
- /// 典型值为6米
- ///
- private const double ControlFieldDiameter = 6.0;
-
///
/// 上一次的误差向量
///
@@ -175,8 +145,6 @@ namespace ThreatSource.Guidance
: base(id, maxAcceleration, guidanceCoefficient, simulationManager)
{
config = guidanceConfig;
- LaserSourcePosition = Vector3D.Zero;
- LaserDirection = Vector3D.Zero;
LaserPower = 0;
LaserIlluminationOn = false;
LastError = Vector3D.Zero;
@@ -205,7 +173,7 @@ namespace ThreatSource.Guidance
base.Activate();
// 在这里订阅事件,确保只订阅一次
SimulationManager.SubscribeToEvent(OnLaserJamming);
- SimulationManager.SubscribeToEvent(OnLaserBeamStart);
+ SimulationManager.SubscribeToEvent(OnLaserBeamStart);
SimulationManager.SubscribeToEvent(OnLaserBeamStop);
}
@@ -217,7 +185,7 @@ namespace ThreatSource.Guidance
base.Deactivate();
// 取消订阅事件
SimulationManager.UnsubscribeFromEvent(OnLaserJamming);
- SimulationManager.UnsubscribeFromEvent(OnLaserBeamStart);
+ SimulationManager.UnsubscribeFromEvent(OnLaserBeamStart);
SimulationManager.UnsubscribeFromEvent(OnLaserBeamStop);
}
@@ -350,10 +318,11 @@ namespace ThreatSource.Guidance
///
public void DeactivateLaserBeam()
{
- LaserSourcePosition = Vector3D.Zero;
- LaserDirection = Vector3D.Zero;
+ LaserSourcePosition = null;
+ LaserDirection = null;
LaserPower = 0;
HasGuidance = false;
+ LaserIlluminationOn = false;
}
///
@@ -411,11 +380,16 @@ namespace ThreatSource.Guidance
///
private void UpdateGuidanceStatus()
{
- // 计算导弹到激光束的最短距离
+ if (LaserSourcePosition == null)
+ {
+ HasGuidance = false;
+ Trace.WriteLine($"激光驾束引导系统: 失去引导, 原因: 激光源位置未知");
+ return;
+ }
+
Vector3D shortestDistanceVector = CalculateShortestDistanceToLaserBeam();
double shortestDistance = shortestDistanceVector.Magnitude();
- // 检查导弹是否在控制场内
if (shortestDistance > config.ControlFieldDiameter / 2)
{
HasGuidance = false;
@@ -425,11 +399,9 @@ namespace ThreatSource.Guidance
Debug.WriteLine($"激光驾束引导系统: 在控制场内, 距离: {shortestDistance}");
- // 计算导弹到激光源的距离
Vector3D missileToSource = LaserSourcePosition - Position;
double distance = missileToSource.Magnitude();
- // 计算接收到的激光功率
double receivedPower = CalculateReceivedLaserPower(distance);
Debug.WriteLine($"激光驾束引导系统: 接收到的激光功率: {receivedPower:E} W");
@@ -498,53 +470,48 @@ namespace ThreatSource.Guidance
/// - 合成最终制导指令
/// - 应用低通滤波
///
- protected void CalculateGuidanceAcceleration(double deltaTime)
+ protected void CalculateGuidanceAcceleration(double deltaTime)
{
- // 计算导弹到激光束的最短距离
+ if (LaserDirection == null)
+ {
+ GuidanceAcceleration = Vector3D.Zero;
+ LastError = Vector3D.Zero;
+ IntegralError = Vector3D.Zero;
+ return;
+ }
+
Vector3D shortestDistanceVector = CalculateShortestDistanceToLaserBeam();
- // PID控制
Vector3D error = shortestDistanceVector;
- // 积分项
IntegralError += error * deltaTime;
- // 微分项
Vector3D derivativeError = (error - LastError) / deltaTime;
- // 计算PID输出
Vector3D pidOutput = error * config.ProportionalGain +
IntegralError * config.IntegralGain +
derivativeError * config.DerivativeGain;
- // 非线性增益
double distance = shortestDistanceVector.Magnitude();
double nonLinearGain = Math.Tanh(distance / config.NonlinearGain);
- // 计算横向加速度
Vector3D lateralAcceleration = pidOutput * nonLinearGain;
- // 限制最大加速度
if (lateralAcceleration.Magnitude() > config.MaxGuidanceAcceleration)
{
lateralAcceleration = lateralAcceleration.Normalize() * config.MaxGuidanceAcceleration;
}
- // 计算前向加速度
Vector3D forwardDirection = LaserDirection;
Vector3D currentDirection = Velocity.Normalize();
Vector3D rotationAxis = Vector3D.CrossProduct(currentDirection, forwardDirection);
double rotationAngle = Math.Acos(Vector3D.DotProduct(currentDirection, forwardDirection));
Vector3D forwardAcceleration = Vector3D.CrossProduct(rotationAxis, Velocity) * rotationAngle * ProportionalNavigationCoefficient;
- // 合并横向和前向加速度
GuidanceAcceleration = lateralAcceleration + forwardAcceleration;
-
- // 低通滤波
GuidanceAcceleration = GuidanceAcceleration * config.LowPassFilterCoefficient +
LastGuidanceAcceleration * (1 - config.LowPassFilterCoefficient);
- // 更新上一次的误差和制导加速度
LastError = error;
LastGuidanceAcceleration = GuidanceAcceleration;
}
@@ -572,7 +539,6 @@ namespace ThreatSource.Guidance
Debug.WriteLine($"激光驾束制导系统干扰状态 - IsJammed: {IsJammed}, 干扰功率: {evt.JammingPower}W, 抗性阈值: {config.JammingResistanceThreshold}W");
}
-
///
/// 处理系统被干扰的事件
///
@@ -621,7 +587,10 @@ namespace ThreatSource.Guidance
///
public override string GetStatus()
{
- return base.GetStatus() + $"激光指示器功率: {LaserPower:E} W," + $" 激光照射状态: {LaserIlluminationOn}";
+ string sourcePosStr = LaserSourcePosition != null ? LaserSourcePosition.ToString() : "null";
+ string directionStr = LaserDirection != null ? LaserDirection.ToString() : "null";
+ return base.GetStatus() + $", SourcePos: {sourcePosStr}, Direction: {directionStr}, " +
+ $"LaserPower: {LaserPower:E} W, Illumination: {LaserIlluminationOn}";
}
///
@@ -637,16 +606,14 @@ namespace ThreatSource.Guidance
///
private Vector3D CalculateShortestDistanceToLaserBeam()
{
- // 计算导弹到激光源的向量
+ if (LaserSourcePosition == null || LaserDirection == null)
+ {
+ return Vector3D.Zero;
+ }
+
Vector3D missileToSource = LaserSourcePosition - Position;
-
- // 计算导弹在激光方向上的投影长度
double projectionLength = Vector3D.DotProduct(missileToSource, LaserDirection);
-
- // 计算激光束上最接近导弹的点
Vector3D closestPointOnBeam = LaserSourcePosition - LaserDirection * projectionLength;
-
- // 计算导弹到激光束最近点的向量(即最短距离向量)
Vector3D shortestDistanceVector = closestPointOnBeam - Position;
return shortestDistanceVector;
@@ -656,22 +623,22 @@ namespace ThreatSource.Guidance
/// 处理激光波束开始事件
///
/// 激光波束开始事件
- private void OnLaserBeamStart(LaserBeamStartEvent evt)
+ private void OnLaserBeamStart(LaserBeamEvent evt)
{
if(evt?.LaserBeamRiderId != null && evt.LaserCodeConfig != null)
{
if(evt.LaserCodeConfig.IsCodeEnabled)
{
- // 检查编码是否匹配
bool codeMatched = CheckLaserCode(evt.LaserCodeConfig);
if (!codeMatched)
{
- // 发布编码不匹配事件
PublishCodeMismatchEvent(evt.LaserBeamRiderId, evt.LaserCodeConfig);
Debug.WriteLine("激光驾束制导系统接收到不匹配的激光编码,忽略信号");
HasGuidance = false;
LaserIlluminationOn = false;
+ LaserSourcePosition = null;
+ LaserDirection = null;
return;
}
}
@@ -691,6 +658,8 @@ namespace ThreatSource.Guidance
{
LaserIlluminationOn = false;
HasGuidance = false;
+ LaserSourcePosition = null;
+ LaserDirection = null;
}
}
}
diff --git a/ThreatSource/src/Guidance/LaserSemiActiveGuidanceSystem.cs b/ThreatSource/src/Guidance/LaserSemiActiveGuidanceSystem.cs
index 433e5e9..3e8120f 100644
--- a/ThreatSource/src/Guidance/LaserSemiActiveGuidanceSystem.cs
+++ b/ThreatSource/src/Guidance/LaserSemiActiveGuidanceSystem.cs
@@ -24,13 +24,13 @@ namespace ThreatSource.Guidance
private readonly LaserSemiActiveGuidanceConfig config;
///
- /// 获取或设置目标位置
+ /// 获取或设置目标位置 (使用可空类型)
///
///
/// 记录当前跟踪目标的三维位置
/// 用于制导计算
///
- private Vector3D TargetPosition { get; set; }
+ private Vector3D? TargetPosition { get; set; }
///
/// 获取或设置接收到的激光功率
@@ -150,7 +150,6 @@ namespace ThreatSource.Guidance
{
config = guidanceConfig;
- TargetPosition = Vector3D.Zero;
LaserIlluminationOn = false;
InternalLaserCodeConfig = laserCodeConfig;
@@ -217,6 +216,7 @@ namespace ThreatSource.Guidance
// 取消订阅诱偏目标照射事件
SimulationManager.UnsubscribeFromEvent(OnLaserDecoy);
SimulationManager.UnsubscribeFromEvent(OnLaserDecoyStop);
+ TargetPosition = null;
}
///
@@ -261,6 +261,7 @@ namespace ThreatSource.Guidance
LaserIlluminationOn = false;
HasGuidance = false; // 禁用制导
PreviousGuidanceAcceleration = Vector3D.Zero; // 重置历史加速度
+ TargetPosition = null;
}
///
@@ -320,7 +321,7 @@ namespace ThreatSource.Guidance
if (IsHardJammed)
{
// 清除目标信息
- TargetPosition = Vector3D.Zero;
+ TargetPosition = null;
LaserIlluminationOn = false;
// 记录干扰信息
Trace.WriteLine($"激光半主动制导系统被硬干扰 - 功率: {evt.JammingPower}W, 位置: {evt.JammingSourcePosition}, 方向: {evt.JammingDirection}");
@@ -381,11 +382,24 @@ namespace ThreatSource.Guidance
{
if (SimulationManager.GetEntityById(parameters.JammerId) is SmokeGrenade smokeGrenade)
{
- // 计算烟幕衰减
- if (LaserIlluminationOn)
+ // 检查目标位置是否有效,并且激光照射是否开启 (烟幕只影响接收到的信号)
+ if (TargetPosition != null && LaserIlluminationOn)
{
+ // 计算烟幕衰减 (1.0 表示无衰减)
SmokeAttenuation = smokeGrenade.GetSmokeTransmittanceOnLine(Position, TargetPosition, config.LaserWavelength);
+ Console.WriteLine($"[烟幕干扰应用 Laser] 视线透过率/衰减系数: {SmokeAttenuation:F3}");
}
+ else
+ {
+ // 目标无效或激光未照射,暂不计算特定视线衰减
+ SmokeAttenuation = 1.0;
+ Console.WriteLine("[烟幕干扰应用 Laser] 目标位置无效或激光未照射,暂不计算烟幕衰减。");
+ }
+ }
+ else
+ {
+ // 未找到烟幕弹,假定无衰减
+ SmokeAttenuation = 1.0;
}
}
}
@@ -623,7 +637,13 @@ namespace ThreatSource.Guidance
///
private Vector2D CalculateSpotOffset()
{
- // 计算理想指向方向(从导弹到目标)
+ // Check TargetPosition != null before using it
+ if (TargetPosition == null)
+ {
+ return Vector2D.Zero;
+ }
+
+ // No cast needed, just use TargetPosition directly
Vector3D idealDirection = (TargetPosition - Position).Normalize();
// 计算当前导弹前向方向
diff --git a/ThreatSource/src/Guidance/MillimeterWaveGuidanceSystem.cs b/ThreatSource/src/Guidance/MillimeterWaveGuidanceSystem.cs
index 3ba381f..f06eb97 100644
--- a/ThreatSource/src/Guidance/MillimeterWaveGuidanceSystem.cs
+++ b/ThreatSource/src/Guidance/MillimeterWaveGuidanceSystem.cs
@@ -1,4 +1,3 @@
-
using ThreatSource.Utils;
using ThreatSource.Equipment;
using System.Diagnostics;
@@ -51,22 +50,22 @@ namespace ThreatSource.Guidance
private readonly Random random = new();
///
- /// 上一次探测到的目标位置
+ /// 上一次探测到的目标位置 (使用可空类型)
///
///
/// 记录目标的历史位置
/// 用于计算目标速度
///
- private Vector3D lastTargetPosition;
+ private Vector3D? lastTargetPosition { get; set; }
///
- /// 上一次探测到的目标速度
+ /// 上一次探测到的目标速度 (使用可空类型)
///
///
/// 记录目标的历史速度
/// 用于计算目标速度
///
- private Vector3D lastTargetVelocity;
+ private Vector3D? lastTargetVelocity { get; set; }
///
/// 目标丢失计时器
@@ -134,6 +133,10 @@ namespace ThreatSource.Guidance
///
private double maxScanRadius => config.FieldOfViewAngle * Math.PI / 180.0 / 2;
+ ///
+ /// 当前视线的烟幕透过率 (0.0 - 1.0)
+ ///
+ private double _currentSmokeTransmittance = 1.0;
///
@@ -161,10 +164,7 @@ namespace ThreatSource.Guidance
: base(id, maxAcceleration, guidanceCoefficient, simulationManager)
{
this.config = config;
- lastTargetPosition = Vector3D.Zero;
- lastTargetVelocity = Vector3D.Zero;
-
- InitializeJamming(config.JammingResistanceThreshold, [JammingType.MillimeterWave]);
+ InitializeJamming(config.JammingResistanceThreshold, [JammingType.MillimeterWave, JammingType.SmokeScreen]);
SwitchToSearchMode(); // 初始化为搜索模式
}
@@ -180,6 +180,8 @@ namespace ThreatSource.Guidance
lockConfirmationTimer = 0;
currentScanAngle = 0;
currentScanRadius = config.SearchBeamWidth * Math.PI / 720.0; // 从半个波束宽度的一半开始
+ lastTargetPosition = null;
+ lastTargetVelocity = null;
Trace.WriteLine($"切换到搜索模式,波束宽度: {config.SearchBeamWidth}度");
}
@@ -214,7 +216,9 @@ namespace ThreatSource.Guidance
IsActive = true;
// 在这里订阅事件,确保只订阅一次
SimulationManager.SubscribeToEvent(OnMillimeterWaveJamming);
- }
+ // 添加对烟幕事件的订阅
+ SimulationManager.SubscribeToEvent(OnSmokeScreen);
+ }
base.Activate();
SwitchToSearchMode();
}
@@ -228,11 +232,15 @@ namespace ThreatSource.Guidance
{
IsActive = false;
SimulationManager.UnsubscribeFromEvent(OnMillimeterWaveJamming);
+ // 添加取消对烟幕事件的订阅
+ SimulationManager.UnsubscribeFromEvent(OnSmokeScreen);
}
base.Deactivate();
HasTarget = false;
HasGuidance = false;
GuidanceAcceleration = Vector3D.Zero;
+ lastTargetPosition = null;
+ lastTargetVelocity = null;
}
///
@@ -265,22 +273,77 @@ namespace ThreatSource.Guidance
Debug.WriteLine($"毫米波导引头系统干扰状态 - IsJammed: {IsJammed}, 干扰功率: {evt.JammingPower}W, 抗性阈值: {config.JammingResistanceThreshold}W");
}
+ ///
+ /// 处理烟幕事件,触发干扰应用
+ ///
+ /// 烟幕事件
+ private void OnSmokeScreen(SmokeScreenEvent evt)
+ {
+ if (evt != null && evt.SmokeGrenadeId != null)
+ {
+ // 获取烟幕弹实例以创建干扰参数
+ if (SimulationManager.GetEntityById(evt.SmokeGrenadeId) is SmokeGrenade smokeGrenade)
+ {
+ var parameters = new JammingParameters
+ {
+ Type = JammingType.SmokeScreen,
+ JammerId = smokeGrenade.Id,
+ SourcePosition = smokeGrenade.Position,
+ Direction = smokeGrenade.Orientation.ToVector(),
+ Mode = JammingMode.Obscuration // 表明是遮蔽干扰
+ // JammableComponent可能需要其他烟幕属性,如果需要则从smokeGrenade.CurrentParameters获取
+ };
+ // 应用干扰效果,这将调用HandleJammingApplied
+ ApplyJamming(parameters);
+ }
+ }
+ }
+
///
/// 处理系统被干扰的事件
///
/// 干扰参数
protected override void HandleJammingApplied(JammingParameters parameters)
{
+ // 1. 让基类处理通用硬干扰逻辑 (如果不是SmokeScreen, 会设置 IsHardJammed 和 HasGuidance = false)
+ base.HandleJammingApplied(parameters);
+
+ // 2. 处理特定于毫米波的硬干扰响应
if (parameters.Type == JammingType.MillimeterWave)
- {
- Debug.WriteLine($"毫米波导引头系统受到毫米波干扰,功率:{parameters.Power}瓦特");
- // 确保基类的处理逻辑被调用,设置HasGuidance = false
- base.HandleJammingApplied(parameters);
+ {
+ Debug.WriteLine($"毫米波导引头系统受到毫米波干扰,功率:{parameters.Power}瓦特");
+ // 在硬干扰下切换到搜索模式 (即使基类已设置HasGuidance=false, 仍可切换模式)
+ if (currentMode != WorkMode.Search)
+ {
+ SwitchToSearchMode();
+ }
}
- // 在强干扰下切换到搜索模式
- if (currentMode != WorkMode.Search)
+ // 3. 处理烟幕干扰 (计算透过率,不直接影响 IsHardJammed 或 HasGuidance)
+ else if (parameters.Type == JammingType.SmokeScreen)
{
- SwitchToSearchMode();
+ if (SimulationManager.GetEntityById(parameters.JammerId) is SmokeGrenade smokeGrenade)
+ {
+ // Check lastTargetPosition != null before using it
+ if (lastTargetPosition != null)
+ {
+ // 计算波长
+ double wavelength = 3e8 / config.WaveFrequency;
+ // 计算视线透过率
+ _currentSmokeTransmittance = smokeGrenade.GetSmokeTransmittanceOnLine(Position, lastTargetPosition, wavelength);
+ Debug.WriteLine($"[烟幕干扰应用 MMW] 视线透过率: {_currentSmokeTransmittance:F3}");
+ }
+ else
+ {
+ // 目标尚未有效跟踪,无法计算特定视线衰减,假定无衰减
+ _currentSmokeTransmittance = 1.0;
+ Debug.WriteLine("[烟幕干扰应用 MMW] 目标位置无效,暂不计算烟幕衰减。");
+ }
+ }
+ else
+ {
+ // 未找到烟幕弹,假定无衰减
+ _currentSmokeTransmittance = 1.0;
+ }
}
}
@@ -290,11 +353,21 @@ namespace ThreatSource.Guidance
/// 被清除的干扰类型
protected override void HandleJammingCleared(JammingType type)
{
- if (type == JammingType.MillimeterWave)
+ // 1. 处理特定于烟幕的清除逻辑
+ if (type == JammingType.SmokeScreen)
{
- Debug.WriteLine("毫米波导引头系统干扰被清除");
- base.HandleJammingCleared(type);
+ _currentSmokeTransmittance = 1.0; // 重置透过率
+ Debug.WriteLine("[烟幕干扰清除 MMW]");
}
+ else if (type == JammingType.MillimeterWave)
+ {
+ Debug.WriteLine("毫米波导引头系统干扰被清除");
+ // 毫米波硬干扰清除的具体行为由基类处理
+ }
+
+ // 2. 最后调用基类方法处理通用清除逻辑
+ // 基类会检查是否所有干扰都已清除,并相应地更新 IsHardJammed 和 HasGuidance
+ base.HandleJammingCleared(type);
}
///
@@ -452,25 +525,28 @@ namespace ThreatSource.Guidance
base.Update(deltaTime, missilePosition, missileVelocity);
- if (!IsJammed)
+ if (!IsHardJammed)
{
- if (TryDetectAndTrackTarget(missilePosition, missileVelocity, deltaTime, out Vector3D targetPosition))
+ if (TryDetectAndTrackTarget(missilePosition, missileVelocity, deltaTime, out Vector3D currentTargetPosition))
{
targetLostTimer = 0;
- Vector3D targetVelocity = (targetPosition - lastTargetPosition) / deltaTime;
- lastTargetPosition = targetPosition;
- lastTargetVelocity = targetVelocity;
+ Vector3D? currentTargetVelocity = null;
+ if (lastTargetPosition != null && deltaTime > 0)
+ {
+ currentTargetVelocity = (currentTargetPosition - lastTargetPosition) / deltaTime;
+ }
+
+ lastTargetPosition = currentTargetPosition;
+ lastTargetVelocity = currentTargetVelocity;
- // 使用比例导引计算制导加速度
GuidanceAcceleration = MotionAlgorithm.CalculateProportionalNavigation(
ProportionalNavigationCoefficient,
missilePosition,
missileVelocity,
- targetPosition,
- targetVelocity
+ currentTargetPosition,
+ currentTargetVelocity ?? Vector3D.Zero
);
- // 限制最大加速度
if (GuidanceAcceleration.Magnitude() > MaxAcceleration)
{
GuidanceAcceleration = GuidanceAcceleration.Normalize() * MaxAcceleration;
@@ -484,7 +560,6 @@ namespace ThreatSource.Guidance
if (currentMode != WorkMode.Search)
{
targetLostTimer += deltaTime;
- // 如果目标丢失时间达到阈值,切换回搜索模式
if (targetLostTimer >= config.TargetLostTolerance)
{
HasGuidance = false;
@@ -528,7 +603,6 @@ namespace ThreatSource.Guidance
bool foundTarget = false;
double currentSNR = double.MinValue;
- // 如果被干扰,直接返回false
if (isJammed)
{
Trace.WriteLine($"毫米波导引头受到干扰,干扰功率: {jammingPower:F2}W");
@@ -545,13 +619,11 @@ namespace ThreatSource.Guidance
if (distance <= config.MaxDetectionRange)
{
- // 计算信噪比
double snr = CalculateSNR(distance, target.Properties.RadarCrossSection);
Console.WriteLine($"信噪比: {snr:F2}dB");
if (currentMode == WorkMode.Search)
{
- // 在搜索模式下进行波束判断
if (IsTargetInBeam(missileVelocity, toTarget) && snr >= config.RecognitionSNRThreshold)
{
targetPosition = target.Position;
@@ -562,11 +634,10 @@ namespace ThreatSource.Guidance
}
else if (currentMode == WorkMode.Track || currentMode == WorkMode.Lock)
{
- // 波束内判断
if (IsTargetInBeam(missileVelocity, toTarget) &&
+ lastTargetPosition != null &&
Vector3D.Distance(target.Position, lastTargetPosition) < 100.0)
{
- // 在跟踪模式下,SNR至少要达到识别阈值
double requiredSNR = (currentMode == WorkMode.Track) ?
config.RecognitionSNRThreshold : config.LockSNRThreshold;
@@ -588,9 +659,7 @@ namespace ThreatSource.Guidance
}
}
- // 根据当前模式和探测结果更新系统状态
UpdateSystemState(foundTarget, currentSNR, deltaTime);
-
HasTarget = foundTarget;
return foundTarget;
}
@@ -657,10 +726,13 @@ namespace ThreatSource.Guidance
///
public override string GetStatus()
{
+ string lastPosStr = lastTargetPosition != null ? lastTargetPosition.ToString() : "null";
+ string lastVelStr = lastTargetVelocity != null ? lastTargetVelocity.ToString() : "null";
+
return base.GetStatus() +
$"\n当前模式: {currentMode}" +
- $"\n目标位置: {lastTargetPosition}" +
- $"\n目标速度: {lastTargetVelocity}" +
+ $"\n最后目标位置: {lastPosStr}" +
+ $"\n最后目标速度: {lastVelStr}" +
$"\n是否有目标: {HasTarget}";
}
@@ -713,6 +785,9 @@ namespace ThreatSource.Guidance
signalPower *= atmosphericTransmittance;
+ // 应用当前生效的烟幕衰减 (通过存储的透过率)
+ signalPower *= _currentSmokeTransmittance;
+
// 计算噪声功率
double noisePower = k * T0 * bandwidth * noiseFigure;
diff --git a/ThreatSource/src/Indicator/LaserBeamRider.cs b/ThreatSource/src/Indicator/LaserBeamRider.cs
index 1d787f4..b9795ea 100644
--- a/ThreatSource/src/Indicator/LaserBeamRider.cs
+++ b/ThreatSource/src/Indicator/LaserBeamRider.cs
@@ -182,6 +182,7 @@ namespace ThreatSource.Indicator
Vector3D targetPosition = target.Position;
LaserDirection = (targetPosition - Position).Normalize();
Debug.WriteLine($"激光驾束仪 {Id} 更新激光指向: {LaserDirection}");
+ PublishLaserBeamEvent();
}
}
}
@@ -287,7 +288,7 @@ namespace ThreatSource.Indicator
{
LaserDirection = (target.Position - Position).Normalize();
IsBeamOn = true;
- PublishLaserBeamStartEvent();
+ PublishLaserBeamEvent();
}
}
}
@@ -318,9 +319,9 @@ namespace ThreatSource.Indicator
/// 通知仿真系统激光波束开始工作
/// 包含制导器ID等关键信息
///
- private void PublishLaserBeamStartEvent()
+ private void PublishLaserBeamEvent()
{
- PublishEvent(new LaserBeamStartEvent
+ PublishEvent(new LaserBeamEvent
{
LaserBeamRiderId = Id
});
diff --git a/ThreatSource/src/MIssile/LaserBeamRiderMissile.cs b/ThreatSource/src/MIssile/LaserBeamRiderMissile.cs
index 4a40a2f..473fdb2 100644
--- a/ThreatSource/src/MIssile/LaserBeamRiderMissile.cs
+++ b/ThreatSource/src/MIssile/LaserBeamRiderMissile.cs
@@ -96,26 +96,7 @@ namespace ThreatSource.Missile
/// - 更新波束参数
/// - 开始波束跟踪
///
- private void OnLaserBeamStart(LaserBeamStartEvent evt)
- {
- if (evt?.LaserBeamRiderId != null)
- {
- LaserBeamRider laserBeamRider = SimulationManager.GetEntityById(evt.LaserBeamRiderId) as LaserBeamRider ?? throw new Exception("激光驾束仪不存在");
- guidanceSystem?.UpdateLaserBeamRider(laserBeamRider.Position, laserBeamRider.LaserDirection, laserBeamRider.LaserPower);
- }
- }
-
- ///
- /// 处理激光束更新事件
- ///
- /// 激光束更新事件数据
- ///
- /// 处理过程:
- /// - 验证激光驾束仪
- /// - 更新波束位置和方向
- /// - 更新制导参数
- ///
- private void OnLaserBeamUpdate(LaserBeamUpdateEvent evt)
+ private void OnLaserBeamEvent(LaserBeamEvent evt)
{
if (evt?.LaserBeamRiderId != null)
{
@@ -235,9 +216,8 @@ namespace ThreatSource.Missile
// 激活制导系统
guidanceSystem.Activate();
// 订阅激光波束事件
- SimulationManager.SubscribeToEvent(OnLaserBeamStart);
+ SimulationManager.SubscribeToEvent(OnLaserBeamEvent);
SimulationManager.SubscribeToEvent(OnLaserBeamStop);
- SimulationManager.SubscribeToEvent(OnLaserBeamUpdate);
}
///
@@ -255,9 +235,8 @@ namespace ThreatSource.Missile
// 停用制导系统
guidanceSystem.Deactivate();
// 取消订阅波束事件
- SimulationManager.UnsubscribeFromEvent(OnLaserBeamStart);
+ SimulationManager.UnsubscribeFromEvent(OnLaserBeamEvent);
SimulationManager.UnsubscribeFromEvent(OnLaserBeamStop);
- SimulationManager.UnsubscribeFromEvent(OnLaserBeamUpdate);
}
///
diff --git a/ThreatSource/src/Simulation/SimulationEvents.cs b/ThreatSource/src/Simulation/SimulationEvents.cs
index b3968d7..7779079 100644
--- a/ThreatSource/src/Simulation/SimulationEvents.cs
+++ b/ThreatSource/src/Simulation/SimulationEvents.cs
@@ -242,42 +242,7 @@ namespace ThreatSource.Simulation
/// 用于通知系统激光波束开始照射
/// 触发时机:激光驾束仪开始工作时
///
- public class LaserBeamStartEvent : SimulationEvent
- {
- ///
- /// 获取或设置激光驾束仪的ID
- ///
- ///
- /// 标识发出激光波束的驾束仪设备
- ///
- public string? LaserBeamRiderId { get; set; }
-
- ///
- /// 获取或设置波束功率
- ///
- ///
- /// 激光波束的发射功率
- ///
- public double BeamPower { get; set; }
-
- ///
- /// 获取或设置激光编码配置
- ///
- ///
- /// 包含激光信号的编码信息
- /// 用于抗干扰和安全识别
- ///
- public LaserCodeConfig? LaserCodeConfig { get; set; }
- }
-
- ///
- /// 激光波束更新事件,表示激光波束状态的更新
- ///
- ///
- /// 用于实时更新激光波束的状态
- /// 在波束照射过程中周期性触发
- ///
- public class LaserBeamUpdateEvent : SimulationEvent
+ public class LaserBeamEvent : SimulationEvent
{
///
/// 获取或设置激光驾束仪的ID
diff --git a/VERSION b/VERSION
index f8112eb..25cd22b 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-0.2.11
\ No newline at end of file
+0.2.12
\ No newline at end of file
diff --git a/tools/ComprehensiveMissileSimulator.cs b/tools/ComprehensiveMissileSimulator.cs
index dfcc38e..e1d664a 100644
--- a/tools/ComprehensiveMissileSimulator.cs
+++ b/tools/ComprehensiveMissileSimulator.cs
@@ -250,7 +250,7 @@ namespace ThreatSource.Tools.MissileSimulation
{
var motionParameters = new MotionParameters
{
- Position = new Vector3D(2000, 1, 50),
+ Position = new Vector3D(2000, 1, 30),
Orientation = new Orientation(Math.PI, 0.02, 0),
InitialSpeed = 300
};
@@ -268,7 +268,7 @@ namespace ThreatSource.Tools.MissileSimulation
{
var motionParameters = new MotionParameters
{
- Position = new Vector3D(3000, 1, 20),
+ Position = new Vector3D(2000, 1, 20),
Orientation = new Orientation(Math.PI, 0.01, 0),
InitialSpeed = 300
};
@@ -383,16 +383,6 @@ namespace ThreatSource.Tools.MissileSimulation
indicators["LD_1"].Activate();
}
Console.WriteLine($"干扰器数量 {jammers.Count}");
- // if (jammers.ContainsKey("LDY_1"))
- // {
- // jammers["LDY_1"].Activate();
- // Console.WriteLine($"激活激光诱偏目标 {jammers["LDY_1"].Id}");
- // }
- if (jammers.ContainsKey("SG_1"))
- {
- //jammers["SG_1"].Activate();
- Console.WriteLine($"激活烟幕弹 {jammers["SG_1"].Id}");
- }
break;
case "LBRM_1": // 激光驾束制导导弹
if (indicators.ContainsKey("LBR_1"))