把制导系统引用添加到导弹基类中,并完善了制导状态的判断逻辑,完善了导引头的朝向控制逻辑和导弹的朝向控制逻辑

This commit is contained in:
Tian jianyong 2025-05-27 16:04:26 +08:00
parent 982ceffb73
commit 612b8638f1
27 changed files with 615 additions and 317 deletions

View File

@ -21,6 +21,8 @@
## [1.1.22] - 2025-05-26
- 完善了集成测试的菜单逻辑,干扰器正常工作了
- 增加了导弹生命周期的状态事件和制导事件
- 把制导系统引用添加到导弹基类中,并完善了制导状态的判断逻辑
- 完善了导引头的朝向控制逻辑和导弹的朝向控制逻辑
## [1.1.21] - 2025-05-24
- 增加了升力加速度的计算

View File

@ -1 +0,0 @@

View File

@ -61,7 +61,8 @@ namespace ThreatSource.Tests.Indicator
_infraredTracker = new InfraredTracker(
"tracker1",
"target1",
"target1",
"missile1",
_config,
trackerInitialMotion,
_simulationManager
@ -74,7 +75,7 @@ namespace ThreatSource.Tests.Indicator
{
Assert.Equal("tracker1", _infraredTracker.Id);
Assert.Equal("target1", _infraredTracker.TargetId);
Assert.Null(_infraredTracker.MissileId);
Assert.Equal("missile1", _infraredTracker.MissileId);
Assert.False(_infraredTracker.IsActive);
}
@ -234,7 +235,7 @@ namespace ThreatSource.Tests.Indicator
_infraredTracker.Update(0.1);
// Assert
Assert.Null(_infraredTracker.MissileId);
Assert.Equal("missile1", _infraredTracker.MissileId);
}
}
}

View File

