Automatic Global Navigator originated and written in 'C' by Robert John Morton YE572246C.

Global Navigator

This description is of the short version of the global navigator of which the pre­viously described applet was a demon­strator. It is written ent­ire­ly in 'C' using only the X11 wind­ow­ing facility: no ex­ternal graphics or widget libraries are neces­sary. Com­pile this program from the sup­plied source code and run on a Unix-type oper­ating system e.g. Linux, System V or BSD. [PDF]

Before you can run this program you must first compile it from the source code. Please click on the image [above right] for access to the source code and instruc­tions on how to compile it. To start the program, open a terminal, change directory to where the compiled program 'nav' resides, along with its route data files, and enter the command './nav'. After you have started the program, wait until the "Flight ready to depart." message appears in the message bar at the bottom left of the window. This confirms that the data pertaining to the default route has been loaded and initialised. This program is controlled entirely by the mouse. It has no keyboard input. It outputs only to the screen and also optionally to 'stdout'. It reads route information from text files and can, under certain circumstances, take input from 'stdin'. It does not write to disk: it has no output files, although you may redirect 'stdout' to a text file of your choice via the command line if you wish.

The program's controls comprise selection menus and button-style selectors. The REFRESH RATE menu at the bottom left allows you to select how often the map and flight data are updated: every second, every 200 milliseconds or every 40 milli­seconds. To select a new refresh rate, click the mouse's left button within the dark grey area containing the refresh rate you want. You may change the MAP SIZE [or scale], the ROUTE to be flown, the GEOID to be used, the GEOID SELECTION MODE and the NEXT or PREVious waypoint in the current route, all in the same way. Click­ing the START button initiates a flight. Having been thus clicked, the button be­comes a STOP button with the word 'STOP' shown in red. The RESET button resets the current flight back to the beginning of the route. The WIND button effects a 5 metres per second wind from a bearing of 230°. The lettering is bright white when the wind is on and grey when it is off. The CMD TO STDOUT button sends flight command information to the program's 'stdout', which is usually the terminal from which the program was started. The lettering on this button is bright white when the output is in effect and grey when it is not. The CLEAR MESSAGE button simply wipes the message currently displayed on the message line below. The SPARE button is not currently used but is there in case an extra facility needs to be added.

The program is designed to run in one of 3 different situations: in isolation, with output-only, or with input and output. When running in isolation, the program is merely a demonstrator, which flies a fictitious aircraft from the selected route's prescribed origin to its prescribed destination, with or without internally-simulated wind. To start the program in this mode, open a terminal, go to the directory containing the program 'nav' plus its route files and enter the command './nav'. When running with output only, the program additionally outputs its heading, speed and height commands to 'stdout'. To start the program in this mode, enter the com­mand './nav -o'. If you would like to collect the output in a text file for later analysis, you can re-direct the output from 'stdout' to a file by entering the command './nav -o > output.txt', where 'output.txt' is the name of the file containing the output. Note that clicking the 'CMD TO STDOUT' button once the pro­gram has been started in isolation mode sends output to 'stdout' but this cannot in this circumstance be re-directed to a file.

The third situation [with input and output] is quite different from the other two. In this situation, the program is part of a control loop that can be flying a real air veh­icle or a simulated vehicle in an environment that is external to the program. In this situation, the program receives input of the air vehicle's real-world latitude and longitude via 'stdin' at regular intervals of 1 second, 200 milliseconds or 40 milli­seconds as required. It then computes and outputs the heading, speed and height commands required to navigate the air vehicle, from its origin to its destination, along the selected route.

The automatic global navigator program set in a pipe to receive live position input and return live output commands.

In the above illustration, pos is a program that supplies the air vehicle's live lati­tude and longitude, which it acquires from a hardware interface connected to an external GPS or radio aids receiver or an inertial platform. This program, nav, uses this input to compute and then output the requisite flight commands to the pro­gram apt, which passes them on via another hardware interface to an external autopilot or flight director computer. To set up this situation enter the command:

./pos -io | ./nav -io | ./apt -io

Of course, this is strictly a test-bad development situation. It is not safe to fly real air vehicles by software running under a conventional operating system. For real flight control, the software must be integrated in read-only memory within dedi­cated hardware. Note: to terminate the above pipe command, enter Ctrl-C in the terminal.

