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")
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 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 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:], [], [])