@ -45,6 +45,7 @@ namespace ThreatSource.Tests.Jamming
_infraredTracker = new InfraredTracker(
"tracker1",
"target1",
"missile1",
config,
motionParameters,
_simulationManager

View File

@ -21,7 +21,7 @@ HitProbability = 0.9
SelfDestructHeight = 0.0
CruiseAttackAngle = 5.0 # 巡航阶段攻角 (度)
GuidanceSeekingAngle = 15.0 # 制导阶段导引头下视角 (度)
InfraredRadiationIntensity = 96.0 # 红外辐射强度 (瓦特/球面度)
InfraredRadiationIntensity = 96.0 # 红外辐射强度 (瓦特/球面度)
UltravioletRadiationIntensity = 100.0 # 紫外辐射强度 (瓦特/球面度)
# --- 复合制导特定属性 ---
CompositeWorkMode = "Serial" # 工作模式Serial (串行) 或 Parallel (并行)

View File

@ -21,7 +21,7 @@ HitProbability = 0.9
SelfDestructHeight = 0.0
CruiseAttackAngle = 5.0 # 巡航阶段攻角 (度)
GuidanceSeekingAngle = 15.0 # 制导阶段导引头下视角 (度)
InfraredRadiationIntensity = 96.0 # 红外辐射强度 (瓦特/球面度)
InfraredRadiationIntensity = 96.0 # 红外辐射强度 (瓦特/球面度)
UltravioletRadiationIntensity = 100.0 # 紫外辐射强度 (瓦特/球面度)
# --- 复合制导特定属性 ---
CompositeWorkMode = "Serial" # 工作模式Serial (串行) 或 Parallel (并行)

View File

@ -164,6 +164,7 @@ namespace ThreatSource.Data
IndicatorType.InfraredTracker when data.InfraredTrackerConfig != null => new InfraredTracker(
indicatorId,
targetId,
missileId,
data.InfraredTrackerConfig,
motionParameters,
_simulationManager

View File

@ -25,7 +25,12 @@ namespace ThreatSource.Guidance
/// <summary>
/// 干扰处理组件
/// </summary>
protected readonly JammableComponent _jammingComponent;
protected readonly JammableComponent JammingComponent;
/// <summary>
/// 标记是否保持当前朝向不被导弹状态覆盖
/// </summary>
protected bool PreserveOrientation { get; set; } = false;
/// <summary>
/// 获取设备支持的干扰类型
@ -40,12 +45,12 @@ namespace ThreatSource.Guidance
/// <summary>
/// 获取设备当前是否处于被干扰状态
/// </summary>
public bool IsJammed => _jammingComponent.IsJammed;
public bool IsJammed => JammingComponent.IsJammed;
/// <summary>
/// 获取设备当前是否正受到有效的阻塞式干扰
/// </summary>
public bool IsBlockingJammed => _jammingComponent.IsBlockingJammed;
public bool IsBlockingJammed => JammingComponent.IsBlockingJammed;
/// <summary>
/// 获取或设置父实体ID
@ -87,13 +92,18 @@ namespace ThreatSource.Guidance
public double ProportionalNavigationCoefficient { get; set; }
/// <summary>
/// 获取或设置制导加速度,单位:米/平方秒
/// 制导加速度向量
/// </summary>
/// <remarks>
/// 存储计算得到的制导指令
/// 用于控制导弹的运动轨迹
/// 由子类计算得出的制导加速度
/// 用于导弹的轨迹控制
/// </remarks>
protected Vector3D GuidanceAcceleration { get; set; }
/// <summary>
/// 标记制导阶段朝向是否已初始化
/// </summary>
private bool hasInitializedGuidanceOrientation = false;
/// <summary>
/// 初始化基础制导系统的新实例
@ -126,32 +136,39 @@ namespace ThreatSource.Guidance
ProportionalNavigationCoefficient = proportionalNavigationCoefficient;
// 初始化干扰处理组件
_jammingComponent = new JammableComponent(
JammingComponent = new JammableComponent(
positionProvider: () => base.KState.Position
);
// Subscribe to the events instead
_jammingComponent.JammingApplied += HandleJammingApplied;
_jammingComponent.JammingCleared += HandleJammingCleared;
JammingComponent.JammingApplied += HandleJammingApplied;
JammingComponent.JammingCleared += HandleJammingCleared;
// 子类需要在构造函数中设置支持的干扰类型和阈值
}
/// <summary>
/// 激活制导系统 (基类处理干扰事件订阅)
/// 激活制导系统
/// </summary>
/// <remarks>
/// 激活后,制导系统开始工作
/// 可以接收仿真更新
/// </remarks>
public override void Activate()
{
if (!IsActive)
{
// 重置制导阶段朝向初始化标志
hasInitializedGuidanceOrientation = false;
if (!IsActive)
{
IsActive = true;
// 统一订阅 JammingEvent
SimulationManager.SubscribeToEvent<JammingEvent>(HandleJammingEvent);
SimulationManager.SubscribeToEvent<JammingStoppedEvent>(HandleJammingStoppedEvent);
// 子类应在此方法中调用 base.Activate() 并订阅其他需要的事件
}
// 调用 SimulationElement 的基类 Activate (如果存在)
// base.Activate(); // SimulationElement 似乎没有公开的 Activate
}
// 调用 SimulationElement 的基类 Activate (如果存在)
// base.Activate(); // SimulationElement 似乎没有公开的 Activate
}
/// <summary>
@ -183,10 +200,35 @@ namespace ThreatSource.Guidance
{
if (SimulationManager.GetEntityById(MissileId) is BaseMissile missile)
{
KState = missile.KState;
// 同步位置、速度和速度大小
KState.Position = missile.KState.Position;
KState.Velocity = missile.KState.Velocity;
KState.Speed = missile.KState.Speed;
// 阶段性朝向管理
var missileStageField = missile.GetType().GetField("currentStage",
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
if (missileStageField != null)
{
var currentStage = missileStageField.GetValue(missile);
string stageName = currentStage?.ToString() ?? "Unknown";
if (stageName == "Launch" || stageName == "Cruise")
{
// 发射和巡航阶段:导引头朝向与导弹朝向一致
KState.Orientation = missile.KState.Orientation;
}
else if (stageName == "Guidance")
{
// 制导阶段:朝向管理由导弹统一负责,制导系统不再自己初始化朝向
// 制导阶段的朝向调整由子类的UpdateSeekerOrientation()等方法控制
}
}
}
// 更新干扰状态
_jammingComponent.UpdateJammingStatus(deltaTime);
JammingComponent.UpdateJammingStatus(deltaTime);
}
/// <summary>
@ -280,7 +322,7 @@ namespace ThreatSource.Guidance
/// <param name="threshold">阈值值(单位:瓦特)</param>
protected void SetJammingThreshold(JammingType type, double threshold)
{
_jammingComponent.SetJammingThreshold(type, threshold);
JammingComponent.SetJammingThreshold(type, threshold);
}
/// <summary>
@ -289,7 +331,7 @@ namespace ThreatSource.Guidance
/// <param name="type">干扰类型</param>
protected void AddSupportedJammingType(JammingType type)
{
_jammingComponent.AddSupportedJammingType(type);
JammingComponent.AddSupportedJammingType(type);
}
/// <summary>
@ -299,7 +341,7 @@ namespace ThreatSource.Guidance
/// <param name="threshold">干扰阈值(单位:瓦特)</param>
protected void AddSupportedBlockingJammingType(JammingType type, double threshold)
{
_jammingComponent.AddSupportedBlockingJammingType(type, threshold);
JammingComponent.AddSupportedBlockingJammingType(type, threshold);
}
/// <summary>
@ -308,7 +350,7 @@ namespace ThreatSource.Guidance
/// <param name="parameters">干扰参数</param>
public virtual void ApplyJamming(JammingParameters parameters)
{
_jammingComponent.ApplyJamming(parameters);
JammingComponent.ApplyJamming(parameters);
}
/// <summary>
@ -317,7 +359,7 @@ namespace ThreatSource.Guidance
/// <param name="parameters">干扰参数</param>
public virtual void ClearJamming(JammingParameters parameters)
{
_jammingComponent.ClearJamming(parameters);
JammingComponent.ClearJamming(parameters);
}
/// <summary>
@ -342,7 +384,7 @@ namespace ThreatSource.Guidance
protected virtual void HandleJammingCleared(JammingParameters parameters)
{
// 检查整体干扰状态
if (!_jammingComponent.IsJammed)
if (!JammingComponent.IsJammed)
{
HasGuidance = true;
Trace.TraceInformation($"[{GetType().Name}] 所有干扰已清除。");
@ -363,10 +405,10 @@ namespace ThreatSource.Guidance
/// </remarks>
protected void InitializeJamming(double jammingResistanceThreshold, IEnumerable<JammingType> supportedTypes, IEnumerable<JammingType> supportedBlockingTypes)
{
_jammingComponent.LoadJammingConfigFromThreshold(jammingResistanceThreshold, supportedBlockingTypes);
JammingComponent.LoadJammingConfigFromThreshold(jammingResistanceThreshold, supportedBlockingTypes);
foreach (var type in supportedTypes)
{
_jammingComponent.AddSupportedJammingType(type);
JammingComponent.AddSupportedJammingType(type);
}
}
}

View File

@ -1,6 +1,7 @@
using ThreatSource.Utils;
using ThreatSource.Simulation;
using ThreatSource.Jammer;
using System.Diagnostics;
namespace ThreatSource.Guidance
{
@ -113,6 +114,7 @@ namespace ThreatSource.Guidance
/// 更新过程:
/// - 更新基类状态
/// - 计算制导加速度
/// - 更新导引头朝向
/// </remarks>
public override void Update(double deltaTime)
{
@ -122,6 +124,9 @@ namespace ThreatSource.Guidance
if (HasGuidance)
{
CalculateGuidanceAcceleration(deltaTime);
// 调整导引头朝向目标方向
UpdateSeekerOrientation();
}
else
{
@ -143,6 +148,29 @@ namespace ThreatSource.Guidance
}
}
/// <summary>
/// 更新导引头朝向,使其指向目标方向
/// </summary>
/// <remarks>
/// 在制导阶段,导引头需要指向目标方向以保持跟踪
/// </remarks>
private void UpdateSeekerOrientation()
{
if (LastTrackerToTargetVector.HasValue && LastTrackerToMissileVector.HasValue)
{
// 计算从导弹到目标的方向向量
Vector3D toTarget = (LastTrackerToTargetVector.Value - LastTrackerToMissileVector.Value).Normalize();
// 将方向向量转换为朝向
Orientation targetOrientation = Orientation.FromVector(toTarget);
// 更新导引头朝向
KState.Orientation = targetOrientation;
Debug.WriteLine($"[INFRARED_COMMAND] 导引头朝向已调整指向目标: {targetOrientation}");
}
}
/// <summary>
/// 接收并处理制导指令
/// </summary>

View File

@ -229,14 +229,14 @@ namespace ThreatSource.Guidance
}
/// <summary>
/// 更新引导系统的状态和计算结果
/// 更新制导系统状态
/// </summary>
/// <param name="deltaTime">自上次更新以来的时间间隔,单位:秒</param>
/// <param name="deltaTime">时间步长,单位:秒</param>
/// <remarks>
/// 更新过程:
/// - 探测目标位置
/// - 计算目标速度
/// - 生成制导指令
/// - 尝试探测和识别目标
/// - 计算制导加速度
/// - 更新导引头朝向Track和Lock模式
/// - 限制最大加速度
/// </remarks>
public override void Update(double deltaTime)
@ -271,6 +271,12 @@ namespace ThreatSource.Guidance
}
HasGuidance = true;
// 在Track和Lock模式下持续调整导引头朝向
if (currentMode == WorkMode.Track || currentMode == WorkMode.Lock)
{
UpdateSeekerOrientation();
}
if (currentMode == WorkMode.Lock) {
lockModeTargetLostTimer = 0;
}
@ -353,6 +359,7 @@ namespace ThreatSource.Guidance
/// - 设置小视场角
/// - 更新图像生成器参数
/// - 提高目标识别概率要求
/// - 调整导引头朝向目标
/// </remarks>
public void SwitchToTrackMode()
{
@ -371,6 +378,10 @@ namespace ThreatSource.Guidance
backgroundIntensity: config.BackgroundIntensity,
wavelength: config.Wavelength
);
// 调整导引头朝向目标
UpdateSeekerOrientation();
Debug.WriteLine($"切换到跟踪模式, 视场角: {config.TrackFieldOfView} 度");
}
@ -382,14 +393,42 @@ namespace ThreatSource.Guidance
/// - 设置锁定状态
/// - 保持当前图像生成器参数
/// - 不再进行目标类型识别
/// - 调整导引头朝向目标
/// </remarks>
public void SwitchToLockMode()
{
currentMode = WorkMode.Lock;
lockModeTargetLostTimer = 0;
// 调整导引头朝向目标
UpdateSeekerOrientation();
Debug.WriteLine("切换到锁定模式 - 目标类型确认");
}
/// <summary>
/// 更新导引头朝向,使其指向当前跟踪的目标
/// </summary>
/// <remarks>
/// 在Track和Lock模式下导引头需要持续指向目标以保持跟踪
/// </remarks>
private void UpdateSeekerOrientation()
{
if (currentlyTrackedTargetId != null && LastTargetPosition.HasValue)
{
// 计算从导弹到目标的方向向量
Vector3D toTarget = (LastTargetPosition.Value - KState.Position).Normalize();
// 将方向向量转换为朝向
Orientation targetOrientation = Orientation.FromVector(toTarget);
// 更新导引头朝向
KState.Orientation = targetOrientation;
Debug.WriteLine($"[IR IMAGING] 导引头朝向已调整指向目标 {currentlyTrackedTargetId}: {targetOrientation}");
}
}
/// <summary>
/// 尝试探测和识别目标
/// </summary>
@ -415,23 +454,39 @@ namespace ThreatSource.Guidance
double searchFovRadians = config.SearchFieldOfView * Math.PI / 180.0;
double trackFovRadians = config.TrackFieldOfView * Math.PI / 180.0;
// 获取导引头的朝向向量(搜索中心线方向)
Vector3D missileDirection = KState.Orientation.ToVector();
Debug.WriteLine($"[IR IMAGING DEBUG] 导弹位置: {missilePosition:F2}, 导引头朝向: {missileDirection:F3}");
Debug.WriteLine($"[IR IMAGING DEBUG] 搜索视场角: {config.SearchFieldOfView}°, 最大探测距离: {config.MaxDetectionRange}m");
foreach (var element in SimulationManager.GetEntitiesByType<SimulationElement>())
{
if (element is BaseEquipment currentEntity)
{
Vector3D toTarget = currentEntity.KState.Position - missilePosition;
double distanceToCurrentEntity = toTarget.Magnitude();
Debug.WriteLine($"[IR IMAGING DEBUG] 检查目标 {currentEntity.Id}: 位置={currentEntity.KState.Position:F2}, 距离={distanceToCurrentEntity:F2}m");
var (isGeometricallyObscured, overallTransmittance) = EvaluateSmokeImpact(missilePosition, currentEntity);
bool isWithinFovAndRange;
double relevantFovRadians = currentMode == WorkMode.Search ? searchFovRadians : trackFovRadians;
// 使用导引头朝向而不是速度向量进行视场角检查
double angleToTarget = Math.Acos(Vector3D.DotProduct(toTarget.Normalize(), missileDirection));
double angleToTargetDegrees = angleToTarget * 180.0 / Math.PI;
double fovHalfAngleDegrees = relevantFovRadians / 2 * 180.0 / Math.PI;
isWithinFovAndRange = distanceToCurrentEntity <= config.MaxDetectionRange &&
Math.Acos(Vector3D.DotProduct(toTarget.Normalize(), missileVelocity.Normalize())) <= (relevantFovRadians / 2);
angleToTarget <= (relevantFovRadians / 2);
Debug.WriteLine($"[IR IMAGING DEBUG] 目标 {currentEntity.Id}: 角度={angleToTargetDegrees:F2}°, FOV半角={fovHalfAngleDegrees:F2}°, 在FOV内={angleToTarget <= (relevantFovRadians / 2)}, 在距离内={distanceToCurrentEntity <= config.MaxDetectionRange}");
if (!isWithinFovAndRange || isGeometricallyObscured)
{
Debug.WriteLine($"[IR IMAGING DEBUG] 目标 {currentEntity.Id} 不满足基本条件: FOV={isWithinFovAndRange}, 遮挡={isGeometricallyObscured}");
// 如果是 Search 模式下的焦点目标,但它不再满足基本条件,则清除焦点
if (currentMode == WorkMode.Search && currentEntity.Id == searchModeFocusCandidateId)
{
@ -442,6 +497,8 @@ namespace ThreatSource.Guidance
continue; // 不满足基本FOV、距离或被烟幕遮挡处理下一个实体
}
Debug.WriteLine($"[IR IMAGING DEBUG] 目标 {currentEntity.Id} 通过基本检查,进入模式处理");
switch (currentMode)
{
case WorkMode.Search:
@ -474,7 +531,7 @@ namespace ThreatSource.Guidance
if (successRate >= COMMON_RECOGNITION_SUCCESS_RATE_THRESHOLD)
{
// 检查是否也在Track模式的FOV内 (因为search FOV可能比track FOV宽)
double angleToTargetForTrackCheck = Math.Acos(Vector3D.DotProduct(toTarget.Normalize(), missileVelocity.Normalize()));
double angleToTargetForTrackCheck = Math.Acos(Vector3D.DotProduct(toTarget.Normalize(), missileDirection));
if (angleToTargetForTrackCheck <= (trackFovRadians / 2))
{
currentlyTrackedTargetId = searchModeFocusCandidateId;

View File

@ -339,6 +339,7 @@ namespace ThreatSource.Guidance
/// - 检查激光照射状态
/// - 更新制导状态
/// - 计算制导指令
/// - 更新导引头朝向
/// - 更新输出参数
/// </remarks>
public override void Update(double deltaTime)
@ -352,20 +353,26 @@ namespace ThreatSource.Guidance
if (HasGuidance)
{
CalculateGuidanceAcceleration(deltaTime);
// 调整导引头朝向激光束方向
UpdateSeekerOrientation();
}
else
{
// 搜索阶段:制导加速度清零,朝向由基类管理
GuidanceAcceleration = Vector3D.Zero;
}
}
else
{
// 无激光束照射时,清除制导
HasGuidance = false;
GuidanceAcceleration = Vector3D.Zero;
}
}
else
{
// 被阻塞干扰时,清除制导
HasGuidance = false;
GuidanceAcceleration = Vector3D.Zero;
}
@ -519,6 +526,26 @@ namespace ThreatSource.Guidance
LastGuidanceAcceleration = GuidanceAcceleration;
}
/// <summary>
/// 更新导引头朝向,使其指向激光束方向
/// </summary>
/// <remarks>
/// 在制导阶段,导引头需要指向激光束方向以保持跟踪
/// </remarks>
private void UpdateSeekerOrientation()
{
if (LaserDirection.HasValue)
{
// 将激光束方向转换为朝向
Orientation beamOrientation = Orientation.FromVector(LaserDirection.Value);
// 更新导引头朝向
KState.Orientation = beamOrientation;
Debug.WriteLine($"[LASER_BEAM_RIDER] 导引头朝向已调整指向激光束: {beamOrientation}");
}
}
/// <summary>
/// 处理系统被干扰的事件
/// </summary>

View File

@ -387,15 +387,20 @@ namespace ThreatSource.Guidance
if (HasGuidance)
{
CalculateGuidanceAcceleration(deltaTime);
// 跟踪阶段:调整导引头朝向目标
UpdateSeekerOrientation();
}
else
{
// 搜索阶段:制导加速度清零,朝向由基类管理
GuidanceAcceleration = Vector3D.Zero;
PreviousGuidanceAcceleration = Vector3D.Zero; // 重置历史加速度
}
}
else
{
// 无激光照射或被阻塞干扰时,清除制导
HasGuidance = false;
GuidanceAcceleration = Vector3D.Zero;
PreviousGuidanceAcceleration = Vector3D.Zero; // 重置历史加速度
@ -547,18 +552,19 @@ namespace ThreatSource.Guidance
/// <param name="targetPos">目标位置</param>
/// <returns>角度偏差,单位:弧度</returns>
/// <remarks>
/// 计算目标方向与导弹当前朝向的夹角
/// 计算目标方向与导引头朝向的夹角用于FOV检查
/// 导引头可能相对弹体有下视角,用于扩大搜索范围
/// </remarks>
private double CalculateAngleDeviation(Vector3D targetPos)
{
// 计算目标方向
Vector3D targetDirection = (targetPos - KState.Position).Normalize();
// 计算当前导弹朝向
Vector3D missileDirection = KState.Velocity.Normalize();
// 计算当前导引头朝向(可能相对弹体有下视角)
Vector3D seekerDirection = KState.Orientation.ToVector();
// 计算夹角
double dotProduct = Vector3D.DotProduct(targetDirection, missileDirection);
double dotProduct = Vector3D.DotProduct(targetDirection, seekerDirection);
dotProduct = Math.Max(-1.0, Math.Min(1.0, dotProduct)); // 确保在[-1,1]范围内
return Math.Acos(dotProduct);
@ -666,6 +672,29 @@ namespace ThreatSource.Guidance
PreviousGuidanceAcceleration = GuidanceAcceleration;
}
/// <summary>
/// 更新导引头朝向,使其指向当前目标
/// </summary>
/// <remarks>
/// 在制导阶段,导引头需要指向目标以保持跟踪
/// </remarks>
private void UpdateSeekerOrientation()
{
if (TargetPosition.HasValue)
{
// 计算从导弹到目标的方向向量
Vector3D toTarget = (TargetPosition.Value - KState.Position).Normalize();
// 将方向向量转换为朝向
Orientation targetOrientation = Orientation.FromVector(toTarget);
// 更新导引头朝向
KState.Orientation = targetOrientation;
Debug.WriteLine($"[LASER_SEMI_ACTIVE] 导引头朝向已调整指向目标: {targetOrientation}");
}
}
/// <summary>
/// 获取四象限探测器的水平误差
/// </summary>

View File

@ -235,6 +235,9 @@ namespace ThreatSource.Guidance
activeDetectionHistory.Clear();
// 调整导引头朝向目标
UpdateSeekerOrientation();
Trace.TraceInformation($"切换到跟踪模式,波束宽度: {config.TrackBeamWidth}度");
}
@ -245,9 +248,36 @@ namespace ThreatSource.Guidance
{
currentMode = WorkMode.Lock;
HasGuidance = true;
// 调整导引头朝向目标
UpdateSeekerOrientation();
Trace.TraceInformation("切换到锁定模式 - 目标锁定成功");
}
/// <summary>
/// 更新导引头朝向,使其指向当前跟踪的目标
/// </summary>
/// <remarks>
/// 在Track和Lock模式下导引头需要持续指向目标以保持跟踪
/// </remarks>
private void UpdateSeekerOrientation()
{
if (currentlyTrackedTargetId != null && LastTargetPosition.HasValue)
{
// 计算从导弹到目标的方向向量
Vector3D toTarget = (LastTargetPosition.Value - KState.Position).Normalize();
// 将方向向量转换为朝向
Orientation targetOrientation = Orientation.FromVector(toTarget);
// 更新导引头朝向
KState.Orientation = targetOrientation;
Debug.WriteLine($"[MMW_GUIDANCE] 导引头朝向已调整指向目标 {currentlyTrackedTargetId}: {targetOrientation}");
}
}
/// <summary>
/// 激活制导系统
/// </summary>
@ -550,6 +580,7 @@ namespace ThreatSource.Guidance
/// - 探测目标位置
/// - 计算目标速度
/// - 生成制导指令
/// - 更新导引头朝向Track和Lock模式
/// - 限制最大加速度
/// </remarks>
public override void Update(double deltaTime)
@ -592,6 +623,13 @@ namespace ThreatSource.Guidance
{
GuidanceAcceleration = GuidanceAcceleration.Normalize() * MaxAcceleration;
}
// 在Track和Lock模式下持续调整导引头朝向
if (currentMode == WorkMode.Track || currentMode == WorkMode.Lock)
{
UpdateSeekerOrientation();
}
Debug.WriteLine($"制导加速度: {GuidanceAcceleration}");
}
else

View File

@ -80,25 +80,4 @@ namespace ThreatSource.Indicator
/// </summary>
Idle
}
/// <summary>
/// 干扰状态枚举,定义了指示器的干扰状态
/// </summary>
/// <remarks>
/// 包含两种基本状态:
/// - Normal正常状态未受到干扰
/// - Jammed干扰状态受到干扰影响
/// 用于干扰状态监控和防护
/// </remarks>
public enum JammingState
{
/// <summary>
/// 正常状态
/// </summary>
Normal,
/// <summary>
/// 干扰状态
/// </summary>
Jammed
}
}

View File

@ -61,6 +61,7 @@ namespace ThreatSource.Indicator
/// </summary>
/// <param name="id">测角仪ID</param>
/// <param name="targetId">目标ID</param>
/// <param name="missileId">要跟踪的导弹ID</param>
/// <param name="config">配置参数</param>
/// <param name="motionParameters">初始运动参数</param>
/// <param name="manager">仿真管理器实例</param>
@ -68,14 +69,15 @@ namespace ThreatSource.Indicator
/// 构造过程:
/// - 初始化基本属性
/// - 设置目标关联
/// - 设置导弹跟踪配置
/// - 配置工作参数
/// - 设置初始状态
/// </remarks>
public InfraredTracker(string id, string targetId, InfraredTrackerConfig config, KinematicState motionParameters, ISimulationManager manager)
public InfraredTracker(string id, string targetId, string missileId, InfraredTrackerConfig config, KinematicState motionParameters, ISimulationManager manager)
: base(id, motionParameters, manager)
{
TargetId = targetId;
MissileId = null;
MissileId = missileId;
this.config = config;
IsTracking = false;
@ -230,13 +232,16 @@ namespace ThreatSource.Indicator
/// <param name="evt">红外热源点亮事件数据</param>
/// <remarks>
/// 处理过程:
/// - 记录导弹ID
/// - 准备开始跟踪
/// - 验证事件来源是否为指定导弹
/// - 开始跟踪
/// </remarks>
private void OnInfraredGuidanceMissileLight(InfraredGuidanceMissileLightEvent evt)
{
// 处理导弹点亮红外热源事件
MissileId = evt.SenderId ?? "";
// 只处理指定导弹的点亮事件
if (evt.SenderId == MissileId)
{
// 导弹点亮红外热源,测角仪开始跟踪
}
}
/// <summary>
@ -245,13 +250,16 @@ namespace ThreatSource.Indicator
/// <param name="evt">红外热源熄灭事件数据</param>
/// <remarks>
/// 处理过程:
/// - 验证导弹ID
/// - 验证事件来源是否为指定导弹
/// - 停止跟踪
/// </remarks>
private void OnInfraredGuidanceMissileLightOff(InfraredGuidanceMissileLightOffEvent evt)
{
// 处理导弹熄灭红外热源事件
if (evt.SenderId == MissileId) StopTracking();
// 只处理指定导弹的熄灭事件
if (evt.SenderId == MissileId)
{
StopTracking();
}
}
/// <summary>

View File

@ -2,6 +2,7 @@ using System.Diagnostics;
using ThreatSource.Simulation;
using ThreatSource.Utils;
using System.Reflection;
using ThreatSource.Guidance;
namespace ThreatSource.Missile
{
@ -49,6 +50,19 @@ namespace ThreatSource.Missile
/// </remarks>
public double EngineBurnTime { get; protected set; }
/// <summary>
/// 获取或设置导弹的制导系统引用
/// </summary>
/// <value>制导系统实例对于没有制导系统的导弹如末敏弹为null</value>
/// <remarks>
/// 提供对制导系统的直接访问:
/// - 可以直接获取制导系统的干扰状态
/// - 可以直接获取制导系统的工作状态
/// - 避免通过SimulationManager查找的开销
/// 对于末敏弹等没有制导系统的导弹此属性为null
/// </remarks>
public BaseGuidanceSystem? GuidanceSystem { get; protected set; }
/// <summary>
/// 获取导弹是否处于制导状态
/// </summary>
@ -57,8 +71,23 @@ namespace ThreatSource.Missile
/// 影响导弹的运动学计算方法
/// 制导状态下使用制导律计算加速度
/// 非制导状态下使用弹道方程计算运动
///
/// 状态判断逻辑:
/// - 如果有制导系统基于制导系统的HasGuidance和干扰状态
/// - 如果无制导系统始终为false如末敏弹
/// </remarks>
public bool IsGuidance { get; protected set; }
public virtual bool IsGuidance
{
get
{
// 如果没有制导系统始终返回false如末敏弹
if (GuidanceSystem == null)
return false;
// 如果有制导系统,基于制导系统状态判断
return GuidanceSystem.HasGuidance && !GuidanceSystem.IsBlockingJammed;
}
}
/// <summary>
/// 获取或设置前一个制导状态
@ -149,6 +178,11 @@ namespace ThreatSource.Missile
/// </summary>
protected MissileFlightStage currentStage = MissileFlightStage.Launch;
/// <summary>
/// 标记是否已完成制导阶段的初始化
/// </summary>
private bool hasInitializedGuidanceStage = false;
/// <summary>
/// 初始化导弹基类的新实例
/// </summary>
@ -178,7 +212,6 @@ namespace ThreatSource.Missile
FlightTime = 0;
FlightDistance = 0;
IsActive = false;
IsGuidance = false;
GuidanceAcceleration = Vector3D.Zero;
LiftAcceleration = Vector3D.Zero;
@ -187,6 +220,19 @@ namespace ThreatSource.Missile
ThrustAcceleration = launchDirection * properties.LaunchAcceleration;
}
/// <summary>
/// 设置导弹的制导系统引用
/// </summary>
/// <param name="guidanceSystem">制导系统实例</param>
/// <remarks>
/// 此方法应在导弹初始化时调用,用于建立导弹与制导系统的关联
/// 对于没有制导系统的导弹(如末敏弹),不需要调用此方法
/// </remarks>
public void SetGuidanceSystem(BaseGuidanceSystem? guidanceSystem)
{
GuidanceSystem = guidanceSystem;
}
/// <summary>
/// 判断是否为末敏弹类型
/// </summary>
@ -300,6 +346,49 @@ namespace ThreatSource.Missile
/// </summary>
protected virtual void OnGuidanceStage(double deltaTime)
{
// 制导阶段初始化:首次进入制导阶段时,将导弹调整为水平飞行
if (!hasInitializedGuidanceStage)
{
// 保持当前偏航角将俯仰角调整为0水平飞行
KState.Orientation = new Orientation(KState.Orientation.Yaw, 0.0, KState.Orientation.Roll);
// 初始化制导系统的导引头朝向
if (GuidanceSystem != null)
{
double seekingAngleRad = Properties.GuidanceSeekingAngle * Math.PI / 180.0;
double newPitch = 0.0 - seekingAngleRad; // 基于水平朝向计算下视角
GuidanceSystem.KState.Orientation = new Orientation(
KState.Orientation.Yaw,
newPitch,
KState.Orientation.Roll
);
Debug.WriteLine($"导弹 {Id}: 初始化制导系统导引头朝向,下视角 {Properties.GuidanceSeekingAngle}度,朝向: {GuidanceSystem.KState.Orientation}");
}
Debug.WriteLine($"导弹 {Id}: 进入制导阶段,调整为水平飞行姿态。新朝向: {KState.Orientation}");
hasInitializedGuidanceStage = true;
}
// 如果有制导系统且制导系统有效,获取制导加速度
if (GuidanceSystem != null && GuidanceSystem.HasGuidance && !GuidanceSystem.IsBlockingJammed)
{
GuidanceAcceleration = GuidanceSystem.GetGuidanceAcceleration();
// 有制导时,导弹朝向跟随速度方向(导弹沿速度方向飞行)
if (KState.Velocity.Magnitude() > 0.1)
{
KState.Orientation = Orientation.FromVector(KState.Velocity.Normalize());
}
}
else
{
// 没有制导系统或制导系统无效时,清零制导加速度
GuidanceAcceleration = Vector3D.Zero;
// 无制导时保持当前朝向(不修改朝向,让搜索继续)
}
// 计算升力加速度。在制导阶段,升力加速度和攻角相关;
LiftAcceleration = LiftModel.CalculateLiftAcceleration(KState.Orientation.Pitch * 180 / Math.PI);
}
@ -345,19 +434,6 @@ namespace ThreatSource.Missile
(KState.Position, KState.Velocity) = MotionAlgorithm.CalculateBallisticMotion(KState.Position, KState.Velocity, acceleration, deltaTime);
}
// 在制导阶段,根据是否获得制导来调整导弹朝向
if(currentStage == MissileFlightStage.Guidance)
{
if (!IsGuidance)
{
// 导引头搜索阶段:保持水平飞行,导弹朝向向下一个固定角度进行搜索
// 不改变速度向量,让导引头在下视角范围内搜索目标
double seekingAngleRad = Properties.GuidanceSeekingAngle * Math.PI / 180.0;
KState.Orientation = new Orientation(KState.Orientation.Yaw, -seekingAngleRad, KState.Orientation.Roll);
}
// 如果IsGuidance为true制导系统会通过GuidanceAcceleration自动调整导弹的飞行轨迹和朝向
}
// 限制速度不超过最大速度
if (KState.Speed > Properties.MaxSpeed)
{
@ -611,6 +687,7 @@ namespace ThreatSource.Missile
/// - 基本状态信息
/// - 导弹固有属性
/// - 导弹运行时状态
/// - 制导系统状态(如果有)
/// </remarks>
public override ElementStatusInfo GetStatusInfo()
{
@ -642,7 +719,17 @@ namespace ThreatSource.Missile
statusInfo.ExtendedProperties["EngineBurnTime"] = EngineBurnTime;
statusInfo.ExtendedProperties["CurrentStage"] = currentStage.ToString();
statusInfo.ExtendedProperties["IsGuidance"] = IsGuidance;
statusInfo.ExtendedProperties["GuidanceAcceleration"] = GuidanceAcceleration;
statusInfo.ExtendedProperties["GuidanceAcceleration"] = GuidanceAcceleration;
// 添加制导系统状态信息(如果有制导系统)
if (GuidanceSystem != null)
{
statusInfo.ExtendedProperties["GuidanceSystem"] = GuidanceSystem.GetStatusInfo();
}
else
{
statusInfo.ExtendedProperties["GuidanceSystem"] = "无制导系统";
}
return statusInfo;
}
@ -667,7 +754,7 @@ namespace ThreatSource.Missile
{
SenderId = Id,
GuidanceType = GetCurrentGuidanceType(),
GuidanceSystemId = GetCurrentGuidanceSystemId()
GuidanceSystemId = GuidanceSystem?.Id
};
SimulationManager.PublishEvent(guidanceAcquiredEvent);
@ -714,29 +801,28 @@ namespace ThreatSource.Missile
};
}
/// <summary>
/// 获取当前制导系统ID
/// </summary>
/// <returns>制导系统ID基类返回null</returns>
/// <remarks>
/// 子类可以重写此方法以提供具体的制导系统ID
/// </remarks>
protected virtual string? GetCurrentGuidanceSystemId()
{
return null;
}
/// <summary>
/// 获取失去制导的原因
/// </summary>
/// <returns>失去制导的原因描述</returns>
/// <remarks>
/// 子类可以重写此方法以提供更具体的失去制导原因
/// 基类默认返回通用描述
/// 基于制导系统状态提供具体的失去制导原因:
/// - 如果制导系统被阻塞干扰:返回干扰相关原因
/// - 如果制导系统失去制导能力:返回系统失效原因
/// - 如果没有制导系统:返回通用原因
/// </remarks>
protected virtual string GetGuidanceLostReason()
{
return "制导系统失效或信号中断";
if (GuidanceSystem == null)
return "导弹无制导系统";
if (GuidanceSystem.IsBlockingJammed)
return "制导系统受到阻塞干扰";
if (!GuidanceSystem.HasGuidance)
return "制导系统失去目标或信号中断";
return "制导系统失效或信号中断";
}
}
}

