예제 #1
0
    def update(self):
        # FMS LNAV mode:
        # qdr[deg],distinnm[nm]
        qdr, distinnm = geo.qdrdist(bs.traf.lat, bs.traf.lon,
                                    bs.traf.actwp.lat, bs.traf.actwp.lon)  # [deg][nm])
        dist = distinnm*nm  # Conversion to meters


        # FMS route update
        self.update_fms(qdr, dist)

        #================= Continuous FMS guidance ========================

        # Waypoint switching in the loop above was scalar (per a/c with index i)
        # Code below is vectorized, with arrays for all aircraft

        # Do VNAV start of descent check
        dy = (bs.traf.actwp.lat - bs.traf.lat)  #[deg lat = 60 nm]
        dx = (bs.traf.actwp.lon - bs.traf.lon) * bs.traf.coslat #[corrected deg lon = 60 nm]
        dist2wp   = 60. * nm * np.sqrt(dx * dx + dy * dy) # [m]

        # VNAV logic: descend as late as possible, climb as soon as possible
        startdescent = (dist2wp < self.dist2vs) + (bs.traf.actwp.nextaltco > bs.traf.alt)

        # If not lnav:Climb/descend if doing so before lnav/vnav was switched off
        #    (because there are no more waypoints). This is needed
        #    to continue descending when you get into a conflict
        #    while descending to the destination (the last waypoint)
        #    Use 0.1 nm (185.2 m) circle in case turndist might be zero
        self.swvnavvs = bs.traf.swvnav * np.where(bs.traf.swlnav, startdescent,
                                        dist <= np.maximum(185.2,bs.traf.actwp.turndist))

        #Recalculate V/S based on current altitude and distance to next alt constraint
        # How much time do we have before we need to descend?

        t2go2alt = np.maximum(0.,(dist2wp + bs.traf.actwp.xtoalt - bs.traf.actwp.turndist)) \
                                    / np.maximum(0.5,bs.traf.gs)

        # use steepness to calculate V/S unless we need to descend faster
        bs.traf.actwp.vs = np.maximum(self.steepness*bs.traf.gs, \
                                np.abs((bs.traf.actwp.nextaltco-bs.traf.alt))  \
                                /np.maximum(1.0,t2go2alt))

        self.vnavvs  = np.where(self.swvnavvs, bs.traf.actwp.vs, self.vnavvs)
        #was: self.vnavvs  = np.where(self.swvnavvs, self.steepness * bs.traf.gs, self.vnavvs)

        # self.vs = np.where(self.swvnavvs, self.vnavvs, bs.traf.apvsdef * bs.traf.limvs_flag)
        selvs    = np.where(abs(bs.traf.selvs) > 0.1, bs.traf.selvs, bs.traf.apvsdef) # m/s
        self.vs  = np.where(self.swvnavvs, self.vnavvs, selvs)
        self.alt = np.where(self.swvnavvs, bs.traf.actwp.nextaltco, bs.traf.selalt)

        # When descending or climbing in VNAV also update altitude command of select/hold mode
        bs.traf.selalt = np.where(self.swvnavvs,bs.traf.actwp.nextaltco,bs.traf.selalt)

        # LNAV commanded track angle
        self.trk = np.where(bs.traf.swlnav, qdr, self.trk)

        # FMS speed guidance: anticipate accel/decel distance for next leg or turn

        # Actual distance it takes to decelerate
        # Normally next leg speed (actwp.spd) but in case we fly turns with a specified turn speed
        # use the turn speed
        swturnspd = bs.traf.actwp.flyturn*(bs.traf.actwp.turnspd>0.001)
        nexttas   = np.where(swturnspd,
                             vcas2tas(bs.traf.actwp.turnspd,bs.traf.alt),
                             vcasormach2tas(bs.traf.actwp.spd,bs.traf.alt))
        tasdiff   = nexttas - bs.traf.tas # [m/s]

        # dt = dv/a   dx = v*dt + 0.5*a*dt2 => dx = dv/a * (v + 0.5*dv)
        dxspdchg = swturnspd*bs.traf.actwp.turndist + np.sign(tasdiff)/np.maximum(0.01,np.abs(bs.traf.ax)) * \
                   (bs.traf.tas+0.5*tasdiff)

        # Check also whether VNAVSPD is on, if not, SPD SEL has override for next leg
        # and same for turn logic
        usespdcon      = (dist2wp < dxspdchg)*(bs.traf.actwp.spdcon > -990.) * \
                            bs.traf.swvnavspd*bs.traf.swvnav

        bs.traf.selspd = np.where(usespdcon, np.where(swturnspd,bs.traf.actwp.turnspd,
                                                      bs.traf.actwp.spd), bs.traf.selspd)

        # Below crossover altitude: CAS=const, above crossover altitude: Mach = const
        self.tas = vcasormach2tas(bs.traf.selspd, bs.traf.alt)
