Example #1
0
def shevell(weight_landing, number_of_engines, thrust_sea_level, thrust_landing):

    #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 # 1476 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
Example #2
0
class Aircraft(Data):
	
	def __defaults__(self):
		
		self.tag = 'aircraft'
		self.wings = Data()
		self.bodies = Data()
	
	def append_wing(self,wing):
		# assert database type
		if not isinstance(wing,Wing):
			raise Component_Exception, 'input component must be of type AVL.Data.Wing()'

		# store data
		self.wings.append(wing)
		return


	def append_body(self,body):
		# assert database type
		if not isinstance(body,Body):
			raise Component_Exception, 'input component must be of type AVL.Data.Body()'

		# store data
		self.bodies.append(body)
		return
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
Example #4
0
    def compute_forces(self,conditions):
        
        # unpack
        q    = conditions.freestream.dynamic_pressure
        Sref = self.geometry.reference_area
        
        # 
        CL = conditions.aerodynamics.lift_coefficient
        CD = conditions.aerodynamics.drag_coefficient
        
        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]

        results = Data()
        results.lift_force_vector = L
        results.drag_force_vector = D

        return results        
    
        
        
Example #5
0
File: Cases.py Project: michK/SUAVE
    def append_control_deflection(self,control_tag,deflection):
        """ Adds a control deflection case 

	Assumptions:
	    None
    
	Source:
	    None
    
	Inputs:
	    None
    
	Outputs:
	    None
    
	Properties Used:
	    N/A
	"""         
        control_deflection              = Data()
        control_deflection.tag          = control_tag
        control_deflection.deflection   = deflection
        if self.stability_and_control.control_deflections is None:
            self.stability_and_control.control_deflections = Data()
        self.stability_and_control.control_deflections.append(control_deflection)

        return
 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 fuel_for_missions(interface):

    # unpack data
    config   = interface.configs.cruise
    analyses = interface.analyses

    mission         = interface.analyses.missions.fuel.mission
    mission_payload = interface.analyses.missions.fuel.payload
    
    # determine maximum range based in tow short_field
    from SUAVE.Methods.Performance import size_mission_range_given_weights
    
    # unpack
    cruise_segment_tag = 'cruise'
    
    weight_max    = config.mass_properties.max_takeoff
    weight_min    = config.mass_properties.operating_empty + 0.10 * mission_payload  # 10%
    
    takeoff_weight_vec  = np.linspace(weight_min,weight_max,3)
    distance_vec        = np.zeros_like(takeoff_weight_vec)
    fuel_vec            = np.zeros_like(takeoff_weight_vec)
    
    # call function
    distance_vec,fuel_vec = size_mission_range_given_weights(config,mission,cruise_segment_tag,mission_payload,takeoff_weight_vec)

    # pack 
    results = Data()
    results.tag            = 'missions_fuel'
    results.weights        = takeoff_weight_vec
    results.distances      = distance_vec
    results.fuels          = fuel_vec
    
##    print results
    
    return results
def main():
    
    # setup the interface
    interface = setup_interface()
    
    # quick test
    inputs = Data()
    inputs.projected_span  = 36.
    inputs.fuselage_length = 58.
    
    # evalute!
    results = interface.evaluate(inputs)
    
    """
    VEHICLE EVALUATION 1
    
    INPUTS
    <data object 'SUAVE.Core.Data'>
    projected_span : 36.0
    fuselage_length : 58.0
    
    RESULTS
    <data object 'SUAVE.Core.Data'>
    fuel_burn : 15700.3830236
    weight_empty : 62746.4
    """
    
    return
def short_field(interface):

    # unpack data
    results_field   = interface.results.takeoff_field_length
    results_fuel    = interface.results.fuel_for_missions
    available_tofl  = interface.analyses.missions.short_field.mission.airport.available_tofl
 
    tofl_vec        = results_field.takeoff_field_length
    weight_vec_tofl = results_field.takeoff_weights
    
    range_vec       = results_fuel.distances
    weight_vec_fuel = results_fuel.weights
    fuel_vec        = results_fuel.fuels
        
    # evaluate maximum allowable takeoff weight from a given airfield
    tow_short_field = np.interp(available_tofl,tofl_vec,weight_vec_tofl)

    # determine maximum range/fuel based in tow short_field
    range_short_field = np.interp(tow_short_field,weight_vec_fuel,range_vec)
    fuel_short_field  = np.interp(tow_short_field,weight_vec_fuel,fuel_vec)

    # pack 
    results = Data()
    results.tag            = 'short_field'
    results.takeoff_weight = tow_short_field
    results.range          = range_short_field
    results.fuel           = fuel_short_field

    return results
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 = [[ 1365.96369614],[  853.74651524],[  820.78323974],[    0.        ]]

    
    max_error =  np.max(np.abs(fluxes-truth_fluxes))
    
    assert( max_error < 1e-5 )
    
    return
Example #11
0
    def __defaults__(self):
        """This sets the default for wing segments in SUAVE.

        Assumptions:
        None

        Source:
        N/A

        Inputs:
        None

        Outputs:
        None

        Properties Used:
        N/A
        """         
        self.tag = 'segment'
        self.percent_span_location = 0.0
        self.twist                 = 0.0
        self.root_chord_percent    = 0.0
        self.dihedral_outboard     = 0.0
        self.sweeps                = Data()
        self.sweeps.quarter_chord  = 0.0
        self.sweeps.leading_edge   = 0.0
        self.Airfoil               = Data()
        self.control_surfaces      = Data()  
Example #12
0
    def sample_training(self):
        
        # unpack
        geometry = self.geometry
        settings = self.settings
        training = self.training
        
        AoA = training.angle_of_attack
        CL  = np.zeros_like(AoA)

        # condition input, local, do not keep
        konditions              = Data()
        konditions.aerodynamics = Data()

        # calculate aerodynamics for table
        for i,_ in enumerate(AoA):
            
            # 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, settings, geometry)

        # store training data
        training.lift_coefficient = CL

        return
Example #13
0
def main():
    
    # ------------------------------------------------------------------
    # Testing
    # Using NACA 2410
    # ------------------------------------------------------------------
    camber       = 0.02
    camber_loc   = 0.4
    thickness    = 0.10
    npoints      = 10
    upper,lower  = compute_naca_4series(camber, camber_loc, thickness,npoints) 
    
    truth_upper      = ([[ 0.        ,  0.        ],
                         [ 0.08654358,  0.04528598],
                         [ 0.25116155,  0.06683575],
                         [ 0.46508794,  0.06561866],
                         [ 0.71656695,  0.04370913],
                         [ 1.        ,  0.        ]])
    
    truth_lower      = ([[ 0.        ,  0.        ],
                         [ 0.09234186, -0.02939744],
                         [ 0.25480288, -0.03223931],
                         [ 0.46442806, -0.02608462],
                         [ 0.71451656, -0.01477209],
                         [ 1.        ,  0.        ]])
    

    # Compute Errors
    error       = Data() 
    error.upper = np.abs(upper-truth_upper)
    error.lower = np.abs(lower-truth_lower)
    
    for k,v in list(error.items()):
        assert np.any(np.abs(v)<1e-6)
Example #14
0
class Wing(Data):
	def __defaults__(self):

		self.tag = 'wing'
		self.symmetric = True
		self.vertical  = False
		self.origin    = [0.,0.,0.]

		self.sweep        = 0.0
		self.dihedral     = 0.0

		self.sections = Data()
		self.configuration = Data()
		self.control_surfaces = Data()

		self.configuration.nspanwise = 10
		self.configuration.nchordwise = 5
		self.configuration.sspace = 1.0
		self.configuration.cspace = 1.0


	def append_section(self,section):
		""" adds a segment to the wing """

		# assert database type
		if not isinstance(section,Data):
			raise Component_Exception, 'input component must be of type Data()'

		# store data
		self.sections.append(section)
		return
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
Example #16
0
def estimate_hourly_rates(year):
    """Estimates the hourly rate according to a trend line.

    Assumptions:
    None

    Source:
    Trends in hourly rates according to "Fundamentals of Aircraft Design", 
      vol 1, Nicolai Figure 24.4.

    Inputs:
    year              [-]

    Outputs:
    hourly_rates.
      engineering     [$/hr]
      tooling         [$/hr]
      manufacturing   [$/hr]
      quality_control [$/hr]

    Properties Used:
    N/A
    """
    # Unpack
    reference_year = year

    hourly_rates = Data()
    hourly_rates.engineering     = 2.576 * reference_year - 5058.
    hourly_rates.tooling         = 2.883 * reference_year - 5666.
    hourly_rates.manufacturing   = 2.316 * reference_year - 4552.
    hourly_rates.quality_control = 2.600 * reference_year - 5112.

    return hourly_rates
Example #17
0
def read_results(avl_object):

    results = Data()

    for case in avl_object.current_status.cases:
        num_ctrl = case.stability_and_control.control_deflections.size
        with open(case.result_filename,'r') as res_file:
            case_res = Results()
            case_res.tag = case.tag
            lines   = res_file.readlines()
            case_res.aerodynamics.roll_moment_coefficient  = float(lines[19][32:42].strip())
            case_res.aerodynamics.pitch_moment_coefficient = float(lines[20][32:42].strip())
            case_res.aerodynamics.yaw_moment_coefficient   = float(lines[21][32:42].strip())
            case_res.aerodynamics.total_lift_coefficient   = float(lines[23][10:20].strip())
            #case_res.aerodynamics.total_drag_coefficient   = float(lines[24][10:20].strip())
            case_res.aerodynamics.induced_drag_coefficient = float(lines[25][32:42].strip())
            case_res.aerodynamics.span_efficiency_factor   = float(lines[27][32:42].strip())

            case_res.stability.alpha_derivatives.lift_curve_slope           = float(lines[36+num_ctrl][25:35].strip())
            case_res.stability.alpha_derivatives.side_force_derivative      = float(lines[37+num_ctrl][25:35].strip())
            case_res.stability.alpha_derivatives.roll_moment_derivative     = float(lines[38+num_ctrl][25:35].strip())
            case_res.stability.alpha_derivatives.pitch_moment_derivative    = float(lines[39+num_ctrl][25:35].strip())
            case_res.stability.alpha_derivatives.yaw_moment_derivative      = float(lines[40+num_ctrl][25:35].strip())
            case_res.stability.beta_derivatives.lift_coefficient_derivative = float(lines[36+num_ctrl][44:55].strip())
            case_res.stability.beta_derivatives.side_force_derivative       = float(lines[37+num_ctrl][44:55].strip())
            case_res.stability.beta_derivatives.roll_moment_derivative      = float(lines[38+num_ctrl][44:55].strip())
            case_res.stability.beta_derivatives.pitch_moment_derivative     = float(lines[39+num_ctrl][44:55].strip())
            case_res.stability.beta_derivatives.yaw_moment_derivative       = float(lines[40+num_ctrl][44:55].strip())
            case_res.stability.neutral_point                                = float(lines[50+13*(num_ctrl>0)][22:33].strip())

            results.append(case_res)


    return results
Example #18
0
def main():
    #only do calculation for 747
    from Boeing_747 import vehicle_setup, configs_setup
    vehicle = vehicle_setup()
    configs = configs_setup(vehicle)
    
    Mach                          = np.array([0.198])
    
    segment                              = SUAVE.Analyses.Mission.Segments.Segment()
    segment.freestream                   = Data()
    segment.freestream.mach_number       = Mach
    segment.atmosphere                   = SUAVE.Analyses.Atmospheric.US_Standard_1976()
    altitude                             = 0.0 * Units.feet
    conditions                           = segment.atmosphere.compute_values(altitude / Units.km)
    segment.a                            = conditions.speed_of_sound
    segment.freestream.density           = conditions.density
    segment.freestream.dynamic_viscosity = conditions.dynamic_viscosity
    segment.freestream.velocity          = segment.freestream.mach_number * segment.a
  
    
    #Method Test
    cn_b = taw_cnbeta(vehicle,segment,configs.base)
    expected = 0.09427599 # Should be 0.184
    error = Data()
    error.cn_b_747 = (cn_b-expected)/expected

  
  
    
    print(error)
    for k,v in list(error.items()):
        assert(np.abs(v)<1e-6)

    return
Example #19
0
    def evaluate(self,state,settings=None,geometry=None):
        
        # unpack
        aoa           = state.conditions.aerodynamics.angle_of_attack
        Sref          = self.geometry.reference_area

        # evaluate surrogates
        CL  = self.surrogates.lift_coefficient(aoa)
        CDi = self.surrogates.induced_drag_coefficient(aoa)
        Cm  = self.surrogates.pitch_moment_coefficient(aoa)

        # pack conditions
        state.conditions.aerodynamics.lift_coefficient = CL
        state.conditions.aerodynamics.drag_coefficient = CDi
        state.conditions.aerodynamics.pitch_moment_coefficient = Cm

        # pack results
        results = Data()
        results.lift_coefficient = CL
        results.drag_coefficient = CDi
        results.induced_drag_coefficient = CDi
        results.pitch_moment_coefficient = Cm
        
        #results.update( self.compute_forces(state.conditions) )

        return results
Example #20
0
def Empty(vehicle):
    
    """
    Structural Weight correlation from all 415 samples of fixed-wing UAVs and sailplanes
    Equation 3.16 from 'Design of Solar Powered Airplanes for Continuous Flight' by Andre Noth
    Relatively valid for a wide variety of vehicles, may be optimistic
    Assumes a 'main wing' is attached
    
    """
    
    # Unpack
    S     = vehicle.reference_area
    AR    = vehicle.wings['main_wing'].aspect_ratio
    Earth = SUAVE.Attributes.Planets.Earth()
    g     = Earth.sea_level_gravity
    
    
    # Airframe weight
    Waf = (5.58*(S**1.59)*(AR**0.71))/g # All Samples
    #Waf = (0.44*(S**1.55)*(AR**1.30))/g  # Top 19
    
    # Pack
    weight = Data()
    weight.empty = Waf
    
    return weight
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 compute_ducted_fan_geometry(ducted_fan, conditions):
    """ SUAVE.Methods.Geometry.Two_Dimensional.Planform.wing_fuel_volume(wing):
        Estimates wing fuel capacity based in correlation methods.



    """

    # unpack
    thrust            = ducted_fan.thrust
    fan_nozzle        = ducted_fan.fan_nozzle
    mass_flow         = thrust.mass_flow_rate_design

    #evaluate engine at these conditions
    state=Data()
    state.conditions=conditions
    state.numerics= Data()
    ducted_fan.evaluate_thrust(state)
    
    #determine geometry
    U0       = conditions.freestream.velocity
    rho0     = conditions.freestream.density
    Ue       = fan_nozzle.outputs.velocity
    rhoe     = fan_nozzle.outputs.density
    Ae       = mass_flow[0][0]/(rhoe[0][0]*Ue[0][0]) #ducted fan nozzle exit area
    A0       = (mass_flow/(rho0*U0))[0][0]
    

   
    ducted_fan.areas.maximum = 1.2*Ae/fan_nozzle.outputs.area_ratio[0][0]
    ducted_fan.nacelle_diameter = 2.1*((ducted_fan.areas.maximum/np.pi)**.5)

    ducted_fan.engine_length    = 1.5*ducted_fan.nacelle_diameter
    ducted_fan.areas.wetted     = ducted_fan.nacelle_diameter*ducted_fan.engine_length*np.pi
Example #23
0
def main():
    
    problem = setup()

    n_des_var = 13

    var = np.zeros(n_des_var)

    var = [134.6,9.6105641082,35.0,0.123,49200.0,70000.0,0.75,6.6,30.0,70000.0,70000.0,11.5,283.0]

    input_vec = var / problem.optimization_problem.inputs[:,3]

    problem.objective(input_vec)

    objectives  = problem.objective()       * problem.optimization_problem.objective[:,1]

    noise_cumulative_margin = objectives[0]
    
    actual = Data()    
    actual.noise_cumulative_margin = 19.7810544184

    error = Data()
    error.noise_cumulative_margin = abs(actual.noise_cumulative_margin - noise_cumulative_margin)/actual.noise_cumulative_margin
    
    print 'noise_cumulative_margin=', noise_cumulative_margin
    
    print error.noise_cumulative_margin
    print error
    for k,v in error.items():
        assert(np.abs(v)<1e-6) 
        
    return
def main():

    configs, analyses = full_setup()

    simple_sizing(configs)

    configs.finalize()
    analyses.finalize()

    # weight analysis
    weights = analyses.configs.base.weights
    breakdown = weights.evaluate()      

    # mission analysis
    mission = analyses.missions.base
    results = mission.evaluate()

    # print weight breakdown
    print_weight_breakdown(configs.base,filename = 'weight_breakdown.dat')

    # print engine data into file
    print_engine_data(configs.base,filename = 'B737_engine_data.dat')

    # print parasite drag data into file
    # define reference condition for parasite drag
    ref_condition = Data()
    ref_condition.mach_number = 0.3
    ref_condition.reynolds_number = 12e6     
    print_parasite_drag(ref_condition,configs.cruise,analyses,'B737_parasite_drag.dat')

    # print compressibility drag data into file
    print_compress_drag(configs.cruise,analyses,filename = 'B737_compress_drag.dat')

    # print mission breakdown
    print_mission_breakdown(results,filename='B737_mission_breakdown.dat')

    # load older results
    #save_results(results)
    old_results = load_results()   

    # plt the old results
    plot_mission(results)
    plot_mission(old_results,'k-')

    # check the results
    check_results(results,old_results)

##	# print some results, for check agaist Aviation paper
##    end_segment = results.segments[-1]
##    time     = end_segment.conditions.frames.inertial.time[-1,0] / Units.min
##    distance = end_segment.conditions.frames.inertial.position_vector[-1,0] / Units.nautical_miles
##    mass_end     = end_segment.conditions.weights.total_mass[-1,0]
##    mass_begin   = results.segments[0].conditions.weights.total_mass[0,0]
##    fuelburn = (mass_begin- mass_end) / Units.lbs
##    
##    print 'Time: {:5.0f} min , Distance: {:5.0f} nm ; FuelBurn: {:5.0f} lbs'.format(time,distance,fuelburn)

    return
Example #25
0
    def evaluate(self,conditions):
        """ process vehicle to setup geometry, condititon and settings

            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 settings
        """

        # unpack
        settings   = self.settings
        geometry   = self.geometry
        surrogates = self.surrogates
        
        q    = conditions.freestream.dynamic_pressure
        AoA  = conditions.aerodynamics.angle_of_attack
        Sref = geometry.reference_area
        
        wings_lift_model = surrogates.lift_coefficient
        
        # inviscid lift of wings only
        inviscid_wings_lift = wings_lift_model(AoA)
        conditions.aerodynamics.lift_breakdown.inviscid_wings_lift = inviscid_wings_lift
        
        # lift needs to compute first, updates data needed for drag
        CL = compute_aircraft_lift(conditions,settings,geometry)
        
        # drag computes second
        CD = compute_aircraft_drag(conditions,settings,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]

        results.lift_force_vector = L
        results.drag_force_vector = D

        return results
def summarize(interface):
    
    vehicle = interface.configs.base
    
    results = interface.results
    mission_profile = results.missions.base
    
    
    # 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 mission_profile.segments:
        if conditions is None:
            conditions = segment.conditions
            continue
        conditions = conditions.do_recursive(stack_condition,segment.conditions)
      
    # pack
    summary = SUAVE.Core.Results()
    
    summary.weight_empty = vehicle.mass_properties.operating_empty
    
    summary.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
    
    summary.noise = results.noise    
    
    summary.mission_time_min = max(conditions.frames.inertial.time[:,0] / Units.min)
    summary.max_altitude_km = max(conditions.freestream.altitude[:,0] / Units.km)
    
    summary.range_nmi = mission_profile.segments[-1].conditions.frames.inertial.position_vector[-1,0] / Units.nmi
    
    summary.field_length = results.field_length
    
    summary.stability = Data()
    summary.stability.cm_alpha = max(conditions.stability.static.cm_alpha[:,0])
    summary.stability.cn_beta  = max(conditions.stability.static.cn_beta[:,0])
    
    #summary.conditions = conditions
    
    #TODO: revisit how this is calculated
    summary.second_segment_climb_rate = mission_profile.segments[1].climb_rate
    
    
    printme = Data()
    printme.fuel_burn = summary.fuel_burn
    printme.weight_empty = summary.weight_empty
    print "RESULTS"
    print printme
    
    return summary
Example #27
0
    def sample_training(self):
        """Call methods to run vortex lattice for sample point evaluation.

        Assumptions:
        None

        Source:
        N/A

        Inputs:
        see properties used

        Outputs:
        self.training.
          lift_coefficient            [-] 
          wing_lift_coefficients      [-] (wing specific)

        Properties Used:
        self.geometry.wings.*.tag
        self.settings                 (passed to calculate vortex lattice)
        self.training.angle_of_attack [radians]
        """        
        # unpack
        geometry = self.geometry
        settings = self.settings
        training = self.training
        
        AoA = training.angle_of_attack
        CL  = np.zeros_like(AoA)
        
        wing_CLs = Data.fromkeys(geometry.wings.keys(), np.zeros_like(AoA))
        # The above performs the function of:
        #wing_CLs = Data() 
        #for wing in geometry.wings.values():
        #    wing_CLs[wing.tag] = np.zeros_like(AoA)

        # condition input, local, do not keep
        konditions              = Data()
        konditions.aerodynamics = Data()

        # calculate aerodynamics for table
        for i,_ in enumerate(AoA):
            
            # overriding conditions, thus the name mangling
            konditions.aerodynamics.angle_of_attack = AoA[i]
            
            # these functions are inherited from Aerodynamics() or overridden
            CL[i], wing_lifts = calculate_lift_vortex_lattice(konditions, settings, geometry)
            for wing in geometry.wings.values():
                wing_CLs[wing.tag][i] = wing_lifts[wing.tag]

        # store training data
        training.lift_coefficient = CL
        training.wing_lift_coefficients = wing_CLs

        return