View File

@ -80,7 +80,11 @@ namespace ThreatSource.Missile
: base(missileId, properties, kinematicState, manager)
{
targetType = primaryTargetType;
InitializeGuidanceSuite();
InitializeGuidanceSuite();
// 对于复合制导导弹,制导系统引用会在激活特定制导系统时动态设置
// 初始时设置为null表示没有激活的制导系统
SetGuidanceSystem(null);
}
/// <summary>
@ -195,11 +199,6 @@ namespace ThreatSource.Missile
return;
}
if (currentActiveGuidance is SimulationElement se)
{
se.Update(deltaTime);
}
if (currentActiveConfig == null)
{
Debug.WriteLine("[CompositeGuidance.Logic] 错误currentActiveGuidance 不为null但 currentActiveConfig 为null。");
@ -274,13 +273,29 @@ namespace ThreatSource.Missile
/// <param name="deactivatePrevious">是否应停用当前活动的制导系统(如果存在)。</param>
private void TryActivateNextGuidanceSystem(bool deactivatePrevious = false)
{
// 保存前一个制导系统的目标方向信息
Vector3D? previousTargetDirection = null;
if (deactivatePrevious && currentActiveGuidance != null)
{
Debug.WriteLine($"[CompositeGuidance.ActivateNext] 停用先前模块: {currentActiveConfig?.ComponentName ?? "Unknown"}");
if (currentActiveGuidance is BaseGuidanceSystem prevBaseGs)
// 尝试获取前一个制导系统的目标方向
if (currentActiveGuidance is BaseGuidanceSystem prevBaseGs && prevBaseGs.HasGuidance)
{
prevBaseGs.Deactivate();
// 使用制导系统当前的朝向作为目标方向
previousTargetDirection = prevBaseGs.KState.Orientation.ToVector();
Debug.WriteLine($"[CompositeGuidance.ActivateNext] 保存前一制导系统的目标方向: {previousTargetDirection:F3}");
}
if (currentActiveGuidance is BaseGuidanceSystem prevGs)
{
prevGs.Deactivate();
// 注销先前的制导系统
SimulationManager.UnregisterEntity(prevGs.Id);
}
// 清除基类的制导系统引用
SetGuidanceSystem(null);
}
currentGuidancePhaseIndex++;
@ -291,6 +306,8 @@ namespace ThreatSource.Missile
guidanceChainHaltedOrCompleted = true;
currentActiveGuidance = null;
currentActiveConfig = null;
// 清除基类的制导系统引用
SetGuidanceSystem(null);
return;
}
@ -300,7 +317,26 @@ namespace ThreatSource.Missile
Debug.WriteLine($"[CompositeGuidance.ActivateNext] 尝试激活模块: {currentActiveConfig.ComponentName} (类型: {currentActiveConfig.GuidanceSystemType})");
if (currentActiveGuidance is BaseGuidanceSystem currentBaseGs)
{
// 注册制导系统为独立实体
SimulationManager.RegisterEntity(currentBaseGs.Id, currentBaseGs);
currentBaseGs.Activate();
// 如果有前一个制导系统的目标方向信息,则调整新制导系统的导引头朝向
if (previousTargetDirection.HasValue)
{
Debug.WriteLine($"[CompositeGuidance.ActivateNext] 为新制导系统设置目标方向");
// 将目标方向转换为朝向
Orientation targetOrientation = Orientation.FromVector(previousTargetDirection.Value);
// 更新导引头朝向指向目标方向
currentBaseGs.KState.Orientation = targetOrientation;
Debug.WriteLine($"[CompositeGuidance.ActivateNext] 制导系统导引头朝向已调整为: {targetOrientation}");
}
// 设置基类的制导系统引用为当前激活的制导系统
SetGuidanceSystem(currentBaseGs);
}
currentPhaseActivationTime = FlightTime;
@ -323,11 +359,15 @@ namespace ThreatSource.Missile
if (currentActiveGuidance is BaseGuidanceSystem baseGsToDeactivate)
{
baseGsToDeactivate.Deactivate();
// 注销失败的制导系统
SimulationManager.UnregisterEntity(baseGsToDeactivate.Id);
}
}
currentActiveGuidance = null;
currentActiveConfig = null;
// 清除基类的制导系统引用
SetGuidanceSystem(null);
if (continueChain)
{
@ -353,16 +393,7 @@ namespace ThreatSource.Missile
UpdateGuidanceLogic(deltaTime);
}
if (currentActiveGuidance != null && currentActiveGuidance.HasGuidance)
{
IsGuidance = true;
GuidanceAcceleration = currentActiveGuidance.GetGuidanceAcceleration();
}
else
{
IsGuidance = false;
GuidanceAcceleration = Vector3D.Zero;
}
// 制导加速度和状态由基类自动处理基于当前设置的GuidanceSystem引用
base.Update(deltaTime); // 调用基类更新,处理运动学等
}
@ -393,6 +424,7 @@ namespace ThreatSource.Missile
UpdateGuidanceLogic(deltaTime);
// 调用基类方法处理制导加速度和升力计算
base.OnGuidanceStage(deltaTime);
}
@ -408,11 +440,15 @@ namespace ThreatSource.Missile
if (currentActiveGuidance is BaseGuidanceSystem activeBaseGs)
{
activeBaseGs.Deactivate();
// 注销当前活动的制导系统
SimulationManager.UnregisterEntity(activeBaseGs.Id);
}
currentActiveGuidance = null;
}
guidanceChainHaltedOrCompleted = true;
currentActiveConfig = null;
// 清除基类的制导系统引用
SetGuidanceSystem(null);
Debug.WriteLine($"[CompositeGuidedMissile.Deactivate] 导弹 {Id} 已停用. 活动制导系统已处理.");
}