Program Structure

The main() function of this program sets up and initialises the window and event listeners, then enters a permanent loop which is broken only by a click from the left mouse button on the X at the top right of the window. Main()'s permanent loop triggers 3 different execution chains, respectively comprising what must be done:

  1. upon initial exposure or re-exposure of the window
  2. on receipt of a left-button mouse click from a menu or control button
  3. once every clocked refresh cycle

On initial exposure of the window, the function getRoutes() loads the route names and the default route's way­points and initialises the aircraft data to the start of the route. The function drawWords() then sets all menus and control buttons to their default selections and displays these plus the map and flight data. On re-exposure — when the window is returned from a minimised state or the user returns from having visited another desktop — the drawWords() function simply re-draws the menus, control buttons, map and flight data in their current states: NOT their default states. The getRoutes() function is not called in this case, as this would reset any flight that was in progress when the window was minimised or the user left the desktop on which the program is running.

The receipt of a mouse click from a menu or control button, calls the whichButton() function, which selects and highlights the menu item or control button and initiates the processing required by that selection.

Once every refresh rate period, if a flight is in progress, the Advance() function is called to advance the aircraft along its route and the updateMap() function is called to re-display the updated map and flight data. The autoGeoid() function is called to see if the geoid selection is in automatic mode [the default]. If so, it checks the aircraft's position to see if it has entered the area covered by a different geoid, in which case the new geoid's details are passed to the Vincenty functions.

Fourteen significant functions [including main()] make up the essence of this pro­gram. Another 11 functions, which are not discussed further herein, perform auxil­iary tasks such as converting and formatting numbers for display.

This table shows the functions called by each of the 3 triggers in main()'s perman­ent loop. All other functions in the program are called by drawWords(), whichButton() or Advance(). getRoutes() does not call any further functions.

✔2 setAircraft()
✔2 ✔6 updateMap()
✔5 VSGIP()
The adjacent table shows which of the functions shown across the top call which of the functions listed on the right. A tick [✔] indicates a call. The number after the tick shows from how many places within the calling function a call is made to the called function. The functions shown on a blue back­ground are first-level functions called directly by main(). The functions on a yellow background are 2nd level func­tions which call each other plus sub­ordinate 3rd-level functions shown on a white background. These call only auxiliary plus C/X11 library functions. The essence of each of the functions named in these tables is adequately described within the program listing in 'nav.c'.

Most of these functions implement the user interface of menus and buttons. All menus and buttons in this program are plane simple areas of the window that are sensitive to mouse clicks. Animated buttons and menus have been avoided as they require large swathes of extra code that contribute nothing to the actual function­ality of the user interface. The logic within the user interface functions can be quite tricky in places due to the fact that clicking on some buttons and menus, in some circumstances, systemically requires that other buttons and menus be automatic­ally 'clicked' in consequence.

The user interface is not really part of the navigational essence of this program, so the functions that implement it are not discussed further herein. This leaves the 6 major functions of the program that deal directly with navigation. These are listed in the following table.

VSGDP() Computes the position of a waypoint from the position of the aircraft and the distance & bearing of the waypoint from the aircraft. by getWayPoints() and Advance()
VSGIP() Computes distance + forward & backward bearings, given the positions of the aircraft and a waypoint. by getWayPoints(), Advance() or updateMap()
getRoutes() Loads the route names and runway headings for all routes. when the program is started
getWayPoints() Loads latitude, longitude and height of each waypoint in the new route then computes inbound & outbound radials plus the latitude & longitude of the centre of each waypoint's turning circle. when the program is started and whenever a new route is selected
Advance() Advances the aircraft along its route by the amount it would travel during a refresh-rate period of 1000, 200 or 40 milliseconds. every refresh rate cycle
updateMap() Updates the flight data and map showing the new position of the current waypoint and all other waypoints and geographic features within map range. every refresh rate cycle

The remainder of this document is devoted to the 6 navigation functions shown in the above table.

Position, Distance & Bearing

