How do I calculate GPS distance accurately in Python - python

I am trying to update distance traveled between GPS coordinates. My error is that the GPS can move short distances while sitting still. I am currently adding the new coordinates to a list every second, calculating the distance between this second and last second, then appending the distances to a new list then add them all together.
The issue is that the small movements in distance while standing still keep accumulating. Does anyone know the proper way to do this?
self.breadcrumbs = []
#Calc Linear Distance GPS
while 1:
report = gpsp.get_current_value() #Retrieves GPS Values
try:
self.lat = report.lat
self.lon = report.lon
self.latlon = (self.lat, self.lon) #Put lat lon into tuple
self.breadcrumbs.append(self.latlon) #Append lat lon to breadcrumb list
breadcrumb_distances = [] #Holds distances between latlon data points
for i, b in enumerate(self.breadcrumbs):
current_location = b
last_location = self.breadcrumbs[i - 1]
miles = geodesic(current_location, last_location).miles
feet = miles * 5280 #convert to feet
breadcrumb_distances.append(feet)
cumulative_distance = round(sum(breadcrumb_distances),2)
print(cumulative_distance)
except Exception as e:
print(e)
sleep(1)

There is no single "right" way to do this. The problem is that when you are moving very slowly, the "erroneous" movement overwhelms what the user would perceive as the actual movement. It becomes a tradeoff between taking data that is in error and dropping data that represents actual motion. The problem increases the faster you take data and the slower the velocity.
One method is to set a minimum distance that will cause you to log new data. If the new point is within some distance ϵ of the previous one, drop the point. For good choices, this will ignore motion when actually stopped. You then need to not care about the time between data points, or you need to log the time for points (or somehow indicate the location and duration of the gaps). If the problem is due to stopped periods, this may be the best.
Another method is to reduce the logging frequency. For some applications, backing off to 5s or similar may be sufficient.

Related

Anyone knows a more efficient way to run a pairwise comparison of hundreds of trajectories?

So I have two different files containing multiple trajectories in a squared map (512x512 pixels). Each file contains information about the spatial position of each particle within a track/trajectory (X and Y coordinates) and to which track/trajectory that spot belongs to (TRACK_ID).
My goal was to find a way to cluster similar trajectories between both files. I found a nice way to do this (distance clustering comparison), but the code it's too slow. I was just wondering if someone has some suggestions to make it faster.
My files look something like this:
The approach that I implemented finds similar trajectories based on something called Fréchet Distance (maybe not to relevant here). Below you can find the function that I wrote, but briefly this is the rationale:
group all the spots by track using pandas.groupby function for file1 (growth_xml) and file2 (shrinkage_xml)
for each trajectories in growth_xml (loop) I compare with each trajectory in growth_xml
if they pass the Fréchet Distance criteria that I defined (an if statement) I save both tracks in a new table. you can see an additional filter condition that I called delay, but I guess that is not important to explain here.
so really simple:
def distance_clustering(growth_xml,shrinkage_xml):
coords_g = pd.DataFrame() # empty dataframes to save filtered tracks
coords_s = pd.DataFrame()
counter = 0 #initalize counter to count number of filtered tracks
for track_g, param_g in growth_xml.groupby('TRACK_ID'):
# define growing track as multi-point line object
traj1 = [(x,y) for x,y in zip(param_g.POSITION_X.values, param_g.POSITION_Y.values)]
for track_s, param_s in shrinkage_xml.groupby('TRACK_ID'):
# define shrinking track as a second multi-point line object
traj2 = [(x,y) for x,y in zip(param_s.POSITION_X.values, param_s.POSITION_Y.values)]
# compute delay between shrinkage and growing ends to use as an extra filter
delay = (param_s.FRAME.iloc[0] - param_g.FRAME.iloc[0])
# keep track only if the frechet Distance is lower than 0.2 microns
if frechetDist(traj1, traj2) < 0.2 and delay > 0:
counter += 1
param_g = param_g.assign(NEW_ID = np.ones(param_g.shape[0]) * counter)
coords_g = pd.concat([coords_g, param_g])
param_s = param_s.assign(NEW_ID = np.ones(param_s.shape[0]) * counter)
coords_s = pd.concat([coords_s, param_s])
coords_g.reset_index(drop = True, inplace = True)
coords_s.reset_index(drop = True, inplace = True)
return coords_g, coords_s
The main problem is that most of the times I have more than 2 thousand tracks (!!) and this pairwise combination takes forever. I'm wondering if there's a simple and more efficient way to do this. Perhaps by doing the pairwise combination in multiple small areas instead of the whole map? not sure...
Have you tried to make a matrix (DeltaX,DeltaY) lookUpTable for the pairwise combination distance. It will take some long time to calc the LUT once, or you can write it in a file and load it when the algo starts.
Then you'll only have to look on correct case to have the result instead of calc each time.
You can too make a polynomial regression for the distance calc, it will be less precise but definitely faster
Maybe not an outright answer, but it's been a while. Could you not segment the lines and use minimum bounding box around each segment to assess similarities? I might be thinking of your problem the wrong way around. I'm not sure. Right now I'm trying to work with polygons from two different data sets and want to optimize the processing by first identifying the polygons in both geometries that overlap.
In your case, I think segments would you leave you with some edge artifacts. Maybe look at this paper: https://drops.dagstuhl.de/opus/volltexte/2021/14879/pdf/OASIcs-ATMOS-2021-10.pdf or this paper (with python code): https://www.austriaca.at/0xc1aa5576_0x003aba2b.pdf