def main():

    data = Data()
    data.x = 'x'
    data.y = 'y'
    data.sub = Data()
    data.sub.z = 'z'
    data.sub.a = 1

    IO.D3JS.save_tree(data,'tree.json',root_name='data')
def main():
    output = Data()
    
    output.hello = Data()
    output.hello.world = 'watsup'
    output.hello.now = None
    output.hello['we are'] = None
    output.hello.rockin = ['a','list','of','items']
    
    IO.FreeMind.save(output,'output.mm')
Example #30
0
    def append_control_deflection(self,control_tag,deflection):
        """ adds a control deflection case """
        control_deflection = Data()
        control_deflection.tag        = control_tag
        control_deflection.deflection = deflection
        if self.stability_and_control.control_deflections is None:
            self.stability_and_control.control_deflections = Data()
        self.stability_and_control.control_deflections.append(control_deflection)

        return
Example #31
0
def mission_setup(analyses):

    # ------------------------------------------------------------------
    #   Initialize the Mission
    # ------------------------------------------------------------------

    mission = SUAVE.Analyses.Mission.Sequential_Segments()
    mission.tag = 'the_mission'

    #airport
    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()

    mission.airport = airport

    # unpack Segments module
    Segments = SUAVE.Analyses.Mission.Segments

    # base segment
    base_segment = Segments.Segment()
    ones_row = base_segment.state.ones_row
    base_segment.process.iterate.initials.initialize_battery = SUAVE.Methods.Missions.Segments.Common.Energy.initialize_battery
    base_segment.process.iterate.conditions.planet_position = SUAVE.Methods.skip
    base_segment.process.iterate.unknowns.network = analyses.vehicle.propulsors.turboprop.unpack_unknowns
    base_segment.process.iterate.residuals.network = analyses.vehicle.propulsors.turboprop.residuals
    base_segment.state.unknowns.pitch_command = ones_row(1) * 0. * Units.deg
    base_segment.state.conditions.propulsion = Data()
    base_segment.state.conditions.propulsion.rpm = 1200 * ones_row(1)
    base_segment.state.residuals.net = 0. * ones_row(1)
    base_segment.state.numerics.number_control_points = 10
    base_segment.state.conditions.freestream = Data()
    base_segment.state.conditions.freestream.delta_ISA = airport.delta_isa * ones_row(
        1)

    climb_segment = deepcopy(base_segment)
    base_segment.state.unknowns.throttle = ones_row(1)
    climb_segment.state.numerics.number_control_points = 3

    # ------------------------------------------------------------------
    #   First Climb Segment: Constant Speed, Constant Rate
    # ------------------------------------------------------------------

    segment = Segments.Climb.Constant_Throttle_Constant_Speed(climb_segment)
    segment.tag = "climb_1"

    segment.analyses.extend(analyses.takeoff)

    segment.altitude_start = 0.0 * Units.ft
    segment.altitude_end = 1500.0 * Units.ft
    segment.air_speed = 173.0 * Units.knots
    segment.throttle = 1.

    segment.state.conditions.propulsion.gas_turbine_rating = 'MCL'
    # add to misison
    mission.append_segment(segment)

    # ------------------------------------------------------------------
    #   Second Climb Segment: Constant Speed, Constant Rate
    # ------------------------------------------------------------------

    segment = Segments.Climb.Constant_Throttle_Constant_Speed(climb_segment)
    segment.tag = "climb_2"

    segment.analyses.extend(analyses.cruise)

    segment.altitude_start = 1500.0 * Units.ft
    segment.altitude_end = 4000.0 * Units.ft
    segment.air_speed = 180.0 * Units.knots
    segment.throttle = 1.
    # segment.climb_rate     = 915.   * Units['ft/min']

    segment.state.conditions.propulsion.gas_turbine_rating = 'MCL'
    # add to misison
    mission.append_segment(segment)

    # ------------------------------------------------------------------
    #   Third Climb Segment: Constant Speed, Constant Rate
    # ------------------------------------------------------------------

    segment = Segments.Climb.Constant_Throttle_Constant_Speed(climb_segment)
    segment.tag = "climb_3"

    segment.analyses.extend(analyses.cruise)

    segment.altitude_start = 4000.0 * Units.ft
    segment.altitude_end = 7000.0 * Units.ft
    segment.air_speed = 187.0 * Units.knots
    segment.throttle = 1.

    segment.state.conditions.propulsion.gas_turbine_rating = 'MCL'
    # add to misison
    mission.append_segment(segment)

    # ------------------------------------------------------------------
    #   Fourth Climb Segment: Constant Speed, Constant Rate
    # ------------------------------------------------------------------

    segment = Segments.Climb.Constant_Throttle_Constant_Speed(climb_segment)
    segment.tag = "climb_4"

    segment.analyses.extend(analyses.cruise)

    segment.altitude_start = 7000.0 * Units.ft
    segment.altitude_end = 10000.0 * Units.ft
    segment.air_speed = 195.0 * Units.knots
    segment.throttle = 1.

    segment.state.conditions.propulsion.gas_turbine_rating = 'MCL'
    # add to misison
    mission.append_segment(segment)
    # ------------------------------------------------------------------
    #   Fifth Climb Segment: Constant Speed, Constant Rate
    # ------------------------------------------------------------------

    segment = Segments.Climb.Constant_Throttle_Constant_Speed(climb_segment)
    segment.tag = "climb_5"

    segment.analyses.extend(analyses.takeoff)

    segment.altitude_start = 10000.0 * Units.ft
    segment.altitude_end = 12000.0 * Units.ft
    segment.air_speed = 203.5 * Units.knots
    segment.throttle = 1.

    segment.state.conditions.propulsion.gas_turbine_rating = 'MCL'
    # add to misison
    mission.append_segment(segment)

    # ------------------------------------------------------------------
    #   Sixth Climb Segment: Constant Speed, Constant Rate
    # ------------------------------------------------------------------

    segment = Segments.Climb.Constant_Throttle_Constant_Speed(climb_segment)
    segment.tag = "climb_6"

    segment.analyses.extend(analyses.cruise)

    segment.altitude_start = 12000.0 * Units.ft
    segment.altitude_end = 14000.0 * Units.ft
    segment.air_speed = 210.0 * Units.knots
    segment.throttle = 1.

    segment.state.conditions.propulsion.gas_turbine_rating = 'MCL'
    # add to misison
    mission.append_segment(segment)

    # ------------------------------------------------------------------
    #   Seventh Climb Segment: Constant Speed, Constant Rate
    # ------------------------------------------------------------------

    segment = Segments.Climb.Constant_Throttle_Constant_Speed(climb_segment)
    segment.tag = "climb_7"

    segment.analyses.extend(analyses.cruise)

    segment.altitude_start = 14000.0 * Units.ft
    segment.altitude_end = 16000.0 * Units.ft
    segment.air_speed = 217.0 * Units.knots
    segment.throttle = 1.

    segment.state.conditions.propulsion.gas_turbine_rating = 'MCL'
    # add to misison
    mission.append_segment(segment)

    # ------------------------------------------------------------------
    #   Eighth Climb Segment: Constant Speed, Constant Rate
    # ------------------------------------------------------------------

    segment = Segments.Climb.Constant_Throttle_Constant_Speed(climb_segment)
    segment.tag = "climb_8"

    segment.analyses.extend(analyses.cruise)

    segment.altitude_start = 16000.0 * Units.ft
    segment.altitude_end = 18000.0 * Units.ft
    segment.air_speed = 225.0 * Units.knots
    segment.throttle = 1.

    segment.state.conditions.propulsion.gas_turbine_rating = 'MCL'
    # add to misison
    mission.append_segment(segment)

    # ------------------------------------------------------------------
    #   Ninth Climb Segment: Constant Speed, Constant Rate
    # ------------------------------------------------------------------

    segment = Segments.Climb.Constant_Throttle_Constant_Speed(climb_segment)
    segment.tag = "climb_9"

    segment.analyses.extend(analyses.cruise)

    segment.altitude_start = 18000.0 * Units.ft
    segment.altitude_end = 21000.0 * Units.ft
    segment.air_speed = 235.0 * Units.knots
    segment.throttle = 1.

    segment.state.conditions.propulsion.gas_turbine_rating = 'MCL'
    # add to misison
    mission.append_segment(segment)

    # ------------------------------------------------------------------
    #   Cruise Segment: Constant Speed, Constant Altitude
    # ------------------------------------------------------------------

    segment = Segments.Cruise.Constant_Speed_Constant_Altitude(base_segment)
    segment.tag = "cruise"

    segment.analyses.extend(analyses.cruise)

    segment.air_speed = 260. * Units.knots
    segment.distance = 86. * Units.nautical_miles

    segment.state.conditions.propulsion.gas_turbine_rating = 'MCR'

    # add to mission
    mission.append_segment(segment)

    # ------------------------------------------------------------------
    #   First Descent Segment: Constant Speed, Constant Rate
    # ------------------------------------------------------------------

    segment = Segments.Descent.Constant_Speed_Constant_Rate(base_segment)
    segment.tag = "descent_1"

    segment.analyses.extend(analyses.cruise)

    segment.altitude_end = 18000. * Units.ft
    segment.air_speed = 283.0 * Units.knots
    segment.descent_rate = 2000. * Units['ft/min']

    segment.state.conditions.propulsion.gas_turbine_rating = 'MCR'
    # add to mission
    mission.append_segment(segment)

    # ------------------------------------------------------------------
    #   Second Descent Segment: Constant Speed, Constant Rate
    # ------------------------------------------------------------------

    segment = Segments.Descent.Constant_Speed_Constant_Rate(base_segment)
    segment.tag = "descent_2"

    segment.analyses.extend(analyses.cruise)

    segment.altitude_end = 10000. * Units.ft
    segment.air_speed = 275.0 * Units.knots
    segment.descent_rate = 2000. * Units['ft/min']

    segment.state.conditions.propulsion.gas_turbine_rating = 'MCR'
    # add to mission
    mission.append_segment(segment)

    # ------------------------------------------------------------------
    #   Third Descent Segment: Constant Speed, Constant Rate
    # ------------------------------------------------------------------

    segment = Segments.Descent.Constant_Speed_Constant_Rate(base_segment)
    segment.tag = "descent_3"

    segment.analyses.extend(analyses.landing)

    segment.altitude_end = 0. * Units.ft
    segment.air_speed = 260.0 * Units.knots
    segment.descent_rate = 2000. * Units['ft/min']

    segment.state.conditions.propulsion.gas_turbine_rating = 'MCR'
    # add to mission
    mission.append_segment(segment)

    # ------------------------------------------------------------------
    #   Mission definition complete
    # ------------------------------------------------------------------
    #
    ####################################################################
    # ------------------------------------------------------------------
    #   MISSION TO ESTIMATE TYPICAL RESERVES - 100 nm + 45 min (900 kg)
    # ------------------------------------------------------------------
    #
    # ------------------------------------------------------------------
    #   First Climb Segment: Constant Speed, Constant Rate
    # # ------------------------------------------------------------------
    #
    # segment = Segments.Climb.Constant_Speed_Constant_Rate(base_segment)
    # segment.tag = "climb_1_reserve"
    #
    # segment.analyses.extend(analyses.takeoff)
    #
    # segment.altitude_start = 0.0 * Units.ft
    # segment.altitude_end = 5000.0 * Units.ft
    # segment.air_speed = 180.0 * Units.knots
    # segment.climb_rate = 1220. * Units['ft/min']
    #
    # segment.state.conditions.propulsion.gas_turbine_rating = 'MCL'
    # # add to misison
    # mission.append_segment(segment)
    #
    # # ------------------------------------------------------------------
    # #   Second Climb Segment: Constant Speed, Constant Rate
    # # ------------------------------------------------------------------
    #
    # segment = Segments.Climb.Constant_Speed_Constant_Rate(base_segment)
    # segment.tag = "climb_2_reserve"
    #
    # segment.analyses.extend(analyses.cruise)
    #
    # segment.altitude_start = 5000.0 * Units.ft
    # segment.altitude_end = 10000.0 * Units.ft
    # segment.air_speed = 197.0 * Units.knots
    # segment.climb_rate = 915. * Units['ft/min']
    #
    # segment.state.conditions.propulsion.gas_turbine_rating = 'MCL'
    # # add to misison
    # mission.append_segment(segment)
    # # ------------------------------------------------------------------
    # #   Cruise Segment: Constant Speed, Constant Altitude
    # # ------------------------------------------------------------------
    #
    # # segment = Segments.Cruise.Constant_Speed_Constant_Altitude(base_segment)
    # # segment.tag = "cruise_reserve_Dist"
    # #
    # # segment.analyses.extend(analyses.cruise)
    # #
    # # segment.air_speed = 170. * Units.knots
    # # segment.distance  = 20.  * Units.nautical_miles
    # #
    # # segment.state.conditions.propulsion.gas_turbine_rating = 'MCR'
    #
    # # add to mission
    # mission.append_segment(segment)
    #
    # # ------------------------------------------------------------------
    # #   Cruise Segment: Constant Speed, Constant Altitude
    # # ------------------------------------------------------------------
    #
    # segment = Segments.Cruise.Constant_Speed_Constant_Altitude(base_segment)
    # segment.tag = "cruise_reserve_time"
    #
    # segment.analyses.extend(analyses.cruise)
    #
    # segment.air_speed = 178. * Units.knots
    # segment.distance  = 127. * Units.nautical_miles
    # # Considering 45 min as being more 127 nm for 178 KTAS
    # segment.state.conditions.propulsion.gas_turbine_rating = 'MCR'
    #
    # # add to mission
    # mission.append_segment(segment)
    #
    # # ------------------------------------------------------------------
    # #   Third Descent Segment: Constant Speed, Constant Rate
    # # ------------------------------------------------------------------
    #
    # segment = Segments.Descent.Constant_Speed_Constant_Rate(base_segment)
    # segment.tag = "descent_3_reserve"
    #
    # segment.analyses.extend(analyses.landing)
    #
    # segment.altitude_end = 0. * Units.ft
    # segment.air_speed = 240.0 * Units.knots
    # segment.descent_rate = 1500. * Units['ft/min']
    #
    # # segment.state.conditions.propulsion.gas_turbine_rating = 'FID'
    # segment.state.conditions.propulsion.gas_turbine_rating = 'MCR'
    # # add to mission
    # mission.append_segment(segment)

    return mission
Example #32
0
def main():
   
    #------------------------------------------------------------------
    # Propulsor
    #------------------------------------------------------------------

    # build network
    net = Solar_Low_Fidelity()
    net.number_of_engines = 1.
    net.nacelle_diameter  = 0.05
    net.areas             = Data()
    net.areas.wetted      = 0.01*(2*np.pi*0.01/2)
    net.engine_length     = 0.01

    # Component 1 the Sun
    sun = SUAVE.Components.Energy.Processes.Solar_Radiation()
    net.solar_flux = sun

    # Component 2 the solar panels
    panel = SUAVE.Components.Energy.Converters.Solar_Panel()
    panel.ratio                = 0.9
    panel.area                 = 1.0 * panel.ratio 
    panel.efficiency           = 0.25
    panel.mass_properties.mass = panel.area*(0.60 * Units.kg)
    net.solar_panel            = panel

    # Component 3 the ESC
    esc = SUAVE.Components.Energy.Distributors.Electronic_Speed_Controller()
    esc.efficiency = 0.95 # Gundlach for brushless motors
    net.esc        = esc

    # Component 5 the Propeller
    prop = SUAVE.Components.Energy.Converters.Propeller_Lo_Fid()
    prop.propulsive_efficiency = 0.825
    net.propeller        = prop
    
    # Component 4 the Motor
    motor = SUAVE.Components.Energy.Converters.Motor_Lo_Fid() 
    motor.speed_constant       = 800. * Units['rpm/volt'] # RPM/volt is standard
    motor                      = size_from_kv(motor)    
    motor.gear_ratio           = 1. # Gear ratio, no gearbox
    motor.gearbox_efficiency   = 1. # Gear box efficiency, no gearbox
    motor.motor_efficiency     = 0.825;
    net.motor                  = motor    

    # Component 6 the Payload
    payload = SUAVE.Components.Energy.Peripherals.Payload()
    payload.power_draw           = 0. #Watts 
    payload.mass_properties.mass = 0.0 * Units.kg
    net.payload                  = payload

    # Component 7 the Avionics
    avionics = SUAVE.Components.Energy.Peripherals.Avionics()
    avionics.power_draw = 10. #Watts  
    net.avionics        = avionics      

    # Component 8 the Battery
    bat = SUAVE.Components.Energy.Storages.Batteries.Constant_Mass.Lithium_Ion()
    bat.mass_properties.mass = 5.0  * Units.kg
    bat.specific_energy      = 250. *Units.Wh/Units.kg
    bat.resistance           = 0.003
    bat.iters                = 0
    initialize_from_mass(bat,bat.mass_properties.mass)
    net.battery              = bat

    #Component 9 the system logic controller and MPPT
    logic = SUAVE.Components.Energy.Distributors.Solar_Logic()
    logic.system_voltage  = 18.5
    logic.MPPT_efficiency = 0.95
    net.solar_logic       = logic
    
    # Setup the conditions to run the network
    state            = Data()
    state.conditions = SUAVE.Analyses.Mission.Segments.Conditions.Aerodynamics()
    state.numerics   = SUAVE.Analyses.Mission.Segments.Conditions.Numerics()
    
    conditions = state.conditions
    numerics   = state.numerics
    
    # Calculate atmospheric properties
    atmosphere = SUAVE.Analyses.Atmospheric.US_Standard_1976()
    atmosphere_conditions =  atmosphere.compute_values(1000.*Units.ft)
    
    rho = atmosphere_conditions.density[0,:]
    a   = atmosphere_conditions.speed_of_sound[0,:]
    mu  = atmosphere_conditions.dynamic_viscosity[0,:]
    T   = atmosphere_conditions.temperature[0,:]

    conditions.propulsion.throttle            = np.array([[1.0],[1.0]])
    conditions.freestream.velocity            = np.array([[1.0],[1.0]])
    conditions.freestream.density             = np.array([rho,rho])
    conditions.freestream.dynamic_viscosity   = np.array([mu, mu])
    conditions.freestream.speed_of_sound      = np.array([a, a])
    conditions.freestream.altitude            = np.array([[1000.0],[1000.0]])
    conditions.propulsion.battery_energy      = bat.max_energy*np.ones_like(conditions.freestream.altitude)
    conditions.frames.body.inertial_rotations = np.zeros([2,3])
    conditions.frames.inertial.time           = np.array([[0.0],[1.0]])
    numerics.time.integrate                   = np.array([[0, 0],[0, 1]])
    numerics.time.differentiate               = np.array([[0, 0],[0, 1]])
    conditions.frames.planet.start_time       = time.strptime("Sat, Jun 21 06:00:00  2014", "%a, %b %d %H:%M:%S %Y",) 
    conditions.frames.planet.latitude         = np.array([[0.0],[0.0]])
    conditions.frames.planet.longitude        = np.array([[0.0],[0.0]])
    conditions.freestream.temperature         = np.array([T, T])
    conditions.frames.body.transform_to_inertial = np.array([[[ 1.,  0.,  0.],
                                                              [ 0.,  1.,  0.],
                                                              [ 0.,  0.,  1.]],
                                                             [[ 1.,  0.,  0.],
                                                              [ 0.,  1.,  0.],
                                                              [ 0.,  0.,  1.]]])   
    # Run the network and print the results
    results = net(state)
    F       = results.thrust_force_vector
    
    # Truth results
    truth_F   = [[ 68.78277813   ], [ 68.78277813     ]]
    truth_i   = [[ 5.75011436    ], [ 5.75011436      ]]
    truth_rpm = [[ 14390.30435183], [ 14390.30435183  ]]
    truth_bat = [[ 4500000.      ], [ 4499883.5041616 ]]
    
    error = Data()
    error.Thrust = np.max(np.abs(F[:,0]-truth_F))
    error.RPM = np.max(np.abs(conditions.propulsion.propeller_rpm-truth_rpm))
    error.Current  = np.max(np.abs(conditions.propulsion.battery_current-truth_i))
    error.Battery = np.max(np.abs(bat.current_energy-truth_bat))
    
    print(error)
    
    for k,v in list(error.items()):
        assert(np.abs(v)<1e-6)        
    
    return