View File

@ -80,6 +80,9 @@ namespace ThreatSource.Missile
properties.ProportionalNavigationCoefficient,
manager
);
// 设置制导系统引用到基类
SetGuidanceSystem(guidanceSystem);
}
/// <summary>
@ -89,17 +92,21 @@ namespace ThreatSource.Missile
/// <remarks>
/// 制导阶段处理:
/// - 启用制导控制
/// - 更新制导系统
/// - 计算制导加速度
/// - 制导加速度和状态由基类自动处理
/// - 制导系统作为独立实体由仿真管理器更新
/// </remarks>
protected override void OnGuidanceStage(double deltaTime)
{
// 点亮红外热源
LightInfraredSource();
// 更新制导系统
guidanceSystem.Update(deltaTime);
GuidanceAcceleration = guidanceSystem.GetGuidanceAcceleration();
IsGuidance = guidanceSystem.HasGuidance;
// 激活制导系统
if(!guidanceSystem.IsActive)
{
guidanceSystem.Activate();
}
// 制导系统作为独立实体由仿真管理器更新不需要在这里手动调用Update
// 调用基类方法处理制导加速度和升力计算
base.OnGuidanceStage(deltaTime);
}
/// <summary>
@ -157,12 +164,18 @@ namespace ThreatSource.Missile
/// <remarks>
/// 激活过程:
/// - 调用基类激活方法
/// - 注册制导系统为独立实体
/// - 激活制导系统
/// - 点亮红外热源
/// - 订阅制导指令事件
/// - 准备接收制导指令
/// </remarks>
public override void Activate()
{
base.Activate();
// 将制导系统注册到仿真管理器
SimulationManager.RegisterEntity(guidanceSystem.Id, guidanceSystem);
guidanceSystem.Activate();
// 点亮红外热源
LightInfraredSource();
@ -176,8 +189,10 @@ namespace ThreatSource.Missile
/// <remarks>
/// 停用过程:
/// - 调用基类停用方法
/// - 停用制导系统
/// - 熄灭红外热源
/// - 取消订阅制导事件
/// - 注销制导系统
/// </remarks>
public override void Deactivate()
{
@ -187,6 +202,8 @@ namespace ThreatSource.Missile
LightOffInfraredSource();
// 取消订阅红外指令制导事件
SimulationManager.UnsubscribeFromEvent<InfraredGuidanceCommandEvent>(HandleGuidanceCommand);
// 取消制导系统注册
SimulationManager.UnregisterEntity(guidanceSystem.Id);
}
/// <summary>
@ -195,12 +212,13 @@ namespace ThreatSource.Missile
/// <returns>包含导弹状态的详细描述</returns>
/// <remarks>
/// 返回信息包括:
/// - 基本状态信息
/// - 基本状态信息(由基类提供)
/// - 制导系统状态(由基类提供)
/// </remarks>
public override ElementStatusInfo GetStatusInfo()
{
var statusInfo = base.GetStatusInfo();
statusInfo.ExtendedProperties["GuidanceSystem"] = guidanceSystem.GetStatusInfo();
// 制导系统信息现在由基类统一处理
return statusInfo;
}
}

