752 lines
30 KiB
C#
752 lines
30 KiB
C#
using ThreatSource.Utils;
|
||
using ThreatSource.Equipment;
|
||
using System.Diagnostics;
|
||
using ThreatSource.Jammer;
|
||
using ThreatSource.Simulation;
|
||
using AirTransmission;
|
||
|
||
|
||
namespace ThreatSource.Guidance
|
||
{
|
||
/// <summary>
|
||
/// 毫米波导引头系统类,实现了基于毫米波雷达的目标探测和跟踪功能
|
||
/// </summary>
|
||
/// <remarks>
|
||
/// 该类提供了毫米波导引头系统的核心功能:
|
||
/// - 目标探测和识别
|
||
/// - 信噪比计算
|
||
/// - 抗干扰处理
|
||
/// - 比例导引控制
|
||
/// 用于实现全天候制导打击
|
||
/// </remarks>
|
||
public class MillimeterWaveGuidanceSystem : BaseGuidanceSystem
|
||
{
|
||
/// <summary>
|
||
/// 工作模式枚举
|
||
/// </summary>
|
||
private enum WorkMode
|
||
{
|
||
Search, // 搜索模式
|
||
Track, // 跟踪模式
|
||
Lock // 锁定模式
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取设备支持的阻塞干扰类型
|
||
/// </summary>
|
||
public override IEnumerable<JammingType> SupportedBlockingJammingTypes => [JammingType.MillimeterWave];
|
||
|
||
/// <summary>
|
||
/// 获取设备支持的干扰类型
|
||
/// </summary>
|
||
public override IEnumerable<JammingType> SupportedJammingTypes => [JammingType.MillimeterWave, JammingType.SmokeGrenade];
|
||
|
||
/// <summary>
|
||
/// 毫米波导引系统配置
|
||
/// </summary>
|
||
/// <remarks>
|
||
/// 存储系统的所有可配置参数
|
||
/// 包括探测范围、视场角等
|
||
/// </remarks>
|
||
private readonly MillimeterWaveGuidanceConfig config;
|
||
|
||
/// <summary>
|
||
/// 随机数生成器实例
|
||
/// </summary>
|
||
/// <remarks>
|
||
/// 用于生成随机扰动
|
||
/// 模拟系统噪声和识别概率
|
||
/// </remarks>
|
||
private readonly Random random = new();
|
||
|
||
/// <summary>
|
||
/// 上一次探测到的目标位置 (使用可空类型)
|
||
/// </summary>
|
||
/// <remarks>
|
||
/// 记录目标的历史位置
|
||
/// 用于计算目标速度
|
||
/// </remarks>
|
||
private Vector3D? lastTargetPosition { get; set; }
|
||
|
||
/// <summary>
|
||
/// 上一次探测到的目标速度 (使用可空类型)
|
||
/// </summary>
|
||
/// <remarks>
|
||
/// 记录目标的历史速度
|
||
/// 用于计算目标速度
|
||
/// </remarks>
|
||
private Vector3D? lastTargetVelocity { get; set; }
|
||
|
||
/// <summary>
|
||
/// 目标丢失计时器
|
||
/// </summary>
|
||
/// <remarks>
|
||
/// 记录目标丢失的时间
|
||
/// 用于切换到搜索模式
|
||
/// </remarks>
|
||
private double targetLostTimer = 0;
|
||
|
||
/// <summary>
|
||
/// 锁定确认计时器
|
||
/// </summary>
|
||
/// <remarks>
|
||
/// 记录锁定确认的时间
|
||
/// 用于切换到锁定模式
|
||
/// </remarks>
|
||
private double lockConfirmationTimer = 0;
|
||
|
||
/// <summary>
|
||
/// 当前工作模式
|
||
/// </summary>
|
||
private WorkMode currentMode = WorkMode.Search;
|
||
|
||
/// <summary>
|
||
/// 是否有目标
|
||
/// </summary>
|
||
public bool HasTarget { get; private set; }
|
||
|
||
/// <summary>
|
||
/// 是否在锁定模式
|
||
/// </summary>
|
||
public bool IsInLockMode => currentMode == WorkMode.Lock;
|
||
|
||
/// <summary>
|
||
/// 当前扫描角度,单位:弧度
|
||
/// </summary>
|
||
private double currentScanAngle = 0;
|
||
|
||
/// <summary>
|
||
/// 当前扫描半径,单位:弧度
|
||
/// </summary>
|
||
private double currentScanRadius = 0;
|
||
|
||
/// <summary>
|
||
/// 最大扫描半径,单位:弧度
|
||
/// </summary>
|
||
private double maxScanRadius => config.FieldOfViewAngle * Math.PI / 180.0 / 2;
|
||
|
||
/// <summary>
|
||
/// 当前视线的烟幕透过率 (0.0 - 1.0)
|
||
/// </summary>
|
||
private double _currentSmokeTransmittance = 1.0;
|
||
|
||
|
||
/// <summary>
|
||
/// 初始化毫米波制导系统的新实例
|
||
/// </summary>
|
||
/// <param name="id">制导系统ID</param>
|
||
/// <param name="maxAcceleration">最大加速度,单位:米/平方秒</param>
|
||
/// <param name="guidanceCoefficient">制导系数</param>
|
||
/// <param name="simulationManager">仿真管理器实例</param>
|
||
/// <param name="config">毫米波导引系统配置</param>
|
||
/// <remarks>
|
||
/// 构造过程:
|
||
/// - 初始化基类参数
|
||
/// - 设置仿真管理器
|
||
/// - 初始化目标位置
|
||
/// - 注册干扰事件处理
|
||
/// - 加载干扰阈值配置
|
||
/// </remarks>
|
||
public MillimeterWaveGuidanceSystem(
|
||
string id,
|
||
double maxAcceleration,
|
||
double guidanceCoefficient,
|
||
MillimeterWaveGuidanceConfig config,
|
||
ISimulationManager simulationManager)
|
||
: base(id, maxAcceleration, guidanceCoefficient, simulationManager)
|
||
{
|
||
this.config = config;
|
||
InitializeJamming(config.JammingResistanceThreshold, SupportedJammingTypes, SupportedBlockingJammingTypes);
|
||
SwitchToSearchMode(); // 初始化为搜索模式
|
||
}
|
||
|
||
/// <summary>
|
||
/// 切换到搜索模式
|
||
/// </summary>
|
||
public void SwitchToSearchMode()
|
||
{
|
||
currentMode = WorkMode.Search;
|
||
HasTarget = false;
|
||
HasGuidance = false;
|
||
targetLostTimer = 0;
|
||
lockConfirmationTimer = 0;
|
||
currentScanAngle = 0;
|
||
currentScanRadius = config.SearchBeamWidth * Math.PI / 720.0; // 从半个波束宽度的一半开始
|
||
lastTargetPosition = null;
|
||
lastTargetVelocity = null;
|
||
Trace.WriteLine($"切换到搜索模式,波束宽度: {config.SearchBeamWidth}度");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 切换到跟踪模式
|
||
/// </summary>
|
||
private void SwitchToTrackMode()
|
||
{
|
||
currentMode = WorkMode.Track;
|
||
lockConfirmationTimer = 0;
|
||
HasGuidance = true;
|
||
Trace.WriteLine($"切换到跟踪模式,波束宽度: {config.TrackBeamWidth}度");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 切换到锁定模式
|
||
/// </summary>
|
||
private void SwitchToLockMode()
|
||
{
|
||
currentMode = WorkMode.Lock;
|
||
HasGuidance = true;
|
||
Trace.WriteLine("切换到锁定模式 - 目标锁定成功");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 激活制导系统
|
||
/// </summary>
|
||
public override void Activate()
|
||
{
|
||
if (!IsActive)
|
||
{
|
||
IsActive = true;
|
||
// 在这里订阅事件,确保只订阅一次
|
||
SimulationManager.SubscribeToEvent<JammingEvent>(HandleJammingEvent);
|
||
}
|
||
base.Activate();
|
||
SwitchToSearchMode();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 停用制导系统
|
||
/// </summary>
|
||
public override void Deactivate()
|
||
{
|
||
if (IsActive)
|
||
{
|
||
IsActive = false;
|
||
SimulationManager.UnsubscribeFromEvent<JammingEvent>(HandleJammingEvent);
|
||
}
|
||
base.Deactivate();
|
||
HasTarget = false;
|
||
HasGuidance = false;
|
||
GuidanceAcceleration = Vector3D.Zero;
|
||
lastTargetPosition = null;
|
||
lastTargetVelocity = null;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 处理系统被干扰的事件
|
||
/// </summary>
|
||
/// <param name="parameters">干扰参数</param>
|
||
protected override void HandleJammingApplied(JammingParameters parameters)
|
||
{
|
||
base.HandleJammingApplied(parameters);
|
||
|
||
if (parameters.Type == JammingType.MillimeterWave)
|
||
{
|
||
Debug.WriteLine($"[MMW_GUIDANCE] 受到毫米波干扰,功率:{parameters.Power} W。切换到搜索模式。", "Jamming");
|
||
// 干扰时切换到搜索模式
|
||
if (currentMode != WorkMode.Search)
|
||
{
|
||
SwitchToSearchMode();
|
||
}
|
||
}
|
||
else if (parameters.Type == JammingType.SmokeGrenade)
|
||
{
|
||
// 计算烟幕透过率
|
||
// TODO: 实现基于 JammingParameters 中烟幕属性 (浓度、厚度等) 的真实透过率计算。
|
||
_currentSmokeTransmittance = 1.0; // 暂时设置为无遮挡
|
||
Debug.WriteLine($"[MMW_GUIDANCE] 烟幕干扰应用,(临时) 透过率: {_currentSmokeTransmittance:P2}", "Jamming");
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 处理系统干扰被清除的事件
|
||
/// </summary>
|
||
/// <param name="parameters">干扰参数</param>
|
||
protected override void HandleJammingCleared(JammingParameters parameters)
|
||
{
|
||
base.HandleJammingCleared(parameters); // 调用基类处理 IsHardJammed 和 HasGuidance
|
||
|
||
if (parameters.Type == JammingType.MillimeterWave)
|
||
{
|
||
Debug.WriteLine($"[MMW_GUIDANCE] 毫米波干扰已清除。", "Jamming");
|
||
// 干扰清除后是否需要切换模式?取决于当前是否有目标。Update 会处理。
|
||
}
|
||
else if (parameters.Type == JammingType.SmokeGrenade)
|
||
{
|
||
_currentSmokeTransmittance = 1.0; // 重置烟幕透过率
|
||
Debug.WriteLine($"[MMW_GUIDANCE] 烟幕干扰已清除。", "Jamming");
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 判断是否应该处理传入的干扰参数(毫米波干扰需要额外检查波长)
|
||
/// </summary>
|
||
/// <param name="parameters">干扰参数</param>
|
||
/// <returns>如果应该处理则返回 true,否则返回 false</returns>
|
||
protected override bool ShouldHandleJamming(JammingParameters parameters)
|
||
{
|
||
// 首先调用基类检查是否支持该干扰类型
|
||
if (!base.ShouldHandleJamming(parameters))
|
||
{
|
||
return false;
|
||
}
|
||
|
||
// 对毫米波干扰添加波长检查
|
||
if (parameters.Type == JammingType.MillimeterWave)
|
||
{
|
||
// 检查波长是否与工作波长匹配 (单位: 毫米 mm)
|
||
// 计算配置波长 (单位: mm), 直接使用光速值 3e8 m/s
|
||
const double speedOfLight = 3e8;
|
||
double configWavelength = speedOfLight / config.WaveFrequency * 1000.0; // m/s / Hz * 1000 = mm
|
||
|
||
if (Math.Abs((parameters.Wavelength ?? 0) - configWavelength) > 1e-1) // 允许 0.1mm 偏差
|
||
{
|
||
Debug.WriteLine($"[MMW_GUIDANCE] {Id} 忽略毫米波干扰:干扰波长 {parameters.Wavelength}mm 与系统工作波长 {configWavelength:F2}mm (频率 {config.WaveFrequency/1e9:F1}GHz) 不匹配。", "Jamming");
|
||
return false;
|
||
}
|
||
}
|
||
|
||
// 如果是支持的非毫米波干扰 (例如烟幕) 或通过了毫米波检查,则返回 true
|
||
return true;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 更新圆锥扫描参数
|
||
/// </summary>
|
||
private void UpdateConicalScan(double deltaTime)
|
||
{
|
||
if (currentMode == WorkMode.Search)
|
||
{
|
||
// 使用配置参数
|
||
currentScanAngle += config.ScanAngularSpeedDeg * Math.PI / 180.0 * deltaTime;
|
||
currentScanRadius += config.ScanRadiusGrowthRateDeg * Math.PI / 180.0 * deltaTime;
|
||
currentScanRadius = Math.Min(currentScanRadius, maxScanRadius);
|
||
|
||
if (currentScanAngle >= 2 * Math.PI)
|
||
{
|
||
currentScanAngle -= 2 * Math.PI;
|
||
}
|
||
|
||
Console.WriteLine($"扫描参数 - 半径: {currentScanRadius * 180/Math.PI:F2}度, 角度: {currentScanAngle * 180/Math.PI:F2}度");
|
||
}
|
||
else
|
||
{
|
||
currentScanAngle = 0;
|
||
// 非搜索模式时重置扫描参数
|
||
currentScanRadius = config.SearchBeamWidth * Math.PI / 720.0;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 单脉冲和差测角处理(仅用于跟踪/锁定模式)
|
||
/// </summary>
|
||
/// <param name="toTarget">弹目视线方向向量</param>
|
||
/// <param name="missileVelocity">导弹速度向量</param>
|
||
/// <returns>(方位误差弧度, 俯仰误差弧度)</returns>
|
||
private (double azimuthError, double elevationError) ProcessMonopulse(Vector3D toTarget, Vector3D missileVelocity)
|
||
{
|
||
// 建立弹体坐标系(X轴为导弹速度方向)
|
||
Vector3D xAxis = missileVelocity.Normalize();
|
||
// 使用地面垂直方向作为参考
|
||
Vector3D up = Vector3D.UnitY;
|
||
// 计算水平方向
|
||
Vector3D yAxis = Vector3D.CrossProduct(up, xAxis).Normalize();
|
||
if (yAxis.Magnitude() < 1e-6)
|
||
{
|
||
// 如果导弹垂直飞行,使用北向作为参考
|
||
yAxis = Vector3D.CrossProduct(Vector3D.UnitZ, xAxis).Normalize();
|
||
}
|
||
// 计算垂直方向
|
||
Vector3D zAxis = Vector3D.CrossProduct(xAxis, yAxis).Normalize();
|
||
|
||
// 将目标向量转换到弹体坐标系
|
||
Vector3D targetBodyFrame = new(
|
||
Vector3D.DotProduct(toTarget, xAxis),
|
||
Vector3D.DotProduct(toTarget, yAxis),
|
||
Vector3D.DotProduct(toTarget, zAxis)
|
||
);
|
||
|
||
// 计算方位角和俯仰角
|
||
double azimuthError = Math.Atan2(targetBodyFrame.Y, targetBodyFrame.X);
|
||
double elevationError = Math.Atan2(targetBodyFrame.Z, Math.Sqrt(targetBodyFrame.X * targetBodyFrame.X + targetBodyFrame.Y * targetBodyFrame.Y));
|
||
|
||
// 应用灵敏度系数
|
||
return (
|
||
azimuthError * config.MonopulseSensitivity,
|
||
elevationError * config.MonopulseSensitivity
|
||
);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 计算目标是否在当前扫描波束内
|
||
/// </summary>
|
||
private bool IsTargetInBeam(Vector3D missileVelocity, Vector3D toTarget)
|
||
{
|
||
// 根据当前模式选择波束宽度
|
||
double currentBeamWidth = currentMode switch
|
||
{
|
||
WorkMode.Search => config.SearchBeamWidth * Math.PI / 180.0,
|
||
WorkMode.Track => config.TrackBeamWidth * Math.PI / 180.0,
|
||
WorkMode.Lock => config.LockBeamWidth * Math.PI / 180.0,
|
||
_ => config.SearchBeamWidth * Math.PI / 180.0
|
||
};
|
||
|
||
if (currentMode == WorkMode.Search)
|
||
{
|
||
// 搜索模式使用圆锥扫描
|
||
// 建立以前进方向为X轴的右手坐标系
|
||
Vector3D xAxis = missileVelocity.Normalize();
|
||
Vector3D yAxis;
|
||
Vector3D referenceAxis = Vector3D.UnitY; // 优先使用垂直轴作为参考
|
||
|
||
// 处理近乎垂直飞行的情况
|
||
if (Math.Abs(xAxis.Y) > 0.9)
|
||
{
|
||
referenceAxis = Vector3D.UnitZ; // 改用Z轴作为参考
|
||
}
|
||
|
||
// 构建正交坐标系
|
||
yAxis = Vector3D.CrossProduct(Vector3D.CrossProduct(xAxis, referenceAxis), xAxis).Normalize();
|
||
Vector3D zAxis = Vector3D.CrossProduct(xAxis, yAxis).Normalize();
|
||
|
||
// 计算圆锥扫描方向
|
||
double offsetAngle = currentScanRadius;
|
||
// X轴为主轴的圆锥扫描参数
|
||
double x = Math.Cos(offsetAngle); // 主轴分量
|
||
double y = Math.Sin(offsetAngle) * Math.Sin(currentScanAngle); // 垂直分量
|
||
double z = Math.Sin(offsetAngle) * Math.Cos(currentScanAngle); // 水平分量
|
||
|
||
// 合成扫描方向向量
|
||
Vector3D scanDirection = (
|
||
xAxis * x +
|
||
yAxis * y +
|
||
zAxis * z
|
||
).Normalize();
|
||
|
||
// 调试输出
|
||
Console.WriteLine($"导弹前进方向: {xAxis}");
|
||
Console.WriteLine($"目标方向: {toTarget.Normalize()}");
|
||
Console.WriteLine($"扫描方向: {scanDirection}");
|
||
|
||
// 计算目标夹角
|
||
double angle = Vector3D.AngleBetween(scanDirection, toTarget.Normalize());
|
||
Console.WriteLine($"目标夹角: {angle * 180/Math.PI:F2}度");
|
||
Console.WriteLine($"波束宽度: {currentBeamWidth * 180/Math.PI:F2}度,SNR阈值: {config.RecognitionSNRThreshold}dB");
|
||
|
||
return angle <= currentBeamWidth;
|
||
}
|
||
else
|
||
{
|
||
// 跟踪/锁定模式使用单脉冲测角
|
||
var (azError, elError) = ProcessMonopulse(toTarget.Normalize(), missileVelocity);
|
||
Console.WriteLine($"[单脉冲测角] 方位误差: {azError * 180/Math.PI:F3}度, 俯仰误差: {elError * 180/Math.PI:F3}度");
|
||
Console.WriteLine($"[波束宽度检查] 当前阈值: {currentBeamWidth * 180/Math.PI:F3}度,实际误差: {Math.Sqrt(azError*azError + elError*elError) * 180/Math.PI:F3}度");
|
||
return Math.Sqrt(azError*azError + elError*elError) < currentBeamWidth;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 更新制导系统的状态
|
||
/// </summary>
|
||
/// <param name="deltaTime">自上次更新以来的时间间隔,单位:秒</param>
|
||
/// <param name="missilePosition">导弹当前位置,单位:米</param>
|
||
/// <param name="missileVelocity">导弹当前速度,单位:米/秒</param>
|
||
/// <remarks>
|
||
/// 更新过程:
|
||
/// - 探测目标位置
|
||
/// - 计算目标速度
|
||
/// - 生成制导指令
|
||
/// - 限制最大加速度
|
||
/// </remarks>
|
||
public override void Update(double deltaTime, Vector3D missilePosition, Vector3D missileVelocity)
|
||
{
|
||
base.Update(deltaTime, missilePosition, missileVelocity); // 更新基类状态和干扰状态
|
||
|
||
// 在执行核心逻辑前检查干扰状态
|
||
if (IsJammed) // 使用基类的 IsJammed 状态
|
||
{
|
||
// 如果被干扰,确保处于搜索模式并且没有制导
|
||
if (currentMode != WorkMode.Search)
|
||
{
|
||
SwitchToSearchMode();
|
||
}
|
||
HasGuidance = false;
|
||
GuidanceAcceleration = Vector3D.Zero;
|
||
// Debug.WriteLine($"[MMW_GUIDANCE] {Id} 处于干扰状态,跳过制导计算。", "Jamming");
|
||
return; // 不执行后续逻辑
|
||
}
|
||
|
||
// 更新扫描参数
|
||
UpdateConicalScan(deltaTime);
|
||
|
||
if (TryDetectAndTrackTarget(missilePosition, missileVelocity, deltaTime, out Vector3D currentTargetPosition))
|
||
{
|
||
targetLostTimer = 0;
|
||
Vector3D? currentTargetVelocity = null;
|
||
if (lastTargetPosition != null && deltaTime > 0)
|
||
{
|
||
currentTargetVelocity = (currentTargetPosition - lastTargetPosition) / deltaTime;
|
||
}
|
||
|
||
lastTargetPosition = currentTargetPosition;
|
||
lastTargetVelocity = currentTargetVelocity;
|
||
|
||
GuidanceAcceleration = MotionAlgorithm.CalculateProportionalNavigation(
|
||
ProportionalNavigationCoefficient,
|
||
missilePosition,
|
||
missileVelocity,
|
||
currentTargetPosition,
|
||
currentTargetVelocity ?? Vector3D.Zero
|
||
);
|
||
|
||
if (GuidanceAcceleration.Magnitude() > MaxAcceleration)
|
||
{
|
||
GuidanceAcceleration = GuidanceAcceleration.Normalize() * MaxAcceleration;
|
||
}
|
||
|
||
Console.WriteLine($"制导加速度: {GuidanceAcceleration}");
|
||
HasGuidance = true;
|
||
}
|
||
else
|
||
{
|
||
if (currentMode != WorkMode.Search)
|
||
{
|
||
targetLostTimer += deltaTime;
|
||
if (targetLostTimer >= config.TargetLostTolerance)
|
||
{
|
||
HasGuidance = false;
|
||
Trace.WriteLine($"目标丢失 {targetLostTimer:F3}秒,切换回搜索模式");
|
||
SwitchToSearchMode();
|
||
}
|
||
}
|
||
else
|
||
{
|
||
HasGuidance = false;
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 尝试探测和跟踪目标
|
||
/// </summary>
|
||
/// <param name="missilePosition">导弹当前位置,单位:米</param>
|
||
/// <param name="missileVelocity">导弹当前速度,单位:米/秒</param>
|
||
/// <param name="deltaTime">自上次更新以来的时间间隔,单位:秒</param>
|
||
/// <param name="targetPosition">输出探测到的目标位置,单位:米</param>
|
||
/// <returns>是否成功探测到目标</returns>
|
||
/// <remarks>
|
||
/// 探测过程:
|
||
/// - 检查干扰状态
|
||
/// - 遍历场景中的目标
|
||
/// - 检查距离和角度
|
||
/// - 计算信噪比
|
||
/// - 判断目标有效性
|
||
/// </remarks>
|
||
private bool TryDetectAndTrackTarget(Vector3D missilePosition, Vector3D missileVelocity, double deltaTime, out Vector3D targetPosition)
|
||
{
|
||
targetPosition = Vector3D.Zero;
|
||
double minDistance = double.MaxValue;
|
||
bool foundTarget = false;
|
||
double currentSNR = double.MinValue;
|
||
|
||
if (IsJammed)
|
||
{
|
||
HasGuidance = false;
|
||
return false;
|
||
}
|
||
|
||
foreach (var element in SimulationManager.GetEntitiesByType<SimulationElement>())
|
||
{
|
||
if (element is BaseEquipment target)
|
||
{
|
||
Vector3D toTarget = target.Position - missilePosition;
|
||
double distance = toTarget.Magnitude();
|
||
|
||
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;
|
||
minDistance = distance;
|
||
foundTarget = true;
|
||
currentSNR = snr;
|
||
}
|
||
}
|
||
else if (currentMode == WorkMode.Track || currentMode == WorkMode.Lock)
|
||
{
|
||
if (IsTargetInBeam(missileVelocity, toTarget) &&
|
||
lastTargetPosition != null &&
|
||
Vector3D.Distance(target.Position, lastTargetPosition) < 100.0)
|
||
{
|
||
double requiredSNR = (currentMode == WorkMode.Track) ?
|
||
config.RecognitionSNRThreshold : config.LockSNRThreshold;
|
||
|
||
if (snr >= requiredSNR)
|
||
{
|
||
targetPosition = target.Position;
|
||
foundTarget = true;
|
||
currentSNR = snr;
|
||
Console.WriteLine($"[目标跟踪] 距离: {distance:F1}米, SNR: {snr:F2}dB, 要求SNR: {requiredSNR:F2}dB");
|
||
break;
|
||
}
|
||
else
|
||
{
|
||
Console.WriteLine($"[目标丢失] 距离: {distance:F1}米, SNR: {snr:F2}dB, 要求SNR: {requiredSNR:F2}dB");
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
UpdateSystemState(foundTarget, currentSNR, deltaTime);
|
||
HasTarget = foundTarget;
|
||
return foundTarget;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 更新系统状态
|
||
/// </summary>
|
||
private void UpdateSystemState(bool hasTarget, double snr, double deltaTime)
|
||
{
|
||
if (!hasTarget)
|
||
{
|
||
targetLostTimer += deltaTime;
|
||
if (targetLostTimer >= config.TargetLostTolerance)
|
||
{
|
||
SwitchToSearchMode();
|
||
}
|
||
return;
|
||
}
|
||
|
||
targetLostTimer = 0;
|
||
|
||
switch (currentMode)
|
||
{
|
||
case WorkMode.Search:
|
||
if (snr >= config.RecognitionSNRThreshold)
|
||
{
|
||
SwitchToTrackMode();
|
||
}
|
||
break;
|
||
|
||
case WorkMode.Track:
|
||
if (snr >= config.LockSNRThreshold)
|
||
{
|
||
lockConfirmationTimer += deltaTime;
|
||
if (lockConfirmationTimer >= config.LockConfirmationTime)
|
||
{
|
||
SwitchToLockMode();
|
||
}
|
||
}
|
||
else
|
||
{
|
||
lockConfirmationTimer = 0;
|
||
}
|
||
break;
|
||
|
||
case WorkMode.Lock:
|
||
if (snr < config.LockSNRThreshold)
|
||
{
|
||
SwitchToTrackMode();
|
||
}
|
||
break;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取制导系统的详细状态信息
|
||
/// </summary>
|
||
/// <returns>包含完整状态参数的ElementStatusInfo对象</returns>
|
||
/// <remarks>
|
||
/// 特有的返回信息:
|
||
/// - 当前模式
|
||
/// - 目标位置
|
||
/// - 目标速度
|
||
/// - 是否有目标
|
||
/// 用于系统监控和调试
|
||
/// </remarks>
|
||
public override ElementStatusInfo GetStatusInfo()
|
||
{
|
||
var statusInfo = base.GetStatusInfo();
|
||
|
||
string lastPosStr = lastTargetPosition != null ? lastTargetPosition.ToString() : "null";
|
||
string lastVelStr = lastTargetVelocity != null ? lastTargetVelocity.ToString() : "null";
|
||
|
||
statusInfo.ExtendedProperties["Mode"] = currentMode.ToString();
|
||
statusInfo.ExtendedProperties["LastTargetPosition"] = lastPosStr;
|
||
statusInfo.ExtendedProperties["LastTargetVelocity"] = lastVelStr;
|
||
statusInfo.ExtendedProperties["HasTarget"] = HasTarget.ToString();
|
||
|
||
return statusInfo;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 计算目标的信噪比
|
||
/// </summary>
|
||
/// <param name="distance">到目标的距离,单位:米</param>
|
||
/// <param name="radarCrossSection">目标雷达散射截面积,单位:平方米</param>
|
||
/// <returns>信噪比,单位:分贝</returns>
|
||
/// <remarks>
|
||
/// 计算过程:
|
||
/// - 设置雷达参数
|
||
/// - 计算信号功率
|
||
/// - 计算噪声功率
|
||
/// - 计算信噪比
|
||
/// - 转换为分贝值
|
||
/// </remarks>
|
||
private double CalculateSNR(double distance, double radarCrossSection)
|
||
{
|
||
// 雷达参数
|
||
double transmitPower = config.TransmitPower; // 发射功率(W),典型值0.3W
|
||
double antennaGain = Math.Pow(10, config.AntennaGainDB/10); // 天线增益(线性值)
|
||
double wavelength = 3e8 / config.WaveFrequency; // 波长(m),94GHz -> 3.19mm
|
||
double bandwidth = 1.0 / config.PulseDuration; // 带宽(Hz),由脉冲持续时间决定
|
||
double noiseFigure = Math.Pow(10, config.NoiseFigureDB/10); // 噪声系数(线性值)
|
||
|
||
// 系统损耗,单位:dB
|
||
double atmosphericLoss = 0.4 * distance / 1000.0; // 大气衰减,0.4dB/km
|
||
double totalLoss = Math.Pow(10, (atmosphericLoss + config.SystemLossDB) / 10); // 转换为线性值
|
||
|
||
// 常量
|
||
double k = 1.38e-23; // 玻尔兹曼常数
|
||
double T0 = 290; // 标准噪声温度(K)
|
||
|
||
// 计算接收信号功率
|
||
double signalPower = (transmitPower * Math.Pow(antennaGain, 2) * Math.Pow(wavelength, 2) * radarCrossSection)
|
||
/ (Math.Pow(4 * Math.PI, 3) * Math.Pow(distance, 4) * totalLoss);
|
||
|
||
// 考虑大气透过率,如果当前天气为null,则认为大气透过率为1.0
|
||
double atmosphericTransmittance = 1.0;
|
||
|
||
if(SimulationManager.CurrentWeather != null)
|
||
{
|
||
atmosphericTransmittance = AtmosphereDllWrapper.CalculateTransmittance(
|
||
distance,
|
||
RadiationType.MillimeterWave,
|
||
wavelength,
|
||
SimulationManager.CurrentWeather);
|
||
}
|
||
|
||
signalPower *= atmosphericTransmittance;
|
||
|
||
// 应用当前生效的烟幕衰减 (通过存储的透过率)
|
||
signalPower *= _currentSmokeTransmittance;
|
||
|
||
// 计算噪声功率
|
||
double noisePower = k * T0 * bandwidth * noiseFigure;
|
||
|
||
// 计算信噪比
|
||
double snr = signalPower / noisePower;
|
||
|
||
// 转换为dB
|
||
return 10 * Math.Log10(snr);
|
||
}
|
||
}
|
||
}
|
||
|