Exemple #1
0
def DropandHover():
    global s

    PP = GetParams()[1]

    s = simulate(500)

    initialHeight = 500

    s.y0 = [0, initialHeight, 0, 0]
    s.x2[s.n] = initialHeight
    s.pitch[s.n] = 90

    s.pitchShape = 'const'
    s.pitchCeiling = 90

    # make the aircraft mass lower because the powerplant is not enough to
    # make the full aircraft hover
    s.totalMass = 4

    weight = s.totalMass * AC['g']

    s.TShape = 'sigmoid'
    s.TFloor = 0
    s.TCeiling = weight
    s.TStart = 0
    s.TEnd = 50

    s.runtime = 200
    s.steps = 200
    s.RunInterval()

    Plot(s,
         'thrust',
         'pitch',
         'x2',
         'v2',
         save=True,
         title=False,
         direct='simulationPics/hover/')

    Fig, ax1 = plt.subplots()
    ax2 = ax1.twinx()
    ax1.plot(s.timeArray[:s.n], s.x2[:s.n], label='Height')
    ax2.plot(s.timeArray[:s.n], s.v2[:s.n], 'r', label='V2')

    ax1.yaxis.set_major_formatter(StrMethodFormatter('{x:,.0f}'))

    lines, labels = ax1.get_legend_handles_labels()
    lines2, labels2 = ax2.get_legend_handles_labels()

    ax1.set_xlabel('time (seconds)')
    ax1.set_ylabel('AGL (m)')
    ax2.set_ylabel('velocity (m/s)')

    ax2.legend(lines + lines2, labels + labels2, loc=0)
    plt.tight_layout()
    plt.savefig('simulationPics/hover/x2v2.png')
    plt.show()
Exemple #2
0
    def __init__(self, rng=50, plant=None):
        self.xHist = np.zeros((4, 1))
        self.cHist = np.zeros(1)

        # if plant is not given, use standard unsized plant
        if not plant:
            self.plant = GetParams()[1]
        else:
            self.plant = plant

        self.rng = rng

        self.iterations = 0
        self.result = None

        self.x0 = np.array([10, 2.9, 5, 25])
Exemple #3
0
def Fly():
    global sim, fly

    _, PP = GetParams()

    # initialize classes
    sim = simulate(700, PP)

    # take off
    TakeOff(sim)

    Climb(sim, v1=13.66, desiredCR=2, desiredHeight=410)

    Cruise(sim, v1=16.9, distance=500)

    Glide(sim, 0)

    sim.CalculateE()
Exemple #4
0
def PlotPlantSizing():
    """
    Plots the power plant mass (ICE mass + EM mass) produced when sizing at different
    rEM. rEM = maximum EM power / total power demand as given by ADRpy

    Returns
    -------
    None.

    """
    _, PP = GetParams()

    rEMArray = np.linspace(0, 1, 11)
    massArray = np.zeros(11)

    for index, i in enumerate(rEMArray):
        sizedP = PlantSizing(PP, i)
        m = sizedP['EMMass'] + sizedP['ICEMass']
        massArray[index] = m

    plt.plot(rEMArray, massArray)
    plt.xlabel('Ratio of power produced by EM')
    plt.ylabel('ICE + EM mass (kg)')
    plt.title('Plant mass at different ICE and EM sizes')
