I would like to know what's the best way to calculate the current speed with GPS.
I've an external GPS receiver which is connected via USB to my car-notebook. It gives me just the following information:
- Longitude
- Latitude
- Altitude
My try is to get two location-infos with timestamps.
Then I am finding the difference in time (timestamp2 - timestamp1) and calculating the speed (distance/time).
Are there any other possibilites oder maybe any libraries available?
To calculate the distance, you will need the Haversine Formula.
You will find many implementations of it around the web, here is one I use in C#:
private static double ArcInMeters(double lat0, double lon0, double lat1, double lon1)
{
double earthRadius = 6372797.560856; // m
return earthRadius * ArcInRadians(lat0, lon0, lat1, lon1);
}
private static double ArcInRadians(double lat0, double lon0, double lat1, double lon1)
{
double latitudeArc = DegToRad(lat0 - lat1);
double longitudeArc = DegToRad(lon0 - lon1);
double latitudeH = Math.Sin(latitudeArc * 0.5);
latitudeH *= latitudeH;
double lontitudeH = Math.Sin(longitudeArc * 0.5);
lontitudeH *= lontitudeH;
double tmp = Math.Cos(DegToRad(lat0)) * Math.Cos(DegToRad(lat1));
return 2.0 * Math.Asin(Math.Sqrt(latitudeH + tmp * lontitudeH));
}
private static double DegToRad(double x)
{
return x * Math.PI / 180;
}
Related
I want to calculate bearing between 2 GPS positions, I foollowed this page recommandations for my algorythm:
public static double Bearing(IPointGps pt1, IPointGps pt2)
{
double x = Math.Cos(pt1.Latitude) * Math.Sin(pt2.Latitude) - Math.Sin(pt1.Latitude) * Math.Cos(pt2.Latitude) * Math.Cos(pt2.Longitude - pt1.Longitude);
double y = Math.Sin(pt2.Longitude - pt1.Longitude) * Math.Cos(pt2.Latitude);
// Math.Atan2 can return negative value, 0 <= output value < 2*PI expected
return (Math.Atan2(y, x) + Math.PI * 2)%(Math.PI * 2);
}
Then I transform my value in degrees using this method
public static double RadiansToDegrees(double angle)
{
return (angle * 180.0) / Math.PI;
}
I have the following test sample:
Point1 (lat, long) = 43.6373638888888888888888888888889, 1.35762222222222222222222222222222
Point2 (lat, long) = 43.6156444444444444444444444444444,1.380225
Expected bearing = 323°
However, I obtain a bearing of 315.5° (5.5062235835910762 rad). If i calculate the expected radian value, i get 5.637413 which leaves no doubt that my problem lies in my bearing method.
I already implemented other computation methods using .Net Math package (including Cos, Sin, Tan and ATan methods) and my unit tests pass with 1e-12 precision. What am I missing?
PS: I also tryied to reimplement the Atan2 method in case there is a lack of precision in it. I obtain the very same result
edit: My Latitude and Longitude are double as per the following interface
public interface IPointGps
{
double Latitude { get; }
double Longitude { get; }
}
Math.Sin() and all similar methods expect argument in radians, but your latitudes and longitudes are in degrees. You have to convert IPointGps to radians before you calculate bearing, or modify Bearing calculation, e.g.:
public static double Bearing(IPointGps pt1, IPointGps pt2)
{
double x = Math.Cos(DegreesToRadians(pt1.Latitude)) * Math.Sin(DegreesToRadians(pt2.Latitude)) - Math.Sin(DegreesToRadians(pt1.Latitude)) * Math.Cos(DegreesToRadians(pt2.Latitude)) * Math.Cos(DegreesToRadians(pt2.Longitude - pt1.Longitude));
double y = Math.Sin(DegreesToRadians(pt2.Longitude - pt1.Longitude)) * Math.Cos(DegreesToRadians(pt2.Latitude));
// Math.Atan2 can return negative value, 0 <= output value < 2*PI expected
return (Math.Atan2(y, x) + Math.PI * 2) % (Math.PI * 2);
}
public static double DegreesToRadians(double angle)
{
return angle * Math.PI / 180.0d;
}
returns bearing 5.637716736134105.
It looks like your latitude and longitude variables are float (single precision). If that is the case, then your are facing a precision error.
I want to calculate bearing between 2 GPS positions, I foollowed this page recommandations for my algorythm:
public static double Bearing(IPointGps pt1, IPointGps pt2)
{
double x = Math.Cos(pt1.Latitude) * Math.Sin(pt2.Latitude) - Math.Sin(pt1.Latitude) * Math.Cos(pt2.Latitude) * Math.Cos(pt2.Longitude - pt1.Longitude);
double y = Math.Sin(pt2.Longitude - pt1.Longitude) * Math.Cos(pt2.Latitude);
// Math.Atan2 can return negative value, 0 <= output value < 2*PI expected
return (Math.Atan2(y, x) + Math.PI * 2)%(Math.PI * 2);
}
Then I transform my value in degrees using this method
public static double RadiansToDegrees(double angle)
{
return (angle * 180.0) / Math.PI;
}
I have the following test sample:
Point1 (lat, long) = 43.6373638888888888888888888888889, 1.35762222222222222222222222222222
Point2 (lat, long) = 43.6156444444444444444444444444444,1.380225
Expected bearing = 323°
However, I obtain a bearing of 315.5° (5.5062235835910762 rad). If i calculate the expected radian value, i get 5.637413 which leaves no doubt that my problem lies in my bearing method.
I already implemented other computation methods using .Net Math package (including Cos, Sin, Tan and ATan methods) and my unit tests pass with 1e-12 precision. What am I missing?
PS: I also tryied to reimplement the Atan2 method in case there is a lack of precision in it. I obtain the very same result
edit: My Latitude and Longitude are double as per the following interface
public interface IPointGps
{
double Latitude { get; }
double Longitude { get; }
}
Math.Sin() and all similar methods expect argument in radians, but your latitudes and longitudes are in degrees. You have to convert IPointGps to radians before you calculate bearing, or modify Bearing calculation, e.g.:
public static double Bearing(IPointGps pt1, IPointGps pt2)
{
double x = Math.Cos(DegreesToRadians(pt1.Latitude)) * Math.Sin(DegreesToRadians(pt2.Latitude)) - Math.Sin(DegreesToRadians(pt1.Latitude)) * Math.Cos(DegreesToRadians(pt2.Latitude)) * Math.Cos(DegreesToRadians(pt2.Longitude - pt1.Longitude));
double y = Math.Sin(DegreesToRadians(pt2.Longitude - pt1.Longitude)) * Math.Cos(DegreesToRadians(pt2.Latitude));
// Math.Atan2 can return negative value, 0 <= output value < 2*PI expected
return (Math.Atan2(y, x) + Math.PI * 2) % (Math.PI * 2);
}
public static double DegreesToRadians(double angle)
{
return angle * Math.PI / 180.0d;
}
returns bearing 5.637716736134105.
It looks like your latitude and longitude variables are float (single precision). If that is the case, then your are facing a precision error.
In my previous question, I looked to speed up list selection based on a function result. Now, my bottleneck is the function itself.
It's a basic Haversine function, using the code below:
private static double Haversine(double lat1, double lat2, double lon1, double lon2)
{
const double r = 6371e3; // meters
var dlat = (lat2 - lat1)/2;
var dlon = (lon2 - lon1)/2;
var q = Math.Pow(Math.Sin(dlat), 2) + Math.Cos(lat1) * Math.Cos(lat2) * Math.Pow(Math.Sin(dlon), 2);
var c = 2 * Math.Atan2(Math.Sqrt(q), Math.Sqrt(1 - q));
var d = r * c;
return d / 1000;
}
So... why does it need to be so fast? The issue is that I'm calling it a lot. Think north of 16,500,000 times.
Obviously, that's a lot. And in my use case I'm passing it objects that it has to get the location data from and then convert Latitude and Longitude to radians, which increases the time further (only by about 15%). I don't know that there's much I can do about that, but I do know that by passing it purely doubles in radians (as above) it takes ~4.5 seconds - which is more than 75% of the processing time in my implementation. The lines assigning values to q and c seems to take up the most time.
As it's being called a lot, I'm looking to make it a bit faster. I'm open to multithreaded solutions (and am currently working on one myself), but it may be a bit more difficult to implement given the use case in my previous question (linked above).
This was as optimized as I could get the answer (and, to my knowledge, this is the most optimized the answer could possibly get without doing some wizard-level optimization on the formula itself):
private static double Haversine(double lat1, double lat2, double lon1, double lon2)
{
const double r = 6378100; // meters
var sdlat = Math.Sin((lat2 - lat1) / 2);
var sdlon = Math.Sin((lon2 - lon1) / 2);
var q = sdlat * sdlat + Math.Cos(lat1) * Math.Cos(lat2) * sdlon * sdlon;
var d = 2 * r * Math.Asin(Math.Sqrt(q));
return d;
}
On my machine, this formula, when run 16.5 million times, runs at almost exactly 3 seconds, whereas the above version runs at just shy of 5.
However, I maintain that the biggest optimization could be in the system that actually calls this method. 33,000 times on each of 500 Latitude-Longitude pairs? That's a system that is likely in dire need of optimization itself. For starters, you could first calculate the linear-distance-squared of your pairs and only process pairs that are below a certain threshold. Or you could maintain a look-up table to avoid calculating the same pair more than once. Or, depending on the source of that 33,000 number, you can prioritize so that you don't need to call the method nearly that much.
For me this is more accurate
public static class Haversine {
public static double calculate(double lat1, double lon1, double lat2, double lon2) {
var R = 6372.8; // In kilometers
var dLat = toRadians(lat2 - lat1);
var dLon = toRadians(lon2 - lon1);
lat1 = toRadians(lat1);
lat2 = toRadians(lat2);
var a = Math.Sin(dLat / 2) * Math.Sin(dLat / 2) + Math.Sin(dLon / 2) * Math.Sin(dLon / 2) * Math.Cos(lat1) * Math.Cos(lat2);
var c = 2 * Math.Asin(Math.Sqrt(a));
return R * c;
}
public static double toRadians(double angle) {
return Math.PI * angle / 180.0;
}
}
void Main() {
Console.WriteLine(String.Format("The distance between coordinates {0},{1} and {2},{3} is: {4}", 36.12, -86.67, 33.94, -118.40, Haversine.calculate(36.12, -86.67, 33.94, -118.40)));
}
// Returns: The distance between coordinates 36.12,-86.67 and 33.94,-118.4 is: 2887.25995060711
I have been trying to find out what unit the .DistanceTo gives me.
The articles related so far mention geounits, but no further explanation
Using an elapsed time, and 2 locations I am calculating the speed my device is going.
I'm not sure how to get the result from distance=Location1.DistanceTo(Location2); in Km, or any other METRIC unit. I have to use metric for my app.
Any help solving this or guiding me toward the solution would be helpful.
According to the developer documentation the method returns the distance in metres.
Returns the approximate distance in meters between this location and
the given location.
So to get it in kilometres, just divide the result by 1000:
float distanceInMetres = Location1.DistanceTo(Location2);
float distanceInKilometres = distanceInMetres / 1000;
public double CalculationByDistance(GeoPoint StartP, GeoPoint EndP) {
int Radius=6371;//radius of earth in Km
double lat1 = StartP.getLatitudeE6()/1E6;
double lat2 = EndP.getLatitudeE6()/1E6;
double lon1 = StartP.getLongitudeE6()/1E6;
double lon2 = EndP.getLongitudeE6()/1E6;
double dLat = Math.toRadians(lat2-lat1);
double dLon = Math.toRadians(lon2-lon1);
double a = Math.sin(dLat/2) * Math.sin(dLat/2) +
Math.cos(Math.toRadians(lat1)) * Math.cos(Math.toRadians(lat2)) *
Math.sin(dLon/2) * Math.sin(dLon/2);
double c = 2 * Math.asin(Math.sqrt(a));
double valueResult= Radius*c;
double km=valueResult/1;
DecimalFormat newFormat = new DecimalFormat("####");
kmInDec = Integer.valueOf(newFormat.format(km));
meter=valueResult%1000;
meterInDec= Integer.valueOf(newFormat.format(meter));
Log.i("Radius Value",""+valueResult+" KM "+kmInDec+" Meter "+meterInDec);
return Radius * c;
}
I have a database with a list of latitude and longitude
-DeviceName
-Latitude
-Longitude
Given my current device's latitude and longitude, I want to get all devices within the database list in distance/proximity of X kilometres.
How do I calculate the proximity of my location vs other locations?
I think you want to have a peep at this amazing presentation. it will tell you how to use (and for bonus points explains!) the haversine formula to calcuate distances on the surface of the earth accounting for curviture and how to avoid some common mistakes in your database queries etc. His dataset is pretty much exactly what yours is - item, longitude and latitude.
If you're after the raw code, this should help you:
private static Double rad2deg(Double rad) {
return (rad / Math.PI * 180.0);
}
private static Double deg2rad(Double deg) {
return (deg * Math.PI / 180.0);
}
private const Double kEarthRadiusKms = 6376.5;
private static Double CalculateDistance(Double latitude1, Double longitude1, Double latitude2, Double longitude2) {
double theta = longitude1 - longitude2;
double dist = Math.Sin(deg2rad(latitude1)) * Math.Sin(deg2rad(latitude2)) + Math.Cos(deg2rad(latitude1)) * Math.Cos(deg2rad(latitude2)) * Math.Cos(deg2rad(theta));
dist = Math.Acos(dist);
dist = rad2deg(dist);
dist = dist * 60 * 1.1515;
dist = dist * 1.609344;
return (dist);
}