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: 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: start.true_airspeed = atm.get_true_airspeed( start.equivalent_airspeed) elif self.target.mach == self.CONSTANT_VALUE: start.true_airspeed = start.mach * atm.speed_of_sound return super().compute_from(start)
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: 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 # 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.")
def compute_from(self, start: FlightPoint) -> pd.DataFrame: start = FlightPoint(start) self.complete_flight_point(start) # needed to ensure all speed values are computed. if self.target.altitude and self.target.altitude < 0.0: # 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 self.interrupt_if_getting_further_from_target = False atm = AtmosphereSI(start.altitude) if self.target.equivalent_airspeed == "constant": start.true_airspeed = atm.get_true_airspeed(start.equivalent_airspeed) elif self.target.mach == "constant": start.true_airspeed = start.mach * atm.speed_of_sound return super().compute_from(start)
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)