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 +4 -4
- data/README.md +13 -2
- data/exe/gps_pvt +28 -19
- data/ext/gps_pvt/GPS/GPS_wrap.cxx +81 -29
- data/ext/ninja-scan-light/tool/navigation/GPS_Solver_Base.h +27 -20
- data/ext/ninja-scan-light/tool/navigation/RINEX.h +15 -5
- data/ext/ninja-scan-light/tool/swig/GPS.i +93 -40
- data/ext/ninja-scan-light/tool/swig/spec/GPS_spec.rb +18 -1
- data/lib/gps_pvt/receiver.rb +13 -5
- data/lib/gps_pvt/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: cd084c2ca722a761b9dbae3ea2fde546531f403ebff8e87b5d7b9632986c3aa8
|
4
|
+
data.tar.gz: 92943ca82b4ab13794dc39c51e71a23d178baf483fd1dd782a7305fc7a121de5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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.
|
18
|
-
next
|
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
|
-
|
21
|
-
}
|
22
|
-
|
23
|
-
# Check file existence
|
24
|
-
|
25
|
-
raise "File not found: #{
|
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
|
-
|
34
|
-
|
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
|
-
|
40
|
-
case
|
41
|
-
when
|
42
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
3656
|
+
GPS_Solver<double>::base_t::relative_property_t
|
3652
3657
|
GPS_Solver<double>::relative_property(
|
3653
|
-
const
|
3654
|
-
const
|
3655
|
-
const
|
3656
|
-
const
|
3657
|
-
const
|
3658
|
-
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
|
-
|
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
|
3713
|
-
|
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
|
-
|
3720
|
-
const_cast<
|
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
|
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
|
-
|
399
|
-
res
|
400
|
-
|
401
|
-
|
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
|
-
|
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,
|
432
|
-
rotation_matrix * C.partial(3,
|
433
|
-
res.partial(
|
434
|
-
C.partial(
|
435
|
-
res(3,
|
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
|
-
|
474
|
-
res
|
475
|
-
|
476
|
-
|
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,
|
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,
|
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
|
-
|
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(
|
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
|
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
|
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
|
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
|
-
|
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
|
-
|
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
|
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
|
-
|
948
|
+
GPS_Solver<FloatT>::base_t::relative_property_t
|
944
949
|
GPS_Solver<FloatT>::relative_property(
|
945
|
-
const
|
946
|
-
const
|
947
|
-
const
|
948
|
-
const
|
949
|
-
const
|
950
|
-
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
|
-
|
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
|
1005
|
-
|
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
|
-
|
1012
|
-
%const_cast(geomat,
|
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
|
-
|
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]}
|
data/lib/gps_pvt/receiver.rb
CHANGED
@@ -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
|
-
|
481
|
-
|
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
|
-
|
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
|
}
|
data/lib/gps_pvt/version.rb
CHANGED
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.
|
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-
|
11
|
+
date: 2022-01-31 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|