gps_pvt 0.1.7 → 0.2.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -405,11 +405,12 @@ struct GPS_Time {
405
405
  }
406
406
 
407
407
  // process remaining 4 years
408
- int doy_i(0), doy[] = {
408
+ int doy[] = {
409
409
  leap_year ? 366 : 365,
410
410
  365, 365, 365,
411
411
  is_leap_year(year + 4) ? 366 : 365,
412
412
  };
413
+ std::size_t doy_i(0);
413
414
  for(; doy_i < sizeof(doy) / sizeof(doy[0]); ++doy_i){
414
415
  if(days <= doy[doy_i]){break;}
415
416
  days -= doy[doy_i];
@@ -525,6 +526,9 @@ class GPS_SpaceNode {
525
526
  return res;
526
527
  }
527
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
+ }
528
532
 
529
533
  protected:
530
534
  static float_t rad2sc(const float_t &rad) {return rad / M_PI;}
@@ -2051,6 +2055,7 @@ if(std::abs(TARGET - eph.TARGET) > raw_t::sf[raw_t::SF_ ## TARGET]){break;}
2051
2055
  * @param height_over_ellipsoid
2052
2056
  * @see spherically single layer approach, for example,
2053
2057
  * Eq.(3) of "Ionospheric Range Error Correction Models" by N. Jakowski
2058
+ * @see DO-229D A4.4.10.4 Eq.(A-42) is equivalent
2054
2059
  */
2055
2060
  static float_t slant_factor(
2056
2061
  const enu_t &relative_pos,
@@ -2089,8 +2094,7 @@ if(std::abs(TARGET - eph.TARGET) > raw_t::sf[raw_t::SF_ ## TARGET]){break;}
2089
2094
  // Elevation and azimuth
2090
2095
  float_t el(relative_pos.elevation()),
2091
2096
  az(relative_pos.azimuth());
2092
- float_t sc_el(rad2sc(el)),
2093
- sc_az(rad2sc(az));
2097
+ float_t sc_el(rad2sc(el));
2094
2098
 
2095
2099
  // Pierce point (PP stands for the earth projection of the Pierce point)
2096
2100
  // (the following equation is based on GPS ICD)
@@ -2150,37 +2154,17 @@ if(std::abs(TARGET - eph.TARGET) > raw_t::sf[raw_t::SF_ ## TARGET]){break;}
2150
2154
  usr.llh(),
2151
2155
  t);
2152
2156
  }
2153
-
2154
- struct IonospericCorrection {
2155
- const GPS_SpaceNode<float_t> &space_node;
2156
- float_t operator()(
2157
- const enu_t &relative_pos,
2158
- const llh_t &usrllh,
2159
- const gps_time_t &t) const {
2160
- return space_node.iono_correction(relative_pos, usrllh, t);
2161
- }
2162
- float_t operator()(
2163
- const xyz_t &sat,
2164
- const xyz_t &usr,
2165
- const gps_time_t &t) const {
2166
- return space_node.iono_correction(sat, usr, t);
2167
- }
2168
- };
2169
- IonospericCorrection iono_correction() const {
2170
- IonospericCorrection res = {*this};
2171
- return res;
2172
- }
2173
2157
 
2174
2158
  /**
2175
- * Calculate correction value in accordance with tropospheric model
2159
+ * Calculate correction value in accordance with tropospheric Hopfield model
2176
2160
  *
2177
2161
  * @param relative_pos satellite position (relative position, NEU)
2178
2162
  * @param usrllh user position (absolute position, LLH)
2179
2163
  * @return correction in meters
2180
2164
  */
2181
- float_t tropo_correction(
2165
+ static float_t tropo_correction(
2182
2166
  const enu_t &relative_pos,
2183
- const llh_t &usrllh) const {
2167
+ const llh_t &usrllh){
2184
2168
 
2185
2169
  // Elevation (rad)
2186
2170
  float_t el(relative_pos.elevation());
@@ -2290,31 +2274,13 @@ if(std::abs(TARGET - eph.TARGET) > raw_t::sf[raw_t::SF_ ## TARGET]){break;}
2290
2274
  * @param usr user position (absolute position, XYZ)
2291
2275
  * @return correction in meters
2292
2276
  */
2293
- float_t tropo_correction(
2277
+ static float_t tropo_correction(
2294
2278
  const xyz_t &sat,
2295
- const xyz_t &usr) const {
2279
+ const xyz_t &usr) {
2296
2280
  return tropo_correction(
2297
2281
  enu_t::relative(sat, usr),
2298
2282
  usr.llh());
2299
2283
  }
2300
-
2301
- struct TropospericCorrection {
2302
- const GPS_SpaceNode<float_t> &space_node;
2303
- float_t operator()(
2304
- const enu_t &relative_pos,
2305
- const llh_t &usrllh) const {
2306
- return space_node.tropo_correction(relative_pos, usrllh);
2307
- }
2308
- float_t operator()(
2309
- const xyz_t &sat,
2310
- const xyz_t &usr) const {
2311
- return space_node.tropo_correction(sat, usr);
2312
- }
2313
- };
2314
- TropospericCorrection tropo_correction() const {
2315
- TropospericCorrection res = {*this};
2316
- return res;
2317
- }
2318
2284
  };
2319
2285
 
2320
2286
  template <class FloatT>
@@ -43,6 +43,7 @@
43
43
  #include <exception>
44
44
 
45
45
  #include <cmath>
46
+ #include <cstddef>
46
47
 
47
48
  #include "param/bit_array.h"
48
49
 
@@ -55,49 +56,10 @@ struct GPS_Solver_GeneralOptions {
55
56
  FloatT elevation_mask;
56
57
  FloatT residual_mask;
57
58
 
58
- enum ionospheric_model_t {
59
- IONOSPHERIC_KLOBUCHAR,
60
- IONOSPHERIC_NTCM_GL,
61
- IONOSPHERIC_NONE, // which allows no correction
62
- IONOSPHERIC_MODELS,
63
- IONOSPHERIC_SKIP = IONOSPHERIC_MODELS, // which means delegating the next slot
64
- };
65
- ionospheric_model_t ionospheric_models[IONOSPHERIC_MODELS]; // lower index means having higher priority
66
-
67
- int count_ionospheric_models() const {
68
- int res(0);
69
- for(int i(0); i < sizeof(ionospheric_models) / sizeof(ionospheric_models[0]); ++i){
70
- if(ionospheric_models[i] != IONOSPHERIC_SKIP){res++;}
71
- }
72
- return res;
73
- }
74
-
75
- FloatT f_10_7;
76
-
77
59
  GPS_Solver_GeneralOptions()
78
60
  : elevation_mask(0), // elevation mask default is 0 [deg]
79
- residual_mask(30), // range residual mask is 30 [m]
80
- f_10_7(-1) {
81
- for(int i(0); i < sizeof(ionospheric_models) / sizeof(ionospheric_models[0]); ++i){
82
- ionospheric_models[i] = IONOSPHERIC_SKIP;
83
- }
84
- // default: broadcasted Klobuchar parameters are at least required for solution.
85
- ionospheric_models[0] = IONOSPHERIC_KLOBUCHAR;
86
- }
61
+ residual_mask(30) { // range residual mask is 30 [m]
87
62
 
88
- bool insert_ionospheric_model(const ionospheric_model_t &model, const int &index = 0) {
89
- if((index < 0)
90
- || (index >= sizeof(ionospheric_models) / sizeof(ionospheric_models[0]))){
91
- return false;
92
- }
93
-
94
- // shift, then replace
95
- for(int i(index), j(i + 1); j < sizeof(ionospheric_models) / sizeof(ionospheric_models[0]); ++i, ++j){
96
- ionospheric_models[j] = ionospheric_models[i];
97
- }
98
- ionospheric_models[index] = model;
99
-
100
- return true;
101
63
  }
102
64
  };
103
65
 
@@ -145,6 +107,8 @@ class GPS_SinglePositioning : public SolverBaseT {
145
107
  typedef typename base_t::measurement_t measurement_t;
146
108
  inheritate_type(measurement_items_t);
147
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;
148
112
 
149
113
  inheritate_type(relative_property_t);
150
114
  inheritate_type(geometric_matrices_t);
@@ -161,37 +125,50 @@ class GPS_SinglePositioning : public SolverBaseT {
161
125
  public:
162
126
  const space_node_t &space_node() const {return _space_node;}
163
127
 
164
- /**
165
- * Check availability of ionospheric models
166
- * If a model is completely unavailable, it will be replaced to IONOSPHERIC_SKIP.
167
- * It implies that when a model has conditional applicability (such as SBAS), it will be retained.
168
- *
169
- * @return (int) number of (possibly) available models
170
- */
171
- int filter_ionospheric_models(GPS_SinglePositioning_Options<float_t> &opt) const {
172
-
173
- int available_models(0);
174
-
175
- for(int i(0); i < sizeof(opt.ionospheric_models) / sizeof(opt.ionospheric_models[0]); ++i){
176
- switch(opt.ionospheric_models[i]){
177
- case options_t::IONOSPHERIC_KLOBUCHAR:
178
- // check whether Klobuchar parameters alpha and beta have been already received
179
- if(_space_node.is_valid_iono()){break;}
180
- opt.ionospheric_models[i] = options_t::IONOSPHERIC_SKIP;
181
- continue;
182
- case options_t::IONOSPHERIC_NTCM_GL:
183
- if(opt.f_10_7 >= 0){break;}
184
- // check F10.7 has been already configured
185
- opt.ionospheric_models[i] = options_t::IONOSPHERIC_SKIP;
186
- continue;
187
- case options_t::IONOSPHERIC_SKIP:
188
- continue;
189
- }
190
- available_models++;
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));
191
138
  }
139
+ } ionospheric_klobuchar;
192
140
 
193
- return available_models;
194
- }
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;
195
172
 
196
173
  options_t available_options() const {
197
174
  return options_t(base_t::available_options(), _options);
@@ -199,18 +176,26 @@ class GPS_SinglePositioning : public SolverBaseT {
199
176
 
200
177
  options_t available_options(const options_t &opt_wish) const {
201
178
  GPS_SinglePositioning_Options<float_t> opt(opt_wish);
202
- filter_ionospheric_models(opt);
203
179
  return options_t(base_t::available_options(opt_wish), opt);
204
180
  }
205
181
 
206
182
  options_t update_options(const options_t &opt_wish){
207
- filter_ionospheric_models(_options = opt_wish);
183
+ _options = opt_wish;
208
184
  return options_t(base_t::update_options(opt_wish), _options);
209
185
  }
210
186
 
211
187
  GPS_SinglePositioning(const space_node_t &sn)
212
- : base_t(), _space_node(sn), _options() {
213
- 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);
214
199
  }
215
200
 
216
201
  ~GPS_SinglePositioning(){}
@@ -264,38 +249,14 @@ class GPS_SinglePositioning : public SolverBaseT {
264
249
  enu_t relative_pos(enu_t::relative(sat_pos, usr_pos.xyz));
265
250
 
266
251
  if(error.unknown_flag & range_error_t::MASK_IONOSPHERIC){
267
- // Ionospheric model selection, the fall back is no correction
268
- bool iono_model_hit(false);
269
- for(int i(0); i < sizeof(_options.ionospheric_models) / sizeof(_options.ionospheric_models[0]); ++i){
270
- switch(_options.ionospheric_models[i]){
271
- case options_t::IONOSPHERIC_KLOBUCHAR:
272
- residual.residual += _space_node.iono_correction(relative_pos, usr_pos.llh, time_arrival);
273
- break;
274
- case options_t::IONOSPHERIC_NTCM_GL: {
275
- // TODO f_10_7 setup, optimization (mag_model etc.)
276
- typename space_node_t::pierce_point_res_t pp(_space_node.pierce_point(relative_pos, usr_pos.llh));
277
- residual.residual -= space_node_t::tec2delay(
278
- _space_node.slant_factor(relative_pos)
279
- * NTCM_GL_Generic<float_t>::tec_vert(
280
- pp.latitude, pp.longitude,
281
- time_arrival.year(), _options.f_10_7));
282
- break;
283
- }
284
- case options_t::IONOSPHERIC_NONE:
285
- break;
286
- default:
287
- continue;
288
- }
289
- iono_model_hit = true;
290
- break;
291
- }
252
+ residual.residual += ionospheric_correction(time_arrival, usr_pos, relative_pos);
292
253
  }else{
293
254
  residual.residual += error.value[range_error_t::IONOSPHERIC];
294
255
  }
295
256
 
296
257
  // Tropospheric
297
258
  residual.residual += (error.unknown_flag & range_error_t::MASK_TROPOSPHERIC)
298
- ? _space_node.tropo_correction(relative_pos, usr_pos.llh)
259
+ ? tropospheric_correction(time_arrival, usr_pos, relative_pos)
299
260
  : error.value[range_error_t::TROPOSPHERIC];
300
261
 
301
262
  // Setup weight
@@ -441,7 +402,7 @@ class GPS_SinglePositioning : public SolverBaseT {
441
402
 
442
403
  res.receiver_time = receiver_time;
443
404
 
444
- if(_options.count_ionospheric_models() == 0){
405
+ if(!ionospheric_correction.select(receiver_time)){
445
406
  res.error_code = user_pvt_t::ERROR_INVALID_IONO_MODEL;
446
407
  return;
447
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
  };
@@ -202,9 +205,9 @@ struct GPS_Solver_Base {
202
205
  virtual const float_t *rate(
203
206
  const typename measurement_t::mapped_type &values, float_t &buf) const {
204
207
  const float_t *res;
205
- if(res = find_value(values, measurement_items_t::L1_RANGE_RATE, buf)){
208
+ if((res = find_value(values, measurement_items_t::L1_RANGE_RATE, buf))){
206
209
 
207
- }else if(res = find_value(values, measurement_items_t::L1_DOPPLER, buf)){
210
+ }else if((res = find_value(values, measurement_items_t::L1_DOPPLER, buf))){
208
211
  // Fall back to doppler
209
212
  buf *= -space_node_t::L1_WaveLength();
210
213
  }
@@ -214,15 +217,62 @@ struct GPS_Solver_Base {
214
217
  virtual const float_t *rate_sigma(
215
218
  const typename measurement_t::mapped_type &values, float_t &buf) const {
216
219
  const float_t *res;
217
- if(res = find_value(values, measurement_items_t::L1_RANGE_RATE_SIGMA, buf)){
220
+ if((res = find_value(values, measurement_items_t::L1_RANGE_RATE_SIGMA, buf))){
218
221
 
219
- }else if(res = find_value(values, measurement_items_t::L1_DOPPLER_SIGMA, buf)){
222
+ }else if((res = find_value(values, measurement_items_t::L1_DOPPLER_SIGMA, buf))){
220
223
  // Fall back to doppler
221
224
  buf *= space_node_t::L1_WaveLength();
222
225
  }
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
@@ -308,8 +358,9 @@ struct GPS_Solver_Base {
308
358
  case ERROR_VELOCITY_INSUFFICIENT_SATELLITES:
309
359
  case ERROR_VELOCITY_LS:
310
360
  return true;
361
+ default:
362
+ return false;
311
363
  }
312
- return false;
313
364
  }
314
365
  bool velocity_solved() const {
315
366
  return error_code == ERROR_NO;
@@ -394,10 +445,11 @@ protected:
394
445
  * @return transformed design matrix G'
395
446
  */
396
447
  static matrix_t rotate_G(const MatrixT &G_, const matrix_t &rotation_matrix){
397
- matrix_t res(G_.rows(), 4);
398
- res.partial(G_.rows(), 3).replace(
399
- G_.partial(G_.rows(), 3) * rotation_matrix.transpose());
400
- 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));
401
453
  return res;
402
454
  }
403
455
 
@@ -424,14 +476,16 @@ protected:
424
476
  * @see rotate_G
425
477
  */
426
478
  static matrix_t rotate_C(const matrix_t &C, const matrix_t &rotation_matrix){
427
- matrix_t res(4, 4);
479
+ unsigned int n(C.rows()); // Normally n=4
480
+ matrix_t res(n, n);
428
481
  res.partial(3, 3).replace( // upper left
429
482
  rotation_matrix * C.partial(3, 3) * rotation_matrix.transpose());
430
- res.partial(3, 1, 0, 3).replace( // upper right
431
- rotation_matrix * C.partial(3, 1, 0, 3));
432
- res.partial(1, 3, 3, 0).replace( // lower left
433
- C.partial(1, 3, 3, 0) * rotation_matrix.transpose());
434
- 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));
435
489
  return res;
436
490
  }
437
491
  /**
@@ -469,11 +523,10 @@ protected:
469
523
  * @see rotate_G
470
524
  */
471
525
  static matrix_t rotate_S(const matrix_t &S, const matrix_t &rotation_matrix){
472
- matrix_t res(4, S.columns());
473
- res.partial(3, S.columns()).replace(rotation_matrix * S.partial(3, S.columns()));
474
- for(unsigned int j(0), j_end(S.columns()); j < j_end; ++j){
475
- res(3, j) = S(3, j);
476
- }
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));
477
530
  return res;
478
531
  }
479
532
  /**
@@ -536,7 +589,7 @@ protected:
536
589
  partial_t partial(unsigned int size) const {
537
590
  if(size >= G.rows()){size = G.rows();}
538
591
  return partial_t(
539
- 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));
540
593
  }
541
594
  typedef linear_solver_t<typename MatrixT::circular_t> exclude_t;
542
595
  exclude_t exclude(const unsigned int &row) const {
@@ -544,14 +597,16 @@ protected:
544
597
  if(size >= 1){size--;}
545
598
  // generate matrices having circular view
546
599
  return exclude_t(
547
- G.circular(offset, 0, size, 4),
600
+ G.circular(offset, 0, size, G.columns()),
548
601
  W.circular(offset, offset, size, size),
549
602
  delta_r.circular(offset, 0, size, 1));
550
603
  }
551
604
  template <class MatrixT2>
552
605
  void copy_G_W_row(const linear_solver_t<MatrixT2> &src,
553
606
  const unsigned int &i_src, const unsigned int &i_dst){
554
- 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){
555
610
  G(i_dst, j) = src.G(i_src, j);
556
611
  }
557
612
  W(i_dst, i_dst) = src.W(i_src, i_src);
@@ -560,9 +615,12 @@ protected:
560
615
 
561
616
  struct geometric_matrices_t : public linear_solver_t<matrix_t> {
562
617
  typedef linear_solver_t<matrix_t> super_t;
563
- geometric_matrices_t(const unsigned int &capacity)
618
+ geometric_matrices_t(
619
+ const unsigned int &capacity,
620
+ const unsigned int &estimate_system_differences = 0)
564
621
  : super_t(
565
- 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)) {
566
624
  for(unsigned int i(0); i < capacity; ++i){
567
625
  super_t::G(i, 3) = 1;
568
626
  }
@@ -1035,6 +1093,10 @@ const typename GPS_Solver_Base<FloatT>::range_error_t
1035
1093
  {0},
1036
1094
  };
1037
1095
 
1096
+ template <class FloatT>
1097
+ const typename GPS_Solver_Base<FloatT>::no_correction_t
1098
+ GPS_Solver_Base<FloatT>::no_correction;
1099
+
1038
1100
  template <class FloatT, class PVT_BaseT = typename GPS_Solver_Base<FloatT>::user_pvt_t>
1039
1101
  struct GPS_PVT_Debug : public PVT_BaseT {
1040
1102
  typename GPS_Solver_Base<FloatT>::matrix_t G, W, delta_r;
@@ -0,0 +1,62 @@
1
+ /*
2
+ * Copyright (c) 2021, M.Naruoka (fenrir)
3
+ * All rights reserved.
4
+ *
5
+ * Redistribution and use in source and binary forms, with or without modification,
6
+ * are permitted provided that the following conditions are met:
7
+ *
8
+ * - Redistributions of source code must retain the above copyright notice,
9
+ * this list of conditions and the following disclaimer.
10
+ * - Redistributions in binary form must reproduce the above copyright notice,
11
+ * this list of conditions and the following disclaimer in the documentation
12
+ * and/or other materials provided with the distribution.
13
+ * - Neither the name of the naruoka.org nor the names of its contributors
14
+ * may be used to endorse or promote products derived from this software
15
+ * without specific prior written permission.
16
+ *
17
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
19
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS
21
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
22
+ * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
28
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
+ *
30
+ */
31
+
32
+ #ifndef __QZSS_H__
33
+ #define __QZSS_H__
34
+
35
+ /** @file
36
+ * @brief QZSS ICD definitions
37
+ */
38
+
39
+ #include "GPS.h"
40
+ #include <limits>
41
+
42
+ template <class FloatT>
43
+ struct QZSS_LNAV_Ephemeris_Raw : public GPS_SpaceNode<FloatT>::Satellite::Ephemeris::raw_t {
44
+ typedef typename GPS_SpaceNode<FloatT>::Satellite::Ephemeris eph_t;
45
+ typedef typename eph_t::raw_t super_t;
46
+
47
+ operator eph_t() const {
48
+ eph_t res(super_t::operator eph_t());
49
+ res.fit_interval = super_t::fit_interval_flag
50
+ ? (std::numeric_limits<FloatT>::max)()
51
+ : (2 * 60 * 60); // Fit interval (ICD:4.1.2.4 Subframe 2); should be zero
52
+ return res;
53
+ };
54
+
55
+ QZSS_LNAV_Ephemeris_Raw &operator=(const eph_t &eph){
56
+ super_t::operator=(eph);
57
+ super_t::fit_interval_flag = (eph.fit_interval > 2 * 60 * 60);
58
+ return *this;
59
+ }
60
+ };
61
+
62
+ #endif /* __QZSS_H__ */