コード例 #1
0
ファイル: t_atmospheres.py プロジェクト: yaseen157/ADRpy
 def test_m310(self):
     """Tests access to the MIL HDBK 310 atmospheres"""
     print("MIL HDBK 310 - high temp at 10km.")
     obs1p, _ = at.mil_hdbk_310('high', 'temp', 10)
     m310_high10_1p = at.Atmosphere(profile=obs1p)
     sltemp_c = m310_high10_1p.airtemp_c(100)
     self.assertEqual(round(1000 * sltemp_c), round(1000 * 25.501))
コード例 #2
0
    def test_take_off(self):
        """Tests the take-off constraint calculation"""

        print("Take-off constraint test.")

        designbrief = {'rwyelevation_m': 1000, 'groundrun_m': 1200}
        designdefinition = {'aspectratio': 7.3, 'bpr': 3.9, 'tr': 1.05}
        designperformance = {
            'CDTO': 0.04,
            'CLTO': 0.9,
            'CLmaxTO': 1.6,
            'mu_R': 0.02
        }

        wingloadinglist_pa = [2000, 3000, 4000, 5000]

        atm = at.Atmosphere()
        concept = ca.AircraftConcept(designbrief, designdefinition,
                                     designperformance, atm)

        tw_sl, liftoffspeed_mpstas, _ = concept.twrequired_to(
            wingloadinglist_pa)

        self.assertEqual(round(10000 * tw_sl[0]), round(10000 * 0.19397876))
        self.assertEqual(round(10000 * liftoffspeed_mpstas[0]),
                         round(10000 * 52.16511207))

        self.assertEqual(round(10000 * tw_sl[3]), round(10000 * 0.41110154))
        self.assertEqual(round(10000 * liftoffspeed_mpstas[3]),
                         round(10000 * 82.48028428))
コード例 #3
0
ファイル: get_params.py プロジェクト: HansDy/IP
def Density(h):
    """
    Air density at a given altitude based on ideal gas law

    Parameters
    ----------
    h : int or float
        Altitude.

    Raises
    ------
    ValueError
        When wrong arg type is passed.

    Returns
    -------
    rho : float
        Density at altitude.

    """

    if not isinstance(h, numbers.Number):
        raise ValueError('Wrong arg type passed to Density() for h. Must be' +
                         ' int or float')

    return at.Atmosphere().airdens_kgpm3(h)
コード例 #4
0
ファイル: t_atmospheres.py プロジェクト: yaseen157/ADRpy
 def test_isa_sl(self):
     """Tests the atmosphere class instantiated for an ISA at SL"""
     print("ISA (SL).")
     alt_m = 0
     isa = at.Atmosphere()
     self.assertEqual(isa.airtemp_c(alt_m), 15)
     self.assertEqual(round(100 * isa.airpress_mbar(alt_m)), 101325)
     self.assertEqual(round(1000 * isa.airdens_kgpm3(alt_m)), 1225)
     self.assertEqual(round(100 * isa.vsound_mps(alt_m)),
                      round(100 * 340.29))
コード例 #5
0
ファイル: t_atmospheres.py プロジェクト: yaseen157/ADRpy
 def test_isa_10k_geop(self):
     """Tests the atmosphere class instantiated for an ISA at 10km geopotential"""
     print("ISA (10,000m geopotential).")
     # ISA at 10,000m geopotential, 10,015.8m geometric altitude.
     alt_m = 10000
     isa = at.Atmosphere()
     self.assertEqual(isa.airtemp_c(alt_m), -50)
     self.assertEqual(round(100 * isa.airpress_mbar(alt_m)), 26436)
     self.assertEqual(round(100000 * isa.airdens_kgpm3(alt_m)), 41271)
     self.assertEqual(round(1000 * isa.vsound_mps(alt_m)),
                      round(1000 * 299.463))
コード例 #6
0
ファイル: t_atmospheres.py プロジェクト: yaseen157/ADRpy
 def test_isa_minus5k_geop(self):
     """Tests the atmosphere class instantiated for an ISA at -5km geopotential alt"""
     print("ISA (-5,000m geopotential).")
     # ISA at Z = -4996.1m geometric, H = -5000m geopotential altitude.
     alt_m = -5000
     isa = at.Atmosphere()
     self.assertEqual(round(1000 * isa.airtemp_c(alt_m)),
                      round(1000 * 47.5002))
     self.assertEqual(round(10 * isa.airpress_mbar(alt_m)),
                      round(10 * 1776.88))
     self.assertEqual(round(10000 * isa.airdens_kgpm3(alt_m)),
                      round(10000 * 1.93048))
     self.assertEqual(round(1000 * isa.vsound_mps(alt_m)),
                      round(1000 * 358.972))