How calculate in python a history of x,y data to calculate movement?

Hello im trying to calculate if an object is stopped or in movement.
In my code I have a list for x, y coordinates like a history.
history = [[12,30],[15,30],[25,30],[35,30],[45,30],[50,32],[50,33],[51,32]]
Id like to calculate in a history if this object is stopped or in movement.
If I take the distance from last two coordinates I will have a low value that can return for me that this object is stopped.
But id like to get more data like the last 10 information but if i don't have the 10 items in my list I will get all list.
And after that i want calculate the movement distance for each point in a median.
My actual function for distance:
def calculateDistance(x1,y1,x2,y2):
dist = math.sqrt((x2 - x1)**2 + (y2 - y1)**2)
return dist
any one can help me ?
Assuming your position history was sampled at regular intervals you can group the positions by streaks of "closeness" using zip and list enumerations. With these groups of "stillness" you can select the periods of time where a pause of a minimal duration occurred.
Note that this only requires comparing distances so you don't need to use the square root.
history = [[12,30],[15,30],[25,30],[35,30],[45,30],[50,32],[50,33],[51,32]]
minDist = 5 # this is your distance threshold to determine if a movement occurred
minTime = 3 # stillness time expressed in number of position samples
dists = ( (ax-bx)**2+(ay-by)**2 for (ax,ay),(bx,by) in zip(history,history[1:]) ) # distance to neighbour
moves = [ i for i,d in enumerate(dists,1) if d>minDist**2 ] # positions where movement occurred
pauses = [ history[s:e] for s,e in zip([0]+moves,moves+[len(history)]) ] # groups of "stillness"
output:
for pause in pauses:
if len(pause) >= minTime: # check stayed sill for a minimum amount of time
print(pause[0],len(pause))
# [50, 32] 3
You could refine this by checking if all points in the group are within 1/2 distance from the center (averageX,averageY) and break down the group further based on that (using the same technique if needed)
you can calculate all the distance between two consecutive values.
def calculateDistance(x1,y1,x2,y2):
dist = math.sqrt((x2 - x1)**2 + (y2 - y1)**2)
return dist
history = [[12,30],[15,30],[25,30],[35,30],[45,30],[50,32],[50,33],[51,32]]
distanceHistory = []
for index in range(0,len(history)):
distance = calculateDistance(history[idx][0],history[idx][1], history[idx+1][0],history[idx+1][1])
distanceHistory.append(distance)
Answering here as I can't comment yet. For the first question: with only a pair of coordinates you won't be able to easily identify whether the player/object is moving or stopped. You could add a third variable, time. Between two past moves you'd be able to tell for how long the object stood still or how long the move took. If you add a check every x time period, you'd have even more accuracy and you'd know surely if they stood still or not.

Fast great circle for multiple points - Python geopy

