gps_pvt 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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;