http://www.hamradio.in/circuits/grid_locator_system.php
This code will convert a Maidenhead locator to Latitude/Longitude in degrees.
It seems that everyone tries to implement this, but I can not find any clean source code...
So here is my implementation, 2 ways, from lat,long -> maidenhead and reverse...
This is plain "C" code tested on linux, but I will include it on my STM32F4 dev board.
This code will convert a Maidenhead locator to Latitude/Longitude in degrees.
It seems that everyone tries to implement this, but I can not find any clean source code...
So here is my implementation, 2 ways, from lat,long -> maidenhead and reverse...
This is plain "C" code tested on linux, but I will include it on my STM32F4 dev board.
typedef struct { double latitude; double longitude; int errorcode; } lat_lon_t; uint8_t to_upper(char c) { if (c >= 'a' && c <= 'z') { return c - 0x20; } return c; } // the equator and the 0 meridian are the reference // we call them +90 (instead of 0) and +180 (instead of 0) to prevent negative numbers // the world is divided into 18 * 18 fields (324 fields total) // these fields are sub-divided into squares and sub-squares and sub-sub-squares etc forever // but only 5 iterations make sense (size of a house) // and work on http://www.k7fry.com/grid/?qth=JO21TL51XT JO21QM83BI // to divide the world into a 18x18 grid the size of the grid is 20 by 10 degrees // 360 deg / 18 => 20 degrees horizontal (longitude) // 180 deg / 18 => 10 degrees vertical (latitude) // http://www.wikiwand.com/en/Maidenhead_Locator_System lat_lon_t maidenhead_to_latlon(const char *mhl) { lat_lon_t value = {0}; static const double table[] = { /* scaling for maidenhead grid to degrees latitude */ 20.0, 2.0, (1.0 / 12.0), (1.0 / 120.0), (1.0 / 2880.0), (1.0 / 28800.0), (1.0 / 6912000.0), (1.0 / 69120000.0), (1.0 / 165888000.0) }; size_t len = strlen(mhl); if ((len % 2) != 0) { // odd number of chars, invalid value.errorcode = 1; return value; } if (len > (sizeof(table) / sizeof(table[0]) * 2)) { // too long maidenhead string value.errorcode = 2; return value; } // loop iterations int j = 0; double lat_tmp = 0.0f; // result latitude in degrees double lon_tmp = 0.0f; // result longitude in degrees char uc; // grid latitude cell number char ud; // grid longitude cell number for (size_t i = 0; i < len; i += 2) { if (j % 2 == 0) { // A uc = to_upper(*(mhl + i)) - 'A'; ud = to_upper(*(mhl + i + 1)) - 'A'; } else { // 0 uc = *(mhl + i) - '0'; ud = *(mhl + i + 1) - '0'; } lon_tmp += uc * table[j]; lat_tmp += ud * table[j]; j++; } // table was in latitude, fix scale by 2 lat_tmp /= 2.0f; // offset of MH grid to GPS lon_tmp -= 180.0f; lat_tmp -= 90.0f; // prepare return value value.latitude = lat_tmp; value.longitude = lon_tmp; return value; } int lat_lon_to_maidenhead(lat_lon_t location, char *resultbuf, uint8_t iterations) { // convert location to Maidenhead locator string // store into buffer (at least 16 bytes) // return 0 on success double tmp_lat = location.latitude; double tmp_lon = location.longitude; char mhstr_tmp[16] = {0}; // result will be here eg "JO32tl" for 51.465779 N 5.633263 E tmp_lon = (tmp_lon + 180.0f) / 20.0f; // offset from 0 meridian half a rotation, then divide by 20 to make 18 tmp_lat = (tmp_lat + 90.0f) / 10.0f; // offset from equator, then divide by 10 to make 18 uint8_t i = 0; // loop counter char ref; //'A' or 'a' char *ptr = mhstr_tmp; // first position of result string while (i < iterations) { int loni = (int) (tmp_lon); int lati = (int) (tmp_lat); // odd or even iteration if (!(i & 0x01U)) { ref = (i > 1) ? 'a' : 'A'; // lower case after first grid // number to grid 0->'A' or 0->'a' etc *ptr++ = ref + loni; *ptr++ = ref + lati; *ptr = 0; // zoom in on grid tmp_lon = (tmp_lon - loni) * 10.0; tmp_lat = (tmp_lat - lati) * 10.0; } else { // number to grid 0->'0' etc *ptr++ = '0' + loni; *ptr++ = '0' + lati; *ptr = 0; // zoom in on grid tmp_lon = (tmp_lon - loni) * 24.0; tmp_lat = (tmp_lat - lati) * 24.0; } i++; } printf("Lat %f Long %f => Maidenhead : \"%s\" \n", location.latitude, location.longitude, mhstr_tmp); strcpy(resultbuf, mhstr_tmp); return 0; } int main(int argc, char **argv) { const char testval[] = "JO21tl51xs"; lat_lon_t lat_lon = maidenhead_to_latlon(testval); printf("rv=%d\n", lat_lon.errorcode); printf("%s => lat=%G lon=%G\n", testval, lat_lon.latitude, lat_lon.longitude); // lets convert it back to maidenhead char buffer[16] = {0}; if (0 == lat_lon_to_maidenhead(lat_lon, buffer, 5)) printf("Coverted back : %s\n", buffer); else printf("conversion error\n"); exit(0); }
// =========================
$ gcc test.c -o test $ ./test JO21tl51xs => lat=51.4656 lon=5.63299 Lat 51.465625 Long 5.632986 => Maidenhead : "JO21tl51xs" Coverted back : JO21tl51xs This code I wrote (c) 2019 Edwin van den Oetelaar, MIT license.
Reacties