TransWikia.com

Techniques for point-level speed calculation from GPS traces

Geographic Information Systems Asked on December 10, 2021

I am working with a GPS dataset where GPS speed is not available, only the lat/lon coordinates and timestamp.

Currently, I calculate point-level speed from rate of distance between two consecutive points (distance/delta_time). However, the result usually gave large errors due to the errors in GPS.

Are the other means or techniques to estimate the point-point speed?

EDIT

Currently, I calculate the speed in python using the geopy package, like so:

from geopy.distance import vincenty
A = (Data[i, 0], Data[i, 1])
B = (Data[i + 1, 0], Data[i + 1, 1])
pointSpeed = vincenty(A, B).meters/delta_time[i]

One Answer

I took a shot at @FSimardGIS 's suggestion for moving average.
Inputs: pandas dataframe df of the gps data containing timestamp, latitude, longitude columns, sorted by timestamp and with pure index (0 to end).
And a time_interval in mins, default: 5 mins

import pandas as pd
# main function
def findSpeed(df, time_interval = 5):    
    computeDistance(df)
    df['offset'] = getTimeOffsets(df)
    df['dspan'] = df['tspan'] = df['cspeed'] = df['diff'] = None
    
    for N in range(len(df)):
        if N == 0: continue
        backi = N
        totOffset = df.at[N,'offset']
        while totOffset <= time_interval*60 :
            backi -= 1
            totOffset += df.at[backi,'offset']
            if backi == 0: break

        tspan = df.at[N,'timestamp'] - df.at[backi,'timestamp']
        df.at[N,'tspan'] = tspan.seconds
        distance = df.at[N,'ll_dist_traveled'] - df.at[backi,'ll_dist_traveled']
        df.at[N,'dspan'] = round(distance,3)
        if distance == 0:
            speed = df.at[N, 'cspeed'] = 0
        else:
            speed = round(distance / tspan.seconds * 3600,2)
            df.at[N, 'cspeed'] = speed
        speed_diff = round(df.at[N,'speed'] - speed, 2)
        df.at[N,'diff'] = speed_diff
    return df

# calling the function
df1 = findSpeed(df, time_interval = 5)

There are some supporting functions I've developed in earlier projects: computeDistance: finds distance between consecutive lat-longs and adds it up to a cumulative distance column ll_dist_traveled
getTimeOffsets: gives a column of time offset between timestamps in seconds

These are used by the program to identify [time_interval] (or lower) time period correspondng to each row and calculate speed from that group of data.

from math import sin, cos, sqrt, atan2, radians
def lat_long_dist(lat1,lon1,lat2,lon2):
    # function for calculating ground distance between two lat-long locations
    R = 6373.0 # approximate radius of earth in km. 
    lat1 = radians( float(lat1) )
    lon1 = radians( float(lon1) )
    lat2 = radians( float(lat2) )
    lon2 = radians( float(lon2) )
    dlon = lon2 - lon1
    dlat = lat2 - lat1
    a = sin(dlat / 2)**2 + cos(lat1) * cos(lat2) * sin(dlon / 2)**2
    c = 2 * atan2(sqrt(a), sqrt(1 - a))
    distance = round(R * c, 6)
    return distance

def computeDistance(sequencedf):
    prevLat = prevLon = 0 # dummy initiation
    total_dist = 0
    for N in range(len(sequencedf)):
        lat = float(sequencedf.at[N,'latitude'])
        lon = float(sequencedf.at[N,'longitude'])
        if N == 0:
            sequencedf.at[N,'ll_dist'] = 0
        else:
            sequencedf.at[N,'ll_dist'] = lat_long_dist(lat,lon, prevLat,prevLon)
        total_dist += sequencedf.at[N,'ll_dist']
        sequencedf.at[N,'ll_dist_traveled'] = round(total_dist,6)
        prevLat = lat
        prevLon = lon
    return round(total_dist,6)
    # also the original df gets ll_dist and ll_dist_traveled columns added to it

def getTimeOffsets(df, timestamp_col='timestamp'):
    timeOffsets = (df[timestamp_col] - df[timestamp_col].shift()).fillna(pd.Timedelta(seconds=0))
    return timeOffsets.dt.total_seconds().astype(int)

Feel free to change the lat_long_dist function to your preferred method (or use a routing tool like OSRM).

Output: same df (table / dataframe), with some middle-step new columns and a 'cspeed' column with calculated speed in km/hr.

I had a gps stream with original speed values from the device. Calculated with different time interval settings and plotted.

t1

t2

t3

t5

t10

As observable, even the original data (in orange) is quite jittery. Moving average helps smoothen it out, but there's a tradeoff with accuracy. I'm still not clear about which time interval value to take. Hope this helps someone!

Answered by Nikhil VJ on December 10, 2021

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP