gps_pvt 0.2.1 → 0.3.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -49,11 +49,7 @@ struct SBAS_SinglePositioning_Options : public GPS_Solver_GeneralOptions<FloatT>
49
49
 
50
50
  typename GPS_Solver_Base<FloatT>::options_t::template exclude_prn_t<120, 158> exclude_prn; // SBAS PRN ranges from 120 to 158
51
51
  SBAS_SinglePositioning_Options()
52
- : super_t() {
53
- // default: SBAS IGP, then broadcasted Klobuchar.
54
- super_t::ionospheric_models[0] = super_t::IONOSPHERIC_SBAS;
55
- super_t::ionospheric_models[1] = super_t::IONOSPHERIC_KLOBUCHAR;
56
-
52
+ : super_t(), exclude_prn() {
57
53
  exclude_prn.set(true); // SBAS ranging is default off.
58
54
  }
59
55
  };
@@ -86,6 +82,8 @@ class SBAS_SinglePositioning : public SolverBaseT {
86
82
 
87
83
  typedef typename base_t::measurement_t measurement_t;
88
84
  typedef typename base_t::range_error_t range_error_t;
85
+ typedef typename base_t::range_corrector_t range_corrector_t;
86
+ typedef typename base_t::range_correction_t range_correction_t;
89
87
 
90
88
  inheritate_type(relative_property_t);
91
89
  #undef inheritate_type
@@ -93,8 +91,6 @@ class SBAS_SinglePositioning : public SolverBaseT {
93
91
  typedef typename GPS_Solver_Base<float_t>::options_t::template merge_t<
94
92
  SBAS_SinglePositioning_Options<float_t>, base_t> options_t;
95
93
 
96
- typedef GPS_SpaceNode<float_t> gps_space_node_t;
97
- const gps_space_node_t *space_node_gps; ///< optional
98
94
  protected:
99
95
  const space_node_t &_space_node;
100
96
  SBAS_SinglePositioning_Options<float_t> _options;
@@ -102,40 +98,47 @@ class SBAS_SinglePositioning : public SolverBaseT {
102
98
  public:
103
99
  const space_node_t &space_node() const {return _space_node;}
104
100
 
105
- /**
106
- * Check availability of ionospheric models
107
- * If a model is completely unavailable, it will be replaced to IONOSPHERIC_SKIP.
108
- * It implies that when a model has conditional applicability (such as SBAS), it will be retained.
109
- *
110
- * @return (int) number of (possibly) available models
111
- */
112
- int filter_ionospheric_models(SBAS_SinglePositioning_Options<float_t> &opt) const {
113
- int available_models(0);
114
- for(std::size_t i(0); i < sizeof(opt.ionospheric_models) / sizeof(opt.ionospheric_models[0]); ++i){
115
- bool usable(false);
116
- switch(opt.ionospheric_models[i]){
117
- case options_t::IONOSPHERIC_KLOBUCHAR:
118
- // check whether Klobuchar parameters alpha and beta have been already received
119
- if(space_node_gps && space_node_gps->is_valid_iono()){usable = true;}
120
- break;
121
- case options_t::IONOSPHERIC_SBAS:
122
- usable = true;
123
- break;
124
- case options_t::IONOSPHERIC_NTCM_GL:
125
- if(opt.f_10_7 >= 0){usable = true;}
126
- // check F10.7 has been already configured
127
- break;
128
- default:
129
- break;
130
- }
131
- if(usable){
132
- available_models++;
133
- }else{
134
- opt.ionospheric_models[i] = options_t::IONOSPHERIC_SKIP;
101
+ struct ionospheric_sbas_t : public range_corrector_t {
102
+ const space_node_t &space_node;
103
+ ionospheric_sbas_t(const space_node_t &sn) : range_corrector_t(), space_node(sn) {}
104
+ bool is_available(const gps_time_t &t) const {
105
+ return true;
106
+ }
107
+ float_t *calculate(
108
+ const gps_time_t &t, const pos_t &usr_pos, const enu_t &sat_rel_pos,
109
+ float_t &buf) const {
110
+
111
+ // placeholder of checking availability and performing correction
112
+ typedef typename space_node_t::available_satellites_t sats_t;
113
+ sats_t sats(space_node.available_satellites(usr_pos.llh.longitude()));
114
+
115
+ typename space_node_t::IonosphericGridPoints::PointProperty prop;
116
+ for(typename sats_t::const_iterator it(sats.begin()); it != sats.end(); ++it){
117
+ prop = it->second
118
+ ->ionospheric_grid_points().iono_correction(sat_rel_pos, usr_pos.llh);
119
+ if(prop.is_available()){
120
+ return &(buf = prop.delay);
121
+ }
122
+ break; // TODO The nearest satellite is only checked
135
123
  }
124
+ return NULL;
136
125
  }
137
- return available_models;
138
- }
126
+ } ionospheric_sbas;
127
+
128
+ struct tropospheric_sbas_t : public range_corrector_t {
129
+ tropospheric_sbas_t() : range_corrector_t() {}
130
+ bool is_available(const gps_time_t &t) const {
131
+ return true;
132
+ }
133
+ float_t *calculate(
134
+ const gps_time_t &t, const pos_t &usr_pos, const enu_t &sat_rel_pos,
135
+ float_t &buf) const {
136
+ return &(buf = space_node_t::tropo_correction(
137
+ t.year(), sat_rel_pos, usr_pos.llh));
138
+ }
139
+ } tropospheric_sbas;
140
+
141
+ range_correction_t ionospheric_correction, tropospheric_correction;
139
142
 
140
143
  options_t available_options() const {
141
144
  return options_t(base_t::available_options(), _options);
@@ -143,19 +146,24 @@ class SBAS_SinglePositioning : public SolverBaseT {
143
146
 
144
147
  options_t available_options(const options_t &opt_wish) const {
145
148
  SBAS_SinglePositioning_Options<float_t> opt(opt_wish);
146
- filter_ionospheric_models(opt);
147
149
  return options_t(base_t::available_options(opt_wish), opt);
148
150
  }
149
151
 
150
152
  options_t update_options(const options_t &opt_wish){
151
- filter_ionospheric_models(_options = opt_wish);
153
+ _options = opt_wish;
152
154
  return options_t(base_t::update_options(opt_wish), _options);
153
155
  }
154
156
 
155
- SBAS_SinglePositioning(const space_node_t &sn, const options_t &opt_wish = options_t())
156
- : base_t(),
157
- _space_node(sn), space_node_gps(NULL),
158
- _options(available_options(opt_wish)) {}
157
+ SBAS_SinglePositioning(const space_node_t &sn)
158
+ : base_t(), _space_node(sn), _options(available_options(options_t())),
159
+ ionospheric_sbas(sn), tropospheric_sbas() {
160
+
161
+ // default ionospheric correction: Broadcasted IGP.
162
+ ionospheric_correction.push_front(&ionospheric_sbas);
163
+
164
+ // default troposheric correction: SBAS
165
+ tropospheric_correction.push_front(&tropospheric_sbas);
166
+ }
159
167
 
160
168
  ~SBAS_SinglePositioning(){}
161
169
 
@@ -245,43 +253,12 @@ class SBAS_SinglePositioning : public SolverBaseT {
245
253
 
246
254
  // Tropospheric (2.1.4.10.3, A.4.2.4)
247
255
  res.range_residual += (range_error.unknown_flag & range_error_t::MASK_TROPOSPHERIC)
248
- ? _space_node.tropo_correction(time_arrival.year(), relative_pos, usr_pos.llh)
256
+ ? tropospheric_correction(time_arrival, usr_pos, relative_pos)
249
257
  : range_error.value[range_error_t::TROPOSPHERIC];
250
258
 
251
259
  // Ionospheric (2.1.4.10.2, A.4.4.10.4)
252
260
  if(range_error.unknown_flag & range_error_t::MASK_IONOSPHERIC){
253
- // Ionospheric model selection, the fall back is no correction
254
- bool iono_model_hit(false);
255
- for(std::size_t i(0); i < sizeof(_options.ionospheric_models) / sizeof(_options.ionospheric_models[0]); ++i){
256
- switch(_options.ionospheric_models[i]){
257
- case options_t::IONOSPHERIC_KLOBUCHAR: // 20.3.3.5.2.5
258
- res.range_residual += space_node_gps->iono_correction(relative_pos, usr_pos.llh, time_arrival);
259
- break;
260
- case options_t::IONOSPHERIC_SBAS: { // 2.1.4.10.2, A.4.4.10.4
261
- typename space_node_t::IonosphericGridPoints::PointProperty prop(
262
- sat->ionospheric_grid_points().iono_correction(relative_pos, usr_pos.llh));
263
- if(!prop.is_available()){continue;}
264
- res.range_residual += prop.delay;
265
- break;
266
- }
267
- case options_t::IONOSPHERIC_NTCM_GL: {
268
- // TODO f_10_7 setup, optimization (mag_model etc.)
269
- typename gps_space_node_t::pierce_point_res_t pp(gps_space_node_t::pierce_point(relative_pos, usr_pos.llh));
270
- res.range_residual -= gps_space_node_t::tec2delay(
271
- gps_space_node_t::slant_factor(relative_pos)
272
- * NTCM_GL_Generic<float_t>::tec_vert(
273
- pp.latitude, pp.longitude,
274
- time_arrival.year(), _options.f_10_7));
275
- break;
276
- }
277
- case options_t::IONOSPHERIC_NONE:
278
- break;
279
- default:
280
- continue;
281
- }
282
- iono_model_hit = true;
283
- break;
284
- }
261
+ res.range_residual += ionospheric_correction(time_arrival, usr_pos, relative_pos);
285
262
  }else{
286
263
  res.range_residual += range_error.value[range_error_t::IONOSPHERIC];
287
264
  }
@@ -60,6 +60,7 @@ struct const_div_t<denom, denom, log2, 0> {
60
60
  template <int MAX_SIZE, class ContainerT = unsigned char>
61
61
  struct BitArray {
62
62
  static const int bits_per_addr = (int)sizeof(ContainerT) * CHAR_BIT;
63
+ static const int max_size = MAX_SIZE;
63
64
  ContainerT buf[(MAX_SIZE + bits_per_addr - 1) / bits_per_addr];
64
65
  void set(const bool &new_bit = false) {
65
66
  std::memset(buf, (new_bit ? (~0) : 0), sizeof(buf));
@@ -128,14 +129,14 @@ struct BitArray {
128
129
  std::vector<int> res;
129
130
  int idx(0);
130
131
  static const const_div_t<bits_per_addr> qr(MAX_SIZE);
131
- int rem(qr.rem);
132
- for(int i(0); i < qr.quot; ++i, idx += bits_per_addr){
132
+ int rem(qr.rem), i(0);
133
+ for(; i < qr.quot; ++i, idx += bits_per_addr){
133
134
  int idx2(idx);
134
135
  for(ContainerT temp(buf[i]); temp > 0; temp >>= 1, ++idx2){
135
136
  if(temp & 0x1){res.push_back(idx2);}
136
137
  }
137
138
  }
138
- for(ContainerT temp(buf[qr.quot + 1]); (temp > 0) && (rem > 0); --rem, ++idx, temp >>= 1){
139
+ for(ContainerT temp(buf[i]); (temp > 0) && (rem > 0); --rem, ++idx, temp >>= 1){
139
140
  if(temp & 0x1){res.push_back(idx);}
140
141
  }
141
142
  return res;
@@ -153,12 +153,26 @@ static std::string inspect_str(const VALUE &v){
153
153
  $1 = (TYPE($input) == T_ARRAY) ? 1 : 0;
154
154
  }
155
155
  #endif
156
+ %ignore canonicalize();
157
+ %ignore GPS_Time(const int &_week, const float_t &_seconds);
158
+ %typemap(in, numinputs=0) void *dummy "";
159
+ GPS_Time(const int &week_, const float_t &seconds_, void *dummy){
160
+ return &((new GPS_Time<FloatT>(week_, seconds_))->canonicalize());
161
+ }
156
162
  %apply int *OUTPUT { int *week };
157
163
  %apply FloatT *OUTPUT { FloatT *seconds };
158
164
  void to_a(int *week, FloatT *seconds) const {
159
165
  *week = self->week;
160
166
  *seconds = self->seconds;
161
167
  }
168
+ #if defined(SWIG)
169
+ int __cmp__(const GPS_Time<FloatT> &t) const {
170
+ return ((self->week < t.week) ? -1
171
+ : ((self->week > t.week) ? 1
172
+ : (self->seconds < t.seconds ? -1
173
+ : (self->seconds > t.seconds ? 1 : 0))));
174
+ }
175
+ #endif
162
176
  }
163
177
 
164
178
  %define MAKE_ACCESSOR(name, type)
@@ -413,8 +427,6 @@ struct GPS_Ephemeris : public GPS_SpaceNode<FloatT>::SatelliteProperties::Epheme
413
427
  %append_output(swig::from($1.latitude));
414
428
  %append_output(swig::from($1.longitude));
415
429
  }
416
- %ignore iono_correction() const;
417
- %ignore tropo_correction() const;
418
430
  int read(const char *fname) {
419
431
  std::fstream fin(fname, std::ios::in | std::ios::binary);
420
432
  typename RINEX_NAV_Reader<FloatT>::space_node_list_t space_nodes = {self};
@@ -800,6 +812,7 @@ struct GPS_Measurement {
800
812
  L1_RANGE_RATE_SIGMA,
801
813
  L1_SIGNAL_STRENGTH_dBHz,
802
814
  L1_LOCK_SEC,
815
+ L1_FREQUENCY,
803
816
  ITEMS_PREDEFINED,
804
817
  };
805
818
  void add(const int &prn, const int &key, const FloatT &value){
@@ -821,71 +834,15 @@ const type &get_ ## name () const {
821
834
  %enddef
822
835
  MAKE_ACCESSOR2(elevation_mask, FloatT);
823
836
  MAKE_ACCESSOR2(residual_mask, FloatT);
824
- MAKE_ACCESSOR2(f_10_7, FloatT);
825
837
  #undef MAKE_ACCESSOR2
826
838
  MAKE_VECTOR2ARRAY(int);
827
839
  %ignore cast_base;
828
- #ifdef SWIGRUBY
829
- %rename("ionospheric_models=") set_ionospheric_models;
830
- %rename("ionospheric_models") get_ionospheric_models;
831
- #endif
832
- %typemap(in) const std::vector<int> &models (std::vector<int> temp) {
833
- $1 = &temp;
834
- #ifdef SWIGRUBY
835
- if(RB_TYPE_P($input, T_ARRAY)){
836
- for(int i(0), i_max(RARRAY_LEN($input)); i < i_max; ++i){
837
- SWIG_Object obj(RARRAY_AREF($input, i));
838
- int v;
839
- if(SWIG_IsOK(SWIG_AsVal(int)(obj, &v))){
840
- temp.push_back(v);
841
- }else{
842
- SWIG_exception(SWIG_TypeError, "$*1_ltype is expected");
843
- }
844
- }
845
- }
846
- #endif
847
- }
848
840
  }
849
841
  %inline %{
850
842
  template <class FloatT>
851
843
  struct GPS_SolverOptions_Common {
852
- enum {
853
- IONOSPHERIC_KLOBUCHAR,
854
- IONOSPHERIC_SBAS,
855
- IONOSPHERIC_NTCM_GL,
856
- IONOSPHERIC_NONE, // which allows no correction
857
- IONOSPHERIC_MODELS,
858
- IONOSPHERIC_SKIP = IONOSPHERIC_MODELS, // which means delegating the next slot
859
- };
860
844
  virtual GPS_Solver_GeneralOptions<FloatT> *cast_general() = 0;
861
845
  virtual const GPS_Solver_GeneralOptions<FloatT> *cast_general() const = 0;
862
- std::vector<int> get_ionospheric_models() const {
863
- typedef GPS_Solver_GeneralOptions<FloatT> general_t;
864
- const general_t *general(this->cast_general());
865
- std::vector<int> res;
866
- for(int i(0); i < general_t::IONOSPHERIC_MODELS; ++i){
867
- int v((int)(general->ionospheric_models[i]));
868
- if(v == general_t::IONOSPHERIC_SKIP){break;}
869
- res.push_back(v);
870
- }
871
- return res;
872
- }
873
- std::vector<int> set_ionospheric_models(const std::vector<int> &models){
874
- typedef GPS_Solver_GeneralOptions<FloatT> general_t;
875
- general_t *general(this->cast_general());
876
- typedef typename general_t::ionospheric_model_t model_t;
877
- for(int i(0), j(0), j_max(models.size()); i < general_t::IONOSPHERIC_MODELS; ++i){
878
- model_t v(general_t::IONOSPHERIC_SKIP);
879
- if(j < j_max){
880
- if((models[j] >= 0) && (models[j] < general_t::IONOSPHERIC_SKIP)){
881
- v = (model_t)models[j];
882
- }
883
- ++j;
884
- }
885
- general->ionospheric_models[i] = v;
886
- }
887
- return get_ionospheric_models();
888
- }
889
846
  };
890
847
  %}
891
848
 
@@ -927,6 +884,27 @@ struct SBAS_SolverOptions
927
884
  };
928
885
  %}
929
886
 
887
+ %header {
888
+ template <class FloatT>
889
+ struct GPS_RangeCorrector
890
+ : public GPS_Solver_Base<FloatT>::range_corrector_t {
891
+ SWIG_Object callback;
892
+ GPS_RangeCorrector(const SWIG_Object &callback_)
893
+ : GPS_Solver_Base<FloatT>::range_corrector_t(),
894
+ callback(callback_) {}
895
+ bool is_available(const typename GPS_Solver_Base<FloatT>::gps_time_t &t) const {
896
+ return false;
897
+ }
898
+ FloatT *calculate(
899
+ const typename GPS_Solver_Base<FloatT>::gps_time_t &t,
900
+ const typename GPS_Solver_Base<FloatT>::pos_t &usr_pos,
901
+ const typename GPS_Solver_Base<FloatT>::enu_t &sat_rel_pos,
902
+ FloatT &buf) const {
903
+ return NULL;
904
+ }
905
+ };
906
+ }
907
+
930
908
  %extend GPS_Solver {
931
909
  %ignore super_t;
932
910
  %ignore base_t;
@@ -938,6 +916,8 @@ struct SBAS_SolverOptions
938
916
  %ignore relative_property;
939
917
  %ignore satellite_position;
940
918
  %ignore update_position_solution;
919
+ %ignore user_correctors_t;
920
+ %ignore user_correctors;
941
921
  %immutable hooks;
942
922
  %ignore mark;
943
923
  %fragment("hook"{GPS_Solver<FloatT>}, "header",
@@ -1022,7 +1002,9 @@ struct SBAS_SolverOptions
1022
1002
  SWIG_NewPointerObj(&geomat_.W,
1023
1003
  $descriptor(Matrix<FloatT, Array2D_Dense<FloatT>, MatrixViewBase<> > *), 0),
1024
1004
  SWIG_NewPointerObj(&geomat_.delta_r,
1025
- $descriptor(Matrix<FloatT, Array2D_Dense<FloatT>, MatrixViewBase<> > *), 0)};
1005
+ $descriptor(Matrix<FloatT, Array2D_Dense<FloatT>, MatrixViewBase<> > *), 0),
1006
+ SWIG_NewPointerObj(&res,
1007
+ $descriptor(GPS_User_PVT<FloatT> *), 0)};
1026
1008
  proc_call_throw_if_error(hook, sizeof(values) / sizeof(values[0]), values);
1027
1009
  }while(false);
1028
1010
  #endif
@@ -1075,6 +1057,152 @@ struct SBAS_SolverOptions
1075
1057
  }
1076
1058
  }
1077
1059
  %fragment("hook"{GPS_Solver<FloatT>});
1060
+ %ignore update_correction;
1061
+ #ifdef SWIGRUBY
1062
+ %fragment("correction"{GPS_Solver<FloatT>}, "header",
1063
+ fragment=SWIG_From_frag(int),
1064
+ fragment=SWIG_Traits_frag(FloatT)){
1065
+ template <>
1066
+ bool GPS_RangeCorrector<FloatT>::is_available(
1067
+ const typename GPS_Solver_Base<FloatT>::gps_time_t &t) const {
1068
+ VALUE values[] = {
1069
+ SWIG_NewPointerObj(
1070
+ %const_cast(&t, GPS_Time<FloatT> *), $descriptor(GPS_Time<FloatT> *), 0),
1071
+ };
1072
+ VALUE res(proc_call_throw_if_error(
1073
+ callback, sizeof(values) / sizeof(values[0]), values));
1074
+ return RTEST(res) ? true : false;
1075
+ }
1076
+ template <>
1077
+ FloatT *GPS_RangeCorrector<FloatT>::calculate(
1078
+ const typename GPS_Solver_Base<FloatT>::gps_time_t &t,
1079
+ const typename GPS_Solver_Base<FloatT>::pos_t &usr_pos,
1080
+ const typename GPS_Solver_Base<FloatT>::enu_t &sat_rel_pos,
1081
+ FloatT &buf) const {
1082
+ VALUE values[] = {
1083
+ SWIG_NewPointerObj(
1084
+ %const_cast(&t, GPS_Time<FloatT> *),
1085
+ $descriptor(GPS_Time<FloatT> *), 0),
1086
+ SWIG_NewPointerObj(
1087
+ (%const_cast(&usr_pos.xyz, System_XYZ<FloatT, WGS84> *)),
1088
+ $descriptor(System_XYZ<FloatT, WGS84> *), 0),
1089
+ SWIG_NewPointerObj(
1090
+ (%const_cast(&sat_rel_pos, System_ENU<FloatT, WGS84> *)),
1091
+ $descriptor(System_ENU<FloatT, WGS84> *), 0),
1092
+ };
1093
+ VALUE res(proc_call_throw_if_error(
1094
+ callback, sizeof(values) / sizeof(values[0]), values));
1095
+ return SWIG_IsOK(swig::asval(res, &buf)) ? &buf : NULL;
1096
+ }
1097
+ template<>
1098
+ VALUE GPS_Solver<FloatT>::update_correction(
1099
+ const bool &update, const VALUE &hash){
1100
+ typedef range_correction_list_t list_t;
1101
+ static const VALUE k_root[] = {
1102
+ ID2SYM(rb_intern("gps_ionospheric")),
1103
+ ID2SYM(rb_intern("gps_tropospheric")),
1104
+ ID2SYM(rb_intern("sbas_ionospheric")),
1105
+ ID2SYM(rb_intern("sbas_tropospheric")),
1106
+ };
1107
+ static const VALUE k_opt(ID2SYM(rb_intern("options")));
1108
+ static const VALUE k_f_10_7(ID2SYM(rb_intern("f_10_7")));
1109
+ static const VALUE k_known(ID2SYM(rb_intern("known")));
1110
+ struct {
1111
+ VALUE sym;
1112
+ list_t::mapped_type::value_type obj;
1113
+ } item[] = {
1114
+ {ID2SYM(rb_intern("no_correction")), &base_t::no_correction},
1115
+ {ID2SYM(rb_intern("klobuchar")), &this->gps.solver.ionospheric_klobuchar},
1116
+ {ID2SYM(rb_intern("ntcm_gl")), &this->gps.solver.ionospheric_ntcm_gl},
1117
+ {ID2SYM(rb_intern("hopfield")), &this->gps.solver.tropospheric_simplified},
1118
+ {ID2SYM(rb_intern("sbas_igp")), &this->sbas.solver.ionospheric_sbas},
1119
+ {ID2SYM(rb_intern("sbas_tropo")), &this->sbas.solver.tropospheric_sbas},
1120
+ };
1121
+ list_t input;
1122
+ if(update){
1123
+ if(!RB_TYPE_P(hash, T_HASH)){
1124
+ throw std::runtime_error(
1125
+ std::string("Hash is expected, however ").append(inspect_str(hash)));
1126
+ }
1127
+ for(std::size_t i(0); i < sizeof(k_root) / sizeof(k_root[0]); ++i){
1128
+ VALUE ary = rb_hash_lookup(hash, k_root[i]);
1129
+ if(NIL_P(ary)){continue;}
1130
+ if(!RB_TYPE_P(ary, T_ARRAY)){
1131
+ ary = rb_ary_new_from_values(1, &ary);
1132
+ }
1133
+ for(int j(0); j < RARRAY_LEN(ary); ++j){
1134
+ std::size_t k(0);
1135
+ VALUE v(rb_ary_entry(ary, j));
1136
+ for(; k < sizeof(item) / sizeof(item[0]); ++k){
1137
+ if(v == item[k].sym){break;}
1138
+ }
1139
+ if(k >= sizeof(item) / sizeof(item[0])){ // other than symbol
1140
+ user_correctors.push_back(GPS_RangeCorrector<FloatT>(v));
1141
+ input[i].push_back(&user_correctors.back());
1142
+ }else{
1143
+ input[i].push_back(item[k].obj);
1144
+ }
1145
+ }
1146
+ }
1147
+ VALUE opt(rb_hash_lookup(hash, k_opt));
1148
+ if(RB_TYPE_P(opt, T_HASH)){
1149
+ swig::asval(rb_hash_lookup(opt, k_f_10_7), // ntcm_gl
1150
+ &this->gps.solver.ionospheric_ntcm_gl.f_10_7);
1151
+ }
1152
+ }
1153
+ list_t output(update_correction(update, input));
1154
+ VALUE res = rb_hash_new();
1155
+ for(list_t::const_iterator it(output.begin()), it_end(output.end());
1156
+ it != it_end; ++it){
1157
+ VALUE k;
1158
+ if((it->first < 0) || (it->first >= (int)(sizeof(k_root) / sizeof(k_root[0])))){
1159
+ k = SWIG_From(int)(it->first);
1160
+ }else{
1161
+ k = k_root[it->first];
1162
+ }
1163
+ VALUE v = rb_ary_new();
1164
+ for(list_t::mapped_type::const_iterator
1165
+ it2(it->second.begin()), it2_end(it->second.end());
1166
+ it2 != it2_end; ++it2){
1167
+ std::size_t i(0);
1168
+ for(; i < sizeof(item) / sizeof(item[0]); ++i){
1169
+ if(*it2 == item[i].obj){break;}
1170
+ }
1171
+ if(i >= sizeof(item) / sizeof(item[0])){ // other than built-in corrector
1172
+ rb_ary_push(v,
1173
+ reinterpret_cast<const GPS_RangeCorrector<FloatT> *>(*it2)->callback);
1174
+ }else{
1175
+ rb_ary_push(v, item[i].sym);
1176
+ }
1177
+ }
1178
+ rb_hash_aset(res, k, v);
1179
+ }
1180
+ { // common options
1181
+ VALUE opt = rb_hash_new();
1182
+ rb_hash_aset(res, k_opt, opt);
1183
+ rb_hash_aset(opt, k_f_10_7, // ntcm_gl
1184
+ swig::from(this->gps.solver.ionospheric_ntcm_gl.f_10_7));
1185
+ }
1186
+ { // known models
1187
+ VALUE ary = rb_ary_new_capa((int)(sizeof(item) / sizeof(item[0])));
1188
+ for(std::size_t i(0); i < sizeof(item) / sizeof(item[0]); ++i){
1189
+ rb_ary_push(ary, item[i].sym);
1190
+ }
1191
+ rb_hash_aset(res, k_known, ary);
1192
+ }
1193
+ return res;
1194
+ }
1195
+ }
1196
+ %fragment("correction"{GPS_Solver<FloatT>});
1197
+ %rename("correction") get_correction;
1198
+ %rename("correction=") set_correction;
1199
+ VALUE get_correction() const {
1200
+ return const_cast<GPS_Solver<FloatT> *>(self)->update_correction(false, Qnil);
1201
+ }
1202
+ VALUE set_correction(VALUE hash){
1203
+ return self->update_correction(true, hash);
1204
+ }
1205
+ #endif
1078
1206
  }
1079
1207
  %inline {
1080
1208
  template <class FloatT>
@@ -1097,19 +1225,36 @@ struct GPS_Solver
1097
1225
  sbas_t() : space_node(), options(), solver(space_node) {}
1098
1226
  } sbas;
1099
1227
  SWIG_Object hooks;
1228
+ typedef std::vector<GPS_RangeCorrector<FloatT> > user_correctors_t;
1229
+ user_correctors_t user_correctors;
1100
1230
  #ifdef SWIGRUBY
1101
1231
  static void mark(void *ptr){
1102
1232
  GPS_Solver<FloatT> *solver = (GPS_Solver<FloatT> *)ptr;
1103
- if(solver->hooks == Qnil){return;}
1104
1233
  rb_gc_mark(solver->hooks);
1234
+ for(typename user_correctors_t::const_iterator
1235
+ it(solver->user_correctors.begin()), it_end(solver->user_correctors.end());
1236
+ it != it_end; ++it){
1237
+ rb_gc_mark(it->callback);
1238
+ }
1105
1239
  }
1106
1240
  #endif
1107
- GPS_Solver() : super_t(), gps(), sbas(), hooks() {
1108
- gps.solver.space_node_sbas = &sbas.space_node;
1109
- sbas.solver.space_node_gps = &gps.space_node;
1241
+ GPS_Solver() : super_t(),
1242
+ gps(), sbas(),
1243
+ hooks(), user_correctors() {
1110
1244
  #ifdef SWIGRUBY
1111
1245
  hooks = rb_hash_new();
1112
1246
  #endif
1247
+ typename base_t::range_correction_t ionospheric, tropospheric;
1248
+ ionospheric.push_back(&sbas.solver.ionospheric_sbas);
1249
+ ionospheric.push_back(&gps.solver.ionospheric_klobuchar);
1250
+ tropospheric.push_back(&sbas.solver.tropospheric_sbas);
1251
+ tropospheric.push_back(&gps.solver.tropospheric_simplified);
1252
+ gps.solver.ionospheric_correction
1253
+ = sbas.solver.ionospheric_correction
1254
+ = ionospheric;
1255
+ gps.solver.tropospheric_correction
1256
+ = sbas.solver.tropospheric_correction
1257
+ = tropospheric;
1113
1258
  }
1114
1259
  GPS_SpaceNode<FloatT> &gps_space_node() {return gps.space_node;}
1115
1260
  GPS_SolverOptions<FloatT> &gps_options() {return gps.options;}
@@ -1149,6 +1294,53 @@ struct GPS_Solver
1149
1294
  const_cast<sbas_t &>(sbas).solver.update_options(sbas.options);
1150
1295
  return super_t::solve().user_pvt(measurement.items, receiver_time);
1151
1296
  }
1297
+ typedef
1298
+ std::map<int, std::vector<const typename base_t::range_corrector_t *> >
1299
+ range_correction_list_t;
1300
+ range_correction_list_t update_correction(
1301
+ const bool &update,
1302
+ const range_correction_list_t &list = range_correction_list_t()){
1303
+ range_correction_list_t res;
1304
+ typename base_t::range_correction_t *root[] = {
1305
+ &gps.solver.ionospheric_correction,
1306
+ &gps.solver.tropospheric_correction,
1307
+ &sbas.solver.ionospheric_correction,
1308
+ &sbas.solver.tropospheric_correction,
1309
+ };
1310
+ for(std::size_t i(0); i < sizeof(root) / sizeof(root[0]); ++i){
1311
+ do{
1312
+ if(!update){break;}
1313
+ typename range_correction_list_t::const_iterator it(list.find(i));
1314
+ if(it == list.end()){break;}
1315
+
1316
+ // Remove user defined unused correctors
1317
+ for(typename base_t::range_correction_t::const_iterator
1318
+ it2(root[i]->begin()), it2_end(root[i]->end());
1319
+ it2 != it2_end; ++it2){
1320
+ for(typename user_correctors_t::const_iterator
1321
+ it3(user_correctors.begin()), it3_end(user_correctors.end());
1322
+ it3 != it3_end; ++it3){
1323
+ if(*it2 != &(*it3)){continue;}
1324
+ user_correctors.erase(it3);
1325
+ }
1326
+ }
1327
+
1328
+ root[i]->clear();
1329
+ for(typename range_correction_list_t::mapped_type::const_iterator
1330
+ it2(it->second.begin()), it2_end(it->second.end());
1331
+ it2 != it2_end; ++it2){
1332
+ root[i]->push_back(*it2);
1333
+ }
1334
+ }while(false);
1335
+ for(typename base_t::range_correction_t::const_iterator
1336
+ it(root[i]->begin()), it_end(root[i]->end());
1337
+ it != it_end; ++it){
1338
+ res[i].push_back(*it);
1339
+ }
1340
+ }
1341
+ return res;
1342
+ }
1343
+ SWIG_Object update_correction(const bool &update, const SWIG_Object &hash);
1152
1344
  };
1153
1345
  }
1154
1346