View File

@ -78,17 +78,20 @@ namespace ThreatSource.Missile
properties.ProportionalNavigationCoefficient,
manager
);
// 设置制导系统引用到基类
SetGuidanceSystem(guidanceSystem);
}
/// <summary>
/// 更新制导阶段状态
/// 更新制导阶段状态
/// </summary>
/// <param name="deltaTime">时间步长,单位:秒</param>
/// <remarks>
/// 制导阶段特点
/// - 完全依赖导航系统的工作模式
/// - 根据导航系统状态更新制导
/// - 持续到命中目标
/// 制导阶段处理
/// - 启用制导控制
/// - 制导加速度和状态由基类自动处理
/// - 制导系统作为独立实体由仿真管理器更新
/// </remarks>
protected override void OnGuidanceStage(double deltaTime)
{
@ -96,15 +99,11 @@ namespace ThreatSource.Missile
if(!guidanceSystem.IsActive)
{
guidanceSystem.Activate();
KState.Orientation = new Orientation(KState.Orientation.Yaw, -0.1, KState.Orientation.Roll);
KState.Velocity = KState.Orientation.ToVector() * KState.Speed;
}
// 更新制导系统
guidanceSystem.Update(deltaTime);
GuidanceAcceleration = guidanceSystem.GetGuidanceAcceleration();
IsGuidance = guidanceSystem.HasGuidance;
// 制导系统作为独立实体由仿真管理器更新不需要在这里手动调用Update
// 调用基类方法处理制导加速度和升力计算
base.OnGuidanceStage(deltaTime);
}
@ -114,11 +113,18 @@ namespace ThreatSource.Missile
/// <remarks>
/// 激活过程:
/// - 调用基类激活方法
/// - 注册制导系统为独立实体
/// - 激活制导系统
/// </remarks>
public override void Activate()
{
base.Activate();
// 将制导系统注册到仿真管理器
SimulationManager.RegisterEntity(guidanceSystem.Id, guidanceSystem);
// 激活制导系统
guidanceSystem.Activate();
}
/// <summary>
@ -128,11 +134,14 @@ namespace ThreatSource.Missile
/// 停用过程:
/// - 调用基类停用方法
/// - 停用制导系统
/// - 注销制导系统
/// </remarks>
public override void Deactivate()
{
base.Deactivate();
guidanceSystem.Deactivate();
// 取消制导系统注册
SimulationManager.UnregisterEntity(guidanceSystem.Id);
}
/// <summary>
@ -141,13 +150,13 @@ namespace ThreatSource.Missile
/// <returns>包含导弹状态的详细描述</returns>
/// <remarks>
/// 返回信息包括:
/// - 基本状态信息
/// - 当前飞行阶段
/// - 基本状态信息(由基类提供)
/// - 制导系统状态(由基类提供)
/// </remarks>
public override ElementStatusInfo GetStatusInfo()
{
var statusInfo = base.GetStatusInfo();
statusInfo.ExtendedProperties["GuidanceSystem"] = guidanceSystem.GetStatusInfo();
// 制导系统信息现在由基类统一处理
return statusInfo;
}
}

