Source code for fastoad.models.performances.mission.flight.standard_flight

"""Definition of the standard flight missions."""
#  This file is part of FAST : A framework for rapid Overall Aircraft Design
#  Copyright (C) 2020  ONERA & ISAE-SUPAERO
#  FAST is free software: you can redistribute it and/or modify
#  it under the terms of the GNU General Public License as published by
#  the Free Software Foundation, either version 3 of the License, or
#  (at your option) any later version.
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#  You should have received a copy of the GNU General Public License
#  along with this program.  If not, see <https://www.gnu.org/licenses/>.

from typing import Dict, List, Union

from scipy.constants import foot, knot

from fastoad.base.flight_point import FlightPoint
from fastoad.constants import FlightPhase, EngineSetting
from fastoad.models.propulsion import IPropulsion
from .base import AbstractSimpleFlight
from ..base import IFlightPart, AbstractManualThrustFlightPhase
from ..polar import Polar
from ..segments.altitude_change import AltitudeChangeSegment
from ..segments.cruise import CruiseSegment
from ..segments.speed_change import SpeedChangeSegment


[docs]class InitialClimbPhase(AbstractManualThrustFlightPhase): """ Preset for initial climb phase. - Climbs up to 400ft at constant EAS - Accelerates to EAS = 250kt at constant altitude - Climbs up to 1500ft at constant EAS """ @property def flight_sequence(self) -> List[Union[IFlightPart, str]]: return [ AltitudeChangeSegment( target=FlightPoint(equivalent_airspeed="constant", altitude=400.0 * foot), engine_setting=EngineSetting.TAKEOFF, **self.segment_kwargs, ), SpeedChangeSegment( target=FlightPoint(equivalent_airspeed=250.0 * knot), engine_setting=EngineSetting.TAKEOFF, **self.segment_kwargs, ), AltitudeChangeSegment( target=FlightPoint(equivalent_airspeed="constant", altitude=1500.0 * foot), engine_setting=EngineSetting.TAKEOFF, **self.segment_kwargs, ), ]
[docs]class ClimbPhase(AbstractManualThrustFlightPhase): """ Preset for climb phase. - Climbs up to 10000ft at constant EAS - Accelerates to EAS = 300kt at constant altitude - Climbs up to target altitude at constant EAS """ def __init__(self, **kwargs): """ Uses keyword arguments as for :meth:`AbstractManualThrustFlightPhase` with these additional keywords: :param maximum_mach: Mach number that won't be exceeded during climb :param target_altitude: target altitude in meters, can be a float or AltitudeChangeSegment.OPTIMAL_ALTITUDE to target altitude with maximum lift/drag ratio """ if "maximum_mach" in kwargs: self.maximum_mach = kwargs.pop("maximum_mach") self.target_altitude = kwargs.pop("target_altitude") super().__init__(**kwargs) @property def flight_sequence(self) -> List[Union[IFlightPart, str]]: self.segment_kwargs["engine_setting"] = EngineSetting.CLIMB return [ AltitudeChangeSegment( target=FlightPoint(equivalent_airspeed="constant", altitude=10000.0 * foot), **self.segment_kwargs, ), SpeedChangeSegment( target=FlightPoint(equivalent_airspeed=300.0 * knot), **self.segment_kwargs, ), AltitudeChangeSegment( target=FlightPoint(equivalent_airspeed="constant", altitude=self.target_altitude), **self.segment_kwargs, maximum_mach=self.maximum_mach, ), ]
[docs]class DescentPhase(AbstractManualThrustFlightPhase): """ Preset for descent phase. - Descends down to EAS = 300kt at constant Mach - Descends down to 10000ft at constant EAS - Decelerates to EAS = 250kt - Descends down to target altitude at constant EAS """ def __init__(self, **kwargs): """ Uses keyword arguments as for :meth:`AbstractManualThrustFlightPhase` with this additional keyword: :param target_altitude: target altitude in meters """ self.target_altitude = kwargs.pop("target_altitude") super().__init__(**kwargs) @property def flight_sequence(self) -> List[Union[IFlightPart, str]]: self.segment_kwargs["engine_setting"] = EngineSetting.IDLE return [ AltitudeChangeSegment( target=FlightPoint(equivalent_airspeed=300.0 * knot, mach="constant"), **self.segment_kwargs, ), AltitudeChangeSegment( target=FlightPoint(altitude=10000.0 * foot, equivalent_airspeed="constant"), **self.segment_kwargs, ), SpeedChangeSegment( target=FlightPoint(equivalent_airspeed=250.0 * knot), **self.segment_kwargs, ), AltitudeChangeSegment( target=FlightPoint(altitude=self.target_altitude, equivalent_airspeed="constant"), **self.segment_kwargs, ), ]
[docs]class StandardFlight(AbstractSimpleFlight): """ Defines and computes a standard flight mission. The flight sequence is: - initial climb - climb - cruise at constant altitude - descent """ def __init__( self, propulsion: IPropulsion, reference_area: float, low_speed_climb_polar: Polar, high_speed_polar: Polar, cruise_mach: float, thrust_rates: Dict[FlightPhase, float], cruise_distance: float = 0.0, climb_target_altitude: float = AltitudeChangeSegment.OPTIMAL_FLIGHT_LEVEL, descent_target_altitude: float = 1500.0 * foot, time_step=None, ): """ :param propulsion: :param reference_area: :param low_speed_climb_polar: :param high_speed_polar: :param cruise_mach: :param thrust_rates: :param cruise_distance: :param climb_target_altitude: (in m) altitude where cruise will begin. If value is AltitudeChangeSegment.OPTIMAL_ALTITUDE (default), climb will stop when maximum lift/drag ratio is achieved. Cruise will go on at the same altitude. :param descent_target_altitude: (in m) altitude where descent will end in meters Default is 457.2m (1500ft) :param time_step: if provided, this time step will be applied for all segments. """ self.flight_phase_kwargs = { "propulsion": propulsion, "reference_area": reference_area, "time_step": time_step, } self.low_speed_climb_polar = low_speed_climb_polar self.high_speed_polar = high_speed_polar self.cruise_mach = cruise_mach self.thrust_rates = thrust_rates self.climb_target_altitude = climb_target_altitude self.descent_target_altitude = descent_target_altitude self.time_step = time_step kwargs = { "propulsion": propulsion, "reference_area": reference_area, "time_step": time_step, } initial_climb = InitialClimbPhase( **kwargs, polar=low_speed_climb_polar, thrust_rate=1.0, name=FlightPhase.INITIAL_CLIMB.value, ) climb = ClimbPhase( **kwargs, polar=high_speed_polar, thrust_rate=thrust_rates[FlightPhase.CLIMB], target_altitude=self.climb_target_altitude, maximum_mach=self.cruise_mach, name=FlightPhase.CLIMB.value, ) cruise = CruiseSegment( **kwargs, target=FlightPoint(), polar=high_speed_polar, engine_setting=EngineSetting.CRUISE, name=FlightPhase.CRUISE.value, ) descent = DescentPhase( **kwargs, polar=high_speed_polar, thrust_rate=thrust_rates[FlightPhase.DESCENT], target_altitude=self.descent_target_altitude, name=FlightPhase.DESCENT.value, ) super().__init__( cruise_distance, [initial_climb, climb], cruise, [descent], )