예제 #2
0
파일: autopilot.py 프로젝트: eman89/bluesky
    def update(self, simt):
        # Scheduling: when dt has passed or restart
        if self.t0 + self.dt < simt or simt < self.t0:
            self.t0 = simt

            # FMS LNAV mode:
            qdr, dist = geo.qdrdist(bs.traf.lat, bs.traf.lon,
                                    bs.traf.actwp.lat,
                                    bs.traf.actwp.lon)  # [deg][nm])

            # Shift waypoints for aircraft i where necessary
            for i in bs.traf.actwp.Reached(qdr, dist, bs.traf.actwp.flyby):
                # Save current wp speed
                oldspd = bs.traf.actwp.spd[i]

                # Get next wp (lnavon = False if no more waypoints)
                lat, lon, alt, spd, bs.traf.actwp.xtoalt, toalt, \
                          lnavon, flyby, bs.traf.actwp.next_qdr[i] =  \
                       self.route[i].getnextwp()  # note: xtoalt,toalt in [m]

                # End of route/no more waypoints: switch off LNAV
                bs.traf.swlnav[i] = bs.traf.swlnav[i] and lnavon

                # In case of no LNAV, do not allow VNAV mode on its own
                bs.traf.swvnav[i] = bs.traf.swvnav[i] and bs.traf.swlnav[i]

                bs.traf.actwp.lat[i] = lat
                bs.traf.actwp.lon[i] = lon
                bs.traf.actwp.flyby[i] = int(
                    flyby)  # 1.0 in case of fly by, else fly over

                # User has entered an altitude for this waypoint
                if alt >= 0.:
                    bs.traf.actwp.nextaltco[i] = alt

                if spd > 0. and bs.traf.swlnav[i] and bs.traf.swvnav[i]:

                    # Valid speed and LNAV and VNAV ap modes are on
                    # Depending on crossover altitude we fix CAS or Mach
                    if bs.traf.abco[i] and spd > 2.0:
                        bs.traf.actwp.spd[i] = cas2mach(spd, bs.traf.alt[i])

                    elif bs.traf.belco[i] and spd <= 2.0:
                        bs.traf.actwp.spd[i] = mach2cas(spd, bs.traf.alt[i])

                    else:
                        bs.traf.actwp.spd[i] = spd

                else:
                    bs.traf.actwp.spd[i] = -999.

                # VNAV spd mode: use speed of this waypoint as commanded speed
                # while passing waypoint and save next speed for passing next wp
                # Speed is now from speed! Next speed is ready in wpdata
                if bs.traf.swvnav[i] and oldspd > 0.0:
                    bs.traf.selspd[i] = oldspd

                # VNAV = FMS ALT/SPD mode
                self.ComputeVNAV(i, toalt, bs.traf.actwp.xtoalt)

            #=============== End of Waypoint switching loop ===================

            #================= Continuous FMS guidance ========================
            # Do VNAV start of descent check
            dy = (bs.traf.actwp.lat - bs.traf.lat)
            dx = (bs.traf.actwp.lon - bs.traf.lon) * bs.traf.coslat
            dist2wp = 60. * nm * np.sqrt(dx * dx + dy * dy)

            # VNAV logic: descend as late as possible, climb as soon as possible
            startdescent = bs.traf.swvnav * (
                (dist2wp < self.dist2vs) +
                (bs.traf.actwp.nextaltco > bs.traf.alt))

            # If not lnav:Climb/descend if doing so before lnav/vnav was switched off
            #    (because there are no more waypoints). This is needed
            #    to continue descending when you get into a conflict
            #    while descending to the destination (the last waypoint)
            #    Use 100 nm (185.2 m) circle in case turndist might be zero
            self.swvnavvs = np.where(
                bs.traf.swlnav, startdescent,
                dist <= np.maximum(185.2, bs.traf.actwp.turndist))

            #Recalculate V/S based on current altitude and distance to next alt constraint
            t2go2alt = np.maximum(0.,(dist2wp + bs.traf.actwp.xtoalt - bs.traf.actwp.turndist*nm)) \
                                        / np.maximum(0.5,bs.traf.gs)

            bs.traf.actwp.vs = np.maximum(self.steepness*bs.traf.gs, \
                                   np.abs((bs.traf.actwp.nextaltco-bs.traf.alt))/np.maximum(1.0,t2go2alt))

            self.vnavvs = np.where(self.swvnavvs, bs.traf.actwp.vs,
                                   self.vnavvs)
            #was: self.vnavvs  = np.where(self.swvnavvs, self.steepness * bs.traf.gs, self.vnavvs)

            # self.vs = np.where(self.swvnavvs, self.vnavvs, bs.traf.apvsdef * bs.traf.limvs_flag)
            selvs = np.where(
                abs(bs.traf.selvs) > 0.1, bs.traf.selvs,
                bs.traf.apvsdef)  # m/s
            self.vs = np.where(self.swvnavvs, self.vnavvs, selvs)

            self.alt = np.where(self.swvnavvs, bs.traf.actwp.nextaltco,
                                bs.traf.selalt)

            # When descending or climbing in VNAV also update altitude command of select/hold mode
            bs.traf.selalt = np.where(self.swvnavvs, bs.traf.actwp.nextaltco,
                                      bs.traf.selalt)

            # LNAV commanded track angle
            self.trk = np.where(bs.traf.swlnav, qdr, self.trk)

            # FMS speed guidance: anticipate accel distance

            # Actual distance it takes to decelerate
            nexttas = vcasormach2tas(bs.traf.actwp.spd, bs.traf.alt)
            tasdiff = nexttas - bs.traf.tas  # [m/s]
            dtspdchg = np.abs(tasdiff) / np.maximum(0.01, np.abs(bs.traf.ax))
            dxspdchg = 0.5 * np.sign(tasdiff) * np.abs(
                bs.traf.ax) * dtspdchg * dtspdchg + bs.traf.tas * dtspdchg

            usespdcon = (dist2wp < dxspdchg) * (bs.traf.actwp.spd >
                                                0.) * bs.traf.swvnav
            bs.traf.selspd = np.where(usespdcon, bs.traf.actwp.spd,
                                      bs.traf.selspd)

        # Below crossover altitude: CAS=const, above crossover altitude: Mach = const
        self.tas = vcasormach2tas(bs.traf.selspd, bs.traf.alt)
