def air_path(aircraft, nei, altp, disa, speed_mode, speed, mass, rating): """ Retrieves air path in various conditions """ g = earth.gravity() [pamb, tamb, tstd, dtodz] = earth.atmosphere(altp, disa) mach = get_mach(pamb, speed_mode, speed) fn, data = propu.thrust(aircraft, pamb, tamb, mach, rating, nei) cz = lift_from_speed(aircraft, pamb, mach, mass) [cx, lod] = aero.drag(aircraft, pamb, tamb, mach, cz) if (nei > 0): dcx = propu.oei_drag(aircraft, pamb, mach) cx = cx + dcx * nei lod = cz / cx acc_factor = earth.climb_mode(speed_mode, dtodz, tstd, disa, mach) slope = (fn / (mass * g) - 1 / lod) / acc_factor vsnd = earth.sound_speed(tamb) v_z = mach * vsnd * slope return slope, v_z
def lift_from_speed(aircraft, pamb, mach, mass): wing = aircraft.wing g = earth.gravity() gam = earth.heat_ratio() c_z = (2 * mass * g) / (gam * pamb * mach**2 * wing.area) return c_z
def speed_from_lift(aircraft, pamb, cz, mass): wing = aircraft.wing g = earth.gravity() gam = earth.heat_ratio() mach = numpy.sqrt((mass * g) / (0.5 * gam * pamb * wing.area * cz)) return mach
def pressure_altitude_grad(pamb, pamb_d): """ Pressure altitude from ground to 50 km """ g = earth.gravity() R = earth.gaz_constant() Z = numpy.array([0., 10999., 19999., 31999., 46999., 49999.]) dtodz = numpy.array([-0.0065, 0., 0.0010, 0.0028, 0.]) P = numpy.array([earth.sea_level_pressure(), 0., 0., 0., 0., 0.]) T = numpy.array([earth.sea_level_temperature(), 0., 0., 0., 0., 0.]) j = 0 n = len(P) - 1 P[1] = P[0] * (1 + (dtodz[0] / T[0]) * (Z[1] - Z[0]))**(-g / (R * dtodz[0])) T[1] = T[0] + dtodz[0] * (Z[1] - Z[0]) while (j < n and pamb < P[j + 1]): j = j + 1 T[j + 1] = T[j] + dtodz[j] * (Z[j + 1] - Z[j]) if (0. < numpy.abs(dtodz[j])): P[j + 1] = P[j] * (1 + (dtodz[j] / T[j]) * (Z[j + 1] - Z[j]))**(-g / (R * dtodz[j])) else: P[j + 1] = P[j] * numpy.exp(-(g / R) * ((Z[j + 1] - Z[j]) / T[j])) if (pamb < P[n]): raise Exception("pressure_altitude_grad, altitude cannot exceed 50km") if (0. < numpy.abs(dtodz[j])): altp = Z[j] + ( (pamb / P[j])**(-(R * dtodz[j]) / g) - 1) * (T[j] / dtodz[j]) altp_d = (T[j] / dtodz[j]) * (-(R * dtodz[j]) / (g * P[j])) * pamb_d * (pamb / P[j])**( -(R * dtodz[j]) / g - 1) else: altp = Z[j] - (T[j] / (g / R)) * numpy.log(pamb / P[j]) altp_d = -((T[j] * R) / g) * (pamb_d / pamb) return altp, altp_d
def approach_speed(aircraft, altp, disa, mass, hld_conf): """ Minimum approach speed (VLS) """ wing = aircraft.wing g = earth.gravity() czmax, trash = airplane_aero.high_lift(wing, hld_conf) stall_margin = regul.kvs1g_min_landing() [pamb, tamb, tstd, dtodz] = earth.atmosphere(altp, disa) [rho, sig] = earth.air_density(pamb, tamb) vapp = numpy.sqrt( (mass * g) / (0.5 * rho * wing.area * (czmax / stall_margin**2))) return vapp
def specific_air_range(aircraft, altp, mass, mach, disa): propulsion = aircraft.propulsion (MTO, MCN, MCL, MCR, FID) = propulsion.rating_code g = earth.gravity() pamb, tamb, tstd, dtodz = earth.atmosphere(altp, disa) vsnd = earth.sound_speed(tamb) Cz = flight.lift_from_speed(aircraft, pamb, mach, mass) [Cx, LoD] = airplane_aero.drag(aircraft, pamb, tamb, mach, Cz) nei = 0. sfc = propu.sfc(aircraft, pamb, tamb, mach, MCR, nei) sar = (vsnd * mach * LoD) / (mass * g * sfc) return sar
def state_dot(xin, state, rating, nei, aircraft): g = earth.gravity() gam = earth.heat_ratio() area = aircraft.wing.area cz, fn = xin t, mass, xg, zg, vgnd, path = state xg_d = vgnd * numpy.cos(path) zg_d = vgnd * numpy.sin(path) pamb, pamb_d, tamb, tamb_d, disa, disa_d, wx, wx_d, wz, wz_d = air( xg, zg, xg_d, zg_d) rho, rho_d, sig, sig_d = g_earth.air_density_grad(pamb, pamb_d, tamb, tamb_d) vsnd, vsnd_d = g_earth.sound_speed_grad(tamb, tamb_d) altp, altp_d = g_earth.pressure_altitude_grad(pamb, pamb_d) # Compute state_dot #----------------------------------------------------------------------------------------------------------- vxair = xg_d - wx # Local wind is introduced here vzair = zg_d - wz vair = numpy.sqrt(vxair**2 + vzair**2) mach = vair / vsnd cx, lod = airplane_aero.drag(aircraft, pamb, tamb, mach, cz) # Aerodynamic drag model path_d = ((0.5 * rho * vair**2) * area * cz - mass * g * numpy.cos(path)) / (mass * vair) # Lift equation vgnd_d = (fn - mass * g * numpy.sin(path) - (0.5 * rho * vair**2) * area * cx) / mass # Drag equation sfc = propu.sfc(aircraft, pamb, tamb, mach, rating, nei) # Propulsion consumption model mass_d = -sfc * fn state_d = numpy.array([1., mass_d, xg_d, zg_d, vgnd_d, path_d]) # Compute other derivatives #----------------------------------------------------------------------------------------------------------- vxgnd_d = vgnd_d * numpy.cos(path) - vgnd * numpy.sin(path) * path_d vzgnd_d = vgnd_d * numpy.sin(path) + vgnd * numpy.cos(path) * path_d vxair_d = vxgnd_d - wx_d vzair_d = vzgnd_d - wz_d vair_d = (vxair * vxair_d + vzair * vzair_d) / vair mach_d = vair_d / vsnd - vair * vsnd_d / vsnd**2 vcas, vcas_d = g_earth.vcas_from_mach_grad(pamb, pamb_d, mach, mach_d) xout = numpy.array([ t, mass, xg, zg, vgnd, path, 1., mass_d, xg_d, zg_d, vgnd_d, path_d, vxgnd_d, vzgnd_d, vair, vair_d, vxair, vxair_d, vzair, vzair_d, mach, mach_d, vcas, vcas_d, altp, altp_d, pamb, pamb_d, tamb, tamb_d, disa, disa_d, rho, rho_d, wx, wx_d, wz, wz_d, cz, cx, fn ]) return xout, state_d
def eval_wing_design(aircraft): """ Wing predesign """ design_driver = aircraft.design_driver fuselage = aircraft.fuselage vtp = aircraft.vertical_tail nacelle = aircraft.turbofan_nacelle weights = aircraft.weights c_g = aircraft.center_of_gravity wing = aircraft.wing wing.t_o_c_t = 0.10 wing.t_o_c_k = wing.t_o_c_t + 0.01 wing.t_o_c_r = wing.t_o_c_k + 0.03 wing.sweep = 1.6 * max(0, (design_driver.cruise_mach - 0.5)) # Empirical law wing.dihedral = unit.rad_deg(5) if (wing.morphing == 1): # Aspect ratio is driving parameter wing.span = numpy.sqrt(wing.aspect_ratio * wing.area) elif (wing.morphing == 2): # Span is driving parameter wing.aspect_ratio = wing.span**2 / wing.area else: print("geometry_predesign_, wing_morphing index is unkown") # Correlation between span loading and tapper ratio wing.taper_ratio = 0.3 - 0.025 * (1e-3 * weights.mtow / wing.span) # Factor 1.64 accounts for the part of HTP ref area hidden in the fuselage wing.net_wetted_area = 1.64 * wing.area wing.y_kink = 0.7 * fuselage.width + 1.4 * nacelle.width # statistical regression wing.y_root = 0.5 * fuselage.width wing.y_tip = 0.5 * wing.span if (15 < unit.deg_rad(wing.sweep)): # With kink Phi100intTE = max(0, 2 * (wing.sweep - unit.rad_deg(32))) tan_phi100 = numpy.tan(Phi100intTE) A = ((1 - 0.25 * wing.taper_ratio) * wing.y_kink + 0.25 * wing.taper_ratio * wing.y_root - wing.y_tip) / ( 0.75 * wing.y_kink + 0.25 * wing.y_root - wing.y_tip) B = (numpy.tan(wing.sweep) - tan_phi100) * ( (wing.y_tip - wing.y_kink) * (wing.y_kink - wing.y_root)) / (0.25 * wing.y_root + 0.75 * wing.y_kink - wing.y_tip) wing.c_root = (wing.area - B * (wing.y_tip - wing.y_root)) / ( wing.y_root + wing.y_kink + A * (wing.y_tip - wing.y_root) + wing.taper_ratio * (wing.y_tip - wing.y_kink)) wing.c_kink = A * wing.c_root + B wing.c_tip = wing.taper_ratio * wing.c_root else: # Without kink wing.c_root = 2 * wing.area / ( 2 * wing.y_root * (1 - wing.taper_ratio) + (1 + wing.taper_ratio) * numpy.sqrt(wing.aspect_ratio * wing.area)) wing.c_tip = wing.taper_ratio * wing.c_root wing.c_kink = ((wing.y_tip - wing.y_kink) * wing.c_root + (wing.y_kink - wing.y_root) * wing.c_tip) / ( wing.y_tip - wing.y_root) tan_phi0 = 0.25 * (wing.c_kink - wing.c_tip) / ( wing.y_tip - wing.y_kink) + numpy.tan(wing.sweep) wing.mac = 2.*(3*wing.y_root*wing.c_root**2 \ +(wing.y_kink-wing.y_root)*(wing.c_root**2+wing.c_kink**2+wing.c_root*wing.c_kink) \ +(wing.y_tip-wing.y_kink)*(wing.c_kink**2+wing.c_tip**2+wing.c_kink*wing.c_tip) \ )/(3*wing.area) wing.y_mac = ( 3*wing.c_root*wing.y_root**2 \ +(wing.y_kink-wing.y_root)*(wing.c_kink*(wing.y_root+wing.y_kink*2.)+wing.c_root*(wing.y_kink+wing.y_root*2.)) \ +(wing.y_tip-wing.y_kink)*(wing.c_tip*(wing.y_kink+wing.y_tip*2.)+wing.c_kink*(wing.y_tip+wing.y_kink*2.)) \ )/(3*wing.area) x_mac_local = ( (wing.y_kink-wing.y_root)*tan_phi0*((wing.y_kink-wing.y_root)*(wing.c_kink*2.+wing.c_root) \ +(wing.y_tip-wing.y_kink)*(wing.c_kink*2.+wing.c_tip))+(wing.y_tip-wing.y_root)*tan_phi0*(wing.y_tip-wing.y_kink)*(wing.c_tip*2.+wing.c_kink) \ )/(3*wing.area) wing.x_root = vtp.x_mac + 0.25 * vtp.mac - vtp.lever_arm - 0.25 * wing.mac - x_mac_local wing.x_kink = wing.x_root + (wing.y_kink - wing.y_root) * tan_phi0 wing.x_tip = wing.x_root + (wing.y_tip - wing.y_root) * tan_phi0 wing.x_mac = wing.x_root+( (wing.x_kink-wing.x_root)*((wing.y_kink-wing.y_root)*(wing.c_kink*2.+wing.c_root) \ +(wing.y_tip-wing.y_kink)*(wing.c_kink*2.+wing.c_tip))+(wing.x_tip-wing.x_root)*(wing.y_tip-wing.y_kink)*(wing.c_tip*2.+wing.c_kink) \ )/(wing.area*3.) if (wing.attachment == 1): wing.z_root = 0 else: wing.z_root = fuselage.height - 0.5 * wing.t_o_c_r * wing.c_root wing.z_kink = wing.z_root + (wing.y_kink - wing.y_root) * numpy.tan( wing.dihedral) wing.z_tip = wing.z_root + (wing.y_tip - wing.y_root) * numpy.tan( wing.dihedral) # Wing setting #----------------------------------------------------------------------------------------------------------- g = earth.gravity() gam = earth.heat_ratio() disa = 0 rca = design_driver.ref_cruise_altp mach = design_driver.cruise_mach mass = 0.95 * weights.mtow pamb, tamb, tstd, dtodz = earth.atmosphere(rca, disa) cza_wo_htp = frame_aero.cza_wo_htp(mach, fuselage.width, wing.aspect_ratio, wing.span, wing.sweep) # AoA = 2.5° at cruise start wing.setting = (0.97 * mass * g) / (0.5 * gam * pamb * mach**2 * wing.area * cza_wo_htp) - unit.rad_deg(2.5) return
def mission(aircraft, dist_range, tow, altp, mach, disa): """ Mission computation using breguet equation, fixed L/D and fixed sfc """ engine = aircraft.turbofan_engine propulsion = aircraft.propulsion battery = aircraft.battery (MTO, MCN, MCL, MCR, FID) = propulsion.rating_code g = earth.gravity() pamb, tamb, tstd, dtodz = earth.atmosphere(altp, disa) vsnd = earth.sound_speed(tamb) tas = vsnd * mach lod_max, cz_lod_max = airplane_aero.lod_max(aircraft, pamb, tamb, mach) lod_cruise = 0.95 * lod_max nei = 0. sfc = propu.sfc(aircraft, pamb, tamb, mach, MCR, nei) if (propulsion.architecture == 2): fn, sec, data = propu.hybrid_thrust(aircraft, pamb, tamb, mach, MCR, nei) if (propulsion.architecture == 3): fn, sec, data = propu.hybrid_thrust(aircraft, pamb, tamb, mach, MCR, nei) # Departure ground phases #----------------------------------------------------------------------------------------------------------- fuel_taxi_out = (34 + 2.3e-4 * engine.reference_thrust) * engine.n_engine time_taxi_out = 540 fuel_take_off = 1e-4 * (2.8 + 2.3 / engine.bpr) * tow time_take_off = 220 * tow / (engine.reference_thrust * engine.n_engine) # Mission leg #----------------------------------------------------------------------------------------------------------- if (propulsion.architecture == 1): fuel_mission = tow * (1 - numpy.exp(-(sfc * g * dist_range) / (tas * lod_cruise))) elif (propulsion.architecture == 2): fuel_mission = tow*(1-numpy.exp(-(sfc*g*dist_range)/(tas*lod_cruise))) \ - (sfc/sec)*battery.energy_cruise elif (propulsion.architecture == 3): fuel_mission = tow*(1-numpy.exp(-(sfc*g*dist_range)/(tas*lod_cruise))) \ - (sfc/sec)*battery.energy_cruise elif (propulsion.architecture == 4): fuel_mission = tow * (1 - numpy.exp(-(sfc * g * dist_range) / (tas * lod_cruise))) else: raise Exception("propulsion.architecture index is out of range") time_mission = 1.09 * (dist_range / tas) l_w = tow - fuel_mission # Arrival ground phases #----------------------------------------------------------------------------------------------------------- fuel_landing = 1e-4 * (0.5 + 2.3 / engine.bpr) * l_w time_landing = 180 fuel_taxi_in = (26 + 1.8e-4 * engine.reference_thrust) * engine.n_engine time_taxi_in = 420 # Block fuel and time #----------------------------------------------------------------------------------------------------------- block_fuel = fuel_taxi_out + fuel_take_off + fuel_mission + fuel_landing + fuel_taxi_in time_block = time_taxi_out + time_take_off + time_mission + time_landing + time_taxi_in # Diversion and holding reserve fuel #----------------------------------------------------------------------------------------------------------- fuel_diversion = l_w * (1 - numpy.exp(-(sfc * g * regul.diversion_range()) / (tas * lod_cruise))) fuel_holding = sfc * (l_w * g / lod_max) * regul.holding_time() # Total #----------------------------------------------------------------------------------------------------------- design_range = aircraft.design_driver.design_range fuel_total = fuel_mission * (1 + regul.reserve_fuel_ratio(design_range) ) + fuel_diversion + fuel_holding #----------------------------------------------------------------------------------------------------------- return block_fuel, time_block, fuel_total
def atmosphere_grad(altp, altp_d, disa, disa_d): """ Pressure from pressure altitude from ground to 50 km """ g = earth.gravity() R = earth.gaz_constant() Z = numpy.array([0., 10999., 19999., 31999., 46999., 49999.]) Z_d = numpy.array([0., 0., 0., 0., 0., 0.]) dtodz = numpy.array([-0.0065, 0., 0.0010, 0.0028, 0.]) dtodz_d = numpy.array([0., 0., 0., 0., 0.]) P = numpy.array([earth.sea_level_pressure(), 0., 0., 0., 0., 0.]) P_d = numpy.array([0., 0., 0., 0., 0., 0.]) T = numpy.array([earth.sea_level_temperature(), 0., 0., 0., 0., 0.]) T_d = numpy.array([0., 0., 0., 0., 0., 0.]) if (Z[-1] < altp): raise Exception("atmosphere_grad, altitude cannot exceed 50km") j = 0 while (Z[1 + j] <= altp): T[j + 1] = T[j] + dtodz[j] * (Z[j + 1] - Z[j]) T_d[j + 1] = T_d[j] + dtodz_d[j] * (Z[j + 1] - Z[j]) + dtodz[j] * ( Z_d[j + 1] - Z_d[j]) if (0. < numpy.abs(dtodz[j])): B1 = 1 + (dtodz[j] * (Z[1 + j] - Z[j])) / (T[j] + disa) B1_dz = (dtodz[j] * (Z_d[1 + j] - Z_d[j])) / (T[j] + disa) B1_dt = (dtodz_d[j] * (Z[1 + j] - Z[j])) / (T[j] + disa) - ( dtodz[j] * (Z[1 + j] - Z[j]) * disa_d) / (T[j] + disa)**2 B2 = -g / (R * dtodz[j]) B2_dt = (g * dtodz_d[j]) / (R * dtodz[j]**2) P[1 + j] = P[j] * B1**B2 P_d[1 + j] = P[j] * ( B2 * B1_dz * B1**(B2 - 1) + (B1**B2) * (B2_dt * numpy.log(B1) + B2 * B1_dt / B1)) + P_d[j] * B1**B2 else: B3 = -(g / R) * ((Z[1 + j] - Z[j]) / (T[j] + disa)) B3_d = -(g / R) * ((Z_d[1 + j] - Z_d[j]) / (T[j] + disa)) + (g / R) * ((Z[1 + j] - Z[j]) * (T_d[j] + disa_d) / (T[j] + disa)**2) P[j + 1] = P[j] * numpy.exp(B3) P_d[j + 1] = P_d[j] * numpy.exp(B3) + P[j] * B3_d * numpy.exp(B3) j = j + 1 if (0. < numpy.abs(dtodz[j])): B1 = 1 + (dtodz[j] * (altp - Z[j])) / (T[j] + disa) B1_dz = (dtodz[j] * (altp_d - Z_d[j])) / (T[j] + disa) B1_dt = (dtodz_d[j] * (altp - Z[j])) / (T[j] + disa) - (dtodz[j] * (altp - Z[j]) * disa_d) / (T[j] + disa)**2 B2 = -g / (R * dtodz[j]) B2_dt = (g * dtodz_d[j]) / (R * dtodz[j]**2) pamb = P[j] * B1**B2 pamb_d = P[j] * ( B2 * B1_dz * B1**(B2 - 1) + (B1**B2) * (B2_dt * numpy.log(B1) + B2 * B1_dt / B1)) + P_d[j] * B1**B2 else: B3 = -(g / R) * ((altp - Z[j]) / (T[j] + disa)) B3_d = -(g / R) * ((altp_d - Z_d[j]) / (T[j] + disa)) + (g / R) * ((altp - Z[j]) * (T_d[j] + disa_d) / (T[j] + disa)**2) pamb = P[j] * numpy.exp(B3) pamb_d = P_d[j] * numpy.exp(B3) + P[j] * B3_d * numpy.exp(B3) tamb = T[j] + dtodz[j] * (altp - Z[j]) + disa tamb_d = T_d[j] + dtodz_d[j] * (altp - Z[j]) + dtodz[j] * (altp_d - Z_d[j]) + disa_d return pamb, pamb_d, tamb, tamb_d, dtodz[j]