I'm developing an android application using GPS. I'd like to implement a feature that displays the users average speed over the 1/5/15 minute. Something like the CPU load on unix. I can calculate average easily by cumulating the distance traveled second by second and divide it by the elapsed time, but I can't think of a smart way of calculating the moving average.
Obviously I can get id done by putting the distance between the last and the current position in an array every second while deleting the oldest value.
I'm looking for a neat way of doing this.
Heres one way to go about it that is pretty straight forward:
If you are sampling position every second keep 901 samples in a queue, thats 15 mins worth (and 1 extra).
Position 0 is the most recent measurement, effectively your current position.
For an average speed over the last X minutes:
s = X * 60;
point1 = postion_queue[0]; // this is your current position
point2 = postion_queue[s]; // this is your position s seconds ago
d = distance_between_points(point1, point2);
speed = d / s;
speed is now distance units per second, convert to mph, or kph or whatever units you need. Different values of X can be used for any average between 1 and 15 minutes.
You will need to store all the values for the whole time span, as you already suggested. The reason is that you somehow need to "forget" the contributions of the old values to the moving average. You can't do that exactly if you don't know what these values where (i.e. if you do not store them).
In your case, 1 value each second for 15 minutes amounts to 15 * 60 = 900 data points, that should be OK.
Note that you do not need to perform a sum over the whole array each time you update: You can calculate the new moving average from the number of data points, the new value and the value you are "forgetting" at that moment:
new_average = (n * old_average - x_forget + x_new) / n
Here, n is the number of data points (900 in your case), x_forget is the value you are "forgetting" and x_new is the latest value. You then drop x_forget from the front of your array and store x_new at the end. Instead of an array you might want to use a queue implemented via a linked list.
Related
The Problem I am having is that I have charts which should always show a fixed range of XValues let's say all 24 hours in a day, but the Chart is only showing XValues up to and starting from the point of the first and last YValue, that is if I have two Y events, let's say 2am and 3pm, instead of showing the whole 24 hours, it will start at 2am and end at 3pm.
I think this has something to do with the new way to handle XValues via IAxisValueFormatter, since this used to work fine when we could add both X and Y values to a ChartData.
One hack to workaround this I found is to add empty YValues to first and last hour in my case 0 values, but this brings another issue that no matter what I set the minimum in LeftAxis it starts showing negative label values (starts in -15 instead of 0).
Is there an official way to do this? I have researched quite a bit about this and I am thinking on going back to a previous version of the library where I could just use the old way.
Edit: Just to clarify the problem doesn't have anything to do with the labels, but with the start and end of the Chart in X, it is discarding the range of X which doesn't have any YValues which I understand makes sense but it makes the results look ugly in certain cases.
You can use the setLabelCount() method to force the axis to draw labels according to the count you specify
According to the documentation:
setLabelCount(int count, boolean force)
#param count: the number of y-axis labels that should be displayed
#param force if enabled, the set label count will be forced, meaning that the exact specified count of labels will be drawn and evenly distributed alongside the axis - this might cause labels to have uneven values
And the setLabelCount method is defined below
public void setLabelCount(int count) {
if (count > 25)
count = 25;
if (count < 2)
count = 2;
mLabelCount = count;
mForceLabels = false;
}
You can use setLabelCount() with setAxisMaximum() and setAxisMinimum()
For example:
axis.setLabelCount(24, true);
axis.setAxisMaximum(24f);
axis.setAxisMinimum(0f);
This will draw values from 0 - 24 regardless of Y-Axis values
Ok so delta-time is 1/fps right? Say the fps was 50, then delta time would equal 1/50= 0.02. My question is that frame rate varies(one second it might be 50, another it might be 52). So say for one second the fps is 50, that means that delta time will be equal to 0.02, but the NEXT second the fps will be 52, but we don't know that yet. So our animations are being done with delta time of 1/50 but the fps is actually 52. Until the next second is finished we won't know that the fps has changed. This may not seem like a big deal if the changes are small, but if they become very big then we have a problem. So the thing is we are always doing calculations based on the previous second's fps. I want to know how to solve this. Thanks!
You're right that 1/fps = delta-time. However, fps isn't known at the present, and as you pointed out going about it this way would cause a problem! In practice, the formula is re-arranged such that 1/dt = fps.
So, we determine delta-time by determining how much time has passed since the last update( deltaTime = (CurrentTime - LastTime) ). If we were to have a variable that we add delta time to every every update (say, deltaCounter += deltaTime), and another variable which is a counter we add one to each update (Counter++), we would see that when deltaCounter is becomes equal to 1, the Counter variable is our fps for that second.
Further Reading on Delta Time and its Implementation
I have completed a phonegap app which pools gps cordinate data every 10 sec to the server. now according to the calculations 8 hours of tracking it will store around 8*60*6=2880 records per user. my current requirement is limited to use of 20 user. (basically it tracks a users rout travelled)
There are two parts to the question:
what is the best way to store the data and retrieve it as fast as possible.
is it possible to display 2880 coordinates at a time on google maps API v3 ? if not, what is the best way to display the rout traveled?
I am having good results with 90 or so points, for one of my demos, but the enormous 2880 records per user per 8 hours is what worries me.
Thanks
EDIT 1
Although this is an old question , I recently worked on a project where I displayed about 10K points on the map, I hope my observations would help the future visitors:
The google maps as if now do not have a hard limit on the number of points you can display on the client side.
The number of points you can display on the client side is entirely dependent on the client side `Hardware` , bigger the number of points using a jpeg or gif marker , slower will be the renders , when moving around or zooming in and out
To have huge number of pointers on the map with a minimal performance hit, precomputing the number of points needed to be rendered before and after pan or zoom occurs will help a lot.
So here is a possible solution:
First of all, you need to find out how many points Google Maps API can handle and still show the line. I think this will just take some testing or researching. Anyways once you find your magical number of points to display to plot your path then take that number and multiply it by 2/3.
For instance if a good path needs have say 90 points then calculate 90*2/3
The reason for 2/3 is that the following loop will return a max number of points that is averagely equal to 3/2 times the variable we use so using. 60 would give us on average 90 plots. There is a case where the most returned plots would be (2 * (magical number of points)) - 1 for instance say we want on average of 90 points then we could in some rare cases have (2*(90*2/3))-1 = 119 points You will just have to do some testing after implementation to make sure that your magical number of points works good for maps with 2/3 of the magical number of points and 2 * magical number of points -1. I hope this isn't too confusing... I tried to explain as best I can.
The rest of this is going to be sudo code. You will have to adapt it for whatever language you connect to MySQL with:
//get the total number of rows returned
var total_rows = mysql->num_rows;
//calculate max to be 2/3 times your magic number for max plots, i.e. 90
var max_plots = 90*2/3;
//define empty plots array to fill with coordinates
var plots = array();
//check if total_rows is less than max_plots then:
if(total_rows > max_plots){
//find the quotient of the the divident total_rows and the divisor max_plots rounded down to the nearest whole int
var quotient = floor(total_rows/max_plots);
//define variable i to use in loop
var i = 1;
//loop through returned rows
while(row = mysql->fetch_row()){
//return only rows that are the first, last, or are dividable by the quotient evenly; Note: if your language supports it, use the Modulus operator like (i % quotient) == 0 for the last or statement.
if(i == 1 || 1 == total_rows || (i - (i * (floor(i/quotient)))) == 0){
//set plots to use on map
plots[] = array(
'lat' => row['lat'],
'lon' => row['lon'],
);
}
//increment counting variable
i++;
}
// else if total_rows less than or equal to max_plots retrieve all plots
} else {
while(row = mysql->fetch_row()){
plots[] = array(
'lat' => row['lat'],
'lon' => row['lon'],
);
}
}
This may not be the best way as it still requires to retrieve all of the rows from the database, but it does solve how to only print a selected maximum amount evenly spaced on the Google map.
Note: Be sure that your query orders the rows by an auto incrementing key or some other way so that the plots will be in order that they were entered into the database.
The most detailed maps would be a map with (2 * magic_plot_number) - 1 and your least details map would contain magic_plot_number or if lower, the number of total_plots. That being said an 8 hour tracking would plot a path with points every 7 minutes and 51 seconds totaling 61 points over 8 hours using the magic plot number of 90. The more plots the closer number of points will be to 2/3 * the magic plot number
I hope this helps you with this situation.
I have database with about 12 000 entries. Each entry has given latitude, longitude and empty distance. What I need to do is to find 25 nearest entries from current GPS position. My ORM is greenDao.
Have 2 problems:
I don't know distance between me and entries yet and I can't load all entries to RAM because when I do, heap goes up to 70MB and app crashes at OutOfMemoryException (so I need to use lazy loading).
I tried this approach:
Get iterator for given table
load entry, calculate its distance from my current position, save entry to ArrayList buffer (I flush buffer every 1000 entries back into db (it is just updateInTx(...)) and then clean it)
repeat point 2 until iterator.hasNext();
query from entries with limit(25).orderAsc()
result
This works, but from point 1-3 it is very very slow (takes about 25 sec on Nexus 7) . Rest takes about 1.5 sec.
I have to do this every time when user launches app or requests data refresh.
Any ideas how to solve it better way?
Thanks
EDIT:
This is function for calculating distance, so its hard to make this in SQL :(
double getDistance(GPSCoords myPos, Place place) {
double dlong = (place.getLongitude() - myPos.getLongitude()) * d2r;
double dlat = (place.getLatitude() - myPos.getLatitude()) * d2r;
double a = Math.pow(Math.sin(dlat / 2.0), 2) + Math.cos(myPos.getLatitude() * d2r)
* Math.cos(place.getLatitude() * d2r) * Math.pow(Math.sin(dlong / 2.0), 2);
double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
double d = 6367 * c;
return d;
}
You should be able to let SQL do the work inside the database:
select ((x - ?)*(x - ?) + (y - ?)*(y - ?)) as distsq from entries
order by dist limit 20
Unfortunately sqlite doesn't provide exponentiation, so the duplicated terms are needed.
If this is still not fast enough, another approach would be to make bounding box queries centered on your location, adjusting the size of the bounding box by binary search until you have 30 or a few more entries. Indexes on each of the x and y dimension will speed these along.
Edit Since the OP says earth curvature is important, a bounding box technique is probably the best approach we can get with unextended sqlite. Here is a proposed algorithm:
Let P be the current position
Let Slat = lat0 be the bounding box latitude half-size initialized with a "best guess"
Let Slon = lon0 be the bounding box longitude half-size initialized with a "best guess"
// NB the best guesses should cover an approximately square area on the ground
loop
Let W = P.lon - Slon, E = P.lon + Slon, N = P.lat + Slat, S = P.lat - Slat
C = select count(*) from entries
where W <= lon and lon <= E and S <= lat and lat <= N
if C indicates the result is too big (e.g. for memory or read time),
Slat = 0.5 * Slat
Slon = 0.5 * Slon
else
Let R be the result of the same query for * instead of count(*)
Let D be the geometric distance from P to the nearest point on bounding box
Compute r.dist for all r in R (in memory)
Sort R by dist (in memory)
Throw away the tail elements of R where r.dist > D
// Can't use these because points outside bounding box might be closer!
If at least 20 remaining R elements,
return top 20
else
Slat = 2 * Slat
Slon = 2 * Slon
end if
end if
end loop
Note you need indices for lat and lon. I don't know how good the SQLite query optimizer is in this case. A good optimizer will pick either the lat or lon index based on statistics accumulated from past queries, use this to quickly find all points in the bounding box range for that dimension, then do a scan of this result to get the final. If the optimizer is not that clever, you want to index only the dimension likely to produce the smallest initial result: in the average case this is the one with greatest geometric extent (distance covered).
The r* tree index will make the bounding box queries much faster, but at least through Jelly Bean, you'd have to provide your own SQLite instance with this extension included. Perhaps later Android versions included it? I don't know.
Additionally, if you get to the point of including a custom SQLite with the app, it would be pretty easy to add the distance (with curvature) function as an extension.
I don't see why exactly you feel you need to lazy load your entries. The 70MB heap number sounds pretty suspicious with only 12k entries. Are you grabbing the entire row just to calculate distance? Try just grabbing the columns you need:
Latitude
Longitude
Primary Key
Assuming each is 8 bytes apiece, that's 24 * 12000 bytes, or roughly 280 kilobytes. Give it some overhead room for just being Java, but you're still looking at something very manageable.
Then you can do the calculations in code, and just have it spit out the primary key for each of the closest points. A second query can grab just those 25(the entire row this time), and you're done!
There are a lot of examples of distance calculation using different flavors of SQL out there. Loading every row from your DB and calculating how far it is, then sorting and taking the closest is going to be slow just from the back and forth to the database. Doing the calculation in SQL and only retrieving the ones you need is going to be much more performant.
You can try moving the distance calculation to the sql db.
you can also put some smarter code, that will run distance calculation until he finds 25 places that their distance from current location is less than x(you choose). or even less than 25 items (maybe you just need 7 to fill the screen) and than continue the calculation in background when user is already in the app.
It'll be a much better user experience.
So, this is a common problem in apps that track your location over a journey (a run or cycle workout, for example).
Clearly GPS navigators have less trouble, since they can assume you snap to a point on a road - however, if you're running in the park, snapping to some road grid is going to give you totally crazy numbers.
The problem as far as I see it is to combine the great-circle distances between the waypoints, but taking into account the errors (accuracy values) such that you don't veer off course too far for a low-accuracy point. The rough implementation in my head involves plotting some bezier curve (using the velocity/bearing at the point to add spline direction and weight) and integrating over it.
However, clearly this is something people have sovled before. Anyone know of the implementations, or are they all buried in proprietary software?
Bonus points for anyone who can also use the (mostly) less accurate cell tower points (which come with different/out-of-sync timestamps, and no velocity or bearing information).
The eventual implementation will be in javascript or python, whichever is faster (I'm using SL4A,) but I'm looking for general algorithms here.
To get everyone started, here is the naive algorithm, not using any velocity or bearing info.
The arc length s is calculable from the two (long, lat) pairs (the start and end waypoints) of the segment we'll start with, by the standard formula.
Assuming we've converted the value pairs into standard spherical coordinates phi and theta (here as arrays, so using phi[0] and phi[1] for locations 0 and 1) in radians, the arc length is just:
from math import sin, cos, arccos, sqrt
s = arccos(
sin(phi[0]) * sin(phi[1]) * cos(theta[0] - theta[1]) +
cos(phi[0]) * cos(phi[1])
)
However, since we've got a massive horrid function, we need to use the chain rule to work out the first order errors, and we get the following monster for delta_s:
delta_s = (1.0 / abs(sin(s))) * (
delta_phi[0] * abs(
sin(phi[0]) * cos(phi[1]) -
cos(phi[0]) * sin(phi[1]) * cos(theta[0] - theta[1])
) +
delta_phi[1] * abs(
sin(phi[1]) * cos(phi[0]) -
cos(phi[1]) * sin(phi[0]) * cos(theta[0] - theta[1])
) +
(delta_theta[0] + delta_theta[1]) * abs(
sin(phi[0]) * sin(phi[1]) * sin(theta[0] - theta[1])
)
)
We perform this operation on every pair of successive points in order, sum the ss, add the errors in quadrature as normal:
accumulator = 0.0
for error in errors:
accumulator += error * error
journey_error = sqrt(accumulator)
and thus, we know the uncertainty on our rubbish distance estimate. (we can even keep the accumulator around to speed up the calculation if we add a few points on the end - as we could in practise with real time data.)
However, this is going to give us huge errors, and only a very fuzzy idea of how far we've actually gone. This can't be how actual GPS equipment estimates distances, as it would never be accurate enough unless it had amazing signal all the time:
What we need is some more nuanced path approximation, which only bends the path out of position for the type of inaccurate points shown, rather than diverting it completely and massively increasing the distance estimate — in asking the question I was hoping to find out how all the existing implementations (probably) do it!