ISEarth.c
Go to the documentation of this file.
1 /*
2 MIT LICENSE
3 
4 Copyright (c) 2014-2021 Inertial Sense, Inc. - http://inertialsense.com
5 
6 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions :
7 
8 The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
9 
10 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT, IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
11 */
12 
13 #define _MATH_DEFINES_DEFINED
14 #include <math.h>
15 
16 // #include "misc/debug.h"
17 // #include "ISConstants.h"
18 
19 #include "ISEarth.h"
20 
21 //_____ M A C R O S ________________________________________________________
22 
23 //_____ D E F I N I T I O N S ______________________________________________
24 
25 #define C_NEG_MG_DIV_KT0_F -1.18558314779367E-04f // - (M * g) / (K * T0)
26 #define C_NEG_KT0_DIV_MG_F -8.43466779922578000E+03f // - (K * T0) / (M * g)
27 
28 //_____ G L O B A L S ______________________________________________________
29 
30 //_____ L O C A L P R O T O T Y P E S ____________________________________
31 
32 //_____ F U N C T I O N S __________________________________________________
33 // static const double Ra = 6378137.0; // (m) Earth equatorial radius
34 // static const double Rb = 6356752.31424518; // (m) Earth polar radius Rb = Ra * (1-f) (from flattening, f = 1/298.257223563)
35 
36 #define POWA2 40680631590769.000 // = pow(6378137.0,2)
37 #define POWB2 40408299984661.453 // = pow(6356752.31424518,2)
38 #define POWA2_F 40680631590769.000f // = pow(6378137.0,2)
39 #define POWB2_F 40408299984661.453f // = pow(6356752.31424518,2)
40 
41 #define ONE_MINUS_F 0.996647189335253 // (1 - f), where f = 1.0 / 298.257223563 is Earth flattening
42 #define E_SQ 0.006694379990141 // e2 = 1 - (1-f)*(1-f) - square of first eccentricity
43 #define REQ 6378137.0 // Re - Equatorial radius, m
44 #define REP 6356752.314245179 // Rp - Polar radius, m
45 #define E2xREQ 42697.67270717795 // e2 * Re
46 #define E2xREQdivIFE 42841.31151331153 // e2 * Re / (1 -f)
47 #define GEQ 9.7803253359 // Equatorial gravity
48 #define K_GRAV 0.00193185265241 // defined gravity constants
49 #define K3_GRAV 3.0877e-6 //
50 #define K4_GRAV 4.0e-9 //
51 #define K5_GRAV 7.2e-14 //
52 
53 /* Coordinate transformation from ECEF coordinates to latitude/longitude/altitude (rad,rad,m) */
54 void ecef2lla(const double *Pe, double *LLA, const int Niter)
55 {
56  int i;
57  double s, Rn, sinmu, beta;
58 
59  // Earth equatorial radius
60  // Re = 6378137; // m
61  // Square of first eccentricity
62  // e2 = 1 - (1-f)*(1-f);
63 
64  // Longitude
65  LLA[1] = atan2(Pe[1], Pe[0]);
66 
67  // Latitude computation using Bowring's method,
68  // which typically converges after 2 or 3 iterations
69  s = sqrt(Pe[0] * Pe[0] + Pe[1] * Pe[1]);
70  beta = atan2(Pe[2], ONE_MINUS_F * s); // reduced latitude, initial guess
71 
72  // Precompute these values to speed-up computation
73  // B = e2 * Re; // >>> this is now E2xREQ
74  // A = e2 * Re / (1 - f); // >>> this is now E2xREQdivIFE
75  for (i = 0; i < Niter; i++) {
76  // iterative latitude computation
77  LLA[0] = atan2(Pe[2] + E2xREQdivIFE * pow(sin(beta), 3), s - E2xREQ * pow(cos(beta), 3));
78  beta = atan(ONE_MINUS_F * tan(LLA[0]));
79  }
80 
81  // Radius of curvature in the vertical prime
82  sinmu = sin(LLA[0]);
83  Rn = REQ / sqrt(1.0 - E_SQ * sinmu * sinmu);
84 
85  // Altitude above planetary ellipsoid
86  LLA[2] = s * cos(LLA[0]) + (Pe[2] + E_SQ * Rn * sinmu) * sinmu - Rn;
87 }
88 
89 
90 /* Coordinate transformation from latitude/longitude/altitude (rad,rad,m) to ECEF coordinates */
91 void lla2ecef(const double *LLA, double *Pe)
92 {
93  //double e = 0.08181919084262; // Earth first eccentricity: e = sqrt((R^2-b^2)/R^2);
94  double Rn, Smu, Cmu, Sl, Cl;
95 
96  /* Earth equatorial and polar radii
97  (from flattening, f = 1/298.257223563; */
98  // R = 6378137; // m
99  // Earth polar radius b = R * (1-f)
100  // b = 6356752.31424518;
101 
102  Smu = sin(LLA[0]);
103  Cmu = cos(LLA[0]);
104  Sl = sin(LLA[1]);
105  Cl = cos(LLA[1]);
106 
107  // Radius of curvature at a surface point:
108  Rn = REQ / sqrt(1.0 - E_SQ * Smu * Smu);
109 
110  Pe[0] = (Rn + LLA[2]) * Cmu * Cl;
111  Pe[1] = (Rn + LLA[2]) * Cmu * Sl;
112  Pe[2] = (Rn * POWB2 / POWA2 + LLA[2]) * Smu;
113 }
114 
115 
116 /*
117  * Find NED (north, east, down) from LLAref to LLA (WGS-84 standard)
118  *
119  * lla[0] = latitude (rad)
120  * lla[1] = longitude (rad)
121  * lla[2] = msl altitude (m)
122  */
123 void lla2ned(ixVector3 llaRef, ixVector3 lla, ixVector3 result)
124 {
125  ixVector3 deltaLLA;
126  deltaLLA[0] = lla[0] - llaRef[0];
127  deltaLLA[1] = lla[1] - llaRef[1];
128  deltaLLA[2] = lla[2] - llaRef[2];
129 
130  // Handle longitude wrapping
131  UNWRAP_F32(deltaLLA[1]);
132 
133  // Find NED
134  result[0] = deltaLLA[0] * EARTH_RADIUS_F;
135  result[1] = deltaLLA[1] * EARTH_RADIUS_F * _COS( llaRef[0] );
136  result[2] = -deltaLLA[2];
137 }
138 
139 
140 /*
141  * Find NED (north, east, down) from LLAref to LLA (WGS-84 standard)
142  *
143  * lla[0] = latitude (rad)
144  * lla[1] = longitude (rad)
145  * lla[2] = msl altitude (m)
146  */
147 void lla2ned_d(double llaRef[3], double lla[3], ixVector3 result)
148 {
149  ixVector3 deltaLLA;
150  deltaLLA[0] = (f_t)(lla[0] - llaRef[0]);
151  deltaLLA[1] = (f_t)(lla[1] - llaRef[1]);
152  deltaLLA[2] = (f_t)(lla[2] - llaRef[2]);
153 
154  // Handle longitude wrapping in radians
155  UNWRAP_F32(deltaLLA[1]);
156 
157  // Find NED
158  result[0] = deltaLLA[0] * EARTH_RADIUS_F;
159  result[1] = deltaLLA[1] * EARTH_RADIUS_F * _COS( ((f_t)llaRef[0]) );
160  result[2] = -deltaLLA[2];
161 }
162 
163 /*
164  * Find NED (north, east, down) from LLAref to LLA (WGS-84 standard)
165  *
166  * lla[0] = latitude (deg)
167  * lla[1] = longitude (deg)
168  * lla[2] = msl altitude (m)
169  */
170 void llaDeg2ned_d(double llaRef[3], double lla[3], ixVector3 result)
171 {
172  ixVector3 deltaLLA;
173  deltaLLA[0] = (f_t)(lla[0] - llaRef[0]);
174  deltaLLA[1] = (f_t)(lla[1] - llaRef[1]);
175  deltaLLA[2] = (f_t)(lla[2] - llaRef[2]);
176 
177  // Handle longitude wrapping
178  UNWRAP_DEG_F32(deltaLLA[1]);
179 
180  // Find NED
181  result[0] = deltaLLA[0] * DEG2RAD_EARTH_RADIUS_F;
182  result[1] = deltaLLA[1] * DEG2RAD_EARTH_RADIUS_F * _COS( ((f_t)llaRef[0]) * C_DEG2RAD_F );
183  result[2] = -deltaLLA[2];
184 }
185 
186 
187 /*
188  * Find LLA of NED (north, east, down) from LLAref (WGS-84 standard)
189  *
190  * lla[0] = latitude (rad)
191  * lla[1] = longitude (rad)
192  * lla[2] = msl altitude (m)
193  */
194 void ned2lla(ixVector3 ned, ixVector3 llaRef, ixVector3 result)
195 {
196  ixVector3 deltaLLA;
197  ned2DeltaLla( ned, llaRef, deltaLLA );
198 
199  // Find LLA
200  result[0] = llaRef[0] + deltaLLA[0];
201  result[1] = llaRef[1] + deltaLLA[1];
202  result[2] = llaRef[2] + deltaLLA[2];
203 }
204 
205 
206 /*
207  * Find LLA of NED (north, east, down) from LLAref (WGS-84 standard)
208  *
209  * lla[0] = latitude (rad)
210  * lla[1] = longitude (rad)
211  * lla[2] = msl altitude (m)
212  */
213 void ned2lla_d(ixVector3 ned, double llaRef[3], double result[3])
214 {
215  double deltaLLA[3];
216  ned2DeltaLla_d( ned, llaRef, deltaLLA );
217 
218  // Find LLA
219  result[0] = llaRef[0] + deltaLLA[0];
220  result[1] = llaRef[1] + deltaLLA[1];
221  result[2] = llaRef[2] + deltaLLA[2];
222 }
223 
224 
225 /*
226 * Find LLA of NED (north, east, down) from LLAref (WGS-84 standard)
227 *
228 * lla[0] = latitude (degrees)
229 * lla[1] = longitude (degrees)
230 * lla[2] = msl altitude (m)
231 */
232 void ned2llaDeg_d(ixVector3 ned, double llaRef[3], double result[3])
233 {
234  double deltaLLA[3];
235  ned2DeltaLlaDeg_d(ned, llaRef, deltaLLA);
236 
237  // Find LLA
238  result[0] = llaRef[0] + deltaLLA[0];
239  result[1] = llaRef[1] + deltaLLA[1];
240  result[2] = llaRef[2] + deltaLLA[2];
241 }
242 
243 
244 /*
245  * Find msl altitude based on barometric pressure
246  * https://en.wikipedia.org/wiki/Atmospheric_pressure
247  *
248  * baroKPa = (kPa) barometric pressure in kilopascals
249  * return = (m) msl altitude in meters
250  */
251 f_t baro2msl( f_t pKPa )
252 {
253  if( pKPa <= _ZERO )
254  return _ZERO;
255  else
256  return (f_t)C_NEG_KT0_DIV_MG_F * _LOG( pKPa * (f_t)C_INV_P0_KPA_F );
257 }
258 
259 
260 /*
261  * Find linear distance between lat,lon,alt (rad,rad,m) coordinates.
262  *
263  * return = (m) distance in meters
264  */
265 f_t llaRadDistance( double lla1[3], double lla2[3] )
266 {
267  ixVector3 ned;
268 
269  lla2ned_d( lla1, lla2, ned );
270 
271  return _SQRT( ned[0]*ned[0] + ned[1]*ned[1] + ned[2]*ned[2] );
272 }
273 
274 /*
275  * Find linear distance between lat,lon,alt (deg,deg,m) coordinates.
276  *
277  * return = (m) distance in meters
278  */
279 f_t llaDegDistance( double lla1[3], double lla2[3] )
280 {
281  ixVector3 ned;
282 
283  llaDeg2ned_d( lla1, lla2, ned );
284 
285  return _SQRT( ned[0]*ned[0] + ned[1]*ned[1] + ned[2]*ned[2] );
286 }
287 
288 void ned2DeltaLla(ixVector3 ned, ixVector3 llaRef, ixVector3 deltaLLA)
289 {
290  deltaLLA[0] = ned[0] * INV_EARTH_RADIUS_F;
291  deltaLLA[1] = ned[1] * INV_EARTH_RADIUS_F / _COS(((f_t)llaRef[0]));
292  deltaLLA[2] = -ned[2];
293 }
294 
295 void ned2DeltaLla_d(ixVector3 ned, double llaRef[3], double deltaLLA[3])
296 {
297  deltaLLA[0] = (double)( ned[0] * INV_EARTH_RADIUS_F);
298  deltaLLA[1] = (double)( ned[1] * INV_EARTH_RADIUS_F / _COS(((f_t)llaRef[0])) );
299  deltaLLA[2] = (double)(-ned[2]);
300 }
301 
302 void ned2DeltaLlaDeg_d(ixVector3 ned, double llaRef[3], double deltaLLA[3])
303 {
304  deltaLLA[0] = (double)(ned[0] * INV_EARTH_RADIUS_F * C_RAD2DEG_F);
305  deltaLLA[1] = (double)(ned[1] * INV_EARTH_RADIUS_F * C_RAD2DEG_F / _COS( (((f_t)llaRef[0])*C_DEG2RAD_F) ) );
306  deltaLLA[2] = (double)(-ned[2]);
307 }
308 
309 // Convert LLA from radians to degrees
310 void lla_Rad2Deg_d(double result[3], double lla[3])
311 {
312  result[0] = C_RAD2DEG * lla[0];
313  result[1] = C_RAD2DEG * lla[1];
314  result[2] = lla[2];
315 }
316 
317 // Convert LLA from degrees to radians
318 void lla_Deg2Rad_d(double result[3], double lla[3])
319 {
320  result[0] = C_DEG2RAD * lla[0];
321  result[1] = C_DEG2RAD * lla[1];
322  result[2] = lla[2];
323 }
324 
325 void lla_Deg2Rad_d2(double result[3], double lat, double lon, double alt)
326 {
327  result[0] = C_DEG2RAD * lat;
328  result[1] = C_DEG2RAD * lon;
329  result[2] = alt;
330 }
331 
332 /*
333  * Check if lat,lon,alt (deg,deg,m) coordinates are valid.
334  *
335  * return 1 on success, 0 on failure.
336  */
337 int llaDegValid( double lla[3] )
338 {
339  if( (lla[0]<-90.0) || (lla[0]>90.0) || // Lat
340  (lla[1]<-180.0) || (lla[1]>180.0) || // Lon
341  (lla[2]<-10000.0) || (lla[2]>1000000.0) ) // Alt: -10 to 1,000 kilometers
342  { // Invalid
343  return 0;
344  }
345  else
346  { // Valid
347  return 1;
348  }
349 }
350 
351 /* IGF-80 gravity model with WGS-84 ellipsoid refinement */
352 float gravity_igf80(double lat, double alt)
353 {
354  double g0, sinmu2;
355 
356  // Equatorial gravity
357  //float ge = 9.7803253359f;
358  // Defined constant k = (b*gp - a*ge) / a / ge;
359  //double k = 0.00193185265241;
360  // Square of first eccentricity e^2 = 1 - (1 - f)^2 = 1 - (b/a)^2;
361  //double e2 = 0.00669437999013;
362 
363  sinmu2 = sin(lat) * sin(lat);
364  g0 = GEQ * (1.0 + K_GRAV * sinmu2) / sqrt(1.0 - E_SQ * sinmu2);
365 
366  // Free air correction
367  return (float)( g0 - (K3_GRAV - K4_GRAV * sinmu2 - K5_GRAV * alt) * alt );
368 }
369 
#define E2xREQ
Definition: ISEarth.c:45
#define C_DEG2RAD
Definition: ISConstants.h:559
f_t ixVector3[3]
Definition: ISConstants.h:791
void ned2DeltaLla_d(ixVector3 ned, double llaRef[3], double deltaLLA[3])
Definition: ISEarth.c:295
f_t llaDegDistance(double lla1[3], double lla2[3])
Definition: ISEarth.c:279
float f_t
Definition: ISConstants.h:786
#define E_SQ
Definition: ISEarth.c:42
void ned2llaDeg_d(ixVector3 ned, double llaRef[3], double result[3])
Definition: ISEarth.c:232
void ned2lla(ixVector3 ned, ixVector3 llaRef, ixVector3 result)
Definition: ISEarth.c:194
#define GEQ
Definition: ISEarth.c:47
XmlRpcServer s
void lla_Deg2Rad_d2(double result[3], double lat, double lon, double alt)
Definition: ISEarth.c:325
#define _ZERO
Definition: ISConstants.h:782
f_t baro2msl(f_t pKPa)
Definition: ISEarth.c:251
void lla2ned(ixVector3 llaRef, ixVector3 lla, ixVector3 result)
Definition: ISEarth.c:123
int llaDegValid(double lla[3])
Definition: ISEarth.c:337
#define _LOG
Definition: ISConstants.h:778
#define C_NEG_KT0_DIV_MG_F
Definition: ISEarth.c:26
#define _SQRT
Definition: ISConstants.h:776
#define E2xREQdivIFE
Definition: ISEarth.c:46
void lla_Rad2Deg_d(double result[3], double lla[3])
Definition: ISEarth.c:310
#define C_RAD2DEG_F
Definition: ISConstants.h:562
#define K4_GRAV
Definition: ISEarth.c:50
#define C_DEG2RAD_F
Definition: ISConstants.h:560
void lla2ecef(const double *LLA, double *Pe)
Definition: ISEarth.c:91
void ned2DeltaLla(ixVector3 ned, ixVector3 llaRef, ixVector3 deltaLLA)
Definition: ISEarth.c:288
#define C_INV_P0_KPA_F
Definition: ISConstants.h:504
#define K5_GRAV
Definition: ISEarth.c:51
void lla_Deg2Rad_d(double result[3], double lla[3])
Definition: ISEarth.c:318
#define INV_EARTH_RADIUS_F
Definition: ISEarth.h:30
#define POWA2
Definition: ISEarth.c:36
void lla2ned_d(double llaRef[3], double lla[3], ixVector3 result)
Definition: ISEarth.c:147
#define C_RAD2DEG
Definition: ISConstants.h:561
void llaDeg2ned_d(double llaRef[3], double lla[3], ixVector3 result)
Definition: ISEarth.c:170
#define DEG2RAD_EARTH_RADIUS_F
Definition: ISEarth.h:26
void ecef2lla(const double *Pe, double *LLA, const int Niter)
Definition: ISEarth.c:54
f_t llaRadDistance(double lla1[3], double lla2[3])
Definition: ISEarth.c:265
#define POWB2
Definition: ISEarth.c:37
#define REQ
Definition: ISEarth.c:43
void ned2lla_d(ixVector3 ned, double llaRef[3], double result[3])
Definition: ISEarth.c:213
#define UNWRAP_F32(x)
Definition: ISConstants.h:766
#define _COS
Definition: ISConstants.h:771
void ned2DeltaLlaDeg_d(ixVector3 ned, double llaRef[3], double deltaLLA[3])
Definition: ISEarth.c:302
#define ONE_MINUS_F
Definition: ISEarth.c:41
#define K_GRAV
Definition: ISEarth.c:48
#define EARTH_RADIUS_F
Definition: ISEarth.h:29
float gravity_igf80(double lat, double alt)
Definition: ISEarth.c:352
#define K3_GRAV
Definition: ISEarth.c:49
#define UNWRAP_DEG_F32(x)
Definition: ISConstants.h:762


inertial_sense_ros
Author(s):
autogenerated on Sun Feb 28 2021 03:17:57