Two items vital to this navigation program are the Vincenty position, distance and bearing functions VSGDP() and VSGIP(). Respectively, they compute:

  1. the position [latitude and longitude] of a waypoint, given the position [latitude and longitude] of the aircraft, plus the distance and bearing of the waypoint from the point of view of the aircraft, and

  2. the distance between a waypoint and the aircraft, plus the bearing of the waypoint from the point of view of the aircraft and the bearing of the aircraft from the point of view of the waypoint, given the positions [latitudes and longitudes] of the aircraft and the waypoint.

Note that the bearing of the waypoint from the point of view of the aircraft and the bearing of the aircraft from the point of view of the waypoint [in item 2. above] are two separately calculated angles. In the spherical geometry of the Earth's surface, one is not simply the reverse of the other. The bearing of the aircraft from the waypoint is not simply the bearing of the waypoint from the aircraft + 180°.

Formally, the first computation is known as the Solution to the Geodetic Direct Problem and the second is known as the Solution to the Geodetic Inverse Problem. The algorithmic solutions used in this program are those formulated by Thaddeus Vincenty in 1975. The direct VSGDP() and inverse VSGIP() functions used in this program are my transcodings into 'C' of FORTRAN versions by Lcdr. L. Pfeifer of NGS Rockville MD dated 20 February 1975. I have changed some of the names of the variables to conform more to the nomenclatures in the rest of the program.

The Vincenty functions use an ellipsoidal geodetic model of the planet. Notwith­standing, the Earth is not perfectly ellipsoidal. It is more pear-shaped, with the neck of the pear at the North Pole and the flattened bottom of the pear at the South Pole. Consequently, an ellipsoid that fits the earth's surface faithfully over one part of the globe isn't equally accurate in other parts of the globe. To resolve this prob­lem various people and institutions at various times have constructed ellipsoidal models that fit their respective parts of the globe more accurately. Hence, this program has a Geoid Selection menu so that the user can select the geoid most appropriate to the part of the globe over which the current flight is passing. The program default is for the geodetic ellipsoid to be selected automatically according to the current position of the aircraft. However, as currently implemented, this is as yet not very comprehensive.

There are many sources on the Web giving detailed treatments of the methodology, geometry and computations involved in the Vincenty solutions.

Loading Route Names

When the program is started, the getRoutes() function loads the file 'routes.txt'. This contains the names of all the available routes plus the take-off runway heading at the origin and landing runway heading at the destination for each route. The format of the data within each line of the file 'routes.txt' is illustrated by the follow­ing example:

224 161 Stansted to Belo Horizonte

The two 3-digit numbers at the beginning of the line are respectively the runway headings [in degrees] of the origin and destination airports. The remainder of the line is the name of the route, which comprises the names of the origin and dest­ination airports.

Once it has loaded 'routes.txt', the program loads the waypoints data pertaining to the default route.

Loading Waypoint Data

Route loading and initialisation is performed by the function getWayPoints(). The name of a waypoints data file comprises the word "route" followed by a 2-digit number [with leading zero if necessary] followed by the file name extension '.txt'. Route numbers start at '00'. Thus the name of the first waypoints data file is 'route00.txt'. The format of each line of a waypoints data file is illustrated by the following example:

* 186780     780  106 Stansted

If the initial character is an asterisk '*', the data line pertains to a waypoint within the route. If the initial character is a space, the item is simply a passive geographic feature, which will appear on the map as an additional visual reference. All way­points must appear in route order from the beginning of the file. All passive geo­graphic features must be added after the destination waypoint.

The 7 characters immediately following the asterisk [or space] specify the latitude of the waypoint. The next 8 characters specify the waypoint's longitude. Latitude and longitude are expressed in integral seconds of arc. The figures are preceded immediately by minus signs where necessary. The remainder of the field is padded, if necessary, with leading spaces: not zeros. The next 5 characters are the way­point's elevation above sea level in metres [positive only]. The height field is also padded with leading spaces: not zeros. The remainder of the line, after the space, comprises the name of the waypoint, terminated with a 'new line' character.

Upon input, the latitude and longitude are converted to double-precision floating point values expressed in radians. They are stored, along with the other items of waypoint data, in an array of geographic feature and waypoint data structures.

Initialising a Route