예제 #3
0
    def update(self, simt):
        # Scheduling: when dt has passed or restart
        if self.t0 + self.dt < simt or simt < self.t0 or simt<self.dt:
            self.t0 = simt

            # FMS LNAV mode:
            # qdr[deg],distinnm[nm]
            qdr, distinnm = geo.qdrdist(bs.traf.lat, bs.traf.lon,
                                    bs.traf.actwp.lat, bs.traf.actwp.lon)  # [deg][nm])
            dist = distinnm*nm # Conversion to meters

            # Shift waypoints for aircraft i where necessary
            for i in bs.traf.actwp.Reached(qdr,dist,bs.traf.actwp.flyby):
                # Save current wp speed
                oldspd = bs.traf.actwp.spd[i]

                # Get next wp (lnavon = False if no more waypoints)
                lat, lon, alt, spd, bs.traf.actwp.xtoalt[i], toalt, \
                          lnavon, flyby, bs.traf.actwp.next_qdr[i] =  \
                       self.route[i].getnextwp()  # note: xtoalt,toalt in [m]

                # End of route/no more waypoints: switch off LNAV
                bs.traf.swlnav[i] = bs.traf.swlnav[i] and lnavon

                # In case of no LNAV, do not allow VNAV mode on its own
                bs.traf.swvnav[i] = bs.traf.swvnav[i] and bs.traf.swlnav[i]

                bs.traf.actwp.lat[i]   = lat  # [deg]
                bs.traf.actwp.lon[i]   = lon  # [deg]
                bs.traf.actwp.flyby[i] = int(flyby)  # 1.0 in case of fly by, else fly over

                # User has entered an altitude for this waypoint
                if alt >= -0.01:
                    bs.traf.actwp.nextaltco[i] = alt #[m]

                if spd > -990. and bs.traf.swlnav[i] and bs.traf.swvnav[i]:

                    # Valid speed and LNAV and VNAV ap modes are on
                    # Depending on crossover altitude we fix CAS or Mach
                    if bs.traf.abco[i] and spd>1.0:
                        bs.traf.actwp.spd[i] = cas2mach(spd,bs.traf.alt[i])

                    elif bs.traf.belco[i] and 0. < spd<=1.0:
                        bs.traf.actwp.spd[i] = mach2cas(spd,bs.traf.alt[i])

                    else:
                        bs.traf.actwp.spd[i] = spd
                        
                else:
                    bs.traf.actwp.spd[i] = -999.

                # VNAV spd mode: use speed of this waypoint as commanded speed
                # while passing waypoint and save next speed for passing next wp
                # Speed is now from speed! Next speed is ready in wpdata
                if bs.traf.swvnav[i] and oldspd > 0.0:
                        bs.traf.selspd[i] = oldspd


                # VNAV = FMS ALT/SPD mode
                self.ComputeVNAV(i, toalt, bs.traf.actwp.xtoalt[i])

            #=============== End of Waypoint switching loop ===================

            #================= Continuous FMS guidance ========================

            # Waypoint switching in the loop above was scalar (per a/c with index i)
            # Code below is vectorized, with arrays for all aircraft

            # Do VNAV start of descent check
            dy = (bs.traf.actwp.lat - bs.traf.lat)  #[deg lat = 60 nm]
            dx = (bs.traf.actwp.lon - bs.traf.lon) * bs.traf.coslat #[corrected deg lon = 60 nm]
            dist2wp   = 60. * nm * np.sqrt(dx * dx + dy * dy) # [m]

            # VNAV logic: descend as late as possible, climb as soon as possible
            startdescent = (dist2wp < self.dist2vs) + (bs.traf.actwp.nextaltco > bs.traf.alt)

            # If not lnav:Climb/descend if doing so before lnav/vnav was switched off
            #    (because there are no more waypoints). This is needed
            #    to continue descending when you get into a conflict
            #    while descending to the destination (the last waypoint)
            #    Use 0.1 nm (185.2 m) circle in case turndist might be zero
            self.swvnavvs = bs.traf.swvnav * np.where(bs.traf.swlnav, startdescent,
                                         dist <= np.maximum(185.2,bs.traf.actwp.turndist))

            #Recalculate V/S based on current altitude and distance to next alt constraint
            # How much time do we have before we need to descend?

            t2go2alt = np.maximum(0.,(dist2wp + bs.traf.actwp.xtoalt - bs.traf.actwp.turndist)) \
                                        / np.maximum(0.5,bs.traf.gs)

            # use steepness to calculate V/S unless we need to descend faster
            bs.traf.actwp.vs = np.maximum(self.steepness*bs.traf.gs, \
                                   np.abs((bs.traf.actwp.nextaltco-bs.traf.alt))  \
                                   /np.maximum(1.0,t2go2alt))


            self.vnavvs  = np.where(self.swvnavvs, bs.traf.actwp.vs, self.vnavvs)
            #was: self.vnavvs  = np.where(self.swvnavvs, self.steepness * bs.traf.gs, self.vnavvs)

            # self.vs = np.where(self.swvnavvs, self.vnavvs, bs.traf.apvsdef * bs.traf.limvs_flag)
            selvs = np.where(abs(bs.traf.selvs) > 0.1, bs.traf.selvs, bs.traf.apvsdef) # m/s
            self.vs = np.where(self.swvnavvs, self.vnavvs, selvs)
            self.alt = np.where(self.swvnavvs, bs.traf.actwp.nextaltco, bs.traf.selalt)

            # When descending or climbing in VNAV also update altitude command of select/hold mode
            bs.traf.selalt = np.where(self.swvnavvs,bs.traf.actwp.nextaltco,bs.traf.selalt)

            # LNAV commanded track angle
            self.trk = np.where(bs.traf.swlnav, qdr, self.trk)

            # FMS speed guidance: anticipate accel distance

            # Actual distance it takes to decelerate
            nexttas  = vcasormach2tas(bs.traf.actwp.spd,bs.traf.alt)
            tasdiff  = nexttas - bs.traf.tas # [m/s]
            dtspdchg = np.abs(tasdiff)/np.maximum(0.01,np.abs(bs.traf.ax)) #[s]
            dxspdchg = 0.5*np.sign(tasdiff)*np.abs(bs.traf.ax)*dtspdchg*dtspdchg + bs.traf.tas*dtspdchg #[m]

            usespdcon      = (dist2wp < dxspdchg)*(bs.traf.actwp.spd > -990.)*bs.traf.swvnav
            bs.traf.selspd = np.where(usespdcon, bs.traf.actwp.spd, bs.traf.selspd)
            

        # Below crossover altitude: CAS=const, above crossover altitude: Mach = const
        self.tas = vcasormach2tas(bs.traf.selspd, bs.traf.alt)
