Example #1
0
    def perf(self):
        """Aircraft performance"""
        swbada = False # no-bada version

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

        # AERODYNAMICS
        # compute CL: CL = 2*m*g/(VTAS^2*rho*S)
        self.qS = 0.5*self.traf.rho*np.maximum(1.,self.traf.tas)*np.maximum(1.,self.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
        
        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)*(self.traf.alt>=450)*coeffBS.d_CD0j[4] + \
               (self.phase==5)*(self.etype==1)*(self.traf.alt<450)*coeffBS.d_CD0j[5] + \
               (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]
                   
        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)*(self.traf.alt>=450)*coeffBS.d_kj[4] + \
               (self.phase==5)*(self.etype==1)*(self.traf.alt<450)*coeffBS.d_kj[5] + \
               (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)*(self.traf.alt>=450)*coeffBS.d_kt[4] + \
               (self.phase==5)*(self.etype==2)*(self.traf.alt<450)*coeffBS.d_kt[5]   

        # print "KF climb",(self.phase == 3)*(self.etype==1)*(self.traf.delalt>1)*coeffBS.d_kj[1]
        # print "KF cruise",(self.phase == 3)*(self.etype==1)*((self.traf.delalt>-1 )& (self.traf.delalt<1))*coeffBS.d_kj[2] 
        # print "KF descent",(self.phase == 3)*(self.etype==1)*(self.traf.delalt<-1)*coeffBS.d_kj[3]

        # print CD0f, kf


        # line for kf-c and kf+fuel
        cd = self.CD0*CD0f + self.k*kf*(cl**2)

        # line for w/o
        #cd = self.CD0+self.k*(cl**2)
        
        # print "CL", cl, "CD", cd
        # 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]*self.traf.ntraf)   
        self.climb = np.array(self.traf.delalt > epsalt)
        self.descent = np.array(self.traf.delalt<epsalt)
  
        #crossover altitude (BADA User Manual 3.12, p. 12)
        self.atrans = (1000/6.5)*(T0*(1-((((1+gamma1*(self.refcas/a0)**2)**(gamma2))-1) /  \
        (((1+gamma1*self.refma**2)**(gamma2))-1))**((-(beta)*R)/g0)))

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

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


        # THRUST
        # determine vertical speed
        swvs = (np.abs(self.traf.desvs) > self.traf.eps)
        vspd = swvs * self.traf.desvs + (1. - swvs) * self.traf.avsdef * np.sign(self.traf.delalt)
        swaltsel = np.abs(self.traf.delalt) > np.abs(2. * self.traf.perfdt * np.abs(vspd))
        self.traf.vs = swaltsel * vspd  

        self.Thr = (((self.traf.vs*self.mass*g0)/(self.ESF*np.maximum(self.traf.eps, self.traf.tas))) + self.D) 

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

        # maximum thrust prop (Raymer, p.36):
        mt_prop = self.P*self.eta/np.maximum(self.traf.eps, self.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)*self.traf.alt + self.PSFC_TO)*(self.traf.alt<20.000) + \
                self.PSFC_CR*(self.traf.alt >= 20.000)

        TSFC =PSFC*self.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.traf.perfdt/60. # Use fuelflow in kg/min

        # print self.traf.id, self.phase, self.traf.alt/ft, self.traf.tas/kts, self.traf.cas/kts, self.traf.M,  \
        # self.Thr, self.D, self.ff,  cl, cd, self.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

        return
