コード例 #1
0
    def __defaults__(self):
        self.tag = ' U.S. Standard Atmosphere (1976)'

        # break point data: 
        self.fluid_properties = Air()
        self.planet = Earth()
        self.breaks = Data()
        self.breaks.altitude    = np.array(   [-2.00    , 0.00,     11.00,      20.00,      32.00,      47.00,      51.00,      71.00,      84.852]) * Units.km     # m, geopotential altitude
        self.breaks.temperature = np.array(   [301.15   , 288.15,   216.65,     216.65,     228.65,     270.65,     270.65,     214.65,     186.95])      # K
        self.breaks.pressure    = np.array(   [127774.0 , 101325.0, 22632.1,    5474.89,    868.019,    110.906,    66.9389,    3.95642,    0.3734])      # Pa
        self.breaks.density     = np.array( [1.47808e0, 1.2250e0, 3.63918e-1, 8.80349e-2, 1.32250e-2, 1.42753e-3, 8.61606e-4, 6.42099e-5, 6.95792e-6])  # kg/m^3
コード例 #2
0
ファイル: Fuel_Cell.py プロジェクト: spendres/SUAVE
    def __defaults__(self):
        self.tag = 'Fuel Cell'
        self.propellant = Gaseous_H2()
        self.oxidizer = Air()
        self.MaxPower = 0.  #maximum power fuel cell is capable of outputting [W]
        """
        self.tag='Fuel_Cell'
        self.type='H2'                     #only uses a Hydrogen fuel cell for now
        self.Power=0
        self.SpecificPower = 2.08          # kW/kg
        self.eff=0.6                       #stack efficiency
        self.MassDensity =1203.208556      # kg/m^3
        self.Volume = 0.034                # m^3
        self.Fuel = Propellant()
        """

        print self.propellant.tag
        if self.propellant.tag == 'H2 Gas':
            self.efficiency = .65  #normal fuel cell operating efficiency at sea level
            self.SpecificPower = 2.08  #specific power of fuel cell [kW/kg]; default is Nissan 2011 level
            self.MassDensity = 1203.208556  #take default as specs from Nissan 2011 fuel cell
            self.Volume = .034

        else:
            self.SpecificPower = 0.0
            self.eff = 0.0
            self.MassDensity = 0.0
            self.Volume = 0.0
コード例 #3
0
ファイル: Fuel_Cell.py プロジェクト: zpgcl97001/SUAVE
    def __defaults__(self):
        """This sets the default values for the component to function.

        Assumptions:
        None

        Source:
        Some default values come from a Nissan 2011 fuel cell

        Inputs:
        None

        Outputs:
        None

        Properties Used:
        None
        """
        self.propellant = Gaseous_H2()
        self.oxidizer = Air()
        self.efficiency = .65  # normal fuel cell operating efficiency at sea level
        self.specific_power = 2.08 * Units.kW / Units.kg  # specific power of fuel cell [kW/kg]; default is Nissan 2011 level
        self.mass_density = 1203.208556 * Units.kg / Units.m**3.  # take default as specs from Nissan 2011 fuel cell
        self.volume = 0.0
        self.max_power = 0.0
        self.discharge_model = zero_fidelity
コード例 #4
0
    def __defaults__(self):
        """This sets the default values at breaks in the atmosphere.

        Assumptions:
        Constant temperature

        Source:
        U.S. Standard Atmosphere (1976 version)

        Inputs:
        None

        Outputs:
        None

        Properties Used:
        None
        """          
        self.fluid_properties = Air()
        self.planet = Earth()
        self.breaks = Data()
        self.breaks.altitude    = np.array( [-2.00    , 0.00,     11.00,      20.00,      32.00,      47.00,      51.00,      71.00,      84.852]) * Units.km     # m, geopotential altitude
        self.breaks.temperature = np.array( [301.15   , 301.15,    301.15,    301.15,     301.15,     301.15,     301.15,     301.15,     301.15])      # K
        self.breaks.pressure    = np.array( [127774.0 , 101325.0, 22632.1,    5474.89,    868.019,    110.906,    66.9389,    3.95642,    0.3734])      # Pa
        self.breaks.density     = np.array( [1.545586 , 1.2256523,.273764,	 .0662256,	0.0105000 ,	1.3415E-03,	8.0971E-04,	4.78579E-05, 4.51674E-06]) #kg/m^3
コード例 #5
0
 def __defaults__(self):
     self.fluid_properties = Air()
     self.planet = Earth()
     self.breaks = Data()
     self.breaks.altitude    = np.array( [-2.00    , 0.00,     11.00,      20.00,      32.00,      47.00,      51.00,      71.00,      84.852]) * Units.km     # m, geopotential altitude
     self.breaks.temperature = np.array( [301.15   , 301.15,    301.15,    301.15,     301.15,     301.15,     301.15,     301.15,     301.15])      # K
     self.breaks.pressure    = np.array( [127774.0 , 101325.0, 22632.1,    5474.89,    868.019,    110.906,    66.9389,    3.95642,    0.3734])      # Pa
     self.breaks.density     = np.array( [1.545586 , 1.2256523,.273764,	 .0662256,	0.0105000 ,	1.3415E-03,	8.0971E-04,	4.78579E-05, 4.51674E-06]) #kg/m^3
コード例 #6
0
ファイル: Fuel_Cell.py プロジェクト: tristanpaine/SUAVE
 def __defaults__(self):
     self.propellant = Gaseous_H2()
     self.oxidizer = Air()
     self.efficiency = .65  #normal fuel cell operating efficiency at sea level
     self.specific_power = 2.08 * Units.kW / Units.kg  #specific power of fuel cell [kW/kg]; default is Nissan 2011 level
     self.mass_density = 1203.208556 * Units.kg / Units.m**3.  #take default as specs from Nissan 2011 fuel cell
     self.volume = 0.0
     self.max_power = 0.0
     self.discharge_model = zero_fidelity
コード例 #7
0
ファイル: US_Standard_1976.py プロジェクト: thearn/SUAVE
    def __defaults__(self):
        self.tag = ' U.S. Standard Atmosphere (1976)'

        # break point data: 
        self.gas = Air()
        self.planet = Earth()
        self.z_breaks = np.array(   [-2.00    , 0.00,     11.00,      20.00,      32.00,      47.00,      51.00,      71.00,      84.852]) * Units.km     # m, geopotential altitude
        self.T_breaks = np.array(   [301.15   , 288.15,   216.65,     216.65,     228.65,     270.65,     270.65,     214.65,     186.95])      # K
        self.p_breaks = np.array(   [127774.0 , 101325.0, 22632.1,    5474.89,    868.019,    110.906,    66.9389,    3.95642,    0.3734])      # Pa
        self.rho_breaks = np.array( [1.47808e0, 1.2250e0, 3.63918e-1, 8.80349e-2, 1.32250e-2, 1.42753e-3, 8.61606e-4, 6.42099e-5, 6.95792e-6])  # kg/m^3
コード例 #8
0
    def __defaults__(self):

        self.tag = 'Fuel Cell'
        self.propellant = Gaseous_H2()
        self.oxidizer = Air()
        self.type='H2'                #only uses a Hydrogen fuel cell for now
        self.Ncell=0.0                #number of fuel cells in the stack
        self.A=875.                   # area of the fuel cell interface (cm^2)
        self.Prat=2.                  # fuel cell compressor ratio
        self.MassDensity = 0.0,       # kg/m^3
        self.SpecificPower = 0.0,     # kW/kg
        self.Volume = 0.0             # m^3
        
        self.rhoc=1988.               # fuel cell density in kg/m^3
        self.zeta=.6                  # porosity coefficient
        self.twall=.0022224           # thickness of cell wall in meters
        if self.propellant.tag=='H2 Gas'or 'H2':
            self.r=2.45E-4            # area specific resistance [k-Ohm-cm^2]
            self.Eoc=.931             # effective activation energy (V)
            self.A1=.03               # slope of the Tafel line (models activation losses) (V)
            self.m=1.05E-4            # constant in mass-transfer overvoltage equation (V)
            self.n=8E-3               # constant in mass-transfer overvoltage equation
