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 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 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 thrust_yaw_moment(aircraft, fn, pamb, mach, dcx_oei): """ Assumed right engine inoperative """ propulsion = aircraft.propulsion wing = aircraft.wing gam = earth.heat_ratio() if (propulsion.architecture == 1): nacelle = aircraft.turbofan_nacelle elif (propulsion.architecture == 2): nacelle = aircraft.turbofan_nacelle elif (propulsion.architecture == 3): nacelle = aircraft.turbofan_nacelle elif (propulsion.architecture == 4): nacelle = aircraft.turboprop_nacelle else: raise Exception("propulsion.architecture index is out of range") cn_prop = (nacelle.y_ext / wing.mac) * (fn / (0.5 * gam * pamb * mach**2 * wing.area) + dcx_oei) return cn_prop
def thrust_pitch_moment(aircraft, fn, pamb, mach, dcx_oei): propulsion = aircraft.propulsion wing = aircraft.wing gam = earth.heat_ratio() if (propulsion.architecture == 1): nacelle = aircraft.turbofan_nacelle elif (propulsion.architecture == 2): nacelle = aircraft.turbofan_nacelle elif (propulsion.architecture == 3): nacelle = aircraft.turbofan_nacelle elif (propulsion.architecture == 4): nacelle = aircraft.turboprop_nacelle else: raise Exception("propulsion.architecture index is out of range") cm_prop = nacelle.z_ext * (dcx_oei - fn / (0.5 * gam * pamb * mach**2 * wing.area)) return cm_prop
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 corrected_air_flow(Ptot, Ttot, Mach): """ Computes the corrected air flow per square meter """ R = earth.gaz_constant() gam = earth.heat_ratio() f_M = Mach * (1. + 0.5 * (gam - 1) * Mach**2)**(-(gam + 1.) / (2. * (gam - 1.))) CQoA = (math.sqrt(gam / R) * Ptot / math.sqrt(Ttot)) * f_M return CQoA
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 eval_bli_nacelle_design(this_nacelle, Pamb, Tamb, Mach, shaft_power, hub_width, body_length, body_width): """ BLI nacelle design """ gam = earth.heat_ratio() r = earth.gaz_constant() Cp = earth.heat_constant(gam, r) (rho, sig) = earth.air_density(Pamb, Tamb) Vsnd = earth.sound_speed(Tamb) Re = craft_aero.reynolds_number(Pamb, Tamb, Mach) Vair = Vsnd * Mach # Precalculation of the relation between d0 and d1 #----------------------------------------------------------------------------------------------------------- body_bnd_layer = eval_boundary_layer(body_width, hub_width) # Electrical nacelle geometry : e-nacelle diameter is size by cruise conditions #----------------------------------------------------------------------------------------------------------- r0 = 0.5 * body_width # Radius of the fuselage, supposed constant d0 = craft_aero.boundary_layer( Re, body_length ) # theoritical thickness of the boundary layer without taking account of fuselage tapering r1 = 0.5 * hub_width # Radius of the hub of the efan nacelle d1 = lin_interp_1d(d0, body_bnd_layer[:, 0], body_bnd_layer[:, 1]) # Thickness of the BL around the hub deltaV = 2. * Vair * ( this_nacelle.efficiency_fan / this_nacelle.efficiency_prop - 1. ) # speed variation produced by the fan PwInput = this_nacelle.efficiency_fan * shaft_power # kinetic energy produced by the fan #=========================================================================================================== def fct_power_1(y, PwInput, deltaV, rho, Vair, r1, d1): (q0, q1, q2, v1, dVbli) = craft_aero.air_flows(rho, Vair, r1, d1, y) Vinlet = Vair - dVbli Vjet = Vinlet + deltaV Pw = 0.5 * q1 * (Vjet**2 - Vinlet**2) y = PwInput - Pw return y #----------------------------------------------------------------------------------------------------------- fct_arg = (PwInput, deltaV, rho, Vair, r1, d1) # Computation of y1 : thickness of the vein swallowed by the inlet output_dict = fsolve(fct_power_1, x0=d1, args=fct_arg, full_output=True) y1 = output_dict[0][0] (q0, q1, q2, v1, dVbli) = craft_aero.air_flows(rho, Vair, r1, d1, y1) MachInlet = v1 / Vsnd # Mean Mach number at inlet position Ptot = earth.total_pressure( Pamb, MachInlet) # Stagnation pressure at inlet position Ttot = earth.total_temperature( Tamb, MachInlet) # Stagnation temperature at inlet position MachFan = 0.5 # required Mach number at fan position CQoA1 = craft_aero.corrected_air_flow( Ptot, Ttot, MachFan) # Corrected air flow per area at fan position eFanArea = q1 / CQoA1 # Fan area around the hub fan_width = math.sqrt(hub_width**2 + 4 * eFanArea / math.pi) # Fan diameter Vjet = v1 + deltaV # Jet velocity TtotJet = Ttot + shaft_power / ( q1 * Cp) # Stagnation pressure increases due to introduced work Tstat = TtotJet - 0.5 * Vjet**2 / Cp # static temperature VsndJet = math.sqrt(gam * r * Tstat) # Sound velocity at nozzle exhaust MachJet = Vjet / VsndJet # Mach number at nozzle output PtotJet = earth.total_pressure( Pamb, MachJet) # total pressure at nozzle exhaust (P = Pamb) CQoA2 = craft_aero.corrected_air_flow( PtotJet, TtotJet, MachJet) # Corrected air flow per area at nozzle output nozzle_area = q1 / CQoA2 # Fan area around the hub nozzle_width = math.sqrt(4 * nozzle_area / math.pi) # Nozzle diameter this_nacelle.hub_width = hub_width this_nacelle.fan_width = fan_width this_nacelle.nozzle_width = nozzle_width this_nacelle.nozzle_area = nozzle_area this_nacelle.width = 1.19 * fan_width # Surrounding structure this_nacelle.length = 1.68 * this_nacelle.width this_nacelle.net_wetted_area = math.pi * this_nacelle.width * this_nacelle.length # Nacelle wetted area this_nacelle.bnd_layer = body_bnd_layer this_nacelle.body_length = body_length return
def fan_thrust_with_bli(nacelle, Pamb, Tamb, Mach, Vair, PwShaft): """ Compute the thrust of a fan of a given geometry swallowing the boundary layer (BL) of a body of a given geometry The amount of swallowed BL depends on the given shaft power and flying conditions. """ bnd_layer = nacelle.bnd_layer gam = earth.heat_ratio() r = earth.gaz_constant() Cp = earth.heat_constant(gam, r) Re = craft_aero.reynolds_number(Pamb, Tamb, Mach) (rho, sig) = earth.air_density(Pamb, Tamb) Vsnd = earth.sound_speed(Tamb) d0 = craft_aero.boundary_layer( Re, nacelle.body_length ) # theorical thickness of the boundary layer without taking account of fuselage tapering r1 = 0.5 * nacelle.hub_width # Radius of the hub of the eFan nacelle d1 = lin_interp_1d(d0, bnd_layer[:, 0], bnd_layer[:, 1]) # Using the precomputed relation #=========================================================================================================== def fct_power_bli(y, PwShaft, Tamb, Pamb, rho, Mach, Vair, Vsnd, r1, d1, nozzle_area): Ttot = earth.total_temperature( Tamb, Mach) # Stagnation temperature at inlet position (q0, q1, q2, Vinlet, dVbli) = craft_aero.air_flows(rho, Vair, r1, d1, y) Tstat = Ttot - 0.5 * Vinlet**2 / Cp # Static temperature at inlet position Vsnd_inlet = earth.sound_speed(Tstat) # Sound speed at inlet position MachInlet = Vinlet / Vsnd_inlet # Mean Mach number at inlet position PwInput = nacelle.efficiency_fan * PwShaft Vjet = math.sqrt(2. * PwInput / q1 + Vinlet**2) TtotJet = Ttot + PwShaft / ( q1 * Cp) # Stagnation temperature increases due to introduced work Tstat = TtotJet - 0.5 * Vjet**2 / Cp # Static temperature VsndJet = earth.sound_speed(Tstat) # Sound speed at nozzle exhaust MachJet = Vjet / VsndJet # Mach number at nozzle output PtotJet = earth.total_pressure( Pamb, MachJet) # total pressure at nozzle exhaust (P = Pamb) CQoA1 = craft_aero.corrected_air_flow( PtotJet, TtotJet, MachJet) # Corrected air flow per area at fan position q = CQoA1 * nozzle_area y = q1 - q return y #----------------------------------------------------------------------------------------------------------- nozzle_area = nacelle.nozzle_area fct_arg = (PwShaft, Tamb, Pamb, rho, Mach, Vair, Vsnd, r1, d1, nozzle_area) # Computation of y1 : thikness of the vein swallowed by the inlet output_dict = fsolve(fct_power_bli, x0=0.50, args=fct_arg, full_output=True) y = output_dict[0][0] Ttot = earth.total_temperature( Tamb, Mach) # Stagnation temperature at inlet position (q0, q1, q2, Vinlet, dVbli) = craft_aero.air_flows(rho, Vair, r1, d1, y) Tstat = Ttot - 0.5 * Vinlet**2 / Cp # Static temperature at inlet position Vsnd_inlet = earth.sound_speed(Tstat) # Sound speed at inlet position MachInlet = Vinlet / Vsnd_inlet # Mean Mach number at inlet position PwInput = nacelle.efficiency_fan * PwShaft Vjet = math.sqrt(2. * PwInput / q1 + Vinlet**2) eFn = q1 * (Vjet - Vinlet) return (eFn, q1, dVbli)