def __init__(self, ac, eng=None): """Intitialize the generator. Args: ac (string): Aircraft type. eng (string): Engine type. Leave empty for default engine type in OpenAP. Returns: dict: flight trajectory """ super(Generator, self).__init__() self.ac = ac self.acdict = prop.aircraft(self.ac) if eng is None: self.eng = self.acdict['engine']['default'] else: self.eng = eng self.engdict = prop.engine(self.eng) self.wrap = WRAP(self.ac) # self.thrust = Thrust(self.ac, self.eng) # self.drag = Drag(self.ac) # self.fuelflow = Thrust(self.ac, self.eng) # for noise generation self.sigma_v = 0 self.sigma_vs = 0 self.sigma_h = 0 self.sigma_s = 0
def __init__(self, icao_type: str, callsign: str) -> None: self.performance = Performance(icao_type) self.autoThrust = Autothrust() self.autoPilot = Autopilot() self.latitude = 0.0 self.longitude = 0.0 self.ground_level = 0.0 self.callsign = callsign self.takeoff = False self.wrap = WRAP(ac=icao_type) self.target_alt = 6_000 * aero.ft self.id = 0
f"{self.drag},{self.thrust},{self.t_d},{self.pitch},"\ f"{self.fpa},{self.aoa},{self.Q},{self.acc_x},{self.acc_y},"\ f"{self.distance_x},{self.d_x},{self.d_y},{self.phase},"\ f"{self.cd},{self.drag0},{self.gear},{self.flaps},{self.cl},"\ f"{self.lift},{self.weight},{self.l_w},{self.thrust_lever},"\ f"{self.altitude / aero.ft},{self.g},{self.pitch_target}\n" def __get_header(self): return "Mass,Altitude,Pressure,Density,Temperature,Cas,Tas,Vy,VS,"\ "Drag,Thrust,T-D,Pitch,FPA,AOA,Q,AccelerationX,AccelerationY,"\ "DistanceX,Dx,Dy,Phase,Cd,Cd0,Gear,Flaps,Cl,Lift,Weight,L-W,"\ "Thrust Limit,Altitude FT,Gravity,Target Pitch\n" if __name__ == "__main__": from openap import WRAP a319 = Performance("A319") a319_wrp = WRAP(ac="A319") a319.cas = a319_wrp.takeoff_speed()["default"] a319.tas = aero.cas2tas(a319.cas, a319.altitude) a319.pitch = 15.0 a319.v_y = 2000 * aero.fpm a319.gear = True a319.flaps = 2 print(a319.v_y) print("Starting") for i in range(10): a319.run() print("Finished")
class Aircraft: """Represent an aircraft""" def __init__(self, icao_type: str, callsign: str) -> None: self.performance = Performance(icao_type) self.autoThrust = Autothrust() self.autoPilot = Autopilot() self.latitude = 0.0 self.longitude = 0.0 self.ground_level = 0.0 self.callsign = callsign self.takeoff = False self.wrap = WRAP(ac=icao_type) self.target_alt = 6_000 * aero.ft self.id = 0 def get_ap_vert_mode(self) -> dict: return { "Altitude Aquire": Autopilot.alt_aquire, "Altitude Hold": Autopilot.alt_hold, "Speed Hold": Autopilot.speed_hold, "Mach Hold": Autopilot.mach_hold, "Vert Speed Hold": Autopilot.vs_hold } def set_ap_vert_mode(self, mode: int, target: float, target_altitude: float) -> bool: if mode == Autopilot.alt_aquire: self.autoPilot.AltitudeAquire(target_altitude) elif mode == Autopilot.alt_hold: self.autoPilot.AltitudeHold(target_altitude) elif mode == Autopilot.speed_hold: self.autoPilot.SpeedHold(target, target_altitude) elif mode == Autopilot.mach_hold: self.autoPilot.MachHold(target, target_altitude) elif mode == Autopilot.vs_hold: self.autoPilot.VerticalSpeedHold(target, target_altitude) else: return False return True def run(self) -> int: self.performance.run() if self.takeoff: if self.performance.pitch < self.target_to_pitch and\ self.cas() >= self.wrap.takeoff_speed()["default"]: self.performance.pitch += 3.0 * self.performance.dt if self.performance.pitch >= self.target_to_pitch and\ self.cas() >= self.wrap.takeoff_speed()["default"]: self.takeoff = False self.autoPilot.SpeedHold(self.cas(), self.target_alt) if self.autoPilot.active_mode is not None: self.performance.pitch = self.autoPilot.run(self.cas(), self.vertical_speed(), self.altitude(), self.pitch(), self.mach()) if self.autoThrust.active_mode is not None: self.performance.thrust_lever = self.autoThrust.run(self.cas()) @property def pitch(self) -> float: return self.performance.pitch @property def altitude(self) -> float: return self.performance.altitude @property def tas(self) -> float: return self.performance.tas @property def cas(self) -> float: return self.performance.cas @property def mach(self) -> float: return aero.tas2mach(self.tas, self.altitude) @property def vertical_speed(self) -> float: return self.performance.v_y def angle_of_attack(self) -> float: return self.performance.aoa @property def mass(self) -> float: return self.performance.mass @mass.setter def mass(self, value: float) -> None: self.performance.mass = value def create(self, position: tuple, mass: float, ground_level: float = 0.0, altitude: float = 0.0, cas: float = 0.0, takeoff: bool = False, target_alt: float = None) -> bool: self.performance.mass = mass self.latitude, self.longitude = position self.ground_level = ground_level self.performance.altitude = altitude self.performance.cas = cas self.performance.tas = aero.cas2tas(cas, self.performance.altitude) self.mach = aero.cas2mach(self.performance.cas, self.performance.altitude) if target_alt is not None: self.target_alt = target_alt elif not takeoff and altitude > 0 and altitude > ground_level: self.target_alt = altitude elif not takeoff: takeoff = True if not takeoff: self.autoPilot.AltitudeHold(self.altitude) def set_target_alt(self, altitude: float) -> None: self.target_alt = altitude
class Generator(object): """Generate trajectory using WRAP model.""" def __init__(self, ac, eng=None): """Intitialize the generator. Args: ac (string): Aircraft type. eng (string): Engine type. Leave empty for default engine type in OpenAP. Returns: dict: flight trajectory """ super(Generator, self).__init__() self.ac = ac self.acdict = prop.aircraft(self.ac) if eng is None: self.eng = self.acdict['engine']['default'] else: self.eng = eng self.engdict = prop.engine(self.eng) self.wrap = WRAP(self.ac) # self.thrust = Thrust(self.ac, self.eng) # self.drag = Drag(self.ac) # self.fuelflow = Thrust(self.ac, self.eng) # for noise generation self.sigma_v = 0 self.sigma_vs = 0 self.sigma_h = 0 self.sigma_s = 0 def enable_noise(self): """Adding noise to the generated trajectory. The noise model is based on ADS-B Version 1&2, NACv=3 and NACp=10 """ self.sigma_v = 0.5 self.sigma_vs = 0.75 self.sigma_h = 7.5 self.sigma_s = 5 def climb(self, **kwargs): """Generate climb trajectory based on WRAP model. Args: **dt (int): Time step in seconds. **cas_const_cl (int): Constaant CAS for climb (kt). **mach_const_cl (float): Constaant Mach for climb (-). **h_cr (int): Target cruise altitude (km). **random (bool): Generate trajectory with random paramerters. Returns: dict: Flight trajectory. """ dt = kwargs.get('dt', 1) random = kwargs.get('random', False) a_tof = self.wrap.takeoff_acceleration()['default'] v_tof = self.wrap.takeoff_speed()['default'] if random: cas_const = kwargs.get( 'cas_const_cl', np.random.uniform(self.wrap.climb_const_vcas()['minimum'], self.wrap.climb_const_vcas()['maximum']) / aero.kts) mach_const = kwargs.get( 'mach_const_cl', np.random.uniform(self.wrap.climb_const_mach()['minimum'], self.wrap.climb_const_mach()['maximum'])) h_cr = kwargs.get( 'h_cr', np.random.uniform(self.wrap.cruise_alt()['minimum'], self.wrap.cruise_alt()['maximum']) * 1000) vs_pre_constcas = np.random.uniform( self.wrap.climb_vs_pre_concas()['minimum'], self.wrap.climb_vs_pre_concas()['maximum']) vs_constcas = np.random.uniform( self.wrap.climb_vs_concas()['minimum'], self.wrap.climb_vs_concas()['maximum']) vs_constmach = np.random.uniform( self.wrap.climb_vs_conmach()['minimum'], self.wrap.climb_vs_conmach()['maximum']) else: cas_const = kwargs.get( 'cas_const_cl', self.wrap.climb_const_vcas()['default'] / aero.kts) mach_const = kwargs.get('mach_const_cl', self.wrap.climb_const_mach()['default']) h_cr = kwargs.get('h_cr', self.wrap.cruise_alt()['default'] * 1000) vs_pre_constcas = self.wrap.climb_vs_pre_concas()['default'] vs_constcas = self.wrap.climb_vs_concas()['default'] vs_constmach = self.wrap.climb_vs_conmach()['default'] vcas_const = cas_const * aero.kts h_cr = np.round(h_cr / aero.ft, -2) * aero.ft # round cruise altitude to flight level vs_ic = self.wrap.initclimb_vs()['default'] h_const_cas = self.wrap.climb_cross_alt_concas()['default'] * 1000 h_const_mach = aero.crossover_alt(vcas_const, mach_const) if h_const_mach > h_cr: print( 'Warining: const mach crossover altitude higher than cruise altitude, altitude clipped.' ) data = [] # intitial conditions t = 0 tcr = 0 h = 0 s = 0 v = 0 vs = 0 a = 0.5 # standard acceleration m/s^2 seg = None while True: data.append([t, h, s, v, vs, seg]) t = t + dt s = s + v * dt h = h + vs * dt if v < v_tof: v = v + a_tof * dt vs = 0 seg = 'TO' elif h < 1500 * aero.ft: v = v + a * dt vs = vs_ic seg = 'IC' elif h < h_const_cas: v = v + a * dt if aero.tas2cas(v, h) >= vcas_const: v = aero.cas2tas(vcas_const, h) vs = vs_pre_constcas seg = 'PRE-CAS' elif h < h_const_mach: v = aero.cas2tas(vcas_const, h) vs = vs_constcas seg = 'CAS' elif h < h_cr: v = aero.mach2tas(mach_const, h) vs = vs_constmach seg = 'MACH' else: v = aero.mach2tas(mach_const, h) vs = 0 seg = 'CR' if tcr == 0: tcr = t if t - tcr > 60: break data = np.array(data) ndata = len(data) datadict = { 't': data[:, 0], 'h': data[:, 1] + np.random.normal(0, self.sigma_h, ndata), 's': data[:, 2] + np.random.normal(0, self.sigma_s, ndata), 'v': data[:, 3] + np.random.normal(0, self.sigma_v, ndata), 'vs': data[:, 4] + np.random.normal(0, self.sigma_vs, ndata), 'seg': data[:, 5], 'cas_const_cl': cas_const, 'mach_const_cl': mach_const, 'h_cr': h_cr } return datadict def descent(self, **kwargs): """Generate descent trajectory based on WRAP model. Args: **dt (int): Time step in seconds. **cas_const_de (int): Constaant CAS for climb (kt). **mach_const_de (float): Constaant Mach for climb (-). **h_cr (int): Target cruise altitude (km). **random (bool): Generate trajectory with random paramerters. Returns: dict: Flight trajectory. """ dt = kwargs.get('dt', 1) random = kwargs.get('random', False) a_lnd = self.wrap.landing_acceleration()['default'] v_app = self.wrap.finalapp_vcas()['default'] if random: h_cr = kwargs.get( 'h_cr', np.random.uniform(self.wrap.cruise_alt()['minimum'], self.wrap.cruise_alt()['maximum']) * 1000) mach_const = kwargs.get( 'mach_const_de', np.random.uniform(self.wrap.descent_const_mach()['minimum'], self.wrap.descent_const_mach()['maximum'])) cas_const = kwargs.get( 'cas_const_de', np.random.uniform(self.wrap.descent_const_vcas()['minimum'], self.wrap.descent_const_vcas()['maximum']) / aero.kts) vs_constmach = np.random.uniform( self.wrap.descent_vs_conmach()['minimum'], self.wrap.descent_vs_conmach()['maximum']) vs_constcas = np.random.uniform( self.wrap.descent_vs_concas()['minimum'], self.wrap.descent_vs_concas()['maximum']) vs_post_constcas = np.random.uniform( self.wrap.descent_vs_post_concas()['minimum'], self.wrap.descent_vs_post_concas()['maximum']) else: mach_const = kwargs.get('mach_const_de', self.wrap.descent_const_mach()['default']) cas_const = kwargs.get( 'cas_const_de', self.wrap.descent_const_vcas()['default'] / aero.kts) h_cr = kwargs.get('h_cr', self.wrap.cruise_alt()['default'] * 1000) vs_constmach = self.wrap.descent_vs_conmach()['default'] vs_constcas = self.wrap.descent_vs_concas()['default'] vs_post_constcas = self.wrap.descent_vs_post_concas()['default'] vcas_const = cas_const * aero.kts h_cr = np.round(h_cr / aero.ft, -2) * aero.ft # round cruise altitude to flight level vs_fa = self.wrap.finalapp_vs()['default'] h_const_cas = self.wrap.descent_cross_alt_concas()['default'] * 1000 h_const_mach = aero.crossover_alt(vcas_const, mach_const) if h_const_mach > h_cr: print( 'Warining: const mach crossover altitude higher than cruise altitude, altitude clipped.' ) data = [] # intitial conditions a = -0.5 t = 0 s = 0 h = h_cr v = aero.mach2tas(mach_const, h_cr) vs = 0 seg = None while True: data.append([t, h, s, v, vs, seg]) t = t + dt s = s + v * dt h = h + vs * dt if t < 60: v = aero.mach2tas(mach_const, h) vs = 0 seg = 'CR' elif h > h_const_mach: v = aero.mach2tas(mach_const, h) vs = vs_constmach seg = 'MACH' elif h > h_const_cas: v = aero.cas2tas(vcas_const, h) vs = vs_constcas seg = 'CAS' elif h > 1000 * aero.ft: v = v + a * dt if aero.tas2cas(v, h) < v_app: v = aero.cas2tas(v_app, h) vs = vs_post_constcas seg = 'POST-CAS' elif h > 0: v = v_app vs = vs_fa seg = 'FA' else: h = 0 vs = 0 v = v + a_lnd * dt seg = 'LD' if v <= 0: break data = np.array(data) ndata = len(data) datadict = { 't': data[:, 0], 'h': data[:, 1] + np.random.normal(0, self.sigma_h, ndata), 's': data[:, 2] + np.random.normal(0, self.sigma_s, ndata), 'v': data[:, 3] + np.random.normal(0, self.sigma_v, ndata), 'vs': data[:, 4] + np.random.normal(0, self.sigma_vs, ndata), 'seg': data[:, 5], 'cas_const_de': cas_const, 'vcas_const_de': vcas_const, 'mach_const_de': mach_const, 'h_cr': h_cr } return datadict def cruise(self, **kwargs): """Generate descent trajectory based on WRAP model. Args: **dt (int): Time step in seconds. **range_cr (int): Cruise range (km). **h_cr (int): Cruise altitude (km). **mach_cr (float): Cruise Mach number (-). **random (bool): Generate trajectory with random paramerters. Returns: dict: flight trajectory """ dt = kwargs.get('dt', 1) random = kwargs.get('random', False) if random: range = kwargs.get( 'range_cr', np.random.uniform(self.wrap.cruise_range()['minimum'], self.wrap.cruise_range()['maximum']) * 1000) h_cr = kwargs.get( 'h_cr', np.random.uniform(self.wrap.cruise_alt()['minimum'], self.wrap.cruise_alt()['maximum']) * 1000) mach_cr = kwargs.get( 'mach_cr', np.random.uniform(self.wrap.cruise_mach()['minimum'], self.wrap.cruise_mach()['maximum'])) else: range = kwargs.get('range_cr', self.wrap.cruise_range()['default'] * 1000) mach_cr = kwargs.get('mach_cr', self.wrap.cruise_mach()['default']) h_cr = kwargs.get('h_cr', self.wrap.cruise_alt()['default'] * 1000) h_cr = np.round(h_cr / aero.ft, -3) * aero.ft # round cruise altitude to flight level data = [] # intitial conditions t = 0 s = 0 v = aero.mach2tas(mach_cr, h_cr) vs = 0 while True: data.append([t, h_cr, s, v, vs]) t = t + dt s = s + v * dt if s > range: break data = np.array(data) ndata = len(data) datadict = { 't': data[:, 0], 'h': data[:, 1] + np.random.normal(0, self.sigma_h, ndata), 's': data[:, 2] + np.random.normal(0, self.sigma_s, ndata), 'v': data[:, 3] + np.random.normal(0, self.sigma_v, ndata), 'vs': data[:, 4] + np.random.normal(0, self.sigma_vs, ndata), 'h_cr': h_cr, 'mach_cr': mach_cr, } return datadict def complete(self, **kwargs): """Generate a complete trajectory based on WRAP model. Args: **dt (int): Time step in seconds. **cas_const_cl (int): Constaant CAS for climb (kt). **mach_const_cl (float): Constaant Mach for climb (-). **cas_const_de (int): Constaant CAS for climb (kt). **mach_const_de (float): Constaant Mach for climb (-). **range_cr (int): Cruise range (km). **h_cr (int): Target cruise altitude (km). **mach_cr (float): Cruise Mach number (-). **random (bool): Generate trajectory with random paramerters. Returns: dict: Flight trajectory. """ data_cr = self.cruise(**kwargs) data_cl = self.climb(h_cr=data_cr['h_cr'], mach_cr=data_cr['mach_cr'], **kwargs) data_de = self.descent(h_cr=data_cr['h_cr'], mach_cr=data_cr['mach_cr'], **kwargs) data = { 't': np.concatenate([ data_cl['t'], data_cl['t'][-1] + data_cr['t'], data_cl['t'][-1] + data_cr['t'][-1] + data_de['t'] ]), 'h': np.concatenate([data_cl['h'], data_cr['h'], data_de['h']]), 's': np.concatenate([ data_cl['s'], data_cl['s'][-1] + data_cr['s'], data_cl['s'][-1] + data_cr['s'][-1] + data_de['s'] ]), 'v': np.concatenate([data_cl['v'], data_cr['v'], data_de['v']]), 'vs': np.concatenate([data_cl['vs'], data_cr['vs'], data_de['vs']]), } return data
class Generator(object): """Generate trajectory using WRAP model.""" def __init__(self, ac, eng=None): """Intitialize the generator. Args: ac (string): Aircraft type. eng (string): Engine type. Leave empty for default engine type in OpenAP. Returns: dict: flight trajectory """ super(Generator, self).__init__() self.ac = ac self.acdict = prop.aircraft(self.ac) if eng is None: self.eng = self.acdict["engine"]["default"] else: self.eng = eng self.engdict = prop.engine(self.eng) self.wrap = WRAP(self.ac) # self.thrust = Thrust(self.ac, self.eng) # self.drag = Drag(self.ac) # self.fuelflow = Thrust(self.ac, self.eng) # for noise generation self.sigma_v = 0 self.sigma_vs = 0 self.sigma_h = 0 self.sigma_s = 0 def enable_noise(self): """Adding noise to the generated trajectory. The noise model is based on ADS-B Version 1&2, NACv=3 and NACp=10 """ self.sigma_v = 0.5 self.sigma_vs = 0.75 self.sigma_h = 7.5 self.sigma_s = 5 def climb(self, **kwargs): """Generate climb trajectory based on WRAP model. Args: **dt (int): Time step in seconds. **cas_const_cl (int): Constaant CAS for climb (kt). **mach_const_cl (float): Constaant Mach for climb (-). **alt_cr (int): Target cruise altitude (ft). **random (bool): Generate trajectory with random paramerters. Returns: dict: Flight trajectory. """ dt = kwargs.get("dt", 1) random = kwargs.get("random", False) a_tof = self.wrap.takeoff_acceleration()["default"] v_tof = self.wrap.takeoff_speed()["default"] if random: cas_const = kwargs.get( "cas_const_cl", np.random.uniform( self.wrap.climb_const_vcas()["minimum"], self.wrap.climb_const_vcas()["maximum"], ) / aero.kts, ) mach_const = kwargs.get( "mach_const_cl", np.random.uniform( self.wrap.climb_const_mach()["minimum"], self.wrap.climb_const_mach()["maximum"], ), ) alt_cr = kwargs.get( "alt_cr", np.random.uniform(self.wrap.cruise_alt()["minimum"], self.wrap.cruise_alt()["maximum"]) * 1000 / aero.ft, ) vs_pre_constcas = np.random.uniform( self.wrap.climb_vs_pre_concas()["minimum"], self.wrap.climb_vs_pre_concas()["maximum"], ) vs_constcas = np.random.uniform( self.wrap.climb_vs_concas()["minimum"], self.wrap.climb_vs_concas()["maximum"], ) vs_constmach = np.random.uniform( self.wrap.climb_vs_conmach()["minimum"], self.wrap.climb_vs_conmach()["maximum"], ) else: cas_const = kwargs.get( "cas_const_cl", self.wrap.climb_const_vcas()["default"] / aero.kts) cas_const = max( cas_const, v_tof / aero.kts) # cas can not be smaller then takeoff speed mach_const = kwargs.get("mach_const_cl", self.wrap.climb_const_mach()["default"]) alt_cr = kwargs.get( "alt_cr", self.wrap.cruise_alt()["default"] * 1000 / aero.ft) vs_pre_constcas = self.wrap.climb_vs_pre_concas()["default"] vs_constcas = self.wrap.climb_vs_concas()["default"] vs_constmach = self.wrap.climb_vs_conmach()["default"] vcas_const = cas_const * aero.kts alt_cr = np.round(alt_cr, -2) # round cruise altitude to flight level h_cr = alt_cr * aero.ft # meters vs_ic = self.wrap.initclimb_vs()["default"] h_const_cas = self.wrap.climb_cross_alt_concas()["default"] * 1000 h_const_mach = aero.crossover_alt(vcas_const, mach_const) if h_const_mach > h_cr: print( "Warining: const mach crossover altitude higher than cruise altitude, altitude clipped." ) data = [] # intitial conditions t = 0 tcr = 0 h = 0 s = 0 v = 0 vs = 0 a = 0.5 # standard acceleration m/s^2 seg = None while True: data.append([t, h, s, v, vs, seg]) t = t + dt s = s + v * dt h = h + vs * dt if v < v_tof: v = v + a_tof * dt vs = 0 seg = "TO" elif h < 1500 * aero.ft: v = v + a * dt if aero.tas2cas(v, h) >= vcas_const: v = aero.cas2tas(vcas_const, h) vs = vs_ic seg = "IC" elif h < h_const_cas: v = v + a * dt if aero.tas2cas(v, h) >= vcas_const: v = aero.cas2tas(vcas_const, h) vs = vs_pre_constcas seg = "PRE-CAS" elif h < h_const_mach: v = aero.cas2tas(vcas_const, h) vs = vs_constcas seg = "CAS" elif h < h_cr: v = aero.mach2tas(mach_const, h) vs = vs_constmach seg = "MACH" else: v = aero.mach2tas(mach_const, h) vs = 0 seg = "CR" if tcr == 0: tcr = t if t - tcr > 60: break data = np.array(data) ndata = len(data) datadict = { "t": data[:, 0], # t, seconds "h": data[:, 1] + np.random.normal(0, self.sigma_h, ndata), # h, m "s": data[:, 2] + np.random.normal(0, self.sigma_s, ndata), # s, m "v": data[:, 3] + np.random.normal(0, self.sigma_v, ndata), # v, m/s "vs": data[:, 4] + np.random.normal(0, self.sigma_vs, ndata), # VS, m/s "seg": data[:, 5], "cas_const_cl": cas_const, "mach_const_cl": mach_const, "alt_cr": alt_cr, # alt_cr, ft } return datadict def descent(self, **kwargs): """Generate descent trajectory based on WRAP model. Args: **dt (int): Time step in seconds. **cas_const_de (int): Constaant CAS for climb (kt). **mach_const_de (float): Constaant Mach for climb (-). **alt_cr (int): Target cruise altitude (ft). **random (bool): Generate trajectory with random paramerters. Returns: dict: Flight trajectory. """ dt = kwargs.get("dt", 1) random = kwargs.get("random", False) a_lnd = self.wrap.landing_acceleration()["default"] v_app = self.wrap.finalapp_vcas()["default"] if random: alt_cr = kwargs.get( "alt_cr", np.random.uniform(self.wrap.cruise_alt()["minimum"], self.wrap.cruise_alt()["maximum"]) * 1000 / aero.ft, ) mach_const = kwargs.get( "mach_const_de", np.random.uniform( self.wrap.descent_const_mach()["minimum"], self.wrap.descent_const_mach()["maximum"], ), ) cas_const = kwargs.get( "cas_const_de", np.random.uniform( self.wrap.descent_const_vcas()["minimum"], self.wrap.descent_const_vcas()["maximum"], ) / aero.kts, ) vs_constmach = np.random.uniform( self.wrap.descent_vs_conmach()["minimum"], self.wrap.descent_vs_conmach()["maximum"], ) vs_constcas = np.random.uniform( self.wrap.descent_vs_concas()["minimum"], self.wrap.descent_vs_concas()["maximum"], ) vs_post_constcas = np.random.uniform( self.wrap.descent_vs_post_concas()["minimum"], self.wrap.descent_vs_post_concas()["maximum"], ) else: mach_const = kwargs.get("mach_const_de", self.wrap.descent_const_mach()["default"]) cas_const = kwargs.get( "cas_const_de", self.wrap.descent_const_vcas()["default"] / aero.kts) alt_cr = kwargs.get( "alt_cr", self.wrap.cruise_alt()["default"] * 1000 / aero.ft) vs_constmach = self.wrap.descent_vs_conmach()["default"] vs_constcas = self.wrap.descent_vs_concas()["default"] vs_post_constcas = self.wrap.descent_vs_post_concas()["default"] vcas_const = cas_const * aero.kts alt_cr = np.round(alt_cr, -2) # round cruise altitude to flight level h_cr = alt_cr * aero.ft vs_fa = self.wrap.finalapp_vs()["default"] h_const_cas = self.wrap.descent_cross_alt_concas()["default"] * 1000 h_const_mach = aero.crossover_alt(vcas_const, mach_const) if h_const_mach > h_cr: print( "Warining: const mach crossover altitude higher than cruise altitude, altitude clipped." ) data = [] # intitial conditions a = -0.5 t = 0 s = 0 h = h_cr v = aero.mach2tas(mach_const, h_cr) vs = 0 seg = None while True: data.append([t, h, s, v, vs, seg]) t = t + dt s = s + v * dt h = h + vs * dt if t < 60: v = aero.mach2tas(mach_const, h) vs = 0 seg = "CR" elif h > h_const_mach: v = aero.mach2tas(mach_const, h) vs = vs_constmach seg = "MACH" elif h > h_const_cas: v = aero.cas2tas(vcas_const, h) vs = vs_constcas seg = "CAS" elif h > 1000 * aero.ft: v = v + a * dt if aero.tas2cas(v, h) < v_app: v = aero.cas2tas(v_app, h) vs = vs_post_constcas seg = "POST-CAS" elif h > 0: v = v_app vs = vs_fa seg = "FA" else: h = 0 vs = 0 v = v + a_lnd * dt seg = "LD" if v <= 0: break data = np.array(data) ndata = len(data) datadict = { "t": data[:, 0], "h": data[:, 1] + np.random.normal(0, self.sigma_h, ndata), "s": data[:, 2] + np.random.normal(0, self.sigma_s, ndata), "v": data[:, 3] + np.random.normal(0, self.sigma_v, ndata), "vs": data[:, 4] + np.random.normal(0, self.sigma_vs, ndata), "seg": data[:, 5], "cas_const_de": cas_const, "vcas_const_de": vcas_const, "mach_const_de": mach_const, "alt_cr": alt_cr, } return datadict def cruise(self, **kwargs): """Generate descent trajectory based on WRAP model. Args: **dt (int): Time step in seconds. **range_cr (int): Cruise range (km). **alt_cr (int): Cruise altitude (ft). **mach_cr (float): Cruise Mach number (-). **random (bool): Generate trajectory with random paramerters. Returns: dict: flight trajectory """ dt = kwargs.get("dt", 1) random = kwargs.get("random", False) if random: range = kwargs.get( "range_cr", np.random.uniform( self.wrap.cruise_range()["minimum"], self.wrap.cruise_range()["maximum"], ) * 1000, ) alt_cr = kwargs.get( "alt_cr", np.random.uniform(self.wrap.cruise_alt()["minimum"], self.wrap.cruise_alt()["maximum"]) * 1000 / aero.ft, ) mach_cr = kwargs.get( "mach_cr", np.random.uniform( self.wrap.cruise_mach()["minimum"], self.wrap.cruise_mach()["maximum"], ), ) else: range = kwargs.get("range_cr", self.wrap.cruise_range()["default"] * 1000) mach_cr = kwargs.get("mach_cr", self.wrap.cruise_mach()["default"]) alt_cr = kwargs.get( "alt_cr", self.wrap.cruise_alt()["default"] * 1000 / aero.ft) alt_cr = np.round(alt_cr, -2) # round cruise altitude to flight level h_cr = alt_cr * aero.ft data = [] # intitial conditions t = 0 s = 0 v = aero.mach2tas(mach_cr, h_cr) vs = 0 while True: data.append([t, h_cr, s, v, vs]) t = t + dt s = s + v * dt if s > range: break data = np.array(data) ndata = len(data) datadict = { "t": data[:, 0], "h": data[:, 1] + np.random.normal(0, self.sigma_h, ndata), "s": data[:, 2] + np.random.normal(0, self.sigma_s, ndata), "v": data[:, 3] + np.random.normal(0, self.sigma_v, ndata), "vs": data[:, 4] + np.random.normal(0, self.sigma_vs, ndata), "alt_cr": alt_cr, "mach_cr": mach_cr, } return datadict def complete(self, **kwargs): """Generate a complete trajectory based on WRAP model. Args: **dt (int): Time step in seconds. **cas_const_cl (int): Constaant CAS for climb (kt). **mach_const_cl (float): Constaant Mach for climb (-). **cas_const_de (int): Constaant CAS for climb (kt). **mach_const_de (float): Constaant Mach for climb (-). **range_cr (int): Cruise range (km). **alt_cr (int): Target cruise altitude (ft). **mach_cr (float): Cruise Mach number (-). **random (bool): Generate trajectory with random paramerters. Returns: dict: Flight trajectory. """ data_cr = self.cruise(**kwargs) if "alt_cr" not in kwargs: kwargs["alt_cr"] = data_cr["alt_cr"] data_cl = self.climb(mach_const_cl=data_cr["mach_cr"], **kwargs) data_de = self.descent(mach_const_de=data_cr["mach_cr"], **kwargs) data = { "t": np.concatenate([ data_cl["t"], data_cl["t"][-1] + data_cr["t"], data_cl["t"][-1] + data_cr["t"][-1] + data_de["t"], ]), "h": np.concatenate([data_cl["h"], data_cr["h"], data_de["h"]]), "s": np.concatenate([ data_cl["s"], data_cl["s"][-1] + data_cr["s"], data_cl["s"][-1] + data_cr["s"][-1] + data_de["s"], ]), "v": np.concatenate([data_cl["v"], data_cr["v"], data_de["v"]]), "vs": np.concatenate([data_cl["vs"], data_cr["vs"], data_de["vs"]]), } return data
def main(): # Debug output debug = open("./debug.log", 'w+') debug.write("altitude,vs,cas,tas,aoa,cl,cd,drag,lift,mass,thrust\n") debug.flush() # PID Setup a319 = performance.Performance("A319", False) a319_wrp = WRAP(ac="A319") autopilot = Autopilot() autothrust = Autothrust() a319.mass = 60_000.00 a319.pitch = 0.0 a319.gear = True a319.flaps = 1 a319.pitch_target = 0.0 a319.pitch_rate_of_change = 3.0 target_alt = 6_000 * aero.ft # simulation varibale a319.phase = 0 pitchs = [] fd_pitchs = [] alts = [] vs = [] cas = [] times = [] thrusts = [] drags = [] phases = [] i = 0 distance_0 = 0.0 run = True # a319.run() # while run and a319.altitude >= 0: # a319.run() # if a319.cas > a319_wrp.takeoff_speed()["default"] and a319.phase == 0: # a319.phase = 1 # a319.pitch_target = 15.0 # # When passing 100ft RA, the gear is up # if a319.gear and (a319.altitude / aero.ft) > 100.0: # a319.gear = False # if a319.flaps > 0 and (a319.cas / aero.kts) > 210.0: # a319.flaps = 0 # if (a319.altitude / aero.ft) > 1500.0 and\ # (a319.altitude / aero.ft) < 1550.0 and a319.phase < 2: # a319.thrust_lever = 1. # a319.phase = 2 # if (a319.altitude / aero.ft) > 3000.0 and a319.phase < 4: # if a319.phase != 3: # a319.phase = 3 # autopilot.VerticalSpeedHold(1000.0 * aero.fpm, target_alt) # if a319.flaps == 0 and round(a319.cas / aero.kts) > 250\ # and a319.altitude < target_alt: # if a319.phase != 4: # a319.phase = 4 # speed_target = 250 * aero.kts # autopilot.SpeedHold(speed_target, target_alt) # # # speed_target = 320 * aero.kts # # # if a319.altitude / aero.ft < 10_000: # # # speed_target = 250 * aero.kts # # # elif a319.altitude >= aero.crossover_alt(320 * aero.kts, 0.78): # # # speed_target = aero.mach2cas(0.78, a319.altitude) # # # a319.thrust_lever = 1.0 # # # if autopilot.active_mode != Autopilot.speed_hold \ # # # or autopilot.target != speed_target: # # # autopilot.SpeedHold(speed_target, target_alt) # if a319.altitude + (a319.v_y * 30) >= target_alt: # if a319.phase != 5: # a319.phase = 5 # autopilot.AltitudeAquire(target_alt) # if a319.altitude > target_alt + 61: # if a319.phase != 7: # a319.phase = 7 # autopilot.VerticalSpeedHold(-1000 * aero.fpm, target_alt) # a319.thrust_lever = 0.0 # if target_alt - 61 <= a319.altitude <= target_alt + 61: # if a319.phase != 6: # a319.phase = 6 # autopilot.AltitudeHold(target_alt) # if distance_0 == 0.0: # distance_0 = a319.distance_x # if (a319.distance_x - distance_0) / aero.nm >= 5.0: # run = False # # run = False # # continue # if a319.cas / aero.kts >= 320: # a319.tas = aero.cas2tas(320 * aero.kts, a319.altitude) # # if a319.phase != 6: # # if a319.tas > aero.mach2tas(0.78, a319.altitude)\ # # and autopilot.active_mode != Autopilot.mach_hold: # # autopilot.MachHold(0.78, target_alt) # if a319.phase >= 0: # if (a319.pitch > 0 or a319.altitude > 0) \ # and (round((a319.altitude / aero.ft) / 10) * 10) \ # % 5000 == 0: # debug.write(f"{a319.altitude / aero.ft},{a319.vs}," # f"{a319.cas / aero.kts},{a319.tas/ aero.kts}," # f"{a319.aoa},{a319.cl},{a319.cd},{a319.drag}," # f"{a319.lift},{a319.mass},{a319.thrust}\n") # debug.flush() # if a319.phase < 7 and a319.altitude > 10_000 * aero.ft: # a319.thrust_lever = 1.0 # if a319.phase == 7: # a319.thrust_lever = 0.0 # mach = aero.tas2mach(a319.tas, a319.altitude) # if autopilot.active_mode is not None: # a319.pitch_target = autopilot.run(a319.cas, # a319.v_y, # a319.altitude, # a319.pitch, # mach) # a319.pitch = a319.pitch_target a319.tas = aero.cas2tas(200 * aero.kts, 0.0) a319.pitch = 0.0 a319.aoa = 0.0 a319.altitude = 5000.0 * aero.ft a319.flaps = 1 for e in range(60): a319.run() # alts.append(int(round(a319.altitude / aero.ft))) # vs.append(int(a319.vs)) # cas.append(a319.cas / aero.kts) # pitchs.append(a319.pitch) # thrusts.append(a319.thrust_lever) # times.append(e / 60.0) i = 61 target_alt = 1000.0 * aero.ft autopilot.SpeedHold(180 * aero.kts, target_alt) # spd_target = 320 * aero.kts # autothrust.SpeedHold(spd_target) run = True a319.thrust_lever = 0.0 while not (target_alt + 1 > a319.altitude > target_alt - 1): a319.run() mach = tas2mach(a319.tas, a319.altitude) a319.pitch_target = autopilot.run(a319.cas, a319.v_y, a319.altitude, a319.pitch, mach) a319.pitch = a319.pitch_target # if a319.altitude < (12_000 * aero.ft)\ # and autopilot.target != 220 * aero.kts: # autopilot.target = 220 * aero.kts if autopilot.active_mode == autopilot.alt_aquire: if autothrust.active_mode is None: autothrust.SpeedHold(180 * aero.kts) a319.thrust_lever = autothrust.run(a319.cas) print(f"{a319.phase} : {a319.altitude / aero.ft:02f}", f"- {a319.vs:02f} - {a319.cas / aero.kts:02f} - ", f"{mach:0.3f} - {a319.aoa:0.2f} ", f"{a319.pitch:02f} / {a319.pitch_target:02f} - ", f"{a319.cl:04f} - {a319.cd:04f} - {a319.thrust_lever:03f}") alts.append(int(round(a319.altitude / aero.ft))) vs.append(int(a319.vs)) cas.append(a319.cas / aero.kts) pitchs.append(a319.pitch) times.append(i / 60.0) fd_pitchs.append(a319.pitch_target) thrusts.append(a319.thrust_lever) drags.append(a319.drag) phases.append(a319.phase) i += 1 print(f"Cas End = {max(cas)}") draw(times[60:], vs[60:], alts[60:], cas[60:], pitchs[60:], [], thrusts[60:], [], [])
from openap import prop, FuelFlow, Emission, WRAP available_acs = prop.available_aircraft(use_synonym=True) for actype in available_acs: # print(actype) aircraft = prop.aircraft(ac=actype, use_synonym=True) wrap = WRAP(ac=actype, use_synonym=True) fuelflow = FuelFlow(ac=actype, use_synonym=True) emission = Emission(ac=actype, use_synonym=True) available_acs = prop.available_aircraft(use_synonym=False) for actype in available_acs: # print(actype) aircraft = prop.aircraft(ac=actype, use_synonym=False) wrap = WRAP(ac=actype, use_synonym=True) fuelflow = FuelFlow(ac=actype, use_synonym=True) emission = Emission(ac=actype, use_synonym=True)
from openap import WRAP wrap = WRAP('A320') for func in dir(wrap): if callable(getattr(wrap, func)): if not func.startswith('_'): print(getattr(wrap, func)())