예제 #4
0
파일: autopilot.py 프로젝트: poyoin/bluesky
    def update(self, simt):
        # Scheduling: when dt has passed or restart
        if self.t0 + self.dt < simt or simt < self.t0 or simt<self.dt:
            self.t0 = simt

            # FMS LNAV mode:
            # qdr[deg],distinnm[nm]
            qdr, distinnm = geo.qdrdist(bs.traf.lat, bs.traf.lon,
                                    bs.traf.actwp.lat, bs.traf.actwp.lon)  # [deg][nm])
            dist = distinnm*nm # Conversion to meters

            # Shift waypoints for aircraft i where necessary
            for i in bs.traf.actwp.Reached(qdr,dist,bs.traf.actwp.flyby):

                # Save current wp speed for use on next leg when we pass this waypoint
                # VNAV speeds are always FROM-speed, so we accelerate/decellerate at the waypoint
                # where this speed is specified, so we need to save it for use now
                # before getting the new data for the next waypoint

                oldspd = bs.traf.actwp.spd[i] # Save speed as specified for the waypoint we pass

                # Get next wp (lnavon = False if no more waypoints)
                lat, lon, alt, spd, bs.traf.actwp.xtoalt[i], toalt, \
                          lnavon, flyby, bs.traf.actwp.next_qdr[i] =  \
                       self.route[i].getnextwp()  # note: xtoalt,toalt in [m]

                # End of route/no more waypoints: switch off LNAV
                bs.traf.swlnav[i] = bs.traf.swlnav[i] and lnavon

                # In case of no LNAV, do not allow VNAV mode on its own
                bs.traf.swvnav[i] = bs.traf.swvnav[i] and bs.traf.swlnav[i]

                bs.traf.actwp.lat[i]   = lat  # [deg]
                bs.traf.actwp.lon[i]   = lon  # [deg]
                bs.traf.actwp.flyby[i] = int(flyby)  # 1.0 in case of fly by, else fly over

                # User has entered an altitude for this waypoint
                if alt >= -0.01:
                    bs.traf.actwp.nextaltco[i] = alt #[m]

                if spd > -990. and bs.traf.swlnav[i] and bs.traf.swvnav[i]:

                    # Valid speed and LNAV and VNAV ap modes are on
                    # Depending on crossover altitude we fix CAS or Mach
                    if bs.traf.abco[i] and spd>1.0:
                        bs.traf.actwp.spd[i] = cas2mach(spd,bs.traf.alt[i])

                    elif bs.traf.belco[i] and 0. < spd<=1.0:
                        bs.traf.actwp.spd[i] = mach2cas(spd,bs.traf.alt[i])

                    else:
                        bs.traf.actwp.spd[i] = spd
                        
                else:
                    bs.traf.actwp.spd[i] = -999.

                # VNAV spd mode: use speed of this waypoint as commanded speed
                # while passing waypoint and save next speed for passing next wp
                # Speed is now from speed! Next speed is ready in wpdata
                if bs.traf.swvnav[i] and oldspd > 0.0:
                        bs.traf.selspd[i] = oldspd

                # Update qdr and turndist for this new waypoint for ComputeVNAV
                dummy, qdr[i] = geo.qdrdist(bs.traf.lat[i], bs.traf.lon[i],
                                                bs.traf.actwp.lat[i], bs.traf.actwp.lon[i])

                # Update turndist so ComputeVNAV wokrs, is there a next leg direction or not?
                if bs.traf.actwp.next_qdr[i] < -900.:
                    local_next_qdr = qdr[i]
                else:
                    local_next_qdr = bs.traf.actwp.next_qdr[i]

                # Calculate turn dist 9and radius which we do not use) now for scalar variable [i]
                bs.traf.actwp.turndist[i],dummy = \
                    bs.traf.actwp.calcturn(bs.traf.tas[i], bs.traf.bank[i],
                                            qdr[i], local_next_qdr)# update turn distance for VNAV

                # VNAV = FMS ALT/SPD mode
                self.ComputeVNAV(i, toalt, bs.traf.actwp.xtoalt[i])

            #=============== End of Waypoint switching loop ===================

            #================= Continuous FMS guidance ========================

            # Waypoint switching in the loop above was scalar (per a/c with index i)
            # Code below is vectorized, with arrays for all aircraft

            # Do VNAV start of descent check
            dy = (bs.traf.actwp.lat - bs.traf.lat)  #[deg lat = 60 nm]
            dx = (bs.traf.actwp.lon - bs.traf.lon) * bs.traf.coslat #[corrected deg lon = 60 nm]
            dist2wp   = 60. * nm * np.sqrt(dx * dx + dy * dy) # [m]
            #print("dist2wp =",dist2wp,"   self.dist2vs =",self.dist2vs)


            # VNAV logic: descend as late as possible, climb as soon as possible
            startdescent = (dist2wp < self.dist2vs) + (bs.traf.actwp.nextaltco > bs.traf.alt)

            # If not lnav:Climb/descend if doing so before lnav/vnav was switched off
            #    (because there are no more waypoints). This is needed
            #    to continue descending when you get into a conflict
            #    while descending to the destination (the last waypoint)
            #    Use 0.1 nm (185.2 m) circle in case turndist might be zero
            self.swvnavvs = bs.traf.swvnav * np.where(bs.traf.swlnav, startdescent,
                                         dist <= np.maximum(185.2,bs.traf.actwp.turndist))

            #Recalculate V/S based on current altitude and distance to next alt constraint
            # How much time do we have before we need to descend?

            t2go2alt = np.maximum(0.,(dist2wp + bs.traf.actwp.xtoalt - bs.traf.actwp.turndist)) \
                                        / np.maximum(0.5,bs.traf.gs)

            # use steepness to calculate V/S unless we need to descend faster
            bs.traf.actwp.vs = np.maximum(self.steepness*bs.traf.gs, \
                                   np.abs((bs.traf.actwp.nextaltco-bs.traf.alt))  \
                                   /np.maximum(1.0,t2go2alt))


            self.vnavvs  = np.where(self.swvnavvs, bs.traf.actwp.vs, self.vnavvs)
            #was: self.vnavvs  = np.where(self.swvnavvs, self.steepness * bs.traf.gs, self.vnavvs)

            # self.vs = np.where(self.swvnavvs, self.vnavvs, bs.traf.apvsdef * bs.traf.limvs_flag)
            selvs    = np.where(abs(bs.traf.selvs) > 0.1, bs.traf.selvs, bs.traf.apvsdef) # m/s
            self.vs  = np.where(self.swvnavvs, self.vnavvs, selvs)
            self.alt = np.where(self.swvnavvs, bs.traf.actwp.nextaltco, bs.traf.selalt)

            # When descending or climbing in VNAV also update altitude command of select/hold mode
            bs.traf.selalt = np.where(self.swvnavvs,bs.traf.actwp.nextaltco,bs.traf.selalt)

            # LNAV commanded track angle
            self.trk = np.where(bs.traf.swlnav, qdr, self.trk)

            # FMS speed guidance: anticipate accel distance

            # Actual distance it takes to decelerate
            nexttas  = vcasormach2tas(bs.traf.actwp.spd,bs.traf.alt)
            tasdiff  = nexttas - bs.traf.tas # [m/s]
            dtspdchg = np.abs(tasdiff)/np.maximum(0.01,np.abs(bs.traf.ax)) #[s]
            dxspdchg = 0.5*np.sign(tasdiff)*np.abs(bs.traf.ax)*dtspdchg*dtspdchg + bs.traf.tas*dtspdchg #[m]

            usespdcon      = (dist2wp < dxspdchg)*(bs.traf.actwp.spd > -990.)*bs.traf.swvnav
            bs.traf.selspd = np.where(usespdcon, bs.traf.actwp.spd, bs.traf.selspd)
            

        # Below crossover altitude: CAS=const, above crossover altitude: Mach = const
        self.tas = vcasormach2tas(bs.traf.selspd, bs.traf.alt)
