Ejemplo n.º 1
0
    def perf(self, simt):
        if abs(simt - self.t0) >= self.dt:
            self.t0 = simt
        else:
            return
        """Aircraft performance"""
        swbada = False  # no-bada version

        # allocate aircraft to their flight phase
        self.phase, self.bank = \
           phases(bs.traf.alt, bs.traf.gs, bs.traf.delalt, \
           bs.traf.cas, self.vmto, self.vmic, self.vmap, self.vmcr, self.vmld, bs.traf.bank, bs.traf.bphase, \
           bs.traf.swhdgsel,swbada)

        # AERODYNAMICS
        # compute CL: CL = 2*m*g/(VTAS^2*rho*S)
        self.qS = 0.5 * bs.traf.rho * np.maximum(1., bs.traf.tas) * np.maximum(
            1., bs.traf.tas) * self.Sref

        cl = self.mass * g0 / (self.qS * np.cos(self.bank)) * (
            self.phase != 6) + 0. * (self.phase == 6)

        # scaling factors for CD0 and CDi during flight phases according to FAA (2005): SAGE, V. 1.5, Technical Manual

        # For takeoff (phase = 6) drag is assumed equal to the takeoff phase
        CD0f = (self.phase==1)*(self.etype==1)*coeffBS.d_CD0j[0] + \
               (self.phase==2)*(self.etype==1)*coeffBS.d_CD0j[1]  + \
               (self.phase==3)*(self.etype==1)*coeffBS.d_CD0j[2] + \
               (self.phase==4)*(self.etype==1)*coeffBS.d_CD0j[3] + \
               (self.phase==5)*(self.etype==1)*(bs.traf.alt>=450.0)*coeffBS.d_CD0j[4] + \
               (self.phase==5)*(self.etype==1)*(bs.traf.alt<450.0)*coeffBS.d_CD0j[5] + \
               (self.phase==6)*(self.etype==1)*coeffBS.d_CD0j[0] + \
               (self.phase==1)*(self.etype==2)*coeffBS.d_CD0t[0] + \
               (self.phase==2)*(self.etype==2)*coeffBS.d_CD0t[1]  + \
               (self.phase==3)*(self.etype==2)*coeffBS.d_CD0t[2] + \
               (self.phase==4)*(self.etype==2)*coeffBS.d_CD0t[3]
        # (self.phase==5)*(self.etype==2)*(self.alt>=450)*coeffBS.d_CD0t[4] + \
        # (self.phase==5)*(self.etype==2)*(self.alt<450)*coeffBS.d_CD0t[5]

        # For takeoff (phase = 6) induced drag is assumed equal to the takeoff phase
        kf =   (self.phase==1)*(self.etype==1)*coeffBS.d_kj[0] + \
               (self.phase==2)*(self.etype==1)*coeffBS.d_kj[1]  + \
               (self.phase==3)*(self.etype==1)*coeffBS.d_kj[2] + \
               (self.phase==4)*(self.etype==1)*coeffBS.d_kj[3] + \
               (self.phase==5)*(self.etype==1)*(bs.traf.alt>=450)*coeffBS.d_kj[4] + \
               (self.phase==5)*(self.etype==1)*(bs.traf.alt<450)*coeffBS.d_kj[5] + \
               (self.phase==6)*(self.etype==1)*coeffBS.d_kj[0] + \
               (self.phase==1)*(self.etype==2)*coeffBS.d_kt[0] + \
               (self.phase==2)*(self.etype==2)*coeffBS.d_kt[1]  + \
               (self.phase==3)*(self.etype==2)*coeffBS.d_kt[2] + \
               (self.phase==4)*(self.etype==2)*coeffBS.d_kt[3] + \
               (self.phase==5)*(self.etype==2)*(bs.traf.alt>=450)*coeffBS.d_kt[4] + \
               (self.phase==5)*(self.etype==2)*(bs.traf.alt<450)*coeffBS.d_kt[5]

        # drag coefficient
        cd = self.CD0 * CD0f + self.k * kf * (cl * cl)

        # compute drag: CD = CD0 + CDi * CL^2 and D = rho/2*VTAS^2*CD*S
        self.D = cd * self.qS
        # energy share factor and crossover altitude
        epsalt = np.array([0.001] * bs.traf.ntraf)
        self.climb = np.array(bs.traf.delalt > epsalt)
        self.descent = np.array(bs.traf.delalt < -epsalt)

        # crossover altitiude
        bs.traf.abco = np.array(bs.traf.alt > self.atrans)
        bs.traf.belco = np.array(bs.traf.alt < self.atrans)

        # energy share factor
        self.ESF = esf(bs.traf.abco, bs.traf.belco, bs.traf.alt, bs.traf.M,\
                  self.climb, self.descent, bs.traf.delspd)

        # determine thrust
        self.Thr = (((bs.traf.vs * self.mass * g0) /
                     (self.ESF * np.maximum(bs.traf.eps, bs.traf.tas))) +
                    self.D)
        # determine thrust required to fulfill requests from pilot
        # self.Thr_pilot = (((bs.traf.pilot.vs*self.mass*g0)/(self.ESF*np.maximum(bs.traf.eps, bs.traf.pilot.tas))) + self.D)
        self.Thr_pilot = (
            ((bs.traf.ap.vs * self.mass * g0) /
             (self.ESF * np.maximum(bs.traf.eps, bs.traf.pilot.tas))) + self.D)

        # maximum thrust jet (Bruenig et al., p. 66):
        mt_jet = self.rThr * (bs.traf.rho / rho0)**0.75

        # maximum thrust prop (Raymer, p.36):
        mt_prop = self.P * self.eta / np.maximum(bs.traf.eps, bs.traf.tas)

        # merge
        self.maxthr = mt_jet * (self.etype == 1) + mt_prop * (self.etype == 2)

        # Fuel Flow

        # jet aircraft
        # ratio current thrust/rated thrust
        pThr = self.Thr / self.rThr
        # fuel flow is assumed to be proportional to thrust(Torenbeek, p.62).
        #For ground operations, idle thrust is used
        # cruise thrust is approximately equal to approach thrust
        ff_jet = ((pThr*self.ffto)*(self.phase!=6)*(self.phase!=3)+ \
        self.ffid*(self.phase==6) + self.ffap*(self.phase==3) )*(self.etype==1)
        # print "FFJET",  (pThr*self.ffto)*(self.phase!=6)*(self.phase!=3), self.ffid*(self.phase==6), self.ffap*(self.phase==3)
        # print "FFJET", ff_jet

        # turboprop aircraft
        # to be refined - f(spd)
        # CRUISE-ALTITUDE!!!
        # above cruise altitude: PSFC_CR
        PSFC = (((self.PSFC_CR - self.PSFC_TO) / 20000.0)*bs.traf.alt + self.PSFC_TO)*(bs.traf.alt<20.000) + \
                self.PSFC_CR*(bs.traf.alt >= 20.000)

        TSFC = PSFC * bs.traf.tas / (550.0 * self.eta)

        # formula p.36 Raymer is missing here!
        ff_prop = self.Thr * TSFC * (self.etype == 2)

        # combine
        self.ff = ff_jet + ff_prop

        # update mass
        #self.mass = self.mass - self.ff*self.dt/60. # Use fuelflow in kg/min

        # print bs.traf.id, self.phase, bs.traf.alt/ft, bs.traf.tas/kts, bs.traf.cas/kts, bs.traf.M,  \
        # self.Thr, self.D, self.ff,  cl, cd, bs.traf.vs/fpm, self.ESF,self.atrans, self.maxthr, \
        # self.vmto/kts, self.vmic/kts ,self.vmcr/kts, self.vmap/kts, self.vmld/kts, \
        # CD0f, kf, self.hmaxact

        # for aircraft on the runway and taxiways we need to know, whether they
        # are prior or after their flight
        self.post_flight = np.where(self.descent, True, self.post_flight)

        # when landing, we would like to stop the aircraft.
        bs.traf.pilot.tas = np.where(
            (bs.traf.alt < 0.5) * (self.post_flight) * self.pf_flag, 0.0,
            bs.traf.pilot.tas)
        # the impulse for reducing the speed to 0 should only be given once,
        # otherwise taxiing will be impossible afterwards
        self.pf_flag = np.where((bs.traf.alt < 0.5) * (self.post_flight),
                                False, self.pf_flag)

        return
