↑ ↓ to move · enter to open

E08 · Physics · Charts, bearings, vectors

navigation at sea

Out of sight of land, a navigator answers three questions with a pencil, a pair of dividers and a compass. How far is it? Where am I? Which way do I steer when the water itself is moving? Distances here are in nautical miles (nmi), exactly 1852 m or , and speeds in knots, one nautical mile per hour or 1.151 mph. Directions are angles clockwise from north, written with three digits and labeled true (T), magnetic (M) or compass (C).

LAB 1

a mile is a minute

Latitude says how far north or south of the equator you are, as an angle measured at Earth's center: 0° at the equator, 90° at a pole. Longitude is the angle east or west of the Greenwich meridian. Each degree splits into 60 minutes, written ′. Walk one minute of latitude due north and you cover about 1852 m, which is where the nautical mile comes from. A minute of longitude is shorter away from the equator, because the meridians close in toward the poles. A Mercator chart stretches the north–south direction by the same amount as east–west at every latitude, so angles on the chart match angles at sea. On it, a rhumb line (one steady compass course) is a straight line, while the shortest route over the globe, a great circle, bends toward the pole.

Mercator chart

How to read this: a Mercator chart of a spherical Earth, zoomed to fit the route. Grid lines are meridians and parallels; the parallels spread apart toward the poles. Drag A or B anywhere and the chart refits when you let go.

  • great circle (shortest)
  • rhumb line (constant course)
  • A, start
  • B, destination
  • equator

Try this: pick San Francisco → Tokyo and compare the two distances, then pick Along 60°N and watch the great circle climb toward the pole.

—

How to read this: top, a close-up chart covering 40′ of latitude. Drag either divider point. The gold bar is the same divider span laid on the latitude scale at the same latitude, which is how a navigator measures distance. The red bar is the same span laid on the longitude scale, which overstates it. Bottom, the length of one minute at every latitude.

  • dividers
  • track being measured
  • span on the latitude scale (right)
  • span on the longitude scale (wrong)
  • 1′ of latitude (ellipsoid)
  • 1′ of longitude
  • 1 nmi = 1852 m

Try this: slide the chart latitude from 0° to 60° and watch the red bar's reading grow to about twice the gold one, as cos 60° = 0.5 predicts.

Spherical Earth with R = 6371 km for all distances (accurate to about 0.5%). The ellipsoid curve uses WGS84 (a = 6,378,137 m, e² = 0.00669438). The dividers' reading uses 1′ of latitude = 1 nmi, the chart convention.
—
A
—
B
—
Great circle distance
—
Rhumb line distance
—
Great circle course
—
Rhumb line course
—
Rhumb line is longer by
—
Great circle's highest latitude

Minutes, Mercator, two routes

1′ of latitude = R·(π/180)/60 = 1853.2 m (sphere, R = 6371 km)
1′ of longitude = cos φ × 1′ of latitude
Mercator: y = ψ(φ) = ln tan(π/4 + φ/2), x = λ
great circle: h = sin²(Δφ/2) + cos φ₁·cos φ₂·sin²(Δλ/2)
d = 2R·asin √h
rhumb: Δψ = ψ₂ − ψ₁, q = Δφ/Δψ
d = R·√(Δφ² + q²·Δλ²), course = atan2(Δλ, Δψ)

φ is latitude and λ longitude, in radians inside the formulas. The great-circle formula is the haversine formula. In the rhumb formula q is the average of cos φ along the track, so q·Δλ is the east–west distance squeezed by the convergence of the meridians; on an east–west course (Δψ = 0) q is just cos φ.

Dividers on the chart

—
Dividers on the latitude scale
—
Rhumb formula, same two points
—
Read on the longitude scale
—
Course between the points
—
1′ of latitude here
—
1′ of longitude here

Why a minute, and why Mercator

A minute of latitude is a fixed slice of a meridian, so on a sphere every minute of latitude has the same length. The real Earth is slightly flattened: on the WGS84 ellipsoid a minute of latitude runs from about 1843 m at the equator to about 1862 m at the poles. The international nautical mile was fixed at exactly 1852 m in 1929, a round value that matches a minute of latitude near 45°.

Mercator's stretch grows as 1/cos φ, exactly the amount a minute of longitude shrinks. That is why a navigator never measures distance on the longitude scale, and why the latitude scale must be read beside the place being measured: at 60° a chart minute is drawn twice as long as at the equator. A great circle looks longer on the chart because the chart exaggerates high latitudes, where it runs. Big-circle routes and the distances between internet cables and cities work the same way; see C03 · How the internet works.

CodePython

import math
R = 6371000 / 1852                  # sphere radius in nautical miles

