完善各组件的干扰处理
This commit is contained in:
parent
fedd54d999
commit
c0c8c4b3a6
@ -16,7 +16,13 @@
|
||||
- 多种发射弹道模式:低平弹道、高抛弹道、俯冲弹道
|
||||
- 双模、多模制导
|
||||
- Orientation 坐标系的调整(前向方向从 X 轴改为 Z 轴)
|
||||
- 末敏弹各探测组件的干扰处理,增加毫米波补偿干扰
|
||||
|
||||
## [0.2.16] - 2025-05-09
|
||||
- 支持每个组件同时处理多种干扰
|
||||
- 把各组件的烟幕透过率计算移到 update 方法中
|
||||
- 完善了指示器的烟幕遮挡计算逻辑
|
||||
- 完善了激光半主动导弹的落点计算逻辑
|
||||
- 完善了配置文件格式
|
||||
|
||||
## [0.2.15] - 2025-05-07
|
||||
- 增加了毫米波补偿干扰器
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
"type": "LaserDecoy",
|
||||
"LaserDecoyConfig": {
|
||||
"Mode": "Deception",
|
||||
"Power": 25.0,
|
||||
"Power": 200.0,
|
||||
"Wavelength": 1.06,
|
||||
"DivergenceAngle": 0.001,
|
||||
"ReflectiveArea": 1.2,
|
||||
|
||||
20
ThreatSource/data/jammers/smoke_grenades/mmw.json
Normal file
20
ThreatSource/data/jammers/smoke_grenades/mmw.json
Normal file
@ -0,0 +1,20 @@
|
||||
{
|
||||
"name": {
|
||||
"zh": "周边烟幕弹",
|
||||
"en": "Surround Smoke Grenade"
|
||||
},
|
||||
"type": "SmokeGrenade",
|
||||
"SmokeGrenadeConfig": {
|
||||
"smokeType": "Wall",
|
||||
"IsObscuring": true,
|
||||
"RadiationTemperature": 173.15,
|
||||
"concentration": 0.2,
|
||||
"duration": 60.0,
|
||||
"wallWidth": 50.0,
|
||||
"wallHeight": 10.0,
|
||||
"cloudDiameter": 0.0,
|
||||
"thickness": 5.0,
|
||||
"formationDelay": 2.0,
|
||||
"expansionRate": 5.0
|
||||
}
|
||||
}
|
||||
@ -5,6 +5,7 @@
|
||||
},
|
||||
"type": "InfraredCommandGuidance",
|
||||
"properties": {
|
||||
"type": "InfraredCommandGuidance",
|
||||
"maxSpeed": 300.0,
|
||||
"maxFlightTime": 60.0,
|
||||
"maxFlightDistance": 5000.0,
|
||||
|
||||
@ -5,6 +5,7 @@
|
||||
},
|
||||
"type": "InfraredImagingTerminalGuidance",
|
||||
"properties": {
|
||||
"type": "InfraredImagingTerminalGuidance",
|
||||
"maxSpeed": 250.0,
|
||||
"maxFlightTime": 60.0,
|
||||
"maxFlightDistance": 5000.0,
|
||||
|
||||
@ -5,6 +5,7 @@
|
||||
},
|
||||
"type": "LaserBeamRiderGuidance",
|
||||
"properties": {
|
||||
"type": "LaserBeamRiderGuidance",
|
||||
"maxSpeed": 300.0,
|
||||
"maxFlightTime": 60.0,
|
||||
"maxFlightDistance": 5000.0,
|
||||
|
||||
@ -5,6 +5,7 @@
|
||||
},
|
||||
"type": "LaserBeamRiderGuidance",
|
||||
"properties": {
|
||||
"type": "LaserBeamRiderGuidance",
|
||||
"maxSpeed": 300.0,
|
||||
"maxFlightTime": 70.0,
|
||||
"maxFlightDistance": 5500.0,
|
||||
|
||||
@ -5,6 +5,7 @@
|
||||
},
|
||||
"type": "LaserBeamRiderGuidance",
|
||||
"properties": {
|
||||
"type": "LaserBeamRiderGuidance",
|
||||
"maxSpeed": 278.0,
|
||||
"maxFlightTime": 65.0,
|
||||
"maxFlightDistance": 4500.0,
|
||||
|
||||
@ -5,6 +5,7 @@
|
||||
},
|
||||
"type": "LaserSemiActiveGuidance",
|
||||
"properties": {
|
||||
"type": "LaserSemiActiveGuidance",
|
||||
"maxSpeed": 800.0,
|
||||
"maxFlightTime": 60.0,
|
||||
"maxFlightDistance": 4000.0,
|
||||
|
||||
@ -5,6 +5,7 @@
|
||||
},
|
||||
"type": "MillimeterWaveTerminalGuidance",
|
||||
"properties": {
|
||||
"type": "MillimeterWaveTerminalGuidance",
|
||||
"maxSpeed": 250.0,
|
||||
"maxFlightTime": 60.0,
|
||||
"maxFlightDistance": 8000.0,
|
||||
|
||||
@ -5,6 +5,7 @@
|
||||
},
|
||||
"type": "TerminalSensitiveMissile",
|
||||
"properties": {
|
||||
"type": "TerminalSensitiveMissile",
|
||||
"maxSpeed": 1000.0,
|
||||
"maxFlightTime": 100.0,
|
||||
"maxFlightDistance": 5000.0,
|
||||
|
||||
@ -4,31 +4,32 @@
|
||||
"en": "Armored Personnel Carrier-001"
|
||||
},
|
||||
"type": "APC",
|
||||
"mass": 25000.0,
|
||||
"length": 7.0,
|
||||
"width": 3.2,
|
||||
"height": 2.8,
|
||||
"maxSpeed": 80.0,
|
||||
"armorThickness": 400.0,
|
||||
|
||||
"radarCrossSection": 12.0,
|
||||
"infraredRadiationIntensity": 2000.0,
|
||||
"ultravioletRadiationIntensity": 12.0,
|
||||
"millimeterWaveRadiationIntensity": 8.0,
|
||||
"millimeterWaveRadiationTemperature": 350.0,
|
||||
"laserReflectivity": 0.25,
|
||||
|
||||
"thermalPattern": {
|
||||
"description": "3x3 matrix representing side view temperature distribution (°C)",
|
||||
"static": [
|
||||
[35, 40, 65],
|
||||
[30, 35, 70],
|
||||
[40, 40, 45]
|
||||
],
|
||||
"moving": [
|
||||
[40, 45, 70],
|
||||
[35, 40, 75],
|
||||
[50, 50, 55]
|
||||
]
|
||||
"properties": {
|
||||
"type": "APC",
|
||||
"mass": 25000.0,
|
||||
"length": 7.0,
|
||||
"width": 3.2,
|
||||
"height": 2.8,
|
||||
"maxSpeed": 80.0,
|
||||
"armorThickness": 400.0,
|
||||
"radarCrossSection": 12.0,
|
||||
"infraredRadiationIntensity": 2000.0,
|
||||
"ultravioletRadiationIntensity": 12.0,
|
||||
"millimeterWaveRadiationIntensity": 8.0,
|
||||
"millimeterWaveRadiationTemperature": 350.0,
|
||||
"laserReflectivity": 0.25,
|
||||
"thermalPattern": {
|
||||
"description": "3x3 matrix representing side view temperature distribution (°C)",
|
||||
"static": [
|
||||
[35, 40, 65],
|
||||
[30, 35, 70],
|
||||
[40, 40, 45]
|
||||
],
|
||||
"moving": [
|
||||
[40, 45, 70],
|
||||
[35, 40, 75],
|
||||
[50, 50, 55]
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -4,31 +4,32 @@
|
||||
"en": "Attack Helicopter-001"
|
||||
},
|
||||
"type": "Helicopter",
|
||||
"mass": 10000.0,
|
||||
"length": 17.0,
|
||||
"width": 3.0,
|
||||
"height": 4.5,
|
||||
"maxSpeed": 280.0,
|
||||
"armorThickness": 150.0,
|
||||
|
||||
"radarCrossSection": 8.0,
|
||||
"infraredRadiationIntensity": 3000.0,
|
||||
"ultravioletRadiationIntensity": 20.0,
|
||||
"millimeterWaveRadiationIntensity": 6.0,
|
||||
"millimeterWaveRadiationTemperature": 450.0,
|
||||
"laserReflectivity": 0.2,
|
||||
|
||||
"thermalPattern": {
|
||||
"description": "3x3 matrix representing side view temperature distribution (°C)",
|
||||
"static": [
|
||||
[85, 110, 80],
|
||||
[35, 45, 40],
|
||||
[30, 35, 30]
|
||||
],
|
||||
"moving": [
|
||||
[90, 115, 85],
|
||||
[40, 50, 45],
|
||||
[35, 40, 35]
|
||||
]
|
||||
"properties": {
|
||||
"type": "Helicopter",
|
||||
"mass": 10000.0,
|
||||
"length": 17.0,
|
||||
"width": 3.0,
|
||||
"height": 4.5,
|
||||
"maxSpeed": 280.0,
|
||||
"armorThickness": 150.0,
|
||||
"radarCrossSection": 8.0,
|
||||
"infraredRadiationIntensity": 3000.0,
|
||||
"ultravioletRadiationIntensity": 20.0,
|
||||
"millimeterWaveRadiationIntensity": 6.0,
|
||||
"millimeterWaveRadiationTemperature": 450.0,
|
||||
"laserReflectivity": 0.2,
|
||||
"thermalPattern": {
|
||||
"description": "3x3 matrix representing side view temperature distribution (°C)",
|
||||
"static": [
|
||||
[85, 110, 80],
|
||||
[35, 45, 40],
|
||||
[30, 35, 30]
|
||||
],
|
||||
"moving": [
|
||||
[90, 115, 85],
|
||||
[40, 50, 45],
|
||||
[35, 40, 35]
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -5,6 +5,7 @@
|
||||
},
|
||||
"type": "Tank",
|
||||
"properties": {
|
||||
"type": "Tank",
|
||||
"mass": 50000.0,
|
||||
"length": 10.0,
|
||||
"width": 3.5,
|
||||
|
||||
@ -221,6 +221,7 @@ namespace ThreatSource.Guidance
|
||||
// 添加制导系统特有属性
|
||||
statusInfo.ExtendedProperties["HasGuidance"] = HasGuidance;
|
||||
statusInfo.ExtendedProperties["IsJammed"] = IsJammed;
|
||||
statusInfo.ExtendedProperties["IsBlockingJammed"] = IsBlockingJammed;
|
||||
statusInfo.ExtendedProperties["GuidanceAcceleration"] = GuidanceAcceleration;
|
||||
statusInfo.ExtendedProperties["MaxAcceleration"] = MaxAcceleration;
|
||||
statusInfo.ExtendedProperties["ProportionalNavigationCoefficient"] = ProportionalNavigationCoefficient;
|
||||
@ -366,7 +367,7 @@ namespace ThreatSource.Guidance
|
||||
/// </remarks>
|
||||
protected void InitializeJamming(double jammingResistanceThreshold, IEnumerable<JammingType> supportedTypes, IEnumerable<JammingType> supportedBlockingTypes)
|
||||
{
|
||||
_jammingComponent.LoadJammingConfigFromThreshold(jammingResistanceThreshold, supportedTypes);
|
||||
_jammingComponent.LoadJammingConfigFromThreshold(jammingResistanceThreshold, supportedBlockingTypes);
|
||||
foreach (var type in supportedTypes)
|
||||
{
|
||||
_jammingComponent.AddSupportedJammingType(type);
|
||||
|
||||
@ -102,12 +102,6 @@ namespace ThreatSource.Guidance
|
||||
/// </summary>
|
||||
private double lockConfirmationTimer = 0;
|
||||
|
||||
/// <summary>
|
||||
/// 烟幕衰减
|
||||
/// </summary>
|
||||
private double SmokeAttenuation { get; set; } = 1.0;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 初始化红外成像制导系统的新实例
|
||||
/// </summary>
|
||||
@ -164,36 +158,14 @@ namespace ThreatSource.Guidance
|
||||
{
|
||||
Debug.WriteLine($"红外引导系统受到红外干扰,功率:{parameters.Power}瓦特");
|
||||
|
||||
// 在强干扰下切换到搜索模式
|
||||
if (currentMode != WorkMode.Search)
|
||||
{
|
||||
SwitchToSearchMode();
|
||||
}
|
||||
// 调用基类处理硬干扰状态
|
||||
base.HandleJammingApplied(parameters);
|
||||
}
|
||||
else if (parameters.Type == JammingType.SmokeGrenade)
|
||||
{
|
||||
if (SimulationManager.GetEntityById(parameters.JammerId) is SmokeGrenade smokeGrenade)
|
||||
{
|
||||
if (lastTargetPosition != null)
|
||||
{
|
||||
// 计算烟幕衰减 (这里存储衰减系数,1.0表示无衰减)
|
||||
SmokeAttenuation = smokeGrenade.GetSmokeTransmittanceOnLine(Position, lastTargetPosition, config.Wavelength);
|
||||
Console.WriteLine($"[烟幕干扰IR] 视线透过率: {SmokeAttenuation:F3}");
|
||||
}
|
||||
else
|
||||
{
|
||||
// 目标尚未有效跟踪,计算视线方向衰减
|
||||
var intersection = MotionAlgorithm.CalculateIntersectionWithGround(Position, Orientation.ToVector(), 0);
|
||||
Console.WriteLine($"[###烟幕干扰IR] 计算视线方向衰减,交点: {intersection}");
|
||||
if (intersection != null)
|
||||
{
|
||||
SmokeAttenuation = smokeGrenade.GetSmokeTransmittanceOnLine(Position, intersection, config.Wavelength);
|
||||
Console.WriteLine($"[烟幕干扰IR] 没有发现目标位置,只计算视线透过率: {SmokeAttenuation:F3}");
|
||||
}
|
||||
}
|
||||
}
|
||||
Debug.WriteLine($"[IR IMAGING] 烟幕干扰事件 {parameters.JammerId} 应用。", "Jamming");
|
||||
}
|
||||
}
|
||||
|
||||
@ -212,8 +184,7 @@ namespace ThreatSource.Guidance
|
||||
}
|
||||
else if (parameters.Type == JammingType.SmokeGrenade)
|
||||
{
|
||||
SmokeAttenuation = 1.0;
|
||||
Debug.WriteLine("[烟幕干扰清除 IR]");
|
||||
Debug.WriteLine($"[IR IMAGING] 烟幕干扰事件 {parameters.JammerId} 清除。", "Jamming");
|
||||
}
|
||||
}
|
||||
|
||||
@ -235,9 +206,6 @@ namespace ThreatSource.Guidance
|
||||
HasTarget = false;
|
||||
HasGuidance = false;
|
||||
GuidanceAcceleration = Vector3D.Zero;
|
||||
// Optionally reset timers?
|
||||
// targetLostTimer = 0;
|
||||
// lockConfirmationTimer = 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -260,17 +228,13 @@ namespace ThreatSource.Guidance
|
||||
{
|
||||
targetLostTimer = 0; // 重置丢失计时器
|
||||
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;
|
||||
|
||||
// Use proportional navigation, provide default if velocity is null
|
||||
GuidanceAcceleration = MotionAlgorithm.CalculateProportionalNavigation(
|
||||
ProportionalNavigationCoefficient,
|
||||
Position,
|
||||
@ -418,20 +382,21 @@ namespace ThreatSource.Guidance
|
||||
{
|
||||
// 检查视线角条件
|
||||
double angle = Math.Acos(Vector3D.DotProduct(toTarget.Normalize(), missileVelocity.Normalize()));
|
||||
Console.WriteLine($"[红外成像制导系统] 目标 {target.Id} 视线角: {angle * 180 / Math.PI} 度, 视场角范围: {currentFov * 180 / Math.PI} 度");
|
||||
if (angle <= currentFov / 2)
|
||||
{
|
||||
// 在生成红外图像前,检查目标是否被烟幕遮挡
|
||||
bool isTargetObscuredBySmoke = CheckIfTargetObscuredBySmoke(missilePosition, target);
|
||||
if (isTargetObscuredBySmoke)
|
||||
// 在生成红外图像前,检查目标是否被烟幕几何遮挡
|
||||
bool isTargetGeometricallyObscured = CheckIfTargetObscuredBySmoke(missilePosition, target);
|
||||
if (isTargetGeometricallyObscured)
|
||||
{
|
||||
Console.WriteLine($"[红外成像制导系统] 目标 {target.Id} 被烟幕完全遮挡,跳过图像生成");
|
||||
Console.WriteLine($"[红外成像制导系统] 目标 {target.Id} 被烟幕几何遮挡,跳过图像生成");
|
||||
continue; // 如果目标被完全遮挡,跳过此目标
|
||||
}
|
||||
|
||||
// 实时计算当前目标到导弹之间的烟幕透过率
|
||||
double liveSmokeTransmittance = CalculateLiveSmokeTransmittance(missilePosition, target.Position);
|
||||
|
||||
// 生成红外图像
|
||||
Console.WriteLine($"[红外成像制导系统] 生成红外图像,目标类型: {target.GetType().Name}, 烟幕衰减: {SmokeAttenuation}");
|
||||
var image = imageGenerator.GenerateImage(target, missilePosition, SmokeAttenuation, SimulationManager);
|
||||
var image = imageGenerator.GenerateImage(target, missilePosition, liveSmokeTransmittance, SimulationManager);
|
||||
|
||||
switch (currentMode)
|
||||
{
|
||||
@ -571,6 +536,39 @@ namespace ThreatSource.Guidance
|
||||
return false; // 没有烟幕能有效遮挡目标
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 计算给定观察点和目标点之间的总烟幕透过率
|
||||
/// </summary>
|
||||
/// <param name="observerPosition">观察者位置</param>
|
||||
/// <param name="targetEndPosition">目标位置</param>
|
||||
/// <returns>总透过率 (0.0 到 1.0)</returns>
|
||||
private double CalculateLiveSmokeTransmittance(Vector3D observerPosition, Vector3D targetEndPosition)
|
||||
{
|
||||
double totalTransmittance = 1.0;
|
||||
var activeSmokeGrenades = SimulationManager.GetEntitiesByType<SmokeGrenade>()
|
||||
.Where(sg => sg.IsActive && sg.config != null && sg.IsJamming) // 确保烟幕弹已激活并正在干扰
|
||||
.ToList();
|
||||
|
||||
if (!activeSmokeGrenades.Any())
|
||||
{
|
||||
return 1.0; // 没有活动的、正在干扰的烟幕,无衰减
|
||||
}
|
||||
|
||||
foreach (var smokeGrenade in activeSmokeGrenades)
|
||||
{
|
||||
// 调用 SmokeGrenade 实例的方法来计算其对视线的透过率
|
||||
double transmittanceForThisSmoke = smokeGrenade.GetSmokeTransmittanceOnLine(observerPosition, targetEndPosition, config.Wavelength);
|
||||
totalTransmittance *= transmittanceForThisSmoke; // 叠加衰减效应(透过率相乘)
|
||||
|
||||
// 如果透过率已经很低,可以提前退出以优化
|
||||
if (totalTransmittance < 0.001)
|
||||
{
|
||||
return 0.0;
|
||||
}
|
||||
}
|
||||
return Math.Max(0.0, totalTransmittance); //确保不为负
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取红外图像制导系统的详细状态信息
|
||||
/// </summary>
|
||||
|
||||
@ -349,7 +349,7 @@ namespace ThreatSource.Guidance
|
||||
public override void Update(double deltaTime)
|
||||
{
|
||||
base.Update(deltaTime);
|
||||
if (!IsJammed)
|
||||
if (!IsBlockingJammed)
|
||||
{
|
||||
if (LaserIlluminationOn)
|
||||
{
|
||||
|
||||
@ -6,6 +6,7 @@ using ThreatSource.Jammer;
|
||||
using System.Diagnostics;
|
||||
using AirTransmission;
|
||||
using System.Transactions;
|
||||
using System.Linq;
|
||||
|
||||
namespace ThreatSource.Guidance
|
||||
{
|
||||
@ -123,11 +124,6 @@ namespace ThreatSource.Guidance
|
||||
/// </remarks>
|
||||
private const double AccelerationSmoothingFactor = 0.5;
|
||||
|
||||
/// <summary>
|
||||
/// 烟幕衰减
|
||||
/// </summary>
|
||||
private double SmokeAttenuation { get; set; } = 1.0;
|
||||
|
||||
/// <summary>
|
||||
/// 激光目标列表,包括真实目标和诱偏目标
|
||||
/// </summary>
|
||||
@ -299,19 +295,16 @@ namespace ThreatSource.Guidance
|
||||
if (parameters.Type == JammingType.Laser)
|
||||
{
|
||||
Debug.WriteLine($"[LASER_SEMI_ACTIVE] 受到激光干扰。", "Jamming");
|
||||
// 基类已将 HasGuidance 设为 false
|
||||
TargetPosition = null; // 丢失目标位置
|
||||
LaserIlluminationOn = false; // 无法确认照射状态
|
||||
// 不需要再次设置 HasGuidance = false
|
||||
}
|
||||
else if (parameters.Type == JammingType.SmokeGrenade)
|
||||
{
|
||||
// 计算并应用烟幕衰减
|
||||
SmokeAttenuation = CalculateSmokeAttenuation(parameters);
|
||||
Debug.WriteLine($"[LASER_SEMI_ACTIVE] 烟幕干扰应用,衰减因子: {SmokeAttenuation:P2}", "Jamming");
|
||||
Debug.WriteLine($"[LASER_SEMI_ACTIVE] 烟幕干扰应用,JammerId: {parameters.JammerId}", "Jamming");
|
||||
}
|
||||
else if (parameters.Type == JammingType.LaserDecoy)
|
||||
{
|
||||
Console.WriteLine($"[LASER_SEMI_ACTIVE] 受到激光诱偏干扰。JammerId: {parameters.JammerId}, SourceId: {parameters.SourceId}");
|
||||
if (parameters.JammerId != null && parameters.SourceId != null)
|
||||
{
|
||||
LaserDecoy decoyTarget = SimulationManager.GetEntityById(parameters.JammerId) as LaserDecoy ?? throw new Exception("诱偏目标不存在");
|
||||
@ -320,6 +313,7 @@ namespace ThreatSource.Guidance
|
||||
if (!laserTargets.Any(t => t.Target.Id == decoyTarget.Id))
|
||||
{
|
||||
laserTargets.Add((decoyTarget, decoyTarget.Position, decoySource));
|
||||
Console.WriteLine($"[LASER_SEMI_ACTIVE] 诱偏目标添加到激光目标列表。当前激光目标数量: {laserTargets.Count}");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -336,13 +330,10 @@ namespace ThreatSource.Guidance
|
||||
if (parameters.Type == JammingType.Laser)
|
||||
{
|
||||
Debug.WriteLine($"[LASER_SEMI_ACTIVE] 激光干扰已清除。", "Jamming");
|
||||
// 不需要设置 HasGuidance = true, 基类可能已处理
|
||||
// 激光照射状态 LaserIlluminationOn 会在收到下一个有效 Update 事件时恢复
|
||||
}
|
||||
else if (parameters.Type == JammingType.SmokeGrenade)
|
||||
{
|
||||
SmokeAttenuation = 1.0; // 重置烟幕衰减
|
||||
Debug.WriteLine($"[LASER_SEMI_ACTIVE] 烟幕干扰已清除。", "Jamming");
|
||||
Debug.WriteLine($"[LASER_SEMI_ACTIVE] 烟幕干扰已清除,JammerId: {parameters.JammerId}", "Jamming");
|
||||
}
|
||||
else if (parameters.Type == JammingType.LaserDecoy)
|
||||
{
|
||||
@ -367,7 +358,7 @@ namespace ThreatSource.Guidance
|
||||
}
|
||||
|
||||
// 对激光干扰添加波长检查
|
||||
if (parameters.Type == JammingType.Laser)
|
||||
if (parameters.Type == JammingType.Laser || parameters.Type == JammingType.LaserDecoy)
|
||||
{
|
||||
// 1. 检查波长
|
||||
if (Math.Abs((parameters.Wavelength ?? 0) - config.Wavelength) > 1e-6)
|
||||
@ -375,9 +366,6 @@ namespace ThreatSource.Guidance
|
||||
Debug.WriteLine($"[LASER_SEMI_ACTIVE] {Id} 忽略激光干扰:波长 {parameters.Wavelength}um 与期望波长 {config.Wavelength}um 不匹配。", "Jamming");
|
||||
return false;
|
||||
}
|
||||
|
||||
// 2. 移除干扰事件中的编码检查: JammingParameters 不包含 LaserCode.
|
||||
// 编码检查已移至 OnLaserIlluminationUpdate
|
||||
}
|
||||
|
||||
// 如果是支持的非激光干扰 (例如烟幕) 或通过了激光检查,则返回 true
|
||||
@ -511,60 +499,49 @@ namespace ThreatSource.Guidance
|
||||
/// <returns>接收到的激光功率,单位:瓦特</returns>
|
||||
private double CalculateReceivedPower(Vector3D sourcePos, Vector3D targetPos, double laserPower, double laserDivergenceAngle)
|
||||
{
|
||||
double distanceDesignatorToTarget = (sourcePos - targetPos).Magnitude();
|
||||
double distanceMissileToTarget = (Position - targetPos).Magnitude();
|
||||
|
||||
// 计算大气透过率 (1.使用从激光源到目标的单程透过率,2.使用从目标到导弹的单程透过率)
|
||||
// 如果当前天气为null,则认为大气透过率为1.0
|
||||
double atmosphericTransmittanceToTarget = 1.0;
|
||||
double atmosphericTransmittanceToMissile = 1.0;
|
||||
|
||||
// 考虑烟幕衰减,计算大气透过率
|
||||
if(SimulationManager.CurrentWeather != null)
|
||||
// --- 路径1: 指示器 (source) 到目标 (target) ---
|
||||
double distanceSourceToTarget = (sourcePos - targetPos).Magnitude();
|
||||
double smokeTransmittance_S2T = CalculateLiveSmokeTransmittanceForPath(sourcePos, targetPos);
|
||||
double atmTransmittance_S2T = 1.0;
|
||||
if (SimulationManager.CurrentWeather != null)
|
||||
{
|
||||
atmosphericTransmittanceToTarget = SmokeAttenuation * AtmosphereDllWrapper.CalculateTransmittance(
|
||||
distanceDesignatorToTarget,
|
||||
RadiationType.Laser,
|
||||
config.Wavelength,
|
||||
SimulationManager.CurrentWeather);
|
||||
|
||||
atmosphericTransmittanceToMissile = SmokeAttenuation * AtmosphereDllWrapper.CalculateTransmittance(
|
||||
distanceMissileToTarget,
|
||||
RadiationType.Laser,
|
||||
config.Wavelength,
|
||||
SimulationManager.CurrentWeather);
|
||||
atmTransmittance_S2T = AtmosphereDllWrapper.CalculateTransmittance(
|
||||
distanceSourceToTarget, RadiationType.Laser, config.Wavelength, SimulationManager.CurrentWeather);
|
||||
}
|
||||
double totalTransmittance_S2T = smokeTransmittance_S2T * atmTransmittance_S2T;
|
||||
|
||||
// 计算目标处的光斑面积
|
||||
double spotAreaAtTarget = Math.PI * Math.Pow(distanceDesignatorToTarget * Math.Tan(laserDivergenceAngle), 2);
|
||||
|
||||
// 计算目标处的激光功率密度,考虑大气衰减和发射系统透过率
|
||||
double powerDensityAtTarget = laserPower * atmosphericTransmittanceToTarget * config.TransmitterEfficiency / spotAreaAtTarget;
|
||||
|
||||
// 计算从目标反射的总功率
|
||||
double reflectedPower = powerDensityAtTarget * config.TargetReflectiveArea * config.ReflectionCoefficient;
|
||||
|
||||
// 计算反射光在导弹处的扩散面积(假设漫反射)
|
||||
double reflectedSpotArea = 2 * Math.PI * Math.Pow(distanceMissileToTarget, 2);
|
||||
|
||||
// 计算导弹接收到的功率,考虑大气衰减和接收系统透过率
|
||||
double receivedPower = reflectedPower * atmosphericTransmittanceToMissile * config.ReceiverEfficiency / reflectedSpotArea;
|
||||
// 功率密度在目标表面
|
||||
double spotAreaAtTarget = Math.PI * Math.Pow(distanceSourceToTarget * Math.Tan(laserDivergenceAngle), 2);
|
||||
if (spotAreaAtTarget < 1e-9) spotAreaAtTarget = 1e-9; // 防止除零
|
||||
double powerDensityOnTargetSurface = laserPower * config.TransmitterEfficiency * totalTransmittance_S2T / spotAreaAtTarget;
|
||||
|
||||
// 计算镜头接收到的功率比例
|
||||
// 目标反射的总功率
|
||||
double totalPowerReflectedByTarget = powerDensityOnTargetSurface * config.TargetReflectiveArea * config.ReflectionCoefficient;
|
||||
|
||||
// --- 路径2: 目标 (target) 到导弹 (missile) ---
|
||||
double distanceTargetToMissile = (targetPos - Position).Magnitude();
|
||||
if (distanceTargetToMissile < 1e-9) distanceTargetToMissile = 1e-9; // 防止除零
|
||||
double smokeTransmittance_T2M = CalculateLiveSmokeTransmittanceForPath(targetPos, Position);
|
||||
double atmTransmittance_T2M = 1.0;
|
||||
if (SimulationManager.CurrentWeather != null)
|
||||
{
|
||||
atmTransmittance_T2M = AtmosphereDllWrapper.CalculateTransmittance(
|
||||
distanceTargetToMissile, RadiationType.Laser, config.Wavelength, SimulationManager.CurrentWeather);
|
||||
}
|
||||
double totalTransmittance_T2M = smokeTransmittance_T2M * atmTransmittance_T2M;
|
||||
|
||||
// 导弹接收孔径处的功率密度 (来自目标反射,假设朗伯体)
|
||||
// 反射功率在2*PI立体角内分布(朗伯反射体)
|
||||
// 功率密度 = 总反射功率 / (2 * PI * R^2)
|
||||
// 在此步骤应用路径2的透过率,因为它影响从目标到导弹的信号强度
|
||||
double powerDensityAtMissileAperture = totalPowerReflectedByTarget * totalTransmittance_T2M / (2 * Math.PI * Math.Pow(distanceTargetToMissile, 2));
|
||||
|
||||
// 导弹最终接收到的功率
|
||||
double lensArea = Math.PI * Math.Pow(config.LensDiameter / 2, 2);
|
||||
double illuminatedArea = Math.PI * Math.Pow(distanceMissileToTarget * Math.Tan(config.FieldOfViewAngleInRadians / 2), 2);
|
||||
double powerRatio = Math.Min(1, lensArea / illuminatedArea);
|
||||
|
||||
// 计算聚焦后的功率密度增加
|
||||
double sensorArea = Math.PI * Math.Pow(config.SensorDiameter / 2, 2);
|
||||
double focusedArea = Math.PI * Math.Pow(config.FocusedSpotDiameter / 2, 2);
|
||||
double focusingFactor = sensorArea / focusedArea;
|
||||
|
||||
// 计算最终接收到的功率
|
||||
double finalReceivedPower = receivedPower * powerRatio * focusingFactor;
|
||||
double finalReceivedPower = powerDensityAtMissileAperture * lensArea * config.ReceiverEfficiency;
|
||||
|
||||
Debug.WriteLine($"激光功率计算: 源->目标距离={distanceDesignatorToTarget:F1}m (透过率={atmosphericTransmittanceToTarget:F3}), " +
|
||||
$"目标->导弹距离={distanceMissileToTarget:F1}m (透过率={atmosphericTransmittanceToMissile:F3}), " +
|
||||
Console.WriteLine($"激光功率计算: S2T D={distanceSourceToTarget:F1}m (Path1 T={totalTransmittance_S2T:F3}), " +
|
||||
$"T2M D={distanceTargetToMissile:F1}m (Path2 T={totalTransmittance_T2M:F3}), " +
|
||||
$"最终功率={finalReceivedPower:E}W");
|
||||
|
||||
return finalReceivedPower;
|
||||
@ -852,46 +829,36 @@ namespace ThreatSource.Guidance
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 计算烟幕对激光的衰减因子
|
||||
/// 计算给定路径上的总烟幕透过率
|
||||
/// </summary>
|
||||
/// <param name="parameters">烟幕干扰参数</param>
|
||||
/// <returns>衰减因子,范围:0-1,0表示完全衰减,1表示无衰减</returns>
|
||||
private double CalculateSmokeAttenuation(JammingParameters parameters)
|
||||
/// <param name="pathStart">路径起点</param>
|
||||
/// <param name="pathEnd">路径终点</param>
|
||||
/// <returns>总透过率 (0.0 到 1.0)</returns>
|
||||
private double CalculateLiveSmokeTransmittanceForPath(Vector3D pathStart, Vector3D pathEnd)
|
||||
{
|
||||
if (!parameters.SmokeConcentration.HasValue)
|
||||
return 1.0; // 无衰减
|
||||
double totalTransmittance = 1.0;
|
||||
var activeSmokeGrenades = SimulationManager.GetEntitiesByType<SmokeGrenade>()
|
||||
.Where(sg => sg.IsActive && sg.config != null && sg.IsJamming) // 确保烟幕弹已激活并正在干扰
|
||||
.ToList();
|
||||
|
||||
if (!activeSmokeGrenades.Any())
|
||||
{
|
||||
return 1.0; // 没有活动的、正在干扰的烟幕,无衰减
|
||||
}
|
||||
|
||||
foreach (var smokeGrenade in activeSmokeGrenades)
|
||||
{
|
||||
// 调用 SmokeGrenade 实例的方法来计算其对视线的透过率
|
||||
double transmittanceForThisSmoke = smokeGrenade.GetSmokeTransmittanceOnLine(pathStart, pathEnd, config.Wavelength);
|
||||
totalTransmittance *= transmittanceForThisSmoke; // 叠加衰减效应(透过率相乘)
|
||||
|
||||
// 获取烟幕浓度
|
||||
double concentration = parameters.SmokeConcentration.Value;
|
||||
|
||||
// 计算烟幕厚度(设备到烟幕边缘的距离)
|
||||
double effectiveThickness = 0;
|
||||
if (parameters.SmokeType == SmokeScreenType.Cloud)
|
||||
{
|
||||
// 对于云状烟幕,使用设备到烟幕中心的距离
|
||||
double distanceToCenter = (Position - parameters.SourcePosition).Magnitude();
|
||||
double radius = parameters.SmokeThickness.HasValue ? parameters.SmokeThickness.Value / 2 : 10.0;
|
||||
effectiveThickness = Math.Max(0, radius - distanceToCenter);
|
||||
if (distanceToCenter < radius) // 如果在烟幕内部
|
||||
effectiveThickness = 2 * (radius - distanceToCenter); // 双倍路径
|
||||
// 如果透过率已经很低,可以提前退出以优化
|
||||
if (totalTransmittance < 0.001)
|
||||
{
|
||||
return 0.0;
|
||||
}
|
||||
}
|
||||
else // SmokeScreenType.Wall
|
||||
{
|
||||
// 对于墙状烟幕,使用烟幕厚度
|
||||
effectiveThickness = parameters.SmokeThickness.HasValue ? parameters.SmokeThickness.Value : 5.0;
|
||||
// 可以进一步计算有效厚度,但这里简化处理
|
||||
}
|
||||
|
||||
// 使用 AtmosphereDllWrapper 计算烟幕透过率
|
||||
double transmittance = AtmosphereDllWrapper.CalculateSmokeScreenTransmittance(
|
||||
config.Wavelength, // 激光波长(微米)
|
||||
concentration, // 烟幕浓度(g/m³)
|
||||
effectiveThickness // 烟幕厚度(米)
|
||||
);
|
||||
|
||||
Debug.WriteLine($"烟幕衰减计算 - 波长: {config.Wavelength:F2}um, 浓度: {concentration}g/m³, 厚度: {effectiveThickness}m, 透过率: {transmittance:P2}");
|
||||
|
||||
return transmittance;
|
||||
return Math.Max(0.0, totalTransmittance); //确保不为负
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -66,7 +66,7 @@ namespace ThreatSource.Guidance
|
||||
/// 记录目标的历史位置
|
||||
/// 用于计算目标速度
|
||||
/// </remarks>
|
||||
private Vector3D? lastTargetPosition { get; set; }
|
||||
private Vector3D? LastTargetPosition { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 上一次探测到的目标速度 (使用可空类型)
|
||||
@ -75,7 +75,7 @@ namespace ThreatSource.Guidance
|
||||
/// 记录目标的历史速度
|
||||
/// 用于计算目标速度
|
||||
/// </remarks>
|
||||
private Vector3D? lastTargetVelocity { get; set; }
|
||||
private Vector3D? LastTargetVelocity { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 目标丢失计时器
|
||||
@ -125,11 +125,7 @@ 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;
|
||||
|
||||
private const double SpeedOfLight = 299792458.0; // m/s
|
||||
|
||||
/// <summary>
|
||||
/// 初始化毫米波制导系统的新实例
|
||||
@ -174,8 +170,8 @@ namespace ThreatSource.Guidance
|
||||
lockConfirmationTimer = 0;
|
||||
currentScanAngle = 0;
|
||||
currentScanRadius = config.SearchBeamWidth * Math.PI / 720.0; // 从半个波束宽度的一半开始
|
||||
lastTargetPosition = null;
|
||||
lastTargetVelocity = null;
|
||||
LastTargetPosition = null;
|
||||
LastTargetVelocity = null;
|
||||
Trace.WriteLine($"切换到搜索模式,波束宽度: {config.SearchBeamWidth}度");
|
||||
}
|
||||
|
||||
@ -229,8 +225,8 @@ namespace ThreatSource.Guidance
|
||||
HasTarget = false;
|
||||
HasGuidance = false;
|
||||
GuidanceAcceleration = Vector3D.Zero;
|
||||
lastTargetPosition = null;
|
||||
lastTargetVelocity = null;
|
||||
LastTargetPosition = null;
|
||||
LastTargetVelocity = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -252,10 +248,8 @@ namespace ThreatSource.Guidance
|
||||
}
|
||||
else if (parameters.Type == JammingType.SmokeGrenade)
|
||||
{
|
||||
// 计算烟幕透过率
|
||||
// TODO: 实现基于 JammingParameters 中烟幕属性 (浓度、厚度等) 的真实透过率计算。
|
||||
_currentSmokeTransmittance = 1.0; // 暂时设置为无遮挡
|
||||
Debug.WriteLine($"[MMW_GUIDANCE] 烟幕干扰应用,(临时) 透过率: {_currentSmokeTransmittance:P2}", "Jamming");
|
||||
Debug.WriteLine($"[MMW_GUIDANCE] 受到烟幕干扰影响。Jammer ID: {parameters.JammerId}", "Jamming");
|
||||
// 烟幕主要通过影响SNR体现,不直接触发模式切换
|
||||
}
|
||||
}
|
||||
|
||||
@ -274,8 +268,8 @@ namespace ThreatSource.Guidance
|
||||
}
|
||||
else if (parameters.Type == JammingType.SmokeGrenade)
|
||||
{
|
||||
_currentSmokeTransmittance = 1.0; // 重置烟幕透过率
|
||||
Debug.WriteLine($"[MMW_GUIDANCE] 烟幕干扰已清除。", "Jamming");
|
||||
// _currentSmokeTransmittance = 1.0; // Field removed, no longer needed here
|
||||
Debug.WriteLine($"[MMW_GUIDANCE] 烟幕干扰解除。Jammer ID: {parameters.JammerId}", "Jamming");
|
||||
}
|
||||
}
|
||||
|
||||
@ -298,11 +292,11 @@ namespace ThreatSource.Guidance
|
||||
// 检查波长是否与工作波长匹配 (单位: 毫米 mm)
|
||||
// 计算配置波长 (单位: mm), 直接使用光速值 3e8 m/s
|
||||
const double speedOfLight = 3e8;
|
||||
double configWavelength = speedOfLight / config.WaveFrequency * 1000.0; // m/s / Hz * 1000 = mm
|
||||
double configWavelength_mm = speedOfLight / config.WaveFrequency * 1000.0; // m/s / Hz * 1000 = mm
|
||||
|
||||
if (Math.Abs((parameters.Wavelength ?? 0) - configWavelength) > 1e-1) // 允许 0.1mm 偏差
|
||||
if (Math.Abs((parameters.Wavelength ?? 0) - configWavelength_mm) > 1e-1) // 允许 0.1mm 偏差
|
||||
{
|
||||
Debug.WriteLine($"[MMW_GUIDANCE] {Id} 忽略毫米波干扰:干扰波长 {parameters.Wavelength}mm 与系统工作波长 {configWavelength:F2}mm (频率 {config.WaveFrequency/1e9:F1}GHz) 不匹配。", "Jamming");
|
||||
Debug.WriteLine($"[MMW_GUIDANCE] {Id} 忽略毫米波干扰:干扰波长 {parameters.Wavelength}mm 与系统工作波长 {configWavelength_mm:F2}mm (频率 {config.WaveFrequency/1e9:F1}GHz) 不匹配。", "Jamming");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -461,18 +455,17 @@ namespace ThreatSource.Guidance
|
||||
{
|
||||
base.Update(deltaTime); // 更新基类状态和干扰状态
|
||||
|
||||
// 在执行核心逻辑前检查干扰状态
|
||||
if (IsJammed) // 使用基类的 IsJammed 状态
|
||||
// 在执行核心逻辑前检查阻塞性干扰状态
|
||||
if (IsBlockingJammed)
|
||||
{
|
||||
// 如果被干扰,确保处于搜索模式并且没有制导
|
||||
// 如果被阻塞性干扰,确保处于搜索模式并且没有制导
|
||||
if (currentMode != WorkMode.Search)
|
||||
{
|
||||
SwitchToSearchMode();
|
||||
}
|
||||
HasGuidance = false;
|
||||
GuidanceAcceleration = Vector3D.Zero;
|
||||
// Debug.WriteLine($"[MMW_GUIDANCE] {Id} 处于干扰状态,跳过制导计算。", "Jamming");
|
||||
return; // 不执行后续逻辑
|
||||
return;
|
||||
}
|
||||
|
||||
// 更新扫描参数
|
||||
@ -482,13 +475,13 @@ namespace ThreatSource.Guidance
|
||||
{
|
||||
targetLostTimer = 0;
|
||||
Vector3D? currentTargetVelocity = null;
|
||||
if (lastTargetPosition != null && deltaTime > 0)
|
||||
if (LastTargetPosition != null && deltaTime > 0)
|
||||
{
|
||||
currentTargetVelocity = (currentTargetPosition - lastTargetPosition) / deltaTime;
|
||||
currentTargetVelocity = (currentTargetPosition - LastTargetPosition) / deltaTime;
|
||||
}
|
||||
|
||||
lastTargetPosition = currentTargetPosition;
|
||||
lastTargetVelocity = currentTargetVelocity;
|
||||
LastTargetPosition = currentTargetPosition;
|
||||
LastTargetVelocity = currentTargetVelocity;
|
||||
|
||||
GuidanceAcceleration = MotionAlgorithm.CalculateProportionalNavigation(
|
||||
ProportionalNavigationCoefficient,
|
||||
@ -546,56 +539,53 @@ namespace ThreatSource.Guidance
|
||||
targetPosition = Vector3D.Zero;
|
||||
double minDistance = double.MaxValue;
|
||||
bool foundTarget = false;
|
||||
double currentSNR = double.MinValue;
|
||||
|
||||
if (IsJammed)
|
||||
{
|
||||
HasGuidance = false;
|
||||
return false;
|
||||
}
|
||||
double currentSNR_dB = double.MinValue;
|
||||
|
||||
foreach (var element in SimulationManager.GetEntitiesByType<SimulationElement>())
|
||||
{
|
||||
if (element is BaseEquipment target)
|
||||
if (element is BaseEquipment target && target.Id != MissileId && target.IsActive)
|
||||
{
|
||||
Vector3D toTarget = target.Position - missilePosition;
|
||||
double distance = toTarget.Magnitude();
|
||||
|
||||
if (distance <= config.MaxDetectionRange)
|
||||
if (distance <= config.MaxDetectionRange && distance > 0)
|
||||
{
|
||||
double snr = CalculateSNR(distance, target.Properties.RadarCrossSection);
|
||||
Console.WriteLine($"信噪比: {snr:F2}dB");
|
||||
double liveSmokeTransmittance = CalculateLiveSmokeTransmittance(missilePosition, target.Position);
|
||||
double snr_dB = CalculateSNR(distance, target.Properties.RadarCrossSection, liveSmokeTransmittance);
|
||||
|
||||
if (currentMode == WorkMode.Search)
|
||||
{
|
||||
if (IsTargetInBeam(missileVelocity, toTarget) && snr >= config.RecognitionSNRThreshold)
|
||||
if (IsTargetInBeam(missileVelocity, toTarget) && snr_dB >= config.RecognitionSNRThreshold)
|
||||
{
|
||||
targetPosition = target.Position;
|
||||
minDistance = distance;
|
||||
foundTarget = true;
|
||||
currentSNR = snr;
|
||||
if (distance < minDistance)
|
||||
{
|
||||
targetPosition = target.Position;
|
||||
minDistance = distance;
|
||||
foundTarget = true;
|
||||
currentSNR_dB = snr_dB;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (currentMode == WorkMode.Track || currentMode == WorkMode.Lock)
|
||||
{
|
||||
if (IsTargetInBeam(missileVelocity, toTarget) &&
|
||||
lastTargetPosition != null &&
|
||||
Vector3D.Distance(target.Position, lastTargetPosition) < 100.0)
|
||||
bool isPotentiallyTrackedTarget = true;
|
||||
if (LastTargetPosition != null)
|
||||
{
|
||||
double requiredSNR = (currentMode == WorkMode.Track) ?
|
||||
double proximityThreshold = (target.Properties.Length > 0) ? target.Properties.Length * 5.0 : 100.0;
|
||||
isPotentiallyTrackedTarget = Vector3D.Distance(target.Position, LastTargetPosition) < proximityThreshold;
|
||||
}
|
||||
|
||||
if (IsTargetInBeam(missileVelocity, toTarget) && isPotentiallyTrackedTarget)
|
||||
{
|
||||
double requiredSNR_dB = (currentMode == WorkMode.Track) ?
|
||||
config.RecognitionSNRThreshold : config.LockSNRThreshold;
|
||||
|
||||
if (snr >= requiredSNR)
|
||||
if (snr_dB >= requiredSNR_dB)
|
||||
{
|
||||
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");
|
||||
currentSNR_dB = snr_dB;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -603,8 +593,8 @@ namespace ThreatSource.Guidance
|
||||
}
|
||||
}
|
||||
|
||||
UpdateSystemState(foundTarget, currentSNR, deltaTime);
|
||||
HasTarget = foundTarget;
|
||||
UpdateSystemState(foundTarget, currentSNR_dB, deltaTime);
|
||||
HasTarget = foundTarget;
|
||||
return foundTarget;
|
||||
}
|
||||
|
||||
@ -674,8 +664,8 @@ namespace ThreatSource.Guidance
|
||||
{
|
||||
var statusInfo = base.GetStatusInfo();
|
||||
|
||||
string lastPosStr = lastTargetPosition != null ? lastTargetPosition.ToString() : "null";
|
||||
string lastVelStr = lastTargetVelocity != null ? lastTargetVelocity.ToString() : "null";
|
||||
string lastPosStr = LastTargetPosition != null ? LastTargetPosition.ToString() : "null";
|
||||
string lastVelStr = LastTargetVelocity != null ? LastTargetVelocity.ToString() : "null";
|
||||
|
||||
statusInfo.ExtendedProperties["Mode"] = currentMode.ToString();
|
||||
statusInfo.ExtendedProperties["LastTargetPosition"] = lastPosStr;
|
||||
@ -690,6 +680,7 @@ namespace ThreatSource.Guidance
|
||||
/// </summary>
|
||||
/// <param name="distance">到目标的距离,单位:米</param>
|
||||
/// <param name="radarCrossSection">目标雷达散射截面积,单位:平方米</param>
|
||||
/// <param name="smokeTransmittanceLinear">当前视线的烟幕总线性透过率 (0.0 到 1.0)</param>
|
||||
/// <returns>信噪比,单位:分贝</returns>
|
||||
/// <remarks>
|
||||
/// 计算过程:
|
||||
@ -698,53 +689,116 @@ namespace ThreatSource.Guidance
|
||||
/// - 计算噪声功率
|
||||
/// - 计算信噪比
|
||||
/// - 转换为分贝值
|
||||
/// - 应用烟幕衰减
|
||||
/// </remarks>
|
||||
private double CalculateSNR(double distance, double radarCrossSection)
|
||||
private double CalculateSNR(double distance, double radarCrossSection, double smokeTransmittanceLinear)
|
||||
{
|
||||
// 雷达参数
|
||||
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); // 噪声系数(线性值)
|
||||
double transmitPower = config.TransmitPower;
|
||||
double antennaGain = Math.Pow(10, config.AntennaGainDB/10);
|
||||
|
||||
// 系统损耗,单位:dB
|
||||
double atmosphericLoss = 0.4 * distance / 1000.0; // 大气衰减,0.4dB/km
|
||||
double totalLoss = Math.Pow(10, (atmosphericLoss + config.SystemLossDB) / 10); // 转换为线性值
|
||||
// 波长,单位:米 (m),用于雷达方程核心计算
|
||||
double wavelength_m = SpeedOfLight / config.WaveFrequency;
|
||||
// 波长,单位:微米 (µm),用于需要微米单位的函数调用
|
||||
double wavelength_um = SpeedOfLight / config.WaveFrequency * 1e6;
|
||||
|
||||
// 常量
|
||||
double k = 1.38e-23; // 玻尔兹曼常数
|
||||
double T0 = 290; // 标准噪声温度(K)
|
||||
double bandwidth = 1.0 / config.PulseDuration;
|
||||
double noiseFigure = Math.Pow(10, config.NoiseFigureDB/10);
|
||||
|
||||
double atmosphericLoss_dB = 0.4 * distance / 1000.0;
|
||||
double totalSystemLoss_linear = Math.Pow(10, (atmosphericLoss_dB + config.SystemLossDB) / 10.0);
|
||||
|
||||
// 计算接收信号功率
|
||||
double signalPower = (transmitPower * Math.Pow(antennaGain, 2) * Math.Pow(wavelength, 2) * radarCrossSection)
|
||||
/ (Math.Pow(4 * Math.PI, 3) * Math.Pow(distance, 4) * totalLoss);
|
||||
double k = 1.38e-23;
|
||||
double T0 = 290;
|
||||
|
||||
// 考虑大气透过率,如果当前天气为null,则认为大气透过率为1.0
|
||||
double atmosphericTransmittance = 1.0;
|
||||
double signalPowerNumerator = transmitPower * Math.Pow(antennaGain, 2) * Math.Pow(wavelength_m, 2) * radarCrossSection; // Use wavelength_m
|
||||
double signalPowerDenominator = Math.Pow(4 * Math.PI, 3) * Math.Pow(distance, 4) * totalSystemLoss_linear;
|
||||
|
||||
if(SimulationManager.CurrentWeather != null)
|
||||
{
|
||||
atmosphericTransmittance = AtmosphereDllWrapper.CalculateTransmittance(
|
||||
if (signalPowerDenominator == 0) return -100.0;
|
||||
double signalPower = signalPowerNumerator / signalPowerDenominator;
|
||||
|
||||
double weatherSpecificAtmosphericTransmittance = 1.0;
|
||||
if(SimulationManager?.CurrentWeather != null)
|
||||
{
|
||||
weatherSpecificAtmosphericTransmittance = AtmosphereDllWrapper.CalculateTransmittance(
|
||||
distance,
|
||||
RadiationType.MillimeterWave,
|
||||
wavelength,
|
||||
wavelength_um, // Use wavelength_um
|
||||
SimulationManager.CurrentWeather);
|
||||
}
|
||||
signalPower *= weatherSpecificAtmosphericTransmittance;
|
||||
|
||||
signalPower *= atmosphericTransmittance;
|
||||
|
||||
// 应用当前生效的烟幕衰减 (通过存储的透过率)
|
||||
signalPower *= _currentSmokeTransmittance;
|
||||
|
||||
// 计算噪声功率
|
||||
double noisePower = k * T0 * bandwidth * noiseFigure;
|
||||
if (noisePower == 0) return 100.0;
|
||||
|
||||
// 计算信噪比
|
||||
double snr = signalPower / noisePower;
|
||||
double snr_linear = signalPower / noisePower;
|
||||
|
||||
// 转换为dB
|
||||
return 10 * Math.Log10(snr);
|
||||
if (snr_linear <= 0) return -100.0;
|
||||
|
||||
double snr_dB_no_smoke = 10 * Math.Log10(snr_linear);
|
||||
Console.WriteLine($"[SNR_CALC] SNR_dB (before smoke): {snr_dB_no_smoke:F2} dB. Incoming SmokeTransmittance_Linear: {smokeTransmittanceLinear:F6}");
|
||||
|
||||
// 应用当前生效的烟幕衰减 (通过存储的透过率) - REMOVED _currentSmokeTransmittance FIELD USAGE
|
||||
// signalPower *= _currentSmokeTransmittance; // This line is now handled by the parameter
|
||||
|
||||
// 应用烟幕透过率 (smokeTransmittanceLinear is already linear 0-1)
|
||||
if (smokeTransmittanceLinear <= 0.000001) // Threshold to prevent log(0) or very large negative numbers
|
||||
{
|
||||
Console.WriteLine($"[SNR_CALC] Smoke transmittance too low. Final_SNR_dB: -100.0 dB");
|
||||
return -100.0; // Effectively zero signal due to smoke
|
||||
}
|
||||
|
||||
// Loss_smoke_dB = -10 * log10(T_smoke_linear)
|
||||
// SNR_final_dB = SNR_original_dB - Loss_smoke_dB = SNR_original_dB + 10 * log10(T_smoke_linear)
|
||||
double smokeEffect_dB = 10 * Math.Log10(smokeTransmittanceLinear);
|
||||
double final_snr_dB = snr_dB_no_smoke + smokeEffect_dB;
|
||||
Console.WriteLine($"[SNR_CALC] SmokeEffect: {smokeEffect_dB:F2} dB. Final_SNR_dB (after smoke): {final_snr_dB:F2} dB");
|
||||
|
||||
return final_snr_dB;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 计算给定观察点和目标点之间的总烟幕透过率。
|
||||
/// </summary>
|
||||
/// <param name="observerPosition">观察者位置</param>
|
||||
/// <param name="targetEndPosition">目标位置</param>
|
||||
/// <returns>总透过率 (0.0 到 1.0)。</returns>
|
||||
private double CalculateLiveSmokeTransmittance(Vector3D observerPosition, Vector3D targetEndPosition)
|
||||
{
|
||||
double totalTransmittance = 1.0;
|
||||
if (SimulationManager == null)
|
||||
{
|
||||
Trace.WriteLineIf(SimulationManager == null, "[MMW_GUIDANCE] SimulationManager is null in CalculateLiveSmokeTransmittance. Assuming no smoke.", "Warning");
|
||||
return 1.0;
|
||||
}
|
||||
|
||||
var activeSmokeGrenades = SimulationManager.GetEntitiesByType<SmokeGrenade>()
|
||||
.Where(sg => sg.IsActive && sg.IsJamming && sg.config != null)
|
||||
.ToList();
|
||||
|
||||
if (activeSmokeGrenades.Count == 0)
|
||||
{
|
||||
return 1.0;
|
||||
}
|
||||
|
||||
double wavelength_um = SpeedOfLight / config.WaveFrequency * 1e6;
|
||||
|
||||
if (wavelength_um <= 0) {
|
||||
Trace.WriteLine("[MMW_GUIDANCE] Calculated wavelength in meters is invalid in CalculateLiveSmokeTransmittance. Assuming no smoke effect.", "Error");
|
||||
return 1.0;
|
||||
}
|
||||
|
||||
foreach (var smokeGrenade in activeSmokeGrenades)
|
||||
{
|
||||
double transmittanceForThisSmoke = smokeGrenade.GetSmokeTransmittanceOnLine(observerPosition, targetEndPosition, wavelength_um);
|
||||
totalTransmittance *= transmittanceForThisSmoke;
|
||||
|
||||
if (totalTransmittance < 0.000001) // Use a smaller threshold for early exit if transmittance is effectively zero
|
||||
{
|
||||
return 0.0;
|
||||
}
|
||||
}
|
||||
return Math.Max(0.0, totalTransmittance);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -158,18 +158,7 @@ namespace ThreatSource.Indicator
|
||||
/// <param name="parameters">干扰参数</param>
|
||||
protected virtual void HandleJammingApplied(JammingParameters parameters)
|
||||
{
|
||||
// 如果是烟幕干扰,重新计算遮挡状态
|
||||
if (parameters.Type == JammingType.SmokeGrenade)
|
||||
{
|
||||
RecalculateObscurationStatus();
|
||||
Debug.WriteLine($"[BaseIndicator] 烟幕状态更新,IsTargetObscured: {IsTargetObscured}", "Jamming");
|
||||
}
|
||||
else // 其他干扰类型打印通用消息
|
||||
{
|
||||
// 子类可以重写此方法以实现特定的干扰响应
|
||||
Debug.WriteLine($"[BaseIndicator] {this.GetType().Name} {Id} 受到 {parameters.Type} 类型干扰,功率:{parameters.Power}W", "Jamming");
|
||||
}
|
||||
|
||||
Debug.WriteLine($"[BaseIndicator] {this.GetType().Name} {Id} 接收到应用干扰事件: {parameters.Type}, 功率: {parameters.Power}W", "Jamming");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -178,44 +167,31 @@ namespace ThreatSource.Indicator
|
||||
/// <param name="parameters">干扰参数</param>
|
||||
protected virtual void HandleJammingCleared(JammingParameters parameters)
|
||||
{
|
||||
// 如果是烟幕干扰,重新计算遮挡状态
|
||||
if (parameters.Type == JammingType.SmokeGrenade)
|
||||
{
|
||||
RecalculateObscurationStatus();
|
||||
Debug.WriteLine($"[BaseIndicator] 烟幕状态更新,IsTargetObscured: {IsTargetObscured}", "Jamming");
|
||||
}
|
||||
else // 其他干扰类型打印通用消息
|
||||
{
|
||||
// 子类可以重写此方法以实现干扰清除后的特定行为
|
||||
Debug.WriteLine($"[BaseIndicator] {this.GetType().Name} {Id} {parameters.Type} 类型干扰已清除", "Jamming");
|
||||
}
|
||||
Debug.WriteLine($"[BaseIndicator] {this.GetType().Name} {Id} 接收到清除干扰事件: {parameters.Type}", "Jamming");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 激活指示器 (基类统一处理干扰事件订阅)
|
||||
/// 激活指示器
|
||||
/// </summary>
|
||||
public override void Activate()
|
||||
{
|
||||
if (!IsActive)
|
||||
{
|
||||
IsActive = true;
|
||||
// 统一订阅 JammingEvent
|
||||
SimulationManager.SubscribeToEvent<JammingEvent>(HandleJammingEvent);
|
||||
SimulationManager.SubscribeToEvent<JammingStoppedEvent>(HandleJammingStoppedEvent);
|
||||
}
|
||||
base.Activate();
|
||||
RecalculateObscurationStatus(); // 激活时检查一次初始遮挡状态
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 停用指示器 (基类统一处理干扰事件取消订阅)
|
||||
/// 停用指示器
|
||||
/// </summary>
|
||||
public override void Deactivate()
|
||||
{
|
||||
if (IsActive)
|
||||
{
|
||||
IsActive = false;
|
||||
// 统一取消订阅 JammingEvent
|
||||
SimulationManager.UnsubscribeFromEvent<JammingEvent>(HandleJammingEvent);
|
||||
SimulationManager.UnsubscribeFromEvent<JammingStoppedEvent>(HandleJammingStoppedEvent);
|
||||
}
|
||||
@ -231,15 +207,18 @@ namespace ThreatSource.Indicator
|
||||
/// </summary>
|
||||
public override void Update(double deltaTime)
|
||||
{
|
||||
_jammingComponent.UpdateJammingStatus(deltaTime); // 更新干扰状态(包括持续时间等)
|
||||
_jammingComponent.UpdateJammingStatus(deltaTime);
|
||||
|
||||
if (IsActive)
|
||||
if (IsActive)
|
||||
{
|
||||
// 只有未被电子干扰时才更新指示器特定功能
|
||||
// 烟幕遮挡 (IsTargetObscured) 在 UpdateIndicator 内部处理
|
||||
if (!IsJammed)
|
||||
if(IsJammed && !IsBlockingJammed)
|
||||
{
|
||||
UpdateIndicator(deltaTime);
|
||||
RecalculateObscurationStatus();
|
||||
}
|
||||
|
||||
if (!IsBlockingJammed)
|
||||
{
|
||||
UpdateIndicator(deltaTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -273,6 +252,7 @@ namespace ThreatSource.Indicator
|
||||
statusInfo.ExtendedProperties["lastKnownTargetOrientation"] = _lastKnownTargetOrientation ?? new Orientation(0, 0, 0);
|
||||
statusInfo.ExtendedProperties["IsTargetObscured"] = IsTargetObscured;
|
||||
statusInfo.ExtendedProperties["IsJammed"] = IsJammed;
|
||||
statusInfo.ExtendedProperties["IsBlockingJammed"] = IsBlockingJammed;
|
||||
|
||||
return statusInfo;
|
||||
}
|
||||
@ -321,11 +301,8 @@ namespace ThreatSource.Indicator
|
||||
}
|
||||
|
||||
// 3. 获取活动的烟幕
|
||||
var activeSmokeGrenades = SimulationManager.GetEntitiesByType<SmokeGrenade>()
|
||||
.Where(sg => sg != null && sg.IsActive)
|
||||
.ToList(); // 获取列表以便检查是否为空
|
||||
|
||||
if (activeSmokeGrenades.Count == 0)
|
||||
var activeJammerIds = _jammingComponent.GetActiveJammerIdsOfType(JammingType.SmokeGrenade);
|
||||
if (!activeJammerIds.Any())
|
||||
{
|
||||
return false; // 没有活动的烟幕,视为未遮挡
|
||||
}
|
||||
@ -337,8 +314,14 @@ namespace ThreatSource.Indicator
|
||||
Vector3D targetDims = new(targetFound.Properties.Width, targetFound.Properties.Height, targetFound.Properties.Length);
|
||||
|
||||
// 5. 遍历烟幕检查遮挡
|
||||
foreach (var smokeGrenade in activeSmokeGrenades)
|
||||
foreach (var jammerId in activeJammerIds)
|
||||
{
|
||||
var smokeGrenade = SimulationManager.GetEntityById(jammerId) as SmokeGrenade;
|
||||
if (smokeGrenade == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
Vector3D smokeCenter = smokeGrenade.Position;
|
||||
@ -376,15 +359,12 @@ namespace ThreatSource.Indicator
|
||||
return false; // 未被遮挡
|
||||
}
|
||||
|
||||
// --- 新增干扰事件处理逻辑 ---
|
||||
|
||||
/// <summary>
|
||||
/// 统一处理干扰事件
|
||||
/// 处理干扰事件
|
||||
/// </summary>
|
||||
/// <param name="evt">干扰事件</param>
|
||||
protected virtual void HandleJammingEvent(JammingEvent evt)
|
||||
{
|
||||
Console.WriteLine($"[BaseIndicator] 处理干扰事件: {evt.Parameters.Type}");
|
||||
if (evt == null) return;
|
||||
|
||||
// 在应用干扰前检查是否应该处理此干扰
|
||||
@ -416,8 +396,12 @@ namespace ThreatSource.Indicator
|
||||
/// <returns>如果应该处理则返回 true,否则返回 false</returns>
|
||||
protected virtual bool ShouldHandleJamming(JammingParameters parameters)
|
||||
{
|
||||
// 子类可以重写此方法添加额外检查,如波段匹配
|
||||
// 注意:烟幕干扰虽然通过这里,但主要效果通过 IsTargetObscured 和 RecalculateObscurationStatus 体现
|
||||
// 首先检查当前指示器实例(通过其具体的 SupportedJammingTypes 实现)是否支持此干扰类型
|
||||
if (!this.SupportedJammingTypes.Contains(parameters.Type))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
// 如果类型受支持,则允许子类进行更具体的检查
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@ -90,22 +90,11 @@ namespace ThreatSource.Indicator
|
||||
/// <param name="deltaTime">时间步长,单位:秒</param>
|
||||
/// <remarks>
|
||||
/// 实现红外测角仪特定的更新逻辑:
|
||||
/// - 基类 Update 会检查 IsJammed (电子干扰)
|
||||
/// - UpdateTracking 方法内部会处理 IsTargetObscured (烟幕遮挡)
|
||||
/// - 更新跟踪状态
|
||||
/// </remarks>
|
||||
protected override void UpdateIndicator(double deltaTime)
|
||||
{
|
||||
// 基类 Update 已经检查了 IsJammed
|
||||
// if (IsJammed)
|
||||
// {
|
||||
// StopTracking(); // Logic moved to HandleJammingApplied
|
||||
// Console.WriteLine($"InfraredTracker {Id} 受到红外干扰,停止跟踪。");
|
||||
// return;
|
||||
// }
|
||||
|
||||
// 无论是否被遮挡,都尝试更新跟踪状态
|
||||
// IsTargetObscured is handled within UpdateTracking
|
||||
UpdateTracking();
|
||||
}
|
||||
|
||||
@ -317,7 +306,7 @@ namespace ThreatSource.Indicator
|
||||
/// <returns>如果应该处理则返回 true,否则返回 false</returns>
|
||||
protected override bool ShouldHandleJamming(JammingParameters parameters)
|
||||
{
|
||||
// 首先调用基类检查是否支持该干扰类型 (包括 SmokeScreen)
|
||||
// 首先调用基类的检查,看是否支持此类型
|
||||
if (!base.ShouldHandleJamming(parameters))
|
||||
{
|
||||
return false;
|
||||
@ -337,7 +326,7 @@ namespace ThreatSource.Indicator
|
||||
}
|
||||
}
|
||||
|
||||
// 如果是支持的非红外干扰 (例如烟幕) 或通过了红外波长检查,则返回 true
|
||||
// 如果是支持的类型 (SmokeGrenade) 或通过了特定检查的类型 (Infrared),返回 true
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@ -199,7 +199,7 @@ namespace ThreatSource.Indicator
|
||||
/// <returns>如果应该处理则返回 true,否则返回 false</returns>
|
||||
protected override bool ShouldHandleJamming(JammingParameters parameters)
|
||||
{
|
||||
// 首先调用基类检查是否支持该干扰类型 (包括 SmokeScreen)
|
||||
// 首先调用基类的检查,看是否支持此类型
|
||||
if (!base.ShouldHandleJamming(parameters))
|
||||
{
|
||||
return false;
|
||||
@ -216,7 +216,7 @@ namespace ThreatSource.Indicator
|
||||
}
|
||||
}
|
||||
|
||||
// 如果是支持的非激光干扰 (例如烟幕) 或通过了激光波长检查,则返回 true
|
||||
// 如果是支持的类型 (SmokeGrenade) 或通过了特定检查的类型 (Laser),返回 true
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -335,9 +335,10 @@ namespace ThreatSource.Indicator
|
||||
|
||||
// 添加子类特定响应:如果是激光干扰清除,并且设备仍激活,尝试启动光束
|
||||
if (parameters.Type == JammingType.Laser)
|
||||
{
|
||||
{
|
||||
Debug.WriteLine($"[LaserBeamRider] {Id} 激光干扰已清除。", "Jamming");
|
||||
if (IsActive && !IsJammed) // Check IsJammed in case other jams exist
|
||||
// 如果设备仍处于激活状态,并且没有其他阻塞性干扰,恢复激光照射
|
||||
if (IsActive && !IsBlockingJammed)
|
||||
{
|
||||
StartBeamIllumination();
|
||||
}
|
||||
|
||||
@ -209,8 +209,8 @@ namespace ThreatSource.Indicator
|
||||
if (parameters.Type == JammingType.Laser)
|
||||
{
|
||||
Console.WriteLine($"[LaserDesignator] {Id} 激光干扰已清除。", "Jamming");
|
||||
// 如果设备仍处于激活状态,并且没有其他干扰,恢复激光照射
|
||||
if (IsActive && !IsJammed)
|
||||
// 如果设备仍处于激活状态,并且没有其他阻塞性干扰,恢复激光照射
|
||||
if (IsActive && !IsBlockingJammed)
|
||||
{
|
||||
StartLaserIllumination();
|
||||
}
|
||||
@ -324,7 +324,7 @@ namespace ThreatSource.Indicator
|
||||
/// <returns>如果应该处理则返回 true,否则返回 false</returns>
|
||||
protected override bool ShouldHandleJamming(JammingParameters parameters)
|
||||
{
|
||||
// 首先调用基类检查是否支持该干扰类型 (包括 SmokeScreen)
|
||||
// 首先调用基类的检查,看是否支持此类型
|
||||
if (!base.ShouldHandleJamming(parameters))
|
||||
{
|
||||
return false;
|
||||
@ -340,8 +340,7 @@ namespace ThreatSource.Indicator
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// 如果是支持的非激光干扰 (例如烟幕) 或通过了激光波长检查,则返回 true
|
||||
// 对于其他支持的类型 (如 SmokeGrenade,它没有额外的检查) 或通过了特定检查的类型,返回 true
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@ -171,75 +171,104 @@ namespace ThreatSource.Jammable
|
||||
/// <returns>如果干扰有效返回true,否则返回false</returns>
|
||||
public bool IsJammingEffective(JammingParameters parameters)
|
||||
{
|
||||
// 1. 检查是否支持该干扰类型
|
||||
// 1. 检查是否支持该干扰类型 (这个检查保持在最前面)
|
||||
if (!_supportedJammingTypes.Contains(parameters.Type))
|
||||
{
|
||||
Console.WriteLine($"[干扰有效性检查] 不支持的干扰类型: {parameters.Type}");
|
||||
return false;
|
||||
}
|
||||
|
||||
// 2. 提取原有的角度和距离相关计算逻辑
|
||||
// 计算距离和相对位置
|
||||
Vector3D devicePosition = _positionProvider();
|
||||
Vector3D relativePosition = devicePosition - parameters.SourcePosition;
|
||||
double distance = relativePosition.Magnitude();
|
||||
Console.WriteLine($"干扰计算 - 设备位置: {devicePosition}, 干扰源位置: {parameters.SourcePosition}");
|
||||
Console.WriteLine($"干扰计算 - 相对位置: {relativePosition}, 距离: {distance:F2}m");
|
||||
|
||||
if (distance <= 0)
|
||||
bool isDistanceNearZero = false;
|
||||
// 使用一个小的 epsilon 来判断距离是否接近零
|
||||
if (distance <= 1e-6)
|
||||
{
|
||||
distance = 0.1; // 设置最小距离
|
||||
isDistanceNearZero = true;
|
||||
Console.WriteLine($"干扰计算 - 调整近零距离为 {distance}m");
|
||||
}
|
||||
Console.WriteLine($"干扰计算 - 设备位置: {devicePosition}, 干扰源位置: {parameters.SourcePosition}");
|
||||
Console.WriteLine($"干扰计算 - 相对位置: {relativePosition}, 距离: {distance:F2}m");
|
||||
|
||||
// 角度检查逻辑 (普遍适用)
|
||||
// 仅当 AngleRange 有意义时 (大于0且小于360,表示有方向性) 才进行角度检查
|
||||
if (parameters.AngleRange > 0 && parameters.AngleRange < 360)
|
||||
|
||||
// 2. 选择性角度约束检查
|
||||
bool performAngleCheck = false;
|
||||
// 仅当 AngleRange 被指定且表示方向性时才检查
|
||||
if (parameters.AngleRange > 0 && parameters.AngleRange < 360)
|
||||
{
|
||||
Vector3D jammerDirection = parameters.Direction.Normalize();
|
||||
Vector3D jammerToDeviceDirection = relativePosition.Normalize();
|
||||
double dotProduct = Vector3D.DotProduct(jammerDirection, jammerToDeviceDirection);
|
||||
double angle = Math.Acos(Math.Clamp(dotProduct, -1.0, 1.0)); // 弧度
|
||||
|
||||
Console.WriteLine($"干扰计算 - 干扰器方向: {jammerDirection}, 到设备方向: {jammerToDeviceDirection}");
|
||||
Console.WriteLine($"干扰计算 - 点积: {dotProduct:F2}, 夹角: {angle * 180 / Math.PI:F2} 度, 波束范围: {parameters.AngleRange:F2} 度");
|
||||
|
||||
// 如果到设备的角度超出了干扰器波束半角 (AngleRange 是总锥角)
|
||||
if (angle > (parameters.AngleRange * Math.PI / 360.0) )
|
||||
// 定义哪些类型/模式需要进行角度检查
|
||||
if (parameters.Mode == JammingMode.Blocking ||
|
||||
parameters.Type == JammingType.MillimeterWaveCompensation) // 在此添加其他需要角度检查的类型
|
||||
{
|
||||
Console.WriteLine($"[干扰有效性检查] 类型 {parameters.Type}, 模式 {parameters.Mode}:超出波束角度。判定无效。");
|
||||
return false; // 超出角度,对于所有模式都判定无效
|
||||
performAngleCheck = true;
|
||||
}
|
||||
}
|
||||
|
||||
// 3. 特定于模式的检查
|
||||
if (performAngleCheck)
|
||||
{
|
||||
Console.WriteLine($"[干扰有效性检查] 类型 {parameters.Type},模式 {parameters.Mode}:需要进行角度检查。");
|
||||
Vector3D jammerDirection = parameters.Direction.Normalize();
|
||||
// 如果距离非常近,避免对零向量进行归一化
|
||||
Vector3D jammerToDeviceDirection = !isDistanceNearZero ? relativePosition.Normalize() : Vector3D.Zero;
|
||||
|
||||
// 如果距离非常近,我们可能认为它总是在波束内,跳过角度比较。
|
||||
if (isDistanceNearZero) {
|
||||
Console.WriteLine($"干扰计算 - 距离过近,跳过角度约束比较。");
|
||||
}
|
||||
else // 距离不近,执行角度比较
|
||||
{
|
||||
double dotProduct = Vector3D.DotProduct(jammerDirection, jammerToDeviceDirection);
|
||||
// Clamp dot product 以避免 Math.Acos 的定义域错误
|
||||
dotProduct = Math.Max(-1.0, Math.Min(1.0, dotProduct));
|
||||
double angle = Math.Acos(dotProduct); // 角度(弧度)
|
||||
|
||||
Console.WriteLine($"干扰计算 - 干扰器方向: {jammerDirection}, 到设备方向: {jammerToDeviceDirection}");
|
||||
Console.WriteLine($"干扰计算 - 点积: {dotProduct:F2}, 夹角: {angle * 180 / Math.PI:F2} 度, 波束范围: {parameters.AngleRange:F2} 度");
|
||||
|
||||
// AngleRange 是总锥角,与半角进行比较
|
||||
if (angle > (parameters.AngleRange * Math.PI / 360.0))
|
||||
{
|
||||
Console.WriteLine($"[干扰有效性检查] 类型 {parameters.Type},模式 {parameters.Mode}:超出波束角度。判定无效。");
|
||||
return false; // 未通过角度约束
|
||||
}
|
||||
Console.WriteLine($"[干扰有效性检查] 类型 {parameters.Type},模式 {parameters.Mode}:通过角度检查。");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine($"[干扰有效性检查] 类型 {parameters.Type},模式 {parameters.Mode}:无需角度检查 (AngleRange={parameters.AngleRange})。");
|
||||
}
|
||||
|
||||
// 3. 针对阻塞模式的检查
|
||||
if (parameters.Mode == JammingMode.Blocking)
|
||||
{
|
||||
// 检查是否支持该干扰类型且定义了阻塞干扰的阈值
|
||||
// 对阻塞干扰进行功率阈值检查
|
||||
if (!_jammingThresholds.TryGetValue(parameters.Type, out double threshold))
|
||||
{
|
||||
Console.WriteLine($"[干扰有效性检查] 阻塞干扰 {parameters.Type} 未找到阈值。假设无效。");
|
||||
Console.WriteLine($"[干扰有效性检查] 阻塞干扰 {parameters.Type} 未找到阈值。判定无效。");
|
||||
return false;
|
||||
}
|
||||
|
||||
// 球面扩散损耗模型
|
||||
// 使用已计算的距离
|
||||
double receivedPower = parameters.Power / (4 * Math.PI * distance * distance);
|
||||
|
||||
Console.WriteLine($"[干扰有效性检查] 阻塞干扰 {parameters.Type} - 发射功率: {parameters.Power}W, 接收功率: {receivedPower:E6}W, 阈值: {threshold:E6}W, 距离: {distance:F2}m");
|
||||
|
||||
if (receivedPower < threshold)
|
||||
{
|
||||
Console.WriteLine($"[干扰有效性检查] 阻塞干扰 {parameters.Type}:接收功率低于阈值。判定无效。");
|
||||
return false; // 功率不足,判定无效
|
||||
return false; // 未通过功率阈值检查
|
||||
}
|
||||
|
||||
Console.WriteLine($"[干扰有效性检查] 阻塞干扰 {parameters.Type}:通过角度和功率检查。判定有效。");
|
||||
return true; // 通过所有阻塞特定检查
|
||||
|
||||
Console.WriteLine($"[干扰有效性检查] 阻塞干扰 {parameters.Type}:通过所有检查。判定有效。");
|
||||
return true; // 通过了阻塞模式的所有检查
|
||||
}
|
||||
else // 非阻塞干扰 (e.g., Deception, Compensation)
|
||||
else // 非阻塞模式 (Deception, Compensation, 等)
|
||||
{
|
||||
// 对于非阻塞干扰,如果通过了上面的类型支持和角度检查,则认为它们是有效的。
|
||||
Console.WriteLine($"[干扰有效性检查] 非阻塞干扰 {parameters.Type}:通过类型支持和角度检查。判定有效。");
|
||||
return true;
|
||||
Console.WriteLine($"[干扰有效性检查] 非阻塞干扰 {parameters.Type}:通过检查。判定有效。");
|
||||
return true; // 如果是非阻塞且通过了初步检查,则认为有效
|
||||
}
|
||||
}
|
||||
|
||||
@ -270,13 +299,10 @@ namespace ThreatSource.Jammable
|
||||
/// <summary>
|
||||
/// 处理内部 JammingHandler 的 JammingCleared 事件
|
||||
/// </summary>
|
||||
private void HandleInternalJammingCleared(JammingParameters? parameters)
|
||||
private void HandleInternalJammingCleared(JammingParameters parameters)
|
||||
{
|
||||
// 触发公共事件,如果可用,则提供类型
|
||||
if (parameters != null)
|
||||
{
|
||||
JammingCleared?.Invoke(parameters);
|
||||
}
|
||||
// 触发公共事件
|
||||
JammingCleared?.Invoke(parameters);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
using ThreatSource.Jammer;
|
||||
using System; // Added for Action delegate
|
||||
using System.Collections.Generic;
|
||||
using System.Linq; // Added for Linq methods like Any() and FirstOrDefault()
|
||||
|
||||
namespace ThreatSource.Jammable
|
||||
{
|
||||
@ -9,34 +10,41 @@ namespace ThreatSource.Jammable
|
||||
/// </summary>
|
||||
public class JammingHandler
|
||||
{
|
||||
/// <summary>
|
||||
/// 内部类,用于管理单个活动干扰的状态
|
||||
/// </summary>
|
||||
private class ActiveJammingState
|
||||
{
|
||||
public JammingParameters Parameters { get; }
|
||||
public double ElapsedTime { get; set; }
|
||||
|
||||
public ActiveJammingState(JammingParameters parameters)
|
||||
{
|
||||
Parameters = parameters ?? throw new ArgumentNullException(nameof(parameters));
|
||||
ElapsedTime = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 当前所有激活的干扰状态列表
|
||||
/// </summary>
|
||||
private readonly List<ActiveJammingState> _activeJammingStates = new List<ActiveJammingState>();
|
||||
|
||||
/// <summary>
|
||||
/// 是否处于被干扰状态
|
||||
/// </summary>
|
||||
public bool IsJammed { get; private set; }
|
||||
public bool IsJammed => _activeJammingStates.Any();
|
||||
|
||||
/// <summary>
|
||||
/// 获取当前是否正受到有效的阻塞式干扰
|
||||
/// </summary>
|
||||
public bool IsBlockingJammed
|
||||
{
|
||||
get
|
||||
{
|
||||
// 如果没有被干扰,或者当前没有干扰参数,则肯定不是阻塞干扰
|
||||
// 否则,检查当前干扰的模式是否为阻塞
|
||||
return IsJammed && CurrentJamming != null && CurrentJamming.Mode == JammingMode.Blocking;
|
||||
}
|
||||
}
|
||||
public bool IsBlockingJammed => _activeJammingStates.Any(state => state.Parameters.Mode == JammingMode.Blocking);
|
||||
|
||||
/// <summary>
|
||||
/// 当前干扰参数
|
||||
/// </summary>
|
||||
protected JammingParameters? CurrentJamming { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 累积的干扰时间
|
||||
/// </summary>
|
||||
private double _elapsedTime;
|
||||
|
||||
/// <summary>
|
||||
/// 当干扰被应用时触发
|
||||
/// </summary>
|
||||
@ -53,13 +61,20 @@ namespace ThreatSource.Jammable
|
||||
/// <param name="deltaTime">时间步长,单位:秒</param>
|
||||
public virtual void Update(double deltaTime)
|
||||
{
|
||||
if (IsJammed && CurrentJamming?.Duration != null)
|
||||
// 从后向前遍历,以便在迭代过程中安全地移除元素
|
||||
for (int i = _activeJammingStates.Count - 1; i >= 0; i--)
|
||||
{
|
||||
_elapsedTime += deltaTime;
|
||||
// 检查是否超时
|
||||
if (_elapsedTime >= CurrentJamming.Duration.Value)
|
||||
var state = _activeJammingStates[i];
|
||||
if (state.Parameters.Duration != null)
|
||||
{
|
||||
ClearJamming(CurrentJamming);
|
||||
state.ElapsedTime += deltaTime;
|
||||
// 检查是否超时
|
||||
if (state.ElapsedTime >= state.Parameters.Duration.Value)
|
||||
{
|
||||
var clearedJamming = state.Parameters;
|
||||
_activeJammingStates.RemoveAt(i);
|
||||
OnJammingCleared(clearedJamming);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -70,24 +85,43 @@ namespace ThreatSource.Jammable
|
||||
/// <param name="parameters">干扰参数</param>
|
||||
public virtual void HandleJamming(JammingParameters parameters)
|
||||
{
|
||||
_elapsedTime = 0;
|
||||
IsJammed = true;
|
||||
CurrentJamming = parameters;
|
||||
OnJammingApplied(parameters);
|
||||
if (parameters == null) throw new ArgumentNullException(nameof(parameters));
|
||||
|
||||
// 可选:替换来自同一干扰源且类型相同的现有干扰
|
||||
var existingState = _activeJammingStates.FirstOrDefault(s =>
|
||||
s.Parameters.JammerId == parameters.JammerId &&
|
||||
s.Parameters.Type == parameters.Type);
|
||||
|
||||
if (existingState != null)
|
||||
{
|
||||
var replacedJamming = existingState.Parameters;
|
||||
_activeJammingStates.Remove(existingState);
|
||||
// OnJammingCleared(replacedJamming); // 可选:为被替换的干扰触发清除事件,如果需要
|
||||
}
|
||||
|
||||
var newState = new ActiveJammingState(parameters);
|
||||
_activeJammingStates.Add(newState);
|
||||
OnJammingApplied(parameters);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 清除干扰
|
||||
/// 清除与指定参数匹配的干扰
|
||||
/// </summary>
|
||||
public virtual void ClearJamming(JammingParameters parameters)
|
||||
/// <param name="parametersToClearCriteria">用于匹配要清除的干扰的参数。
|
||||
/// 通常会基于 JammerId 和 Type 进行匹配。</param>
|
||||
public virtual void ClearJamming(JammingParameters parametersToClearCriteria)
|
||||
{
|
||||
if (IsJammed)
|
||||
if (parametersToClearCriteria == null) return; // 或者抛出异常
|
||||
|
||||
var statesToClear = _activeJammingStates
|
||||
.Where(s => s.Parameters.JammerId == parametersToClearCriteria.JammerId &&
|
||||
s.Parameters.Type == parametersToClearCriteria.Type)
|
||||
.ToList(); // ToList() to avoid modification issues during enumeration
|
||||
|
||||
foreach (var state in statesToClear)
|
||||
{
|
||||
IsJammed = false;
|
||||
_elapsedTime = 0;
|
||||
var oldJamming = CurrentJamming;
|
||||
CurrentJamming = null;
|
||||
OnJammingCleared(oldJamming);
|
||||
_activeJammingStates.Remove(state);
|
||||
OnJammingCleared(state.Parameters);
|
||||
}
|
||||
}
|
||||
|
||||
@ -119,17 +153,20 @@ namespace ThreatSource.Jammable
|
||||
/// <returns>匹配的活动干扰源ID枚举;若无则为空枚举</returns>
|
||||
public IEnumerable<string> GetActiveJammerIds(JammingType? typeFilter = null)
|
||||
{
|
||||
if (IsJammed && CurrentJamming != null)
|
||||
{
|
||||
if (typeFilter == null || CurrentJamming.Type == typeFilter)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(CurrentJamming.JammerId))
|
||||
{
|
||||
yield return CurrentJamming.JammerId;
|
||||
}
|
||||
}
|
||||
}
|
||||
yield break; //确保在没有匹配项时返回一个空的IEnumerable
|
||||
return _activeJammingStates
|
||||
.Where(s => (typeFilter == null || s.Parameters.Type == typeFilter) &&
|
||||
!string.IsNullOrEmpty(s.Parameters.JammerId))
|
||||
.Select(s => s.Parameters.JammerId!)
|
||||
.Distinct();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取当前所有活动的干扰参数
|
||||
/// </summary>
|
||||
/// <returns>当前所有活动干扰参数的枚举</returns>
|
||||
public IEnumerable<JammingParameters> GetAllActiveJammings()
|
||||
{
|
||||
return _activeJammingStates.Select(s => s.Parameters);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -146,7 +146,7 @@ namespace ThreatSource.Jammer
|
||||
|
||||
if (thickness > 0.1 && config.IsObscuring)
|
||||
{
|
||||
effectiveTransmittance = physicalTransmittance * 0.01;
|
||||
effectiveTransmittance = physicalTransmittance * 1e-3;
|
||||
Console.WriteLine($"[烟幕透过率计算] 屏蔽型烟幕生效,透射率调整为: {effectiveTransmittance} (物理透射率: {physicalTransmittance})");
|
||||
}
|
||||
|
||||
|
||||
@ -500,6 +500,7 @@ namespace ThreatSource.Missile
|
||||
statusInfo.ExtendedProperties["IsGuidance"] = IsGuidance;
|
||||
statusInfo.ExtendedProperties["LostGuidanceTime"] = LostGuidanceTime;
|
||||
statusInfo.ExtendedProperties["Velocity"] = Velocity;
|
||||
statusInfo.ExtendedProperties["GuidanceAcceleration"] = GuidanceAcceleration;
|
||||
|
||||
return statusInfo;
|
||||
}
|
||||
|
||||
@ -185,7 +185,7 @@ namespace ThreatSource.Sensor
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 统一处理干扰事件
|
||||
/// 处理干扰事件
|
||||
/// </summary>
|
||||
/// <param name="evt">干扰事件</param>
|
||||
protected virtual void HandleJammingEvent(JammingEvent evt)
|
||||
@ -201,7 +201,7 @@ namespace ThreatSource.Sensor
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 统一处理干扰停止事件
|
||||
/// 处理干扰停止事件
|
||||
/// </summary>
|
||||
/// <param name="evt">干扰停止事件</param>
|
||||
protected virtual void HandleJammingStoppedEvent(JammingStoppedEvent evt)
|
||||
@ -271,7 +271,7 @@ namespace ThreatSource.Sensor
|
||||
if (!IsActive)
|
||||
{
|
||||
IsActive = true;
|
||||
// 统一订阅 HandleJammingEvent
|
||||
// 订阅 HandleJammingEvent
|
||||
SimulationManager.SubscribeToEvent<JammingEvent>(HandleJammingEvent);
|
||||
SimulationManager.SubscribeToEvent<JammingStoppedEvent>(HandleJammingStoppedEvent);
|
||||
}
|
||||
@ -286,7 +286,7 @@ namespace ThreatSource.Sensor
|
||||
if (IsActive)
|
||||
{
|
||||
IsActive = false;
|
||||
// 统一取消订阅 HandleJammingEvent
|
||||
// 取消订阅 HandleJammingEvent
|
||||
SimulationManager.UnsubscribeFromEvent<JammingEvent>(HandleJammingEvent);
|
||||
SimulationManager.UnsubscribeFromEvent<JammingStoppedEvent>(HandleJammingStoppedEvent);
|
||||
}
|
||||
|
||||
@ -178,30 +178,28 @@ namespace ThreatSource.Sensor
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if ((!IsJammed || IsJammed && !IsBlockingJammed) && smokeAttenuation > 0.1)
|
||||
// 只有在没有阻塞性干扰(虽然对该传感器为false)且烟雾不影响时才进行核心更新
|
||||
if (!IsBlockingJammed && smokeAttenuation > 0.1)
|
||||
{
|
||||
// 获取当前方向上的辐射温度
|
||||
// 获取当前方向上的辐射温度 (此方法内部会考虑 isCompensationJammed)
|
||||
double currentDirectionRadiationTemperature = GetCurrentDirectionRadiationTemperature();
|
||||
|
||||
// 计算辐射温度差
|
||||
double temperatureDifference = Math.Abs(currentDirectionRadiationTemperature - lastDetectionTemperature);
|
||||
|
||||
// 如果温度差大于检测阈值,则认为检测到目标
|
||||
if (temperatureDifference >= DetectionTemperatureDifferenceThreshold)
|
||||
{
|
||||
sensorData.IsTargetDetected = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
sensorData.IsTargetDetected = false;
|
||||
}
|
||||
sensorData.IsTargetDetected = temperatureDifference >= DetectionTemperatureDifferenceThreshold;
|
||||
sensorData.IsValid = true; // 数据流是有效的,即使可能被欺骗
|
||||
|
||||
// 更新上次检测温度
|
||||
lastDetectionTemperature = currentDirectionRadiationTemperature;
|
||||
}
|
||||
else
|
||||
else // 由于阻塞或烟雾导致无法工作
|
||||
{
|
||||
sensorData.IsValid = false;
|
||||
sensorData.IsTargetDetected = false;
|
||||
lastDetectionTemperature = BackgroundTemperature; // 重置,避免下次计算异常
|
||||
}
|
||||
}
|
||||
|
||||
@ -312,16 +310,14 @@ namespace ThreatSource.Sensor
|
||||
base.HandleJammingCleared(parameters);
|
||||
if (parameters.Type == JammingType.MillimeterWaveCompensation)
|
||||
{
|
||||
Debug.WriteLine("[MillimeterWaveRadiometer] 毫米波辐射计干扰已清除", "Jamming");
|
||||
// 只有在整体未被干扰时才恢复有效状态
|
||||
if (!IsJammed)
|
||||
Debug.WriteLine("[MillimeterWaveRadiometer] 毫米波辐射计补偿干扰已清除", "Jamming");
|
||||
isCompensationJammed = false; // 确保重置补偿干扰标志
|
||||
|
||||
// 只有在整体未被其他类型干扰(例如持续的烟幕)时才恢复有效状态
|
||||
if (!IsJammed)
|
||||
{
|
||||
sensorData.IsValid = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
sensorData.IsValid = false; // 如果仍被干扰,保持无效
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -7,6 +7,13 @@
|
||||
- 事件描述
|
||||
- 分析处理
|
||||
|
||||
## 2025-05-09 完善了各组件的干扰功能
|
||||
- 把各组件的烟幕透过率计算移到 update 方法中
|
||||
- 完善了指示器的烟幕遮挡计算逻辑
|
||||
- 完善了激光半主动导弹的落点计算逻辑
|
||||
- 完善了配置文件格式
|
||||
- 集成测试的正常运行,坦克、指示器、导弹的初始化运动参数关联很大,修改了可能会影响很多测试场景。
|
||||
|
||||
## 2025-05-07 完善了末敏弹各传感器的干扰功能
|
||||
- 增加了烟幕弹对末敏弹的干扰功能
|
||||
|
||||
|
||||
@ -263,4 +263,45 @@
|
||||
[LaserDesignator] LD_1 受到激光干扰,停止照射。
|
||||
```
|
||||
|
||||
实验结论:当激光干扰器的发射功率是 2000W 时,距离 2000米时,如果激光指示器或导弹的阻塞干扰阈值是 1e-5W,干扰效果是有效的。
|
||||
实验结论:当激光干扰器的发射功率是 2000W 时,距离 2000米时,如果激光指示器或导弹的阻塞干扰阈值是 1e-5W,干扰效果是有效的。
|
||||
|
||||
## 激光驾束导弹实验记录(v0.2.16)
|
||||
|
||||
时间:2025-05-08 10:00:00
|
||||
版本:v0.2.14
|
||||
|
||||
### 初始位置
|
||||
1. 导弹和驾束仪初始位置
|
||||
因为导弹必须沿着激光束飞行,所以需要调整激光束的初始位置,使得导弹在激光束的初始位置附近。
|
||||
假设光束直径是6米,导弹发射出去之后必须要进入这个光束,才能沿着光束飞行。所以两者的初始位置的距离必须小于3米。
|
||||
|
||||
2. 坦克初始位置
|
||||
如果是烟幕干扰,因为烟幕的底边在地面上,所以坦克全部都需要在地面以上,才能被烟幕遮住。所以坦克的中心位置,高度应该是坦克高度的 1/2。
|
||||
|
||||
## 激光半主动导弹实验记录(v0.2.16)
|
||||
|
||||
时间:2025-05-09 10:00:00
|
||||
版本:v0.2.15
|
||||
|
||||
### 激光诱偏参数和结果
|
||||
1. 坦克初始位置
|
||||
(0.0,1.2,0.0)
|
||||
|
||||
2. 诱偏激光目标位置
|
||||
(0.0,0.0,50.0)
|
||||
|
||||
3. 导弹视场角
|
||||
30 度
|
||||
|
||||
4. 运行结果
|
||||
诱偏功率 25W,落点位置 (-97.01, 0.02, 29.87)
|
||||
诱偏功率 50W,落点位置 (-57.31, 0.01, 37.83)
|
||||
诱偏功率 100W,落点位置 (-20.88, 0.00, 43.26)
|
||||
诱偏功率 200W,落点位置 (5.64, 0.01, 46.44)
|
||||
|
||||
结论:
|
||||
1. 诱偏功率越大,落点越接近假目标。
|
||||
2. 接近计算出的落点时,两个目标都离开了导引头视野,不再计算落点。导弹会惯性飞行,会偏离之前计算出的落点。
|
||||
|
||||
|
||||
|
||||
|
||||
@ -93,8 +93,8 @@ namespace ThreatSource.Tools.MissileSimulation
|
||||
// 激光驾束导弹
|
||||
missileJammingMap["LBRM_1"] = new List<(JammingType, string, string, string, string)>
|
||||
{
|
||||
(JammingType.Laser, "激光干扰", "LaserJammer_Designator", "阻塞", "指示器"),
|
||||
(JammingType.SmokeGrenade, "烟幕弹", "SG_1", "遮蔽", "两者")
|
||||
(JammingType.Laser, "激光干扰", "LaserJammer_Designator", "阻塞", "驾束仪"),
|
||||
(JammingType.SmokeGrenade, "烟幕弹", "SG_1", "遮蔽", "驾束仪")
|
||||
};
|
||||
|
||||
// 激光半主动制导导弹
|
||||
@ -124,7 +124,7 @@ namespace ThreatSource.Tools.MissileSimulation
|
||||
missileJammingMap["MMWG_1"] = new List<(JammingType, string, string, string, string)>
|
||||
{
|
||||
(JammingType.MillimeterWave, "毫米波干扰", "MillimeterWaveJammer_Missile", "阻塞", "导弹"),
|
||||
(JammingType.SmokeGrenade, "烟幕弹", "SG_1", "遮蔽", "导弹")
|
||||
(JammingType.SmokeGrenade, "烟幕弹", "SG_3", "遮蔽", "导弹")
|
||||
};
|
||||
|
||||
// 末敏子弹药
|
||||
@ -134,7 +134,7 @@ namespace ThreatSource.Tools.MissileSimulation
|
||||
(JammingType.Infrared, "红外干扰", "InfraredJammer_Submunition", "阻塞", "子弹药"),
|
||||
(JammingType.MillimeterWave, "毫米波干扰", "MillimeterWaveJammer_Submunition", "阻塞", "子弹药"),
|
||||
(JammingType.MillimeterWave, "毫米波假信号", "MillimeterWaveCompensationJammer_Submunition", "欺骗", "子弹药"),
|
||||
(JammingType.SmokeGrenade, "烟幕弹", "SG_3", "遮蔽", "子弹药")
|
||||
(JammingType.SmokeGrenade, "烟幕弹", "SG_4", "遮蔽", "子弹药")
|
||||
};
|
||||
}
|
||||
|
||||
@ -158,7 +158,7 @@ namespace ThreatSource.Tools.MissileSimulation
|
||||
AddMillimeterWaveMissile();
|
||||
|
||||
// 添加各种传感器和指示器
|
||||
AddDesignators();
|
||||
AddIndicators();
|
||||
|
||||
// 添加烟幕弹
|
||||
AddSmokeGrenade();
|
||||
@ -193,7 +193,7 @@ namespace ThreatSource.Tools.MissileSimulation
|
||||
{
|
||||
Position = new Vector3D(0, 1.2, 0),
|
||||
Orientation = new Orientation(Math.PI/2, 0.0, 0.0),
|
||||
InitialSpeed = 0.0
|
||||
InitialSpeed = 2.0
|
||||
};
|
||||
string targetId = "Tank_1";
|
||||
var target = _threatSourceFactory.CreateTarget(targetId, "mbt_001", motionParameters);
|
||||
@ -252,18 +252,27 @@ namespace ThreatSource.Tools.MissileSimulation
|
||||
Console.WriteLine($"注册烟幕弹 {smokeGrenadeId}");
|
||||
}
|
||||
|
||||
smokeGrenadeId = "SG_3";
|
||||
smokeGrenade = _threatSourceFactory.CreateJammer(smokeGrenadeId, "mmw", motionParameters, "Tank_1");
|
||||
if (smokeGrenade is BaseJammer jammer3)
|
||||
{
|
||||
simulationManager.RegisterEntity(smokeGrenadeId, jammer3);
|
||||
jammers[smokeGrenadeId] = jammer3;
|
||||
Console.WriteLine($"注册烟幕弹 {smokeGrenadeId}");
|
||||
}
|
||||
|
||||
var motionParametersTop = new MotionParameters
|
||||
{
|
||||
Position = new Vector3D(0, 10, 0),
|
||||
Orientation = Orientation.FromVector(Vector3D.UnitY),
|
||||
InitialSpeed = 0.0
|
||||
};
|
||||
smokeGrenadeId = "SG_3";
|
||||
smokeGrenadeId = "SG_4";
|
||||
smokeGrenade = _threatSourceFactory.CreateJammer(smokeGrenadeId, "top", motionParametersTop, "Tank_1");
|
||||
if (smokeGrenade is BaseJammer jammer3)
|
||||
if (smokeGrenade is BaseJammer jammer4)
|
||||
{
|
||||
simulationManager.RegisterEntity(smokeGrenadeId, jammer3);
|
||||
jammers[smokeGrenadeId] = jammer3;
|
||||
simulationManager.RegisterEntity(smokeGrenadeId, jammer4);
|
||||
jammers[smokeGrenadeId] = jammer4;
|
||||
Console.WriteLine($"注册烟幕弹 {smokeGrenadeId}");
|
||||
}
|
||||
}
|
||||
@ -275,8 +284,8 @@ namespace ThreatSource.Tools.MissileSimulation
|
||||
{
|
||||
var motionParameters = new MotionParameters
|
||||
{
|
||||
Position = new Vector3D(2000, 1, 20),
|
||||
Orientation = new Orientation(Math.PI, 0.01, 0),
|
||||
Position = new Vector3D(2000, 10, 20),
|
||||
Orientation = new Orientation(Math.PI, -0.01, 0),
|
||||
InitialSpeed = 700
|
||||
};
|
||||
string missileId = "LSGM_1";
|
||||
@ -293,8 +302,8 @@ namespace ThreatSource.Tools.MissileSimulation
|
||||
{
|
||||
var motionParameters = new MotionParameters
|
||||
{
|
||||
Position = new Vector3D(2000, 1, 20),
|
||||
Orientation = new Orientation(Math.PI, 0.01, 0.0),
|
||||
Position = new Vector3D(2000, 10, 10),
|
||||
Orientation = new Orientation(Math.PI, -0.01, 0.0),
|
||||
InitialSpeed = 300
|
||||
};
|
||||
string missileId = "LBRM_1";
|
||||
@ -382,7 +391,7 @@ namespace ThreatSource.Tools.MissileSimulation
|
||||
/// <summary>
|
||||
/// 添加传感器和指示器
|
||||
/// </summary>
|
||||
private void AddDesignators()
|
||||
private void AddIndicators()
|
||||
{
|
||||
// 添加激光目标指示器
|
||||
string laserDesignatorId = "LD_1";
|
||||
@ -401,7 +410,7 @@ namespace ThreatSource.Tools.MissileSimulation
|
||||
string laserBeamRiderId = "LBR_1";
|
||||
var laserBeamRiderLaunchParams = new MotionParameters
|
||||
{
|
||||
Position = new Vector3D(2100, 1, 20),
|
||||
Position = new Vector3D(2100, 1, 10),
|
||||
Orientation = new Orientation(Math.PI, 0, 0),
|
||||
InitialSpeed = 0
|
||||
};
|
||||
|
||||
Loading…
Reference in New Issue
Block a user