예제 #5
0
파일: autopilot.py 프로젝트: outsbr/bluesky
    def update(self):
        # FMS LNAV mode:
        # qdr[deg],distinnm[nm]
        qdr, distinnm = geo.qdrdist(bs.traf.lat, bs.traf.lon,
                                    bs.traf.actwp.lat, bs.traf.actwp.lon)  # [deg][nm])
        self.qdr2wp  = qdr
        dist2wp = distinnm*nm  # Conversion to meters

        # FMS route update and possibly waypoint shift. Note: qdr, dist2wp will be updated accordingly in case of wp switch
        self.update_fms(qdr, dist2wp) # Updates self.qdr2wp when necessary

        #================= Continuous FMS guidance ========================

        # Waypoint switching in the loop above was scalar (per a/c with index i)
        # Code below is vectorized, with arrays for all aircraft

        # Do VNAV start of descent check
        #dy = (bs.traf.actwp.lat - bs.traf.lat)  #[deg lat = 60 nm]
        #dx = (bs.traf.actwp.lon - bs.traf.lon) * bs.traf.coslat #[corrected deg lon = 60 nm]
        #dist2wp   = 60. * nm * np.sqrt(dx * dx + dy * dy) # [m]

        # VNAV logic: descend as late as possible, climb as soon as possible
        startdescent = (dist2wp < self.dist2vs) + (bs.traf.actwp.nextaltco > bs.traf.alt)

        # If not lnav:Climb/descend if doing so before lnav/vnav was switched off
        #    (because there are no more waypoints). This is needed
        #    to continue descending when you get into a conflict
        #    while descending to the destination (the last waypoint)
        #    Use 0.1 nm (185.2 m) circle in case turndist might be zero
        self.swvnavvs = bs.traf.swvnav * np.where(bs.traf.swlnav, startdescent,
                                        dist2wp <= np.maximum(185.2,bs.traf.actwp.turndist))

        #Recalculate V/S based on current altitude and distance to next alt constraint
        # How much time do we have before we need to descend?

        t2go2alt = np.maximum(0.,(dist2wp + bs.traf.actwp.xtoalt - bs.traf.actwp.turndist)) \
                                    / np.maximum(0.5,bs.traf.gs)

        # use steepness to calculate V/S unless we need to descend faster
        bs.traf.actwp.vs = np.maximum(self.steepness*bs.traf.gs, \
                                np.abs((bs.traf.actwp.nextaltco-bs.traf.alt))  \
                                /np.maximum(1.0,t2go2alt))

        self.vnavvs  = np.where(self.swvnavvs, bs.traf.actwp.vs, self.vnavvs)
        #was: self.vnavvs  = np.where(self.swvnavvs, self.steepness * bs.traf.gs, self.vnavvs)

        # self.vs = np.where(self.swvnavvs, self.vnavvs, bs.traf.apvsdef * bs.traf.limvs_flag)
        selvs    = np.where(abs(bs.traf.selvs) > 0.1, bs.traf.selvs, bs.traf.apvsdef) # m/s
        self.vs  = np.where(self.swvnavvs, self.vnavvs, selvs)
        self.alt = np.where(self.swvnavvs, bs.traf.actwp.nextaltco, bs.traf.selalt)

        # When descending or climbing in VNAV also update altitude command of select/hold mode
        bs.traf.selalt = np.where(self.swvnavvs,bs.traf.actwp.nextaltco,bs.traf.selalt)

        # LNAV commanded track angle
        self.trk = np.where(bs.traf.swlnav, self.qdr2wp, self.trk)

        # FMS speed guidance: anticipate accel/decel distance for next leg or turn

        # Calculate actual distance it takes to decelerate/accelerate based on two cases: turning speed (decel)

        # Normally next leg speed (actwp.spd) but in case we fly turns with a specified turn speed
        # use the turn speed

        # Is turn speed specified and are we not already slow enough? We only decelerate for turns, not accel.
        turntas       = np.where(bs.traf.actwp.turnspd>0.0, vcas2tas(bs.traf.actwp.turnspd, bs.traf.alt),
                                 -1.0+0.*bs.traf.tas)
        swturnspd     = bs.traf.actwp.flyturn*(turntas>0.0)*(bs.traf.actwp.turnspd>0.0)
        turntasdiff   = np.maximum(0.,(bs.traf.tas - turntas)*(turntas>0.0))

        # dt = dv/a ;  dx = v*dt + 0.5*a*dt2 => dx = dv/a * (v + 0.5*dv)
        ax = bs.traf.perf.acceleration()
        dxturnspdchg  = np.where(swturnspd, np.abs(turntasdiff)/np.maximum(0.01,ax)*(bs.traf.tas+0.5*np.abs(turntasdiff)),
                                                                   0.0*bs.traf.tas)

        # Decelerate or accelerate for next required speed because of speed constraint or RTA speed
        nexttas   = vcasormach2tas(bs.traf.actwp.nextspd,bs.traf.alt)
        tasdiff   = (nexttas - bs.traf.tas)*(bs.traf.actwp.spd>=0.) # [m/s]

        # dt = dv/a   dx = v*dt + 0.5*a*dt2 => dx = dv/a * (v + 0.5*dv)
        dxspdconchg = np.abs(tasdiff)/np.maximum(0.01, np.abs(ax)) * (bs.traf.tas+0.5*np.abs(tasdiff))


        # Check also whether VNAVSPD is on, if not, SPD SEL has override for next leg
        # and same for turn logic
        usenextspdcon = (dist2wp < dxspdconchg)*(bs.traf.actwp.nextspd> -990.) * \
                            bs.traf.swvnavspd*bs.traf.swvnav*bs.traf.swlnav
        useturnspd = np.logical_or(bs.traf.actwp.turntonextwp,(dist2wp < dxturnspdchg+bs.traf.actwp.turndist) *\
                                                              swturnspd*bs.traf.swvnavspd*bs.traf.swvnav*bs.traf.swlnav)

        # Hold turn mode can only be switched on here, cannot be switched off here (happeps upon passing wp)
        bs.traf.actwp.turntonextwp = np.logical_or(bs.traf.actwp.turntonextwp,useturnspd)

        # Which CAS/Mach do we have to keep? VNAV, last turn or next turn?
        oncurrentleg = (abs(degto180(bs.traf.trk - qdr)) < 2.0) # [deg]
        inoldturn    = (bs.traf.actwp.oldturnspd > 0.) * np.logical_not(oncurrentleg)

        # Avoid using old turning speeds when turning of this leg to the next leg
        # by disabling (old) turningspd when on leg
        bs.traf.actwp.oldturnspd = np.where(oncurrentleg*(bs.traf.actwp.oldturnspd>0.), -999.,
                                            bs.traf.actwp.oldturnspd)

        # turnfromlastwp can only be switched off here, not on (latter happens upon passing wp)
        bs.traf.actwp.turnfromlastwp = np.logical_and(bs.traf.actwp.turnfromlastwp,inoldturn)

        # Select speed: turn sped, next speed constraint, or current speed constraint
        bs.traf.selspd = np.where(useturnspd,bs.traf.actwp.turnspd,
                                  np.where(usenextspdcon, bs.traf.actwp.nextspd,
                                           np.where((bs.traf.actwp.spdcon>0)*bs.traf.swvnavspd,bs.traf.actwp.spd,
                                                                            bs.traf.selspd)))


        # Temporary override when still in old turn
        bs.traf.selspd = np.where(inoldturn*(bs.traf.actwp.oldturnspd>0.)*bs.traf.swvnavspd*bs.traf.swvnav*bs.traf.swlnav,
                                  bs.traf.actwp.oldturnspd,bs.traf.selspd)

        #debug if inoldturn[0]:
        #debug     print("inoldturn bs.traf.trk =",bs.traf.trk[0],"qdr =",qdr)
        #debug elif usenextspdcon[0]:
        #debug     print("usenextspdcon")
        #debug elif useturnspd[0]:
        #debug     print("useturnspd")
        #debug elif bs.traf.actwp.spdcon>0:
        #debug     print("using current speed constraint")
        #debug else:
        #debug     print("no speed given")

        # Below crossover altitude: CAS=const, above crossover altitude: Mach = const
        self.tas = vcasormach2tas(bs.traf.selspd, bs.traf.alt)

        return
