def clean(self, mass, tas, alt, path_angle=0): """Compute drag at clean configuration (considering compressibility). Args: mass (int or ndarray): Mass of the aircraft (unit: kg). tas (int or ndarray): True airspeed (unit: kt). alt (int or ndarray): Altitude (unit: ft). path_angle (float or ndarray): Path angle (unit: degree). Defaults to 0. Returns: int: Total drag (unit: N). """ cd0 = self.polar["clean"]["cd0"] k = self.polar["clean"]["k"] if self.wave_drag: mach_crit = self.polar["mach_crit"] mach = aero.tas2mach(tas * aero.kts, alt * aero.ft) dCdw = np.where(mach > mach_crit, 20 * (mach - mach_crit)**4, 0) else: dCdw = 0 cd0 = cd0 + dCdw D = self._calc_drag(mass, tas, alt, cd0, k, path_angle) return D
def takeoff(self, tas, alt=None): """Calculate thrust during the takeoff. Args: tas (float or ndarray): True airspeed (kt). alt (float or ndarray): Altitude of the runway (ft). Defaults to 0. Returns: float or ndarray: Total thrust (unit: N). """ mach = aero.tas2mach(tas*aero.kts, 0) eng_bpr = self.eng_bpr G0 = 0.0606 * self.eng_bpr + 0.6337 if alt is None: # at sea level ratio = 1 - 0.377 * (1+eng_bpr) / np.sqrt((1+0.82*eng_bpr)*G0) * mach \ + (0.23 + 0.19 * np.sqrt(eng_bpr)) * mach**2 else: # at certain altitude P = aero.pressure(alt * aero.ft) dP = P / aero.p0 A = -0.4327 * dP**2 + 1.3855 * dP + 0.0472 Z = 0.9106 * dP**3 - 1.7736 * dP**2 + 1.8697 * dP X = 0.1377 * dP**3 - 0.4374 * dP**2 + 1.3003 * dP ratio = A - 0.377 * (1+eng_bpr) / np.sqrt((1+0.82*eng_bpr)*G0) * Z * mach \ + (0.23 + 0.19 * np.sqrt(eng_bpr)) * X * mach**2 F = ratio * self.eng_max_thrust * self.eng_number return F
def _sl2fl(self, tas, alt): M = aero.tas2mach(tas * aero.kts, alt * aero.ft) beta = np.exp(0.2 * (M**2)) theta = (aero.temperature(alt * aero.ft) / 288.15) / beta delta = (1 - 0.0019812 * alt / 288.15)**5.255876 / np.power(beta, 3.5) ratio = (theta**3.3) / (delta**1.02) return beta, theta, delta, ratio
def climb(self, tas, alt, roc): """Calculate thrust during the climb. Args: tas (float or ndarray): True airspeed (kt). alt (float or ndarray): Altitude(ft) roc (float or ndarray): Vertical rate (ft/min). Returns: float or ndarray: Total thrust (unit: N). """ roc = np.abs(roc) h = alt * aero.ft tas = np.where(tas < 10, 10, tas) mach = aero.tas2mach(tas * aero.kts, h) vcas = aero.tas2cas(tas * aero.kts, h) P = aero.pressure(h) P10 = aero.pressure(10000 * aero.ft) Pcr = aero.pressure(self.cruise_alt * aero.ft) # approximate thrust at top of climb (REF 2) Fcr = self.eng_cruise_thrust * self.eng_number vcas_ref = aero.mach2cas(self.cruise_mach, self.cruise_alt * aero.ft) # segment 3: alt > 30000: d = self._dfunc(mach / self.cruise_mach) b = (mach / self.cruise_mach)**(-0.11) ratio_seg3 = d * np.log(P / Pcr) + b # segment 2: 10000 < alt <= 30000: a = (vcas / vcas_ref)**(-0.1) n = self._nfunc(roc) ratio_seg2 = a * (P / Pcr)**(-0.355 * (vcas / vcas_ref) + n) # segment 1: alt <= 10000: F10 = Fcr * a * (P10 / Pcr)**(-0.355 * (vcas / vcas_ref) + n) m = self._mfunc(vcas / vcas_ref, roc) ratio_seg1 = m * (P / Pcr) + (F10 / Fcr - m * (P10 / Pcr)) ratio = np.where(alt > 30000, ratio_seg3, np.where(alt > 10000, ratio_seg2, ratio_seg1)) F = ratio * Fcr return F
def mach(self) -> float: return aero.tas2mach(self.tas, self.altitude)
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:], [], [])