Doorgaan naar hoofdcontent

Maidenhead locator to Degrees and back again

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.

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

Populaire posts van deze blog

Denon DHT T100 DESIGNED TO FAIL : bad caps (ceramic caps this time)

A friend gave me a Denon DHT-T100 to look at.
Do not spend much time on it.. ok.


It had a problem, it started clicking and ticking after power on, and after some time.
(a so called intermittent problem)

Sometimes it did not tick or click, but it was basically not usable.
The clicking had a sharp click in one channel and repeated after about a second, then sound recovered and it would click and drop out again.

He told me, do not spend any time on it, yeah, right. ;-) like I would give up after 15 minutes.
I wanted to know what was going on with this thing, I found some schematic online and started measuring the usual things.

The power supply, 24V did it drop down when a tick occurred ? Difficult to find out because sometimes the thing would play for hours without a glitch.

I eventually found out the 24 V PSU, the step down SMPS on board and the LDO's were all ok, all power rails remained within spec, but it still glitched sometimes. (while power was ok)

I investigated methodically,…

Raspberry Pi, PyFace Digital, the lost documentation, I found it finally

The Raspberry PI or R-pi from http://www.raspberrypi.org/ is well known these days.
It is not an accident that I have one, I have been doing Linux stuff since 1991, and professionally since 1996 I can not skip over these developments, have to keep up with the new kids. :-)
Times have changed, hardware has become very affordable, everybody knows the Arduino, Raspberry Pi and Beagle-Bone-Black (BBB). Not everybody knows the stuff that http://www.acmesystems.it/ aka Acme-Systems and https://github.com/OLIMEX/OLINUXINO aka Olimex make, so I will endorse them here.
Since I am an engineer I expect to connect switches and relays to the boards and some documentation with products, not so with the "PiFace Digital" board, it comes without serious documentation, not a even the schematic. All links on their blog point nowhere. People asked them many times, yet nowhere is the schematic to be found.

I finally found some info after hours of google-work, someone made a copy!
https://github.c…

Nederland van het aardgas af, dat schiet lekker op (NOT!)

Om dingen even in perspectief te plaatsen moet je gewoon even wat berekeningen maken.
We gaan Nederland van het aardgas afhalen (de burgers) omdat?

https://www.ad.nl/wonen/nederland-heeft-nog-lange-weg-te-gaan-gasverbruik-stijgt~aaf1527e/

In USA fakkelen ze 2123763,4944 m3 aardgas af per UUR
(bij winning van olie, gas is ongewenst daar, opslag niet handig, goedkoper om te fakkelen)


1.8 miljard cubic feet per dag...

Ons Nederlandse gasverbruik (huishoudens) is : 1500 m3 per jaar per huishouden

Even rekenen 2.1 miljoen m3 per uur, dat is

24 * 365 * 2.100.000,00 = 18.400.000.000,00 m3 aardgas affakkelen per jaar

(even de rekenmachine pakken)

18.400.000.000 / 1500 => aantal huishoudens Nederland

dat is voor 12.3 miljoen huishoudens (met gasverbruik van 1550 m3/jr)

Naast het opbranden lozen ze ook nog gewoon aardgas direct in de atmosfeer. (genaamd Venting)

Waarom moet ik ook alweer van het aardgas af?

Niet voor het milieu en de toekomst van onze kinderen, daarvoor helpt het helemaal…