summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--geoid.c5
-rw-r--r--gps.h3
-rw-r--r--gpsutils.c103
-rw-r--r--monitor_sirf.c5
4 files changed, 67 insertions, 49 deletions
diff --git a/geoid.c b/geoid.c
index fa79104d..5db3ca68 100644
--- a/geoid.c
+++ b/geoid.c
@@ -90,9 +90,8 @@ void ecef_to_wgs84fix(struct gps_data_t *gpsdata,
/* fill in WGS84 position/velocity fields from ECEF coordinates */
{
double lambda,phi,p,theta,n,h,vnorth,veast,heading;
- const double a = 6378137; /* equatorial radius */
- const double f = 1 / 298.257223563; /* flattening */
- const double b = a * (1 - f); /* polar radius */
+ const double a = WGS84A; /* equatorial radius */
+ const double b = WGS84B; /* polar radius */
const double e2 = (a*a - b*b) / (a*a);
const double e_2 = (a*a - b*b) / (b*b);
diff --git a/gps.h b/gps.h
index 7a06c15b..5ad4b5be 100644
--- a/gps.h
+++ b/gps.h
@@ -35,6 +35,9 @@ extern "C" {
#define MAXCHANNELS 20 /* maximum GPS channels (*not* satellites!) */
#define GPS_PRNMAX 32 /* above this number are SBAS satellites */
+#define WGS84A 6378137 /* equatorial radius */
+#define WGS84F 298.257223563 /* flattening */
+#define WGS84B 6356752.3142 /* polar radius */
/*
* The structure describing an uncertainty volume in kinematic space.
* This is what GPSes are meant to produce; all the other info is
diff --git a/gpsutils.c b/gpsutils.c
index 110e64eb..0797a705 100644
--- a/gpsutils.c
+++ b/gpsutils.c
@@ -254,52 +254,69 @@ void unix_to_gpstime(double unixtime, /*@out@*/int *week, /*@out@*/double *tow)
#define Deg2Rad(n) ((n) * DEG_2_RAD)
-static double CalcRad(double lat)
-/* earth's radius of curvature in meters at specified latitude.*/
-{
- const double a = 6378.137;
- const double e2 = 0.081082 * 0.081082;
- // the radius of curvature of an ellipsoidal Earth in the plane of a
- // meridian of latitude is given by
- //
- // R' = a * (1 - e^2) / (1 - e^2 * (sin(lat))^2)^(3/2)
- //
- // where a is the equatorial radius,
- // b is the polar radius, and
- // e is the eccentricity of the ellipsoid = sqrt(1 - b^2/a^2)
- //
- // a = 6378 km (3963 mi) Equatorial radius (surface to center distance)
- // b = 6356.752 km (3950 mi) Polar radius (surface to center distance)
- // e = 0.081082 Eccentricity
- double sc = sin(Deg2Rad(lat));
- double x = a * (1.0 - e2);
- double z = 1.0 - e2 * sc * sc;
- double y = pow(z, 1.5);
- double r = x / y;
-
- return r * 1000.0; // Convert to meters
-}
-
double earth_distance(double lat1, double lon1, double lat2, double lon2)
/* distance in meters between two points specified in degrees. */
{
- double x1 = CalcRad(lat1) * cos(Deg2Rad(lon1)) * sin(Deg2Rad(90-lat1));
- double x2 = CalcRad(lat2) * cos(Deg2Rad(lon2)) * sin(Deg2Rad(90-lat2));
- double y1 = CalcRad(lat1) * sin(Deg2Rad(lon1)) * sin(Deg2Rad(90-lat1));
- double y2 = CalcRad(lat2) * sin(Deg2Rad(lon2)) * sin(Deg2Rad(90-lat2));
- double z1 = CalcRad(lat1) * cos(Deg2Rad(90-lat1));
- double z2 = CalcRad(lat2) * cos(Deg2Rad(90-lat2));
- double a = (x1*x2 + y1*y2 + z1*z2)/pow(CalcRad((lat1+lat2)/2),2);
-
- // a should be in [1, -1] but can sometimes fall outside it by
- // a very small amount due to rounding errors in the preceding
- // calculations. This is prone to happen when the argument points
- // are very close together. Return NaN so calculations trying
- // to use this will also blow up.
- if (fabs(a) > 1)
- return NAN;
- else
- return CalcRad((lat1+lat2) / 2) * acos(a);
+ /*
+ * this is a translation of the javascript implementation of the
+ * Vincenty distance formula by Chris Veness. See
+ * http://www.movable-type.co.uk/scripts/latlong-vincenty.html
+ */
+ double a, b, f; // WGS-84 ellipsoid params
+ double L, L_P, U1, U2, s_U1, c_U1, s_U2, c_U2;
+ double uSq, A, B, d_S, lambda;
+ double s_L, c_L, s_S, C;
+ double c_S, S, s_A, c_SqA, c_2SM;
+ int i = 100;
+
+ a = WGS84A;
+ b = WGS84B;
+ f = 1/WGS84F;
+ L = Deg2Rad(lon2 - lon1);
+ U1 = atan((1 - f) * tan(Deg2Rad(lat1)));
+ U2 = atan((1 - f) * tan(Deg2Rad(lat2)));
+ s_U1 = sin(U1);
+ c_U1 = cos(U1);
+ s_U2 = sin(U2);
+ c_U2 = cos(U2);
+ lambda = L;
+
+ do {
+ s_L = sin(lambda);
+ c_L = cos(lambda);
+ s_S = sqrt((c_U2 * s_L) * (c_U2 * s_L) +
+ (c_U1 * s_U2 - s_U1 * c_U2 * c_L) *
+ (c_U1 * s_U2 - s_U1 * c_U2 * c_L));
+
+ if (s_S==0)
+ return 0;
+
+ c_S = s_U1 * s_U2 + c_U1 * c_U2 * c_L;
+ S = atan2(s_S, c_S);
+ s_A = c_U1 * c_U2 * s_L / s_S;
+ c_SqA = 1 - s_A * s_A;
+ c_2SM = c_S - 2 * s_U1 * s_U2 / c_SqA;
+
+ if (isnan(c_2SM))
+ c_2SM = 0;
+
+ C = f / 16 * c_SqA * (4 + f * (4 - 3 * c_SqA));
+ L_P = lambda;
+ lambda = L + (1 - C) * f * s_A *
+ (S + C * s_S * (c_2SM + C * c_S * (2 * c_2SM * c_2SM - 1)));
+ } while ((fabs(lambda - L_P) > 1.0e-12) && (--i > 0));
+
+ if (i == 0)
+ return NAN; // formula failed to converge
+
+ uSq = c_SqA * ((a*a) - (b*b)) / (b*b);
+ A = 1 + uSq / 16384 * (4096 + uSq * (-768 + uSq * (320 - 175 * uSq)));
+ B = uSq / 1024 * (256 + uSq * (-128 + uSq * (74 - 47 * uSq)));
+ d_S = B * s_S * (c_2SM + B/4 *
+ (c_S * (-1 + 2 * c_2SM * c_2SM) - B/6 * c_2SM *
+ (-3 + 4 * s_S * s_S) * (-3 + 4 * c_2SM * c_2SM)));
+
+ return(WGS84B * A * (S - d_S));
}
/*****************************************************************************
diff --git a/monitor_sirf.c b/monitor_sirf.c
index 685ee592..0c012772 100644
--- a/monitor_sirf.c
+++ b/monitor_sirf.c
@@ -235,9 +235,8 @@ static void decode_time(int week, int tow)
static void decode_ecef(double x, double y, double z,
double vx, double vy, double vz)
{
- const double a = 6378137;
- const double f = 1 / 298.257223563;
- const double b = a * (1 - f);
+ const double a = WGS84A;
+ const double b = WGS84B;
const double e2 = (a*a - b*b) / (a*a);
const double e_2 = (a*a - b*b) / (b*b);
double lambda,p,theta,phi,n,h,vnorth,veast,vup,speed,heading;