TinyGPS++ and speed 'smoothing'

I have been using an Adafruit Ultimate GPS with the TinyGPS++ library for about 18 months, in a little speedometer that outputs the speed in MPH onto a seven-segment display.

I have noticed recently that the speed data seems to have some sort of "smoothing" applied to it, where it drifts slowly up and down over time. I was just wondering if anyone could tell me whether this is something that always happens with GPS data itself, or if TinyGPS++ is doing this smoothing. (I don't see any TinyGPS++ code that looks like it's doing it, but I am still pretty new at this). And... is there any way to get direct observations without this smoothing?

I would like to program my own data smoothing to see if I can do it in a way that also allows for a more responsive speedometer number, e.g. when I accelerate from a stop. Currently this smoothing seems to add quite a bit of latency between when my car begins accelerating and when the GPS sends a speed signal for that acceleration.

Thanks for any insights anyone might be able to share!

Here is an example of the NMEA sentences I see (I am focused on the 'knots' field which in the below output is starting at 0.74):

$GPRMC,092000.000,A,4228.3244,N,07125.3676,W,0.74,80.95,060624,,,A*4E
$GPRMC,092000.200,A,4228.3244,N,07125.3675,W,0.75,80.66,060624,,,A*42
$GPRMC,092000.400,A,4228.3244,N,07125.3674,W,0.76,80.41,060624,,,A*43
$GPRMC,092000.600,A,4228.3244,N,07125.3674,W,0.75,80.18,060624,,,A*4E
$GPRMC,092000.800,A,4228.3245,N,07125.3674,W,0.74,79.96,060624,,,A*40
$GPRMC,092001.000,A,4228.3245,N,07125.3673,W,0.73,79.36,060624,,,A*43
$GPRMC,092001.200,A,4228.3245,N,07125.3673,W,0.71,78.32,060624,,,A*46
$GPRMC,092001.400,A,4228.3245,N,07125.3673,W,0.70,76.58,060624,,,A*43
$GPRMC,092001.600,A,4228.3246,N,07125.3672,W,0.69,75.93,060624,,,A*4F
$GPRMC,092001.800,A,4228.3246,N,07125.3671,W,0.68,74.82,060624,,,A*42
$GPRMC,092002.000,A,4228.3247,N,07125.3671,W,0.69,73.19,060624,,,A*4C
$GPRMC,092002.200,A,4228.3247,N,07125.3670,W,0.70,70.58,060624,,,A*41
$GPRMC,092002.400,A,4228.3248,N,07125.3670,W,0.71,68.83,060624,,,A*46
$GPRMC,092002.600,A,4228.3248,N,07125.3669,W,0.72,68.52,060624,,,A*43
$GPRMC,092002.800,A,4228.3248,N,07125.3669,W,0.73,68.32,060624,,,A*4A
$GPRMC,092003.000,A,4228.3249,N,07125.3668,W,0.73,67.86,060624,,,A*43
$GPRMC,092003.200,A,4228.3249,N,07125.3668,W,0.73,67.33,060624,,,A*4F
$GPRMC,092003.400,A,4228.3250,N,07125.3667,W,0.73,67.07,060624,,,A*49
$GPRMC,092003.600,A,4228.3250,N,07125.3666,W,0.72,66.73,060624,,,A*49
$GPRMC,092003.800,A,4228.3251,N,07125.3666,W,0.72,66.20,060624,,,A*40
$GPRMC,092004.000,A,4228.3251,N,07125.3666,W,0.70,65.32,060624,,,A*4D
$GPRMC,092004.200,A,4228.3252,N,07125.3665,W,0.68,65.35,060624,,,A*41
$GPRMC,092004.400,A,4228.3252,N,07125.3665,W,0.66,66.00,060624,,,A*4C
$GPRMC,092004.600,A,4228.3253,N,07125.3664,W,0.65,66.64,060624,,,A*4F
$GPRMC,092004.800,A,4228.3253,N,07125.3663,W,0.65,67.57,060624,,,A*47
$GPRMC,092005.000,A,4228.3253,N,07125.3662,W,0.65,67.24,060624,,,A*4B
$GPRMC,092005.200,A,4228.3254,N,07125.3661,W,0.66,66.45,060624,,,A*48
$GPRMC,092005.400,A,4228.3254,N,07125.3661,W,0.66,65.88,060624,,,A*4C
$GPRMC,092005.600,A,4228.3255,N,07125.3661,W,0.64,65.50,060624,,,A*48
$GPRMC,092005.800,A,4228.3255,N,07125.3661,W,0.63,64.84,060624,,,A*49
$GPRMC,092006.000,A,4228.3256,N,07125.3660,W,0.61,63.99,060624,,,A*49
$GPRMC,092006.200,A,4228.3257,N,07125.3659,W,0.61,63.16,060624,,,A*47
$GPRMC,092006.400,A,4228.3257,N,07125.3658,W,0.61,62.61,060624,,,A*41

If the GPS was giving direct observation numbers for knots, I would expect it to jump around a bit more, e.g. 0.23, 0.75, 0.57, 1.02, 0.13, etc. I had thought it was doing this 18 months ago when I was first working on this project but I don't have any written record of the outputs so I am not 100% sure.

And here is my code:


void feedGPS() {
  while (neogps.available()) {
    int c = neogps.read();
//#ifdef mydebug
    Serial.write(c);  // only for debugging
//#endif
    if (gps.encode(c)) {
      newGPSdata = true;
    }
  }
}

void loop() {
  feedGPS();
  if (newGPSdata == true) {
    newGPSdata = false;
    if (gps.location.isValid()) {
      if (gps.speed.isUpdated()) {
        if (gpsLock == 0) {
          gpsLock = 1;
          display.clear();
#ifdef mydebug
          Serial.print("acquired GPS signal at "); Serial.println(millis());
#endif
            display.showNumberDecEx(currentSpeed, 0b10000000, true, 1, 1);
        }
      }
    }
  }
}

The GPS module measures only locations, so speed is determined from distance between successive locations and time. Because of the large amount of noise in successive location determinations, especially at low speeds, some smoothing is generally required.

You can do the same in your code using successive location measurements, and implement your own smoothing.

Beware that with 8 bit Arduinos like the Uno, double precision floats are not implemented, and single precision float operations will introduce additional errors in GPS location and speed calculations.

1 Like

Thank you, that is helpful! Is it accurate to say that the GPS module itself (in this case an Adafruit unit) is doing the smoothing, rather than the TinyGPS++ library?

If it is the GPS module itself, I guess I am stuck with their method or manually calculating from the positions myself. If it is the TinyGPS++ library, I could try to modify it there, but I didn't see it in my look through that code. (I am pretty novice though, so I might have missed it!)

Yes, if you are getting the speed from the NMEA sentence produced by the module.

Adafruit does not make GPS modules, only breakout boards for commercial modules. The module used in the "Ultimate GPS" has a very skimpy data sheet and seems not well documented.

Thank you again! I had mistakenly thought the NMEA sentences were sent by the satellites :slight_smile: I also didn't really understand what the Adafruit item name meant; I thought it was just branding. I will look into some other GPS modules to see if they have better feedback or specifications than the "Ultimate GPS".

In the nearer term, I am probably going to try to update the Ultimate GPS to go 10Hz instead of the 5Hz I am using now. That might give me a bit more responsiveness to speed changes (e.g. accelerating to a stop or from a stop in my car) while I look into a better technical solution.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.