Gateway Location Drift: Raspberry Pi3 + IC880a + GPS PPS

I have several gateways successfully running with GPS and PPS. I would like to use the GPS PPS time reference, but do not want to use the GPS gateway position. The position reported in the packet metadata is constantly moving and one occasion caused TTN Mapper to delete historic mapping data for the gateway. For this reason I would like the gateways to report their position as the values entered in the global_conf.json or the TTN Console Gateway Location settings.

My set-up is:

My global_conf.json contains:
"gateway_conf": { "fake_gps": false, "gps": true, }

I have tried changing global_conf settings:

  • fake_gps: false, gps: false > the journal reports ‘GPS IS DISABLED!’ There are no messages about time keeping
  • fake_gps: true, gps: true > The journal reports ‘No time keeping possible due to fake gps’

Please can you advise if I can fix my location while using GPS PPS as a time reference?

This is my first ever post to a forum so please be gentle.

I’m not sure if that is a supported capability but the C code of the packet forwarder is fairly easy to modify to make it send whatever you want.

GPS drift should not be that severe. You should try to use a better GPS antenna and try to find a better location (for the antenna).

Thanks for responding.
These gateways have active GPS antennas with short cable lengths and are mounted on a bracket on roof top antenna poles. The GPS drift is typically in the range of 2-10 meters but on one occasion, one gateway’s reported position moved by approx 40km for no apparent reason. TTN mapper deletes historic data when a gateway position moved 100m or more to ensure that the map is a map of current coverage. There was a storm at the time which may have contributed, it may have been someone using a GPS jammer, or perhaps RF noise, either way I would like to avoid this happening again.

Prior to this incident, a friend asked me to investigate fixing gateway position for a project that he is attempting with students using geolocation using TDOA from known, local gateways with accurate GPS time reference. Even normal GPS drift introduces unnecessary error into the calculation.

Thanks again.

This is indeed a problem for which the common solution is to not use a GPS and rather set the gateway location on the TTN Console. On the most gateway, especially DIY ones, having a GPS for time stamping is unnecessary as the accuracy of the time stamping is anyway too low for trilateration.

For research purposes I do however see the point of adding a GPS to test how inaccurate the trilateration is. In this case one can either not use TTN Mapper to show the coverage, or we can make an exception to hardcode the gateway locations on TTN Mapper’s side. This will allow both the coverage to be shown as well as the PPS to be used for timestamping. The problem with this method is however that when the gateway is moved the move is not detected by TTN Mapper and old invalid coverage data is shown.

The third option that has already been mentioned is to modify the packet forwarder to still use the PPS signal, but not use the latitude and longitude from the GPS.

1 Like

The pakket forwarder does not use the PPS signal, it is just used by the hardware for time stamping. So it should be possible to set the gateway to not supply GPS coordinates and just enter them at the TTN console.


@kersing Thank you for your work on this code and responding to my post. For the moment I will use brute force and hack cp_gps_coord = reference_coord; in stats.c. Am I correct in assuming from your
comment that if I omit the gateway location, the packet metadata will be populated with the TTN console gateway location?

Thank you for responding to my post. Whilst this is a frustration I fully understand your reasoning for using the self reported gateway location and deleting historic data for gateways that have moved. I think that even with these problems, GPS enabled gateways reduce the problem of gateways misreporting their location. I have contacted 2 gateway owners this week asking them to update their config files to reflect the actual gateway location. The whole mapping process has become rather addictive, I’ve even bought the T shirt! Thanks again, Kevin

The data forwarded to the application should have the position as entered in the gateway console. No need to hack the software, just disable the gps in the configuration.

Yes, as Kersing says one should rather use the Console to set the location rather than hardcoding it in the gateway’s config files. See the logic described here: Gateway GPS configuration in local_conf.json


I would still like to use PPS for the time reference. My understanding is that disabling GPS disables crystal correction. Is this correct?

It appears from mp_pkt_fwd.c that the crystal correction is performed by:


