gps_pvt 0.2.0 → 0.3.0

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.
@@ -526,6 +526,9 @@ class GPS_SpaceNode {
526
526
  return res;
527
527
  }
528
528
  static const float_t gamma_L1_L2;
529
+ static const float_t gamma_per_L1(const float_t &freq){
530
+ return std::pow(L1_Frequency / freq, 2);
531
+ }
529
532
 
530
533
  protected:
531
534
  static float_t rad2sc(const float_t &rad) {return rad / M_PI;}
@@ -2151,37 +2154,17 @@ if(std::abs(TARGET - eph.TARGET) > raw_t::sf[raw_t::SF_ ## TARGET]){break;}
2151
2154
  usr.llh(),
2152
2155
  t);
2153
2156
  }
2154
-
2155
- struct IonospericCorrection {
2156
- const GPS_SpaceNode<float_t> &space_node;
2157
- float_t operator()(
2158
- const enu_t &relative_pos,
2159
- const llh_t &usrllh,
2160
- const gps_time_t &t) const {
2161
- return space_node.iono_correction(relative_pos, usrllh, t);
2162
- }
2163
- float_t operator()(
2164
- const xyz_t &sat,
2165
- const xyz_t &usr,
2166
- const gps_time_t &t) const {
2167
- return space_node.iono_correction(sat, usr, t);
2168
- }
2169
- };
2170
- IonospericCorrection iono_correction() const {
2171
- IonospericCorrection res = {*this};
2172
- return res;
2173
- }
2174
2157
 
2175
2158
  /**
2176
- * Calculate correction value in accordance with tropospheric model
2159
+ * Calculate correction value in accordance with tropospheric Hopfield model
2177
2160
  *
2178
2161
  * @param relative_pos satellite position (relative position, NEU)
2179
2162
  * @param usrllh user position (absolute position, LLH)
2180
2163
  * @return correction in meters
2181
2164
  */
