Exemple #1
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))
    def test_0createobject(self):
        """Tests parameters were copied in correctly"""

        print("Create concept test.")

        # Choose and build a random aircraft from the aircraft test library

        self.ac_rand_i = random.randint(0, len(self.ac_lib) - 1)
        self.ac_random = ca.AircraftConcept(self.ac_lib[self.ac_rand_i][0],
                                            self.ac_lib[self.ac_rand_i][1],
                                            self.ac_lib[self.ac_rand_i][2])

        # For each design dictionary of the random aircraft picked
        for dictindex in range(len(self.ac_lib[self.ac_rand_i])):
            # Go through each item of a single design dictionary from the test library and confirm it copied correctly
            for i, (k, test_value) in enumerate(
                    self.ac_lib[self.ac_rand_i][dictindex].items()):
                if type(self.ac_random.designspace[dictindex][k]) == list:
                    dictvalue = sum(self.ac_random.designspace[dictindex][k]) \
                                / len(self.ac_random.designspace[dictindex][k])
                else:
                    dictvalue = self.ac_random.designspace[dictindex][k]

                self.assertEqual(dictvalue, test_value)

        # Build the last aircraft in the aircraft test library

        self.ac_last = ca.AircraftConcept(self.ac_lib[-1][0],
                                          self.ac_lib[-1][1],
                                          self.ac_lib[-1][2])

        # For each design dictionary of the random aircraft picked
        for dictindex in range(len(self.ac_lib[-1])):
            # Go through each item of a single design dictionary from the test library and confirm it copied correctly
            for i, (k, test_value) in enumerate(
                    self.ac_lib[-1][dictindex].items()):
                if type(self.ac_last.designspace[dictindex][k]) == list:
                    dictvalue = sum(self.ac_last.designspace[dictindex][k]) \
                                / len(self.ac_last.designspace[dictindex][k])
                else:
                    dictvalue = self.ac_last.designspace[dictindex][k]

                self.assertEqual(dictvalue, test_value)

        return
Exemple #3
0
 def __init__(self,
              brief=None,
              design=None,
              performance=None,
              designatm=None):
     # Build an aircraft object based on the design dictionaries and atmosphere object
     self.acobj = ca.AircraftConcept(brief=brief,
                                     design=design,
                                     performance=performance,
                                     designatm=designatm)
     return
Exemple #4
0
    def __init__(self, brief=None, design=None, performance=None, designatm=None, propulsion=None, csbrief=None):

        # Assign a default, if needed, to the csbrief dictionary
        if csbrief is None:
            csbrief = {}

        # Build an aircraft object based on the design dictionaries and atmosphere object
        self.acobj = ca.AircraftConcept(brief=brief, design=design, performance=performance, designatm=designatm)

        # Specify default flags or parameters for the Vn definitions dictionary, if parameter is left unspecified

        default_csbrief = {
            # Certification category
            'certcat': 'norm',  # Default category is normal
            # Vn altitude query
            'altitude_m': 0,  # Assign sea level (h = 0 metres)
            # Design Airspeeds
            'cruisespeed_keas': False,  # Flag as not specified
            'divespeed_keas': False,  # Flag as not specified
            'maxlevelspeed_keas': False,  # Flag as not specified
            # Vn loading query, fraction of MTOW
            'weightfraction': 1  # Assume V-n diagram applies to MTOW loading
        }

        # Use the templates (default dictionaries) to populate missing values in the provided design dictionaries

        # Iterate through the defaults dictionary
        for _, (defaults_k, defaults_v) in enumerate(default_csbrief.items()):
            # If a parameter of csbrief is left unspecified by the user, copy in the default value
            if defaults_k not in csbrief:
                csbrief.update({defaults_k: defaults_v})

        # FURTHER COMPREHENSION: If design cruise speed was not specified in the csbrief dictionary argument
        if csbrief['cruisespeed_keas'] is False:
            # Check to see if a cruise speed can instead be swiped from the design brief
            if self.acobj.cruisespeed_ktas is False:
                self.cruisespeed_keas = False
            else:
                rho_kgpm3 = self.acobj.designatm.airdens_kgpm3(csbrief['altitude_m'])
                self.cruisespeed_keas = co.tas2eas(self.acobj.cruisespeed_ktas, rho_kgpm3)
        else:
            self.cruisespeed_keas = csbrief['cruisespeed_keas']

        # Populate object attributes
        self.category = csbrief['certcat']
        self.divespeed_keas = csbrief['divespeed_keas']
        self.maxlevelspeed_keas = csbrief['maxlevelspeed_keas']
        self.altitude_m = csbrief['altitude_m']
        self.weightfraction = csbrief['weightfraction']

        return
