Ejemplo n.º 1
0
    def limits(self, intent_v_tas, intent_vs, intent_h, ax):
        """apply limits on indent speed, vertical speed, and altitude (called in pilot module)

        Args:
            intent_v_tas (float or 1D-array): intent true airspeed
            intent_vs (float or 1D-array): intent vertical speed
            intent_h (float or 1D-array): intent altitude
            ax (float or 1D-array): acceleration
        Returns:
            floats or 1D-arrays: Allowed TAS, Allowed vetical rate, Allowed altitude
        """
        allow_h = np.where(intent_h > self.hmax, self.hmax, intent_h)

        intent_v_cas = aero.vtas2cas(intent_v_tas, allow_h)
        allow_v_cas = np.where((intent_v_cas < self.vmin), self.vmin, intent_v_cas)
        allow_v_cas = np.where(intent_v_cas > self.vmax, self.vmax, allow_v_cas)
        allow_v_tas = aero.vcas2tas(allow_v_cas, allow_h)
        allow_v_tas = np.where(
            aero.vtas2mach(allow_v_tas, allow_h) > self.mmo,
            aero.vmach2tas(self.mmo, allow_h),
            allow_v_tas,
        )  # maximum cannot exceed MMO

        vs_max_with_acc = (1 - ax / self.axmax) * self.vsmax
        allow_vs = np.where(
            (intent_vs > 0) & (intent_vs > self.vsmax), vs_max_with_acc, intent_vs
        )  # for climb with vs larger than vsmax
        allow_vs = np.where(
            (intent_vs < 0) & (intent_vs < self.vsmin), vs_max_with_acc, allow_vs
        )  # for descent with vs smaller than vsmin (negative)
        allow_vs = np.where(
            (self.phase == ph.GD) & (bs.traf.tas < self.vminto), 0, allow_vs
        )  # takeoff aircraft

        # corect rotercraft speed limits
        ir = np.where(self.lifttype == coeff.LIFT_ROTOR)[0]
        allow_v_tas[ir] = np.where(
            (intent_v_tas[ir] < self.vmin[ir]), self.vmin[ir], intent_v_tas[ir]
        )
        allow_v_tas[ir] = np.where(
            (intent_v_tas[ir] > self.vmax[ir]), self.vmax[ir], allow_v_tas[ir]
        )
        allow_vs[ir] = np.where(
            (intent_vs[ir] < self.vsmin[ir]), self.vsmin[ir], intent_vs[ir]
        )
        allow_vs[ir] = np.where(
            (intent_vs[ir] > self.vsmax[ir]), self.vsmax[ir], allow_vs[ir]
        )

        return allow_v_tas, allow_vs, allow_h
Ejemplo n.º 2
0
    def currentlimits(self, id=None):
        """Get current kinematic performance envelop.

        Args:
            id (int or 1D-array): Aircraft ID(s). Defualt to None (all aircraft).

        Returns:
            floats or 1D-arrays: Min TAS, Max TAS, Min VS, Max VS

        """
        vtasmin = aero.vcas2tas(self.vmin, bs.traf.alt)

        vtasmax = np.minimum(aero.vcas2tas(self.vmax, bs.traf.alt),
                             aero.vmach2tas(self.mmo, bs.traf.alt))

        if id is not None:
            return vtasmin[id], vtasmax[id], self.vsmin[id], self.vsmax[id]
        else:
            return vtasmin, vtasmax, self.vsmin, self.vsmax
Ejemplo n.º 3
0
    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):
                # Save current wp speed
                oldspd = bs.traf.actwp.spd[i]

                # Get next wp (lnavon = False if no more waypoints)
                lat, lon, alt, spd, 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.alt[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
                    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
                if bs.traf.swvnav[i] and oldspd > 0.0:
                    destalt = alt if alt > 0.0 else bs.traf.alt[i]
                    if oldspd<2.0:
                        bs.traf.aspd[i] = mach2cas(oldspd, destalt)
                        bs.traf.ama[i]  = oldspd
                    else:
                        bs.traf.aspd[i] = oldspd
                        bs.traf.ama[i]  = cas2mach(oldspd, destalt)

                # VNAV = FMS ALT/SPD mode
                self.ComputeVNAV(i, toalt, 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.alt > 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
            t2go = dist2wp/np.maximum(0.5,bs.traf.gs)
            bs.traf.actwp.vs = (bs.traf.actwp.alt-bs.traf.alt)/np.maximum(1.0,t2go)

            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.avsdef * bs.traf.limvs_flag)
            avs = np.where(abs(bs.traf.avs) > 0.1, bs.traf.avs, bs.traf.avsdef) # m/s
            self.vs = np.where(self.swvnavvs, self.vnavvs, avs * bs.traf.limvs_flag)

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

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

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

        # Below crossover altitude: CAS=const, above crossover altitude: MA = const
        self.tas = vcas2tas(bs.traf.aspd, bs.traf.alt) * bs.traf.belco + vmach2tas(bs.traf.ama, bs.traf.alt) * bs.traf.abco