예제 #6
0
    def update(self):
        # FMS LNAV mode:
        # qdr[deg],distinnm[nm]
        qdr, distinnm = geo.qdrdist(bs.traf.lat, bs.traf.lon,
                                    bs.traf.actwp.lat,
                                    bs.traf.actwp.lon)  # [deg][nm])

        self.qdr2wp = qdr
        self.dist2wp = distinnm * nm  # Conversion to meters

        # FMS route update and possibly waypoint shift. Note: qdr, dist2wp will be updated accordingly in case of wp switch
        self.update_fms(qdr,
                        self.dist2wp)  # Updates self.qdr2wp when necessary

        #================= Continuous FMS guidance ========================

        # Note that the code below is vectorized, with traffic arrays, so for all aircraft
        # ComputeVNAV and inside waypoint loop of update_fms, it was scalar (per a/c with index i)

        # VNAV guidance logic (using the variables prepared by ComputeVNAV when activating waypoint)
        #
        # Central question is:
        # - Can we please we start to descend or to climb?
        #
        # Well, when Top of Descent (ToD) switch is on, descend as late as possible,
        # But when Top of Climb switch is on or off, climb as soon as possible, only difference is steepness used in ComputeVNAV
        # to calculate bs.traf.actwp.vs
        # Only use this logic if there is a valid next altitude constraint (nextaltco)

        startdescorclimb = (bs.traf.actwp.nextaltco>=-0.1) * \
                           np.logical_or(self.swtod * (bs.traf.alt>bs.traf.actwp.nextaltco) * (self.dist2wp < self.dist2vs),
                                         bs.traf.alt<bs.traf.actwp.nextaltco)

        #print("self.dist2vs =",self.dist2vs)

        # If not lnav:Climb/descend if doing so before lnav/vnav was switched off
        #    (because there are no more waypoints). This is needed
        #    to continue descending when you get into a conflict
        #    while descending to the destination (the last waypoint)
        #    Use 0.1 nm (185.2 m) circle in case turndist might be zero
        self.swvnavvs = bs.traf.swvnav * np.where(
            bs.traf.swlnav, startdescorclimb,
            self.dist2wp <= np.maximum(0.1 * nm, bs.traf.actwp.turndist))

        # Recalculate V/S based on current altitude and distance to next alt constraint
        # How much time do we have before we need to descend?
        # Now done in ComputeVNAV
        # See ComputeVNAV for bs.traf.actwp.vs calculation

        self.vnavvs = np.where(self.swvnavvs, bs.traf.actwp.vs, self.vnavvs)
        #was: self.vnavvs  = np.where(self.swvnavvs, self.steepness * bs.traf.gs, self.vnavvs)

        # self.vs = np.where(self.swvnavvs, self.vnavvs, self.vsdef * bs.traf.limvs_flag)
        # for VNAV use fixed V/S and change start of descent
        selvs = np.where(abs(bs.traf.selvs) > 0.1, bs.traf.selvs,
                         self.vsdef)  # m/s
        self.vs = np.where(self.swvnavvs, self.vnavvs, selvs)
        self.alt = np.where(self.swvnavvs, bs.traf.actwp.nextaltco,
                            bs.traf.selalt)

        # When descending or climbing in VNAV also update altitude command of select/hold mode
        bs.traf.selalt = np.where(self.swvnavvs, bs.traf.actwp.nextaltco,
                                  bs.traf.selalt)

        # LNAV commanded track angle
        self.trk = np.where(bs.traf.swlnav, self.qdr2wp, self.trk)

        # FMS speed guidance: anticipate accel/decel distance for next leg or turn

        # Calculate actual distance it takes to decelerate/accelerate based on two cases: turning speed (decel)

        # Normally next leg speed (actwp.spd) but in case we fly turns with a specified turn speed
        # use the turn speed

        # Is turn speed specified and are we not already slow enough? We only decelerate for turns, not accel.
        turntas = np.where(bs.traf.actwp.nextturnspd > 0.0,
                           vcas2tas(bs.traf.actwp.nextturnspd, bs.traf.alt),
                           -1.0 + 0. * bs.traf.tas)
        # Switch is now whether the aircraft has any turn waypoints
        swturnspd = bs.traf.actwp.nextturnidx > 0
        turntasdiff = np.maximum(0., (bs.traf.tas - turntas) * (turntas > 0.0))

        # t = (v1-v0)/a ; x = v0*t+1/2*a*t*t => dx = (v1*v1-v0*v0)/ (2a)
        dxturnspdchg = distaccel(turntas, bs.traf.perf.vmax,
                                 bs.traf.perf.axmax)
        #        dxturnspdchg = 0.5*np.abs(turntas*turntas-bs.traf.tas*bs.traf.tas)/(np.sign(turntas-bs.traf.tas)*np.maximum(0.01,np.abs(ax)))
        #        dxturnspdchg  = np.where(swturnspd, np.abs(turntasdiff)/np.maximum(0.01,ax)*(bs.traf.tas+0.5*np.abs(turntasdiff)),
        #                                                                   0.0*bs.traf.tas)

        # Decelerate or accelerate for next required speed because of speed constraint or RTA speed
        # Note that because nextspd comes from the stack, and can be either a mach number or
        # a calibrated airspeed, it can only be converted from Mach / CAS [kts] to TAS [m/s]
        # once the altitude is known.
        nexttas = vcasormach2tas(bs.traf.actwp.nextspd, bs.traf.alt)

        #        tasdiff   = (nexttas - bs.traf.tas)*(bs.traf.actwp.spd>=0.) # [m/s]

        # t = (v1-v0)/a ; x = v0*t+1/2*a*t*t => dx = (v1*v1-v0*v0)/ (2a)

        dxspdconchg = distaccel(bs.traf.tas, nexttas, bs.traf.perf.axmax)

        qdrturn, dist2turn = geo.qdrdist(bs.traf.lat, bs.traf.lon,
                                         bs.traf.actwp.nextturnlat,
                                         bs.traf.actwp.nextturnlon)

        self.qdrturn = qdrturn
        dist2turn = dist2turn * nm

        # Where we don't have a turn waypoint, as in turn idx is negative, then put distance
        # as Earth circumference.
        self.dist2turn = np.where(bs.traf.actwp.nextturnidx > 0, dist2turn,
                                  40075000)

        # Check also whether VNAVSPD is on, if not, SPD SEL has override for next leg
        # and same for turn logic
        usenextspdcon = (self.dist2wp < dxspdconchg)*(bs.traf.actwp.nextspd>-990.) * \
                            bs.traf.swvnavspd*bs.traf.swvnav*bs.traf.swlnav
        useturnspd = np.logical_or(bs.traf.actwp.turntonextwp,
                                   (self.dist2turn < (dxturnspdchg+bs.traf.actwp.turndist))) * \
                                        swturnspd*bs.traf.swvnavspd*bs.traf.swvnav*bs.traf.swlnav

        # Hold turn mode can only be switched on here, cannot be switched off here (happeps upon passing wp)
        bs.traf.actwp.turntonextwp = bs.traf.swlnav * np.logical_or(
            bs.traf.actwp.turntonextwp, useturnspd)

        # Which CAS/Mach do we have to keep? VNAV, last turn or next turn?
        oncurrentleg = (abs(degto180(bs.traf.trk - qdr)) < 2.0)  # [deg]
        inoldturn = (bs.traf.actwp.oldturnspd >
                     0.) * np.logical_not(oncurrentleg)

        # Avoid using old turning speeds when turning of this leg to the next leg
        # by disabling (old) turningspd when on leg
        bs.traf.actwp.oldturnspd = np.where(
            oncurrentleg * (bs.traf.actwp.oldturnspd > 0.), -998.,
            bs.traf.actwp.oldturnspd)

        # turnfromlastwp can only be switched off here, not on (latter happens upon passing wp)
        bs.traf.actwp.turnfromlastwp = np.logical_and(
            bs.traf.actwp.turnfromlastwp, inoldturn)

        # Select speed: turn sped, next speed constraint, or current speed constraint
        bs.traf.selspd = np.where(
            useturnspd, bs.traf.actwp.nextturnspd,
            np.where(
                usenextspdcon, bs.traf.actwp.nextspd,
                np.where((bs.traf.actwp.spdcon >= 0) * bs.traf.swvnavspd,
                         bs.traf.actwp.spd, bs.traf.selspd)))

        # Temporary override when still in old turn
        bs.traf.selspd = np.where(
            inoldturn * (bs.traf.actwp.oldturnspd > 0.) * bs.traf.swvnavspd *
            bs.traf.swvnav * bs.traf.swlnav, bs.traf.actwp.oldturnspd,
            bs.traf.selspd)

        self.inturn = np.logical_or(useturnspd, inoldturn)

        #debug if inoldturn[0]:
        #debug     print("inoldturn bs.traf.trk =",bs.traf.trk[0],"qdr =",qdr)
        #debug elif usenextspdcon[0]:
        #debug     print("usenextspdcon")
        #debug elif useturnspd[0]:
        #debug     print("useturnspd")
        #debug elif bs.traf.actwp.spdcon>0:
        #debug     print("using current speed constraint")
        #debug else:
        #debug     print("no speed given")

        # Below crossover altitude: CAS=const, above crossover altitude: Mach = const
        self.tas = vcasormach2tas(bs.traf.selspd, bs.traf.alt)
