增加激光编码功能
This commit is contained in:
parent
43e4549c6a
commit
0019f795f8
13
CHANGELOG.md
13
CHANGELOG.md
@ -13,6 +13,19 @@
|
||||
- 实现实时仿真数据同步
|
||||
- 处理不同时间步长的协调
|
||||
|
||||
## [0.2.4] - 2025-02-25
|
||||
|
||||
### 功能优化
|
||||
- 增加了激光半主动导弹和激光目标指示器的激光编码功能
|
||||
- 增加了对应的测试用例
|
||||
- 支持六种激光编码类型
|
||||
- PRF:脉冲重复频率编码
|
||||
- PPM:脉冲位置调制
|
||||
- PWM:脉冲宽度调制
|
||||
- PseudoRandom:伪随机编码
|
||||
- Frequency:频率编码
|
||||
- Phase:相位编码
|
||||
|
||||
## [0.2.3] - 2025-02-17
|
||||
|
||||
### 功能优化
|
||||
|
||||
@ -0,0 +1,233 @@
|
||||
using Xunit;
|
||||
using ThreatSource.Guidance;
|
||||
using ThreatSource.Simulation;
|
||||
using ThreatSource.Utils;
|
||||
using ThreatSource.Simulation.Testing;
|
||||
|
||||
namespace ThreatSource.Tests.Guidance
|
||||
{
|
||||
public class LaserSemiActiveGuidanceSystemCodeTests
|
||||
{
|
||||
private readonly SimulationManager _simulationManager;
|
||||
private readonly TestSimulationAdapter _testAdapter;
|
||||
private readonly LaserSemiActiveGuidanceSystem _guidanceSystem;
|
||||
|
||||
public LaserSemiActiveGuidanceSystemCodeTests()
|
||||
{
|
||||
_simulationManager = new SimulationManager();
|
||||
_testAdapter = new TestSimulationAdapter(_simulationManager);
|
||||
_simulationManager.SetSimulationAdapter(_testAdapter);
|
||||
|
||||
_guidanceSystem = new LaserSemiActiveGuidanceSystem(
|
||||
"guidance1",
|
||||
50, // maxAcceleration
|
||||
3, // guidanceCoefficient
|
||||
_simulationManager
|
||||
);
|
||||
_guidanceSystem.ParentId = "missile1";
|
||||
_simulationManager.RegisterEntity("guidance1", _guidanceSystem);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SetExpectedLaserCode_SetsCodeCorrectly()
|
||||
{
|
||||
// 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 ProcessLaserIlluminationEvent test
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AddExpectedCodeParameter_AddsParameterCorrectly()
|
||||
{
|
||||
// Arrange
|
||||
_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 ProcessLaserIlluminationEvent test
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SetCodeMatchRequired_SetsRequirementCorrectly()
|
||||
{
|
||||
// Act
|
||||
_guidanceSystem.SetCodeMatchRequired(true);
|
||||
|
||||
// Assert - We can't directly check the private field, but we can test the behavior
|
||||
// This will be tested in the ProcessLaserIlluminationEvent test
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ProcessLaserIlluminationEvent_WithMatchingCode_PublishesMatchEvent()
|
||||
{
|
||||
// Arrange
|
||||
_guidanceSystem.SetExpectedLaserCode(LaserCodeType.PRF, 1234);
|
||||
_guidanceSystem.SetCodeMatchRequired(true);
|
||||
|
||||
var illuminationEvent = new LaserIlluminationStartEvent
|
||||
{
|
||||
LaserDesignatorId = "laser1",
|
||||
TargetId = "target1",
|
||||
IsCodeEnabled = true,
|
||||
LaserCode = new LaserCode
|
||||
{
|
||||
CodeType = LaserCodeType.PRF,
|
||||
CodeValue = 1234
|
||||
}
|
||||
};
|
||||
|
||||
// Act
|
||||
_guidanceSystem.ProcessLaserIlluminationEvent(illuminationEvent);
|
||||
|
||||
// Assert
|
||||
var matchEvents = _testAdapter.GetPublishedEvents<LaserCodeMatchEvent>();
|
||||
Assert.NotEmpty(matchEvents);
|
||||
|
||||
var lastEvent = matchEvents[matchEvents.Count - 1];
|
||||
Assert.Equal("missile1", lastEvent.MissileId);
|
||||
Assert.Equal("laser1", lastEvent.DesignatorId);
|
||||
Assert.NotNull(lastEvent.MatchedCode);
|
||||
Assert.Equal(LaserCodeType.PRF, lastEvent.MatchedCode.CodeType);
|
||||
Assert.Equal(1234, lastEvent.MatchedCode.CodeValue);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ProcessLaserIlluminationEvent_WithMismatchingCode_PublishesMismatchEvent()
|
||||
{
|
||||
// Arrange
|
||||
_guidanceSystem.SetExpectedLaserCode(LaserCodeType.PRF, 1234);
|
||||
_guidanceSystem.SetCodeMatchRequired(true);
|
||||
|
||||
var illuminationEvent = new LaserIlluminationStartEvent
|
||||
{
|
||||
LaserDesignatorId = "laser1",
|
||||
TargetId = "target1",
|
||||
IsCodeEnabled = true,
|
||||
LaserCode = new LaserCode
|
||||
{
|
||||
CodeType = LaserCodeType.PRF,
|
||||
CodeValue = 5678 // Different code value
|
||||
}
|
||||
};
|
||||
|
||||
// Act
|
||||
_guidanceSystem.ProcessLaserIlluminationEvent(illuminationEvent);
|
||||
|
||||
// Assert
|
||||
var mismatchEvents = _testAdapter.GetPublishedEvents<LaserCodeMismatchEvent>();
|
||||
Assert.NotEmpty(mismatchEvents);
|
||||
|
||||
var lastEvent = mismatchEvents[mismatchEvents.Count - 1];
|
||||
Assert.Equal("missile1", lastEvent.MissileId);
|
||||
Assert.Equal("laser1", lastEvent.DesignatorId);
|
||||
Assert.NotNull(lastEvent.ExpectedCode);
|
||||
Assert.Equal(LaserCodeType.PRF, lastEvent.ExpectedCode.CodeType);
|
||||
Assert.Equal(1234, lastEvent.ExpectedCode.CodeValue);
|
||||
Assert.NotNull(lastEvent.ReceivedCode);
|
||||
Assert.Equal(LaserCodeType.PRF, lastEvent.ReceivedCode.CodeType);
|
||||
Assert.Equal(5678, lastEvent.ReceivedCode.CodeValue);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ProcessLaserIlluminationEvent_WithDifferentCodeType_PublishesMismatchEvent()
|
||||
{
|
||||
// Arrange
|
||||
_guidanceSystem.SetExpectedLaserCode(LaserCodeType.PRF, 1234);
|
||||
_guidanceSystem.SetCodeMatchRequired(true);
|
||||
|
||||
var illuminationEvent = new LaserIlluminationStartEvent
|
||||
{
|
||||
LaserDesignatorId = "laser1",
|
||||
TargetId = "target1",
|
||||
IsCodeEnabled = true,
|
||||
LaserCode = new LaserCode
|
||||
{
|
||||
CodeType = LaserCodeType.PPM, // Different code type
|
||||
CodeValue = 1234
|
||||
}
|
||||
};
|
||||
|
||||
// Act
|
||||
_guidanceSystem.ProcessLaserIlluminationEvent(illuminationEvent);
|
||||
|
||||
// Assert
|
||||
var mismatchEvents = _testAdapter.GetPublishedEvents<LaserCodeMismatchEvent>();
|
||||
Assert.NotEmpty(mismatchEvents);
|
||||
|
||||
var lastEvent = mismatchEvents[mismatchEvents.Count - 1];
|
||||
Assert.Equal("missile1", lastEvent.MissileId);
|
||||
Assert.Equal("laser1", lastEvent.DesignatorId);
|
||||
Assert.NotNull(lastEvent.ExpectedCode);
|
||||
Assert.Equal(LaserCodeType.PRF, lastEvent.ExpectedCode.CodeType);
|
||||
Assert.Equal(1234, lastEvent.ExpectedCode.CodeValue);
|
||||
Assert.NotNull(lastEvent.ReceivedCode);
|
||||
Assert.Equal(LaserCodeType.PPM, lastEvent.ReceivedCode.CodeType);
|
||||
Assert.Equal(1234, lastEvent.ReceivedCode.CodeValue);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ProcessLaserIlluminationEvent_WithCodeDisabled_IgnoresCode()
|
||||
{
|
||||
// Arrange
|
||||
_guidanceSystem.SetExpectedLaserCode(LaserCodeType.PRF, 1234);
|
||||
_guidanceSystem.SetCodeMatchRequired(false); // Not required
|
||||
|
||||
var illuminationEvent = new LaserIlluminationStartEvent
|
||||
{
|
||||
LaserDesignatorId = "laser1",
|
||||
TargetId = "target1",
|
||||
IsCodeEnabled = false, // Code disabled
|
||||
LaserCode = new LaserCode
|
||||
{
|
||||
CodeType = LaserCodeType.PRF,
|
||||
CodeValue = 5678 // Different code value
|
||||
}
|
||||
};
|
||||
|
||||
// Act
|
||||
_guidanceSystem.ProcessLaserIlluminationEvent(illuminationEvent);
|
||||
|
||||
// Assert - No mismatch events should be published
|
||||
var mismatchEvents = _testAdapter.GetPublishedEvents<LaserCodeMismatchEvent>();
|
||||
Assert.Empty(mismatchEvents);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ProcessLaserIlluminationUpdateEvent_WithMatchingCode_PublishesMatchEvent()
|
||||
{
|
||||
// Arrange
|
||||
_guidanceSystem.SetExpectedLaserCode(LaserCodeType.PRF, 1234);
|
||||
_guidanceSystem.SetCodeMatchRequired(true);
|
||||
|
||||
var illuminationEvent = new LaserIlluminationUpdateEvent
|
||||
{
|
||||
LaserDesignatorId = "laser1",
|
||||
TargetId = "target1",
|
||||
IsCodeEnabled = true,
|
||||
LaserCode = new LaserCode
|
||||
{
|
||||
CodeType = LaserCodeType.PRF,
|
||||
CodeValue = 1234
|
||||
}
|
||||
};
|
||||
|
||||
// Act
|
||||
_guidanceSystem.ProcessLaserIlluminationUpdateEvent(illuminationEvent);
|
||||
|
||||
// Assert
|
||||
var matchEvents = _testAdapter.GetPublishedEvents<LaserCodeMatchEvent>();
|
||||
Assert.NotEmpty(matchEvents);
|
||||
|
||||
var lastEvent = matchEvents[matchEvents.Count - 1];
|
||||
Assert.Equal("missile1", lastEvent.MissileId);
|
||||
Assert.Equal("laser1", lastEvent.DesignatorId);
|
||||
Assert.NotNull(lastEvent.MatchedCode);
|
||||
Assert.Equal(LaserCodeType.PRF, lastEvent.MatchedCode.CodeType);
|
||||
Assert.Equal(1234, lastEvent.MatchedCode.CodeValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
150
ThreatSource.Tests/src/Indicator/LaserDesignatorCodeTests.cs
Normal file
150
ThreatSource.Tests/src/Indicator/LaserDesignatorCodeTests.cs
Normal file
@ -0,0 +1,150 @@
|
||||
using Xunit;
|
||||
using ThreatSource.Indicator;
|
||||
using ThreatSource.Simulation;
|
||||
using ThreatSource.Utils;
|
||||
using ThreatSource.Simulation.Testing;
|
||||
using ThreatSource.Target;
|
||||
|
||||
namespace ThreatSource.Tests.Indicator
|
||||
{
|
||||
public class LaserDesignatorCodeTests
|
||||
{
|
||||
private readonly SimulationManager _simulationManager;
|
||||
private readonly TestSimulationAdapter _testAdapter;
|
||||
private readonly LaserDesignator _laserDesignator;
|
||||
private readonly LaserDesignatorConfig _config;
|
||||
private readonly Tank _tank;
|
||||
|
||||
public LaserDesignatorCodeTests()
|
||||
{
|
||||
_simulationManager = new SimulationManager();
|
||||
_testAdapter = new TestSimulationAdapter(_simulationManager);
|
||||
_simulationManager.SetSimulationAdapter(_testAdapter);
|
||||
|
||||
_config = new LaserDesignatorConfig
|
||||
{
|
||||
Id = "laser1",
|
||||
InitialPosition = new Vector3D(0, 0, 0),
|
||||
LaserPower = 1000,
|
||||
LaserDivergenceAngle = 0.001
|
||||
};
|
||||
|
||||
_tank = new Tank("target1", new Vector3D(100, 0, 0), 0, _simulationManager);
|
||||
_simulationManager.RegisterEntity("target1", _tank);
|
||||
|
||||
_laserDesignator = new LaserDesignator(
|
||||
"laser1",
|
||||
"target1",
|
||||
"missile1",
|
||||
10,
|
||||
_config,
|
||||
_simulationManager
|
||||
);
|
||||
_simulationManager.RegisterEntity("laser1", _laserDesignator);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SetLaserCode_SetsCodeCorrectly()
|
||||
{
|
||||
// Arrange
|
||||
_laserDesignator.Activate();
|
||||
|
||||
// Act
|
||||
_laserDesignator.SetLaserCode(LaserCodeType.PRF, 1234);
|
||||
_laserDesignator.Update(0.1);
|
||||
|
||||
// Assert
|
||||
var events = _testAdapter.GetPublishedEvents<LaserIlluminationUpdateEvent>();
|
||||
Assert.NotEmpty(events);
|
||||
|
||||
var lastEvent = events[events.Count - 1];
|
||||
Assert.True(lastEvent.IsCodeEnabled);
|
||||
Assert.NotNull(lastEvent.LaserCode);
|
||||
Assert.Equal(LaserCodeType.PRF, lastEvent.LaserCode.CodeType);
|
||||
Assert.Equal(1234, lastEvent.LaserCode.CodeValue);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AddCodeParameter_AddsParameterCorrectly()
|
||||
{
|
||||
// Arrange
|
||||
_laserDesignator.Activate();
|
||||
_laserDesignator.SetLaserCode(LaserCodeType.PPM, 5678);
|
||||
|
||||
// Act
|
||||
_laserDesignator.AddCodeParameter("PulseWidth", 0.001);
|
||||
_laserDesignator.Update(0.1);
|
||||
|
||||
// Assert
|
||||
var events = _testAdapter.GetPublishedEvents<LaserIlluminationUpdateEvent>();
|
||||
Assert.NotEmpty(events);
|
||||
|
||||
var lastEvent = events[events.Count - 1];
|
||||
Assert.True(lastEvent.IsCodeEnabled);
|
||||
Assert.NotNull(lastEvent.LaserCode);
|
||||
Assert.Equal(LaserCodeType.PPM, lastEvent.LaserCode.CodeType);
|
||||
Assert.Equal(5678, lastEvent.LaserCode.CodeValue);
|
||||
Assert.True(lastEvent.LaserCode.Parameters.ContainsKey("PulseWidth"));
|
||||
Assert.Equal(0.001, lastEvent.LaserCode.Parameters["PulseWidth"]);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void EnableCode_EnablesAndDisablesCodeCorrectly()
|
||||
{
|
||||
// Arrange
|
||||
_laserDesignator.Activate();
|
||||
_laserDesignator.SetLaserCode(LaserCodeType.PRF, 1234);
|
||||
|
||||
// Act - Disable code
|
||||
_laserDesignator.EnableCode(false);
|
||||
_laserDesignator.Update(0.1);
|
||||
|
||||
// Assert - Code should be disabled
|
||||
var eventsAfterDisable = _testAdapter.GetPublishedEvents<LaserIlluminationUpdateEvent>();
|
||||
Assert.NotEmpty(eventsAfterDisable);
|
||||
var lastEventAfterDisable = eventsAfterDisable[eventsAfterDisable.Count - 1];
|
||||
Assert.False(lastEventAfterDisable.IsCodeEnabled);
|
||||
|
||||
// Act - Enable code again
|
||||
_laserDesignator.EnableCode(true);
|
||||
_laserDesignator.Update(0.1);
|
||||
|
||||
// Assert - Code should be enabled
|
||||
var eventsAfterEnable = _testAdapter.GetPublishedEvents<LaserIlluminationUpdateEvent>();
|
||||
Assert.NotEmpty(eventsAfterEnable);
|
||||
var lastEventAfterEnable = eventsAfterEnable[eventsAfterEnable.Count - 1];
|
||||
Assert.True(lastEventAfterEnable.IsCodeEnabled);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void LaserIlluminationEvents_IncludeCodeInformation()
|
||||
{
|
||||
// Arrange
|
||||
_laserDesignator.SetLaserCode(LaserCodeType.PRF, 1234);
|
||||
|
||||
// Act - Start illumination
|
||||
_laserDesignator.Activate();
|
||||
|
||||
// Assert - Start event should include code
|
||||
var startEvents = _testAdapter.GetPublishedEvents<LaserIlluminationStartEvent>();
|
||||
Assert.NotEmpty(startEvents);
|
||||
var startEvent = startEvents[startEvents.Count - 1];
|
||||
Assert.True(startEvent.IsCodeEnabled);
|
||||
Assert.NotNull(startEvent.LaserCode);
|
||||
Assert.Equal(LaserCodeType.PRF, startEvent.LaserCode.CodeType);
|
||||
Assert.Equal(1234, startEvent.LaserCode.CodeValue);
|
||||
|
||||
// Act - Update illumination
|
||||
_laserDesignator.Update(0.1);
|
||||
|
||||
// Assert - Update event should include code
|
||||
var updateEvents = _testAdapter.GetPublishedEvents<LaserIlluminationUpdateEvent>();
|
||||
Assert.NotEmpty(updateEvents);
|
||||
var updateEvent = updateEvents[updateEvents.Count - 1];
|
||||
Assert.True(updateEvent.IsCodeEnabled);
|
||||
Assert.NotNull(updateEvent.LaserCode);
|
||||
Assert.Equal(LaserCodeType.PRF, updateEvent.LaserCode.CodeType);
|
||||
Assert.Equal(1234, updateEvent.LaserCode.CodeValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,283 @@
|
||||
using Xunit;
|
||||
using ThreatSource.Missile;
|
||||
using ThreatSource.Simulation;
|
||||
using ThreatSource.Utils;
|
||||
using ThreatSource.Simulation.Testing;
|
||||
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
|
||||
{
|
||||
Id = "missile1",
|
||||
InitialPosition = new Vector3D(0, 0, 0),
|
||||
InitialOrientation = new Orientation(0, 0, 0),
|
||||
InitialSpeed = 100,
|
||||
MaxSpeed = 1000,
|
||||
MaxFlightTime = 100,
|
||||
MaxFlightDistance = 10000,
|
||||
MaxAcceleration = 50,
|
||||
ProportionalNavigationCoefficient = 3,
|
||||
Mass = 100,
|
||||
ExplosionRadius = 10,
|
||||
HitProbability = 0.9,
|
||||
Type = MissileType.LaserSemiActiveGuidance
|
||||
};
|
||||
|
||||
// 创建并注册模拟的激光指示器
|
||||
_laserDesignator = new MockLaserDesignator("laser1", _simulationManager);
|
||||
_testAdapter.AddTestEntity("laser1", _laserDesignator);
|
||||
|
||||
// 创建并注册模拟的目标
|
||||
_target = new MockTarget("target1", _simulationManager);
|
||||
_testAdapter.AddTestEntity("target1", _target);
|
||||
|
||||
// 创建导弹并注册到仿真管理器
|
||||
_missile = new LaserSemiActiveGuidedMissile(_properties, _simulationManager);
|
||||
_simulationManager.RegisterEntity("missile1", _missile);
|
||||
}
|
||||
|
||||
// 模拟的激光指示器类
|
||||
private class MockLaserDesignator : LaserDesignator
|
||||
{
|
||||
public MockLaserDesignator(string id, ISimulationManager simulationManager)
|
||||
: base(id, "target1", "missile1", 0, new LaserDesignatorConfig
|
||||
{
|
||||
Id = id,
|
||||
InitialPosition = new Vector3D(100, 0, 0),
|
||||
LaserPower = 100,
|
||||
LaserDivergenceAngle = 0.001
|
||||
}, simulationManager)
|
||||
{
|
||||
// 不需要额外设置属性,因为基类构造函数已经设置了
|
||||
}
|
||||
}
|
||||
|
||||
// 模拟的目标类
|
||||
private class MockTarget : Tank
|
||||
{
|
||||
public MockTarget(string id, ISimulationManager simulationManager)
|
||||
: base(id, new Vector3D(1000, 0, 0), 10, simulationManager)
|
||||
{
|
||||
// 不需要额外设置属性,因为基类构造函数已经设置了
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SetLaserCode_SetsCodeCorrectly()
|
||||
{
|
||||
// Arrange
|
||||
_missile.Fire();
|
||||
_missile.Activate();
|
||||
|
||||
// Act
|
||||
_missile.SetLaserCode(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();
|
||||
_missile.SetLaserCode(LaserCodeType.PPM, 5678);
|
||||
|
||||
// Act
|
||||
_missile.AddLaserCodeParameter("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();
|
||||
|
||||
// Act
|
||||
_missile.SetCodeMatchRequired(true);
|
||||
|
||||
// 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();
|
||||
_missile.SetLaserCode(LaserCodeType.PRF, 1234);
|
||||
_missile.SetCodeMatchRequired(true);
|
||||
_missile.Update(0.1); // Move past launch stage
|
||||
|
||||
// Act - Send matching code illumination
|
||||
var illuminationEvent = new LaserIlluminationStartEvent
|
||||
{
|
||||
LaserDesignatorId = "laser1",
|
||||
TargetId = "target1",
|
||||
IsCodeEnabled = true,
|
||||
LaserCode = new LaserCode
|
||||
{
|
||||
CodeType = LaserCodeType.PRF,
|
||||
CodeValue = 1234
|
||||
}
|
||||
};
|
||||
_simulationManager.PublishEvent(illuminationEvent);
|
||||
_missile.Update(0.1);
|
||||
|
||||
// Assert
|
||||
var matchEvents = _testAdapter.GetPublishedEvents<LaserCodeMatchEvent>();
|
||||
Assert.NotEmpty(matchEvents);
|
||||
|
||||
// Guidance should be enabled with matching code
|
||||
Assert.True(_missile.IsGuidance);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void LaserIllumination_WithMismatchingCode_DisablesGuidance()
|
||||
{
|
||||
// Arrange
|
||||
_missile.Fire();
|
||||
_missile.Activate();
|
||||
_missile.SetLaserCode(LaserCodeType.PRF, 1234);
|
||||
_missile.SetCodeMatchRequired(true);
|
||||
_missile.Update(0.1); // Move past launch stage
|
||||
|
||||
// Act - Send mismatching code illumination
|
||||
var illuminationEvent = new LaserIlluminationStartEvent
|
||||
{
|
||||
LaserDesignatorId = "laser1",
|
||||
TargetId = "target1",
|
||||
IsCodeEnabled = true,
|
||||
LaserCode = new LaserCode
|
||||
{
|
||||
CodeType = LaserCodeType.PRF,
|
||||
CodeValue = 5678 // Different code
|
||||
}
|
||||
};
|
||||
_simulationManager.PublishEvent(illuminationEvent);
|
||||
_missile.Update(0.1);
|
||||
|
||||
// Assert
|
||||
var mismatchEvents = _testAdapter.GetPublishedEvents<LaserCodeMismatchEvent>();
|
||||
Assert.NotEmpty(mismatchEvents);
|
||||
|
||||
// Guidance should be disabled with mismatching code
|
||||
Assert.False(_missile.IsGuidance);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void LaserIllumination_WithCodeDisabled_EnablesGuidanceIfNotRequired()
|
||||
{
|
||||
// Arrange
|
||||
_missile.Fire();
|
||||
_missile.Activate();
|
||||
_missile.SetLaserCode(LaserCodeType.PRF, 1234);
|
||||
_missile.SetCodeMatchRequired(false); // Not required
|
||||
_missile.Update(0.1); // Move past launch stage
|
||||
|
||||
// Act - Send illumination with code disabled
|
||||
var illuminationEvent = new LaserIlluminationStartEvent
|
||||
{
|
||||
LaserDesignatorId = "laser1",
|
||||
TargetId = "target1",
|
||||
IsCodeEnabled = false,
|
||||
LaserCode = null
|
||||
};
|
||||
_simulationManager.PublishEvent(illuminationEvent);
|
||||
_missile.Update(0.1);
|
||||
|
||||
// Assert
|
||||
// Guidance should be enabled even without code when not required
|
||||
Assert.True(_missile.IsGuidance);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void LaserIllumination_WithCodeDisabled_DisablesGuidanceIfRequired()
|
||||
{
|
||||
// Arrange
|
||||
_missile.Fire();
|
||||
_missile.Activate();
|
||||
_missile.SetLaserCode(LaserCodeType.PRF, 1234);
|
||||
_missile.SetCodeMatchRequired(true); // Required
|
||||
_missile.Update(0.1); // Move past launch stage
|
||||
|
||||
// Act - Send illumination with code disabled
|
||||
var illuminationEvent = new LaserIlluminationStartEvent
|
||||
{
|
||||
LaserDesignatorId = "laser1",
|
||||
TargetId = "target1",
|
||||
IsCodeEnabled = false,
|
||||
LaserCode = null
|
||||
};
|
||||
_simulationManager.PublishEvent(illuminationEvent);
|
||||
_missile.Update(0.1);
|
||||
|
||||
// Assert
|
||||
// Guidance should be disabled without code when required
|
||||
Assert.False(_missile.IsGuidance);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void LaserIlluminationStop_DisablesGuidance()
|
||||
{
|
||||
// Arrange - First enable guidance with matching code
|
||||
_missile.Fire();
|
||||
_missile.Activate();
|
||||
_missile.SetLaserCode(LaserCodeType.PRF, 1234);
|
||||
_missile.Update(0.1); // Move past launch stage
|
||||
|
||||
var illuminationEvent = new LaserIlluminationStartEvent
|
||||
{
|
||||
LaserDesignatorId = "laser1",
|
||||
TargetId = "target1",
|
||||
IsCodeEnabled = true,
|
||||
LaserCode = new LaserCode
|
||||
{
|
||||
CodeType = LaserCodeType.PRF,
|
||||
CodeValue = 1234
|
||||
}
|
||||
};
|
||||
_simulationManager.PublishEvent(illuminationEvent);
|
||||
_missile.Update(0.1);
|
||||
|
||||
// Verify guidance is enabled
|
||||
Assert.True(_missile.IsGuidance);
|
||||
|
||||
// Act - Stop illumination
|
||||
var stopEvent = new LaserIlluminationStopEvent
|
||||
{
|
||||
LaserDesignatorId = "laser1",
|
||||
TargetId = "target1"
|
||||
};
|
||||
_simulationManager.PublishEvent(stopEvent);
|
||||
_missile.Update(0.1);
|
||||
|
||||
// Assert
|
||||
Assert.False(_missile.IsGuidance);
|
||||
}
|
||||
}
|
||||
}
|
||||
155
ThreatSource.Tests/src/Utils/LaserCodeTests.cs
Normal file
155
ThreatSource.Tests/src/Utils/LaserCodeTests.cs
Normal file
@ -0,0 +1,155 @@
|
||||
using Xunit;
|
||||
using ThreatSource.Utils;
|
||||
|
||||
namespace ThreatSource.Tests.Utils
|
||||
{
|
||||
public class LaserCodeTests
|
||||
{
|
||||
[Fact]
|
||||
public void Constructor_InitializesPropertiesCorrectly()
|
||||
{
|
||||
// Arrange & Act
|
||||
var laserCode = new LaserCode
|
||||
{
|
||||
CodeType = LaserCodeType.PRF,
|
||||
CodeValue = 1234
|
||||
};
|
||||
|
||||
// Assert
|
||||
Assert.Equal(LaserCodeType.PRF, laserCode.CodeType);
|
||||
Assert.Equal(1234, laserCode.CodeValue);
|
||||
Assert.Empty(laserCode.Parameters);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Parameters_CanAddAndRetrieveValues()
|
||||
{
|
||||
// Arrange
|
||||
var laserCode = new LaserCode
|
||||
{
|
||||
CodeType = LaserCodeType.PPM,
|
||||
CodeValue = 5678
|
||||
};
|
||||
|
||||
// Act
|
||||
laserCode.Parameters["PulseWidth"] = 0.001;
|
||||
laserCode.Parameters["PulseCount"] = 10;
|
||||
|
||||
// Assert
|
||||
Assert.Equal(0.001, laserCode.Parameters["PulseWidth"]);
|
||||
Assert.Equal(10, laserCode.Parameters["PulseCount"]);
|
||||
Assert.Equal(2, laserCode.Parameters.Count);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Matches_ReturnsTrueForMatchingCodes()
|
||||
{
|
||||
// Arrange
|
||||
var code1 = new LaserCode
|
||||
{
|
||||
CodeType = LaserCodeType.PRF,
|
||||
CodeValue = 1234
|
||||
};
|
||||
|
||||
var code2 = new LaserCode
|
||||
{
|
||||
CodeType = LaserCodeType.PRF,
|
||||
CodeValue = 1234
|
||||
};
|
||||
|
||||
// Act
|
||||
bool result = code1.Matches(code2);
|
||||
|
||||
// Assert
|
||||
Assert.True(result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Matches_ReturnsFalseForDifferentCodeTypes()
|
||||
{
|
||||
// Arrange
|
||||
var code1 = new LaserCode
|
||||
{
|
||||
CodeType = LaserCodeType.PRF,
|
||||
CodeValue = 1234
|
||||
};
|
||||
|
||||
var code2 = new LaserCode
|
||||
{
|
||||
CodeType = LaserCodeType.PPM,
|
||||
CodeValue = 1234
|
||||
};
|
||||
|
||||
// Act
|
||||
bool result = code1.Matches(code2);
|
||||
|
||||
// Assert
|
||||
Assert.False(result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Matches_ReturnsFalseForDifferentCodeValues()
|
||||
{
|
||||
// Arrange
|
||||
var code1 = new LaserCode
|
||||
{
|
||||
CodeType = LaserCodeType.PRF,
|
||||
CodeValue = 1234
|
||||
};
|
||||
|
||||
var code2 = new LaserCode
|
||||
{
|
||||
CodeType = LaserCodeType.PRF,
|
||||
CodeValue = 5678
|
||||
};
|
||||
|
||||
// Act
|
||||
bool result = code1.Matches(code2);
|
||||
|
||||
// Assert
|
||||
Assert.False(result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Matches_ReturnsFalseForNullCode()
|
||||
{
|
||||
// Arrange
|
||||
var code = new LaserCode
|
||||
{
|
||||
CodeType = LaserCodeType.PRF,
|
||||
CodeValue = 1234
|
||||
};
|
||||
|
||||
// Act
|
||||
bool result = code.Matches(null);
|
||||
|
||||
// Assert
|
||||
Assert.False(result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Matches_IgnoresParameters()
|
||||
{
|
||||
// Arrange
|
||||
var code1 = new LaserCode
|
||||
{
|
||||
CodeType = LaserCodeType.PRF,
|
||||
CodeValue = 1234
|
||||
};
|
||||
code1.Parameters["PulseWidth"] = 0.001;
|
||||
|
||||
var code2 = new LaserCode
|
||||
{
|
||||
CodeType = LaserCodeType.PRF,
|
||||
CodeValue = 1234
|
||||
};
|
||||
code2.Parameters["PulseWidth"] = 0.002; // Different parameter value
|
||||
|
||||
// Act
|
||||
bool result = code1.Matches(code2);
|
||||
|
||||
// Assert
|
||||
Assert.True(result); // Should still match because parameters are ignored
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using ThreatSource.Utils;
|
||||
using ThreatSource.Simulation;
|
||||
|
||||
namespace ThreatSource.Guidance
|
||||
{
|
||||
@ -12,10 +13,20 @@ namespace ThreatSource.Guidance
|
||||
/// - 运动参数记录
|
||||
/// - 加速度限制
|
||||
/// - 比例导引系数
|
||||
/// - 事件发布
|
||||
/// 是其他具体制导系统的基类
|
||||
/// </remarks>
|
||||
public class BasicGuidanceSystem : IGuidanceSystem
|
||||
public class BasicGuidanceSystem : SimulationElement, IGuidanceSystem
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取或设置父实体ID
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 记录所属导弹的ID
|
||||
/// 用于事件发布和状态关联
|
||||
/// </remarks>
|
||||
public string? ParentId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取或设置是否有有效的制导信息
|
||||
/// </summary>
|
||||
@ -46,24 +57,6 @@ namespace ThreatSource.Guidance
|
||||
/// </remarks>
|
||||
public double ProportionalNavigationCoefficient { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取或设置导弹位置,单位:米
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 记录导弹的当前位置
|
||||
/// 用于制导计算和状态更新
|
||||
/// </remarks>
|
||||
protected Vector3D Position { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取或设置导弹速度,单位:米/秒
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 记录导弹的当前速度
|
||||
/// 用于制导计算和状态更新
|
||||
/// </remarks>
|
||||
protected Vector3D Velocity { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取或设置制导加速度,单位:米/平方秒
|
||||
/// </summary>
|
||||
@ -76,20 +69,22 @@ namespace ThreatSource.Guidance
|
||||
/// <summary>
|
||||
/// 初始化基础制导系统的新实例
|
||||
/// </summary>
|
||||
/// <param name="id">制导系统ID</param>
|
||||
/// <param name="maxAcceleration">最大加速度,单位:米/平方秒</param>
|
||||
/// <param name="proportionalNavigationCoefficient">比例导引系数</param>
|
||||
/// <param name="simulationManager">仿真管理器实例</param>
|
||||
/// <remarks>
|
||||
/// 构造过程:
|
||||
/// - 初始化基类参数
|
||||
/// - 初始化制导状态
|
||||
/// - 设置运动参数
|
||||
/// - 配置制导参数
|
||||
/// </remarks>
|
||||
public BasicGuidanceSystem(double maxAcceleration, double proportionalNavigationCoefficient)
|
||||
public BasicGuidanceSystem(string id, double maxAcceleration, double proportionalNavigationCoefficient, ISimulationManager simulationManager)
|
||||
: base(id, Vector3D.Zero, new Orientation(), 0, simulationManager)
|
||||
{
|
||||
HasGuidance = false;
|
||||
GuidanceAcceleration = Vector3D.Zero;
|
||||
Position = Vector3D.Zero;
|
||||
Velocity = Vector3D.Zero;
|
||||
MaxAcceleration = maxAcceleration;
|
||||
ProportionalNavigationCoefficient = proportionalNavigationCoefficient;
|
||||
}
|
||||
@ -112,6 +107,21 @@ namespace ThreatSource.Guidance
|
||||
Velocity = missileVelocity;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更新制导系统状态
|
||||
/// </summary>
|
||||
/// <param name="deltaTime">时间步长,单位:秒</param>
|
||||
/// <remarks>
|
||||
/// 实现 SimulationElement 的抽象方法
|
||||
/// 在此方法中不执行实际操作,制导系统通过 Update(deltaTime, position, velocity) 更新
|
||||
/// </remarks>
|
||||
public override void Update(double deltaTime)
|
||||
{
|
||||
// 警告:制导系统不应直接由仿真系统调用
|
||||
Console.WriteLine("警告:制导系统的Update(deltaTime)方法被直接调用,这可能是一个错误。");
|
||||
// 制导系统应通过Update(deltaTime, position, velocity)方法更新
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取制导加速度指令
|
||||
/// </summary>
|
||||
@ -157,9 +167,9 @@ namespace ThreatSource.Guidance
|
||||
/// - 加速度信息
|
||||
/// 用于状态监控和调试
|
||||
/// </remarks>
|
||||
public virtual string GetStatus()
|
||||
public override string GetStatus()
|
||||
{
|
||||
return $" 导引头状态: 有制导={HasGuidance}, 位置={Position}, 速度={Velocity}, 制导加速度={GuidanceAcceleration}";
|
||||
return base.GetStatus() + $"\n 导引头状态: 有制导={HasGuidance}, 制导加速度={GuidanceAcceleration}";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
using ThreatSource.Utils;
|
||||
using ThreatSource.Simulation;
|
||||
|
||||
namespace ThreatSource.Guidance
|
||||
{
|
||||
@ -74,16 +75,18 @@ namespace ThreatSource.Guidance
|
||||
/// <summary>
|
||||
/// 初始化红外指令导引系统的新实例
|
||||
/// </summary>
|
||||
/// <param name="id">系统标识</param>
|
||||
/// <param name="maxAcceleration">最大加速度,单位:米/平方秒</param>
|
||||
/// <param name="guidanceCoefficient">制导系数</param>
|
||||
/// <param name="simulationManager">模拟管理器</param>
|
||||
/// <remarks>
|
||||
/// 构造过程:
|
||||
/// - 初始化基类参数
|
||||
/// - 初始化向量记录
|
||||
/// - 清零转向速率
|
||||
/// </remarks>
|
||||
public InfraredCommandGuidanceSystem(double maxAcceleration, double guidanceCoefficient)
|
||||
: base(maxAcceleration, guidanceCoefficient)
|
||||
public InfraredCommandGuidanceSystem(string id, double maxAcceleration, double guidanceCoefficient, ISimulationManager simulationManager)
|
||||
: base(id, maxAcceleration, guidanceCoefficient, simulationManager)
|
||||
{
|
||||
lastTrackerToMissileVector = Vector3D.Zero;
|
||||
lastTrackerToTargetVector = Vector3D.Zero;
|
||||
|
||||
@ -76,15 +76,6 @@ namespace ThreatSource.Guidance
|
||||
/// </remarks>
|
||||
private readonly Random random = new();
|
||||
|
||||
/// <summary>
|
||||
/// 获取或设置仿真管理器实例
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 用于获取场景中的目标信息
|
||||
/// 实现目标探测功能
|
||||
/// </remarks>
|
||||
public ISimulationManager SimulationManager { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 上一次探测到的目标位置
|
||||
/// </summary>
|
||||
@ -95,8 +86,9 @@ namespace ThreatSource.Guidance
|
||||
private Vector3D lastTargetPosition;
|
||||
|
||||
/// <summary>
|
||||
/// 初始化红外成像引导系统的新实例
|
||||
/// 初始化红外成像制导系统的新实例
|
||||
/// </summary>
|
||||
/// <param name="id">系统标识</param>
|
||||
/// <param name="maxAcceleration">最大加速度,单位:米/平方秒</param>
|
||||
/// <param name="proportionalNavigationCoefficient">比例导引系数</param>
|
||||
/// <param name="simulationManager">仿真管理器实例</param>
|
||||
@ -106,9 +98,9 @@ namespace ThreatSource.Guidance
|
||||
/// - 设置仿真管理器
|
||||
/// - 初始化目标位置
|
||||
/// </remarks>
|
||||
public InfraredImagingGuidanceSystem(double maxAcceleration, double proportionalNavigationCoefficient, ISimulationManager simulationManager) : base(maxAcceleration, proportionalNavigationCoefficient)
|
||||
public InfraredImagingGuidanceSystem(string id, double maxAcceleration, double proportionalNavigationCoefficient, ISimulationManager simulationManager)
|
||||
: base(id, maxAcceleration, proportionalNavigationCoefficient, simulationManager)
|
||||
{
|
||||
SimulationManager = simulationManager;
|
||||
lastTargetPosition = Vector3D.Zero;
|
||||
}
|
||||
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
using ThreatSource.Utils;
|
||||
using ThreatSource.Simulation;
|
||||
|
||||
namespace ThreatSource.Guidance
|
||||
{
|
||||
@ -111,15 +112,18 @@ namespace ThreatSource.Guidance
|
||||
/// <summary>
|
||||
/// 初始化激光驾束制导系统的新实例
|
||||
/// </summary>
|
||||
/// <param name="id">制导系统ID</param>
|
||||
/// <param name="maxAcceleration">最大加速度,单位:米/平方秒</param>
|
||||
/// <param name="guidanceCoefficient">制导系数</param>
|
||||
/// <param name="simulationManager">仿真管理器实例</param>
|
||||
/// <remarks>
|
||||
/// 构造过程:
|
||||
/// - 初始化基类参数
|
||||
/// - 初始化激光参数
|
||||
/// - 初始化控制参数
|
||||
/// </remarks>
|
||||
public LaserBeamRiderGuidanceSystem(double maxAcceleration, double guidanceCoefficient) : base(maxAcceleration, guidanceCoefficient)
|
||||
public LaserBeamRiderGuidanceSystem(string id, double maxAcceleration, double guidanceCoefficient, ISimulationManager simulationManager)
|
||||
: base(id, maxAcceleration, guidanceCoefficient, simulationManager)
|
||||
{
|
||||
LaserSourcePosition = Vector3D.Zero;
|
||||
LaserDirection = Vector3D.Zero;
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
using ThreatSource.Utils;
|
||||
using ThreatSource.Simulation;
|
||||
|
||||
namespace ThreatSource.Guidance
|
||||
{
|
||||
@ -129,18 +130,54 @@ namespace ThreatSource.Guidance
|
||||
/// </remarks>
|
||||
private double LaserDivergenceAngle { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取或设置期望的激光编码
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 导弹期望接收的编码信息
|
||||
/// 用于验证接收到的激光信号
|
||||
/// </remarks>
|
||||
private LaserCode? expectedLaserCode = null;
|
||||
|
||||
/// <summary>
|
||||
/// 获取或设置是否要求编码匹配
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// true表示只响应匹配编码的激光信号
|
||||
/// false表示响应所有激光信号
|
||||
/// 默认为false
|
||||
/// </remarks>
|
||||
private bool isCodeMatchRequired = false;
|
||||
|
||||
/// <summary>
|
||||
/// 获取或设置支持的编码类型列表
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 定义导弹支持的编码类型
|
||||
/// 默认支持PRF、PPM和PWM编码
|
||||
/// </remarks>
|
||||
private List<LaserCodeType> supportedCodeTypes = new List<LaserCodeType>
|
||||
{
|
||||
LaserCodeType.PRF,
|
||||
LaserCodeType.PPM,
|
||||
LaserCodeType.PWM
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// 初始化激光半主动制导系统的新实例
|
||||
/// </summary>
|
||||
/// <param name="id">制导系统ID</param>
|
||||
/// <param name="maxAcceleration">最大加速度,单位:米/平方秒</param>
|
||||
/// <param name="guidanceCoefficient">制导系数</param>
|
||||
/// <param name="simulationManager">仿真管理器实例</param>
|
||||
/// <remarks>
|
||||
/// 构造过程:
|
||||
/// - 初始化基类参数
|
||||
/// - 初始化目标信息
|
||||
/// - 初始化激光参数
|
||||
/// </remarks>
|
||||
public LaserSemiActiveGuidanceSystem(double maxAcceleration, double guidanceCoefficient) : base(maxAcceleration, guidanceCoefficient)
|
||||
public LaserSemiActiveGuidanceSystem(string id, double maxAcceleration, double guidanceCoefficient, ISimulationManager simulationManager)
|
||||
: base(id, maxAcceleration, guidanceCoefficient, simulationManager)
|
||||
{
|
||||
TargetPosition = Vector3D.Zero;
|
||||
TargetVelocity = Vector3D.Zero;
|
||||
@ -212,7 +249,12 @@ namespace ThreatSource.Guidance
|
||||
base.Update(deltaTime, missilePosition, missileVelocity);
|
||||
if (LaserIlluminationOn)
|
||||
{
|
||||
HasGuidance = CalculateReceivedLaserPower() > LockThreshold;
|
||||
// 只有当HasGuidance为false时才根据接收功率计算,避免覆盖ProcessLaserIlluminationEvent中设置的值
|
||||
if (!HasGuidance)
|
||||
{
|
||||
HasGuidance = CalculateReceivedLaserPower() > LockThreshold;
|
||||
}
|
||||
|
||||
if (HasGuidance)
|
||||
{
|
||||
CalculateGuidanceAcceleration(deltaTime);
|
||||
@ -224,6 +266,7 @@ namespace ThreatSource.Guidance
|
||||
}
|
||||
else
|
||||
{
|
||||
HasGuidance = false; // 如果没有激光照射,则禁用制导
|
||||
GuidanceAcceleration = Vector3D.Zero;
|
||||
}
|
||||
}
|
||||
@ -314,5 +357,257 @@ namespace ThreatSource.Guidance
|
||||
{
|
||||
return base.GetStatus() + $" 接收到的激光功率: {CalculateReceivedLaserPower():E} W 锁定阈值: {LockThreshold:E} W";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置期望的激光编码
|
||||
/// </summary>
|
||||
/// <param name="codeType">编码类型</param>
|
||||
/// <param name="codeValue">编码值</param>
|
||||
/// <remarks>
|
||||
/// 设置过程:
|
||||
/// - 检查编码类型是否支持
|
||||
/// - 创建新的编码对象
|
||||
/// - 设置编码类型和值
|
||||
/// </remarks>
|
||||
public void SetExpectedLaserCode(LaserCodeType codeType, int codeValue)
|
||||
{
|
||||
if (supportedCodeTypes.Contains(codeType))
|
||||
{
|
||||
expectedLaserCode = new LaserCode
|
||||
{
|
||||
CodeType = codeType,
|
||||
CodeValue = codeValue
|
||||
};
|
||||
Console.WriteLine($"激光半主动制导系统设置期望编码:类型={codeType},值={codeValue}");
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine($"激光半主动制导系统不支持编码类型:{codeType}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 添加期望编码参数
|
||||
/// </summary>
|
||||
/// <param name="key">参数名称</param>
|
||||
/// <param name="value">参数值</param>
|
||||
/// <remarks>
|
||||
/// 添加特定编码类型的额外参数
|
||||
/// 如PPM编码的脉冲位置模式、PWM编码的脉冲宽度等
|
||||
/// </remarks>
|
||||
public void AddExpectedCodeParameter(string key, object value)
|
||||
{
|
||||
if (expectedLaserCode != null)
|
||||
{
|
||||
expectedLaserCode.Parameters[key] = value;
|
||||
Console.WriteLine($"激光半主动制导系统添加期望编码参数:{key}={value}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置是否要求编码匹配
|
||||
/// </summary>
|
||||
/// <param name="required">是否要求匹配</param>
|
||||
/// <remarks>
|
||||
/// true表示只响应匹配编码的激光信号
|
||||
/// false表示响应所有激光信号
|
||||
/// </remarks>
|
||||
public void SetCodeMatchRequired(bool required)
|
||||
{
|
||||
isCodeMatchRequired = required;
|
||||
Console.WriteLine($"激光半主动制导系统{(required ? "要求" : "不要求")}编码匹配");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 处理激光照射事件
|
||||
/// </summary>
|
||||
/// <param name="illuminationEvent">激光照射事件</param>
|
||||
/// <remarks>
|
||||
/// 处理过程:
|
||||
/// - 检查编码是否匹配
|
||||
/// - 如果要求匹配且不匹配,则忽略信号
|
||||
/// - 如果匹配或不要求匹配,则处理信号
|
||||
/// - 更新激光照射状态
|
||||
/// </remarks>
|
||||
public void ProcessLaserIlluminationEvent(LaserIlluminationStartEvent illuminationEvent)
|
||||
{
|
||||
// 检查编码是否匹配
|
||||
bool codeMatched = CheckCodeMatch(illuminationEvent.LaserCode, illuminationEvent.IsCodeEnabled);
|
||||
|
||||
if (isCodeMatchRequired && !codeMatched)
|
||||
{
|
||||
// 发布编码不匹配事件
|
||||
PublishCodeMismatchEvent(illuminationEvent.LaserDesignatorId, illuminationEvent.LaserCode);
|
||||
Console.WriteLine("激光半主动制导系统接收到不匹配的激光编码,忽略信号");
|
||||
HasGuidance = false; // 禁用制导
|
||||
return; // 不处理不匹配的信号
|
||||
}
|
||||
|
||||
// 如果编码匹配或不要求匹配,继续处理
|
||||
if (codeMatched)
|
||||
{
|
||||
// 发布编码匹配事件
|
||||
PublishCodeMatchEvent(illuminationEvent.LaserDesignatorId, illuminationEvent.LaserCode);
|
||||
Console.WriteLine("激光半主动制导系统接收到匹配的激光编码,处理信号");
|
||||
HasGuidance = true; // 启用制导
|
||||
}
|
||||
else if (!isCodeMatchRequired)
|
||||
{
|
||||
// 不要求编码匹配,但也没有编码
|
||||
HasGuidance = true; // 启用制导
|
||||
}
|
||||
|
||||
// 更新激光照射状态
|
||||
LaserIlluminationOn = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 处理激光照射更新事件
|
||||
/// </summary>
|
||||
/// <param name="illuminationEvent">激光照射更新事件</param>
|
||||
/// <remarks>
|
||||
/// 处理过程:
|
||||
/// - 检查编码是否匹配
|
||||
/// - 如果要求匹配且不匹配,则忽略信号
|
||||
/// - 如果匹配或不要求匹配,则处理信号
|
||||
/// - 更新激光照射状态
|
||||
/// </remarks>
|
||||
public void ProcessLaserIlluminationUpdateEvent(LaserIlluminationUpdateEvent illuminationEvent)
|
||||
{
|
||||
// 检查编码是否匹配
|
||||
bool codeMatched = CheckCodeMatch(illuminationEvent.LaserCode, illuminationEvent.IsCodeEnabled);
|
||||
|
||||
if (isCodeMatchRequired && !codeMatched)
|
||||
{
|
||||
// 发布编码不匹配事件
|
||||
PublishCodeMismatchEvent(illuminationEvent.LaserDesignatorId, illuminationEvent.LaserCode);
|
||||
Console.WriteLine("激光半主动制导系统接收到不匹配的激光编码,忽略信号");
|
||||
HasGuidance = false; // 禁用制导
|
||||
return; // 不处理不匹配的信号
|
||||
}
|
||||
|
||||
// 如果编码匹配或不要求匹配,继续处理
|
||||
if (codeMatched && !LaserIlluminationOn)
|
||||
{
|
||||
// 发布编码匹配事件
|
||||
PublishCodeMatchEvent(illuminationEvent.LaserDesignatorId, illuminationEvent.LaserCode);
|
||||
Console.WriteLine("激光半主动制导系统接收到匹配的激光编码,处理信号");
|
||||
HasGuidance = true; // 启用制导
|
||||
}
|
||||
else if (!isCodeMatchRequired)
|
||||
{
|
||||
// 不要求编码匹配,但也没有编码
|
||||
HasGuidance = true; // 启用制导
|
||||
}
|
||||
|
||||
// 更新激光照射状态
|
||||
LaserIlluminationOn = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 处理激光照射停止事件
|
||||
/// </summary>
|
||||
/// <param name="illuminationEvent">激光照射停止事件</param>
|
||||
/// <remarks>
|
||||
/// 处理过程:
|
||||
/// - 停止激光照射状态
|
||||
/// - 清理相关参数
|
||||
/// </remarks>
|
||||
public void ProcessLaserIlluminationStopEvent(LaserIlluminationStopEvent illuminationEvent)
|
||||
{
|
||||
LaserIlluminationOn = false;
|
||||
HasGuidance = false; // 禁用制导
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 检查编码是否匹配
|
||||
/// </summary>
|
||||
/// <param name="receivedCode">接收到的编码</param>
|
||||
/// <param name="isCodeEnabled">是否启用编码</param>
|
||||
/// <returns>如果匹配返回true,否则返回false</returns>
|
||||
/// <remarks>
|
||||
/// 匹配规则:
|
||||
/// - 如果不要求匹配,返回true
|
||||
/// - 如果接收到的信号未启用编码,根据配置决定是否匹配
|
||||
/// - 如果导弹未设置期望编码,根据配置决定是否匹配
|
||||
/// - 检查编码类型是否支持
|
||||
/// - 检查编码是否匹配
|
||||
/// </remarks>
|
||||
private bool CheckCodeMatch(LaserCode? receivedCode, bool isCodeEnabled)
|
||||
{
|
||||
// 如果不要求匹配,直接返回true
|
||||
if (!isCodeMatchRequired)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// 如果接收到的信号未启用编码
|
||||
if (!isCodeEnabled || receivedCode == null)
|
||||
{
|
||||
return !isCodeMatchRequired;
|
||||
}
|
||||
|
||||
// 如果导弹未设置期望编码
|
||||
if (expectedLaserCode == null)
|
||||
{
|
||||
return !isCodeMatchRequired;
|
||||
}
|
||||
|
||||
// 检查编码类型是否支持
|
||||
if (!supportedCodeTypes.Contains(receivedCode.CodeType))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// 检查编码是否匹配
|
||||
return expectedLaserCode.Matches(receivedCode);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 发布编码匹配事件
|
||||
/// </summary>
|
||||
/// <param name="designatorId">激光定位器ID</param>
|
||||
/// <param name="matchedCode">匹配的编码</param>
|
||||
/// <remarks>
|
||||
/// 发布过程:
|
||||
/// - 创建事件对象
|
||||
/// - 设置事件属性
|
||||
/// - 发布到事件系统
|
||||
/// </remarks>
|
||||
private void PublishCodeMatchEvent(string? designatorId, LaserCode? matchedCode)
|
||||
{
|
||||
var matchEvent = new LaserCodeMatchEvent
|
||||
{
|
||||
MissileId = ParentId,
|
||||
DesignatorId = designatorId,
|
||||
MatchedCode = matchedCode
|
||||
};
|
||||
|
||||
PublishEvent(matchEvent);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 发布编码不匹配事件
|
||||
/// </summary>
|
||||
/// <param name="designatorId">激光定位器ID</param>
|
||||
/// <param name="receivedCode">接收到的编码</param>
|
||||
/// <remarks>
|
||||
/// 发布过程:
|
||||
/// - 创建事件对象
|
||||
/// - 设置事件属性
|
||||
/// - 发布到事件系统
|
||||
/// </remarks>
|
||||
private void PublishCodeMismatchEvent(string? designatorId, LaserCode? receivedCode)
|
||||
{
|
||||
var mismatchEvent = new LaserCodeMismatchEvent
|
||||
{
|
||||
MissileId = ParentId,
|
||||
DesignatorId = designatorId,
|
||||
ExpectedCode = expectedLaserCode,
|
||||
ReceivedCode = receivedCode
|
||||
};
|
||||
|
||||
PublishEvent(mismatchEvent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -113,17 +113,9 @@ namespace ThreatSource.Guidance
|
||||
private double jammingPower = 0;
|
||||
|
||||
/// <summary>
|
||||
/// 获取或设置仿真管理器实例
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 用于获取场景中的目标信息
|
||||
/// 实现目标探测功能
|
||||
/// </remarks>
|
||||
public ISimulationManager SimulationManager { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 初始化毫米波导引头系统的新实例
|
||||
/// 初始化毫米波制导系统的新实例
|
||||
/// </summary>
|
||||
/// <param name="id">制导系统ID</param>
|
||||
/// <param name="maxAcceleration">最大加速度,单位:米/平方秒</param>
|
||||
/// <param name="guidanceCoefficient">制导系数</param>
|
||||
/// <param name="simulationManager">仿真管理器实例</param>
|
||||
@ -134,9 +126,9 @@ namespace ThreatSource.Guidance
|
||||
/// - 初始化目标位置
|
||||
/// - 注册干扰事件处理
|
||||
/// </remarks>
|
||||
public MillimeterWaveGuidanceSystem(double maxAcceleration, double guidanceCoefficient, ISimulationManager simulationManager) : base(maxAcceleration, guidanceCoefficient)
|
||||
public MillimeterWaveGuidanceSystem(string id, double maxAcceleration, double guidanceCoefficient, ISimulationManager simulationManager)
|
||||
: base(id, maxAcceleration, guidanceCoefficient, simulationManager)
|
||||
{
|
||||
SimulationManager = simulationManager;
|
||||
lastTargetPosition = Vector3D.Zero;
|
||||
|
||||
// 订阅干扰事件
|
||||
|
||||
@ -83,6 +83,25 @@ namespace ThreatSource.Indicator
|
||||
/// </remarks>
|
||||
public double LaserDivergenceAngle { get; private set; } = 0;
|
||||
|
||||
/// <summary>
|
||||
/// 获取或设置激光编码
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 包含激光信号的编码信息
|
||||
/// 用于抗干扰和安全识别
|
||||
/// </remarks>
|
||||
private LaserCode? currentLaserCode = null;
|
||||
|
||||
/// <summary>
|
||||
/// 获取或设置是否启用编码
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// true表示激光信号使用编码
|
||||
/// false表示激光信号不使用编码
|
||||
/// 默认为false
|
||||
/// </remarks>
|
||||
private bool isCodeEnabled = false;
|
||||
|
||||
/// <summary>
|
||||
/// 初始化激光指示器的新实例
|
||||
/// </summary>
|
||||
@ -261,38 +280,122 @@ namespace ThreatSource.Indicator
|
||||
base.Deactivate();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置激光编码
|
||||
/// </summary>
|
||||
/// <param name="codeType">编码类型</param>
|
||||
/// <param name="codeValue">编码值</param>
|
||||
/// <remarks>
|
||||
/// 设置过程:
|
||||
/// - 创建新的编码对象
|
||||
/// - 设置编码类型和值
|
||||
/// - 启用编码功能
|
||||
/// </remarks>
|
||||
public void SetLaserCode(LaserCodeType codeType, int codeValue)
|
||||
{
|
||||
currentLaserCode = new LaserCode
|
||||
{
|
||||
CodeType = codeType,
|
||||
CodeValue = codeValue
|
||||
};
|
||||
isCodeEnabled = true;
|
||||
Console.WriteLine($"激光目标指示器 {Id} 设置编码:类型={codeType},值={codeValue}");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 添加编码参数
|
||||
/// </summary>
|
||||
/// <param name="key">参数名称</param>
|
||||
/// <param name="value">参数值</param>
|
||||
/// <remarks>
|
||||
/// 添加特定编码类型的额外参数
|
||||
/// 如PPM编码的脉冲位置模式、PWM编码的脉冲宽度等
|
||||
/// </remarks>
|
||||
public void AddCodeParameter(string key, object value)
|
||||
{
|
||||
if (currentLaserCode != null)
|
||||
{
|
||||
currentLaserCode.Parameters[key] = value;
|
||||
Console.WriteLine($"激光目标指示器 {Id} 添加编码参数:{key}={value}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 启用或禁用编码
|
||||
/// </summary>
|
||||
/// <param name="enable">是否启用编码</param>
|
||||
/// <remarks>
|
||||
/// true表示启用编码功能
|
||||
/// false表示禁用编码功能
|
||||
/// </remarks>
|
||||
public void EnableCode(bool enable)
|
||||
{
|
||||
isCodeEnabled = enable;
|
||||
Console.WriteLine($"激光目标指示器 {Id} {(enable ? "启用" : "禁用")}编码功能");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 发布激光照射开始事件
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 发布过程:
|
||||
/// - 创建事件对象
|
||||
/// - 设置事件参数
|
||||
/// - 设置事件属性
|
||||
/// - 添加编码信息
|
||||
/// - 发布到事件系统
|
||||
/// - 记录事件日志
|
||||
/// </remarks>
|
||||
private void PublishIlluminationStartEvent()
|
||||
{
|
||||
var evt = new LaserIlluminationStartEvent { LaserDesignatorId = Id, TargetId = TargetId };
|
||||
PublishEvent(evt);
|
||||
Console.WriteLine($"激光指示器 {Id} 发布激光照射事件");
|
||||
var illuminationEvent = new LaserIlluminationStartEvent
|
||||
{
|
||||
LaserDesignatorId = Id,
|
||||
TargetId = TargetId
|
||||
};
|
||||
|
||||
// 添加编码信息
|
||||
if (isCodeEnabled && currentLaserCode != null)
|
||||
{
|
||||
illuminationEvent.LaserCode = currentLaserCode;
|
||||
illuminationEvent.IsCodeEnabled = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
illuminationEvent.IsCodeEnabled = false;
|
||||
}
|
||||
|
||||
PublishEvent(illuminationEvent);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <summary>
|
||||
/// 发布激光照射更新事件
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 发布过程:
|
||||
/// - 创建更新事件
|
||||
/// - 设置最新参数
|
||||
/// - 创建事件对象
|
||||
/// - 设置事件属性
|
||||
/// - 添加编码信息
|
||||
/// - 发布到事件系统
|
||||
/// - 记录更新日志
|
||||
/// </remarks>
|
||||
private void PublishIlluminationUpdateEvent()
|
||||
{
|
||||
var evt = new LaserIlluminationUpdateEvent { LaserDesignatorId = Id, TargetId = TargetId };
|
||||
PublishEvent(evt);
|
||||
Console.WriteLine($"激光指示器 {Id} 发布激光照射更新事件");
|
||||
var illuminationEvent = new LaserIlluminationUpdateEvent
|
||||
{
|
||||
LaserDesignatorId = Id,
|
||||
TargetId = TargetId
|
||||
};
|
||||
|
||||
// 添加编码信息
|
||||
if (isCodeEnabled && currentLaserCode != null)
|
||||
{
|
||||
illuminationEvent.LaserCode = currentLaserCode;
|
||||
illuminationEvent.IsCodeEnabled = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
illuminationEvent.IsCodeEnabled = false;
|
||||
}
|
||||
|
||||
PublishEvent(illuminationEvent);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@ -92,8 +92,10 @@ namespace ThreatSource.Missile
|
||||
|
||||
// 初始化红外指令导引系统,包括自适应 PID 参数
|
||||
guidanceSystem = new InfraredCommandGuidanceSystem(
|
||||
maxAcceleration: config.MaxAcceleration,
|
||||
guidanceCoefficient: config.ProportionalNavigationCoefficient
|
||||
config.Id + "_guidance",
|
||||
config.MaxAcceleration,
|
||||
config.ProportionalNavigationCoefficient,
|
||||
manager
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@ -86,7 +86,11 @@ namespace ThreatSource.Missile
|
||||
: base(config, manager)
|
||||
{
|
||||
currentStage = IRTG_Stage.Launch;
|
||||
guidanceSystem = new InfraredImagingGuidanceSystem(config.MaxAcceleration, config.ProportionalNavigationCoefficient, manager);
|
||||
guidanceSystem = new InfraredImagingGuidanceSystem(
|
||||
config.Id + "_guidance",
|
||||
config.MaxAcceleration,
|
||||
config.ProportionalNavigationCoefficient,
|
||||
manager);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@ -69,7 +69,11 @@ namespace ThreatSource.Missile
|
||||
public LaserBeamRiderMissile(MissileProperties config, ISimulationManager manager)
|
||||
: base(config, manager)
|
||||
{
|
||||
LaserBeamRiderGuidanceSystem = new LaserBeamRiderGuidanceSystem(config.MaxAcceleration, config.ProportionalNavigationCoefficient);
|
||||
LaserBeamRiderGuidanceSystem = new LaserBeamRiderGuidanceSystem(
|
||||
config.Id + "_guidance",
|
||||
config.MaxAcceleration,
|
||||
config.ProportionalNavigationCoefficient,
|
||||
manager);
|
||||
currentStage = LBRM_Stage.Launch;
|
||||
}
|
||||
|
||||
|
||||
@ -80,8 +80,21 @@ namespace ThreatSource.Missile
|
||||
public LaserSemiActiveGuidedMissile(MissileProperties config, ISimulationManager manager)
|
||||
: base(config, manager)
|
||||
{
|
||||
LaserGuidanceSystem = new LaserSemiActiveGuidanceSystem(config.MaxAcceleration, config.ProportionalNavigationCoefficient);
|
||||
LaserGuidanceSystem = new LaserSemiActiveGuidanceSystem(
|
||||
config.Id + "_guidance",
|
||||
config.MaxAcceleration,
|
||||
config.ProportionalNavigationCoefficient,
|
||||
manager);
|
||||
|
||||
// 设置制导系统的ParentId属性
|
||||
LaserGuidanceSystem.ParentId = config.Id;
|
||||
|
||||
currentStage = LSAGM_Stage.Launch;
|
||||
|
||||
// 订阅激光照射事件
|
||||
SimulationManager.SubscribeToEvent<LaserIlluminationStartEvent>(OnLaserIlluminationStart);
|
||||
SimulationManager.SubscribeToEvent<LaserIlluminationUpdateEvent>(OnLaserIlluminationUpdate);
|
||||
SimulationManager.SubscribeToEvent<LaserIlluminationStopEvent>(OnLaserIlluminationStop);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -91,8 +104,8 @@ namespace ThreatSource.Missile
|
||||
/// <remarks>
|
||||
/// 处理过程:
|
||||
/// - 验证激光指示器和目标
|
||||
/// - 更新制导系统参数
|
||||
/// - 开始目标跟踪
|
||||
/// - 更新目标位置和速度
|
||||
/// - 更新制导参数
|
||||
/// </remarks>
|
||||
private void OnLaserIlluminationStart(LaserIlluminationStartEvent evt)
|
||||
{
|
||||
@ -100,8 +113,19 @@ namespace ThreatSource.Missile
|
||||
{
|
||||
LaserDesignator laserDesignator = SimulationManager.GetEntityById(evt.LaserDesignatorId) as LaserDesignator ?? throw new Exception("激光指示器不存在");
|
||||
SimulationElement target = SimulationManager.GetEntityById(evt.TargetId) as SimulationElement ?? throw new Exception("目标不存在");
|
||||
|
||||
// 更新激光指示器信息
|
||||
LaserGuidanceSystem.UpdateLaserDesignator(laserDesignator.Position, target.Position, target.Velocity,
|
||||
laserDesignator.LaserPower, laserDesignator.LaserDivergenceAngle);
|
||||
|
||||
// 处理激光编码
|
||||
if (LaserGuidanceSystem is LaserSemiActiveGuidanceSystem laserGuidance)
|
||||
{
|
||||
laserGuidance.ProcessLaserIlluminationEvent(evt);
|
||||
|
||||
// 直接设置IsGuidance属性
|
||||
IsGuidance = laserGuidance.HasGuidance;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -121,8 +145,19 @@ namespace ThreatSource.Missile
|
||||
{
|
||||
LaserDesignator laserDesignator = SimulationManager.GetEntityById(evt.LaserDesignatorId) as LaserDesignator ?? throw new Exception("激光指示器不存在");
|
||||
SimulationElement target = SimulationManager.GetEntityById(evt.TargetId) as SimulationElement ?? throw new Exception("目标不存在");
|
||||
|
||||
// 更新激光指示器信息
|
||||
LaserGuidanceSystem.UpdateLaserDesignator(laserDesignator.Position, target.Position, target.Velocity,
|
||||
laserDesignator.LaserPower, laserDesignator.LaserDivergenceAngle);
|
||||
|
||||
// 处理激光编码
|
||||
if (LaserGuidanceSystem is LaserSemiActiveGuidanceSystem laserGuidance)
|
||||
{
|
||||
laserGuidance.ProcessLaserIlluminationUpdateEvent(evt);
|
||||
|
||||
// 直接设置IsGuidance属性
|
||||
IsGuidance = laserGuidance.HasGuidance;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -138,7 +173,17 @@ namespace ThreatSource.Missile
|
||||
/// </remarks>
|
||||
private void OnLaserIlluminationStop(LaserIlluminationStopEvent evt)
|
||||
{
|
||||
// 停用激光指示器
|
||||
LaserGuidanceSystem.DeactivateLaserDesignator();
|
||||
|
||||
// 处理激光编码
|
||||
if (LaserGuidanceSystem is LaserSemiActiveGuidanceSystem laserGuidance)
|
||||
{
|
||||
laserGuidance.ProcessLaserIlluminationStopEvent(evt);
|
||||
|
||||
// 直接设置IsGuidance属性
|
||||
IsGuidance = laserGuidance.HasGuidance;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -238,9 +283,23 @@ namespace ThreatSource.Missile
|
||||
/// </remarks>
|
||||
private void UpdateCruiseStage(double deltaTime)
|
||||
{
|
||||
IsGuidance = true;
|
||||
// 更新制导系统
|
||||
LaserGuidanceSystem.Update(deltaTime, Position, Velocity);
|
||||
|
||||
// 根据制导系统的HasGuidance属性设置IsGuidance
|
||||
if (LaserGuidanceSystem is LaserSemiActiveGuidanceSystem laserGuidance)
|
||||
{
|
||||
IsGuidance = laserGuidance.HasGuidance;
|
||||
}
|
||||
else
|
||||
{
|
||||
IsGuidance = true; // 默认情况下启用制导
|
||||
}
|
||||
|
||||
// 获取制导加速度
|
||||
GuidanceAcceleration = LaserGuidanceSystem.GetGuidanceAcceleration();
|
||||
|
||||
// 检查自毁条件
|
||||
if(ShouldSelfDestruct())
|
||||
{
|
||||
currentStage = LSAGM_Stage.SelfDestruct;
|
||||
@ -291,5 +350,55 @@ namespace ThreatSource.Missile
|
||||
string additionalStatus = LaserGuidanceSystem.HasGuidance ? LaserGuidanceSystem.GetStatus() : "";
|
||||
return baseStatus + additionalStatus;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置激光编码
|
||||
/// </summary>
|
||||
/// <param name="codeType">编码类型</param>
|
||||
/// <param name="codeValue">编码值</param>
|
||||
/// <remarks>
|
||||
/// 设置导弹期望接收的激光编码类型和值
|
||||
/// 用于验证接收到的激光信号
|
||||
/// </remarks>
|
||||
public void SetLaserCode(LaserCodeType codeType, int codeValue)
|
||||
{
|
||||
if (LaserGuidanceSystem is LaserSemiActiveGuidanceSystem laserGuidance)
|
||||
{
|
||||
laserGuidance.SetExpectedLaserCode(codeType, codeValue);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 添加激光编码参数
|
||||
/// </summary>
|
||||
/// <param name="key">参数名称</param>
|
||||
/// <param name="value">参数值</param>
|
||||
/// <remarks>
|
||||
/// 添加特定编码类型的额外参数
|
||||
/// 如PPM编码的脉冲位置模式、PWM编码的脉冲宽度等
|
||||
/// </remarks>
|
||||
public void AddLaserCodeParameter(string key, object value)
|
||||
{
|
||||
if (LaserGuidanceSystem is LaserSemiActiveGuidanceSystem laserGuidance)
|
||||
{
|
||||
laserGuidance.AddExpectedCodeParameter(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置是否要求编码匹配
|
||||
/// </summary>
|
||||
/// <param name="required">是否要求匹配</param>
|
||||
/// <remarks>
|
||||
/// true表示只响应匹配编码的激光信号
|
||||
/// false表示响应所有激光信号
|
||||
/// </remarks>
|
||||
public void SetCodeMatchRequired(bool required)
|
||||
{
|
||||
if (LaserGuidanceSystem is LaserSemiActiveGuidanceSystem laserGuidance)
|
||||
{
|
||||
laserGuidance.SetCodeMatchRequired(required);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -86,7 +86,12 @@ namespace ThreatSource.Missile
|
||||
: base(properties, manager)
|
||||
{
|
||||
currentStage = MWTG_Stage.Launch;
|
||||
guidanceSystem = new MillimeterWaveGuidanceSystem(properties.MaxAcceleration, properties.ProportionalNavigationCoefficient, manager);
|
||||
guidanceSystem = new MillimeterWaveGuidanceSystem(
|
||||
properties.Id + "_guidance",
|
||||
properties.MaxAcceleration,
|
||||
properties.ProportionalNavigationCoefficient,
|
||||
manager
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@ -587,10 +587,16 @@ namespace ThreatSource.Missile
|
||||
{
|
||||
targetAngle = radiometerAngle.Value;
|
||||
}
|
||||
else
|
||||
else if (infraredAngle.HasValue)
|
||||
{
|
||||
targetAngle = infraredAngle.Value;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 如果两个角度都为null,设置一个默认值或抛出异常
|
||||
targetAngle = 0;
|
||||
Console.WriteLine("警告:红外和毫米波探测器都未返回有效角度");
|
||||
}
|
||||
|
||||
// 记录首次探测信息
|
||||
isTargetDetected = true;
|
||||
@ -602,9 +608,21 @@ namespace ThreatSource.Missile
|
||||
}
|
||||
else // 已经探测到目标,等待转过一圈进行二次确认
|
||||
{
|
||||
// 确保lastDetectionTime不为null
|
||||
if (!lastDetectionTime.HasValue)
|
||||
{
|
||||
lastDetectionTime = FlightTime;
|
||||
}
|
||||
|
||||
double timeSinceLastDetection = FlightTime - lastDetectionTime.Value;
|
||||
if (timeSinceLastDetection >= 0.75 * 2 * Math.PI / SpiralRotationSpeed) // 转过3/4圈以后
|
||||
{
|
||||
// 确保firstDetectionAngle不为null
|
||||
if (!firstDetectionAngle.HasValue)
|
||||
{
|
||||
firstDetectionAngle = spiralAngle;
|
||||
}
|
||||
|
||||
// 检查当前角度是否接近记录的目标方位角
|
||||
double angleDiff = Math.Abs(spiralAngle - firstDetectionAngle.Value);
|
||||
// 根据仿真步长和转速计算允许的角度误差
|
||||
|
||||
@ -75,6 +75,24 @@ namespace ThreatSource.Simulation
|
||||
/// 标识被激光照射的目标实体
|
||||
/// </remarks>
|
||||
public string? TargetId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取或设置激光编码信息
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 包含激光信号的编码类型和编码值
|
||||
/// 用于抗干扰和安全识别
|
||||
/// </remarks>
|
||||
public LaserCode? LaserCode { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取或设置是否启用编码
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// true表示激光信号使用编码
|
||||
/// false表示激光信号不使用编码
|
||||
/// </remarks>
|
||||
public bool IsCodeEnabled { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -98,9 +116,27 @@ namespace ThreatSource.Simulation
|
||||
/// 获取或设置被照射目标的ID
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 标识正在被照射的目标实体
|
||||
/// 标识被激光照射的目标实体
|
||||
/// </remarks>
|
||||
public string? TargetId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取或设置激光编码信息
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 包含激光信号的编码类型和编码值
|
||||
/// 用于抗干扰和安全识别
|
||||
/// </remarks>
|
||||
public LaserCode? LaserCode { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取或设置是否启用编码
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// true表示激光信号使用编码
|
||||
/// false表示激光信号不使用编码
|
||||
/// </remarks>
|
||||
public bool IsCodeEnabled { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -554,4 +590,80 @@ namespace ThreatSource.Simulation
|
||||
/// </summary>
|
||||
public double WavelengthMax { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 激光编码匹配事件,表示导弹成功匹配激光编码
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 用于通知系统导弹已成功识别激光编码
|
||||
/// 触发时机:导弹接收到匹配的激光编码时
|
||||
/// </remarks>
|
||||
public class LaserCodeMatchEvent : SimulationEvent
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取或设置导弹ID
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 标识接收激光信号的导弹
|
||||
/// </remarks>
|
||||
public string? MissileId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取或设置激光定位器ID
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 标识发送激光信号的定位器
|
||||
/// </remarks>
|
||||
public string? DesignatorId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取或设置匹配的激光编码
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 包含成功匹配的编码信息
|
||||
/// </remarks>
|
||||
public LaserCode? MatchedCode { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 激光编码不匹配事件,表示导弹接收到不匹配的激光编码
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 用于通知系统导弹接收到不匹配的激光编码
|
||||
/// 触发时机:导弹接收到不匹配的激光编码时
|
||||
/// </remarks>
|
||||
public class LaserCodeMismatchEvent : SimulationEvent
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取或设置导弹ID
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 标识接收激光信号的导弹
|
||||
/// </remarks>
|
||||
public string? MissileId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取或设置激光定位器ID
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 标识发送激光信号的定位器
|
||||
/// </remarks>
|
||||
public string? DesignatorId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取或设置期望的激光编码
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 导弹期望接收的编码信息
|
||||
/// </remarks>
|
||||
public LaserCode? ExpectedCode { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取或设置接收到的激光编码
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 导弹实际接收到的编码信息
|
||||
/// </remarks>
|
||||
public LaserCode? ReceivedCode { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@ -90,6 +90,16 @@ namespace ThreatSource.Simulation.Testing
|
||||
return _publishedEvents;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取指定类型的已发布事件
|
||||
/// </summary>
|
||||
/// <typeparam name="T">事件类型</typeparam>
|
||||
/// <returns>指定类型的已发布事件列表</returns>
|
||||
public List<T> GetPublishedEvents<T>() where T : SimulationEvent
|
||||
{
|
||||
return _publishedEvents.OfType<T>().ToList();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取已接收的事件
|
||||
/// </summary>
|
||||
|
||||
139
ThreatSource/src/Utils/LaserCode.cs
Normal file
139
ThreatSource/src/Utils/LaserCode.cs
Normal file
@ -0,0 +1,139 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace ThreatSource.Utils
|
||||
{
|
||||
/// <summary>
|
||||
/// 激光编码类型枚举,定义支持的不同编码类型
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 包含多种常见的激光编码类型:
|
||||
/// - PRF:脉冲重复频率编码
|
||||
/// - PPM:脉冲位置调制
|
||||
/// - PWM:脉冲宽度调制
|
||||
/// - PseudoRandom:伪随机编码
|
||||
/// - Frequency:频率编码
|
||||
/// - Phase:相位编码
|
||||
/// </remarks>
|
||||
public enum LaserCodeType
|
||||
{
|
||||
/// <summary>
|
||||
/// 无编码
|
||||
/// </summary>
|
||||
None = 0,
|
||||
|
||||
/// <summary>
|
||||
/// 脉冲重复频率编码
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 最常用的激光编码方式
|
||||
/// NATO标准使用的编码方式
|
||||
/// 通常使用4位数字编码(1111-1788)
|
||||
/// </remarks>
|
||||
PRF = 1,
|
||||
|
||||
/// <summary>
|
||||
/// 脉冲位置调制
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 通过改变脉冲在时间窗口中的位置来编码信息
|
||||
/// 抗干扰能力较强
|
||||
/// </remarks>
|
||||
PPM = 2,
|
||||
|
||||
/// <summary>
|
||||
/// 脉冲宽度调制
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 通过改变脉冲宽度来编码信息
|
||||
/// 实现简单,抗干扰能力一般
|
||||
/// </remarks>
|
||||
PWM = 3,
|
||||
|
||||
/// <summary>
|
||||
/// 伪随机编码
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 使用伪随机序列对激光信号进行调制
|
||||
/// 抗干扰能力极强
|
||||
/// </remarks>
|
||||
PseudoRandom = 4,
|
||||
|
||||
/// <summary>
|
||||
/// 频率编码
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 使用不同频率的激光进行编码
|
||||
/// 可以同时使用多个频率
|
||||
/// </remarks>
|
||||
Frequency = 5,
|
||||
|
||||
/// <summary>
|
||||
/// 相位编码
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 通过调制激光信号的相位来编码信息
|
||||
/// 编码容量大,抗干扰能力强
|
||||
/// </remarks>
|
||||
Phase = 6
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 激光编码类,用于表示激光信号的编码信息
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 提供了激光编码的基本属性和方法:
|
||||
/// - 编码类型
|
||||
/// - 编码值
|
||||
/// - 附加参数
|
||||
/// - 编码匹配判断
|
||||
/// 用于实现激光信号的编码和解码功能
|
||||
/// </remarks>
|
||||
public class LaserCode
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取或设置编码类型
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 指定使用的编码方案
|
||||
/// 默认为None(无编码)
|
||||
/// </remarks>
|
||||
public LaserCodeType CodeType { get; set; } = LaserCodeType.None;
|
||||
|
||||
/// <summary>
|
||||
/// 获取或设置编码值
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 对于不同类型的编码,解释方式不同
|
||||
/// 对于PRF编码,表示1111-1788范围内的编码值
|
||||
/// </remarks>
|
||||
public int CodeValue { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取或设置附加参数
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 用于存储特定编码类型的额外信息
|
||||
/// 如PPM编码的脉冲位置模式、PWM编码的脉冲宽度等
|
||||
/// </remarks>
|
||||
public Dictionary<string, object> Parameters { get; set; } = new Dictionary<string, object>();
|
||||
|
||||
/// <summary>
|
||||
/// 判断当前编码是否与指定编码匹配
|
||||
/// </summary>
|
||||
/// <param name="other">要比较的编码</param>
|
||||
/// <returns>如果匹配返回true,否则返回false</returns>
|
||||
/// <remarks>
|
||||
/// 匹配规则:
|
||||
/// - 编码类型必须相同
|
||||
/// - 编码值必须相同
|
||||
/// 不考虑附加参数的匹配
|
||||
/// </remarks>
|
||||
public bool Matches(LaserCode other)
|
||||
{
|
||||
if (other == null)
|
||||
return false;
|
||||
|
||||
return CodeType == other.CodeType && CodeValue == other.CodeValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -919,11 +919,11 @@ graph TB
|
||||
- 干扰抑制效果
|
||||
- 跟踪恢复性能
|
||||
|
||||
### 3.6 末敏导弹
|
||||
### 3.6 末敏弹
|
||||
|
||||
#### 3.6.1 工作原理
|
||||
|
||||
末敏导弹系统由母弹和子弹两部分组成,通过多传感器融合实现精确打击。其基本工作过程如下:
|
||||
末敏弹系统由母弹和子弹两部分组成,通过多传感器融合实现精确打击。其基本工作过程如下:
|
||||
|
||||
1. 母弹飞行阶段
|
||||
- 母弹发射并飞向预定分离点
|
||||
|
||||
@ -7,6 +7,10 @@
|
||||
- 事件描述
|
||||
- 分析处理
|
||||
|
||||
## 2025-02-25 给激光半主动导弹和激光目标指示器增加激光编码特性
|
||||
- 增加了 6 种激光编码方式
|
||||
- 当激光编码方式和编码匹配,才能激活导引
|
||||
|
||||
## 2025-02-17 末敏弹的探测逻辑优化
|
||||
|
||||
- 优化了末敏弹的探测逻辑,完善了几个传感器的逻辑
|
||||
|
||||
Loading…
Reference in New Issue
Block a user