コード例 #7
0
ファイル: t_atmospheres.py プロジェクト: yaseen157/ADRpy
 def test_isa_10k_geom(self):
     """Tests the atmosphere class instantiated for an ISA at 10km geometric alt"""
     print("ISA (10,000m geometric).")
     # ISA at Z = 10,000m geometric, H = 9,984.3m geopotential altitude.
     alt_m = 9984.3
     isa = at.Atmosphere()
     self.assertEqual(round(10000 * isa.airtemp_c(alt_m)),
                      round(10000 * -49.8979))
     self.assertEqual(round(100 * isa.airpress_mbar(alt_m)),
                      round(100 * 264.999))
     self.assertEqual(round(100000 * isa.airdens_kgpm3(alt_m)),
                      round(100000 * 0.413511))
     self.assertEqual(round(1000 * isa.vsound_mps(alt_m)),
                      round(1000 * 299.532))
コード例 #8
0
    def vstall_kias(self, wingloadinglist_pa, clmax):
        """Calculates the stall speed (indicated) for a given wing loading
        in a specified cofiguration.

        **Parameters:**

        wingloading_pa
            float or numpy array, list of wing loading values in Pa.

        clmax
            maximum lift coefficient (float) or the name of a standard configuration
            (string) for which a maximum lift coefficient was specified in the
            :code:`performance` dictionary (currently implemented: 'take-off').

        **Returns:**

        stall speed in knots (float or numpy array)

        **Note:**

        The calculation is performed assuming standard day ISA sea level
        conditions (not in the consitions specified in the atmosphere used
        when instantiating the :code:`AircraftConcept` object!) so the
        speed returned is an indicated (IAS) / calibrated (CAS) value.

        **Example**::

            from ADRpy import constraintanalysis as ca

            designperformance = {'CLmaxTO':1.6}

            concept = ca.AircraftConcept({}, {}, designperformance, {})

            wingloading_pa = 3500

            print("VS1(take-off):",
                concept.vstall_kias(wingloading_pa, 'take-off'))

        """

        isa = at.Atmosphere()
        rho0_kgpm3 = isa.airdens_kgpm3()

        if clmax == 'take-off':
            clmax = self.clmaxto

        vs_mps = math.sqrt(2 * wingloadinglist_pa / (rho0_kgpm3 * clmax))

        return co.mps2kts(vs_mps)
