gps_pvt 0.2.0 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b49839b2da332d30293697783114af90a441fe477dfb85e17ac166c381970836
4
- data.tar.gz: 4227cc97c2bdd1c5994a598ab1723c9bad86331478f0cc60aaa8435302bc9838
3
+ metadata.gz: cd084c2ca722a761b9dbae3ea2fde546531f403ebff8e87b5d7b9632986c3aa8
4
+ data.tar.gz: 92943ca82b4ab13794dc39c51e71a23d178baf483fd1dd782a7305fc7a121de5
5
5
  SHA512:
6
- metadata.gz: a81577f725c28dfe949342076d10826eb14238ec791bc58bc8b7797715b5bc6d6b014fd10454e8f2c56a66ac6b6d03965c79f9e94f39ac65b193fa815cd83924
7
- data.tar.gz: f7eb1d3c1eb4e4ef61d8ada6b12efe1a0d4a9c167d87fc6d2ee7f829dcddb0f3b3c50c6a47a58b08cce57ca220283e2f73af24fafed27da3bb112e4af71a5efd
6
+ metadata.gz: 48597633d7d70da6f7458f00482873d8c2f695dfb352ce0d5a1c6529b495eb0f3c26e07df89249d5a5dd34a82b13bcfd964fcac330e775f9b2f1cf90bd3274ab
7
+ data.tar.gz: 31baba44c7d446334ed3fc9c73c73dd69500f7548ba417a1da92d20c991fc33c799a3a38e0f4651ff873e3caf4d7a3123b4e0e9514d50523cb9003f02f2affd2
data/README.md CHANGED
@@ -31,6 +31,16 @@ For user who just generate PVT solution, an attached executable is useful. After
31
31
 
32
32
  $ gps_pvt RINEX_or_UBX_file(s)
33
33
 
34
+ The format of RINEX_or_UBX_file is automatically determined with its extention, such as .ubx will be treated as UBX format. If you want to specify the file format, instead of RINEX_or_UBX_file(s), use the following arguments:
35
+
36
+ --rinex_nav=filename
37
+ --rinex_obs=filename
38
+ --ubx=filename
39
+
40
+ From version 0.2.0, SBAS and QZSS are supported in addition to GPS. QZSS ranging is activated in default, however, SBAS is just utilized for ionospheric correction. If you want to activate SBAS ranging, "--with=(SBAS PRN number, ex. 137)" option is used with gps_pvt executable like
41
+
42
+ $ gps_pvt --with=137 RINEX_or_UBX_file(s)
43
+
34
44
  For developer, this library will be used in the following:
35
45
 
