Skip to content
This repository was archived by the owner on Apr 13, 2021. It is now read-only.

Commit 45657c9

Browse files
committed
Merge pull request #269 from swift-nav/improve-almanac
Improve almanac and ephemeris functions
2 parents c0c00b4 + 2c5bc9b commit 45657c9

File tree

15 files changed

+828
-415
lines changed

15 files changed

+828
-415
lines changed

include/libswiftnav/almanac.h

Lines changed: 37 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -15,57 +15,60 @@
1515

1616
#include <libswiftnav/common.h>
1717
#include <libswiftnav/signal.h>
18+
#include <libswiftnav/time.h>
1819

1920
/** \addtogroup almanac
2021
* \{ */
2122

2223
/** Structure containing the GPS almanac for one satellite. */
2324
typedef struct {
24-
double ecc; /**< Eccentricity (unitless) */
25-
double toa; /**< Time of Applicability in seconds since Sunday. */
26-
double inc; /**< Inclination in radians. */
27-
double rora; /**< Rate of Right Ascension in radians/sec. */
28-
double a; /**< Semi-major axis in meters. */
29-
double raaw; /**< Right Ascension at Week in radians. */
30-
double argp; /**< Argument of Perigee in radians. */
31-
double ma; /**< Mean Anomaly at Time of Applicability in radians. */
32-
double af0; /**< 0-order clock correction in seconds. */
33-
double af1; /**< 1-order clock correction in seconds/second. */
34-
u16 week; /**< GPS week number, modulo 1024. */
35-
} almanac_gps_t;
25+
double m0; /**< Mean anomaly at reference time [semi-circles] */
26+
double ecc; /**< Eccentricity. */
27+
double sqrta; /**< Square root of the semi-major axis [sqrt(m)] */
28+
double omega0; /**< Longitude of ascending node
29+
of orbit plane at weekly epoch [semi-circles] */
30+
double omegadot; /**< Rate of right ascension [semi-circles/s] */
31+
double w; /**< Argument of perigee [semi-circles] */
32+
double inc; /**< Inclindation angle at reference time [semi-circles]
33+
This must include the 0.3 offset from NAV delta_i. */
34+
double af0; /**< Time offset of the sat clock [s] **/
35+
double af1; /**< Drift of the sat clock [s/s] **/
36+
} almanac_kepler_t;
3637

3738
/** Structure containing the SBAS almanac for one satellite. */
3839
typedef struct {
39-
u8 data_id; /**< Data ID. */
40-
41-
u16 x; /**< X coordinate ECEF. */
42-
u16 y; /**< Y coordinate ECEF. */
43-
u16 z; /**< Z coordinate ECEF. */
44-
45-
u8 x_rate; /**< X coordinate rate of change [m/s]. */
46-
u8 y_rate; /**< Y coordinate rate of change [m/s]. */
47-
u8 z_rate; /**< Z coordinate rate of change [m/s]. */
48-
49-
u16 t0; /**< Time of day [seconds]. */
50-
} almanac_sbas_t;
40+
double pos[3]; /**< Position of the GEO at time toe [m] */
41+
double vel[3]; /**< velocity of the GEO at time toe [m/s] */
42+
double acc[3]; /**< velocity of the GEO at time toe [m/s^2] */
43+
} almanac_xyz_t;
5144

45+
/** Structure containing the almanac for one satellite. */
5246
typedef struct {
5347
gnss_signal_t sid; /**< Signal ID. */
54-
u8 healthy; /**< Satellite health status. */
55-
u8 valid; /**< Almanac is valid. */
48+
gps_time_t toa; /**< Reference time of almanac. */
49+
float ura; /**< User range accuracy [m] */
50+
u32 fit_interval; /**< Curve fit interval [s] */
51+
u8 valid; /**< Almanac is valid. */
52+
u8 healthy; /**< Satellite health status. */
5653
union {
57-
almanac_gps_t gps;
58-
almanac_sbas_t sbas;
54+
almanac_kepler_t kepler; /**< Parameters specific to GPS. */
55+
almanac_xyz_t xyz; /**< Parameters specific to SBAS. */
5956
};
6057
} almanac_t;
6158

