Source code for RCAIDE.Library.Methods.Performance.estimate_take_off_field_length

# estimate_take_off_field_length.py
#
# Created:  Jun 2014, T. Orra, C. Ilario, Celso, 
# Modified: Apr 2015, M. Vegh 
#           Jan 2016, E. Botero
#           Mar 2020, M. Clarke
#           May 2020, E. Botero
#           Jul 2020, E. Botero 


# ----------------------------------------------------------------------
#  Imports
# ----------------------------------------------------------------------

# RCAIDE Imports
import RCAIDE
from RCAIDE.Framework.Core            import Data, Units     
from RCAIDE.Library.Methods.Aerodynamics.Common.Drag import * 
from RCAIDE.Library.Methods.Aerodynamics.Common.Lift import *

# package imports
import numpy as np

# ----------------------------------------------------------------------
#  Compute field length required for takeoff
# ----------------------------------------------------------------------
[docs] def estimate_take_off_field_length(vehicle,analyses,altitude = 0, delta_isa = 0, compute_2nd_seg_climb = False): """ Computes the takeoff field length and optionally the second segment climb gradient for a given vehicle configuration. Parameters ---------- vehicle : Vehicle The vehicle instance containing: - mass_properties.takeoff : float Takeoff weight [kg] - reference_area : float Wing reference area [m²] - V2_VS_ratio : float, optional Ratio of V2 to stall speed, default 1.20 - networks.*.number_of_engines : int Number of engines per network analyses : Analyses Container with atmosphere and aerodynamic analyses altitude : float, optional Airport altitude [m], default 0 delta_isa : float, optional Temperature offset from ISA conditions [K], default 0 compute_2nd_seg_climb : bool, optional Flag to compute second segment climb gradient, default False Returns ------- takeoff_field_length : float Required takeoff field length [m] second_seg_climb_gradient : float, optional Second segment climb gradient [unitless], only if compute_2nd_seg_climb=True Notes ----- The takeoff field length is computed using empirical correlations: .. math:: TOFL = k_0 + k_1(V_2^2/T/W) + k_2(V_2^2/T/W)^2 where k₀, k₁, k₂ depend on number of engines: * 2 engines: [857.4, 2.476, 0.00014] * 3 engines: [667.9, 2.343, 0.000093] * 4 engines: [486.7, 2.282, 0.0000705] **Major Assumptions** * Sea level standard conditions unless specified * Standard V2 speed ratio (1.20 × stall speed) * No wind conditions * Dry runway surface * For second segment climb: - One engine inoperative - Only validated for two-engine aircraft **Theory** Second segment climb gradient is computed as: .. math:: \gamma = T/W - 1/L/D where L/D includes effects of: * Windmilling drag * Asymmetric drag * High-lift device drag References ---------- [1] Stanford University AA241 Aircraft Design Course Notes http://adg.stanford.edu/aa241/AircraftDesign.html See Also -------- RCAIDE.Library.Methods.Aerodynamics.Common.Drag.windmilling_drag RCAIDE.Library.Methods.Aerodynamics.Common.Drag.asymmetry_drag """ # ============================================== # Unpack # ============================================== atmo = analyses.atmosphere 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 = RCAIDE.Framework.Mission.Common.Results() 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 = RCAIDE.Framework.Mission.Common.Results() 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, 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 network in vehicle.networks : # may have than one network engine_number += len(network.propulsors) if engine_number == 0: raise ValueError("No engine found in the vehicle") # ============================================== # Getting engine thrust # ============================================== # Step 28: Static Sea Level Thrust planet = RCAIDE.Library.Attributes.Planets.Earth() atmosphere_sls = RCAIDE.Framework.Analyses.Atmospheric.US_Standard_1976() atmo_data = atmosphere_sls.compute_values(0.0,0.0) p = atmo_data.pressure T = atmo_data.temperature rho = atmo_data.density a = atmo_data.speed_of_sound mu = atmo_data.dynamic_viscosity conditions = RCAIDE.Framework.Mission.Common.Results() conditions.freestream.altitude = np.atleast_1d(0) conditions.freestream.mach_number = np.atleast_1d(0.01) conditions.freestream.pressure = np.atleast_1d(p) conditions.freestream.temperature = np.atleast_1d(T) conditions.freestream.density = np.atleast_1d(rho) conditions.freestream.dynamic_viscosity = np.atleast_1d(mu) conditions.freestream.gravity = np.atleast_2d(planet.sea_level_gravity) conditions.freestream.speed_of_sound = np.atleast_1d(a) conditions.freestream.velocity = np.atleast_1d(a*0.01) # setup conditions segment = RCAIDE.Framework.Mission.Segments.Segment() segment.state.conditions = conditions thrust = np.array([[0.0, 0.0, 0.0]]) analysis = RCAIDE.Framework.Analyses.Vehicle() energy = RCAIDE.Framework.Analyses.Energy.Energy() energy.vehicle = vehicle analysis.append(energy) segment.analyses = analysis for network in vehicle.networks: network.add_unknowns_and_residuals_to_segment(segment) for propulsor in network.propulsors: segment.state.conditions.energy.propulsors[propulsor.tag].throttle = np.array([[1]]) network.evaluate(segment.state,center_of_gravity = vehicle.mass_properties.center_of_gravity) thrust += conditions.energy.thrust_force_vector # ============================================== # Calculate takeoff distance # ============================================== # Defining takeoff distance equations coefficients 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)) state.conditions.freestream.dynamic_viscosity = np.array(np.atleast_1d(mu)) state.conditions.freestream.density = np.array(np.atleast_1d(rho)) # engine condition num_propulsors = 0 for network in vehicle.networks: num_propulsors += len(network.propulsors) for propulsor in network.propulsors: engine_out_location = propulsor.origin[0][1] thrust = thrust * (num_propulsors -1 )/num_propulsors single_engine_thrust = np.linalg.norm(thrust /num_propulsors) # Compute windmilling drag windmilling_drag_coefficient = windmilling_drag(vehicle,state) # Compute asymmetry drag asymmetry_drag_coefficient = asymmetry_drag(state, vehicle,engine_out_location, single_engine_thrust, windmilling_drag_coefficient) # Compute l over d ratio for takeoff condition, NO engine failure l_over_d = estimate_2ndseg_lift_drag_ratio(state,settings,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[0][0], second_seg_climb_gradient[0][0] else: # return only takeoff_field_length return takeoff_field_length[0][0],0