コード例 #9
0
    def __defaults__(self):

        self.tag = 'Generic_Lithium_Ion_Battery_Cell'
        self.cell = Data()
        self.module = Data()
        self.pack_config = Data()
        self.module_config = Data()

        self.age = 0  # [days]
        self.cell.mass = None
        self.cell.charging_SOC_cutoff = 1.
        self.cell.charging_current = 3.0  # [Amps]
        self.cell.charging_voltage = 3  # [Volts]

        self.convective_heat_transfer_coefficient = 35.  # [W/m^2K]
        self.heat_transfer_efficiency = 1.0

        self.pack_config.series = 1
        self.pack_config.parallel = 1
        self.pack_config.total = 1
        self.module_config.total = 1
        self.module_config.normal_count = 1  # number of cells normal to flow
        self.module_config.parallel_count = 1  # number of cells parallel to flow
        self.module_config.normal_spacing = 0.02
        self.module_config.parallel_spacing = 0.02

        self.cooling_fluid = Air()
        self.cooling_fluid.cooling_flowspeed = 0.01

        # defaults that are overwritten if specific cell chemistry is used
        self.specific_energy = 200. * Units.Wh / Units.kg
        self.specific_power = 1. * Units.kW / Units.kg
        self.ragone.const_1 = 88.818 * Units.kW / Units.kg
        self.ragone.const_2 = -.01533 / (Units.Wh / Units.kg)
        self.ragone.lower_bound = 60. * Units.Wh / Units.kg
        self.ragone.upper_bound = 225. * Units.Wh / Units.kg
        return
コード例 #10
0
# Modified:

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

# local imports
from compressible_turbulent_flat_plate import compressible_turbulent_flat_plate

# suave imports

from compressible_turbulent_flat_plate import compressible_turbulent_flat_plate

from SUAVE.Attributes.Gases import Air  # you should let the user pass this as input
from SUAVE.Attributes.Results.Result import Result
air = Air()
compute_speed_of_sound = air.compute_speed_of_sound

# python imports
import os, sys, shutil
from copy import deepcopy
from warnings import warn

# package imports
import numpy as np
import scipy as sp

# ----------------------------------------------------------------------
#   The Function
# ----------------------------------------------------------------------
コード例 #11
0
ファイル: US_Standard_1976.py プロジェクト: thearn/SUAVE
class US_Standard_1976(Atmosphere):

    """ Implements the U.S. Standard Atmosphere (1976 version)
    """
    
    def __defaults__(self):
        self.tag = ' U.S. Standard Atmosphere (1976)'

        # break point data: 
        self.gas = Air()
        self.planet = Earth()
        self.z_breaks = np.array(   [-2.00    , 0.00,     11.00,      20.00,      32.00,      47.00,      51.00,      71.00,      84.852]) * Units.km     # m, geopotential altitude
        self.T_breaks = np.array(   [301.15   , 288.15,   216.65,     216.65,     228.65,     270.65,     270.65,     214.65,     186.95])      # K
        self.p_breaks = np.array(   [127774.0 , 101325.0, 22632.1,    5474.89,    868.019,    110.906,    66.9389,    3.95642,    0.3734])      # Pa
        self.rho_breaks = np.array( [1.47808e0, 1.2250e0, 3.63918e-1, 8.80349e-2, 1.32250e-2, 1.42753e-3, 8.61606e-4, 6.42099e-5, 6.95792e-6])  # kg/m^3
    
    def compute_values(self,altitude,type="all"):

        """ Computes values from the International Standard Atmosphere

        Inputs:
            altitude     : geometric altitude (elevation) (m)
                           can be a float, list or 1D array of floats
         
        Outputs:
            list of conditions -
                pressure       : static pressure (Pa)
                temperature    : static temperature (K)
                density        : density (kg/m^3)
                speed_of_sound : speed of sound (m/s)
                viscosity      : viscosity (kg/m-s)
            
        Example:
            atmosphere = SUAVE.Attributes.Atmospheres.Earth.USStandard1976()
            atmosphere.ComputeValues(1000).pressure
          
        """

        # unpack
        zs   = altitude
        gas  = self.gas
        grav = self.planet.sea_level_gravity
        Rad  = self.planet.mean_radius

        # return options
        all_vars = ["all", "everything"]
        pressure = ["p", "pressure"]
        temp = ["t", "temp", "temperature"]
        density = ["rho", "density"]
        speed_of_sound = ["speed_of_sound", "a"]
        viscosity = ["viscosity", "mew"]

        # some up-front logic for outputs based on thermo
        need_p = True; need_T = True; need_rho = True; need_a = True; need_mew = True;
        if type.lower() in pressure:
            need_T = False; need_rho = False; need_a = False; need_mew = False
        elif type.lower() in temp:
            need_p = False; need_rho = False; need_a = False; need_mew = False
        elif type.lower() in density:
            need_a = False; need_mew = False
        elif type.lower() in speed_of_sound:
            need_p = False; need_rho = False; need_mew = False
        elif type.lower() in viscosity:
            need_p = False; need_rho = False; need_a = False

        # convert input if necessary
        if isinstance(zs, int): 
            zs = np.array([float(zs)])
        elif isinstance(zs, float):
            zs = np.array([zs])

        # convert geometric to geopotential altitude
        zs = zs/(1 + zs/Rad)

        # initialize return data
        p = np.array([])
        T = np.array([])
        rho = np.array([])
        a = np.array([])
        mew = np.array([])
        
        # evaluate at each altitude
        for z in zs:
            
            # check altitude range
            too_low = False; too_high = False
            if (z < self.z_breaks[0]):
                too_low = True
                print "Warning: altitude requested below minimum for this atmospheric model; returning values for h = -2.0 km"
            elif (z > self.z_breaks[-1]):
                too_high = True
                print "Warning: altitude requested above maximum for this atmospheric model; returning values for h = 86.0 km"
            else:
                # loop through breaks
                for i in range(len(self.z_breaks)):
                    if z >= self.z_breaks[i] and z < self.z_breaks[i+1]:
                        z0 = self.z_breaks[i]; T0 = self.T_breaks[i]; p0 = self.p_breaks[i]
                        alpha = -(self.T_breaks[i+1] - self.T_breaks[i])/ \
                            (self.z_breaks[i+1] - self.z_breaks[i])     # lapse rate K/km
                        dz = z - z0
                        break

            # pressure
            if need_p:
                if too_low:
                    pz = self.p_breaks[0]
                elif too_high:
                    pz = self.p_breaks[-1]
                else:
                    if alpha == 0.0:
                        pz = p0*np.exp(-1*dz*grav/(gas.R*T0))
                    else:
                        pz = p0*((1 - alpha*dz/T0)**(1*grav/(alpha*gas.R)))
                p = np.append(p,pz)

            # temperature
            if need_T:
                if too_low:
                    Tz = self.T_breaks[0]
                elif too_high:
                    Tz = self.T_breaks[-1]
                else:
                    Tz = T0 - dz*alpha      # note: alpha = lapse rate (negative)
                T = np.append(T,Tz)

            if need_rho:
                if too_low:
                    rho = np.append(rho,self.rho_breaks[0])
                elif too_high:
                    rho = np.append(rho,self.rho_breaks[-1])
                else:
                    rho = np.append(rho,self.gas.compute_density(Tz,pz))
            
            if need_a:
                a = np.append(a,self.gas.compute_speed_of_sound(Tz))

            if need_mew:
                mew = np.append(mew,self.gas.compute_absolute_viscosity(Tz))

        # for each altitude

        # return requested data
        if type.lower() in all_vars:
            return (p, T, rho, a, mew)

        if type.lower() in pressure:
            return p
                      
        elif type.lower() in temp:
            return T

        elif type.lower() in density:
            return rho
            
        elif type.lower() in speed_of_sound:
            return a

        elif type.lower() in viscosity:
            return mew

        else:
            raise Exception , "Unknown atmosphere data type, " + type
コード例 #12
0
 def __defaults__(self):
     self.tag = 'Propulsor'
     self.breathing = True
     self.gas = Air()
