gps_pvt 0.2.3 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +20 -4
- data/Rakefile +0 -0
- data/exe/gps_pvt +0 -0
- data/ext/gps_pvt/GPS/GPS_wrap.cxx +85 -8
- data/ext/gps_pvt/SylphideMath/SylphideMath_wrap.cxx +0 -0
- data/ext/ninja-scan-light/tool/navigation/GPS.h +0 -0
- data/ext/ninja-scan-light/tool/navigation/GPS_Solver.h +0 -0
- data/ext/ninja-scan-light/tool/navigation/GPS_Solver_Base.h +2 -2
- data/ext/ninja-scan-light/tool/navigation/SBAS.h +0 -0
- data/ext/ninja-scan-light/tool/navigation/SBAS_Solver.h +0 -0
- data/ext/ninja-scan-light/tool/param/bit_array.h +0 -0
- data/ext/ninja-scan-light/tool/swig/GPS.i +88 -8
- data/ext/ninja-scan-light/tool/swig/SylphideMath.i +0 -0
- data/ext/ninja-scan-light/tool/swig/spec/GPS_spec.rb +6 -1
- data/ext/ninja-scan-light/tool/swig/spec/SylphideMath_spec.rb +0 -0
- data/gps_pvt.gemspec +0 -0
- data/lib/gps_pvt/receiver.rb +36 -11
- data/lib/gps_pvt/version.rb +1 -1
- metadata +6 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3ceeb392e9d4a3df9a3b6af1ed6b19a92fec4fae110c9c89118602f3213d6905
|
4
|
+
data.tar.gz: c91c94043d2e39dde8ea0909dbd862f0194b15a4f2baa3030b48d760f933a147
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bcf702f83fd0df488470b385df370c3639e953b064a6acd9cdc4418a98b03ffab9c15dc9af0ad79185177bc3feb03e74b0ee0c9dba667bf73af1e1afabdca7be
|
7
|
+
data.tar.gz: eac046233bfd52db17a3fb94d2c74fcf01c8cd3200d0d5dce2546a669bb9313cccda4bdb74e2b991f1397d27325ec87d79d8c0e87be36b05fa6856daf0342ad0
|
data/README.md
CHANGED
@@ -41,7 +41,7 @@ From version 0.2.0, SBAS and QZSS are supported in addition to GPS. QZSS ranging
|
|
41
41
|
|
42
42
|
$ gps_pvt --with=137 RINEX_or_UBX_file(s)
|
43
43
|
|
44
|
-
For developer, this library will be used
|
44
|
+
For developer, this library will be used like:
|
45
45
|
|
46
46
|
```ruby
|
47
47
|
require 'gps_pvt'
|
@@ -81,25 +81,41 @@ receiver.parse_rinex_obs(rinex_obs_file){|pvt, meas| # per epoch
|
|
81
81
|
}
|
82
82
|
}
|
83
83
|
|
84
|
-
|
84
|
+
## Further customization
|
85
|
+
# General options
|
85
86
|
receiver.solver.gps_options.exclude(prn) # Exclude satellite; the default is to use every satellite if visible
|
86
87
|
receiver.solver.gps_options.include(prn) # Discard previous setting of exclusion
|
87
88
|
receiver.solver.gps_options.elevation_mask = Math::PI / 180 * 10 # example 10 [deg] elevation mask
|
89
|
+
# receiver.solver.sbas_options is for SBAS.
|
90
|
+
|
91
|
+
# Precise control of properties for each satellite and for each iteration
|
88
92
|
receiver.solver.hooks[:relative_property] = proc{|prn, rel_prop, meas, rcv_e, t_arv, usr_pos, usr_vel|
|
89
|
-
# control weight per satellite per iteration
|
90
93
|
weight, range_c, range_r, rate_rel_neg, *los_neg = rel_prop # relative property
|
91
94
|
# meas is measurement represented by pseudo range of the selected satellite.
|
92
95
|
# rcv_e, t_arv, usr_pos, usr_vel are temporary solution of
|
93
96
|
# receiver clock error [m], time of arrival [s], user position and velocity in ECEF, respectively.
|
94
97
|
|
95
98
|
weight = 1 # same as default; identical weight for each visible satellite
|
96
|
-
# or weight based on elevation
|
99
|
+
# or weight based on elevation, for example:
|
97
100
|
# elv = GPS_PVT::Coordinate::ENU::relative_rel(GPS_PVT::Coordinate::XYZ::new(*los_neg), usr_pos).elevation
|
98
101
|
# weight = (Math::sin(elv)/0.8)**2
|
99
102
|
|
100
103
|
[weight, range_c, range_r, rate_rel_neg] + los_neg # must return relative property
|
101
104
|
}
|
102
105
|
|
106
|
+
# Range correction (since v0.3.0)
|
107
|
+
receiver.solver.correction = { # provide by using a Hash
|
108
|
+
# ionospheric and transpheric models are changeable, and current configuration
|
109
|
+
# can be obtained by receiver.solver.correction without assigner.
|
110
|
+
:gps_ionospheric => proc{|t, usr_pos_xyz, sat_pos_enu|
|
111
|
+
# t, usr_pos_xyz, sat_pos_enu are temporary solution of
|
112
|
+
# time of arrival [s], user position in ECEF,
|
113
|
+
# and satellite position in ENU respectively.
|
114
|
+
0 # must return correction value, delaying is negative.
|
115
|
+
},
|
116
|
+
# combination of (gps or sbas) and (ionospheric or tropospheric) are available
|
117
|
+
}
|
118
|
+
|
103
119
|
# Dynamic customization of weight for each epoch
|
104
120
|
(class << receiver; self; end).instance_eval{ # do before parse_XXX
|
105
121
|
alias_method(:run_orig, :run)
|
data/Rakefile
CHANGED
File without changes
|
data/exe/gps_pvt
CHANGED
File without changes
|
@@ -2507,6 +2507,26 @@ struct SBAS_SolverOptions
|
|
2507
2507
|
};
|
2508
2508
|
|
2509
2509
|
|
2510
|
+
template <class FloatT>
|
2511
|
+
struct GPS_RangeCorrector
|
2512
|
+
: public GPS_Solver_Base<FloatT>::range_corrector_t {
|
2513
|
+
VALUE callback;
|
2514
|
+
GPS_RangeCorrector(const VALUE &callback_)
|
2515
|
+
: GPS_Solver_Base<FloatT>::range_corrector_t(),
|
2516
|
+
callback(callback_) {}
|
2517
|
+
bool is_available(const typename GPS_Solver_Base<FloatT>::gps_time_t &t) const {
|
2518
|
+
return false;
|
2519
|
+
}
|
2520
|
+
FloatT *calculate(
|
2521
|
+
const typename GPS_Solver_Base<FloatT>::gps_time_t &t,
|
2522
|
+
const typename GPS_Solver_Base<FloatT>::pos_t &usr_pos,
|
2523
|
+
const typename GPS_Solver_Base<FloatT>::enu_t &sat_rel_pos,
|
2524
|
+
FloatT &buf) const {
|
2525
|
+
return NULL;
|
2526
|
+
}
|
2527
|
+
};
|
2528
|
+
|
2529
|
+
|
2510
2530
|
template <class FloatT>
|
2511
2531
|
struct GPS_Solver
|
2512
2532
|
: public GPS_Solver_RAIM_LSR<FloatT,
|
@@ -2527,14 +2547,22 @@ struct GPS_Solver
|
|
2527
2547
|
sbas_t() : space_node(), options(), solver(space_node) {}
|
2528
2548
|
} sbas;
|
2529
2549
|
VALUE hooks;
|
2550
|
+
typedef std::vector<GPS_RangeCorrector<FloatT> > user_correctors_t;
|
2551
|
+
user_correctors_t user_correctors;
|
2530
2552
|
|
2531
2553
|
static void mark(void *ptr){
|
2532
2554
|
GPS_Solver<FloatT> *solver = (GPS_Solver<FloatT> *)ptr;
|
2533
|
-
if(solver->hooks == Qnil){return;}
|
2534
2555
|
rb_gc_mark(solver->hooks);
|
2556
|
+
for(typename user_correctors_t::const_iterator
|
2557
|
+
it(solver->user_correctors.begin()), it_end(solver->user_correctors.end());
|
2558
|
+
it != it_end; ++it){
|
2559
|
+
rb_gc_mark(it->callback);
|
2560
|
+
}
|
2535
2561
|
}
|
2536
2562
|
|
2537
|
-
GPS_Solver() : super_t(),
|
2563
|
+
GPS_Solver() : super_t(),
|
2564
|
+
gps(), sbas(),
|
2565
|
+
hooks(), user_correctors() {
|
2538
2566
|
|
2539
2567
|
hooks = rb_hash_new();
|
2540
2568
|
|
@@ -2606,6 +2634,19 @@ struct GPS_Solver
|
|
2606
2634
|
if(!update){break;}
|
2607
2635
|
typename range_correction_list_t::const_iterator it(list.find(i));
|
2608
2636
|
if(it == list.end()){break;}
|
2637
|
+
|
2638
|
+
// Remove user defined unused correctors
|
2639
|
+
for(typename base_t::range_correction_t::const_iterator
|
2640
|
+
it2(root[i]->begin()), it2_end(root[i]->end());
|
2641
|
+
it2 != it2_end; ++it2){
|
2642
|
+
for(typename user_correctors_t::const_iterator
|
2643
|
+
it3(user_correctors.begin()), it3_end(user_correctors.end());
|
2644
|
+
it3 != it3_end; ++it3){
|
2645
|
+
if(*it2 != &(*it3)){continue;}
|
2646
|
+
user_correctors.erase(it3);
|
2647
|
+
}
|
2648
|
+
}
|
2649
|
+
|
2609
2650
|
root[i]->clear();
|
2610
2651
|
for(typename range_correction_list_t::mapped_type::const_iterator
|
2611
2652
|
it2(it->second.begin()), it2_end(it->second.end());
|
@@ -3794,6 +3835,38 @@ SWIGINTERN double const &GPS_SolverOptions_Common_Sl_double_Sg__get_residual_mas
|
|
3794
3835
|
}
|
3795
3836
|
|
3796
3837
|
|
3838
|
+
template <>
|
3839
|
+
bool GPS_RangeCorrector<double>::is_available(
|
3840
|
+
const typename GPS_Solver_Base<double>::gps_time_t &t) const {
|
3841
|
+
VALUE values[] = {
|
3842
|
+
SWIG_NewPointerObj(
|
3843
|
+
const_cast< GPS_Time<double> * >(&t), SWIGTYPE_p_GPS_TimeT_double_t, 0),
|
3844
|
+
};
|
3845
|
+
VALUE res(proc_call_throw_if_error(
|
3846
|
+
callback, sizeof(values) / sizeof(values[0]), values));
|
3847
|
+
return RTEST(res) ? true : false;
|
3848
|
+
}
|
3849
|
+
template <>
|
3850
|
+
double *GPS_RangeCorrector<double>::calculate(
|
3851
|
+
const typename GPS_Solver_Base<double>::gps_time_t &t,
|
3852
|
+
const typename GPS_Solver_Base<double>::pos_t &usr_pos,
|
3853
|
+
const typename GPS_Solver_Base<double>::enu_t &sat_rel_pos,
|
3854
|
+
double &buf) const {
|
3855
|
+
VALUE values[] = {
|
3856
|
+
SWIG_NewPointerObj(
|
3857
|
+
const_cast< GPS_Time<double> * >(&t),
|
3858
|
+
SWIGTYPE_p_GPS_TimeT_double_t, 0),
|
3859
|
+
SWIG_NewPointerObj(
|
3860
|
+
(const_cast< System_XYZ<double,WGS84> * >(&usr_pos.xyz)),
|
3861
|
+
SWIGTYPE_p_System_XYZT_double_WGS84_t, 0),
|
3862
|
+
SWIG_NewPointerObj(
|
3863
|
+
(const_cast< System_ENU<double,WGS84> * >(&sat_rel_pos)),
|
3864
|
+
SWIGTYPE_p_System_ENUT_double_WGS84_t, 0),
|
3865
|
+
};
|
3866
|
+
VALUE res(proc_call_throw_if_error(
|
3867
|
+
callback, sizeof(values) / sizeof(values[0]), values));
|
3868
|
+
return SWIG_IsOK(swig::asval(res, &buf)) ? &buf : NULL;
|
3869
|
+
}
|
3797
3870
|
template<>
|
3798
3871
|
VALUE GPS_Solver<double>::update_correction(
|
3799
3872
|
const bool &update, const VALUE &hash){
|
@@ -3836,10 +3909,12 @@ SWIGINTERN double const &GPS_SolverOptions_Common_Sl_double_Sg__get_residual_mas
|
|
3836
3909
|
for(; k < sizeof(item) / sizeof(item[0]); ++k){
|
3837
3910
|
if(v == item[k].sym){break;}
|
3838
3911
|
}
|
3839
|
-
if(k >= sizeof(item) / sizeof(item[0])){
|
3840
|
-
|
3912
|
+
if(k >= sizeof(item) / sizeof(item[0])){ // other than symbol
|
3913
|
+
user_correctors.push_back(GPS_RangeCorrector<double>(v));
|
3914
|
+
input[i].push_back(&user_correctors.back());
|
3915
|
+
}else{
|
3916
|
+
input[i].push_back(item[k].obj);
|
3841
3917
|
}
|
3842
|
-
input[i].push_back(item[k].obj);
|
3843
3918
|
}
|
3844
3919
|
}
|
3845
3920
|
VALUE opt(rb_hash_lookup(hash, k_opt));
|
@@ -3866,10 +3941,12 @@ SWIGINTERN double const &GPS_SolverOptions_Common_Sl_double_Sg__get_residual_mas
|
|
3866
3941
|
for(; i < sizeof(item) / sizeof(item[0]); ++i){
|
3867
3942
|
if(*it2 == item[i].obj){break;}
|
3868
3943
|
}
|
3869
|
-
if(i >= sizeof(item) / sizeof(item[0])){
|
3870
|
-
|
3944
|
+
if(i >= sizeof(item) / sizeof(item[0])){ // other than built-in corrector
|
3945
|
+
rb_ary_push(v,
|
3946
|
+
reinterpret_cast<const GPS_RangeCorrector<double> *>(*it2)->callback);
|
3947
|
+
}else{
|
3948
|
+
rb_ary_push(v, item[i].sym);
|
3871
3949
|
}
|
3872
|
-
rb_ary_push(v, item[i].sym);
|
3873
3950
|
}
|
3874
3951
|
rb_hash_aset(res, k, v);
|
3875
3952
|
}
|
File without changes
|
File without changes
|
File without changes
|
@@ -652,14 +652,14 @@ protected:
|
|
652
652
|
// Least square
|
653
653
|
matrix_t delta_x(geomat.partial(res.used_satellites).least_square());
|
654
654
|
|
655
|
-
xyz_t delta_user_position(delta_x.partial(3, 1
|
655
|
+
xyz_t delta_user_position(delta_x.partial(3, 1));
|
656
656
|
res.user_position.xyz += delta_user_position;
|
657
657
|
res.user_position.llh = res.user_position.xyz.llh();
|
658
658
|
|
659
659
|
const float_t &delta_receiver_error(delta_x(3, 0));
|
660
660
|
res.receiver_error += delta_receiver_error;
|
661
661
|
|
662
|
-
return (
|
662
|
+
return (delta_x.partial(4, 1).norm2F() <= 1E-6); // equivalent to abs(x) <= 1E-3 [m]
|
663
663
|
}
|
664
664
|
|
665
665
|
struct user_pvt_opt_t {
|
File without changes
|
File without changes
|
File without changes
|
@@ -878,6 +878,27 @@ struct SBAS_SolverOptions
|
|
878
878
|
};
|
879
879
|
%}
|
880
880
|
|
881
|
+
%header {
|
882
|
+
template <class FloatT>
|
883
|
+
struct GPS_RangeCorrector
|
884
|
+
: public GPS_Solver_Base<FloatT>::range_corrector_t {
|
885
|
+
SWIG_Object callback;
|
886
|
+
GPS_RangeCorrector(const SWIG_Object &callback_)
|
887
|
+
: GPS_Solver_Base<FloatT>::range_corrector_t(),
|
888
|
+
callback(callback_) {}
|
889
|
+
bool is_available(const typename GPS_Solver_Base<FloatT>::gps_time_t &t) const {
|
890
|
+
return false;
|
891
|
+
}
|
892
|
+
FloatT *calculate(
|
893
|
+
const typename GPS_Solver_Base<FloatT>::gps_time_t &t,
|
894
|
+
const typename GPS_Solver_Base<FloatT>::pos_t &usr_pos,
|
895
|
+
const typename GPS_Solver_Base<FloatT>::enu_t &sat_rel_pos,
|
896
|
+
FloatT &buf) const {
|
897
|
+
return NULL;
|
898
|
+
}
|
899
|
+
};
|
900
|
+
}
|
901
|
+
|
881
902
|
%extend GPS_Solver {
|
882
903
|
%ignore super_t;
|
883
904
|
%ignore base_t;
|
@@ -889,6 +910,8 @@ struct SBAS_SolverOptions
|
|
889
910
|
%ignore relative_property;
|
890
911
|
%ignore satellite_position;
|
891
912
|
%ignore update_position_solution;
|
913
|
+
%ignore user_correctors_t;
|
914
|
+
%ignore user_correctors;
|
892
915
|
%immutable hooks;
|
893
916
|
%ignore mark;
|
894
917
|
%fragment("hook"{GPS_Solver<FloatT>}, "header",
|
@@ -1033,6 +1056,38 @@ struct SBAS_SolverOptions
|
|
1033
1056
|
%fragment("correction"{GPS_Solver<FloatT>}, "header",
|
1034
1057
|
fragment=SWIG_From_frag(int),
|
1035
1058
|
fragment=SWIG_Traits_frag(FloatT)){
|
1059
|
+
template <>
|
1060
|
+
bool GPS_RangeCorrector<FloatT>::is_available(
|
1061
|
+
const typename GPS_Solver_Base<FloatT>::gps_time_t &t) const {
|
1062
|
+
VALUE values[] = {
|
1063
|
+
SWIG_NewPointerObj(
|
1064
|
+
%const_cast(&t, GPS_Time<FloatT> *), $descriptor(GPS_Time<FloatT> *), 0),
|
1065
|
+
};
|
1066
|
+
VALUE res(proc_call_throw_if_error(
|
1067
|
+
callback, sizeof(values) / sizeof(values[0]), values));
|
1068
|
+
return RTEST(res) ? true : false;
|
1069
|
+
}
|
1070
|
+
template <>
|
1071
|
+
FloatT *GPS_RangeCorrector<FloatT>::calculate(
|
1072
|
+
const typename GPS_Solver_Base<FloatT>::gps_time_t &t,
|
1073
|
+
const typename GPS_Solver_Base<FloatT>::pos_t &usr_pos,
|
1074
|
+
const typename GPS_Solver_Base<FloatT>::enu_t &sat_rel_pos,
|
1075
|
+
FloatT &buf) const {
|
1076
|
+
VALUE values[] = {
|
1077
|
+
SWIG_NewPointerObj(
|
1078
|
+
%const_cast(&t, GPS_Time<FloatT> *),
|
1079
|
+
$descriptor(GPS_Time<FloatT> *), 0),
|
1080
|
+
SWIG_NewPointerObj(
|
1081
|
+
(%const_cast(&usr_pos.xyz, System_XYZ<FloatT, WGS84> *)),
|
1082
|
+
$descriptor(System_XYZ<FloatT, WGS84> *), 0),
|
1083
|
+
SWIG_NewPointerObj(
|
1084
|
+
(%const_cast(&sat_rel_pos, System_ENU<FloatT, WGS84> *)),
|
1085
|
+
$descriptor(System_ENU<FloatT, WGS84> *), 0),
|
1086
|
+
};
|
1087
|
+
VALUE res(proc_call_throw_if_error(
|
1088
|
+
callback, sizeof(values) / sizeof(values[0]), values));
|
1089
|
+
return SWIG_IsOK(swig::asval(res, &buf)) ? &buf : NULL;
|
1090
|
+
}
|
1036
1091
|
template<>
|
1037
1092
|
VALUE GPS_Solver<FloatT>::update_correction(
|
1038
1093
|
const bool &update, const VALUE &hash){
|
@@ -1075,10 +1130,12 @@ struct SBAS_SolverOptions
|
|
1075
1130
|
for(; k < sizeof(item) / sizeof(item[0]); ++k){
|
1076
1131
|
if(v == item[k].sym){break;}
|
1077
1132
|
}
|
1078
|
-
if(k >= sizeof(item) / sizeof(item[0])){
|
1079
|
-
|
1133
|
+
if(k >= sizeof(item) / sizeof(item[0])){ // other than symbol
|
1134
|
+
user_correctors.push_back(GPS_RangeCorrector<FloatT>(v));
|
1135
|
+
input[i].push_back(&user_correctors.back());
|
1136
|
+
}else{
|
1137
|
+
input[i].push_back(item[k].obj);
|
1080
1138
|
}
|
1081
|
-
input[i].push_back(item[k].obj);
|
1082
1139
|
}
|
1083
1140
|
}
|
1084
1141
|
VALUE opt(rb_hash_lookup(hash, k_opt));
|
@@ -1105,10 +1162,12 @@ struct SBAS_SolverOptions
|
|
1105
1162
|
for(; i < sizeof(item) / sizeof(item[0]); ++i){
|
1106
1163
|
if(*it2 == item[i].obj){break;}
|
1107
1164
|
}
|
1108
|
-
if(i >= sizeof(item) / sizeof(item[0])){
|
1109
|
-
|
1165
|
+
if(i >= sizeof(item) / sizeof(item[0])){ // other than built-in corrector
|
1166
|
+
rb_ary_push(v,
|
1167
|
+
reinterpret_cast<const GPS_RangeCorrector<FloatT> *>(*it2)->callback);
|
1168
|
+
}else{
|
1169
|
+
rb_ary_push(v, item[i].sym);
|
1110
1170
|
}
|
1111
|
-
rb_ary_push(v, item[i].sym);
|
1112
1171
|
}
|
1113
1172
|
rb_hash_aset(res, k, v);
|
1114
1173
|
}
|
@@ -1160,14 +1219,22 @@ struct GPS_Solver
|
|
1160
1219
|
sbas_t() : space_node(), options(), solver(space_node) {}
|
1161
1220
|
} sbas;
|
1162
1221
|
SWIG_Object hooks;
|
1222
|
+
typedef std::vector<GPS_RangeCorrector<FloatT> > user_correctors_t;
|
1223
|
+
user_correctors_t user_correctors;
|
1163
1224
|
#ifdef SWIGRUBY
|
1164
1225
|
static void mark(void *ptr){
|
1165
1226
|
GPS_Solver<FloatT> *solver = (GPS_Solver<FloatT> *)ptr;
|
1166
|
-
if(solver->hooks == Qnil){return;}
|
1167
1227
|
rb_gc_mark(solver->hooks);
|
1228
|
+
for(typename user_correctors_t::const_iterator
|
1229
|
+
it(solver->user_correctors.begin()), it_end(solver->user_correctors.end());
|
1230
|
+
it != it_end; ++it){
|
1231
|
+
rb_gc_mark(it->callback);
|
1232
|
+
}
|
1168
1233
|
}
|
1169
1234
|
#endif
|
1170
|
-
GPS_Solver() : super_t(),
|
1235
|
+
GPS_Solver() : super_t(),
|
1236
|
+
gps(), sbas(),
|
1237
|
+
hooks(), user_correctors() {
|
1171
1238
|
#ifdef SWIGRUBY
|
1172
1239
|
hooks = rb_hash_new();
|
1173
1240
|
#endif
|
@@ -1239,6 +1306,19 @@ struct GPS_Solver
|
|
1239
1306
|
if(!update){break;}
|
1240
1307
|
typename range_correction_list_t::const_iterator it(list.find(i));
|
1241
1308
|
if(it == list.end()){break;}
|
1309
|
+
|
1310
|
+
// Remove user defined unused correctors
|
1311
|
+
for(typename base_t::range_correction_t::const_iterator
|
1312
|
+
it2(root[i]->begin()), it2_end(root[i]->end());
|
1313
|
+
it2 != it2_end; ++it2){
|
1314
|
+
for(typename user_correctors_t::const_iterator
|
1315
|
+
it3(user_correctors.begin()), it3_end(user_correctors.end());
|
1316
|
+
it3 != it3_end; ++it3){
|
1317
|
+
if(*it2 != &(*it3)){continue;}
|
1318
|
+
user_correctors.erase(it3);
|
1319
|
+
}
|
1320
|
+
}
|
1321
|
+
|
1242
1322
|
root[i]->clear();
|
1243
1323
|
for(typename range_correction_list_t::mapped_type::const_iterator
|
1244
1324
|
it2(it->second.begin()), it2_end(it->second.end());
|
File without changes
|
@@ -343,7 +343,12 @@ __RINEX_OBS_TEXT__
|
|
343
343
|
expect(solver.correction[:gps_tropospheric]).to include(:hopfield)
|
344
344
|
expect{solver.correction = nil}.to raise_error(RuntimeError)
|
345
345
|
expect{solver.correction = {
|
346
|
-
:gps_ionospheric => [
|
346
|
+
:gps_ionospheric => [proc{|t, usr_pos, sat_pos|
|
347
|
+
expect(t).to be_a_kind_of(GPS::Time)
|
348
|
+
expect(usr_pos).to be_a_kind_of(Coordinate::XYZ) unless usr_pos
|
349
|
+
expect(sat_pos).to be_a_kind_of(Coordinate::ENU) unless sat_pos
|
350
|
+
false
|
351
|
+
}, :klobuchar, :no_correction],
|
347
352
|
:options => {:f_10_7 => 10},
|
348
353
|
}}.not_to raise_error
|
349
354
|
expect(solver.correction[:gps_ionospheric]).to include(:no_correction)
|
File without changes
|
data/gps_pvt.gemspec
CHANGED
File without changes
|
data/lib/gps_pvt/receiver.rb
CHANGED
@@ -47,23 +47,31 @@ class Receiver
|
|
47
47
|
]] + [
|
48
48
|
[:used_satellites, proc{|pvt| pvt.used_satellites}],
|
49
49
|
] + opt[:system].collect{|sys, range|
|
50
|
-
|
51
|
-
|
50
|
+
range = range.kind_of?(Array) ? proc{
|
51
|
+
# check whether inputs can be converted to Range
|
52
|
+
next nil if range.empty?
|
53
|
+
a, b = range.minmax
|
54
|
+
((b - a) == (range.length - 1)) ? (a..b) : range
|
55
|
+
}.call : range
|
56
|
+
next nil unless range
|
57
|
+
bit_flip, label = case range
|
58
|
+
when Array
|
59
|
+
[proc{|res, i|
|
52
60
|
res[i] = "1" if i = range.index(i)
|
53
61
|
res
|
54
|
-
}
|
55
|
-
|
62
|
+
}, range.collect{|pen| pen & 0xFF}.reverse.join('+')]
|
63
|
+
when Range
|
56
64
|
base_prn = range.min
|
57
|
-
proc{|res, i|
|
65
|
+
[proc{|res, i|
|
58
66
|
res[i - base_prn] = "1" if range.include?(i)
|
59
67
|
res
|
60
|
-
}
|
68
|
+
}, [:max, :min].collect{|f| range.send(f) & 0xFF}.join('..')]
|
61
69
|
end
|
62
|
-
["#{sys}_PRN", proc{|pvt|
|
70
|
+
["#{sys}_PRN(#{label})", proc{|pvt|
|
63
71
|
pvt.used_satellite_list.inject("0" * range.size, &bit_flip) \
|
64
72
|
.scan(/.{1,8}/).join('_').reverse
|
65
73
|
}]
|
66
|
-
} + [[
|
74
|
+
}.compact + [[
|
67
75
|
opt[:satellites].collect{|prn, label|
|
68
76
|
[:range_residual, :weight, :azimuth, :elevation, :slopeH, :slopeV].collect{|str|
|
69
77
|
"#{str}(#{label || prn})"
|
@@ -138,8 +146,11 @@ class Receiver
|
|
138
146
|
rel_prop
|
139
147
|
}
|
140
148
|
@debug = {}
|
141
|
-
[:gps_options, :sbas_options].
|
142
|
-
|
149
|
+
solver_opts = [:gps_options, :sbas_options].collect{|target|
|
150
|
+
@solver.send(target)
|
151
|
+
}
|
152
|
+
solver_opts.each{|opt|
|
153
|
+
# default solver options
|
143
154
|
opt.elevation_mask = 0.0 / 180 * Math::PI # 0 deg (use satellite over horizon)
|
144
155
|
opt.residual_mask = 1E4 # 10 km (without residual filter, practically)
|
145
156
|
}
|
@@ -168,6 +179,13 @@ class Receiver
|
|
168
179
|
when :identical # same as default
|
169
180
|
next true
|
170
181
|
end
|
182
|
+
when :elevation_mask_deg
|
183
|
+
raise "Unknown elevation mask angle: #{v}" unless elv_deg = (Float(v) rescue nil)
|
184
|
+
$stderr.puts "Elevation mask: #{elv_deg} deg"
|
185
|
+
solver_opts.each{|opt|
|
186
|
+
opt.elevation_mask = elv_deg / 180 * Math::PI # 0 deg (use satellite over horizon)
|
187
|
+
}
|
188
|
+
next true
|
171
189
|
when :base_station
|
172
190
|
crd, sys = v.split(/ *, */).collect.with_index{|item, i|
|
173
191
|
case item
|
@@ -219,12 +237,14 @@ class Receiver
|
|
219
237
|
i = -1
|
220
238
|
output_options[:system] << [sys_target, []]
|
221
239
|
else
|
222
|
-
output_options[:system][i].reject!{|prn| prns.include?(prn)}
|
240
|
+
output_options[:system][i][1].reject!{|prn| prns.include?(prn)}
|
223
241
|
end
|
224
242
|
output_options[:satellites].reject!{|prn, label| prns.include?(prn)}
|
225
243
|
if mode == :include then
|
226
244
|
output_options[:system][i][1] += prns
|
245
|
+
output_options[:system][i][1].sort!
|
227
246
|
output_options[:satellites] += (labels ? prns.zip(labels) : prns)
|
247
|
+
output_options[:satellites].sort!{|a, b| [a].flatten[0] <=> [b].flatten[0]}
|
228
248
|
end
|
229
249
|
}
|
230
250
|
check_sys_svid = proc{|sys_target, range_in_sys, offset|
|
@@ -328,6 +348,11 @@ class Receiver
|
|
328
348
|
[:azimuth, :elevation, :slopeH, :slopeV].each{|k|
|
329
349
|
eval("define_method(:#{k}){@#{k} || self.post_solution(:@#{k})}")
|
330
350
|
}
|
351
|
+
define_method(:other_state){
|
352
|
+
# If a design matrix G has columns larger than 4,
|
353
|
+
# other states excluding position and time are estimated.
|
354
|
+
(self.G.rows <= 4) ? [] : (self.S * self.delta_r).transpose.to_a[0][4..-1]
|
355
|
+
}
|
331
356
|
}
|
332
357
|
|
333
358
|
proc{
|
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.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- fenrir(M.Naruoka)
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-03-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|
@@ -100,7 +100,7 @@ licenses: []
|
|
100
100
|
metadata:
|
101
101
|
homepage_uri: https://github.com/fenrir-naru/gps_pvt
|
102
102
|
source_code_uri: https://github.com/fenrir-naru/gps_pvt
|
103
|
-
post_install_message:
|
103
|
+
post_install_message:
|
104
104
|
rdoc_options: []
|
105
105
|
require_paths:
|
106
106
|
- lib
|
@@ -115,8 +115,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
115
115
|
- !ruby/object:Gem::Version
|
116
116
|
version: '0'
|
117
117
|
requirements: []
|
118
|
-
rubygems_version: 3.
|
119
|
-
signing_key:
|
118
|
+
rubygems_version: 3.1.2
|
119
|
+
signing_key:
|
120
120
|
specification_version: 4
|
121
121
|
summary: GPS position, velocity, and time (PVT) solver
|
122
122
|
test_files: []
|