def estimate_2ndseg_lift_drag_ratio(config): """Estimates the 2nd segment climb lift to drag ratio (all engine operating) Assumptions: All engines operating Source: Fig. 27.34 of "Aerodynamic Design of Transport Airplane" - Obert Inputs: config. V2_VS_ratio [Unitless] wings. areas.reference [m^2] spans.projected [m] aspect_ratio [Unitless] maximum_lift_coefficient [Unitless] Outputs: lift_drag_ratio [Unitless] Properties Used: N/A """ # ============================================== # Unpack # ============================================== try: V2_VS_ratio = config.V2_VS_ratio except: V2_VS_ratio = 1.20 # typical condition # getting geometrical data (aspect ratio) n_wing = 0 for wing in config.wings: if not isinstance(wing,Wings.Main_Wing): continue reference_area = wing.areas.reference wing_span = wing.spans.projected try: aspect_ratio = wing.aspect_ratio except: aspect_ratio = wing_span ** 2 / reference_area n_wing += 1 if n_wing > 1: print(' More than one Main_Wing in the config. Last one will be considered.') elif n_wing == 0: print('No Main_Wing defined! Using the 1st wing found') for wing in config.wings: if not isinstance(wing,Wings.Wing): continue reference_area = wing.areas.reference wing_span = wing.spans.projected try: aspect_ratio = wing.aspect_ratio except: aspect_ratio = wing_span ** 2 / reference_area break # Determining vehicle maximum lift coefficient try: # aircraft maximum lift informed by user maximum_lift_coefficient = config.maximum_lift_coefficient except: # Using semi-empirical method for maximum lift coefficient calculation from SUAVE.Methods.Aerodynamics.Fidelity_Zero.Lift import compute_max_lift_coeff # Condition to CLmax calculation: 90KTAS @ 10000ft, ISA conditions = Data() conditions.freestream = Data() conditions.freestream.density = 0.90477283 conditions.freestream.dynamic_viscosity = 1.69220918e-05 conditions.freestream.velocity = 90. * Units.knots try: maximum_lift_coefficient, induced_drag_high_lift = compute_max_lift_coeff(config,conditions) config.maximum_lift_coefficient = maximum_lift_coefficient except: raise ValueError("Maximum lift coefficient calculation error. Please, check inputs") # Compute CL in V2 lift_coeff = maximum_lift_coefficient / (V2_VS_ratio ** 2) # Estimate L/D in 2nd segment condition, ALL ENGINES OPERATIVE! lift_drag_ratio = -6.464 * lift_coeff + 7.264 * aspect_ratio ** 0.5 return lift_drag_ratio
def estimate_take_off_field_length(vehicle,analyses,airport,compute_2nd_seg_climb = 0): """ Computes the takeoff field length for a given vehicle configuration in a given airport. Also optionally computes the second segment climb gradient. Assumptions: For second segment climb gradient: One engine inoperative Only validated for two engine aircraft Source: http://adg.stanford.edu/aa241/AircraftDesign.html Inputs: analyses.base.atmosphere [SUAVE data type] airport. altitude [m] delta_isa [K] vehicle. mass_properties.takeoff [kg] reference_area [m^2] V2_VS_ratio (optional) [Unitless] maximum_lift_coefficient (optional) [Unitless] propulsors.*.number_of_engines [Unitless] Outputs: takeoff_field_length [m] Properties Used: N/A """ # ============================================== # Unpack # ============================================== atmo = analyses.base.atmosphere altitude = airport.altitude * Units.ft delta_isa = airport.delta_isa weight = vehicle.mass_properties.takeoff reference_area = vehicle.reference_area try: V2_VS_ratio = vehicle.V2_VS_ratio except: V2_VS_ratio = 1.20 # ============================================== # Computing atmospheric conditions # ============================================== atmo_values = atmo.compute_values(altitude,delta_isa) conditions = SUAVE.Analyses.Mission.Segments.Conditions.Aerodynamics() p = atmo_values.pressure T = atmo_values.temperature rho = atmo_values.density a = atmo_values.speed_of_sound mu = atmo_values.dynamic_viscosity sea_level_gravity = atmo.planet.sea_level_gravity # ============================================== # Determining vehicle maximum lift coefficient # ============================================== try: # aircraft maximum lift informed by user maximum_lift_coefficient = vehicle.maximum_lift_coefficient except: # Using semi-empirical method for maximum lift coefficient calculation from SUAVE.Methods.Aerodynamics.Fidelity_Zero.Lift import compute_max_lift_coeff # Condition to CLmax calculation: 90KTAS @ 10000ft, ISA conditions = atmo.compute_values(10000. * Units.ft) conditions.freestream=Data() conditions.freestream.density = conditions.density conditions.freestream.dynamic_viscosity = conditions.dynamic_viscosity conditions.freestream.velocity = 90. * Units.knots try: maximum_lift_coefficient, induced_drag_high_lift = compute_max_lift_coeff(vehicle,conditions) vehicle.maximum_lift_coefficient = maximum_lift_coefficient except: raise ValueError, "Maximum lift coefficient calculation error. Please, check inputs" # ============================================== # Computing speeds (Vs, V2, 0.7*V2) # ============================================== stall_speed = (2 * weight * sea_level_gravity / (rho * reference_area * maximum_lift_coefficient)) ** 0.5 V2_speed = V2_VS_ratio * stall_speed speed_for_thrust = 0.70 * V2_speed # ============================================== # Determining vehicle number of engines # ============================================== engine_number = 0. for propulsor in vehicle.propulsors : # may have than one propulsor engine_number += propulsor.number_of_engines if engine_number == 0: raise ValueError, "No engine found in the vehicle" # ============================================== # Getting engine thrust # ============================================== state = Data() state.conditions = Aerodynamics() state.numerics = Numerics() conditions = state.conditions conditions.freestream.dynamic_pressure = np.array(np.atleast_1d(0.5 * rho * speed_for_thrust**2)) conditions.freestream.gravity = np.array([np.atleast_1d(sea_level_gravity)]) conditions.freestream.velocity = np.array(np.atleast_1d(speed_for_thrust)) conditions.freestream.mach_number = np.array(np.atleast_1d(speed_for_thrust/ a)) conditions.freestream.speed_of_sound = np.array(a) conditions.freestream.temperature = np.array(np.atleast_1d(T)) conditions.freestream.pressure = np.array(np.atleast_1d(p)) conditions.propulsion.throttle = np.array(np.atleast_1d(1.)) results = vehicle.propulsors.evaluate_thrust(state) # total thrust thrust = results.thrust_force_vector # ============================================== # Calculate takeoff distance # ============================================== # Defining takeoff distance equations coefficients try: takeoff_constants = vehicle.takeoff_constants # user defined except: # default values takeoff_constants = np.zeros(3) if engine_number == 2: takeoff_constants[0] = 857.4 takeoff_constants[1] = 2.476 takeoff_constants[2] = 0.00014 elif engine_number == 3: takeoff_constants[0] = 667.9 takeoff_constants[1] = 2.343 takeoff_constants[2] = 0.000093 elif engine_number == 4: takeoff_constants[0] = 486.7 takeoff_constants[1] = 2.282 takeoff_constants[2] = 0.0000705 elif engine_number > 4: takeoff_constants[0] = 486.7 takeoff_constants[1] = 2.282 takeoff_constants[2] = 0.0000705 print 'The vehicle has more than 4 engines. Using 4 engine correlation. Result may not be correct.' else: takeoff_constants[0] = 857.4 takeoff_constants[1] = 2.476 takeoff_constants[2] = 0.00014 print 'Incorrect number of engines: {0:.1f}. Using twin engine correlation.'.format(engine_number) # Define takeoff index (V2^2 / (T/W) takeoff_index = V2_speed**2. / (thrust[0][0] / weight) # Calculating takeoff field length takeoff_field_length = 0. for idx,constant in enumerate(takeoff_constants): takeoff_field_length += constant * takeoff_index**idx takeoff_field_length = takeoff_field_length * Units.ft # calculating second segment climb gradient, if required by user input if compute_2nd_seg_climb: # Getting engine thrust at V2 (update only speed related conditions) state.conditions.freestream.dynamic_pressure = np.array(np.atleast_1d(0.5 * rho * V2_speed**2)) state.conditions.freestream.velocity = np.array(np.atleast_1d(V2_speed)) state.conditions.freestream.mach_number = np.array(np.atleast_1d(V2_speed/ a)) results = vehicle.propulsors['turbofan'].engine_out(state) thrust = results.thrust_force_vector[0][0] # Compute windmilling drag windmilling_drag_coefficient = windmilling_drag(vehicle,state) # Compute asymmetry drag asymmetry_drag_coefficient = asymmetry_drag(state, vehicle, windmilling_drag_coefficient) # Compute l over d ratio for takeoff condition, NO engine failure l_over_d = estimate_2ndseg_lift_drag_ratio(vehicle) # Compute L over D ratio for takeoff condition, WITH engine failure clv2 = maximum_lift_coefficient / (V2_VS_ratio) **2 cdv2_all_engine = clv2 / l_over_d cdv2 = cdv2_all_engine + asymmetry_drag_coefficient + windmilling_drag_coefficient l_over_d_v2 = clv2 / cdv2 # Compute 2nd segment climb gradient second_seg_climb_gradient = thrust / (weight*sea_level_gravity) - 1. / l_over_d_v2 return takeoff_field_length, second_seg_climb_gradient else: # return only takeoff_field_length return takeoff_field_length
def estimate_landing_field_length(vehicle, analyses, airport): """ Computes the landing field length for a given vehicle configuration in a given airport. Assumptions: See source Two wheel trucks (code needed for four wheel trucks also included) Source: Torenbeek, E., "Advanced Aircraft Design", 2013 (equation 9.25) Inputs: airport. atmosphere [SUAVE data type] altitude [m] delta_isa [K] vehicle. mass_properties.landing [kg] reference_area [m^2] maximum_lift_coefficient (optional) [Unitless] Outputs: landing_field_length [m] Properties Used: N/A """ # ============================================== # Unpack # ============================================== atmo = airport.atmosphere altitude = airport.altitude * Units.ft delta_isa = airport.delta_isa weight = vehicle.mass_properties.landing reference_area = vehicle.reference_area try: Vref_VS_ratio = vehicle.Vref_VS_ratio except: Vref_VS_ratio = 1.23 # ============================================== # Computing atmospheric conditions # ============================================== atmo_values = atmo.compute_values(altitude, delta_isa) p = atmo_values.pressure T = atmo_values.temperature rho = atmo_values.density a = atmo_values.speed_of_sound mu = atmo_values.dynamic_viscosity sea_level_gravity = atmo.planet.sea_level_gravity # ============================================== # Determining vehicle maximum lift coefficient # ============================================== # Condition to CLmax calculation: 90KTAS @ airport state = Data() state.conditions = SUAVE.Analyses.Mission.Segments.Conditions.Aerodynamics( ) state.conditions.freestream = Data() state.conditions.freestream.density = rho state.conditions.freestream.velocity = 90. * Units.knots state.conditions.freestream.dynamic_viscosity = mu settings = analyses.aerodynamics.settings maximum_lift_coefficient, induced_drag_high_lift = compute_max_lift_coeff( state, settings, vehicle) # ============================================== # Computing speeds (Vs, Vref) # ============================================== stall_speed = (2 * weight * sea_level_gravity / (rho * reference_area * maximum_lift_coefficient))**0.5 Vref = stall_speed * Vref_VS_ratio # ======================================================================================== # Computing landing distance, according to Torenbeek equation # Landing Field Length = k1 + k2 * Vref**2 # ======================================================================================== # Defining landing distance equation coefficients try: landing_constants = config.landing_constants # user defined except: # default values - According to Torenbeek book landing_constants = np.zeros(3) landing_constants[0] = 250. landing_constants[1] = 0. landing_constants[ 2] = 2.485 / sea_level_gravity # Two-wheels truck : [ (1.56 / 0.40 + 1.07) / (2*sea_level_gravity) ] #landing_constants[2] = 2.9725 / sea_level_gravity # Four-wheels truck: [ (1.56 / 0.32 + 1.07) / (2*sea_level_gravity) ] # Calculating landing field length landing_field_length = 0. for idx, constant in enumerate(landing_constants): landing_field_length += constant * Vref**idx # return return landing_field_length
def estimate_landing_field_length(vehicle,config,airport): """ SUAVE.Methods.Performance.estimate_landing_field_length(vehicle,config,airport): Computes the landing field length for a given vehicle condition in a given airport Inputs: vehicle - SUAVE type vehicle config - data dictionary with fields: Mass_Properties.landing - Landing weight to be evaluated S - Wing Area Vref_VS_ratio - Ratio between Approach Speed and Stall speed [optional. Default value = 1.23] maximum_lift_coefficient - Maximum lift coefficient for the config [optional. Calculated if not informed] airport - SUAVE type airport data, with followig fields: atmosphere - Airport atmosphere (SUAVE type) altitude - Airport altitude delta_isa - ISA Temperature deviation Outputs: landing_field_length - Landing field length Assumptions: - Landing field length calculated according to Torenbeek, E., "Advanced Aircraft Design", 2013 (equation 9.25) - Considering average aav/g values of two-wheel truck (0.40) """ # ============================================== # Unpack # ============================================== atmo = airport.atmosphere altitude = airport.altitude * Units.ft delta_isa = airport.delta_isa weight = config.mass_properties.landing reference_area = config.reference_area try: Vref_VS_ratio = config.Vref_VS_ratio except: Vref_VS_ratio = 1.23 # ============================================== # Computing atmospheric conditions # ============================================== p0, T0, rho0, a0, mu0 = atmo.compute_values(0) p , T , rho , a , mu = atmo.compute_values(altitude) T_delta_ISA = T + delta_isa sigma_disa = (p/p0) / (T_delta_ISA/T0) rho = rho0 * sigma_disa a_delta_ISA = atmo.fluid_properties.compute_speed_of_sound(T_delta_ISA) mu = 1.78938028e-05 * ((T0 + 120) / T0 ** 1.5) * ((T_delta_ISA ** 1.5) / (T_delta_ISA + 120)) sea_level_gravity = atmo.planet.sea_level_gravity # ============================================== # Determining vehicle maximum lift coefficient # ============================================== try: # aircraft maximum lift informed by user maximum_lift_coefficient = config.maximum_lift_coefficient except: # Using semi-empirical method for maximum lift coefficient calculation from SUAVE.Methods.Aerodynamics.Fidelity_Zero.Lift import compute_max_lift_coeff # Condition to CLmax calculation: 90KTAS @ 10000ft, ISA p_stall , T_stall , rho_stall , a_stall , mu_stall = atmo.compute_values(10000. * Units.ft) conditions = Data() conditions.freestream = Data() conditions.freestream.density = rho_stall conditions.freestream.viscosity = mu_stall conditions.freestream.velocity = 90. * Units.knots try: maximum_lift_coefficient, induced_drag_high_lift = compute_max_lift_coeff(config,conditions) config.maximum_lift_coefficient = maximum_lift_coefficient except: raise ValueError, "Maximum lift coefficient calculation error. Please, check inputs" # ============================================== # Computing speeds (Vs, Vref) # ============================================== stall_speed = (2 * weight * sea_level_gravity / (rho * reference_area * maximum_lift_coefficient)) ** 0.5 Vref = stall_speed * Vref_VS_ratio # ======================================================================================== # Computing landing distance, according to Torenbeek equation # Landing Field Length = k1 + k2 * Vref**2 # ======================================================================================== # Defining landing distance equation coefficients try: landing_constants = config.landing_constants # user defined except: # default values - According to Torenbeek book landing_constants = np.zeros(3) landing_constants[0] = 250. landing_constants[1] = 0. landing_constants[2] = 2.485 / sea_level_gravity # Two-wheels truck : [ (1.56 / 0.40 + 1.07) / (2*sea_level_gravity) ] ## landing_constants[2] = 2.9725 / sea_level_gravity # Four-wheels truck: [ (1.56 / 0.32 + 1.07) / (2*sea_level_gravity) ] # Calculating landing field length landing_field_length = 0. for idx,constant in enumerate(landing_constants): landing_field_length += constant * Vref**idx # return return landing_field_length
def estimate_landing_field_length(vehicle, analyses, airport): """ SUAVE.Methods.Performance.estimate_landing_field_length(vehicle,config,airport): Computes the landing field length for a given vehicle condition in a given airport Inputs: vehicle - SUAVE type vehicle config - data dictionary with fields: Mass_Properties.landing - Landing weight to be evaluated S - Wing Area Vref_VS_ratio - Ratio between Approach Speed and Stall speed [optional. Default value = 1.23] maximum_lift_coefficient - Maximum lift coefficient for the config [optional. Calculated if not informed] airport - SUAVE type airport data, with followig fields: atmosphere - Airport atmosphere (SUAVE type) altitude - Airport altitude delta_isa - ISA Temperature deviation Outputs: landing_field_length - Landing field length Assumptions: - Landing field length calculated according to Torenbeek, E., "Advanced Aircraft Design", 2013 (equation 9.25) - Considering average aav/g values of two-wheel truck (0.40) """ # ============================================== # Unpack # ============================================== atmo = airport.atmosphere altitude = airport.altitude * Units.ft delta_isa = airport.delta_isa weight = vehicle.mass_properties.landing reference_area = vehicle.reference_area try: Vref_VS_ratio = config.Vref_VS_ratio except: Vref_VS_ratio = 1.23 # ============================================== # Computing atmospheric conditions # ============================================== atmo_values = atmo.compute_values(altitude, delta_isa) conditions = SUAVE.Analyses.Mission.Segments.Conditions.Aerodynamics() p = atmo_values.pressure T = atmo_values.temperature rho = atmo_values.density a = atmo_values.speed_of_sound mu = atmo_values.dynamic_viscosity sea_level_gravity = atmo.planet.sea_level_gravity # ============================================== # Determining vehicle maximum lift coefficient # ============================================== try: # aircraft maximum lift informed by user maximum_lift_coefficient = vehicle.maximum_lift_coefficient except: # Using semi-empirical method for maximum lift coefficient calculation from SUAVE.Methods.Aerodynamics.Fidelity_Zero.Lift import compute_max_lift_coeff conditions.freestream = Data() conditions.freestream.density = rho conditions.freestream.dynamic_viscosity = mu conditions.freestream.velocity = 90. * Units.knots try: maximum_lift_coefficient, induced_drag_high_lift = compute_max_lift_coeff( vehicle, conditions) vehicle.maximum_lift_coefficient = maximum_lift_coefficient except: raise ValueError, "Maximum lift coefficient calculation error. Please, check inputs" # ============================================== # Computing speeds (Vs, Vref) # ============================================== stall_speed = (2 * weight * sea_level_gravity / (rho * reference_area * maximum_lift_coefficient))**0.5 Vref = stall_speed * Vref_VS_ratio # ======================================================================================== # Computing landing distance, according to Torenbeek equation # Landing Field Length = k1 + k2 * Vref**2 # ======================================================================================== # Defining landing distance equation coefficients try: landing_constants = config.landing_constants # user defined except: # default values - According to Torenbeek book landing_constants = np.zeros(3) landing_constants[0] = 250. landing_constants[1] = 0. landing_constants[ 2] = 2.485 / sea_level_gravity # Two-wheels truck : [ (1.56 / 0.40 + 1.07) / (2*sea_level_gravity) ] ## landing_constants[2] = 2.9725 / sea_level_gravity # Four-wheels truck: [ (1.56 / 0.32 + 1.07) / (2*sea_level_gravity) ] # Calculating landing field length landing_field_length = 0. for idx, constant in enumerate(landing_constants): landing_field_length += constant * Vref**idx # return return landing_field_length
def estimate_2ndseg_lift_drag_ratio(config): """Estimates the 2nd segment climb lift to drag ratio (all engine operating) Assumptions: All engines operating Source: Fig. 27.34 of "Aerodynamic Design of Transport Airplane" - Obert Inputs: config. V2_VS_ratio [Unitless] wings. areas.reference [m^2] spans.projected [m] aspect_ratio [Unitless] maximum_lift_coefficient [Unitless] Outputs: lift_drag_ratio [Unitless] Properties Used: N/A """ # ============================================== # Unpack # ============================================== try: V2_VS_ratio = config.V2_VS_ratio except: V2_VS_ratio = 1.20 # typical condition # getting geometrical data (aspect ratio) n_wing = 0 for wing in config.wings: if not isinstance(wing,Wings.Main_Wing): continue reference_area = wing.areas.reference wing_span = wing.spans.projected try: aspect_ratio = wing.aspect_ratio except: aspect_ratio = wing_span ** 2 / reference_area n_wing += 1 if n_wing > 1: print ' More than one Main_Wing in the config. Last one will be considered.' elif n_wing == 0: print 'No Main_Wing defined! Using the 1st wing found' for wing in config.wings: if not isinstance(wing,Wings.Wing): continue reference_area = wing.areas.reference wing_span = wing.spans.projected try: aspect_ratio = wing.aspect_ratio except: aspect_ratio = wing_span ** 2 / reference_area break # Determining vehicle maximum lift coefficient try: # aircraft maximum lift informed by user maximum_lift_coefficient = config.maximum_lift_coefficient except: # Using semi-empirical method for maximum lift coefficient calculation from SUAVE.Methods.Aerodynamics.Fidelity_Zero.Lift import compute_max_lift_coeff # Condition to CLmax calculation: 90KTAS @ 10000ft, ISA conditions = Data() conditions.freestream = Data() conditions.freestream.density = 0.90477283 conditions.freestream.dynamic_viscosity = 1.69220918e-05 conditions.freestream.velocity = 90. * Units.knots try: maximum_lift_coefficient, induced_drag_high_lift = compute_max_lift_coeff(config,conditions) config.maximum_lift_coefficient = maximum_lift_coefficient except: raise ValueError, "Maximum lift coefficient calculation error. Please, check inputs" # Compute CL in V2 lift_coeff = maximum_lift_coefficient / (V2_VS_ratio ** 2) # Estimate L/D in 2nd segment condition, ALL ENGINES OPERATIVE! lift_drag_ratio = -6.464 * lift_coeff + 7.264 * aspect_ratio ** 0.5 return lift_drag_ratio
def estimate_take_off_field_length(vehicle, analyses, airport, compute_2nd_seg_climb=0): """ Computes the takeoff field length for a given vehicle configuration in a given airport. Also optionally computes the second segment climb gradient. Assumptions: For second segment climb gradient: One engine inoperative Only validated for two engine aircraft Source: http://adg.stanford.edu/aa241/AircraftDesign.html Inputs: analyses.base.atmosphere [SUAVE data type] airport. altitude [m] delta_isa [K] vehicle. mass_properties.takeoff [kg] reference_area [m^2] V2_VS_ratio (optional) [Unitless] maximum_lift_coefficient (optional) [Unitless] propulsors.*.number_of_engines [Unitless] Outputs: takeoff_field_length [m] Properties Used: N/A """ # ============================================== # Unpack # ============================================== atmo = analyses.base.atmosphere altitude = airport.altitude * Units.ft delta_isa = airport.delta_isa weight = vehicle.mass_properties.takeoff reference_area = vehicle.reference_area try: V2_VS_ratio = vehicle.V2_VS_ratio except: V2_VS_ratio = 1.20 # ============================================== # Computing atmospheric conditions # ============================================== atmo_values = atmo.compute_values(altitude, delta_isa) conditions = SUAVE.Analyses.Mission.Segments.Conditions.Aerodynamics() p = atmo_values.pressure T = atmo_values.temperature rho = atmo_values.density a = atmo_values.speed_of_sound mu = atmo_values.dynamic_viscosity sea_level_gravity = atmo.planet.sea_level_gravity # ============================================== # Determining vehicle maximum lift coefficient # ============================================== try: # aircraft maximum lift informed by user maximum_lift_coefficient = vehicle.maximum_lift_coefficient except: # Using semi-empirical method for maximum lift coefficient calculation from SUAVE.Methods.Aerodynamics.Fidelity_Zero.Lift import compute_max_lift_coeff # Condition to CLmax calculation: 90KTAS @ 10000ft, ISA conditions = atmo.compute_values(10000. * Units.ft) conditions.freestream = Data() conditions.freestream.density = conditions.density conditions.freestream.dynamic_viscosity = conditions.dynamic_viscosity conditions.freestream.velocity = 90. * Units.knots try: maximum_lift_coefficient, induced_drag_high_lift = compute_max_lift_coeff( vehicle, conditions) vehicle.maximum_lift_coefficient = maximum_lift_coefficient except: raise ValueError, "Maximum lift coefficient calculation error. Please, check inputs" # ============================================== # Computing speeds (Vs, V2, 0.7*V2) # ============================================== stall_speed = (2 * weight * sea_level_gravity / (rho * reference_area * maximum_lift_coefficient))**0.5 V2_speed = V2_VS_ratio * stall_speed speed_for_thrust = 0.70 * V2_speed # ============================================== # Determining vehicle number of engines # ============================================== engine_number = 0. for propulsor in vehicle.propulsors: # may have than one propulsor engine_number += propulsor.number_of_engines if engine_number == 0: raise ValueError, "No engine found in the vehicle" # ============================================== # Getting engine thrust # ============================================== state = Data() state.conditions = Aerodynamics() state.numerics = Numerics() conditions = state.conditions conditions.freestream.dynamic_pressure = np.array( np.atleast_1d(0.5 * rho * speed_for_thrust**2)) conditions.freestream.gravity = np.array( [np.atleast_1d(sea_level_gravity)]) conditions.freestream.velocity = np.array(np.atleast_1d(speed_for_thrust)) conditions.freestream.mach_number = np.array( np.atleast_1d(speed_for_thrust / a)) conditions.freestream.temperature = np.array(np.atleast_1d(T)) conditions.freestream.pressure = np.array(np.atleast_1d(p)) conditions.propulsion.throttle = np.array(np.atleast_1d(1.)) results = vehicle.propulsors.evaluate_thrust(state) # total thrust thrust = results.thrust_force_vector # ============================================== # Calculate takeoff distance # ============================================== # Defining takeoff distance equations coefficients try: takeoff_constants = vehicle.takeoff_constants # user defined except: # default values takeoff_constants = np.zeros(3) if engine_number == 2: takeoff_constants[0] = 857.4 takeoff_constants[1] = 2.476 takeoff_constants[2] = 0.00014 elif engine_number == 3: takeoff_constants[0] = 667.9 takeoff_constants[1] = 2.343 takeoff_constants[2] = 0.000093 elif engine_number == 4: takeoff_constants[0] = 486.7 takeoff_constants[1] = 2.282 takeoff_constants[2] = 0.0000705 elif engine_number > 4: takeoff_constants[0] = 486.7 takeoff_constants[1] = 2.282 takeoff_constants[2] = 0.0000705 print 'The vehicle has more than 4 engines. Using 4 engine correlation. Result may not be correct.' else: takeoff_constants[0] = 857.4 takeoff_constants[1] = 2.476 takeoff_constants[2] = 0.00014 print 'Incorrect number of engines: {0:.1f}. Using twin engine correlation.'.format( engine_number) # Define takeoff index (V2^2 / (T/W) takeoff_index = V2_speed**2. / (thrust[0][0] / weight) # Calculating takeoff field length takeoff_field_length = 0. for idx, constant in enumerate(takeoff_constants): takeoff_field_length += constant * takeoff_index**idx takeoff_field_length = takeoff_field_length * Units.ft # calculating second segment climb gradient, if required by user input if compute_2nd_seg_climb: # Getting engine thrust at V2 (update only speed related conditions) state.conditions.freestream.dynamic_pressure = np.array( np.atleast_1d(0.5 * rho * V2_speed**2)) state.conditions.freestream.velocity = np.array( np.atleast_1d(V2_speed)) state.conditions.freestream.mach_number = np.array( np.atleast_1d(V2_speed / a)) results = vehicle.propulsors['turbofan'].engine_out(state) thrust = results.thrust_force_vector[0][0] # Compute windmilling drag windmilling_drag_coefficient = windmilling_drag(vehicle, state) # Compute asymmetry drag asymmetry_drag_coefficient = asymmetry_drag( state, vehicle, windmilling_drag_coefficient) # Compute l over d ratio for takeoff condition, NO engine failure l_over_d = estimate_2ndseg_lift_drag_ratio(vehicle) # Compute L over D ratio for takeoff condition, WITH engine failure clv2 = maximum_lift_coefficient / (V2_VS_ratio)**2 cdv2_all_engine = clv2 / l_over_d cdv2 = cdv2_all_engine + asymmetry_drag_coefficient + windmilling_drag_coefficient l_over_d_v2 = clv2 / cdv2 # Compute 2nd segment climb gradient second_seg_climb_gradient = thrust / ( weight * sea_level_gravity) - 1. / l_over_d_v2 return takeoff_field_length, second_seg_climb_gradient else: # return only takeoff_field_length return takeoff_field_length
def estimate_2ndseg_lift_drag_ratio(config): """ SUAVE.Methods.Aerodynamics.Drag.Correlations.estimate_2ndseg_lift_drag_ratio(config): Estimates the 2nd segment Lift to drag ration (all engine operating) Inputs: config - data dictionary with fields: reference_area - Airplane reference area V2_VS_ratio - Ratio between V2 and Stall speed [optional. Default value = 1.20] Main_Wing.aspect_ratio - Main_Wing aspect ratio maximum_lift_coefficient - Maximum lift coefficient for the config [Calculated if not informed] Outputs: takeoff_field_length - Takeoff field length Assumptions: All engines Operating. Must be corrected for second segment climb configuration reference: Fig. 27.34 of "Aerodynamic Design of Transport Airplane" - Obert """ # ============================================== # Unpack # ============================================== try: V2_VS_ratio = config.V2_VS_ratio except: V2_VS_ratio = 1.20 # typical condition # getting geometrical data (aspect ratio) n_wing = 0 for wing in config.wings: if not isinstance(wing, Wings.Main_Wing): continue reference_area = wing.areas.reference wing_span = wing.spans.projected try: aspect_ratio = wing.aspect_ratio except: aspect_ratio = wing_span**2 / reference_area n_wing += 1 if n_wing > 1: print ' More than one Main_Wing in the config. Last one will be considered.' elif n_wing == 0: print 'No Main_Wing defined! Using the 1st wing found' for wing in config.wings: if not isinstance(wing, Wings.Wing): continue reference_area = wing.areas.reference wing_span = wing.spans.projected try: aspect_ratio = wing.aspect_ratio except: aspect_ratio = wing_span**2 / reference_area break # Determining vehicle maximum lift coefficient try: # aircraft maximum lift informed by user maximum_lift_coefficient = config.maximum_lift_coefficient except: # Using semi-empirical method for maximum lift coefficient calculation from SUAVE.Methods.Aerodynamics.Fidelity_Zero.Lift import compute_max_lift_coeff # Condition to CLmax calculation: 90KTAS @ 10000ft, ISA conditions = Data() conditions.freestream = Data() conditions.freestream.density = 0.90477283 conditions.freestream.dynamic_viscosity = 1.69220918e-05 conditions.freestream.velocity = 90. * Units.knots try: maximum_lift_coefficient, induced_drag_high_lift = compute_max_lift_coeff( config, conditions) config.maximum_lift_coefficient = maximum_lift_coefficient except: raise ValueError, "Maximum lift coefficient calculation error. Please, check inputs" # Compute CL in V2 lift_coeff = maximum_lift_coefficient / (V2_VS_ratio**2) # Estimate L/D in 2nd segment condition, ALL ENGINES OPERATIVE! lift_drag_ratio = -6.464 * lift_coeff + 7.264 * aspect_ratio**0.5 return lift_drag_ratio
def estimate_take_off_field_length(vehicle,analyses,airport,compute_2nd_seg_climb = 0): """ SUAVE.Methods.Performance.estimate_take_off_field_length(vehicle,analyses,airport,compute_2nd_seg_climb = 0): Computes the takeoff field length for a given vehicle condition in a given airport, and allow user to compute 2nd segment climb gradient Inputs: vehicle - SUAVE type vehicle, with following fields: mass_properties.takeoff - Takeoff weight to be evaluated vehicle.reference_area - Airplane reference area V2_VS_ratio - Ratio between V2 and Stall speed [optional. Default value = 1.20] takeoff_constants - Coefficients for takeoff field length equation [optional. Default values: AA241 method] maximum_lift_coefficient - Maximum lift coefficient for the config [Calculated if not informed] analyses - SUAVE analyses type data structure, with the following fields: analyses.base.atmosphere - Atmosphere to be used for calculation airport - SUAVE type airport data, with followig fields: atmosphere - Airport atmosphere (SUAVE type) altitude - Airport altitude delta_isa - ISA Temperature deviation compute_2nd_seg_climb - Flag to define if second segment climb gradient should be calculated Outputs: takeoff_field_length - Takeoff field length second_seg_climb_gradient - Second Segment Climb gradient [ optional] Assumptions: Correlation based. Second segment climb gradient: - Considers ONE engine inoperative, for any number of engines. - Valid for twin engine airplane - NOT VALIDATED/VERIFICATED WITH 3 OR MORE ENGINES. """ # ============================================== # Unpack # ============================================== atmo = analyses.base.atmosphere altitude = airport.altitude * Units.ft delta_isa = airport.delta_isa weight = vehicle.mass_properties.takeoff reference_area = vehicle.reference_area try: V2_VS_ratio = vehicle.V2_VS_ratio except: V2_VS_ratio = 1.20 # ============================================== # Computing atmospheric conditions # ============================================== atmo_values = atmo.compute_values(altitude,delta_isa) conditions = SUAVE.Analyses.Mission.Segments.Conditions.Aerodynamics() p = atmo_values.pressure T = atmo_values.temperature rho = atmo_values.density a = atmo_values.speed_of_sound mu = atmo_values.dynamic_viscosity sea_level_gravity = atmo.planet.sea_level_gravity # ============================================== # Determining vehicle maximum lift coefficient # ============================================== try: # aircraft maximum lift informed by user maximum_lift_coefficient = vehicle.maximum_lift_coefficient except: # Using semi-empirical method for maximum lift coefficient calculation from SUAVE.Methods.Aerodynamics.Fidelity_Zero.Lift import compute_max_lift_coeff # Condition to CLmax calculation: 90KTAS @ 10000ft, ISA conditions = atmo.compute_values(10000. * Units.ft) conditions.freestream=Data() conditions.freestream.density = conditions.density conditions.freestream.dynamic_viscosity = conditions.dynamic_viscosity conditions.freestream.velocity = 90. * Units.knots try: maximum_lift_coefficient, induced_drag_high_lift = compute_max_lift_coeff(vehicle,conditions) vehicle.maximum_lift_coefficient = maximum_lift_coefficient except: raise ValueError, "Maximum lift coefficient calculation error. Please, check inputs" # ============================================== # Computing speeds (Vs, V2, 0.7*V2) # ============================================== stall_speed = (2 * weight * sea_level_gravity / (rho * reference_area * maximum_lift_coefficient)) ** 0.5 V2_speed = V2_VS_ratio * stall_speed speed_for_thrust = 0.70 * V2_speed # ============================================== # Determining vehicle number of engines # ============================================== engine_number = 0. for propulsor in vehicle.propulsors : # may have than one propulsor engine_number += propulsor.number_of_engines if engine_number == 0: raise ValueError, "No engine found in the vehicle" # ============================================== # Getting engine thrust # ============================================== state = Data() state.conditions = Aerodynamics() state.numerics = Numerics() conditions = state.conditions conditions.freestream.dynamic_pressure = np.array(np.atleast_1d(0.5 * rho * speed_for_thrust**2)) conditions.freestream.gravity = np.array([np.atleast_1d(sea_level_gravity)]) conditions.freestream.velocity = np.array(np.atleast_1d(speed_for_thrust)) conditions.freestream.mach_number = np.array(np.atleast_1d(speed_for_thrust/ a)) conditions.freestream.temperature = np.array(np.atleast_1d(T)) conditions.freestream.pressure = np.array(np.atleast_1d(p)) conditions.propulsion.throttle = np.array(np.atleast_1d(1.)) results = vehicle.propulsors.evaluate_thrust(state) # total thrust thrust = results.thrust_force_vector # ============================================== # Calculate takeoff distance # ============================================== # Defining takeoff distance equations coefficients try: takeoff_constants = vehicle.takeoff_constants # user defined except: # default values takeoff_constants = np.zeros(3) if engine_number == 2: takeoff_constants[0] = 857.4 takeoff_constants[1] = 2.476 takeoff_constants[2] = 0.00014 elif engine_number == 3: takeoff_constants[0] = 667.9 takeoff_constants[1] = 2.343 takeoff_constants[2] = 0.000093 elif engine_number == 4: takeoff_constants[0] = 486.7 takeoff_constants[1] = 2.282 takeoff_constants[2] = 0.0000705 elif engine_number > 4: takeoff_constants[0] = 486.7 takeoff_constants[1] = 2.282 takeoff_constants[2] = 0.0000705 print 'The vehicle has more than 4 engines. Using 4 engine correlation. Result may not be correct.' else: takeoff_constants[0] = 857.4 takeoff_constants[1] = 2.476 takeoff_constants[2] = 0.00014 print 'Incorrect number of engines: {0:.1f}. Using twin engine correlation.'.format(engine_number) # Define takeoff index (V2^2 / (T/W) takeoff_index = V2_speed**2. / (thrust[0][0] / weight) # Calculating takeoff field length takeoff_field_length = 0. for idx,constant in enumerate(takeoff_constants): takeoff_field_length += constant * takeoff_index**idx takeoff_field_length = takeoff_field_length * Units.ft # calculating second segment climb gradient, if required by user input if compute_2nd_seg_climb: # Getting engine thrust at V2 (update only speed related conditions) state.conditions.freestream.dynamic_pressure = np.array(np.atleast_1d(0.5 * rho * V2_speed**2)) state.conditions.freestream.velocity = np.array(np.atleast_1d(V2_speed)) state.conditions.freestream.mach_number = np.array(np.atleast_1d(V2_speed/ a)) results = vehicle.propulsors[0].engine_out(state) thrust = results.thrust_force_vector[0][0] # Compute windmilling drag windmilling_drag_coefficient = windmilling_drag(vehicle,state) # Compute asymmetry drag asymmetry_drag_coefficient = asymmetry_drag(state, vehicle, windmilling_drag_coefficient) # Compute l over d ratio for takeoff condition, NO engine failure l_over_d = estimate_2ndseg_lift_drag_ratio(vehicle) # Compute L over D ratio for takeoff condition, WITH engine failure clv2 = maximum_lift_coefficient / (V2_VS_ratio) **2 cdv2_all_engine = clv2 / l_over_d cdv2 = cdv2_all_engine + asymmetry_drag_coefficient + windmilling_drag_coefficient l_over_d_v2 = clv2 / cdv2 # Compute 2nd segment climb gradient second_seg_climb_gradient = thrust / (weight*sea_level_gravity) - 1. / l_over_d_v2 return takeoff_field_length, second_seg_climb_gradient else: # return only takeoff_field_length return takeoff_field_length
def estimate_take_off_field_length(vehicle,analyses,airport): """ SUAVE.Methods.Performance.estimate_take_off_field_length(vehicle,airport): Computes the takeoff field length for a given vehicle condition in a given airport Inputs: vehicle - SUAVE type vehicle includes these fields: Mass_Properties.takeoff - Takeoff weight to be evaluated S - Wing Area V2_VS_ratio - Ratio between V2 and Stall speed [optional. Default value = 1.20] takeoff_constants - Coefficients for takeoff field length equation [optional. Default values: AA241 method] maximum_lift_coefficient - Maximum lift coefficient for the config [optional. Calculated if not informed] airport - SUAVE type airport data, with followig fields: atmosphere - Airport atmosphere (SUAVE type) altitude - Airport altitude delta_isa - ISA Temperature deviation Outputs: takeoff_field_length - Takeoff field length Assumptions: Correlation based. """ # ============================================== # Unpack # ============================================== atmo = airport.atmosphere altitude = airport.altitude * Units.ft delta_isa = airport.delta_isa weight = vehicle.mass_properties.takeoff reference_area = vehicle.reference_area try: V2_VS_ratio = vehicle.V2_VS_ratio except: V2_VS_ratio = 1.20 # ============================================== # Computing atmospheric conditions # ============================================== conditions0 = atmo.compute_values(0.) atmo_values = atmo.compute_values(altitude) conditions =SUAVE.Analyses.Mission.Segments.Conditions.Aerodynamics() p = atmo_values.pressure T = atmo_values.temperature rho = atmo_values.density a = atmo_values.speed_of_sound mu =atmo_values.dynamic_viscosity p0 = conditions0.pressure T0 = conditions0.temperature rho0 = conditions0.density a0 = conditions0.speed_of_sound mu0 = conditions0.dynamic_viscosity T_delta_ISA = T + delta_isa sigma_disa = (p/p0) / (T_delta_ISA/T0) rho = rho0 * sigma_disa a_delta_ISA = atmo.fluid_properties.compute_speed_of_sound(T_delta_ISA) mu = 1.78938028e-05 * ((T0 + 120) / T0 ** 1.5) * ((T_delta_ISA ** 1.5) / (T_delta_ISA + 120)) sea_level_gravity = atmo.planet.sea_level_gravity # ============================================== # Determining vehicle maximum lift coefficient # ============================================== try: # aircraft maximum lift informed by user maximum_lift_coefficient = vehicle.maximum_lift_coefficient except: # Using semi-empirical method for maximum lift coefficient calculation from SUAVE.Methods.Aerodynamics.Fidelity_Zero.Lift import compute_max_lift_coeff # Condition to CLmax calculation: 90KTAS @ 10000ft, ISA conditions = atmo.compute_values(10000. * Units.ft) conditions.freestream=Data() conditions.freestream.density = conditions.density conditions.freestream.dynamic_viscosity = conditions.dynamic_viscosity conditions.freestream.velocity = 90. * Units.knots try: maximum_lift_coefficient, induced_drag_high_lift = compute_max_lift_coeff(vehicle,conditions) vehicle.maximum_lift_coefficient = maximum_lift_coefficient except: raise ValueError, "Maximum lift coefficient calculation error. Please, check inputs" # ============================================== # Computing speeds (Vs, V2, 0.7*V2) # ============================================== stall_speed = (2 * weight * sea_level_gravity / (rho * reference_area * maximum_lift_coefficient)) ** 0.5 V2_speed = V2_VS_ratio * stall_speed speed_for_thrust = 0.70 * V2_speed # ============================================== # Determining vehicle number of engines # ============================================== engine_number = 0. for propulsor in vehicle.propulsors : # may have than one propulsor engine_number += propulsor.number_of_engines if engine_number == 0: raise ValueError, "No engine found in the vehicle" # ============================================== # Getting engine thrust # ============================================== state = Data() state.conditions = conditions state.numerics = Data() conditions.freestream = Data() conditions.propulsion = Data() conditions.freestream.dynamic_pressure = np.array(np.atleast_1d(0.5 * rho * speed_for_thrust**2)) conditions.freestream.gravity = np.array([np.atleast_1d(sea_level_gravity)]) conditions.freestream.velocity = np.array(np.atleast_1d(speed_for_thrust)) conditions.freestream.mach_number = np.array(np.atleast_1d(speed_for_thrust/ a_delta_ISA)) conditions.freestream.temperature = np.array(np.atleast_1d(T_delta_ISA)) conditions.freestream.pressure = np.array(np.atleast_1d(p)) conditions.propulsion.throttle = np.array(np.atleast_1d(1.)) results = vehicle.propulsors.evaluate_thrust(state) # total thrust thrust = results.thrust_force_vector # ============================================== # Calculate takeoff distance # ============================================== # Defining takeoff distance equations coefficients try: takeoff_constants = vehicle.takeoff_constants # user defined except: # default values takeoff_constants = np.zeros(3) if engine_number == 2: takeoff_constants[0] = 857.4 takeoff_constants[1] = 2.476 takeoff_constants[2] = 0.00014 elif engine_number == 3: takeoff_constants[0] = 667.9 takeoff_constants[1] = 2.343 takeoff_constants[2] = 0.000093 elif engine_number == 4: takeoff_constants[0] = 486.7 takeoff_constants[1] = 2.282 takeoff_constants[2] = 0.0000705 elif engine_number > 4: takeoff_constants[0] = 486.7 takeoff_constants[1] = 2.282 takeoff_constants[2] = 0.0000705 print 'The vehicle has more than 4 engines. Using 4 engine correlation. Result may not be correct.' else: takeoff_constants[0] = 857.4 takeoff_constants[1] = 2.476 takeoff_constants[2] = 0.00014 print 'Incorrect number of engines: {0:.1f}. Using twin engine correlation.'.format(engine_number) # Define takeoff index (V2^2 / (T/W) takeoff_index = V2_speed**2. / (thrust[0][0] / weight) # Calculating takeoff field length takeoff_field_length = 0. for idx,constant in enumerate(takeoff_constants): takeoff_field_length += constant * takeoff_index**idx p takeoff_field_length = takeoff_field_length * Units.ft # return return takeoff_field_length
def estimate_2ndseg_lift_drag_ratio(config): """ SUAVE.Methods.Aerodynamics.Drag.Correlations.estimate_2ndseg_lift_drag_ratio(config): Estimates the 2nd segment Lift to drag ration (all engine operating) Inputs: config - data dictionary with fields: reference_area - Airplane reference area V2_VS_ratio - Ratio between V2 and Stall speed [optional. Default value = 1.20] Main_Wing.aspect_ratio - Main_Wing aspect ratio maximum_lift_coefficient - Maximum lift coefficient for the config [Calculated if not informed] Outputs: takeoff_field_length - Takeoff field length Assumptions: All engines Operating. Must be corrected for second segment climb configuration reference: Fig. 27.34 of "Aerodynamic Design of Transport Airplane" - Obert """ # ============================================== # Unpack # ============================================== try: V2_VS_ratio = config.V2_VS_ratio except: V2_VS_ratio = 1.20 # typical condition # getting geometrical data (aspect ratio) n_wing = 0 for wing in config.wings: if not isinstance(wing,Wings.Main_Wing): continue reference_area = wing.areas.reference wing_span = wing.spans.projected try: aspect_ratio = wing.aspect_ratio except: aspect_ratio = wing_span ** 2 / reference_area n_wing += 1 if n_wing > 1: print ' More than one Main_Wing in the config. Last one will be considered.' elif n_wing == 0: print 'No Main_Wing defined! Using the 1st wing found' for wing in config.wings: if not isinstance(wing,Wings.Wing): continue reference_area = wing.areas.reference wing_span = wing.spans.projected try: aspect_ratio = wing.aspect_ratio except: aspect_ratio = wing_span ** 2 / reference_area break # Determining vehicle maximum lift coefficient try: # aircraft maximum lift informed by user maximum_lift_coefficient = config.maximum_lift_coefficient except: # Using semi-empirical method for maximum lift coefficient calculation from SUAVE.Methods.Aerodynamics.Fidelity_Zero.Lift import compute_max_lift_coeff # Condition to CLmax calculation: 90KTAS @ 10000ft, ISA conditions = Data() conditions.freestream = Data() conditions.freestream.density = 0.90477283 conditions.freestream.dynamic_viscosity = 1.69220918e-05 conditions.freestream.velocity = 90. * Units.knots try: maximum_lift_coefficient, induced_drag_high_lift = compute_max_lift_coeff(config,conditions) config.maximum_lift_coefficient = maximum_lift_coefficient except: raise ValueError, "Maximum lift coefficient calculation error. Please, check inputs" # Compute CL in V2 lift_coeff = maximum_lift_coefficient / (V2_VS_ratio ** 2) # Estimate L/D in 2nd segment condition, ALL ENGINES OPERATIVE! lift_drag_ratio = -6.464 * lift_coeff + 7.264 * aspect_ratio ** 0.5 return lift_drag_ratio
def estimate_take_off_field_length(vehicle, analyses, airport): """ SUAVE.Methods.Performance.estimate_take_off_field_length(vehicle,airport): Computes the takeoff field length for a given vehicle condition in a given airport Inputs: vehicle - SUAVE type vehicle includes these fields: Mass_Properties.takeoff - Takeoff weight to be evaluated S - Wing Area V2_VS_ratio - Ratio between V2 and Stall speed [optional. Default value = 1.20] takeoff_constants - Coefficients for takeoff field length equation [optional. Default values: AA241 method] maximum_lift_coefficient - Maximum lift coefficient for the config [optional. Calculated if not informed] airport - SUAVE type airport data, with followig fields: atmosphere - Airport atmosphere (SUAVE type) altitude - Airport altitude delta_isa - ISA Temperature deviation Outputs: takeoff_field_length - Takeoff field length Assumptions: Correlation based. """ # ============================================== # Unpack # ============================================== atmo = airport.atmosphere altitude = airport.altitude * Units.ft delta_isa = airport.delta_isa weight = vehicle.mass_properties.takeoff reference_area = vehicle.reference_area try: V2_VS_ratio = vehicle.V2_VS_ratio except: V2_VS_ratio = 1.20 # ============================================== # Computing atmospheric conditions # ============================================== conditions0 = atmo.compute_values(0.) atmo_values = atmo.compute_values(altitude) conditions = SUAVE.Analyses.Mission.Segments.Conditions.Aerodynamics() p = atmo_values.pressure T = atmo_values.temperature rho = atmo_values.density a = atmo_values.speed_of_sound mu = atmo_values.dynamic_viscosity p0 = conditions0.pressure T0 = conditions0.temperature rho0 = conditions0.density a0 = conditions0.speed_of_sound mu0 = conditions0.dynamic_viscosity T_delta_ISA = T + delta_isa sigma_disa = (p / p0) / (T_delta_ISA / T0) rho = rho0 * sigma_disa a_delta_ISA = atmo.fluid_properties.compute_speed_of_sound(T_delta_ISA) mu = 1.78938028e-05 * ((T0 + 120) / T0**1.5) * ((T_delta_ISA**1.5) / (T_delta_ISA + 120)) sea_level_gravity = atmo.planet.sea_level_gravity # ============================================== # Determining vehicle maximum lift coefficient # ============================================== try: # aircraft maximum lift informed by user maximum_lift_coefficient = vehicle.maximum_lift_coefficient except: # Using semi-empirical method for maximum lift coefficient calculation from SUAVE.Methods.Aerodynamics.Fidelity_Zero.Lift import compute_max_lift_coeff # Condition to CLmax calculation: 90KTAS @ 10000ft, ISA conditions = atmo.compute_values(10000. * Units.ft) conditions.freestream = Data() conditions.freestream.density = conditions.density conditions.freestream.dynamic_viscosity = conditions.dynamic_viscosity conditions.freestream.velocity = 90. * Units.knots try: maximum_lift_coefficient, induced_drag_high_lift = compute_max_lift_coeff( vehicle, conditions) vehicle.maximum_lift_coefficient = maximum_lift_coefficient except: raise ValueError, "Maximum lift coefficient calculation error. Please, check inputs" # ============================================== # Computing speeds (Vs, V2, 0.7*V2) # ============================================== stall_speed = (2 * weight * sea_level_gravity / (rho * reference_area * maximum_lift_coefficient))**0.5 V2_speed = V2_VS_ratio * stall_speed speed_for_thrust = 0.70 * V2_speed # ============================================== # Determining vehicle number of engines # ============================================== engine_number = 0. for propulsor in vehicle.propulsors: # may have than one propulsor engine_number += propulsor.number_of_engines if engine_number == 0: raise ValueError, "No engine found in the vehicle" # ============================================== # Getting engine thrust # ============================================== state = Data() state.conditions = conditions state.numerics = Data() conditions.freestream = Data() conditions.propulsion = Data() conditions.freestream.dynamic_pressure = np.array( np.atleast_1d(0.5 * rho * speed_for_thrust**2)) conditions.freestream.gravity = np.array( [np.atleast_1d(sea_level_gravity)]) conditions.freestream.velocity = np.array(np.atleast_1d(speed_for_thrust)) conditions.freestream.mach_number = np.array( np.atleast_1d(speed_for_thrust / a_delta_ISA)) conditions.freestream.temperature = np.array(np.atleast_1d(T_delta_ISA)) conditions.freestream.pressure = np.array(np.atleast_1d(p)) conditions.propulsion.throttle = np.array(np.atleast_1d(1.)) results = vehicle.propulsors.evaluate_thrust(state) # total thrust thrust = results.thrust_force_vector # ============================================== # Calculate takeoff distance # ============================================== # Defining takeoff distance equations coefficients try: takeoff_constants = vehicle.takeoff_constants # user defined except: # default values takeoff_constants = np.zeros(3) if engine_number == 2: takeoff_constants[0] = 857.4 takeoff_constants[1] = 2.476 takeoff_constants[2] = 0.00014 elif engine_number == 3: takeoff_constants[0] = 667.9 takeoff_constants[1] = 2.343 takeoff_constants[2] = 0.000093 elif engine_number == 4: takeoff_constants[0] = 486.7 takeoff_constants[1] = 2.282 takeoff_constants[2] = 0.0000705 elif engine_number > 4: takeoff_constants[0] = 486.7 takeoff_constants[1] = 2.282 takeoff_constants[2] = 0.0000705 print 'The vehicle has more than 4 engines. Using 4 engine correlation. Result may not be correct.' else: takeoff_constants[0] = 857.4 takeoff_constants[1] = 2.476 takeoff_constants[2] = 0.00014 print 'Incorrect number of engines: {0:.1f}. Using twin engine correlation.'.format( engine_number) # Define takeoff index (V2^2 / (T/W) takeoff_index = V2_speed**2. / (thrust[0][0] / weight) # Calculating takeoff field length takeoff_field_length = 0. for idx, constant in enumerate(takeoff_constants): takeoff_field_length += constant * takeoff_index**idx p takeoff_field_length = takeoff_field_length * Units.ft # return return takeoff_field_length
def V_n_diagram(vehicle, analyses, weight, altitude, delta_ISA): """ Computes a V-n diagram for a given aircraft and given regulations for ISA conditions Source: S. Gudmundsson "General Aviation Aircraft Design: Applied Methods and Procedures", Butterworth-Heinemann; 1 edition CFR FAR Part 23: https://www.ecfr.gov/cgi-bin/text-idx?SID=0e6a13c7c1de7f501d0eb0a4d71418bd&mc=true&tpl=/ecfrbrowse/Title14/14cfr23_main_02.tpl CFR FAR Part 25: https://www.ecfr.gov/cgi-bin/text-idx?tpl=/ecfrbrowse/Title14/14cfr25_main_02.tpl Inputs: analyses.base.atmosphere [SUAVE data type] vehicle. reference_area [m^2] maximum_lift_coefficient [Unitless] minimum_lift_coefficient [Unitless] chords.mean_aerodynamic [m] envelope.FARpart_number [Unitless] limit_loads.positive [Unitless] limit_loads.negative [Unitless] cruise_mach [Unitless] weight [kg] altitude [m] delta_ISA [deg C] Outputs: V_n_data Properties Used: N/A Description: The script creates an aircraft V-n diagram based on the input parameters specified by the user. Depending on the certification flag, an appropriate diagram, output and log files are created. """ #------------------------ # Create a log - file #------------------------ flog = open("V_n_diagram_" + vehicle.tag + ".log", "w") print('Running the V-n diagram calculation...') flog.write('Running the V-n diagram calculation...\n') flog.write('Aircraft: ' + vehicle.tag + '\n') flog.write('Category: ' + vehicle.envelope.category + '\n') flog.write('FAR certification: Part ' + str(vehicle.envelope.FAR_part_number) + '\n\n') # ---------------------------------------------- # Unpack # ---------------------------------------------- flog.write('Unpacking the input and calculating required inputs...\n') FAR_part_number = vehicle.envelope.FAR_part_number atmo = analyses.atmosphere Mc = vehicle.envelope.cruise_mach for wing in vehicle.wings: reference_area = vehicle.reference_area Cmac = wing.chords.mean_aerodynamic for envelope in vehicle: pos_limit_load = vehicle.envelope.limit_loads.positive neg_limit_load = vehicle.envelope.limit_loads.negative category_tag = vehicle.envelope.category # ---------------------------------------------- # Computing atmospheric conditions # ---------------------------------------------- atmo_values = atmo.compute_values(altitude, delta_ISA) SL_atmo_values = atmo.compute_values(0, delta_ISA) conditions = SUAVE.Analyses.Mission.Segments.Conditions.Aerodynamics() rho = atmo_values.density sea_level_rho = SL_atmo_values.density sea_level_gravity = atmo.planet.sea_level_gravity Vc = Mc * (1.4 * 287 * atmo_values.temperature)**0.5 # ------------------------------ # Computing lift-curve slope # ------------------------------ CLa = datcom(vehicle.wings.main_wing, np.array([Mc])) CLa = CLa[0] # ----------------------------------------------------------- # Determining vehicle minimum and maximum lift coefficients # ----------------------------------------------------------- try: # aircraft maximum lift informed by user maximum_lift_coefficient = vehicle.maximum_lift_coefficient except: # Condition to CLmax calculation: 0.333 * Vc @ specified altitude, ISA conditions.freestream = Data() conditions.freestream.density = atmo_values.density conditions.freestream.dynamic_viscosity = atmo_values.dynamic_viscosity conditions.freestream.velocity = 0.333 * Vc try: max_lift_coefficient, induced_drag_high_lift \ = compute_max_lift_coeff(vehicle,conditions) maximum_lift_coefficient = max_lift_coefficient[0][0] vehicle.maximum_lift_coefficient = maximum_lift_coefficient except: raise ValueError( "Maximum lift coefficient calculation error. Please, check inputs" ) try: # aircraft minimum lift informed by user minimum_lift_coefficient = vehicle.minimum_lift_coefficient except: raise ValueError( "The value not found. Specify minimum lift coefficient") # ----------------------------------------------------------------------------- # Convert all terms to English (Used for FAR) and remove elements from arrays # ----------------------------------------------------------------------------- altitude = altitude / Units.ft rho = rho[0, 0] / Units['slug/ft**3'] sea_level_rho = sea_level_rho[0, 0] / Units['slug/ft**3'] density_ratio = (rho / sea_level_rho)**0.5 sea_level_gravity = sea_level_gravity / Units['ft/s**2'] weight = weight / Units['slug'] * sea_level_gravity reference_area = reference_area / Units['ft**2'] Cmac = Cmac / Units.ft wing_loading = weight / reference_area Vc = Vc / Units['ft/s'] load_factors_pos = np.zeros(shape=(5)) load_factors_neg = np.zeros(shape=(5)) load_factors_pos[1] = 1 load_factors_neg[1] = -1 airspeeds_pos = np.zeros(shape=(5)) airspeeds_neg = np.zeros(shape=(5)) # -------------------------------------------------- # Establish limit maneuver load factors n+ and n- # -------------------------------------------------- flog.write('Establish limit maneuver load factors n+ and n-...\n') # CFR Part 25 # Positive and negative limits if FAR_part_number == 25: # Positive limit flog.write(' Estimating n+...\n') load_factors_pos[2] = 2.1 + 24000 / (weight + 10000) if load_factors_pos[2] < 2.5: flog.write( ' Defined positive limit load factor < 2.5. Setting 2.5...\n' ) load_factors_pos[2] = 2.5 elif load_factors_pos[2] < pos_limit_load: load_factors_pos[2] = pos_limit_load elif load_factors_pos[2] > 3.8: flog.write( ' Defined positive limit load factor > 3.8. Setting 3.8...\n' ) load_factors_pos[2] = 3.8 # Negative limit flog.write(' Estimating n-...\n') load_factors_neg[2] = neg_limit_load if load_factors_neg[2] > -1: flog.write( ' Negative limit load factor magnitude is too small. Setting to -1...\n' ) load_factors_neg[2] = -1 elif FAR_part_number == 23: if category_tag == 'normal' or category_tag == 'commuter': # Positive limit flog.write(' Estimating n+...\n') load_factors_pos[2] = 2.1 + 24000 / (weight + 10000) if load_factors_pos[2] < 2.5: flog.write( ' Defined positive limit load factor < 2.5. Setting 2.5...\n' ) load_factors_pos[2] = 2.5 elif load_factors_pos[2] < pos_limit_load: load_factors_pos[2] = pos_limit_load elif load_factors_pos[2] > 3.8: flog.write( ' Defined positive limit load factor > 3.8. Setting 3.8...\n' ) load_factors_pos[2] = 3.8 # Negative limit flog.write(' Estimating n-...\n') load_factors_neg[2] = -0.4 * load_factors_pos[2] elif category_tag == 'utility': # Positive limit flog.write(' Estimating n+...\n') load_factors_pos[2] = pos_limit_load if load_factors_pos[2] < 4.4: flog.write( ' Defined positive limit load factor < 4.4. Setting 4.4...\n' ) load_factors_pos[2] = 4.4 # Negative limit flog.write(' Estimating n-...\n') load_factors_neg[2] = -0.4 * load_factors_pos[2] elif category_tag == 'acrobatic': # Positive limit load_factors_pos[2] = pos_limit_load if load_factors_pos[2] < 6.0: flog.write( ' Defined positive limit load factor < 6.0. Setting 6.0...\n' ) load_factors_pos[2] = 6.0 # Negative limit load_factors_neg[2] = -0.5 * load_factors_pos[2] else: raise ValueError( "Check the category_tag input. The parameter was not found") else: raise ValueError( "Check the FARflag input. The parameter was not found") # Check input of the limit load if abs(neg_limit_load) > abs(load_factors_neg[2]): load_factors_neg[2] = neg_limit_load #---------------------------------------- # Generate a V-n diagram data structure #---------------------------------------- V_n_data = Data() V_n_data.limit_loads = Data() V_n_data.limit_loads.dive = Data() V_n_data.load_factors = Data() V_n_data.gust_load_factors = Data() V_n_data.Vb_load_factor = Data() V_n_data.airspeeds = Data() V_n_data.Vs1 = Data() V_n_data.Va = Data() V_n_data.Vb = Data() V_n_data.load_factors.positive = load_factors_pos V_n_data.load_factors.negative = load_factors_neg V_n_data.airspeeds.positive = airspeeds_pos V_n_data.airspeeds.negative = airspeeds_neg V_n_data.Vc = Vc V_n_data.weight = weight V_n_data.wing_loading = wing_loading V_n_data.altitude = altitude V_n_data.density = rho V_n_data.density_ratio = density_ratio V_n_data.reference_area = reference_area V_n_data.maximum_lift_coefficient = maximum_lift_coefficient V_n_data.minimum_lift_coefficient = minimum_lift_coefficient V_n_data.limit_loads.positive = load_factors_pos[2] V_n_data.limit_loads.negative = load_factors_neg[2] # -------------------------------------------------- # Computing critical speeds (Va, Vc, Vb, Vd, Vs1) # -------------------------------------------------- flog.write('Computing critical speeds (Va, Vc, Vb, Vd, Vs1)...\n') # Calculate Stall and Maneuver speeds flog.write(' Computing Vs1 and Va...\n') stall_maneuver_speeds(V_n_data) # convert speeds to KEAS for future calculations convert_keas(V_n_data) # unpack modified airspeeds airspeeds_pos = V_n_data.airspeeds.positive airspeeds_neg = V_n_data.airspeeds.negative Vc = V_n_data.Vc Va_pos = V_n_data.Va.positive Va_neg = V_n_data.Va.negative Va_pos = V_n_data.Va.positive Va_neg = V_n_data.Va.negative flog.write(' Checking Vc wrt Va...\n') if Va_neg > Vc and Va_neg > Va_pos: flog.write(' Negative Va > Vc. Setting Vc = 1.15 * Va...\n') Vc = 1.15 * Va_neg elif Va_pos > Vc and Va_neg < Va_pos: flog.write(' Positive Va > Vc. Setting Vc = 1.15 * Va...\n') Vc = 1.15 * Va_pos # Gust speeds between Vb and Vc (EAS) and minimum Vc miu = 2 * wing_loading / (rho * Cmac * CLa * sea_level_gravity) Kg = 0.88 * miu / (5.3 + miu) if FAR_part_number == 25: if altitude < 15000: Uref_cruise = (-0.0008 * altitude + 56) Uref_rough = Uref_cruise Uref_dive = 0.5 * Uref_cruise else: Uref_cruise = (-0.0005142 * altitude + 51.7133) Uref_rough = Uref_cruise Uref_dive = 0.5 * Uref_cruise # Minimum Cruise speed Vc_min coefs = [ 1, -Uref_cruise * (2.64 + (Kg * CLa * airspeeds_pos[1]**2) / (498 * wing_loading)), 1.72424 * Uref_cruise**2 - airspeeds_pos[1]**2 ] Vc1 = max(np.roots(coefs)) elif FAR_part_number == 23: if altitude < 20000: Uref_cruise = 50 Uref_dive = 25 else: Uref_cruise = (-0.0008333 * altitude + 66.67) Uref_dive = (-0.0004167 * altitude + 33.334) if category_tag == 'commuter': if altitude < 20000: Uref_rough = 66 else: Uref_rough = -0.000933 * altitude + 84.667 else: Uref_rough = Uref_cruise # Minimum Cruise speed Vc_min if category_tag == 'acrobatic': Vc1 = 36 * wing_loading**0.5 if wing_loading >= 20: Vc1 = (-0.0925 * wing_loading + 37.85) * wing_loading**0.5 else: Vc1 = 33 * wing_loading**0.5 if wing_loading >= 20: Vc1 = (-0.055 * wing_loading + 34.1) * wing_loading**0.5 # checking input Cruise speed flog.write(' Checking Vc wrt Vcmin... \n') if Vc1 > Vc: flog.write( ' Specified cruise speed is less than the minimum required. Setting th minimum required value...\n' ) Vc = Vc1 # Dive speed flog.write(' Computing Vd...\n') if FAR_part_number == 25: airspeeds_pos[4] = 1.25 * Vc elif FAR_part_number == 23: if category_tag == 'acrobatic': airspeeds_pos[4] = 1.55 * Vc1 if wing_loading > 20: airspeeds_pos[4] = (-0.0025 * wing_loading + 1.6) * Vc1 elif category_tag == 'utility': airspeeds_pos[4] = 1.5 * Vc1 if wing_loading > 20: airspeeds_pos[4] = (-0.001875 * wing_loading + 1.5375) * Vc1 else: airspeeds_pos[4] = 1.4 * Vc1 if wing_loading > 20: airspeeds_pos[4] = (-0.000625 * wing_loading + 1.4125) * Vc1 if airspeeds_pos[4] < 1.15 * Vc: flog.write( ' Based on min Vc, Vd is too close Vc. Setting Vd = 1.15 Vc...\n' ) airspeeds_pos[4] = 1.15 * Vc Vd = airspeeds_pos[4] airspeeds_pos[3] = airspeeds_pos[4] airspeeds_neg[3] = Vc airspeeds_neg[4] = airspeeds_pos[4] # complete initial load factors load_factors_pos[4] = 0 load_factors_neg[4] = 0 if category_tag == 'acrobatic' or category_tag == 'utility': load_factors_neg[4] = -1 load_factors_pos[3] = load_factors_pos[2] load_factors_neg[3] = load_factors_neg[2] # add parameters to the data structure V_n_data.load_factors.positive = load_factors_pos V_n_data.load_factors.negative = load_factors_neg V_n_data.airspeeds.positive = airspeeds_pos V_n_data.airspeeds.negative = airspeeds_neg V_n_data.Vd = Vd V_n_data.Vc = Vc #------------------------ # Create Stall lines #------------------------ flog.write('Creating stall lines...\n') Num_of_points = 20 # number of points for the stall line upper_bound = 2 lower_bound = 1 stall_line(V_n_data, upper_bound, lower_bound, Num_of_points, 1) stall_line(V_n_data, upper_bound, lower_bound, Num_of_points, 2) # ---------------------------------------------- # Determine Gust loads # ---------------------------------------------- flog.write('Calculating gust loads...\n') V_n_data.gust_data = Data() V_n_data.gust_data.airspeeds = Data() V_n_data.gust_data.airspeeds.rough_gust = Uref_rough V_n_data.gust_data.airspeeds.cruise_gust = Uref_cruise V_n_data.gust_data.airspeeds.dive_gust = Uref_dive gust_loads(category_tag, V_n_data, Kg, CLa, Num_of_points, FAR_part_number, 1) gust_loads(category_tag, V_n_data, Kg, CLa, Num_of_points, FAR_part_number, 2) #---------------------------------------------------------------- # Finalize the load factors for acrobatic and utility aircraft #---------------------------------------------------------------- if category_tag == 'acrobatic' or category_tag == 'utility': V_n_data.airspeeds.negative = np.append(V_n_data.airspeeds.negative, Vd) V_n_data.load_factors.negative = np.append( V_n_data.load_factors.negative, 0) # ---------------------------------------------- # Post-processing the V-n diagram # ---------------------------------------------- flog.write('Post-Processing...\n') V_n_data.limit_loads.positive = max(V_n_data.load_factors.positive) V_n_data.limit_loads.negative = min(V_n_data.load_factors.negative) post_processing(category_tag, Uref_rough, Uref_cruise, Uref_dive, V_n_data, vehicle) print('Calculation complete...') flog.write('Calculation complete\n') flog.close() return V_n_data
def estimate_2ndseg_lift_drag_ratio(state, settings, geometry): """Estimates the 2nd segment climb lift to drag ratio (all engine operating) Assumptions: All engines operating Source: Fig. 27.34 of "Aerodynamic Design of Transport Airplane" - Obert Inputs: config. V2_VS_ratio [Unitless] wings. areas.reference [m^2] spans.projected [m] aspect_ratio [Unitless] maximum_lift_coefficient [Unitless] Outputs: lift_drag_ratio [Unitless] Properties Used: N/A """ # ============================================== # Unpack # ============================================== try: V2_VS_ratio = geometry.V2_VS_ratio except: V2_VS_ratio = 1.20 # typical condition # getting geometrical data (aspect ratio) n_wing = 0 for wing in geometry.wings: if not isinstance(wing, Wings.Main_Wing): continue reference_area = wing.areas.reference wing_span = wing.spans.projected try: aspect_ratio = wing.aspect_ratio except: aspect_ratio = wing_span**2 / reference_area n_wing += 1 if n_wing > 1: print( ' More than one Main_Wing in the config. Last one will be considered.' ) elif n_wing == 0: print('No Main_Wing defined! Using the 1st wing found') for wing in geometry.wings: if not isinstance(wing, Wings.Wing): continue reference_area = wing.areas.reference wing_span = wing.spans.projected try: aspect_ratio = wing.aspect_ratio except: aspect_ratio = wing_span**2 / reference_area break # ============================================== # Determining vehicle maximum lift coefficient # ============================================== maximum_lift_coefficient, induced_drag_high_lift = compute_max_lift_coeff( state, settings, geometry) # Compute CL in V2 lift_coeff = maximum_lift_coefficient / (V2_VS_ratio**2) # Estimate L/D in 2nd segment condition, ALL ENGINES OPERATIVE! lift_drag_ratio = -6.464 * lift_coeff + 7.264 * aspect_ratio**0.5 return lift_drag_ratio
def estimate_landing_field_length(vehicle,analyses,airport): """ Computes the landing field length for a given vehicle configuration in a given airport. Assumptions: See source Two wheel trucks (code needed for four wheel trucks also included) Source: Torenbeek, E., "Advanced Aircraft Design", 2013 (equation 9.25) Inputs: airport. atmosphere [SUAVE data type] altitude [m] delta_isa [K] vehicle. mass_properties.landing [kg] reference_area [m^2] maximum_lift_coefficient (optional) [Unitless] Outputs: landing_field_length [m] Properties Used: N/A """ # ============================================== # Unpack # ============================================== atmo = airport.atmosphere altitude = airport.altitude * Units.ft delta_isa = airport.delta_isa weight = vehicle.mass_properties.landing reference_area = vehicle.reference_area try: Vref_VS_ratio = config.Vref_VS_ratio except: Vref_VS_ratio = 1.23 # ============================================== # Computing atmospheric conditions # ============================================== atmo_values = atmo.compute_values(altitude,delta_isa) conditions = SUAVE.Analyses.Mission.Segments.Conditions.Aerodynamics() p = atmo_values.pressure T = atmo_values.temperature rho = atmo_values.density a = atmo_values.speed_of_sound mu = atmo_values.dynamic_viscosity sea_level_gravity = atmo.planet.sea_level_gravity # ============================================== # Determining vehicle maximum lift coefficient # ============================================== try: # aircraft maximum lift informed by user maximum_lift_coefficient = vehicle.maximum_lift_coefficient except: # Using semi-empirical method for maximum lift coefficient calculation from SUAVE.Methods.Aerodynamics.Fidelity_Zero.Lift import compute_max_lift_coeff conditions.freestream = Data() conditions.freestream.density = rho conditions.freestream.dynamic_viscosity = mu conditions.freestream.velocity = 90. * Units.knots try: maximum_lift_coefficient, induced_drag_high_lift = compute_max_lift_coeff(vehicle,conditions) vehicle.maximum_lift_coefficient = maximum_lift_coefficient except: raise ValueError("Maximum lift coefficient calculation error. Please, check inputs") # ============================================== # Computing speeds (Vs, Vref) # ============================================== stall_speed = (2 * weight * sea_level_gravity / (rho * reference_area * maximum_lift_coefficient)) ** 0.5 Vref = stall_speed * Vref_VS_ratio # ======================================================================================== # Computing landing distance, according to Torenbeek equation # Landing Field Length = k1 + k2 * Vref**2 # ======================================================================================== # Defining landing distance equation coefficients try: landing_constants = config.landing_constants # user defined except: # default values - According to Torenbeek book landing_constants = np.zeros(3) landing_constants[0] = 250. landing_constants[1] = 0. landing_constants[2] = 2.485 / sea_level_gravity # Two-wheels truck : [ (1.56 / 0.40 + 1.07) / (2*sea_level_gravity) ] ## landing_constants[2] = 2.9725 / sea_level_gravity # Four-wheels truck: [ (1.56 / 0.32 + 1.07) / (2*sea_level_gravity) ] # Calculating landing field length landing_field_length = 0. for idx,constant in enumerate(landing_constants): landing_field_length += constant * Vref**idx # return return landing_field_length