Example #33
0
def setup():

    nexus = Nexus()
    problem = Data()
    nexus.optimization_problem = problem

    # -------------------------------------------------------------------
    # Inputs
    # -------------------------------------------------------------------

    #   [ tag                            , initial, (lb,ub)             , scaling , units ]
    problem.inputs = np.array([
        #[ 'wing_span'      ,  9.4   , (   8.0 ,   15.   ) ,   9.4 , Units.meter],
        #[ 'wing_root_chord'  ,  2.0    , (   1.  ,    4.   ) ,   2.0  , Units.meter],
        #[ 'wing_thickness_to_chord'  ,  0.15    , (   0.1  ,    0.5   ) ,   0.15  , Units.less],
        #[ 'wing_taper_ratio'  ,  0.9    , (   0.55  ,    1.0   ) ,   0.9  , Units.less],
        #[ 'cruise_distance'        ,  150.    , (   50.  ,    1000.   ) ,   150.  , Units.nautical_miles],
        #[ 'cruise_airspeed'        ,  200.   , (   90.  ,    300.   ) ,   200.  , Units['m/s']],
        #[ 'climb1_airspeed'        , 125.0   , (   50.0  ,  250.0      ) ,  125.0   , Units['m/s']],
        #[ 'climb2_airspeed'        ,  190.0   , ( 70.0    ,  270.0     ) ,   190.0  , Units['m/s']],
        #[ 'descent1_airspeed'      ,  180.0  , ( 100.    ,  270.     ) ,  180.0   , Units['m/s']],
        #[ 'descent2_airspeed'      ,   145.0   , ( 50.    ,  200.0     ) ,  145.0   , Units['m/s']],
        #[ 'climb1_altitude'        ,   3.  , (  1.   ,  5.     ) ,  3.   , Units.km],
        #[ 'climb2_altitude'        ,   8.0   , (   7.  ,  15.     ) , 8.0    , Units.km],
        #[ 'descent1_altitude'      ,  3.0    , (  2.   ,  7.     ) ,   3.0  , Units.km],
        #[ 'climb1_rate'        ,    6.0  , (   3.  ,  17.     ) ,  6.0   , Units['m/s']],
        #[ 'climb2_rate'        ,    3.0  , (  2.   ,   12.    ) ,   3.0  , Units['m/s']],
        #[ 'descent1_rate'      ,   4.5   , (  3.   ,   15.    ) ,  4.5   , Units['m/s']],
        #[ 'descent2_rate'      ,    3.0  , (  2.   ,   12.    ) ,  3.0   , Units['m/s']],
        ['voltage', 470., (30., 10000.), 470., Units['volt']],
        ['motor_kv_cruise', 181., (10., 500.), 181., Units['rpm/volt']],
        ['motor_kv_HL', 91., (5., 300.), 91., Units['rpm/volt']],
        ['bat_spec_energy', 6.1, (3., 10000.), 6.1, Units.Wh / Units.kg],
        ['bat_spec_power', 0.833, (0.5, 1000.), 0.833, Units.kW / Units.kg],
        ['bat_max_voltage', 60.1, (0.5, 100000.), 60.1, Units['volt']],
        ['bat_resistance', 0.0151, (0.0001, 100.), 0.0151, Units['ohm']],
        ['payload_draw', 50.1, (5., 50000.), 50.1, Units.watts],
        ['avionics_draw', 50.1, (5., 50000.), 50.1, Units.watts],
    ])

    # -------------------------------------------------------------------
    # Objective
    # -------------------------------------------------------------------

    # throw an error if the user isn't specific about wildcards
    # [ tag, scaling, units ]
    problem.objective = np.array([
        #[ 'range', -540.9079921321364, Units.nautical_miles ],
        ['battery_energy_max', 8476560.0, Units.Wh],
    ])

    # -------------------------------------------------------------------
    # Constraints
    # -------------------------------------------------------------------

    # [ tag, sense, edge, scaling, units ]
    problem.constraints = np.array([
        #[ 'energy_constraint', '=', 0.0, 1.0, Units.less],
        ['battery_energy_min', '>', 0.0, 111153486.035, Units.Wh],
        #[ 'battery_draw'     , '>', -0.1, 1.0, Units.kW  ],
        #[ 'CL'               , '>', 0.0, 1.0, Units.less],
        ['Throttle_cruise', '>', -0.1, 1.0, Units.less],
        ['Throttle_HL', '>', -0.1, 1.0, Units.less],
        ['Throttle_cruise', '<', 1.5, 1.0, Units.less],
        ['Throttle_HL', '<', 1.5, 1.0, Units.less],
        ['HL_rpm_min', '>', -0.1, 1.0, Units['rpm']],
        ['HL_rpm_max', '<', 15000, 1.0, Units['rpm']],
        ['cruise_rpm_min', '>', -0.1, 1.0, Units['rpm']],
        ['cruise_rpm_max', '<', 50000, 1.0, Units['rpm']],
        #[ 'lift_coefficient'       , '>', -0.1, 1.0, Units.less],
        ['mach_number', '<', 1.5, 1.0, Units.less],
    ])

    # -------------------------------------------------------------------
    #  Aliases
    # -------------------------------------------------------------------

    # [ 'alias' , ['data.path1.name','data.path2.name'] ]

    problem.aliases = [
        #[ 'wing_span'          ,    'vehicle_configurations.*.wings.main_wing.spans.projected'],
        #[ 'wing_root_chord'                  ,     'vehicle_configurations.*.wings.main_wing.chords.root'         ],
        #[ 'wing_thickness_to_chord'          ,     'vehicle_configurations.*.wings.main_wing.thickness_to_chord'         ],
        #[ 'wing_taper_ratio'          ,     'vehicle_configurations.*.wings.main_wing.taper'         ],
        #[ 'cruise_distance'            ,   'missions.mission.segments.cruise.distance'              ],
        #[ 'cruise_airspeed'            ,   'missions.mission.segments.cruise.air_speed'              ],
        #[ 'climb1_airspeed'            ,   'missions.mission.segments.climb_1.air_speed'             ],
        #[ 'climb2_airspeed'            ,   'missions.mission.segments.climb_2.air_speed'              ],
        #[ 'descent1_airspeed'            ,  'missions.mission.segments.descent_1.air_speed'               ],
        #[ 'descent2_airspeed'            ,  'missions.mission.segments.descent_2.air_speed'               ],
        #[ 'climb1_altitude'            ,   'missions.mission.segments.climb_1.altitude_end'              ],
        #[ 'climb2_altitude'            ,   'missions.mission.segments.climb_2.altitude_end'              ],
        #[ 'descent1_altitude'            , 'missions.mission.segments.descent_1.altitude_end'                ],
        #[ 'climb1_rate'            ,   'missions.mission.segments.climb_1.climb_rate'              ],
        #[ 'climb2_rate'            ,   'missions.mission.segments.climb_2.climb_rate'              ],
        #[ 'descent1_rate'            ,  'missions.mission.segments.descent_1.descent_rate'               ],
        #[ 'descent2_rate'            ,  'missions.mission.segments.descent_2.descent_rate'               ],
        ['voltage', 'vehicle_configurations.*.propulsors.propulsor.voltage'],
        [
            'motor_kv_cruise',
            'vehicle_configurations.*.propulsors.propulsor.motor_forward.speed_constant'
        ],
        [
            'motor_kv_HL',
            'vehicle_configurations.*.propulsors.propulsor.motor_lift.speed_constant'
        ],
        [
            'bat_spec_energy',
            'vehicle_configurations.*.propulsors.propulsor.battery.specific_energy'
        ],
        [
            'bat_spec_power',
            'vehicle_configurations.*.propulsors.propulsor.battery.specific_power'
        ],
        [
            'bat_max_voltage',
            'vehicle_configurations.*.propulsors.propulsor.battery.max_voltage'
        ],
        [
            'bat_resistance',
            'vehicle_configurations.*.propulsors.propulsor.battery.resistance'
        ],
        [
            'payload_draw',
            'vehicle_configurations.*.propulsors.propulsor.payload.power_draw'
        ],
        [
            'avionics_draw',
            'vehicle_configurations.*.propulsors.propulsor.avionics.power_draw'
        ],
        #[ 'range'            ,    'summary.total_range'            ],
        #[ 'max_lift'            ,    'summary.max_lift_coefficient_all_segments'            ],
        ['battery_energy_max', 'summary.max_battery_energy_all_segments'],
        ['battery_energy_min', 'summary.min_battery_energy_all_segments'],
        ['battery_draw', 'summary.battery_charging_power_all_segments'],
        ['Throttle_cruise', 'summary.throttle_all_segments'],
        ['Throttle_HL', 'summary.lift_throttle_all_segments'],
        ['HL_rpm_min', 'summary.min_rpm_lift_all_segments'],
        ['HL_rpm_max', 'summary.max_rpm_lift_all_segments'],
        ['cruise_rpm_min', 'summary.min_rpm_forward_all_segments'],
        ['cruise_rpm_max', 'summary.max_rpm_forward_all_segments'],
        ['lift_coefficient', 'summary.lift_coefficient_all_segments'],
        ['mach_number', 'summary.mach_number_all_segments'],
        ['AoA_min', 'summary.min_aoa_all_segments'],
    ]

    # -------------------------------------------------------------------
    #  Vehicles
    # -------------------------------------------------------------------
    nexus.vehicle_configurations = Vehicles.setup()

    # -------------------------------------------------------------------
    #  Analyses
    # -------------------------------------------------------------------
    nexus.analyses = Analyses.setup(nexus.vehicle_configurations)

    # -------------------------------------------------------------------
    #  Missions
    # -------------------------------------------------------------------
    nexus.missions = Missions.setup(nexus.analyses,
                                    nexus.vehicle_configurations)

    # -------------------------------------------------------------------
    #  Procedure
    # -------------------------------------------------------------------
    nexus.procedure = Procedure.setup()

    # -------------------------------------------------------------------
    #  Summary
    # -------------------------------------------------------------------
    #nexus.summary = Data()

    nexus.total_number_of_iterations = 0

    return nexus
Example #34
0
def energy_network():

    # ------------------------------------------------------------------
    #   Evaluation Conditions
    # ------------------------------------------------------------------

    # --- Conditions
    ones_1col = np.ones([1, 1])

    # setup conditions
    conditions = SUAVE.Analyses.Mission.Segments.Conditions.Aerodynamics()
    '''
    conditions.frames       = Data()
    conditions.freestream   = Data()
    conditions.aerodynamics = Data()
    conditions.propulsion   = Data()
    conditions.weights      = Data()
    conditions.energies     = Data()
    '''
    #  self.conditions = conditions

    # freestream conditions
    conditions.freestream.mach_number = ones_1col * 0.8
    conditions.freestream.pressure = ones_1col * 20000.
    conditions.freestream.temperature = ones_1col * 215.
    conditions.freestream.density = ones_1col * 0.8

    conditions.freestream.dynamic_viscosity = ones_1col * 0.000001475
    conditions.freestream.altitude = ones_1col * 10.
    conditions.freestream.gravity = ones_1col * 9.81
    conditions.freestream.gamma = ones_1col * 1.4
    conditions.freestream.Cp = 1.4 * 287.87 / (1.4 - 1)
    conditions.freestream.R = 287.87
    conditions.M = conditions.freestream.mach_number
    conditions.T = conditions.freestream.temperature
    conditions.p = conditions.freestream.pressure
    conditions.freestream.speed_of_sound = ones_1col * np.sqrt(
        conditions.freestream.Cp /
        (conditions.freestream.Cp - conditions.freestream.R) *
        conditions.freestream.R * conditions.freestream.temperature)  #300.
    conditions.freestream.velocity = conditions.M * conditions.freestream.speed_of_sound
    conditions.velocity = conditions.M * conditions.freestream.speed_of_sound
    conditions.q = 0.5 * conditions.freestream.density * conditions.velocity**2
    conditions.g0 = conditions.freestream.gravity

    # propulsion conditions
    conditions.propulsion.throttle = ones_1col * 1.0

    # ------------------------------------------------------------------
    #   Design/sizing conditions
    # ------------------------------------------------------------------

    # --- Conditions
    ones_1col = np.ones([1, 1])

    # setup conditions
    conditions_sizing = SUAVE.Analyses.Mission.Segments.Conditions.Aerodynamics(
    )
    '''
    conditions_sizing.frames       = Data()
    conditions_sizing.freestream   = Data()
    conditions_sizing.aerodynamics = Data()
    conditions_sizing.propulsion   = Data()
    conditions_sizing.weights      = Data()
    conditions_sizing.energies     = Data()
    '''
    #  self.conditions = conditions

    # freestream conditions
    conditions_sizing.freestream.mach_number = ones_1col * 0.8
    conditions_sizing.freestream.pressure = ones_1col * 26499.73156529
    conditions_sizing.freestream.temperature = ones_1col * 223.25186491
    conditions_sizing.freestream.density = ones_1col * 0.41350854

    conditions_sizing.freestream.dynamic_viscosity = ones_1col * 1.45766126e-05  #*1.789*10**(-5)
    conditions_sizing.freestream.altitude = ones_1col * 10000.  #* 0.5

    conditions_sizing.freestream.gravity = ones_1col * 9.81
    conditions_sizing.freestream.gamma = ones_1col * 1.4
    conditions_sizing.freestream.Cp = 1.4 * 287.87 / (1.4 - 1)
    conditions_sizing.freestream.R = 287.87
    conditions_sizing.freestream.speed_of_sound = 299.53150968
    conditions_sizing.freestream.velocity = conditions_sizing.freestream.mach_number * conditions_sizing.freestream.speed_of_sound

    # propulsion conditions
    conditions_sizing.propulsion.throttle = ones_1col * 1.0

    state_sizing = Data()
    state_sizing.numerics = Data()
    state_sizing.conditions = conditions_sizing
    state_off_design = Data()
    state_off_design.numerics = Data()
    state_off_design.conditions = conditions

    # ------------------------------------------------------------------
    #   Turbofan Network
    # ------------------------------------------------------------------

    #instantiate the gas turbine network
    turbofan = SUAVE.Components.Energy.Networks.Turbofan()
    turbofan.tag = 'turbo_fan'

    # setup
    turbofan.bypass_ratio = 5.4
    turbofan.number_of_engines = 2.0
    turbofan.engine_length = 2.5
    turbofan.nacelle_diameter = 1.580

    # working fluid
    turbofan.working_fluid = SUAVE.Attributes.Gases.Air()

    # ------------------------------------------------------------------
    #   Component 1 - Ram

    # to convert freestream static to stagnation quantities

    # instantiate
    ram = SUAVE.Components.Energy.Converters.Ram()
    ram.tag = 'ram'

    # add to the network
    turbofan.append(ram)

    # ------------------------------------------------------------------
    #  Component 2 - Inlet Nozzle

    # instantiate
    inlet_nozzle = SUAVE.Components.Energy.Converters.Compression_Nozzle()
    inlet_nozzle.tag = 'inlet_nozzle'

    # setup
    inlet_nozzle.polytropic_efficiency = 0.98
    inlet_nozzle.pressure_ratio = 0.98

    # add to network
    turbofan.append(inlet_nozzle)

    # ------------------------------------------------------------------
    #  Component 3 - Low Pressure Compressor

    # instantiate
    compressor = SUAVE.Components.Energy.Converters.Compressor()
    compressor.tag = 'low_pressure_compressor'

    # setup
    compressor.polytropic_efficiency = 0.91
    compressor.pressure_ratio = 1.14

    # add to network
    turbofan.append(compressor)

    # ------------------------------------------------------------------
    #  Component 4 - High Pressure Compressor

    # instantiate
    compressor = SUAVE.Components.Energy.Converters.Compressor()
    compressor.tag = 'high_pressure_compressor'

    # setup
    compressor.polytropic_efficiency = 0.91
    compressor.pressure_ratio = 13.415

    # add to network
    turbofan.append(compressor)

    # ------------------------------------------------------------------
    #  Component 5 - Low Pressure Turbine

    # instantiate
    turbine = SUAVE.Components.Energy.Converters.Turbine()
    turbine.tag = 'low_pressure_turbine'

    # setup
    turbine.mechanical_efficiency = 0.99
    turbine.polytropic_efficiency = 0.93

    # add to network
    turbofan.append(turbine)

    # ------------------------------------------------------------------
    #  Component 6 - High Pressure Turbine

    # instantiate
    turbine = SUAVE.Components.Energy.Converters.Turbine()
    turbine.tag = 'high_pressure_turbine'

    # setup
    turbine.mechanical_efficiency = 0.99
    turbine.polytropic_efficiency = 0.93

    # add to network
    turbofan.append(turbine)

    # ------------------------------------------------------------------
    #  Component 7 - Combustor

    # instantiate
    combustor = SUAVE.Components.Energy.Converters.Combustor()
    combustor.tag = 'combustor'

    # setup
    combustor.efficiency = 0.99
    combustor.alphac = 1.0
    combustor.turbine_inlet_temperature = 1450
    combustor.pressure_ratio = 0.95
    combustor.fuel_data = SUAVE.Attributes.Propellants.Jet_A()

    # add to network
    turbofan.append(combustor)

    # ------------------------------------------------------------------
    #  Component 8 - Core Nozzle

    # instantiate
    nozzle = SUAVE.Components.Energy.Converters.Expansion_Nozzle()
    nozzle.tag = 'core_nozzle'

    # setup
    nozzle.polytropic_efficiency = 0.95
    nozzle.pressure_ratio = 0.99

    # add to network
    turbofan.append(nozzle)

    # ------------------------------------------------------------------
    #  Component 9 - Fan Nozzle

    # instantiate
    nozzle = SUAVE.Components.Energy.Converters.Expansion_Nozzle()
    nozzle.tag = 'fan_nozzle'

    # setup
    nozzle.polytropic_efficiency = 0.95
    nozzle.pressure_ratio = 0.99

    # add to network
    turbofan.append(nozzle)

    # ------------------------------------------------------------------
    #  Component 10 - Fan

    # instantiate
    fan = SUAVE.Components.Energy.Converters.Fan()
    fan.tag = 'fan'

    # setup
    fan.polytropic_efficiency = 0.93
    fan.pressure_ratio = 1.7

    # add to network
    turbofan.append(fan)

    # ------------------------------------------------------------------
    #  Component 10 - Thrust

    # to compute thrust

    # instantiate
    thrust = SUAVE.Components.Energy.Processes.Thrust()
    thrust.tag = 'thrust'

    # setup
    thrust.total_design = 42383.01818423

    # add to network
    turbofan.thrust = thrust

    #bypass ratio  closer to fan

    numerics = Data()

    eta = 1.0

    #size the turbofan
    turbofan_sizing(turbofan, 0.8, 10000.0)

    print "Design thrust ", turbofan.design_thrust
    print "Sealevel static thrust ", turbofan.sealevel_static_thrust

    results_design = turbofan(state_sizing)
    results_off_design = turbofan(state_off_design)
    F = results_design.thrust_force_vector
    mdot = results_design.vehicle_mass_rate
    F_off_design = results_off_design.thrust_force_vector
    mdot_off_design = results_off_design.vehicle_mass_rate

    #Test the model

    #Specify the expected values
    expected = Data()

    expected.thrust = 42383.01818423
    expected.mdot = 0.7657905

    #error data function
    error = Data()

    error.thrust_error = (F[0][0] - expected.thrust) / expected.thrust
    error.mdot_error = (mdot[0][0] - expected.mdot) / expected.mdot
    print error

    for k, v in error.items():
        assert (np.abs(v) < 1e-4)

    return