Route initialisation is also done by getWayPoints(). For each waypoint in the route, the bearing to the previous waypoint [the inbound radial] and the bearing to the next waypoint [the outbound radial] are then computed and stored. Of course, the first waypoint of a route has no inbound radial. Its take-off runway heading is an extension of what would otherwise be its inbound radial. Similarly, the destination waypoint has no outbound radial. Its landing runway heading is its outbound radial.

Geometry showing to how inbound and outbound radials are calculated when setting up a new air route. The geometry of the turning arc for each en-route waypoint is then constructed as shown in the adjacent diagram. This involves com­puting the latitude & longitude of the centre of the turning circle, from its distance and bearing from the waypoint, using the Vin­centy Direct function: VSGDP(). From this is com­puted the distance from the waypoint where the turning arc begins and ends, i.e. where the waypoint's inbound and outbound radials touch the turning circle tangentially. The latitude & longitude of the centre of the turning arc, plus the distance of the start of the turn from the waypoint along each rad­ial, are stored as part of the waypoint's data for use later by the in-flight computations. Scan for [REF:TURNCTR] in 'nav.c'.

In-Flight Computations

The core of this program is the Advance() function. This advances the aircraft along its route by the amount it would travel during each refresh-rate period. The Advance() function performs the following tasks in the sequence shown:

  1. Manage changeovers from the aircraft's encounter with its current waypoint to its encounter with the next waypoint en-route.

  2. When receiving live inputs of real-world latitude & longitude of the aircraft via 'stdin', compute the positional error due to real-world wind drift and the consequential required correction to the aircraft's thrust heading.

  3. Compute the distance and bearing of the current waypoint from the aircraft and update the TO/FROM status as necessary.

  4. Compute the aircraft's new required heading according to whether the air­craft is travelling TO or FROM the current waypoint, is making a turn AT the current waypoint, or is flying trans-oceanic, beyond the 'radio range' of the current waypoint. Damp the rate of change of the computed required head­ing of the aircraft to create a smoothly incrementing/decrementing comm­and heading.

  5. Compute the aircraft's required air speed as a biased and capped non-linear function of its distance from its current waypoint, starting and finishing the journey smoothly at take-off and landing speed. Damp the rate of change of the computed required speed of the aircraft to create a smoothly increment­ing/decrementing command speed.

  6. Compute the anticipated distances the aircraft travelled (1) due to engine thrust and (2) due to wind drift, and from this derive the resulting new anti­cipated latitude & longitude of the aircraft after this pass of the program.

  7. Compute the change in the required height of the aircraft during this pass of the program, according to a sigmoidal profile of the height difference be­tween the current and next waypoints [the FROM situation] or previous and current waypoints [the TO situation]. Damp the rate of change of the com­puted required height of the aircraft to create a smoothly incrementing or decrementing command height.

  8. When output mode is active, send live heading, speed & height commands to 'stdout'.

1. Waypoint Encounters

A flight, from an origin to a destination, comprises a series of encounters, in pre­scribed order, with the waypoints that make up the route being flown.

NOTE: the sample routes accompanying this program use cities as way­points. Real air routes don't do this: they use radio aids stations or sign­ificant geographic features. Cities are used here for ease of perception because people do not generally know the locations of radio-navigation stations.

Waypoint Encounter Geometry A waypoint encounter comprises three phases: a 'TO' phase, a 'TURN' phase and a 'FROM' phase. The exam­ple on the left shows the aircraft's encounter with the Montreal waypoint. The previous waypoint in the route is Hawkesbury. The next waypoint is Sorel-Tracy. The 'TO' phase of the Montreal encounter is from the half-way point between Hawkesbury and Montreal up to the point where the inbound radial touches the Montreal turning arc. The 'FROM' phase is from where the out­bound radial touches the Montreal turning arc to the half-way point between Montreal and Sorel-Tracy.

The turning arc is a part of what is termed the 'turning circle'. The turning circle for all waypoints has a radius of 10,000 metres. It is located such that the inbound radial from the previous waypoint and the outbound radial to the next waypoint form tangents to it. During the 'TO' and 'FROM' phases of the encounter, the point of reference for the aircraft is the waypoint itself. However, during the 'TURN' phase, the aircraft's point of reference is switched to the centre of the turning circle. This is to avoid possible rogue values of distance and bearing as the aircraft passes very close to the waypoint.