Exemple #5
0
    def __init__(self, rng, plant=None, runSizing=True):
        self.plotMarkers = np.array([])
        self.rng = rng * 1000
        self.runtime = 0.
        self.integrator = 'odeint'
        self.steps = 0
        self.time = 0.
        self.payloadDropped = False

        if not plant:
            _, self.PP = GetParams()
        else:
            self.PP = plant.copy()

        # size the powerplant, get updated dictionary to store in object
        if runSizing:
            self.PP = PlantSizing(self.PP)

        self.battChoice = int(self.PP['battChoice'])

        self.battCap = self.PP['battCapList'][self.battChoice]
        self.battSE = self.PP['battSEList'][self.battChoice]
        self.battMass = self.PP['battMassList'][self.battChoice]

        # zero fuel mass - everything but fuel is included here
        self.zfm = self.battMass + AC['emptyMass'] + AC['payloadMass']

        self.totalMass = AC['emptyMass'] + AC['payloadMass'] + self.PP['fullTankMass']\
            + self.battMass + self.PP['EMMass'] + self.PP['ICEMass']

        # contains x1, x2, v1, v2 in four columns
        self.solution = False

        # vars for sigmoid schedules
        self.TFloor = 0.
        self.pitchFloor = 0.
        self.TCeiling = 0.
        self.pitchCeiling = 0.
        self.TStart = 0.
        self.pitchStart = 0.
        self.TEnd = 0.
        self.pitchEnd = 0.
        self.TShape = 'const'
        self.pitchShape = 'const'

        # total amount of data, total time steps returned from ODE solver
        self.n = 0

        # initial values for ode solver
        self.y0 = np.zeros(4)
        """ data arrays """

        # angles
        self.alpha = np.zeros(10**3)
        self.pitch = np.zeros(10**3)
        self.gamma = np.zeros(10**3)

        # kinematics
        self.x1 = np.zeros(10**3)
        self.x2 = np.zeros(10**3)
        self.v1 = np.zeros(10**3)
        self.v2 = np.zeros(10**3)
        self.a1 = np.zeros(10**3)
        self.a2 = np.zeros(10**3)

        # time that corresponds with each index
        self.timeArray = np.zeros(10**3)

        # thrust
        self.thrust = np.zeros(10**3)
        self.EMThrust = np.zeros(10**3)
        self.ICEThrust = np.zeros(10**3)

        # energy related
        self.totalE = np.zeros(10**3)
        self.fuelMass = np.zeros(10**3)
        self.fuelE = np.zeros(10**3)
        self.SOC = np.zeros(10**3)
        self.battE = np.zeros(10**3)

        # power related
        self.power = np.zeros(10**3)  # total power coming out of the prop
        self.fuelP = np.zeros(10**3)  # power consumed by ICE
        self.battP = np.zeros(10**3)  # power consumed by EM
        self.ICEShaftP = np.zeros(10**3)
        self.EMShaftP = np.zeros(10**3)
        self.ICEPropP = np.zeros(
            10**3)  # total power produced by the ICE connected propeller
        self.EMPropP = np.zeros(
            10**3)  # total power produced by the EM connected propeller

        self.ICEEff = np.zeros(10**3)  # ICE brake efficiency

        ### propeller related ###
        # -- EM Propeller -- #               # -- ICE Propeller -- #
        self.EMrps = np.zeros(10**3)
        self.ICErps = np.zeros(10**3)
        self.EMJ = np.zeros(10**3)
        self.ICEJ = np.zeros(10**3)
        self.EMPropEff = np.zeros(10**3)
        self.ICEPropEff = np.zeros(10**3)

        self.EMTotEff = np.zeros(10**3)
        self.ICETotEff = np.zeros(10**3)
        self.rEM = np.zeros(10**3)  # ratio of output power provided by EM

        # 0 - off, 1 - ICE only, 2 - ICE ideal and EM, 3 - EM max and ICE, 4 - excess
        self.RBOut = np.zeros(10**3)
        self.massCost = np.zeros(10**3)
Exemple #6
0
        # artificial fix if the J value passed is too far out of the interpolation range
        if PropCq < 0:
            PropCq = 0

        Q = PropCq * Density(h) * rps**2 * D**5

        return Q


def PropTFun(v, rps, h):
    # prevent division by zero when calculating J
    if rps == 0:
        return 0

    else:
        J = v / (rps * PP['D'])

        PropCt = PP['CtFun'](J)

        # artificial fix if the J value passed is too far out of the interpolation range
        if PropCt < 0:
            PropCt = 0

        T = PropCt * Density(h) * rps**2 * PP['D']**4

        return T


