Flight Planning

January 19, 2010

We begin with some simple definitions from trigonometry. Rnd provides both rounding and a type conversion from inexact (real) arithmetic to exact (integer). Xmodulo is like the modulo function, but simpler. We also use the square function from the Standard Prelude:

(define pi 3.141592653589793)
(define (radian->degree r) (/ r pi 2/360))
(define (degree->radian d) (* d 2/360 pi))
(define (rnd x) (round (inexact->exact x)))
(define (xmodulo x y)
(cond
  ((<= 0 x y) x)
  ((< x 0) (xmodulo (+ x y) y))
  ((>= x y) (xmodulo (- x y) y))))

For the first method, navigate1 follows the definition exactly through a sequence of temporary variables:

(define (navigate1 d gt wn ws as)
 (let*
  ((b (- gt wn -180))
   (b-radians (degree->radian b))
   (sin-b (sin b-radians))
   (a (radian->degree (asin (/ (* sin-b ws) as))))
   (th (xmodulo (+ gt a) 360))
   (gs (+ (* as (cos (degree->radian (- th gt))))
          (* ws (cos b-radians))))
   (th (+ gt a))
   (ft (/ d gs)))
  (list
   (rnd gs)
   (rnd a)
   (xmodulo (rnd th) 360)
   (rnd (* 60 ft)))))

For the second method, det uses the cosine rule in the calculation of the ground speed, and a uses the inverse of the cosine rule to calculate the angle of correction between the ground track and the true heading:

(define (navigate2 d gt wn ws as)
 (let*
  ((b (xmodulo (- gt wn -180) 360))
   (cos-b (cos (degree->radian b)))
   (wsqr (square ws))
   (asqr (square as))
   (det (+ (square (* ws cos-b)) (- wsqr) asqr))
   (gs (+ (* ws cos-b) (sqrt det)))
   (a (radian->degree (acos (/ (+ asqr (square gs) (- wsqr)) (* 2 gs as)))))
   (a ((if (< b 180) + -) a))
   (th (+ gt a))
   (ft (/ d gs)))
  (if (or (< det 0) (< gs 0)) ('error 'navigate "STRANGE" det gs))
  (list
   (rnd gs)
   (rnd a)
   (xmodulo (rnd th) 360)
   (rnd (* 60 ft)))))

An example is given below:

> (navigate1 180 90 90 20 90)
(70 0 90 154)
> (navigate2 180 90 90 20 90)
(70 0 90 154)

You can run the program at http://programmingpraxis.codepad.org/yE35J5Pw.

Pages: 1 2

2 Responses to “Flight Planning”

  1. […] Praxis – Flight Planning By Remco Niemeijer In today’s Programming Praxis exercise we have to implement two algorithms for flight […]

  2. Remco Niemeijer said

    My Haskell solution (see http://bonsaicode.wordpress.com/2010/01/19/programming-praxis-flight-planning/ for a version with comments):

    import Data.Fixed
    
    toDeg, toRad :: Floating a => a -> a
    toDeg d = d * 180 / pi
    toRad d = d * pi / 180
    
    navigate1 :: Float -> Float -> Float -> Float -> Float -> [Int]
    navigate1 d gt wn ws as = map round [gs, a, th, ft] where
        b  = toRad $ gt - wn + 180
        a  = toDeg $ asin (ws * sin b / as)
        th = mod' (gt + a) 360
        gs = (cos . toRad $ th - gt) * as + ws * cos b
        ft = d / gs * 60
    
    navigate2 :: Float -> Float -> Float -> Float -> Float -> [Int]
    navigate2 d gt wn ws as = if det < 0 || gs < 0 then error "strange"
                              else map round [gs, a, th, ft] where
        b   = mod' (gt - wn + 180) 360
        x   = ws * cos (toRad b)
        det = x^2 - ws^2 + as^2
        gs  = x + sqrt det
        a   = (if b < 180 then id else negate) . toDeg . acos $
              (as^2 + gs^2 - ws^2) / (2 * gs * as)
        th  = gt + a
        ft  = d / gs * 60
    

Leave a comment