def compute(self, inputs, outputs, discrete_inputs=None, discrete_outputs=None): # Sizing constraints for the vertical tail. # Limiting cases: rotating torque objective (cn_beta_goal) during cruise, and # compensation of engine failure induced torque at approach speed/altitude. # Returns maximum area. propulsion_model = FuelEngineSet( self._engine_wrapper.get_model(inputs), inputs["data:geometry:propulsion:count"] ) engine_number = inputs["data:geometry:propulsion:count"] wing_area = inputs["data:geometry:wing:area"] span = inputs["data:geometry:wing:span"] l0_wing = inputs["data:geometry:wing:MAC:length"] cg_mac_position = inputs["data:weight:aircraft:CG:aft:MAC_position"] cn_beta_fuselage = inputs["data:aerodynamics:fuselage:cruise:CnBeta"] cl_alpha_vt = inputs["data:aerodynamics:vertical_tail:cruise:CL_alpha"] cruise_speed = inputs["data:TLAR:v_cruise"] approach_speed = inputs["data:TLAR:v_approach"] cruise_altitude = inputs["data:mission:sizing:main_route:cruise:altitude"] wing_htp_distance = inputs["data:geometry:vertical_tail:MAC:at25percent:x:from_wingMAC25"] nac_wet_area = inputs["data:geometry:propulsion:nacelle:wet_area"] y_nacelle = inputs["data:geometry:propulsion:nacelle:y"] # CASE1: OBJECTIVE TORQUE @ CRUISE ############################################################################# atm = Atmosphere(cruise_altitude) speed_of_sound = atm.speed_of_sound cruise_mach = cruise_speed / speed_of_sound # Matches suggested goal by Raymer, Fig 16.20 cn_beta_goal = 0.0569 - 0.01694 * cruise_mach + 0.15904 * cruise_mach ** 2 required_cnbeta_vtp = cn_beta_goal - cn_beta_fuselage distance_to_cg = wing_htp_distance + 0.25 * l0_wing - cg_mac_position * l0_wing area_1 = required_cnbeta_vtp / (distance_to_cg / wing_area / span * cl_alpha_vt) # CASE2: ENGINE FAILURE COMPENSATION DURING CLIMB ############################################################## failure_altitude = 5000.0 # CS23 for Twin engine - at 5000ft atm = Atmosphere(failure_altitude) speed_of_sound = atm.speed_of_sound pressure = atm.pressure if engine_number == 2.0: stall_speed = approach_speed / 1.3 mc_speed = 1.2 * stall_speed # Flights mechanics from GA - Serge Bonnet CS23 mc_mach = mc_speed / speed_of_sound # Calculation of engine power for given conditions flight_point = FlightPoint( mach=mc_mach, altitude=failure_altitude, engine_setting=EngineSetting.CLIMB, thrust_rate=1.0 ) # forced to maximum thrust propulsion_model.compute_flight_points(flight_point) thrust = float(flight_point.thrust) # Calculation of engine thrust and nacelle drag (failed one) nac_drag = 0.07 * nac_wet_area # FIXME: the form factor should not be fixed outside propulsion module! # Torque compensation area_2 = ( 2 * (y_nacelle / wing_htp_distance) * (thrust + nac_drag) / (pressure * mc_mach ** 2 * 0.9 * 0.42 * 10) ) else: area_2 = 0.0 outputs["data:geometry:vertical_tail:area"] = max(area_1, area_2)
def compute(self, inputs, outputs, discrete_inputs=None, discrete_outputs=None): # Sizing constraints for the horizontal tail (methods from Torenbeek). # Limiting cases: Rotating power at takeoff/landing, with the most # forward CG position. Returns maximum area. propulsion_model = FuelEngineSet( self._engine_wrapper.get_model(inputs), inputs["data:geometry:propulsion:count"]) n_engines = inputs["data:geometry:propulsion:count"] cg_range = inputs["settings:weight:aircraft:CG:range"] takeoff_t_rate = inputs["data:mission:sizing:takeoff:thrust_rate"] wing_area = inputs["data:geometry:wing:area"] x_wing_aero_center = inputs["data:geometry:wing:MAC:at25percent:x"] lp_ht = inputs[ "data:geometry:horizontal_tail:MAC:at25percent:x:from_wingMAC25"] wing_mac = inputs["data:geometry:wing:MAC:length"] mtow = inputs["data:weight:aircraft:MTOW"] mlw = inputs["data:weight:aircraft:MLW"] x_cg_aft = inputs["data:weight:aircraft:CG:aft:x"] z_cg_aircraft = inputs["data:weight:aircraft_empty:CG:z"] z_cg_engine = inputs["data:weight:propulsion:engine:CG:z"] x_lg = inputs["data:weight:airframe:landing_gear:main:CG:x"] cl0_clean = inputs["data:aerodynamics:wing:low_speed:CL0_clean"] cl_max_clean = inputs["data:aerodynamics:wing:low_speed:CL_max_clean"] cl_max_landing = inputs["data:aerodynamics:aircraft:landing:CL_max"] cl_max_takeoff = inputs["data:aerodynamics:aircraft:takeoff:CL_max"] cl_flaps_landing = inputs["data:aerodynamics:flaps:landing:CL"] cl_flaps_takeoff = inputs["data:aerodynamics:flaps:takeoff:CL"] tail_efficiency_factor = inputs[ "data:aerodynamics:horizontal_tail:efficiency"] cl_htp_landing = inputs["landing:cl_htp"] cl_htp_takeoff = inputs["takeoff:cl_htp"] cm_landing = inputs[ "data:aerodynamics:wing:low_speed:CM0_clean"] + inputs[ "data:aerodynamics:flaps:landing:CM"] cm_takeoff = inputs[ "data:aerodynamics:wing:low_speed:CM0_clean"] + inputs[ "data:aerodynamics:flaps:takeoff:CM"] cl_alpha_htp_isolated = inputs["low_speed:cl_alpha_htp_isolated"] z_eng = z_cg_aircraft - z_cg_engine # Conditions for calculation atm = Atmosphere(0.0) rho = atm.density # CASE1: TAKE-OFF ############################################################################################## # method extracted from Torenbeek 1982 p325 # Calculation of take-off minimum speed weight = mtow * g vs0 = math.sqrt(weight / (0.5 * rho * wing_area * cl_max_takeoff)) vs1 = math.sqrt(weight / (0.5 * rho * wing_area * cl_max_clean)) # Rotation speed requirement from FAR 23.51 (depends on number of engines) if n_engines == 1: v_r = vs1 * 1.0 else: v_r = vs1 * 1.1 # Definition of max forward gravity center position x_cg = x_cg_aft - cg_range * wing_mac # Definition of horizontal tail global position x_ht = x_wing_aero_center + lp_ht # Calculation of wheel factor flight_point = FlightPoint(mach=v_r / atm.speed_of_sound, altitude=0.0, engine_setting=EngineSetting.TAKEOFF, thrust_rate=takeoff_t_rate) propulsion_model.compute_flight_points(flight_point) thrust = float(flight_point.thrust) fact_wheel = ( (x_lg - x_cg - z_eng * thrust / weight) / wing_mac * (vs0 / v_r)**2 ) # FIXME: not clear if vs0 or vs1 should be used in formula # Compute aerodynamic coefficients for takeoff @ 0° aircraft angle cl0_takeoff = cl0_clean + cl_flaps_takeoff # Calculation of correction coefficient n_h and n_q n_h = ( x_ht - x_lg ) / lp_ht * tail_efficiency_factor # tail_efficiency_factor: dynamic pressure reduction at # tail (typical value) n_q = 1 + cl_alpha_htp_isolated / cl_htp_takeoff * _ANG_VEL * ( x_ht - x_lg) / v_r # Calculation of volume coefficient based on Torenbeek formula coef_vol = (cl_max_takeoff / (n_h * n_q * cl_htp_takeoff) * (cm_takeoff / cl_max_takeoff - fact_wheel) + cl0_takeoff / cl_htp_takeoff * (x_lg - x_wing_aero_center) / wing_mac) # Calculation of equivalent area area_1 = coef_vol * wing_area * wing_mac / lp_ht # CASE2: LANDING ############################################################################################### # method extracted from Torenbeek 1982 p325 # Calculation of take-off minimum speed weight = mlw * g vs0 = math.sqrt(weight / (0.5 * rho * wing_area * cl_max_landing)) # Rotation speed requirement from FAR 23.73 v_r = vs0 * 1.3 # Calculation of wheel factor flight_point = FlightPoint( mach=v_r / atm.speed_of_sound, altitude=0.0, engine_setting=EngineSetting.IDLE, thrust_rate=0.1 ) # FIXME: fixed thrust rate (should depend on wished descent rate) propulsion_model.compute_flight_points(flight_point) thrust = float(flight_point.thrust) fact_wheel = ( (x_lg - x_cg - z_eng * thrust / weight) / wing_mac * (vs0 / v_r)**2 ) # FIXME: not clear if vs0 or vs1 should be used in formula # Evaluate aircraft overall angle (aoa) cl0_landing = cl0_clean + cl_flaps_landing # Calculation of correction coefficient n_h and n_q n_h = ( x_ht - x_lg ) / lp_ht * tail_efficiency_factor # tail_efficiency_factor: dynamic pressure reduction at # tail (typical value) n_q = 1 + cl_alpha_htp_isolated / cl_htp_landing * _ANG_VEL * ( x_ht - x_lg) / v_r # Calculation of volume coefficient based on Torenbeek formula coef_vol = (cl_max_landing / (n_h * n_q * cl_htp_landing) * (cm_landing / cl_max_landing - fact_wheel) + cl0_landing / cl_htp_landing * (x_lg - x_wing_aero_center) / wing_mac) # Calculation of equivalent area area_2 = coef_vol * wing_area * wing_mac / lp_ht if max(area_1, area_2) < 0.0: print( "Warning: HTP area estimated negative (in ComputeHTArea) forced to 1m²!" ) outputs["data:geometry:horizontal_tail:area"] = 1.0 else: outputs["data:geometry:horizontal_tail:area"] = max(area_1, area_2)
def compute(self, inputs, outputs, discrete_inputs=None, discrete_outputs=None): cl_max_takeoff = inputs["data:aerodynamics:wing:low_speed:CL_max_clean"] cl0_clean = inputs["data:aerodynamics:wing:low_speed:CL0_clean"] cl_flaps_takeoff = inputs["data:aerodynamics:flaps:takeoff:CL"] cm_takeoff = inputs["takeoff:cm_wing"] cl_alpha_htp_isolated = inputs["data:aerodynamics:horizontal_tail:low_speed:CL_alpha_isolated"] cl_htp = inputs["takeoff:cl_htp"] tail_efficiency_factor = inputs["data:aerodynamics:horizontal_tail:efficiency"] n_engines = inputs["data:geometry:propulsion:count"] x_wing_aero_center = inputs["data:geometry:wing:MAC:at25percent:x"] wing_area = inputs["data:geometry:wing:area"] wing_mac = inputs["data:geometry:wing:MAC:length"] ht_area = inputs["data:geometry:horizontal_tail:area"] lp_ht = inputs["data:geometry:horizontal_tail:MAC:at25percent:x:from_wingMAC25"] mtow = inputs["data:weight:aircraft:MTOW"] x_lg = inputs["data:weight:airframe:landing_gear:main:CG:x"] z_cg_aircraft = inputs["data:weight:aircraft_empty:CG:z"] z_cg_engine = inputs["data:weight:propulsion:engine:CG:z"] propulsion_model = FuelEngineSet( self._engine_wrapper.get_model(inputs), inputs["data:geometry:propulsion:count"] ) # Conditions for calculation atm = Atmosphere(0.0) rho = atm.density sos = atm.speed_of_sound # Calculation of take-off minimum speed weight = mtow * g vs1 = math.sqrt(weight / (0.5 * rho * wing_area * cl_max_takeoff)) if n_engines == 1.0: vr = 1.10 * vs1 else: vr = 1.0 * vs1 mach_r = vr / sos flight_point = FlightPoint( mach=mach_r, altitude=0.0, engine_setting=EngineSetting.TAKEOFF, thrust_rate=1.0 ) propulsion_model.compute_flight_points(flight_point) thrust = float(flight_point.thrust) x_ht = x_wing_aero_center + lp_ht # Compute aerodynamic coefficients for takeoff @ 0° aircraft angle cl0_takeoff = cl0_clean + cl_flaps_takeoff eta_q = 1. + cl_alpha_htp_isolated / cl_htp * _ANG_VEL * (x_ht - x_lg) / vr eta_h = (x_ht - x_lg) / lp_ht * tail_efficiency_factor k_cl = cl_max_takeoff / (eta_q * eta_h * cl_htp) tail_volume_coefficient = ht_area * lp_ht / (wing_area * wing_mac) zt = z_cg_aircraft - z_cg_engine engine_contribution = zt * thrust / weight x_cg = ( 1. / k_cl * ( tail_volume_coefficient - cl0_takeoff / cl_htp * (x_lg / wing_mac - 0.25) ) - cm_takeoff / cl_max_takeoff ) * (vr / vs1) ** 2.0 + x_lg - engine_contribution outputs["data:handling_qualities:to_rotation_limit:x"] = x_cg x_cg_ratio = (x_cg - x_wing_aero_center + 0.25 * wing_mac) / wing_mac outputs["data:handling_qualities:to_rotation_limit:MAC_position"] = x_cg_ratio