def haversine_nm(lat1, lon1, lat2, lon2):
    p1, p2 = math.radians(lat1), math.radians(lat2)
    dp, dl = p2 - p1, math.radians(lon2 - lon1)
    h = math.sin(dp/2)**2 + math.cos(p1)*math.cos(p2)*math.sin(dl/2)**2
    return 2*R*math.asin(min(1, math.sqrt(h)))

def gc_course(lat1, lon1, lat2, lon2):   # initial course, degrees true
    p1, p2 = math.radians(lat1), math.radians(lat2)
    dl = math.radians(lon2 - lon1)
    y = math.sin(dl)*math.cos(p2)
    x = math.cos(p1)*math.sin(p2) - math.sin(p1)*math.cos(p2)*math.cos(dl)
    return math.degrees(math.atan2(y, x)) % 360

def psi(lat):                         # Mercator stretched latitude
    return math.log(math.tan(math.pi/4 + math.radians(lat)/2))

def rhumb(lat1, lon1, lat2, lon2):
    dphi = math.radians(lat2 - lat1)
    dpsi = psi(lat2) - psi(lat1)
    dlam = math.radians((lon2 - lon1 + 180) % 360 - 180)   # short way round
    q = dphi/dpsi if abs(dpsi) > 1e-12 else math.cos(math.radians(lat1))
    return R*math.hypot(dphi, q*dlam), math.degrees(math.atan2(dlam, dpsi)) % 360

ny, ldn = (40.71, -74.01), (51.51, -0.13)
print("great circle %.0f nmi, course %03.0f T" % (haversine_nm(*ny, *ldn), gc_course(*ny, *ldn)))
print("rhumb line   %.0f nmi, course %03.0f T" % rhumb(*ny, *ldn))
print("1' of latitude: %.1f m" % (6371000*math.radians(1/60)))
for lat in (0, 30, 50, 60, 70):
    print(lat, "deg: 1' of longitude = %.3f nmi" % (R*math.radians(1/60)*math.cos(math.radians(lat))))
LAB 2

where am I?

