Example #1
0
    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)
Example #3
0
    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