void thread_valid(void){
  /* GPS reference validation variables */
long gps_ref_age = 0;
bool ref_valid_local = false;
double xtal_err_cpy;

/* variables for XTAL correction averaging */
unsigned init_cpt = 0;
double init_acc = 0.0;
double x;

MSG("INFO: Validation thread activated.\n");

/* correction debug */
// FILE * log_file = NULL;
// time_t now_time;
// char log_name[64];

/* initialization */
// time(&now_time);
// strftime(log_name,sizeof log_name,"xtal_err_%Y%m%dT%H%M%SZ.csv",localtime(&now_time));
// log_file = fopen(log_name, "w");
// setbuf(log_file, NULL);
// fprintf(log_file,"\"xtal_correct\",\"XERR_INIT_AVG %u XERR_FILT_COEF %u\"\n", XERR_INIT_AVG, XERR_FILT_COEF); // DEBUG

/* main loop task */
while (!exit_sig && !quit_sig) {

    /* calculate when the time reference was last updated */
    gps_ref_age = (long)difftime(time(NULL), time_reference_gps.systime);
    if ((gps_ref_age >= 0) && (gps_ref_age <= GPS_REF_MAX_AGE)) {
        /* time ref is ok, validate and  */
        gps_ref_valid = true;
        ref_valid_local = true;
        xtal_err_cpy = time_reference_gps.xtal_err;
    } else {
        /* time ref is too old, invalidate */
        gps_ref_valid = false;
        ref_valid_local = false;

    /* manage XTAL correction */
    if (ref_valid_local == false) {
        /* couldn't sync, or sync too old -> invalidate XTAL correction */
        xtal_correct_ok = false;
        xtal_correct = 1.0;
        init_cpt = 0;
        init_acc = 0.0;
    } else {
        if (init_cpt < XERR_INIT_AVG) {
            /* initial accumulation */
            init_acc += xtal_err_cpy;
        } else if (init_cpt == XERR_INIT_AVG) {
            /* initial average calculation */
            xtal_correct = (double)(XERR_INIT_AVG) / init_acc;
            xtal_correct_ok = true;
            // fprintf(log_file,"%.18lf,\"average\"\n", xtal_correct); // DEBUG
        } else {
            /* tracking with low-pass filter */
            x = 1 / xtal_err_cpy;
            xtal_correct = xtal_correct - xtal_correct/XERR_FILT_COEF + x/XERR_FILT_COEF;
            // fprintf(log_file,"%.18lf,\"track\"\n", xtal_correct); // DEBUG
    MSG_DEBUG(DEBUG_LOG,"Time ref: %s, XTAL correct: %s (%.15lf)\n", ref_valid_local?"valid":"invalid", xtal_correct_ok?"valid":"invalid", xtal_correct); // DEBUG
MSG("INFO: End of validation thread\n");


This thread is only spawned if gps_active == true which requires fake_gps:false in gateway_conf.

 /* -------------------------------------------------------------------------- */
/* --- MAIN FUNCTION -------------------------------------------------------- */

/* spawn thread to manage GPS */
if (gps_active == true) {
    i = pthread_create( &thrid_gps, NULL, (void * (*)(void *))thread_gps, NULL);
    if (i != 0) {
        MSG("ERROR: [main] impossible to create GPS thread\n");
    i = pthread_create( &thrid_valid, NULL, (void * (*)(void *))thread_valid, NULL);
    if (i != 0) {
        MSG("ERROR: [main] impossible to create validation thread\n");

If you take another moment to search the sources you will notice the only place the variable is used is for Class B beaconing which is not used anyway. Disabling GPS will have no impact on PPS.

1 Like

Thank you again for your patience and support.

That’s a very helpful ‘value added’ comment!

It (the drift) is and it’s unnecessary. All that is required from the GPS is the precise timing as the location of the gateway is known and normally pretty static. Kev (a newbie) has a simple request here.

@kersing I have disabled GPS and my gateway timestamp is now truncated to a 1 second resolution.

  "gateways": [
  "gtw_id": "partridge_croft_01",
  "gtw_trusted": true,
  "timestamp": 3973382755,
  "time": "2019-08-14T07:53:00Z",
  "channel": 1,
  "rssi": -71,
  "snr": 9.25,
  "rf_chain": 1,
  "latitude": 51.48876,
  "longitude": -3.161574,
  "altitude": 24,
  "location_source": "registry"

I will look more closely at the source code at the weekend.

Worth noting that if the location is drifting, the timecode output is too, as time and location are inseparable in GPS. Granted (ignoring specific geometry) the reported 40 km position drift is comparable to around an 8th of a millisecond.

Kev (a newbie) has a simple request here.

It may look that way, but simple requests often raise deeper questions, for example this raises the question of why GPS is being desired at all, if the chain of logic connecting the original desire to the apparent need for GPS is technically sound, and if all the other pieces needed to support the goal that inspired the need currently exist in working fashion.

If it is not actually needed, or not useful because some other part of the goal is missing, not using it may be simplest of all.

Incidentally, I’m not sure I agree with Kersing that (apart from beacon transmission) the hardware itself uses the PPS signal; reading through at least Semtech’s version of the HAL and packet forwarder code, it seems what happens is that the received packets are always timestamped by the independent receiver clock. But in GPS mode, there’s a register that latches the internal clock value at the last PPS signal, which can then be used by the software to apply a correction for internal clock drift. It seems the SX130x is operated in GPS mode regardless if a GPS is present and configured or not. However, if the serial port for receiving GPS messages is not enabled as a result of not having GPS enabled in the config file, I strongly suspect the code that gets the hardware timestamp of the latest GPS PPS never activates, and no GPS correction is ever applied to the receive timestamps - so in effect, GPS is not actually used if it is not enabled. That said, I’ve not managed to yet find exactly where in the code the timestamp would be altered by the GPS model, only where the model is calculated after each GPS message. But that’s largely moot as the timestamp is really just used to transmit in receive windows the correct amount of time after an uplink, which is a few seconds later and would correspond to software timing on the node end. It’s almost simpler to get that right without clock corrections than with.