Dead reckoning (DR) finds your position from your last known one using only the course you steered, your speed through the water from the log (the boat's speedometer) and the time elapsed: distance = speed × time, laid off along the course. Any error in the compass, the log or an unknown current gets multiplied by time, so a DR position grows less certain every hour. A fix resets the error. Take a compass bearing (the direction from you to a charted landmark) and you know you're somewhere on a line through that landmark, a line of position. Two lines cross at your position. A third line rarely passes through the same point, because each bearing has a few degrees of error, and the small triangle it leaves is the cocked hat.

plot
— —
—
— —
— —

How to read this: north is up. Both tracks start at the same fix. The amber track is what the navigator plots from course, log speed and time; the green track is where the boat really goes with the hidden errors you set. The red ring is the worst case if you know how big each error could be but not which way it points.

  • starting fix
  • DR track, hourly DR positions
  • actual track
  • gap at each hour
  • worst-case circle

Try this: press Strong tide, then Run, and watch the red gap lines grow by the same amount every hour.

—
—

How to read this: north is up; land is the shaded area. Each colored line is a line of position drawn from a landmark along the bearing you measured. The green dot is where the boat really is (drag it); the gold dot is the estimate. Bearing numbers sit at the outer end of each line.

  • lighthouse bearing
  • spire bearing
  • mast bearing
  • cocked hat
  • fix (centroid of the hat)
  • least-squares point
  • true position

Try this: press Run 1,000 fixes and read how often the true position lands inside the cocked hat. Then set the same-error slider to 4° with σ at 0.

Toy chart, flat over its 10 nmi width. Random bearing errors are normal with standard deviation σ, drawn from a seeded generator; each press of New random errors draws a new set.
—
Distance run by log
—
DR position from the fix
—
Actual position from the fix
—
DR error now
—
Error per hour, % of run
—
Worst-case radius

Dead reckoning

DR = start + S·t·(sin C, cos C) (east, north)
actual = start + t·[S(1+e)·(sin(C+δ), cos(C+δ)) + c·(sin σ, cos σ)]
worst case r(t) = S·t·√((1+e)² + 1 − 2(1+e)·cos δ) + c·t

C is the course steered, S the log speed and t the time. δ is the steering or compass error, e the fractional log error, and the current has set σ (the direction it flows toward) and drift c (its speed). Every term in the error grows in proportion to t, so the DR error does too. Plotting the known current as well gives an estimated position (EP).

—
Lighthouse bearing
—
Spire bearing
—
Mast bearing
—
Cocked hat, longest side
—
Fix error (centroid)
—
Least-squares error
—
Smallest angle of cut
—
1,000 fixes: true position inside

Lines of position

bearing to landmark L: B = atan2(xL − x, yL − y)
line of position: p = L − s·(sin B′, cos B′), s ≥ 0
two lines: L₁ − s·u₁ = L₂ − r·u₂ (2 × 2 linear solve)
fix ≈ centroid = (P₁₂ + P₂₃ + P₁₃)/3
least squares: minimize Σ (ni·(p − Li))²

B is the true bearing, B′ the measured one, u the unit vector along it and n the unit vector at right angles to it. Each line runs from the landmark back toward the boat. The least-squares point is the spot with the smallest total squared distance to all the lines.

What the cocked hat can't tell you

A small hat feels reassuring, but with three independent, unbiased bearing errors the true position lies inside the hat only about one time in four. Run 1,000 fixes to see it. The centroid is a sensible middle point and carries no promise. If every bearing carries the same error, say an uncorrected deviation, the lines can make a neat small hat that sits well away from the boat. Navigators pick landmarks whose bearings cross at wide angles (near 90° for two, about 60° apart for three) and, when the hat is large, assume they are at whichever corner is closest to danger.

Bearings in this lab are already corrected to true; lab 3 shows how compass readings get there.

CodePython

import math, random

def unit(b):                     # bearing in degrees -> (east, north)
    return math.sin(math.radians(b)), math.cos(math.radians(b))

def dead_reckon(x, y, course, speed, hours):
    ux, uy = unit(course)
    return x + ux*speed*hours, y + uy*speed*hours

def actual(x, y, course, speed, hours, steer=0, log=0, set_=0, drift=0):
    ux, uy = unit(course + steer); cx, cy = unit(set_)
    s = speed*(1 + log/100)
    return x + (ux*s + cx*drift)*hours, y + (uy*s + cy*drift)*hours

def bearing(p, L):
    return math.degrees(math.atan2(L[0] - p[0], L[1] - p[1])) % 360

def lop_cross(L1, b1, L2, b2):      # where two lines of position meet
    ux, uy = unit(b1); vx, vy = unit(b2)
    dx, dy = L2[0] - L1[0], L2[1] - L1[1]
    det = -ux*vy + vx*uy
    s = (dx*vy - vx*dy)/det
    return L1[0] - s*ux, L1[1] - s*uy

def inside(p, a, b, c):
    cr = lambda o, q, r: (q[0]-o[0])*(r[1]-o[1]) - (q[1]-o[1])*(r[0]-o[0])
    d = [cr(a, b, p), cr(b, c, p), cr(c, a, p)]
    return min(d) >= 0 or max(d) <= 0

print("DR after 5 h:", dead_reckon(0, 0, 60, 6, 5))
print("actual:      ", actual(0, 0, 60, 6, 5, steer=3, log=-5, set_=200, drift=0.8))

marks = [(1.6, 5.75), (5.3, 6.9), (9.8, 3.0)]   # lighthouse, spire, mast (nmi)
boat, hits, n = (4.4, 2.0), 0, 10000
for _ in range(n):
    obs = [bearing(boat, L) + random.gauss(0, 2) for L in marks]
    hat = [lop_cross(marks[i], obs[i], marks[j], obs[j]) for i, j in ((0, 1), (1, 2), (0, 2))]
    hits += inside(boat, *hat)
print("true position inside the hat: %.1f%%" % (100*hits/n))   # about 25%
LAB 3

steering against the current

A boat moves through the water, and the water moves over the ground. Your heading is where the bow points; with your speed through the water it makes the water track. The current has a set (the direction it flows toward) and a drift (its speed). Add the two and you get the ground track: course over ground (COG) and speed over ground (SOG). To reach a mark in a cross current you aim upstream of it and let the current carry you across, which looks like crabbing. Wind adds leeway, a few degrees of sideways slip (see E05 · How sailboats sail upwind). Finally the compass doesn't point at true north, so the course has to be converted before you can steer it.

current triangle
— —
— —
— —

How to read this: top, north is up and the faint amber arrows show the current. The green boat steers the solved course and crabs along the straight gold line; the red boat keeps its bow on the mark and gets swept into a curve. Bottom, the current triangle for one hour of sailing: green plus amber equals gold.

  • ground track (COG, SOG)
  • water track and boat speed
  • current (set, drift)
  • bow always on the mark
  • heading, track wanted
  • leeway angle
  • the mark

Try this: press Run, then press Too strong: once the cross current beats the boat speed, no heading makes good the track.

—
Slider sets
— Deviation card

How to read this: top, true north is straight up. The inner ring is turned by the variation, like the magnetic ring printed inside a chart's compass rose. The white line is the boat's heading; the three numbers at its tip are the same direction measured from the three norths. Bottom, the boat's deviation card: how far its compass is pulled off magnetic north on each heading.

  • true north, true ring
  • magnetic north, magnetic ring
  • compass north, deviation curve
  • heading
  • this heading on the card

Try this: pick the Large card and sweep the heading: the compass reading wanders off magnetic by up to 8° and back as the boat turns.

Idealized: steady, uniform current; boat speed and leeway constant; tacks and turns instant. The deviation cards are toy curves of the standard form A + B sin C + C₂ cos C + D sin 2C + E cos 2C; a real card comes from swinging the boat's compass.
—
Course to steer (heading)
—
Water track
—
Crab angle off the track
—
Speed over ground
—
Time, steering the solution
—
Time, bow on the mark

The current triangle

ground = water + current (vectors, one hour each)
β = set − track, sin α = drift·sin β / V (law of sines)
water track = track − α
SOG = V·cos α + drift·cos β
heading = water track − leeway

V is the boat's speed through the water and α the angle you aim upstream. The sideways part of the current, drift·sin β, has to be cancelled by the sideways part of your own speed, V·sin α. If drift·sin β is bigger than V there is no solution. Leeway (positive when the wind pushes you to starboard) is applied last: turn the bow that many degrees further into the wind.

—
True
—
Variation
—
Magnetic
—
Deviation on this heading
—
Compass
—
Round-trip check

True, magnetic, compass

M = T − Var, C = M − Dev (east positive)
T = C + Dev + Var
Dev depends on the compass heading: C = M − Dev(C), solved by iteration

Variation is the angle between true north and magnetic north where you are. The chart's compass rose prints it, with the year and its yearly change. Deviation is the extra pull of the boat's own iron and electronics on its compass. It changes with the boat's heading, so each boat carries a deviation card.

Write the letters down the page: True, Variation, Magnetic, Deviation, Compass, remembered as "True Virgins Make Dull Companions". Going up from compass to true, add easterly errors and subtract westerly ones. Going down from true to compass, do the opposite. The rhyme "error east, compass least; error west, compass best" says the same thing: with an easterly error the compass reads less than true.

Why aiming at the mark is slower

The boat that keeps its bow on the mark is always pointing at it, so it never aims upstream. The current pushes it sideways all the time, its track curves downstream, and it ends up crossing the last stretch nearly head-on into the current. It sails a longer path at a lower speed over the ground. Working out the course to steer once and holding it gives a straight line. In tidal waters the set and drift change through the day; see E09 · Tides for sailors and W10 · Tides. For how fast a hull can go through the water in the first place, see E06 · Hull speed, and for why the wind's sideways push doesn't tip the boat over, E07 · Why sailboats don't tip over.

CodePython

import math

def unit(b): return math.sin(math.radians(b)), math.cos(math.radians(b))

def course_to_steer(track, speed, set_, drift, leeway=0):
    beta = math.radians(set_ - track)
    s = drift*math.sin(beta)/speed          # law of sines
    if abs(s) >= 1: return None             # cross current too strong
    a = math.asin(s)
    sog = speed*math.cos(a) + drift*math.cos(beta)
    if sog <= 0: return None
    water_track = (track - math.degrees(a)) % 360
    return (water_track - leeway) % 360, water_track, sog

def bow_on_mark(mark, speed, set_, drift, leeway=0, dt=1/720):
    x = y = t = 0.0; cx, cy = unit(set_)
    while math.hypot(mark[0] - x, mark[1] - y) > 0.01 and t < 10:
        h = math.degrees(math.atan2(mark[0] - x, mark[1] - y))
        ux, uy = unit(h + leeway)
        x += (speed*ux + drift*cx)*dt; y += (speed*uy + drift*cy)*dt; t += dt
    return t

def card(C):                            # toy "small" deviation card, east +
    r = math.radians(C)
    return 0.5 + 2*math.sin(r) - math.cos(r) + 0.5*math.sin(2*r)

def true_to_compass(T, var):
    M = (T - var) % 360; C = M
    for _ in range(50): C = (M - card(C)) % 360   # deviation is read at C
    return M, C

def compass_to_true(C, var):             # add easterly going up
    M = (C + card(C)) % 360
    return M, (M + var) % 360

h, wt, sog = course_to_steer(45, 5, 150, 2)
mark = (8*math.sin(math.radians(45)), 8*math.cos(math.radians(45)))
print("steer %03.0f T, SOG %.2f kn, %.0f min" % (h, sog, 8/sog*60))
print("bow on the mark: %.0f min" % (bow_on_mark(mark, 5, 150, 2)*60))
M, C = true_to_compass(h, -4)          # variation 4 degrees W
print("M %05.1f  C %05.1f  back to T %05.1f" % (M, C, compass_to_true(C, -4)[1]))