gps_pvt 0.1.7 → 0.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,306 @@
1
+ /**
2
+ * @file SBAS solver
3
+ *
4
+ */
5
+
6
+ /*
7
+ * Copyright (c) 2020, M.Naruoka (fenrir)
8
+ * All rights reserved.
9
+ *
10
+ * Redistribution and use in source and binary forms, with or without modification,
11
+ * are permitted provided that the following conditions are met:
12
+ *
13
+ * - Redistributions of source code must retain the above copyright notice,
14
+ * this list of conditions and the following disclaimer.
15
+ * - Redistributions in binary form must reproduce the above copyright notice,
16
+ * this list of conditions and the following disclaimer in the documentation
17
+ * and/or other materials provided with the distribution.
18
+ * - Neither the name of the naruoka.org nor the names of its contributors
19
+ * may be used to endorse or promote products derived from this software
20
+ * without specific prior written permission.
21
+ *
22
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
24
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS
26
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
27
+ * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
28
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
31
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
33
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34
+ *
35
+ */
36
+
37
+ #ifndef __SBAS_SOLVER_H__
38
+ #define __SBAS_SOLVER_H__
39
+
40
+ #include "SBAS.h"
41
+ #include "GPS_Solver_Base.h"
42
+ #include "GPS_Solver.h"
43
+
44
+ #include <cstddef>
45
+
46
+ template <class FloatT>
47
+ struct SBAS_SinglePositioning_Options : public GPS_Solver_GeneralOptions<FloatT> {
48
+ typedef GPS_Solver_GeneralOptions<FloatT> super_t;
49
+
50
+ typename GPS_Solver_Base<FloatT>::options_t::template exclude_prn_t<120, 158> exclude_prn; // SBAS PRN ranges from 120 to 158
51
+ SBAS_SinglePositioning_Options()
52
+ : super_t(), exclude_prn() {
53
+ exclude_prn.set(true); // SBAS ranging is default off.
54
+ }
55
+ };
56
+
57
+ template <class FloatT, class SolverBaseT = GPS_Solver_Base<FloatT> >
58
+ class SBAS_SinglePositioning : public SolverBaseT {
59
+ private:
60
+ SBAS_SinglePositioning<FloatT> &operator=(const SBAS_SinglePositioning<FloatT> &);
61
+ public:
62
+ typedef SBAS_SinglePositioning<FloatT> self_t;
63
+ typedef SolverBaseT base_t;
64
+
65
+ #if defined(__GNUC__) && (__GNUC__ < 5)
66
+ #define inheritate_type(x) typedef typename base_t::x x;
67
+ #else
68
+ #define inheritate_type(x) using typename base_t::x;
69
+ #endif
70
+
71
+ inheritate_type(float_t);
72
+ inheritate_type(prn_t);
73
+
74
+ typedef SBAS_SpaceNode<float_t> space_node_t;
75
+ inheritate_type(gps_time_t);
76
+ typedef typename space_node_t::Satellite satellite_t;
77
+
78
+ inheritate_type(xyz_t);
79
+ inheritate_type(enu_t);
80
+
81
+ inheritate_type(pos_t);
82
+
83
+ typedef typename base_t::measurement_t measurement_t;
84
+ typedef typename base_t::range_error_t range_error_t;
85
+ typedef typename base_t::range_corrector_t range_corrector_t;
86
+ typedef typename base_t::range_correction_t range_correction_t;
87
+
88
+ inheritate_type(relative_property_t);
89
+ #undef inheritate_type
90
+
91
+ typedef typename GPS_Solver_Base<float_t>::options_t::template merge_t<
92
+ SBAS_SinglePositioning_Options<float_t>, base_t> options_t;
93
+
94
+ protected:
95
+ const space_node_t &_space_node;
96
+ SBAS_SinglePositioning_Options<float_t> _options;
97
+
98
+ public:
99
+ const space_node_t &space_node() const {return _space_node;}
100
+
101
+ struct ionospheric_sbas_t : public range_corrector_t {
102
+ const space_node_t &space_node;
103
+ ionospheric_sbas_t(const space_node_t &sn) : range_corrector_t(), space_node(sn) {}
104
+ bool is_available(const gps_time_t &t) const {
105
+ return true;
106
+ }
107
+ float_t *calculate(
108
+ const gps_time_t &t, const pos_t &usr_pos, const enu_t &sat_rel_pos,
109
+ float_t &buf) const {
110
+
111
+ // placeholder of checking availability and performing correction
112
+ typedef typename space_node_t::available_satellites_t sats_t;
113
+ sats_t sats(space_node.available_satellites(usr_pos.llh.longitude()));
114
+
115
+ typename space_node_t::IonosphericGridPoints::PointProperty prop;
116
+ for(typename sats_t::const_iterator it(sats.begin()); it != sats.end(); ++it){
117
+ prop = it->second
118
+ ->ionospheric_grid_points().iono_correction(sat_rel_pos, usr_pos.llh);
119
+ if(prop.is_available()){
120
+ return &(buf = prop.delay);
121
+ }
122
+ break; // TODO The nearest satellite is only checked
123
+ }
124
+ return NULL;
125
+ }
126
+ } ionospheric_sbas;
127
+
128
+ struct tropospheric_sbas_t : public range_corrector_t {
129
+ tropospheric_sbas_t() : range_corrector_t() {}
130
+ bool is_available(const gps_time_t &t) const {
131
+ return true;
132
+ }
133
+ float_t *calculate(
134
+ const gps_time_t &t, const pos_t &usr_pos, const enu_t &sat_rel_pos,
135
+ float_t &buf) const {
136
+ return &(buf = space_node_t::tropo_correction(
137
+ t.year(), sat_rel_pos, usr_pos.llh));
138
+ }
139
+ } tropospheric_sbas;
140
+
141
+ range_correction_t ionospheric_correction, tropospheric_correction;
142
+
143
+ options_t available_options() const {
144
+ return options_t(base_t::available_options(), _options);
145
+ }
146
+
147
+ options_t available_options(const options_t &opt_wish) const {
148
+ SBAS_SinglePositioning_Options<float_t> opt(opt_wish);
149
+ return options_t(base_t::available_options(opt_wish), opt);
150
+ }
151
+
152
+ options_t update_options(const options_t &opt_wish){
153
+ _options = opt_wish;
154
+ return options_t(base_t::update_options(opt_wish), _options);
155
+ }
156
+
157
+ SBAS_SinglePositioning(const space_node_t &sn)
158
+ : base_t(), _space_node(sn), _options(available_options(options_t())),
159
+ ionospheric_sbas(sn), tropospheric_sbas() {
160
+
161
+ // default ionospheric correction: Broadcasted IGP.
162
+ ionospheric_correction.push_front(&ionospheric_sbas);
163
+
164
+ // default troposheric correction: SBAS
165
+ tropospheric_correction.push_front(&tropospheric_sbas);
166
+ }
167
+
168
+ ~SBAS_SinglePositioning(){}
169
+
170
+ /**
171
+ * Check availability of a satellite with which observation is associated
172
+ *
173
+ * @param prn satellite number
174
+ * @param receiver_time receiver time
175
+ * @return (const satellite_t *) If available, const pointer to satellite is returned,
176
+ * otherwise NULL.
177
+ */
178
+ const satellite_t *is_available(
179
+ const typename space_node_t::satellites_t::key_type &prn,
180
+ const gps_time_t &receiver_time) const {
181
+
182
+ const typename space_node_t::satellites_t &sats(_space_node.satellites());
183
+ const typename space_node_t::satellites_t::const_iterator it_sat(sats.find(prn));
184
+ if((it_sat == sats.end()) // has ephemeris?
185
+ || (!it_sat->second.ephemeris().is_valid(receiver_time))){ // valid ephemeris?
186
+ return NULL;
187
+ }
188
+
189
+ return &(it_sat->second);
190
+ }
191
+
192
+ /**
193
+ * Calculate relative range and rate information to a satellite
194
+ *
195
+ * @param prn satellite number
196
+ * @param measurement measurement (per satellite) containing pseudo range
197
+ * @param receiver_error (temporal solution of) receiver clock error in meter
198
+ * @param time_arrival time when signal arrive at receiver
199
+ * @param usr_pos (temporal solution of) user position
200
+ * @param usr_vel (temporal solution of) user velocity
201
+ * @return (relative_property_t) relative information
202
+ */
203
+ relative_property_t relative_property(
204
+ const prn_t &prn,
205
+ const typename measurement_t::mapped_type &measurement,
206
+ const float_t &receiver_error,
207
+ const gps_time_t &time_arrival,
208
+ const pos_t &usr_pos,
209
+ const xyz_t &usr_vel) const {
210
+
211
+ relative_property_t res = {0};
212
+
213
+ if(_options.exclude_prn[prn]){return res;}
214
+
215
+ float_t range;
216
+ range_error_t range_error;
217
+ if(!this->range(measurement, range, &range_error)){
218
+ return res; // If no range entry, return with weight = 0
219
+ }
220
+
221
+ const satellite_t *sat(is_available(prn, time_arrival));
222
+ if(!sat){return res;} // If satellite is unavailable, return with weight = 0
223
+
224
+ ///< The following procedure is based on Appendix.S with modification
225
+
226
+ range -= receiver_error;
227
+
228
+ // Clock correction will be performed in the following constellation()
229
+ if(!(range_error.unknown_flag & range_error_t::SATELLITE_CLOCK)){
230
+ range += range_error.value[range_error_t::SATELLITE_CLOCK];
231
+ }
232
+
233
+ // TODO WAAS long term clock correction (2.1.1.4.11)
234
+
235
+ // Calculate satellite position and velocity
236
+ typename space_node_t::SatelliteProperties::constellation_t sat_pos_vel(
237
+ sat->ephemeris().constellation(time_arrival, range));
238
+
239
+ const xyz_t &sat_pos(sat_pos_vel.position);
240
+ float_t geometric_range(usr_pos.xyz.dist(sat_pos));
241
+
242
+ // Calculate residual with Sagnac correction (A.4.4.11)
243
+ res.range_residual = range
244
+ + space_node_t::sagnac_correction(sat_pos, usr_pos.xyz)
245
+ - geometric_range;
246
+
247
+ // Setup design matrix
248
+ res.los_neg[0] = -(sat_pos.x() - usr_pos.xyz.x()) / geometric_range;
249
+ res.los_neg[1] = -(sat_pos.y() - usr_pos.xyz.y()) / geometric_range;
250
+ res.los_neg[2] = -(sat_pos.z() - usr_pos.xyz.z()) / geometric_range;
251
+
252
+ enu_t relative_pos(enu_t::relative(sat_pos, usr_pos.xyz));
253
+
254
+ // Tropospheric (2.1.4.10.3, A.4.2.4)
255
+ res.range_residual += (range_error.unknown_flag & range_error_t::MASK_TROPOSPHERIC)
256
+ ? tropospheric_correction(time_arrival, usr_pos, relative_pos)
257
+ : range_error.value[range_error_t::TROPOSPHERIC];
258
+
259
+ // Ionospheric (2.1.4.10.2, A.4.4.10.4)
260
+ if(range_error.unknown_flag & range_error_t::MASK_IONOSPHERIC){
261
+ res.range_residual += ionospheric_correction(time_arrival, usr_pos, relative_pos);
262
+ }else{
263
+ res.range_residual += range_error.value[range_error_t::IONOSPHERIC];
264
+ }
265
+
266
+ // TODO Fast corrections (2.1.1.4.12)
267
+
268
+ // TODO Setup weight
269
+ if(std::abs(res.range_residual) > _options.residual_mask){
270
+ // If residual is too big, gently exclude it by decreasing its weight.
271
+ res.weight = 1E-8;
272
+ }else{
273
+
274
+ float_t elv(relative_pos.elevation());
275
+ if(elv < _options.elevation_mask){
276
+ res.weight = 0; // exclude it when elevation is less than threshold
277
+ }else{
278
+ // elevation weight based on "GPS���p�v���O���~���O" @see GPS_Solver.h
279
+ res.weight = std::pow(sin(elv)/0.8, 2);
280
+ if(res.weight < 1E-3){res.weight = 1E-3;}
281
+ }
282
+ }
283
+
284
+ res.range_corrected = range;
285
+
286
+ xyz_t rel_vel(sat_pos_vel.velocity - usr_vel); // Calculate velocity
287
+
288
+ // Note: clock rate error is already accounted for in constellation()
289
+ res.rate_relative_neg = res.los_neg[0] * rel_vel.x()
290
+ + res.los_neg[1] * rel_vel.y()
291
+ + res.los_neg[2] * rel_vel.z();
292
+
293
+ return res;
294
+ }
295
+
296
+ xyz_t *satellite_position(
297
+ const prn_t &prn,
298
+ const gps_time_t &time,
299
+ xyz_t &res) const {
300
+
301
+ const satellite_t *sat(is_available(prn, time));
302
+ return sat ? &(res = sat->ephemeris().constellation(time).position) : NULL;
303
+ }
304
+ };
305
+
306
+ #endif /* __SBAS_SOLVER_H__ */
@@ -60,6 +60,7 @@ struct const_div_t<denom, denom, log2, 0> {
60
60
  template <int MAX_SIZE, class ContainerT = unsigned char>
61
61
  struct BitArray {
62
62
  static const int bits_per_addr = (int)sizeof(ContainerT) * CHAR_BIT;
63
+ static const int max_size = MAX_SIZE;
63
64
  ContainerT buf[(MAX_SIZE + bits_per_addr - 1) / bits_per_addr];
64
65
  void set(const bool &new_bit = false) {
65
66
  std::memset(buf, (new_bit ? (~0) : 0), sizeof(buf));
@@ -128,14 +129,14 @@ struct BitArray {
128
129
  std::vector<int> res;
129
130
  int idx(0);
130
131
  static const const_div_t<bits_per_addr> qr(MAX_SIZE);
131
- int rem(qr.rem);
132
- for(int i(0); i < qr.quot; ++i, idx += bits_per_addr){
132
+ int rem(qr.rem), i(0);
133
+ for(; i < qr.quot; ++i, idx += bits_per_addr){
133
134
  int idx2(idx);
134
135
  for(ContainerT temp(buf[i]); temp > 0; temp >>= 1, ++idx2){
135
136
  if(temp & 0x1){res.push_back(idx2);}
136
137
  }
137
138
  }
138
- for(ContainerT temp(buf[qr.quot + 1]); (temp > 0) && (rem > 0); --rem, ++idx, temp >>= 1){
139
+ for(ContainerT temp(buf[i]); (temp > 0) && (rem > 0); --rem, ++idx, temp >>= 1){
139
140
  if(temp & 0x1){res.push_back(idx);}
140
141
  }
141
142
  return res;