6259
/** \} */
6360

64-
void calc_sat_state_almanac(const almanac_t* alm, double t, s16 week,
65-
double pos[3], double vel[3]);
66-
void calc_sat_az_el_almanac(const almanac_t* alm, double t, s16 week,
67-
const double ref[3], double* az, double* el);
68-
double calc_sat_doppler_almanac(const almanac_t* alm, double t, s16 week,
69-
const double ref[3]);
61+
s8 calc_sat_state_almanac(const almanac_t *a, const gps_time_t *t,
62+
double pos[3], double vel[3],
63+
double *clock_err, double *clock_rate_err);
64+
s8 calc_sat_az_el_almanac(const almanac_t *a, const gps_time_t *t,
65+
const double ref[3], double *az, double *el);
66+
s8 calc_sat_doppler_almanac(const almanac_t *a, const gps_time_t *t,
67+
const double ref[3], double *doppler);
68+
69+
u8 almanac_valid(const almanac_t *a, const gps_time_t *t);
70+
u8 satellite_healthy_almanac(const almanac_t *a);
71+
72+
bool almanac_equal(const almanac_t *a, const almanac_t *b);
7073

7174
#endif /* LIBSWIFTNAV_ALMANAC_H */

include/libswiftnav/ephemeris.h

Lines changed: 58 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -18,50 +18,81 @@
1818
#include <libswiftnav/time.h>
1919
#include <libswiftnav/common.h>
2020

21+
/** \addtogroup ephemeris
22+
* \{ */
23+
24+
/** Structure containing the GPS ephemeris for one satellite. */
2125
typedef struct {
22-
double tgd;
23-
double crs, crc, cuc, cus, cic, cis;
24-
double dn, m0, ecc, sqrta, omega0, omegadot, w, inc, inc_dot;
25-
double af0, af1, af2;
26-
gps_time_t toc;
27-
u16 iodc;
28-
u8 iode;
26+
double tgd; /**< Group delay between L1 and L2 [s] */
27+
double crc; /**< Amplitude of the cosine harmonic correction term
28+
to the orbit radius [m] */
29+
double crs; /**< Amplitude of the sine harmonic correction term
30+
to the orbit radius [m] */
31+
double cuc; /**< Amplitude of the cosine harmonic correction term
32+
to the argument of latitude [rad] */
33+
double cus; /**< Amplitude of the sine harmonic correction term
34+
to the argument of latitude [rad] */
35+
double cic; /**< Amplitude of the cosine harmonic correction term
36+
to the angle of inclination [rad] */
37+
double cis; /**< Amplitude of the sine harmonic correction term
38+
to the angle of inclination [rad] */
39+
double dn; /**< Mean motion difference from computed value
40+
[semi-circles/s] */
41+
double m0; /**< Mean anomaly at reference time [semi-circles] */
42+
double ecc; /**< Eccentricity. */
43+
double sqrta; /**< Square root of the semi-major axis [sqrt(m)] */
44+
double omega0; /**< Longitude of ascending node
45+
of orbit plane at weekly epoch [semi-circles] */
46+
double omegadot; /**< Rate of right ascension [semi-circles/s] */
47+
double w; /**< Argument of perigee [semi-circles] */
48+
double inc; /**< Inclindation angle at reference time [semi-circles] */
49+
double inc_dot; /**< Rate of inclination angle [semi-circles/s] */
50+
double af0; /**< Time offset of the sat clock [s] **/
51+
double af1; /**< Drift of the sat clock [s/s] **/
52+
double af2; /**< Acceleration of the sat clock [s/s^2] **/
53+
gps_time_t toc; /**< Reference time of clock. */
54+
u16 iodc; /**< Issue of data clock. */
55+
u8 iode; /**< Issue of data ephemeris. */
2956
} ephemeris_kepler_t;
3057