Example #35
0
    def __defaults__(self):
        """ This sets the default values for the component to function.
        
        Assumptions:
        None
    
        Source:
        N/A
    
        Inputs:
        None
    
        Outputs:
        None
    
        Properties Used:
        None
        """      
        
        self.tag = 'fuselage'
        self.origin             = [[0.0,0.0,0.0]]
        self.aerodynamic_center = [0.0,0.0,0.0]
        self.Sections    = Lofted_Body.Section.Container()
        self.Segments    = ContainerOrdered()
        
        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.x_rotation  = 0.0
        self.y_rotation  = 0.0
        self.z_rotation  = 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
        
        # for BWB 
        self.aft_centerbody_area  = 0.0
        self.aft_centerbody_taper = 0.0
        self.cabin_area           = 0.0

        self.Fuel_Tanks = Container()

        # For VSP
        self.vsp_data                = Data()
        self.vsp_data.xsec_surf_id   = ''    # There is only one XSecSurf in each VSP geom.
        self.vsp_data.xsec_num       = None  # Number if XSecs in fuselage geom.
        
        self.Segments           = SUAVE.Core.ContainerOrdered()
    def evaluate_thrust(self, state):
        """ Calculate thrust given the current state of the vehicle
    
            Assumptions:
            Caps the throttle at 110% and linearly interpolates thrust off that
    
            Source:
            N/A
    
            Inputs:
            state [state()]
    
            Outputs:
            results.thrust_force_vector [Newtons]
            results.vehicle_mass_rate   [kg/s]
            conditions.propulsion:
                rpm_lift                 [radians/sec]
                rpm _forward             [radians/sec]
                current_lift             [amps]
                current_forward          [amps]
                battery_draw             [watts]
                battery_energy           [joules]
                voltage_open_circuit     [volts]
                voltage_under_load       [volts]
                motor_torque_lift        [N-M]
                motor_torque_forward     [N-M]
                propeller_torque_lift    [N-M]
                propeller_torque_forward [N-M]
    
            Properties Used:
            Defaulted values
        """

        # unpack
        conditions = state.conditions
        numerics = state.numerics
        motor_lift = self.motor_lift
        motor_forward = self.motor_forward
        propeller_lift = self.propeller_lift
        propeller_forward = self.propeller_forward
        esc_lift = self.esc_lift
        esc_forward = self.esc_forward
        avionics = self.avionics
        payload = self.payload
        battery = self.battery
        num_lift = self.number_of_engines_lift
        num_forward = self.number_of_engines_forward

        ###
        # Setup batteries and ESC's
        ###

        # Set battery energy
        battery.current_energy = conditions.propulsion.battery_energy

        volts = state.unknowns.battery_voltage_under_load
        volts[volts > self.voltage] = self.voltage

        # ESC Voltage
        esc_lift.inputs.voltagein = volts
        esc_forward.inputs.voltagein = volts

        ###
        # Evaluate thrust from the forward propulsors
        ###

        # Throttle the voltage
        esc_forward.voltageout(conditions)
        # link
        motor_forward.inputs.voltage = esc_forward.outputs.voltageout

        # Run the motor
        motor_forward.omega(conditions)
        # link
        propeller_forward.inputs.omega = motor_forward.outputs.omega
        propeller_forward.thrust_angle = self.thrust_angle_forward

        # Run the propeller
        F_forward, Q_forward, P_forward, Cp_forward = propeller_forward.spin(
            conditions)

        # Check to see if magic thrust is needed, the ESC caps throttle at 1.1 already
        eta = conditions.propulsion.throttle[:, 0, None]
        P_forward[eta > 1.0] = P_forward[eta > 1.0] * eta[eta > 1.0]
        F_forward[eta > 1.0] = F_forward[eta > 1.0] * eta[eta > 1.0]

        # Run the motor for current
        motor_forward.current(conditions)
        # link
        esc_forward.inputs.currentout = motor_forward.outputs.current

        # Run the esc
        esc_forward.currentin()

        ###
        # Evaluate thrust from the lift propulsors
        ###

        # Make a new set of konditions, since there are differences for the esc and motor
        konditions = Data()
        konditions.propulsion = Data()
        konditions.freestream = Data()
        konditions.frames = Data()
        konditions.frames.inertial = Data()
        konditions.frames.body = Data()
        konditions.propulsion.throttle = conditions.propulsion.lift_throttle * 1.
        konditions.propulsion.propeller_power_coefficient = conditions.propulsion.propeller_power_coefficient_lift * 1.
        konditions.freestream.density = conditions.freestream.density * 1.
        konditions.freestream.velocity = conditions.freestream.velocity * 1.
        konditions.freestream.dynamic_viscosity = conditions.freestream.dynamic_viscosity * 1.
        konditions.freestream.speed_of_sound = conditions.freestream.speed_of_sound * 1.
        konditions.freestream.temperature = conditions.freestream.temperature * 1.
        konditions.frames.inertial.velocity_vector = conditions.frames.inertial.velocity_vector * 1.
        konditions.frames.body.transform_to_inertial = conditions.frames.body.transform_to_inertial

        # Throttle the voltage
        esc_lift.voltageout(konditions)
        # link
        motor_lift.inputs.voltage = esc_lift.outputs.voltageout

        # Run the motor
        motor_lift.omega(konditions)
        # link
        propeller_lift.inputs.omega = motor_lift.outputs.omega
        propeller_lift.thrust_angle = self.thrust_angle_lift

        # Run the propeller
        F_lift, Q_lift, P_lift, Cp_lift = propeller_lift.spin(konditions)

        # Check to see if magic thrust is needed, the ESC caps throttle at 1.1 already
        eta = state.conditions.propulsion.lift_throttle
        P_lift[eta > 1.0] = P_lift[eta > 1.0] * eta[eta > 1.0]
        F_lift[eta > 1.0] = F_lift[eta > 1.0] * eta[eta > 1.0]

        # Run the motor for current
        motor_lift.current(conditions)
        # link
        esc_lift.inputs.currentout = motor_lift.outputs.current

        # Run the esc
        esc_lift.currentin()

        ###
        # Combine the thrusts and powers
        ###

        # Run the avionics
        avionics.power()

        # Run the payload
        payload.power()

        # Calculate avionics and payload power
        avionics_payload_power = avionics.outputs.power + payload.outputs.power

        # Calculate avionics and payload current
        i_avionics_payload = avionics_payload_power / state.unknowns.battery_voltage_under_load

        # Add up the power usages
        i_lift = esc_lift.outputs.currentin * num_lift
        i_forward = esc_forward.outputs.currentin * num_forward

        current_total = i_lift + i_forward + i_avionics_payload
        power_total = current_total * state.unknowns.battery_voltage_under_load

        battery.inputs.current = current_total
        battery.inputs.power_in = -power_total

        # Run the battery
        battery.energy_calc(numerics)

        # Pack the conditions
        rpm_lift = motor_lift.outputs.omega * 60. / (2. * np.pi)
        rpm_forward = motor_forward.outputs.omega * 60. / (2. * np.pi)
        battery_draw = battery.inputs.power_in
        battery_energy = battery.current_energy
        voltage_open_circuit = battery.voltage_open_circuit
        voltage_under_load = battery.voltage_under_load

        conditions.propulsion.rpm_lift = rpm_lift
        conditions.propulsion.rpm_forward = rpm_forward
        conditions.propulsion.current_lift = i_lift
        conditions.propulsion.current_forward = i_forward
        conditions.propulsion.motor_torque_lift = motor_lift.outputs.torque
        conditions.propulsion.motor_torque_forward = motor_forward.outputs.torque
        conditions.propulsion.propeller_torque_lift = Q_lift
        conditions.propulsion.propeller_torque_forward = Q_forward

        conditions.propulsion.battery_draw = battery_draw
        conditions.propulsion.battery_energy = battery_energy
        conditions.propulsion.voltage_open_circuit = voltage_open_circuit
        conditions.propulsion.voltage_under_load = voltage_under_load

        # Calculate the thrust and mdot
        F_lift_total = F_lift * num_lift * [
            np.cos(self.thrust_angle_lift), 0, -np.sin(self.thrust_angle_lift)
        ]
        F_forward_total = F_forward * num_forward * [
            np.cos(self.thrust_angle_forward), 0,
            -np.sin(self.thrust_angle_forward)
        ]

        F_total = F_lift_total + F_forward_total
        mdot = np.zeros_like(F_total)

        results = Data()
        results.thrust_force_vector = F_total
        results.vehicle_mass_rate = mdot

        return results
Example #37
0
def main():

    vehicle = vehicle_setup()  # Create the vehicle for testing
    for wing in vehicle.wings:
        wing.areas.wetted = 2.0 * wing.areas.reference
        wing.areas.exposed = 0.8 * wing.areas.wetted
        wing.areas.affected = 0.6 * wing.areas.wetted
    aerodynamics = SUAVE.Analyses.Aerodynamics.Supersonic_Zero()
    aerodynamics.geometry = vehicle
    aerodynamics.settings.drag_coefficient_increment = 0.0000
    vehicle.aerodynamics_model = aerodynamics
    vehicle.aerodynamics_model.initialize()

    test_num = 11  # Length of arrays used in this test

    # --------------------------------------------------------------------
    # Test Lift Surrogate
    # --------------------------------------------------------------------

    AoA = np.linspace(-.174, .174, test_num)[:, None]  # +- 10 degrees

    # Cruise conditions (except Mach number)
    state = SUAVE.Analyses.Mission.Segments.Conditions.State()
    state.conditions = SUAVE.Analyses.Mission.Segments.Conditions.Aerodynamics(
    )

    state.expand_rows(test_num)

    # --------------------------------------------------------------------
    # Initialize variables needed for CL and CD calculations
    # Use a seeded random order for values
    # --------------------------------------------------------------------

    random.seed(1)
    Mc = np.linspace(0.05, 0.9, test_num)
    random.shuffle(Mc)
    AoA = AoA.reshape(test_num, 1)
    Mc = Mc.reshape(test_num, 1)

    rho = np.linspace(0.3, 1.3, test_num)
    random.shuffle(rho)
    rho = rho.reshape(test_num, 1)

    mu = np.linspace(5 * 10**-6, 20 * 10**-6, test_num)
    random.shuffle(mu)
    mu = mu.reshape(test_num, 1)

    T = np.linspace(200, 300, test_num)
    random.shuffle(T)
    T = T.reshape(test_num, 1)

    pressure = np.linspace(10**5, 10**6, test_num)
    pressure = pressure.reshape(test_num, 1)

    state.conditions.freestream.mach_number = Mc
    state.conditions.freestream.density = rho
    state.conditions.freestream.dynamic_viscosity = mu
    state.conditions.freestream.temperature = T
    state.conditions.freestream.pressure = pressure

    state.conditions.aerodynamics.angle_of_attack = AoA

    # --------------------------------------------------------------------
    # Surrogate
    # --------------------------------------------------------------------

    #call the aero model
    results = aerodynamics.evaluate(state)

    #build a polar for the markup aero
    polar = Data()
    CL = results.lift.total
    CD = results.drag.total
    polar.lift = CL
    polar.drag = CD

    # --------------------------------------------------------------------
    # Test compute Lift
    # --------------------------------------------------------------------

    #compute_aircraft_lift(conditions, configuration, geometry)

    lift = state.conditions.aerodynamics.lift_coefficient

    # Truth value
    lift_r = np.array([
        -2.42489437, -0.90696416, -0.53991953, -0.3044834, -0.03710598,
        0.31061936, 0.52106899, 0.77407765, 1.22389024, 1.86240501, 1.54587835
    ])[:, None]
    lift_r = lift_r.reshape(test_num, 1)

    lift_test = np.abs((lift - lift_r) / lift)

    print '\nCompute Lift Test Results\n'
    print lift_test

    assert (np.max(lift_test) <
            1e-4), 'Supersonic Aero regression failed at compute lift test'

    # --------------------------------------------------------------------
    # Test compute drag
    # --------------------------------------------------------------------

    #compute_aircraft_drag(conditions, configuration, geometry)

    # Pull calculated values
    drag_breakdown = state.conditions.aerodynamics.drag_breakdown

    # Only one wing is evaluated since they rely on the same function
    cd_c = drag_breakdown.compressible['main_wing'].compressibility_drag
    cd_i = drag_breakdown.induced.total
    cd_m = drag_breakdown.miscellaneous.total
    cd_m_fuse_base = drag_breakdown.miscellaneous.fuselage_base
    cd_m_fuse_up = drag_breakdown.miscellaneous.fuselage_upsweep
    cd_m_nac_base = drag_breakdown.miscellaneous.nacelle_base['turbo_fan']
    cd_m_ctrl = drag_breakdown.miscellaneous.control_gaps
    cd_p_fuse = drag_breakdown.parasite['fuselage'].parasite_drag_coefficient
    cd_p_wing = drag_breakdown.parasite['main_wing'].parasite_drag_coefficient
    cd_tot = drag_breakdown.total

    print cd_c
    print cd_i
    print cd_m
    print cd_m_fuse_base
    print cd_m_fuse_up
    print cd_m_nac_base
    print cd_m_ctrl
    print cd_p_fuse
    print cd_p_wing
    print cd_tot

    # Truth values
    (cd_c_r, cd_i_r, cd_m_r, cd_m_fuse_base_r, cd_m_fuse_up_r, cd_m_nac_base_r,
     cd_m_ctrl_r, cd_p_fuse_r, cd_p_wing_r, cd_tot_r) = reg_values()

    cd_c_r = cd_c_r.reshape(test_num, 1)
    cd_i_r = cd_i_r.reshape(test_num, 1)
    cd_m_r = cd_m_r.reshape(test_num, 1)
    cd_m_fuse_base_r = cd_m_fuse_base_r.reshape(test_num, 1)
    cd_m_fuse_up_r = cd_m_fuse_up_r.reshape(test_num, 1)
    cd_m_nac_base_r = cd_m_nac_base_r.reshape(test_num, 1)
    cd_m_ctrl_r = cd_m_ctrl_r.reshape(test_num, 1)
    cd_p_fuse_r = cd_p_fuse_r.reshape(test_num, 1)
    cd_p_wing_r = cd_p_wing_r.reshape(test_num, 1)
    cd_tot_r = cd_tot_r.reshape(test_num, 1)

    drag_tests = Data()
    drag_tests.cd_c = np.abs((cd_c - cd_c_r) / cd_c)
    drag_tests.cd_i = np.abs((cd_i - cd_i_r) / cd_i)
    drag_tests.cd_m = np.abs((cd_m - cd_m_r) / cd_m)
    # Line below is not normalized since regression values are 0, insert commented line if this changes
    drag_tests.cd_m_fuse_base = np.abs(
        (cd_m_fuse_base - cd_m_fuse_base_r
         ))  # np.abs((cd_m_fuse_base-cd_m_fuse_base_r)/cd_m_fuse_base)
    drag_tests.cd_m_fuse_up = np.abs(
        (cd_m_fuse_up - cd_m_fuse_up_r) / cd_m_fuse_up)
    drag_tests.cd_m_ctrl = np.abs((cd_m_ctrl - cd_m_ctrl_r) / cd_m_ctrl)
    drag_tests.cd_p_fuse = np.abs((cd_p_fuse - cd_p_fuse_r) / cd_p_fuse)
    drag_tests.cd_p_wing = np.abs((cd_p_wing - cd_p_wing_r) / cd_p_wing)
    drag_tests.cd_tot = np.abs((cd_tot - cd_tot_r) / cd_tot)

    print '\nCompute Drag Test Results\n'
    #print drag_tests

    for i, tests in drag_tests.items():
        assert (np.max(tests) <
                1e-4), 'Supersonic Aero regression test failed at ' + i
Example #38
0
def simple_sizing(nexus):
    configs    = nexus.vehicle_configurations
    analyses   = nexus.analyses
    base       = configs.base

    
    
    m_guess                            = nexus.m_guess #take in sizing inputs
    base.mass_properties.max_takeoff   = m_guess
 
    #find conditions
    air_speed   = nexus.missions.base.segments['cruise'].air_speed 
    altitude    = nexus.missions.base.segments['climb_3'].altitude_end
    atmosphere  = SUAVE.Analyses.Atmospheric.US_Standard_1976()
    freestream  = atmosphere.compute_values(altitude)
    freestream0 = atmosphere.compute_values(6000.*Units.ft)  #cabin altitude
    
    
    diff_pressure                  = np.max(freestream0.pressure-freestream.pressure,0)
    fuselage                       = base.fuselages['fuselage']
    fuselage.differential_pressure = diff_pressure 
    
    #now size engine
    mach_number        = air_speed/freestream.speed_of_sound
    
    #now add to freestream data object
    freestream.velocity    = air_speed
    freestream.mach_number = mach_number
    freestream.gravity     = 9.81
    
    conditions             = SUAVE.Analyses.Mission.Segments.Conditions.Aerodynamics()   #assign conditions in form for propulsor sizing
    conditions.freestream  = freestream
    
    nose_load_fraction     = .06
   
    #now evaluate all of the vehicle configurations
    for config in configs:
        config.wings.horizontal_stabilizer.areas.reference = (26.0/92.0)*config.wings.main_wing.areas.reference
         
         
        for wing in config.wings:
            
            wing = SUAVE.Methods.Geometry.Two_Dimensional.Planform.wing_planform(wing)
            
            wing.areas.exposed  = 0.8 * wing.areas.wetted
            wing.areas.affected = 0.6 * wing.areas.reference
            


        fuselage                       = config.fuselages['fuselage']
        fuselage.differential_pressure = diff_pressure 
     
        #now evaluate weights

        # diff the new data
        
        config.mass_properties.max_takeoff     = m_guess #take in parameters
        config.mass_properties.takeoff         = m_guess 
        config.mass_properties.max_zero_fuel   = base.mass_properties.max_zero_fuel
        config.store_diff()
       
       
    #now evaluate the weights   
    weights = analyses.base.weights.evaluate() #base.weights.evaluate()  
    #update zfw
    empty_weight       = base.mass_properties.operating_empty
    payload            = base.mass_properties.max_payload
    zfw                = empty_weight + payload 
    
    base.max_zero_fuel = zfw  
    base.store_diff()
    for config in configs:
        config.pull_base()
    # ------------------------------------------------------------------
    #   Landing Configuration
    # ------------------------------------------------------------------
    landing = nexus.vehicle_configurations.landing
    landing_conditions = Data()
    landing_conditions.freestream = Data()

    # landing weight
    landing.mass_properties.landing = base.mass_properties.max_zero_fuel
    
    # Landing CL_max
    altitude                                         = nexus.missions.base.segments[-1].altitude_end
    atmosphere                                       = SUAVE.Analyses.Atmospheric.US_Standard_1976()
    
    freestream             = atmosphere.compute_values(altitude)
    mu                     = freestream.dynamic_viscosity
    rho                    = freestream.density

    landing_conditions.freestream.velocity           = nexus.missions.base.segments['descent_3'].air_speed
    landing_conditions.freestream.density            = rho
    landing_conditions.freestream.dynamic_viscosity  = mu/rho
    CL_max_landing,CDi                               = compute_max_lift_coeff(landing,landing_conditions)
    landing.maximum_lift_coefficient                 = CL_max_landing
    # diff the new data
    landing.store_diff()
    
    
    #Takeoff CL_max
    takeoff                                          = nexus.vehicle_configurations.takeoff
    takeoff_conditions                               = Data()
    takeoff_conditions.freestream                    = Data()    
    altitude                                         = nexus.missions.base.airport.altitude
    atmosphere                                       = SUAVE.Analyses.Atmospheric.US_Standard_1976()
    freestream                                       = atmosphere.compute_values(altitude)
    mu                                               = freestream.dynamic_viscosity
    rho                                              = freestream.density
    takeoff_conditions.freestream.velocity           = nexus.missions.base.segments.climb_1.air_speed
    takeoff_conditions.freestream.density            = rho
    takeoff_conditions.freestream.dynamic_viscosity  = mu/rho 
    max_CL_takeoff,CDi                               = compute_max_lift_coeff(takeoff,takeoff_conditions) 
    takeoff.maximum_lift_coefficient                 = max_CL_takeoff
    
    takeoff.store_diff()
    
   

    #Base config CL_max
    base                                          = nexus.vehicle_configurations.base
    base_conditions                               = Data()
    base_conditions.freestream                    = Data()    
    altitude                                      = nexus.missions.base.airport.altitude
    atmosphere                                    = SUAVE.Analyses.Atmospheric.US_Standard_1976()
    freestream                                    = atmosphere.compute_values(altitude)
    mu                                            = freestream.dynamic_viscosity
    rho                                           = freestream.density
    
    
    
    base_conditions.freestream.velocity           = nexus.missions.base.segments.climb_1.air_speed
    base_conditions.freestream.density            = rho
    base_conditions.freestream.dynamic_viscosity  = mu/rho 
    max_CL_base,CDi                               = compute_max_lift_coeff(base,base_conditions) 
    base.maximum_lift_coefficient                 = max_CL_base    
    base.store_diff()
    
    # done!
    
    return nexus
Example #39
0
def simple_sizing(nexus):
    configs = nexus.vehicle_configurations
    base = configs.base

    #find conditions
    air_speed = nexus.missions.base.segments['cruise'].air_speed
    altitude = nexus.missions.base.segments['climb_5'].altitude_end
    atmosphere = SUAVE.Analyses.Atmospheric.US_Standard_1976()

    freestream = atmosphere.compute_values(altitude)
    freestream0 = atmosphere.compute_values(6000. * Units.ft)  #cabin altitude

    diff_pressure = np.max(freestream0.pressure - freestream.pressure, 0)
    fuselage = base.fuselages['fuselage']
    fuselage.differential_pressure = diff_pressure

    #now size engine
    mach_number = air_speed / freestream.speed_of_sound

    #now add to freestream data object
    freestream.velocity = air_speed
    freestream.mach_number = mach_number
    freestream.gravity = 9.81

    conditions = SUAVE.Analyses.Mission.Segments.Conditions.Aerodynamics(
    )  #assign conditions in form for propulsor sizing
    conditions.freestream = freestream

    for config in configs:
        config.wings.horizontal_stabilizer.areas.reference = (
            26.0 / 92.0) * config.wings.main_wing.areas.reference

        for wing in config.wings:

            wing = SUAVE.Methods.Geometry.Two_Dimensional.Planform.wing_planform(
                wing)
            wing.areas.exposed = 0.8 * wing.areas.wetted
            wing.areas.affected = 0.6 * wing.areas.reference

        fuselage = config.fuselages['fuselage']
        fuselage.differential_pressure = diff_pressure

        turbofan_sizing(config.propulsors['turbofan'],
                        mach_number=mach_number,
                        altitude=altitude)
        compute_turbofan_geometry(config.propulsors['turbofan'], conditions)

    # ------------------------------------------------------------------
    #   Landing Configuration
    # ------------------------------------------------------------------
    landing = nexus.vehicle_configurations.landing
    landing_conditions = Data()
    landing_conditions.freestream = Data()

    # landing weight
    landing.mass_properties.landing = 0.85 * config.mass_properties.takeoff

    # Landing CL_max
    altitude = nexus.missions.base.segments[-1].altitude_end
    atmosphere = SUAVE.Analyses.Atmospheric.US_Standard_1976()
    freestream_landing = atmosphere.compute_values(0.)
    landing_conditions.freestream.velocity = nexus.missions.base.segments[
        'descent_3'].air_speed
    landing_conditions.freestream.density = freestream_landing.density
    landing_conditions.freestream.dynamic_viscosity = freestream_landing.dynamic_viscosity
    CL_max_landing, CDi = compute_max_lift_coeff(landing, landing_conditions)
    landing.maximum_lift_coefficient = CL_max_landing

    #Takeoff CL_max
    takeoff = nexus.vehicle_configurations.takeoff
    takeoff_conditions = Data()
    takeoff_conditions.freestream = Data()
    altitude = nexus.missions.base.airport.altitude
    freestream_takeoff = atmosphere.compute_values(altitude)

    takeoff_conditions.freestream.velocity = nexus.missions.base.segments.climb_1.air_speed
    takeoff_conditions.freestream.density = freestream_takeoff.density
    takeoff_conditions.freestream.dynamic_viscosity = freestream_takeoff.dynamic_viscosity
    max_CL_takeoff, CDi = compute_max_lift_coeff(takeoff, takeoff_conditions)
    takeoff.maximum_lift_coefficient = max_CL_takeoff

    #Base config CL_max
    base = nexus.vehicle_configurations.base
    base_conditions = Data()
    base_conditions.freestream = takeoff_conditions.freestream
    max_CL_base, CDi = compute_max_lift_coeff(base, base_conditions)
    base.maximum_lift_coefficient = max_CL_base

    return nexus
