增加了烟幕对毫米波制导导弹的影响,完善了一些测试
This commit is contained in:
parent
c8240a075d
commit
6e990f65a4
@ -15,6 +15,10 @@
|
||||
- 毫米波跟踪和锁定阶段采用脉冲多普勒制导、目标 RCS 特征矩阵
|
||||
- 多种发射弹道模式:低平弹道、高抛弹道、俯冲弹道
|
||||
- 双模、多模制导
|
||||
- 烟幕弹对毫米波末制导、末敏弹、激光目标指示器、激光驾束仪、红外指令制导指令发射端的干扰
|
||||
|
||||
## [0.2.12] - 2025-04-18
|
||||
- 改进了红外成像制导的目标识别和烟幕弹干扰算法
|
||||
|
||||
## [0.2.11] - 2025-04-14
|
||||
- 增加了激光诱偏目标的干扰功能
|
||||
|
||||
@ -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]
|
||||
|
||||
@ -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]
|
||||
|
||||
@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// 激光半主动导弹集成测试类
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 该测试类验证激光半主动导弹的整体性能:
|
||||
/// - 验证导弹能否在正常条件下命中目标
|
||||
/// - 验证导弹在低功率条件下的行为
|
||||
/// - 验证导弹在干扰环境下的表现
|
||||
/// </remarks>
|
||||
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)
|
||||
{
|
||||
// 不需要额外设置属性,因为基类构造函数已经设置了
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 模拟导弹飞行过程,直到命中目标或超时
|
||||
/// </summary>
|
||||
/// <param name="laserPower">激光功率</param>
|
||||
/// <returns>导弹与目标之间的最小距离</returns>
|
||||
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}米");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -18,31 +18,31 @@ namespace ThreatSource.Guidance
|
||||
public class InfraredCommandGuidanceSystem : BasicGuidanceSystem
|
||||
{
|
||||
/// <summary>
|
||||
/// 跟踪器到导弹的方向向量
|
||||
/// 跟踪器到导弹的方向向量 (使用可空类型)
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 记录上一次接收到的跟踪器指向导弹的方向
|
||||
/// 用于计算导弹的相对位置
|
||||
/// </remarks>
|
||||
private Vector3D lastTrackerToMissileVector;
|
||||
private Vector3D? lastTrackerToMissileVector { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 跟踪器到目标的方向向量
|
||||
/// 跟踪器到目标的方向向量 (使用可空类型)
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 记录上一次接收到的跟踪器指向目标的方向
|
||||
/// 用于计算目标的相对位置
|
||||
/// </remarks>
|
||||
private Vector3D lastTrackerToTargetVector;
|
||||
private Vector3D? lastTrackerToTargetVector { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 上一次的期望飞行方向
|
||||
/// 上一次的期望飞行方向 (使用可空类型)
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 记录上一次计算的期望飞行方向
|
||||
/// 用于计算转向速率
|
||||
/// </remarks>
|
||||
private Vector3D lastDesiredDirection;
|
||||
private Vector3D? lastDesiredDirection { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 当前转向速率,单位:弧度/秒
|
||||
@ -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
|
||||
/// </remarks>
|
||||
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
|
||||
/// </remarks>
|
||||
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} 弧度/秒";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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");
|
||||
*/
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@ -53,13 +53,13 @@ namespace ThreatSource.Guidance
|
||||
public bool IsInLockMode => currentMode == WorkMode.Lock;
|
||||
|
||||
/// <summary>
|
||||
/// 上一次探测到的目标位置
|
||||
/// 上一次探测到的目标位置 (使用可空类型)
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 记录目标的历史位置
|
||||
/// 用于计算目标速度
|
||||
/// </remarks>
|
||||
private Vector3D lastTargetPosition;
|
||||
private Vector3D? lastTargetPosition { get; set; } // Changed to nullable Vector3D?
|
||||
|
||||
/// <summary>
|
||||
/// 红外图像生成器
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -234,6 +259,13 @@ namespace ThreatSource.Guidance
|
||||
base.Deactivate();
|
||||
SimulationManager.UnsubscribeFromEvent<InfraredJammingEvent>(OnInfraredJamming);
|
||||
SimulationManager.UnsubscribeFromEvent<SmokeScreenEvent>(OnSmokeScreen);
|
||||
lastTargetPosition = null; // Add reset to null
|
||||
HasTarget = false;
|
||||
HasGuidance = false;
|
||||
GuidanceAcceleration = Vector3D.Zero;
|
||||
// Optionally reset timers?
|
||||
// targetLostTimer = 0;
|
||||
// lockConfirmationTimer = 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -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
|
||||
/// </remarks>
|
||||
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}";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -58,32 +58,16 @@ namespace ThreatSource.Guidance
|
||||
/// </remarks>
|
||||
public class InfraredTargetRecognizer
|
||||
{
|
||||
/// <summary>
|
||||
/// 仿真管理器实例
|
||||
/// </summary>
|
||||
private readonly ISimulationManager simulationManager;
|
||||
|
||||
/// <summary>
|
||||
/// 目标特征数据库
|
||||
/// </summary>
|
||||
private readonly Dictionary<EquipmentType, TargetFeature> targetFeatures;
|
||||
|
||||
/// <summary>
|
||||
/// 识别阈值
|
||||
/// </summary>
|
||||
private const double RECOGNITION_THRESHOLD = 0.7;
|
||||
|
||||
/// <summary>
|
||||
/// 背景辐射强度,用于阈值计算
|
||||
/// </summary>
|
||||
private const double BACKGROUND_INTENSITY = 0.0001;
|
||||
|
||||
/// <summary>
|
||||
/// 初始化红外图像目标识别器
|
||||
/// </summary>
|
||||
public InfraredTargetRecognizer(ISimulationManager simulationManager)
|
||||
public InfraredTargetRecognizer()
|
||||
{
|
||||
this.simulationManager = simulationManager;
|
||||
// 初始化目标特征数据库 - 使用相对特征值
|
||||
targetFeatures = new Dictionary<EquipmentType, TargetFeature>
|
||||
{
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -20,22 +20,22 @@ namespace ThreatSource.Guidance
|
||||
public class LaserBeamRiderGuidanceSystem : BasicGuidanceSystem
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取或设置激光源位置
|
||||
/// 获取或设置激光源位置 (使用可空类型)
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 记录激光发射源的三维位置
|
||||
/// 用于计算导弹与激光束的相对位置
|
||||
/// </remarks>
|
||||
private Vector3D LaserSourcePosition { get; set; }
|
||||
private Vector3D? LaserSourcePosition { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取或设置激光方向
|
||||
/// 获取或设置激光方向 (使用可空类型)
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 记录激光束的传播方向
|
||||
/// 用于计算导弹与激光束的偏差
|
||||
/// </remarks>
|
||||
private Vector3D LaserDirection { get; set; }
|
||||
private Vector3D? LaserDirection { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取或设置激光指示器激光功率,单位:瓦特
|
||||
@ -46,36 +46,6 @@ namespace ThreatSource.Guidance
|
||||
/// </remarks>
|
||||
public double LaserPower { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 最小可探测功率,单位:瓦特
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 定义了探测器的灵敏度阈值
|
||||
/// 低于此值时无法有效探测
|
||||
/// 典型值为1e-10瓦
|
||||
/// </remarks>
|
||||
private const double MinDetectablePower = 1e-10;
|
||||
|
||||
/// <summary>
|
||||
/// 探测器直径,单位:米
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 定义了探测器的物理尺寸
|
||||
/// 影响系统的接收能力
|
||||
/// 典型值为0.03米
|
||||
/// </remarks>
|
||||
private const double DetectorDiameter = 0.03;
|
||||
|
||||
/// <summary>
|
||||
/// 控制场直径,单位:米
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 定义了有效制导范围
|
||||
/// 超出此范围将失去制导
|
||||
/// 典型值为6米
|
||||
/// </remarks>
|
||||
private const double ControlFieldDiameter = 6.0;
|
||||
|
||||
/// <summary>
|
||||
/// 上一次的误差向量
|
||||
/// </summary>
|
||||
@ -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<LaserJammingEvent>(OnLaserJamming);
|
||||
SimulationManager.SubscribeToEvent<LaserBeamStartEvent>(OnLaserBeamStart);
|
||||
SimulationManager.SubscribeToEvent<LaserBeamEvent>(OnLaserBeamStart);
|
||||
SimulationManager.SubscribeToEvent<LaserBeamStopEvent>(OnLaserBeamStop);
|
||||
}
|
||||
|
||||
@ -217,7 +185,7 @@ namespace ThreatSource.Guidance
|
||||
base.Deactivate();
|
||||
// 取消订阅事件
|
||||
SimulationManager.UnsubscribeFromEvent<LaserJammingEvent>(OnLaserJamming);
|
||||
SimulationManager.UnsubscribeFromEvent<LaserBeamStartEvent>(OnLaserBeamStart);
|
||||
SimulationManager.UnsubscribeFromEvent<LaserBeamEvent>(OnLaserBeamStart);
|
||||
SimulationManager.UnsubscribeFromEvent<LaserBeamStopEvent>(OnLaserBeamStop);
|
||||
}
|
||||
|
||||
@ -350,10 +318,11 @@ namespace ThreatSource.Guidance
|
||||
/// </remarks>
|
||||
public void DeactivateLaserBeam()
|
||||
{
|
||||
LaserSourcePosition = Vector3D.Zero;
|
||||
LaserDirection = Vector3D.Zero;
|
||||
LaserSourcePosition = null;
|
||||
LaserDirection = null;
|
||||
LaserPower = 0;
|
||||
HasGuidance = false;
|
||||
LaserIlluminationOn = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -411,11 +380,16 @@ namespace ThreatSource.Guidance
|
||||
/// </remarks>
|
||||
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
|
||||
/// - 合成最终制导指令
|
||||
/// - 应用低通滤波
|
||||
/// </remarks>
|
||||
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");
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 处理系统被干扰的事件
|
||||
/// </summary>
|
||||
@ -621,7 +587,10 @@ namespace ThreatSource.Guidance
|
||||
/// </remarks>
|
||||
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}";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -637,16 +606,14 @@ namespace ThreatSource.Guidance
|
||||
/// </remarks>
|
||||
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
|
||||
/// 处理激光波束开始事件
|
||||
/// </summary>
|
||||
/// <param name="evt">激光波束开始事件</param>
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -24,13 +24,13 @@ namespace ThreatSource.Guidance
|
||||
private readonly LaserSemiActiveGuidanceConfig config;
|
||||
|
||||
/// <summary>
|
||||
/// 获取或设置目标位置
|
||||
/// 获取或设置目标位置 (使用可空类型)
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 记录当前跟踪目标的三维位置
|
||||
/// 用于制导计算
|
||||
/// </remarks>
|
||||
private Vector3D TargetPosition { get; set; }
|
||||
private Vector3D? TargetPosition { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取或设置接收到的激光功率
|
||||
@ -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<LaserDecoyEvent>(OnLaserDecoy);
|
||||
SimulationManager.UnsubscribeFromEvent<LaserDecoyStopEvent>(OnLaserDecoyStop);
|
||||
TargetPosition = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -261,6 +261,7 @@ namespace ThreatSource.Guidance
|
||||
LaserIlluminationOn = false;
|
||||
HasGuidance = false; // 禁用制导
|
||||
PreviousGuidanceAcceleration = Vector3D.Zero; // 重置历史加速度
|
||||
TargetPosition = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -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
|
||||
/// </remarks>
|
||||
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();
|
||||
|
||||
// 计算当前导弹前向方向
|
||||
|
||||
@ -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();
|
||||
|
||||
/// <summary>
|
||||
/// 上一次探测到的目标位置
|
||||
/// 上一次探测到的目标位置 (使用可空类型)
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 记录目标的历史位置
|
||||
/// 用于计算目标速度
|
||||
/// </remarks>
|
||||
private Vector3D lastTargetPosition;
|
||||
private Vector3D? lastTargetPosition { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 上一次探测到的目标速度
|
||||
/// 上一次探测到的目标速度 (使用可空类型)
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 记录目标的历史速度
|
||||
/// 用于计算目标速度
|
||||
/// </remarks>
|
||||
private Vector3D lastTargetVelocity;
|
||||
private Vector3D? lastTargetVelocity { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 目标丢失计时器
|
||||
@ -134,6 +133,10 @@ namespace ThreatSource.Guidance
|
||||
/// </summary>
|
||||
private double maxScanRadius => config.FieldOfViewAngle * Math.PI / 180.0 / 2;
|
||||
|
||||
/// <summary>
|
||||
/// 当前视线的烟幕透过率 (0.0 - 1.0)
|
||||
/// </summary>
|
||||
private double _currentSmokeTransmittance = 1.0;
|
||||
|
||||
|
||||
/// <summary>
|
||||
@ -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<MillimeterWaveJammingEvent>(OnMillimeterWaveJamming);
|
||||
}
|
||||
// 添加对烟幕事件的订阅
|
||||
SimulationManager.SubscribeToEvent<SmokeScreenEvent>(OnSmokeScreen);
|
||||
}
|
||||
base.Activate();
|
||||
SwitchToSearchMode();
|
||||
}
|
||||
@ -228,11 +232,15 @@ namespace ThreatSource.Guidance
|
||||
{
|
||||
IsActive = false;
|
||||
SimulationManager.UnsubscribeFromEvent<MillimeterWaveJammingEvent>(OnMillimeterWaveJamming);
|
||||
// 添加取消对烟幕事件的订阅
|
||||
SimulationManager.UnsubscribeFromEvent<SmokeScreenEvent>(OnSmokeScreen);
|
||||
}
|
||||
base.Deactivate();
|
||||
HasTarget = false;
|
||||
HasGuidance = false;
|
||||
GuidanceAcceleration = Vector3D.Zero;
|
||||
lastTargetPosition = null;
|
||||
lastTargetVelocity = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -265,22 +273,77 @@ namespace ThreatSource.Guidance
|
||||
Debug.WriteLine($"毫米波导引头系统干扰状态 - IsJammed: {IsJammed}, 干扰功率: {evt.JammingPower}W, 抗性阈值: {config.JammingResistanceThreshold}W");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 处理烟幕事件,触发干扰应用
|
||||
/// </summary>
|
||||
/// <param name="evt">烟幕事件</param>
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 处理系统被干扰的事件
|
||||
/// </summary>
|
||||
/// <param name="parameters">干扰参数</param>
|
||||
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
|
||||
/// <param name="type">被清除的干扰类型</param>
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -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
|
||||
/// </remarks>
|
||||
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;
|
||||
|
||||
|
||||
@ -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等关键信息
|
||||
/// </remarks>
|
||||
private void PublishLaserBeamStartEvent()
|
||||
private void PublishLaserBeamEvent()
|
||||
{
|
||||
PublishEvent(new LaserBeamStartEvent
|
||||
PublishEvent(new LaserBeamEvent
|
||||
{
|
||||
LaserBeamRiderId = Id
|
||||
});
|
||||
|
||||
@ -96,26 +96,7 @@ namespace ThreatSource.Missile
|
||||
/// - 更新波束参数
|
||||
/// - 开始波束跟踪
|
||||
/// </remarks>
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 处理激光束更新事件
|
||||
/// </summary>
|
||||
/// <param name="evt">激光束更新事件数据</param>
|
||||
/// <remarks>
|
||||
/// 处理过程:
|
||||
/// - 验证激光驾束仪
|
||||
/// - 更新波束位置和方向
|
||||
/// - 更新制导参数
|
||||
/// </remarks>
|
||||
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<LaserBeamStartEvent>(OnLaserBeamStart);
|
||||
SimulationManager.SubscribeToEvent<LaserBeamEvent>(OnLaserBeamEvent);
|
||||
SimulationManager.SubscribeToEvent<LaserBeamStopEvent>(OnLaserBeamStop);
|
||||
SimulationManager.SubscribeToEvent<LaserBeamUpdateEvent>(OnLaserBeamUpdate);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -255,9 +235,8 @@ namespace ThreatSource.Missile
|
||||
// 停用制导系统
|
||||
guidanceSystem.Deactivate();
|
||||
// 取消订阅波束事件
|
||||
SimulationManager.UnsubscribeFromEvent<LaserBeamStartEvent>(OnLaserBeamStart);
|
||||
SimulationManager.UnsubscribeFromEvent<LaserBeamEvent>(OnLaserBeamEvent);
|
||||
SimulationManager.UnsubscribeFromEvent<LaserBeamStopEvent>(OnLaserBeamStop);
|
||||
SimulationManager.UnsubscribeFromEvent<LaserBeamUpdateEvent>(OnLaserBeamUpdate);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@ -242,42 +242,7 @@ namespace ThreatSource.Simulation
|
||||
/// 用于通知系统激光波束开始照射
|
||||
/// 触发时机:激光驾束仪开始工作时
|
||||
/// </remarks>
|
||||
public class LaserBeamStartEvent : SimulationEvent
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取或设置激光驾束仪的ID
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 标识发出激光波束的驾束仪设备
|
||||
/// </remarks>
|
||||
public string? LaserBeamRiderId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取或设置波束功率
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 激光波束的发射功率
|
||||
/// </remarks>
|
||||
public double BeamPower { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取或设置激光编码配置
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 包含激光信号的编码信息
|
||||
/// 用于抗干扰和安全识别
|
||||
/// </remarks>
|
||||
public LaserCodeConfig? LaserCodeConfig { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 激光波束更新事件,表示激光波束状态的更新
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 用于实时更新激光波束的状态
|
||||
/// 在波束照射过程中周期性触发
|
||||
/// </remarks>
|
||||
public class LaserBeamUpdateEvent : SimulationEvent
|
||||
public class LaserBeamEvent : SimulationEvent
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取或设置激光驾束仪的ID
|
||||
|
||||
@ -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"))
|
||||
|
||||
Loading…
Reference in New Issue
Block a user