Example #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.hdgsel, swbada)

        # AERODYNAMICS
        # Lift
        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 != 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 * self.qS

        # energy share factor and crossover altitude

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

        # crossover altitiude
        atrans = self.atranscl * self.climb + self.atransdes * (1 - self.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,\
                  self.climb, self.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([self.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([self.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([self.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(
            [self.descent, high])

        # below Hpdes
        low = np.array(delh < 0)
        # phase cruise
        Tdeslc = maxthr * self.ctdesl * np.logical_and.reduce(
            [self.descent, low, (self.phase == PHASE['CR'])])
        # phase approach
        Tdesla = maxthr * self.ctdesa * np.logical_and.reduce(
            [self.descent, low, (self.phase == PHASE['AP'])])
        # phase landing
        Tdesll = maxthr * self.ctdesld * np.logical_and.reduce(
            [self.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, self.climb])
        cred = self.cred * clh
        cpred = 1 - cred * ((self.mmax - self.mass) / (self.mmax - self.mmin))

        # switch for given vertical speed avs
        if (bs.traf.avs.any() > 0) or (bs.traf.avs.any() < 0):
            # thrust = f(avs)
            T = ((bs.traf.avs!=0)*(((bs.traf.pilot.vs*self.mass*g0)/     \
                      (self.ESF*np.maximum(bs.traf.eps,bs.traf.tas)*cpred)) \
                      + self.D)) + ((bs.traf.avs==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([self.climb,
                                    (self.phase == PHASE['CR'])]) * 1
        ffcc = fnom * cc

        # cruise and level
        ffcrl = fcr * lvl

        # descent cruise configuration
        cd2 = np.logical_and.reduce(
            [self.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(self.descent, True, self.post_flight)

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

        # 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
Example #3
0
    def perf(self):
        """AIRCRAFT PERFORMANCE"""
        # flight phase
        self.phase, self.bank = \
        phases(self.traf.alt, self.traf.gs, self.traf.delalt, \
        self.traf.cas, self.vmto, self.vmic, self.vmap, self.vmcr, self.vmld, self.traf.bank, self.traf.bphase, \
        self.traf.hdgsel, self.traf.bada)

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

        # Drag
        # Drag Coefficient

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

        # phase AP
        cdapp = self.cd0ap+self.cd2ap*(cl**2)

        # in case approach coefficients in OPF-Files are set to zero: 
        #Use cruise values instead
        cdapp = cdapp + (cdapp ==0)*cdph

        # phase LD
        cdld = self.cd0ld + self.gear + self.cd2ld*(cl**2)

        # in case landing coefficients in OPF-Files are set to zero: 
        #Use cruise values instead
        cdld = cdld + (cdld ==0)*cdph   

        # now combine phases            
        cd = (self.phase==1)*cdph + (self.phase==2)*cdph + (self.phase==3)*cdph \
            + (self.phase==4)*cdapp + (self.phase ==5)*cdld  

        # Drag:
        self.D = cd*self.qS 

        # energy share factor and crossover altitude  

        # conditions
        epsalt = np.array([0.001]*self.traf.ntraf)   
        self.climb = np.array(self.traf.delalt > epsalt)
        self.descent = np.array(self.traf.delalt<epsalt)
        lvl = np.array(np.abs(self.traf.delalt)<0.0001)*1
        
        # designate reference CAS to phases
        cascl = self.cascl*self.climb
        cascr = self.cascr*lvl
        casdes = self.casdes*self.descent
        
        self.refcas = np.maximum.reduce([cascl, cascr, casdes])

        # designate reference Ma to phases
        macl = self.macl*self.climb
        macr = self.macr*(np.abs(self.traf.delalt) < epsalt)
        mades = self.mades*self.descent

        self.refma = np.maximum.reduce([macl, macr, mades])

        # crossover altitude (BADA User Manual 3.12, p. 12)
        self.atrans = (1000/6.5)*(T0*(1-((((1+gamma1*(self.refcas/a0)**2)**(gamma2))-1) /  \
        (((1+gamma1*self.refma**2)**(gamma2))-1))**((-(beta)*R)/g0)))

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

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

        # THRUST  
        # 1. climb: max.climb thrust in ISA conditions (p. 32, BADA User Manual 3.12)
        # condition: delta altitude positive
        self.jet = np.array(self.etype == 1)*1
        self.turbo = np.array(self.etype == 2) *1 
        self.piston = np.array(self.etype == 3)*1

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

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

        # combine jet and default aircraft
        Tjc = cljet*Tj # *ThrISA
        
        # turboprop
        # condition
        clturbo = np.logical_and.reduce([self.climb, self.turbo])*1

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

        # merge
        Ttc = clturbo*Tt # *ThrISA

        # piston
        clpiston = np.logical_and.reduce([self.climb, self.piston])*1            
        Tp = self.ctcth1*(1-(self.traf.alt/ft)/self.ctcth2)+self.ctcth3/np.maximum(1.,self.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 = (self.traf.alt - self.hpdes)
        
        # above Hpdes:  
        high = np.array(delh>0)            
        Tdesh = maxthr*self.ctdesh*np.logical_and.reduce([self.descent, high])            
               
        # below Hpdes
        low = np.array(delh<0)  
        # phase cruise
        Tdeslc = maxthr*self.ctdesl*np.logical_and.reduce([self.descent, low, (self.phase==3)])
        # phase approach
        Tdesla = maxthr*self.ctdesa*np.logical_and.reduce([self.descent, low, (self.phase==4)])
        # phase landing
        Tdesll = maxthr*self.ctdesld*np.logical_and.reduce([self.descent, low, (self.phase==5)])
        # phase ground: minimum descent thrust as a first approach
        Tgd = np.minimum.reduce([Tdesh, Tdeslc])*(self.phase==6)   

        # 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(self.traf.alt < (self.hmaxact*0.8))
        clh = np.logical_and.reduce([hcred, self.climb])
        cred = self.cred*clh
        cpred = 1-cred*((self.mmax-self.mass)/(self.mmax-self.mmin)) 
        
        vs = (((T-self.D)*self.traf.tas) /(self.mass*g0))*self.ESF*cpred
        
        # switch for given vertical speed avs
        if (self.traf.avs.any()>0) or (self.traf.avs.any()<0):
            # thrust = f(avs)
            T = ((self.traf.avs!=0)*(((self.traf.desvs*self.mass*g0)/     \
                      (self.ESF*np.maximum(self.traf.eps,self.traf.tas)*cpred)) \
                      + self.D)) + ((self.traf.avs==0)*T)
                      
            vs = (self.traf.avs!=0)*self.traf.avs + (self.traf.avs==0)*vs 
        self.traf.vs = vs
        self.Thr = T
            


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

        # thrust specific fuel consumption - turboprop

        # thrust
        etat = self.cf1*(1.-(self.traf.tas/kts)/self.cf2)*((self.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-(self.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.cf5*jt
        fcrp = self.cf1*self.cf5*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==1)

        # initial climb
        ffic = fnom*(self.phase==2)/2

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

        # cruise and level
        ffcrl = fcr*lvl

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

        # approach
        ffap = fal*(self.phase==4)

        # landing
        ffld = fal*(self.phase==5)
        
        # ground
        ffgd = fmin*(self.phase==6)

        # 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.traf.perfdt # Use fuelflow in kg/min
        return
Example #4
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.hdgsel,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

        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)*coeffBS.d_CD0j[4] + \
               (self.phase==5)*(self.etype==1)*(bs.traf.alt<450)*coeffBS.d_CD0j[5] + \
               (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]

        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==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)

        # 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.spd = np.where(
            (bs.traf.alt < 0.5) * (self.post_flight) * self.pf_flag, 0.0,
            bs.traf.pilot.spd)
        # 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
Example #5
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(self.traf.alt, self.traf.gs, self.traf.delalt, \
           self.traf.cas, self.vmto, self.vmic, self.vmap, self.vmcr, self.vmld, self.traf.bank, self.traf.bphase, \
           self.traf.hdgsel,swbada)

        # AERODYNAMICS
        # compute CL: CL = 2*m*g/(VTAS^2*rho*S)
        self.qS = 0.5*self.traf.rho*np.maximum(1.,self.traf.tas)*np.maximum(1.,self.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
        
        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)*(self.traf.alt>=450)*coeffBS.d_CD0j[4] + \
               (self.phase==5)*(self.etype==1)*(self.traf.alt<450)*coeffBS.d_CD0j[5] + \
               (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]
                   
        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)*(self.traf.alt>=450)*coeffBS.d_kj[4] + \
               (self.phase==5)*(self.etype==1)*(self.traf.alt<450)*coeffBS.d_kj[5] + \
               (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)*(self.traf.alt>=450)*coeffBS.d_kt[4] + \
               (self.phase==5)*(self.etype==2)*(self.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]*self.traf.ntraf)   
        self.climb = np.array(self.traf.delalt > epsalt)
        self.descent = np.array(self.traf.delalt< -epsalt)
  

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

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


        # determine vertical speed
        swvs = (np.abs(self.traf.pilot.spd) > self.traf.eps)
        vspd = swvs * self.traf.pilot.spd + (1. - swvs) * self.traf.avs * np.sign(self.traf.delalt)
        swaltsel = np.abs(self.traf.delalt) > np.abs(2. * self.dt * np.abs(vspd))
        self.traf.vs = swaltsel * vspd  

        # determine thrust
        self.Thr = (((self.traf.vs*self.mass*g0)/(self.ESF*np.maximum(self.traf.eps, self.traf.tas))) + self.D) 

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

        # maximum thrust prop (Raymer, p.36):
        mt_prop = self.P*self.eta/np.maximum(self.traf.eps, self.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)*self.traf.alt + self.PSFC_TO)*(self.traf.alt<20.000) + \
                self.PSFC_CR*(self.traf.alt >= 20.000)

        TSFC =PSFC*self.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 self.traf.id, self.phase, self.traf.alt/ft, self.traf.tas/kts, self.traf.cas/kts, self.traf.M,  \
        # self.Thr, self.D, self.ff,  cl, cd, self.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.
        self.traf.aspd = np.where((self.traf.alt <0.5)*(self.post_flight)*self.pf_flag, 0.0, self.traf.aspd)
        # the impulse for reducing the speed to 0 should only be given once,
        # otherwise taxiing will be impossible afterwards
        self.pf_flag = np.where ((self.traf.alt <0.5)*(self.post_flight), False, self.pf_flag)

        return