Exemple #5
0
    def test_vstall(self):
        """Tests the stall speed method"""

        print("Stall speed method (vstall_kias) test.")

        designperformance = {'CLmaxTO': 1.6}

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

        wingloading_pa = 3500

        self.assertEqual(
            round(10000 * concept.vstall_kias(wingloading_pa, 'take-off')),
            round(10000 * 116.166934173))
Exemple #6
0
    def test_wig(self):
        """Tests the wing in ground effect factor calculation"""

        print("WIG factor test.")

        designdef = {'aspectratio': 8}
        wingarea_m2 = 10
        wingspan_m = math.sqrt(designdef['aspectratio'] * wingarea_m2)

        for wingheight_m in [0.6, 0.8, 1.0]:
            designdef['wingheightratio'] = wingheight_m / wingspan_m
            aircraft = ca.AircraftConcept({}, designdef, {}, {})

        self.assertEqual(round(10000 * aircraft.wigfactor()),
                         round(10000 * 0.7619047))
    def test_findchordsweep(self):
        """Tests the calculation of sweep angle in radians, at some point of the wing chord"""

        print("Find arbitrary chord-sweep test.")

        # Use Aircraft 1: Piston propeller aircraft
        acindex = 1
        concept = ca.AircraftConcept(self.ac_lib[acindex][0],
                                     self.ac_lib[acindex][1],
                                     self.ac_lib[acindex][2])

        sweep_le_rad = concept.sweep_le_rad
        sweep_25_rad = concept.sweep_25_rad

        self.assertEqual(concept.findchordsweep_rad(0), sweep_le_rad)
        self.assertEqual(concept.findchordsweep_rad(0.25), sweep_25_rad)

        return
    def test_estimateliftslope(self):
        """Tests the generation of predicted lift-slope with mach number"""

        print("Lift-curve slope estimation test.")

        # Use Aircraft 2: F/A-18C
        acindex = 2
        concept = ca.AircraftConcept(self.ac_lib[acindex][0],
                                     self.ac_lib[acindex][1],
                                     self.ac_lib[acindex][2])

        macharray = np.arange(0.1, 4, 0.1)
        liftslopelist = []
        for mach_inf in macharray:
            liftslopelist.append(concept.liftslope(mach_inf=mach_inf))

        # Assert that the lift curve slope is never below or equal to zero
        self.assertGreater(min(liftslopelist), 0)

        return
    def test_kfactorlesm(self):
        """Tests the induced drag factor K calculation using LESM"""

        print("Induced drag factor test.")

        # Use Aircraft 2: F/A-18C
        acindex = 2
        concept = ca.AircraftConcept(self.ac_lib[acindex][0],
                                     self.ac_lib[acindex][1],
                                     self.ac_lib[acindex][2])

        macharray = np.arange(0.1, 2, 0.1)
        kpredlist = []

        for mach_inf in macharray:
            kpredlist.append(
                concept.induceddragfact_lesm(mach_inf=mach_inf, cl_real=0.455))

        # Assert that the induced drag is never below or equal to zero
        self.assertGreater(min(kpredlist), 0)

        return