At the start of a flight, the aircraft's encounter is with the initial waypoint [the origin airport]. The initialisation of this first encounter is done when the route's waypoints data are loaded and initialised or when a flight is RESET to the beginning. It is also done every time the aircraft, during a flight, passes the halfway point between two consecutive waypoints of the route. This task is performed in all these cases by the function initEncounter(). The first task of the Advance() function [item 1. above] is to call this function every time the aircraft passes the halfway point to the next en-route waypoint.

2. Heading Compensation for Wind

Geometry to compute the wind speed and bearing by comparing where the aircraft is with where it was predicted to be. If this program is receiving the actual latitudes and longitudes of the aircraft as provided by sources such as GPS, inertial platform or ground-based radio aids, it uses the Vincenty Inverse function to get the distance and bearing of the real position of the aircraft from the point of view of where it was predicted to be from the previous calculation. It is assumed that this error is due to displacement of the aircraft by the wind. The corrected distance blown by the wind since the previous calculation is therefore: D = sqrt(X * X + Y * Y) as shown in the adjacent diagram. Scan for [REF:WIND] in 'nav.c'.

If the program is not receiving live positional data, the aircraft's latitude & longitude previously com­puted are used instead of the live input val­ues. In this case, if simulated wind is switched on, the radial intercept functions bias the aircraft's head­ing automatically to compensate for the wind.

Geometry to compute the heading offset command required to compensate for the aircraft's displacement due to the wind. From this positional error, the program then com­putes the heading offset, that must be added to the aircraft's command heading, in order to com­pensate for this positional error. The vector geom­etry for this computation is shown in the adjacent diagram. Note that the diagram shows the case for the positive/positive quadrant only. However, the atan2() function used in the program takes care of all the +/- sign conditions for the 4 quad­rants. The Advance() function then uses the rece­ived values of aircraft latitude and longitude to compute the required heading, command heading, speed and anticipated latitude and longitude to be used in the next pass of the program.

Note that, even if it is switched on, simulated wind is ignored if the program is receiving live latitude and longitude input.

3. Distance & Bearing and TO/FROM Status

The pivotal task in navigating the aircraft along its route is to compute the current distance [WptDst] between the aircraft and the waypoint it is currently referencing. Before it does this, however, the program notes and preserves the old distance [PreDst] computed during its previous pass.

Geometry of the distance and bearing computation. The program then calls the Vincenty Inverse fun­ction [VSGIP()] to get the new distance [WptDst] and the forward and back bearings [FwdBrg and BakBrg]. As shown in the adjacent diagram, North at the aircraft is not the same direction as North at the waypoint, except where both are on the Equa­tor. In the northern hemisphere the two North lines [lines of longitude] converge; whereas in the sou­th­ern hemisphere they diverge. Consequently, the back bearing is not simply the forward bearing minus π/2 [180°]. Neither is the calculation a simple matter of spherical geometry: it requires an iterative convergence on an ellipsoidal geoid.

The newly computed distance between the aircraft and the waypoint are then compared. If the new distance is less than last time's distance, the aircraft is flying TO the waypoint: if the new distance is greater than the old distance, the aircraft is flying away FROM the waypoint. The program's 'TO' flag is set accordingly.

4. Compute Required Heading

Scan for [REF:TO/FROM] in 'nav.c'.

The 'TO' phase of a waypoint encounter. The 'TO' phase of the program computes the re­quired heading [ReqHdg] which the aircraft must fly in order to remain on — or make an asympto­tic approach to — the waypoint's INbound radial. The '0.49' in the formula at the top of the dia­gram is to ensure that the computed required heading is always less than π/2 [90°] from the inbound radial; i.e. the aircraft is always directed TOwards the waypoint; never away from it.

The 'FROM' phase of a waypoint encounter. The 'FROM' phase of the program computes the requ­ired heading [ReqHdg] which the aircraft must fly in order to remain on — or make an asympto­tic appro­ach to — the waypoint's OUTbound radial. The formula for the FROM phase is quite different, being based on a non-linear heading correction factor to compensate for the inevitable decrease in accuracy with increasing distance from the waypoint.

