From 27060ee12410403de94afa2fe8f5bdb4e38c88f3 Mon Sep 17 00:00:00 2001
From: Tian jianyong <11429339@qq.com>
Date: Fri, 18 Apr 2025 18:17:39 +0800
Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E7=BA=A2=E5=A4=96=E7=9B=AE?=
=?UTF-8?q?=E6=A0=87=E8=AF=86=E5=88=AB=E7=AE=97=E6=B3=95=E5=92=8C=E7=83=9F?=
=?UTF-8?q?=E5=B9=95=E5=BC=B9=E4=BD=9C=E7=94=A8=E7=AE=97=E6=B3=95?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../data/jammers/smoke_grenades/infrared.json | 20 ++
.../data/jammers/smoke_grenades/surround.json | 4 +-
.../data/jammers/smoke_grenades/top.json | 2 +
.../data/missiles/ir_imaging/itg_001.json | 5 +-
ThreatSource/src/Guidance/InfraredImage.cs | 10 +-
.../src/Guidance/InfraredImageGenerator.cs | 291 ++++++++++++++----
.../Guidance/InfraredImagingGuidanceSystem.cs | 86 ++++--
.../src/Guidance/InfraredTargetRecognizer.cs | 286 ++++++++++++-----
.../src/Simulation/ISimulationManager.cs | 2 +-
.../src/Simulation/SimulationConfig.cs | 22 ++
.../src/Simulation/SimulationElement.cs | 10 +-
.../src/Simulation/SimulationManager.cs | 5 +-
tools/ComprehensiveMissileSimulator.cs | 54 ++--
tools/Program.cs | 2 +-
14 files changed, 605 insertions(+), 194 deletions(-)
create mode 100644 ThreatSource/data/jammers/smoke_grenades/infrared.json
diff --git a/ThreatSource/data/jammers/smoke_grenades/infrared.json b/ThreatSource/data/jammers/smoke_grenades/infrared.json
new file mode 100644
index 0000000..4453a36
--- /dev/null
+++ b/ThreatSource/data/jammers/smoke_grenades/infrared.json
@@ -0,0 +1,20 @@
+{
+ "name": {
+ "zh": "周边烟幕弹",
+ "en": "Surround Smoke Grenade"
+ },
+ "type": "SmokeGrenade",
+ "SmokeGrenadeConfig": {
+ "smokeType": "Wall",
+ "IsObscuring": true,
+ "RadiationTemperature": 373.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
+ }
+}
\ No newline at end of file
diff --git a/ThreatSource/data/jammers/smoke_grenades/surround.json b/ThreatSource/data/jammers/smoke_grenades/surround.json
index af6a9ed..5e63b69 100644
--- a/ThreatSource/data/jammers/smoke_grenades/surround.json
+++ b/ThreatSource/data/jammers/smoke_grenades/surround.json
@@ -6,13 +6,15 @@
"type": "SmokeGrenade",
"SmokeGrenadeConfig": {
"smokeType": "Wall",
+ "IsObscuring": false,
+ "RadiationTemperature": 293.15,
"concentration": 0.2,
"duration": 60.0,
"wallWidth": 50.0,
"wallHeight": 10.0,
"cloudDiameter": 0.0,
"thickness": 5.0,
- "formationDelay": 1.5,
+ "formationDelay": 2.0,
"expansionRate": 5.0
}
}
\ No newline at end of file
diff --git a/ThreatSource/data/jammers/smoke_grenades/top.json b/ThreatSource/data/jammers/smoke_grenades/top.json
index 7abc495..654dac4 100644
--- a/ThreatSource/data/jammers/smoke_grenades/top.json
+++ b/ThreatSource/data/jammers/smoke_grenades/top.json
@@ -6,6 +6,8 @@
"type": "SmokeGrenade",
"SmokeGrenadeConfig": {
"smokeType": "Cloud",
+ "IsObscuring": true,
+ "RadiationTemperature": 373.15,
"concentration": 0.2,
"duration": 60.0,
"wallWidth": 0.0,
diff --git a/ThreatSource/data/missiles/ir_imaging/itg_001.json b/ThreatSource/data/missiles/ir_imaging/itg_001.json
index ee48218..93db051 100644
--- a/ThreatSource/data/missiles/ir_imaging/itg_001.json
+++ b/ThreatSource/data/missiles/ir_imaging/itg_001.json
@@ -24,11 +24,12 @@
"trackFieldOfView": 0.052,
"imageWidth": 640,
"imageHeight": 512,
- "backgroundIntensity": 0.01,
+ "backgroundIntensity": 1e-4,
"searchRecognitionProbability": 0.6,
"trackRecognitionProbability": 0.8,
"targetLostTolerance": 0.2,
"lockConfirmationTime": 0.3,
- "jammingResistanceThreshold": 1e-3
+ "jammingResistanceThreshold": 1e-3,
+ "waveLength": 3.0
}
}
\ No newline at end of file
diff --git a/ThreatSource/src/Guidance/InfraredImage.cs b/ThreatSource/src/Guidance/InfraredImage.cs
index 45fc82e..7a35893 100644
--- a/ThreatSource/src/Guidance/InfraredImage.cs
+++ b/ThreatSource/src/Guidance/InfraredImage.cs
@@ -40,6 +40,11 @@ namespace ThreatSource.Guidance
///
public Vector3D LineOfSight { get; }
+ ///
+ /// 烟幕覆盖掩码 (true 表示被遮蔽烟幕覆盖)
+ ///
+ public bool[,] SmokeCoverageMask { get; }
+
///
/// 初始化红外图像的新实例
///
@@ -47,13 +52,16 @@ namespace ThreatSource.Guidance
/// 图像高度
/// 像素物理尺寸
/// 视线方向
- public InfraredImage(int width, int height, double pixelSize, Vector3D lineOfSight)
+ /// 烟幕覆盖掩码 (可选)
+ public InfraredImage(int width, int height, double pixelSize, Vector3D lineOfSight, bool[,] smokeCoverageMask = null)
{
Width = width;
Height = height;
PixelSize = pixelSize;
LineOfSight = lineOfSight;
Intensity = new double[height, width];
+
+ SmokeCoverageMask = smokeCoverageMask ?? new bool[height, width];
}
///
diff --git a/ThreatSource/src/Guidance/InfraredImageGenerator.cs b/ThreatSource/src/Guidance/InfraredImageGenerator.cs
index 9e6e6e6..22f7e3a 100644
--- a/ThreatSource/src/Guidance/InfraredImageGenerator.cs
+++ b/ThreatSource/src/Guidance/InfraredImageGenerator.cs
@@ -1,7 +1,10 @@
using System;
+using System.Linq; // Add Linq for FirstOrDefault
using ThreatSource.Equipment;
using ThreatSource.Utils;
-using AirTransmission; // 添加引用
+using AirTransmission;
+using ThreatSource.Jammer; // 添加引用
+using ThreatSource.Simulation; // Add Simulation namespace
namespace ThreatSource.Guidance
{
@@ -47,6 +50,11 @@ namespace ThreatSource.Guidance
///
private readonly Random random = new();
+ ///
+ /// 烟幕温度转换为强度的比例因子 (简化 T^4 关系)
+ ///
+ private const double SMOKE_TEMPERATURE_FACTOR = 1e-11;
+
// 视线坐标系
private Vector3D forward; // 视线方向
private Vector3D right; // 图像平面右方向
@@ -138,44 +146,165 @@ namespace ThreatSource.Guidance
///
/// 距离(米)
/// 天气条件
+ /// 烟幕衰减
/// 大气透过率(0-1之间)
- private double CalculateAtmosphericTransmittance(double distance, Weather? weather)
+ private double CalculateAtmosphericTransmittance(double distance, Weather weather, double smokeAttenuation)
{
double transmittance;
- if (weather == null)
- {
- // 如果没有天气信息,使用基于距离的简化模型
- transmittance = Math.Exp(-0.2 * distance / 1000.0); // 0.2/km的衰减率
- return transmittance;
- }
-
// 使用AtmosphereDllWrapper计算红外波段的透过率
transmittance = AtmosphereDllWrapper.CalculateTransmittance(
distance,
RadiationType.Infrared,
wavelength,
weather);
+
+ // 考虑烟幕衰减
+ transmittance*= smokeAttenuation;
return transmittance;
}
+ ///
+ /// 应用遮蔽型烟幕效果 (根据类型区分形状)
+ ///
+ /// 存储烟幕强度的图层
+ /// 导弹当前位置
+ /// 仿真管理器实例
+ private void ApplyObscuringSmokeOverlay(double[,] smokeIntensityLayer, Vector3D missilePosition, ISimulationManager simulationManager)
+ {
+ const int minPixelSize = 3; // 最小像素尺寸 (直径或边长)
+
+ var smokeGrenades = simulationManager.GetEntitiesByType();
+
+ foreach (var smoke in smokeGrenades)
+ {
+ // 检查是否是遮蔽型烟幕 - 通过 config 访问
+ // 确保 config 和 RadiationTemperature 存在
+ if (smoke.IsActive ==false || smoke.config == null || !smoke.config.IsObscuring || smoke.config.RadiationTemperature <= 0) continue;
+
+ Vector3D toSmoke = smoke.Position - missilePosition;
+ double distance = toSmoke.Magnitude();
+
+ // 粗略检查烟幕是否在前方视野内
+ if (Vector3D.DotProduct(toSmoke.Normalize(), forward) < Math.Cos(fieldOfView / 2.0)) continue; // Use half FOV
+
+ // 计算烟幕强度 (基于 T^4 简化模型) - 通过 config 访问
+ // 注意: 这里没有考虑从烟幕到导弹的大气衰减,可以根据需要添加
+ double smokeIntensity = SMOKE_TEMPERATURE_FACTOR * Math.Pow(smoke.config.RadiationTemperature, 4);
+
+ // 投影烟幕中心
+ var (angleX, angleY) = ProjectToImagePlane(smoke.Position, missilePosition);
+ var (smokeCenterX, smokeCenterY) = AngleToPixel(angleX, angleY);
+
+ // 检查投影中心是否大致在图像内 (允许部分超出)
+ // if (smokeCenterX < -imageWidth/2 || smokeCenterX >= imageWidth*1.5 || smokeCenterY < -imageHeight/2 || smokeCenterY >= imageHeight*1.5) continue;
+ // More robust check needed? For now, let's proceed if center is roughly projectable.
+
+ // 根据烟幕类型计算尺寸并填充 - 通过 config 访问
+ switch (smoke.config.SmokeType)
+ {
+
+ case SmokeScreenType.Wall:
+ // 墙状烟幕,近似为水平矩形
+ double wallWidth = smoke.config.WallWidth; // 通过 config 访问
+ double wallHeight = smoke.config.WallHeight; // 通过 config 访问
+ int pixelWidth = (int)Math.Max(minPixelSize, (wallWidth / distance) * imageWidth / fieldOfView);
+ int pixelHeight = (int)Math.Max(minPixelSize, (wallHeight / distance) * imageHeight / fieldOfView); // Use imageHeight for vertical FOV estimate
+
+ int halfPixelWidth = pixelWidth / 2;
+ int halfPixelHeight = pixelHeight / 2;
+
+ // 确定绘制边界,确保在图像范围内
+ int minX_rect = Math.Max(0, smokeCenterX - halfPixelWidth);
+ int maxX_rect = Math.Min(imageWidth - 1, smokeCenterX + halfPixelWidth);
+ int minY_rect = Math.Max(0, smokeCenterY - halfPixelHeight);
+ int maxY_rect = Math.Min(imageHeight - 1, smokeCenterY + halfPixelHeight);
+
+ for (int y = minY_rect; y <= maxY_rect; y++)
+ {
+ for (int x = minX_rect; x <= maxX_rect; x++)
+ {
+ // 存储烟幕强度,处理重叠(取最大值)
+ smokeIntensityLayer[y, x] = Math.Max(smokeIntensityLayer[y, x], smokeIntensity);
+ }
+ }
+ Console.WriteLine($"记录遮蔽烟幕(Wall): 中心({smokeCenterX},{smokeCenterY}), 尺寸{pixelWidth}x{pixelHeight}px, 强度{smokeIntensity:F6}");
+ break;
+
+ case SmokeScreenType.Cloud:
+ // 云状烟幕,近似为圆形
+ double cloudDiameter = smoke.config.CloudDiameter; // 通过 config 访问
+ int pixelDiameter = (int)Math.Max(minPixelSize, (cloudDiameter / distance) * imageWidth / fieldOfView);
+ int pixelRadius = pixelDiameter / 2;
+ int radiusSquared = pixelRadius * pixelRadius;
+
+ // 确定绘制边界,确保在图像范围内
+ int minX_circle = Math.Max(0, smokeCenterX - pixelRadius);
+ int maxX_circle = Math.Min(imageWidth - 1, smokeCenterX + pixelRadius);
+ int minY_circle = Math.Max(0, smokeCenterY - pixelRadius);
+ int maxY_circle = Math.Min(imageHeight - 1, smokeCenterY + pixelRadius);
+
+ for (int y = minY_circle; y <= maxY_circle; y++)
+ {
+ for (int x = minX_circle; x <= maxX_circle; x++)
+ {
+ int dx = x - smokeCenterX;
+ int dy = y - smokeCenterY;
+ if (dx * dx + dy * dy <= radiusSquared)
+ {
+ // 存储烟幕强度,处理重叠(取最大值)
+ smokeIntensityLayer[y, x] = Math.Max(smokeIntensityLayer[y, x], smokeIntensity);
+ }
+ }
+ }
+ Console.WriteLine($"记录遮蔽烟幕(Cloud): 中心({smokeCenterX},{smokeCenterY}), 半径{pixelRadius}px, 强度{smokeIntensity:F6}");
+ break;
+ }
+ }
+ }
+
///
/// 生成目标的红外图像
///
/// 目标对象
/// 导弹位置
- /// 导弹速度
- /// 天气条件
+ /// 衰减型烟幕透过率
+ /// 仿真管理器实例
/// 红外图像
- public InfraredImage GenerateImage(BaseEquipment target, Vector3D missilePosition, Vector3D missileVelocity, Weather? weather)
+ public InfraredImage GenerateImage(BaseEquipment target, Vector3D missilePosition, double smokeAttenuation, ISimulationManager simulationManager)
{
// 更新视线坐标系
UpdateLineOfSightFrame(missilePosition, target.Position);
-
- // 创建图像
- var image = new InfraredImage(imageWidth, imageHeight, fieldOfView / imageWidth, forward);
-
+
+ // 创建并初始化烟幕强度图层 (-1表示无烟幕)
+ double[,] smokeIntensityLayer = new double[imageHeight, imageWidth];
+ for (int y = 0; y < imageHeight; y++)
+ {
+ for (int x = 0; x < imageWidth; x++)
+ {
+ smokeIntensityLayer[y, x] = -1.0;
+ }
+ }
+
+ // 应用(记录)遮蔽型烟幕效果到图层
+ ApplyObscuringSmokeOverlay(smokeIntensityLayer, missilePosition, simulationManager);
+
+ // --- 新增:根据烟幕强度图层创建烟幕覆盖掩码 ---
+ bool[,] smokeCoverageMask = new bool[imageHeight, imageWidth];
+ for (int y = 0; y < imageHeight; y++)
+ {
+ for (int x = 0; x < imageWidth; x++)
+ {
+ smokeCoverageMask[y, x] = (smokeIntensityLayer[y, x] >= 0); // >= 0 表示被覆盖
+ }
+ }
+ // --- 结束新增 ---
+
+ // --- 新增:在此处创建 image 对象并传入掩码 ---
+ var image = new InfraredImage(imageWidth, imageHeight, fieldOfView / imageWidth, forward, smokeCoverageMask);
+ // --- 结束新增 ---
+
// 计算目标中心投影
var (angleX, angleY) = ProjectToImagePlane(target.Position, missilePosition);
var (centerX, centerY) = AngleToPixel(angleX, angleY);
@@ -193,77 +322,106 @@ namespace ThreatSource.Guidance
pixelWidth = Math.Max(1, pixelWidth);
Console.WriteLine($"生成目标 {target.Id} 的图像,尺寸: {pixelLength}x{pixelWidth} 像素,目标中心: ({centerX}, {centerY})");
+
+ // 计算大气和衰减型烟幕的总透过率
+ double transmittance = CalculateAtmosphericTransmittance(distance, simulationManager.CurrentWeather, smokeAttenuation);
+ Console.WriteLine($"大气及衰减烟幕透过率: {transmittance}");
+
+ // 生成目标图像强度,考虑遮蔽烟幕覆盖
+ GenerateTargetIntensity(image, smokeIntensityLayer, centerX, centerY, pixelLength, pixelWidth, target, distance, transmittance);
- // 生成目标图像,传递距离参数
- GenerateTargetIntensity(image, centerX, centerY, pixelLength, pixelWidth, target, distance, weather);
-
- // 添加背景和噪声
- AddBackgroundAndNoise(image, weather);
+ // 添加背景和噪声(这会影响到烟幕和目标区域)
+ AddBackgroundAndNoise(image, simulationManager.CurrentWeather);
return image;
}
///
- /// 生成目标的红外强度分布
+ /// 生成目标的红外强度分布,考虑遮蔽烟幕覆盖
///
- private void GenerateTargetIntensity(
+ /// 红外图像对象
+ /// 遮蔽烟幕强度图层
+ /// 目标中心X像素坐标
+ /// 目标中心Y像素坐标
+ /// 目标像素长度
+ /// 目标像素宽度
+ /// 目标设备对象
+ /// 目标距离
+ /// 大气和衰减烟幕透过率
+ private static void GenerateTargetIntensity(
InfraredImage image,
+ double[,] smokeIntensityLayer, // 新增参数
int centerX,
int centerY,
int pixelLength,
int pixelWidth,
BaseEquipment target,
double distance,
- Weather? weather)
+ double transmittance)
{
- // 计算大气透过率
- double transmittance = CalculateAtmosphericTransmittance(distance, weather);
-
- // 计算目标辐射强度,考虑距离和大气透过率的影响
- double targetIntensity = target.Properties.InfraredRadiationIntensity * transmittance / Math.Pow(distance, 1.8);
+ // 计算目标自身应有的辐射强度(未被遮挡时)
+ double targetBaseIntensity = target.Properties.InfraredRadiationIntensity * transmittance / Math.Pow(distance, 1.8);
- // 计算分布参数
- double sigmaX = pixelLength / 6.0;
+ // 计算高斯分布参数
+ double sigmaX = pixelLength / 6.0; // 标准差设为长度/宽度的1/6,覆盖约99.7%范围
double sigmaY = pixelWidth / 6.0;
-
+
+ // 避免除以零
+ sigmaX = Math.Max(sigmaX, 1e-6);
+ sigmaY = Math.Max(sigmaY, 1e-6);
+
int halfLength = pixelLength / 2;
int halfWidth = pixelWidth / 2;
-
+
int pixelsSet = 0;
double maxSetIntensity = 0;
-
+
// 设置强度分布
for (int dy = -halfWidth; dy <= halfWidth; dy++)
{
int y = centerY + dy;
if (y < 0 || y >= image.Height) continue;
-
+
for (int dx = -halfLength; dx <= halfLength; dx++)
{
int x = centerX + dx;
if (x < 0 || x >= image.Width) continue;
-
- // 计算归一化距离
- double normalizedX = dx / sigmaX;
- double normalizedY = dy / sigmaY;
- double r2 = normalizedX * normalizedX + normalizedY * normalizedY;
-
- // 高斯分布
- double intensity = targetIntensity * Math.Exp(-r2 / 2.0);
-
- image.SetIntensity(y, x, intensity);
+
+ double finalIntensity;
+ double smokeIntensity = smokeIntensityLayer[y, x];
+
+ if (smokeIntensity >= 0) // 检查此像素是否被遮蔽烟幕覆盖
+ {
+ // 如果被覆盖,使用烟幕的强度
+ finalIntensity = smokeIntensity;
+ }
+ else
+ {
+ // 如果未被覆盖,计算目标的强度
+ // 计算归一化距离 (相对于高斯分布中心)
+ double normalizedX = dx / sigmaX;
+ double normalizedY = dy / sigmaY;
+ double r2 = normalizedX * normalizedX + normalizedY * normalizedY;
+
+ // 计算高斯分布下的目标强度
+ finalIntensity = targetBaseIntensity * Math.Exp(-r2 / 2.0);
+ // Console.WriteLine($"像素 ({x},{y}) 未被烟幕覆盖,使用目标强度: {finalIntensity:F6}");
+ }
+
+ // 设置最终计算出的强度到图像
+ image.SetIntensity(y, x, finalIntensity);
pixelsSet++;
- maxSetIntensity = Math.Max(maxSetIntensity, intensity);
+ maxSetIntensity = Math.Max(maxSetIntensity, finalIntensity);
}
}
-
- Console.WriteLine($"目标强度分布: 像素设置: {pixelsSet}, 最大强度: {maxSetIntensity:F6} W/sr");
+
+ Console.WriteLine($"目标/烟幕强度分布: 像素设置: {pixelsSet}, 最大强度: {maxSetIntensity:F6} W/sr");
}
///
/// 添加背景辐射和噪声
///
- private void AddBackgroundAndNoise(InfraredImage image, Weather? weather)
+ private void AddBackgroundAndNoise(InfraredImage image, Weather weather)
{
double maxIntensityBefore = double.MinValue;
double maxIntensityAfter = double.MinValue;
@@ -273,25 +431,24 @@ namespace ThreatSource.Guidance
double noiseLevel = 0.2; // 默认噪声水平
double bgIntensity = backgroundIntensity;
- if (weather != null)
+
+ // 雾、雨、雪等天气增加背景噪声
+ if (weather.Type == WeatherType.Fog)
{
- // 雾、雨、雪等天气增加背景噪声
- if (weather.Type == WeatherType.Fog)
+ noiseLevel = 0.5;
+ bgIntensity *= (1.0 + (1.0 - weather.Visibility / 10.0)); // 雾增加背景辐射
+ }
+ else if (weather.Type == WeatherType.Rain || weather.Type == WeatherType.Snow)
+ {
+ noiseLevel = 0.3;
+ // 降水增加噪声水平
+ if (weather.Precipitation > 0)
{
- noiseLevel = 0.5;
- bgIntensity *= (1.0 + (1.0 - weather.Visibility / 10.0)); // 雾增加背景辐射
- }
- else if (weather.Type == WeatherType.Rain || weather.Type == WeatherType.Snow)
- {
- noiseLevel = 0.3;
- // 降水增加噪声水平
- if (weather.Precipitation > 0)
- {
- noiseLevel += 0.1 * Math.Min(1.0, weather.Precipitation / 10.0);
- }
+ noiseLevel += 0.1 * Math.Min(1.0, weather.Precipitation / 10.0);
}
}
+
for (int y = 0; y < image.Height; y++)
{
for (int x = 0; x < image.Width; x++)
@@ -300,14 +457,16 @@ namespace ThreatSource.Guidance
maxIntensityBefore = Math.Max(maxIntensityBefore, currentIntensity);
// 只在非目标区域添加背景
- if (currentIntensity < bgIntensity * 0.1)
+ if (currentIntensity < bgIntensity)
{
currentIntensity = bgIntensity;
pixelsModified++;
}
- // 添加高斯噪声
- double noise = (random.NextDouble() - 0.5) * bgIntensity * noiseLevel;
+ // 添加高斯噪声 (降低噪声水平)
+ double noiseReductionFactor = 0.0001; // 从 0.001 改为 0.0001
+ double reducedNoiseLevel = noiseLevel * noiseReductionFactor;
+ double noise = (random.NextDouble() - 0.5) * bgIntensity * reducedNoiseLevel;
currentIntensity += noise;
// 确保非负
diff --git a/ThreatSource/src/Guidance/InfraredImagingGuidanceSystem.cs b/ThreatSource/src/Guidance/InfraredImagingGuidanceSystem.cs
index 28f3a23..f5e3485 100644
--- a/ThreatSource/src/Guidance/InfraredImagingGuidanceSystem.cs
+++ b/ThreatSource/src/Guidance/InfraredImagingGuidanceSystem.cs
@@ -91,6 +91,11 @@ namespace ThreatSource.Guidance
///
private double lockConfirmationTimer = 0;
+ ///
+ /// 烟幕衰减
+ ///
+ private double SmokeAttenuation { get; set; } = 1.0;
+
///
/// 初始化红外成像制导系统的新实例
@@ -128,9 +133,10 @@ namespace ThreatSource.Guidance
imageWidth: guidanceConfig.ImageWidth,
imageHeight: guidanceConfig.ImageHeight,
fieldOfView: guidanceConfig.SearchFieldOfView,
- backgroundIntensity: guidanceConfig.BackgroundIntensity
+ backgroundIntensity: guidanceConfig.BackgroundIntensity,
+ wavelength: guidanceConfig.WaveLength
);
- InitializeJamming(guidanceConfig.JammingResistanceThreshold, [JammingType.Infrared]);
+ InitializeJamming(guidanceConfig.JammingResistanceThreshold, [JammingType.Infrared, JammingType.SmokeScreen]);
SwitchToSearchMode(); // 初始化为搜索模式
}
@@ -170,11 +176,11 @@ namespace ThreatSource.Guidance
/// 干扰参数
protected override void HandleJammingApplied(JammingParameters parameters)
{
+ base.HandleJammingApplied(parameters);
+
if (parameters.Type == JammingType.Infrared)
{
Debug.WriteLine($"红外引导系统受到红外干扰,功率:{parameters.Power}瓦特");
- // 确保基类的处理逻辑被调用,设置HasGuidance = false
- base.HandleJammingApplied(parameters);
// 在强干扰下切换到搜索模式
if (currentMode != WorkMode.Search)
@@ -182,6 +188,14 @@ namespace ThreatSource.Guidance
SwitchToSearchMode();
}
}
+ else if (parameters.Type == JammingType.SmokeScreen)
+ {
+ if (SimulationManager.GetEntityById(parameters.JammerId) is SmokeGrenade smokeGrenade)
+ {
+ // 计算烟幕衰减
+ SmokeAttenuation = smokeGrenade.GetSmokeTransmittanceOnLine(Position, lastTargetPosition, config.WaveLength);
+ }
+ }
}
///
@@ -204,13 +218,12 @@ namespace ThreatSource.Guidance
///
public override void Activate()
{
- if (!IsActive)
- {
- IsActive = true;
- // 在这里订阅事件,确保只订阅一次
- SimulationManager.SubscribeToEvent(OnInfraredJamming);
- }
base.Activate();
+ // 在这里订阅事件,确保只订阅一次
+ SimulationManager.SubscribeToEvent(OnInfraredJamming);
+
+ // 订阅烟幕事件
+ SimulationManager.SubscribeToEvent(OnSmokeScreen);
}
///
@@ -218,14 +231,46 @@ namespace ThreatSource.Guidance
///
public override void Deactivate()
{
- if (IsActive)
- {
- IsActive = false;
- SimulationManager.UnsubscribeFromEvent(OnInfraredJamming);
- }
base.Deactivate();
+ SimulationManager.UnsubscribeFromEvent(OnInfraredJamming);
+ SimulationManager.UnsubscribeFromEvent(OnSmokeScreen);
}
+ ///
+ /// 处理烟幕事件
+ ///
+ /// 烟幕事件
+ private void OnSmokeScreen(SmokeScreenEvent evt)
+ {
+ if (evt != null && evt.SmokeGrenadeId != null)
+ {
+ // 获取烟幕弹的配置
+ if (SimulationManager.GetEntityById(evt.SmokeGrenadeId) is SmokeGrenade smokeGrenade)
+ {
+ var config = smokeGrenade.config;
+ // 创建干扰参数
+ var parameters = new JammingParameters
+ {
+ Type = JammingType.SmokeScreen,
+ JammerId = smokeGrenade.Id,
+ SourcePosition = smokeGrenade.Position,
+ Direction = smokeGrenade.Orientation.ToVector(),
+ AngleRange = config.SmokeType == SmokeScreenType.Wall ? Math.PI : Math.PI * 2, // 墙状烟幕为半球形覆盖,云状为全方位
+ SmokeConcentration = config.Concentration,
+ SmokeType = config.SmokeType,
+ SmokeThickness = config.Thickness,
+ Duration = config.Duration,
+ Mode = JammingMode.Obscuration
+ };
+
+ // 使用JammableComponent进行干扰判断
+ ApplyJamming(parameters);
+ }
+ }
+ }
+
+
+
///
/// 更新引导系统的状态和计算结果
///
@@ -242,7 +287,7 @@ namespace ThreatSource.Guidance
public override void Update(double deltaTime, Vector3D missilePosition, Vector3D missileVelocity)
{
base.Update(deltaTime, missilePosition, missileVelocity);
- if (!IsJammed)
+ if (!IsHardJammed)
{
if (TryDetectAndIdentifyTarget(missilePosition, missileVelocity, deltaTime, out Vector3D tankPosition))
{
@@ -284,7 +329,6 @@ namespace ThreatSource.Guidance
}
else
{
- HasGuidance = false;
GuidanceAcceleration = Vector3D.Zero;
}
}
@@ -309,7 +353,8 @@ namespace ThreatSource.Guidance
imageWidth: config.ImageWidth,
imageHeight: config.ImageHeight,
fieldOfView: config.SearchFieldOfView,
- backgroundIntensity: config.BackgroundIntensity
+ backgroundIntensity: config.BackgroundIntensity,
+ wavelength: config.WaveLength
);
Console.WriteLine($"切换到搜索模式, 视场角: {config.SearchFieldOfView * 180 / Math.PI} 度");
}
@@ -333,7 +378,8 @@ namespace ThreatSource.Guidance
imageWidth: config.ImageWidth,
imageHeight: config.ImageHeight,
fieldOfView: config.TrackFieldOfView,
- backgroundIntensity: config.BackgroundIntensity
+ backgroundIntensity: config.BackgroundIntensity,
+ wavelength: config.WaveLength
);
Console.WriteLine($"切换到跟踪模式, 视场角: {config.TrackFieldOfView * 180 / Math.PI} 度");
}
@@ -393,7 +439,7 @@ namespace ThreatSource.Guidance
if (angle <= currentFov / 2)
{
// 生成红外图像
- var image = imageGenerator.GenerateImage(target, missilePosition, missileVelocity, SimulationManager.CurrentWeather );
+ var image = imageGenerator.GenerateImage(target, missilePosition, SmokeAttenuation, SimulationManager);
switch (currentMode)
{
diff --git a/ThreatSource/src/Guidance/InfraredTargetRecognizer.cs b/ThreatSource/src/Guidance/InfraredTargetRecognizer.cs
index c81d0a3..517ef35 100644
--- a/ThreatSource/src/Guidance/InfraredTargetRecognizer.cs
+++ b/ThreatSource/src/Guidance/InfraredTargetRecognizer.cs
@@ -1,5 +1,7 @@
using ThreatSource.Equipment;
using ThreatSource.Simulation;
+using System.Collections.Generic; // For Queue and List
+using System.Linq; // For OrderByDescending
namespace ThreatSource.Guidance
{
@@ -74,7 +76,7 @@ namespace ThreatSource.Guidance
///
/// 背景辐射强度,用于阈值计算
///
- private const double BACKGROUND_INTENSITY = 0.01;
+ private const double BACKGROUND_INTENSITY = 0.0001;
///
/// 初始化红外图像目标识别器
@@ -149,51 +151,139 @@ namespace ThreatSource.Guidance
}
///
- /// 图像分割,提取目标区域
+ /// 图像分割,提取目标区域 - **重写:使用连通区域分析**
///
private ImageSegment SegmentTarget(InfraredImage image)
{
- // 使用简单的阈值分割方法
double threshold = CalculateThreshold(image);
- int minX = image.Width, minY = image.Height, maxX = 0, maxY = 0;
- bool found = false;
- int pixelsAboveThreshold = 0;
+ int width = image.Width;
+ int height = image.Height;
+ bool[,] visited = new bool[height, width];
+ List blobs = new List();
+ Queue<(int x, int y)> queue = new Queue<(int x, int y)>();
- // 寻找目标边界
- for (int y = 0; y < image.Height; y++)
+ Console.WriteLine($"开始连通区域分析,阈值: {threshold:F6}");
+
+ // 1. 查找所有连通区域 (Blobs)
+ for (int y = 0; y < height; y++)
{
- for (int x = 0; x < image.Width; x++)
+ for (int x = 0; x < width; x++)
{
- double intensity = image.GetIntensity(y, x);
- if (intensity > threshold)
+ if (!visited[y, x] && image.GetIntensity(y, x) > threshold)
{
- minX = Math.Min(minX, x);
- minY = Math.Min(minY, y);
- maxX = Math.Max(maxX, x);
- maxY = Math.Max(maxY, y);
- found = true;
- pixelsAboveThreshold++;
+ // 发现新 Blob 的起点
+ var currentBlob = new Blob
+ {
+ Label = blobs.Count + 1,
+ Pixels = new List<(int x, int y)>(),
+ MinX = x, MinY = y, MaxX = x, MaxY = y
+ };
+
+ queue.Enqueue((x, y));
+ visited[y, x] = true;
+
+ while (queue.Count > 0)
+ {
+ var (qx, qy) = queue.Dequeue();
+ currentBlob.Pixels.Add((qx, qy));
+
+ // 更新边界框
+ currentBlob.MinX = Math.Min(currentBlob.MinX, qx);
+ currentBlob.MinY = Math.Min(currentBlob.MinY, qy);
+ currentBlob.MaxX = Math.Max(currentBlob.MaxX, qx);
+ currentBlob.MaxY = Math.Max(currentBlob.MaxY, qy);
+
+ // 检查 4-邻域
+ int[] dx = { 0, 0, 1, -1 };
+ int[] dy = { 1, -1, 0, 0 };
+
+ for (int i = 0; i < 4; i++)
+ {
+ int nx = qx + dx[i];
+ int ny = qy + dy[i];
+
+ if (nx >= 0 && nx < width && ny >= 0 && ny < height &&
+ !visited[ny, nx] && image.GetIntensity(ny, nx) > threshold)
+ {
+ visited[ny, nx] = true;
+ queue.Enqueue((nx, ny));
+ }
+ }
+ }
+ blobs.Add(currentBlob);
+ Console.WriteLine($" 发现 Blob {currentBlob.Label}: 面积={currentBlob.Area}, 边界=({currentBlob.MinX},{currentBlob.MinY})-({currentBlob.MaxX},{currentBlob.MaxY})");
}
}
}
- Console.WriteLine($"分割结果:");
- Console.WriteLine($" 像素超过阈值: {pixelsAboveThreshold}");
- if (found)
+ Console.WriteLine($"发现 {blobs.Count} 个 Blobs");
+
+ // 2. 过滤 Blobs
+ List filteredBlobs = new List();
+ int minArea = 10; // 最小面积阈值 (过滤噪声)
+ int maxArea = (int)(width * height * 0.25); // 最大面积阈值 (过滤背景或巨大干扰, 25%)
+ const double SMOKE_COVERAGE_THRESHOLD = 0.75; // 烟幕覆盖率阈值
+
+ foreach (var blob in blobs)
{
- Console.WriteLine($" 目标边界: ({minX},{minY}) 到 ({maxX},{maxY})");
- Console.WriteLine($" 目标尺寸: {maxX - minX + 1}x{maxY - minY + 1} 像素");
+ // 检查面积
+ if (blob.Area < minArea || blob.Area > maxArea)
+ {
+ Console.WriteLine($" Blob {blob.Label} 因面积 ({blob.Area}) 不符被过滤 (允许范围: {minArea}-{maxArea})");
+ continue;
+ }
+
+ // 检查烟幕覆盖率 (使用 Blob 边界框)
+ int smokeCoveredPixelsInBox = 0;
+ int totalPixelsInBox = 0; // 只统计边界框内高于阈值的像素
+ bool[,] smokeMask = image.SmokeCoverageMask;
+ for (int by = blob.MinY; by <= blob.MaxY; by++)
+ {
+ for (int bx = blob.MinX; bx <= blob.MaxX; bx++)
+ {
+ // 检查像素是否属于该 Blob (近似检查:在边界框内且高于阈值)
+ if (image.GetIntensity(by, bx) > threshold)
+ {
+ totalPixelsInBox++;
+ if (smokeMask[by, bx])
+ {
+ smokeCoveredPixelsInBox++;
+ }
+ }
+ }
+ }
+ if (totalPixelsInBox > 0)
+ {
+ double smokeCoverageRatio = (double)smokeCoveredPixelsInBox / totalPixelsInBox;
+ Console.WriteLine($" Blob {blob.Label} 烟幕覆盖率: {smokeCoverageRatio:P2} ({smokeCoveredPixelsInBox}/{totalPixelsInBox})");
+ if (smokeCoverageRatio >= SMOKE_COVERAGE_THRESHOLD)
+ {
+ Console.WriteLine($" Blob {blob.Label} 因烟幕覆盖率过高被过滤");
+ continue;
+ }
+ }
+
+ // 通过所有检查,添加到过滤后的列表
+ filteredBlobs.Add(blob);
+ Console.WriteLine($" Blob {blob.Label} 通过过滤");
}
- if (!found)
+ // 3. 选择最佳 Blob
+ if (filteredBlobs.Count == 0)
{
- return new ImageSegment();
+ Console.WriteLine("没有找到有效的 Blob");
+ return new ImageSegment(); // 返回无效分割
}
+ // 选择面积最大的 Blob 作为目标
+ Blob targetBlob = filteredBlobs.OrderByDescending(b => b.Area).First();
+ Console.WriteLine($"选择 Blob {targetBlob.Label} 作为目标 (面积: {targetBlob.Area})");
+
+ // 4. 返回基于选定 Blob 的 ImageSegment
return new ImageSegment(
isValid: true,
- center: ((minX + maxX) / 2, (minY + maxY) / 2),
- size: (maxX - minX + 1, maxY - minY + 1)
+ center: targetBlob.Center,
+ size: (targetBlob.Width, targetBlob.Height)
);
}
@@ -212,31 +302,44 @@ namespace ThreatSource.Guidance
for (int x = 0; x < image.Width; x++)
{
double value = image.GetIntensity(y, x);
- maxIntensity = Math.Max(maxIntensity, value);
- minIntensity = Math.Min(minIntensity, value);
- sum += value;
- count++;
+ // Skip completely black pixels if necessary, or handle potential division by zero later
+ if (value > 0) // Avoid issues if minIntensity remains double.MaxValue
+ {
+ maxIntensity = Math.Max(maxIntensity, value);
+ minIntensity = Math.Min(minIntensity, value);
+ sum += value;
+ count++;
+ }
}
}
+
+ // Handle case where image is entirely black or has no valid pixels
+ if (count == 0 || maxIntensity <= minIntensity)
+ {
+ Console.WriteLine("图像全黑或无有效强度信息,无法计算阈值,返回0");
+ return 0; // Or handle appropriately
+ }
+
double mean = sum / count;
-
- // 计算背景基准阈值
- double backgroundThreshold = BACKGROUND_INTENSITY * 1.2;
-
- // 计算目标基准阈值
- double targetThreshold = maxIntensity * 0.2;
-
- // 取两个基准中的较大值作为最终阈值
- double threshold = Math.Max(backgroundThreshold, targetThreshold);
+
+ // --- 修改为基于动态范围的阈值计算 ---
+ double thresholdFactor = 0.001; // 基于动态范围的因子 (初始值设为0.15, 从 0.05 改为 0.01)
+ double dynamicRange = maxIntensity - minIntensity;
+ double threshold = minIntensity + dynamicRange * thresholdFactor;
+
+ // 添加一个小的偏移量,以确保阈值严格大于最小强度,避免将所有背景像素包含进来
+ // double epsilon = 1e-9;
+ // threshold = Math.Max(threshold, minIntensity + epsilon); // 确保阈值至少比最小值大一点点
Console.WriteLine($"图像统计:");
Console.WriteLine($" 最大强度: {maxIntensity:F6}");
Console.WriteLine($" 最小强度: {minIntensity:F6}");
Console.WriteLine($" 平均强度: {mean:F6}");
- Console.WriteLine($" 背景阈值: {backgroundThreshold:F6}");
- Console.WriteLine($" 目标阈值: {targetThreshold:F6}");
+ Console.WriteLine($" 动态范围: {dynamicRange:F6}");
+ Console.WriteLine($" 动态阈值因子: {thresholdFactor:P1}");
Console.WriteLine($" 最终阈值: {threshold:F6}");
+ // --- 结束修改 ---
return threshold;
}
@@ -309,28 +412,32 @@ namespace ThreatSource.Guidance
}
///
- /// 计算温度梯度特征
+ /// 计算温度梯度特征 - **修正:强制基于图像计算**
///
private double CalculateTemperatureGradient(InfraredImage image, ImageSegment segment, IEquipment target)
{
- // 直接从目标获取温度分布数据
- double[,] thermalPattern = target.GetCurrentThermalPattern();
- if (thermalPattern == null)
- {
- Console.WriteLine("没有温度分布数据, 使用图像计算梯度");
- return CalculateImageBasedGradient(image, segment);
- }
+ // -- 移除直接从目标获取理想温度分布数据的逻辑 --
+ // double[,] thermalPattern = target.GetCurrentThermalPattern(); // 错误:这会绕过烟幕遮蔽效果
+ // if (thermalPattern == null)
+ // {
+ // Console.WriteLine("没有温度分布数据, 使用图像计算梯度");
+ // return CalculateImageBasedGradient(image, segment);
+ // }
+ //
+ // var pattern = new ThermalPattern(thermalPattern, thermalPattern);
+ //
+ // // 判断目标是否在运动 (这个判断可能仍然有用,但基于图像的梯度计算目前不使用它)
+ // bool isMoving = IsTargetMoving(image, segment);
+ // Console.WriteLine($"目标运动状态: {(isMoving ? "移动" : "静止")}");
+ //
+ // // 使用理想温度分布模式计算梯度特征 (错误)
+ // double gradientFeature = pattern.CalculateGradientFeature(isMoving);
+ //
+ // return gradientFeature;
- var pattern = new ThermalPattern(thermalPattern, thermalPattern);
-
- // 判断目标是否在运动
- bool isMoving = IsTargetMoving(image, segment);
- Console.WriteLine($"目标运动状态: {(isMoving ? "移动" : "静止")}");
-
- // 使用温度分布模式计算梯度特征
- double gradientFeature = pattern.CalculateGradientFeature(isMoving);
-
- return gradientFeature;
+ // **修正:始终基于传入的红外图像计算梯度特征**
+ Console.WriteLine("计算基于图像的温度梯度特征");
+ return CalculateImageBasedGradient(image, segment);
}
///
@@ -428,14 +535,14 @@ namespace ThreatSource.Guidance
// 计算中部区域的梯度特征
double middleAreaGradient = avgGridGradients[1, 1];
- // 计算梯度分布特征
- double gradientDistribution = engineAreaGradient / (frontAreaGradient + 0.1);
- double gradientContrast = engineAreaGradient / (middleAreaGradient + 0.1);
+ // 计算梯度分布特征 (调整除零保护)
+ double gradientDistribution = engineAreaGradient / (frontAreaGradient + 1e-6);
+ double gradientContrast = engineAreaGradient / (middleAreaGradient + 1e-6);
- // 最终得分:后部梯度强度(0.3) + 梯度分布特征(0.4) + 梯度对比度(0.3)
- return engineAreaGradient * 0.3 +
- Math.Min(gradientDistribution, 3.0) / 3.0 * 0.4 +
- Math.Min(gradientContrast, 3.0) / 3.0 * 0.3;
+ // 最终得分:调整权重 (engine*0.5 + dist*0.3 + contrast*0.2)
+ return engineAreaGradient * 0.5 +
+ Math.Min(gradientDistribution, 3.0) / 3.0 * 0.3 +
+ Math.Min(gradientContrast, 3.0) / 3.0 * 0.2;
}
///
@@ -525,20 +632,21 @@ namespace ThreatSource.Guidance
histogram[i] /= totalPixels;
}
- // 计算集中度得分:高强度bin的占比越高,得分越高
+ // 计算集中度得分:改为计算最高 30% bin 的占比
double concentrationScore = 0;
- for (int i = 0; i < BINS; i++)
+ int topBinsStart = (int)(BINS * 0.7); // Start from the 70th percentile bin (e.g., index 7 for BINS=10)
+ for (int i = topBinsStart; i < BINS; i++)
{
- // 使用指数权重,使高强度bin的影响更大
- double weight = Math.Pow(2, i) / Math.Pow(2, BINS-1); // 指数增长的权重
- concentrationScore += histogram[i] * weight;
+ concentrationScore += histogram[i];
}
// 计算中心区域相对强度比
- double centerIntensityRatio = avgCenterIntensity / avgTotalIntensity;
+ double centerIntensityRatio = avgTotalIntensity > 0 ? avgCenterIntensity / avgTotalIntensity : 0; // Avoid division by zero
// 最终得分:集中度得分(0.6)和中心强度比(0.4)的加权和
- return concentrationScore * 0.6 + centerIntensityRatio * 0.4;
+ // 同时确保最终结果在 [0, 1] 范围内
+ double finalScore = concentrationScore * 0.6 + centerIntensityRatio * 0.4;
+ return Math.Max(0, Math.Min(1, finalScore)); // Clamp result to [0, 1]
}
///
@@ -578,13 +686,15 @@ namespace ThreatSource.Guidance
private double[] CalculateFeatureWeights(TargetFeature features)
{
// 使用固定权重,基于特征的重要性
- return new[]
- {
- 0.3, // 长宽比权重
- 0.2, // 相对尺寸权重
- 0.25, // 强度模式权重
- 0.25 // 温度梯度权重
- };
+ // **重新平衡权重:降低梯度权重,提升形状和尺寸权重**
+ return
+ [
+ 0.30, // 长宽比权重 (原 0.15, 最初 0.3)
+ 0.25, // 相对尺寸权重 (原 0.15, 最初 0.2)
+ 0.15, // 强度模式权重 (原 0.20, 最初 0.25)
+ 0.30 // 温度梯度权重 (原 0.50, 最初 0.25)
+ // 总和为 1.00
+ ];
}
///
@@ -673,5 +783,21 @@ namespace ThreatSource.Guidance
Size = size;
}
}
+
+ // --- 新增:Blob 结构体,用于存储连通区域信息 ---
+ private struct Blob
+ {
+ public int Label { get; set; }
+ public List<(int x, int y)> Pixels { get; set; }
+ public int MinX { get; set; }
+ public int MinY { get; set; }
+ public int MaxX { get; set; }
+ public int MaxY { get; set; }
+ public int Area => Pixels?.Count ?? 0;
+ public int Width => MaxX - MinX + 1;
+ public int Height => MaxY - MinY + 1;
+ public (int X, int Y) Center => ((MinX + MaxX) / 2, (MinY + MaxY) / 2);
+ }
+ // --- 结束新增 ---
}
}
\ No newline at end of file
diff --git a/ThreatSource/src/Simulation/ISimulationManager.cs b/ThreatSource/src/Simulation/ISimulationManager.cs
index b832e28..6d07e02 100644
--- a/ThreatSource/src/Simulation/ISimulationManager.cs
+++ b/ThreatSource/src/Simulation/ISimulationManager.cs
@@ -123,7 +123,7 @@ namespace ThreatSource.Simulation
///
/// 获取当前天气系统
///
- Weather? CurrentWeather { get; }
+ Weather CurrentWeather { get; }
///
/// 设置当前天气
diff --git a/ThreatSource/src/Simulation/SimulationConfig.cs b/ThreatSource/src/Simulation/SimulationConfig.cs
index bb7e78b..720c25d 100644
--- a/ThreatSource/src/Simulation/SimulationConfig.cs
+++ b/ThreatSource/src/Simulation/SimulationConfig.cs
@@ -592,6 +592,11 @@ namespace ThreatSource.Simulation
///
public double JammingResistanceThreshold { get; set; } = 1e-3;
+ ///
+ /// 波长,单位:微米
+ ///
+ public double WaveLength { get; set; } = 8.0;
+
///
/// 初始化红外成像导引配置的新实例
///
@@ -1621,6 +1626,14 @@ namespace ThreatSource.Simulation
///
public SmokeScreenType SmokeType { get; set; } = SmokeScreenType.Cloud;
+ ///
+ /// 是否是遮蔽型烟幕
+ ///
+ ///
+ /// 遮蔽型烟幕会使用固定高强度值 (W/sr)
+ ///
+ public bool IsObscuring { get; set; } = false;
+
///
/// 烟幕浓度,单位:g/m³
///
@@ -1630,6 +1643,15 @@ namespace ThreatSource.Simulation
///
public double Concentration { get; set; } = 0.2;
+ ///
+ /// 辐射温度,单位:K
+ ///
+ ///
+ /// 烟幕的辐射温度,影响其热辐射特性
+ /// 标准辐射温度范围:200-300 K
+ ///
+ public double RadiationTemperature { get; set; } = 273.15;
+
///
/// 烟幕持续时间,单位:秒
///
diff --git a/ThreatSource/src/Simulation/SimulationElement.cs b/ThreatSource/src/Simulation/SimulationElement.cs
index 840a396..b4cbb89 100644
--- a/ThreatSource/src/Simulation/SimulationElement.cs
+++ b/ThreatSource/src/Simulation/SimulationElement.cs
@@ -125,7 +125,10 @@ namespace ThreatSource.Simulation
///
public virtual void Activate()
{
- IsActive = true;
+ if (!IsActive)
+ {
+ IsActive = true;
+ }
}
///
@@ -139,7 +142,10 @@ namespace ThreatSource.Simulation
///
public virtual void Deactivate()
{
- IsActive = false;
+ if (IsActive)
+ {
+ IsActive = false;
+ }
}
}
}
diff --git a/ThreatSource/src/Simulation/SimulationManager.cs b/ThreatSource/src/Simulation/SimulationManager.cs
index 4b19ffe..289ef93 100644
--- a/ThreatSource/src/Simulation/SimulationManager.cs
+++ b/ThreatSource/src/Simulation/SimulationManager.cs
@@ -72,13 +72,14 @@ namespace ThreatSource.Simulation
///
/// 当前天气系统
+ /// 默认为无风晴朗天气
///
- private Weather? _currentWeather;
+ private Weather _currentWeather = new(WeatherType.Clear, 25, 50, 23, 0, 415, 1013, 0, 0);
///
/// 获取当前天气系统
///
- public Weather? CurrentWeather => _currentWeather;
+ public Weather CurrentWeather => _currentWeather;
///
/// 启动仿真系统
diff --git a/tools/ComprehensiveMissileSimulator.cs b/tools/ComprehensiveMissileSimulator.cs
index bc962de..ed1add7 100644
--- a/tools/ComprehensiveMissileSimulator.cs
+++ b/tools/ComprehensiveMissileSimulator.cs
@@ -136,7 +136,7 @@ namespace ThreatSource.Tools.MissileSimulation
{
var motionParameters = new MotionParameters
{
- Position = new Vector3D(100, 5, 0),
+ Position = new Vector3D(50, 5, 0),
Orientation = Orientation.FromVector(Vector3D.UnitX),
InitialSpeed = 0.0
};
@@ -148,6 +148,24 @@ namespace ThreatSource.Tools.MissileSimulation
jammers[smokeGrenadeId] = smokeGrenade as BaseJammer;
Console.WriteLine($"注册烟幕弹 {smokeGrenadeId}");
}
+
+ smokeGrenadeId = "SG_2";
+ smokeGrenade = _threatSourceFactory.CreateJammer(smokeGrenadeId, "infrared", motionParameters, "Tank_1");
+ if (smokeGrenade != null)
+ {
+ simulationManager.RegisterEntity(smokeGrenadeId, smokeGrenade);
+ jammers[smokeGrenadeId] = smokeGrenade as BaseJammer;
+ Console.WriteLine($"注册烟幕弹 {smokeGrenadeId}");
+ }
+
+ smokeGrenadeId = "SG_3";
+ smokeGrenade = _threatSourceFactory.CreateJammer(smokeGrenadeId, "top", motionParameters, "Tank_1");
+ if (smokeGrenade != null)
+ {
+ simulationManager.RegisterEntity(smokeGrenadeId, smokeGrenade);
+ jammers[smokeGrenadeId] = smokeGrenade as BaseJammer;
+ Console.WriteLine($"注册烟幕弹 {smokeGrenadeId}");
+ }
}
///
@@ -157,7 +175,7 @@ namespace ThreatSource.Tools.MissileSimulation
{
var motionParameters = new MotionParameters
{
- Position = new Vector3D(2000, 1, 0),
+ Position = new Vector3D(2000, 1, 20),
Orientation = new Orientation(Math.PI, 0.01, 0),
InitialSpeed = 700
};
@@ -175,8 +193,8 @@ namespace ThreatSource.Tools.MissileSimulation
{
var motionParameters = new MotionParameters
{
- Position = new Vector3D(2000, 10, 100),
- Orientation = new Orientation(Math.PI, 0.0, 0.0),
+ Position = new Vector3D(2000, 1, 20),
+ Orientation = new Orientation(Math.PI, 0.01, 0.0),
InitialSpeed = 300
};
string missileId = "LBRM_1";
@@ -193,7 +211,7 @@ namespace ThreatSource.Tools.MissileSimulation
{
var motionParameters = new MotionParameters
{
- Position = new Vector3D(3000, 0, 100),
+ Position = new Vector3D(3000, 0, 20),
Orientation = new Orientation(Math.PI, 0, 0),
InitialSpeed = 800
};
@@ -213,8 +231,8 @@ namespace ThreatSource.Tools.MissileSimulation
{
var motionParameters = new MotionParameters
{
- Position = new Vector3D(2000, 10, 100),
- Orientation = new Orientation(Math.PI, 0.0, 0),
+ Position = new Vector3D(2000, 1, 20),
+ Orientation = new Orientation(Math.PI, 0.01, 0),
InitialSpeed = 300
};
@@ -232,8 +250,8 @@ namespace ThreatSource.Tools.MissileSimulation
{
var motionParameters = new MotionParameters
{
- Position = new Vector3D(2000, 20, 50),
- Orientation = new Orientation(Math.PI, 0.0, 0),
+ Position = new Vector3D(2000, 1, 0),
+ Orientation = new Orientation(Math.PI, 0.02, 0),
InitialSpeed = 300
};
string missileId = "ITGM_1";
@@ -250,8 +268,8 @@ namespace ThreatSource.Tools.MissileSimulation
{
var motionParameters = new MotionParameters
{
- Position = new Vector3D(3000, 20, 100),
- Orientation = new Orientation(Math.PI, 0.0, 0),
+ Position = new Vector3D(3000, 1, 20),
+ Orientation = new Orientation(Math.PI, 0.01, 0),
InitialSpeed = 300
};
string missileId = "MMWG_1";
@@ -270,8 +288,8 @@ namespace ThreatSource.Tools.MissileSimulation
string laserDesignatorId = "LD_1";
var laserDesignatorLaunchParams = new MotionParameters
{
- Position = new Vector3D(2100, 10, 100),
- Orientation = new Orientation(Math.PI, 0, 0),
+ Position = new Vector3D(2100, 1, 100),
+ Orientation = new Orientation(Math.PI, 0.01, 0),
InitialSpeed = 0
};
var laserDesignator = _threatSourceFactory.CreateIndicator(laserDesignatorId, "ld_001", "Tank_1", "LSGM_1", laserDesignatorLaunchParams);
@@ -283,7 +301,7 @@ namespace ThreatSource.Tools.MissileSimulation
string laserBeamRiderId = "LBR_1";
var laserBeamRiderLaunchParams = new MotionParameters
{
- Position = new Vector3D(2100, 10, 100),
+ Position = new Vector3D(2100, 1, 20),
Orientation = new Orientation(Math.PI, 0, 0),
InitialSpeed = 0
};
@@ -296,7 +314,7 @@ namespace ThreatSource.Tools.MissileSimulation
string infraredTrackerId = "IT_1";
var infraredTrackerLaunchParams = new MotionParameters
{
- Position = new Vector3D(2100, 10, 100),
+ Position = new Vector3D(2100, 1, 100),
Orientation = new Orientation(Math.PI, 0, 0),
InitialSpeed = 0
};
@@ -372,7 +390,7 @@ namespace ThreatSource.Tools.MissileSimulation
// }
if (jammers.ContainsKey("SG_1"))
{
- jammers["SG_1"].Activate();
+ //jammers["SG_1"].Activate();
Console.WriteLine($"激活烟幕弹 {jammers["SG_1"].Id}");
}
break;
@@ -413,8 +431,8 @@ namespace ThreatSource.Tools.MissileSimulation
switch (type)
{
case JammingType.SmokeScreen:
- jammingParams.JammerId = "SG_1";
- jammers["SG_1"].Activate();
+ jammingParams.JammerId = "SG_2";
+ jammers["SG_2"].Activate();
break;
case JammingType.Decoy:
jammingParams.JammerId = "LDY_1";
diff --git a/tools/Program.cs b/tools/Program.cs
index c11b11a..bfe3e95 100644
--- a/tools/Program.cs
+++ b/tools/Program.cs
@@ -174,7 +174,7 @@ namespace ThreatSource.Tools.MissileSimulation
(JammingType.Infrared, "红外干扰"),
(JammingType.MillimeterWave, "毫米波干扰"),
(JammingType.Laser, "激光干扰"),
- (JammingType.SmokeScreen, "烟幕干扰"),
+ (JammingType.SmokeScreen, "烟幕弹"),
(JammingType.Decoy, "假目标干扰")
};