QTH Locator Distance & Bearing

← All samples

qth-locator.dply
1---
2version: 0.1.0
3precision: 3
4form_title: QTH Locator Distance & Bearing
5form_description: Great-circle distance and beam heading between two Maidenhead locators. Enter six-character locators like JN48HU — upper or lower case both work.
6form_inputs: Your locator|loc1, DX locator|loc2
7form_outputs: Distance (km)|distance, Distance (mi)|distance_mi, Beam heading (°)|bearing, Return heading (°)|bearing_back, Your latitude (°)|lat1, Your longitude (°)|lon1
8---
9# draftply — QTH Locator Distance & Bearing
10# Where do I point the antenna, and how far is it?
11#
12# A Maidenhead locator nests three levels: field (18×18 letters A–R),
13# square (10×10 digits) and subsquare (24×24 letters A–X). Note the 24 —
14# a subsquare is 5' of longitude and 2.5' of latitude, NOT a sixtieth.
15
16# ── The two stations ───────────────────────────
17loc1 = "JN48HU" # your QTH
18loc2 = "FN42FB" # the DX station
19
20# ── Decoding ───────────────────────────────────
21# ord() turns text into its character codes, so a locator becomes a list
22# of six numbers that we can do arithmetic on.
23A = ord("A")
24N0 = ord("0")
25c1 = ord(loc1)
26c2 = ord(loc2)
27
28# Locators are often written with lower-case subsquares (JN48hu).
29# Subtracting 32 for codes ≥ 97 folds those back to upper case.
30up(x) = x - 32 * (x >= 97)
31
32# field (20°/10° per letter) + square (2°/1° per digit) + subsquare
33# (2/24° / 1/24° per letter), then half a subsquare to land in its centre.
34lon1 = (up(c1[0]) - A) * 20 - 180 + (c1[2] - N0) * 2 + (up(c1[4]) - A) / 12 + 1 / 24
35lat1 = (up(c1[1]) - A) * 10 - 90 + (c1[3] - N0) * 1 + (up(c1[5]) - A) / 24 + 1 / 48
36lon2 = (up(c2[0]) - A) * 20 - 180 + (c2[2] - N0) * 2 + (up(c2[4]) - A) / 12 + 1 / 24
37lat2 = (up(c2[1]) - A) * 10 - 90 + (c2[3] - N0) * 1 + (up(c2[5]) - A) / 24 + 1 / 48
38
39"Your latitude (°N)": lat1
40"Your longitude (°E)": lon1
41"DX latitude (°N)": lat2
42"DX longitude (°E)": lon2
43
44# ── Great-circle distance (haversine) ──────────
45R = 6371 km # mean Earth radius
46
47phi1 = lat1 * pi / 180
48phi2 = lat2 * pi / 180
49dphi = (lat2 - lat1) * pi / 180
50dlam = (lon2 - lon1) * pi / 180
51
52a = sin(dphi / 2)^2 + cos(phi1) * cos(phi2) * sin(dlam / 2)^2
53distance = 2 * R * atan2(sqrt(a), sqrt(1 - a))
54distance_mi = distance * 0.621371
55
56# ── Beam headings ──────────────────────────────
57# Initial bearing from station 1 to station 2, and the way back.
58y1 = sin(dlam) * cos(phi2)
59x1 = cos(phi1) * sin(phi2) - sin(phi1) * cos(phi2) * cos(dlam)
60bearing = mod(atan2(y1, x1) * 180 / pi + 360, 360)
61
62y2 = sin(-dlam) * cos(phi1)
63x2 = cos(phi2) * sin(phi1) - sin(phi2) * cos(phi1) * cos(dlam)
64bearing_back = mod(atan2(y2, x2) * 180 / pi + 360, 360)
65
66# ── Results ────────────────────────────────────
67"Distance": distance
68"Distance (miles)": distance_mi
69"Beam heading, you → DX (°)": bearing
70"Return heading, DX → you (°)": bearing_back
71
72# Long path: the other way round the globe.
73"Long-path heading (°)": mod(bearing + 180, 360)
74"Long-path distance": 2 * pi * R - distance
75