Is it possible to speed up the great_circle(pos1, pos2).miles from geopy if using it for multiple thousand points?
I want to create something like a distance matrix and at the moment my machine needs 5 seconds for 250,000 calculations.
Actually pos1 is always the same if it helps.
Another "restriction" in my case is that I only want all points pos2 which have a distance less than a constant x.
(The exact distance doesn't matter in my case)
Is there a fast method? Do I need to use a faster function than great_circle which is less accurate or is it possible to speed it up without losing accuracy?
Update
In my case the question is whether a point is inside a circle.
Therefore it is easily possible to first get whether a point is inside a square.
start = geopy.Point(mid_point_lat, mid_point_lon)
d = geopy.distance.VincentyDistance(miles=radius)
p_north_lat = d.destination(point=start, bearing=0).latitude
# check whether the given point lat is > p_north_lat
# and so on for east, south and west

Finding a gps location at a certain time given two points?

If I have two known locations and a known speed, how can I calculate the current position at distance d (in km)?
For example, given:
Two gps locations in ES4236:
37.783333, -122.416667 # San Francisco
32.715, -117.1625 # San Diego
Traveling at 1km/min in a straight line (ignoring altitude)
How can I find the gps coordinate at a certain distance? A similar SO question uses VincentyDistance in geopy to calculate the next point based on bearing and distance.
I guess, more specifically:
How can I calculate the bearing between two gps points using geopy?
Using VincentyDistance to get the next gps point by bearing and distance, how do I know if I have arrived at my destination, or if I should keep going? It doesn't need to be exactly on the destination to be considered being arrived. Maybe any point with a radius of .5 km of the destination is considered 'arrived'.
ie,
import geopy
POS1 = (37.783333, -122.416667) # origin
POS2 = (32.715, -117.1625) # dest
def get_current_position(d):
# use geopy to calculate bearing between POS1 and POS2
# then use VincentyDistance to get next coord
return gps_coord_at_distance_d
# If current position is within .5 km of destination, consider it 'arrived'
def has_arrived(curr_pos):
return True/False
d = 50 # 50 km
print get_current_position(d)
print has_arrived(get_current_position(d))
Ok, figured I'd come back to this question and give it my best shot given that it hasn't seen any other solutions. Unfortunately I can't test code right now, but I believe there is a solution to your problem using both geopy and geographiclib. Here goes.
From the terminal (possibly with sudo)
pip install geographiclib
pip install geopy
Now with Python
Get Current Position
import geographiclib
from geopy import geopy.distance
# Get the first azimuth, which should be the bearing
bearing = geographiclib.WGS84.Inverse(37.783333, -122.416667, 32.715, -117.1625)[2]
# Now we use geopy to calculate the distance over time
dist = geopy.distance.VincentyDistance(kilometers = 1)
san_fran = geopy.Point(37.783333, -122.416667)
print dist.destination(point=san_fran, bearing=bearing)
Has Arrived
def has_arrived(d):
return geopy.distance.vincenty(curr_pos, (32.715, -117.1625)).kilometers < .5
Like I said, I unfortunately can't test this, but I believe this is correct. It's possible there will be some unit differences with the bearing calculation: it calculates bearing off of North as seen here. Sorry if this isn't exactly correct, but like I said since this hasn't received a response since I figured I may as well throw in what I know.

Using pyephem to calculate when a satellite crosses a Longitude

I am having a hard time figuring out how to calculate when a satellite crosses a specific Longitude. It would be nice to able to provide a time period and a TLE and be able to return all the times at which the satellite crosses a given longitude during the specified time period. Does pyephem support something like this?
There are so many possible circumstances that users might ask about — when a satellite crosses a specific longitude; when it reaches a specific latitude; when it reaches a certain height or descends to its lowest altitude; when its velocity is greatest or least — that PyEphem does not try to provide built-in functions for all of them. Instead, it provides a newton() function that lets you find the zero-crossing of whatever comparison you want to make between a satellite attribute and a pre-determined value of that attribute that you want to search for.
Note that the SciPy Python library contains several very careful search functions that are much more sophisticated than PyEphem's newton() function, in case you are dealing with a particularly poorly-behaved function:
http://docs.scipy.org/doc/scipy/reference/optimize.html
Here is how you might search for when a satellite — in this example, the ISS — passes a particular longitude, to show the general technique. This is not the fastest possible approach — the minute-by-minute search, in particular, could be sped up if we were very careful — but it is written to be very general and very safe, in case there are other values besides longitude that you also want to search for. I have tried to add documentation and comments to explain what is going on, and why I use znorm instead of returning the simple difference. Let me know if this script works for you, and explains its approach clearly enough!
import ephem
line0 = 'ISS (ZARYA) '
line1 = '1 25544U 98067A 13110.27262069 .00008419 00000-0 14271-3 0 6447'
line2 = '2 25544 51.6474 35.7007 0010356 160.4171 304.1803 15.52381363825715'
sat = ephem.readtle(line0, line1, line2)
target_long = ephem.degrees('-83.8889')
def longitude_difference(t):
'''Return how far the satellite is from the target longitude.
Note carefully that this function does not simply return the
difference of the two longitudes, since that would produce a
terrible jagged discontinuity from 2pi to 0 when the satellite
crosses from -180 to 180 degrees longitude, which could happen to be
a point close to the target longitude. So after computing the
difference in the two angles we run degrees.znorm on it, so that the
result is smooth around the point of zero difference, and the
discontinuity sits as far away from the target position as possible.
'''
sat.compute(t)
return ephem.degrees(sat.sublong - target_long).znorm
t = ephem.date('2013/4/20')
# How did I know to make jumps by minute here? I experimented: a
# `print` statement in the loop showing the difference showed huge jumps
# when looping by a day or hour at a time, but minute-by-minute results
# were small enough steps to bring the satellite gradually closer to the
# target longitude at a rate slow enough that we could stop near it.
#
# The direction that the ISS travels makes the longitude difference
# increase with time; `print` statements at one-minute increments show a
# series like this:
#
# -25:16:40.9
# -19:47:17.3
# -14:03:34.0
# -8:09:21.0
# -2:09:27.0
# 3:50:44.9
# 9:45:50.0
# 15:30:54.7
#
# So the first `while` loop detects if we are in the rising, positive
# region of this negative-positive pattern and skips the positive
# region, since if the difference is positive then the ISS has already
# passed the target longitude and is on its way around the rest of
# the planet.
d = longitude_difference(t)
while d > 0:
t += ephem.minute
sat.compute(t)
d = longitude_difference(t)
# We now know that we are on the negative-valued portion of the cycle,
# and that the ISS is closing in on our longitude. So we keep going
# only as long as the difference is negative, since once it jumps to
# positive the ISS has passed the target longitude, as in the sample
# data series above when the difference goes from -2:09:27.0 to
# 3:50:44.9.
while d < 0:
t += ephem.minute
sat.compute(t)
d = longitude_difference(t)
# We are now sitting at a point in time when the ISS has just passed the
# target longitude. The znorm of the longitude difference ought to be a
# gently sloping zero-crossing curve in this region, so it should be
# safe to set Newton's method to work on it!
tn = ephem.newton(longitude_difference, t - ephem.minute, t)
# This should be the answer! So we print it, and also double-check
# ourselves by printing the longitude to see how closely it matches.
print 'When did ISS cross this longitude?', target_long
print 'At this specific date and time:', ephem.date(tn)
sat.compute(tn)
print 'To double-check, at that time, sublong =', sat.sublong
The output that I get when running this script suggests that it has indeed found the moment (within reasonable tolerance) when the ISS reaches the target longitude:
When did ISS cross this longitude? -83:53:20.0
At this specific date and time: 2013/4/20 00:18:21
To double-check, at that time, sublong = -83:53:20.1
There is a difference of time between the time the program calculates the passes over the longitude and the real time. I've checked it with the LIS system ( that it's inside the ISS ) of the Nasa to find lightnings.
And I have discovered that in Europe in some orbits the time that the program calculates the pass, it's 30 seconds in advanced than the real time. And in Colombia in some orbits the time in advanced is about 3 minutes ( perhaps because 1 degree of longitud in Colombia is bigger in amount of Km than 1 degree of longitude in Europe ). But this problem only happens in 2 particular orbits ! The one that pass over France and goes down in Sicilia. And the one that pass over USA, and goes down in Cuba.
Why could this be possible ?
In my pinion I think maybe there's some mistake in the ephem.newton algorithm or maybe with the TLE, that normally it reads the one created at 00:00:00 at night when it changes of day (and not the actual, because the ISS creates 3-4 TLE per day ) or maybe with the sat.sublong function that calculates a wrong Nadir of the satellite.
Does anyone has an idea or an explanation for this problem ?
Why it happens ?.
PS: I need to checked it for sure because I need to know when the ISS crosses an area ( for detecting the lightnings inside the area ). And if the time that the program calculates in some orbits it's in advanced than the real time, then the sat.sublong function calculates it's outside the area ( it calculates it hasn't arrived to the area yet ) but the program shows it's inside the area. So the real time doesn't match with the one that the program calculates, in some occasions.
Thanks a lot for your time !

Categories