Ejemplo n.º 2
0
    def perf(self, simt):
        if abs(simt - self.t0) >= self.dt:
            self.t0 = simt
        else:
            return
        """AIRCRAFT PERFORMANCE"""
        # BADA version
        swbada = True
        # flight phase
        self.phase, self.bank = \
        phases(bs.traf.alt, bs.traf.gs, bs.traf.delalt, \
        bs.traf.cas, self.vmto, self.vmic, self.vmap, self.vmcr, self.vmld, bs.traf.bank, bs.traf.bphase, \
        bs.traf.swhdgsel, swbada)

        # AERODYNAMICS
        # Lift
        qS = 0.5*bs.traf.rho*np.maximum(1.,bs.traf.tas)*np.maximum(1.,bs.traf.tas)*self.Sref
        cl = self.mass*g0/(qS*np.cos(self.bank))*(self.phase!=PHASE["GD"])+ 0.*(self.phase==PHASE["GD"])

        # Drag
        # Drag Coefficient

        # phases TO, IC, CR
        cdph = self.cd0cr+self.cd2cr*(cl*cl)

        # phase AP
        # in case approach coefficients in OPF-Files are set to zero:
        #Use cruise values instead
        cdapp = np.where(self.cd0ap !=0, self.cd0ap+self.cd2ap*(cl*cl), cdph)

        # phase LD
        # in case landing coefficients in OPF-Files are set to zero:
        #Use cruise values instead
        cdld = np.where(self.cd0ld !=0, self.cd0ld+self.cd2ld*(cl*cl), cdph)


        # now combine phases
        cd = (self.phase==PHASE['TO'])*cdph + (self.phase==PHASE["IC"])*cdph + (self.phase==PHASE["CR"])*cdph \
            + (self.phase==PHASE['AP'])*cdapp + (self.phase ==PHASE['LD'])*cdld

        # Drag:
        self.D = cd*qS

        # energy share factor and crossover altitude

        # conditions
        epsalt = np.array([0.001]*bs.traf.ntraf)
        climb = np.array(bs.traf.delalt > epsalt)
        descent = np.array(bs.traf.delalt<-epsalt)
        lvl = np.array(np.abs(bs.traf.delalt)<0.0001)*1



        # crossover altitiude
        atrans = self.atranscl*climb + self.atransdes*(1-climb)
        bs.traf.abco = np.array(bs.traf.alt>atrans)
        bs.traf.belco = np.array(bs.traf.alt<atrans)

        # energy share factor
        self.ESF = esf(bs.traf.abco, bs.traf.belco, bs.traf.alt, bs.traf.M,\
                  climb, descent, bs.traf.delspd)

        # THRUST
        # 1. climb: max.climb thrust in ISA conditions (p. 32, BADA User Manual 3.12)
        # condition: delta altitude positive


        # temperature correction for non-ISA (as soon as applied)
        #            ThrISA = (1-self.ctct2*(self.dtemp-self.ctct1))
        # jet
        # condition
        cljet = np.logical_and.reduce([climb, self.jet]) * 1

        # thrust
        Tj = self.ctcth1* (1-(bs.traf.alt/ft)/self.ctcth2+self.ctcth3*(bs.traf.alt/ft)*(bs.traf.alt/ft))

        # combine jet and default aircraft
        Tjc = cljet*Tj # *ThrISA

        # turboprop
        # condition
        clturbo = np.logical_and.reduce([climb, self.turbo]) * 1

        # thrust
        Tt = self.ctcth1/np.maximum(1.,bs.traf.tas/kts)*(1-(bs.traf.alt/ft)/self.ctcth2)+self.ctcth3

        # merge
        Ttc = clturbo*Tt # *ThrISA

        # piston
        clpiston = np.logical_and.reduce([climb, self.piston])*1
        Tp = self.ctcth1*(1-(bs.traf.alt/ft)/self.ctcth2)+self.ctcth3/np.maximum(1.,bs.traf.tas/kts)
        Tpc = clpiston*Tp

        # max climb thrust for futher calculations (equals maximum avaliable thrust)
        maxthr = Tj*self.jet + Tt*self.turbo + Tp*self.piston

        # 2. level flight: Thr = D.
        Tlvl = lvl*self.D

        # 3. Descent: condition: vs negative/ H>hdes: fixed formula. H<hdes: phase cr, ap, ld

        # above or below Hpdes? Careful! If non-ISA: ALT must be replaced by Hp!
        delh = (bs.traf.alt - self.hpdes)

        # above Hpdes:
        high = np.array(delh>0)
        Tdesh = maxthr*self.ctdesh*np.logical_and.reduce([descent, high])

        # below Hpdes
        low = np.array(delh<0)
        # phase cruise
        Tdeslc = maxthr*self.ctdesl*np.logical_and.reduce([descent, low, (self.phase==PHASE['CR'])])
        # phase approach
        Tdesla = maxthr*self.ctdesa*np.logical_and.reduce([descent, low, (self.phase==PHASE['AP'])])
        # phase landing
        Tdesll = maxthr*self.ctdesld*np.logical_and.reduce([descent, low, (self.phase==PHASE['LD'])])
        # phase ground: minimum descent thrust as a first approach
        Tgd = np.minimum.reduce([Tdesh, Tdeslc])*(self.phase==PHASE['GD'])

        # merge all thrust conditions
        T = np.maximum.reduce([Tjc, Ttc, Tpc, Tlvl, Tdesh, Tdeslc, Tdesla, Tdesll, Tgd])


        # vertical speed
        # vertical speed. Note: ISA only ( tISA = 1 )
        # for climbs: reducing factor (reduced climb power) is multiplied
        # cred applies below 0.8*hmax and for climbing aircraft only
        hcred = np.array(bs.traf.alt < (self.hmaxact*0.8))
        clh = np.logical_and.reduce([hcred, climb])
        cred = self.cred*clh
        cpred = 1-cred*((self.mmax-self.mass)/(self.mmax-self.mmin))


        # switch for given vertical speed selvs
        if (bs.traf.selvs.any()>0.) or (bs.traf.selvs.any()<0.):
            # thrust = f(selvs)
            T = ((bs.traf.selvs!=0)*(((bs.traf.pilot.vs*self.mass*g0)/     \
                      (self.ESF*np.maximum(bs.traf.eps,bs.traf.tas)*cpred)) \
                      + self.D)) + ((bs.traf.selvs==0)*T)

        self.Thr = T


        # Fuel consumption
        # thrust specific fuel consumption - jet
        # thrust
        etaj = self.cf1*(1.0+(bs.traf.tas/kts)/self.cf2)
        # merge
        ej = etaj*self.jet

        # thrust specific fuel consumption - turboprop

        # thrust
        etat = self.cf1*(1.-(bs.traf.tas/kts)/self.cf2)*((bs.traf.tas/kts)/1000.)
        # merge
        et = etat*self.turbo

        # thrust specific fuel consumption for all aircraft
        # eta is given in [kg/(min*kN)] - convert to [kg/(min*N)]
        eta = np.maximum.reduce([ej, et])/1000.

        # nominal fuel flow - (jet & turbo) and piston
        # condition jet,turbo:
        jt = np.maximum.reduce([self.jet, self.turbo])
        pdf = np.maximum.reduce ([self.piston])

        fnomjt = eta*self.Thr*jt
        fnomp = self.cf1*pdf
        # merge
        fnom = fnomjt + fnomp

        # minimal fuel flow jet, turbo and piston
        fminjt = self.cf3*(1-(bs.traf.alt/ft)/self.cf4)*jt
        fminp = self.cf3*pdf
        #merge
        fmin = fminjt + fminp

        # cruise fuel flow jet, turbo and piston
        fcrjt = eta*self.Thr*self.cf_cruise*jt
        fcrp = self.cf1*self.cf_cruise*pdf
        #merge
        fcr = fcrjt + fcrp

        # approach/landing fuel flow
        fal = np.maximum(fnom, fmin)

        # designate each aircraft to its fuelflow
        # takeoff
        ffto = fnom*(self.phase==PHASE['TO'])

        # initial climb
        ffic = fnom*(self.phase==PHASE['IC'])/2

        # phase cruise and climb
        cc = np.logical_and.reduce([climb, (self.phase==PHASE['CR'])])*1
        ffcc = fnom*cc

        # cruise and level
        ffcrl = fcr*lvl

        # descent cruise configuration
        cd2 = np.logical_and.reduce ([descent, (self.phase==PHASE['CR'])])*1
        ffcd = cd2*fmin

        # approach
        ffap = fal*(self.phase==PHASE['AP'])

        # landing
        ffld = fal*(self.phase==PHASE['LD'])

        # ground
        ffgd = fmin*(self.phase==PHASE['GD'])

        # fuel flow for each condition
        self.ff = np.maximum.reduce([ffto, ffic, ffcc, ffcrl, ffcd, ffap, ffld, ffgd])/60. # convert from kg/min to kg/sec

        # update mass
        self.mass = self.mass - self.ff*self.dt # Use fuelflow in kg/min



        # for aircraft on the runway and taxiways we need to know, whether they
        # are prior or after their flight
        self.post_flight = np.where(descent, True, self.post_flight)

        # when landing, we would like to stop the aircraft.
        bs.traf.pilot.tas = np.where((bs.traf.alt <0.5)*(self.post_flight)*self.pf_flag, 0.0, bs.traf.pilot.tas)


        # otherwise taxiing will be impossible afterwards
        # pf_flag is released so post_flight flag is only triggered once

        self.pf_flag = np.where ((bs.traf.alt <0.5)*(self.post_flight), False, self.pf_flag)

        return
