using ThreatSource.Utils;
using ThreatSource.Equipment;
using System.Diagnostics;
using ThreatSource.Jammer;
using ThreatSource.Simulation;
using AirTransmission;
namespace ThreatSource.Guidance
{
///
/// 毫米波导引头系统类,实现了基于毫米波雷达的目标探测和跟踪功能
///
///
/// 该类提供了毫米波导引头系统的核心功能:
/// - 目标探测和识别
/// - 信噪比计算
/// - 抗干扰处理
/// - 比例导引控制
/// 用于实现全天候制导打击
///
public class MillimeterWaveGuidanceSystem : BasicGuidanceSystem
{
///
/// 工作模式枚举
///
private enum WorkMode
{
Search, // 搜索模式
Track, // 跟踪模式
Lock // 锁定模式
}
///
/// 毫米波导引系统配置
///
///
/// 存储系统的所有可配置参数
/// 包括探测范围、视场角等
///
private readonly MillimeterWaveGuidanceConfig config;
///
/// 随机数生成器实例
///
///
/// 用于生成随机扰动
/// 模拟系统噪声和识别概率
///
private readonly Random random = new();
///
/// 上一次探测到的目标位置
///
///
/// 记录目标的历史位置
/// 用于计算目标速度
///
private Vector3D lastTargetPosition;
///
/// 上一次探测到的目标速度
///
///
/// 记录目标的历史速度
/// 用于计算目标速度
///
private Vector3D lastTargetVelocity;
///
/// 目标丢失计时器
///
///
/// 记录目标丢失的时间
/// 用于切换到搜索模式
///
private double targetLostTimer = 0;
///
/// 锁定确认计时器
///
///
/// 记录锁定确认的时间
/// 用于切换到锁定模式
///
private double lockConfirmationTimer = 0;
///
/// 当前工作模式
///
private WorkMode currentMode = WorkMode.Search;
///
/// 是否受到干扰
///
///
/// 指示当前是否受到电子干扰
/// 影响系统的工作状态
///
private bool isJammed = false;
///
/// 干扰功率,单位:瓦特
///
///
/// 记录接收到的干扰信号功率
/// 用于评估干扰效果
///
private double jammingPower = 0;
///
/// 是否有目标
///
public bool HasTarget { get; private set; }
///
/// 是否在锁定模式
///
public bool IsInLockMode => currentMode == WorkMode.Lock;
///
/// 当前扫描角度,单位:弧度
///
private double currentScanAngle = 0;
///
/// 当前扫描半径,单位:弧度
///
private double currentScanRadius = 0;
///
/// 最大扫描半径,单位:弧度
///
private double maxScanRadius => config.FieldOfViewAngle * Math.PI / 180.0 / 2;
///
/// 初始化毫米波制导系统的新实例
///
/// 制导系统ID
/// 最大加速度,单位:米/平方秒
/// 制导系数
/// 仿真管理器实例
/// 毫米波导引系统配置
///
/// 构造过程:
/// - 初始化基类参数
/// - 设置仿真管理器
/// - 初始化目标位置
/// - 注册干扰事件处理
/// - 加载干扰阈值配置
///
public MillimeterWaveGuidanceSystem(
string id,
double maxAcceleration,
double guidanceCoefficient,
MillimeterWaveGuidanceConfig config,
ISimulationManager simulationManager)
: base(id, maxAcceleration, guidanceCoefficient, simulationManager)
{
this.config = config;
lastTargetPosition = Vector3D.Zero;
lastTargetVelocity = Vector3D.Zero;
InitializeJamming(config.JammingResistanceThreshold, [JammingType.MillimeterWave]);
SwitchToSearchMode(); // 初始化为搜索模式
}
///
/// 切换到搜索模式
///
public void SwitchToSearchMode()
{
currentMode = WorkMode.Search;
HasTarget = false;
HasGuidance = false;
targetLostTimer = 0;
lockConfirmationTimer = 0;
currentScanAngle = 0;
currentScanRadius = config.SearchBeamWidth * Math.PI / 720.0; // 从半个波束宽度的一半开始
Trace.WriteLine($"切换到搜索模式,波束宽度: {config.SearchBeamWidth}度");
}
///
/// 切换到跟踪模式
///
private void SwitchToTrackMode()
{
currentMode = WorkMode.Track;
lockConfirmationTimer = 0;
HasGuidance = true;
Trace.WriteLine($"切换到跟踪模式,波束宽度: {config.TrackBeamWidth}度");
}
///
/// 切换到锁定模式
///
private void SwitchToLockMode()
{
currentMode = WorkMode.Lock;
HasGuidance = true;
Trace.WriteLine("切换到锁定模式 - 目标锁定成功");
}
///
/// 激活制导系统
///
public override void Activate()
{
if (!IsActive)
{
IsActive = true;
// 在这里订阅事件,确保只订阅一次
SimulationManager.SubscribeToEvent(OnMillimeterWaveJamming);
}
base.Activate();
SwitchToSearchMode();
}
///
/// 停用制导系统
///
public override void Deactivate()
{
if (IsActive)
{
IsActive = false;
SimulationManager.UnsubscribeFromEvent(OnMillimeterWaveJamming);
}
base.Deactivate();
HasTarget = false;
HasGuidance = false;
GuidanceAcceleration = Vector3D.Zero;
}
///
/// 处理毫米波干扰事件
///
/// 干扰事件参数
///
/// 处理过程:
/// - 更新干扰状态
/// - 记录干扰功率
///
private void OnMillimeterWaveJamming(MillimeterWaveJammingEvent evt)
{
if (evt == null) return;
// 创建干扰参数
var parameters = new JammingParameters
{
Type = JammingType.MillimeterWave,
Power = evt.JammingPower,
Direction = evt.JammingDirection,
SourcePosition = evt.JammingSourcePosition,
AngleRange = evt.JammingAngleRange,
Mode = evt.JammingMode,
Duration = evt.Duration
};
// 使用JammableComponent进行干扰判断
ApplyJamming(parameters);
Debug.WriteLine($"毫米波导引头系统干扰状态 - IsJammed: {IsJammed}, 干扰功率: {evt.JammingPower}W, 抗性阈值: {config.JammingResistanceThreshold}W");
}
///
/// 处理系统被干扰的事件
///
/// 干扰参数
protected override void HandleJammingApplied(JammingParameters parameters)
{
if (parameters.Type == JammingType.MillimeterWave)
{
Debug.WriteLine($"毫米波导引头系统受到毫米波干扰,功率:{parameters.Power}瓦特");
// 确保基类的处理逻辑被调用,设置HasGuidance = false
base.HandleJammingApplied(parameters);
}
// 在强干扰下切换到搜索模式
if (currentMode != WorkMode.Search)
{
SwitchToSearchMode();
}
}
///
/// 处理系统干扰被清除的事件
///
/// 被清除的干扰类型
protected override void HandleJammingCleared(JammingType type)
{
if (type == JammingType.MillimeterWave)
{
Debug.WriteLine("毫米波导引头系统干扰被清除");
base.HandleJammingCleared(type);
}
}
///
/// 更新圆锥扫描参数
///
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;
}
}
///
/// 单脉冲和差测角处理(仅用于跟踪/锁定模式)
///
/// 弹目视线方向向量
/// 导弹速度向量
/// (方位误差弧度, 俯仰误差弧度)
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
);
}
///
/// 计算目标是否在当前扫描波束内
///
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;
}
}
///
/// 更新制导系统的状态
///
/// 自上次更新以来的时间间隔,单位:秒
/// 导弹当前位置,单位:米
/// 导弹当前速度,单位:米/秒
///
/// 更新过程:
/// - 探测目标位置
/// - 计算目标速度
/// - 生成制导指令
/// - 限制最大加速度
///
public override void Update(double deltaTime, Vector3D missilePosition, Vector3D missileVelocity)
{
// 更新扫描参数
UpdateConicalScan(deltaTime);
base.Update(deltaTime, missilePosition, missileVelocity);
if (!IsJammed)
{
if (TryDetectAndTrackTarget(missilePosition, missileVelocity, deltaTime, out Vector3D targetPosition))
{
targetLostTimer = 0;
Vector3D targetVelocity = (targetPosition - lastTargetPosition) / deltaTime;
lastTargetPosition = targetPosition;
lastTargetVelocity = targetVelocity;
// 使用比例导引计算制导加速度
GuidanceAcceleration = MotionAlgorithm.CalculateProportionalNavigation(
ProportionalNavigationCoefficient,
missilePosition,
missileVelocity,
targetPosition,
targetVelocity
);
// 限制最大加速度
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;
}
}
}
else
{
HasGuidance = false;
GuidanceAcceleration = Vector3D.Zero;
}
}
///
/// 尝试探测和跟踪目标
///
/// 导弹当前位置,单位:米
/// 导弹当前速度,单位:米/秒
/// 自上次更新以来的时间间隔,单位:秒
/// 输出探测到的目标位置,单位:米
/// 是否成功探测到目标
///
/// 探测过程:
/// - 检查干扰状态
/// - 遍历场景中的目标
/// - 检查距离和角度
/// - 计算信噪比
/// - 判断目标有效性
///
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;
// 如果被干扰,直接返回false
if (isJammed)
{
Trace.WriteLine($"毫米波导引头受到干扰,干扰功率: {jammingPower:F2}W");
HasGuidance = false;
return false;
}
foreach (var element in SimulationManager.GetEntitiesByType())
{
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) &&
Vector3D.Distance(target.Position, lastTargetPosition) < 100.0)
{
// 在跟踪模式下,SNR至少要达到识别阈值
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;
}
///
/// 更新系统状态
///
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;
}
}
///
/// 获取制导系统的详细状态信息
///
/// 包含完整状态参数的字符串
///
/// 返回信息:
/// - 基本状态信息
/// - 目标位置
/// 用于系统监控和调试
///
public override string GetStatus()
{
return base.GetStatus() +
$"\n当前模式: {currentMode}" +
$"\n目标位置: {lastTargetPosition}" +
$"\n目标速度: {lastTargetVelocity}" +
$"\n是否有目标: {HasTarget}";
}
///
/// 计算目标的信噪比
///
/// 到目标的距离,单位:米
/// 目标雷达散射截面积,单位:平方米
/// 信噪比,单位:分贝
///
/// 计算过程:
/// - 设置雷达参数
/// - 计算信号功率
/// - 计算噪声功率
/// - 计算信噪比
/// - 转换为分贝值
///
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;
// 计算噪声功率
double noisePower = k * T0 * bandwidth * noiseFigure;
// 计算信噪比
double snr = signalPower / noisePower;
// 转换为dB
return 10 * Math.Log10(snr);
}
}
}