Example #40
0
def check_cruise_altitude(analyses):
    # ------------------------------------------------------------------
    #   Initialize the Mission
    # ------------------------------------------------------------------

    mission = SUAVE.Analyses.Mission.Sequential_Segments()
    mission.tag = 'the_dummy_mission'

    # airport
    airport = SUAVE.Attributes.Airports.Airport()
    airport.altitude = 0.0 * Units.ft
    airport.delta_isa = 0.0
    airport.atmosphere = SUAVE.Analyses.Atmospheric.US_Standard_1976()

    mission.airport = airport

    # unpack Segments module
    Segments = SUAVE.Analyses.Mission.Segments

    # base segment
    base_segment = Segments.Segment()
    ones_row = base_segment.state.ones_row
    base_segment.process.iterate.initials.initialize_battery = SUAVE.Methods.Missions.Segments.Common.Energy.initialize_battery
    base_segment.process.iterate.conditions.planet_position = SUAVE.Methods.skip
    base_segment.process.iterate.unknowns.network = analyses.vehicle.propulsors.turboprop.unpack_unknowns
    base_segment.process.iterate.residuals.network = analyses.vehicle.propulsors.turboprop.residuals
    base_segment.state.unknowns.pitch_command = ones_row(1) * 0. * Units.deg
    base_segment.state.conditions.propulsion = Data()
    base_segment.state.conditions.propulsion.rpm = 1200 * ones_row(1)
    base_segment.state.residuals.net = 0. * ones_row(1)
    base_segment.state.numerics.number_control_points = 10
    base_segment.state.conditions.freestream = Data()
    base_segment.state.conditions.freestream.delta_ISA = airport.delta_isa * ones_row(1)
    base_segment.state.numerics.number_control_points = 20
    planet = SUAVE.Attributes.Planets.Earth()
    atmosphere = SUAVE.Attributes.Atmospheres.Earth.US_Standard_1976()
    # ------------------------------------------------------------------
    #   First Climb Segment: Constant Speed, Constant Rate
    # ------------------------------------------------------------------

    segment = Segments.Climb.Constant_EAS_Constant_Rate(base_segment)
    segment.tag = "climb_dummy"

    # connect vehicle configuration
    segment.analyses.extend(analyses.base)

    # define segment attributes
    segment.atmosphere = atmosphere
    segment.planet = planet

    segment.altitude_start       = 0.0      * Units.ft
    segment.altitude_end         = 21000.   * Units.ft
    segment.equivalent_air_speed = 168.2981 * Units.knots
    segment.climb_rate           = 300.     * Units['ft/min']
    segment.state.conditions.propulsion.gas_turbine_rating = 'MCL'
    # add to mission
    mission.append_segment(segment)

    results = mission.evaluate()

    cruise_altitude = 21000.
    for segment in results.segments.values():
        altitude = segment.conditions.freestream.altitude[:, 0] / Units.ft
        eta = segment.conditions.propulsion.throttle[:, 0]
        for i in range(len(altitude)):
            if eta[i] > 1.:
                cruise_altitude = altitude[i - 1]
            elif eta[i] < 1. and i == len(altitude) - 1:
                cruise_altitude = altitude[i]

    print ('Cruise altitude: ' + str(int((cruise_altitude+1)/100.)*100.)+' ft')
    cruise_altitude = int(cruise_altitude/100.)*100. * Units.ft

    return cruise_altitude
Example #41
0
def vehicle_setup():

    # ------------------------------------------------------------------
    #   Initialize the Vehicle
    # ------------------------------------------------------------------

    vehicle = SUAVE.Vehicle()
    vehicle.tag = 'Tecnam_P2006TElectric'

    # ------------------------------------------------------------------
    #   Vehicle-level Properties
    # ------------------------------------------------------------------

    # mass properties
    vehicle.mass_properties.max_takeoff = 1400 * Units.kilogram
    vehicle.mass_properties.takeoff = 1400 * Units.kilogram
    vehicle.mass_properties.operating_empty = 1000 * Units.kilogram
    vehicle.mass_properties.max_zero_fuel = 1400 * Units.kilogram
    vehicle.mass_properties.cargo = 80 * Units.kilogram

    # envelope properties
    vehicle.envelope.ultimate_load = 5.7
    vehicle.envelope.limit_load = 3.8

    # basic parameters
    vehicle.reference_area = 64.4 * Units['meters**2']
    vehicle.passengers = 4
    vehicle.systems.control = "fully powered"
    vehicle.systems.accessories = "medium range"

    # ------------------------------------------------------------------
    #  Landing Gear
    # ------------------------------------------------------------------
    # used for noise calculations
    landing_gear = SUAVE.Components.Landing_Gear.Landing_Gear()
    landing_gear.tag = "main_landing_gear"

    landing_gear.main_tire_diameter = 0.423 * Units.m
    landing_gear.nose_tire_diameter = 0.3625 * Units.m
    landing_gear.main_strut_length = 0.4833 * Units.m
    landing_gear.nose_strut_length = 0.3625 * Units.m
    landing_gear.main_units = 2  #number of main landing gear units
    landing_gear.nose_units = 1  #number of nose landing gear
    landing_gear.main_wheels = 1  #number of wheels on the main landing gear
    landing_gear.nose_wheels = 1  #number of wheels on the nose landing gear
    vehicle.landing_gear = landing_gear

    # ------------------------------------------------------------------
    #  Fuselage
    # ------------------------------------------------------------------

    fuselage = SUAVE.Components.Fuselages.Fuselage()
    fuselage.tag = 'fuselage'

    fuselage.number_coach_seats = vehicle.passengers
    fuselage.seats_abreast = 2
    fuselage.seat_pitch = 0.995 * Units.meter
    fuselage.fineness.nose = 1.27
    fuselage.fineness.tail = 1  #3.31
    fuselage.lengths.nose = 1.16 * Units.meter
    fuselage.lengths.tail = 4.637 * Units.meter
    fuselage.lengths.cabin = 2.653 * Units.meter
    fuselage.lengths.total = 8.45 * Units.meter
    fuselage.lengths.fore_space = 0.0 * Units.meter
    fuselage.lengths.aft_space = 0.0 * Units.meter
    fuselage.width = 1.22 * Units.meter
    fuselage.heights.maximum = 1.41 * Units.meter
    fuselage.effective_diameter = 2 * Units.meter
    fuselage.areas.side_projected = 7.46 * Units['meters**2']
    fuselage.areas.wetted = 25.0 * Units['meters**2']
    fuselage.areas.front_projected = 1.54 * Units['meters**2']
    fuselage.differential_pressure = 0.0 * Units.pascal  # Maximum differential pressure

    fuselage.heights.at_quarter_length = 1.077 * Units.meter
    fuselage.heights.at_three_quarters_length = 0.5 * Units.meter  #0.621 * Units.meter
    fuselage.heights.at_wing_root_quarter_chord = 1.41 * Units.meter

    # add to vehicle
    vehicle.append_component(fuselage)

    # ------------------------------------------------------------------
    #   Main Wing
    # ------------------------------------------------------------------

    wing = SUAVE.Components.Wings.Main_Wing()
    wing.tag = 'main_wing'

    wing.thickness_to_chord = 0.15
    wing.taper = 0.7016
    wing.spans.projected = 9.631680 * Units.meter
    wing.chords.root = 0.7559040 * Units.meter
    wing.chords.tip = wing.chords.root * wing.taper
    wing.chords.mean_aerodynamic = 0.6 * Units.meter
    wing.areas.reference = (wing.chords.root +
                            wing.chords.tip) * wing.spans.projected / 2
    wing.twists.root = 0. * Units.degrees
    wing.twists.tip = 0. * Units.degrees
    wing.dihedral = 1. * Units.degrees
    wing.origin = [2.986, 0, 1.077]  # meters
    wing.sweeps.leading_edge = 1.9 * Units.deg
    wing.aspect_ratio = (wing.spans.projected *
                         wing.spans.projected) / wing.areas.reference
    wing.span_efficiency = 0.99 * (
        1 - 0.0407 * (fuselage.width / wing.spans.projected) - 1.792 *
        ((fuselage.width / wing.spans.projected)**2))
    wing.vertical = False
    wing.symmetric = True
    wing.high_lift = True
    wing.dynamic_pressure_ratio = 1.0

    # ------------------------------------------------------------------
    #   Flaps
    # ------------------------------------------------------------------

    wing.flaps.chord = 0.20
    wing.flaps.span_start = 0.1053
    wing.flaps.span_end = 0.6842
    wing.flaps.type = 'single_slotted'

    # add to vehicle
    vehicle.append_component(wing)

    # ------------------------------------------------------------------
    #  Horizontal Stabilizer
    # ------------------------------------------------------------------

    wing = SUAVE.Components.Wings.Wing()
    wing.tag = 'horizontal_stabilizer'

    wing.aspect_ratio = 4.193
    wing.sweeps.quarter_chord = 0.0 * Units.deg
    wing.thickness_to_chord = 0.12
    wing.taper = 1.0
    wing.span_efficiency = 0.733
    wing.spans.projected = 3.3 * Units.meter
    wing.chords.root = 0.787 * Units.meter
    wing.chords.tip = 0.787 * Units.meter
    wing.chords.mean_aerodynamic = (wing.chords.root * (2.0 / 3.0) *
                                    ((1.0 + wing.taper + wing.taper**2.0) /
                                     (1.0 + wing.taper))) * Units.meter
    wing.areas.reference = 2.5971 * Units['meters**2']
    wing.areas.exposed = 4.0 * Units['meters**2']
    wing.areas.wetted = 4.0 * Units['meters**2']
    wing.twists.root = 0.0 * Units.degrees
    wing.twists.tip = 0.0 * Units.degrees
    wing.origin = [7.789, 0.0, 0.3314]  # meters
    wing.vertical = False
    wing.symmetric = True
    wing.dynamic_pressure_ratio = 0.9

    # add to vehicle
    vehicle.append_component(wing)

    # ------------------------------------------------------------------
    #   Vertical Stabilizer
    # ------------------------------------------------------------------

    wing = SUAVE.Components.Wings.Wing()
    wing.tag = 'vertical_stabilizer'

    wing.aspect_ratio = 1.407
    wing.sweeps.quarter_chord = 38.75 * Units.deg
    wing.thickness_to_chord = 0.12
    wing.taper = 1.0
    wing.span_efficiency = -0.107
    wing.spans.projected = 1.574 * Units.meter
    wing.chords.root = 1.2 * Units.meter
    wing.chords.tip = 0.497 * Units.meter
    wing.chords.mean_aerodynamic = (wing.chords.root * (2.0 / 3.0) *
                                    ((1.0 + wing.taper + wing.taper**2.0) /
                                     (1.0 + wing.taper))) * Units.meter
    wing.areas.reference = 1.761 * Units['meters**2']
    wing.twists.root = 0.0 * Units.degrees
    wing.twists.tip = 0.0 * Units.degrees
    wing.origin = [7.25, 0, 0.497]  # meters
    wing.vertical = True
    wing.symmetric = False
    wing.t_tail = False
    wing.dynamic_pressure_ratio = 1.0

    # add to vehicle
    vehicle.append_component(wing)

    # ------------------------------------------------------------------
    #  Propellers Powered By Batteries
    # ------------------------------------------------------------------

    # build network
    net = SUAVE.Components.Energy.Networks.Lift_Forward_Propulsor_Network_Lo_Fi(
    )

    net.nacelle_diameter_lift = 0.08 * Units.meters
    net.nacelle_diameter_forward = 0.1732 * Units.meters
    net.engine_length_lift = 0.47244 * Units.meters
    net.engine_length_forward = 1.2 * Units.meters
    net.number_of_engines_lift = 12
    net.number_of_engines_forward = 2
    net.thrust_angle_lift = 0.0 * Units.degrees
    net.thrust_angle_forward = 0.0 * Units.degrees
    net.voltage = 461.
    net.areas_forward = Data()
    net.areas_forward.wetted = 1.1 * np.pi * net.nacelle_diameter_forward * net.engine_length_forward
    net.areas_lift = Data()
    net.areas_lift.wetted = 1.1 * np.pi * net.nacelle_diameter_forward * net.engine_length_lift

    # Component 1 - Tip ESC
    esc = SUAVE.Components.Energy.Distributors.Electronic_Speed_Controller()
    esc.efficiency = 0.95  # Gundlach for brushless motors
    net.esc_forward = esc

    # Component 1 - High Lift ESC
    esc = SUAVE.Components.Energy.Distributors.Electronic_Speed_Controller()
    esc.efficiency = 0.95  # Gundlach for brushless motors
    net.esc_lift = esc

    # Component 2 Tip Propeller
    prop = SUAVE.Components.Energy.Converters.Propeller_Lo_Fid()
    prop.propulsive_efficiency = 0.95
    prop.tip_radius = 0.762 * Units.meter
    net.propeller_forward = prop

    # Component 2 High Lift Propeller
    prop = SUAVE.Components.Energy.Converters.Propeller_Lo_Fid()
    prop.propulsive_efficiency = 0.95
    prop.tip_radius = 0.2880360 * Units.meter
    net.propeller_lift = prop

    # Component 3 Tip Motor
    motor = SUAVE.Components.Energy.Converters.Motor_Lo_Fid()
    kv = 300. * Units['rpm/volt']  # RPM/volt is standard
    motor.expected_current = 1000.0
    motor = size_from_kv(motor, kv)
    motor.gear_ratio = 1.  # Gear ratio, no gearbox
    motor.gearbox_efficiency = 1.  # Gear box efficiency, no gearbox
    motor.motor_efficiency = 0.95
    net.motor_forward = motor

    # Component 3 High Lift Motor
    motor = SUAVE.Components.Energy.Converters.Motor_Lo_Fid()
    kv = 3691. * Units['rpm/volt']  # RPM/volt is standard
    motor.expected_current = 1000.0
    motor = size_from_kv(motor, kv)
    motor.gear_ratio = 1.  # Gear ratio, no gearbox
    motor.gearbox_efficiency = 1.  # Gear box efficiency, no gearbox
    motor.motor_efficiency = 0.95
    net.motor_lift = motor

    # Component 4 - the Payload
    payload = SUAVE.Components.Energy.Peripherals.Payload()
    payload.power_draw = 50. * Units.watts
    payload.mass_properties.mass = 5.0 * Units.kg
    net.payload = payload

    # Component 5 - the Avionics
    avionics = SUAVE.Components.Energy.Peripherals.Avionics()
    avionics.power_draw = 50. * Units.watts
    net.avionics = avionics

    # Component 6 - the Battery
    bat = SUAVE.Components.Energy.Storages.Batteries.Constant_Mass.Lithium_Ion(
    )
    bat.mass_properties.mass = 358.33 * Units.kg
    bat.specific_energy = 192.84 * Units.Wh / Units.kg
    bat.specific_power = 0.837 * Units.kW / Units.kg
    bat.resistance = 0.0153
    bat.max_voltage = 11.078
    initialize_from_mass(bat, bat.mass_properties.mass)
    net.battery = bat

    # ------------------------------------------------------------------
    #   Vehicle Definition Complete
    # ------------------------------------------------------------------

    # add the energy network to the vehicle
    vehicle.append_component(net)

    #print vehicle

    return vehicle
Example #42
0
def simulation_settings(vehicle):

    # grid conditions for downstream propeller
    grid_settings = Data()
    grid_settings.radius = vehicle.networks.prop_net.propeller.tip_radius
    grid_settings.hub_radius = vehicle.networks.prop_net.propeller.hub_radius
    grid_settings.Nr = 40
    grid_settings.Na = 40

    # cartesian grid specs
    grid_settings.Ny = 50
    grid_settings.Nz = 50
    grid_settings.grid_mode = 'cartesian'

    VLM_settings = Data()
    VLM_settings.number_spanwise_vortices = 10
    VLM_settings.number_chordwise_vortices = 4
    VLM_settings.use_surrogate = True
    VLM_settings.propeller_wake_model = False
    VLM_settings.model_fuselage = False
    VLM_settings.spanwise_cosine_spacing = True
    VLM_settings.number_of_wake_timesteps = 0.
    VLM_settings.leading_edge_suction_multiplier = 1.
    VLM_settings.initial_timestep_offset = 0.
    VLM_settings.wake_development_time = 0.5

    return grid_settings, VLM_settings
Example #43
0
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 = shevell(weight_landing, number_of_engines, thrust_sea_level,
                    thrust_landing)

    actual = Data()
    actual.takeoff = 99.982372547196633
    actual.side_line = 97.482372547196633
    actual.landing = 105.69577388532885

    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 list(error.items()):
        assert (np.abs(v) < 1e-6)

    return