コード例 #13
0
class US_Standard_1976(Atmosphere):

    """ Implements the U.S. Standard Atmosphere (1976 version)
    """
    
    def __defaults__(self):
        self.tag = ' U.S. Standard Atmosphere (1976)'

        # break point data: 
        self.fluid_properties = Air()
        self.planet = Earth()
        self.breaks = Data()
        self.breaks.altitude    = np.array(   [-2.00    , 0.00,     11.00,      20.00,      32.00,      47.00,      51.00,      71.00,      84.852]) * Units.km     # m, geopotential altitude
        self.breaks.temperature = np.array(   [301.15   , 288.15,   216.65,     216.65,     228.65,     270.65,     270.65,     214.65,     186.95])      # K
        self.breaks.pressure    = np.array(   [127774.0 , 101325.0, 22632.1,    5474.89,    868.019,    110.906,    66.9389,    3.95642,    0.3734])      # Pa
        self.breaks.density     = np.array( [1.47808e0, 1.2250e0, 3.63918e-1, 8.80349e-2, 1.32250e-2, 1.42753e-3, 8.61606e-4, 6.42099e-5, 6.95792e-6])  # kg/m^3
    
    def compute_values(self,altitude,type="all"):

        """ Computes values from the International Standard Atmosphere

        Inputs:
            altitude     : geometric altitude (elevation) (m)
                           can be a float, list or 1D array of floats
         
        Outputs:
            list of conditions -
                pressure       : static pressure (Pa)
                temperature    : static temperature (K)
                density        : density (kg/m^3)
                speed_of_sound : speed of sound (m/s)
                viscosity      : viscosity (kg/m-s)
            
        Example:
            atmosphere = SUAVE.Attributes.Atmospheres.Earth.USStandard1976()
            atmosphere.ComputeValues(1000).pressure
          
        """

        # unpack
        zs   = altitude
        gas  = self.fluid_properties
        grav = self.planet.sea_level_gravity
        Rad  = self.planet.mean_radius

        # return options
        all_vars = ["all", "everything"]
        pressure = ["p", "pressure"]
        temp = ["t", "temp", "temperature"]
        density = ["rho", "density"]
        speed_of_sound = ["speed_of_sound", "a"]
        viscosity = ["viscosity", "mew"]

        # some up-front logic for outputs based on thermo
        need_p = True; need_T = True; need_rho = True; need_a = True; need_mew = True;
        if type.lower() in pressure:
            need_T = False; need_rho = False; need_a = False; need_mew = False
        elif type.lower() in temp:
            need_p = False; need_rho = False; need_a = False; need_mew = False
        elif type.lower() in density:
            need_a = False; need_mew = False
        elif type.lower() in speed_of_sound:
            need_p = False; need_rho = False; need_mew = False
        elif type.lower() in viscosity:
            need_p = False; need_rho = False; need_a = False

        # convert input if necessary
        if isinstance(zs, int): 
            zs = np.array([float(zs)])
        elif isinstance(zs, float):
            zs = np.array([zs])

        # convert geometric to geopotential altitude
        zs = zs/(1 + zs/Rad)

        # initialize return data
        p = np.array([])
        T = np.array([])
        rho = np.array([])
        a = np.array([])
        mew = np.array([])
        
        # evaluate at each altitude
        for z in zs:
            
            # check altitude range
            too_low = False; too_high = False
            if (z < self.breaks.altitude[0]):
                too_low = True
                print "Warning: altitude requested below minimum for this atmospheric model; returning values for h = -2.0 km"
            elif (z > self.breaks.altitude[-1]):
                too_high = True
                print "Warning: altitude requested above maximum for this atmospheric model; returning values for h = 86.0 km"
            else:
                # loop through breaks
                for i in range(len(self.breaks.altitude)):
                    if z >= self.breaks.altitude[i] and z < self.breaks.altitude[i+1]:
                        z0 = self.breaks.altitude[i]; T0 = self.breaks.temperature[i]; p0 = self.breaks.pressure[i]
                        alpha = -(self.breaks.temperature[i+1] - self.breaks.temperature[i])/ \
                            (self.breaks.altitude[i+1] - self.breaks.altitude[i])     # lapse rate K/km
                        dz = z - z0
                        break

            # pressure
            if need_p:
                if too_low:
                    pz = self.breaks.pressure[0]
                elif too_high:
                    pz = self.breaks.pressure[-1]
                else:
                    if alpha == 0.0:
                        pz = p0*np.exp(-1*dz*grav/(gas.gas_specific_constant*T0))
                    else:
                        pz = p0*((1 - alpha*dz/T0)**(1*grav/(alpha*gas.gas_specific_constant)))
                p = np.append(p,pz)

            # temperature
            if need_T:
                if too_low:
                    Tz = self.breaks.temperature[0]
                elif too_high:
                    Tz = self.breaks.temperature[-1]
                else:
                    Tz = T0 - dz*alpha      # note: alpha = lapse rate (negative)
                T = np.append(T,Tz)

            if need_rho:
                if too_low:
                    rho = np.append(rho,self.breaks.density[0])
                elif too_high:
                    rho = np.append(rho,self.breaks.density[-1])
                else:
                    rho = np.append(rho,self.fluid_properties.compute_density(Tz,pz))
            
            if need_a:
                a = np.append(a,self.fluid_properties.compute_speed_of_sound(Tz))

            if need_mew:
                mew = np.append(mew,self.fluid_properties.compute_absolute_viscosity(Tz))

        # for each altitude

        # return requested data
        if type.lower() in all_vars:
            return (p, T, rho, a, mew)

        if type.lower() in pressure:
            return p
                      
        elif type.lower() in temp:
            return T

        elif type.lower() in density:
            return rho
            
        elif type.lower() in speed_of_sound:
            return a

        elif type.lower() in viscosity:
            return mew

        else:
            raise Exception , "Unknown atmosphere data type, " + type
