Exemple #1
0
    def compute_from(self, start: FlightPoint) -> pd.DataFrame:
        self.complete_flight_point(start)  # needed to ensure all speed values are computed.

        if self.target.altitude is not None:
            if isinstance(self.target.altitude, str):
                # Target altitude will be modified along the process, so we keep track
                # of the original order in target CL, that is not used otherwise.
                self.target.CL = self.target.altitude  # pylint: disable=invalid-name
                # let's put a numerical, negative value in self.target.altitude to
                # ensure there will be no problem in self._get_distance_to_target()
                self.target.altitude = -1000.0
                self.interrupt_if_getting_further_from_target = False
            else:
                # Target altitude is fixed, back to original settings (in case
                # this instance is used more than once)
                self.target.CL = None
                self.interrupt_if_getting_further_from_target = True

        atm = AtmosphereSI(start.altitude)
        if self.target.equivalent_airspeed == self.CONSTANT_VALUE:
            atm.equivalent_airspeed = start.equivalent_airspeed
            start.true_airspeed = atm.true_airspeed
        elif self.target.mach == self.CONSTANT_VALUE:
            atm.mach = start.mach
            start.true_airspeed = atm.true_airspeed

        return super().compute_from(start)
Exemple #2
0
    def _get_distance_to_target(self, flight_points: List[FlightPoint]) -> float:
        current = flight_points[-1]

        # Max flight level is first priority
        max_authorized_altitude = self.maximum_flight_level * 100.0 * foot
        if current.altitude >= max_authorized_altitude:
            return max_authorized_altitude - current.altitude

        if self.target.CL:
            # Optimal altitude is based on a target Mach number, though target speed
            # may be specified as TAS or EAS. If so, Mach number has to be computed
            # for target altitude and speed.

            # First, as target speed is expected to be set to self.CONSTANT_VALUE for one
            # parameter. Let's get the real value from start point.
            target_speed = copy(self.target)
            for speed_param in ["true_airspeed", "equivalent_airspeed", "mach"]:
                if isinstance(getattr(target_speed, speed_param), str):
                    setattr(target_speed, speed_param, getattr(flight_points[0], speed_param))

            # Now, let's compute target Mach number
            atm = AtmosphereSI(max(self.target.altitude, current.altitude))
            if target_speed.equivalent_airspeed:
                atm.equivalent_airspeed = target_speed.equivalent_airspeed
                target_speed.true_airspeed = atm.true_airspeed
            if target_speed.true_airspeed:
                atm.true_airspeed = target_speed.true_airspeed
                target_speed.mach = atm.mach

            # Now we compute optimal altitude
            optimal_altitude = self._get_optimal_altitude(
                current.mass, target_speed.mach, current.altitude
            )
            if self.target.CL == self.OPTIMAL_ALTITUDE:
                self.target.altitude = optimal_altitude
            else:  # self.target.CL == self.OPTIMAL_FLIGHT_LEVEL:
                self.target.altitude = get_closest_flight_level(
                    optimal_altitude, up_direction=False
                )

        if self.target.altitude is not None:
            return self.target.altitude - current.altitude
        if self.target.true_airspeed and self.target.true_airspeed != self.CONSTANT_VALUE:
            return self.target.true_airspeed - current.true_airspeed
        if (
            self.target.equivalent_airspeed
            and self.target.equivalent_airspeed != self.CONSTANT_VALUE
        ):
            return self.target.equivalent_airspeed - current.equivalent_airspeed
        if self.target.mach is not None and self.target.mach != self.CONSTANT_VALUE:
            return self.target.mach - current.mach

        raise FastFlightSegmentIncompleteFlightPoint(
            "No valid target definition for altitude change."
        )
Exemple #3
0
 def distance_to_optimum(altitude):
     atm = AtmosphereSI(altitude)
     true_airspeed = mach * atm.speed_of_sound
     optimal_air_density = (2.0 * mass * g /
                            (self.reference_area * true_airspeed**2 *
                             self.polar.optimal_cl))
     return (atm.density - optimal_air_density) * 100.0
Exemple #4
0
    def complete_flight_point(self, flight_point: FlightPoint):
        """
        Computes data for provided flight point.

        Assumes that it is already defined for time, altitude, mass,
        ground distance and speed (TAS, EAS, or Mach).

        :param flight_point: the flight point that will be completed in-place
        """
        flight_point.engine_setting = self.engine_setting

        self._complete_speed_values(flight_point)

        atm = AtmosphereSI(flight_point.altitude)
        reference_force = 0.5 * atm.density * flight_point.true_airspeed**2 * self.reference_area

        if self.polar:
            flight_point.CL = flight_point.mass * g / reference_force
            flight_point.CD = self.polar.cd(flight_point.CL)
        else:
            flight_point.CL = flight_point.CD = 0.0
        flight_point.drag = flight_point.CD * reference_force

        self._compute_propulsion(flight_point)
        flight_point.slope_angle, flight_point.acceleration = self._get_gamma_and_acceleration(
            flight_point.mass, flight_point.drag, flight_point.thrust)
Exemple #5
0
    def compute(self,
                inputs,
                outputs,
                discrete_inputs=None,
                discrete_outputs=None):
        if self.options["low_speed_aero"]:
            mach = inputs["data:aerodynamics:aircraft:takeoff:mach"]
            altitude = 0.0
        else:
            mach = inputs["data:TLAR:cruise_mach"]
            altitude = inputs["data:mission:sizing:main_route:cruise:altitude"]

        atm = AtmosphereSI(altitude)
        atm.mach = mach
        reynolds = atm.unitary_reynolds

        if self.options["low_speed_aero"]:
            outputs["data:aerodynamics:wing:low_speed:reynolds"] = reynolds
        else:
            outputs["data:aerodynamics:wing:cruise:reynolds"] = reynolds
Exemple #6
0
    def _complete_speed_values(flight_point: FlightPoint):
        """
        Computes consistent values between TAS, EAS and Mach, assuming one of them is defined.
        """
        atm = AtmosphereSI(flight_point.altitude)

        if flight_point.true_airspeed is None:
            if flight_point.mach is not None:
                atm.mach = flight_point.mach
            elif flight_point.equivalent_airspeed is not None:
                atm.equivalent_airspeed = flight_point.equivalent_airspeed
            else:
                raise FastFlightSegmentIncompleteFlightPoint(
                    "Flight point should be defined for true_airspeed, "
                    "equivalent_airspeed, or mach.")
            flight_point.true_airspeed = atm.true_airspeed
        else:
            atm.true_airspeed = flight_point.true_airspeed

        flight_point.mach = atm.mach
        flight_point.equivalent_airspeed = atm.equivalent_airspeed
Exemple #7
0
#  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 stdatm import AtmosphereSI

RUBBER_ENGINE_DESCRIPTION = """
Parametric engine model as OpenMDAO component.

Implementation of E. Roux models for fuel consumption of low bypass ratio engines
For more information, see RubberEngine class in FAST-OAD developer documentation.
"""

# Atmosphere at limits of troposhere
ATM_SEA_LEVEL = AtmosphereSI(0)
ATM_TROPOPAUSE = AtmosphereSI(11000)

# Constants for computation of maximum thrust ---------------------------------
# (see E. Roux model definition in roux:2005)
A_MS = -2.74e-4
A_FM = 2.67e-4
B_MS = 1.91e-2
B_FM = -2.35e-2
C_MS = 1.21e-3
C_FM = -1.32e-3
D_MS = -8.48e-4
D_FM = 3.14e-4
E_MS = 8.96e-1
E_FM = 5.22e-1