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, "假目标干扰") };