Ejemplo n.º 3
0
    def perf(self,simt):
        if abs(simt - self.t0) >= self.dt:
            self.t0 = simt
        else:
            return
        """Aircraft performance"""
        swbada = False # no-bada version

        # allocate aircraft to their flight phase
        self.phase, self.bank = \
           phases(bs.traf.alt, bs.traf.gs, bs.traf.delalt, \
           bs.traf.cas, self.vmto, self.vmic, self.vmap, self.vmcr, self.vmld, bs.traf.bank, bs.traf.bphase, \
           bs.traf.swhdgsel,swbada)

        # AERODYNAMICS
        # compute CL: CL = 2*m*g/(VTAS^2*rho*S)
        self.qS = 0.5*bs.traf.rho*np.maximum(1.,bs.traf.tas)*np.maximum(1.,bs.traf.tas)*self.Sref

        cl = self.mass*g0/(self.qS*np.cos(self.bank))*(self.phase!=6)+ 0.*(self.phase==6)

        # scaling factors for CD0 and CDi during flight phases according to FAA (2005): SAGE, V. 1.5, Technical Manual

        # For takeoff (phase = 6) drag is assumed equal to the takeoff phase
        CD0f = (self.phase==1)*(self.etype==1)*coeffBS.d_CD0j[0] + \
               (self.phase==2)*(self.etype==1)*coeffBS.d_CD0j[1]  + \
               (self.phase==3)*(self.etype==1)*coeffBS.d_CD0j[2] + \
               (self.phase==4)*(self.etype==1)*coeffBS.d_CD0j[3] + \
               (self.phase==5)*(self.etype==1)*(bs.traf.alt>=450.0)*coeffBS.d_CD0j[4] + \
               (self.phase==5)*(self.etype==1)*(bs.traf.alt<450.0)*coeffBS.d_CD0j[5] + \
               (self.phase==6)*(self.etype==1)*coeffBS.d_CD0j[0] + \
               (self.phase==1)*(self.etype==2)*coeffBS.d_CD0t[0] + \
               (self.phase==2)*(self.etype==2)*coeffBS.d_CD0t[1]  + \
               (self.phase==3)*(self.etype==2)*coeffBS.d_CD0t[2] + \
               (self.phase==4)*(self.etype==2)*coeffBS.d_CD0t[3]
                   # (self.phase==5)*(self.etype==2)*(self.alt>=450)*coeffBS.d_CD0t[4] + \
                   # (self.phase==5)*(self.etype==2)*(self.alt<450)*coeffBS.d_CD0t[5]

        # For takeoff (phase = 6) induced drag is assumed equal to the takeoff phase
        kf =   (self.phase==1)*(self.etype==1)*coeffBS.d_kj[0] + \
               (self.phase==2)*(self.etype==1)*coeffBS.d_kj[1]  + \
               (self.phase==3)*(self.etype==1)*coeffBS.d_kj[2] + \
               (self.phase==4)*(self.etype==1)*coeffBS.d_kj[3] + \
               (self.phase==5)*(self.etype==1)*(bs.traf.alt>=450)*coeffBS.d_kj[4] + \
               (self.phase==5)*(self.etype==1)*(bs.traf.alt<450)*coeffBS.d_kj[5] + \
               (self.phase==6)*(self.etype==1)*coeffBS.d_kj[0] + \
               (self.phase==1)*(self.etype==2)*coeffBS.d_kt[0] + \
               (self.phase==2)*(self.etype==2)*coeffBS.d_kt[1]  + \
               (self.phase==3)*(self.etype==2)*coeffBS.d_kt[2] + \
               (self.phase==4)*(self.etype==2)*coeffBS.d_kt[3] + \
               (self.phase==5)*(self.etype==2)*(bs.traf.alt>=450)*coeffBS.d_kt[4] + \
               (self.phase==5)*(self.etype==2)*(bs.traf.alt<450)*coeffBS.d_kt[5]


        # drag coefficient
        cd = self.CD0*CD0f + self.k*kf*(cl*cl)

        # compute drag: CD = CD0 + CDi * CL^2 and D = rho/2*VTAS^2*CD*S
        self.D = cd*self.qS
        # energy share factor and crossover altitude
        epsalt = np.array([0.001]*bs.traf.ntraf)
        self.climb = np.array(bs.traf.delalt > epsalt)
        self.descent = np.array(bs.traf.delalt< -epsalt)


        # crossover altitiude
        bs.traf.abco = np.array(bs.traf.alt>self.atrans)
        bs.traf.belco = np.array(bs.traf.alt<self.atrans)

        # energy share factor
        self.ESF = esf(bs.traf.abco, bs.traf.belco, bs.traf.alt, bs.traf.M,\
                  self.climb, self.descent, bs.traf.delspd)

        # determine thrust
        self.Thr = (((bs.traf.vs*self.mass*g0)/(self.ESF*np.maximum(bs.traf.eps, bs.traf.tas))) + self.D)
        # determine thrust required to fulfill requests from pilot
        # self.Thr_pilot = (((bs.traf.pilot.vs*self.mass*g0)/(self.ESF*np.maximum(bs.traf.eps, bs.traf.pilot.tas))) + self.D)
        self.Thr_pilot = (((bs.traf.ap.vs*self.mass*g0)/(self.ESF*np.maximum(bs.traf.eps, bs.traf.pilot.tas))) + self.D)

        # maximum thrust jet (Bruenig et al., p. 66):
        mt_jet = self.rThr*(bs.traf.rho/rho0)**0.75

        # maximum thrust prop (Raymer, p.36):
        mt_prop = self.P*self.eta/np.maximum(bs.traf.eps, bs.traf.tas)

        # merge
        self.maxthr = mt_jet*(self.etype==1) + mt_prop*(self.etype==2)

        # Fuel Flow

        # jet aircraft
        # ratio current thrust/rated thrust
        pThr = self.Thr/self.rThr
        # fuel flow is assumed to be proportional to thrust(Torenbeek, p.62).
        #For ground operations, idle thrust is used
        # cruise thrust is approximately equal to approach thrust
        ff_jet = ((pThr*self.ffto)*(self.phase!=6)*(self.phase!=3)+ \
        self.ffid*(self.phase==6) + self.ffap*(self.phase==3) )*(self.etype==1)
        # print "FFJET",  (pThr*self.ffto)*(self.phase!=6)*(self.phase!=3), self.ffid*(self.phase==6), self.ffap*(self.phase==3)
        # print "FFJET", ff_jet

        # turboprop aircraft
        # to be refined - f(spd)
        # CRUISE-ALTITUDE!!!
        # above cruise altitude: PSFC_CR
        PSFC = (((self.PSFC_CR - self.PSFC_TO) / 20000.0)*bs.traf.alt + self.PSFC_TO)*(bs.traf.alt<20.000) + \
                self.PSFC_CR*(bs.traf.alt >= 20.000)

        TSFC = PSFC*bs.traf.tas/(550.0*self.eta)

        # formula p.36 Raymer is missing here!
        ff_prop = self.Thr*TSFC*(self.etype==2)


        # combine
        self.ff = np.maximum(0.0,ff_jet + ff_prop)

        # update mass
        #self.mass = self.mass - self.ff*self.dt/60. # Use fuelflow in kg/min

        # print bs.traf.id, self.phase, bs.traf.alt/ft, bs.traf.tas/kts, bs.traf.cas/kts, bs.traf.M,  \
        # self.Thr, self.D, self.ff,  cl, cd, bs.traf.vs/fpm, self.ESF,self.atrans, self.maxthr, \
        # self.vmto/kts, self.vmic/kts ,self.vmcr/kts, self.vmap/kts, self.vmld/kts, \
        # CD0f, kf, self.hmaxact


        # for aircraft on the runway and taxiways we need to know, whether they
        # are prior or after their flight
        self.post_flight = np.where(self.descent, True, self.post_flight)

        # when landing, we would like to stop the aircraft.
        bs.traf.pilot.tas = np.where((bs.traf.alt <0.5)*(self.post_flight)*self.pf_flag, 0.0, bs.traf.pilot.tas)
        # the impulse for reducing the speed to 0 should only be given once,
        # otherwise taxiing will be impossible afterwards
        self.pf_flag = np.where ((bs.traf.alt <0.5)*(self.post_flight), False, self.pf_flag)

        return
