426 lines
15 KiB
C#
426 lines
15 KiB
C#
using Xunit;
|
||
using ThreatSource.Missile;
|
||
using ThreatSource.Simulation;
|
||
using ThreatSource.Utils;
|
||
using ThreatSource.Tests.Simulation;
|
||
using ThreatSource.Guidance;
|
||
using ThreatSource.Indicator;
|
||
using ThreatSource.Target;
|
||
|
||
namespace ThreatSource.Tests.Missile
|
||
{
|
||
public class LaserSemiActiveGuidedMissileCodeTests
|
||
{
|
||
private readonly SimulationManager _simulationManager;
|
||
private readonly TestSimulationAdapter _testAdapter;
|
||
private readonly LaserSemiActiveGuidedMissile _missile;
|
||
private readonly MissileProperties _properties;
|
||
private readonly MockLaserDesignator _laserDesignator;
|
||
private readonly MockTarget _target;
|
||
|
||
public LaserSemiActiveGuidedMissileCodeTests()
|
||
{
|
||
_simulationManager = new SimulationManager();
|
||
_testAdapter = new TestSimulationAdapter(_simulationManager);
|
||
_simulationManager.SetSimulationAdapter(_testAdapter);
|
||
|
||
_properties = new MissileProperties
|
||
{
|
||
MaxSpeed = 1000,
|
||
MaxFlightTime = 100,
|
||
MaxFlightDistance = 10000,
|
||
MaxAcceleration = 50,
|
||
ProportionalNavigationCoefficient = 3,
|
||
Mass = 100,
|
||
ExplosionRadius = 10,
|
||
HitProbability = 0.9,
|
||
Type = MissileType.LaserSemiActiveGuidance
|
||
};
|
||
|
||
var missileInitialMotion = new InitialMotionParameters
|
||
{
|
||
Position = new Vector3D(0, 0, 0),
|
||
Orientation = new Orientation(0, 0, 0),
|
||
InitialSpeed = 100
|
||
};
|
||
|
||
// 创建并注册模拟的激光指示器,位置在导弹后方100米处
|
||
_laserDesignator = new MockLaserDesignator("laser1", _simulationManager);
|
||
_laserDesignator.Position = new Vector3D(-100, 0, 0);
|
||
_laserDesignator.LaserPower = 100; // 设置足够高的激光功率
|
||
_testAdapter.AddTestEntity("laser1", _laserDesignator);
|
||
|
||
// 创建并注册模拟的目标,位置在导弹前方1000米处
|
||
_target = new MockTarget("target1", _simulationManager);
|
||
_target.Position = new Vector3D(1000, 0, 0);
|
||
_testAdapter.AddTestEntity("target1", _target);
|
||
|
||
var laserCodeConfig = new LaserCodeConfig
|
||
{
|
||
Code = new LaserCode
|
||
{
|
||
CodeType = LaserCodeType.PRF,
|
||
CodeValue = 1234
|
||
}
|
||
};
|
||
|
||
var guidanceConfig = new LaserSemiActiveGuidanceConfig
|
||
{
|
||
FieldOfViewAngle = 30,
|
||
LensDiameter = 0.1,
|
||
SensorDiameter = 0.03,
|
||
FocusedSpotDiameter = 0.006,
|
||
ReflectionCoefficient = 0.2,
|
||
TargetReflectiveArea = 1.0,
|
||
LockThreshold = 1e-12,
|
||
SpotOffsetSensitivity = 0.5
|
||
};
|
||
|
||
_missile = new LaserSemiActiveGuidedMissile(
|
||
"missile1",
|
||
_properties,
|
||
missileInitialMotion,
|
||
laserCodeConfig,
|
||
guidanceConfig,
|
||
_simulationManager
|
||
);
|
||
_simulationManager.RegisterEntity("missile1", _missile);
|
||
|
||
// 创建独立的制导系统用于测试
|
||
var guidanceSystem = new LaserSemiActiveGuidanceSystem(
|
||
"guidance1",
|
||
_properties.MaxAcceleration,
|
||
_properties.ProportionalNavigationCoefficient,
|
||
laserCodeConfig,
|
||
guidanceConfig,
|
||
_simulationManager
|
||
);
|
||
guidanceSystem.ParentId = "missile1";
|
||
_simulationManager.RegisterEntity("guidance1", guidanceSystem);
|
||
}
|
||
|
||
private LaserSemiActiveGuidanceSystem GetGuidanceSystem()
|
||
{
|
||
return (_simulationManager.GetEntityById("guidance1") as LaserSemiActiveGuidanceSystem)!;
|
||
}
|
||
|
||
// 模拟的激光指示器类
|
||
private class MockLaserDesignator : LaserDesignator
|
||
{
|
||
public MockLaserDesignator(string id, ISimulationManager simulationManager)
|
||
: base(id, "target1", "missile1", new LaserDesignatorConfig
|
||
{
|
||
LaserPower = 100,
|
||
LaserDivergenceAngle = 0.001,
|
||
MinWavelength = 1.0,
|
||
MaxWavelength = 1.1
|
||
}, new InitialMotionParameters
|
||
{
|
||
Position = new Vector3D(100, 0, 0),
|
||
Orientation = new Orientation(0, 0, 0),
|
||
InitialSpeed = 0
|
||
}, simulationManager)
|
||
{
|
||
// 不需要额外设置属性,因为基类构造函数已经设置了
|
||
}
|
||
}
|
||
|
||
// 模拟的目标类
|
||
private class MockTarget : Tank
|
||
{
|
||
public MockTarget(string id, ISimulationManager simulationManager)
|
||
: base(id, new InitialMotionParameters
|
||
{
|
||
Position = new Vector3D(1000, 0, 0),
|
||
Orientation = new Orientation(0, 0, 0),
|
||
InitialSpeed = 0
|
||
}, simulationManager)
|
||
{
|
||
// 不需要额外设置属性,因为基类构造函数已经设置了
|
||
}
|
||
}
|
||
|
||
[Fact]
|
||
public void SetLaserCode_SetsCodeCorrectly()
|
||
{
|
||
// Arrange
|
||
_missile.Fire();
|
||
_missile.Activate();
|
||
var guidanceSystem = GetGuidanceSystem();
|
||
|
||
// Act
|
||
guidanceSystem.SetExpectedLaserCode(LaserCodeType.PRF, 1234);
|
||
|
||
// Assert - We can't directly check the private field, but we can test the behavior
|
||
// This will be tested in the LaserIllumination test
|
||
}
|
||
|
||
[Fact]
|
||
public void AddLaserCodeParameter_AddsParameterCorrectly()
|
||
{
|
||
// Arrange
|
||
_missile.Fire();
|
||
_missile.Activate();
|
||
var guidanceSystem = GetGuidanceSystem();
|
||
guidanceSystem.SetExpectedLaserCode(LaserCodeType.PPM, 5678);
|
||
|
||
// Act
|
||
guidanceSystem.AddExpectedCodeParameter("PulseWidth", 0.001);
|
||
|
||
// Assert - We can't directly check the private field, but we can test the behavior
|
||
// This will be tested in the LaserIllumination test
|
||
}
|
||
|
||
[Fact]
|
||
public void SetCodeMatchRequired_SetsRequirementCorrectly()
|
||
{
|
||
// Arrange
|
||
_missile.Fire();
|
||
_missile.Activate();
|
||
var guidanceSystem = GetGuidanceSystem();
|
||
|
||
// Act
|
||
_missile.LaserCodeConfig = new LaserCodeConfig
|
||
{
|
||
IsCodeMatchRequired = true,
|
||
Code = new LaserCode
|
||
{
|
||
CodeType = LaserCodeType.PRF,
|
||
CodeValue = 1234
|
||
}
|
||
};
|
||
|
||
// Assert - We can't directly check the private field, but we can test the behavior
|
||
// This will be tested in the LaserIllumination test
|
||
}
|
||
|
||
[Fact]
|
||
public void LaserIllumination_WithMatchingCode_EnablesGuidance()
|
||
{
|
||
// Arrange
|
||
_missile.Fire();
|
||
_missile.Activate();
|
||
var guidanceSystem = GetGuidanceSystem();
|
||
guidanceSystem.SetExpectedLaserCode(LaserCodeType.PRF, 1234);
|
||
_missile.LaserCodeConfig.IsCodeMatchRequired = true;
|
||
_missile.Update(0.1); // Move past launch stage
|
||
|
||
// 设置激光指示器和目标位置,确保在视场角内
|
||
_laserDesignator.Position = new Vector3D(-100, 0, 0);
|
||
_target.Position = new Vector3D(1000, 0, 0);
|
||
_laserDesignator.LaserPower = 100; // 设置足够高的激光功率
|
||
|
||
// Act - Send matching code illumination
|
||
var illuminationEvent = new LaserIlluminationStartEvent
|
||
{
|
||
LaserDesignatorId = "laser1",
|
||
TargetId = "target1",
|
||
LaserCodeConfig = new LaserCodeConfig
|
||
{
|
||
Code = new LaserCode
|
||
{
|
||
CodeType = LaserCodeType.PRF,
|
||
CodeValue = 1234
|
||
}
|
||
}
|
||
};
|
||
_simulationManager.PublishEvent(illuminationEvent);
|
||
|
||
// 多次更新导弹状态,给系统更多时间处理事件
|
||
for (int i = 0; i < 10; i++)
|
||
{
|
||
_missile.Update(0.1);
|
||
_laserDesignator.Update(0.1);
|
||
}
|
||
|
||
// Assert
|
||
var matchEvents = _testAdapter.GetPublishedEvents<LaserCodeMatchEvent>();
|
||
Assert.NotEmpty(matchEvents);
|
||
Assert.True(_missile.IsGuidance);
|
||
}
|
||
|
||
[Fact]
|
||
public void LaserIllumination_WithMismatchingCode_DisablesGuidance()
|
||
{
|
||
// Arrange
|
||
_missile.Fire();
|
||
_missile.Activate();
|
||
var guidanceSystem = GetGuidanceSystem();
|
||
guidanceSystem.SetExpectedLaserCode(LaserCodeType.PRF, 1234);
|
||
_missile.LaserCodeConfig.IsCodeMatchRequired = true;
|
||
_missile.Update(0.1); // Move past launch stage
|
||
|
||
// 设置激光指示器和目标位置,确保在视场角内
|
||
_laserDesignator.Position = new Vector3D(-100, 0, 0);
|
||
_target.Position = new Vector3D(1000, 0, 0);
|
||
_laserDesignator.LaserPower = 100; // 设置足够高的激光功率
|
||
|
||
// Act - Send mismatching code illumination
|
||
var illuminationEvent = new LaserIlluminationStartEvent
|
||
{
|
||
LaserDesignatorId = "laser1",
|
||
TargetId = "target1",
|
||
LaserCodeConfig = new LaserCodeConfig
|
||
{
|
||
Code = new LaserCode
|
||
{
|
||
CodeType = LaserCodeType.PRF,
|
||
CodeValue = 5678 // Different code
|
||
}
|
||
}
|
||
};
|
||
_simulationManager.PublishEvent(illuminationEvent);
|
||
|
||
// 多次更新导弹状态,给系统更多时间处理事件
|
||
for (int i = 0; i < 10; i++)
|
||
{
|
||
_missile.Update(0.1);
|
||
_laserDesignator.Update(0.1);
|
||
}
|
||
|
||
// Assert
|
||
var mismatchEvents = _testAdapter.GetPublishedEvents<LaserCodeMismatchEvent>();
|
||
Assert.NotEmpty(mismatchEvents);
|
||
Assert.False(_missile.IsGuidance);
|
||
}
|
||
|
||
[Fact]
|
||
public void LaserIllumination_WithCodeDisabled_EnablesGuidanceIfNotRequired()
|
||
{
|
||
// Arrange
|
||
_missile.Fire();
|
||
_missile.Activate();
|
||
var guidanceSystem = GetGuidanceSystem();
|
||
guidanceSystem.SetExpectedLaserCode(LaserCodeType.PRF, 1234);
|
||
_missile.LaserCodeConfig.IsCodeMatchRequired = false; // Not required
|
||
_missile.Update(0.1); // Move past launch stage
|
||
|
||
// 设置激光指示器和目标位置,确保在视场角内
|
||
_laserDesignator.Position = new Vector3D(-100, 0, 0);
|
||
_target.Position = new Vector3D(1000, 0, 0);
|
||
_laserDesignator.LaserPower = 100; // 设置足够高的激光功率
|
||
|
||
// Act - Send illumination with code disabled
|
||
var illuminationEvent = new LaserIlluminationStartEvent
|
||
{
|
||
LaserDesignatorId = "laser1",
|
||
TargetId = "target1",
|
||
LaserCodeConfig = new LaserCodeConfig
|
||
{
|
||
Code = new LaserCode
|
||
{
|
||
CodeType = LaserCodeType.PRF,
|
||
CodeValue = 1234
|
||
}
|
||
}
|
||
};
|
||
_simulationManager.PublishEvent(illuminationEvent);
|
||
|
||
// 多次更新导弹状态,给系统更多时间处理事件
|
||
for (int i = 0; i < 10; i++)
|
||
{
|
||
_missile.Update(0.1);
|
||
_laserDesignator.Update(0.1);
|
||
}
|
||
|
||
// Assert
|
||
Assert.True(_missile.IsGuidance);
|
||
}
|
||
|
||
[Fact]
|
||
public void LaserIllumination_WithCodeDisabled_DisablesGuidanceIfRequired()
|
||
{
|
||
// Arrange
|
||
_missile.Fire();
|
||
_missile.Activate();
|
||
var guidanceSystem = GetGuidanceSystem();
|
||
guidanceSystem.SetExpectedLaserCode(LaserCodeType.PRF, 1234);
|
||
_missile.LaserCodeConfig.IsCodeMatchRequired = true; // Required
|
||
_missile.Update(0.1); // Move past launch stage
|
||
|
||
// Act - Send illumination with code disabled
|
||
var illuminationEvent = new LaserIlluminationStartEvent
|
||
{
|
||
LaserDesignatorId = "laser1",
|
||
TargetId = "target1",
|
||
LaserCodeConfig = new LaserCodeConfig
|
||
{
|
||
Code = new LaserCode
|
||
{
|
||
CodeType = LaserCodeType.PRF,
|
||
CodeValue = 1234
|
||
}
|
||
}
|
||
};
|
||
_simulationManager.PublishEvent(illuminationEvent);
|
||
|
||
// 多次更新导弹状态,给系统更多时间处理事件
|
||
for (int i = 0; i < 5; i++)
|
||
{
|
||
_missile.Update(0.1);
|
||
}
|
||
|
||
// Assert
|
||
// Guidance should be disabled without code when required
|
||
Assert.False(_missile.IsGuidance);
|
||
}
|
||
|
||
[Fact]
|
||
public void LaserIlluminationStop_DisablesGuidance()
|
||
{
|
||
// Arrange
|
||
_missile.Fire();
|
||
_missile.Activate();
|
||
var guidanceSystem = GetGuidanceSystem();
|
||
guidanceSystem.SetExpectedLaserCode(LaserCodeType.PRF, 1234);
|
||
_missile.LaserCodeConfig.IsCodeMatchRequired = true;
|
||
_missile.Update(0.1); // Move past launch stage
|
||
|
||
// 设置激光指示器和目标位置,确保在视场角内
|
||
_laserDesignator.Position = new Vector3D(-100, 0, 0);
|
||
_target.Position = new Vector3D(1000, 0, 0);
|
||
_laserDesignator.LaserPower = 100; // 设置足够高的激光功率
|
||
|
||
// First enable guidance with matching code
|
||
var startEvent = new LaserIlluminationStartEvent
|
||
{
|
||
LaserDesignatorId = "laser1",
|
||
TargetId = "target1",
|
||
LaserCodeConfig = new LaserCodeConfig
|
||
{
|
||
Code = new LaserCode
|
||
{
|
||
CodeType = LaserCodeType.PRF,
|
||
CodeValue = 1234
|
||
}
|
||
}
|
||
};
|
||
_simulationManager.PublishEvent(startEvent);
|
||
|
||
// Update several times to ensure guidance is enabled
|
||
for (int i = 0; i < 10; i++)
|
||
{
|
||
_missile.Update(0.1);
|
||
_laserDesignator.Update(0.1);
|
||
}
|
||
|
||
// Act - Stop laser illumination
|
||
var stopEvent = new LaserIlluminationStopEvent
|
||
{
|
||
LaserDesignatorId = "laser1",
|
||
TargetId = "target1"
|
||
};
|
||
_simulationManager.PublishEvent(stopEvent);
|
||
|
||
// Update several more times to ensure guidance is disabled
|
||
for (int i = 0; i < 10; i++)
|
||
{
|
||
_missile.Update(0.1);
|
||
_laserDesignator.Update(0.1);
|
||
}
|
||
|
||
// Assert
|
||
Assert.False(_missile.IsGuidance);
|
||
}
|
||
}
|
||
} |