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