Ejemplo n.º 4
0
    def update(self, dt=settings.performance_dt):
        """AIRCRAFT PERFORMANCE"""
        # BADA version
        swbada = True
        delalt = bs.traf.selalt - bs.traf.alt
        # flight phase
        self.phase, self.bank = phases(bs.traf.alt, bs.traf.gs, delalt,
                                       bs.traf.cas, self.vmto, self.vmic,
                                       self.vmap, self.vmcr, self.vmld,
                                       bs.traf.bank, bs.traf.bphase,
                                       bs.traf.swhdgsel, swbada)

        # AERODYNAMICS
        # Lift
        qS = 0.5 * bs.traf.rho * np.maximum(1., bs.traf.tas) * np.maximum(
            1., bs.traf.tas) * self.Sref
        cl = self.mass * g0 / (qS * np.cos(self.bank)) * (
            self.phase != PHASE["GD"]) + 0. * (self.phase == PHASE["GD"])

        # Drag
        # Drag Coefficient

        # phases TO, IC, CR
        cdph = self.cd0cr + self.cd2cr * (cl * cl)

        # phase AP
        # in case approach coefficients in OPF-Files are set to zero:
        #Use cruise values instead
        cdapp = np.where(self.cd0ap != 0, self.cd0ap + self.cd2ap * (cl * cl),
                         cdph)

        # phase LD
        # in case landing coefficients in OPF-Files are set to zero:
        #Use cruise values instead
        cdld = np.where(self.cd0ld != 0, self.cd0ld + self.cd2ld * (cl * cl),
                        cdph)

        # now combine phases
        cd = (self.phase==PHASE['TO'])*cdph + (self.phase==PHASE["IC"])*cdph + (self.phase==PHASE["CR"])*cdph \
            + (self.phase==PHASE['AP'])*cdapp + (self.phase ==PHASE['LD'])*cdld

        # Drag:
        self.D = cd * qS

        # energy share factor and crossover altitude

        # conditions
        epsalt = np.array([0.001] * bs.traf.ntraf)
        climb = np.array(delalt > epsalt)
        descent = np.array(delalt < -epsalt)
        lvl = np.array(np.abs(delalt) < 0.0001) * 1

        # energy share factor
        delspd = bs.traf.pilot.tas - bs.traf.tas
        selmach = bs.traf.selspd < 2.0
        self.ESF = esf(bs.traf.alt, bs.traf.M, climb, descent, delspd, selmach)

        # THRUST
        # 1. climb: max.climb thrust in ISA conditions (p. 32, BADA User Manual 3.12)
        # condition: delta altitude positive

        # temperature correction for non-ISA (as soon as applied)
        #            ThrISA = (1-self.ctct2*(self.dtemp-self.ctct1))
        # jet
        # condition
        cljet = np.logical_and.reduce([climb, self.jet]) * 1

        # thrust
        Tj = self.ctcth1 * (1 -
                            (bs.traf.alt / ft) / self.ctcth2 + self.ctcth3 *
                            (bs.traf.alt / ft) * (bs.traf.alt / ft))

        # combine jet and default aircraft
        Tjc = cljet * Tj  # *ThrISA

        # turboprop
        # condition
        clturbo = np.logical_and.reduce([climb, self.turbo]) * 1

        # thrust
        Tt = self.ctcth1 / np.maximum(1., bs.traf.tas / kts) * (
            1 - (bs.traf.alt / ft) / self.ctcth2) + self.ctcth3

        # merge
        Ttc = clturbo * Tt  # *ThrISA

        # piston
        clpiston = np.logical_and.reduce([climb, self.piston]) * 1
        Tp = self.ctcth1 * (
            1 - (bs.traf.alt / ft) / self.ctcth2) + self.ctcth3 / np.maximum(
                1., bs.traf.tas / kts)
        Tpc = clpiston * Tp

        # max climb thrust for futher calculations (equals maximum avaliable thrust)
        maxthr = Tj * self.jet + Tt * self.turbo + Tp * self.piston

        # 2. level flight: Thr = D.
        Tlvl = lvl * (self.D + bs.traf.ax * self.mass)

        # 3. Descent: condition: vs negative/ H>hdes: fixed formula. H<hdes: phase cr, ap, ld

        # above or below Hpdes? Careful! If non-ISA: ALT must be replaced by Hp!
        delh = (bs.traf.alt - self.hpdes)

        # above Hpdes:
        high = np.array(delh > 0)
        Tdesh = maxthr * self.ctdesh * np.logical_and.reduce([descent, high])

        # below Hpdes
        low = np.array(delh < 0)
        # phase cruise
        Tdeslc = maxthr * self.ctdesl * np.logical_and.reduce(
            [descent, low, (self.phase == PHASE['CR'])])
        # phase approach
        Tdesla = maxthr * self.ctdesa * np.logical_and.reduce(
            [descent, low, (self.phase == PHASE['AP'])])
        # phase landing
        Tdesll = maxthr * self.ctdesld * np.logical_and.reduce(
            [descent, low, (self.phase == PHASE['LD'])])
        # phase ground: minimum descent thrust as a first approach
        Tgd = np.minimum.reduce([Tdesh, Tdeslc]) * (self.phase == PHASE['GD'])

        # merge all thrust conditions
        T = np.maximum.reduce(
            [Tjc, Ttc, Tpc, Tlvl, Tdesh, Tdeslc, Tdesla, Tdesll, Tgd])

        # vertical speed
        # vertical speed. Note: ISA only ( tISA = 1 )
        # for climbs: reducing factor (reduced climb power) is multiplied
        # cred applies below 0.8*hmax and for climbing aircraft only
        hcred = np.array(bs.traf.alt < (self.hmaxact * 0.8))
        clh = np.logical_and.reduce([hcred, climb])
        cred = self.cred * clh
        cpred = 1 - cred * ((self.mmax - self.mass) / (self.mmax - self.mmin))

        # switch for given vertical speed selvs
        if (bs.traf.selvs.any() > 0.) or (bs.traf.selvs.any() < 0.):
            # thrust = f(selvs)
            T = ((bs.traf.selvs!=0)*(((bs.traf.pilot.vs*self.mass*g0)/     \
                      (self.ESF*np.maximum(bs.traf.eps,bs.traf.tas)*cpred)) \
                      + self.D)) + ((bs.traf.selvs==0)*T)

        self.Thr = T

        # Fuel consumption
        # thrust specific fuel consumption - jet
        # thrust
        etaj = self.cf1 * (1.0 + (bs.traf.tas / kts) / self.cf2)
        # merge
        ej = etaj * self.jet

        # thrust specific fuel consumption - turboprop

        # thrust
        etat = self.cf1 * (1. - (bs.traf.tas / kts) / self.cf2) * (
            (bs.traf.tas / kts) / 1000.)
        # merge
        et = etat * self.turbo

        # thrust specific fuel consumption for all aircraft
        # eta is given in [kg/(min*kN)] - convert to [kg/(min*N)]
        eta = np.maximum.reduce([ej, et]) / 1000.

        # nominal fuel flow - (jet & turbo) and piston
        # condition jet,turbo:
        jt = np.maximum.reduce([self.jet, self.turbo])
        pdf = np.maximum.reduce([self.piston])

        fnomjt = eta * self.Thr * jt
        fnomp = self.cf1 * pdf
        # merge
        fnom = fnomjt + fnomp

        # minimal fuel flow jet, turbo and piston
        fminjt = self.cf3 * (1 - (bs.traf.alt / ft) / self.cf4) * jt
        fminp = self.cf3 * pdf
        #merge
        fmin = fminjt + fminp

        # cruise fuel flow jet, turbo and piston
        fcrjt = eta * self.Thr * self.cf_cruise * jt
        fcrp = self.cf1 * self.cf_cruise * pdf
        #merge
        fcr = fcrjt + fcrp

        # approach/landing fuel flow
        fal = np.maximum(fnom, fmin)

        # designate each aircraft to its fuelflow
        # takeoff
        ffto = fnom * (self.phase == PHASE['TO'])

        # initial climb
        ffic = fnom * (self.phase == PHASE['IC']) / 2

        # phase cruise and climb
        cc = np.logical_and.reduce([climb, (self.phase == PHASE['CR'])]) * 1
        ffcc = fnom * cc

        # cruise and level
        ffcrl = fcr * lvl

        # descent cruise configuration
        cd2 = np.logical_and.reduce([descent, (self.phase == PHASE['CR'])]) * 1
        ffcd = cd2 * fmin

        # approach
        ffap = fal * (self.phase == PHASE['AP'])

        # landing
        ffld = fal * (self.phase == PHASE['LD'])

        # ground
        ffgd = fmin * (self.phase == PHASE['GD'])

        # fuel flow for each condition
        self.fuelflow = np.maximum.reduce([
            ffto, ffic, ffcc, ffcrl, ffcd, ffap, ffld, ffgd
        ]) / 60.  # convert from kg/min to kg/sec

        # update mass
        self.mass -= self.fuelflow * dt  # Use fuelflow in kg/min

        # for aircraft on the runway and taxiways we need to know, whether they
        # are prior or after their flight
        self.post_flight = np.where(descent, True, self.post_flight)

        # when landing, we would like to stop the aircraft.
        bs.traf.pilot.tas = np.where(
            (bs.traf.alt < 0.5) * (self.post_flight) * self.pf_flag, 0.0,
            bs.traf.pilot.tas)

        # otherwise taxiing will be impossible afterwards
        # pf_flag is released so post_flight flag is only triggered once

        self.pf_flag = np.where((bs.traf.alt < 0.5) * (self.post_flight),
                                False, self.pf_flag)

        return
