class Traffic: """ Traffic class definition : Traffic data Methods: Traffic() : constructor create(acid,actype,aclat,aclon,achdg,acalt,acspd) : create aircraft delete(acid) : delete an aircraft from traffic data update(sim) : do a numerical integration step trafperf () : calculate aircraft performance parameters Members: see create Created by : Jacco M. Hoekstra """ def __init__(self, navdb): self.reset(navdb) return def reset(self, navdb): self.dts = [] self.ntraf = 0 # model-specific parameters. # Default: BlueSky internal performance model. # Insert your BADA files to the folder "BlueSky/data/coefficients/BADA" # for working with EUROCONTROL`s Base of Aircraft Data revision 3.12 self.perf = Perf(self) self.dts = [] self.ntraf = 0 # Create datalog instance self.log = Datalog() # Traffic list & arrays definition # !!!IMPORTANT NOTE!!! # Any variables added here should also be added in the Traffic # methods self.create() (append) and self.delete() (delete) # which can be found directly below __init__ # Traffic basic flight data # Traffic basic flight data self.id = [] # identifier (string) self.type = [] # aircaft type (string) self.lat = np.array([]) # latitude [deg] self.lon = np.array([]) # longitude [deg] self.trk = np.array([]) # track angle [deg] self.tas = np.array([]) # true airspeed [m/s] self.gs = np.array([]) # ground speed [m/s] self.cas = np.array([]) # callibrated airspeed [m/s] self.M = np.array([]) # mach number self.alt = np.array([]) # altitude [m] self.fll = np.array([]) # flight level [ft/100] self.vs = np.array([]) # vertical speed [m/s] self.rho = np.array([]) # atmospheric air density [m/s] self.temp = np.array([]) # atmospheric air temperature [K] self.dtemp = np.array([]) # delta t for non-ISA conditions # Traffic performance data self.avsdef = np.array([]) # [m/s]default vertical speed of autopilot self.aphi = np.array([]) # [rad] bank angle setting of autopilot self.ax = np.array( []) # [m/s2] absolute value of longitudinal accelleration self.bank = np.array([]) # nominal bank angle, [radian] self.bphase = np.array([]) # standard bank angles per phase self.hdgsel = np.array([]) # determines whether aircraft is turning # Crossover altitude self.abco = np.array([]) self.belco = np.array([]) # Traffic autopilot settings self.ahdg = [] # selected heading [deg] self.aspd = [] # selected spd(eas) [m/s] self.aptas = [] # just for initializing self.ama = [] # selected spd above crossover altitude (Mach) [-] self.aalt = [] # selected alt[m] self.afll = [] # selected fl [ft/100] self.avs = [] # selected vertical speed [m/s] # limit settings self.lspd = [] # limit speed self.lalt = [] # limit altitude self.lvs = [] # limit vertical speed due to thrust limitation # Traffic navigation information self.orig = [] # Four letter code of origin airport self.dest = [] # Four letter code of destination airport # LNAV route navigation self.swlnav = np.array([]) # Lateral (HDG) based on nav? self.swvnav = np.array( []) # Vertical/longitudinal (ALT+SPD) based on nav info self.actwplat = np.array([]) # Active WP latitude self.actwplon = np.array([]) # Active WP longitude self.actwpalt = np.array([]) # Active WP altitude to arrive at self.actwpspd = np.array([]) # Active WP speed self.actwpturn = np.array([]) # Distance when to turn to next waypoint # VNAV cruise level self.crzalt = np.array([]) # Cruise altitude[m] # Route info self.route = [] # ASAS info per aircraft: self.iconf = [] # index in 'conflicting' aircraft database self.asasactive = np.array( []) # whether the autopilot follows ASAS or not self.asashdg = np.array([]) # heading provided by the ASAS [deg] self.asasspd = np.array([]) # speed provided by the ASAS (eas) [m/s] self.asasalt = np.array([]) # speed alt by the ASAS [m] self.asasvsp = np.array([]) # speed vspeed by the ASAS [m/s] self.desalt = np.array([]) #desired altitude [m] self.deshdg = np.array([]) #desired heading self.desvs = np.array([]) #desired vertical speed [m/s] self.desspd = np.array([]) #desired speed [m/s] # Display information on label self.label = [] # Text and bitmap of traffic label self.trailcol = [] # Trail color: default 'Blue' # Transmitted data to other aircraft due to truncated effect self.adsbtime = np.array([]) self.adsblat = np.array([]) self.adsblon = np.array([]) self.adsbalt = np.array([]) self.adsbtrk = np.array([]) self.adsbtas = np.array([]) self.adsbgs = np.array([]) self.adsbvs = np.array([]) self.inconflict = np.array([], dtype=bool) #----------------------------------------------------------------------------- # Not per aircraft data # Scheduling of FMS and ASAS self.t0fms = -999. # last time fms was called self.dtfms = 1.01 # interval for fms self.t0asas = -999. # last time ASAS was called self.dtasas = 1.00 # interval for ASAS # Flight performance scheduling self.perfdt = 0.1 # [s] update interval of performance limits self.perft0 = -self.perfdt # [s] last time checked (in terms of simt) self.warned2 = False # Flag: Did we warn for default engine parameters yet? # ADS-B transmission-receiver model self.adsb = ADSBModel(self) # ASAS objects: Conflict Database self.dbconf = Dbconf(self, 300., 5. * nm, 1000. * ft) # hard coded values to be replaced # Import navigation data base self.navdb = navdb # Traffic area: delete traffic when it leaves this area (so not when outside) self.swarea = False self.arealat0 = 0.0 # [deg] lower latitude defining area self.arealat1 = 0.0 # [deg] upper latitude defining area self.arealat0 = 0.0 # [deg] lower longitude defining area self.arealat1 = 0.0 # [deg] upper longitude defining area self.areafloor = -999999.0 # [m] Delete when descending through this h self.areadt = 5.0 # [s] frequency of area check (simtime) self.areat0 = -100. # last time checked self.inside = [] self.fir_circle_point = (0.0, 0.0) self.fir_circle_radius = 1.0 # Taxi switch self.swtaxi = False # Default OFF: delete traffic below 1500 ft # Research Area ("Square" for Square, "Circle" for Circle area) self.area = "" # Bread crumbs for trails self.lastlat = [] self.lastlon = [] self.lasttim = [] self.trails = Trails() self.swtrails = False # Default switched off # ADS-B Coverage area self.swAdsbCoverage = False # Noise (turbulence, ADBS-transmission noise, ADSB-truncated effect) self.setNoise(False) self.eps = np.array([]) return def create_ac(self, acid, actype, aclat, aclon, achdg, acalt, acspd): """Create an aircraft""" # Check if not already exist if self.id.count(acid.upper()) > 0: return False # already exists do nothing # Increase number of aircraft self.ntraf = self.ntraf + 1 # Process input self.id.append(acid.upper()) self.type.append(actype) self.lat = np.append(self.lat, aclat) self.lon = np.append(self.lon, aclon) self.trk = np.append(self.trk, achdg) # TBD: add conversion hdg => trk self.alt = np.append(self.alt, acalt) self.fll = np.append(self.fll, (acalt) / 100) self.vs = np.append(self.vs, 0.) self.rho = np.append(self.rho, density(acalt)) self.temp = np.append(self.temp, temp(acalt)) self.dtemp = np.append(self.dtemp, 0) # at the moment just ISA conditions self.tas = np.append(self.tas, acspd) self.gs = np.append(self.gs, acspd) self.cas = np.append(self.cas, tas2cas(acspd, acalt)) self.M = np.append(self.M, tas2mach(acspd, acalt)) # AC is initialized with neutral max bank angle self.bank = np.append(self.bank, 25.) if self.ntraf < 2: self.bphase = np.deg2rad(np.array([15, 35, 35, 35, 15, 45])) self.hdgsel = np.append(self.hdgsel, False) #------------------------------Performance data-------------------------------- # Type specific data #(temporarily default values) self.avsdef = np.append( self.avsdef, 1500. * fpm) # default vertical speed of autopilot self.aphi = np.append(self.aphi, radians(25.)) # bank angle setting of autopilot self.ax = np.append( self.ax, kts) # absolute value of longitudinal accelleration # Crossover altitude self.abco = np.append(self.abco, 0) self.belco = np.append(self.belco, 1) # performance data self.perf.create(actype) # Traffic autopilot settings: hdg[deg], spd (CAS,m/s), alt[m], vspd[m/s] self.ahdg = np.append(self.ahdg, achdg) # selected heading [deg] self.aspd = np.append(self.aspd, tas2eas(acspd, acalt)) # selected spd(eas) [m/s] self.aptas = np.append(self.aptas, vcas2tas(self.aspd, self.alt)) # [m/s] self.ama = np.append(self.ama, 0.) # selected spd above crossover (Mach) [-] self.aalt = np.append(self.aalt, acalt) # selected alt[m] self.afll = np.append(self.afll, (acalt / 100)) # selected fl[ft/100] self.avs = np.append(self.avs, 0.) # selected vertical speed [m/s] # limit settings: initialize with 0 self.lspd = np.append(self.lspd, 0.0) self.lalt = np.append(self.lalt, 0.0) self.lvs = np.append(self.lvs, 0.0) # Traffic navigation information self.dest.append("") self.orig.append("") # LNAV route navigation self.swlnav = np.append(self.swlnav, False) # Lateral (HDG) based on nav self.swvnav = np.append( self.swvnav, False) # Vertical/longitudinal (ALT+SPD) based on nav info self.actwplat = np.append(self.actwplat, 89.99) # Active WP latitude self.actwplon = np.append(self.actwplon, 0.0) # Active WP longitude self.actwpalt = np.append(self.actwpalt, 0.0) # Active WP altitude self.actwpspd = np.append(self.actwpspd, -999.) # Active WP speed self.actwpturn = np.append( self.actwpturn, 1.0) # Distance to active waypoint where to turn # VNAV cruise level self.crzalt = np.append(self.crzalt, -999.) # Cruise altitude[m] <0=None # Route info self.route.append(Route( self.navdb)) # create empty route connected with nav databse # ASAS info: no conflict => -1 self.iconf.append(-1) # index in 'conflicting' aircraft database self.asasactive = np.append(self.asasactive, False) self.asashdg = np.append(self.asashdg, achdg) self.asasspd = np.append(self.asasspd, tas2eas(acspd, acalt)) self.asasalt = np.append(self.asasalt, acalt) self.asasvsp = np.append(self.asasvsp, 0.) # Area variable set to False to avoid deletion upon creation outside self.inside.append(False) # Display information on label self.label.append(['', '', '', 0]) # Bread crumbs for trails self.trailcol.append(self.trails.defcolor) self.lastlat = np.append(self.lastlat, aclat) self.lastlon = np.append(self.lastlon, aclon) self.lasttim = np.append(self.lasttim, 0.0) # ADS-B Coverage area self.swAdsbCoverage = False # Transmitted data to other aircraft due to truncated effect self.adsbtime = np.append(self.adsbtime, np.random.rand(self.trunctime)) self.adsblat = np.append(self.adsblat, aclat) self.adsblon = np.append(self.adsblon, aclon) self.adsbalt = np.append(self.adsbalt, acalt) self.adsbtrk = np.append(self.adsbtrk, achdg) self.adsbtas = np.append(self.adsbtas, acspd) self.adsbgs = np.append(self.adsbgs, acspd) self.adsbvs = np.append(self.adsbvs, 0.) self.inconflict = np.append(self.inconflict, False) self.eps = np.append(self.eps, 0.01) return True def delete(self, acid): """Delete an aircraft""" try: # prevent error due to not found idx = self.id.index(acid) except: return False del self.id[idx] del self.type[idx] # Traffic basic data self.lat = np.delete(self.lat, idx) self.lon = np.delete(self.lon, idx) self.trk = np.delete(self.trk, idx) self.alt = np.delete(self.alt, idx) self.fll = np.delete(self.fll, idx) self.vs = np.delete(self.vs, idx) self.tas = np.delete(self.tas, idx) self.gs = np.delete(self.gs, idx) self.cas = np.delete(self.cas, idx) self.M = np.delete(self.M, idx) self.T = np.delete(self.T, idx) self.p = np.delete(self.p, idx) self.rho = np.delete(self.rho, idx) self.temp = np.delete(self.temp, idx) self.dtemp = np.delete(self.dtemp, idx) self.hdgsel = np.delete(self.hdgsel, idx) self.bank = np.delete(self.bank, idx) # Crossover altitude self.abco = np.delete(self.abco, idx) self.belco = np.delete(self.belco, idx) # Type specific data (temporarily default values) self.avsdef = np.delete(self.avsdef, idx) self.aphi = np.delete(self.aphi, idx) self.ax = np.delete(self.ax, idx) # performance data self.perf.delete(idx) # Traffic autopilot settings: hdg[deg], spd (CAS,m/s), alt[m], vspd[m/s] self.ahdg = np.delete(self.ahdg, idx) self.aspd = np.delete(self.aspd, idx) self.ama = np.delete(self.ama, idx) self.aptas = np.delete(self.aptas, idx) self.aalt = np.delete(self.aalt, idx) self.afll = np.delete(self.afll, idx) self.avs = np.delete(self.avs, idx) # limit settings self.lspd = np.delete(self.lspd, idx) self.lalt = np.delete(self.lalt, idx) self.lvs = np.delete(self.lvs, idx) # Traffic navigation variables del self.dest[idx] del self.orig[idx] self.swlnav = np.delete(self.swlnav, idx) self.swvnav = np.delete(self.swvnav, idx) self.actwplat = np.delete(self.actwplat, idx) self.actwplon = np.delete(self.actwplon, idx) self.actwpalt = np.delete(self.actwpalt, idx) self.actwpspd = np.delete(self.actwpspd, idx) self.actwpturn = np.delete(self.actwpturn, idx) # VNAV cruise level self.crzalt = np.delete(self.crzalt, idx) # Route info del self.route[idx] # ASAS info del self.iconf[idx] self.asasactive = np.delete(self.asasactive, idx) self.asashdg = np.delete(self.asashdg, idx) self.asasspd = np.delete(self.asasspd, idx) self.asasalt = np.delete(self.asasalt, idx) self.asasvsp = np.delete(self.asasvsp, idx) self.desalt = np.delete(self.desalt, idx) self.desvs = np.delete(self.desvs, idx) self.desspd = np.delete(self.desspd, idx) self.deshdg = np.delete(self.deshdg, idx) # Metrics, area del self.inside[idx] # Traffic display data: label del self.label[idx] # Delete bread crumb data self.lastlat = np.delete(self.lastlat, idx) self.lastlon = np.delete(self.lastlon, idx) self.lasttim = np.delete(self.lasttim, idx) del self.trailcol[idx] # Transmitted data to other aircraft due to truncated effect self.adsbtime = np.delete(self.adsbtime, idx) self.adsblat = np.delete(self.adsblat, idx) self.adsblon = np.delete(self.adsblon, idx) self.adsbalt = np.delete(self.adsbalt, idx) self.adsbtrk = np.delete(self.adsbtrk, idx) self.adsbtas = np.delete(self.adsbtas, idx) self.adsbgs = np.delete(self.adsbgs, idx) self.adsbvs = np.delete(self.adsbvs, idx) self.inconflict = np.delete(self.inconflict, idx) # Decrease number fo aircraft self.ntraf = self.ntraf - 1 self.eps = np.delete(self.eps, idx) return True def deleteall(self): """Clear traffic buffer""" ndel = self.ntraf for i in range(ndel): self.delete(self.id[-1]) self.ntraf = 0 self.dbconf.reset() self.perf.reset() return def update(self, simt, simdt): # i = self.id2idx("TP233") # if i>=0: # print "LNAV TP233:",self.swlnav[i] # Update only necessary if there is traffic if self.ntraf == 0: return self.dts.append(simdt) #---------------- Atmosphere ---------------- self.T, self.rho, self.p = vatmos(self.alt) #-------------- Performance limits autopilot settings -------------- # Check difference with AP settings for trafperf and autopilot self.delalt = self.aalt - self.alt # [m] # below crossover altitude: CAS=const, above crossover altitude: MA = const # aptas hast to be calculated before delspd self.aptas = vcas2tas(self.aspd, self.alt) * self.belco + vmach2tas( self.ama, self.alt) * self.abco self.delspd = self.aptas - self.tas ############################################################################### # Debugging: add 10000 random aircraft # if simt>1.0 and self.ntraf<1000: # for i in range(10000): # acid="KL"+str(i) # aclat = random.random()*180.-90. # aclon = random.random()*360.-180. # achdg = random.random()*360. # acalt = (random.random()*18000.+2000.)*0.3048 # self.create(acid,'B747',aclat,aclon,achdg,acalt,350.) # ################################################################################# #-------------------- ADSB update: -------------------- self.adsbtime = self.adsbtime + simdt if self.ADSBtrunc: ADSB_update = np.where(self.adsbtime > self.trunctime) else: ADSB_update = range(self.ntraf) for i in ADSB_update: self.adsbtime[i] = self.adsbtime[i] - self.trunctime self.adsblat[i] = self.lat[i] self.adsblon[i] = self.lon[i] self.adsbalt[i] = self.alt[i] self.adsbtrk[i] = self.trk[i] self.adsbtas[i] = self.tas[i] self.adsbgs[i] = self.gs[i] self.adsbvs[i] = self.vs[i] # New version ADSB Model self.adsb.update() #------------------- ASAS update: --------------------- # Scheduling: when dt has passed or restart: if self.t0asas+self.dtasas<simt or simt<self.t0asas \ and self.dbconf.swasas: self.t0asas = simt # Save old result iconf0 = np.array(self.iconf) # Call with traffic database and sim data self.dbconf.detect() self.dbconf.conflictlist(simt) self.dbconf.APorASAS() self.dbconf.resolve() # Reset label because of colour change chnged = np.where(iconf0 != np.array(self.iconf))[0] for i in chnged: self.label[i] = [" ", " ", "", " "] #----------------- FMS GUIDANCE & NAVIGATION ------------------ # Scheduling: when dt has passed or restart: if self.t0fms + self.dtfms < simt or simt < self.t0fms: self.t0fms = simt # FMS LNAV mode: qdr, dist = qdrdist(self.lat, self.lon, self.actwplat, self.actwplon) #[deg][nm] # Check whether shift based dist [nm] is required, set closer than WP turn distance iwpclose = np.where(self.swlnav * (dist < self.actwpturn))[0] # Shift for aircraft i where necessary for i in iwpclose: # Get next wp (lnavon = False if no more waypoints) lat, lon, alt, spd, xtoalt, toalt, lnavon = \ self.route[i].getnextwp() # note: xtoalt,toalt in [m] # End of route/no more waypoints: switch off LNAV if not lnavon: self.swlnav[i] = False # Drop LNAV at end of route # In case of no LNAV, do not allow VNAV mode on it sown if not self.swlnav[i]: self.swvnav[i] = False self.actwplat[i] = lat self.actwplon[i] = lon # User entered altitude if alt >= 0.: self.actwpalt[i] = alt # VNAV calculated altitude is available and active if toalt >= 0. and self.swvnav[i]: # Descent VNAV mode (T/D logic) if self.alt[ i] > toalt + 10. * ft: # Descent part is in this range of waypoints: # Flat earth distance to next wp dy = (lat - self.lat[i]) dx = (lon - self.lon[i]) * cos(radians(lat)) dist2wp = 60. * nm * sqrt(dx * dx + dy * dy) steepness = 3000. * ft / ( 10. * nm) # 1:3 rule of thumb for now maxaltwp = toalt + xtoalt * steepness # max allowed altitude at next wp self.actwpalt[i] = min( self.alt[i], maxaltwp) #To descend now or descend later? if maxaltwp < self.alt[ i]: # if descent is necessary with maximum steepness self.aalt[i] = self.actwpalt[ i] # dial in altitude of next waypoint as calculated t2go = max(0.1, dist2wp) / max(0.01, self.gs[i]) self.avs[i] = ( self.actwpalt[i] - self.alt[i]) / t2go else: print "else 1" pass # TBD # Climb VNAV mode: climb as soon as possible (T/C logic) elif self.swvnav[i] and self.alt[i] < toalt - 10. * ft: # Flat earth distance to next wp dy = (lat - self.lat[i]) dx = (lon - self.lon[i]) * cos(radians(lat)) dist2wp = 60. * nm * sqrt(dx * dx + dy * dy) self.aalt[i] = self.actwpalt[ i] # dial in altitude of next waypoint as calculated t2go = max(0.1, dist2wp) / max(0.01, self.gs[i]) self.avs[i] = (self.actwpalt[i] - self.alt[i]) / t2go if spd > 0. and lnavon and self.swvnav[i]: if spd < 2.0: self.actwpspd[i] = mach2cas(spd, self.alt[i]) else: self.actwpspd[i] = cas2tas(spd, self.alt[i]) else: self.actwpspd[i] = -999. # Calculate distance before waypoint where to start the turn # Turn radius: R = V2 tan phi / g # Distance to turn: wpturn = R * tan (1/2 delhdg) but max 4 times radius turnrad = self.tas[i] * self.tas[i] / tan( self.bank[i] ) / g0 / nm # [nm] default bank angle per flight phase # print turnrad dy = (self.actwplat[i] - self.lat[i]) dx = (self.actwplon[i] - self.lon[i]) * cos( radians(self.lat[i])) qdr[i] = degrees(atan2(dx, dy)) self.actwpturn[i] = max(3.,abs(turnrad*tan(radians(0.5*degto180(qdr[i]- \ self.route[i].wpdirfrom[self.route[i].iactwp]))))) # [nm] # Set headings based on swlnav self.ahdg = np.where(self.swlnav, qdr, self.ahdg) # NOISE: Turbulence if self.turbulence: timescale = np.sqrt(simdt) trkrad = np.radians(self.trk) #write turbulences in array turb = np.array(self.standardturbulence) turb = np.where(turb > 1e-6, turb, 1e-6) #horizontal flight direction turbhf = np.random.normal(0, turb[0] * timescale, self.ntraf) #[m] #horizontal wing direction turbhw = np.random.normal(0, turb[1] * timescale, self.ntraf) #[m] #vertical direction turbalt = np.random.normal(0, turb[2] * timescale, self.ntraf) #[m] #latitudinal, longitudinal direction turblat = np.cos(trkrad) * turbhf - np.sin(trkrad) * turbhw #[m] turblon = np.sin(trkrad) * turbhf + np.cos(trkrad) * turbhw #[m] else: turbalt = np.zeros(self.ntraf) #[m] turblat = np.zeros(self.ntraf) #[m] turblon = np.zeros(self.ntraf) #[m] # ASAS AP switches #--------- Select Autopilot settings to follow: destination or ASAS ---------- # desired autopilot settings due to ASAS self.deshdg = self.asasactive * self.asashdg + ( 1 - self.asasactive) * self.ahdg self.desspd = self.asasactive * self.asasspd + ( 1 - self.asasactive) * self.aspd self.desalt = self.asasactive * self.asasalt + ( 1 - self.asasactive) * self.aalt self.desvs = self.asasactive * self.asasvsp + ( 1 - self.asasactive) * self.avs # check for the flight envelope self.perf.limits() # update autopilot settings with values within the flight envelope # speed self.aspd = (self.lspd == 0) * self.desspd + (self.lspd != 0) * self.lspd # altitude self.aalt = (self.lalt == 0) * self.desalt + (self.lalt != 0) * self.lalt # hdg self.ahdg = self.deshdg # vs self.avs = (self.lvs == 0) * self.desvs + (self.lvs != 0) * self.lvs # below crossover altitude: CAS=const, above crossover altitude: MA = const #climb/descend above crossover: Ma = const, else CAS = const #ama is fixed when above crossover check = self.abco * (self.ama == 0.) swma = np.where(check == True) self.ama[swma] = cas2mach(self.aspd[swma], self.alt[swma]) # ama is deleted when below crossover check2 = self.belco * (self.ama != 0.) swma2 = np.where(check2 == True) self.ama[swma2] = 0. #---------- Basic Autopilot modes ---------- # SPD HOLD/SEL mode: aspd = autopilot selected speed (first only eas) # for information: self.aptas = (self.actwpspd>0.)*self.actwpspd + \ (self.actwpspd<=0.)*self.aptas self.delspd = self.aptas - self.tas swspdsel = np.abs(self.delspd) > 0.4 # <1 kts = 0.514444 m/s ax = np.minimum(abs(self.delspd / max(1e-8, simdt)), self.ax) self.tas = swspdsel * (self.tas + ax * np.sign(self.delspd) * \ simdt) + (1. - swspdsel) * self.aptas # print "DELSPD", self.delspd/simdt, "AX", self.ax, "SELECTED", ax # without that part: non-accelerating ac would have TAS = 0 # print "1-sw", (1. - swspdsel) * self.aptas # print "NEW TAS", self.tas # Speed conversions self.cas = vtas2cas(self.tas, self.alt) self.gs = self.tas self.M = vtas2mach(self.tas, self.alt) # Update performance every self.perfdt seconds if abs(simt - self.perft0) >= self.perfdt: self.perft0 = simt self.perf.perf() # update altitude self.eps = np.array( self.ntraf * [0.01]) # almost zero for misc purposes swaltsel = np.abs(self.aalt-self.alt) > \ np.maximum(3.,np.abs(2. * simdt * np.abs(self.vs))) # 3.[m] = 10 [ft] eps alt # print swaltsel self.vs = swaltsel*np.sign(self.aalt-self.alt)* \ ( (1-self.swvnav)*np.abs(1500./60.*ft) + \ self.swvnav*np.abs(self.avs) ) self.alt = swaltsel * (self.alt + self.vs * simdt) + \ (1. - swaltsel) * self.aalt + turbalt # HDG HOLD/SEL mode: ahdg = ap selected heading delhdg = (self.ahdg - self.trk + 180.) % 360 - 180. #[deg] # print delhdg # omega = np.degrees(g0 * np.tan(self.aphi) / \ # np.maximum(self.tas, self.eps)) # nominal bank angles per phase from BADA 3.12 omega = np.degrees(g0 * np.tan(self.bank) / \ np.maximum(self.tas, self.eps)) self.hdgsel = np.abs(delhdg) > np.abs(2. * simdt * omega) self.trk = ( self.trk + simdt * omega * self.hdgsel * np.sign(delhdg)) % 360. #--------- Kinematics: update lat,lon,alt ---------- ds = simdt * self.gs self.lat = self.lat + np.degrees(ds * np.cos(np.radians(self.trk)+turblat) \ / Rearth) self.lon = self.lon + np.degrees(ds * np.sin(np.radians(self.trk)+turblon) \ / np.cos(np.radians(self.lat)) / Rearth) # Update trails when switched on if self.swtrails: self.trails.update(simt, self.lat, self.lon, self.lastlat, self.lastlon, self.lasttim, self.id, self.trailcol) else: self.lastlat = self.lat self.lastlon = self.lon self.lattime = simt # ----------------AREA check---------------- # Update area once per areadt seconds: if self.swarea and abs(simt - self.areat0) > self.areadt: # Update loop timer self.areat0 = simt # Check all aircraft i = 0 while (i < self.ntraf): # Current status if self.area == "Square": inside = self.arealat0 <= self.lat[i] <= self.arealat1 and \ self.arealon0 <= self.lon[i] <= self.arealon1 and \ self.alt[i] >= self.areafloor and \ (self.alt[i] >= 1500 or self.swtaxi) elif self.area == "Circle": pass ## Average of lat latavg = (radians(self.lat[i]) + radians( self.fir_circle_point[0])) / 2 cosdlat = (cos(latavg)) # Distance x to centroid dx = ( self.lon[i] - self.fir_circle_point[1]) * cosdlat * 60 dx2 = dx * dx # Distance y to centroid dy = self.lat[i] - self.fir_circle_point[0] dy2 = dy * dy * 3600 # Radius squared r2 = self.fir_circle_radius * self.fir_circle_radius # Inside if smaller inside = (dx2 + dy2) < r2 # Compare with previous: when leaving area: delete command if self.inside[i] and not inside: self.delete(self.id[i]) else: # Update area status self.inside[i] = inside i = i + 1 return def id2idx(self, acid): """Find index of aircraft id""" try: return self.id.index(acid.upper()) except: return -1 def changeTrailColor(self, color, idx): """Change color of aircraft trail""" # print color # print idx # print " " + str(self.trails.colorsOfAC[idx]) self.trailcol[idx] = self.trails.colorList[color] # print " " + str(self.trails.colorsOfAC[idx]) return def setNoise(self, A): """Noise (turbulence, ADBS-transmission noise, ADSB-truncated effect)""" self.noise = A self.trunctime = 1 # seconds self.transerror = [ 1, 100, 100 * ft ] #[degree,m,m] standard bearing, distance, altitude error self.standardturbulence = [0, 0.1, 0.1 ] #m/s standard turbulence (nonnegative) # in (horizontal flight direction, horizontal wing direction, vertical) self.turbulence = self.noise self.ADSBtransnoise = self.noise self.ADSBtrunc = self.noise def engchange(self, acid, engid): """Change of engines""" self.perf.engchange(acid, engid) return def create(self, arglist): # CRE command if len(arglist) < 7: return False acid = arglist[0] if self.id.count(acid.upper()) > 0: return False, acid + " already exists" actype = arglist[1] aclat = arglist[2] aclon = arglist[3] achdg = arglist[4] acalt = arglist[5] # m cmdspd = arglist[6] # Mach/IAS kts (float if 0.1 < cmdspd < 1.0: acspd = mach2tas(cmdspd, acalt) else: acspd = cas2tas(cmdspd * kts, acalt) sw = self.create_ac(acid, actype, aclat, aclon, achdg, acalt, acspd) return sw def selhdg(self, arglist): # HDG command # Select heading command: HDG acid, hdg if len(arglist) < 2: return False #Error/Display helptext print "en voorbij de check" # unwrap arguments idx = arglist[0] # aircraft index hdg = arglist[1] # float # Give autopilot commands self.ahdg[idx] = hdg self.swlnav[idx] = False # Everything went ok! return True