コード例 #14
0
def setup_vehicle():

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

    # Create a vehicle and set level properties
    vehicle = SUAVE.Vehicle()
    vehicle.tag = 'eVTOL'

    # ------------------------------------------------------------------
    #   Vehicle-level Properties
    # ------------------------------------------------------------------
    # mass properties
    vehicle.mass_properties.takeoff = 2500. * Units.lb
    vehicle.mass_properties.operating_empty = 2150. * Units.lb
    vehicle.mass_properties.max_takeoff = 2500. * Units.lb
    vehicle.mass_properties.max_payload = 100. * Units.lb
    vehicle.mass_properties.center_of_gravity = [[2.0, 0.,
                                                  0.]]  # I made this up

    # basic parameters
    vehicle.envelope.ultimate_load = 5.7
    vehicle.envelope.limit_load = 3.

    # ------------------------------------------------------------------
    # WINGS
    # ------------------------------------------------------------------
    # WING PROPERTIES
    wing = SUAVE.Components.Wings.Main_Wing()
    wing.tag = 'main_wing'
    wing.origin = [[1.5, 0., -0.5]]
    wing.spans.projected = 35.0 * Units.feet
    wing.chords.root = 3.25 * Units.feet

    # Segment
    segment = SUAVE.Components.Wings.Segment()
    segment.tag = 'Root'
    segment.percent_span_location = 0.
    segment.twist = 0.
    segment.root_chord_percent = 1.5
    segment.dihedral_outboard = 1.0 * Units.degrees
    segment.sweeps.quarter_chord = 8.5 * Units.degrees
    segment.thickness_to_chord = 0.18
    wing.Segments.append(segment)

    # Segment
    segment = SUAVE.Components.Wings.Segment()
    segment.tag = 'Section_2'
    segment.percent_span_location = 0.227
    segment.twist = 0.
    segment.root_chord_percent = 1.
    segment.dihedral_outboard = 1.0 * Units.degrees
    segment.sweeps.quarter_chord = 0.0 * Units.degrees
    segment.thickness_to_chord = 0.12
    wing.Segments.append(segment)

    # Segment
    segment = SUAVE.Components.Wings.Segment()
    segment.tag = 'Tip'
    segment.percent_span_location = 1.0
    segment.twist = 0.
    segment.root_chord_percent = 1.0
    segment.dihedral_outboard = 0.0 * Units.degrees
    segment.sweeps.quarter_chord = 0.0 * Units.degrees
    segment.thickness_to_chord = 0.12
    wing.Segments.append(segment)

    # Fill out more segment properties automatically
    wing = segment_properties(wing)
    wing = wing_segmented_planform(wing)

    ## ALSO SET THE VEHICLE REFERENCE AREA
    vehicle.reference_area = wing.areas.reference

    # add to vehicle
    vehicle.append_component(wing)

    # Add a horizontal tail
    # WING PROPERTIES
    wing = SUAVE.Components.Wings.Horizontal_Tail()
    wing.tag = 'horizontal_tail'
    wing.areas.reference = 2.0
    wing.taper = 0.5
    wing.sweeps.quarter_chord = 20. * Units.degrees
    wing.aspect_ratio = 5.0
    wing.thickness_to_chord = 0.12
    wing.dihedral = 5. * Units.degrees
    wing.origin = [[5.5, 0.0, 0.65]]

    # Fill out more segment properties automatically
    wing = wing_planform(wing)

    # add to vehicle
    vehicle.append_component(wing)

    # Add a vertical tail
    wing = SUAVE.Components.Wings.Vertical_Tail()
    wing.tag = 'vertical_tail'
    wing.areas.reference = 1.0
    wing.taper = 0.5
    wing.sweeps.quarter_chord = 30 * Units.degrees
    wing.aspect_ratio = 2.5
    wing.thickness_to_chord = 0.12
    wing.origin = [[5.5, 0.0, 0.65]]

    # Fill out more segment properties automatically
    wing = wing_planform(wing)

    # add to vehicle
    vehicle.append_component(wing)

    # Add a fuseelage

    # ---------------------------------------------------------------
    # FUSELAGE
    # ---------------------------------------------------------------
    # FUSELAGE PROPERTIES
    fuselage = SUAVE.Components.Fuselages.Fuselage()
    fuselage.tag = 'fuselage'
    fuselage.seats_abreast = 2.
    fuselage.fineness.nose = 0.88
    fuselage.fineness.tail = 1.13
    fuselage.lengths.nose = 3.2 * Units.feet
    fuselage.lengths.tail = 6.4 * Units.feet
    fuselage.lengths.cabin = 6.4 * Units.feet
    fuselage.lengths.total = 6.0
    fuselage.width = 5.85 * Units.feet
    fuselage.heights.maximum = 4.65 * Units.feet
    fuselage.heights.at_quarter_length = 3.75 * Units.feet
    fuselage.heights.at_wing_root_quarter_chord = 4.65 * Units.feet
    fuselage.heights.at_three_quarters_length = 4.26 * Units.feet
    fuselage.areas.wetted = 236. * Units.feet**2
    fuselage.areas.front_projected = 0.14 * Units.feet**2
    fuselage.effective_diameter = 5.85 * Units.feet
    fuselage.differential_pressure = 0.

    # Segment
    segment = SUAVE.Components.Lofted_Body_Segment.Segment()
    segment.tag = 'segment_0'
    segment.percent_x_location = 0.
    segment.percent_z_location = -0.05
    segment.height = 0.1
    segment.width = 0.1
    fuselage.Segments.append(segment)

    # Segment
    segment = SUAVE.Components.Lofted_Body_Segment.Segment()
    segment.tag = 'segment_1'
    segment.percent_x_location = 0.06
    segment.percent_z_location = -0.05
    segment.height = 0.52
    segment.width = 0.75
    fuselage.Segments.append(segment)

    # Segment
    segment = SUAVE.Components.Lofted_Body_Segment.Segment()
    segment.tag = 'segment_2'
    segment.percent_x_location = 0.25
    segment.percent_z_location = -.01
    segment.height = 1.2
    segment.width = 1.43
    fuselage.Segments.append(segment)

    # Segment
    segment = SUAVE.Components.Lofted_Body_Segment.Segment()
    segment.tag = 'segment_3'
    segment.percent_x_location = 0.475
    segment.percent_z_location = 0
    segment.height = 1.4
    segment.width = 1.4
    fuselage.Segments.append(segment)

    # Segment
    segment = SUAVE.Components.Lofted_Body_Segment.Segment()
    segment.tag = 'segment_4'
    segment.percent_x_location = 0.75
    segment.percent_z_location = 0.06
    segment.height = 0.6
    segment.width = 0.4
    fuselage.Segments.append(segment)

    # Segment
    segment = SUAVE.Components.Lofted_Body_Segment.Segment()
    segment.tag = 'segment_5'
    segment.percent_x_location = 1.
    segment.percent_z_location = 0.1
    segment.height = 0.05
    segment.width = 0.05
    fuselage.Segments.append(segment)

    # add to vehicle
    vehicle.append_component(fuselage)

    #-------------------------------------------------------------------
    # Booms
    #-------------------------------------------------------------------
    # Add booms for the motors
    boom = SUAVE.Components.Fuselages.Fuselage()
    boom.tag = 'boom_R'
    boom.origin = [[0.525, 3.0, -0.35]]
    boom.lengths.nose = 0.2
    boom.lengths.tail = 0.2
    boom.lengths.total = 4
    boom.width = 0.15
    boom.heights.maximum = 0.15
    boom.heights.at_quarter_length = 0.15
    boom.heights.at_three_quarters_length = 0.15
    boom.heights.at_wing_root_quarter_chord = 0.15
    boom.effective_diameter = 0.15
    boom.areas.wetted = 2 * np.pi * (0.075) * 3.5
    boom.areas.front_projected = np.pi * 0.15
    boom.fineness.nose = 0.15 / 0.2
    boom.fineness.tail = 0.15 / 0.2

    vehicle.append_component(boom)

    # Now attach the mirrored boom
    other_boom = deepcopy(boom)
    other_boom.origin[0][1] = -boom.origin[0][1]
    other_boom.tag = 'boom_L'
    vehicle.append_component(other_boom)

    #------------------------------------------------------------------
    # Network
    #------------------------------------------------------------------
    net = SUAVE.Components.Energy.Networks.Lift_Cruise()
    net.number_of_lift_rotor_engines = 4
    net.number_of_propeller_engines = 1
    net.identical_propellers = True
    net.identical_lift_rotors = True
    net.voltage = 400.

    #------------------------------------------------------------------
    # Electronic Speed Controller
    #------------------------------------------------------------------
    lift_rotor_esc = SUAVE.Components.Energy.Distributors.Electronic_Speed_Controller(
    )
    lift_rotor_esc.efficiency = 0.95
    net.lift_rotor_esc = lift_rotor_esc

    propeller_esc = SUAVE.Components.Energy.Distributors.Electronic_Speed_Controller(
    )
    propeller_esc.efficiency = 0.95
    net.propeller_esc = propeller_esc

    #------------------------------------------------------------------
    # Payload
    #------------------------------------------------------------------
    payload = SUAVE.Components.Energy.Peripherals.Avionics()
    payload.power_draw = 0.
    net.payload = payload

    #------------------------------------------------------------------
    # Avionics
    #------------------------------------------------------------------
    avionics = SUAVE.Components.Energy.Peripherals.Avionics()
    avionics.power_draw = 300. * Units.watts
    net.avionics = avionics

    #------------------------------------------------------------------
    # Design Battery
    #------------------------------------------------------------------
    bat = SUAVE.Components.Energy.Storages.Batteries.Constant_Mass.Lithium_Ion_LiNiMnCoO2_18650(
    )
    bat.mass_properties.mass = 1000. * Units.lb
    bat.max_voltage = net.voltage
    initialize_from_mass(bat)
    net.battery = bat

    #------------------------------------------------------------------
    # Design Rotors and Propellers
    #------------------------------------------------------------------

    # The tractor propeller
    propeller = SUAVE.Components.Energy.Converters.Propeller()
    propeller.origin = [[0, 0, -0.325]]
    propeller.number_of_blades = 3
    propeller.tip_radius = 0.9
    propeller.hub_radius = 0.1
    propeller.angular_velocity = 2200 * Units.rpm
    propeller.freestream_velocity = 100. * Units.knots
    propeller.design_Cl = 0.7
    propeller.design_altitude = 5000. * Units.feet
    propeller.design_thrust = 500. * Units.lbf
    propeller.airfoil_geometry = ['./Airfoils/NACA_4412.txt']
    propeller.airfoil_polars = [[
        './Airfoils/Polars/NACA_4412_polar_Re_50000.txt',
        './Airfoils/Polars/NACA_4412_polar_Re_100000.txt',
        './Airfoils/Polars/NACA_4412_polar_Re_200000.txt',
        './Airfoils/Polars/NACA_4412_polar_Re_500000.txt',
        './Airfoils/Polars/NACA_4412_polar_Re_1000000.txt'
    ]]
    propeller.airfoil_polar_stations = np.zeros((20), dtype=np.int8).tolist()
    propeller = propeller_design(propeller)
    net.propellers.append(propeller)

    # The lift rotors
    lift_rotor = SUAVE.Components.Energy.Converters.Lift_Rotor()
    lift_rotor.tip_radius = 1.5
    lift_rotor.hub_radius = 0.15
    lift_rotor.number_of_blades = 4
    lift_rotor.design_tip_mach = 0.65
    lift_rotor.freestream_velocity = 500. * Units['ft/min']
    lift_rotor.angular_velocity = lift_rotor.design_tip_mach * Air(
    ).compute_speed_of_sound() / lift_rotor.tip_radius
    lift_rotor.design_Cl = 0.7
    lift_rotor.design_altitude = 3000. * Units.feet
    lift_rotor.design_thrust = 2500 * Units.lbf / 4
    lift_rotor.variable_pitch = False
    lift_rotor.airfoil_geometry = ['./Airfoils/NACA_4412.txt']
    lift_rotor.airfoil_polars = [[
        './Airfoils/Polars/NACA_4412_polar_Re_50000.txt',
        './Airfoils/Polars/NACA_4412_polar_Re_100000.txt',
        './Airfoils/Polars/NACA_4412_polar_Re_200000.txt',
        './Airfoils/Polars/NACA_4412_polar_Re_500000.txt',
        './Airfoils/Polars/NACA_4412_polar_Re_1000000.txt'
    ]]

    lift_rotor.airfoil_polar_stations = np.zeros((20), dtype=np.int8).tolist()
    lift_rotor = propeller_design(lift_rotor)

    # Appending rotors with different origins
    rotations = [1, -1, -1, 1]
    origins = [[0.6, 3., -0.125], [4.5, 3., -0.125], [0.6, -3., -0.125],
               [4.5, -3., -0.125]]

    for ii in range(4):
        lift_rotor = deepcopy(lift_rotor)
        lift_rotor.tag = 'lift_rotor'
        lift_rotor.rotation = rotations[ii]
        lift_rotor.origin = [origins[ii]]
        net.lift_rotors.append(lift_rotor)

    #------------------------------------------------------------------
    # Design Motors
    #------------------------------------------------------------------
    # Propeller (Thrust) motor
    propeller_motor = SUAVE.Components.Energy.Converters.Motor()
    propeller_motor.efficiency = 0.95
    propeller_motor.nominal_voltage = bat.max_voltage
    propeller_motor.mass_properties.mass = 2.0 * Units.kg
    propeller_motor.origin = propeller.origin
    propeller_motor.propeller_radius = propeller.tip_radius
    propeller_motor.no_load_current = 2.0
    propeller_motor = size_optimal_motor(propeller_motor, propeller)
    net.propeller_motors.append(propeller_motor)

    # Rotor (Lift) Motor
    lift_rotor_motor = SUAVE.Components.Energy.Converters.Motor()
    lift_rotor_motor.efficiency = 0.85
    lift_rotor_motor.nominal_voltage = bat.max_voltage * 3 / 4
    lift_rotor_motor.mass_properties.mass = 3. * Units.kg
    lift_rotor_motor.origin = lift_rotor.origin
    lift_rotor_motor.propeller_radius = lift_rotor.tip_radius
    lift_rotor_motor.gearbox_efficiency = 1.0
    lift_rotor_motor.no_load_current = 4.0
    lift_rotor_motor = size_optimal_motor(lift_rotor_motor, lift_rotor)

    for _ in range(4):
        lift_rotor_motor = deepcopy(lift_rotor_motor)
        lift_rotor_motor.tag = 'motor'
        net.lift_rotor_motors.append(lift_rotor_motor)

    vehicle.append_component(net)

    # Now account for things that have been overlooked for now:
    vehicle.excrescence_area = 0.1

    return vehicle