View File

@ -56,26 +56,33 @@ namespace ThreatSource.Missile
properties.ProportionalNavigationCoefficient,
guidanceSystemConfig,
manager);
// 设置制导系统引用到基类
SetGuidanceSystem(guidanceSystem);
}
/// <summary>
/// 制导阶段默认实现
/// 更新制导阶段状态
/// </summary>
/// <param name="deltaTime">时间步长,单位:秒</param>
/// <remarks>
/// 制导阶段处理:
/// - 更新制导系统
/// - 获取制导加速度
/// - 设置制导状态
/// - 启用制导控制
/// - 制导加速度和状态由基类自动处理
/// - 制导系统作为独立实体由仿真管理器更新
/// </remarks>
/// </summary>
protected override void OnGuidanceStage(double deltaTime)
{
// 更新制导系统
guidanceSystem.Update(deltaTime);
// 获取制导加速度
GuidanceAcceleration = guidanceSystem.GetGuidanceAcceleration();
// 设置制导状态
IsGuidance = guidanceSystem.HasGuidance;
// 激活制导系统
if(!guidanceSystem.IsActive)
{
guidanceSystem.Activate();
}
// 制导系统作为独立实体由仿真管理器更新不需要在这里手动调用Update
// 调用基类方法处理制导加速度和升力计算
base.OnGuidanceStage(deltaTime);
}
/// <summary>
@ -84,12 +91,16 @@ namespace ThreatSource.Missile
/// <remarks>
/// 激活过程:
/// - 调用基类激活方法
/// - 订阅激光波束事件
/// - 准备波束跟踪
/// - 注册制导系统为独立实体
/// - 激活制导系统
/// </remarks>
public override void Activate()
{
base.Activate();
// 将制导系统注册到仿真管理器
SimulationManager.RegisterEntity(guidanceSystem.Id, guidanceSystem);
// 激活制导系统
guidanceSystem.Activate();
}
@ -100,14 +111,16 @@ namespace ThreatSource.Missile
/// <remarks>
/// 停用过程:
/// - 调用基类停用方法
/// - 取消订阅波束事件
/// - 清理制导状态
/// - 停用制导系统
/// - 注销制导系统
/// </remarks>
public override void Deactivate()
{
base.Deactivate();
// 停用制导系统
guidanceSystem.Deactivate();
// 取消制导系统注册
SimulationManager.UnregisterEntity(guidanceSystem.Id);
}
/// <summary>
@ -116,12 +129,13 @@ namespace ThreatSource.Missile
/// <returns>包含导弹状态的详细描述</returns>
/// <remarks>
/// 返回信息包括:
/// - 基本状态信息
/// - 基本状态信息(由基类提供)
/// - 制导系统状态(由基类提供)
/// </remarks>
public override ElementStatusInfo GetStatusInfo()
{
var statusInfo = base.GetStatusInfo();
statusInfo.ExtendedProperties["GuidanceSystem"] = guidanceSystem.GetStatusInfo();
// 制导系统信息现在由基类统一处理
return statusInfo;
}
}

