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) # Mach number is capped by self.maximum_mach if flight_point.mach > self.maximum_mach: flight_point.mach = self.maximum_mach flight_point.true_airspeed = flight_point.equivalent_airspeed = None 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 )
def compute_next_flight_point( self, flight_points: List[FlightPoint], time_step: float ) -> FlightPoint: """ Computes time, altitude, speed, mass and ground distance of next flight point. :param flight_points: previous flight points :param time_step: time step for computing next point :return: the computed next flight point """ start = flight_points[0] previous = flight_points[-1] next_point = FlightPoint() next_point.mass = previous.mass - self.propulsion.get_consumed_mass(previous, time_step) next_point.time = previous.time + time_step next_point.ground_distance = ( previous.ground_distance + previous.true_airspeed * time_step * np.cos(previous.slope_angle) ) self._compute_next_altitude(next_point, previous) if self.target.true_airspeed == "constant": next_point.true_airspeed = previous.true_airspeed elif self.target.equivalent_airspeed == "constant": next_point.equivalent_airspeed = start.equivalent_airspeed elif self.target.mach == "constant": next_point.mach = start.mach else: next_point.true_airspeed = previous.true_airspeed + time_step * previous.acceleration # The naming is not done in complete_flight_point for not naming the start point next_point.name = self.name return next_point
def _get_distance_to_target(self, flight_points: List[FlightPoint]) -> bool: current = flight_points[-1] 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 "constant" for one # parameter. Let's get the real value from start point. target_speed = FlightPoint(self.target) for speed_param in ["true_airspeed", "equivalent_airspeed", "mach"]: if isinstance(target_speed.get(speed_param), str): target_speed[speed_param] = 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: target_speed.true_airspeed = atm.get_true_airspeed(target_speed.equivalent_airspeed) if target_speed.true_airspeed: target_speed.mach = target_speed.true_airspeed / atm.speed_of_sound # Mach number has to be capped by self.maximum_mach target_mach = min(target_speed.mach, self.maximum_mach) # Now we compute optimal altitude optimal_altitude = self._get_optimal_altitude( current.mass, target_mach, current.altitude ) if self.target.CL == self.OPTIMAL_ALTITUDE: self.target.altitude = optimal_altitude else: # self.target.CL == self.OPTIMAL_FLIGHT_LEVEL: flight_level = 1000 * foot self.target.altitude = flight_level * np.floor(optimal_altitude / flight_level) if self.target.altitude: return self.target.altitude - current.altitude elif self.target.true_airspeed: return self.target.true_airspeed - current.true_airspeed elif self.target.equivalent_airspeed: return self.target.equivalent_airspeed - current.equivalent_airspeed elif self.target.mach: return self.target.mach - current.mach
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: flight_point.true_airspeed = flight_point.mach * atm.speed_of_sound elif flight_point.equivalent_airspeed is not None: flight_point.true_airspeed = atm.get_true_airspeed( flight_point.equivalent_airspeed) else: raise FastFlightSegmentIncompleteFlightPoint( "Flight point should be defined for true_airspeed, " "equivalent_airspeed, or mach.") if flight_point.mach is None: flight_point.mach = flight_point.true_airspeed / atm.speed_of_sound if flight_point.equivalent_airspeed is None: flight_point.equivalent_airspeed = atm.get_equivalent_airspeed( flight_point.true_airspeed)