コード例 #15
0
    def compute_values(self,altitude,temperature=288.15):

        """Computes atmospheric values.
    
        Assumptions:
        Constant temperature atmosphere
    
        Source:
        U.S. Standard Atmosphere, 1976, U.S. Government Printing Office, Washington, D.C., 1976
    
        Inputs:
        altitude                                 [m]
        temperature                              [K]

        Outputs:
        atmo_data.
          pressure                               [Pa]
          temperature                            [K]
          speed_of_sound                         [m/s]
          dynamic_viscosity                      [kg/(m*s)]
    
        Properties Used:
        self.
          fluid_properties.gas_specific_constant [J/(kg*K)]
          planet.sea_level_gravity               [m/s^2]
          planet.mean_radius                     [m]
          breaks.
            altitude                             [m]
            pressure                             [Pa]
        """

        # unpack
        zs        = altitude
        gas       = self.fluid_properties
        planet    = self.planet
        grav      = self.planet.sea_level_gravity        
        Rad       = self.planet.mean_radius
        R         = gas.gas_specific_constant
        
        # check properties
        if not gas == Air():
            warn('Constant_Temperature Atmosphere not using Air fluid properties')
        if not planet == Earth():
            warn('Constant_Temperature Atmosphere not using Earth planet properties')          
        
        # convert input if necessary
        zs = atleast_2d_col(zs)

        # get model altitude bounds
        zmin = self.breaks.altitude[0]
        zmax = self.breaks.altitude[-1]   
        
        # convert geometric to geopotential altitude
        zs = zs/(1 + zs/Rad)
        
        # check ranges
        if np.amin(zs) < zmin:
            print "Warning: altitude requested below minimum for this atmospheric model; returning values for h = -2.0 km"
            zs[zs < zmin] = zmin
        if np.amax(zs) > zmax:
            print "Warning: altitude requested above maximum for this atmospheric model; returning values for h = 86.0 km"   
            zs[zs > zmax] = zmax        

        # initialize return data
        zeros = np.zeros_like(zs)
        p     = zeros * 0.0
        T     = zeros * 0.0
        rho   = zeros * 0.0
        a     = zeros * 0.0
        mu    = zeros * 0.0
        z0    = zeros * 0.0
        T0    = zeros * 0.0
        p0    = zeros * 0.0
        alpha = zeros * 0.0
        
        # populate the altitude breaks
        # this uses >= and <= to capture both edges and because values should be the same at the edges
        for i in range( len(self.breaks.altitude)-1 ): 
            i_inside = (zs >= self.breaks.altitude[i]) & (zs <= self.breaks.altitude[i+1])
            z0[ i_inside ]    = self.breaks.altitude[i]
            T0[ i_inside ]    = temperature
            p0[ i_inside ]    = self.breaks.pressure[i]
            self.breaks.temperature[i+1]=temperature
            alpha[ i_inside ] = -(temperature - temperature)/ \
                                 (self.breaks.altitude[i+1]    - self.breaks.altitude[i])
        
        # interpolate the breaks
        dz = zs-z0
        i_isoth = (alpha == 0.)

        p = p0* np.exp(-1.*dz*grav/(R*T0))
       
        T   = temperature
        rho = gas.compute_density(T,p)
        a   = gas.compute_speed_of_sound(T)
        mu  = gas.compute_absolute_viscosity(T)
        

                
        atmo_data = Conditions()
        atmo_data.expand_rows(zs.shape[0])
        atmo_data.pressure          = p
        atmo_data.temperature       = T
        atmo_data.density           = rho
        atmo_data.speed_of_sound    = a
        atmo_data.dynamic_viscosity = mu
        
        return atmo_data
コード例 #16
0
    def compute_values(self,altitude,temperature_deviation = 0):

        """ Computes values from the International Standard Atmosphere

        Inputs:
            altitude     : geometric altitude (elevation) (m)
                           can be a float, list or 1D array of floats
            temperature_deviation :  delta_isa
         
        Outputs:
            list of conditions -
                pressure       : static pressure (Pa)
                temperature    : static temperature (K)
                density        : density (kg/m^3)
                speed_of_sound : speed of sound (m/s)
                dynamic_viscosity      : dynamic_viscosity (kg/m-s)
            
        Example:
            atmosphere = SUAVE.Attributes.Atmospheres.Earth.USStandard1976()
            atmosphere.ComputeValues(1000).pressure
          
        """

        # unpack
        zs   = altitude
        gas    = self.fluid_properties
        planet = self.planet
        grav   = self.planet.sea_level_gravity        
        Rad    = self.planet.mean_radius
        gamma  = gas.gas_specific_constant
        delta_isa = temperature_deviation
        
        # check properties
        if not gas == Air():
            warn('US Standard Atmosphere not using Air fluid properties')
        if not planet == Earth():
            warn('US Standard Atmosphere not using Earth planet properties')          
        
        # convert input if necessary
        zs = atleast_2d_col(zs)

        # get model altitude bounds
        zmin = self.breaks.altitude[0]
        zmax = self.breaks.altitude[-1]   
        
        # convert geometric to geopotential altitude
        zs = zs/(1 + zs/Rad)
        
        # check ranges
        if np.amin(zs) < zmin:
            print "Warning: altitude requested below minimum for this atmospheric model; returning values for h = -2.0 km"
            zs[zs < zmin] = zmin
        if np.amax(zs) > zmax:
            print "Warning: altitude requested above maximum for this atmospheric model; returning values for h = 86.0 km"   
            zs[zs > zmax] = zmax        

        # initialize return data
        zeros = np.zeros_like(zs)
        p     = zeros * 0.0
        T     = zeros * 0.0
        rho   = zeros * 0.0
        a     = zeros * 0.0
        mew   = zeros * 0.0
        z0    = zeros * 0.0
        T0    = zeros * 0.0
        p0    = zeros * 0.0
        alpha = zeros * 0.0
        
        # populate the altitude breaks
        # this uses >= and <= to capture both edges and because values should be the same at the edges
        for i in range( len(self.breaks.altitude)-1 ): 
            i_inside = (zs >= self.breaks.altitude[i]) & (zs <= self.breaks.altitude[i+1])
            z0[ i_inside ]    = self.breaks.altitude[i]
            T0[ i_inside ]    = self.breaks.temperature[i]
            p0[ i_inside ]    = self.breaks.pressure[i]
            alpha[ i_inside ] = -(self.breaks.temperature[i+1] - self.breaks.temperature[i])/ \
                                 (self.breaks.altitude[i+1]    - self.breaks.altitude[i])
        
        # interpolate the breaks
        dz = zs-z0
        i_isoth = (alpha == 0.)
        i_adiab = (alpha != 0.)
        p[i_isoth] = p0[i_isoth] * np.exp(-1.*dz[i_isoth]*grav/(gamma*T0[i_isoth]))
        p[i_adiab] = p0[i_adiab] * ( (1.-alpha[i_adiab]*dz[i_adiab]/T0[i_adiab]) **(1.*grav/(alpha[i_adiab]*gamma)) )
        
        T   = T0 - dz*alpha + delta_isa
        rho = gas.compute_density(T,p)
        a   = gas.compute_speed_of_sound(T)
        mew = gas.compute_absolute_viscosity(T)
        

                
        atmo_data = Conditions()
        atmo_data.expand_rows(zs.shape[0])
        atmo_data.pressure          = p
        atmo_data.temperature       = T
        atmo_data.density           = rho
        atmo_data.speed_of_sound    = a
        atmo_data.dynamic_viscosity = mew
        
        return atmo_data