Ejemplo n.º 5
0
    def update(self, dt):
        ''' Periodic update function for performance calculations. '''
        swbada = False  # no-bada version
        delalt = bs.traf.selalt - bs.traf.alt
        # allocate aircraft to their flight phase
        self.phase, self.bank = phases(bs.traf.alt, bs.traf.gs, delalt,
                                       bs.traf.cas, self.vmto, self.vmic,
                                       self.vmap, self.vmcr, self.vmld,
                                       bs.traf.ap.bankdef, bs.traf.bphase,
                                       bs.traf.swhdgsel, swbada)

        # AERODYNAMICS
        # compute CL: CL = 2*m*g/(VTAS^2*rho*S)
        self.qS = 0.5 * bs.traf.rho * np.maximum(1., bs.traf.tas) * np.maximum(
            1., bs.traf.tas) * self.Sref

        cl = self.mass * g0 / (self.qS * np.cos(self.bank)) * (
            self.phase != 6) + 0. * (self.phase == 6)

        # scaling factors for CD0 and CDi during flight phases according to FAA (2005): SAGE, V. 1.5, Technical Manual

        # For takeoff (phase = 6) drag is assumed equal to the takeoff phase
        CD0f = (self.phase==1)*(self.etype==1)*coeffBS.d_CD0j[0] + \
               (self.phase==2)*(self.etype==1)*coeffBS.d_CD0j[1]  + \
               (self.phase==3)*(self.etype==1)*coeffBS.d_CD0j[2] + \
               (self.phase==4)*(self.etype==1)*coeffBS.d_CD0j[3] + \
               (self.phase==5)*(self.etype==1)*(bs.traf.alt>=450.0)*coeffBS.d_CD0j[4] + \
               (self.phase==5)*(self.etype==1)*(bs.traf.alt<450.0)*coeffBS.d_CD0j[5] + \
               (self.phase==6)*(self.etype==1)*coeffBS.d_CD0j[0] + \
               (self.phase==1)*(self.etype==2)*coeffBS.d_CD0t[0] + \
               (self.phase==2)*(self.etype==2)*coeffBS.d_CD0t[1]  + \
               (self.phase==3)*(self.etype==2)*coeffBS.d_CD0t[2] + \
               (self.phase==4)*(self.etype==2)*coeffBS.d_CD0t[3]
        # (self.phase==5)*(self.etype==2)*(self.alt>=450)*coeffBS.d_CD0t[4] + \
        # (self.phase==5)*(self.etype==2)*(self.alt<450)*coeffBS.d_CD0t[5]

        # For takeoff (phase = 6) induced drag is assumed equal to the takeoff phase
        kf =   (self.phase==1)*(self.etype==1)*coeffBS.d_kj[0] + \
               (self.phase==2)*(self.etype==1)*coeffBS.d_kj[1]  + \
               (self.phase==3)*(self.etype==1)*coeffBS.d_kj[2] + \
               (self.phase==4)*(self.etype==1)*coeffBS.d_kj[3] + \
               (self.phase==5)*(self.etype==1)*(bs.traf.alt>=450)*coeffBS.d_kj[4] + \
               (self.phase==5)*(self.etype==1)*(bs.traf.alt<450)*coeffBS.d_kj[5] + \
               (self.phase==6)*(self.etype==1)*coeffBS.d_kj[0] + \
               (self.phase==1)*(self.etype==2)*coeffBS.d_kt[0] + \
               (self.phase==2)*(self.etype==2)*coeffBS.d_kt[1]  + \
               (self.phase==3)*(self.etype==2)*coeffBS.d_kt[2] + \
               (self.phase==4)*(self.etype==2)*coeffBS.d_kt[3] + \
               (self.phase==5)*(self.etype==2)*(bs.traf.alt>=450)*coeffBS.d_kt[4] + \
               (self.phase==5)*(self.etype==2)*(bs.traf.alt<450)*coeffBS.d_kt[5]

        # drag coefficient
        cd = self.CD0 * CD0f + self.k * kf * (cl * cl)

        # compute drag: CD = CD0 + CDi * CL^2 and D = rho/2*VTAS^2*CD*S
        self.D = cd * self.qS
        # energy share factor and crossover altitude
        epsalt = np.array([0.001] * bs.traf.ntraf)
        climb = np.array(delalt > epsalt)
        descent = np.array(delalt < -epsalt)

        # energy share factor
        delspd = bs.traf.aporasas.tas - bs.traf.tas
        selmach = bs.traf.selspd < 2.0
        self.ESF = esf(bs.traf.alt, bs.traf.M, climb, descent, delspd, selmach)

        # determine thrust
        self.thrust = (((bs.traf.vs * self.mass * g0) /
                        (self.ESF * np.maximum(bs.traf.eps, bs.traf.tas))) +
                       self.D)
        # determine thrust required to fulfill requests from pilot
        # self.thrust_pilot = (((bs.traf.aporasas.vs*self.mass*g0)/(self.ESF*np.maximum(bs.traf.eps, bs.traf.aporasas.tas))) + self.D)
        self.thrust_pilot = (
            ((bs.traf.ap.vs * self.mass * g0) /
             (self.ESF * np.maximum(bs.traf.eps, bs.traf.aporasas.tas))) +
            self.D)

        # maximum thrust jet (Bruenig et al., p. 66):
        mt_jet = self.rated_thrust * (bs.traf.rho / rho0)**0.75

        # maximum thrust prop (Raymer, p.36):
        mt_prop = self.P * self.eta / np.maximum(bs.traf.eps, bs.traf.tas)

        # merge
        self.maxthr = mt_jet * (self.etype == 1) + mt_prop * (self.etype == 2)

        # Fuel Flow

        # jet aircraft
        # ratio current thrust/rated thrust
        pThr = self.thrust / self.rated_thrust
        # fuel flow is assumed to be proportional to thrust(Torenbeek, p.62).
        #For ground operations, idle thrust is used
        # cruise thrust is approximately equal to approach thrust
        ff_jet = ((pThr*self.ffto)*(self.phase!=6)*(self.phase!=3)+ \
        self.ffid*(self.phase==6) + self.ffap*(self.phase==3) )*(self.etype==1)
        # print "FFJET",  (pThr*self.ffto)*(self.phase!=6)*(self.phase!=3), self.ffid*(self.phase==6), self.ffap*(self.phase==3)
        # print "FFJET", ff_jet

        # turboprop aircraft
        # to be refined - f(spd)
        # CRUISE-ALTITUDE!!!
        # above cruise altitude: PSFC_CR
        PSFC = (((self.PSFC_CR - self.PSFC_TO) / 20000.0)*bs.traf.alt + self.PSFC_TO)*(bs.traf.alt<20.000) + \
                self.PSFC_CR*(bs.traf.alt >= 20.000)

        TSFC = PSFC * bs.traf.tas / (550.0 * self.eta)

        # formula p.36 Raymer is missing here!
        ff_prop = self.thrust * TSFC * (self.etype == 2)

        # combine
        self.fuelflow = np.maximum(0.0, ff_jet + ff_prop)

        # update mass
        self.mass -= self.fuelflow * dt

        # print bs.traf.id, self.phase, bs.traf.alt/ft, bs.traf.tas/kts, bs.traf.cas/kts, bs.traf.M,  \
        # self.thrust, self.D, self.ff,  cl, cd, bs.traf.vs/fpm, self.ESF,self.atrans, self.maxthr, \
        # self.vmto/kts, self.vmic/kts ,self.vmcr/kts, self.vmap/kts, self.vmld/kts, \
        # CD0f, kf, self.hmaxact

        # for aircraft on the runway and taxiways we need to know, whether they
        # are prior or after their flight
        self.post_flight = np.where(descent, True, self.post_flight)

        # when landing, we would like to stop the aircraft.
        bs.traf.aporasas.tas = np.where(
            (bs.traf.alt < 0.5) * (self.post_flight) * self.pf_flag, 0.0,
            bs.traf.aporasas.tas)
        # the impulse for reducing the speed to 0 should only be given once,
        # otherwise taxiing will be impossible afterwards
        self.pf_flag = np.where((bs.traf.alt < 0.5) * (self.post_flight),
                                False, self.pf_flag)

        # define acceleration: aircraft taxiing and taking off use ground acceleration,
        # landing aircraft use ground deceleration, others use standard acceleration
        self.axmax = ((self.phase == PHASE['IC']) + (self.phase == PHASE['CR']) + (self.phase == PHASE['AP']) + (self.phase == PHASE['LD'])) * 0.5 \
            + ((self.phase == PHASE['TO']) + (self.phase == PHASE['GD'])*(1-self.post_flight)) * self.gr_acc  \
            + (self.phase == PHASE['GD']) * self.post_flight * self.gr_dec