AC, PP = GetParams('aircraft_params.txt')
PP = PlantSizing(PP)
Exemple #7
0
def Results(rng=50):
    global op, op1, op2, op3

    _, plant0 = GetParams()

    plant0 = PlantSizing(plant0)

    # save unchanged simulator for later
    s0 = simulate(rng, plant0, runSizing=False)

    ########## Start 1st opt ##########

    # create a sized plant dictionary
    _, plant1 = GetParams()
    plant1 = PlantSizing(plant1)

    # get prelim results with sized plant
    op1 = Optimize(rng, plant1)
    op1.optm()

    # save the simulator object that contains the last iteration of the optimisation
    op1.MCostF(op1.result.x, saveSim=True)

    # amount of fuel actually needed for flight
    usedFuelM1 = op1.sim.fuelMassCost[op1.sim.n - 1]

    # necessary batter capacity needed for flight
    usedBattE1 = op1.sim.battE[op1.sim.n - 1]

    battChoice1 = 4
    for index, i in enumerate(plant1['battCapList']):
        if i > usedBattE1:
            battChoice1 = index
            break

    print('\nFuel mass used on the first optimisation:', round(usedFuelM1, 3),
          'kg')
    print('Battery energy used on the first optimisation:',
          round(usedBattE1 / 1000, 3), 'kJ')
    print('Now attempting to fly with the', s0.PP['battMassList'][battChoice1],
          'kg battery\n')

    ########## End 1st opt ##########

    ########## Start 2nd opt ##########
    # create another sized plant dictionary
    _, plant2 = GetParams()
    plant2 = PlantSizing(plant2)

    # update the masses, only change the plant2 dict to keep track of old values
    plant2['fullTankMass'] = usedFuelM1
    plant2['battChoice'] = battChoice1

    # get prelim results with sized plant
    op2 = Optimize(rng, plant2)
    op2.optm()

    # save new, lighter profile
    op2.MCostF(op2.result.x, saveSim=True)

    # amount of fuel actually needed for flight
    usedFuelM2 = op2.sim.fuelMassCost[op2.sim.n - 1]
    # necessary battery capacity needed for flight
    usedBattE2 = op2.sim.battE[op2.sim.n - 1]

    # check if the same battery should be used
    for index, i in enumerate(plant2['battCapList']):
        if i > usedBattE2:
            battChoice2 = index
            break

    # check how much less fuel is used on second flight
    fSavings = abs((usedFuelM1 - usedFuelM2) / usedFuelM1)

    print('\nFuel mass used on the second optimisation:', round(usedFuelM2, 3),
          'kg')
    print('Battery energy used on the second optimisation:',
          round(usedBattE2 / 1000, 3), 'kJ\n')

    ########## End Second opt ##########

    ########## Start 3rd opt ##########

    # if the fuel savings are siginificant again, or a different battery can be chosen
    # run the optimisation again
    if fSavings > 0.1 or battChoice2 != battChoice1:
        print('Now attempting to fly with the',
              s0.PP['battMassList'][battChoice2], 'kg battery')
        _, plant3 = GetParams()
        plant3 = PlantSizing(plant3)

        # update the masses, only change the s3 plant dict to keep track of values

        plant3['fullTankMass'] = usedFuelM2
        plant3['battChoice'] = battChoice2

        # run optimization again but with smaller battery etc.
        op3 = Optimize(rng, plant3)
        op3.optm()

        # save new profile
        op3.MCostF(op3.result.x, saveSim=True)

        battMassSavings = s0.battMass - op3.sim.battMass
        fuelMassSavings = s0.PP['fullTankMass'] - op3.sim.PP['fullTankMass']

    ########## End 3rd opt ##########

    # if second run was sufficient, should get values for saved mass
    else:
        battMassSavings = s0.battMass - op2.sim.battMass
        fuelMassSavings = s0.PP['fullTankMass'] - op2.sim.PP['fullTankMass']

    print('The optimisation terminated. The optimisation saved at least',
          round(battMassSavings, 2), 'kg in battery mass and ',
          round(fuelMassSavings, 2), 'kg in fuel which are now available',
          'for payload')

    if 's3' in locals():
        return op1, op2, op3

    else:
        return op1, op2