| | 1 | | using UnityEngine; |
| | 2 | |
|
| | 3 | | // The iterative launch planner class is a launch planner that performs an iterative process to |
| | 4 | | // determine the intercept point. The algorithm continuously performs the following 2-step iterative |
| | 5 | | // process: |
| | 6 | | // 1. Time-to-intercept estimation: The algorithm determines the time it takes the interceptor to |
| | 7 | | // reach the target at the predicted intercept position, which is initialized to the target's |
| | 8 | | // current position. |
| | 9 | | // 2. Intercept position estimation: The algorithm predicts the target position at the estimated |
| | 10 | | // time-to-intercept. |
| | 11 | | public class IterativeLaunchPlanner : ILaunchPlanner { |
| | 12 | | // Maximum number of iterations before declaring failure. In certain cases, the predictor and |
| | 13 | | // planner do not converge, so we need to limit the number of iterations. |
| | 14 | | private const int MaxNumIterations = 10; |
| | 15 | |
|
| | 16 | | // Convergence threshold in meters for the difference vector magnitude. Convergence is declared |
| | 17 | | // when the intercept position has not changed by more than this threshold between iterations. |
| | 18 | | private const float ConvergenceThreshold = 10f; |
| | 19 | |
|
| | 20 | | // Maximum intercept position threshold in meters to declare convergence. This threshold is used |
| | 21 | | // as a final sanity check to ensure that the predicted target position and intercept position do |
| | 22 | | // not differ by more than this threshold. This threshold should be set depending on the |
| | 23 | | // granularity of the possible intercept positions. |
| | 24 | | private const float InterceptPositionThreshold = 1000f; |
| | 25 | |
|
| | 26 | | public IterativeLaunchPlanner(ILaunchAnglePlanner launchAnglePlanner, IPredictor predictor) |
| 18 | 27 | | : base(launchAnglePlanner, predictor) {} |
| | 28 | |
|
| | 29 | | // Plan the launch. |
| 6 | 30 | | public override LaunchPlan Plan() { |
| 6 | 31 | | PredictorState initialState = _predictor.Predict(time: 0); |
| 6 | 32 | | Vector3 targetPosition = initialState.Position; |
| | 33 | |
|
| 6 | 34 | | LaunchAngleOutput launchAngleOutput = new LaunchAngleOutput(); |
| 6 | 35 | | Vector3 interceptPosition = new Vector3(); |
| 33 | 36 | | for (int i = 0; i < MaxNumIterations; ++i) { |
| | 37 | | // Estimate the time-to-intercept. |
| 11 | 38 | | launchAngleOutput = _launchAnglePlanner.Plan(targetPosition); |
| 11 | 39 | | float timeToIntercept = launchAngleOutput.TimeToPosition; |
| | 40 | |
|
| | 41 | | // Estimate the target position. |
| 11 | 42 | | PredictorState predictedState = _predictor.Predict(timeToIntercept); |
| 11 | 43 | | targetPosition = predictedState.Position; |
| | 44 | |
|
| | 45 | | // Check whether the intercept direction has changed, in which case the algorithm has |
| | 46 | | // converged. |
| 11 | 47 | | Vector3 newInterceptPosition = _launchAnglePlanner.GetInterceptPosition(targetPosition); |
| 16 | 48 | | if ((interceptPosition - newInterceptPosition).magnitude < ConvergenceThreshold) { |
| 5 | 49 | | interceptPosition = newInterceptPosition; |
| 5 | 50 | | break; |
| | 51 | | } |
| 6 | 52 | | interceptPosition = newInterceptPosition; |
| | 53 | |
|
| | 54 | | // Check that the target is moving towards the intercept position. Otherwise, the interceptor |
| | 55 | | // should wait to be launched. |
| 6 | 56 | | Vector3 targetToInterceptPosition = interceptPosition - initialState.Position; |
| 6 | 57 | | Vector3 targetToPredictedPosition = targetPosition - initialState.Position; |
| 7 | 58 | | if (Vector3.Dot(targetToInterceptPosition, targetToPredictedPosition) < 0) { |
| 1 | 59 | | return LaunchPlan.NoLaunch; |
| | 60 | | } |
| 5 | 61 | | } |
| | 62 | |
|
| | 63 | | // Check that the interceptor is moving towards the target. If the target is moving too fast, |
| | 64 | | // the interceptor might be launched backwards because the intercept position and the predicted |
| | 65 | | // position are behind the asset. In this case, the interceptor should wait to be launched. |
| 5 | 66 | | Vector3 interceptorToInterceptPosition = interceptPosition; |
| 5 | 67 | | Vector3 threatToPredictedPosition = targetPosition - initialState.Position; |
| 6 | 68 | | if (Vector3.Dot(interceptorToInterceptPosition, threatToPredictedPosition) > 0) { |
| 1 | 69 | | return LaunchPlan.NoLaunch; |
| | 70 | | } |
| | 71 | |
|
| | 72 | | // Check that the intercept position and the predicted position are within some threshold |
| | 73 | | // distance of each other. |
| 7 | 74 | | if (Vector3.Distance(interceptPosition, targetPosition) < InterceptPositionThreshold) { |
| 3 | 75 | | return new LaunchPlan(launchAngleOutput.LaunchAngle, targetPosition); |
| | 76 | | } |
| 1 | 77 | | return LaunchPlan.NoLaunch; |
| 6 | 78 | | } |
| | 79 | | } |