コード例 #17
0
ファイル: US_Standard_1976.py プロジェクト: kushalam/SUAVE
    def compute_values(self,altitude,temperature_deviation=0.0,var_gamma=False):

        """Computes atmospheric values.

        Assumptions:
        US 1976 Standard Atmosphere

        Source:
        U.S. Standard Atmosphere, 1976, U.S. Government Printing Office, Washington, D.C., 1976

        Inputs:
        altitude                                 [m]
        temperature_deviation                    [K]

        Output:
        atmo_data.
          pressure                               [Pa]
          temperature                            [K]
          speed_of_sound                         [m/s]
          dynamic_viscosity                      [kg/(m*s)]
          kinematic_viscosity                    [m^2/s]
          thermal_conductivity                   [W/(m*K)]
          prandtl_number                         [-]
           
        Properties Used:
        self.
          fluid_properties.gas_specific_constant [J/(kg*K)]
          planet.sea_level_gravity               [m/s^2]
          planet.mean_radius                     [m]
          breaks.
            altitude                             [m]
            temperature                          [K]
            pressure                             [Pa]
        """

        # unpack
        zs        = altitude
        gas       = self.fluid_properties
        planet    = self.planet
        grav      = self.planet.sea_level_gravity        
        Rad       = self.planet.mean_radius
        R         = gas.gas_specific_constant
        delta_isa = temperature_deviation
        
        # check properties
        if not gas == Air():
            warn('US Standard Atmosphere not using Air fluid properties')
        if not planet == Earth():
            warn('US Standard Atmosphere not using Earth planet properties')          
        
        # convert input if necessary
        zs = atleast_2d_col(zs)

        # get model altitude bounds
        zmin = self.breaks.altitude[0]
        zmax = self.breaks.altitude[-1]   
        
        # convert geometric to geopotential altitude
        zs = zs/(1 + zs/Rad)
        
        # check ranges
        if np.amin(zs) < zmin:
            print("Warning: altitude requested below minimum for this atmospheric model; returning values for h = -2.0 km")
            zs[zs < zmin] = zmin
        if np.amax(zs) > zmax:
            print("Warning: altitude requested above maximum for this atmospheric model; returning values for h = 86.0 km")   
            zs[zs > zmax] = zmax        

        # initialize return data
        zeros = np.zeros_like(zs)
        p     = zeros * 0.0
        T     = zeros * 0.0
        rho   = zeros * 0.0
        a     = zeros * 0.0
        mu    = zeros * 0.0
        z0    = zeros * 0.0
        T0    = zeros * 0.0
        p0    = zeros * 0.0
        alpha = zeros * 0.0
        
        # populate the altitude breaks
        # this uses >= and <= to capture both edges and because values should be the same at the edges
        for i in range( len(self.breaks.altitude)-1 ): 
            i_inside = (zs >= self.breaks.altitude[i]) & (zs <= self.breaks.altitude[i+1])
            z0[ i_inside ]    = self.breaks.altitude[i]
            T0[ i_inside ]    = self.breaks.temperature[i]
            p0[ i_inside ]    = self.breaks.pressure[i]
            alpha[ i_inside ] = -(self.breaks.temperature[i+1] - self.breaks.temperature[i])/ \
                                 (self.breaks.altitude[i+1]    - self.breaks.altitude[i])
        
        # interpolate the breaks
        dz = zs-z0
        i_isoth = (alpha == 0.)
        i_adiab = (alpha != 0.)
        p[i_isoth] = p0[i_isoth] * np.exp(-1.*dz[i_isoth]*grav/(R*T0[i_isoth]))
        p[i_adiab] = p0[i_adiab] * ( (1.-alpha[i_adiab]*dz[i_adiab]/T0[i_adiab]) **(1.*grav/(alpha[i_adiab]*R)) )
        
        T   = T0 - dz*alpha + delta_isa
        rho = gas.compute_density(T,p)
        a   = gas.compute_speed_of_sound(T,p,var_gamma)
        mu  = gas.compute_absolute_viscosity(T)
        K   = gas.compute_thermal_conductivity(T)  
        Pr  = gas.compute_prandtl_number(T)     
        
        atmo_data = Conditions()
        atmo_data.expand_rows(zs.shape[0])
        atmo_data.pressure             = p
        atmo_data.temperature          = T
        atmo_data.density              = rho
        atmo_data.speed_of_sound       = a
        atmo_data.dynamic_viscosity    = mu
        atmo_data.kinematic_viscosity  = mu/rho
        atmo_data.thermal_conductivity = K
        atmo_data.prandtl_number       = Pr
        
        return atmo_data