コード例 #9
0
    def __init__(self, brief, design, performance, designatm):

        # Assign a default, if needed, to the atmosphere
        if not designatm:
            designatm = at.Atmosphere()
        self.designatm = designatm

        # Unpick the design brief dictionary first:

        if 'groundrun_m' in brief:
            self.groundrun_m = brief['groundrun_m']
        else:
            # Flag if not specified, error thrown by t/o constraint
            self.groundrun_m = -1

        if 'rwyelevation_m' in brief:
            self.rwyelevation_m = brief['rwyelevation_m']
        else:
            # Assign sea level, if not specified
            self.rwyelevation_m = 0

        if 'turnalt_m' in brief:
            self.turnalt_m = brief['turnalt_m']
        else:
            # Assign sea level, if not specified
            self.turnalt_m = 0

        if 'turnspeed_ktas' in brief:
            self.turnspeed_ktas = brief['turnspeed_ktas']
        else:
            # Flag if not specified, error thrown by turn constraint
            self.turnspeed_ktas = -1

        if 'stloadfactor' in brief:
            self.stloadfactor = brief['stloadfactor']
        else:
            # Flag if not specified, error thrown by climb constraint
            self.stloadfactor = -1

        if 'climbalt_m' in brief:
            self.climbalt_m = brief['climbalt_m']
        else:
            # Assign sea level, if not specified
            self.climbalt_m = 0

        if 'climbspeed_kias' in brief:
            self.climbspeed_kias = brief['climbspeed_kias']
        else:
            # Flag if not specified, error thrown by climb constraint
            self.climbspeed_kias = -1

        if 'climbrate_fpm' in brief:
            self.climbrate_fpm = brief['climbrate_fpm']
        else:
            # Flag if not specified, error thrown by climb constraint
            self.climbrate_fpm = -1

        if 'cruisealt_m' in brief:
            self.cruisealt_m = brief['cruisealt_m']
        else:
            # Flag if not specified, error thrown by cruise constraint
            self.cruisealt_m = -1

        if 'cruisespeed_ktas' in brief: # Option to specify Mach number instead coming soon
            self.cruisespeed_ktas = brief['cruisespeed_ktas']
        else:
            # Flag if not specified, error thrown by cruise constraint
            self.cruisespeed_ktas = -1

        if 'cruisethrustfact' in brief:
            self.cruisethrustfact = brief['cruisethrustfact']
        else:
            # Assume 100% throttle in cruise
            self.cruisethrustfact = 1.0

        if 'servceil_m' in brief:
            self.servceil_m = brief['servceil_m']
        else:
            # Flag if not specified, error thrown by cruise constraint
            self.servceil_m = -1

        if 'secclimbspd_kias' in brief:
            self.secclimbspd_kias = brief['secclimbspd_kias']
        else:
            # Flag if not specified, error thrown by cruise constraint
            self.secclimbspd_kias = -1

        if 'vstallclean_kcas' in brief:
            self.vstallclean_kcas = brief['vstallclean_kcas']
        else:
            # Flag if not specified, error thrown by cruise constraint
            self.vstallclean_kcas = -1


        # Unpick the design dictionary next:

        if 'aspectratio' in design:
            self.aspectratio = design['aspectratio']
        else:
            self.aspectratio = 8

        if 'bpr' in design:
            self.bpr = design['bpr']
        else:
            # Piston engine
            self.bpr = -1

        if 'tr' in design:
            self.throttle_r = design['tr']
        else:
            self.throttle_r = 1.07

        if 'wingheightratio' in design:
            self.wingheightratio = design['wingheightratio']
        else:
            # Set to a large number if unspecified, leading to
            # WIG factor of near-unity
            self.wingheightratio = 100

        if 'sweep_le_deg' in design:
            self.sweep_le_deg = design['sweep_le_deg']
            self.sweep_le_rad = math.radians(self.sweep_le_deg)
        else:
            self.sweep_le_deg = 0
            self.sweep_le_rad = 0

        if 'sweep_mt_deg' in design:
            self.sweep_mt_deg = design['sweep_mt_deg']
            self.sweep_mt_rad = math.radians(self.sweep_mt_deg)
        else:
            self.sweep_mt_deg = self.sweep_le_deg
            self.sweep_mt_rad = self.sweep_le_rad

        if 'weightfractions' in design:
            if 'cruise' in design['weightfractions']:
                self.cruise_weight_fraction = design['weightfractions']['cruise']
            else:
                self.cruise_weight_fraction = 1.0
            if 'servceil' in design['weightfractions']:
                self.sec_weight_fraction = design['weightfractions']['servceil']
            else:
                self.sec_weight_fraction = 1.0
            if 'turn' in design['weightfractions']:
                self.turn_weight_fraction = design['weightfractions']['turn']
            else:
                self.turn_weight_fraction = 1.0
            if 'climb' in design['weightfractions']:
                self.climb_weight_fraction = design['weightfractions']['climb']
            else:
                self.climb_weight_fraction = 1.0
        else:
            # Assume all constraints at same weight (e.g., electrically powered a/c)
            self.cruise_weight_fraction = 1.0
            self.sec_weight_fraction = 1.0
            self.turn_weight_fraction = 1.0
            self.climb_weight_fraction = 1.0

        # Next, unpick the performance dictionary

        if 'CDTO' in performance:
            self.cdto = performance['CDTO']
        else:
            self.cdto = 0.09

        if 'CDminclean' in performance:
            self.cdminclean = performance['CDminclean']
        else:
            self.cdminclean = 0.03

        if 'mu_R' in performance:
            self.mu_r = performance['mu_R']
        else:
            self.mu_r = 0.03

        if 'CLTO' in performance:
            self.clto = performance['CLTO']
        else:
            self.clto = 0.95

        if 'CLmaxTO' in performance:
            self.clmaxto = performance['CLmaxTO']
        else:
            self.clmaxto = 1.5

        if 'etaprop' in performance:
            self.etaprop = performance['etaprop']
        else:
            self.etaprop = -1

        if 'CLmaxclean' in performance:
            self.clmaxclean = performance['CLmaxclean']
        else:
            self.clmaxclean = -1

        self.etadefaultflag = 0
        if 'etaprop' in performance:
            if 'take-off' in performance['etaprop']:
                self.etaprop_to = performance['etaprop']['take-off']
            else:
                self.etaprop_to = 0.45
                self.etadefaultflag += 1
            if 'cruise' in performance['etaprop']:
                self.etaprop_cruise = performance['etaprop']['cruise']
            else:
                self.etaprop_cruise = 0.85
                self.etadefaultflag += 1
            if 'servceil' in performance['etaprop']:
                self.etaprop_sec = performance['etaprop']['servceil']
            else:
                self.etaprop_sec = 0.65
                self.etadefaultflag += 1
            if 'turn' in performance['etaprop']:
                self.etaprop_turn = performance['etaprop']['turn']
            else:
                self.etaprop_turn = 0.85
                self.etadefaultflag += 1
            if 'climb' in performance['etaprop']:
                self.etaprop_climb = performance['etaprop']['climb']
            else:
                self.etaprop_climb = 0.75
                self.etadefaultflag += 1
        else:
            self.etaprop_to = 0.45
            self.etaprop_cruise = 0.85
            self.etaprop_sec = 0.65
            self.etaprop_climb = 0.75
            self.etaprop_turn = 0.85
            self.etadefaultflag = 5
