def simple_method(input1,input2=None): """ SUAVE.Methods.SimpleMethod(input1,input2=None) does something useful Inputs: input1 - description [units] input2 - description [units] Outputs: output1 - description output2 - description >> try to minimize outputs >> pack up outputs into Data() if needed Assumptions: if needed """ # unpack inputs var1 = input1.var1 var2 = inputs.var2 # setup var3 = var1 * var2 # process magic = np.log(var3) # packup outputs output = Data() output.magic = magic output.var3 = var3 return output
def do_this(input1,input2=None): """ SUAVE.Attributes.Attribute.do_this(input1,input2=None) conditions data for some useful purpose Inputs: input1 - description [units] input2 - description [units] Outpus: output1 - description output2 - description >> try to minimize outputs >> pack up outputs into Data() if needed Assumptions: if needed """ # unpack inputs var1 = input1.var1 var2 = inputs.var2 # setup var3 = var1 * var2 # process magic = np.log(var3) # packup outputs output = Data() output.magic = magic output.var3 = var3 return output
def evaluate_field_length(vehicle): # --------------------------- # Check field performance # --------------------------- # define takeoff and landing configuration #print ' Defining takeoff and landing configurations' takeoff_config,landing_config = define_field_configs(vehicle) # define airport to be evaluated airport = SUAVE.Attributes.Airports.Airport() airport.altitude = 0.0 * Units.ft airport.delta_isa = 0.0 airport.atmosphere = SUAVE.Attributes.Atmospheres.Earth.US_Standard_1976() # evaluate takeoff / landing #print ' Estimating takeoff performance' TOFL = estimate_take_off_field_length(vehicle,takeoff_config,airport) #print ' Estimating landing performance' LFL = estimate_landing_field_length(vehicle,landing_config,airport) fldlength = Data() fldlength.TOFL = TOFL fldlength.LFL = LFL return fldlength
def main(): # Setup and pack inputs, test several cases conditions = Data() conditions.frames = Data() conditions.frames.body = Data() conditions.frames.planet = Data() conditions.frames.inertial = Data() conditions.freestream = Data() conditions.frames.body.inertial_rotations = np.zeros((4,3)) conditions.frames.planet.start_time = time.strptime("Thu, Mar 20 12:00:00 2014", "%a, %b %d %H:%M:%S %Y",) conditions.frames.planet.latitude = np.array([[0.0],[35],[70],[0.0]]) conditions.frames.planet.longitude = np.array([[0.0],[0.0],[0.0],[0.0]]) conditions.frames.body.inertial_rotations[:,0] = np.array([0.0,np.pi/10,np.pi/5,0.0]) # Phi conditions.frames.body.inertial_rotations[:,1] = np.array([0.0,np.pi/10,np.pi/5,0.0]) # Theta conditions.frames.body.inertial_rotations[:,2] = np.array([0.0,np.pi/2,np.pi,0.0]) # Psi conditions.freestream.altitude = np.array([[600000.0],[0.0],[60000],[1000]]) conditions.frames.inertial.time = np.array([[0.0],[0.0],[0.0],[43200]]) # Call solar radiation rad = SUAVE.Components.Energy.Processes.Solar_Radiation() fluxes = rad.solar_radiation(conditions) print('Solar Fluxes') print fluxes truth_fluxes = [[ 1304.01069749],[ 815.02502004],[ 783.55678702],[0.0]] max_error = np.max(np.abs(fluxes-truth_fluxes)) assert( max_error < 1e-5 ) return
def evaluate_range_from_short_field(vehicle,mission,results): # unpack airport_short_field = mission.airport_short_field tofl = airport_short_field.field_lenght takeoff_config = vehicle.configs.takeoff from SUAVE.Methods.Performance import find_takeoff_weight_given_tofl # evaluate maximum allowable takeoff weight from a short field tow_short_field = find_takeoff_weight_given_tofl(vehicle,takeoff_config,airport_short_field,tofl) # determine maximum range based in tow short_field from SUAVE.Methods.Performance import size_mission_range_given_weights # unpack cruise_segment_tag = 'Cruise' mission_payload = vehicle.mass_properties.payload # call function distance,fuel = size_mission_range_given_weights(vehicle,mission,cruise_segment_tag,mission_payload,tow_short_field) # pack short_field = Data() short_field.tag = 'short_field' short_field.takeoff_weight = tow_short_field short_field.range = distance short_field.fuel = fuel results.short_field = short_field return results
def do_this(input1, input2=None): """ SUAVE.Attributes.Attribute.do_this(input1,input2=None) conditions data for some useful purpose Inputs: input1 - description [units] input2 - description [units] Outpus: output1 - description output2 - description >> try to minimize outputs >> pack up outputs into Data() if needed Assumptions: if needed """ # unpack inputs var1 = input1.var1 var2 = inputs.var2 # setup var3 = var1 * var2 # process magic = np.log(var3) # packup outputs output = Data() output.magic = magic output.var3 = var3 return output
def simple_method(input1, input2=None): """ SUAVE.Methods.SimpleMethod(input1,input2=None) does something useful Inputs: input1 - description [units] input2 - description [units] Outputs: output1 - description output2 - description >> try to minimize outputs >> pack up outputs into Data() if needed Assumptions: if needed """ # unpack inputs var1 = input1.var1 var2 = inputs.var2 # setup var3 = var1 * var2 # process magic = np.log(var3) # packup outputs output = Data() output.magic = magic output.var3 = var3 return output
def __defaults__(self): self.tag = 'Turbojet Variable Nozzle' self.thrust_sls = 0.0 self.sfc_TF = 0.0 self.kwt0_eng = 0.0 self.type = 0 self.length = 0.0 self.cowl_length = 0.0 self.eng_thrt_ratio = 0.0 self.hilight_thrt_ratio = 0.0 self.lip_finess_ratio = 0.0 self.height_width_ratio = 0.0 self.upper_surf_shape_factor = 0.0 self.lower_surf_shape_factor = 0.0 self.dive_flap_ratio = 0.0 self.tip = Data() self.inlet = Data() self.diverter = Data() self.nozzle = Data() self.analysis_type= 'pass' #--geometry pass like self.engine_dia= 0.0 self.engine_length= 0.0 self.nacelle_dia= 0.0 self.inlet_length= 0.0 self.eng_maxarea= 0.0 self.inlet_area= 0.0 #newly added for 1d engine analysis self.diffuser_pressure_ratio = 1.0 self.fan_pressure_ratio = 1.0 self.fan_nozzle_pressure_ratio = 1.0 self.lpc_pressure_ratio = 1.0 self.hpc_pressure_ratio = 1.0 self.burner_pressure_ratio = 1.0 self.turbine_nozzle_pressure_ratio = 1.0 self.Tt4 = 1400 self.bypass_ratio = 0.0 self.mdhc = 0.0 self.thrust = Data() self.thrust.design = 1.0 self.no_of_engines=0.0 #----geometry self.A2 = 0.0 self.df = 0.0 self.A2_5 = 0.0 self.dhc = 0.0 self.A7 = 0.0 self.A5 = 0.0 self.Ao = 0.0 self.mdt = 0.0 self.mlt = 0.0 self.mdf = 0.0 self.mdlc = 0.0 self.mdot_core = 0.0 self.D=0.0
def __defaults__(self): # function handles for input self.inputs = Data() # function handles for output self.outputs = Data() return
def __call__(self,conditions): """ process vehicle to setup geometry, condititon and configuration Inputs: conditions - DataDict() of aerodynamic conditions Outputs: CL - array of lift coefficients, same size as alpha CD - array of drag coefficients, same size as alpha Assumptions: linear intperolation surrogate model on Mach, Angle of Attack and Reynolds number locations outside the surrogate's table are held to nearest data no changes to initial geometry or configuration """ # unpack configuration = self.configuration geometry = self.geometry q = conditions.freestream.dynamic_pressure Sref = geometry.reference_area # lift needs to compute first, updates data needed for drag CL = SUAVE.Methods.Aerodynamics.Supersonic_Zero.Lift.compute_aircraft_lift(conditions,configuration,geometry) # drag computes second CD = compute_aircraft_drag(conditions,configuration,geometry) # pack conditions conditions.aerodynamics.lift_coefficient = CL conditions.aerodynamics.drag_coefficient = CD # pack results results = Data() results.lift_coefficient = CL results.drag_coefficient = CD N = q.shape[0] L = np.zeros([N,3]) D = np.zeros([N,3]) L[:,2] = ( -CL * q * Sref )[:,0] D[:,0] = ( -CD * q * Sref )[:,0] #if L.any < 0.0: #k = 1 results.lift_force_vector = L results.drag_force_vector = D return results
def __defaults__(self): self.tag = 'Aerodynamics' self.geometry = Geometry() self.configuration = Configuration() self.conditions_table = Conditions( angle_of_attack=np.linspace(-10., 10., 5) * Units.deg, ) self.model = Data()
def short_period(velocity, density, S_gross_w, mac, Cm_q, Cz_alpha, mass, Cm_alpha, Iy, Cm_alpha_dot): """ output = SUAVE.Methods.Flight_Dynamics.Dynamic_Stablity.Approximations.short_period(velocity, density, S_gross_w, mac, Cm_q, Cz_alpha, mass, Cm_alpha, Iy, Cm_alpha_dot) Calculate the natural frequency and damping ratio for the approximate short period characteristics Inputs: velocity - flight velocity at the condition being considered [meters/seconds] density - flight density at condition being considered [kg/meters**3] S_gross_w - area of the wing [meters**2] mac - mean aerodynamic chord of the wing [meters] Cm_q - coefficient for the change in pitching moment due to pitch rate [dimensionless] Cz_alpha - coefficient for the change in Z force due to the angle of attack [dimensionless] mass - mass of the aircraft [kilograms] Cm_alpha - coefficient for the change in pitching moment due to angle of attack [dimensionless] Iy - moment of interia about the body y axis [kg * meters**2] Cm_alpha_dot - coefficient for the change in pitching moment due to rate of change of angle of attack [dimensionless] Outputs: output - a data dictionary with fields: w_n - natural frequency of the short period mode [radian/second] zeta - damping ratio of the short period mode [dimensionless] Assumptions: X-Z axis is plane of symmetry Constant mass of aircraft Origin of axis system at c.g. of aircraft Aircraft is a rigid body Earth is inertial reference frame Perturbations from equilibrium are small Flow is Quasisteady Constant forward airspeed Neglect Cz_alpha_dot and Cz_q Theta = 0 Source: J.H. Blakelock, "Automatic Control of Aircraft and Missiles" Wiley & Sons, Inc. New York, 1991, p 46-50. """ #process w_n = velocity * density * S_gross_w * mac / 2. * ( (0.5 * Cm_q * Cz_alpha - 2. * mass / density / S_gross_w / mac * Cm_alpha) / Iy / mass)**(0.5) zeta = -0.25 * (Cm_q + Cm_alpha_dot + 2. * Iy * Cz_alpha / mass / (mac**2.)) * (mass * mac**2. / Iy / (Cm_q * Cz_alpha * 0.5 - 2. * mass * Cm_alpha / density / S_gross_w / mac))**0.5 output = Data() output.natural_frequency = w_n output.damping_ratio = zeta return output
def __defaults__(self): self.tag = 'Aerodynamics' self.geometry = Geometry() self.configuration = Configuration() self.conditions_table = Conditions( angle_of_attack=np.linspace(-10., 10., 5) * Units.deg, mach_number=np.linspace(0.0, 1.0, 5), reynolds_number=np.linspace(1.e4, 1.e10, 3), ) self.model = Data()
def tail_vertical(S_v,Nult,b_v,TOW,t_c_v,sweep_v,S_gross_w,t_tail,rudder_fraction = 0.25): """ output = SUAVE.Methods.Weights.Correlations.Tube_Wing.tail_vertical(S_v,Nult,b_v,TOW,t_c_v,sweep_v,S_gross_w,t_tail) Calculate the weight of the vertical fin of an aircraft without the weight of the rudder and then calculate the weight of the rudder Inputs: S_v - area of the vertical tail (combined fin and rudder) [meters**2] Nult - ultimate load of the aircraft [dimensionless] b_v - span of the vertical [meters] TOW - maximum takeoff weight of the aircraft [kilograms] t_c_v - thickness-to-chord ratio of the vertical tail [dimensionless] sweep_v - sweep angle of the vertical tail [radians] S_gross_w - wing gross area [meters**2] t_tail - factor to determine if aircraft has a t-tail [dimensionless] rudder_fraction - fraction of the vertical tail that is the rudder [dimensionless] Outputs: output - a dictionary with outputs: wt_tail_vertical - weight of the vertical fin portion of the vertical tail [kilograms] wt_rudder - weight of the rudder on the aircraft [kilograms] Assumptions: Vertical tail weight is the weight of the vertical fin without the rudder weight. Rudder occupies 25% of the S_v and weighs 60% more per unit area. """ # unpack inputs span = b_v / Units.ft # Convert meters to ft sweep = sweep_v # Convert deg to radians area = S_v / Units.ft**2 # Convert meters squared to ft squared mtow = TOW / Units.lb # Convert kg to lbs Sref = S_gross_w / Units.ft**2 # Convert from meters squared to ft squared # process # Determine weight of the vertical portion of the tail if t_tail == "yes": T_tail_factor = 1.25 # Weight of vertical portion of the T-tail is 25% more than a conventional tail else: T_tail_factor = 1.0 # Calculate weight of wing for traditional aircraft vertical tail without rudder tail_vert_English = T_tail_factor * (2.62*area+1.5*10.**(-5.)*Nult*span**3.*(8.+0.44*mtow/Sref)/(t_c_v*(np.cos(sweep)**2.))) # packup outputs output = Data() output.wt_tail_vertical = tail_vert_English * Units.lbs # Convert from lbs to kg output.wt_rudder = output.wt_tail_vertical * rudder_fraction * 1.6 return output
def main(): # define the problem additional_drag_coefficient = 0.0000 vehicle, mission = full_setup(additional_drag_coefficient) # run the problem results = Data() results.mission_profile = Data() results.mission_profile = SUAVE.Methods.Performance.evaluate_mission(mission) # post process the results plot_mission(vehicle,mission,results) return
def get_final_conditions(self): conditions = self.conditions finals = Data() # the update function def pull_conditions(A,B): for k,v in A.iteritems(): # recursion if isinstance(v,Data): B[k] = Data() pull_conditions(A[k],B[k]) # need arrays here elif not isinstance(v,np.ndarray): continue #raise ValueError , 'condition "%s" must be type np.array' % k # the copy else: B[k] = A[k][-1,:][None,:] #: if type #: for each key,value #: def pull_conditions() # do the update! pull_conditions(conditions,finals) return finals
def build_surrogate_sup(self): # unpack data conditions_table = self.conditions_table AoA_data = conditions_table.angle_of_attack # CL_data = conditions_table.lift_coefficient # pack for surrogate X_data = np.array([AoA_data]).T # assign models X_data = np.reshape(X_data,-1) # assign models #Interpolation = Aerodynamics_1d_Surrogate.Interpolation(X_data,CL_data) Interpolation = np.poly1d(np.polyfit(X_data, CL_data ,1)) #Interpolation = Fidelity_Zero.Interpolation self.models.lift_coefficient = Interpolation # assign to configuration self.configuration.surrogate_models_sup = Data() self.configuration.surrogate_models_sup.lift_coefficient = Interpolation return
def short_period(velocity, density, S_gross_w, mac, Cm_q, Cz_alpha, mass, Cm_alpha, Iy, Cm_alpha_dot): """ output = SUAVE.Methods.Flight_Dynamics.Dynamic_Stablity.Approximations.short_period(velocity, density, S_gross_w, mac, Cm_q, Cz_alpha, mass, Cm_alpha, Iy, Cm_alpha_dot) Calculate the natural frequency and damping ratio for the approximate short period characteristics Inputs: velocity - flight velocity at the condition being considered [meters/seconds] density - flight density at condition being considered [kg/meters**3] S_gross_w - area of the wing [meters**2] mac - mean aerodynamic chord of the wing [meters] Cm_q - coefficient for the change in pitching moment due to pitch rate [dimensionless] Cz_alpha - coefficient for the change in Z force due to the angle of attack [dimensionless] mass - mass of the aircraft [kilograms] Cm_alpha - coefficient for the change in pitching moment due to angle of attack [dimensionless] Iy - moment of interia about the body y axis [kg * meters**2] Cm_alpha_dot - coefficient for the change in pitching moment due to rate of change of angle of attack [dimensionless] Outputs: output - a data dictionary with fields: w_n - natural frequency of the short period mode [radian/second] zeta - damping ratio of the short period mode [dimensionless] Assumptions: X-Z axis is plane of symmetry Constant mass of aircraft Origin of axis system at c.g. of aircraft Aircraft is a rigid body Earth is inertial reference frame Perturbations from equilibrium are small Flow is Quasisteady Constant forward airspeed Neglect Cz_alpha_dot and Cz_q Theta = 0 Source: J.H. Blakelock, "Automatic Control of Aircraft and Missiles" Wiley & Sons, Inc. New York, 1991, p 46-50. """ #process w_n = velocity * density * S_gross_w * mac / 2. * ((0.5*Cm_q*Cz_alpha - 2. * mass / density /S_gross_w /mac * Cm_alpha) / Iy /mass)**(0.5) zeta = -0.25 * (Cm_q + Cm_alpha_dot + 2. * Iy * Cz_alpha / mass / (mac ** 2.)) * ( mass * mac ** 2. / Iy / (Cm_q * Cz_alpha * 0.5 - 2. * mass * Cm_alpha / density / S_gross_w / mac)) ** 0.5 output = Data() output.natural_frequency = w_n output.damping_ratio = zeta return output
def dutch_roll(velocity, Cn_Beta, S_gross_w, density, span, I_z, Cn_r): """ output = SUAVE.Methods.Flight_Dynamics.Dynamic_Stablity.Approximations.dutch_roll(velocity, Cn_Beta, S_gross_w, density, span, I_z, Cn_r) Calculate the natural frequency and damping ratio for the approximate dutch roll characteristics Inputs: velocity - flight velocity at the condition being considered [meters/seconds] Cn_Beta - coefficient for change in yawing moment due to sideslip [dimensionless] S_gross_w - area of the wing [meters**2] density - flight density at condition being considered [kg/meters**3] span - wing span of the aircraft [meters] I_z - moment of interia about the body z axis [kg * meters**2] Cn_r - coefficient for change in yawing moment due to yawing velocity [dimensionless] Outputs: output - a data dictionary with fields: dutch_w_n - natural frequency of the dutch roll mode [radian/second] dutch_zeta - damping ratio of the dutch roll mode [dimensionless] Assumptions: Major effect of rudder deflection is the generation of the Dutch roll mode. Dutch roll mode only consists of sideslip and yaw Beta = -Psi Phi and its derivatives are zero consider only delta_r input and Theta = 0 Neglect Cy_r X-Z axis is plane of symmetry Constant mass of aircraft Origin of axis system at c.g. of aircraft Aircraft is a rigid body Earth is inertial reference frame Perturbations from equilibrium are small Flow is Quasisteady Source: J.H. Blakelock, "Automatic Control of Aircraft and Missiles" Wiley & Sons, Inc. New York, 1991, p 132-134. """ #process w_n = velocity * (Cn_Beta*S_gross_w*density*span/2./I_z)**0.5 # natural frequency zeta = -Cn_r /8. * (2.*S_gross_w*density*span**3./I_z/Cn_Beta)**0.5 # damping ratio output = Data() output.natural_frequency = w_n output.damping_ratio = zeta return output
def check_results(new_results): # check segment values truth = Data() truth.dist = [6426122.4935872, 5848398.49923247, 7044468.46851841] truth.fuel = [14771., 12695., 12695.] error = Data() error.dist = np.max(np.abs(new_results.dist - truth.dist)) error.fuel = np.max(np.abs(new_results.fuel - truth.fuel)) for k, v in error.items(): assert (np.abs(v) < 0.001)
def __defaults__(self): self.molecular_mass = 0.0 self.composition = Data() self.composition.liquid = 1.0 self.heat_of_vaporization = 0. #heat of vaporization of water [J/kg] self.density = 0. #density (kg/ self.boiling_point = 0. #boiling point [K]
def logic(self, conditions, numerics): """ The power being sent to the battery Inputs: payload power avionics power current to the esc voltage of the system MPPT efficiency Outputs: power to the battery Assumptions: Many: the system voltage is constant, the maximum power point is at a constant voltage """ #Unpack pin = self.inputs.powerin[:, 0, None] pavionics = self.inputs.pavionics ppayload = self.inputs.ppayload volts_motor = self.inputs.volts_motor volts = self.voltage() esccurrent = self.inputs.currentesc I = numerics.integrate_time pavail = pin * self.MPPT_efficiency plevel = pavail - pavionics - ppayload - volts_motor * esccurrent # Integrate the plevel over time to assess the energy consumption # or energy storage e = np.dot(I, plevel) # Send or take power out of the battery, Pack up batlogic = Data() batlogic.pbat = plevel batlogic.Ibat = (plevel / volts) batlogic.e = e # Output self.outputs.batlogic = batlogic return
def EvaluatePASS(vehicle, mission): """ Compute the Pass Performance Calculations using SU AA 241 course notes """ # unpack maxto = vehicle.Mass.mtow mzfw_ratio = vehicle.Mass.fmzfw sref = vehicle.Wing['Main Wing'].sref sfc_sfcref = vehicle.Turbo_Fan['TheTurboFan'].sfc_TF sls_thrust = vehicle.Turbo_Fan['TheTurboFan'].thrust_sls eng_type = vehicle.Turbo_Fan['TheTurboFan'].type_engine out = Data() # Calculate fuel_manuever = WeightManeuver(maxto) fuel_climb_added = WeightClimbAdded(vehicle, mission, maxto) reserve_fuel = FuelReserve(mission, maxto, mzfw_ratio, 0) out.range, fuel_cruise = CruiseRange(vehicle, mission, maxto, fuel_burn_maneuever, fuel_climb_added, reserve_fuel, sfc_sfcref, sls_thrust, eng_type, mzfw_ratio) out.fuel_burn = (2 * fuel_manuever) + fuel_climb_added + fuel_cruise out.tofl = TOFL(vehicle, mission, maxto, sref, sfc_sfcref, sls_thrust, eng_type) out.climb_grad = ClimbGradient(vehicle, mission, maxto, sfc_sfcref, sls_thrust, eng_type) out.lfl = LFL(vehicle, mission, maxto, mzfw_ratio, fuel_burn_maneuever, reserve_fuel, sref, sfc_sfcref, sls_thrust, eng_type) return out
def check_results(new_results): # check segment values truth = Data() truth.fuel = [14246., 12234., 12162.] truth.tow = [53855., 49919., 39989.] error = Data() error.fuel = np.max(np.abs(new_results.fuel - truth.fuel)) error.tow = np.max(np.abs(new_results.tow - truth.tow)) for k, v in error.items(): assert (np.abs(v) < 0.5)
def logic(self,conditions,numerics): """ The power being sent to the battery Inputs: payload power avionics power current to the esc voltage of the system MPPT efficiency Outputs: power to the battery Assumptions: Many: the system voltage is constant, the maximum power point is at a constant voltage """ #Unpack pin = self.inputs.powerin[:,0,None] pavionics = self.inputs.pavionics ppayload = self.inputs.ppayload volts_motor = self.inputs.volts_motor volts = self.voltage() esccurrent = self.inputs.currentesc I = numerics.integrate_time pavail = pin*self.MPPT_efficiency plevel = pavail -pavionics -ppayload - volts_motor*esccurrent # Integrate the plevel over time to assess the energy consumption # or energy storage e = np.dot(I,plevel) # Send or take power out of the battery, Pack up batlogic = Data() batlogic.pbat = plevel batlogic.Ibat = abs(plevel/volts) batlogic.e = e # Output self.outputs.batlogic = batlogic return
def __defaults__(self): self.uknots = [] self.vknots = [] self.p = 3 self.q = 3 self.N = 0 self.M = 0 self.CPs = Data() self.CPs.x = []; self.CPs.y = []; self.CPs.z = []; self.w = []
def __defaults__(self): self.tag = 'Constant-property atmopshere' self.pressure = 0.0 # Pa self.temperature = 0.0 # K self.density = 0.0 # kg/m^3 self.speed_of_sound = 0.0 # m/s self.dynamic_viscosity = 0.0 # Pa-s self.composition = Data() self.composition.gas = 1.0
def __defaults__(self): self.tag = 'Ductedfan' self.thrust_sls = 0.0 self.sfc_TF = 0.0 self.kwt0_eng = 0.0 self.type = 0 self.length = 0.0 self.cowl_length = 0.0 self.eng_thrt_ratio = 0.0 self.hilight_thrt_ratio = 0.0 self.lip_finess_ratio = 0.0 self.height_width_ratio = 0.0 self.upper_surf_shape_factor = 0.0 self.lower_surf_shape_factor = 0.0 self.dive_flap_ratio = 0.0 self.tip = Data() self.inlet = Data() self.diverter = Data() self.nozzle = Data() self.analysis_type = 'pass' self.battery = Battery() #--geometry pass like self.engine_dia = 0.0 self.engine_length = 0.0 self.nacelle_dia = 0.0 self.inlet_length = 0.0 self.eng_maxarea = 0.0 self.inlet_area = 0.0 #newly added for 1d engine analysis self.diffuser_pressure_ratio = 1.0 self.fan_pressure_ratio = 1.0 self.fan_nozzle_pressure_ratio = 1.0 self.design_thrust = 1.0 #----geometry self.A2 = 0.0 self.df = 0.0 self.A7 = 0.0 self.Ao = 0.0 self.mdf = 0.0 self.mdot_core = 0.0
def extrapolation(weight_landing, number_of_engines, thrust_sea_level, thrust_landing): """ weight = SUAVE.Methods.Weights.Correlations.Tube_Wing.landing_gear(TOW) Inputs: Outputs: Assumptions: The baseline case is 101 PNdb, 25,000 lb thrust, 1 engine, 1000ft """ #process baseline_noise = 101 thrust_percentage = (thrust_sea_level / Units.force_pound) / 25000 * 100. thrust_reduction = thrust_landing / thrust_sea_level * 100. noise_increase_due_to_thrust = -0.0002193 * thrust_percentage**2. + 0.09454 * thrust_percentage - 7.30116 noise_landing = -0.0015766 * thrust_reduction**2. + 0.34882 * thrust_reduction - 19.2569 takeoff_distance_noise = -4. # 1500 ft altitude at 6500m from start of take-off sideline_distance_noise = -6.5 #1 476 ft (450m) from centerline (effective distance = 1476*1.25 = 1845ft) landing_distance_noise = 9.1 # 370 ft altitude at 6562 ft (2000m) from runway takeoff = 10. * np.log10( 10.**(baseline_noise / 10.) * number_of_engines ) - 4. + takeoff_distance_noise + noise_increase_due_to_thrust side_line = 10. * np.log10( 10.**(baseline_noise / 10.) * number_of_engines ) - 4. + sideline_distance_noise + noise_increase_due_to_thrust landing = 10. * np.log10( 10.**(baseline_noise / 10.) * number_of_engines ) - 5. + landing_distance_noise + noise_increase_due_to_thrust + noise_landing airframe = 40. + 10. * np.log10(weight_landing) output = Data() output.takeoff = takeoff output.side_line = side_line output.landing = 10. * np.log10(10.**(airframe / 10.) + 10.**(landing / 10.)) return output
def initialize(self,vehicle): # unpack conditions_table = self.conditions_table geometry = self.geometry configuration = self.configuration # AoA = conditions_table.angle_of_attack n_conditions = len(AoA) # copy geometry for k in ['fuselages','wings','propulsors']: geometry[k] = deepcopy(vehicle[k]) # reference area geometry.reference_area = vehicle.reference_area # arrays CL = np.zeros_like(AoA) # condition input, local, do not keep konditions = Conditions() konditions.aerodynamics = Data() # calculate aerodynamics for table for i in xrange(n_conditions): # overriding conditions, thus the name mangling konditions.aerodynamics.angle_of_attack = AoA[i] # these functions are inherited from Aerodynamics() or overridden CL[i] = calculate_lift_vortex_lattice(konditions, configuration, geometry) # store table conditions_table.lift_coefficient = CL # build surrogate self.build_surrogate_sub() # calculate aerodynamics for table for i in xrange(n_conditions): # overriding conditions, thus the name mangling konditions.aerodynamics.angle_of_attack = AoA[i] # these functions are inherited from Aerodynamics() or overridden CL[i] = calculate_lift_linear_supersonic(konditions, configuration, geometry) # store table conditions_table.lift_coefficient = CL # build surrogate self.build_surrogate_sup() return
def compile_results(vehicle, mission, results): # merge all segment conditions def stack_condition(a, b): if isinstance(a, np.ndarray): return np.vstack([a, b]) else: return None conditions = None for segment in results.mission_profile.segments: if conditions is None: conditions = segment.conditions continue conditions = conditions.do_recursive(stack_condition, segment.conditions) # pack results.output = Data() results.output.stability = Data() results.output.weight_empty = vehicle.mass_properties.operating_empty results.output.fuel_burn = max(conditions.weights.total_mass[:, 0]) - min( conditions.weights.total_mass[:, 0]) #results.output.max_usable_fuel = vehicle.mass_properties.max_usable_fuel results.output.noise = results.noise results.output.mission_time_min = max( conditions.frames.inertial.time[:, 0] / Units.min) results.output.max_altitude_km = max(conditions.freestream.altitude[:, 0] / Units.km) results.output.range_nmi = results.mission_profile.segments[ -1].conditions.frames.inertial.position_vector[-1, 0] / Units.nmi results.output.field_length = results.field_length results.output.stability.cm_alpha = max( conditions.aerodynamics.cm_alpha[:, 0]) results.output.stability.cn_beta = max(conditions.aerodynamics.cn_beta[:, 0]) results.conditions = conditions #TODO: revisit how this is calculated results.output.second_segment_climb_rate = results.mission_profile.segments[ 1].climb_rate return results
def __defaults__(self): self.p = 3 # degree, e.g. cubic spline: order = 4, degree = 3 self.N = 0 self.dims = 2 self.w = [] self.knots = [] self.CPs = Data() self.CPs.x = [] self.CPs.y = [] self.CPs.z = []
def __defaults__(self): self.molecular_mass = 28.96442 # kg/kmol self.gas_specific_constant = 287.0528742 # m^2/s^2-K, specific gas constant self.composition = Data() self.composition.O2 = 0.20946 self.composition.Ar = 0.00934 self.composition.CO2 = 0.00036 self.composition.N2 = 0.78084 self.composition.other = 0.00
def __defaults__(self): self.mass = 0.0 self.volume = 0.0 self.center_of_gravity = [0.0, 0.0, 0.0] self.moments_of_inertia = Data() self.moments_of_inertia.center = [0.0, 0.0, 0.0] self.moments_of_inertia.tensor = [[0.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0]]
def __defaults__(self): self.tag = 'Fuselage' self.aerodynamic_center = [0.0,0.0,0.0] self.Sections = Lofted_Body.Section.Container() self.Segments = Lofted_Body.Segment.Container() self.number_coach_seats = 0.0 self.seats_abreast = 0.0 self.seat_pitch = 1.0 self.areas = Data() self.areas.front_projected = 0.0 self.areas.side_projected = 0.0 self.areas.wetted = 0.0 self.effective_diameter = 0.0 self.width = 0.0 self.heights = Data() self.heights.maximum = 0.0 self.heights.at_quarter_length = 0.0 self.heights.at_three_quarters_length = 0.0 self.heights.at_wing_root_quarter_chord = 0.0 self.lengths = Data() self.lengths.nose = 0.0 self.lengths.tail = 0.0 self.lengths.total = 0.0 self.lengths.cabin = 0.0 self.lengths.fore_space = 0.0 self.lengths.aft_space = 0.0 self.fineness = Data() self.fineness.nose = 0.0 self.fineness.tail = 0.0 self.differential_pressure = 0.0 self.Fineness = Data() self.Fineness.nose = 0.0 self.Fineness.tail = 0.0 self.differential_pressure = 0.0
def phugoid(g, velocity, CD, CL): """ output = SUAVE.Methods.Flight_Dynamics.Dynamic_Stablity.Approximations.phugoid(g, velocity, CD, CL) Calculate the natural frequency and damping ratio for the approximate phugoid characteristics Inputs: g - gravitational constant [meters/second**2] velocity - flight velocity at the condition being considered [meters/seconds] CD - coefficient of drag [dimensionless] CL - coefficient of lift [dimensionless] Outputs: output - a data dictionary with fields: phugoid_w_n - natural frequency of the phugoid mode [radian/second] phugoid_zeta - damping ratio of the phugoid mode [dimensionless] Assumptions: constant angle of attack theta changes very slowly Inertial forces are neglected Neglect Cz_q Theta = 0 X-Z axis is plane of symmetry Constant mass of aircraft Origin of axis system at c.g. of aircraft Aircraft is a rigid body Earth is inertial reference frame Perturbations from equilibrium are small Flow is Quasisteady Source: J.H. Blakelock, "Automatic Control of Aircraft and Missiles" Wiley & Sons, Inc. New York, 1991, p 50-53. """ #process w_n = g / velocity * (2.)**0.5 zeta = CD / (CL * (2.)**0.5) output = Data() output.natural_frequency = w_n output.damping_ratio = zeta return output
def shevell(weight_landing, number_of_engines, thrust_sea_level, thrust_landing): """ weight = SUAVE.Methods.Noise.Correlations.shevell(weight_landing, number_of_engines, thrust_sea_level, thrust_landing) Inputs: weight_landing - Landing weight of the aircraft [kilograms] number of engines - Number of engines installed on the aircraft [Dimensionless] thrust_sea_level - Sea Level Thrust of the Engine [Newtons] thrust_landing - Thrust of the aircraft coming in for landing [Newtons] Outputs: output() - Data Class takeoff - Noise of the aircraft at takeoff directly along the runway centerline (500 ft altitude at 6500m from start of take-off) [dB] side_line - Noise of the aircraft at takeoff at the sideline measurement station (1,476 ft (450m) from centerline (effective distance = 1476*1.25 = 1845ft)[dB] landing - Noise of the aircraft at landing directly along the trajectory (370 ft altitude at 6562 ft (2000m) from runway) [dB] Assumptions: The baseline case used is 101 PNdb, 25,000 lb thrust, 1 engine, 1000ft The noise_increase_due_to_thrust and noise_landing are equation extracted from images. This is only meant to give a rough estimate compared to a DC-10 aircraft. As the aircraft configuration varies from this configuration, the validity of the method will also degrade. """ #process baseline_noise = 101 thrust_percentage = (thrust_sea_level/ Units.force_pound)/25000 * 100. thrust_reduction = thrust_landing/thrust_sea_level * 100. noise_increase_due_to_thrust = -0.0002193 * thrust_percentage ** 2. + 0.09454 * thrust_percentage - 7.30116 noise_landing = - 0.0015766 * thrust_reduction ** 2. + 0.34882 * thrust_reduction -19.2569 takeoff_distance_noise = -4. # 1500 ft altitude at 6500m from start of take-off sideline_distance_noise = -6.5 #1 476 ft (450m) from centerline (effective distance = 1476*1.25 = 1845ft) landing_distance_noise = 9.1 # 370 ft altitude at 6562 ft (2000m) from runway takeoff = 10. * np.log10(10. ** (baseline_noise/10.) * number_of_engines) - 4. + takeoff_distance_noise + noise_increase_due_to_thrust side_line = 10. * np.log10(10. ** (baseline_noise/10.) * number_of_engines) - 4. + sideline_distance_noise + noise_increase_due_to_thrust landing = 10. * np.log10(10. ** (baseline_noise/10.) * number_of_engines) - 5. + landing_distance_noise + noise_increase_due_to_thrust + noise_landing airframe = 40. + 10. * np.log10(weight_landing / Units.lbs) output = Data() output.takeoff = takeoff output.side_line = side_line output.landing = 10. * np.log10(10. ** (airframe/10.) + 10. ** (landing/10.)) return output
def phugoid(g, velocity, CD, CL): """ output = SUAVE.Methods.Flight_Dynamics.Dynamic_Stablity.Approximations.phugoid(g, velocity, CD, CL) Calculate the natural frequency and damping ratio for the approximate phugoid characteristics Inputs: g - gravitational constant [meters/second**2] velocity - flight velocity at the condition being considered [meters/seconds] CD - coefficient of drag [dimensionless] CL - coefficient of lift [dimensionless] Outputs: output - a data dictionary with fields: phugoid_w_n - natural frequency of the phugoid mode [radian/second] phugoid_zeta - damping ratio of the phugoid mode [dimensionless] Assumptions: constant angle of attack theta changes very slowly Inertial forces are neglected Neglect Cz_q Theta = 0 X-Z axis is plane of symmetry Constant mass of aircraft Origin of axis system at c.g. of aircraft Aircraft is a rigid body Earth is inertial reference frame Perturbations from equilibrium are small Flow is Quasisteady Source: J.H. Blakelock, "Automatic Control of Aircraft and Missiles" Wiley & Sons, Inc. New York, 1991, p 50-53. """ #process w_n = g/velocity * (2.)**0.5 zeta = CD/(CL*(2.)**0.5) output = Data() output.phugoid_w_n = w_n output.phugoid_zeta = zeta return output
def __defaults__(self): self.tag = 'Aerodynamics' self.geometry = Geometry() self.configuration = Configuration() self.conditions_table = Conditions( angle_of_attack = np.linspace(-10., 10. , 5) * Units.deg , ) self.model = Data()
def main(): # define the problem vehicle, mission = full_setup() # run the problem # defining inputs of the module cruise_segment_tag = 'Cruise' mission_payload = [11792. , 9868. , 0. ] takeoff_weight = [54480. , 50480. , 40612. ] # call module distance,fuel = size_mission_range_given_weights(vehicle,mission,cruise_segment_tag,mission_payload,takeoff_weight) # check the results results = Data() results.dist = distance results.fuel = fuel check_results(results) return
def __call__(self,input1,input2=None): # the method used with the class is called like a function # document at class level # unpack inputs var1 = input1.var1 var2 = inputs.var2 # setup var3 = var1 * var2 # process magic = np.log(var3) # packup outputs output = Data() output.magic = magic output.var3 = var3 return output
def __defaults__(self): self.tag = 'Aerodynamics' self.geometry = Geometry() self.configuration = Configuration() self.conditions_table = Conditions( angle_of_attack = np.linspace(-10., 10. , 5) * Units.deg , mach_number = np.linspace(0.0 , 1.0 , 5) , reynolds_number = np.linspace(1.e4, 1.e10, 3) , ) self.model = Data()
def evaluate_field_length(vehicle,mission,results): # unpack airport = mission.airport takeoff_config = vehicle.configs.takeoff landing_config = vehicle.configs.landing from SUAVE.Methods.Performance import estimate_take_off_field_length from SUAVE.Methods.Performance import estimate_landing_field_length # evaluate TOFL = estimate_take_off_field_length(vehicle,takeoff_config,airport) LFL = estimate_landing_field_length(vehicle,landing_config,airport) # pack field_length = Data() field_length.takeoff = TOFL[0] field_length.landing = LFL[0] results.field_length = field_length return results
def main(): # define the problem vehicle, mission = full_setup() # run the problem # defining inputs of the module cruise_segment_tag = 'Cruise' mission_payload = [11792. , 9868. , 10. ] target_range = np.multiply ( [ 3470. , 3158. , 3804. ] , 1. * Units.nautical_mile ) # call module distance,fuel,tow = size_weights_given_mission_range(vehicle,mission,cruise_segment_tag,mission_payload,target_range) # check the results results = Data() results.dist = distance results.fuel = fuel results.tow = tow check_results(results) return
def check_results(new_results): # check segment values truth = Data() truth.dist = [6426122.4935872 , 5848398.49923247 ,7044468.46851841] truth.fuel = [ 14771. , 12695. , 12695.] error = Data() error.dist = np.max(np.abs(new_results.dist-truth.dist)) error.fuel = np.max(np.abs(new_results.fuel-truth.fuel)) for k,v in error.items(): assert(np.abs(v)<0.001)
def check_results(new_results): # check segment values truth = Data() truth.fuel = [ 14246. , 12234. , 12162.] truth.tow = [ 53855. , 49919. , 39989.] error = Data() error.fuel = np.max(np.abs(new_results.fuel-truth.fuel)) error.tow = np.max(np.abs(new_results.tow-truth.tow)) for k,v in error.items(): assert(np.abs(v)<0.5)
def compute_energies(results,summary=False): # evaluate each segment for i in range(len(results.Segments)): segment = results.Segments[i] eta=segment.conditions.propulsion.throttle[:,0] state = Data() state.q = segment.conditions.freestream.dynamic_pressure[:,0] state.g0 = segment.conditions.freestream.gravity[:,0] state.V = segment.conditions.freestream.velocity[:,0] state.M = segment.conditions.freestream.mach_number[:,0] state.T = segment.conditions.freestream.temperature[:,0] state.p = segment.conditions.freestream.pressure[:,0] segment.P_fuel, segment.P_e = segment.config.Propulsors.power_flow(eta,state) # time integration operator ''' print segment.numerics I = segment.numerics.integrate_time # raw propellant energy consumed segment.energy.propellant = np.dot(I,segment.P_fuel)[-1] # raw electrical energy consumed segment.energy.electric = np.dot(I,segment.P_e)[-1] # energy to gravity segment.energy.gravity = np.dot(I,segment.m*segment.g*segment.vectors.V[:,2])[-1] # J # energy to drag segment.energy.drag = np.dot(I,segment.D*segment.V)[-1] # J if summary: print " " print "####### Energy Summary: Segment " + str(i) + " #######" print " " print "Propellant energy used = " + str(segment.energy.propellant/1e6) + " MJ" print "Electrical energy used = " + str(segment.energy.electric/1e6) + " MJ" print "Energy lost to gravity = " + str(segment.energy.gravity/1e6) + " MJ" print "Energy lost to drag = " + str(segment.energy.drag/1e6) + " MJ" print " " print "#########################################" print " " ''' return
def main(): weight_landing = 300000 * Units.lbs number_of_engines = 3. thrust_sea_level = 40000 * Units.force_pounds thrust_landing = 0.45 * thrust_sea_level noise = Correlations.shevell(weight_landing, number_of_engines, thrust_sea_level, thrust_landing) actual = Data() actual.takeoff = 99.7 actual.side_line = 97.2 actual.landing = 105.2 error = Data() error.takeoff = (actual.takeoff - noise.takeoff)/actual.takeoff error.side_line = (actual.side_line - noise.side_line)/actual.side_line error.landing = (actual.landing - noise.landing)/actual.landing for k,v in error.items(): assert(np.abs(v)<0.003) return
def payload(TOW, empty, num_pax, wt_cargo, wt_passenger = 195.,wt_baggage = 30.): """ output = SUAVE.Methods.Weights.Correlations.Tube_Wing.payload(TOW, empty, num_pax, wt_cargo) Calculate the weight of the payload and the resulting fuel mass Inputs: TOW - [kilograms] wt_empty - Operating empty weight of the aircraft [kilograms] num_pax - number of passengers on the aircraft [dimensionless] wt_cargo - weight of cargo being carried on the aircraft [kilogram] wt_passenger - weight of each passenger on the aircraft [dimensionless] wt_baggage - weight of the baggage for each passenger [dimensionless] Outputs: output - a data dictionary with fields: payload - weight of the passengers plus baggage and paid cargo [kilograms] pax - weight of all the passengers [kilogram] bag - weight of all the baggage [kilogram] fuel - weight of the fuel carried[kilogram] empty - operating empty weight of the aircraft [kilograms] Assumptions: based on FAA guidelines for weight of passengers """ # process wt_pax = wt_passenger * num_pax * Units.lb wt_bag = wt_baggage * num_pax *Units.lb wt_payload = wt_pax + wt_bag + wt_cargo wt_fuel = TOW - wt_payload - empty # packup outputs output = Data() output.payload = wt_payload output.pax = wt_pax output.bag = wt_bag output.fuel = wt_fuel output.empty = empty return output
def evaluate_PASS(vehicle,mission): """ Compute the Pass Performance Calculations using SU AA 241 course notes """ # unpack maxto = vehicle.Mass.mtow mzfw_ratio = vehicle.Mass.fmzfw sref = vehicle.Wing['Main Wing'].sref sfc_sfcref = vehicle.Turbo_Fan['TheTurboFan'].sfc_TF sls_thrust = vehicle.Turbo_Fan['TheTurboFan'].thrust_sls eng_type = vehicle.Turbo_Fan['TheTurboFan'].type_engine out = Data() # Calculate fuel_manuever = WeightManeuver(maxto) fuel_climb_added = WeightClimbAdded(vehicle,mission,maxto) reserve_fuel = FuelReserve(mission,maxto,mzfw_ratio,0) out.range,fuel_cruise = CruiseRange(vehicle,mission,maxto,fuel_burn_maneuever,fuel_climb_added,reserve_fuel,sfc_sfcref,sls_thrust,eng_type,mzfw_ratio) out.fuel_burn = (2 * fuel_manuever) + fuel_climb_added + fuel_cruise out.tofl = TOFL(vehicle,mission,maxto,sref,sfc_sfcref,sls_thrust,eng_type) out.climb_grad = ClimbGradient(vehicle,mission,maxto,sfc_sfcref,sls_thrust,eng_type) out.lfl = LFL(vehicle,mission,maxto,mzfw_ratio,fuel_burn_maneuever,reserve_fuel,sref,sfc_sfcref,sls_thrust,eng_type) return out
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
class Aerodynamics_1d_Surrogate(Aerodynamics): """ SUAVE.Attributes.Aerodynamics.Aerodynamics_Surrogate aerodynamic model that builds a surrogate model this class is callable, see self.__call__ """ def __defaults__(self): self.tag = 'Aerodynamics' self.geometry = Geometry() self.configuration = Configuration() self.conditions_table = Conditions( angle_of_attack = np.linspace(-10., 10. , 5) * Units.deg , ) self.model = Data() def initialize(self): # build the conditions table self.build_conditions_table() # unpack conditions_table = self.conditions_table geometry = self.geometry configuration = self.configuration # AoA = conditions_table.angle_of_attack #Ma = conditions_table.mach_number #Re = conditions_table.reynolds_number # check #assert len(AoA) == len(Ma) == len(Re) , 'condition length mismatch' n_conditions = len(AoA) # arrays CL = np.zeros_like(AoA) CD = np.zeros_like(AoA) # condition input, local, do not keep konditions = Conditions() # calculate aerodynamics for table for i in xrange(n_conditions): # overriding conditions, thus the name mangling konditions.angle_of_attack = AoA[i] #konditions.mach_number = Ma[i] #konditions.reynolds_number = Re[i] # these functions are inherited from Aerodynamics() or overridden CL[i] = self.calculate_lift(konditions, configuration, geometry) CD[i] = self.calculate_drag(konditions, configuration, geometry) # store table conditions_table.lift_coefficient = CL conditions_table.drag_coefficient = CD # build surrogate self.build_surrogate() return #: def initialize() def build_conditions_table(self): conditions_table = self.conditions_table # unpack, check unique just in case AoA_list = np.unique( conditions_table.angle_of_attack ) #Ma_list = np.unique( conditions_table.mach_number ) #Re_list = np.unique( conditions_table.reynolds_number ) # mesh grid, beware of dimensionality! #AoA_list,Ma_list,Re_list = np.meshgrid(AoA_list,Ma_list,Re_list) AoA_list = np.meshgrid(AoA_list) # need 1D lists AoA_list = np.reshape(AoA_list,-1) #Ma_list = np.reshape(Ma_list,-1) #Re_list = np.reshape(Re_list,-1) # repack conditions table conditions_table.angle_of_attack = AoA_list #conditions_table.mach_number = Ma_list #conditions_table.reynolds_number = Re_list return #: def build_conditions_table() def build_surrogate(self): # unpack data conditions_table = self.conditions_table AoA_data = conditions_table.angle_of_attack #Ma_data = conditions_table.mach_number #Re_data = conditions_table.reynolds_number # CL_data = conditions_table.lift_coefficient CD_data = conditions_table.drag_coefficient # reynolds log10 space! #Re_data = np.log10(Re_data) # pack for surrogate #X_data = np.array([AoA_data,Ma_data,Re_data]).T X_data = np.array([AoA_data]).T X_data = np.reshape(X_data,-1) #print X_data.ndim # assign models Interpolation = Aerodynamics_1d_Surrogate.Interpolation self.model.lift_coefficient = Interpolation(X_data,CL_data) self.model.drag_coefficient = Interpolation(X_data,CD_data) return #: def build_surrogate() def __call__(self,conditions): """ process vehicle to setup geometry, condititon and configuration Inputs: conditions - DataDict() of aerodynamic conditions Outputs: CL - array of lift coefficients, same size as alpha CD - array of drag coefficients, same size as alpha Assumptions: linear intperolation surrogate model on Mach, Angle of Attack and Reynolds number locations outside the surrogate's table are held to nearest data no changes to initial geometry or configuration """ # unpack conditions AoA = np.atleast_1d( conditions.angle_of_attack ) #Ma = np.atleast_1d( conditions.mach_number ) #Re = np.atleast_1d( conditions.reynolds_number ) # reynolds log10 space! #Re = np.log10(Re) # pack for interpolate #X_interp = np.array([AoA,Ma,Re]).T #X_interp = np.array([AoA]).T X_interp = np.array(AoA) # interpolate CL = self.model.lift_coefficient(X_interp) CD = self.model.drag_coefficient(X_interp) return CL, CD
def lateral_directional(velocity, Cn_Beta, S_gross_w, density, span, I_z, Cn_r, I_x, Cl_p, J_xz, Cl_r, Cl_Beta, Cn_p, Cy_phi, Cy_psi, Cy_Beta, mass): """ output = SUAVE.Methods.Flight_Dynamics.Dynamic_Stablity.Full_Linearized_Equations.lateral_directional(velocity, Cn_Beta, S_gross_w, density, span, I_z, Cn_r, I_x, Cl_p, J_xz, Cl_r, Cl_Beta, Cn_p, Cy_phi, Cy_psi, Cy_Beta) Calculate the natural frequency and damping ratio for the full linearized dutch roll mode along with the time constants for the roll and spiral modes Inputs: velocity - flight velocity at the condition being considered [meters/seconds] Cn_Beta - coefficient for change in yawing moment due to sideslip [dimensionless] (no simple relation) S_gross_w - area of the wing [meters**2] density - flight density at condition being considered [kg/meters**3] span - wing span of the aircraft [meters] I_z - moment of interia about the body z axis [kg * meters**2] Cn_r - coefficient for change in yawing moment due to yawing velocity [dimensionless] ( - C_D(wing)/4 - 2 * Sv/S * (l_v/b)**2 * (dC_L/dalpha)(vert) * eta(vert)) I_x - moment of interia about the body x axis [kg * meters**2] Cl_p - change in rolling moment due to the rolling velocity [dimensionless] (no simple relation for calculation) J_xz - products of inertia in the x-z direction [kg * meters**2] (if X and Z lie in a plane of symmetry then equal to zero) Cl_r - coefficient for change in rolling moment due to yawing velocity [dimensionless] (Usually equals C_L(wing)/4) Cl_Beta - coefficient for change in rolling moment due to sideslip [dimensionless] Cn_p - coefficient for the change in yawing moment due to rolling velocity [dimensionless] (-C_L(wing)/8*(1 - depsilon/dalpha)) (depsilon/dalpha = 2/pi/e/AspectRatio dC_L(wing)/dalpha) Cy_phi - coefficient for change in sideforce due to aircraft roll [dimensionless] (Usually equals C_L) Cy_psi - coefficient to account for gravity [dimensionless] (C_L * tan(Theta)) Cy_Beta - coefficient for change in Y force due to sideslip [dimensionless] (no simple relation) mass - mass of the aircraft [kilograms] Outputs: output - a data dictionary with fields: dutch_w_n - natural frequency of the dutch roll mode [radian/second] dutch_zeta - damping ratio of the dutch roll mode [dimensionless] roll_tau - approximation of the time constant of the roll mode of an aircraft [seconds] (positive values are bad) spiral_tau - time constant for the spiral mode [seconds] (positive values are bad) Assumptions: X-Z axis is plane of symmetry Constant mass of aircraft Origin of axis system at c.g. of aircraft Aircraft is a rigid body Earth is inertial reference frame Perturbations from equilibrium are small Flow is Quasisteady Zero initial conditions Neglect Cy_p and Cy_r Source: J.H. Blakelock, "Automatic Control of Aircraft and Missiles" Wiley & Sons, Inc. New York, 1991, p 118-124. """ #process # constructing matrix of coefficients A = (0, -span * 0.5 / velocity * Cl_p, I_x/S_gross_w/(0.5*density*velocity**2)/span ) # L moment phi term B = (0, -span * 0.5 / velocity * Cl_r, -J_xz / S_gross_w / (0.5 * density * velocity ** 2.) / span) # L moment psi term C = (-Cl_Beta) # L moment Beta term D = (0, - span * 0.5 / velocity * Cn_p, -J_xz / S_gross_w / (0.5 * density * velocity ** 2.) / span ) # N moment phi term E = (0, - span * 0.5 / velocity * Cn_r, I_z / S_gross_w / (0.5 * density * velocity ** 2.) / span ) # N moment psi term F = (-Cn_Beta) # N moment Beta term G = (-Cy_phi) # Y force phi term H = (-Cy_psi, mass * velocity / S_gross_w / (0.5 * density * velocity ** 2.)) I = (-Cy_Beta, mass * velocity / S_gross_w / (0.5 * density * velocity ** 2.)) # Taking the determinant of the matrix ([A, B, C],[D, E, F],[G, H, I]) EI = P.polymul(E,I) FH = P.polymul(F,H) part1 = P.polymul(A,P.polysub(EI,FH)) DI = P.polymul(D,I) FG = P.polymul(F,G) part2 = P.polymul(B,P.polysub(FG,DI)) DH = P.polymul(D,H) GE = P.polymul(G,E) part3 = P.polymul(C,P.polysub(DH,GE)) total = P.polyadd(part1,P.polyadd(part2,part3)) poly = total / total[5] # Generate the time constant for the spiral and roll modes along with the damping and natural frequency for the dutch roll mode root = np.roots(poly) root = sorted(root,reverse=True) spiral_tau = 1 * root[0].real w_n = (root[1].imag**2 + root[1].real**2)**(-0.5) zeta = -2*root[1].real/w_n roll_tau = 1 * root [3].real output = Data() output.dutch_natural_frequency = w_n output.dutch_damping_ratio = zeta output.spiral_tau = spiral_tau output.roll_tau = roll_tau return output
def __call__(self,conditions): alpha = conditions.angle_of_attack state = Data() state.M = conditions.mach_number state.rho = conditions.density state.mew = conditions.viscosity state.T = conditions.temperature #state.q = conditions.dynamic_pressure state.Sref = self.Sref #N = state.M.shape[0] ##interpolation methods #f_Cl = interp1d(self.aoa_range, self.Cl_a,bounds_error=False) #Cl_inc=f_Cl(alpha) ##Cl_inc=self.f_Cl(alpha) Cl_inc= self.CL0 + self.dCLdalpha*alpha CL=Cl_inc/(numpy.sqrt(1-state.M**2)) #print 'alpha',alpha #print 'Cl_inc',Cl_inc #print 'CL',CL #CD = self.CD0 + (CL**2)/(np.pi*self.AR*self.e) # parbolic drag CD= self.drag(CL,state) results = Data() results.lift_coefficient = CL results.drag_coefficient = CD conditions.lift_coefficient = CL conditions.drag_coefficient = CD L = np.zeros([N,3]) D = np.zeros([N,3]) L[:,2] = ( -CL * state.q * state.Sref )[:,0] D[:,0] = ( -CD * state.q * state.Sref )[:,0] results.lift_force_vector = L results.drag_force_vector = D return [CL,CD]
def empty(vehicle): """ output = SUAVE.Methods.Weights.Correlations.Tube_Wing.empty(engine,wing,aircraft,fuselage,horizontal,vertical) This is for a standard Tube and Wing aircraft configuration. Inputs: engine - a data dictionary with the fields: thrust_sls - sea level static thrust of a single engine [Newtons] wing - a data dictionary with the fields: gross_area - wing gross area [meters**2] span - span of the wing [meters] taper - taper ratio of the wing [dimensionless] t_c - thickness-to-chord ratio of the wing [dimensionless] sweep - sweep angle of the wing [radians] mac - mean aerodynamic chord of the wing [meters] r_c - wing root chord [meters] aircraft - a data dictionary with the fields: Nult - ultimate load of the aircraft [dimensionless] Nlim - limit load factor at zero fuel weight of the aircraft [dimensionless] TOW - maximum takeoff weight of the aircraft [kilograms] zfw - maximum zero fuel weight of the aircraft [kilograms] num_eng - number of engines on the aircraft [dimensionless] num_pax - number of passengers on the aircraft [dimensionless] wt_cargo - weight of the bulk cargo being carried on the aircraft [kilograms] num_seats - number of seats installed on the aircraft [dimensionless] ctrl - specifies if the control system is "fully powered", "partially powered", or not powered [dimensionless] ac - determines type of instruments, electronics, and operating items based on types: "short-range", "medium-range", "long-range", "business", "cargo", "commuter", "sst" [dimensionless] w2h - tail length (distance from the airplane c.g. to the horizontal tail aerodynamic center) [meters] fuselage - a data dictionary with the fields: area - fuselage wetted area [meters**2] diff_p - Maximum fuselage pressure differential [Pascal] width - width of the fuselage [meters] height - height of the fuselage [meters] length - length of the fuselage [meters] horizontal area - area of the horizontal tail [meters**2] span - span of the horizontal tail [meters] sweep - sweep of the horizontal tail [radians] mac - mean aerodynamic chord of the horizontal tail [meters] t_c - thickness-to-chord ratio of the horizontal tail [dimensionless] exposed - exposed area ratio for the horizontal tail [dimensionless] vertical area - area of the vertical tail [meters**2] span - sweight = weight * Units.lbpan of the vertical [meters] t_c - thickness-to-chord ratio of the vertical tail [dimensionless] sweep - sweep angle of the vertical tail [radians] t_tail - factor to determine if aircraft has a t-tail, "yes" [dimensionless] Outputs: output - a data dictionary with fields: wt_payload - weight of the passengers plus baggage and paid cargo [kilograms] wt_pax - weight of all the passengers [kilogram] wt_bag - weight of all the baggage [kilogram] wt_fuel - weight of the fuel carried[kilogram] wt_empty - operating empty weight of the aircraft [kilograms] Assumptions: calculated aircraft weight from correlations created per component of historical aircraft """ # Unpack inputs Nult = vehicle.envelope.ultimate_load Nlim = vehicle.envelope.limit_load TOW = vehicle.mass_properties.max_takeoff wt_zf = vehicle.mass_properties.max_zero_fuel num_pax = vehicle.passengers wt_cargo = vehicle.mass_properties.cargo num_seats = vehicle.fuselages.Fuselage.number_coach_seats ctrl_type = vehicle.systems.control ac_type = vehicle.systems.accessories if not vehicle.propulsors.has_key('Turbo Fan'): wt_engine_jet = 0.0 wt_propulsion = 0.0 warnings.warn("There is no Turbo Fan Engine Weight being added to the Configuration", stacklevel=1) else: num_eng = vehicle.propulsors['Turbo Fan'].number_of_engines thrust_sls = vehicle.propulsors['Turbo Fan'].thrust.design wt_engine_jet = Propulsion.engine_jet(thrust_sls) wt_propulsion = Propulsion.integrated_propulsion(wt_engine_jet,num_eng) S_gross_w = vehicle.reference_area #S_gross_w = vehicle.wings['Main Wing'].Areas.reference if not vehicle.wings.has_key('Main Wing'): wt_wing = 0.0 wing_c_r = 0.0 warnings.warn("There is no Wing Weight being added to the Configuration", stacklevel=1) else: b = vehicle.wings['Main Wing'].spans.projected lambda_w = vehicle.wings['Main Wing'].taper t_c_w = vehicle.wings['Main Wing'].thickness_to_chord sweep_w = vehicle.wings['Main Wing'].sweep mac_w = vehicle.wings['Main Wing'].chords.mean_aerodynamic wing_c_r = vehicle.wings['Main Wing'].chords.root wt_wing = wing_main(S_gross_w,b,lambda_w,t_c_w,sweep_w,Nult,TOW,wt_zf) vehicle.wings['Main Wing'].mass_properties.mass = wt_wing S_fus = vehicle.fuselages.Fuselage.areas.wetted diff_p_fus = vehicle.fuselages.Fuselage.differential_pressure w_fus = vehicle.fuselages.Fuselage.width h_fus = vehicle.fuselages.Fuselage.heights.maximum l_fus = vehicle.fuselages.Fuselage.lengths.total if not vehicle.wings.has_key('Horizontal Stabilizer'): wt_tail_horizontal = 0.0 S_h = 0.0 warnings.warn("There is no Horizontal Tail Weight being added to the Configuration", stacklevel=1) else: S_h = vehicle.wings['Horizontal Stabilizer'].areas.reference b_h = vehicle.wings['Horizontal Stabilizer'].spans.projected sweep_h = vehicle.wings['Horizontal Stabilizer'].sweep mac_h = vehicle.wings['Horizontal Stabilizer'].chords.mean_aerodynamic t_c_h = vehicle.wings['Horizontal Stabilizer'].thickness_to_chord h_tail_exposed = vehicle.wings['Horizontal Stabilizer'].areas.exposed / vehicle.wings['Horizontal Stabilizer'].areas.wetted l_w2h = vehicle.wings['Horizontal Stabilizer'].origin[0] + vehicle.wings['Horizontal Stabilizer'].aerodynamic_center[0] - vehicle.wings['Main Wing'].origin[0] - vehicle.wings['Main Wing'].aerodynamic_center[0] #Need to check this is the length of the horizontal tail moment arm wt_tail_horizontal = tail_horizontal(b_h,sweep_h,Nult,S_h,TOW,mac_w,mac_h,l_w2h,t_c_h, h_tail_exposed) vehicle.wings['Horizontal Stabilizer'].mass_properties.mass = wt_tail_horizontal if not vehicle.wings.has_key('Vertical Stabilizer'): output_3 = Data() output_3.wt_tail_vertical = 0.0 output_3.wt_rudder = 0.0 S_v = 0.0 warnings.warn("There is no Vertical Tail Weight being added to the Configuration", stacklevel=1) else: S_v = vehicle.wings['Vertical Stabilizer'].areas.reference b_v = vehicle.wings['Vertical Stabilizer'].spans.projected t_c_v = vehicle.wings['Vertical Stabilizer'].thickness_to_chord sweep_v = vehicle.wings['Vertical Stabilizer'].sweep t_tail = vehicle.wings['Vertical Stabilizer'].t_tail output_3 = tail_vertical(S_v,Nult,b_v,TOW,t_c_v,sweep_v,S_gross_w,t_tail) vehicle.wings['Vertical Stabilizer'].mass_properties.mass = output_3.wt_tail_vertical + output_3.wt_rudder # process # Calculating Empty Weight of Aircraft wt_landing_gear = landing_gear(TOW) wt_fuselage = tube(S_fus, diff_p_fus,w_fus,h_fus,l_fus,Nlim,wt_zf,wt_wing,wt_propulsion, wing_c_r) output_2 = systems(num_seats, ctrl_type, S_h, S_v, S_gross_w, ac_type) # Calculate the equipment empty weight of the aircraft wt_empty = (wt_wing + wt_fuselage + wt_landing_gear + wt_propulsion + output_2.wt_systems + \ wt_tail_horizontal + output_3.wt_tail_vertical + output_3.wt_rudder) vehicle.fuselages.Fuselage.mass_properties.mass = wt_fuselage # packup outputs output = payload(TOW, wt_empty, num_pax,wt_cargo) output.wing = wt_wing output.fuselage = wt_fuselage output.propulsion = wt_propulsion output.landing_gear = wt_landing_gear output.systems = output_2.wt_systems output.wt_furnish = output_2.wt_furnish output.horizontal_tail = wt_tail_horizontal output.vertical_tail = output_3.wt_tail_vertical output.rudder = output_3.wt_rudder return output