gps_pvt 0.10.0 → 0.10.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -134,7 +134,9 @@ class GLONASS_SinglePositioning : public SolverBaseT {
134
134
  return sat(ptr).clock_error_dot(t_tx);
135
135
  }
136
136
  static float_t range_sigma(const void *ptr, const gps_time_t &t_tx) {
137
- return sat(ptr).ephemeris().F_T;
137
+ return std::sqrt(
138
+ std::pow(sat(ptr).ephemeris().F_T, 2)
139
+ + std::pow(4.5 / 1.96, 2)); // TODO change? (currently same as GPS)
138
140
  }
139
141
  };
140
142
  satellite_t res = {
@@ -229,7 +231,7 @@ class GLONASS_SinglePositioning : public SolverBaseT {
229
231
  * @param prn satellite number
230
232
  * @param measurement measurement (per satellite) containing pseudo range
231
233
  * @param receiver_error (temporal solution of) receiver clock error in meter
232
- * @param time_arrival time when signal arrive at receiver
234
+ * @param time_arrival time when signal arrives at receiver
233
235
  * @param usr_pos (temporal solution of) user position
234
236
  * @param usr_vel (temporal solution of) user velocity
235
237
  * @return (relative_property_t) relative information
@@ -325,11 +327,17 @@ class GLONASS_SinglePositioning : public SolverBaseT {
325
327
  res.range_corrected = range;
326
328
 
327
329
  xyz_t rel_vel(sat.velocity(t_tx, dt_transit) - usr_vel); // Calculate velocity
328
-
329
330
  res.rate_relative_neg = res.los_neg[0] * rel_vel.x()
330
331
  + res.los_neg[1] * rel_vel.y()
331
332
  + res.los_neg[2] * rel_vel.z()
332
333
  + sat.clock_error_dot(t_tx) * c;
334
+ res.rate_sigma = sat.rate_sigma(time_arrival);
335
+
336
+ if(_options.use_external_sigma){
337
+ // Use standard deviation of pseudorange and/or its rate if they are provided by receiver
338
+ this->range_sigma(measurement, res.range_sigma);
339
+ this->rate_sigma(measurement, res.rate_sigma);
340
+ }
333
341
 
334
342
  return res;
335
343
  }
@@ -1156,7 +1156,8 @@ static void name ## _set(InputT *dest, const s ## bits ## _t &src){ \
1156
1156
 
1157
1157
  // Subframe.1
1158
1158
  uint_t WN; ///< Week number
1159
- float_t URA; ///< User range accuracy (m)
1159
+ float_t URA; ///< User range accuracy (m) including all errors
1160
+ ///< for which the Space and Control Segments are responsible. (ICD 6.2.1)
1160
1161
  uint_t SV_health; ///< Health status
1161
1162
  int_t iodc; ///< Issue of clock data
1162
1163
  float_t t_GD; ///< Group delay (s)
@@ -55,10 +55,12 @@ template <class FloatT>
55
55
  struct GPS_Solver_GeneralOptions {
56
56
  FloatT elevation_mask;
57
57
  FloatT residual_mask;
58
+ bool use_external_sigma;
58
59
 
59
60
  GPS_Solver_GeneralOptions()
60
61
  : elevation_mask(0), // elevation mask default is 0 [deg]
61
- residual_mask(30) { // range residual mask is 30 [m]
62
+ residual_mask(1E3), // range residual mask is 1000 [m]
63
+ use_external_sigma(false) { // default is to ignore external sigma inputs
62
64
 
63
65
  }
64
66
  };
@@ -158,7 +160,9 @@ class GPS_SinglePositioning : public SolverBaseT {
158
160
  return sat(ptr).clock_error_dot(t_tx);
159
161
  }
160
162
  static float_t range_sigma(const void *ptr, const gps_time_t &t_tx) {
161
- return sat(ptr).ephemeris().URA;
163
+ return std::sqrt(
164
+ std::pow(sat(ptr).ephemeris().URA, 2)
165
+ + std::pow(4.5 / 1.96, 2)); // UEE of modern receiver Table.B2-1 of April 2020 GPS SPS PS;
162
166
  }
163
167
  };
164
168
  satellite_t res = {
@@ -262,9 +266,9 @@ class GPS_SinglePositioning : public SolverBaseT {
262
266
  *
263
267
  * @param sat satellite
264
268
  * @param range "corrected" pseudo range subtracted by (temporal solution of) receiver clock error in meter
265
- * @param time_arrival time when signal arrive at receiver
269
+ * @param time_arrival time when signal arrives at receiver
266
270
  * @param usr_pos (temporal solution of) user position
267
- * @param residual calculated residual with line of site vector, and pseudorange standard deviation (sigma);
271
+ * @param residual calculated residual with line of sight vector, and pseudorange standard deviation (sigma);
268
272
  * When sigma is equal to or less than zero, the calculated results should not be used.
269
273
  * @param error Some correction can be overwritten. If its unknown_flag is zero,
270
274
  * corrections will be skipped as possible. @see range_errors_t
@@ -280,7 +284,7 @@ class GPS_SinglePositioning : public SolverBaseT {
280
284
 
281
285
  static const float_t &c(space_node_t::light_speed);
282
286
 
283
- // Clock error correction
287
+ // Satellite clock error correction
284
288
  range += ((error.unknown_flag & range_error_t::SATELLITE_CLOCK)
285
289
  ? (sat.clock_error(time_arrival - range / c) * c)
286
290
  : error.value[range_error_t::SATELLITE_CLOCK]);
@@ -294,20 +298,21 @@ class GPS_SinglePositioning : public SolverBaseT {
294
298
  // Calculate residual
295
299
  residual.residual = range - geometric_range;
296
300
 
297
- // Setup design matrix
301
+ // Setup design matrix (direction is negative; satellite -> user)
298
302
  residual.los_neg_x = -(sat_pos.x() - usr_pos.xyz.x()) / geometric_range;
299
303
  residual.los_neg_y = -(sat_pos.y() - usr_pos.xyz.y()) / geometric_range;
300
304
  residual.los_neg_z = -(sat_pos.z() - usr_pos.xyz.z()) / geometric_range;
301
305
 
302
306
  enu_t relative_pos(enu_t::relative(sat_pos, usr_pos.xyz));
303
307
 
308
+ // Ionospheric correction
304
309
  if(error.unknown_flag & range_error_t::MASK_IONOSPHERIC){
305
310
  residual.residual += ionospheric_correction(time_arrival, usr_pos, relative_pos);
306
311
  }else{
307
312
  residual.residual += error.value[range_error_t::IONOSPHERIC];
308
313
  }
309
314
 
310
- // Tropospheric
315
+ // Tropospheric correction
311
316
  residual.residual += (error.unknown_flag & range_error_t::MASK_TROPOSPHERIC)
312
317
  ? tropospheric_correction(time_arrival, usr_pos, relative_pos)
313
318
  : error.value[range_error_t::TROPOSPHERIC];
@@ -347,9 +352,9 @@ class GPS_SinglePositioning : public SolverBaseT {
347
352
  * @param range "corrected" pseudo range subtracted by (temporal solution of) receiver clock error in meter
348
353
  * @param time_arrival time when signal arrive at receiver
349
354
  * @param usr_vel (temporal solution of) user velocity
350
- * @param los_neg_x line of site X
351
- * @param los_neg_y line of site Y
352
- * @param los_neg_z line of site Z
355
+ * @param los_neg_x line of sight X
356
+ * @param los_neg_y line of sight Y
357
+ * @param los_neg_z line of sight Z
353
358
  * @return (float_t) relative rate.
354
359
  */
355
360
  float_t rate_relative_neg(
@@ -425,14 +430,13 @@ class GPS_SinglePositioning : public SolverBaseT {
425
430
  usr_pos, residual, range_error);
426
431
  res.rate_relative_neg = rate_relative_neg(sat, res.range_corrected, time_arrival, usr_vel,
427
432
  res.los_neg[0], res.los_neg[1], res.los_neg[2]);
433
+ res.rate_sigma = sat.rate_sigma(time_arrival);
428
434
 
429
- #if 0
430
- // TODO consider case when standard deviation of pseudorange measurement is provided by receiver
431
- if(!this->range_sigma(measurement, res.range_sigma)){
432
- // If receiver's range variance is not provided
433
- res.range_sigma = 1E0; // TODO range error variance [m]
435
+ if(_options.use_external_sigma){
436
+ // Use standard deviation of pseudorange and/or its rate if they are provided by receiver
437
+ this->range_sigma(measurement, res.range_sigma);
438
+ this->rate_sigma(measurement, res.rate_sigma);
434
439
  }
435
- #endif
436
440
 
437
441
  return res;
438
442
  }
@@ -148,7 +148,7 @@ struct GPS_Solver_Base {
148
148
  * of measurement_t::mapped_type
149
149
  * @param values key-value map
150
150
  * @param key key
151
- * @param buf buffer into which found value is stored
151
+ * @param buf buffer for storing found value, and preserving original value if value is not found
152
152
  * @return (float_t *) When value is found, pointer of buf will be returned.
153
153
  * Otherwise, NULL is returned.
154
154
  */
@@ -209,8 +209,13 @@ struct GPS_Solver_Base {
209
209
  if((res = find_value(values, measurement_items_t::L1_RANGE_RATE, buf))){
210
210
 
211
211
  }else if((res = find_value(values, measurement_items_t::L1_DOPPLER, buf))){
212
- // Fall back to doppler
213
- buf *= -space_node_t::L1_WaveLength();
212
+ // Fall back to Doppler
213
+ float_t freq;
214
+ if(find_value(values, measurement_items_t::L1_FREQUENCY, freq)){
215
+ buf *= -(space_node_t::light_speed / freq);
216
+ }else{
217
+ buf *= -space_node_t::L1_WaveLength();
218
+ }
214
219
  }
215
220
  return res;
216
221
  }
@@ -221,8 +226,13 @@ struct GPS_Solver_Base {
221
226
  if((res = find_value(values, measurement_items_t::L1_RANGE_RATE_SIGMA, buf))){
222
227
 
223
228
  }else if((res = find_value(values, measurement_items_t::L1_DOPPLER_SIGMA, buf))){
224
- // Fall back to doppler
225
- buf *= space_node_t::L1_WaveLength();
229
+ // Fall back to Doppler
230
+ float_t freq;
231
+ if(find_value(values, measurement_items_t::L1_FREQUENCY, freq)){
232
+ buf *= (space_node_t::light_speed / freq);
233
+ }else{
234
+ buf *= space_node_t::L1_WaveLength();
235
+ }
226
236
  }
227
237
  return res;
228
238
  }
@@ -279,7 +289,8 @@ struct GPS_Solver_Base {
279
289
  inline float_t range_sigma(const gps_time_t &t_tx) const {
280
290
  return impl_range_sigma
281
291
  ? impl_range_sigma(impl_error, t_tx)
282
- : 3.5; // 7.0 [m] of 95% (2-sigma) URE in Sec. 3.4.1 of April 2020 GPS SPS PS;
292
+ : (std::sqrt((9.7 * 9.7) + (4.5 * 4.5)) / 1.96); // 5.45 [m]
293
+ // UERE (User Equivalent Range Error) of modern receiver in Eq.(B-8) of April 2020 GPS SPS PS;
283
294
  }
284
295
  /**
285
296
  * Return expected user range rate accuracy (URRA) in standard deviation (1-sigma)
@@ -289,7 +300,12 @@ struct GPS_Solver_Base {
289
300
  inline float_t rate_sigma(const gps_time_t &t_tx) const {
290
301
  return impl_rate_sigma
291
302
  ? impl_rate_sigma(impl_error, t_tx)
292
- : 0.003; // 0.006 [m/s] of 95% (2-sigma) URRE in Sec. 3.4.2 of April 2020 GPS SPS PS
303
+ : 5E-1; // (Empirical value)
304
+ // Alternatives (may occur failure);
305
+ // 1) (std::sqrt(((2.0 * 2.0) + (1.0 * 1.0)) * 2) / 1.96); // 1.61 [m/s]
306
+ // assume differential range with error consisting of "Receiver noise and resolution"
307
+ // and "Other user segment errors" in UEE Table B.2-1 of April 2020 GPS SPS PS
308
+ // 2) 0.006 m/s(95%) SPS SIS URRE in Table 3.4-2 is not considered.
293
309
  }
294
310
  static const satellite_t &unavailable() {
295
311
  struct impl_t {
@@ -388,8 +404,9 @@ struct GPS_Solver_Base {
388
404
  float_t range_sigma; ///< Standard deviation of pseudorange; If zero or negative, other values are invalid.
389
405
  float_t range_corrected; ///< corrected range just including delay, and excluding receiver/satellite error
390
406
  float_t range_residual; ///< residual range
391
- float_t rate_relative_neg; /// relative rate
392
- float_t los_neg[3]; ///< line of site vector from satellite to user
407
+ float_t rate_sigma; ///< Standard deviation of range rate;
408
+ float_t rate_relative_neg; /// relative rate (taking negative value if range is increasing)
409
+ float_t los_neg[3]; ///< line of sight vector from satellite to user in ECEF coordinate
393
410
  };
394
411
 
395
412
  /**
@@ -433,16 +450,16 @@ struct GPS_Solver_Base {
433
450
  float_t receiver_error;
434
451
  enu_t user_velocity_enu;
435
452
  float_t receiver_error_rate;
436
- struct dop_t {
453
+ struct precision_t {
437
454
  float_t g, p, h, v, t;
438
- dop_t() {}
439
- dop_t(const matrix_t &C_enu)
440
- : g(std::sqrt(C_enu.trace())),
441
- p(std::sqrt(C_enu.partial(3, 3).trace())),
442
- h(std::sqrt(C_enu.partial(2, 2).trace())),
443
- v(std::sqrt(C_enu(2, 2))),
444
- t(std::sqrt(C_enu(3, 3))) {}
445
- } dop;
455
+ precision_t() {}
456
+ precision_t(const matrix_t &C_or_P_enu)
457
+ : g(std::sqrt(C_or_P_enu.trace())),
458
+ p(std::sqrt(C_or_P_enu.partial(3, 3).trace())),
459
+ h(std::sqrt(C_or_P_enu.partial(2, 2).trace())),
460
+ v(std::sqrt(C_or_P_enu(2, 2))),
461
+ t(std::sqrt(C_or_P_enu(3, 3))) {}
462
+ } dop, sigma_pos, sigma_vel;
446
463
  unsigned int used_satellites;
447
464
  typedef BitArray<0x400> satellite_mask_t;
448
465
  satellite_mask_t used_satellite_mask; ///< bit pattern(use=1, otherwise=0), PRN 1(LSB) to 32 for GPS
@@ -565,27 +582,48 @@ protected:
565
582
  return (G.transpose() * G).inverse();
566
583
  }
567
584
  /**
568
- * Transform coordinate of matrix C
569
- * C' = (G * R^t)^t * (G * R^t) = R * G^t * G * R^t = R * C * R^t,
585
+ * Calculate P matrix, where P = E[x^t x] = (G^t * W * G)^{-1} to be used for estimated accuracy calculation
586
+ * @return P matrix
587
+ */
588
+ matrix_t P() const {
589
+ return (G.transpose() * W * G).inverse();
590
+ }
591
+ /**
592
+ * Transform coordinate of matrix C/P
593
+ * C' = ((G * R^t)^t * (G * R^t))^-1 = (R * G^t * G * R^t)^-1
594
+ * = (R^t)^-1 * (G^t * G)^-1 * R^-1 = R * C * R^t,
595
+ * P' = ((G * R^t)^t * W * (G * R^t))^-1 = R * P * R^t,
570
596
  * where R is a rotation matrix, for example, ECEF to ENU.
571
597
  *
572
598
  * @param rotation_matrix 3 by 3 rotation matrix
573
- * @return transformed matrix C'
599
+ * @return transformed matrix C' or P'
574
600
  * @see rotate_G
575
601
  */
576
- static matrix_t rotate_C(const matrix_t &C, const matrix_t &rotation_matrix){
577
- unsigned int n(C.rows()); // Normally n=4
602
+ static matrix_t rotate_CP(const matrix_t &C_or_P, const matrix_t &rotation_matrix){
603
+ unsigned int n(C_or_P.rows()); // Normally n=4
578
604
  matrix_t res(n, n);
579
605
  res.partial(3, 3).replace( // upper left
580
- rotation_matrix * C.partial(3, 3) * rotation_matrix.transpose());
606
+ rotation_matrix * C_or_P.partial(3, 3) * rotation_matrix.transpose());
581
607
  res.partial(3, n - 3, 0, 3).replace( // upper right
582
- rotation_matrix * C.partial(3, n - 3, 0, 3));
608
+ rotation_matrix * C_or_P.partial(3, n - 3, 0, 3));
583
609
  res.partial(n - 3, 3, 3, 0).replace( // lower left
584
- C.partial(n - 3, 3, 3, 0) * rotation_matrix.transpose());
610
+ C_or_P.partial(n - 3, 3, 3, 0) * rotation_matrix.transpose());
585
611
  res.partial(n - 3, n - 3, 3, 3).replace( // lower right
586
- C.partial(n - 3, n - 3, 3, 3));
612
+ C_or_P.partial(n - 3, n - 3, 3, 3));
587
613
  return res;
588
614
  }
615
+ typename user_pvt_t::precision_t dop(){
616
+ return typename user_pvt_t::precision_t(C());
617
+ }
618
+ typename user_pvt_t::precision_t dop(const matrix_t &rotation_matrix){
619
+ return typename user_pvt_t::precision_t(rotate_CP(C(), rotation_matrix));
620
+ }
621
+ typename user_pvt_t::precision_t sigma(){
622
+ return typename user_pvt_t::precision_t(P());
623
+ }
624
+ typename user_pvt_t::precision_t sigma(const matrix_t &rotation_matrix){
625
+ return typename user_pvt_t::precision_t(rotate_CP(P(), rotation_matrix));
626
+ }
589
627
  /**
590
628
  * Solve x of linear equation (y = G x + v) to minimize sigma{v^t * v}
591
629
  * where v =~ N(0, sigma), and y and G are observation delta (=delta_r variable)
@@ -594,7 +632,7 @@ protected:
594
632
  *
595
633
  * 4 by row(y) S matrix (=(G^t * W * G)^{-1} * (G^t * W)) will be used to calculate protection level
596
634
  * to investigate relationship between bias on each satellite and solution.
597
- * residual v = (I - P) = (I - G S), where P = G S, which is irrelevant to rotation,
635
+ * residual v = (I - G S) y, which is irrelevant to rotation,
598
636
  * because P = G R R^{t} S = G' S'.
599
637
  *
600
638
  * @param S (output) coefficient matrix to calculate solution, i.e., (G^t * W * G)^{-1} * (G^t * W)
@@ -701,14 +739,13 @@ protected:
701
739
  delta_r.circular(offset, 0, size, 1));
702
740
  }
703
741
  template <class MatrixT2>
704
- void copy_G_W_row(const linear_solver_t<MatrixT2> &src,
742
+ void copy_G_rowwise(const linear_solver_t<MatrixT2> &src,
705
743
  const unsigned int &i_src, const unsigned int &i_dst){
706
744
  unsigned int c_dst(G.columns()), c_src(src.G.columns()),
707
745
  c(c_dst > c_src ? c_src : c_dst); // Normally c=4
708
746
  for(unsigned int j(0); j < c; ++j){
709
747
  G(i_dst, j) = src.G(i_src, j);
710
748
  }
711
- W(i_dst, i_dst) = src.W(i_src, i_src);
712
749
  }
713
750
  };
714
751
 
@@ -806,15 +843,15 @@ protected:
806
843
  res.receiver_error = receiver_error_init;
807
844
 
808
845
  geometric_matrices_t geomat(measurement.size());
809
- typedef std::vector<std::pair<unsigned int, float_t> > index_obs_t;
810
- index_obs_t idx_rate_rel; // [(index of measurement, relative rate), ...]
811
- idx_rate_rel.reserve(measurement.size());
846
+ typedef std::vector<std::pair<unsigned int, relative_property_t> > index_prop_t;
847
+ index_prop_t idx_prop; // [(index of measurement, relative property), ...]
848
+ idx_prop.reserve(measurement.size());
812
849
 
813
850
  // If initialization is not appropriate, more iteration will be performed.
814
851
  bool converged(false);
815
852
  for(int i_trial(-opt.warmup); i_trial < opt.max_trial; i_trial++){
816
853
 
817
- idx_rate_rel.clear();
854
+ idx_prop.clear();
818
855
  unsigned int i_row(0), i_measurement(0);
819
856
  res.used_satellite_mask.clear();
820
857
 
@@ -841,7 +878,7 @@ protected:
841
878
  if(coarse_estimation){
842
879
  prop.range_sigma = 1;
843
880
  }else{
844
- idx_rate_rel.push_back(std::make_pair(i_measurement, prop.rate_relative_neg));
881
+ idx_prop.push_back(std::make_pair(i_measurement, prop));
845
882
  }
846
883
 
847
884
  geomat.delta_r(i_row, 0) = prop.range_residual;
@@ -872,9 +909,11 @@ protected:
872
909
  return;
873
910
  }
874
911
 
912
+ matrix_t rot(res.user_position.ecef2enu());
875
913
  try{
876
- res.dop = typename user_pvt_t::dop_t(geomat.rotate_C(
877
- geomat.partial(res.used_satellites).C(), res.user_position.ecef2enu()));
914
+ typename geometric_matrices_t::partial_t geomat_used(geomat.partial(res.used_satellites));
915
+ res.dop = geomat_used.dop(rot);
916
+ res.sigma_pos = geomat_used.sigma(rot);
878
917
  }catch(const std::runtime_error &e){ // expect to detect matrix operation error
879
918
  res.error_code = user_pvt_t::ERROR_DOP;
880
919
  return;
@@ -892,7 +931,7 @@ protected:
892
931
  geometric_matrices_t geomat2(res.used_satellites);
893
932
  int i_range(0), i_rate(0);
894
933
 
895
- for(typename index_obs_t::const_iterator it(idx_rate_rel.begin()), it_end(idx_rate_rel.end());
934
+ for(typename index_prop_t::const_iterator it(idx_prop.begin()), it_end(idx_prop.end());
896
935
  it != it_end;
897
936
  ++it, ++i_range){
898
937
 
@@ -901,9 +940,10 @@ protected:
901
940
  *(measurement[it->first].k_v_map), // const version of measurement[PRN]
902
941
  rate))){continue;}
903
942
 
904
- // Copy design matrix and set rate
905
- geomat2.copy_G_W_row(geomat, i_range, i_rate);
906
- geomat2.delta_r(i_rate, 0) = rate + it->second;
943
+ // Copy design matrix and set rate and weight
944
+ geomat2.copy_G_rowwise(geomat, i_range, i_rate);
945
+ geomat2.delta_r(i_rate, 0) = rate + it->second.rate_relative_neg;
946
+ geomat2.W(i_rate, i_rate) = 1. / std::pow(it->second.rate_sigma, 2);
907
947
 
908
948
  ++i_rate;
909
949
  }
@@ -915,12 +955,14 @@ protected:
915
955
 
916
956
  try{
917
957
  // Least square
918
- matrix_t sol(geomat2.partial(i_rate).least_square());
958
+ typename geometric_matrices_t::partial_t geomat2_used(geomat2.partial(i_rate));
959
+ matrix_t sol(geomat2_used.least_square());
919
960
 
920
961
  xyz_t vel_xyz(sol.partial(3, 1, 0, 0));
921
962
  res.user_velocity_enu = enu_t::relative_rel(
922
963
  vel_xyz, res.user_position.llh);
923
964
  res.receiver_error_rate = sol(3, 0);
965
+ res.sigma_vel = geomat2_used.sigma(rot);
924
966
  }catch(const std::runtime_error &e){ // expect to detect matrix operation error
925
967
  res.error_code = user_pvt_t::ERROR_VELOCITY_LS;
926
968
  return;
@@ -1145,10 +1187,6 @@ public:
1145
1187
  solver_interface_t<GPS_Solver_Base<FloatT> > solve() const {
1146
1188
  return solver_interface_t<GPS_Solver_Base<FloatT> >(*this);
1147
1189
  }
1148
-
1149
- static typename user_pvt_t::dop_t dop(const matrix_t &C, const pos_t &user_position) {
1150
- return typename user_pvt_t::dop_t(geometric_matrices_t::rotate_C(C, user_position.ecef2enu()));
1151
- }
1152
1190
  };
1153
1191
 
1154
1192
  template <class FloatT>
@@ -56,7 +56,7 @@ struct GPS_PVT_RAIM_LSR : public PVT_BaseT {
56
56
  typename GPS_Solver_Base<FloatT>::prn_t excluded;
57
57
  typename GPS_Solver_Base<FloatT>::pos_t user_position;
58
58
  typename GPS_Solver_Base<FloatT>::float_t receiver_error;
59
- typename GPS_Solver_Base<FloatT>::user_pvt_t::dop_t dop;
59
+ typename GPS_Solver_Base<FloatT>::user_pvt_t::precision_t dop, sigma_pos;
60
60
  } FDE_min, FDE_2nd; ///< Fault exclusion
61
61
  };
62
62
 
@@ -231,6 +231,7 @@ protected:
231
231
  target->user_position = pvt_FDE.user_position;
232
232
  target->receiver_error = pvt_FDE.receiver_error;
233
233
  target->dop = pvt_FDE.dop;
234
+ target->sigma_pos = pvt_FDE.sigma_pos;
234
235
  }
235
236
  }
236
237
  };
@@ -129,7 +129,9 @@ class SBAS_SinglePositioning : public SolverBaseT {
129
129
  return sat(ptr).ephemeris().clock_error_dot(t_tx);
130
130
  }
131
131
  static float_t range_sigma(const void *ptr, const gps_time_t &t_tx) {
132
- return sat(ptr).ephemeris().URA;
132
+ return std::sqrt(
133
+ std::pow(sat(ptr).ephemeris().URA, 2)
134
+ + std::pow(4.5 / 1.96, 2)); // TODO change? (currently same as GPS)
133
135
  }
134
136
  };
135
137
  satellite_t res = {
@@ -330,11 +332,17 @@ class SBAS_SinglePositioning : public SolverBaseT {
330
332
  res.range_corrected = range;
331
333
 
332
334
  xyz_t rel_vel(sat.velocity(t_tx, dt_transit) - usr_vel); // Calculate velocity
333
-
334
335
  res.rate_relative_neg = res.los_neg[0] * rel_vel.x()
335
336
  + res.los_neg[1] * rel_vel.y()
336
337
  + res.los_neg[2] * rel_vel.z()
337
338
  + sat.clock_error_dot(t_tx) * c;
339
+ res.rate_sigma = sat.rate_sigma(time_arrival);
340
+
341
+ if(_options.use_external_sigma){
342
+ // Use standard deviation of pseudorange and/or its rate if they are provided by receiver
343
+ this->range_sigma(measurement, res.range_sigma);
344
+ this->rate_sigma(measurement, res.rate_sigma);
345
+ }
338
346
 
339
347
  return res;
340
348
  }
@@ -368,6 +368,22 @@ struct GPS_Ephemeris : public GPS_SpaceNode<FloatT>::SatelliteProperties::Epheme
368
368
  System_XYZ<FloatT, WGS84> position, velocity;
369
369
  FloatT clock_error, clock_error_dot;
370
370
  };
371
+
372
+ int get_URA_index() const {
373
+ return GPS_Ephemeris<FloatT>::URA_index(this->URA);
374
+ }
375
+ int set_URA_index(const int &idx) {
376
+ this->URA = GPS_Ephemeris<FloatT>::URA_meter(idx);
377
+ return get_URA_index();
378
+ }
379
+ FloatT set_fit_interval(const bool &flag) {
380
+ // set svid/iodc before invocation of this function
381
+ if((this->svid >= 193) && (this->svid <= 202)){ // QZSS
382
+ return (this->fit_interval = (flag ? (std::numeric_limits<FloatT>::max)() : (2 * 60 * 60)));
383
+ }else{
384
+ return (this->fit_interval = GPS_Ephemeris<FloatT>::raw_t::fit_interval(flag, this->iodc));
385
+ }
386
+ }
371
387
  };
372
388
  %}
373
389
  %extend GPS_Ephemeris {
@@ -403,6 +419,9 @@ struct GPS_Ephemeris : public GPS_SpaceNode<FloatT>::SatelliteProperties::Epheme
403
419
  MAKE_ACCESSOR(dot_Omega0, FloatT);
404
420
  MAKE_ACCESSOR(dot_i0, FloatT);
405
421
 
422
+ %rename(%str(URA_index=)) set_URA_index;
423
+ %rename(%str(URA_index)) get_URA_index;
424
+
406
425
  MAKE_ARRAY_INPUT(const unsigned int, buf, SWIG_AsVal(unsigned int));
407
426
  %apply int *OUTPUT { int *subframe_no, int *iodc_or_iode };
408
427
  void parse(const unsigned int buf[10], int *subframe_no, int *iodc_or_iode){
@@ -597,11 +616,18 @@ struct SBAS_Ephemeris : public SBAS_SpaceNode<FloatT>::SatelliteProperties::Ephe
597
616
  return SBAS_SpaceNode<FloatT>::SatelliteProperties::Ephemeris::is_valid(t);
598
617
  }
599
618
  GPS_Time<FloatT> t_applicable() const {return GPS_Time<FloatT>(this->WN, this->t_0);}
619
+ int get_URA_index() const {
620
+ return SBAS_Ephemeris<FloatT>::URA_index(this->URA);
621
+ }
622
+ int set_URA_index(const int &idx) {
623
+ this->URA = SBAS_Ephemeris<FloatT>::URA_meter(idx);
624
+ return get_URA_index();
625
+ }
600
626
  };
601
627
  %}
602
628
  %extend SBAS_Ephemeris {
603
629
  MAKE_ACCESSOR(svid, unsigned int);
604
-
630
+
605
631
  MAKE_ACCESSOR(WN, unsigned int);
606
632
  MAKE_ACCESSOR(t_0, FloatT);
607
633
  MAKE_ACCESSOR(URA, FloatT);
@@ -610,6 +636,9 @@ struct SBAS_Ephemeris : public SBAS_SpaceNode<FloatT>::SatelliteProperties::Ephe
610
636
  MAKE_ACCESSOR(ddx, FloatT); MAKE_ACCESSOR(ddy, FloatT); MAKE_ACCESSOR(ddz, FloatT);
611
637
  MAKE_ACCESSOR(a_Gf0, FloatT);
612
638
  MAKE_ACCESSOR(a_Gf1, FloatT);
639
+ %rename(%str(URA_index=)) set_URA_index;
640
+ %rename(%str(URA_index)) get_URA_index;
641
+
613
642
  /**
614
643
  * Return broadcasted raw data of SBAS ephemeris
615
644
  * @param buf_brdc pointer to store raw data of Type 9 message.
@@ -711,6 +740,21 @@ struct GLONASS_Ephemeris
711
740
  (typename GLONASS_SpaceNode<FloatT>::TimeProperties)(*this)),
712
741
  deltaT));
713
742
  }
743
+
744
+ unsigned char get_F_T_index() const {
745
+ return GLONASS_Ephemeris<FloatT>::F_T_index();
746
+ }
747
+ unsigned char set_F_T_index(const unsigned char &idx) {
748
+ this->F_T = GLONASS_Ephemeris<FloatT>::raw_t::F_T_value(idx);
749
+ return get_F_T_index();
750
+ }
751
+ unsigned char get_P1_index() const {
752
+ return GLONASS_Ephemeris<FloatT>::P1_index();
753
+ }
754
+ unsigned char set_P1_index(const unsigned char &idx) {
755
+ this->P1 = GLONASS_Ephemeris<FloatT>::raw_t::P1_value(idx);
756
+ return get_P1_index();
757
+ }
714
758
  };
715
759
  %}
716
760
  %extend GLONASS_Ephemeris {
@@ -743,12 +787,27 @@ struct GLONASS_Ephemeris
743
787
  MAKE_ACCESSOR2(year, date.year, int);
744
788
  MAKE_ACCESSOR2(day_of_year, date.day_of_year, int);
745
789
 
790
+ %rename(%str(F_T_index=)) set_F_T_index;
791
+ %rename(%str(F_T_index)) get_F_T_index;
792
+ %rename(%str(P1_index=)) set_P1_index;
793
+ %rename(%str(P1_index)) get_P1_index;
794
+
746
795
  void set_date(const unsigned int &N_4, const unsigned int &NA) {
747
796
  self->date = GLONASS_SpaceNode<FloatT>::TimeProperties::raw_t::raw2date(N_4, NA);
748
797
  }
749
798
  void set_date(const std::tm &t) {
750
799
  self->date = GLONASS_SpaceNode<FloatT>::TimeProperties::date_t::from_c_tm(t);
751
800
  }
801
+ unsigned char N_4() const {
802
+ unsigned char res;
803
+ GLONASS_Ephemeris<FloatT>::TimeProperties::raw_t::date2raw(self->date, &res, NULL);
804
+ return res;
805
+ }
806
+ unsigned short NA() const {
807
+ unsigned short res;
808
+ GLONASS_Ephemeris<FloatT>::TimeProperties::raw_t::date2raw(self->date, NULL, &res);
809
+ return res;
810
+ }
752
811
 
753
812
  FloatT frequency_L1() const {
754
813
  return self->L1_frequency();
@@ -939,6 +998,10 @@ struct GPS_User_PVT
939
998
  const FloatT &hdop() const {return base_t::dop.h;}
940
999
  const FloatT &vdop() const {return base_t::dop.v;}
941
1000
  const FloatT &tdop() const {return base_t::dop.t;}
1001
+ const FloatT &hsigma() const {return base_t::sigma_pos.h;}
1002
+ const FloatT &vsigma() const {return base_t::sigma_pos.v;}
1003
+ const FloatT &tsigma() const {return base_t::sigma_pos.t;}
1004
+ const FloatT &vel_sigma() const {return base_t::sigma_vel.p;}
942
1005
  const unsigned int &used_satellites() const {return base_t::used_satellites;}
943
1006
  std::vector<int> used_satellite_list() const {return base_t::used_satellite_mask.indices_one();}
944
1007
  bool position_solved() const {return base_t::position_solved();}
@@ -963,7 +1026,7 @@ struct GPS_User_PVT
963
1026
  return linear_solver().C();
964
1027
  }
965
1028
  Matrix<FloatT, Array2D_Dense<FloatT> > C_enu() const {
966
- return proxy_t::linear_solver_t::rotate_C(C(), base_t::user_position.ecef2enu());
1029
+ return proxy_t::linear_solver_t::rotate_CP(C(), base_t::user_position.ecef2enu());
967
1030
  }
968
1031
  Matrix<FloatT, Array2D_Dense<FloatT> > S() const {
969
1032
  Matrix<FloatT, Array2D_Dense<FloatT> > res;
@@ -1193,6 +1256,7 @@ struct GPS_Measurement {
1193
1256
  %extend GPS_SolverOptions_Common {
1194
1257
  MAKE_ACCESSOR2(elevation_mask, cast_general()->elevation_mask, FloatT);
1195
1258
  MAKE_ACCESSOR2(residual_mask, cast_general()->residual_mask, FloatT);
1259
+ MAKE_ACCESSOR2(use_external_sigma, cast_general()->use_external_sigma, bool);
1196
1260
  MAKE_VECTOR2ARRAY(int);
1197
1261
  %ignore cast_general;
1198
1262
  }
@@ -1375,7 +1439,7 @@ struct HookableSolver : public BaseT {
1375
1439
  const GPS_Solver<FloatT>::base_t::relative_property_t &res_orig) const {
1376
1440
  union {
1377
1441
  base_t::relative_property_t prop;
1378
- FloatT values[7];
1442
+ FloatT values[8];
1379
1443
  } res = {res_orig};
1380
1444
  #ifdef SWIGRUBY
1381
1445
  do{
@@ -1383,15 +1447,19 @@ struct HookableSolver : public BaseT {
1383
1447
  static const int prop_items(sizeof(res.values) / sizeof(res.values[0]));
1384
1448
  VALUE hook(rb_hash_lookup(hooks, key));
1385
1449
  if(NIL_P(hook)){break;}
1386
- FloatT weight((res.prop.range_sigma > 0)
1450
+ FloatT weight_range((res.prop.range_sigma > 0)
1387
1451
  ? (1. / std::pow(res.prop.range_sigma, 2)) // weight=1/(sigma^2)
1388
1452
  : res.prop.range_sigma);
1453
+ FloatT weight_rate((res.prop.rate_sigma > 0)
1454
+ ? (1. / std::pow(res.prop.rate_sigma, 2)) // weight=1/(sigma^2)
1455
+ : res.prop.rate_sigma);
1389
1456
  VALUE values[] = {
1390
1457
  SWIG_From(int)(prn), // prn
1391
1458
  rb_ary_new_from_args(prop_items, // relative_property
1392
- swig::from(weight),
1459
+ swig::from(weight_range),
1393
1460
  swig::from(res.prop.range_corrected),
1394
1461
  swig::from(res.prop.range_residual),
1462
+ swig::from(weight_rate),
1395
1463
  swig::from(res.prop.rate_relative_neg),
1396
1464
  swig::from(res.prop.los_neg[0]),
1397
1465
  swig::from(res.prop.los_neg[1]),
@@ -1424,6 +1492,9 @@ struct HookableSolver : public BaseT {
1424
1492
  if(res.values[0] > 0){
1425
1493
  res.values[0] = std::pow(1. / res.values[0], 0.5); // sigma=(1/weight)^0.5
1426
1494
  }
1495
+ if(res.values[3] > 0){
1496
+ res.values[3] = std::pow(1. / res.values[3], 0.5); // sigma=(1/weight)^0.5
1497
+ }
1427
1498
  }while(false);
1428
1499
  #endif
1429
1500
  return res.prop;