Example #44
0
def vehicle_setup():

    # ------------------------------------------------------------------
    #   Initialize the Vehicle
    # ------------------------------------------------------------------

    vehicle = SUAVE.Vehicle()
    vehicle.tag = 'Tecnam_P2006TElectric'

    # ------------------------------------------------------------------
    #   Vehicle-level Properties
    # ------------------------------------------------------------------

    # mass properties
    vehicle.mass_properties.max_takeoff = 1400 * Units.kilogram
    vehicle.mass_properties.takeoff = 1400 * Units.kilogram
    vehicle.mass_properties.operating_empty = 1000 * Units.kilogram
    vehicle.mass_properties.max_zero_fuel = 1400 * Units.kilogram
    vehicle.mass_properties.cargo = 80 * Units.kilogram

    # envelope properties
    vehicle.envelope.ultimate_load = 5.7
    vehicle.envelope.limit_load = 3.8

    # basic parameters
    vehicle.reference_area = 64.4 * Units['meters**2']
    vehicle.passengers = 4
    vehicle.systems.control = "fully powered"
    vehicle.systems.accessories = "medium range"

    # ------------------------------------------------------------------
    #  Landing Gear
    # ------------------------------------------------------------------
    # used for noise calculations
    #landing_gear = SUAVE.Components.Landing_Gear.Landing_Gear()
    #landing_gear.tag = "main_landing_gear"

    #landing_gear.main_tire_diameter = 0.423 * Units.m
    #landing_gear.nose_tire_diameter = 0.3625 * Units.m
    #landing_gear.main_strut_length  = 0.4833 * Units.m
    #landing_gear.nose_strut_length  = 0.3625 * Units.m
    #landing_gear.main_units  = 2    #number of main landing gear units
    #landing_gear.nose_units  = 1    #number of nose landing gear
    #landing_gear.main_wheels = 1    #number of wheels on the main landing gear
    #landing_gear.nose_wheels = 1    #number of wheels on the nose landing gear
    #vehicle.landing_gear = landing_gear

    # ------------------------------------------------------------------
    #  Fuselage
    # ------------------------------------------------------------------

    fuselage = SUAVE.Components.Fuselages.Fuselage()
    fuselage.tag = 'fuselage'
    aux = time.time()
    fuselage.time = aux

    fuselage.number_coach_seats = vehicle.passengers
    fuselage.seats_abreast = 2
    fuselage.seat_pitch = 0.995 * Units.meter
    fuselage.fineness.nose = 1.27
    fuselage.fineness.tail = 1  #3.31
    fuselage.lengths.nose = 1.16 * Units.meter
    fuselage.lengths.tail = 4.637 * Units.meter
    fuselage.lengths.cabin = 2.653 * Units.meter
    fuselage.lengths.total = 8.45 * Units.meter
    fuselage.lengths.fore_space = 0.0 * Units.meter
    fuselage.lengths.aft_space = 0.0 * Units.meter
    fuselage.width = 1.1 * Units.meter  #1.22
    fuselage.heights.maximum = 1.41 * Units.meter
    fuselage.effective_diameter = 2 * Units.meter
    fuselage.areas.side_projected = 7.46 * Units['meters**2']
    fuselage.areas.wetted = 25.0 * Units['meters**2']
    fuselage.areas.front_projected = 1.54 * Units['meters**2']
    fuselage.differential_pressure = 10**5 * Units.pascal  # Maximum differential pressure

    fuselage.heights.at_quarter_length = 1.077 * Units.meter
    fuselage.heights.at_three_quarters_length = 0.5 * Units.meter  #0.621 * Units.meter
    fuselage.heights.at_wing_root_quarter_chord = 1.41 * Units.meter

    ## OpenVSP Design

    fuselage.OpenVSP_values = Data()  # VSP uses degrees directly

    #MidFuselage1 Section

    fuselage.OpenVSP_values.midfus1 = Data()
    fuselage.OpenVSP_values.midfus1.z_pos = 0.03

    #MidFuselage2 Section

    fuselage.OpenVSP_values.midfus2 = Data()
    fuselage.OpenVSP_values.midfus2.z_pos = 0.06

    #MidFuselage3 Section

    fuselage.OpenVSP_values.midfus3 = Data()
    fuselage.OpenVSP_values.midfus3.z_pos = 0.04

    #Tail Section

    fuselage.OpenVSP_values.tail = Data()
    fuselage.OpenVSP_values.tail.bottom = Data()
    fuselage.OpenVSP_values.tail.z_pos = 0.039
    fuselage.OpenVSP_values.tail.bottom.angle = -20.0
    fuselage.OpenVSP_values.tail.bottom.strength = 1

    # add to vehicle
    vehicle.append_component(fuselage)

    # ------------------------------------------------------------------
    #   Main Wing
    # ------------------------------------------------------------------

    wing = SUAVE.Components.Wings.Main_Wing()
    wing.tag = 'main_wing'

    wing.thickness_to_chord = 0.15
    wing.taper = 0.9
    wing.spans.projected = 9.4 * Units.meter
    wing.chords.root = 2. * Units.meter
    wing.chords.tip = wing.chords.root * wing.taper
    wing.chords.mean_aerodynamic = (wing.chords.root * (2.0 / 3.0) *
                                    ((1.0 + wing.taper + wing.taper**2.0) /
                                     (1.0 + wing.taper)))
    wing.areas.reference = (wing.chords.root +
                            wing.chords.tip) * wing.spans.projected / 2
    print wing.areas.reference
    basearea = wing.areas.reference
    wing.areas.wetted = 2.0 * wing.areas.reference
    wing.areas.exposed = wing.areas.wetted
    wing.areas.affected = wing.areas.wetted
    wing.twists.root = 0. * Units.degrees
    wing.twists.tip = 0. * Units.degrees
    wing.dihedral = 1. * Units.degrees
    wing.origin = [2.986, 0, 1.077]  # meters
    wing.sweeps.leading_edge = 1.9 * Units.deg
    wing.aspect_ratio = (wing.spans.projected *
                         wing.spans.projected) / wing.areas.reference
    wing.span_efficiency = 0.95
    wing.vertical = False
    wing.symmetric = True
    wing.high_lift = True
    wing.dynamic_pressure_ratio = 1.0

    ## Wing Segments

    # Root Segment

    #segment = SUAVE.Components.Wings.Segment()

    #segment.tag                   = 'root'
    #segment.percent_span_location = 0.0
    #segment.twist                 = 0. * Units.deg
    #segment.root_chord_percent    = 1.
    #segment.dihedral_outboard     = 1. * Units.degrees
    #segment.sweeps.quarter_chord  = 0. * Units.degrees
    #segment.thickness_to_chord    = 0.15

    #airfoil = SUAVE.Components.Wings.Airfoils.Airfoil()
    #airfoil.coordinate_file       = '/Users/Bruno/Documents/Delft/Courses/2016-2017/Thesis/Code/Airfoils/naca642415.dat'

    #segment.append_airfoil(airfoil)
    #wing.Segments.append(segment)

    # Tip Segment

    #segment = SUAVE.Components.Wings.Segment()

    #segment.tag                   = 'tip'
    #segment.percent_span_location = 1.0
    #segment.twist                 = 0. * Units.deg
    #segment.root_chord_percent    = 1.
    #segment.dihedral_outboard     = 1. * Units.degrees
    #segment.sweeps.quarter_chord  = 0. * Units.degrees
    #segment.thickness_to_chord    = 0.15

    #airfoil = SUAVE.Components.Wings.Airfoils.Airfoil()
    #airfoil.coordinate_file       = '/Users/Bruno/Documents/Delft/Courses/2016-2017/Thesis/Code/Airfoils/naca642415.dat'

    #segment.append_airfoil(airfoil)
    #wing.Segments.append(segment)

    # ------------------------------------------------------------------
    #   Flaps
    # ------------------------------------------------------------------

    wing.flaps.chord = wing.chords.root * 0.15
    wing.flaps.span_start = 0.3 * wing.spans.projected
    wing.flaps.span_end = 0.8 * wing.spans.projected
    wing.flaps.area = wing.flaps.chord * (wing.flaps.span_end -
                                          wing.flaps.span_start)
    wing.flaps.type = 'single_slotted'

    # add to vehicle
    vehicle.append_component(wing)

    # ------------------------------------------------------------------
    #  Horizontal Stabilizer
    # ------------------------------------------------------------------

    wing = SUAVE.Components.Wings.Wing()
    wing.tag = 'horizontal_stabilizer'

    wing.aspect_ratio = 4.193
    wing.areas.reference = 0.145 * basearea
    wing.sweeps.quarter_chord = 0.0 * Units.deg
    wing.thickness_to_chord = 0.12
    wing.taper = 1.0
    wing.span_efficiency = 0.97
    wing.spans.projected = np.sqrt(wing.aspect_ratio * wing.areas.reference)
    wing.chords.root = wing.areas.reference / wing.spans.projected
    wing.chords.tip = wing.chords.root
    wing.chords.mean_aerodynamic = (wing.chords.root * (2.0 / 3.0) *
                                    ((1.0 + wing.taper + wing.taper**2.0) /
                                     (1.0 + wing.taper)))
    wing.areas.wetted = 2.0 * wing.areas.reference
    wing.areas.exposed = wing.areas.wetted
    wing.areas.affected = wing.areas.wetted
    wing.twists.root = 0.0 * Units.degrees
    wing.twists.tip = 0.0 * Units.degrees
    wing.origin = [7.789, 0.0, 0.3314]  # meters
    wing.vertical = False
    wing.symmetric = True
    wing.dynamic_pressure_ratio = 0.9

    # add to vehicle
    vehicle.append_component(wing)

    # ------------------------------------------------------------------
    #   Vertical Stabilizer
    # ------------------------------------------------------------------

    wing = SUAVE.Components.Wings.Wing()
    wing.tag = 'vertical_stabilizer'

    wing.areas.reference = 0.099 * basearea
    wing.areas.wetted = 2.0 * wing.areas.reference
    wing.areas.exposed = wing.areas.wetted
    wing.areas.affected = wing.areas.wetted
    wing.aspect_ratio = 1.407
    wing.sweeps.quarter_chord = 38.75 * Units.deg
    wing.thickness_to_chord = 0.12
    wing.taper = 0.4142
    wing.span_efficiency = 0.97
    wing.spans.projected = np.sqrt(wing.aspect_ratio * wing.areas.reference)
    wing.chords.root = (2.0 * wing.areas.reference) / (wing.spans.projected *
                                                       (1 + wing.taper))
    wing.chords.tip = wing.chords.root * wing.taper
    wing.chords.mean_aerodynamic = (wing.chords.root * (2.0 / 3.0) *
                                    ((1.0 + wing.taper + wing.taper**2.0) /
                                     (1.0 + wing.taper)))
    wing.twists.root = 0.0 * Units.degrees
    wing.twists.tip = 0.0 * Units.degrees
    wing.origin = [7.25, 0, 0.497]  # meters
    wing.vertical = True
    wing.symmetric = False
    wing.t_tail = False
    wing.dynamic_pressure_ratio = 1.0

    # add to vehicle
    vehicle.append_component(wing)

    # ------------------------------------------------------------------
    #  Propellers Powered By Batteries
    # ------------------------------------------------------------------

    # build network
    net = SUAVE.Components.Energy.Networks.Lift_Forward_Propulsor()

    net.nacelle_diameter_lift = 0.08 * Units.meters
    net.nacelle_diameter_forward = 0.1732 * Units.meters
    net.engine_length_lift = 0.47244 * Units.meters
    net.engine_length_forward = 1.2 * Units.meters
    net.number_of_engines_lift = 14
    net.number_of_engines_forward = 2
    net.thrust_angle_lift = 0.0 * Units.degrees
    net.thrust_angle_forward = 0.0 * Units.degrees
    net.voltage = 461. * Units['volt']  #461.
    net.areas_forward = Data()
    net.areas_forward.wetted = 1.1 * np.pi * net.nacelle_diameter_forward * net.engine_length_forward
    net.areas_lift = Data()
    net.areas_lift.wetted = 1.1 * np.pi * net.nacelle_diameter_forward * net.engine_length_lift
    net.number_of_engines = 1
    net.nacelle_diameter = net.nacelle_diameter_forward
    net.areas = Data()
    net.areas.wetted = net.areas_lift.wetted
    net.engine_length = 1.

    # Component 1 - Tip ESC
    esc = SUAVE.Components.Energy.Distributors.Electronic_Speed_Controller()
    esc.efficiency = 0.95  # Gundlach for brushless motors
    net.esc_forward = esc

    # Component 1 - High Lift ESC
    esc = SUAVE.Components.Energy.Distributors.Electronic_Speed_Controller()
    esc.efficiency = 0.95  # Gundlach for brushless motors
    net.esc_lift = esc

    # Component 2 - Tip Propeller

    # Design the Propeller
    #prop_attributes = Data()

    #prop_attributes                     = propeller_design(prop_attributes)

    prop_forward = SUAVE.Components.Energy.Converters.Propeller()
    prop_forward.number_blades = 3.0
    prop_forward.propulsive_efficiency = 0.85
    prop_forward.freestream_velocity = 50.0 * Units['m/s']  # freestream m/s
    prop_forward.angular_velocity = 27500. * Units['rpm']  # For 20x10 prop
    prop_forward.tip_radius = 0.5 * Units.meter
    prop_forward.hub_radius = 0.085 * Units.meter
    prop_forward.design_Cl = 0.8
    prop_forward.design_altitude = 14.0 * Units.km
    prop_forward.design_thrust = 0.0 * Units.newton
    prop_forward.design_power = 60000. * Units.watts

    prop_forward = propeller_design(prop_forward)
    net.propeller_forward = prop_forward

    # Component 2 - High Lift Propeller

    # Design the Propeller
    #prop_attributes = Data()

    prop_lift = SUAVE.Components.Energy.Converters.Propeller()
    prop_lift.number_blades = 5.0
    prop_lift.propulsive_efficiency = 0.85
    prop_lift.freestream_velocity = 1. * Units['m/s']  # freestream m/s
    prop_lift.angular_velocity = 2750 * Units['rpm']  # For 20x10 prop
    prop_lift.tip_radius = 0.26 * Units.meter  #0.2880360
    prop_lift.hub_radius = 0.07772400 * Units.meter
    prop_lift.design_Cl = 0.8
    prop_lift.design_altitude = 0.0 * Units.meter
    prop_lift.design_thrust = 0.0 * Units.newton
    prop_lift.design_power = 10500. * Units.watts
    prop_lift = propeller_design(prop_lift)

    net.propeller_lift = prop_lift

    # Component 3 - Tip Motor

    motor = SUAVE.Components.Energy.Converters.Motor_Lo_Fid()
    #motor.resistance           = 1.
    #motor.no_load_current      = 7.  * Units.ampere
    #motor.speed_constant       = 11.9999 * Units['rpm/volt'] # RPM/volt converted to (rad/s)/volt
    #motor.propeller_radius     = prop_forward.tip_radius
    #motor.propeller_Cp         = prop_forward.Cp[0]
    #motor.gear_ratio           = 12. # Gear ratio
    #motor.gearbox_efficiency   = .98 # Gear box efficiency
    #motor.expected_current     = 160. # Expected current
    #motor.mass_properties.mass = 9.0  * Units.kg
    #net.motor_forward          = motor

    kv = 180. * Units['rpm/volt']  # RPM/volt is standard
    #motor.speed_constant       = 0.0
    motor = size_from_kv(motor, kv)
    motor.gear_ratio = 1.  # Gear ratio, no gearbox
    motor.gearbox_efficiency = .98  # Gear box efficiency, no gearbox
    motor.motor_efficiency = 0.825
    net.motor_forward = motor

    # Component 3 - High Lift Motor

    motor = SUAVE.Components.Energy.Converters.Motor_Lo_Fid()
    #motor.resistance           = 0.008
    #motor.no_load_current      = 4.5  * Units.ampere
    #motor.speed_constant       = 5800. * Units['rpm/volt'] # RPM/volt converted to (rad/s)/volt
    #motor.propeller_radius     = prop_lift.tip_radius
    #motor.propeller_Cp         = prop_lift.Cp[0]
    #motor.gear_ratio           = 12. # Gear ratio
    #motor.gearbox_efficiency   = .98 # Gear box efficiency
    #motor.expected_current     = 25. # Expected current
    #motor.mass_properties.mass = 6.0  * Units.kg
    #net.motor_lift             = motor

    kv = 90. * Units['rpm/volt']  # RPM/volt is standard
    #motor.speed_constant       = 0.0
    motor = size_from_kv(motor, kv)
    motor.gear_ratio = 1.  # Gear ratio, no gearbox
    motor.gearbox_efficiency = .98  # Gear box efficiency, no gearbox
    motor.motor_efficiency = 0.825
    net.motor_lift = motor

    # Component 4 - the Payload
    payload = SUAVE.Components.Energy.Peripherals.Payload()
    payload.power_draw = 50. * Units.watts
    payload.mass_properties.mass = 5.0 * Units.kg
    net.payload = payload

    # Component 5 - the Avionics
    avionics = SUAVE.Components.Energy.Peripherals.Avionics()
    avionics.power_draw = 50. * Units.watts
    net.avionics = avionics

    # Component 6 - the Battery
    bat = SUAVE.Components.Energy.Storages.Batteries.Constant_Mass.Lithium_Ion(
    )
    bat.mass_properties.mass = 386.0 * Units.kg
    bat.specific_energy = 121.8 * Units.Wh / Units.kg  #192.84
    bat.specific_power = 0.312 * Units.kW / Units.kg  #0.837
    bat.resistance = 0.32
    bat.max_voltage = 538. * Units['volt']  #10000.
    initialize_from_mass(bat, bat.mass_properties.mass)
    print bat.max_energy
    net.battery = bat

    # ------------------------------------------------------------------
    #   Vehicle Definition Complete
    # ------------------------------------------------------------------

    # add the energy network to the vehicle
    vehicle.append_component(net)

    #now add weights objects
    vehicle.landing_gear = SUAVE.Components.Landing_Gear.Landing_Gear()
    vehicle.control_systems = SUAVE.Components.Physical_Component()
    vehicle.electrical_systems = SUAVE.Components.Physical_Component()
    vehicle.avionics = SUAVE.Components.Energy.Peripherals.Avionics()
    vehicle.passenger_weights = SUAVE.Components.Physical_Component()
    #vehicle.furnishings        = SUAVE.Components.Physical_Component()
    #vehicle.apu                = SUAVE.Components.Physical_Component()
    #vehicle.hydraulics         = SUAVE.Components.Physical_Component()
    vehicle.optionals = SUAVE.Components.Physical_Component()

    vehicle.wings[
        'vertical_stabilizer'].rudder = SUAVE.Components.Physical_Component()

    #print vehicle

    return vehicle
Example #45
0
 def __defaults__(self):
     self.tag = 'structures'
     self.features = Data()
     self.settings = Data()
    def evaluate_thrust(self, state):
        """ Calculate thrust given the current state of the vehicle
    
            Assumptions:
            None
    
            Source:
            N/A
    
            Inputs:
            state [state()]
    
            Outputs:
            results.thrust_force_vector [newtons]
            results.vehicle_mass_rate   [kg/s]
            conditions.propulsion.primary_battery_draw     [watts]
            conditions.propulsion.primary_battery_energy   [joules]
            conditions.propulsion.auxiliary_battery_draw   [watts]
            conditions.propulsion.auxiliary_battery_energy [joules]
    
            Properties Used:
            Defaulted values
        """

        # unpack

        propulsor = self.propulsor
        primary_battery = self.primary_battery
        auxiliary_battery = self.auxiliary_battery
        conditions = state.conditions
        numerics = state.numerics

        results = propulsor.evaluate_thrust(state)

        Pe = results.power

        try:
            initial_energy = conditions.propulsion.primary_battery_energy
            initial_energy_auxiliary = conditions.propulsion.auxiliary_battery_energy
            if initial_energy[0][
                    0] == 0:  #beginning of segment; initialize battery
                primary_battery.current_energy = primary_battery.current_energy[
                    -1] * np.ones_like(initial_energy)
                auxiliary_battery.current_energy = auxiliary_battery.current_energy[
                    -1] * np.ones_like(initial_energy)
        except AttributeError:  #battery energy not initialized, e.g. in takeoff
            primary_battery.current_energy = np.transpose(
                np.array(
                    [primary_battery.current_energy[-1] * np.ones_like(Pe)]))
            auxiliary_battery.current_energy = np.transpose(
                np.array(
                    [auxiliary_battery.current_energy[-1] * np.ones_like(Pe)]))

        pbat = -Pe / self.motor_efficiency
        pbat_primary = copy.copy(pbat)  #prevent deep copy nonsense
        pbat_auxiliary = np.zeros_like(pbat)
        #print 'pbat=', pbat/10**6.
        #print 'max_power prim=', primary_battery.max_power/10**6.
        #print 'max_power aux=', auxiliary_battery.max_power/10**6.
        for i in range(len(pbat)):
            if pbat[i] < -primary_battery.max_power:  #limit power output of primary_battery
                pbat_primary[
                    i] = -primary_battery.max_power  #-power means discharge
                pbat_auxiliary[i] = pbat[i] - pbat_primary[i]
            elif pbat[
                    i] > primary_battery.max_power:  #limit charging rate of battery
                pbat_primary[i] = primary_battery.max_power
                pbat_auxiliary[i] = pbat[i] - pbat_primary[i]
            if pbat_primary[
                    i] > 0:  #don't allow non-rechargable battery to charge
                pbat_primary[i] = 0
                pbat_auxiliary[i] = pbat[i]

        primary_battery_logic = Data()
        primary_battery_logic.power_in = pbat_primary
        primary_battery_logic.current = 90.  #use 90 amps as a default for now; will change this for higher fidelity methods
        auxiliary_battery_logic = copy.copy(primary_battery_logic)
        auxiliary_battery_logic.power_in = pbat_auxiliary
        primary_battery.inputs = primary_battery_logic
        auxiliary_battery.inputs = auxiliary_battery_logic
        tol = 1e-6
        primary_battery.energy_calc(numerics)
        auxiliary_battery.energy_calc(numerics)
        #allow for mass gaining batteries

        try:
            mdot_primary = find_mass_gain_rate(
                primary_battery,
                -(pbat_primary - primary_battery.resistive_losses))
        except AttributeError:
            mdot_primary = np.zeros_like(results.thrust_force_vector[:, 0])
        try:
            mdot_auxiliary = find_mass_gain_rate(
                auxiliary_battery,
                -(pbat_auxiliary - auxiliary_battery.resistive_losses))
        except AttributeError:
            mdot_auxiliary = np.zeros_like(results.thrust_force_vector[:, 0])

        mdot = mdot_primary + mdot_auxiliary
        mdot = np.reshape(mdot, np.shape(conditions.freestream.velocity))
        #Pack the conditions for outputs
        primary_battery_draw = primary_battery.inputs.power_in
        primary_battery_energy = primary_battery.current_energy
        auxiliary_battery_draw = auxiliary_battery.inputs.power_in
        auxiliary_battery_energy = auxiliary_battery.current_energy

        conditions.propulsion.primary_battery_draw = primary_battery_draw
        conditions.propulsion.primary_battery_energy = primary_battery_energy

        conditions.propulsion.auxiliary_battery_draw = auxiliary_battery_draw
        conditions.propulsion.auxiliary_battery_energy = auxiliary_battery_energy

        results.vehicle_mass_rate = mdot

        return results
Example #47
0
    pressure = np.linspace(10**5, 10**6, test_num)
    pressure = pressure.reshape(test_num, 1)

    #specify  the conditions at which to perform the aerodynamic analysis
    state.conditions.aerodynamics.angle_of_attack = AoA  #angle_of_attacks
    state.conditions.freestream.mach_number = Mc  #np.array([0.8]*test_num)
    state.conditions.freestream.density = rho  #np.array([0.3804534]*test_num)
    state.conditions.freestream.dynamic_viscosity = mu  #np.array([1.43408227e-05]*test_num)
    state.conditions.freestream.temperature = T  #np.array([218.92391647]*test_num)
    state.conditions.freestream.pressure = pressure  #np.array([23908.73408391]*test_num)

    #call the aero model
    results = aerodynamics.evaluate(state)

    #build a polar for the markup aero
    polar = Data()
    CL = results.lift.total
    CD = results.drag.total
    polar.lift = CL
    polar.drag = CD

    ##load old results
    #old_polar = SUAVE.Input_Output.load('polar_M8.pkl') #('polar_old2.pkl')
    #CL_old = old_polar.lift
    #CD_old = old_polar.drag

    #plot the results
    plt.figure("Drag Polar")
    axes = plt.gca()
    axes.plot(CD, CL, 'bo-')  #,CD_old,CL_old,'*')
    axes.set_xlabel('$C_D$')