예제 #7
0
    def update(self):
        # FMS LNAV mode:
        # qdr[deg],distinnm[nm]
        qdr, distinnm = geo.qdrdist(bs.traf.lat, bs.traf.lon,
                                    bs.traf.actwp.lat, bs.traf.actwp.lon)  # [deg][nm])
        dist = distinnm*nm  # Conversion to meters

        # FMS route update
        self.update_fms(qdr, dist)

        #================= Continuous FMS guidance ========================

        # Waypoint switching in the loop above was scalar (per a/c with index i)
        # Code below is vectorized, with arrays for all aircraft

        # Do VNAV start of descent check
        dy = (bs.traf.actwp.lat - bs.traf.lat)  #[deg lat = 60 nm]
        dx = (bs.traf.actwp.lon - bs.traf.lon) * bs.traf.coslat #[corrected deg lon = 60 nm]
        dist2wp   = 60. * nm * np.sqrt(dx * dx + dy * dy) # [m]
        #print("dist2wp =",dist2wp,"   self.dist2vs =",self.dist2vs)


        # VNAV logic: descend as late as possible, climb as soon as possible
        startdescent = (dist2wp < self.dist2vs) + (bs.traf.actwp.nextaltco > bs.traf.alt)

        # If not lnav:Climb/descend if doing so before lnav/vnav was switched off
        #    (because there are no more waypoints). This is needed
        #    to continue descending when you get into a conflict
        #    while descending to the destination (the last waypoint)
        #    Use 0.1 nm (185.2 m) circle in case turndist might be zero
        self.swvnavvs = bs.traf.swvnav * np.where(bs.traf.swlnav, startdescent,
                                        dist <= np.maximum(185.2,bs.traf.actwp.turndist))

        #Recalculate V/S based on current altitude and distance to next alt constraint
        # How much time do we have before we need to descend?

        t2go2alt = np.maximum(0.,(dist2wp + bs.traf.actwp.xtoalt - bs.traf.actwp.turndist)) \
                                    / np.maximum(0.5,bs.traf.gs)

        # use steepness to calculate V/S unless we need to descend faster
        bs.traf.actwp.vs = np.maximum(self.steepness*bs.traf.gs, \
                                np.abs((bs.traf.actwp.nextaltco-bs.traf.alt))  \
                                /np.maximum(1.0,t2go2alt))


        self.vnavvs  = np.where(self.swvnavvs, bs.traf.actwp.vs, self.vnavvs)
        #was: self.vnavvs  = np.where(self.swvnavvs, self.steepness * bs.traf.gs, self.vnavvs)

        # self.vs = np.where(self.swvnavvs, self.vnavvs, bs.traf.apvsdef * bs.traf.limvs_flag)
        selvs    = np.where(abs(bs.traf.selvs) > 0.1, bs.traf.selvs, bs.traf.apvsdef) # m/s
        self.vs  = np.where(self.swvnavvs, self.vnavvs, selvs)
        self.alt = np.where(self.swvnavvs, bs.traf.actwp.nextaltco, bs.traf.selalt)

        # When descending or climbing in VNAV also update altitude command of select/hold mode
        bs.traf.selalt = np.where(self.swvnavvs,bs.traf.actwp.nextaltco,bs.traf.selalt)

        # LNAV commanded track angle
        self.trk = np.where(bs.traf.swlnav, qdr, self.trk)

        # FMS speed guidance: anticipate accel distance

        # Actual distance it takes to decelerate
        nexttas  = vcasormach2tas(bs.traf.actwp.spd,bs.traf.alt)
        tasdiff  = nexttas - bs.traf.tas # [m/s]
        dtspdchg = np.abs(tasdiff)/np.maximum(0.01,np.abs(bs.traf.ax)) #[s]
        dxspdchg = 0.5*np.sign(tasdiff)*np.abs(bs.traf.ax)*dtspdchg*dtspdchg + bs.traf.tas*dtspdchg #[m]

        # Chekc also whether VNAVSPD is on, if not, SPD SEL has override
        usespdcon      = (dist2wp < dxspdchg)*(bs.traf.actwp.spd > -990.)*bs.traf.swvnavspd*bs.traf.swvnav

        bs.traf.selspd = np.where(usespdcon, bs.traf.actwp.spd, bs.traf.selspd)

        # Below crossover altitude: CAS=const, above crossover altitude: Mach = const
        self.tas = vcasormach2tas(bs.traf.selspd, bs.traf.alt)