2182
- float_t tropo_correction(
2165
+ static float_t tropo_correction(
2183
2166
  const enu_t &relative_pos,
2184
- const llh_t &usrllh) const {
2167
+ const llh_t &usrllh){
2185
2168
 
2186
2169
  // Elevation (rad)
2187
2170
  float_t el(relative_pos.elevation());
@@ -2291,31 +2274,13 @@ if(std::abs(TARGET - eph.TARGET) > raw_t::sf[raw_t::SF_ ## TARGET]){break;}
2291
2274
  * @param usr user position (absolute position, XYZ)
2292
2275
  * @return correction in meters
2293
2276
  */
2294
- float_t tropo_correction(
2277
+ static float_t tropo_correction(
2295
2278
  const xyz_t &sat,
2296
- const xyz_t &usr) const {
2279
+ const xyz_t &usr) {
2297
2280
  return tropo_correction(
2298
2281
  enu_t::relative(sat, usr),
2299
2282
  usr.llh());
2300
2283
  }
2301
-
2302
- struct TropospericCorrection {
2303
- const GPS_SpaceNode<float_t> &space_node;
2304
- float_t operator()(
2305
- const enu_t &relative_pos,
2306
- const llh_t &usrllh) const {
2307
- return space_node.tropo_correction(relative_pos, usrllh);
2308
- }
2309
- float_t operator()(
2310
- const xyz_t &sat,
2311
- const xyz_t &usr) const {
2312
- return space_node.tropo_correction(sat, usr);
2313
- }
2314
- };
2315
- TropospericCorrection tropo_correction() const {
2316
- TropospericCorrection res = {*this};
2317
- return res;
2318
- }
2319
2284
  };
2320
2285
 
2321
2286
  template <class FloatT>
@@ -49,7 +49,6 @@
49
49
 
50
50
  #include "GPS.h"
51
51
  #include "GPS_Solver_Base.h"
52
- #include "SBAS.h"
53
52
  #include "NTCM.h"
54
53
 
55
54
  template <class FloatT>
@@ -57,66 +56,10 @@ struct GPS_Solver_GeneralOptions {
57
56
  FloatT elevation_mask;
58
57
  FloatT residual_mask;
59
58
 
60
- enum ionospheric_model_t {
61
- IONOSPHERIC_KLOBUCHAR,
62
- IONOSPHERIC_SBAS,
63
- IONOSPHERIC_NTCM_GL,
64
- IONOSPHERIC_NONE, // which allows no correction
65
- IONOSPHERIC_MODELS,
66
- IONOSPHERIC_SKIP = IONOSPHERIC_MODELS, // which means delegating the next slot
67
- };
68
- ionospheric_model_t ionospheric_models[IONOSPHERIC_MODELS]; // lower index means having higher priority
69
-
70
- int count_ionospheric_models() const {
71
- int res(0);
72
- for(std::size_t i(0); i < sizeof(ionospheric_models) / sizeof(ionospheric_models[0]); ++i){
73
- if(ionospheric_models[i] != IONOSPHERIC_SKIP){res++;}
74
- }
75
- return res;
76
- }
77
-
78
- FloatT f_10_7;
79
-
80
59
  GPS_Solver_GeneralOptions()
81
60
  : elevation_mask(0), // elevation mask default is 0 [deg]
82
- residual_mask(30), // range residual mask is 30 [m]
83
- f_10_7(-1) {
84
- for(std::size_t i(0); i < sizeof(ionospheric_models) / sizeof(ionospheric_models[0]); ++i){
85
- ionospheric_models[i] = IONOSPHERIC_SKIP;
86
- }
87
- // default: broadcasted Klobuchar parameters are at least required for solution.
88
- ionospheric_models[0] = IONOSPHERIC_KLOBUCHAR;
89
- }
90
-
91
- bool insert_ionospheric_model(const ionospheric_model_t &model, const int &index = 0) {
92
- if((index < 0)
93
- || (index >= sizeof(ionospheric_models) / sizeof(ionospheric_models[0]))){
94
- return false;
95
- }
61
+ residual_mask(30) { // range residual mask is 30 [m]
96
62
 
97
- // shift, then replace
98
- for(int i(index), j(i + 1); j < sizeof(ionospheric_models) / sizeof(ionospheric_models[0]); ++i, ++j){
99
- ionospheric_models[j] = ionospheric_models[i];
100
- }
101
- ionospheric_models[index] = model;
102
-
103
- return true;
104
- }
105
- bool remove_ionospheric_model(const ionospheric_model_t &model) {
106
- // shift, then replace
107
- int j(0);
108
- for(int i(0); i < sizeof(ionospheric_models) / sizeof(ionospheric_models[0]); ++i){
109
- if(ionospheric_models[i] == model){continue;}
110
- ionospheric_models[j++] = ionospheric_models[i];
111
- }
112
- if(j == (sizeof(ionospheric_models) / sizeof(ionospheric_models[0]))){
113
- return false;
114
- }
115
- do{
116
- ionospheric_models[j++] = IONOSPHERIC_SKIP;
117
- }while(j < sizeof(ionospheric_models) / sizeof(ionospheric_models[0]));
118
-
119
- return true;
120
63
  }
121
64
  };
122
65
 
@@ -158,24 +101,23 @@ class GPS_SinglePositioning : public SolverBaseT {
158
101
  inheritate_type(llh_t);
159
102
  inheritate_type(enu_t);
160
103
 
161
- typedef SBAS_SpaceNode<float_t> sbas_space_node_t;
162
-
163
104
  inheritate_type(pos_t);
164
105
 
165
106
  inheritate_type(prn_obs_t);
166
107
  typedef typename base_t::measurement_t measurement_t;
167
108
  inheritate_type(measurement_items_t);
168
109
  typedef typename base_t::range_error_t range_error_t;
110
+ typedef typename base_t::range_corrector_t range_corrector_t;
111
+ typedef typename base_t::range_correction_t range_correction_t;
169
112
 
170
113
  inheritate_type(relative_property_t);
171
114
  inheritate_type(geometric_matrices_t);
172
115
  inheritate_type(user_pvt_t);
173
116
  #undef inheritate_type
174
117
 
175
- const sbas_space_node_t *space_node_sbas; ///< optional
176
-
177
118
  typedef typename GPS_Solver_Base<float_t>::options_t::template merge_t<
178
119
  GPS_SinglePositioning_Options<float_t>, base_t> options_t;
120
+
179
121
  protected:
180
122
  const space_node_t &_space_node;
181
123
  GPS_SinglePositioning_Options<float_t> _options;
@@ -183,43 +125,50 @@ class GPS_SinglePositioning : public SolverBaseT {
183
125
  public:
184
126
  const space_node_t &space_node() const {return _space_node;}
185
127
 
186
- /**
187
- * Check availability of ionospheric models
188
- * If a model is completely unavailable, it will be replaced to IONOSPHERIC_SKIP.
189
- * It implies that when a model has conditional applicability (such as SBAS), it will be retained.
190
- *
191
- * @return (int) number of (possibly) available models
192
- */
193
- int filter_ionospheric_models(GPS_SinglePositioning_Options<float_t> &opt) const {
194
-
195
- int available_models(0);
196
-
197
- for(std::size_t i(0);
198
- i < sizeof(opt.ionospheric_models) / sizeof(opt.ionospheric_models[0]); ++i){
199
- bool usable(false);
200
- switch(opt.ionospheric_models[i]){
201
- case options_t::IONOSPHERIC_KLOBUCHAR:
202
- // check whether Klobuchar parameters alpha and beta have been already received
203
- if(_space_node.is_valid_iono()){usable = true;}
204
- break;
205
- case options_t::IONOSPHERIC_SBAS:
206
- if(space_node_sbas){usable = true;}
207
- break;
208
- case options_t::IONOSPHERIC_NTCM_GL:
209
- if(opt.f_10_7 >= 0){usable = true;}
210
- // check F10.7 has been already configured
211
- break;
212
- default: break;
213
- }
214
- if(usable){
215
- available_models++;
216
- }else{
217
- opt.ionospheric_models[i] = options_t::IONOSPHERIC_SKIP;
218
- }
128
+ struct klobuchar_t : public range_corrector_t {
129
+ const space_node_t &space_node;
130
+ klobuchar_t(const space_node_t &sn) : range_corrector_t(), space_node(sn) {}
131
+ bool is_available(const gps_time_t &t) const {
132
+ return space_node.is_valid_iono();
133
+ }
134
+ float_t *calculate(
135
+ const gps_time_t &t, const pos_t &usr_pos, const enu_t &sat_rel_pos,
136
+ float_t &buf) const {
137
+ return &(buf = space_node.iono_correction(sat_rel_pos, usr_pos.llh, t));
219
138
  }
139
+ } ionospheric_klobuchar;
220
140
 
221
- return available_models;
222
- }
141
+ struct ntcm_gl_t : public range_corrector_t {
142
+ float_t f_10_7;
143
+ ntcm_gl_t() : range_corrector_t(), f_10_7(-1) {}
144
+ bool is_available(const gps_time_t &t) const {
145
+ return f_10_7 >= 0;
146
+ }
147
+ float_t *calculate(
148
+ const gps_time_t &t, const pos_t &usr_pos, const enu_t &sat_rel_pos,
149
+ float_t &buf) const {
150
+ if(!is_available(t)){return NULL;}
151
+ typename space_node_t::pierce_point_res_t pp(
152
+ space_node_t::pierce_point(sat_rel_pos, usr_pos.llh));
153
+ return &(buf = -space_node_t::tec2delay(space_node_t::slant_factor(sat_rel_pos)
154
+ * NTCM_GL_Generic<float_t>::tec_vert(
155
+ pp.latitude, pp.longitude, t.year(), f_10_7)));
156
+ }
157
+ } ionospheric_ntcm_gl;
158
+
159
+ struct tropospheric_simplified_t : public range_corrector_t {
160
+ tropospheric_simplified_t() : range_corrector_t() {}
161
+ bool is_available(const gps_time_t &t) const {
162
+ return true;
163
+ }
164
+ float_t *calculate(
165
+ const gps_time_t &t, const pos_t &usr_pos, const enu_t &sat_rel_pos,
166
+ float_t &buf) const {
167
+ return &(buf = space_node_t::tropo_correction(sat_rel_pos, usr_pos.llh));
168
+ }
169
+ } tropospheric_simplified;
170
+
171
+ range_correction_t ionospheric_correction, tropospheric_correction;
223
172
 
224
173
  options_t available_options() const {
225
174
  return options_t(base_t::available_options(), _options);
@@ -227,20 +176,26 @@ class GPS_SinglePositioning : public SolverBaseT {
227
176
 
228
177
  options_t available_options(const options_t &opt_wish) const {
229
178
  GPS_SinglePositioning_Options<float_t> opt(opt_wish);
230
- filter_ionospheric_models(opt);
231
179
  return options_t(base_t::available_options(opt_wish), opt);
232
180
  }
233
181
 
234
182
  options_t update_options(const options_t &opt_wish){
235
- filter_ionospheric_models(_options = opt_wish);
183
+ _options = opt_wish;
236
184
  return options_t(base_t::update_options(opt_wish), _options);
237
185
  }
238
186
 
239
187
  GPS_SinglePositioning(const space_node_t &sn)
240
- : base_t(),
241
- _space_node(sn), space_node_sbas(NULL),
242
- _options() {
243
- filter_ionospheric_models(_options);
188
+ : base_t(), _space_node(sn), _options(available_options(options_t())),
189
+ ionospheric_klobuchar(sn), ionospheric_ntcm_gl(),
190
+ tropospheric_simplified(),
191
+ ionospheric_correction(), tropospheric_correction() {
192
+
193
+ // default ionospheric correction:
194
+ // Broadcasted Klobuchar parameters are at least required for solution.
195
+ ionospheric_correction.push_front(&ionospheric_klobuchar);
196
+
197
+ // default troposheric correction: simplified
198
+ tropospheric_correction.push_front(&tropospheric_simplified);
244
199
  }
245
200
 
246
201
  ~GPS_SinglePositioning(){}
@@ -294,55 +249,14 @@ class GPS_SinglePositioning : public SolverBaseT {
294
249
  enu_t relative_pos(enu_t::relative(sat_pos, usr_pos.xyz));
295
250
 
296
251
  if(error.unknown_flag & range_error_t::MASK_IONOSPHERIC){
297
- // Ionospheric model selection, the fall back is no correction
298
- bool iono_model_hit(false);
299
- for(std::size_t i(0);
300
- i < sizeof(_options.ionospheric_models) / sizeof(_options.ionospheric_models[0]);
301
- ++i){
302
- switch(_options.ionospheric_models[i]){
303
- case options_t::IONOSPHERIC_KLOBUCHAR:
304
- residual.residual += _space_node.iono_correction(relative_pos, usr_pos.llh, time_arrival);
305
- break;
306
- case options_t::IONOSPHERIC_SBAS: {
307
- // placeholder of checking availability and performing correction
308
- typedef typename SBAS_SpaceNode<float_t>::available_satellites_t sats_t;
309
- sats_t sats(space_node_sbas->available_satellites(usr_pos.llh.longitude()));
310
-
311
- typename SBAS_SpaceNode<float_t>::IonosphericGridPoints::PointProperty prop;
312
- for(typename sats_t::const_iterator it(sats.begin()); it != sats.end(); ++it){
313
- prop = it->second
314
- ->ionospheric_grid_points().iono_correction(relative_pos, usr_pos.llh);
315
- break; // TODO The nearest satellite is only checked
316
- }
317
- if(!prop.is_available()){continue;}
318
- residual.residual += prop.delay;
319
- break;
320
- }
321
- case options_t::IONOSPHERIC_NTCM_GL: {
322
- // TODO f_10_7 setup, optimization (mag_model etc.)
323
- typename space_node_t::pierce_point_res_t pp(_space_node.pierce_point(relative_pos, usr_pos.llh));
324
- residual.residual -= space_node_t::tec2delay(
325
- _space_node.slant_factor(relative_pos)
326
- * NTCM_GL_Generic<float_t>::tec_vert(
327
- pp.latitude, pp.longitude,
328
- time_arrival.year(), _options.f_10_7));
329
- break;
330
- }
331
- case options_t::IONOSPHERIC_NONE:
332
- break;
333
- default:
334
- continue;
335
- }
336
- iono_model_hit = true;
337
- break;
338
- }
252
+ residual.residual += ionospheric_correction(time_arrival, usr_pos, relative_pos);
339
253
  }else{
340
254
  residual.residual += error.value[range_error_t::IONOSPHERIC];
341
255
  }
342
256
 
343
257
  // Tropospheric
344
258
  residual.residual += (error.unknown_flag & range_error_t::MASK_TROPOSPHERIC)
345
- ? _space_node.tropo_correction(relative_pos, usr_pos.llh)
259
+ ? tropospheric_correction(time_arrival, usr_pos, relative_pos)
346
260
  : error.value[range_error_t::TROPOSPHERIC];
347
261
 
348
262
  // Setup weight
@@ -488,7 +402,7 @@ class GPS_SinglePositioning : public SolverBaseT {
488
402
 
489
403
  res.receiver_time = receiver_time;
490
404
 
491
- if(_options.count_ionospheric_models() == 0){
405
+ if(!ionospheric_correction.select(receiver_time)){
492
406
  res.error_code = user_pvt_t::ERROR_INVALID_IONO_MODEL;
493
407
  return;
494
408
  }
@@ -38,6 +38,8 @@
38
38
  #include <vector>
39
39
  #include <map>
40
40
  #include <utility>
41
+ #include <deque>
42
+ #include <algorithm>
41
43
 
42
44
  #include <cmath>
43
45
  #include <cstring>
@@ -101,6 +103,7 @@ struct GPS_Solver_Base {
101
103
  L1_RANGE_RATE_SIGMA,
102
104
  L1_SIGNAL_STRENGTH_dBHz,
103
105
  L1_LOCK_SEC,
106
+ L1_FREQUENCY,
104
107
  MEASUREMENT_ITEMS_PREDEFINED,
105
108
  };
106
109
  };
@@ -223,6 +226,53 @@ struct GPS_Solver_Base {
223
226
  return res;
224
227
  }
225
228
 
229
+ struct range_corrector_t {
230
+ virtual ~range_corrector_t() {}
231
+ virtual bool is_available(const gps_time_t &t) const {
232
+ return false;
233
+ }
234
+ virtual float_t *calculate(
235
+ const gps_time_t &t, const pos_t &usr_pos, const enu_t &sat_rel_pos,
236
+ float_t &buf) const = 0;
237
+ };
238
+ static const struct no_correction_t : public range_corrector_t {
239
+ bool is_available(const gps_time_t &t) const {
240
+ return true;
241
+ }
242
+ float_t *calculate(
243
+ const gps_time_t &t, const pos_t &usr_pos, const enu_t &sat_rel_pos,
244
+ float_t &buf) const {
245
+ return &(buf = 0);
246
+ }
247
+ } no_correction;
248
+ struct range_correction_t : public std::deque<const range_corrector_t *> {
249
+ typedef std::deque<const range_corrector_t *> super_t;
250
+ range_correction_t() : super_t() {}
251
+ const range_corrector_t *select(const gps_time_t &t) const {
252
+ for(typename super_t::const_iterator it(super_t::begin()), it_end(super_t::end());
253
+ it != it_end; ++it){
254
+ if((*it)->is_available(t)){return *it;}
255
+ }
256
+ return NULL;
257
+ }
258
+ float_t operator()(
259
+ const gps_time_t &t, const pos_t &usr_pos, const enu_t &sat_rel_pos) const {
260
+ float_t res;
261
+ for(typename super_t::const_iterator it(super_t::begin()), it_end(super_t::end());
262
+ it != it_end; ++it){
263
+ if((*it)->calculate(t, usr_pos, sat_rel_pos, res)){return res;}
264
+ }
265
+ return 0;
266
+ }
267
+ void remove(const typename super_t::value_type &v){
268
+ std::remove(super_t::begin(), super_t::end(), v);
269
+ }
270
+ void add(const typename super_t::value_type &v){
271
+ remove(v);
272
+ super_t::push_front(v);
273
+ }
274
+ };
275
+
226
276
  /**
227
277
  * Select appropriate solver, this is provision for GNSS extension
228
278
  * @param prn satellite number
@@ -395,10 +445,11 @@ protected:
395
445
  * @return transformed design matrix G'
396
446
  */
397
447
  static matrix_t rotate_G(const MatrixT &G_, const matrix_t &rotation_matrix){
398
- matrix_t res(G_.rows(), 4);
399
- res.partial(G_.rows(), 3).replace(
400
- G_.partial(G_.rows(), 3) * rotation_matrix.transpose());
401
- res.partial(G_.rows(), 1, 0, 3).replace(G_.partial(G_.rows(), 1, 0, 3));
448
+ unsigned int r(G_.rows()), c(G_.columns()); // Normally c=4
449
+ matrix_t res(r, c);
450
+ res.partial(r, 3).replace(
451
+ G_.partial(r, 3) * rotation_matrix.transpose());
452
+ res.partial(r, c - 3, 0, 3).replace(G_.partial(r, c - 3, 0, 3));
402
453
  return res;
403
454
  }
404
455
 
@@ -425,14 +476,16 @@ protected:
425
476
  * @see rotate_G
426
477
  */
427
478
  static matrix_t rotate_C(const matrix_t &C, const matrix_t &rotation_matrix){
428
- matrix_t res(4, 4);
479
+ unsigned int n(C.rows()); // Normally n=4
480
+ matrix_t res(n, n);
429
481
  res.partial(3, 3).replace( // upper left
430
482
  rotation_matrix * C.partial(3, 3) * rotation_matrix.transpose());
431
- res.partial(3, 1, 0, 3).replace( // upper right
432
- rotation_matrix * C.partial(3, 1, 0, 3));
433
- res.partial(1, 3, 3, 0).replace( // lower left
434
- C.partial(1, 3, 3, 0) * rotation_matrix.transpose());
435
- res(3, 3) = C(3, 3); // lower right
483
+ res.partial(3, n - 3, 0, 3).replace( // upper right
484
+ rotation_matrix * C.partial(3, n - 3, 0, 3));
485
+ res.partial(n - 3, 3, 3, 0).replace( // lower left
486
+ C.partial(n - 3, 3, 3, 0) * rotation_matrix.transpose());
487
+ res.partial(n - 3, n - 3, 3, 3).replace( // lower right
488
+ C.partial(n - 3, n - 3, 3, 3));
436
489
  return res;
437
490
  }
438
491
  /**
@@ -470,11 +523,10 @@ protected:
470
523
  * @see rotate_G
471
524
  */
472
525
  static matrix_t rotate_S(const matrix_t &S, const matrix_t &rotation_matrix){
473
- matrix_t res(4, S.columns());
474
- res.partial(3, S.columns()).replace(rotation_matrix * S.partial(3, S.columns()));
475
- for(unsigned int j(0), j_end(S.columns()); j < j_end; ++j){
476
- res(3, j) = S(3, j);
477
- }
526
+ unsigned int r(S.rows()), c(S.columns()); // Normally r=4
527
+ matrix_t res(r, c);
528
+ res.partial(3, c).replace(rotation_matrix * S.partial(3, c));
529
+ res.partial(r - 3, c, 3, 0).replace(S.partial(r - 3, c, 3, 0));
478
530
  return res;
479
531
  }
480
532
  /**
@@ -537,7 +589,7 @@ protected:
537
589
  partial_t partial(unsigned int size) const {
538
590
  if(size >= G.rows()){size = G.rows();}
539
591
  return partial_t(
540
- G.partial(size, 4), W.partial(size, size), delta_r.partial(size, 1));
592
+ G.partial(size, G.columns()), W.partial(size, size), delta_r.partial(size, 1));
541
593
  }
542
594
  typedef linear_solver_t<typename MatrixT::circular_t> exclude_t;
543
595
  exclude_t exclude(const unsigned int &row) const {
@@ -545,14 +597,16 @@ protected:
545
597
  if(size >= 1){size--;}
546
598
  // generate matrices having circular view
547
599
  return exclude_t(
548
- G.circular(offset, 0, size, 4),
600
+ G.circular(offset, 0, size, G.columns()),
549
601
  W.circular(offset, offset, size, size),
550
602
  delta_r.circular(offset, 0, size, 1));
551
603
  }
552
604
  template <class MatrixT2>
553
605
  void copy_G_W_row(const linear_solver_t<MatrixT2> &src,
554
606
  const unsigned int &i_src, const unsigned int &i_dst){
555
- for(unsigned int j(0); j < 4; ++j){
607
+ unsigned int c_dst(G.columns()), c_src(src.G.columns()),
608
+ c(c_dst > c_src ? c_src : c_dst); // Normally c=4
609
+ for(unsigned int j(0); j < c; ++j){
556
610
  G(i_dst, j) = src.G(i_src, j);
557
611
  }
558
612
  W(i_dst, i_dst) = src.W(i_src, i_src);
@@ -561,9 +615,12 @@ protected:
561
615
 
562
616
  struct geometric_matrices_t : public linear_solver_t<matrix_t> {
563
617
  typedef linear_solver_t<matrix_t> super_t;
564
- geometric_matrices_t(const unsigned int &capacity)
618
+ geometric_matrices_t(
619
+ const unsigned int &capacity,
620
+ const unsigned int &estimate_system_differences = 0)
565
621
  : super_t(
566
- matrix_t(capacity, 4), matrix_t(capacity, capacity), matrix_t(capacity, 1)) {
622
+ matrix_t(capacity, 4 + estimate_system_differences),
623
+ matrix_t(capacity, capacity), matrix_t(capacity, 1)) {
567
624
  for(unsigned int i(0); i < capacity; ++i){
568
625
  super_t::G(i, 3) = 1;
569
626
  }
@@ -595,14 +652,14 @@ protected:
595
652
  // Least square
596
653
  matrix_t delta_x(geomat.partial(res.used_satellites).least_square());
597
654
 
598
- xyz_t delta_user_position(delta_x.partial(3, 1, 0, 0));
655
+ xyz_t delta_user_position(delta_x.partial(3, 1));
599
656
  res.user_position.xyz += delta_user_position;
600
657
  res.user_position.llh = res.user_position.xyz.llh();
601
658
 
602
659
  const float_t &delta_receiver_error(delta_x(3, 0));
603
660
  res.receiver_error += delta_receiver_error;
604
661
 
605
- return ((delta_x.transpose() * delta_x)(0, 0) <= 1E-6); // equivalent to abs(x) <= 1E-3 [m]
662
+ return (delta_x.partial(4, 1).norm2F() <= 1E-6); // equivalent to abs(x) <= 1E-3 [m]
606
663
  }
607
664
 
608
665
  struct user_pvt_opt_t {
@@ -1036,6 +1093,10 @@ const typename GPS_Solver_Base<FloatT>::range_error_t
1036
1093
  {0},
1037
1094
  };
1038
1095
 
1096
+ template <class FloatT>
1097
+ const typename GPS_Solver_Base<FloatT>::no_correction_t
1098
+ GPS_Solver_Base<FloatT>::no_correction;
1099
+
1039
1100
  template <class FloatT, class PVT_BaseT = typename GPS_Solver_Base<FloatT>::user_pvt_t>
1040
1101
  struct GPS_PVT_Debug : public PVT_BaseT {
1041
1102
  typename GPS_Solver_Base<FloatT>::matrix_t G, W, delta_r;
@@ -846,8 +846,10 @@ class RINEX_NAV_Reader : public RINEX_Reader<> {
846
846
  };
847
847
 
848
848
  static int read_all(std::istream &in, space_node_list_t &space_nodes = {0}){
849
- int res(-1);
850
849
  RINEX_NAV_Reader reader(in);
850
+ if(reader.version_type.file_type != version_type_t::FTYPE_NAVIGATION){
851
+ return -1;
852
+ }
851
853
  if(space_nodes.gps){
852
854
  (reader.version_type.version >= 300)
853
855
  ? reader.extract_iono_utc_v3(*space_nodes.gps)
@@ -857,7 +859,7 @@ class RINEX_NAV_Reader : public RINEX_Reader<> {
857
859
  && (reader.version_type.version >= 302)){
858
860
  reader.extract_iono_utc_v3(*space_nodes.qzss);
859
861
  }
860
- res++;
862
+ int res(0);
861
863
  for(; reader.has_next(); reader.next()){
862
864
  switch(reader.sys_of_msg){
863
865
  case super_t::version_type_t::SYS_GPS:
@@ -1140,6 +1142,9 @@ class RINEX_OBS_Reader : public RINEX_Reader<> {
1140
1142
  RINEX_OBS_Reader(std::istream &in)
1141
1143
  : super_t(in, self_t::modify_header),
1142
1144
  obs_types() {
1145
+ if(super_t::version_type.file_type != version_type_t::FTYPE_OBSERVATION){
1146
+ return;
1147
+ }
1143
1148
  typedef super_t::header_t::const_iterator it_t;
1144
1149
  typedef super_t::header_t::mapped_type::const_iterator it2_t;
1145
1150
  it_t it;
@@ -1860,8 +1865,13 @@ class RINEX_NAV_Writer : public RINEX_Writer<> {
1860
1865
  version, super_t::version_type_t::FTYPE_NAVIGATION, sys));
1861
1866
  }
1862
1867
 
1868
+ struct space_node_list_t {
1869
+ const space_node_t *gps;
1870
+ const SBAS_SpaceNode<FloatT> *sbas;
1871
+ const space_node_t *qzss;
1872
+ };
1863
1873
  int write_all(
1864
- const typename reader_t::space_node_list_t &space_nodes,
1874
+ const space_node_list_t &space_nodes,
1865
1875
  const int &version = 304){
1866
1876
  int res(-1);
1867
1877
  int systems(0);
@@ -1966,12 +1976,12 @@ class RINEX_NAV_Writer : public RINEX_Writer<> {
1966
1976
  }
1967
1977
  static int write_all(
1968
1978
  std::ostream &out,
1969
- const typename reader_t::space_node_list_t &space_nodes,
1979
+ const space_node_list_t &space_nodes,
1970
1980
  const int &version = 304){
1971
1981
  return RINEX_NAV_Writer(out).write_all(space_nodes, version);
1972
1982
  }
1973
1983
  int write_all(const space_node_t &space_node, const int &version = 304){
1974
- const typename reader_t::space_node_list_t list = {&const_cast<space_node_t &>(space_node)};
1984
+ space_node_list_t list = {&space_node};
1975
1985
  return write_all(list, version);
1976
1986
  }
1977
1987
  static int write_all(std::ostream &out, const space_node_t &space_node, const int &version = 304){
@@ -1536,10 +1536,10 @@ sf[SF_ ## TARGET] * msg_t::TARGET(buf)
1536
1536
  * @see A.4.2.4
1537
1537
  * @return correction in meters
1538
1538
  */
1539
- float_t tropo_correction(
1539
+ static float_t tropo_correction(
1540
1540
  const float_t &year_utc,
1541
1541
  const enu_t &relative_pos,
1542
- const llh_t &usrllh) const {
1542
+ const llh_t &usrllh){
1543
1543
 
1544
1544
  if(usrllh.height() > 10E3){ // same as RTKlib; troposphere ranges from 0 to approximately 11km
1545
1545
  return 0;