コード例 #18
0
def vehicle_setup():
    """This is the full physical definition of the vehicle, and is designed to be independent of the
    analyses that are selected."""

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

    vehicle = SUAVE.Vehicle()
    vehicle.tag = 'Boeing_737-800'

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

    # Vehicle level mass properties
    # The maximum takeoff gross weight is used by a number of methods, most notably the weight
    # method. However, it does not directly inform mission analysis.
    vehicle.mass_properties.max_takeoff = 79015.8 * Units.kilogram
    # The takeoff weight is used to determine the weight of the vehicle at the start of the mission
    vehicle.mass_properties.takeoff = 79015.8 * Units.kilogram
    # Operating empty may be used by various weight methods or other methods. Importantly, it does
    # not constrain the mission analysis directly, meaning that the vehicle weight in a mission
    # can drop below this value if more fuel is needed than is available.
    vehicle.mass_properties.operating_empty = 62746.4 * Units.kilogram
    # The maximum zero fuel weight is also used by methods such as weights
    vehicle.mass_properties.max_zero_fuel = 62732.0 * Units.kilogram
    # Cargo weight typically feeds directly into weights output and does not affect the mission
    vehicle.mass_properties.cargo = 10000. * Units.kilogram

    # Envelope properties
    # These values are typical FAR values for a transport of this type
    vehicle.envelope.ultimate_load = 3.75
    vehicle.envelope.limit_load = 2.5

    # Vehicle level parameters
    # The vehicle reference area typically matches the main wing reference area
    vehicle.reference_area = 124.862 * Units['meters**2']

    # Number of passengers, control settings, and accessories settings are used by the weights
    # methods
    vehicle.passengers = 170
    vehicle.systems.control = "fully powered"
    vehicle.systems.accessories = "medium range"

    # ------------------------------------------------------------------
    #  Landing Gear
    # ------------------------------------------------------------------

    # The settings here can be used for noise analysis, but are not used in this tutorial
    landing_gear = SUAVE.Components.Landing_Gear.Landing_Gear()
    landing_gear.tag = "main_landing_gear"

    landing_gear.main_tire_diameter = 1.12000 * Units.m
    landing_gear.nose_tire_diameter = 0.6858 * Units.m
    landing_gear.main_strut_length = 1.8 * Units.m
    landing_gear.nose_strut_length = 1.3 * Units.m
    landing_gear.main_units = 2  # Number of main landing gear
    landing_gear.nose_units = 1  # Number of nose landing gear
    landing_gear.main_wheels = 2  # Number of wheels on the main landing gear
    landing_gear.nose_wheels = 2  # Number of wheels on the nose landing gear
    vehicle.landing_gear = landing_gear

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

    # This main wing is approximated as a simple trapezoid. A segmented wing can also be created if
    # desired. Segmented wings appear in later tutorials, and a version of the 737 with segmented
    # wings can be found in the SUAVE testing scripts.

    # SUAVE allows conflicting geometric values to be set in terms of items such as aspect ratio
    # when compared with span and reference area. Sizing scripts may be used to enforce
    # consistency if desired.

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

    wing.aspect_ratio = 10.18
    # Quarter chord sweep is used as the driving sweep in most of the low fidelity analysis methods.
    # If a different known value (such as leading edge sweep) is given, it should be converted to
    # quarter chord sweep and added here. In some cases leading edge sweep will be used directly as
    # well, and can be entered here too.

    wing.sweeps.quarter_chord = 25 * Units.deg
    wing.thickness_to_chord = 0.1
    wing.taper = 0.1
    wing.spans.projected = 34.32 * Units.meter
    wing.chords.root = 7.760 * Units.meter
    wing.chords.tip = 0.782 * Units.meter
    wing.chords.mean_aerodynamic = 4.235 * Units.meter
    wing.areas.reference = 124.862 * Units['meters**2']
    wing.twists.root = 4.0 * Units.degrees
    wing.twists.tip = 0.0 * Units.degrees
    wing.origin = [[13.61, 0, -1.27]] * Units.meter
    wing.vertical = False
    wing.symmetric = True

    # The high lift flag controls aspects of maximum lift coefficient calculations
    wing.high_lift = True
    # The dynamic pressure ratio is used in stability calculations
    wing.dynamic_pressure_ratio = 1.0

    # ------------------------------------------------------------------
    #   Main Wing Control Surfaces
    # ------------------------------------------------------------------

    # Information in this section is used for high lift calculations and when conversion to AVL
    # is desired.

    # Deflections will typically be specified separately in individual vehicle configurations.

    flap = SUAVE.Components.Wings.Control_Surfaces.Flap()
    flap.tag = 'flap'
    flap.span_fraction_start = 0.20
    flap.span_fraction_end = 0.70
    flap.deflection = 0.0 * Units.degrees
    # Flap configuration types are used in computing maximum CL and noise
    flap.configuration_type = 'double_slotted'
    flap.chord_fraction = 0.30
    wing.append_control_surface(flap)

    slat = SUAVE.Components.Wings.Control_Surfaces.Slat()
    slat.tag = 'slat'
    slat.span_fraction_start = 0.324
    slat.span_fraction_end = 0.963
    slat.deflection = 0.0 * Units.degrees
    slat.chord_fraction = 0.1
    wing.append_control_surface(slat)

    aileron = SUAVE.Components.Wings.Control_Surfaces.Aileron()
    aileron.tag = 'aileron'
    aileron.span_fraction_start = 0.7
    aileron.span_fraction_end = 0.963
    aileron.deflection = 0.0 * Units.degrees
    aileron.chord_fraction = 0.16
    wing.append_control_surface(aileron)

    # Add to vehicle
    vehicle.append_component(wing)

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

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

    wing.aspect_ratio = 6.16
    wing.sweeps.quarter_chord = 40.0 * Units.deg
    wing.thickness_to_chord = 0.08
    wing.taper = 0.2
    wing.spans.projected = 14.2 * Units.meter
    wing.chords.root = 4.7 * Units.meter
    wing.chords.tip = 0.955 * Units.meter
    wing.chords.mean_aerodynamic = 3.0 * Units.meter
    wing.areas.reference = 32.488 * Units['meters**2']
    wing.twists.root = 3.0 * Units.degrees
    wing.twists.tip = 3.0 * Units.degrees
    wing.origin = [[32.83 * Units.meter, 0, 1.14 * Units.meter]]
    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.Vertical_Tail()
    wing.tag = 'vertical_stabilizer'

    wing.aspect_ratio = 1.91
    wing.sweeps.quarter_chord = 25. * Units.deg
    wing.thickness_to_chord = 0.08
    wing.taper = 0.25
    wing.spans.projected = 7.777 * Units.meter
    wing.chords.root = 8.19 * Units.meter
    wing.chords.tip = 0.95 * Units.meter
    wing.chords.mean_aerodynamic = 4.0 * Units.meter
    wing.areas.reference = 27.316 * Units['meters**2']
    wing.twists.root = 0.0 * Units.degrees
    wing.twists.tip = 0.0 * Units.degrees
    wing.origin = [[28.79 * Units.meter, 0, 1.54 * Units.meter]]  # meters
    wing.vertical = True
    wing.symmetric = False
    # The t tail flag is used in weights calculations
    wing.t_tail = False
    wing.dynamic_pressure_ratio = 1.0

    # Add to vehicle
    vehicle.append_component(wing)

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

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

    # Number of coach seats is used in some weights methods
    fuselage.number_coach_seats = vehicle.passengers
    # The seats abreast can be used along with seat pitch and the number of coach seats to
    # determine the length of the cabin if desired.
    fuselage.seats_abreast = 6
    fuselage.seat_pitch = 1 * Units.meter
    # Fineness ratios are used to determine VLM fuselage shape and sections to use in OpenVSP
    # output
    fuselage.fineness.nose = 1.6
    fuselage.fineness.tail = 2.
    # Nose and tail lengths are used in the VLM setup
    fuselage.lengths.nose = 6.4 * Units.meter
    fuselage.lengths.tail = 8.0 * Units.meter
    fuselage.lengths.total = 38.02 * Units.meter
    # Fore and aft space are added to the cabin length if the fuselage is sized based on
    # number of seats
    fuselage.lengths.fore_space = 6. * Units.meter
    fuselage.lengths.aft_space = 5. * Units.meter
    fuselage.width = 3.74 * Units.meter
    fuselage.heights.maximum = 3.74 * Units.meter
    fuselage.effective_diameter = 3.74 * Units.meter
    fuselage.areas.side_projected = 142.1948 * Units['meters**2']
    fuselage.areas.wetted = 446.718 * Units['meters**2']
    fuselage.areas.front_projected = 12.57 * Units['meters**2']
    # Maximum differential pressure between the cabin and the atmosphere
    fuselage.differential_pressure = 5.0e4 * Units.pascal

    # Heights at different longitudinal locations are used in stability calculations and
    # in output to OpenVSP
    fuselage.heights.at_quarter_length = 3.74 * Units.meter
    fuselage.heights.at_three_quarters_length = 3.65 * Units.meter
    fuselage.heights.at_wing_root_quarter_chord = 3.74 * Units.meter

    # add to vehicle
    vehicle.append_component(fuselage)

    # ------------------------------------------------------------------
    #   Nacelles
    # ------------------------------------------------------------------
    nacelle = SUAVE.Components.Nacelles.Nacelle()
    nacelle.tag = 'nacelle_1'
    nacelle.length = 2.71
    nacelle.inlet_diameter = 1.90
    nacelle.diameter = 2.05
    nacelle.areas.wetted = 1.1 * np.pi * nacelle.diameter * nacelle.length
    nacelle.origin = [[13.72, -4.86, -1.9]]
    nacelle.flow_through = True
    nacelle_airfoil = SUAVE.Components.Airfoils.Airfoil()
    nacelle_airfoil.naca_4_series_airfoil = '2410'
    nacelle.append_airfoil(nacelle_airfoil)

    nacelle_2 = deepcopy(nacelle)
    nacelle_2.tag = 'nacelle_2'
    nacelle_2.origin = [[13.72, 4.86, -1.9]]

    vehicle.append_component(nacelle)
    vehicle.append_component(nacelle_2)

    # ------------------------------------------------------------------
    #   Turboelectric HTS Ducted Fan Network
    # ------------------------------------------------------------------

    # Instantiate the Turboelectric HTS Ducted Fan Network
    # This also instantiates the component parts of the efan network, then below each part has its properties modified so they are no longer the default properties as created here at instantiation.
    efan = Turboelectric_HTS_Ducted_Fan()
    efan.tag = 'turbo_fan'

    # Outline of Turboelectric drivetrain components. These are populated below.
    # 1. Propulsor     Ducted_fan
    #   1.1 Ram
    #   1.2 Inlet Nozzle
    #   1.3 Fan Nozzle
    #   1.4 Fan
    #   1.5 Thrust
    # 2. Motor
    # 3. Powersupply
    # 4. ESC
    # 5. Rotor
    # 6. Lead
    # 7. CCS
    # 8. Cryocooler
    # 9. Heat Exchanger
    # The components are then sized

    # ------------------------------------------------------------------
    #Component 1 - Ducted Fan

    efan.ducted_fan = SUAVE.Components.Energy.Networks.Ducted_Fan()
    efan.ducted_fan.tag = 'ducted_fan'
    efan.ducted_fan.number_of_engines = 12.
    efan.number_of_engines = efan.ducted_fan.number_of_engines
    efan.ducted_fan.engine_length = 1.1 * Units.meter

    # Positioning variables for the propulsor locations -
    xStart = 15.0
    xSpace = 1.0
    yStart = 3.0
    ySpace = 1.8
    efan.ducted_fan.origin = [
        [xStart + xSpace * 5, -(yStart + ySpace * 5), -2.0],
        [xStart + xSpace * 4, -(yStart + ySpace * 4), -2.0],
        [xStart + xSpace * 3, -(yStart + ySpace * 3), -2.0],
        [xStart + xSpace * 2, -(yStart + ySpace * 2), -2.0],
        [xStart + xSpace * 1, -(yStart + ySpace * 1), -2.0],
        [xStart + xSpace * 0, -(yStart + ySpace * 0), -2.0],
        [xStart + xSpace * 5, (yStart + ySpace * 5), -2.0],
        [xStart + xSpace * 4, (yStart + ySpace * 4), -2.0],
        [xStart + xSpace * 3, (yStart + ySpace * 3), -2.0],
        [xStart + xSpace * 2, (yStart + ySpace * 2), -2.0],
        [xStart + xSpace * 1, (yStart + ySpace * 1), -2.0],
        [xStart + xSpace * 0, (yStart + ySpace * 0), -2.0]
    ]  # meters

    # copy the ducted fan details to the turboelectric ducted fan network to enable drag calculations
    efan.engine_length = efan.ducted_fan.engine_length
    efan.origin = efan.ducted_fan.origin

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

    # ------------------------------------------------------------------
    #   Component 1.1 - Ram

    # to convert freestream static to stagnation quantities
    # instantiate
    ram = SUAVE.Components.Energy.Converters.Ram()
    ram.tag = 'ram'

    # add to the network
    efan.ducted_fan.append(ram)

    # ------------------------------------------------------------------
    #  Component 1.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
    efan.ducted_fan.append(inlet_nozzle)

    # ------------------------------------------------------------------
    #  Component 1.3 - Fan Nozzle

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

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

    # add to network
    efan.ducted_fan.append(fan_nozzle)

    # ------------------------------------------------------------------
    #  Component 1.4 - 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
    efan.ducted_fan.append(fan)

    # ------------------------------------------------------------------
    # Component 1.5 : thrust

    # To compute the thrust
    thrust = SUAVE.Components.Energy.Processes.Thrust()
    thrust.tag = 'compute_thrust'

    # total design thrust (includes all the propulsors)
    thrust.total_design = 2. * 24000. * Units.N  #Newtons

    # design sizing conditions
    altitude = 35000.0 * Units.ft
    mach_number = 0.78
    isa_deviation = 0.

    # add to network
    efan.ducted_fan.thrust = thrust
    # ------------------------------------------------------------------
    # Component 2 : HTS motor

    efan.motor = SUAVE.Components.Energy.Converters.Motor_Lo_Fid()
    efan.motor.tag = 'motor'
    # number_of_motors is not used as the motor count is assumed to match the engine count

    # Set the origin of each motor to match its ducted fan
    efan.motor.origin = efan.ducted_fan.origin
    efan.motor.gear_ratio = 1.0
    efan.motor.gearbox_efficiency = 1.0
    efan.motor.motor_efficiency = 0.96

    # ------------------------------------------------------------------
    #  Component 3 - Powersupply

    efan.powersupply = SUAVE.Components.Energy.Converters.Turboelectric()
    efan.powersupply.tag = 'powersupply'

    efan.number_of_powersupplies = 2.
    efan.powersupply.propellant = SUAVE.Attributes.Propellants.Jet_A()
    efan.powersupply.oxidizer = Air()
    efan.powersupply.number_of_engines = 2.0  # number of turboelectric machines, not propulsors
    efan.powersupply.efficiency = .37  # Approximate average gross efficiency across the product range.
    efan.powersupply.volume = 2.36 * Units.m**3.  # 3m long from RB211 datasheet. 1m estimated radius.
    efan.powersupply.rated_power = 37400.0 * Units.kW
    efan.powersupply.mass_properties.mass = 2500.0 * Units.kg  # 2.5 tonnes from Rolls Royce RB211 datasheet 2013.
    efan.powersupply.specific_power = efan.powersupply.rated_power / efan.powersupply.mass_properties.mass
    efan.powersupply.mass_density = efan.powersupply.mass_properties.mass / efan.powersupply.volume

    # ------------------------------------------------------------------
    #  Component 4 - Electronic Speed Controller (ESC)

    efan.esc = SUAVE.Components.Energy.Distributors.HTS_DC_Supply(
    )  # Could make this where the ESC is defined as a Siemens SD104
    efan.esc.tag = 'esc'

    efan.esc.efficiency = 0.95  # Siemens SD104 SiC Power Electronicss reported to be this efficient

    # ------------------------------------------------------------------
    #  Component 5 - HTS rotor (part of the propulsor motor)

    efan.rotor = SUAVE.Components.Energy.Converters.Motor_HTS_Rotor()
    efan.rotor.tag = 'rotor'

    efan.rotor.temperature = 50.0  # [K]
    efan.rotor.skin_temp = 300.0  # [K]       Temp of rotor outer surface is not ambient
    efan.rotor.current = 1000.0  # [A]       Most of the cryoload will scale with this number if not using HTS Dynamo
    efan.rotor.resistance = 0.0001  # [ohm]     20 x 100 nOhm joints should be possible (2uOhm total) so 1mOhm is an overestimation.
    efan.rotor.number_of_engines = efan.ducted_fan.number_of_engines
    efan.rotor.length = 0.573 * Units.meter  # From paper: DOI:10.2514/6.2019-4517 Would be good to estimate this from power instead.
    efan.rotor.diameter = 0.310 * Units.meter  # From paper: DOI:10.2514/6.2019-4517 Would be good to estimate this from power instead.
    rotor_end_area = np.pi * (efan.rotor.diameter / 2.0)**2.0
    rotor_end_circumference = np.pi * efan.rotor.diameter
    efan.rotor.surface_area = 2.0 * rotor_end_area + efan.rotor.length * rotor_end_circumference
    efan.rotor.R_value = 125.0  # [K.m2/W]  2.0 W/m2 based on experience at Robinson Research

    # ------------------------------------------------------------------
    #  Component 6 - Copper Supply Leads of propulsion motor rotors

    efan.lead = SUAVE.Components.Energy.Distributors.Cryogenic_Lead()
    efan.lead.tag = 'lead'

    copper = Copper()
    efan.lead.cold_temp = efan.rotor.temperature  # [K]
    efan.lead.hot_temp = efan.rotor.skin_temp  # [K]
    efan.lead.current = efan.rotor.current  # [A]
    efan.lead.length = 0.3  # [m]
    efan.lead.material = copper
    efan.leads = efan.ducted_fan.number_of_engines * 2.0  # Each motor has two leads to make a complete circuit

    # ------------------------------------------------------------------
    #  Component 7 - Rotor Constant Current Supply (CCS)

    efan.ccs = SUAVE.Components.Energy.Distributors.HTS_DC_Supply()
    efan.ccs.tag = 'ccs'

    efan.ccs.efficiency = 0.95  # Siemens SD104 SiC Power Electronics reported to be this efficient
    # ------------------------------------------------------------------
    #  Component 8 - Cryocooler, to cool the HTS Rotor

    efan.cryocooler = SUAVE.Components.Energy.Cooling.Cryocooler()
    efan.cryocooler.tag = 'cryocooler'

    efan.cryocooler.cooler_type = 'GM'
    efan.cryocooler.min_cryo_temp = efan.rotor.temperature  # [K]
    efan.cryocooler.ambient_temp = 300.0  # [K]

    # ------------------------------------------------------------------
    #  Component 9 - Cryogenic Heat Exchanger, to cool the HTS Rotor
    efan.heat_exchanger = SUAVE.Components.Energy.Cooling.Cryogenic_Heat_Exchanger(
    )
    efan.heat_exchanger.tag = 'heat_exchanger'

    efan.heat_exchanger.cryogen = SUAVE.Attributes.Cryogens.Liquid_H2()
    efan.heat_exchanger.cryogen_inlet_temperature = 20.0  # [K]
    efan.heat_exchanger.cryogen_outlet_temperature = efan.rotor.temperature  # [K]
    efan.heat_exchanger.cryogen_pressure = 100000.0  # [Pa]
    efan.heat_exchanger.cryogen_is_fuel = 0.0

    # Sizing Conditions. The cryocooler may have greater power requirement at low altitude as the cooling requirement may be static during the flight but the ambient temperature may change.
    cryo_temp = 50.0  # [K]
    amb_temp = 300.0  # [K]

    # ------------------------------------------------------------------
    # Powertrain Sizing

    ducted_fan_sizing(efan.ducted_fan, mach_number, altitude)

    serial_HTS_turboelectric_sizing(efan,
                                    mach_number,
                                    altitude,
                                    cryo_cold_temp=cryo_temp,
                                    cryo_amb_temp=amb_temp)

    # add turboelectric network to the vehicle
    vehicle.append_component(efan)

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

    return vehicle