コード例 #10
0
def PlantSizing(plant, rEM=0.6):

    PP = plant.copy()

    isa = at.Atmosphere()

    # aircraft design concept object creation requires a design-brief
    designbrief = {
        'rwyelevation_m': 0,  # altitudue of the runway
        'groundrun_m': 50,  # maximumm allowed take-off distance
        'climbrate_fpm':
        3.5 * (60 / 0.3048),  # required climb rate that must be achieved
        'climbspeed_kias':
        co.mps2kts(40),  # indidcated airspeed requirement for climb
        'climbalt_m':
        5000,  # altitude at which the climb rate must be achieved
        'secclimbspd_kias':
        co.mps2kts(25),  # speed at which service ceiling is reached
        'cruisespeed_ktas': co.mps2kts(40),  # cruise velocity
        'cruisealt_m':
        5000,  # altitude at which the cruise speed must be achieved
        'cruisethrustfact': 1,  # ratio of cruise thrust to total thrust
        'servceil_m':
        5000,  # alt at which the max rate of climb drops to 100 ft/min
        # dummy values to prevent errors, not needed since no turns are simulated
        'turnspeed_ktas': 10,
        'stloadfactor': 1.5
    }

    # aircraft design concept object creation requires a design spec
    design = {
        'aspectratio': AC['AR'],
        'bpr':
        -3  # bypass ratio; -3 means no thrust correction (neglected for the aircraft)
    }

    # aircraft design concept object creation requires a performance estimate
    designperf = {
        'CDTO': GetCd(AC['maxPitch'], 0),  # take-off coefficient of drag
        'CLTO': GetCl(AC['maxPitch']),  # take-off coefficient of lift
        'CLmaxTO':
        GetCl(AC['maxPitch']),  # take-off maximum coefficient of lift
        'CLmaxclean': GetCl(AC['maxPitch']),  # max lift coefficient in flight,
        # with (non-existant) flaps retracted
        'CDminclean': AC['parasiteDrag'],  # min, zero lift drag coefficient
        'etaprop': {
            'take-off': 0.45,
            'climb': 0.75,
            'cruise': 0.85,
            'turn': 0.85,
            'servceil': 0.65
        },  # propeller efficiencies
    }

    # An aircraft concept object can now be instantiated
    concept = ca.AircraftConcept(designbrief, design, designperf, isa)

    tow = PP['battMassList'][-1] + PP['fullTankMass'] + AC['emptyMass']\
        + AC['payloadMass'] + PP['EMMass'] + PP['ICEMass']

    wingloading = tow * AC['g'] / AC['S']

    power = concept.powerrequired(wingloading, tow, feasibleonly=False)

    # select largest power requirement, covnert from HP to W
    powerReq = max(power['take-off'], power['climb'], power['cruise'])

    powerReq = co.hp2kw(powerReq) * 1000

    # power is satisfied by ICE and EM
    ICEPowerReq = (1 - rEM) * powerReq
    EMPowerReq = rEM * powerReq

    # power available before sizing
    ICEPower = 2 * math.pi * PP['ICEMaprps'][-1] * PP['ICEMapTorque'][-1]
    EMPower = 2 * math.pi * PP['maxEMrps'] * PP['maxEMTorque']

    ICEFactor = ICEPowerReq / ICEPower
    EMFactor = EMPowerReq / EMPower

    # resize the torque scales to get adjusted power limits
    PP['ICEMapTorque'] *= ICEFactor
    PP['maxEMTorque'] *= EMFactor

    PP['maxEMPower'] = 2 * math.pi * PP['maxEMrps'] * PP['maxEMTorque']

    # resize the mass
    PP['ICEMass'] *= ICEFactor
    PP['EMMass'] *= EMFactor

    # propeller sizing
    maxICETorque = PP['ICEMapTorque'][-1]
    maxICErps = PP['ICEMaprps'][-1]

    dFun = lambda D: maxICETorque - PropQFun(1, maxICErps, 0, D)

    PP['D'] = fsolve(dFun, 0.3)

    return PP