36
46
  ```ruby
@@ -75,9 +85,10 @@ receiver.parse_rinex_obs(rinex_obs_file){|pvt, meas| # per epoch
75
85
  receiver.solver.gps_options.exclude(prn) # Exclude satellite; the default is to use every satellite if visible
76
86
  receiver.solver.gps_options.include(prn) # Discard previous setting of exclusion
77
87
  receiver.solver.gps_options.elevation_mask = Math::PI / 180 * 10 # example 10 [deg] elevation mask
78
- receiver.solver.hooks[:relative_property] = proc{|prn, rel_prop, rcv_e, t_arv, usr_pos, usr_vel|
88
+ receiver.solver.hooks[:relative_property] = proc{|prn, rel_prop, meas, rcv_e, t_arv, usr_pos, usr_vel|
79
89
  # control weight per satellite per iteration
80
90
  weight, range_c, range_r, rate_rel_neg, *los_neg = rel_prop # relative property
91
+ # meas is measurement represented by pseudo range of the selected satellite.
81
92
  # rcv_e, t_arv, usr_pos, usr_vel are temporary solution of
82
93
  # receiver clock error [m], time of arrival [s], user position and velocity in ECEF, respectively.
83
94
 
@@ -94,7 +105,7 @@ receiver.solver.hooks[:relative_property] = proc{|prn, rel_prop, rcv_e, t_arv, u
94
105
  alias_method(:run_orig, :run)
95
106
  define_method(:run){|meas, t_meas, &b|
96
107
  meas # observation, same as the 2nd argument of parse_XXX
97
- receiver.solver.hooks[:relative_property] = proc{|prn, rel_prop, rcv_e, t_arv, usr_pos, usr_vel|
108
+ receiver.solver.hooks[:relative_property] = proc{|prn, rel_prop, meas, rcv_e, t_arv, usr_pos, usr_vel|
98
109
  # Do something based on meas, t_meas.
99
110
  rel_prop
100
111
  }
data/exe/gps_pvt CHANGED
@@ -6,23 +6,35 @@ require 'gps_pvt'
6
6
 
7
7
  $stderr.puts <<__STRING__
8
8
  Usage: #{__FILE__} GPS_file1 GPS_file2 ...
9
- As GPS_file, rinex_nav(*.YYn), rinex_obs(*.YYo), and ubx(*.ubx) format are currently supported.
9
+ As GPS_file, rinex_nav(*.YYn, *.YYh, *.YYq), rinex_obs(*.YYo), and ubx(*.ubx) format are currently supported.
10
10
  File format is automatically determined based on its extention described in above parentheses.
11
+ If you want to specify its format manually, --rinex_(nav|obs)=file_name or --ubx=file_name are available.
12
+ Supported RINEX versions are 2 and 3.
11
13
  Note: YY = last two digit of year.
12
14
  __STRING__
13
15
 
14
16
  options = []
15
17
 
16
- # check options
17
- ARGV.reject!{|arg|
18
- next false unless arg =~ /^--([^=]+)=?/
18
+ # check options and file format
19
+ files = ARGV.collect{|arg|
20
+ next [arg, nil] unless arg =~ /^--([^=]+)=?/
21
+ k, v = [$1.downcase.to_sym, $']
22
+ next [v, k] if [:rinex_nav, :rinex_obs, :ubx].include?(k) # file type
19
23
  options << [$1.to_sym, $']
20
- true
21
- }
22
-
23
- # Check file existence
24
- ARGV.each{|arg|
25
- raise "File not found: #{arg}" unless File::exist?(arg)
24
+ nil
25
+ }.compact
26
+
27
+ # Check file existence and extension
28
+ files.collect!{|fname, ftype|
29
+ raise "File not found: #{fname}" unless File::exist?(fname)
30
+ ftype ||= case fname
31
+ when /\.\d{2}[nhq]$/; :rinex_nav
32
+ when /\.\d{2}o$/; :rinex_obs
33
+ when /\.ubx$/; :ubx
34
+ else
35
+ raise "Format cannot be guessed, use --(format, ex. rinex_nav)=#{fname}"
36
+ end
37
+ [fname, ftype]
26
38
  }
27
39
 
28
40
  rcv = GPS_PVT::Receiver::new(options)
@@ -30,17 +42,14 @@ rcv = GPS_PVT::Receiver::new(options)
30
42
  puts rcv.header
31
43
 
32
44
  # parse RINEX NAV
33
- ARGV.reject!{|arg|
34
- next false unless arg =~ /\.\d{2}[nq]$/
35
- rcv.parse_rinex_nav(arg)
45
+ files.each{|fname, ftype|
46
+ rcv.parse_rinex_nav(fname) if ftype == :rinex_nav
36
47
  }
37
48
 
38
49
  # other files
39
- ARGV.each{|arg|
40
- case arg
41
- when /\.ubx$/
42
- rcv.parse_ubx(arg)
43
- when /\.\d{2}o$/
44
- rcv.parse_rinex_obs(arg)
50
+ files.each{|fname, ftype|
51
+ case ftype
52
+ when :ubx; rcv.parse_ubx(fname)
53
+ when :rinex_obs; rcv.parse_rinex_obs(fname)
45
54
  end
46
55
  }
@@ -2584,7 +2584,11 @@ struct GPS_Solver
2584
2584
  if(prn > 0 && prn <= 32){return gps.solver;}
2585
2585
  if(prn >= 120 && prn <= 158){return sbas.solver;}
2586
2586
  if(prn > 192 && prn <= 202){return gps.solver;}
2587
- return *this;
2587
+ // call order: base_t::solve => this returned by select()
2588
+ // => relative_property() => select_solver()
2589
+ // For not supported satellite, call loop prevention is required.
2590
+ static const base_t dummy;
2591
+ return dummy;
2588
2592
  }
2589
2593
  virtual typename base_t::relative_property_t relative_property(
2590
2594
  const typename base_t::prn_t &prn,
@@ -2596,9 +2600,7 @@ struct GPS_Solver
2596
2600
  virtual typename base_t::xyz_t *satellite_position(
2597
2601
  const typename base_t::prn_t &prn,
2598
2602
  const typename base_t::gps_time_t &time,
2599
- typename base_t::xyz_t &res) const {
2600
- return select_solver(prn).satellite_position(prn, time, res);
2601
- }
2603
+ typename base_t::xyz_t &res) const;
2602
2604
  virtual bool update_position_solution(
2603
2605
  const typename base_t::geometric_matrices_t &geomat,
2604
2606
  typename base_t::user_pvt_t &res) const;
@@ -3200,11 +3202,8 @@ SWIG_AsCharPtrAndSize(VALUE obj, char** cptr, size_t* psize, int *alloc)
3200
3202
 
3201
3203
  SWIGINTERN int GPS_SpaceNode_Sl_double_Sg__read(GPS_SpaceNode< double > *self,char const *fname){
3202
3204
  std::fstream fin(fname, std::ios::in | std::ios::binary);
3203
- typename RINEX_NAV_Reader<double>::space_node_list_t space_nodes = {
3204
- self, // GPS
3205
- NULL, // SBAS
3206
- self, // QZSS
3207
- };
3205
+ typename RINEX_NAV_Reader<double>::space_node_list_t space_nodes = {self};
3206
+ space_nodes.qzss = self;
3208
3207
  return RINEX_NAV_Reader<double>::read_all(fin, space_nodes);
3209
3208
  }
3210
3209
  SWIGINTERN void GPS_Ionospheric_UTC_Parameters_Sl_double_Sg__set_alpha(GPS_Ionospheric_UTC_Parameters< double > *self,double const values[4]){
@@ -3593,6 +3592,18 @@ SWIGINTERN void GPS_Ephemeris_Sl_double_Sg__constellation__SWIG_0(GPS_Ephemeris<
3593
3592
 
3594
3593
  return SWIG_ERROR;
3595
3594
  }
3595
+
3596
+ template <>
3597
+ VALUE from(const GPS_Measurement<double>::items_t::mapped_type &val) {
3598
+ VALUE per_sat(rb_hash_new());
3599
+ for(typename GPS_Measurement<double>::items_t::mapped_type::const_iterator
3600
+ it(val.begin()), it_end(val.end());
3601
+ it != it_end; ++it){
3602
+ rb_hash_aset(per_sat, SWIG_From_int (it->first), swig::from(it->second));
3603
+ }
3604
+ return per_sat;
3605
+ }
3606
+
3596
3607
  }
3597
3608
 
3598
3609
  SWIGINTERN void GPS_Measurement_Sl_double_Sg__each(GPS_Measurement< double > const *self){
@@ -3618,13 +3629,7 @@ SWIGINTERN VALUE GPS_Measurement_Sl_double_Sg__to_hash(GPS_Measurement< double >
3618
3629
  for(typename GPS_Measurement<double>::items_t::const_iterator
3619
3630
  it(self->items.begin()), it_end(self->items.end());
3620
3631
  it != it_end; ++it){
3621
- VALUE per_sat(rb_hash_new());
3622
- rb_hash_aset(res, SWIG_From_int (it->first), per_sat);
3623
- for(typename GPS_Measurement<double>::items_t::mapped_type::const_iterator
3624
- it2(it->second.begin()), it2_end(it->second.end());
3625
- it2 != it2_end; ++it2){
3626
- rb_hash_aset(per_sat, SWIG_From_int (it2->first), swig::from(it2->second));
3627
- }
3632
+ rb_hash_aset(res, SWIG_From_int (it->first), swig::from(it->second));
3628
3633
  }
3629
3634
  return res;
3630
3635
  }
@@ -3648,16 +3653,16 @@ SWIGINTERN double const &GPS_SolverOptions_Common_Sl_double_Sg__get_f_10_7(GPS_S
3648
3653
  }
3649
3654
 
3650
3655
  template <>
3651
- typename GPS_Solver<double>::base_t::relative_property_t
3656
+ GPS_Solver<double>::base_t::relative_property_t
3652
3657
  GPS_Solver<double>::relative_property(
3653
- const typename GPS_Solver<double>::base_t::prn_t &prn,
3654
- const typename GPS_Solver<double>::base_t::measurement_t::mapped_type &measurement,
3655
- const typename GPS_Solver<double>::base_t::float_t &receiver_error,
3656
- const typename GPS_Solver<double>::base_t::gps_time_t &time_arrival,
3657
- const typename GPS_Solver<double>::base_t::pos_t &usr_pos,
3658
- const typename GPS_Solver<double>::base_t::xyz_t &usr_vel) const {
3658
+ const GPS_Solver<double>::base_t::prn_t &prn,
3659
+ const GPS_Solver<double>::base_t::measurement_t::mapped_type &measurement,
3660
+ const GPS_Solver<double>::base_t::float_t &receiver_error,
3661
+ const GPS_Solver<double>::base_t::gps_time_t &time_arrival,
3662
+ const GPS_Solver<double>::base_t::pos_t &usr_pos,
3663
+ const GPS_Solver<double>::base_t::xyz_t &usr_vel) const {
3659
3664
  union {
3660
- typename base_t::relative_property_t prop;
3665
+ base_t::relative_property_t prop;
3661
3666
  double values[7];
3662
3667
  } res = {
3663
3668
  select_solver(prn).relative_property(
@@ -3679,6 +3684,7 @@ SWIGINTERN double const &GPS_SolverOptions_Common_Sl_double_Sg__get_f_10_7(GPS_S
3679
3684
  swig::from(res.prop.los_neg[0]),
3680
3685
  swig::from(res.prop.los_neg[1]),
3681
3686
  swig::from(res.prop.los_neg[2])),
3687
+ swig::from(measurement), // measurement => Hash
3682
3688
  swig::from(receiver_error), // receiver_error
3683
3689
  SWIG_NewPointerObj( // time_arrival
3684
3690
  new base_t::gps_time_t(time_arrival), SWIGTYPE_p_GPS_TimeT_double_t, SWIG_POINTER_OWN),
@@ -3709,15 +3715,15 @@ SWIGINTERN double const &GPS_SolverOptions_Common_Sl_double_Sg__get_f_10_7(GPS_S
3709
3715
  }
3710
3716
  template <>
3711
3717
  bool GPS_Solver<double>::update_position_solution(
3712
- const typename GPS_Solver<double>::base_t::geometric_matrices_t &geomat,
3713
- typename GPS_Solver<double>::base_t::user_pvt_t &res) const {
3718
+ const GPS_Solver<double>::base_t::geometric_matrices_t &geomat,
3719
+ GPS_Solver<double>::base_t::user_pvt_t &res) const {
3714
3720
 
3715
3721
  do{
3716
3722
  static const VALUE key(ID2SYM(rb_intern("update_position_solution")));
3717
3723
  VALUE hook(rb_hash_lookup(hooks, key));
3718
3724
  if(NIL_P(hook)){break;}
3719
- typename base_t::geometric_matrices_t &geomat_(
3720
- const_cast< typename base_t::geometric_matrices_t & >(geomat));
3725
+ base_t::geometric_matrices_t &geomat_(
3726
+ const_cast< base_t::geometric_matrices_t & >(geomat));
3721
3727
  VALUE values[] = {
3722
3728
  SWIG_NewPointerObj(&geomat_.G,
3723
3729
  SWIGTYPE_p_MatrixT_double_Array2D_DenseT_double_t_MatrixViewBaseT_t_t, 0),
@@ -3730,6 +3736,51 @@ SWIGINTERN double const &GPS_SolverOptions_Common_Sl_double_Sg__get_f_10_7(GPS_S
3730
3736
 
3731
3737
  return super_t::update_position_solution(geomat, res);
3732
3738
  }
3739
+ template <>
3740
+ GPS_Solver<double>::base_t::xyz_t *GPS_Solver<double>::satellite_position(
3741
+ const GPS_Solver<double>::base_t::prn_t &prn,
3742
+ const GPS_Solver<double>::base_t::gps_time_t &time,
3743
+ GPS_Solver<double>::base_t::xyz_t &buf) const {
3744
+ GPS_Solver<double>::base_t::xyz_t *res(
3745
+ select_solver(prn).satellite_position(prn, time, buf));
3746
+
3747
+ do{
3748
+ static const VALUE key(ID2SYM(rb_intern("satellite_position")));
3749
+ VALUE hook(rb_hash_lookup(hooks, key));
3750
+ if(NIL_P(hook)){break;}
3751
+ VALUE values[] = {
3752
+ SWIG_From_int (prn), // prn
3753
+ SWIG_NewPointerObj( // time
3754
+ new base_t::gps_time_t(time), SWIGTYPE_p_GPS_TimeT_double_t, SWIG_POINTER_OWN),
3755
+ (res // position (internally calculated)
3756
+ ? SWIG_NewPointerObj(res, SWIGTYPE_p_System_XYZT_double_WGS84_t, 0)
3757
+ : Qnil)};
3758
+ VALUE res_hook(proc_call_throw_if_error(hook, sizeof(values) / sizeof(values[0]), values));
3759
+ if(NIL_P(res_hook)){ // unknown position
3760
+ res = NULL;
3761
+ break;
3762
+ }else if(RB_TYPE_P(res_hook, T_ARRAY) && (RARRAY_LEN(res_hook) == 3)){
3763
+ int i(0);
3764
+ for(; i < 3; ++i){
3765
+ VALUE v(RARRAY_AREF(res_hook, i));
3766
+ if(!SWIG_IsOK(swig::asval(v, &buf[i]))){break;}
3767
+ }
3768
+ if(i == 3){
3769
+ res = &buf;
3770
+ break;
3771
+ }
3772
+ }else if(SWIG_IsOK(SWIG_ConvertPtr(
3773
+ res_hook, (void **)&res, SWIGTYPE_p_System_XYZT_double_WGS84_t, 0))){
3774
+ res = &(buf = *res);
3775
+ break;
3776
+ }
3777
+ throw std::runtime_error(
3778
+ std::string("System_XYZ or [d * 3] is expected (d: " "double" "), however ")
3779
+ .append(inspect_str(res_hook)));
3780
+ }while(false);
3781
+
3782
+ return res;
3783
+ }
3733
3784
 
3734
3785
  SWIGINTERN unsigned int SBAS_Ephemeris_Sl_double_Sg__set_svid(SBAS_Ephemeris< double > *self,unsigned int const &v){
3735
3786
  return self->svid = v;
@@ -3836,7 +3887,8 @@ SWIGINTERN SBAS_Ephemeris< double > SBAS_SpaceNode_Sl_double_Sg__ephemeris(SBAS_
3836
3887
  }
3837
3888
  SWIGINTERN int SBAS_SpaceNode_Sl_double_Sg__read(SBAS_SpaceNode< double > *self,char const *fname){
3838
3889
  std::fstream fin(fname, std::ios::in | std::ios::binary);
3839
- RINEX_NAV_Reader<double>::space_node_list_t space_nodes = {NULL, self};
3890
+ RINEX_NAV_Reader<double>::space_node_list_t space_nodes = {NULL};
3891
+ space_nodes.sbas = self;
3840
3892
  return RINEX_NAV_Reader<double>::read_all(fin, space_nodes);
3841
3893
  }
3842
3894
  SWIGINTERN int SBAS_SpaceNode_Sl_double_Sg__decode_message__SWIG_2(SBAS_SpaceNode< double > *self,unsigned int const buf[8],int const &prn,GPS_Time< double > const &t_reception,bool const &LNAV_VNAV_LP_LPV_approach=false){
@@ -395,10 +395,11 @@ protected:
395
395
  * @return transformed design matrix G'
396
396
  */
397
397
  static matrix_t rotate_G(const MatrixT &G_, const matrix_t &rotation_matrix){
398
- matrix_t res(G_.rows(), 4);
399
- res.partial(G_.rows(), 3).replace(
400
- G_.partial(G_.rows(), 3) * rotation_matrix.transpose());
401
- res.partial(G_.rows(), 1, 0, 3).replace(G_.partial(G_.rows(), 1, 0, 3));
398
+ unsigned int r(G_.rows()), c(G_.columns()); // Normally c=4
399
+ matrix_t res(r, c);
400
+ res.partial(r, 3).replace(
401
+ G_.partial(r, 3) * rotation_matrix.transpose());
402
+ res.partial(r, c - 3, 0, 3).replace(G_.partial(r, c - 3, 0, 3));
402
403
  return res;
403
404
  }
404
405
 
@@ -425,14 +426,16 @@ protected:
425
426
  * @see rotate_G
426
427
  */
427
428
  static matrix_t rotate_C(const matrix_t &C, const matrix_t &rotation_matrix){
428
- matrix_t res(4, 4);
429
+ unsigned int n(C.rows()); // Normally n=4
430
+ matrix_t res(n, n);
429
431
  res.partial(3, 3).replace( // upper left
430
432
  rotation_matrix * C.partial(3, 3) * rotation_matrix.transpose());
431
- res.partial(3, 1, 0, 3).replace( // upper right
432
- rotation_matrix * C.partial(3, 1, 0, 3));
433
- res.partial(1, 3, 3, 0).replace( // lower left
434
- C.partial(1, 3, 3, 0) * rotation_matrix.transpose());
435
- res(3, 3) = C(3, 3); // lower right
433
+ res.partial(3, n - 3, 0, 3).replace( // upper right
434
+ rotation_matrix * C.partial(3, n - 3, 0, 3));
435
+ res.partial(n - 3, 3, 3, 0).replace( // lower left
436
+ C.partial(n - 3, 3, 3, 0) * rotation_matrix.transpose());
437
+ res.partial(n - 3, n - 3, 3, 3).replace( // lower right
438
+ C.partial(n - 3, n - 3, 3, 3));
436
439
  return res;
437
440
  }
438
441
  /**
@@ -470,11 +473,10 @@ protected:
470
473
  * @see rotate_G
471
474
  */
472
475
  static matrix_t rotate_S(const matrix_t &S, const matrix_t &rotation_matrix){
473
- matrix_t res(4, S.columns());
474
- res.partial(3, S.columns()).replace(rotation_matrix * S.partial(3, S.columns()));
475
- for(unsigned int j(0), j_end(S.columns()); j < j_end; ++j){
476
- res(3, j) = S(3, j);
477
- }
476
+ unsigned int r(S.rows()), c(S.columns()); // Normally r=4
477
+ matrix_t res(r, c);
478
+ res.partial(3, c).replace(rotation_matrix * S.partial(3, c));
479
+ res.partial(r - 3, c, 3, 0).replace(S.partial(r - 3, c, 3, 0));
478
480
  return res;
479
481
  }
480
482
  /**
@@ -537,7 +539,7 @@ protected:
537
539
  partial_t partial(unsigned int size) const {
538
540
  if(size >= G.rows()){size = G.rows();}
539
541
  return partial_t(
540
- G.partial(size, 4), W.partial(size, size), delta_r.partial(size, 1));
542
+ G.partial(size, G.columns()), W.partial(size, size), delta_r.partial(size, 1));
541
543
  }
542
544
  typedef linear_solver_t<typename MatrixT::circular_t> exclude_t;
543
545
  exclude_t exclude(const unsigned int &row) const {
@@ -545,14 +547,16 @@ protected:
545
547
  if(size >= 1){size--;}
546
548
  // generate matrices having circular view
547
549
  return exclude_t(
548
- G.circular(offset, 0, size, 4),
550
+ G.circular(offset, 0, size, G.columns()),
549
551
  W.circular(offset, offset, size, size),
550
552
  delta_r.circular(offset, 0, size, 1));
551
553
  }
552
554
  template <class MatrixT2>
553
555
  void copy_G_W_row(const linear_solver_t<MatrixT2> &src,
554
556
  const unsigned int &i_src, const unsigned int &i_dst){
555
- for(unsigned int j(0); j < 4; ++j){
557
+ unsigned int c_dst(G.columns()), c_src(src.G.columns()),
558
+ c(c_dst > c_src ? c_src : c_dst); // Normally c=4
559
+ for(unsigned int j(0); j < c; ++j){
556
560
  G(i_dst, j) = src.G(i_src, j);
557
561
  }
558
562
  W(i_dst, i_dst) = src.W(i_src, i_src);
@@ -561,9 +565,12 @@ protected:
561
565
 
562
566
  struct geometric_matrices_t : public linear_solver_t<matrix_t> {
563
567
  typedef linear_solver_t<matrix_t> super_t;
564
- geometric_matrices_t(const unsigned int &capacity)
568
+ geometric_matrices_t(
569
+ const unsigned int &capacity,
570
+ const unsigned int &estimate_system_differences = 0)
565
571
  : super_t(
566
- matrix_t(capacity, 4), matrix_t(capacity, capacity), matrix_t(capacity, 1)) {
572
+ matrix_t(capacity, 4 + estimate_system_differences),
573
+ matrix_t(capacity, capacity), matrix_t(capacity, 1)) {
567
574
  for(unsigned int i(0); i < capacity; ++i){
568
575
  super_t::G(i, 3) = 1;
569
576
  }
@@ -846,8 +846,10 @@ class RINEX_NAV_Reader : public RINEX_Reader<> {
846
846
  };
847
847
 
848
848
  static int read_all(std::istream &in, space_node_list_t &space_nodes = {0}){
849
- int res(-1);
850
849
  RINEX_NAV_Reader reader(in);
850
+ if(reader.version_type.file_type != version_type_t::FTYPE_NAVIGATION){
851
+ return -1;
852
+ }
851
853
  if(space_nodes.gps){
852
854
  (reader.version_type.version >= 300)
853
855
  ? reader.extract_iono_utc_v3(*space_nodes.gps)
@@ -857,7 +859,7 @@ class RINEX_NAV_Reader : public RINEX_Reader<> {
857
859
  && (reader.version_type.version >= 302)){
858
860
  reader.extract_iono_utc_v3(*space_nodes.qzss);
859
861
  }
860
- res++;
862
+ int res(0);
861
863
  for(; reader.has_next(); reader.next()){
862
864
  switch(reader.sys_of_msg){
863
865
  case super_t::version_type_t::SYS_GPS:
@@ -1140,6 +1142,9 @@ class RINEX_OBS_Reader : public RINEX_Reader<> {
1140
1142
  RINEX_OBS_Reader(std::istream &in)
1141
1143
  : super_t(in, self_t::modify_header),
1142
1144
  obs_types() {
1145
+ if(super_t::version_type.file_type != version_type_t::FTYPE_OBSERVATION){
1146
+ return;
1147
+ }
1143
1148
  typedef super_t::header_t::const_iterator it_t;
1144
1149
  typedef super_t::header_t::mapped_type::const_iterator it2_t;
1145
1150
  it_t it;
@@ -1860,8 +1865,13 @@ class RINEX_NAV_Writer : public RINEX_Writer<> {
1860
1865
  version, super_t::version_type_t::FTYPE_NAVIGATION, sys));
1861
1866
  }
1862
1867
 
1868
+ struct space_node_list_t {
1869
+ const space_node_t *gps;
1870
+ const SBAS_SpaceNode<FloatT> *sbas;
1871
+ const space_node_t *qzss;
1872
+ };
1863
1873
  int write_all(
1864
- const typename reader_t::space_node_list_t &space_nodes,
1874
+ const space_node_list_t &space_nodes,
1865
1875
  const int &version = 304){
1866
1876
  int res(-1);
1867
1877
  int systems(0);
@@ -1966,12 +1976,12 @@ class RINEX_NAV_Writer : public RINEX_Writer<> {
1966
1976
  }
1967
1977
  static int write_all(
1968
1978
  std::ostream &out,
1969
- const typename reader_t::space_node_list_t &space_nodes,
1979
+ const space_node_list_t &space_nodes,
1970
1980
  const int &version = 304){
1971
1981
  return RINEX_NAV_Writer(out).write_all(space_nodes, version);
1972
1982
  }
1973
1983
  int write_all(const space_node_t &space_node, const int &version = 304){
1974
- const typename reader_t::space_node_list_t list = {&const_cast<space_node_t &>(space_node)};
1984
+ space_node_list_t list = {&space_node};
1975
1985
  return write_all(list, version);
1976
1986
  }
1977
1987
  static int write_all(std::ostream &out, const space_node_t &space_node, const int &version = 304){
@@ -417,11 +417,8 @@ struct GPS_Ephemeris : public GPS_SpaceNode<FloatT>::SatelliteProperties::Epheme
417
417
  %ignore tropo_correction() const;
418
418
  int read(const char *fname) {
419
419
  std::fstream fin(fname, std::ios::in | std::ios::binary);
420
- typename RINEX_NAV_Reader<FloatT>::space_node_list_t space_nodes = {
421
- self, // GPS
422
- NULL, // SBAS
423
- self, // QZSS
424
- };
420
+ typename RINEX_NAV_Reader<FloatT>::space_node_list_t space_nodes = {self};
421
+ space_nodes.qzss = self;
425
422
  return RINEX_NAV_Reader<FloatT>::read_all(fin, space_nodes);
426
423
  }
427
424
  }
@@ -476,7 +473,8 @@ struct SBAS_Ephemeris : public SBAS_SpaceNode<FloatT>::SatelliteProperties::Ephe
476
473
  }
477
474
  int read(const char *fname) {
478
475
  std::fstream fin(fname, std::ios::in | std::ios::binary);
479
- RINEX_NAV_Reader<FloatT>::space_node_list_t space_nodes = {NULL, self};
476
+ RINEX_NAV_Reader<FloatT>::space_node_list_t space_nodes = {NULL};
477
+ space_nodes.sbas = self;
480
478
  return RINEX_NAV_Reader<FloatT>::read_all(fin, space_nodes);
481
479
  }
482
480
  MAKE_ARRAY_INPUT(const unsigned int, buf, SWIG_AsVal(unsigned int));
@@ -662,23 +660,6 @@ struct GPS_User_PVT
662
660
  }
663
661
  }
664
662
  }
665
- #ifdef SWIGRUBY
666
- VALUE to_hash() const {
667
- VALUE res(rb_hash_new());
668
- for(typename GPS_Measurement<FloatT>::items_t::const_iterator
669
- it(self->items.begin()), it_end(self->items.end());
670
- it != it_end; ++it){
671
- VALUE per_sat(rb_hash_new());
672
- rb_hash_aset(res, SWIG_From(int)(it->first), per_sat);
673
- for(typename GPS_Measurement<FloatT>::items_t::mapped_type::const_iterator
674
- it2(it->second.begin()), it2_end(it->second.end());
675
- it2 != it2_end; ++it2){
676
- rb_hash_aset(per_sat, SWIG_From(int)(it2->first), swig::from(it2->second));
677
- }
678
- }
679
- return res;
680
- }
681
- #endif
682
663
  %fragment(SWIG_Traits_frag(GPS_Measurement<FloatT>), "header",
683
664
  fragment=SWIG_Traits_frag(FloatT)){
684
665
  namespace swig {
@@ -762,9 +743,32 @@ struct GPS_User_PVT
762
743
  #endif
763
744
  return SWIG_ERROR;
764
745
  }
746
+ #ifdef SWIGRUBY
747
+ template <>
748
+ VALUE from(const GPS_Measurement<FloatT>::items_t::mapped_type &val) {
749
+ VALUE per_sat(rb_hash_new());
750
+ for(typename GPS_Measurement<FloatT>::items_t::mapped_type::const_iterator
751
+ it(val.begin()), it_end(val.end());
752
+ it != it_end; ++it){
753
+ rb_hash_aset(per_sat, SWIG_From(int)(it->first), swig::from(it->second));
754
+ }
755
+ return per_sat;
756
+ }
757
+ #endif
765
758
  }
766
759
  }
767
760
  %fragment(SWIG_Traits_frag(GPS_Measurement<FloatT>));
761
+ #ifdef SWIGRUBY
762
+ VALUE to_hash() const {
763
+ VALUE res(rb_hash_new());
764
+ for(typename GPS_Measurement<FloatT>::items_t::const_iterator
765
+ it(self->items.begin()), it_end(self->items.end());
766
+ it != it_end; ++it){
767
+ rb_hash_aset(res, SWIG_From(int)(it->first), swig::from(it->second));
768
+ }
769
+ return res;
770
+ }
771
+ #endif
768
772
  %typemap(typecheck,precedence=SWIG_TYPECHECK_POINTER) const GPS_Measurement<FloatT> & {
769
773
  $1 = SWIG_CheckState(SWIG_ConvertPtr($input, (void **)0, $1_descriptor, 0))
770
774
  || swig::check<GPS_Measurement<FloatT> >($input);
@@ -938,18 +942,19 @@ struct SBAS_SolverOptions
938
942
  %ignore mark;
939
943
  %fragment("hook"{GPS_Solver<FloatT>}, "header",
940
944
  fragment=SWIG_From_frag(int),
941
- fragment=SWIG_Traits_frag(FloatT)){
945
+ fragment=SWIG_Traits_frag(FloatT),
946
+ fragment=SWIG_Traits_frag(GPS_Measurement<FloatT>)){
942
947
  template <>
943
- typename GPS_Solver<FloatT>::base_t::relative_property_t
948
+ GPS_Solver<FloatT>::base_t::relative_property_t
944
949
  GPS_Solver<FloatT>::relative_property(
945
- const typename GPS_Solver<FloatT>::base_t::prn_t &prn,
946
- const typename GPS_Solver<FloatT>::base_t::measurement_t::mapped_type &measurement,
947
- const typename GPS_Solver<FloatT>::base_t::float_t &receiver_error,
948
- const typename GPS_Solver<FloatT>::base_t::gps_time_t &time_arrival,
949
- const typename GPS_Solver<FloatT>::base_t::pos_t &usr_pos,
950
- const typename GPS_Solver<FloatT>::base_t::xyz_t &usr_vel) const {
950
+ const GPS_Solver<FloatT>::base_t::prn_t &prn,
951
+ const GPS_Solver<FloatT>::base_t::measurement_t::mapped_type &measurement,
952
+ const GPS_Solver<FloatT>::base_t::float_t &receiver_error,
953
+ const GPS_Solver<FloatT>::base_t::gps_time_t &time_arrival,
954
+ const GPS_Solver<FloatT>::base_t::pos_t &usr_pos,
955
+ const GPS_Solver<FloatT>::base_t::xyz_t &usr_vel) const {
951
956
  union {
952
- typename base_t::relative_property_t prop;
957
+ base_t::relative_property_t prop;
953
958
  FloatT values[7];
954
959
  } res = {
955
960
  select_solver(prn).relative_property(
@@ -971,6 +976,7 @@ struct SBAS_SolverOptions
971
976
  swig::from(res.prop.los_neg[0]),
972
977
  swig::from(res.prop.los_neg[1]),
973
978
  swig::from(res.prop.los_neg[2])),
979
+ swig::from(measurement), // measurement => Hash
974
980
  swig::from(receiver_error), // receiver_error
975
981
  SWIG_NewPointerObj( // time_arrival
976
982
  new base_t::gps_time_t(time_arrival), $descriptor(GPS_Time<FloatT> *), SWIG_POINTER_OWN),
@@ -1001,15 +1007,15 @@ struct SBAS_SolverOptions
1001
1007
  }
1002
1008
  template <>
1003
1009
  bool GPS_Solver<FloatT>::update_position_solution(
1004
- const typename GPS_Solver<FloatT>::base_t::geometric_matrices_t &geomat,
1005
- typename GPS_Solver<FloatT>::base_t::user_pvt_t &res) const {
1010
+ const GPS_Solver<FloatT>::base_t::geometric_matrices_t &geomat,
1011
+ GPS_Solver<FloatT>::base_t::user_pvt_t &res) const {
1006
1012
  #ifdef SWIGRUBY
1007
1013
  do{
1008
1014
  static const VALUE key(ID2SYM(rb_intern("update_position_solution")));
1009
1015
  VALUE hook(rb_hash_lookup(hooks, key));
1010
1016
  if(NIL_P(hook)){break;}
1011
- typename base_t::geometric_matrices_t &geomat_(
1012
- %const_cast(geomat, typename base_t::geometric_matrices_t &));
1017
+ base_t::geometric_matrices_t &geomat_(
1018
+ %const_cast(geomat, base_t::geometric_matrices_t &));
1013
1019
  VALUE values[] = {
1014
1020
  SWIG_NewPointerObj(&geomat_.G,
1015
1021
  $descriptor(Matrix<FloatT, Array2D_Dense<FloatT>, MatrixViewBase<> > *), 0),
@@ -1022,6 +1028,51 @@ struct SBAS_SolverOptions
1022
1028
  #endif
1023
1029
  return super_t::update_position_solution(geomat, res);
1024
1030
  }
1031
+ template <>
1032
+ GPS_Solver<FloatT>::base_t::xyz_t *GPS_Solver<FloatT>::satellite_position(
1033
+ const GPS_Solver<FloatT>::base_t::prn_t &prn,
1034
+ const GPS_Solver<FloatT>::base_t::gps_time_t &time,
1035
+ GPS_Solver<FloatT>::base_t::xyz_t &buf) const {
1036
+ GPS_Solver<FloatT>::base_t::xyz_t *res(
1037
+ select_solver(prn).satellite_position(prn, time, buf));
1038
+ #ifdef SWIGRUBY
1039
+ do{
1040
+ static const VALUE key(ID2SYM(rb_intern("satellite_position")));
1041
+ VALUE hook(rb_hash_lookup(hooks, key));
1042
+ if(NIL_P(hook)){break;}
1043
+ VALUE values[] = {
1044
+ SWIG_From(int)(prn), // prn
1045
+ SWIG_NewPointerObj( // time
1046
+ new base_t::gps_time_t(time), $descriptor(GPS_Time<FloatT> *), SWIG_POINTER_OWN),
1047
+ (res // position (internally calculated)
1048
+ ? SWIG_NewPointerObj(res, $descriptor(System_XYZ<FloatT, WGS84> *), 0)
1049
+ : Qnil)};
1050
+ VALUE res_hook(proc_call_throw_if_error(hook, sizeof(values) / sizeof(values[0]), values));
1051
+ if(NIL_P(res_hook)){ // unknown position
1052
+ res = NULL;
1053
+ break;
1054
+ }else if(RB_TYPE_P(res_hook, T_ARRAY) && (RARRAY_LEN(res_hook) == 3)){
1055
+ int i(0);
1056
+ for(; i < 3; ++i){
1057
+ VALUE v(RARRAY_AREF(res_hook, i));
1058
+ if(!SWIG_IsOK(swig::asval(v, &buf[i]))){break;}
1059
+ }
1060
+ if(i == 3){
1061
+ res = &buf;
1062
+ break;
1063
+ }
1064
+ }else if(SWIG_IsOK(SWIG_ConvertPtr(
1065
+ res_hook, (void **)&res, $descriptor(System_XYZ<FloatT, WGS84> *), 0))){
1066
+ res = &(buf = *res);
1067
+ break;
1068
+ }
1069
+ throw std::runtime_error(
1070
+ std::string("System_XYZ or [d * 3] is expected (d: " %str(FloatT) "), however ")
1071
+ .append(inspect_str(res_hook)));
1072
+ }while(false);
1073
+ #endif
1074
+ return res;
1075
+ }
1025
1076
  }
1026
1077
  %fragment("hook"{GPS_Solver<FloatT>});
1027
1078
  }
@@ -1069,7 +1120,11 @@ struct GPS_Solver
1069
1120
  if(prn > 0 && prn <= 32){return gps.solver;}
1070
1121
  if(prn >= 120 && prn <= 158){return sbas.solver;}
1071
1122
  if(prn > 192 && prn <= 202){return gps.solver;}
1072
- return *this;
1123
+ // call order: base_t::solve => this returned by select()
1124
+ // => relative_property() => select_solver()
1125
+ // For not supported satellite, call loop prevention is required.
1126
+ static const base_t dummy;
1127
+ return dummy;
1073
1128
  }
1074
1129
  virtual typename base_t::relative_property_t relative_property(
1075
1130
  const typename base_t::prn_t &prn,
@@ -1081,9 +1136,7 @@ struct GPS_Solver
1081
1136
  virtual typename base_t::xyz_t *satellite_position(
1082
1137
  const typename base_t::prn_t &prn,
1083
1138
  const typename base_t::gps_time_t &time,
1084
- typename base_t::xyz_t &res) const {
1085
- return select_solver(prn).satellite_position(prn, time, res);
1086
- }
1139
+ typename base_t::xyz_t &res) const;
1087
1140
  virtual bool update_position_solution(
1088
1141
  const typename base_t::geometric_matrices_t &geomat,
1089
1142
  typename base_t::user_pvt_t &res) const;
@@ -339,8 +339,9 @@ __RINEX_OBS_TEXT__
339
339
  sn.read(input[:rinex_nav])
340
340
  t_meas = GPS::Time::new(1849, 172413)
341
341
  sn.update_all_ephemeris(t_meas)
342
- solver.hooks[:relative_property] = proc{|prn, rel_prop, rcv_e, t_arv, usr_pos, usr_vel|
342
+ solver.hooks[:relative_property] = proc{|prn, rel_prop, meas, rcv_e, t_arv, usr_pos, usr_vel|
343
343
  expect(input[:measurement]).to include(prn)
344
+ expect(meas).to be_a_kind_of(Hash)
344
345
  expect(t_arv).to be_a_kind_of(GPS::Time)
345
346
  expect(usr_pos).to be_a_kind_of(Coordinate::XYZ)
346
347
  expect(usr_vel).to be_a_kind_of(Coordinate::XYZ)
@@ -354,6 +355,22 @@ __RINEX_OBS_TEXT__
354
355
  }
355
356
  mat_G, mat_W, mat_delta_r = mats
356
357
  }
358
+ solver.hooks[:satellite_position] = proc{
359
+ i = 0
360
+ proc{|prn, time, pos|
361
+ expect(input[:measurement]).to include(prn)
362
+ expect(pos).to be_a_kind_of(Coordinate::XYZ).or eq(nil)
363
+ # System_XYZ or [x,y,z] or nil(= unknown position) are acceptable
364
+ case (i += 1) % 5
365
+ when 0
366
+ nil
367
+ when 1
368
+ pos.to_a
369
+ else
370
+ pos
371
+ end
372
+ }
373
+ }.call
357
374
  pvt = solver.solve(
358
375
  input[:measurement].collect{|prn, items|
359
376
  items.collect{|k, v| [prn, k, v]}
@@ -130,7 +130,7 @@ class Receiver
130
130
 
131
131
  def initialize(options = {})
132
132
  @solver = GPS::Solver::new
133
- @solver.hooks[:relative_property] = proc{|prn, rel_prop, rcv_e, t_arv, usr_pos, usr_vel|
133
+ @solver.hooks[:relative_property] = proc{|prn, rel_prop, meas, rcv_e, t_arv, usr_pos, usr_vel|
134
134
  rel_prop[0] = 1 if rel_prop[0] > 0 # weight = 1
135
135
  rel_prop
136
136
  }
@@ -148,7 +148,7 @@ class Receiver
148
148
  when :weight
149
149
  case v.to_sym
150
150
  when :elevation # (same as underneath C++ library)
151
- @solver.hooks[:relative_property] = proc{|prn, rel_prop, rcv_e, t_arv, usr_pos, usr_vel|
151
+ @solver.hooks[:relative_property] = proc{|prn, rel_prop, meas, rcv_e, t_arv, usr_pos, usr_vel|
152
152
  if rel_prop[0] > 0 then
153
153
  elv = Coordinate::ENU::relative_rel(
154
154
  Coordinate::XYZ::new(*rel_prop[4..6]), usr_pos).elevation
@@ -477,8 +477,15 @@ class Receiver
477
477
  end
478
478
 
479
479
  def parse_rinex_nav(fname)
480
- $stderr.puts "Read RINEX NAV file (%s): %d items."%[
481
- fname, @solver.gps_space_node.read(fname)]
480
+ items = [
481
+ @solver.gps_space_node,
482
+ @solver.sbas_space_node,
483
+ ].inject(0){|res, sn|
484
+ loaded_items = sn.send(:read, fname)
485
+ raise "Format error! (Not RINEX) #{fname}" if loaded_items < 0
486
+ res + loaded_items
487
+ }
488
+ $stderr.puts "Read RINEX NAV file (%s): %d items."%[fname, items]
482
489
  end
483
490
 
484
491
  def parse_rinex_obs(fname, &b)
@@ -515,7 +522,8 @@ class Receiver
515
522
  when 'J'; prn += 192
516
523
  else; next
517
524
  end
518
- (types[sys] || []).each{|i, type_|
525
+ types[sys] = (types[' '] || []) unless types[sys]
526
+ types[sys].each{|i, type_|
519
527
  meas.add(prn, type_, v[i][0]) if v[i]
520
528
  }
521
529
  }
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module GPS_PVT
4
- VERSION = "0.2.0"
4
+ VERSION = "0.2.1"
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gps_pvt
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - fenrir(M.Naruoka)
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-01-26 00:00:00.000000000 Z
11
+ date: 2022-01-31 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake