draftply Download

QTH Locator Distance & Bearing

← All samples

qth-locator.dplyEditor
1---
2app_version: 0.7.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# 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 — written out
30// per letter (not as a reusable function) so this sample stays free.
31c1_0 = c1[0] - 32 * (c1[0] >= 97)
32c1_1 = c1[1] - 32 * (c1[1] >= 97)
33c1_4 = c1[4] - 32 * (c1[4] >= 97)
34c1_5 = c1[5] - 32 * (c1[5] >= 97)
35c2_0 = c2[0] - 32 * (c2[0] >= 97)
36c2_1 = c2[1] - 32 * (c2[1] >= 97)
37c2_4 = c2[4] - 32 * (c2[4] >= 97)
38c2_5 = c2[5] - 32 * (c2[5] >= 97)
39
40// field (20°/10° per letter) + square (2°/1° per digit) + subsquare
41// (2/24° / 1/24° per letter), then half a subsquare to land in its centre.
42// Written in degrees, the angles keep their unit — sin and cos below take
43// them as they are, no conversion to radians.
44lon1 = (c1_0 - A) * 20° - 180° + (c1[2] - N0) * 2° + (c1_4 - A) * 1°/12 + 1°/24
45lat1 = (c1_1 - A) * 10° - 90° + (c1[3] - N0) * 1° + (c1_5 - A) * 1°/24 + 1°/48
46lon2 = (c2_0 - A) * 20° - 180° + (c2[2] - N0) * 2° + (c2_4 - A) * 1°/12 + 1°/24
47lat2 = (c2_1 - A) * 10° - 90° + (c2[3] - N0) * 1° + (c2_5 - A) * 1°/24 + 1°/48
48
49"Your latitude (N)": lat1
50"Your longitude (E)": lon1
51"DX latitude (N)": lat2
52"DX longitude (E)": lon2
53
54# Great-circle distance (haversine)
55R = 6371 km // mean Earth radius
56
57dlat = lat2 - lat1
58dlon = lon2 - lon1
59
60a = sin(dlat / 2)^2 + cos(lat1) * cos(lat2) * sin(dlon / 2)^2
61distance = 2 * R * atan2(sqrt(a), sqrt(1 - a))
62distance_mi = distance in mi
63
64# Beam headings
65// Initial bearing from station 1 to station 2, and the way back.
66// atan2 answers in radians; `in deg` turns that into degrees.
67y1 = sin(dlon) * cos(lat2)
68x1 = cos(lat1) * sin(lat2) - sin(lat1) * cos(lat2) * cos(dlon)
69bearing = mod((atan2(y1, x1) in deg) + 360°, 360°)
70
71y2 = sin(-dlon) * cos(lat1)
72x2 = cos(lat2) * sin(lat1) - sin(lat2) * cos(lat1) * cos(dlon)
73bearing_back = mod((atan2(y2, x2) in deg) + 360°, 360°)
74
75# Results
76"Distance": distance
77"Distance (miles)": distance_mi
78"Beam heading, you → DX": bearing
79"Return heading, DX → you": bearing_back
80
81// Long path: the other way round the globe.
82"Long-path heading": mod(bearing + 180°, 360°)
83"Long-path distance": 2pi * R - distance
84