View File

@ -66,6 +66,9 @@ namespace ThreatSource.Missile
properties.ProportionalNavigationCoefficient,
guidanceConfig,
manager);
// 设置制导系统引用到基类
SetGuidanceSystem(guidanceSystem);
}
/// <summary>
@ -106,9 +109,8 @@ namespace ThreatSource.Missile
/// <remarks>
/// 制导阶段处理:
/// - 启用制导控制
/// - 更新制导系统
/// - 计算制导加速度
/// - 检查自毁条件
/// - 制导加速度和状态由基类自动处理
/// - 制导系统作为独立实体由仿真管理器更新
/// </remarks>
protected override void OnGuidanceStage(double deltaTime)
{
@ -118,19 +120,10 @@ namespace ThreatSource.Missile
guidanceSystem.Activate();
}
// 更新制导系统
guidanceSystem.Update(deltaTime);
GuidanceAcceleration = guidanceSystem.GetGuidanceAcceleration();
IsGuidance = guidanceSystem.HasGuidance;
}
/// <summary>
/// 获取制导加速度
/// </summary>
/// <returns>制导加速度向量</returns>
public Vector3D GetGuidanceAcceleration()
{
return GuidanceAcceleration;
// 制导系统作为独立实体由仿真管理器更新不需要在这里手动调用Update
// 调用基类方法处理制导加速度和升力计算
base.OnGuidanceStage(deltaTime);
}
/// <summary>
@ -203,14 +196,13 @@ namespace ThreatSource.Missile
/// <returns>包含导弹状态的详细描述</returns>
/// <remarks>
/// 返回信息包括:
/// - 基本状态信息
/// - 当前飞行阶段
/// - 基本状态信息(由基类提供)
/// - 制导系统状态(由基类提供)
/// </remarks>
public override ElementStatusInfo GetStatusInfo()
{
var statusInfo = base.GetStatusInfo();
statusInfo.ExtendedProperties["CurrentStage"] = currentStage.ToString();
statusInfo.ExtendedProperties["GuidanceSystem"] = guidanceSystem.GetStatusInfo();
// 制导系统信息现在由基类统一处理
return statusInfo;
}
}

View File

@ -73,17 +73,20 @@ namespace ThreatSource.Missile
properties.ProportionalNavigationCoefficient,
guidanceConfig,
manager);
// 设置制导系统引用到基类
SetGuidanceSystem(guidanceSystem);
}
/// <summary>
/// 更新制导阶段状态
/// 更新制导阶段状态
/// </summary>
/// <param name="deltaTime">时间步长,单位:秒</param>
/// <remarks>
/// 制导阶段特点
/// - 完全依赖导航系统的工作模式
/// - 根据导航系统状态更新制导
/// - 持续到命中目标
/// 制导阶段处理
/// - 启用制导控制
/// - 制导加速度和状态由基类自动处理
/// - 制导系统作为独立实体由仿真管理器更新
/// </remarks>
protected override void OnGuidanceStage(double deltaTime)
{
@ -91,15 +94,11 @@ namespace ThreatSource.Missile
if(!guidanceSystem.IsActive)
{
guidanceSystem.Activate();
KState.Orientation = new Orientation(KState.Orientation.Yaw, -0.02, KState.Orientation.Roll);
KState.Velocity = KState.Orientation.ToVector() * KState.Speed;
}
// 更新制导系统
guidanceSystem.Update(deltaTime);
GuidanceAcceleration = guidanceSystem.GetGuidanceAcceleration();
IsGuidance = guidanceSystem.HasGuidance;
// 制导系统作为独立实体由仿真管理器更新不需要在这里手动调用Update
// 调用基类方法处理制导加速度和升力计算
base.OnGuidanceStage(deltaTime);
}
@ -109,11 +108,18 @@ namespace ThreatSource.Missile
/// <remarks>
/// 激活过程:
/// - 调用基类激活方法
/// - 注册制导系统为独立实体
/// - 激活制导系统
/// </remarks>
public override void Activate()
{
base.Activate();
// 将制导系统注册到仿真管理器
SimulationManager.RegisterEntity(guidanceSystem.Id, guidanceSystem);
// 激活制导系统
guidanceSystem.Activate();
}
/// <summary>
@ -123,11 +129,14 @@ namespace ThreatSource.Missile
/// 停用过程:
/// - 调用基类停用方法
/// - 停用制导系统
/// - 注销制导系统
/// </remarks>
public override void Deactivate()
{
base.Deactivate();
guidanceSystem.Deactivate();
// 取消制导系统注册
SimulationManager.UnregisterEntity(guidanceSystem.Id);
}
/// <summary>
@ -136,14 +145,13 @@ namespace ThreatSource.Missile
/// <returns>包含导弹状态的详细描述</returns>
/// <remarks>
/// 返回信息包括:
/// - 基本状态信息
/// - 当前飞行阶段
/// - 基本状态信息(由基类提供)
/// - 制导系统状态(由基类提供)
/// </remarks>
public override ElementStatusInfo GetStatusInfo()
{
var statusInfo = base.GetStatusInfo();
statusInfo.ExtendedProperties["CurrentStage"] = currentStage.ToString();
statusInfo.ExtendedProperties["GuidanceSystem"] = guidanceSystem.GetStatusInfo().ToString();
// 制导系统信息现在由基类统一处理
return statusInfo;
}
}

View File

@ -487,7 +487,6 @@ namespace ThreatSource.Missile
{
// 二次确认成功,进入攻击阶段
Debug.WriteLine($"二次确认成功,进入攻击阶段,当前角度: {spiralAngle * 180 / Math.PI:F2}°");
IsGuidance = true;
currentSubmunitionStage = SubmunitionStage.Attack;
return;
}
@ -711,5 +710,18 @@ namespace ThreatSource.Missile
return false;
}
}
/// <summary>
/// 获取末敏弹子弹是否处于制导状态
/// </summary>
/// <remarks>
/// 对于末敏弹子弹,制导状态基于攻击阶段而非传统制导系统
/// 攻击阶段表示子弹已锁定目标并进行精确攻击
/// 与传统导弹不同,末敏弹子弹使用传感器制导而非制导系统
/// </remarks>
public override bool IsGuidance
{
get => currentSubmunitionStage == SubmunitionStage.Attack;
}
}
}

View File

@ -284,6 +284,24 @@
---
## 事件设计原则
### 包含的事件类型
1. **关键业务动作**: 导弹发射、激光照射、制导指令等
2. **重要结果状态**: 目标命中、摧毁、爆炸等
3. **系统级变化**: 实体激活/停用、仿真控制等
### 不包含的事件类型
1. **运行时状态变化**: 目标丢失、FOV变化、临时干扰等
2. **可查询的状态**: 通过属性直接获取的信息
3. **高频变化状态**: 可能产生事件泛滥的状态变化
### 设计理念
保持事件系统的简洁性和高效性,专注于用户真正需要响应的关键事件,
避免因过度细化而增加系统复杂性。
---
**文档结束**
*此文档将随着系统发展持续更新,请定期检查事件完整性。*

View File