58+
/** Structure containing the SBAS ephemeris for one satellite. */
3159
typedef struct {
32-
double pos[3];
33-
double rate[3];
34-
double acc[3];
35-
u8 iod;
36-
u16 toa;
37-
double a_gf0;
38-
double a_gf1;
60+
double pos[3]; /**< Position of the GEO at time toe [m] */
61+
double vel[3]; /**< velocity of the GEO at time toe [m/s] */
62+
double acc[3]; /**< velocity of the GEO at time toe [m/s^2] */
63+
double a_gf0; /**< Time offset of the GEO clock w.r.t. SNT [s] */
64+
double a_gf1; /**< Drift of the GEO clock w.r.t. SNT [s/s] */
3965
} ephemeris_xyz_t;
4066

67+
/** Structure containing the ephemeris for one satellite. */
4168
typedef struct {
42-
gnss_signal_t sid;
43-
gps_time_t toe;
44-
float ura;
45-
u8 fit_interval;
46-
u8 valid;
47-
u8 healthy;
69+
gnss_signal_t sid; /**< Signal ID. */
70+
gps_time_t toe; /**< Reference time of ephemeris. */
71+
float ura; /**< User range accuracy [m] */
72+
u32 fit_interval; /**< Curve fit interval [s] */
73+
u8 valid; /**< Ephemeris is valid. */
74+
u8 healthy; /**< Satellite health status. */
4875
union {
49-
ephemeris_kepler_t kepler;
50-
ephemeris_xyz_t xyz;
76+
ephemeris_kepler_t kepler; /**< Parameters specific to GPS. */
77+
ephemeris_xyz_t xyz; /**< Parameters specific to SBAS. */
5178
};
5279
} ephemeris_t;
5380

81+
/** \} */
82+
5483
s8 calc_sat_state(const ephemeris_t *e, const gps_time_t *t,
5584
double pos[3], double vel[3],
5685
double *clock_err, double *clock_rate_err);
86+
s8 calc_sat_az_el(const ephemeris_t *e, const gps_time_t *t,
87+
const double ref[3], double *az, double *el);
88+
s8 calc_sat_doppler(const ephemeris_t *e, const gps_time_t *t,
89+
const double ref[3], double *doppler);
5790