Example #48
0
def empty(config,
          contingency_factor=1.1,
          speed_of_sound=340.294,
          max_tip_mach=0.65,
          disk_area_factor=1.15,
          safety_factor=1.5,
          max_thrust_to_weight_ratio=1.1,
          max_g_load=3.8,
          motor_efficiency=0.85 * 0.98):
    """mass = SUAVE.Methods.Weights.Buildups.EVTOL.empty(
            config,
            speed_of_sound                = 340.294,
            max_tip_mach                  = 0.65,
            disk_area_factor              = 1.15,
            max_thrust_to_weight_ratio    = 1.1,
            motor_efficiency              = 0.85 * 0.98)

        Calculates the empty vehicle mass for an EVTOL-type aircraft including seats,
        avionics, servomotors, ballistic recovery system, rotor and hub assembly,
        transmission, and landing gear. Incorporates the results of the following
        common-use buildups:

            fuselage.py
            prop.py
            wing.py
            wiring.py

        Sources:
        Project Vahana Conceptual Trade Study
        https://github.com/VahanaOpenSource


        Inputs:

            config:                     SUAVE Config Data Stucture
            speed_of_sound:             Local Speed of Sound                [m/s]
            max_tip_mach:               Allowable Tip Mach Number           [Unitless]
            disk_area_factor:           Inverse of Disk Area Efficiency     [Unitless]
            max_thrust_to_weight_ratio: Allowable Thrust to Weight Ratio    [Unitless]
            motor_efficiency:           Motor Efficiency                    [Unitless]

        Outpus:

            outputs:                    Data Dictionary of Component Masses [kg]

        Output data dictionary has the following book-keeping hierarchical structure:

            Output
                Total.
                    Empty.
                        Structural.
                            Fuselage
                            Wings
                            Landing Gear
                            Rotors
                            Hubs
                        Seats
                        Battery
                        Motors
                        Servo
                    Systems.
                        Avionics
                        ECS               - Environmental Control System
                        BRS               - Ballistic Recovery System
                        Wiring            - Aircraft Electronic Wiring
                    Payload

    """

    # Set up data structures for SUAVE weight methods
    output = Data()
    output.lift_rotors = 0.0
    output.propellers = 0.0
    output.lift_rotor_motors = 0.0
    output.propeller_motors = 0.0
    output.battery = 0.0
    output.payload = 0.0
    output.servos = 0.0
    output.hubs = 0.0
    output.BRS = 0.0

    config.payload.passengers = SUAVE.Components.Physical_Component()
    config.payload.baggage = SUAVE.Components.Physical_Component()
    config.payload.cargo = SUAVE.Components.Physical_Component()
    control_systems = SUAVE.Components.Physical_Component()
    electrical_systems = SUAVE.Components.Physical_Component()
    furnishings = SUAVE.Components.Physical_Component()
    air_conditioner = SUAVE.Components.Physical_Component()
    fuel = SUAVE.Components.Physical_Component()
    apu = SUAVE.Components.Physical_Component()
    hydraulics = SUAVE.Components.Physical_Component()
    avionics = SUAVE.Components.Energy.Peripherals.Avionics()
    optionals = SUAVE.Components.Physical_Component()

    # assign components to vehicle
    config.systems.control_systems = control_systems
    config.systems.electrical_systems = electrical_systems
    config.systems.avionics = avionics
    config.systems.furnishings = furnishings
    config.systems.air_conditioner = air_conditioner
    config.systems.fuel = fuel
    config.systems.apu = apu
    config.systems.hydraulics = hydraulics
    config.systems.optionals = optionals

    #-------------------------------------------------------------------------------
    # Fixed Weights
    #-------------------------------------------------------------------------------
    MTOW = config.mass_properties.max_takeoff
    output.seats = config.passengers * 15. * Units.kg
    output.passengers = config.passengers * 70. * Units.kg
    output.avionics = 15. * Units.kg
    output.landing_gear = MTOW * 0.02 * Units.kg
    output.ECS = config.passengers * 7. * Units.kg

    # Inputs and other constants
    tipMach = max_tip_mach
    k = disk_area_factor
    ToverW = max_thrust_to_weight_ratio
    eta = motor_efficiency
    rho_ref = 1.225
    maxVTip = speed_of_sound * tipMach  # Prop Tip Velocity
    maxLift = MTOW * ToverW * 9.81  # Maximum Thrust
    AvgBladeCD = 0.012  # Average Blade CD

    # Select a length scale depending on what kind of vehicle this is
    length_scale = 1.
    nose_length = 0.

    # Check if there is a fuselage
    C = SUAVE.Components
    if len(config.fuselages) == 0.:
        for w in config.wings:
            if isinstance(w, C.Wings.Main_Wing):
                b = w.chords.root
                if b > length_scale:
                    length_scale = b
                    nose_length = 0.25 * b
    else:
        for fuse in config.fuselages:
            nose = fuse.lengths.nose
            length = fuse.lengths.total
            if length > length_scale:
                length_scale = length
                nose_length = nose

    #-------------------------------------------------------------------------------
    # Environmental Control System
    #-------------------------------------------------------------------------------
    config.systems.air_conditioner.origin[0][0] = 0.51 * length_scale
    config.systems.air_conditioner.mass_properties.mass = output.ECS

    #-------------------------------------------------------------------------------
    # Network Weight
    #-------------------------------------------------------------------------------
    for network in config.networks:

        #-------------------------------------------------------------------------------
        # Battery Weight
        #-------------------------------------------------------------------------------
        network.battery.origin[0][0] = 0.51 * length_scale
        network.battery.mass_properties.center_of_gravity[0][0] = 0.0
        output.battery += network.battery.mass_properties.mass * Units.kg

        #-------------------------------------------------------------------------------
        # Payload Weight
        #-------------------------------------------------------------------------------
        network.payload.origin[0][0] = 0.51 * length_scale
        network.payload.mass_properties.center_of_gravity[0][0] = 0.0
        output.payload += network.payload.mass_properties.mass * Units.kg

        #-------------------------------------------------------------------------------
        # Avionics Weight
        #-------------------------------------------------------------------------------
        network.avionics.origin[0][0] = 0.4 * nose_length
        network.avionics.mass_properties.center_of_gravity[0][0] = 0.0
        network.avionics.mass_properties.mass = output.avionics

        #-------------------------------------------------------------------------------
        # Servo, Hub and BRS Weights
        #-------------------------------------------------------------------------------

        lift_rotor_hub_weight = 4. * Units.kg
        prop_hub_weight = MTOW * 0.04 * Units.kg

        lift_rotor_BRS_weight = 16. * Units.kg

        #-------------------------------------------------------------------------------
        # Rotor, Propeller, parameters for sizing
        #-------------------------------------------------------------------------------
        if isinstance(network, Lift_Cruise):
            # Total number of rotors and propellers
            nLiftRotors = network.number_of_lift_rotor_engines
            nThrustProps = network.number_of_propeller_engines
            props = network.propellers
            rots = network.lift_rotors
            prop_motors = network.propeller_motors
            rot_motors = network.lift_rotor_motors

        elif isinstance(network, Battery_Propeller):
            # Total number of rotors and propellers

            if network.number_of_lift_rotor_engines == None:
                nLiftRotors = 0
            else:
                nLiftRotors = network.number_of_lift_rotor_engines
                rots = network.lift_rotors
                rot_motors = network.lift_rotor_motors

            if network.number_of_propeller_engines == None:
                nThrustProps = 0
            else:
                nThrustProps = network.number_of_propeller_engines
                props = network.propellers
                prop_motors = network.propeller_motors

        else:
            raise NotImplementedError(
                """eVTOL weight buildup only supports the Battery Propeller and Lift Cruise energy networks.\n
            Weight buildup will not return information on propulsion system.""",
                RuntimeWarning)

        nProps = int(nLiftRotors + nThrustProps)
        if nProps > 1:
            prop_BRS_weight = 16. * Units.kg
        else:
            prop_BRS_weight = 0. * Units.kg

        prop_servo_weight = 0.0

        if nThrustProps > 0:
            if network.identical_propellers:
                # Get reference properties for sizing from first propeller (assumes identical)
                proprotor = props[list(props.keys())[0]]
                propmotor = prop_motors[list(prop_motors.keys())[0]]
                rTip_ref = proprotor.tip_radius
                bladeSol_ref = proprotor.blade_solidity

                if proprotor.variable_pitch:
                    prop_servo_weight = 5.2 * Units.kg

                # Compute and add propeller weights
                propeller_mass = prop(proprotor, maxLift / 5.) * Units.kg
                output.propellers += nThrustProps * propeller_mass
                output.propeller_motors += nThrustProps * propmotor.mass_properties.mass
                proprotor.mass_properties.mass = propeller_mass + prop_hub_weight + prop_servo_weight

            else:
                for idx, propeller in enumerate(network.propellers):
                    proprotor = propeller
                    propmotor = prop_motors[list(prop_motors.keys())[idx]]
                    rTip_ref = proprotor.tip_radius
                    bladeSol_ref = proprotor.blade_solidity

                    if proprotor.variable_pitch:
                        prop_servo_weight = 5.2 * Units.kg

                    # Compute and add propeller weights
                    propeller_mass = prop(proprotor, maxLift / 5.) * Units.kg
                    output.propellers += propeller_mass
                    output.propeller_motors += propmotor.mass_properties.mass
                    proprotor.mass_properties.mass = propeller_mass + prop_hub_weight + prop_servo_weight

        lift_rotor_servo_weight = 0.0
        if nLiftRotors > 0:
            if network.identical_lift_rotors:
                # Get reference properties for sizing from first lift_rotor (assumes identical)
                liftrotor = rots[list(rots.keys())[0]]
                liftmotor = rot_motors[list(rot_motors.keys())[0]]
                rTip_ref = liftrotor.tip_radius
                bladeSol_ref = liftrotor.blade_solidity

                if liftrotor.variable_pitch:
                    lift_rotor_servo_weight = 0.65 * Units.kg

                # Compute and add lift_rotor weights
                lift_rotor_mass = prop(
                    liftrotor, maxLift / max(nLiftRotors - 1, 1)) * Units.kg
                output.lift_rotors += nLiftRotors * lift_rotor_mass
                output.lift_rotor_motors += nLiftRotors * liftmotor.mass_properties.mass
                liftrotor.mass_properties.mass = lift_rotor_mass + lift_rotor_hub_weight + lift_rotor_servo_weight

            else:
                for idx, lift_rotor in enumerate(network.lift_rotors):
                    liftrotor = lift_rotor
                    liftmotor = rot_motors[list(rot_motors.keys())[idx]]
                    rTip_ref = liftrotor.tip_radius
                    bladeSol_ref = liftrotor.blade_solidity

                    if liftrotor.variable_pitch:
                        lift_rotor_servo_weight = 0.65 * Units.kg

                    # Compute and add lift_rotor weights
                    lift_rotor_mass = prop(liftrotor, maxLift /
                                           max(nLiftRotors - 1, 1)) * Units.kg
                    output.lift_rotors += lift_rotor_mass
                    output.lift_rotor_motors += liftmotor.mass_properties.mass
                    liftrotor.mass_properties.mass = lift_rotor_mass + lift_rotor_hub_weight + lift_rotor_servo_weight

        # Add associated weights
        output.servos += (nLiftRotors * lift_rotor_servo_weight +
                          nThrustProps * prop_servo_weight)
        output.hubs += (nLiftRotors * lift_rotor_hub_weight +
                        nThrustProps * prop_hub_weight)
        output.BRS += (prop_BRS_weight + lift_rotor_BRS_weight)

        maxLiftPower = 1.15 * maxLift * (
            k * np.sqrt(maxLift / (2 * rho_ref * np.pi * rTip_ref**2)) +
            bladeSol_ref * AvgBladeCD / 8 * maxVTip**3 /
            (maxLift / (rho_ref * np.pi * rTip_ref**2)))
        # Tail Rotor
        if nLiftRotors == 1:  # this assumes that the vehicle is an electric helicopter with a tail rotor

            maxLiftOmega = maxVTip / rTip_ref
            maxLiftTorque = maxLiftPower / maxLiftOmega

            tailrotor = next(iter(network.lift_rotors))
            output.tail_rotor = prop(tailrotor, 1.5 * maxLiftTorque /
                                     (1.25 * rTip_ref)) * 0.2 * Units.kg
            output.lift_rotors += output.tail_rotor

    # sum motor weight
    output.motors = output.lift_rotor_motors + output.propeller_motors

    #-------------------------------------------------------------------------------
    # Wing and Motor Wiring Weight
    #-------------------------------------------------------------------------------
    total_wing_weight = 0.0
    total_wiring_weight = 0.0
    output.wings = Data()
    output.wiring = Data()

    for w in config.wings:
        if w.symbolic:
            wing_weight = 0
        else:
            wing_weight = wing(w,
                               config,
                               maxLift / 5,
                               safety_factor=safety_factor,
                               max_g_load=max_g_load)
            wing_tag = w.tag
            output.wings[wing_tag] = wing_weight
            w.mass_properties.mass = wing_weight

        total_wing_weight = total_wing_weight + wing_weight

        # wiring weight
        wiring_weight = wiring(w, config, maxLiftPower /
                               (eta * nProps)) * Units.kg
        total_wiring_weight = total_wiring_weight + wiring_weight

    output.wiring = total_wiring_weight
    output.total_wing_weight = total_wing_weight

    #-------------------------------------------------------------------------------
    # Landing Gear Weight
    #-------------------------------------------------------------------------------
    if not hasattr(config.landing_gear, 'nose'):
        config.landing_gear.nose = SUAVE.Components.Landing_Gear.Nose_Landing_Gear(
        )
    config.landing_gear.nose.mass = 0.0
    if not hasattr(config.landing_gear, 'main'):
        config.landing_gear.main = SUAVE.Components.Landing_Gear.Main_Landing_Gear(
        )
    config.landing_gear.main.mass = output.landing_gear

    #-------------------------------------------------------------------------------
    # Fuselage  Weight
    #-------------------------------------------------------------------------------
    output.fuselage = fuselage(config) * Units.kg
    config.fuselages.fuselage.mass_properties.center_of_gravity[0][
        0] = .45 * config.fuselages.fuselage.lengths.total
    config.fuselages.fuselage.mass_properties.mass                    =  output.fuselage + output.passengers + output.seats +\
                                                                         output.wiring + output.BRS

    #-------------------------------------------------------------------------------
    # Pack Up Outputs
    #-------------------------------------------------------------------------------
    output.structural = (output.lift_rotors + output.propellers + output.hubs +
                         output.fuselage + output.landing_gear +
                         output.total_wing_weight) * Units.kg

    output.empty      = (contingency_factor * (output.structural + output.seats + output.avionics +output.ECS +\
                        output.motors + output.servos + output.wiring + output.BRS) + output.battery) *Units.kg

    output.total = output.empty + output.payload + output.passengers

    return output
Example #49
0
    def __defaults__(self):
        """ This sets the default solver flow. Anything in here can be modified after initializing a segment.
    
            Assumptions:
            None
    
            Source:
            N/A
    
            Inputs:
            None
    
            Outputs:
            None
    
            Properties Used:
            None
        """

        # --------------------------------------------------------------
        #   User inputs
        # --------------------------------------------------------------
        self.ground_incline = 0.0
        self.friction_coefficient = 0.04
        self.throttle = None
        self.velocity_start = 0.0
        self.velocity_end = 0.0
        self.time = 0.01
        # --------------------------------------------------------------
        #   State
        # --------------------------------------------------------------

        # conditions
        self.state.conditions.update(Conditions.Aerodynamics())

        # initials and unknowns
        ones_row = self.state.ones_row
        self.state.residuals.acceleration_x = ones_row(1) * 0.0

        # Specific ground things
        self.state.conditions.ground = Data()
        self.state.conditions.ground.incline = ones_row(1) * 0.0
        self.state.conditions.ground.friction_coefficient = ones_row(1) * 0.0
        self.state.conditions.frames.inertial.ground_force_vector = ones_row(
            3) * 0.0

        # --------------------------------------------------------------
        #   The Solving Process
        # --------------------------------------------------------------

        # --------------------------------------------------------------
        #   Initialize - before iteration
        # --------------------------------------------------------------
        initialize = self.process.initialize

        initialize.expand_state = Methods.expand_state
        initialize.differentials = Methods.Common.Numerics.initialize_differentials_dimensionless
        initialize.conditions = Methods.Ground.Common.initialize_conditions

        # --------------------------------------------------------------
        #   Converge - starts iteration
        # --------------------------------------------------------------
        converge = self.process.converge

        converge.converge_root = Methods.converge_root

        # --------------------------------------------------------------
        #   Iterate - this is iterated
        # --------------------------------------------------------------
        iterate = self.process.iterate

        # Update Initials
        iterate.initials = Process()
        iterate.initials.time = Methods.Common.Frames.initialize_time
        iterate.initials.weights = Methods.Common.Weights.initialize_weights
        iterate.initials.inertial_position = Methods.Common.Frames.initialize_inertial_position
        iterate.initials.planet_position = Methods.Common.Frames.initialize_planet_position

        # Unpack Unknowns
        iterate.unknowns = Process()
        iterate.unknowns.mission = Methods.Ground.Common.unpack_unknowns

        # Update Conditions
        iterate.conditions = Process()
        iterate.conditions.differentials = Methods.Common.Numerics.update_differentials_time
        iterate.conditions.altitude = Methods.Common.Aerodynamics.update_altitude
        iterate.conditions.atmosphere = Methods.Common.Aerodynamics.update_atmosphere
        iterate.conditions.gravity = Methods.Common.Weights.update_gravity
        iterate.conditions.freestream = Methods.Common.Aerodynamics.update_freestream
        iterate.conditions.orientations = Methods.Common.Frames.update_orientations
        iterate.conditions.propulsion = Methods.Common.Energy.update_thrust
        iterate.conditions.aerodynamics = Methods.Common.Aerodynamics.update_aerodynamics
        iterate.conditions.stability = Methods.Common.Aerodynamics.update_stability
        iterate.conditions.weights = Methods.Common.Weights.update_weights
        iterate.conditions.forces_ground = Methods.Ground.Common.compute_ground_forces
        iterate.conditions.forces = Methods.Ground.Common.compute_forces
        iterate.conditions.planet_position = Methods.Common.Frames.update_planet_position

        # Solve Residuals
        iterate.residuals = Process()
        iterate.residuals.total_forces = Methods.Ground.Common.solve_residuals

        # --------------------------------------------------------------
        #   Finalize - after iteration
        # --------------------------------------------------------------
        finalize = self.process.finalize

        # Post Processing
        finalize.post_process = Process()
        finalize.post_process.inertial_position = Methods.Common.Frames.integrate_inertial_horizontal_position
        finalize.post_process.stability = Methods.Common.Aerodynamics.update_stability

        return
Example #50
0
    def evaluate_thrust(self, state):
        """ Calculate thrust given the current state of the vehicle
    
            Assumptions:
    
            Source:
            N/A
    
            Inputs:
            state [state()]
    
            Outputs:
            results.thrust_force_vector [newtons]
            results.vehicle_mass_rate   [kg/s]
            conditions.propulsion:
                rpm                  [radians/sec]
                propeller_torque     [N-M]
                power                [W]
    
            Properties Used:
            Defaulted values
        """
        # unpack
        conditions = state.conditions
        engine = self.engine
        propeller = self.propeller
        num_engines = self.number_of_engines

        # Throttle the engine
        engine.inputs.speed = state.conditions.propulsion.rpm * Units.rpm
        conditions.propulsion.combustion_engine_throttle = conditions.propulsion.throttle

        # Run the engine
        engine.power(conditions)
        power_output = engine.outputs.power
        sfc = engine.outputs.power_specific_fuel_consumption
        mdot = engine.outputs.fuel_flow_rate
        torque = engine.outputs.torque

        # link
        propeller.inputs.omega = state.conditions.propulsion.rpm * Units.rpm
        propeller.thrust_angle = self.thrust_angle

        # step 4
        F, Q, P, Cp, outputs, etap = propeller.spin(conditions)

        # Check to see if magic thrust is needed
        eta = conditions.propulsion.throttle
        P[eta > 1.0] = P[eta > 1.0] * eta[eta > 1.0]
        F[eta > 1.0] = F[eta > 1.0] * eta[eta > 1.0]

        # link
        propeller.outputs = outputs

        # Pack the conditions for outputs
        a = conditions.freestream.speed_of_sound
        R = propeller.tip_radius
        rpm = engine.inputs.speed / Units.rpm

        conditions.propulsion.rpm = rpm
        conditions.propulsion.propeller_torque = Q
        conditions.propulsion.power = P
        conditions.propulsion.propeller_tip_mach = (R * rpm * Units.rpm) / a
        conditions.propulsion.motor_torque = torque

        # noise
        outputs.number_of_engines = num_engines
        conditions.noise.sources.propeller = outputs

        # Create the outputs
        F = num_engines * F * [
            np.cos(self.thrust_angle), 0, -np.sin(self.thrust_angle)
        ]
        F_mag = np.atleast_2d(np.linalg.norm(F, axis=1))
        conditions.propulsion.disc_loading = (F_mag.T) / (
            num_engines * np.pi * (R / Units.feet)**2)  # N/m^2
        conditions.propulsion.power_loading = (F_mag.T) / (P)  # N/W

        results = Data()
        results.thrust_force_vector = F
        results.vehicle_mass_rate = mdot

        return results
def setup():

    nexus = Nexus()
    problem = Data()
    nexus.optimization_problem = problem

    # -------------------------------------------------------------------
    # Inputs
    # -------------------------------------------------------------------

    #   [ tag                            , initial, (lb,ub)             , scaling , units ]
    problem.inputs = np.array([
        ['wing_area', 95, (90., 130.), 100., Units.meter**2],
        ['cruise_altitude', 11, (9, 14.), 10., Units.km],
    ])

    # -------------------------------------------------------------------
    # Objective
    # -------------------------------------------------------------------

    # throw an error if the user isn't specific about wildcards
    # [ tag, scaling, units ]
    problem.objective = np.array([['fuel_burn', 10000, Units.kg]])

    # -------------------------------------------------------------------
    # Constraints
    # -------------------------------------------------------------------

    # [ tag, sense, edge, scaling, units ]
    problem.constraints = np.array([
        ['design_range_fuel_margin', '>', 0., 1E-1,
         Units.less],  #fuel margin defined here as fuel 
    ])

    # -------------------------------------------------------------------
    #  Aliases
    # -------------------------------------------------------------------

    # [ 'alias' , ['data.path1.name','data.path2.name'] ]

    problem.aliases = [
        [
            'wing_area',
            [
                'vehicle_configurations.*.wings.main_wing.areas.reference',
                'vehicle_configurations.*.reference_area'
            ]
        ],
        ['cruise_altitude', 'missions.base.segments.climb_5.altitude_end'],
        ['fuel_burn', 'summary.base_mission_fuelburn'],
        ['design_range_fuel_margin', 'summary.max_zero_fuel_margin'],
    ]

    # -------------------------------------------------------------------
    #  Vehicles
    # -------------------------------------------------------------------
    nexus.vehicle_configurations = Vehicles.setup()

    # -------------------------------------------------------------------
    #  Analyses
    # -------------------------------------------------------------------
    nexus.analyses = Analyses.setup(nexus.vehicle_configurations)

    # -------------------------------------------------------------------
    #  Missions
    # -------------------------------------------------------------------
    nexus.missions = Missions.setup(nexus.analyses)

    # -------------------------------------------------------------------
    #  Procedure
    # -------------------------------------------------------------------
    nexus.procedure = Procedure.setup()

    # -------------------------------------------------------------------
    #  Summary
    # -------------------------------------------------------------------
    nexus.summary = Data()
    nexus.total_number_of_iterations = 0
    return nexus
