コード例 #1
0
        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);
        }
コード例 #2
0
            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);
            }
コード例 #3
0
            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);
            }
コード例 #4
0
            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);
            }
コード例 #5
0
        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)));
        }
コード例 #6
0
            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);
            }
コード例 #7
0
            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);
            }
コード例 #8
0
        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);
        }
コード例 #9
0
            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);
            }
コード例 #10
0
        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);
        }
コード例 #11
0
        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);
        }
コード例 #12
0
            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);
            }