58-
u8 ephemeris_valid(const ephemeris_t *eph, const gps_time_t *t);
59-
u8 ephemeris_params_valid(const u8 v, const u8 fit_interval,
91+
u8 ephemeris_valid(const ephemeris_t *e, const gps_time_t *t);
92+
u8 ephemeris_params_valid(const u8 valid, const u32 fit_interval,
6093
const gps_time_t* toe, const gps_time_t *t);
61-
u8 satellite_healthy(const ephemeris_t *eph);
94+
u8 satellite_healthy(const ephemeris_t *e);
6295

63-
float decode_ura_index(const u8 index);
64-
u8 decode_fit_interval(u8 fit_interval_flag, u16 iodc);
6596
void decode_ephemeris(u32 frame_words[3][8], ephemeris_t *e);
6697
bool ephemeris_equal(const ephemeris_t *a, const ephemeris_t *b);
6798

python/swiftnav/almanac.pxd

Lines changed: 25 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -8,43 +8,40 @@
88
# WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
99

1010
from common cimport *
11-
from signal cimport *
11+
from time cimport gps_time_t
12+
from signal cimport gnss_signal_t
1213

1314
cdef extern from "libswiftnav/almanac.h":
14-
ctypedef struct almanac_gps_t:
15-
double ecc
16-
double toa
17-
double inc
18-
double rora
19-
double a
20-
double raaw
21-
double argp
22-
double ma
23-
double af0
24-
double af1
25-
u16 week
15+
ctypedef struct almanac_kepler_t:
16+
double m0, ecc, sqrta, omega0, omegadot, w, inc
17+
double af0, af1
2618

27-
ctypedef struct almanac_sbas_t:
28-
u8 data_id
29-
u16 x
30-
u16 y
31-
u16 z
32-
u8 x_rate
33-
u8 y_rate
34-
u8 z_rate
35-
u16 t0
19+
ctypedef struct almanac_xyz_t:
20+
double pos[3]
21+
double vel[3]
22+
double acc[3]
3623

3724
ctypedef struct almanac_t:
3825
gnss_signal_t sid
39-
u8 healthy
26+
gps_time_t toa
27+
float ura
28+
u32 fit_interval
4029
u8 valid
30+
u8 healthy
4131
# HACK: Actually an anonymous union in libswiftnat!
42-
almanac_gps_t gps
43-
almanac_sbas_t sbas
32+
almanac_kepler_t kepler
33+
almanac_xyz_t xyz
4434

45-
void calc_sat_state_almanac(almanac_t* alm, double t, s16 week, double pos[3], double vel[3])
46-
void calc_sat_az_el_almanac(almanac_t* alm, double t, s16 week, double ref[3], double* az, double* el)
47-
double calc_sat_doppler_almanac(almanac_t* alm, double t, s16 week, double ref[3])
35+
void calc_sat_state_almanac(const almanac_t *a, const gps_time_t *t,
36+
double pos[3], double vel[3],
37+
double *clock_err, double *clock_rate_err)
38+
void calc_sat_az_el_almanac(const almanac_t *a, const gps_time_t *t,
39+
double ref[3], double *az, double *el)
40+
double calc_sat_doppler_almanac(const almanac_t *a, const gps_time_t *t,
41+
double ref[3], double *doppler)
42+
u8 almanac_valid(const almanac_t *a, const gps_time_t *t)
43+
u8 satellite_healthy_almanac(const almanac_t *a)
44+
u8 almanac_equal(const almanac_t *a, const almanac_t *b)
4845

4946
cdef class Almanac:
5047
cdef almanac_t _thisptr

python/swiftnav/almanac.pyx

Lines changed: 25 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ Note: All positions are referenced to the WGS84 coordinate system.
1717
"""
1818

1919
from common cimport *
20+
from time cimport *
21+
from time import GpsTime
2022
from fmt_utils import fmt_repr
2123
from libc.string cimport memset
2224
cimport numpy as np
@@ -27,12 +29,15 @@ cdef class Almanac:
2729
def __init__(self, **kwargs):
2830
memset(&self._thisptr, 0, sizeof(almanac_t))
2931
self._thisptr.sid = kwargs.pop('sid')
30-
self._thisptr.healthy = kwargs.pop('healthy')
32+
self._thisptr.toa = kwargs.pop('toa')
33+
self._thisptr.ura = kwargs.pop('ura')
34+
self._thisptr.fit_interval = kwargs.pop('fit_interval')
3135
self._thisptr.valid = kwargs.pop('valid')
32-
if 'gps' in kwargs:
33-
self._thisptr.gps = kwargs.pop('gps')
34-
elif 'sbas' in kwargs:
35-
self._thisptr.sbas = kwargs.pop('sbas')
36+
self._thisptr.healthy = kwargs.pop('healthy')
37+
if 'kepler' in kwargs:
38+
self._thisptr.kepler = kwargs.pop('kepler')
39+
elif 'xyz' in kwargs:
40+
self._thisptr.xyz = kwargs.pop('xyz')
3641

3742
def __getattr__(self, k):
3843
return self._thisptr.get(k)
@@ -46,17 +51,14 @@ cdef class Almanac:
4651
def from_dict(self, d):
4752
self._thisptr = d
4853

49-
def calc_state(self, t, week=-1):
54+
def calc_state(self, GpsTime t):
5055
"""
5156
Wraps the function :libswiftnav:`calc_sat_state_almanac`.
5257
5358
Parameters
5459
----------
55-
t : float
60+
t : GpsTime
5661
The GPS time at which to calculate the azimuth and elevation.
57-
week : int, optional
58-
The GPS week number modulo 1024. If `None` then it is assumed that `t` is
59-
within one half week of the almanac time of applicability.
6062
6163
Returns
6264
-------
@@ -65,24 +67,22 @@ cdef class Almanac:
6567
coordinate system.
6668
6769
"""
68-
cdef np.ndarray[np.double_t, ndim=1, mode="c"] pos = np.empty(3, dtype=np.double)
69-
cdef np.ndarray[np.double_t, ndim=1, mode="c"] vel = np.empty(3, dtype=np.double)
70-
calc_sat_state_almanac(&self._thisptr, t, week, &pos[0], &vel[0])
71-
return (pos, vel)
70+
cdef np.ndarray[np.double_t, ndim=1, mode="c"] pos = np.array([0,0,0], dtype=np.double)
71+
cdef np.ndarray[np.double_t, ndim=1, mode="c"] vel = np.array([0,0,0], dtype=np.double)
72+
cdef double clock_err, clock_rate_err
73+
calc_sat_state_almanac(&self._thisptr, &t._thisptr, &pos[0], &vel[0], &clock_err, &clock_rate_err)
74+
return (pos, vel, clock_err, clock_rate_err)
7275

73-
def calc_az_el(self, t, ref, week=None):
76+
def calc_az_el(self, GpsTime t, ref):
7477
"""
7578
Wraps the function :libswiftnav:`calc_sat_az_el_almanac`.
7679
7780
Parameters
7881
----------
79-
t : float
82+
t : GpsTime
8083
The GPS time at which to calculate the azimuth and elevation.
8184
ref : (float, float, float)
8285
The tuple of coordinates of the reference position, `(x, y, z)`
83-
week : int, optional
84-
The GPS week number modulo 1024. If `None` then it is assumed that `t` is
85-
within one half week of the almanac time of applicability.
8686
8787
Returns
8888
-------
@@ -93,22 +93,19 @@ cdef class Almanac:
9393
assert len(ref) == 3, "ECEF coordinates must have dimension 3."
9494
cdef np.ndarray[np.double_t, ndim=1, mode="c"] ref_ = np.array(ref, dtype=np.double)
9595
cdef double az, el
96-
calc_sat_az_el_almanac(&self._thisptr, t, week, &ref_[0], &az, &el)
96+
calc_sat_az_el_almanac(&self._thisptr, &t._thisptr, &ref_[0], &az, &el)
9797
return (az, el)
9898

99-
def calc_doppler(self, t, ref, week=-1):
99+
def calc_doppler(self, GpsTime t, ref):
100100
"""
101101
Wraps the function :libswiftnav:`calc_sat_doppler_almanac`.
102102
103103
Parameters
104104
----------
105-
t : float
105+
t : GpsTime
106106
The GPS time at which to calculate the Doppler shift.
107107
ref : (float, float, float)
108108
The tuple of coordinates of the reference position, `(x, y, z)`
109-
week : int, optional
110-
The GPS week number modulo 1024. If `None` then it is assumed that `t` is
111-
within one half week of the almanac time of applicability.
112109
113110
Returns
114111
-------
@@ -118,4 +115,6 @@ cdef class Almanac:
118115
"""
119116
assert len(ref) == 3, "ECEF coordinates must have dimension 3."
120117
cdef np.ndarray[np.double_t, ndim=1, mode="c"] ref_ = np.array(ref, dtype=np.double)
121-
return calc_sat_doppler_almanac(&self._thisptr, t, week, &ref_[0])
118+
cdef double doppler
119+
calc_sat_doppler_almanac(&self._thisptr, &t._thisptr, &ref_[0], &doppler)
120+
return doppler

0 commit comments

Comments
 (0)