gps_pvt 0.2.3 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -20,12 +20,14 @@
20
20
  #include "navigation/GPS.h"
21
21
  #include "navigation/SBAS.h"
22
22
  #include "navigation/QZSS.h"
23
+ #include "navigation/GLONASS.h"
23
24
  #include "navigation/RINEX.h"
24
25
 
25
26
  #include "navigation/GPS_Solver_Base.h"
26
27
  #include "navigation/GPS_Solver.h"
27
28
  #include "navigation/GPS_Solver_RAIM.h"
28
29
  #include "navigation/SBAS_Solver.h"
30
+ #include "navigation/GLONASS_Solver.h"
29
31
 
30
32
  #if defined(__cplusplus) && (__cplusplus < 201103L)
31
33
  namespace std {
@@ -153,6 +155,12 @@ static std::string inspect_str(const VALUE &v){
153
155
  $1 = (TYPE($input) == T_ARRAY) ? 1 : 0;
154
156
  }
155
157
  #endif
158
+ %ignore canonicalize();
159
+ %ignore GPS_Time(const int &_week, const float_t &_seconds);
160
+ %typemap(in, numinputs=0) void *dummy "";
161
+ GPS_Time(const int &week_, const float_t &seconds_, void *dummy){
162
+ return &((new GPS_Time<FloatT>(week_, seconds_))->canonicalize());
163
+ }
156
164
  %apply int *OUTPUT { int *week };
157
165
  %apply FloatT *OUTPUT { FloatT *seconds };
158
166
  void to_a(int *week, FloatT *seconds) const {
@@ -500,6 +508,160 @@ struct SBAS_Ephemeris : public SBAS_SpaceNode<FloatT>::SatelliteProperties::Ephe
500
508
 
501
509
  %include navigation/SBAS.h
502
510
 
511
+ %inline %{
512
+ template <class FloatT>
513
+ struct GLONASS_Ephemeris
514
+ : public GLONASS_SpaceNode<FloatT>::SatelliteProperties::Ephemeris_with_GPS_Time {
515
+ typedef typename GLONASS_SpaceNode<FloatT>::SatelliteProperties::Ephemeris_with_GPS_Time eph_t;
516
+ unsigned int super_frame, has_string;
517
+ typename eph_t::raw_t raw;
518
+ void invalidate() {
519
+ super_frame = 0;
520
+ has_string = 0;
521
+ }
522
+ bool is_consistent() const {
523
+ return has_string == 0x1F;
524
+ }
525
+ GLONASS_Ephemeris() : eph_t() {
526
+ invalidate();
527
+ }
528
+ GLONASS_Ephemeris(const eph_t &eph)
529
+ : eph_t(eph),
530
+ super_frame(0), has_string(0), raw() {
531
+ raw = *this;
532
+ has_string = 0x1F;
533
+ }
534
+ };
535
+ %}
536
+ %extend GLONASS_Ephemeris {
537
+ MAKE_ACCESSOR(svid, unsigned int);
538
+
539
+ MAKE_ACCESSOR(freq_ch, int); // frequency channel to be configured
540
+ MAKE_ACCESSOR(t_k, unsigned int);
541
+ MAKE_ACCESSOR(t_b, unsigned int);
542
+ MAKE_ACCESSOR(M, unsigned int);
543
+ MAKE_ACCESSOR(gamma_n, FloatT);
544
+ MAKE_ACCESSOR(tau_n, FloatT);
545
+
546
+ MAKE_ACCESSOR(xn, FloatT); MAKE_ACCESSOR(xn_dot, FloatT); MAKE_ACCESSOR(xn_ddot, FloatT);
547
+ MAKE_ACCESSOR(yn, FloatT); MAKE_ACCESSOR(yn_dot, FloatT); MAKE_ACCESSOR(yn_ddot, FloatT);
548
+ MAKE_ACCESSOR(zn, FloatT); MAKE_ACCESSOR(zn_dot, FloatT); MAKE_ACCESSOR(zn_ddot, FloatT);
549
+
550
+ MAKE_ACCESSOR(B_n, unsigned int);
551
+ MAKE_ACCESSOR(p, unsigned int);
552
+ MAKE_ACCESSOR(N_T, unsigned int);
553
+ MAKE_ACCESSOR(F_T, FloatT);
554
+ MAKE_ACCESSOR(n, unsigned int);
555
+ MAKE_ACCESSOR(delta_tau_n, FloatT);
556
+ MAKE_ACCESSOR(E_n, unsigned int);
557
+ MAKE_ACCESSOR(P1, unsigned int);
558
+ MAKE_ACCESSOR(P2, bool);
559
+ MAKE_ACCESSOR(P4, bool);
560
+
561
+ MAKE_ACCESSOR(tau_c, FloatT);
562
+ MAKE_ACCESSOR(tau_GPS, FloatT);
563
+
564
+ FloatT frequency_L1() const {
565
+ return self->L1_frequency();
566
+ };
567
+ FloatT frequency_L2() const {
568
+ return self->L2_frequency();
569
+ };
570
+ GPS_Time<FloatT> base_time() const {
571
+ return self->base_time();
572
+ }
573
+
574
+ //MAKE_ACCESSOR(l_n, bool); // exists in both Ephemeris and Time_Properties
575
+
576
+ MAKE_ARRAY_INPUT(const unsigned int, buf, SWIG_AsVal(unsigned int));
577
+ bool parse(const unsigned int buf[4], const unsigned int &leap_seconds = 0){
578
+ typedef typename GLONASS_SpaceNode<FloatT>
579
+ ::template BroadcastedMessage<unsigned int> parser_t;
580
+ unsigned int super_frame(buf[3] >> 16), frame(buf[3] & 0xF), string_no(parser_t::m(buf));
581
+ unsigned int has_string(self->has_string);
582
+ if((has_string > 0) && (self->super_frame != super_frame)){
583
+ has_string = 0; // clean up
584
+ }
585
+ self->super_frame = super_frame;
586
+ has_string |= (0x1 << (string_no - 1));
587
+ switch(string_no){
588
+ case 1: self->raw.template update_string1<0, 0>(buf); break;
589
+ case 2: self->raw.template update_string2<0, 0>(buf); break;
590
+ case 3: self->raw.template update_string3<0, 0>(buf); break;
591
+ case 4: self->raw.template update_string4<0, 0>(buf); break;
592
+ case 5: {
593
+ self->raw.template update_string5<0, 0>(buf);
594
+ if(frame == 4){
595
+ // TODO: require special care for 50th frame? @see Table 4.9 note (4)
596
+ }
597
+ break;
598
+ }
599
+ }
600
+ bool updated(false);
601
+ if((has_string == 0x1F) && (has_string != self->has_string)){
602
+ updated = true;
603
+ // All ephemeris and time info. in the same super frame has been acquired,
604
+ // and this block is called once per one same super frame.
605
+ // Ephemeris_with_Time::raw_t =(cast)=> Ephemeris_with_Time => Ephemeris_with_GPS_Time
606
+ static_cast<GLONASS_Ephemeris<FloatT>::eph_t &>(*self)
607
+ = GLONASS_Ephemeris<FloatT>::eph_t(self->raw);
608
+ self->t_b_gps += leap_seconds;
609
+ }
610
+ self->has_string = has_string;
611
+ return updated;
612
+ }
613
+ FloatT clock_error(
614
+ const GPS_Time<FloatT> &t_arrival, const FloatT &pseudo_range = 0) const {
615
+ return self->clock_error(t_arrival, pseudo_range);
616
+ }
617
+ %typemap(in,numinputs=0) System_XYZ<FloatT, WGS84> & (System_XYZ<FloatT, WGS84> temp) %{
618
+ $1 = &temp;
619
+ %}
620
+ %typemap(argout) System_XYZ<FloatT, WGS84> & {
621
+ %append_output(SWIG_NewPointerObj((new $*1_ltype(*$1)), $1_descriptor, SWIG_POINTER_OWN));
622
+ }
623
+ void constellation(
624
+ System_XYZ<FloatT, WGS84> &position, System_XYZ<FloatT, WGS84> &velocity,
625
+ const GPS_Time<FloatT> &t, const FloatT &pseudo_range = 0) const {
626
+ typename GPS_SpaceNode<FloatT>::SatelliteProperties::constellation_t res(
627
+ self->constellation(t, pseudo_range));
628
+ position = res.position;
629
+ velocity = res.velocity;
630
+ }
631
+ #if defined(SWIGRUBY)
632
+ %rename("consistent?") is_consistent;
633
+ %rename("in_range?") is_in_range;
634
+ #endif
635
+ bool is_in_range(const GPS_Time<FloatT> &t) const {
636
+ // "invalidate()" is used to make raw and converted data inconsistent.
637
+ return self->is_valid(t);
638
+ }
639
+ }
640
+
641
+ %extend GLONASS_SpaceNode {
642
+ %fragment(SWIG_Traits_frag(FloatT));
643
+ %ignore satellites() const;
644
+ %ignore satellite(const int &);
645
+ %ignore latest_ephemeris() const;
646
+ void register_ephemeris(
647
+ const int &prn, const GLONASS_Ephemeris<FloatT> &eph,
648
+ const int &priority_delta = 1){
649
+ self->satellite(prn).register_ephemeris(eph, priority_delta);
650
+ }
651
+ GLONASS_Ephemeris<FloatT> ephemeris(const int &prn) const {
652
+ return GLONASS_Ephemeris<FloatT>(
653
+ %const_cast(self, GLONASS_SpaceNode<FloatT> *)->satellite(prn).ephemeris());
654
+ }
655
+ int read(const char *fname) {
656
+ std::fstream fin(fname, std::ios::in | std::ios::binary);
657
+ typename RINEX_NAV_Reader<FloatT>::space_node_list_t list = {NULL};
658
+ list.glonass = self;
659
+ return RINEX_NAV_Reader<FloatT>::read_all(fin, list);
660
+ }
661
+ }
662
+
663
+ %include navigation/GLONASS.h
664
+
503
665
  %extend GPS_User_PVT {
504
666
  %ignore solver_t;
505
667
  %ignore base_t;
@@ -591,8 +753,9 @@ struct GPS_User_PVT
591
753
  Matrix<FloatT, Array2D_Dense<FloatT> > G_enu() const {
592
754
  return proxy_t::linear_solver_t::rotate_G(base_t::G, base_t::user_position.ecef2enu());
593
755
  }
594
- typename proxy_t::linear_solver_t linear_solver() const {
595
- return typename proxy_t::linear_solver_t(base_t::G, base_t::W, base_t::delta_r);
756
+ typename proxy_t::linear_solver_t::partial_t linear_solver() const {
757
+ return typename proxy_t::linear_solver_t(base_t::G, base_t::W, base_t::delta_r)
758
+ .partial(used_satellites());
596
759
  }
597
760
  Matrix<FloatT, Array2D_Dense<FloatT> > C() const {
598
761
  return linear_solver().C();
@@ -605,14 +768,26 @@ struct GPS_User_PVT
605
768
  linear_solver().least_square(res);
606
769
  return res;
607
770
  }
771
+ Matrix<FloatT, Array2D_Dense<FloatT> > S_enu(
772
+ const Matrix<FloatT, Array2D_Dense<FloatT> > &s) const {
773
+ return proxy_t::linear_solver_t::rotate_S(s, base_t::user_position.ecef2enu());
774
+ }
608
775
  Matrix<FloatT, Array2D_Dense<FloatT> > S_enu() const {
609
- return proxy_t::linear_solver_t::rotate_S(S(), base_t::user_position.ecef2enu());
776
+ return S_enu(S());
777
+ }
778
+ Matrix<FloatT, Array2D_Dense<FloatT> > slope_HV(
779
+ const Matrix<FloatT, Array2D_Dense<FloatT> > &s) const {
780
+ return linear_solver().slope_HV(s);
610
781
  }
611
782
  Matrix<FloatT, Array2D_Dense<FloatT> > slope_HV() const {
612
- return linear_solver().slope_HV(S());
783
+ return slope_HV(S());
784
+ }
785
+ Matrix<FloatT, Array2D_Dense<FloatT> > slope_HV_enu(
786
+ const Matrix<FloatT, Array2D_Dense<FloatT> > &s) const {
787
+ return linear_solver().slope_HV(s, base_t::user_position.ecef2enu());
613
788
  }
614
789
  Matrix<FloatT, Array2D_Dense<FloatT> > slope_HV_enu() const {
615
- return linear_solver().slope_HV(S(), base_t::user_position.ecef2enu());
790
+ return slope_HV_enu(S());
616
791
  }
617
792
 
618
793
  void fd(const typename base_t::detection_t **out) const {*out = &(base_t::FD);}
@@ -878,6 +1053,46 @@ struct SBAS_SolverOptions
878
1053
  };
879
1054
  %}
880
1055
 
1056
+ %extend GLONASS_SolverOptions {
1057
+ %ignore base_t;
1058
+ %ignore cast_general;
1059
+ MAKE_VECTOR2ARRAY(int);
1060
+ }
1061
+ %inline %{
1062
+ template <class FloatT>
1063
+ struct GLONASS_SolverOptions
1064
+ : public GLONASS_SinglePositioning<FloatT>::options_t,
1065
+ GPS_SolverOptions_Common<FloatT> {
1066
+ typedef typename GLONASS_SinglePositioning<FloatT>::options_t base_t;
1067
+ void exclude(const int &prn){base_t::exclude_prn.set(prn);}
1068
+ void include(const int &prn){base_t::exclude_prn.reset(prn);}
1069
+ std::vector<int> excluded() const {return base_t::exclude_prn.excluded();}
1070
+ GPS_Solver_GeneralOptions<FloatT> *cast_general(){return this;}
1071
+ const GPS_Solver_GeneralOptions<FloatT> *cast_general() const {return this;}
1072
+ };
1073
+ %}
1074
+
1075
+ %header {
1076
+ template <class FloatT>
1077
+ struct GPS_RangeCorrector
1078
+ : public GPS_Solver_Base<FloatT>::range_corrector_t {
1079
+ SWIG_Object callback;
1080
+ GPS_RangeCorrector(const SWIG_Object &callback_)
1081
+ : GPS_Solver_Base<FloatT>::range_corrector_t(),
1082
+ callback(callback_) {}
1083
+ bool is_available(const typename GPS_Solver_Base<FloatT>::gps_time_t &t) const {
1084
+ return false;
1085
+ }
1086
+ FloatT *calculate(
1087
+ const typename GPS_Solver_Base<FloatT>::gps_time_t &t,
1088
+ const typename GPS_Solver_Base<FloatT>::pos_t &usr_pos,
1089
+ const typename GPS_Solver_Base<FloatT>::enu_t &sat_rel_pos,
1090
+ FloatT &buf) const {
1091
+ return NULL;
1092
+ }
1093
+ };
1094
+ }
1095
+
881
1096
  %extend GPS_Solver {
882
1097
  %ignore super_t;
883
1098
  %ignore base_t;
@@ -885,10 +1100,14 @@ struct SBAS_SolverOptions
885
1100
  %ignore gps;
886
1101
  %ignore sbas_t;
887
1102
  %ignore sbas;
1103
+ %ignore glonass_t;
1104
+ %ignore glonass;
888
1105
  %ignore select_solver;
889
1106
  %ignore relative_property;
890
1107
  %ignore satellite_position;
891
1108
  %ignore update_position_solution;
1109
+ %ignore user_correctors_t;
1110
+ %ignore user_correctors;
892
1111
  %immutable hooks;
893
1112
  %ignore mark;
894
1113
  %fragment("hook"{GPS_Solver<FloatT>}, "header",
@@ -1033,6 +1252,38 @@ struct SBAS_SolverOptions
1033
1252
  %fragment("correction"{GPS_Solver<FloatT>}, "header",
1034
1253
  fragment=SWIG_From_frag(int),
1035
1254
  fragment=SWIG_Traits_frag(FloatT)){
1255
+ template <>
1256
+ bool GPS_RangeCorrector<FloatT>::is_available(
1257
+ const typename GPS_Solver_Base<FloatT>::gps_time_t &t) const {
1258
+ VALUE values[] = {
1259
+ SWIG_NewPointerObj(
1260
+ %const_cast(&t, GPS_Time<FloatT> *), $descriptor(GPS_Time<FloatT> *), 0),
1261
+ };
1262
+ VALUE res(proc_call_throw_if_error(
1263
+ callback, sizeof(values) / sizeof(values[0]), values));
1264
+ return RTEST(res) ? true : false;
1265
+ }
1266
+ template <>
1267
+ FloatT *GPS_RangeCorrector<FloatT>::calculate(
1268
+ const typename GPS_Solver_Base<FloatT>::gps_time_t &t,
1269
+ const typename GPS_Solver_Base<FloatT>::pos_t &usr_pos,
1270
+ const typename GPS_Solver_Base<FloatT>::enu_t &sat_rel_pos,
1271
+ FloatT &buf) const {
1272
+ VALUE values[] = {
1273
+ SWIG_NewPointerObj(
1274
+ %const_cast(&t, GPS_Time<FloatT> *),
1275
+ $descriptor(GPS_Time<FloatT> *), 0),
1276
+ SWIG_NewPointerObj(
1277
+ (%const_cast(&usr_pos.xyz, System_XYZ<FloatT, WGS84> *)),
1278
+ $descriptor(System_XYZ<FloatT, WGS84> *), 0),
1279
+ SWIG_NewPointerObj(
1280
+ (%const_cast(&sat_rel_pos, System_ENU<FloatT, WGS84> *)),
1281
+ $descriptor(System_ENU<FloatT, WGS84> *), 0),
1282
+ };
1283
+ VALUE res(proc_call_throw_if_error(
1284
+ callback, sizeof(values) / sizeof(values[0]), values));
1285
+ return SWIG_IsOK(swig::asval(res, &buf)) ? &buf : NULL;
1286
+ }
1036
1287
  template<>
1037
1288
  VALUE GPS_Solver<FloatT>::update_correction(
1038
1289
  const bool &update, const VALUE &hash){
@@ -1042,6 +1293,8 @@ struct SBAS_SolverOptions
1042
1293
  ID2SYM(rb_intern("gps_tropospheric")),
1043
1294
  ID2SYM(rb_intern("sbas_ionospheric")),
1044
1295
  ID2SYM(rb_intern("sbas_tropospheric")),
1296
+ ID2SYM(rb_intern("glonass_ionospheric")),
1297
+ ID2SYM(rb_intern("glonass_tropospheric")),
1045
1298
  };
1046
1299
  static const VALUE k_opt(ID2SYM(rb_intern("options")));
1047
1300
  static const VALUE k_f_10_7(ID2SYM(rb_intern("f_10_7")));
@@ -1075,10 +1328,12 @@ struct SBAS_SolverOptions
1075
1328
  for(; k < sizeof(item) / sizeof(item[0]); ++k){
1076
1329
  if(v == item[k].sym){break;}
1077
1330
  }
1078
- if(k >= sizeof(item) / sizeof(item[0])){
1079
- continue; // TODO other than symbol
1331
+ if(k >= sizeof(item) / sizeof(item[0])){ // other than symbol
1332
+ user_correctors.push_back(GPS_RangeCorrector<FloatT>(v));
1333
+ input[i].push_back(&user_correctors.back());
1334
+ }else{
1335
+ input[i].push_back(item[k].obj);
1080
1336
  }
1081
- input[i].push_back(item[k].obj);
1082
1337
  }
1083
1338
  }
1084
1339
  VALUE opt(rb_hash_lookup(hash, k_opt));
@@ -1105,10 +1360,12 @@ struct SBAS_SolverOptions
1105
1360
  for(; i < sizeof(item) / sizeof(item[0]); ++i){
1106
1361
  if(*it2 == item[i].obj){break;}
1107
1362
  }
1108
- if(i >= sizeof(item) / sizeof(item[0])){
1109
- continue; // TODO other than built-in corrector
1363
+ if(i >= sizeof(item) / sizeof(item[0])){ // other than built-in corrector
1364
+ rb_ary_push(v,
1365
+ reinterpret_cast<const GPS_RangeCorrector<FloatT> *>(*it2)->callback);
1366
+ }else{
1367
+ rb_ary_push(v, item[i].sym);
1110
1368
  }
1111
- rb_ary_push(v, item[i].sym);
1112
1369
  }
1113
1370
  rb_hash_aset(res, k, v);
1114
1371
  }
@@ -1159,15 +1416,29 @@ struct GPS_Solver
1159
1416
  SBAS_SinglePositioning<FloatT> solver;
1160
1417
  sbas_t() : space_node(), options(), solver(space_node) {}
1161
1418
  } sbas;
1419
+ struct glonass_t {
1420
+ GLONASS_SpaceNode<FloatT> space_node;
1421
+ GLONASS_SolverOptions<FloatT> options;
1422
+ GLONASS_SinglePositioning<FloatT> solver;
1423
+ glonass_t() : space_node(), options(), solver(space_node) {}
1424
+ } glonass;
1162
1425
  SWIG_Object hooks;
1426
+ typedef std::vector<GPS_RangeCorrector<FloatT> > user_correctors_t;
1427
+ user_correctors_t user_correctors;
1163
1428
  #ifdef SWIGRUBY
1164
1429
  static void mark(void *ptr){
1165
1430
  GPS_Solver<FloatT> *solver = (GPS_Solver<FloatT> *)ptr;
1166
- if(solver->hooks == Qnil){return;}
1167
1431
  rb_gc_mark(solver->hooks);
1432
+ for(typename user_correctors_t::const_iterator
1433
+ it(solver->user_correctors.begin()), it_end(solver->user_correctors.end());
1434
+ it != it_end; ++it){
1435
+ rb_gc_mark(it->callback);
1436
+ }
1168
1437
  }
1169
1438
  #endif
1170
- GPS_Solver() : super_t(), gps(), sbas(), hooks() {
1439
+ GPS_Solver() : super_t(),
1440
+ gps(), sbas(), glonass(),
1441
+ hooks(), user_correctors() {
1171
1442
  #ifdef SWIGRUBY
1172
1443
  hooks = rb_hash_new();
1173
1444
  #endif
@@ -1178,20 +1449,25 @@ struct GPS_Solver
1178
1449
  tropospheric.push_back(&gps.solver.tropospheric_simplified);
1179
1450
  gps.solver.ionospheric_correction
1180
1451
  = sbas.solver.ionospheric_correction
1452
+ = glonass.solver.ionospheric_correction
1181
1453
  = ionospheric;
1182
1454
  gps.solver.tropospheric_correction
1183
1455
  = sbas.solver.tropospheric_correction
1456
+ = glonass.solver.tropospheric_correction
1184
1457
  = tropospheric;
1185
1458
  }
1186
1459
  GPS_SpaceNode<FloatT> &gps_space_node() {return gps.space_node;}
1187
1460
  GPS_SolverOptions<FloatT> &gps_options() {return gps.options;}
1188
1461
  SBAS_SpaceNode<FloatT> &sbas_space_node() {return sbas.space_node;}
1189
1462
  SBAS_SolverOptions<FloatT> &sbas_options() {return sbas.options;}
1463
+ GLONASS_SpaceNode<FloatT> &glonass_space_node() {return glonass.space_node;}
1464
+ GLONASS_SolverOptions<FloatT> &glonass_options() {return glonass.options;}
1190
1465
  const base_t &select_solver(
1191
1466
  const typename base_t::prn_t &prn) const {
1192
1467
  if(prn > 0 && prn <= 32){return gps.solver;}
1193
1468
  if(prn >= 120 && prn <= 158){return sbas.solver;}
1194
1469
  if(prn > 192 && prn <= 202){return gps.solver;}
1470
+ if(prn > 0x100 && prn <= (0x100 + 24)){return glonass.solver;}
1195
1471
  // call order: base_t::solve => this returned by select()
1196
1472
  // => relative_property() => select_solver()
1197
1473
  // For not supported satellite, call loop prevention is required.
@@ -1219,6 +1495,8 @@ struct GPS_Solver
1219
1495
  const_cast<gps_t &>(gps).solver.update_options(gps.options);
1220
1496
  const_cast<sbas_t &>(sbas).space_node.update_all_ephemeris(receiver_time);
1221
1497
  const_cast<sbas_t &>(sbas).solver.update_options(sbas.options);
1498
+ const_cast<glonass_t &>(glonass).space_node.update_all_ephemeris(receiver_time);
1499
+ const_cast<glonass_t &>(glonass).solver.update_options(glonass.options);
1222
1500
  return super_t::solve().user_pvt(measurement.items, receiver_time);
1223
1501
  }
1224
1502
  typedef
@@ -1233,12 +1511,27 @@ struct GPS_Solver
1233
1511
  &gps.solver.tropospheric_correction,
1234
1512
  &sbas.solver.ionospheric_correction,
1235
1513
  &sbas.solver.tropospheric_correction,
1514
+ &glonass.solver.ionospheric_correction,
1515
+ &glonass.solver.tropospheric_correction,
1236
1516
  };
1237
1517
  for(std::size_t i(0); i < sizeof(root) / sizeof(root[0]); ++i){
1238
1518
  do{
1239
1519
  if(!update){break;}
1240
1520
  typename range_correction_list_t::const_iterator it(list.find(i));
1241
1521
  if(it == list.end()){break;}
1522
+
1523
+ // Remove user defined unused correctors
1524
+ for(typename base_t::range_correction_t::const_iterator
1525
+ it2(root[i]->begin()), it2_end(root[i]->end());
1526
+ it2 != it2_end; ++it2){
1527
+ for(typename user_correctors_t::const_iterator
1528
+ it3(user_correctors.begin()), it3_end(user_correctors.end());
1529
+ it3 != it3_end; ++it3){
1530
+ if(*it2 != &(*it3)){continue;}
1531
+ user_correctors.erase(it3);
1532
+ }
1533
+ }
1534
+
1242
1535
  root[i]->clear();
1243
1536
  for(typename range_correction_list_t::mapped_type::const_iterator
1244
1537
  it2(it->second.begin()), it2_end(it->second.end());
@@ -1396,6 +1689,10 @@ struct RINEX_Observation {};
1396
1689
  %template(SpaceNode_SBAS) SBAS_SpaceNode<type>;
1397
1690
  %template(SolverOptions_SBAS) SBAS_SolverOptions<type>;
1398
1691
 
1692
+ %template(SpaceNode_GLONASS) GLONASS_SpaceNode<type>;
1693
+ %template(Ephemeris_GLONASS) GLONASS_Ephemeris<type>;
1694
+ %template(SolverOptions_GLONASS) GLONASS_SolverOptions<type>;
1695
+
1399
1696
  %template(RINEX_Observation) RINEX_Observation<type>;
1400
1697
  %enddef
1401
1698
 
@@ -437,8 +437,6 @@ class Matrix : public Matrix_Frozen<T, Array2D_Type, ViewType> {
437
437
  #endif
438
438
 
439
439
  typedef Matrix<T, Array2D_Type, ViewType> self_t;
440
- self_t &swapRows(const unsigned int &row1, const unsigned int &row2);
441
- self_t &swapColumns(const unsigned int &column1, const unsigned int &column2);
442
440
  };
443
441
 
444
442
  %inline {
@@ -995,7 +993,23 @@ MAKE_TO_S(Matrix_Frozen)
995
993
  }
996
994
  #endif
997
995
 
998
- %typemap(out) self_t & "$result = self;"
996
+ /*
997
+ * Returning (*this) requires special care;
998
+ * "self_t &func(){return (*this);}" in a C++ file may generate
999
+ * a new wrapped object deleted by GC in the target language
1000
+ * unless the care.
1001
+ *
1002
+ * Work around 1)
1003
+ * %typemap(in, numinputs=0) self_t *self_p "";
1004
+ * %typemap(argout) self_t *self_p "$result = self;";
1005
+ * void func(self_t *self_p){...}
1006
+ *
1007
+ * Work around 2) (useful without overwrite of the original source, but may overfit)
1008
+ * %typemap(out) self_t & "$result = self;"
1009
+ * self_t &func(){...; return *$self;}
1010
+ */
1011
+ %typemap(in, numinputs=0) self_t *self_p "";
1012
+ %typemap(argout) self_t *self_p "$result = self;";
999
1013
 
1000
1014
  T &__setitem__(const unsigned int &row, const unsigned int &column, const T &value) {
1001
1015
  return (($self)->operator()(row, column) = value);
@@ -1012,41 +1026,50 @@ MAKE_TO_S(Matrix_Frozen)
1012
1026
  #endif
1013
1027
  %rename("scalar") getScalar;
1014
1028
  %rename("I") getI;
1015
- %rename("swap_rows") swapRows;
1016
- %rename("swap_columns") swapColumns;
1029
+
1030
+ void swap_rows(
1031
+ self_t *self_p,
1032
+ const unsigned int &r1, const unsigned int &r2){
1033
+ $self->swapRows(r1, r2);
1034
+ }
1035
+ void swap_columns(
1036
+ self_t *self_p,
1037
+ const unsigned int &c1, const unsigned int &c2){
1038
+ $self->swapColumns(c1, c2);
1039
+ }
1017
1040
 
1018
1041
  template <class T2, class Array2D_Type2, class ViewType2>
1019
- self_t &replace(const Matrix_Frozen<T2, Array2D_Type2, ViewType2> &matrix){
1020
- return $self->replace(matrix);
1042
+ void replace(
1043
+ self_t *self_p,
1044
+ const Matrix_Frozen<T2, Array2D_Type2, ViewType2> &matrix){
1045
+ $self->replace(matrix);
1021
1046
  }
1022
1047
  INSTANTIATE_MATRIX_FUNC(replace, replace);
1023
1048
 
1024
- self_t &replace(const void *replacer = NULL){
1049
+ void replace(self_t *self_p, const void *replacer = NULL){
1025
1050
  if(!MatrixUtil::replace(*$self, replacer)){
1026
1051
  throw std::runtime_error("Unsupported replacement");
1027
1052
  }
1028
- return *$self;
1029
1053
  }
1030
1054
 
1031
- self_t &replace(const T *serialized){
1055
+ void replace(self_t *self_p, const T *serialized){
1032
1056
  if(!MatrixUtil::replace(*$self, serialized)){
1033
1057
  throw std::runtime_error("Unsupported replacement");
1034
1058
  }
1035
- return *$self;
1036
1059
  }
1037
1060
 
1038
1061
  #ifdef SWIGRUBY
1039
- %bang swapRows(const unsigned int &, const unsigned int &);
1040
- %bang swapColumns(const unsigned int &, const unsigned int &);
1062
+ %bang swap_rows;
1063
+ %bang swap_columns;
1041
1064
  %rename("replace!") replace;
1042
1065
 
1043
- self_t &map_bang(
1066
+ void map_bang(
1067
+ self_t *self_p,
1044
1068
  void (*each_func)(
1045
1069
  const T &src, T *dst,
1046
1070
  const unsigned int &i, const unsigned int &j),
1047
1071
  const typename MatrixUtil::each_which_t &each_which = MatrixUtil::EACH_ALL){
1048
1072
  MatrixUtil::each(*$self, each_func, each_which, $self);
1049
- return *$self;
1050
1073
  }
1051
1074
  %rename("map!") map_bang;
1052
1075
  %alias map_bang "collect!,map_with_index!,collect_with_index!";
@@ -253,6 +253,7 @@ __RINEX_OBS_TEXT__
253
253
  t_meas = GPS::Time::new(1849, 172413)
254
254
  puts "Measurement time: #{t_meas.to_a} (a.k.a #{"%d/%d/%d %02d:%02d:%02d UTC"%[*t_meas.c_tm]})"
255
255
  expect(t_meas.c_tm).to eq([2015, 6, 15, 23, 53, 33])
256
+ expect(GPS::Time::new(0, t_meas.serialize)).to eq(t_meas)
256
257
 
257
258
  sn.update_all_ephemeris(t_meas)
258
259
 
@@ -343,7 +344,12 @@ __RINEX_OBS_TEXT__
343
344
  expect(solver.correction[:gps_tropospheric]).to include(:hopfield)
344
345
  expect{solver.correction = nil}.to raise_error(RuntimeError)
345
346
  expect{solver.correction = {
346
- :gps_ionospheric => [:klobuchar, :no_correction],
347
+ :gps_ionospheric => [proc{|t, usr_pos, sat_pos|
348
+ expect(t).to be_a_kind_of(GPS::Time)
349
+ expect(usr_pos).to be_a_kind_of(Coordinate::XYZ) unless usr_pos
350
+ expect(sat_pos).to be_a_kind_of(Coordinate::ENU) unless sat_pos
351
+ false
352
+ }, :klobuchar, :no_correction],
347
353
  :options => {:f_10_7 => 10},
348
354
  }}.not_to raise_error
349
355
  expect(solver.correction[:gps_ionospheric]).to include(:no_correction)
@@ -214,9 +214,19 @@ shared_examples 'Matrix' do
214
214
  it 'is swappable with swap_rows! or swap_cloumns!' do
215
215
  mat_builtin = Matrix[*compare_with[0]]
216
216
  [:swap_rows!, :swap_columns!].each.with_index{|func, i|
217
- params[:rc][i].times.to_a.combination(2).to_a{|a, b|
218
- mat[0].send(func, a, b)
219
- mat_builtin.send(func, a, b)
217
+ params[:rc][i].times.to_a.combination(2).to_a.each{|a, b|
218
+ mat_mod = mat[0].send(func, a, b)
219
+ case func
220
+ when :swap_rows!
221
+ idxs = mat_builtin.row_count.times.to_a
222
+ idxs[a], idxs[b] = [b, a]
223
+ mat_builtin = Matrix::rows(mat_builtin.row_vectors.values_at(*idxs))
224
+ when :swap_columns!
225
+ idxs = mat_builtin.column_count.times.to_a
226
+ idxs[a], idxs[b] = [b, a]
227
+ mat_builtin = Matrix::columns(mat_builtin.column_vectors.values_at(*idxs))
228
+ end
229
+ expect(mat_mod).to equal(mat[0])
220
230
  expect(mat[0].to_a).to eq(mat_builtin.to_a)
221
231
  }
222
232
  }
data/gps_pvt.gemspec CHANGED
File without changes