Exemple #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
    def test_propulsionsensitivity(self):
        """Tests the statistical analysis method for the one-at-a-time inquiry of T/W sensitivity to input parameters"""

        print("Propulsion Sensitivity (One-at-a-time) test.")

        # Use Aircraft 0: Business jet
        acindex = 0
        concept = ca.AircraftConcept(self.ac_lib[acindex][0],
                                     self.ac_lib[acindex][1],
                                     self.ac_lib[acindex][2])
        wingloadinglist_pa = np.arange(2000, 5000, 10)

        concept.propulsionsensitivity_monothetic(
            wingloading_pa=wingloadinglist_pa,
            y_var='tw',
            x_var='ws_pa',
            show=False)

        # Use Aircraft 3: Custom Business Jet
        acindex = 3
        concept = ca.AircraftConcept(self.ac_lib[acindex][0],
                                     self.ac_lib[acindex][1],
                                     self.ac_lib[acindex][2])
        wingloadinglist_pa = np.arange(2000, 8000, 50)

        customlabelling = {
            'aspectratio': 'AR',
            'bpr': 'BPR',
            'sweep_le_deg': '$\\Lambda_{LE}$',
            'sweep_25_deg': '$\\Lambda_{25}$',
            'sweep_mt_deg': '$\\Lambda_{MT}$'
        }

        concept.propulsionsensitivity_monothetic(
            wingloading_pa=wingloadinglist_pa,
            y_var='tw',
            x_var='s_m2',
            customlabels=customlabelling,
            show=False,
            maskbool=False,
            figsize_in=[16, 9])

        # Use Aircraft 4: Custom SEPPA
        acindex = 4
        concept = ca.AircraftConcept(self.ac_lib[acindex][0],
                                     self.ac_lib[acindex][1],
                                     self.ac_lib[acindex][2])
        wingloadinglist_pa = np.arange(700, 2500, 15)

        concept.propulsionsensitivity_monothetic(
            wingloading_pa=wingloadinglist_pa,
            y_var='p_hp',
            x_var='s_m2',
            show=False,
            maskbool=True)

        # Use Aircraft 5: Keane's Small UAV
        acindex = 5
        concept = ca.AircraftConcept(self.ac_lib[acindex][0],
                                     self.ac_lib[acindex][1],
                                     self.ac_lib[acindex][2])
        wingloadinglist_pa = np.arange(50, 2500, 10)

        concept.propulsionsensitivity_monothetic(
            wingloading_pa=wingloadinglist_pa,
            y_lim=5,
            y_var='p_hp',
            x_var='s_m2',
            show=False,
            maskbool=True)

        return
    def test_twreqconstraint(self):
        """Tests the thrust-to-weight constraint calculations"""

        # Use Aircraft 0: Business Jet
        acindex = 0
        concept = ca.AircraftConcept(self.ac_lib[acindex][0],
                                     self.ac_lib[acindex][1],
                                     self.ac_lib[acindex][2])
        wingloadinglist_pa = [2000, 3000, 4000, 5000, 6000, 7000]

        # Investigate the climb constraint
        print("T/W Climb constraint test.")
        tw_climb = concept.twrequired_clm(wingloading_pa=wingloadinglist_pa)

        testarray1 = np.array([
            0.15268568, 0.1239213, 0.11219318, 0.10727957, 0.10577321,
            0.10621385
        ])
        self.assertIs(tw_climb.all(), testarray1.all())

        # Investigate the cruise constraint
        print("T/W Cruise constraint test.")
        tw_cruise = concept.twrequired_crs(wingloading_pa=wingloadinglist_pa)

        testarray1 = np.array([
            0.37261153, 0.31997436, 0.31512577, 0.32939262, 0.35321719,
            0.38250331
        ])
        self.assertEqual(tw_cruise.all(), testarray1.all())

        # Investigate the service ceiling constraint
        print("T/W Service Ceiling constraint test.")
        tw_serviceceil = concept.twrequired_sec(
            wingloading_pa=wingloadinglist_pa)

        testarray1 = np.array([
            0.46419224, 0.34031968, 0.28625287, 0.26010837, 0.24792501,
            0.24371946
        ])
        self.assertEqual(tw_serviceceil.all(), testarray1.all())

        # Investigate the take-off constraint
        print("T/W Take-off constraint test.")
        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))

        # Investigate the cruise constraint
        print("T/W Turn constraint test.")
        tw_turn = concept.twrequired_trn(wingloading_pa=wingloadinglist_pa)

        testarray1 = np.array([
            0.21826547, 0.21048143, 0.22608074, 0.25103339, 0.28066271,
            0.31296442
        ])
        testarray2 = np.array([
            0.45627288, 0.68440931, 0.91254575, 1.14068219, 1.36881863,
            1.59695506
        ])
        testarray3 = np.array([
            0.21826547, 0.21048143, 0.22608074, 0.25103339, 0.28066271, np.nan
        ])
        self.assertEqual(tw_turn[0].all(), testarray1.all())
        self.assertEqual(tw_turn[1].all(), testarray2.all())
        self.assertEqual(tw_turn[2].all(), testarray3.all())

        return