@ -20,6 +20,11 @@ dotnet test --filter "FullyQualifiedName=ThreatSource.Tests.Utils.Vector3DPerfor
dotnet test --filter "FullyQualifiedName=ThreatSource.Tests.Utils.Vector3DPerformanceTests.Baseline_Vector3D_Class_Performance" --logger "console;verbosity=detailed" | cat
```
4. 测试是否编译正常
```bash
dotnet build
```
### 测试报告
时间2025-05-16
测试目的:测试 Vector3D 作为类和结构体的性能差异

View File

@ -1,76 +0,0 @@
# 上下文
文件名:[missile_lift_model.md]
创建于:[2024-05-23T10:00:00Z]
创建者:[AI]
# 任务描述
用户请求设计并实现导弹的升力加速度模型。
升力加速度az =功角a - 5 度)* 1 米每秒的平方。
功角 a 的范围是大于等于负 5 度且小于等于 15 度。在其他情况下az=0。
功角 a 定义为导弹速度矢量与XY平面水平面的夹角。
升力加速度作用在导弹的垂直方向垂直于速度矢量并在由速度矢量和世界Y轴定义的平面内
# 项目概述
项目为一个导弹仿真系统,需要修改导弹基类及其运动算法来集成新的升力模型。
---
*以下部分由 AI 在协议执行过程中维护*
---
# 分析 (由 RESEARCH 模式填充)
- 升力计算的核心位置在 `BaseMissile.cs``CalculateAcceleration` 方法。
- 攻角 (alpha) 用户定义为速度矢量与水平面 (XZ平面假设Y为垂直轴) 的夹角。
- 升力方向垂直于速度矢量并位于由速度矢量和世界Y轴`Vector3D.UnitY`)定义的平面内。
- `MotionAlgorithm.cs` 是存放运动相关计算的工具类。
# 提议的解决方案 (由 INNOVATE 模式填充)
方案:在 `MotionAlgorithm.cs` 中增加计算攻角和升力矢量的方法。在 `BaseMissile.cs` 中调用这些方法并将升力加入总加速度。
# 实施计划 (由 PLAN 模式生成)
见下方实施检查清单。
实施检查清单:
1. **在 `ThreatSource/src/Utils/MotionAlgorithm.cs` 中**
1. 创建 `public static double CalculateAngleOfAttackFromHorizontal(Vector3D velocity)` 方法。
* 输入: `Vector3D velocity`
* 计算水平速度大小 `horizontalMagnitude = Math.Sqrt(velocity.X * velocity.X + velocity.Z * velocity.Z)`。
* 处理 `horizontalMagnitude < 1e-6` 的情况:
* If `velocity.Y > 0`, return `Math.PI / 2`.
* If `velocity.Y < 0`, return `-Math.PI / 2`.
* Else, return `0.0`.
* 否则,计算 `alpha_rad = Math.Atan2(velocity.Y, horizontalMagnitude)`
* Return `alpha_rad`.
2. **在 `ThreatSource/src/Utils/MotionAlgorithm.cs` 中**
1. 创建 `public static Vector3D CalculateLiftAccelerationVector(Vector3D velocity, double angleOfAttackDegrees)` 方法。
* 输入: `Vector3D velocity`, `double angleOfAttackDegrees`.
* 定义常量: `MIN_AOA_DEG = -5.0`, `MAX_AOA_DEG = 15.0`, `AOA_OFFSET_DEG = 5.0`.
* 计算 `az_magnitude`:
* If `angleOfAttackDegrees >= MIN_AOA_DEG && angleOfAttackDegrees <= MAX_AOA_DEG`:
* `az_magnitude = (angleOfAttackDegrees - AOA_OFFSET_DEG) * 1.0`.
* Else:
* `az_magnitude = 0.0`.
* If `Math.Abs(az_magnitude) < 1e-6 || velocity.MagnitudeSquared() < 1e-9`, return `Vector3D.Zero`.
* 定义 `WorldUp = Vector3D.UnitY`.
* `velocityNormalized = velocity.Normalize()`.
* `RightVec = Vector3D.CrossProduct(velocityNormalized, WorldUp)`.
* If `RightVec.MagnitudeSquared() < 1e-9`, return `Vector3D.Zero` (处理垂直飞行情况).
* `LiftDir = Vector3D.CrossProduct(RightVec, velocityNormalized).Normalize()`.
* `liftAcceleration = LiftDir * az_magnitude`.
* Return `liftAcceleration`.
3. **在 `ThreatSource/src/Missile/BaseMissile.cs` 的 `CalculateAcceleration(Vector3D velocity)` 方法中**
1. 在计算 `totalAcceleration` 之前,获取当前速度 `currentMissileVelocity = velocity` (或直接用 `velocity` 参数)。
2. 计算攻角(度): `double currentAoARad = MotionAlgorithm.CalculateAngleOfAttackFromHorizontal(currentMissileVelocity);`
3. `double currentAoADegrees = currentAoARad * 180.0 / Math.PI;`
4. 计算升力加速度矢量: `Vector3D liftAcceleration = MotionAlgorithm.CalculateLiftAccelerationVector(currentMissileVelocity, currentAoADegrees);`
5. 修改 `totalAcceleration` 的计算公式,加入 `liftAcceleration`:
`Vector3D totalAcceleration = GuidanceAcceleration + ThrustAcceleration + dragAcceleration + GravityAcceleration + liftAcceleration;`
6. 更新 `Debug.WriteLine` 语句,包含 `liftAcceleration` 的值。例如,在原有的基础上追加 `$", 升力: {liftAcceleration}"`
# 当前执行步骤 (由 EXECUTE 模式在开始执行某步骤时更新)
> 正在执行: "1. 在 `ThreatSource/src/Utils/MotionAlgorithm.cs`1. 创建 `public static double CalculateAngleOfAttackFromHorizontal(Vector3D velocity)` 方法。"
# 任务进度 (由 EXECUTE 模式在每步完成后追加)
* [待填写]
# 最终审查 (由 REVIEW 模式填充)
[待填写]

View File

@ -185,42 +185,6 @@ namespace ThreatSource.Tools.MissileSimulation
};
}
/// <summary>
/// 初始化仿真环境
/// </summary>
private void InitializeSimulation()
{
// 添加天气
AddWeathers();
// 添加目标(坦克)
AddTankTarget();
// 添加各种类型的导弹
AddLaserSemiActiveMissile();
AddLaserBeamRiderMissile();
AddTerminalSensitiveMissile();
AddInfraredCommandMissile();
AddInfraredImagingMissile();
AddMillimeterWaveMissile();
AddCompositeGuidanceMissile();
// 添加各种传感器和指示器
AddIndicators();
// 添加烟幕弹
AddSmokeGrenade();
// 添加激光诱偏目标
AddLaserDecoy();
// 添加各类型干扰器
AddJammers();
// 打印所有注册的干扰器
PrintAllJammers();
}
/// <summary>
/// 添加天气
/// </summary>
@ -493,7 +457,7 @@ namespace ThreatSource.Tools.MissileSimulation
Speed = 0
};
var laserDesignator = _threatSourceFactory.CreateIndicator(laserDesignatorId, "ld_001", "Tank_1", "LSGM_1", laserDesignatorLaunchParams);
indicators[laserDesignatorId] = (SimulationElement)laserDesignator;
indicators[laserDesignatorId] = laserDesignator;
simulationManager.RegisterEntity(laserDesignatorId, laserDesignator);
Console.WriteLine($"注册激光目标指示器 {laserDesignatorId}");
@ -506,7 +470,7 @@ namespace ThreatSource.Tools.MissileSimulation
Speed = 0
};
var laserBeamRider = _threatSourceFactory.CreateIndicator(laserBeamRiderId, "br_001", "Tank_1", "LBRM_1", laserBeamRiderLaunchParams);
indicators[laserBeamRiderId] = (SimulationElement)laserBeamRider;
indicators[laserBeamRiderId] = laserBeamRider;
simulationManager.RegisterEntity(laserBeamRiderId, laserBeamRider);
Console.WriteLine($"注册激光驾束仪 {laserBeamRiderId}");
@ -519,7 +483,7 @@ namespace ThreatSource.Tools.MissileSimulation
Speed = 0
};
var infraredTracker = _threatSourceFactory.CreateIndicator(infraredTrackerId, "ir_001", "Tank_1", "ICGM_1", infraredTrackerLaunchParams);
indicators[infraredTrackerId] = (SimulationElement)infraredTracker;
indicators[infraredTrackerId] = infraredTracker;
simulationManager.RegisterEntity(infraredTrackerId, infraredTracker);
Console.WriteLine($"注册红外测角仪 {infraredTrackerId}");
}