The TURN phase of a waypoint encounter, where the aircraft is outside the turning circle. During the TURN phase, the idea is for the aircraft to follow the turning arc. If the aircraft is outside the turning arc, it is directed along the tangent to the arc that lies in the direction of the outbound radial. During this phase, the point of reference for the aircraft is the centre of the turning arc: not the waypoint itself. This means that the aircraft's point of reference is always about 10 km away, so dist­ance and bearing measurements are always reli­able, being free from the wild variations that can occur at close proximity.

Scan for [REF:TURN] in 'nav.c'.

The TURN phase of a waypoint encounter, where the aircraft is inside the turning circle. Under certain conditions, such as high winds, the aircraft can find itself inside the turning arc. In this case, the aircraft is directed along a heading at right-angles to the turning circle radius on which the aircraft currently lies. The required heading [ReqHdg] is simply the bearing of the centre of the turning circle [the aircraft's reference point] from the aircraft − π/2 [90°].

Note that the latitude and longitude of the centre of the turning arc are calculated for each of the waypoints in a route at route initialisation time in the program. Scan for [REF:TURNCTR] in 'nav.c'.

When the aircraft is beyond radio range of its current waypoint [assuming the way­point is an active radio aid such as a VOR/DME station], it resorts to what I term 'trans-oceanic' mode. The aircraft obtains its current position [latitude/Longitude] from a universally available source such as satellite-based global positioning sys­tems [GPS, GLONASS, BeiDou, Galileo], an on-board inertial gyroscopic platform or a LORAN-style long-range hyperbolic radio-location system. Future systems could use natural phenomena such as pulsar signals, which would have the advantage of not being reliant upon sovereign or proprietary artificial infrastructures.

The trans-oceanic mode requires two waypoints. In the FROM case, where the air­craft is receding from its CURRENT waypoint, the second reference is the NEXT waypoint in the route. In the TO case, where the aircraft is approaching its CUR­RENT waypoint, the second reference is the PREVious waypoint. Scan for [REF:OCEANIC] in 'nav.c'.

The 'FROM' phase of a transoceanic waypoint encounter. In the trans-oceanic FROM case, whenever the air­craft finds itself displaced laterally from the great circle that joins the current and next waypoints, it is steered such as to make an asymptotic appro­ach back towards the great-circle. For this pur­pose, it is given a required heading according to the formula derived within the adjacent diagram. This uses the known bearings of each of the two waypoint from the point of view of the aircraft.

The 'TO' phase of a transoceanic waypoint encounter. The trans-oceanic TO case is the same, in principle as the FROM case. However, the formula appears somewhat different because the variables, from which the two bearings are obtained, need to be computed in the reversed sense. The formulae in both cases are safe for any displacement on the globe. An extreme displacement, however, could cause the aircraft to back-track in order to re-join the correct great-circle path.

A complete air route thus comprises a series of straight lines between waypoints [which are, in fact terrestrial great circles] joined together by the turning arcs [which are circular sections] at the waypoints themselves.

Notwithstanding, this is not the track really followed by the aircraft. This is because there are two second order discontinuities in the path. One is where the inbound radial joins the turning circle. The other is where the turning circle joins the out­bound radial. A real object with real inertia, like an aircraft, cannot be travelling a straight path and then instantaneously switch to follow a circular path. Its inertia will constrain it at best to do the following:

  1. When joining the turning arc from the inbound radial, the aircraft cannot avoid overshooting the turning arc while it is in the process of changing from a straight path to a curved path. It will, ideally, follow a spiralated asymptotic tangent to the turning arc.

  2. When joining the outbound radial from the turning arc, the aircraft cannot avoid undershooting the outbound radial while it is in the process of changing from a curved path to a straight path. It will, ideally, follow a sigmoidated asymptotic tangent to the outbound radial.

So why, in the interests of purity, did I not opt to construct the inter-waypoint paths as hyperbolic attractors? The answer is that neither hyperbolas nor any other conic section or combinations of conic sections fit the bill. For a start, unless all pairs of consecutive waypoints in a route are equidistant, the hyperbolic sections will be asymmetrical. That in itself would create a point of second order discontinuity at the point of closest approach to each waypoint. Secondly, if a left turn is followed by a right turn or vice versa, the hyperbolic sections would not meet at the half-way point between consecutive waypoints. They would be off-set sideways.

Notwithstanding, the imaginable smooth trajectory of a route of waypoints does exist in reality. For example, if we imagine the aircraft to be an electron projected on a path that causes it to have close encounters with a sequence of 'protonic' waypoints, it should, as a result of the repulsive electrical force, follow this imagin­able smooth trajectory. But the 'world line' that the electron would follow is not hyperbolic. Nor is it any derivable combination of hyperbolas, parabolas or ellipses — nor even precessing relativistic rosettes. We have encountered what is tradi­tionally known as the Three-Body Problem. Where three or more bodies are in­volved in a system of attractive or repulsive force fields, the world-lines followed by the bodies are smooth and continuous; but mathematically underivable. They can be computed only by fine-grained iterative means, as done in this program.

Mathematics — specifically, in this case, algebraic geometry — is an artificial lang­uage by means of which we try, as best we can, to express our rudimentary under­standing of how nature works. But our mathematics is definitely NOT the way nature actually does it. Nature works according to its own very different rules. It is becoming increasingly apparent that these rules operate at a very fine grain and that they are generally focused one time derivative higher than we think mathe­matically.

An example showing that our mathematics is not the way nature does things is in this very program. It is embedded in the program's most fundamental function: the Vincenty algorithm for computing distance and bearing. This works fine everywhere except near the North and South poles. There it goes haywire. Notwithstanding, the space around the poles is, in reality, no different from the space anywhere else on the planet. If we were to shift the polar origin of our coordinate system of latitude and longitude to Paris and its antipode, then trajectories across the Arctic Sea or central Antarctica would be completely free from navigational anomalies. Thus, it is our mathematics that is the problem: not the fundamental nature of a spherical [or more strictly ellipsoidal] surface.

Consequently, there is nothing impure about taking the systemically pragmatic op­tion of using straight lines and turning arcs as the aircraft's 'world line' through its route of waypoints. Making a simple 'best fit' and then applying error correction is the best option. In fact, this intuitively appears to be much closer to the way nature fundamentally operates.

6. Distance Travelled & Updated Position

The anticipated distance the aircraft travels during the current pass of the program is the newly computed command speed [CmdSpd] multiplied by the elapsed time [ET] since the last time through. The anticipated distance the aircraft is blown by the wind during the current pass of the program is the wind speed [WndSpd] multi­plied by the elapsed time [ET] since the last time through. The wind speed may be as computed from live inputs of the aircraft's latitude and longitude, or an intern­ally simulated wind, according to whether live input is switched on or off.

Geometry of aircraft position update routine. In the adjacent diagram, A is the position [latitude and longitude] of the aircraft at the end of the previous pass of the program. B is the new posi­tion the aircraft would have exclusively due to engine thrust. C is the new position of the aircraft when the effect of wind is added vectorially to the effect of engine thrust. The unannotated red line is the track followed by the aircraft as a result of the combined effects of engine thrust and wind. 'dLat' and 'dLng' are North and East components of the aircraft's displacement since the previous pass of the program. 'dLng' is multiplied by cos(AirLat) be­cause longitudinal degrees represent that much shorter real distances than latitudinal degrees.

dLat and dLng are then respectively added to the previous latitude and longitude of the aircraft to get the new latitude and longitude of the aircraft.

7. Compute Required Height & Height Command

Sigmoid function for aircraft height control. Scan for [REF:HEIGHT] in 'nav.c'. For the aircraft's passage between each pair of way­points of the route, the Advance() function creates a sigmoidal path in the vertical plane beginning and ending respectively at points 100 metres above each of the 2 waypoints. This it does by referring to the standard bipolar sig­moid function shown on the left and then rescaling the height difference between the 2 waypoints and the distance between them. As shown, the function is for when the waypoint from which the aircraft is re­ceding is lower than the waypoint it is approaching. For the converse case the sign of 'y' is reversed.

The Advance() function then attempts to move the aircraft, in the vertical plane, from its actual height, to merge asymptotically onto the height command sigmoid. This it does according to a simple iterative difference function. The aircraft height shown on the program window is the command height to which the aircraft's auto­pilot or flight director must aspire.

This height control method lends itself well to stealth flight. Stealth flying, however, would require many more waypoints. In fact, every significant bump and pimple of the flight-track's terrain would have to be included in a route's sequence of way­points. How low you can fly would be determined solely by how finely the route is waypointed. For covert stealth flights, the flight track's terrain profile would have to be carefully surveyed [probably from satellite photographs and radar imagery] and finely waypointed for every anticipated route in whatever part of the world.

The advantage of a finely graded waypoint route is that it can be flown silently. That is, it can be flown blind without having to use any active sensing devices such as ultrasonic or electromagnetic radar. Thus it can be flown in the dark without advert­ising the aircraft's presence to its surroundings.

Of course, obstacles to low flight may come and go. They can be temporary. In an adversarial situation, obstacles could be such things as strong nets spanning a valley. On-board sensory capability is therefore ultimately necessary. The first and most passive kind could be pitot pressure change sensors. Next could be visual or night-vision devices where the ambient conditions supply adequate illumination. But passive devices may have to trigger short bursts of active sensor activity where necessary. To minimise the risk of detection, these bursts would have to be kept as short as possible.

Aircraft Data & Map Display

The aircraft's position and data are updated by each pass of Advance() throughout a flight. This occurs every second, 200 milliseconds or 40 milliseconds according to the item selected in the Refresh Rate menu. Consequently, the visual display of the aircraft's flight data and map position must be re-displayed. This re-displaying is done by the function updateMap(). A call to updateMap() is the final action done by Advance(). However, updateMap() is also called after the default route has been in­itialised after the program is first started and also every time a new route is selec­ted or a flight is reset.

The first action of updateMap() is to actualise the flight data figures on the left of the window. It then proceeds to update the map display. To do this, it scans through all the geographic features [including waypoints] in the currently selected route. For each geographic feature, it calls the Vincenty Inverse function to obtain its dist­ance from the aircraft. The aircraft is always at the map centre. If the feature is with­in visible map range, it is shortlisted for display. Each geographic feature on the shortlist is then drawn and named in its appropriate position on the map.

Please note that in this C version of the program, unlike the Java version, non-English place names cannot contain accented letters. It is possible to include the extended font libraries but they were excluded to save space.

Once all the in-range geographic features have been drawn and named, the in­bound and outbound radials plus the turning circle arc are drawn for the particular waypoint that is currently being referenced by the aircraft.

Geometry of the programming that chops off the parts of radial lines that
would otherwise protrude beyond the map area. The C version of the program is so fast that it is not necessary to buffer the map graphics. How­ever, the absence of graphics buffering makes it necessary to chop off any drawn object that would otherwise violate the boundary of the map area. The only offenders in this regard are the inbound and outbound radials of the current waypoint. The geometry for chopping these radials short of the map boundary is shown in the adjacent diagram. The chopping must be done separately for each of the inbound and outbound radials. Although the geometry is fairly simple, the coding required to implement it is unintuitively long.

Do a word scan for [REF:CHOP1] and [REF:CHOP2] in 'nav.c'.

If the aircraft is currently out of radio range of its referenced waypoint, it is navig­ating in trans-oceanic mode. For this, instead of the inbound and outbound radials plus turning arc, the display shows a pair of yellow guide bars that point respect­ively towards the next and previous waypoints between which the aircraft is flying.

Finally, the cross-hairs at the centre of the map [representing the position of the aircraft] and the little compass at the bottom right of the map area are displayed.

Note that the sequence in which the components of the map are displayed ensures that they are layered on the map area in the correct order: the geographic features being the bottom layer over which are displayed the radials and turning arc [or trans-oceanic guide bars] over which are displayed the cross-hairs and compass.

Additional Routes

You can create a new 'routeNN.txt' file for any route you wish. However, in the cur­rent state of the program, the routes menu will only accommodate up to 7 routes. Notwithstanding, these can be any 7 routes, so long as their data resides respect­ively in files 'route00.txt' to 'route06.txt'. You could maintain a large number of route files, under appropriate names, in a separate directory. Then you could copy any 7 of them into the 'nav' directory and then rename them 'route00.txt' to 'route06.txt'. Perhaps, at some future date, I will add code to make the routes menu scrollable using the mouse wheel. This would allow an unlimited number of routes to be accommodated.

© March 2020 Robert John Morton