public DistanceCalculatorOutput Calculate() { var state = new AircraftState(); bool hasFailureOccurred = false; int failureSpeed = calculationSettings.FailureSpeed; for (int i = 0; i < calculationSettings.MaximumNrOfTimeSteps; i++) { AircraftAccelerations accelerations = hasFailureOccurred ? failureTakeOffDynamicsCalculator.Calculate(state) : normalTakeOffDynamicsCalculator.Calculate(state); state = integrator.Integrate(state, accelerations, calculationSettings.TimeStep); if (state.TrueAirspeed > failureSpeed) { hasFailureOccurred = true; } if (state.Height >= screenHeight || state.TrueAirspeed <= 0) { if (!hasFailureOccurred) { throw new CalculatorException(Resources.DistanceCalculator_Calculation_converged_before_failure); } return(new DistanceCalculatorOutput(failureSpeed, state.Distance)); } } throw new CalculatorException(Resources.DistanceCalculator_No_calculation_convergence); }
public static void Calculate_WithAirspeedEqualToThresholdAndNoNormalForcePresent_ReturnsExpectedFlightPathAngleRate(AircraftData aircraftData) { // Setup const double heightThreshold = 0.01; var random = new Random(21); var aircraftState = new AircraftState(aircraftData.MaximumPitchAngle, random.NextAngle(), 100, heightThreshold - random.NextDouble(), random.NextDouble()); Angle angleOfAttack = aircraftState.PitchAngle - aircraftState.FlightPathAngle; // Precondition double lift = AerodynamicsHelper.CalculateLift(aircraftData.AerodynamicsData, angleOfAttack, airDensity, aircraftState.TrueAirspeed); double takeOffWeightNewton = aircraftData.TakeOffWeight * 1000; // N Assert.IsTrue(lift > takeOffWeightNewton); var calculator = new TestTakeOffDynamicsCalculator(aircraftData, airDensity, gravitationalAcceleration); // Call AircraftAccelerations accelerations = calculator.Calculate(aircraftState); // Assert double expectedRate = (gravitationalAcceleration * (lift - takeOffWeightNewton)) / (takeOffWeightNewton * aircraftState.TrueAirspeed); Assert.AreEqual(expectedRate, accelerations.FlightPathRate.Radians, tolerance); }
public static void Calculate_WithAircraftStateHeightSmallerThanThresholdAndLiftSmallerThanTakeOffWeight_ReturnsExpectedTrueAirspeedRate(AircraftData aircraftData) { // Setup const int nrOfFailedEngines = 1; const double airspeed = 10.0; const double threshold = 0.01; var random = new Random(21); var aircraftState = new AircraftState(aircraftData.MaximumPitchAngle, random.NextAngle(), airspeed, threshold - random.NextDouble(), random.NextDouble()); Angle angleOfAttack = aircraftState.PitchAngle - aircraftState.FlightPathAngle; // Precondition double lift = AerodynamicsHelper.CalculateLift(aircraftData.AerodynamicsData, angleOfAttack, airDensity, airspeed); double takeOffWeightNewton = aircraftData.TakeOffWeight * 1000; // N Assert.IsTrue(lift < takeOffWeightNewton); var calculator = new ContinuedTakeOffDynamicsCalculator(aircraftData, nrOfFailedEngines, airDensity, gravitationalAcceleration); // Call AircraftAccelerations accelerations = calculator.Calculate(aircraftState); // Assert double liftCoefficient = AerodynamicsHelper.CalculateLiftCoefficient(aircraftData.AerodynamicsData, angleOfAttack); double normalForce = takeOffWeightNewton - lift; double dragForce = AerodynamicsHelper.CalculateDragWithEngineFailure(aircraftData.AerodynamicsData, liftCoefficient, airDensity, airspeed) + normalForce * aircraftData.RollingResistanceCoefficient; double thrustForce = (aircraftData.NrOfEngines - nrOfFailedEngines) * aircraftData.MaximumThrustPerEngine * 1000; double horizontalWeightComponent = takeOffWeightNewton * Math.Sin(aircraftState.FlightPathAngle.Radians); double expectedAcceleration = (gravitationalAcceleration * (thrustForce - dragForce - horizontalWeightComponent)) / takeOffWeightNewton; Assert.AreEqual(expectedAcceleration, accelerations.TrueAirSpeedRate, tolerance); }
public static void Calculate_WithAircraftStateHeightSmallerThanThresholdAndLiftSmallerThanTakeOffWeight_ReturnsExpectedTrueAirspeedRate(AircraftData aircraftData) { // Setup const double airspeed = 10.0; const double threshold = 0.01; var random = new Random(21); var aircraftState = new AircraftState(aircraftData.MaximumPitchAngle, random.NextAngle(), airspeed, threshold - random.NextDouble(), random.NextDouble()); Angle angleOfAttack = aircraftState.PitchAngle - aircraftState.FlightPathAngle; // Precondition double lift = AerodynamicsHelper.CalculateLift(aircraftData.AerodynamicsData, angleOfAttack, airDensity, airspeed); double takeOffWeightNewton = aircraftData.TakeOffWeight * 1000; // N Assert.IsTrue(lift < takeOffWeightNewton); double thrust = random.NextDouble() * 1000; double drag = random.NextDouble() * 100; double frictionCoefficient = random.NextDouble(); var calculator = new TestTakeOffDynamicsCalculator(aircraftData, airDensity, gravitationalAcceleration) { Thrust = thrust, Drag = drag, RollDrag = frictionCoefficient }; // Call AircraftAccelerations accelerations = calculator.Calculate(aircraftState); // Assert double horizontalWeightComponent = takeOffWeightNewton * Math.Sin(aircraftState.FlightPathAngle.Radians); double groundDrag = frictionCoefficient * (aircraftData.TakeOffWeight * 1000 - lift); double expectedAcceleration = (gravitationalAcceleration * (thrust - drag - groundDrag - horizontalWeightComponent)) / takeOffWeightNewton; Assert.AreEqual(expectedAcceleration, accelerations.TrueAirSpeedRate, tolerance); }
public AircraftState Integrate(AircraftState state, AircraftAccelerations accelerations, double timeStep) { if (state == null) { throw new ArgumentNullException(nameof(state)); } if (accelerations == null) { throw new ArgumentNullException(nameof(accelerations)); } return(new AircraftState(IntegrateState(state.PitchAngle, accelerations.PitchRate, timeStep), IntegrateState(state.FlightPathAngle, accelerations.FlightPathRate, timeStep), IntegrateState(state.TrueAirspeed, accelerations.TrueAirSpeedRate, timeStep), IntegrateState(state.Height, accelerations.ClimbRate, timeStep), IntegrateState(state.Distance, state.TrueAirspeed, timeStep))); }
public static void Calculate_WithAircraftStateSpeedHigherThanRotationSpeedAndPitchAngleAtMaximumPitch_ReturnsExpectedZeroPitchRate(AircraftData aircraftData) { // Setup double rotationSpeed = GetRotationSpeed(aircraftData); var random = new Random(21); var aircraftState = new AircraftState(aircraftData.MaximumPitchAngle, random.NextAngle(), rotationSpeed + random.NextDouble(), random.NextDouble(), random.NextDouble()); var calculator = new ContinuedTakeOffDynamicsCalculator(aircraftData, random.Next(), airDensity, random.NextDouble()); // Call AircraftAccelerations accelerations = calculator.Calculate(aircraftState); // Assert Assert.Zero(accelerations.PitchRate.Degrees); }
public static void Calculate_WitAircraftStateSpeedLowerThanRotationSpeed_ReturnsExpectedZeroPitchRate(AircraftData aircraftData) { // Setup double rotationSpeed = GetRotationSpeed(aircraftData); var random = new Random(21); var aircraftState = new AircraftState(random.NextAngle(), random.NextAngle(), rotationSpeed - random.NextDouble(), random.NextDouble(), random.NextDouble()); var calculator = new TestTakeOffDynamicsCalculator(aircraftData, airDensity, random.NextDouble()); // Call AircraftAccelerations accelerations = calculator.Calculate(aircraftState); // Assert Assert.Zero(accelerations.PitchRate.Degrees); }
public static void Calculate_Always_ReturnsExpectedZeroPitchRate() { // Setup var random = new Random(21); AircraftData aircraftData = AircraftDataTestFactory.CreateRandomAircraftData(); Angle angleOfAttack = AerodynamicsDataTestHelper.GetValidAngleOfAttack(aircraftData.AerodynamicsData); var aircraftState = new AircraftState(angleOfAttack, new Angle(), random.NextDouble(), random.NextDouble(), random.NextDouble()); var calculator = new AbortedTakeOffDynamicsCalculator(aircraftData, random.NextDouble(), random.NextDouble()); // Call AircraftAccelerations accelerations = calculator.Calculate(aircraftState); // Assert Assert.Zero(accelerations.PitchRate.Radians); }
public void Calculate_WithAircraftStateAndSpeedHigherThanRotationSpeedAndPitch_ReturnsExpectedPitchRate(AircraftData aircraftData) { // Setup var random = new Random(21); double rotationSpeed = GetRotationSpeed(aircraftData); double pitchAngle = aircraftData.MaximumPitchAngle.Degrees - random.NextDouble(); var aircraftState = new AircraftState(Angle.FromDegrees(pitchAngle), random.NextAngle(), rotationSpeed + random.NextDouble(), random.NextDouble(), random.NextDouble()); var calculator = new ContinuedTakeOffDynamicsCalculator(aircraftData, random.Next(), airDensity, random.NextDouble()); // Call AircraftAccelerations accelerations = calculator.Calculate(aircraftState); // Assert Angle expectedPitchRate = aircraftData.PitchAngleGradient; Assert.AreEqual(expectedPitchRate, accelerations.PitchRate); }
public static void Calculate_WithAircraftStateAlways_ReturnsExpectedClimbRate() { // Setup var random = new Random(21); AircraftData aircraftData = AircraftDataTestFactory.CreateRandomAircraftData(); Angle angleOfAttack = AerodynamicsDataTestHelper.GetValidAngleOfAttack(aircraftData.AerodynamicsData); var aircraftState = new AircraftState(angleOfAttack, new Angle(), random.NextDouble(), random.NextDouble(), random.NextDouble()); var calculator = new TestTakeOffDynamicsCalculator(aircraftData, random.NextDouble(), random.NextDouble()); // Call AircraftAccelerations accelerations = calculator.Calculate(aircraftState); // Assert double expectedClimbRate = aircraftState.TrueAirspeed * Math.Sin(aircraftState.FlightPathAngle.Radians); Assert.AreEqual(expectedClimbRate, accelerations.ClimbRate, tolerance); }
public void Integrate_Always_PerformsExpectedIntegration() { // Setup var random = new Random(21); AircraftState state = CreateAircraftState(); AircraftAccelerations accelerations = CreateAircraftAccelerations(); double timeStep = random.NextDouble(); // Call AircraftState resultingState = new EulerIntegrator().Integrate(state, accelerations, timeStep); // Assert Assert.AreEqual(ExpectedIntegratedValue(state.Height, accelerations.ClimbRate, timeStep), resultingState.Height); Assert.AreEqual(ExpectedIntegratedValue(state.TrueAirspeed, accelerations.TrueAirSpeedRate, timeStep), resultingState.TrueAirspeed); Assert.AreEqual(ExpectedIntegratedValue(state.Distance, state.TrueAirspeed, timeStep), resultingState.Distance); Assert.AreEqual(ExpectedIntegratedValue(state.FlightPathAngle, accelerations.FlightPathRate, timeStep), resultingState.FlightPathAngle); Assert.AreEqual(ExpectedIntegratedValue(state.PitchAngle, accelerations.PitchRate, timeStep), resultingState.PitchAngle); }
public static void Calculate_WithAirspeedLowerThanThreshold_ReturnsExpectedZeroRate() { // Setup var random = new Random(21); AircraftData aircraftData = AircraftDataTestFactory.CreateRandomAircraftData(); Angle angleOfAttack = AerodynamicsDataTestHelper.GetValidAngleOfAttack(aircraftData.AerodynamicsData); var aircraftState = new AircraftState(angleOfAttack, new Angle(), random.NextDouble(), random.NextDouble(), random.NextDouble()); // Precondition Assert.IsTrue(aircraftState.TrueAirspeed < 1); var calculator = new TestTakeOffDynamicsCalculator(aircraftData, random.NextDouble(), random.NextDouble()); // Call AircraftAccelerations accelerations = calculator.Calculate(aircraftState); // Assert Assert.Zero(accelerations.FlightPathRate.Degrees); }