Example #52
0
def windmilling_drag(geometry, state):
    """Computes windmilling drag for turbofan engines

    Assumptions:
    None

    Source:
    http://www.dept.aoe.vt.edu/~mason/Mason_f/AskinThesis2002_13.pdf
    
    Inputs:
    geometry.
      max_mach_operational        [Unitless]
      reference_area              [m^2]
      wings.sref                  [m^2]
      propulsors. 
        areas.wetted              [m^2]
        nacelle_diameter          [m^2]
        engine_length             [m^2]

    Outputs:
    windmilling_drag_coefficient  [Unitless]

    Properties Used:
    N/A
    """
    # ==============================================
    # Unpack
    # ==============================================
    vehicle = geometry

    # Defining reference area
    if vehicle.reference_area:
        reference_area = vehicle.reference_area
    else:
        n_wing = 0
        for wing in vehicle.wings:
            if not isinstance(wing, Wings.Main_Wing): continue
            n_wing = n_wing + 1
            reference_area = wing.sref
        if n_wing > 1:
            print(
                ' More than one Main_Wing in the vehicle. Last one will be considered.'
            )
        elif n_wing == 0:
            print('No Main_Wing defined! Using the 1st wing found')
            for wing in vehicle.wings:
                if not isinstance(wing, Wings.Wing): continue
                reference_area = wing.sref
                break

    # getting geometric data from engine (estimating when not available)
    for idx, propulsor in enumerate(vehicle.propulsors):
        try:
            swet_nac = propulsor.areas.wetted
        except:
            try:
                D_nac = propulsor.nacelle_diameter
                if propulsor.engine_length != 0.:
                    l_nac = propulsor.engine_length
                else:
                    try:
                        MMO = vehicle.max_mach_operational
                    except:
                        MMO = 0.84
                    D_nac_in = D_nac / Units.inches
                    l_nac = (2.36 * D_nac_in - 0.01 *
                             (D_nac_in * MMO)**2) * Units.inches
            except AttributeError:
                print(
                    'Error calculating windmilling drag. Engine dimensions missing.'
                )
            swet_nac = 5.62 * D_nac * l_nac

    # Compute
    windmilling_drag_coefficient = 0.007274 * swet_nac / reference_area

    # dump data to state
    windmilling_result = Data(
        wetted_area=swet_nac,
        windmilling_drag_coefficient=windmilling_drag_coefficient,
    )
    state.conditions.aerodynamics.drag_breakdown.windmilling_drag = windmilling_result

    return windmilling_drag_coefficient
Example #53
0
    def evaluate_thrust(self, state):
        """ Calculate thrust given the current state of the vehicle
    
            Assumptions:
    
            Source:
            N/A
    
            Inputs:
            state [state()]
    
            Outputs:
            results.thrust_force_vector [newtons]
            results.vehicle_mass_rate   [kg/s]
            conditions.propulsion:
                rpm                  [radians/sec]
                propeller_torque     [N-M]
                power                [W]
    
            Properties Used:
            Defaulted values
        """
        # unpack
        conditions = state.conditions
        engines = self.engines
        propellers = self.propellers
        num_engines = self.number_of_engines
        rpm = conditions.propulsion.rpm

        # Unpack conditions
        a = conditions.freestream.speed_of_sound

        # How many evaluations to do
        if self.identical_propellers:
            n_evals = 1
            factor = num_engines * 1
        else:
            n_evals = int(num_engines)
            factor = 1.

        # Setup conditions
        ones_row = conditions.ones_row
        conditions.propulsion.disc_loading = ones_row(n_evals)
        conditions.propulsion.power_loading = ones_row(n_evals)
        conditions.propulsion.propeller_torque = ones_row(n_evals)
        conditions.propulsion.propeller_tip_mach = ones_row(n_evals)
        conditions.propulsion.combustion_engine_throttle = ones_row(n_evals)

        # Setup numbers for iteration
        total_thrust = 0. * state.ones_row(3)
        total_power = 0.
        mdot = 0.
        for ii in range(n_evals):

            # Unpack the engine and props
            engine_key = list(engines.keys())[ii]
            prop_key = list(propellers.keys())[ii]
            engine = self.engines[engine_key]
            prop = self.propellers[prop_key]

            # Run the propeller to get the power
            prop.inputs.pitch_command = conditions.propulsion.throttle - 0.5
            prop.inputs.omega = rpm

            # step 4
            F, Q, P, Cp, outputs, etap = prop.spin(conditions)

            # Run the engine to calculate the throttle setting and the fuel burn
            engine.inputs.power = P
            engine.calculate_throttle(conditions)

            # Create the outputs
            R = prop.tip_radius
            mdot = mdot + engine.outputs.fuel_flow_rate * factor
            F_mag = np.atleast_2d(np.linalg.norm(F, axis=1))
            engine_throttle = engine.outputs.throttle
            total_thrust = total_thrust + F * factor
            total_power = total_power + P * factor

            # Pack the conditions
            conditions.propulsion.propeller_torque[:, ii] = Q[:, 0]
            conditions.propulsion.propeller_tip_mach[:, ii] = (
                R * rpm[:, 0] * Units.rpm) / a[:, 0]
            conditions.propulsion.disc_loading[:, ii] = (F_mag[:, 0]) / (
                np.pi * (R**2))  # N/m^2
            conditions.propulsion.power_loading[:, ii] = (F_mag[:, 0]) / (
                P[:, 0])  # N/W
            conditions.propulsion.combustion_engine_throttle = engine_throttle
            conditions.propulsion.propeller_efficiency = etap[:, 0]

            conditions.noise.sources.propellers[prop.tag] = outputs

        # Create the outputs
        conditions.propulsion.power = total_power

        results = Data()
        results.thrust_force_vector = F
        results.vehicle_mass_rate = mdot

        return results
Example #54
0
def setup():

    nexus = Nexus()
    problem = Data()
    nexus.optimization_problem = problem

    # -------------------------------------------------------------------
    # Inputs
    # -------------------------------------------------------------------

    #   [ tag          , initial, (lb,ub)             , scaling ,    units]
    problem.inputs = np.array([
        ['wing_area', 61., (61., 61.), 61., Units.meter**2],
        ['aspect_ratio', 12., (12., 12.), 12.0, Units.less],
        ['taper_ratio', 0.53, (0.53, 0.53), 0.53, Units.less],
        ['t_c_ratio', 0.15, (0.15, 0.15), 0.15, Units.less],
        ['sweep_angle', 3., (3.0, 3.0), 3.0, Units.deg],
        [
            'cruise_range', 331.5017418, (310., 350.), 331.3,
            Units.nautical_miles
        ],
        ['MTOW', 23009.2657571, (21000., 25000.), 23000., Units.kg],
        ['MZFW_ratio', 0.912696041, (0.8, 0.98), 1., Units.less],
    ])

    # -------------------------------------------------------------------
    # Objective
    # -------------------------------------------------------------------

    # throw an error if the user isn't specific about wildcards
    # [ tag, scaling, units ]
    problem.objective = np.array([
        # ['objective', 1., Units.less],
        ['Nothing', 1., Units.less],
    ])

    # -------------------------------------------------------------------
    # Constraints
    # -------------------------------------------------------------------

    # [ tag, sense, edge, scaling, units ]
    # CONSTRAINTS ARE SET TO BE BIGGER THAN ZERO, SEE PROCEDURE (SciPy's SLSQP optimization algorithm assumes this form)
    problem.constraints = np.array([
        ['mzfw_consistency', '=', 0., 1000., Units.kg],  # MZFW consistency
        ['fuel_margin', '=', 0., 1000.,
         Units.kg],  # fuel margin defined here as fuel
        # ['Throttle_min',             '>', 0., 1.,   Units.less],
        # ['Throttle_max',             '>', 0., 1.,   Units.less],
        # ['tofl_mtow_margin',         '>', 0., 100.,    Units.m],           # take-off field length
        ['design_range_ub', '>', 0., 10.,
         Units.nautical_miles],  # Range consistency
        ['design_range_lb', '>', 0., 10.,
         Units.nautical_miles],  # Range consistency
        # ['time_to_climb',            '>', 0., 10.,  Units.min],            # Time to climb consistency
        # ['climb_gradient',           '>', 0., 1.,  Units.less],            # second segment climb gradient
        # ['lfl_mlw_margin',           '>', 0., 100.,   Units.m],            # landing field length
        # ['max_fuel_margin',          '>', 0., 100.,  Units.kg],            # max fuel margin
        # ['TOW_HH_margin',            '>', 0., 100.,  Units.kg],            # TOW for Hot and High
    ])

    # -------------------------------------------------------------------
    #  Aliases
    # -------------------------------------------------------------------

    # [ 'alias' , ['data.path1.name','data.path2.name'] ]
    problem.aliases = [
        [
            'wing_area',
            [
                'vehicle_configurations.*.wings.main_wing.areas.reference',
                'vehicle_configurations.*.reference_area'
            ]
        ],
        [
            'aspect_ratio',
            'vehicle_configurations.*.wings.main_wing.aspect_ratio'
        ],
        [
            't_c_ratio',
            'vehicle_configurations.*.wings.main_wing.thickness_to_chord'
        ],
        [
            'sweep_angle',
            'vehicle_configurations.*.wings.main_wing.sweeps.quarter_chord'
        ],
        ['cruise_range', 'missions.base.segments.cruise.distance'],
        ['fuel_margin', 'summary.fuel_margin'],
        ['Throttle_min', 'summary.throttle_min'],
        ['Throttle_max', 'summary.throttle_max'],
        ['tofl_mtow_margin', 'summary.takeoff_field_length_margin'],
        ['mzfw_consistency', 'summary.mzfw_consistency'],
        ['design_range_ub', 'summary.design_range_ub'],
        ['design_range_lb', 'summary.design_range_lb'],
        ['time_to_climb', 'summary.time_to_climb'],
        ['climb_gradient', 'summary.climb_gradient'],
        ['lfl_mlw_margin', 'summary.lfl_mlw_margin'],
        ['max_fuel_margin', 'summary.max_fuel_margin'],
        ['TOW_HH_margin', 'summary.TOW_HH_margin'],
        [
            'MTOW',
            [
                'vehicle_configurations.*.mass_properties.max_takeoff',
                'vehicle_configurations.*.mass_properties.takeoff'
            ]
        ],
        ['MZFW_ratio', 'summary.MZFW_ratio'],
        ['beta', 'vehicle_configurations.base.wings.main_wing.beta'],
        ['objective', 'summary.objective'],
        ['Nothing', 'summary.nothing'],
        ['taper_ratio', 'vehicle_configurations.*.wings.main_wing.taper'],
    ]

    # -------------------------------------------------------------------
    #  Vehicles
    # -------------------------------------------------------------------
    nexus.vehicle_configurations = Vehicles.setup()

    # -------------------------------------------------------------------
    #  Analyses
    # -------------------------------------------------------------------
    nexus.analyses = Analyses.setup(nexus.vehicle_configurations)
    nexus.analyses.vehicle = Data()
    nexus.analyses.vehicle = nexus.vehicle_configurations.base
    # -------------------------------------------------------------------
    #  Missions
    # -------------------------------------------------------------------
    nexus.missions = Missions.setup(nexus.analyses)

    # -------------------------------------------------------------------
    #  Procedure
    # -------------------------------------------------------------------
    nexus.procedure = Procedure.setup()

    # -------------------------------------------------------------------
    #  Summary
    # -------------------------------------------------------------------
    nexus.summary = Data()
    nexus.total_number_of_iterations = 0

    nexus.beta = Data()
    nexus.beta = 1.

    return nexus
        # store to outputs
        self.outputs.power = output_power
        self.outputs.power_specific_fuel_consumption = BSFC
        self.outputs.fuel_flow_rate = fuel_flow_rate
        self.outputs.torque = torque

        return self.outputs


if __name__ == '__main__':

    import numpy as np
    import pylab as plt
    import SUAVE
    from SUAVE.Core import Units, Data
    conditions = Data()
    atmo = SUAVE.Analyses.Atmospheric.US_Standard_1976()
    ICE = Internal_Combustion_Engine()
    ICE.sea_level_power = 250.0 * Units.horsepower
    ICE.flat_rate_altitude = 5000. * Units.ft
    ICE.speed = 2200.  # rpm
    ICE.throttle = 1.0
    PSLS = 1.0
    delta_isa = 0.0
    i = 0
    altitude = list()
    rho = list()
    sigma = list()
    Pavailable = list()
    torque = list()
    for h in range(0, 25000, 500):
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.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
    # ==============================================
    # 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, 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 = SUAVE.Analyses.Mission.Segments.Conditions.State()
    conditions = state.conditions
    conditions.update(
        SUAVE.Analyses.Mission.Segments.Conditions.Aerodynamics())

    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_2d([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))
        state.conditions.freestream.dynamic_viscosity = np.array(
            np.atleast_1d(mu))
        state.conditions.freestream.density = np.array(np.atleast_1d(rho))
        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(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]
Example #57
0
 def __defaults__(self):
     self.tag = 'stability'
     self.geometry = Data()
     self.settings = Data()
Example #58
0
    def evaluate_thrust(self, state):
        """ Calculate thrust given the current state of the vehicle
    
            Assumptions:
            Caps the throttle at 110% and linearly interpolates thrust off that
    
            Source:
            N/A
    
            Inputs:
            state [state()]
    
            Outputs:
            results.thrust_force_vector [newtons]
            results.vehicle_mass_rate   [kg/s]
            conditions.propulsion:
                rpm                  [radians/sec]
                current              [amps]
                battery_draw         [watts]
                battery_energy       [joules]
                voltage_open_circuit [volts]
                voltage_under_load   [volts]
                motor_torque         [N-M]
                propeller_torque     [N-M]
    
            Properties Used:
            Defaulted values
        """

        # unpack
        conditions = state.conditions
        numerics = state.numerics
        motor = self.motor
        rotor = self.rotor
        esc = self.esc
        avionics = self.avionics
        payload = self.payload
        battery = self.battery
        num_engines = self.number_of_engines
        t_nondim = state.numerics.dimensionless.control_points

        # Set battery energy
        battery.current_energy = conditions.propulsion.battery_energy

        volts = state.unknowns.battery_voltage_under_load * 1.
        volts[volts > self.voltage] = self.voltage

        # ESC Voltage
        esc.inputs.voltagein = volts

        #---------------------------------------------------------------
        # EVALUATE THRUST FROM PROPULSORS
        #---------------------------------------------------------------
        # Step 2
        esc.voltageout(conditions)

        # link
        motor.inputs.voltage = esc.outputs.voltageout

        # Run the motor
        motor.omega(conditions)

        # Define the thrust angle
        thrust_angle = self.thrust_angle

        # link
        rotor.inputs.omega = motor.outputs.omega
        rotor.thrust_angle = thrust_angle
        rotor.pitch_command = self.pitch_command

        # Run the rotor
        F, Q, P, Cp, outputs, etap = rotor.spin(conditions)

        # Check to see if magic thrust is needed, the ESC caps throttle at 1.1 already
        eta = conditions.propulsion.throttle[:, 0, None]
        P[eta > 1.0] = P[eta > 1.0] * eta[eta > 1.0]
        F[eta > 1.0] = F[eta > 1.0] * eta[eta > 1.0]

        # Run the avionics
        avionics.power()

        # Run the payload
        payload.power()

        # Run the motor for current
        i, etam = motor.current(conditions)

        # Fix the current for the throttle cap
        motor.outputs.current[
            eta > 1.0] = motor.outputs.current[eta > 1.0] * eta[eta > 1.0]

        # link
        esc.inputs.currentout = motor.outputs.current

        # Run the esc
        esc.currentin(conditions)

        # Calculate avionics and payload power
        avionics_payload_power = avionics.outputs.power + payload.outputs.power

        # Calculate avionics and payload current
        avionics_payload_current = avionics_payload_power / self.voltage

        # link
        propeller_current = esc.outputs.currentin * num_engines
        total_current = propeller_current + avionics_payload_current
        battery.inputs.current = total_current
        battery.inputs.power_in = -(
            esc.outputs.voltageout * esc.outputs.currentin * num_engines +
            avionics_payload_power)
        battery.energy_calc(numerics)

        # Pack the conditions for outputs
        rpm = motor.outputs.omega / Units.rpm
        a = conditions.freestream.speed_of_sound
        R = rotor.tip_radius
        current = esc.outputs.currentin
        battery_draw = battery.inputs.power_in
        battery_energy = battery.current_energy
        voltage_open_circuit = battery.voltage_open_circuit
        voltage_under_load = battery.voltage_under_load
        state_of_charge = battery.state_of_charge

        conditions.propulsion.rpm = rpm
        conditions.propulsion.current = current
        conditions.propulsion.battery_draw = battery_draw
        conditions.propulsion.battery_energy = battery_energy
        conditions.propulsion.voltage_open_circuit = voltage_open_circuit
        conditions.propulsion.voltage_under_load = voltage_under_load
        conditions.propulsion.state_of_charge = state_of_charge
        conditions.propulsion.motor_torque = motor.outputs.torque
        conditions.propulsion.propeller_torque = Q
        conditions.propulsion.motor_efficiency = etam
        conditions.propulsion.acoustic_outputs[rotor.tag] = outputs
        conditions.propulsion.battery_specfic_power = -battery_draw / battery.mass_properties.mass  #Wh/kg
        conditions.propulsion.electronics_efficiency = -(
            P * num_engines) / battery_draw
        conditions.propulsion.propeller_tip_mach = (R * rpm * Units.rpm) / a
        conditions.propulsion.battery_current = total_current
        conditions.propulsion.battery_efficiency = (
            battery_draw + battery.resistive_losses) / battery_draw
        conditions.propulsion.payload_efficiency = (
            battery_draw +
            (avionics.outputs.power + payload.outputs.power)) / battery_draw
        conditions.propulsion.propeller_power = P * num_engines
        conditions.propulsion.propeller_thrust_coefficient = Cp
        conditions.propulsion.propeller_efficiency = etap
        conditions.propulsion.propeller_thrust_coefficient = outputs.thrust_coefficient

        # Compute force vector
        F_vec = self.number_of_engines * F * [
            np.cos(self.thrust_angle), 0, -np.sin(self.thrust_angle)
        ]

        F_mag = np.atleast_2d(np.linalg.norm(F_vec, axis=1))

        conditions.propulsion.disc_loading = (F_mag.T) / (num_engines * np.pi *
                                                          (R)**2)  # N/m^2
        conditions.propulsion.power_loading = (F_mag.T) / (P)  # N/W

        mdot = state.ones_row(1) * 0.0

        results = Data()
        results.thrust_force_vector = F_vec
        results.vehicle_mass_rate = mdot

        return results
Example #59
0
def compute_propeller_wake_velocities(prop,
                                      grid_settings,
                                      grid_points,
                                      conditions,
                                      plot_velocities=True):

    x_plane = prop.origin[1, 0]  #second propeller, x-location

    # generate the propeller wake distribution for the upstream propeller
    prop_copy = copy.deepcopy(prop)
    VD = Data()
    cpts = 1  # only testing one condition
    number_of_wake_timesteps = 100
    init_timestep_offset = 0
    time = 10

    props = SUAVE.Core.Container()
    props.append(prop_copy)

    identical_props = True
    WD, dt, ts, B, Nr = generate_propeller_wake_distribution(
        props, identical_props, cpts, VD, init_timestep_offset, time,
        number_of_wake_timesteps, conditions)
    prop.start_angle = prop_copy.start_angle

    # compute the wake induced velocities:
    VD.YC = grid_points.ymesh
    VD.ZC = grid_points.zmesh
    VD.XC = x_plane * np.ones_like(VD.YC)
    VD.n_cp = np.size(VD.YC)
    V_ind = compute_wake_induced_velocity(WD, VD, cpts)
    u = V_ind[0, :, 0]
    v = V_ind[0, :, 1]
    w = V_ind[0, :, 2]

    propeller_wake = Data()
    propeller_wake.u_velocities = u
    propeller_wake.v_velocities = v
    propeller_wake.w_velocities = w
    propeller_wake.VD = VD

    if plot_velocities:
        # plot the velocities input to downstream propeller
        plot_propeller_disc_inflow(prop, propeller_wake, grid_points)

    return propeller_wake
Example #60
0
class Segment(Lofted_Body.Segment):
    def __defaults__(self):
        """This sets the default for wing segments in SUAVE.

        Assumptions:
        None

        Source:
        N/A

        Inputs:
        None

        Outputs:
        None

        Properties Used:
        N/A
        """
        self.tag = 'segment'
        self.percent_span_location = 0.0
        self.twist = 0.0
        self.root_chord_percent = 0.0
        self.dihedral_outboard = 0.0
        self.sweeps = Data()
        self.sweeps.quarter_chord = 0.0
        self.sweeps.leading_edge = None
        self.areas = Data()
        self.areas.reference = 0.0
        self.areas.exposed = 0.0
        self.areas.wetted = 0.0
        self.Airfoil = SUAVE.Core.ContainerOrdered()

        self.control_surfaces = Data()

    def append_airfoil(self, airfoil):
        """ Adds an airfoil to the segment

        Assumptions:
        None

        Source:
        N/A

        Inputs:
        None

        Outputs:
        None

        Properties Used:
        N/A
        """
        # assert database type
        if not isinstance(airfoil, Data):
            raise Exception('input component must be of type Data()')

        # store data
        self.Airfoil.append(airfoil)

    def append_control_surface(self, control_surface):
        """ Adds an control_surface to the segment
        
        Assumptions:
        None
        
        Source:
        N/A
        
        Inputs:
        None
        
        Outputs:
        None
        
        Properties Used:
        N/A
        """
        # assert database type
        if not isinstance(control_surface, Data):
            raise Exception('input component must be of type Data()')

        # store data
        self.control_surfaces.append(control_surface)
        return