def nominal_mission(aircraft): """ Compute nominal mission with range as input """ disa = 0 altp = aircraft.design_driver.ref_cruise_altp mach = aircraft.design_driver.cruise_mach nei = 0 aircraft.nominal_mission.payload = aircraft.payload.nominal aircraft.nominal_mission.range = aircraft.design_driver.design_range aircraft.nominal_mission.tow = aircraft.weights.mtow (MTO, MCN, MCL, MCR, FID) = aircraft.propulsion.rating_code pamb, tamb, tstd, dtodz = earth.atmosphere(altp, disa) lod_max, _ = craft_aero.lod_max(aircraft, pamb, tamb, mach) sfc = propu.sfc(aircraft, pamb, tamb, mach, MCR, nei) aircraft.high_speed.cruise_lod = lod_max aircraft.high_speed.cruise_sfc = sfc payload = aircraft.nominal_mission.payload range = aircraft.nominal_mission.range tow = aircraft.nominal_mission.tow block_fuel, block_time, total_fuel = perfo.mission(aircraft, range, tow, altp, mach, disa) aircraft.nominal_mission.block_fuel = block_fuel aircraft.nominal_mission.block_time = block_time aircraft.nominal_mission.total_fuel = total_fuel return
def acceleration(aircraft, nei, altp, disa, speed_mode, speed, mass, rating): """ Aircraft acceleration on level flight """ wing = aircraft.wing gam = earth.heat_ratio() [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 acc = (fn - 0.5 * gam * pamb * mach**2 * wing.area * cx) / mass return acc
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 eval_turboprop_engine_design(aircraft): """ Turboprop architecture design """ engine = aircraft.turboprop_engine engine.rating_factor = (0.800, 0.688, 0.624, 0.560, 0.100) disa = 0. altp = 0. mach = 0.25 (pamb, tamb, tstd, dtodz) = earth.atmosphere(altp, disa) Vsnd = earth.sound_speed(tamb) Vair = Vsnd * mach engine.reference_power = engine.reference_thrust * ( Vair / engine.propeller_efficiency) # assuming a fan disk load of 3000 N/m2 engine.propeller_diameter = math.sqrt( (4. / math.pi) * (engine.reference_thrust / 3000)) return
def eval_aerodynamics_design(aircraft): """ Defines high lift movable deflection settings HLDconf varies from 0 (clean) to 1 (full deflected) Typically : HLDconf = 1 ==> CzmaxLD : HLDconf = 0.1 to 0.5 ==> CzmaxTO """ design_driver = aircraft.design_driver wing = aircraft.wing aerodynamics = aircraft.aerodynamics mach = design_driver.cruise_mach altp = design_driver.ref_cruise_altp disa = 0 pamb, tamb, tstd, dtodz = earth.atmosphere(altp, disa) aerodynamics.cruise_lod_max, aerodynamics.cz_cruise_lod_max = craft_aero.lod_max( aircraft, pamb, tamb, mach) aerodynamics.hld_conf_clean = 0 # By definition (0=<hld_conf=<1) aerodynamics.cz_max_clean, Cz0 = craft_aero.high_lift( wing, aerodynamics.hld_conf_clean) aerodynamics.hld_conf_to = 0.3 # Take off (empirical setting) aerodynamics.cz_max_to, Cz0 = craft_aero.high_lift( wing, aerodynamics.hld_conf_to) aerodynamics.hld_conf_ld = 1 # By definition (0=<hld_conf=<1), 1 is full landing aerodynamics.cz_max_ld, Cz0 = craft_aero.high_lift( wing, aerodynamics.hld_conf_ld) return
def forward_cg_stall(aircraft, altp, disa, nei, hld_conf, speed_mode, mass): """ Computes max forward trimmable CG position at stall speed """ wing = aircraft.wing htp = aircraft.horizontal_tail gam = earth.heat_ratio() [pamb, tamb, tstd, dtodz] = earth.atmosphere(altp, disa) [cz_max_wing, cz0] = craft_aero.high_lift( wing, hld_conf) # Wing maximum lift coefficient without margin [cza_htp, xlc_htp, aoa_max_htp, ki_htp] = frame_aero.htp_aero_data(aircraft) cz_max_htp = cza_htp * aoa_max_htp c_z = cz_max_wing - cz_max_htp # Max forward Cg assumed, HTP has down lift mach = flight.speed_from_lift(aircraft, pamb, c_z, mass) [cza_wo_htp, xlc_wo_htp, ki_wing] = frame_aero.wing_aero_data(aircraft, mach, hld_conf) if (nei > 0): dcx_oei = nei * propu.oei_drag(pamb, mach) else: dcx_oei = 0 dw_angle = frame_aero.wing_downwash( aircraft, cz_max_wing) # Downwash angle due to the wing cx_basic, lod_trash = craft_aero.drag( aircraft, pamb, tamb, mach, cz_max_wing) # By definition of the drag_ function cxi_htp = (ki_htp * cz_max_htp**2) * (htp.area / wing.area ) # Induced drag generated by HTP cx_inter = cz_max_htp * dw_angle # Interaction drag (due to downwash) cx_trimmed = cx_basic + cxi_htp + cx_inter + dcx_oei fn = 0.5 * gam * pamb * mach**2 * wing.area * cx_trimmed cm_prop = propu.thrust_pitch_moment(aircraft, fn, pamb, mach, dcx_oei) cg_max_fwd_stall = (cm_prop + xlc_wo_htp * cz_max_wing - xlc_htp * cz_max_htp) / (cz_max_wing - cz_max_htp) aoa_wing = (cz_max_wing - cz0) / cza_wo_htp # Wing angle of attack aoa = aoa_wing - wing.setting # Reference angle of attack (fuselage axis versus air speed) ih = -aoa + dw_angle - aoa_max_htp # HTP trim setting speed = flight.get_speed(pamb, speed_mode, mach) return cg_max_fwd_stall, speed, fn, aoa, ih, c_z, cx_trimmed
def fct_max_path(cz, aircraft, nei, altp, disa, speed_mode, mass, rating, isformax): pamb, tamb, tstd, dtodz = earth.atmosphere(altp, disa) mach = speed_from_lift(aircraft, pamb, cz, mass) speed = get_speed(pamb, speed_mode, mach) [slope, vz] = air_path(aircraft, nei, altp, disa, speed_mode, speed, mass, rating) if (isformax == True): return slope elif (isformax == False): return slope, vz, speed
def ceilings(aircraft, toc, oei_ceil): design_driver = aircraft.design_driver propulsion = aircraft.propulsion weights = aircraft.weights (MTO, MCN, MCL, MCR, FID) = propulsion.rating_code disa = 15 # propulsion ceilings #----------------------------------------------------------------------------------------------------------- nei = 0 altp = toc speed_mode = 2 # WARNING : iso Mach climb mode speed = design_driver.cruise_mach mass = 0.97 * weights.mtow rating = MCL # Max Climb slope, vz_clb = flight.air_path(aircraft, nei, altp, disa, speed_mode, speed, mass, rating) rating = MCR # Max Cruise slope, vz_crz = flight.air_path(aircraft, nei, altp, disa, speed_mode, speed, mass, rating) # One engine inoperative ceiling #----------------------------------------------------------------------------------------------------------- nei = 1 altp = oei_ceil speed_mode = 2 # WARNING : iso Mach climb mode pamb, tamb, tstd, dtodz = earth.atmosphere(altp, disa) speed = earth.vcas_from_mach(pamb, design_driver.cruise_mach) mass = 0.95 * weights.mtow rating = MCN oei_slope, vz, oei_mach, cz = flight.max_path(aircraft, nei, altp, disa, speed_mode, mass, rating) #----------------------------------------------------------------------------------------------------------- return vz_clb, vz_crz, oei_slope, oei_mach
def approach_speed(aircraft, altp, disa, mass, hld_conf): """ Minimum approach speed (VLS) """ wing = aircraft.wing g = earth.gravity() czmax, trash = craft_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 take_off(aircraft, kvs1g, altp, disa, mass, hld_conf): """ Take off field length and climb path at 35 ft depending on stall margin (kVs1g) """ wing = aircraft.wing propulsion = aircraft.propulsion (MTO, MCN, MCL, MCR, FID) = propulsion.rating_code czmax, cz_0 = craft_aero.high_lift(wing, hld_conf) rating = MTO [pamb, tamb, tstd, dtodz] = earth.atmosphere(altp, disa) [rho, sig] = earth.air_density(pamb, tamb) cz_to = czmax / kvs1g**2 mach = flight.speed_from_lift(aircraft, pamb, cz_to, mass) nei = 0 # For Magic Line factor computation fn, trash = propu.thrust(aircraft, pamb, tamb, mach, rating, nei) ml_factor = mass**2 / (cz_to * fn * wing.area * sig**0.8 ) # Magic Line factor tofl = 14.23 * ml_factor + 97.58 nei = 1 # For 2nd segment computation speed_mode = 1 speed = flight.get_speed(pamb, speed_mode, mach) seg2path, vz = flight.air_path(aircraft, nei, altp, disa, speed_mode, speed, mass, rating) return seg2path, tofl
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] = craft_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
run.aircraft_pre_design(aircraft) # Estimate all mass and CGs #------------------------------------------------------------------------------------------------------ run.mass_mission_adaptation(aircraft) #run.mass_estimation(aircraft) # Calculate all airplane performances #------------------------------------------------------------------------------------------------------ run.performance_analysis(aircraft) # Print relevant output #------------------------------------------------------------------------------------------------------ altp = unit.m_ft(35000) disa = 0 pamb, tamb, tstd, dtodz = earth.atmosphere(altp, disa) (MTO, MCN, MCL, MCR, FID) = aircraft.propulsion.rating_code nei = 0 Fn, Data = propu.thrust(aircraft, pamb, tamb, cruise_mach, MTO, nei) vsnd = earth.sound_speed(tamb) tas = vsnd * cruise_mach print("") print("True air speed in cruise", "%.1f" % tas, " m/s") print("Totalthrust in cruise", "%.0f" % Fn, " N") print("") print("Engine thrust = ", "%.1f" % (aircraft.propulsion.reference_thrust_effective / 10), " daN") print("Wing area = ", "%.1f" % aircraft.wing.area, " m2") print("MTOW = ", "%.0f" % aircraft.weights.mtow, " kg") print("OWE = ", "%.0f" % aircraft.weights.owe, " kg")
def eval_propulsion_design(aircraft): """ Propulsion architecture design """ propulsion = aircraft.propulsion propulsion.rating_code = (0, 1, 2, 3, 4) if (propulsion.architecture == 1): engine = aircraft.turbofan_engine eval_turbofan_engine_design(aircraft) eval_turbofan_nacelle_design(aircraft) elif (propulsion.architecture == 2): engine = aircraft.turbofan_engine eval_turbofan_engine_design(aircraft) eval_hybrid_engine_design(aircraft) eval_hybrid_nacelle_design(aircraft) elif (propulsion.architecture == 3): engine = aircraft.turbofan_engine eval_hybrid_turbofan_engine_design(aircraft) eval_hybrid_engine_design(aircraft) eval_hybrid_body_nacelle_design(aircraft) elif (propulsion.architecture == 4): engine = aircraft.turboprop_engine eval_turboprop_engine_design(aircraft) eval_turboprop_nacelle_design(aircraft) else: raise Exception("propulsion.architecture index is out of range") (MTO, MCN, MCL, MCR, FID) = propulsion.rating_code disa = 15. altp = 0. mach = 0.25 nei = 0. (pamb, tamb, tstd, dtodz) = earth.atmosphere(altp, disa) (Fn, Data) = propu.thrust(aircraft, pamb, tamb, mach, MTO, nei) propulsion.reference_thrust_effective = (Fn / engine.n_engine) / 0.80 propulsion.mto_thrust_ref = Fn / engine.n_engine disa = aircraft.low_speed.disa_oei altp = aircraft.low_speed.req_oei_altp mach = 0.5 * aircraft.design_driver.cruise_mach nei = 1. (pamb, tamb, tstd, dtodz) = earth.atmosphere(altp, disa) (Fn, Data) = propu.thrust(aircraft, pamb, tamb, mach, MCN, nei) propulsion.mcn_thrust_ref = Fn / (engine.n_engine - nei) disa = 0. altp = aircraft.design_driver.ref_cruise_altp mach = aircraft.design_driver.cruise_mach nei = 0. (pamb, tamb, tstd, dtodz) = earth.atmosphere(altp, disa) propulsion.sfc_cruise_ref = propu.sfc(aircraft, pamb, tamb, mach, MCR, nei) if (propulsion.architecture == 1): sec = 0. elif (propulsion.architecture == 2): fn, sec, data = propu.hybrid_thrust(aircraft, pamb, tamb, mach, MCR, nei) elif (propulsion.architecture == 3): fn, sec, data = propu.hybrid_thrust(aircraft, pamb, tamb, mach, MCR, nei) elif (propulsion.architecture == 4): sec = 0. else: raise Exception("propulsion.architecture index is out of range") propulsion.sec_cruise_ref = sec (Fn, Data) = propu.thrust(aircraft, pamb, tamb, mach, FID, nei) propulsion.fid_thrust_ref = Fn / engine.n_engine disa = 0. altp = aircraft.design_driver.top_of_climb_altp mach = aircraft.design_driver.cruise_mach nei = 0. (pamb, tamb, tstd, dtodz) = earth.atmosphere(altp, disa) (Fn, Data) = propu.thrust(aircraft, pamb, tamb, mach, MCL, nei) propulsion.mcl_thrust_ref = Fn / engine.n_engine (Fn, Data) = propu.thrust(aircraft, pamb, tamb, mach, MCR, nei) propulsion.mcr_thrust_ref = Fn / engine.n_engine return
def eval_pre_design_wing(aircraft): """ Wing predesign """ design_driver = aircraft.design_driver fuselage = aircraft.fuselage vtp = aircraft.vertical_tail nacelle = aircraft.turbofan_nacelle weights = aircraft.weights 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 = nacelle.y_ext 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 = craft_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 #----------------------------------------------------------------------------------------------------------- fuel_total = fuel_mission * ( 1 + regul.reserve_fuel_ratio()) + fuel_diversion + fuel_holding #----------------------------------------------------------------------------------------------------------- return block_fuel, time_block, fuel_total
def eval_hybrid_engine_design(aircraft): """ Thermal propulsive architecture design """ design_driver = aircraft.design_driver fuselage = aircraft.fuselage propulsion = aircraft.propulsion engine = aircraft.turbofan_engine nacelle = aircraft.turbofan_nacelle battery = aircraft.battery power_elec = aircraft.power_elec_chain e_engine = aircraft.electric_engine e_nacelle = aircraft.electric_nacelle low_speed = aircraft.low_speed (MTO, MCN, MCL, MCR, FID) = propulsion.rating_code # Propulsion architecture design #----------------------------------------------------------------------------------------------------------- # Initialisation crm = design_driver.cruise_mach toc = design_driver.top_of_climb_altp rca = design_driver.ref_cruise_altp roa = low_speed.req_oei_altp # MTO MCN MCL MCR FIR fd_disa = numpy.array([15., 0., 0., 0., 0.]) fd_altp = numpy.array([0., roa, toc, rca, rca]) fd_mach = numpy.array([0.25, crm / 2, crm, crm, crm]) fd_nei = numpy.array([0., 1., 0., 0., 0.]) e_engine.flight_data = { "disa": fd_disa, "altp": fd_altp, "mach": fd_mach, "nei": fd_nei } e_fan_power = numpy.array([ power_elec.mto, power_elec.mcn, power_elec.mcl, power_elec.mcr, power_elec.fid ]) # Battery power feed is used in temporary phases only battery_power_feed = numpy.array([1,0,1,0,0])*battery.power_feed \ *e_nacelle.controler_efficiency \ *e_nacelle.motor_efficiency e_power_ratio = numpy.zeros(5) e_shaft_power = numpy.zeros(5) for rating in propulsion.rating_code: (Pamb, Tamb, Tstd, dTodZ) = earth.atmosphere(fd_altp[rating], fd_disa[rating]) (fn, data) = propu.turbofan_thrust(aircraft, Pamb, Tamb, fd_mach[rating], rating, fd_nei[rating]) (fn_core, fn_fan0, fn0, shaft_power0) = data if e_fan_power[rating] > 1: # required eFan shaft power is given # Fraction of the turbofan shaft power dedicated to electric generation e_power_ratio[rating] = ( (e_fan_power[rating] - battery_power_feed[rating] \ )/ power_elec.overall_efficiency \ )/((shaft_power0)*(engine.n_engine-fd_nei[rating])) # e-fan shaft power e_shaft_power[rating] = e_fan_power[rating] else: # required turbofan shaft power ration is given # Shaft power dedicated to electric generator shaft_power2 = e_power_ratio[rating] * shaft_power0 * ( engine.n_engine - fd_nei[rating]) # Fraction of the shaft power dedicated to the electric generation e_power_ratio[rating] = e_fan_power[rating] e_shaft_power[rating] = shaft_power2*power_elec.overall_efficiency \ + battery_power_feed[rating] e_engine.mto_e_power_ratio = e_power_ratio[MTO] e_engine.mcn_e_power_ratio = e_power_ratio[MCN] e_engine.mcl_e_power_ratio = e_power_ratio[MCL] e_engine.mcr_e_power_ratio = e_power_ratio[MCR] e_engine.fid_e_power_ratio = e_power_ratio[FID] e_engine.mto_e_shaft_power = e_shaft_power[MTO] e_engine.mcn_e_shaft_power = e_shaft_power[MCN] e_engine.mcl_e_shaft_power = e_shaft_power[MCL] e_engine.mcr_e_shaft_power = e_shaft_power[MCR] e_engine.fid_e_shaft_power = e_shaft_power[FID] # Engine performance update #----------------------------------------------------------------------------------------------------------- (Pamb, Tamb, Tstd, dTodZ) = earth.atmosphere(fd_altp[MTO], fd_disa[MTO]) (fn, data) = propu.turbofan_thrust(aircraft, Pamb, Tamb, fd_mach[MTO], MTO, fd_nei[MTO]) (fn_core, fn_fan0, fn0, shaft_power0) = data shaft_power1 = (1 - e_power_ratio[MTO] ) * shaft_power0 # Shaft power dedicated to the fan Vsnd = earth.sound_speed(Tamb) Vair = Vsnd * fd_mach[MTO] fn_fan1 = nacelle.efficiency_prop * shaft_power1 / Vair # Effective fan thrust engine.kfn_off_take = ( fn_core + fn_fan1) / fn0 # Thrust reduction due to power off take for the e-fan return
def eval_hybrid_nacelle_design(aircraft): """ Hybrid propulsive architecture design """ design_driver = aircraft.design_driver fuselage = aircraft.fuselage wing = aircraft.wing propulsion = aircraft.propulsion engine = aircraft.turbofan_engine nacelle = aircraft.turbofan_nacelle e_engine = aircraft.electric_engine e_nacelle = aircraft.electric_nacelle (MTO, MCN, MCL, MCR, FID) = propulsion.rating_code # Turbofan nacelles geometry adjustment #----------------------------------------------------------------------------------------------------------- nacWidth0 = 0.49 * engine.bpr**0.67 + 4.8e-6 * engine.reference_thrust # Reference dimensions of the nacelle without power off take nacLength0 = 0.86 * nacWidth0 + engine.bpr**0.37 kSize = math.sqrt( engine.kfn_off_take) # Diameter decrease due to max thrust decrease kSize_eff = (kSize + engine.core_width_ratio * (1 - kSize) ) # Diameter decrease considering core is unchanged nacelle.width = nacWidth0 * kSize_eff # Real nacelle diameter assuming core section remains unchanged nacelle.length = nacLength0 * kSize_eff # Nacelle length is reduced according to the same factor knac = math.pi * nacelle.width * nacelle.length nacelle.net_wetted_area = knac * (1.48 - 0.0076 * knac) * engine.n_engine tan_phi0 = 0.25 * (wing.c_kink - wing.c_tip) / ( wing.y_tip - wing.y_kink) + numpy.tan(wing.sweep) if (nacelle.attachment == 1): nacelle.y_ext = 0.7 * fuselage.width + 1.4 * nacelle.width # statistical regression nacelle.x_ext = wing.x_root + ( nacelle.y_ext - wing.y_root) * tan_phi0 - 0.7 * nacelle.length nacelle.z_ext = - 0.5 * fuselage.height \ + (nacelle.y_ext - 0.5 * fuselage.width) * math.tan(wing.dihedral) \ - 0.5*nacelle.width elif (nacelle.attachment == 2): nacelle.y_ext = 0.5 * fuselage.width + 0.6 * nacelle.width # statistical regression nacelle.x_ext = wing.x_root + ( nacelle.y_ext - wing.y_root) * tan_phi0 - 0.7 * nacelle.length nacelle.z_ext = 0.5 * fuselage.height # Electric nacelle is design for cruise conditions #----------------------------------------------------------------------------------------------------------- dISA = 0. Altp = design_driver.ref_cruise_altp Mach = design_driver.cruise_mach (Pamb, Tamb, Tstd, dTodZ) = earth.atmosphere(Altp, dISA) shaft_power = e_engine.mcr_e_shaft_power hub_width = 0.5 # Diameter of the e fan hub body_length = fuselage.length body_width = fuselage.width eval_bli_nacelle_design(e_nacelle, Pamb, Tamb, Mach, shaft_power, hub_width, body_length, body_width) e_nacelle.x_ext = fuselage.length + 0.2 * e_nacelle.width e_nacelle.y_ext = 0 e_nacelle.z_ext = 0.91 * fuselage.height - 0.51 * fuselage.height # Engine performance update #----------------------------------------------------------------------------------------------------------- fd = e_engine.flight_data e_fan_thrust = numpy.zeros(5) for rating in propulsion.rating_code: altp = fd.get("altp")[rating] disa = fd.get("disa")[rating] mach = fd.get("mach")[rating] nei = fd.get("nei")[rating] (Pamb, Tamb, Tstd, dTodZ) = earth.atmosphere(altp, disa) (fn, sec, data) = propu.hybrid_thrust(aircraft, Pamb, Tamb, mach, rating, nei) (fn_core, fn_fan1, fn_fan2, dVbli_o_V, shaft_power2, fn0, shaft_power0) = data e_fan_thrust[rating] = fn_fan2 e_engine.mto_e_fan_thrust = e_fan_thrust[MTO] e_engine.mcn_e_fan_thrust = e_fan_thrust[MCN] e_engine.mcl_e_fan_thrust = e_fan_thrust[MCL] e_engine.mcr_e_fan_thrust = e_fan_thrust[MCR] e_engine.fid_e_fan_thrust = e_fan_thrust[FID] Vair = Mach * earth.sound_speed(Tamb) (eFanFnBli, q1, dVbli) = propu.fan_thrust_with_bli(e_nacelle, Pamb, Tamb, Mach, Vair, shaft_power) (eFanFn, q0) = propu.fan_thrust(e_nacelle, Pamb, Tamb, Mach, Vair, shaft_power) propulsion.bli_e_thrust_factor = eFanFnBli / eFanFn # Thrust increase due to BLI at iso shaft power propulsion.bli_thrust_factor = 1 # Thrust increase due to BLI at iso shaft power return
def eval_hybrid_body_nacelle_design(aircraft): """ Hybrid propulsive architecture design """ design_driver = aircraft.design_driver fuselage = aircraft.fuselage wing = aircraft.wing propulsion = aircraft.propulsion engine = aircraft.turbofan_engine nacelle = aircraft.turbofan_nacelle body = aircraft.body_nacelle e_engine = aircraft.electric_engine e_nacelle = aircraft.electric_nacelle (MTO, MCN, MCL, MCR, FID) = propulsion.rating_code #----------------------------------------------------------------------------------------------------------- tan_phi0 = 0.25 * (wing.c_kink - wing.c_tip) / ( wing.y_tip - wing.y_kink) + numpy.tan(wing.sweep) body.y_ext = 0.8 * fuselage.width + 1.5 * nacelle.width # statistical regression body.x_ext = wing.x_root + (nacelle.y_ext - wing.y_root) * tan_phi0 - 0.5 * body.length body.z_ext = - 0.5 * fuselage.height \ + (nacelle.y_ext - 0.5 * fuselage.width) * math.tan(wing.dihedral) \ - 0.5*nacelle.width body.net_wetted_area = 2.7 * body.length * body.width * engine.n_engine # All bodies wetted area # Turbofan nacelles geometry is designed according to cruise conditions #----------------------------------------------------------------------------------------------------------- dISA = 0. Altp = design_driver.ref_cruise_altp Mach = design_driver.cruise_mach nei = 0 (Pamb, Tamb, Tstd, dTodZ) = earth.atmosphere(Altp, dISA) fn, data = propu.turbofan_thrust(aircraft, Pamb, Tamb, Mach, MCR, nei) (fn_core, fn_fan0, fn0, shaft_power0) = data shaft_power1 = (1 - e_engine.mcr_e_power_ratio ) * shaft_power0 # Shaft power dedicated to the fan body_hub_width = body.hub_width # Diameter of the fan hub body_length = body.length body_width = body.width eval_bli_nacelle_design(nacelle, Pamb, Tamb, Mach, shaft_power1, body_hub_width, body_length, body_width) nacelle.y_ext = body.y_ext nacelle.x_ext = body.x_ext + body.length nacelle.z_ext = body.z_ext # Electric nacelle is design for cruise conditions #----------------------------------------------------------------------------------------------------------- dISA = 0. Altp = design_driver.ref_cruise_altp Mach = design_driver.cruise_mach (Pamb, Tamb, Tstd, dTodZ) = earth.atmosphere(Altp, dISA) shaft_power = e_engine.mcr_e_shaft_power efan_hub_width = 0.5 # Diameter of the e fan hub body_length = fuselage.length body_width = fuselage.width eval_bli_nacelle_design(e_nacelle, Pamb, Tamb, Mach, shaft_power, efan_hub_width, body_length, body_width) e_nacelle.x_ext = fuselage.length + 0.2 * e_nacelle.width e_nacelle.y_ext = 0 e_nacelle.z_ext = 0.91 * fuselage.height - 0.51 * fuselage.height # Engine performance update #----------------------------------------------------------------------------------------------------------- fd = e_engine.flight_data e_fan_thrust = numpy.zeros(5) for rating in propulsion.rating_code: altp = fd.get("altp")[rating] disa = fd.get("disa")[rating] mach = fd.get("mach")[rating] nei = fd.get("nei")[rating] (Pamb, Tamb, Tstd, dTodZ) = earth.atmosphere(altp, disa) (fn, sec, data) = propu.hybrid_thrust(aircraft, Pamb, Tamb, mach, rating, nei) (fn_core, fn_fan1, fn_fan2, dVbli_o_V, shaft_power2, fn0, shaft_power0) = data e_fan_thrust[rating] = fn_fan2 e_engine.mto_e_fan_thrust = e_fan_thrust[MTO] e_engine.mcn_e_fan_thrust = e_fan_thrust[MCN] e_engine.mcl_e_fan_thrust = e_fan_thrust[MCL] e_engine.mcr_e_fan_thrust = e_fan_thrust[MCR] e_engine.fid_e_fan_thrust = e_fan_thrust[FID] Vair = Mach * earth.sound_speed(Tamb) (eFanFnBli, q1, dVbli) = propu.fan_thrust_with_bli(e_nacelle, Pamb, Tamb, Mach, Vair, shaft_power) (eFanFn, q0) = propu.fan_thrust(e_nacelle, Pamb, Tamb, Mach, Vair, shaft_power) propulsion.bli_e_thrust_factor = eFanFnBli / eFanFn # Thrust increase due to BLI at iso shaft power (FanFnBli, q1, dVbli) = propu.fan_thrust_with_bli(nacelle, Pamb, Tamb, Mach, Vair, shaft_power) (FanFn, q0) = propu.fan_thrust(nacelle, Pamb, Tamb, Mach, Vair, shaft_power) propulsion.bli_thrust_factor = FanFnBli / FanFn # Thrust increase due to BLI at iso shaft power return
def performance_analysis(aircraft): """ Compute operational performances """ # Nominal mission (here : range is an output) #------------------------------------------------------------------------------------------------------ disa = 0. altp = aircraft.design_driver.ref_cruise_altp mach = aircraft.design_driver.cruise_mach nei = 0. (MTO, MCN, MCL, MCR, FID) = aircraft.propulsion.rating_code pamb, tamb, tstd, dtodz = earth.atmosphere(altp, disa) lod_max, _ = craft_aero.lod_max(aircraft, pamb, tamb, mach) sfc = propu.sfc(aircraft, pamb, tamb, mach, MCR, nei) aircraft.high_speed.cruise_lod = lod_max aircraft.high_speed.cruise_sfc = sfc aircraft.nominal_mission.payload = aircraft.payload.nominal aircraft.nominal_mission.range = aircraft.design_driver.design_range aircraft.nominal_mission.tow = aircraft.weights.mtow payload = aircraft.nominal_mission.payload tow = aircraft.nominal_mission.tow range, block_fuel, block_time, total_fuel = sub_proc.mission_range( aircraft, tow, payload, altp, mach, disa) aircraft.nominal_mission.range = range aircraft.nominal_mission.block_fuel = block_fuel aircraft.nominal_mission.block_time = block_time aircraft.nominal_mission.total_fuel = total_fuel # Ceilings #------------------------------------------------------------------------------------------------------ toc = aircraft.design_driver.top_of_climb_altp oei_ceil_req = aircraft.low_speed.req_oei_altp vz_clb, vz_crz, oei_path, oei_mach = perfo.ceilings( aircraft, toc, oei_ceil_req) aircraft.high_speed.eff_vz_climb = vz_clb aircraft.high_speed.eff_vz_cruise = vz_crz aircraft.low_speed.eff_oei_path = oei_path # Time to climb to requested altitude #------------------------------------------------------------------------------------------------------ toc = aircraft.high_speed.req_toc_altp disa = 0 mass = aircraft.weights.mtow vcas1 = aircraft.high_speed.cas1_ttc vcas2 = aircraft.high_speed.cas2_ttc mach = aircraft.design_driver.cruise_mach ttc = perfo.time_to_climb(aircraft, toc, disa, mass, vcas1, vcas2, mach) aircraft.high_speed.eff_ttc = ttc # Take off field length #------------------------------------------------------------------------------------------------------ altp = aircraft.low_speed.altp_tofl disa = aircraft.low_speed.disa_tofl mass = aircraft.weights.mtow hld_conf_to = aircraft.aerodynamics.hld_conf_to tofl, seg2_path, eff_kvs1g, limitation = perfo.take_off_field_length( aircraft, altp, disa, mass, hld_conf_to) aircraft.low_speed.eff_tofl = tofl aircraft.low_speed.eff_kvs1g = eff_kvs1g aircraft.low_speed.seg2_path = seg2_path aircraft.low_speed.limitation = limitation # Approach speed #------------------------------------------------------------------------------------------------------ altp = aircraft.low_speed.altp_app_speed disa = aircraft.low_speed.disa_app_speed mass = aircraft.weights.mlw hld_conf_ld = aircraft.aerodynamics.hld_conf_to app_speed = perfo.approach_speed(aircraft, altp, disa, mass, hld_conf_ld) aircraft.low_speed.eff_app_speed = app_speed # Environment #------------------------------------------------------------------------------------------------------ CO2_metric, rgf = environ.fuel_efficiency_metric(aircraft) aircraft.environmental_impact.rgf = rgf aircraft.environmental_impact.CO2_metric = CO2_metric # Cost mission #----------------------------------------------------------------------------------------------------------------------------------------------- altp = aircraft.design_driver.ref_cruise_altp mach = aircraft.design_driver.cruise_mach disa = aircraft.cost_mission.disa range = aircraft.cost_mission.range payload = aircraft.payload.nominal aircraft.cost_mission.payload = payload tow, block_fuel, block_time, total_fuel = sub_proc.mission_tow( aircraft, payload, range, altp, mach, disa) aircraft.cost_mission.block_fuel = block_fuel aircraft.cost_mission.block_time = block_time aircraft.cost_mission.total_fuel = total_fuel aircraft.cost_mission.block_CO2 = block_fuel * aircraft.environmental_impact.CO2_index # Economics #------------------------------------------------------------------------------------------------------ direct_op_cost, cash_op_cost, block_fuel, engine_price, airplane_price = costing.operating_costs( aircraft, block_fuel, block_time) aircraft.economics.engine_price = engine_price aircraft.economics.airplane_price = airplane_price aircraft.economics.direct_operating_cost = direct_op_cost aircraft.economics.cash_operating_cost = cash_op_cost return
def vertical_tail_sizing(aircraft): """ Computes necessary VTP area variation to meet engine failure case constraint Influence of CG position is ignored """ design_driver = aircraft.design_driver propulsion = aircraft.propulsion wing = aircraft.wing vtp = aircraft.vertical_tail aerodynamics = aircraft.aerodynamics payload = aircraft.payload c_of_g = aircraft.center_of_gravity (MTO, MCN, MCL, MCR, FID) = propulsion.rating_code cyb_vtp, xlc_vtp, aoa_max_vtp, ki_vtp = frame_aero.vtp_aero_data(aircraft) payload = 0.5 * payload.nominal # Light payload range = design_driver.design_range / 15 # Short mission altp = design_driver.ref_cruise_altp mach = design_driver.cruise_mach disa = 30 # Hot condition tow, block_fuel, block_time, total_fuel = sub_proc.mission_tow( aircraft, payload, range, altp, mach, disa) altp = 0 disa = 15 pamb, tamb, tstd, dtodz = earth.atmosphere(altp, disa) stall_margin = regul.kvs1g_min_take_off() czmax_to = aerodynamics.cz_max_to mach_s1g = flight.speed_from_lift(aircraft, pamb, czmax_to, tow) mach_35ft = stall_margin * mach_s1g # V2 speed mach_mca = mach_35ft / 1.1 #Approximation of required VMCA altp = 0 disa = 15 nei = 1 pamb, tamb, tstd, dtodz = earth.atmosphere(altp, disa) fn, data = propu.thrust(aircraft, pamb, tamb, mach_mca, MTO, nei) dcx_oei = propu.oei_drag(aircraft, pamb, tamb) cn_prop = propu.thrust_yaw_moment(aircraft, fn, pamb, mach_mca, dcx_oei) x_cg = c_of_g.max_bwd_req_cg cyb_vtp_req = (cn_prop * wing.mac) / ((xlc_vtp - x_cg) * aoa_max_vtp) k_vtp_area = cyb_vtp_req / cyb_vtp d_vtp_area = (k_vtp_area - 1) * vtp.area return d_vtp_area