gps_pvt 0.4.0 → 0.5.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 +2 -1
- data/exe/gps_pvt +36 -4
- data/ext/gps_pvt/GPS/GPS_wrap.cxx +10 -41
- data/ext/ninja-scan-light/tool/navigation/GLONASS.h +86 -27
- data/ext/ninja-scan-light/tool/navigation/GLONASS_Solver.h +63 -43
- data/ext/ninja-scan-light/tool/navigation/GPS_Solver.h +58 -34
- data/ext/ninja-scan-light/tool/navigation/GPS_Solver_Base.h +42 -17
- data/ext/ninja-scan-light/tool/navigation/RINEX.h +28 -10
- data/ext/ninja-scan-light/tool/navigation/SBAS.h +19 -4
- data/ext/ninja-scan-light/tool/navigation/SBAS_Solver.h +63 -43
- data/ext/ninja-scan-light/tool/swig/GPS.i +11 -42
- data/ext/ninja-scan-light/tool/swig/spec/GPS_spec.rb +0 -16
- data/{sig/gps_pvt.rbs → gps_pvt.rbs} +0 -0
- data/lib/gps_pvt/receiver.rb +8 -5
- data/lib/gps_pvt/util.rb +32 -0
- data/lib/gps_pvt/version.rb +1 -1
- metadata +4 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6b4f5df780c4ff0977b025fab381c327b04a3e8fae742cc6ff672e08839d9c51
|
4
|
+
data.tar.gz: cbbb233acbe548944d9b317449160465ec04d2041e56f54decc286a900503723
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a724b51f5fe55fe9c0d74d02176c26dbad63bcc1fc1fbd477c7a0707e06f832df5110f4a80c5c2807ac5e1ae2d0717846858a30365eec874847c96fb11e12b5e
|
7
|
+
data.tar.gz: 97b3670fd401bc860d9f16ab473fe4c6c33ee87fcf6855757490ec724d8405a6aeb7df22aabaf7e37f559d80ce9b4ce1c764c550acccf591bb940805b3c660a6
|
data/README.md
CHANGED
@@ -32,7 +32,7 @@ An attached executable is useful. After installation, type
|
|
32
32
|
|
33
33
|
$ gps_pvt RINEX_or_UBX_file(s)
|
34
34
|
|
35
|
-
The format of RINEX_or_UBX_file is automatically determined with its
|
35
|
+
The format of RINEX_or_UBX_file is automatically determined with its extension, such as .ubx will be treated as UBX format. A gz compressed file can be specified directly, and URI such as https://... is also acceptable since version 0.5.0. If you want to specify the file format, instead of RINEX_or_UBX_file(s), use the following arguments:
|
36
36
|
|
37
37
|
--rinex_nav=filename
|
38
38
|
--rinex_obs=filename
|
@@ -50,6 +50,7 @@ Additionally, the following command options *--key=value* are available.
|
|
50
50
|
| elevation_mask_deg | numeric | satellite elevation mask specified in degrees. *ex) --elevation_mask_deg=10* | v0.3.0 |
|
51
51
|
| start_time | time string | start time to perform solution. GPS, UTC and other formats are supported. *ex1) --start_time=1234:5678* represents 5678 seconds in 1234 GPS week, *ex2) --start_time="2000-01-01 00:00:00 UTC"* is in UTC format. | v0.3.3 |
|
52
52
|
| end_time | time string | end time to perform solution. Its format is the same as start_time. | v0.3.3 |
|
53
|
+
| online_ephemeris | | automatically load ephemeris published online based on observation | v0.5.0 |
|
53
54
|
|
54
55
|
### For developer
|
55
56
|
|
data/exe/gps_pvt
CHANGED
@@ -1,16 +1,19 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
3
|
require 'gps_pvt'
|
4
|
+
require 'uri'
|
4
5
|
|
5
6
|
# runnable quick example to solve PVT by using RINEX NAV/OBS or u-blox ubx
|
6
7
|
|
7
8
|
$stderr.puts <<__STRING__
|
8
9
|
Usage: #{__FILE__} GPS_file1 GPS_file2 ...
|
9
10
|
As GPS_file, rinex_nav(*.YYn, *.YYh, *.YYq, *.YYg), rinex_obs(*.YYo), and ubx(*.ubx) format are currently supported.
|
11
|
+
(YY = last two digit of year)
|
10
12
|
File format is automatically determined based on its extention described in above parentheses.
|
11
13
|
If you want to specify its format manually, --rinex_(nav|obs)=file_name or --ubx=file_name are available.
|
12
14
|
Supported RINEX versions are 2 and 3.
|
13
|
-
|
15
|
+
A file having additional ".gz" extension is recognized as a file compressed by zlib.
|
16
|
+
Major URL such as http(s)://... is acceptable as an input file name.
|
14
17
|
__STRING__
|
15
18
|
|
16
19
|
options = []
|
@@ -54,6 +57,9 @@ options.reject!{|opt|
|
|
54
57
|
end
|
55
58
|
misc_options[opt[0]] = t
|
56
59
|
true
|
60
|
+
when :online_ephemeris
|
61
|
+
misc_options[opt[0]] = opt[1]
|
62
|
+
true
|
57
63
|
else
|
58
64
|
false
|
59
65
|
end
|
@@ -61,19 +67,45 @@ options.reject!{|opt|
|
|
61
67
|
|
62
68
|
# Check file existence and extension
|
63
69
|
files.collect!{|fname, ftype|
|
64
|
-
raise "File not found: #{fname}" unless File::exist?(fname)
|
65
70
|
ftype ||= case fname
|
66
|
-
when /\.\d{2}[nhqg]
|
67
|
-
when /\.\d{2}o
|
71
|
+
when /\.\d{2}[nhqg](?:\.gz)?$/; :rinex_nav
|
72
|
+
when /\.\d{2}o(?:\.gz)?$/; :rinex_obs
|
68
73
|
when /\.ubx$/; :ubx
|
69
74
|
else
|
70
75
|
raise "Format cannot be guessed, use --(format, ex. rinex_nav)=#{fname}"
|
71
76
|
end
|
77
|
+
fname = proc{
|
78
|
+
next fname if File::exist?(fname)
|
79
|
+
if uri = URI::parse(fname) and !uri.instance_of?(URI::Generic) then
|
80
|
+
next uri
|
81
|
+
end
|
82
|
+
raise "File not found: #{fname}"
|
83
|
+
}.call
|
72
84
|
[fname, ftype]
|
73
85
|
}
|
74
86
|
|
75
87
|
rcv = GPS_PVT::Receiver::new(options)
|
76
88
|
|
89
|
+
proc{|src|
|
90
|
+
next unless src
|
91
|
+
loader = proc{|t_meas|
|
92
|
+
utc = Time::utc(*t_meas.c_tm)
|
93
|
+
y, yday = [:year, :yday].collect{|f| utc.send(f)}
|
94
|
+
uri = URI::parse(
|
95
|
+
"ftp://gssc.esa.int/gnss/data/daily/" +
|
96
|
+
"%04d/brdc/BRDC00IGS_R_%04d%03d0000_01D_MN.rnx.gz"%[y, y, yday])
|
97
|
+
rcv.parse_rinex_nav(uri)
|
98
|
+
uri
|
99
|
+
}
|
100
|
+
run_orig = rcv.method(:run)
|
101
|
+
eph_list = {}
|
102
|
+
rcv.define_singleton_method(:run){|meas, t_meas, *args|
|
103
|
+
w_d = [t_meas.week, (t_meas.seconds.to_i / 86400)]
|
104
|
+
eph_list[w_d] ||= loader.call(t_meas)
|
105
|
+
run_orig.call(meas, t_meas, *args)
|
106
|
+
}
|
107
|
+
}.call(misc_options[:online_ephemeris])
|
108
|
+
|
77
109
|
proc{
|
78
110
|
run_orig = rcv.method(:run)
|
79
111
|
t_start, t_end = [nil, nil]
|
@@ -2671,10 +2671,9 @@ struct GPS_Solver
|
|
2671
2671
|
const typename base_t::gps_time_t &time_arrival,
|
2672
2672
|
const typename base_t::pos_t &usr_pos,
|
2673
2673
|
const typename base_t::xyz_t &usr_vel) const;
|
2674
|
-
virtual typename base_t::
|
2674
|
+
virtual typename base_t::satellite_t select_satellite(
|
2675
2675
|
const typename base_t::prn_t &prn,
|
2676
|
-
const typename base_t::gps_time_t &time
|
2677
|
-
typename base_t::xyz_t &res) const;
|
2676
|
+
const typename base_t::gps_time_t &time) const;
|
2678
2677
|
virtual bool update_position_solution(
|
2679
2678
|
const typename base_t::geometric_matrices_t &geomat,
|
2680
2679
|
typename base_t::user_pvt_t &res) const;
|
@@ -3867,47 +3866,17 @@ SWIGINTERN double const &GPS_SolverOptions_Common_Sl_double_Sg__get_residual_mas
|
|
3867
3866
|
return super_t::update_position_solution(geomat, res);
|
3868
3867
|
}
|
3869
3868
|
template <>
|
3870
|
-
GPS_Solver<double>::base_t::
|
3869
|
+
GPS_Solver<double>::base_t::satellite_t GPS_Solver<double>::select_satellite(
|
3871
3870
|
const GPS_Solver<double>::base_t::prn_t &prn,
|
3872
|
-
const GPS_Solver<double>::base_t::gps_time_t &time
|
3873
|
-
|
3874
|
-
|
3875
|
-
select_solver(prn).satellite_position(prn, time, buf));
|
3871
|
+
const GPS_Solver<double>::base_t::gps_time_t &time) const {
|
3872
|
+
GPS_Solver<double>::base_t::satellite_t res(
|
3873
|
+
select_solver(prn).select_satellite(prn, time));
|
3876
3874
|
|
3877
|
-
|
3878
|
-
static const VALUE key(ID2SYM(rb_intern("
|
3875
|
+
if(!res.is_available()){
|
3876
|
+
static const VALUE key(ID2SYM(rb_intern("relative_property")));
|
3879
3877
|
VALUE hook(rb_hash_lookup(hooks, key));
|
3880
|
-
if(NIL_P(hook)){
|
3881
|
-
|
3882
|
-
SWIG_From_int (prn), // prn
|
3883
|
-
SWIG_NewPointerObj( // time
|
3884
|
-
new base_t::gps_time_t(time), SWIGTYPE_p_GPS_TimeT_double_t, SWIG_POINTER_OWN),
|
3885
|
-
(res // position (internally calculated)
|
3886
|
-
? SWIG_NewPointerObj(res, SWIGTYPE_p_System_XYZT_double_WGS84_t, 0)
|
3887
|
-
: Qnil)};
|
3888
|
-
VALUE res_hook(proc_call_throw_if_error(hook, sizeof(values) / sizeof(values[0]), values));
|
3889
|
-
if(NIL_P(res_hook)){ // unknown position
|
3890
|
-
res = NULL;
|
3891
|
-
break;
|
3892
|
-
}else if(RB_TYPE_P(res_hook, T_ARRAY) && (RARRAY_LEN(res_hook) == 3)){
|
3893
|
-
int i(0);
|
3894
|
-
for(; i < 3; ++i){
|
3895
|
-
VALUE v(RARRAY_AREF(res_hook, i));
|
3896
|
-
if(!SWIG_IsOK(swig::asval(v, &buf[i]))){break;}
|
3897
|
-
}
|
3898
|
-
if(i == 3){
|
3899
|
-
res = &buf;
|
3900
|
-
break;
|
3901
|
-
}
|
3902
|
-
}else if(SWIG_IsOK(SWIG_ConvertPtr(
|
3903
|
-
res_hook, (void **)&res, SWIGTYPE_p_System_XYZT_double_WGS84_t, 0))){
|
3904
|
-
res = &(buf = *res);
|
3905
|
-
break;
|
3906
|
-
}
|
3907
|
-
throw std::runtime_error(
|
3908
|
-
std::string("System_XYZ or [d * 3] is expected (d: " "double" "), however ")
|
3909
|
-
.append(inspect_str(res_hook)));
|
3910
|
-
}while(false);
|
3878
|
+
if(!NIL_P(hook)){res.impl = this;}
|
3879
|
+
}
|
3911
3880
|
|
3912
3881
|
return res;
|
3913
3882
|
}
|
@@ -952,6 +952,8 @@ if(std::abs(TARGET - eph.TARGET) > raw_t::sf[raw_t::SF_ ## TARGET]){break;}
|
|
952
952
|
float_t sidereal_t_b_rad;
|
953
953
|
typename Ephemeris::differential_t eq_of_motion;
|
954
954
|
|
955
|
+
static const float_t time_step_max_per_one_integration;
|
956
|
+
|
955
957
|
void calculate_additional() {
|
956
958
|
sidereal_t_b_rad = TimeProperties::date_t::Greenwich_sidereal_time_deg(
|
957
959
|
TimeProperties::date.c_tm(),
|
@@ -1009,36 +1011,52 @@ if(std::abs(TARGET - eph.TARGET) > raw_t::sf[raw_t::SF_ ## TARGET]){break;}
|
|
1009
1011
|
return calculate_clock_error(t_arrival_onboard - Ephemeris::t_b, pseudo_range);
|
1010
1012
|
}
|
1011
1013
|
/**
|
1012
|
-
* Calculate constellation(t) based on constellation(t_0).
|
1014
|
+
* Calculate absolute constellation(t) based on constellation(t_0).
|
1013
1015
|
* t_0 is a time around t_b, and is used to calculate
|
1014
|
-
*
|
1015
|
-
*
|
1016
|
-
* by using a cache.
|
1017
|
-
* @param delta_t time interval from t_0 to t
|
1018
|
-
* @param pseudo_range measured pusedo_range to correct delta_t
|
1016
|
+
* @param t_step time interval from t_0 to t
|
1017
|
+
* @param times number of integration steps (assume times >=0)
|
1019
1018
|
* @param xa_t_0 constellation(t_0)
|
1020
|
-
* @param t_0_from_t_b time interval from t_b to t_0
|
1019
|
+
* @param t_0_from_t_b time interval from t_b to t_0 (= t_0 - t_b)
|
1021
1020
|
*/
|
1022
|
-
constellation_t
|
1023
|
-
|
1021
|
+
constellation_t constellation_abs(
|
1022
|
+
const float_t &t_step,
|
1023
|
+
int times,
|
1024
1024
|
const constellation_t &xa_t_0, const float_t &t_0_from_t_b) const {
|
1025
1025
|
|
1026
1026
|
constellation_t res(xa_t_0);
|
1027
|
-
|
1028
|
-
|
1029
|
-
|
1030
|
-
int i(std::floor(delta_t_to_transmit / t_step_max));
|
1031
|
-
float_t t_step_remain(delta_t_to_transmit - t_step_max * i);
|
1032
|
-
float_t delta_t_itg(0); // accumulative time of integration
|
1033
|
-
for(; i > 0; --i, delta_t_itg += t_step_max){
|
1034
|
-
res = nextByRK4(eq_of_motion, delta_t_itg, res, t_step_max);
|
1035
|
-
}
|
1036
|
-
res = nextByRK4(eq_of_motion, delta_t_itg, res, t_step_remain);
|
1027
|
+
float_t delta_t_itg(t_0_from_t_b); // accumulative time of integration
|
1028
|
+
for(; times > 0; --times, delta_t_itg += t_step){
|
1029
|
+
res = nextByRK4(eq_of_motion, delta_t_itg, res, t_step);
|
1037
1030
|
}
|
1031
|
+
return res;
|
1032
|
+
}
|
1033
|
+
/**
|
1034
|
+
* Calculate absolute constellation(t) based on constellation(t_0).
|
1035
|
+
* t_0 is a time around t_b, and is used to calculate
|
1036
|
+
* an intermediate result specified with the 2nd argument.
|
1037
|
+
* This method is useful to calculate constellation effectively
|
1038
|
+
* by using a cache.
|
1039
|
+
* @param delta_t time interval from t_0 to t
|
1040
|
+
* @param xa_t_0 constellation(t_0)
|
1041
|
+
* @param t_0_from_t_b time interval from t_b to t_0 (= t_0 - t_b)
|
1042
|
+
*/
|
1043
|
+
constellation_t constellation_abs(
|
1044
|
+
const float_t &delta_t,
|
1045
|
+
const constellation_t &xa_t_0, const float_t &t_0_from_t_b) const {
|
1038
1046
|
|
1039
|
-
|
1040
|
-
|
1041
|
-
|
1047
|
+
float_t t_step_max(delta_t >= 0
|
1048
|
+
? time_step_max_per_one_integration
|
1049
|
+
: -time_step_max_per_one_integration);
|
1050
|
+
int n(std::floor(delta_t / t_step_max));
|
1051
|
+
float_t delta_t_steps(t_step_max * n), delta_t_remain(delta_t - delta_t_steps);
|
1052
|
+
|
1053
|
+
// To perform time integration from t_0 to (t_0 + delta_t),
|
1054
|
+
// n-times integration with t_step_max,
|
1055
|
+
// then, one-time integration with delta_t_remain are conducted.
|
1056
|
+
return constellation_abs(
|
1057
|
+
delta_t_remain, 1,
|
1058
|
+
constellation_abs(t_step_max, n, xa_t_0, t_0_from_t_b),
|
1059
|
+
t_0_from_t_b + delta_t_steps);
|
1042
1060
|
}
|
1043
1061
|
/**
|
1044
1062
|
* Calculate constellation(t) based on constellation(t_b).
|
@@ -1046,8 +1064,14 @@ if(std::abs(TARGET - eph.TARGET) > raw_t::sf[raw_t::SF_ ## TARGET]){break;}
|
|
1046
1064
|
* @param pseudo_range measured pusedo_range to correct delta_t, default is 0.
|
1047
1065
|
*/
|
1048
1066
|
constellation_t calculate_constellation(
|
1049
|
-
float_t delta_t, const float_t &pseudo_range = 0) const {
|
1050
|
-
|
1067
|
+
const float_t &delta_t, const float_t &pseudo_range = 0) const {
|
1068
|
+
|
1069
|
+
float_t delta_t_to_transmit(delta_t - pseudo_range / light_speed);
|
1070
|
+
constellation_t res(
|
1071
|
+
constellation_abs(delta_t_to_transmit, xa_t_b, float_t(0)));
|
1072
|
+
|
1073
|
+
return res.rel_corrdinate(
|
1074
|
+
sidereal_t_b_rad + (constellation_t::omega_E * delta_t)); // transform from abs to PZ-90.02
|
1051
1075
|
}
|
1052
1076
|
/**
|
1053
1077
|
* @param t_arrival_glonass signal arrival time in glonass time scale,
|
@@ -1098,7 +1122,37 @@ if(std::abs(TARGET - eph.TARGET) > raw_t::sf[raw_t::SF_ ## TARGET]){break;}
|
|
1098
1122
|
struct Satellite : public SatelliteProperties {
|
1099
1123
|
public:
|
1100
1124
|
typedef typename SatelliteProperties::Ephemeris_with_GPS_Time eph_t;
|
1101
|
-
|
1125
|
+
|
1126
|
+
struct eph_cached_t : public eph_t {
|
1127
|
+
mutable typename eph_t::constellation_t xa_t_0;
|
1128
|
+
mutable float_t t_0_from_t_b;
|
1129
|
+
eph_cached_t() : eph_t(), xa_t_0(eph_t::xa_t_b), t_0_from_t_b(0) {}
|
1130
|
+
eph_cached_t(const eph_t &eph) : eph_t(eph), xa_t_0(eph.xa_t_b), t_0_from_t_b(0) {}
|
1131
|
+
using eph_t::constellation;
|
1132
|
+
typename eph_t::constellation_t constellation(
|
1133
|
+
const GPS_Time<float_t> &t_arrival_gps, const float_t &pseudo_range = 0) const {
|
1134
|
+
float_t delta_t(t_arrival_gps - eph_t::t_b_gps);
|
1135
|
+
float_t delta_t_transmit_from_t_0(delta_t - pseudo_range / light_speed - t_0_from_t_b);
|
1136
|
+
|
1137
|
+
float_t t_step_max(delta_t_transmit_from_t_0 >= 0
|
1138
|
+
? eph_t::time_step_max_per_one_integration
|
1139
|
+
: -eph_t::time_step_max_per_one_integration);
|
1140
|
+
|
1141
|
+
int big_steps(std::floor(delta_t_transmit_from_t_0 / t_step_max));
|
1142
|
+
if(big_steps > 0){ // perform integration and update cache
|
1143
|
+
xa_t_0 = eph_t::constellation_abs(t_step_max, big_steps, xa_t_0, t_0_from_t_b);
|
1144
|
+
float_t delta_t_updated(t_step_max * big_steps);
|
1145
|
+
t_0_from_t_b += delta_t_updated;
|
1146
|
+
delta_t_transmit_from_t_0 -= delta_t_updated;
|
1147
|
+
}
|
1148
|
+
|
1149
|
+
return eph_t::constellation_abs(delta_t_transmit_from_t_0, 1, xa_t_0, t_0_from_t_b)
|
1150
|
+
.rel_corrdinate(
|
1151
|
+
eph_t::sidereal_t_b_rad + (eph_t::constellation_t::omega_E * delta_t)); // transform from abs to PZ-90.02
|
1152
|
+
}
|
1153
|
+
};
|
1154
|
+
|
1155
|
+
typedef typename GPS_SpaceNode<float_t>::template PropertyHistory<eph_cached_t> eph_list_t;
|
1102
1156
|
protected:
|
1103
1157
|
eph_list_t eph_history;
|
1104
1158
|
public:
|
@@ -1115,7 +1169,7 @@ if(std::abs(TARGET - eph.TARGET) > raw_t::sf[raw_t::SF_ ## TARGET]){break;}
|
|
1115
1169
|
}
|
1116
1170
|
|
1117
1171
|
void register_ephemeris(const eph_t &eph, const int &priority_delta = 1){
|
1118
|
-
eph_history.add(eph, priority_delta);
|
1172
|
+
eph_history.add(eph_cached_t(eph), priority_delta);
|
1119
1173
|
}
|
1120
1174
|
|
1121
1175
|
void merge(const Satellite &another, const bool &keep_original = true){
|
@@ -1143,7 +1197,7 @@ if(std::abs(TARGET - eph.TARGET) > raw_t::sf[raw_t::SF_ ## TARGET]){break;}
|
|
1143
1197
|
typename GPS_SpaceNode<float_t>::SatelliteProperties::constellation_t constellation(
|
1144
1198
|
const GPS_Time<float_t> &t, const float_t &pseudo_range = 0) const {
|
1145
1199
|
return (typename GPS_SpaceNode<float_t>::SatelliteProperties::constellation_t)(
|
1146
|
-
|
1200
|
+
eph_history.current().constellation(t, pseudo_range));
|
1147
1201
|
}
|
1148
1202
|
|
1149
1203
|
typename GPS_SpaceNode<float_t>::xyz_t position(const GPS_Time<float_t> &t, const float_t &pseudo_range = 0) const {
|
@@ -1267,4 +1321,9 @@ typename GLONASS_SpaceNode<FloatT>::u8_t GLONASS_SpaceNode<FloatT>::SatellitePro
|
|
1267
1321
|
return res;
|
1268
1322
|
}
|
1269
1323
|
|
1324
|
+
template <class FloatT>
|
1325
|
+
const typename GLONASS_SpaceNode<FloatT>::float_t
|
1326
|
+
GLONASS_SpaceNode<FloatT>::SatelliteProperties::Ephemeris_with_Time
|
1327
|
+
::time_step_max_per_one_integration = 60;
|
1328
|
+
|
1270
1329
|
#endif /* __GLONASS_H__ */
|
@@ -75,7 +75,6 @@ class GLONASS_SinglePositioning : public SolverBaseT {
|
|
75
75
|
|
76
76
|
typedef GLONASS_SpaceNode<float_t> space_node_t;
|
77
77
|
inheritate_type(gps_time_t);
|
78
|
-
typedef typename space_node_t::Satellite satellite_t;
|
79
78
|
|
80
79
|
inheritate_type(xyz_t);
|
81
80
|
inheritate_type(enu_t);
|
@@ -83,9 +82,10 @@ class GLONASS_SinglePositioning : public SolverBaseT {
|
|
83
82
|
inheritate_type(pos_t);
|
84
83
|
|
85
84
|
typedef typename base_t::measurement_t measurement_t;
|
86
|
-
|
87
|
-
|
88
|
-
|
85
|
+
typedef typename base_t::satellite_t satellite_t;
|
86
|
+
typedef typename base_t::range_error_t range_error_t;
|
87
|
+
typedef typename base_t::range_corrector_t range_corrector_t;
|
88
|
+
typedef typename base_t::range_correction_t range_correction_t;
|
89
89
|
|
90
90
|
inheritate_type(relative_property_t);
|
91
91
|
typedef typename super_t::measurement_items_t measurement_items_t;
|
@@ -97,11 +97,51 @@ class GLONASS_SinglePositioning : public SolverBaseT {
|
|
97
97
|
GLONASS_SinglePositioning_Options<float_t>, base_t> options_t;
|
98
98
|
|
99
99
|
protected:
|
100
|
-
const space_node_t &_space_node;
|
101
100
|
GLONASS_SinglePositioning_Options<float_t> _options;
|
102
101
|
|
103
102
|
public:
|
104
|
-
|
103
|
+
struct satellites_t {
|
104
|
+
const void *impl;
|
105
|
+
satellite_t (*impl_select)(const void *, const prn_t &, const gps_time_t &);
|
106
|
+
inline satellite_t select(const prn_t &prn, const gps_time_t &receiver_time) const {
|
107
|
+
return impl_select(impl, prn, receiver_time);
|
108
|
+
}
|
109
|
+
static satellite_t select_broadcast(
|
110
|
+
const void *ptr, const prn_t &prn, const gps_time_t &receiver_time){
|
111
|
+
const typename space_node_t::satellites_t &sats(
|
112
|
+
reinterpret_cast<const space_node_t *>(ptr)->satellites());
|
113
|
+
const typename space_node_t::satellites_t::const_iterator it_sat(sats.find(prn));
|
114
|
+
if((it_sat == sats.end()) // has ephemeris?
|
115
|
+
|| (!it_sat->second.ephemeris().is_valid(receiver_time))){ // valid ephemeris?
|
116
|
+
return satellite_t::unavailable();
|
117
|
+
}
|
118
|
+
struct impl_t {
|
119
|
+
static inline const typename space_node_t::Satellite &sat(const void *ptr) {
|
120
|
+
return *reinterpret_cast<const typename space_node_t::Satellite *>(ptr);
|
121
|
+
}
|
122
|
+
static xyz_t position(const void *ptr, const gps_time_t &t, const float_t &pseudo_range) {
|
123
|
+
return sat(ptr).constellation(t, pseudo_range).position;
|
124
|
+
}
|
125
|
+
static xyz_t velocity(const void *ptr, const gps_time_t &t, const float_t &pseudo_range) {
|
126
|
+
return sat(ptr).constellation(t, pseudo_range).velocity;
|
127
|
+
}
|
128
|
+
static float_t clock_error(const void *ptr, const gps_time_t &t, const float_t &pseudo_range) {
|
129
|
+
return sat(ptr).clock_error(t, pseudo_range);
|
130
|
+
}
|
131
|
+
static float_t clock_error_dot(const void *ptr, const gps_time_t &t, const float_t &pseudo_range) {
|
132
|
+
// Clock rate error is already taken into account in constellation()
|
133
|
+
return 0;
|
134
|
+
}
|
135
|
+
};
|
136
|
+
satellite_t res = {
|
137
|
+
&(it_sat->second),
|
138
|
+
impl_t::position, impl_t::velocity,
|
139
|
+
impl_t::clock_error, impl_t::clock_error_dot};
|
140
|
+
return res;
|
141
|
+
}
|
142
|
+
satellites_t(const space_node_t &sn)
|
143
|
+
: impl(&sn), impl_select(select_broadcast) {}
|
144
|
+
} satellites;
|
105
145
|
|
106
146
|
range_correction_t ionospheric_correction, tropospheric_correction;
|
107
147
|
|
@@ -120,7 +160,8 @@ class GLONASS_SinglePositioning : public SolverBaseT {
|
|
120
160
|
}
|
121
161
|
|
122
162
|
GLONASS_SinglePositioning(const space_node_t &sn, const options_t &opt_wish = options_t())
|
123
|
-
: base_t(),
|
163
|
+
: base_t(), _options(available_options(opt_wish)),
|
164
|
+
satellites(sn),
|
124
165
|
ionospheric_correction(), tropospheric_correction() {
|
125
166
|
|
126
167
|
// default ionospheric correction: no correction
|
@@ -163,25 +204,18 @@ class GLONASS_SinglePositioning : public SolverBaseT {
|
|
163
204
|
}
|
164
205
|
|
165
206
|
/**
|
166
|
-
*
|
207
|
+
* Select satellite by using PRN and time
|
167
208
|
*
|
168
209
|
* @param prn satellite number
|
169
210
|
* @param receiver_time receiver time
|
170
|
-
* @return (
|
171
|
-
* otherwise NULL.
|
211
|
+
* @return (satellite_t) If available, satellite.is_available() returning true is returned.
|
172
212
|
*/
|
173
|
-
|
174
|
-
const
|
213
|
+
satellite_t select_satellite(
|
214
|
+
const prn_t &prn,
|
175
215
|
const gps_time_t &receiver_time) const {
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
if((it_sat == sats.end()) // has ephemeris?
|
180
|
-
|| (!it_sat->second.ephemeris().is_valid(receiver_time))){ // valid ephemeris?
|
181
|
-
return NULL;
|
182
|
-
}
|
183
|
-
|
184
|
-
return &(it_sat->second);
|
216
|
+
prn_t prn_(prn & 0xFF);
|
217
|
+
if(_options.exclude_prn[prn_]){return satellite_t::unavailable();}
|
218
|
+
return satellites.select(prn_, receiver_time);
|
185
219
|
}
|
186
220
|
|
187
221
|
/**
|
@@ -205,32 +239,27 @@ class GLONASS_SinglePositioning : public SolverBaseT {
|
|
205
239
|
|
206
240
|
relative_property_t res = {0};
|
207
241
|
|
208
|
-
if(_options.exclude_prn[prn & 0xFF]){return res;}
|
209
|
-
|
210
242
|
float_t range;
|
211
243
|
range_error_t range_error;
|
212
244
|
if(!this->range(measurement, range, &range_error)){
|
213
245
|
return res; // If no range entry, return with weight = 0
|
214
246
|
}
|
215
247
|
|
216
|
-
|
217
|
-
if(!sat){return res;} // If satellite is unavailable, return with weight = 0
|
248
|
+
satellite_t sat(select_satellite(prn, time_arrival));
|
249
|
+
if(!sat.is_available()){return res;} // If satellite is unavailable, return with weight = 0
|
218
250
|
|
219
251
|
range -= receiver_error;
|
220
252
|
|
221
253
|
// Clock correction, which will be considered in the next constellation()
|
222
254
|
// as extra transmission time by using extra psuedo range.
|
223
255
|
if(range_error.unknown_flag & range_error_t::SATELLITE_CLOCK){
|
224
|
-
range += (sat
|
256
|
+
range += (sat.clock_error(time_arrival, range) * space_node_t::light_speed);
|
225
257
|
}else{
|
226
258
|
range += range_error.value[range_error_t::SATELLITE_CLOCK];
|
227
259
|
}
|
228
260
|
|
229
|
-
// Calculate satellite position
|
230
|
-
|
231
|
-
sat->constellation(time_arrival, range));
|
232
|
-
|
233
|
-
const xyz_t &sat_pos(sat_pos_vel.position);
|
261
|
+
// Calculate satellite position
|
262
|
+
xyz_t sat_pos(sat.position(time_arrival, range));
|
234
263
|
float_t geometric_range(usr_pos.xyz.dist(sat_pos));
|
235
264
|
|
236
265
|
// Calculate residual
|
@@ -278,24 +307,15 @@ class GLONASS_SinglePositioning : public SolverBaseT {
|
|
278
307
|
|
279
308
|
res.range_corrected = range;
|
280
309
|
|
281
|
-
xyz_t rel_vel(
|
310
|
+
xyz_t rel_vel(sat.velocity(time_arrival, range) - usr_vel); // Calculate velocity
|
282
311
|
|
283
|
-
// Note: clock rate error is already accounted for in constellation()
|
284
312
|
res.rate_relative_neg = res.los_neg[0] * rel_vel.x()
|
285
313
|
+ res.los_neg[1] * rel_vel.y()
|
286
|
-
+ res.los_neg[2] * rel_vel.z()
|
314
|
+
+ res.los_neg[2] * rel_vel.z()
|
315
|
+
+ sat.clock_error_dot(time_arrival, range) * space_node_t::light_speed;
|
287
316
|
|
288
317
|
return res;
|
289
318
|
}
|
290
|
-
|
291
|
-
xyz_t *satellite_position(
|
292
|
-
const prn_t &prn,
|
293
|
-
const gps_time_t &time,
|
294
|
-
xyz_t &res) const {
|
295
|
-
|
296
|
-
const satellite_t *sat(is_available(prn, time));
|
297
|
-
return sat ? &(res = sat->position(time)) : NULL;
|
298
|
-
}
|
299
319
|
};
|
300
320
|
|
301
321
|
template <class FloatT, class SolverBaseT>
|
@@ -95,7 +95,6 @@ class GPS_SinglePositioning : public SolverBaseT {
|
|
95
95
|
|
96
96
|
typedef typename base_t::space_node_t space_node_t;
|
97
97
|
inheritate_type(gps_time_t);
|
98
|
-
typedef typename space_node_t::Satellite satellite_t;
|
99
98
|
|
100
99
|
inheritate_type(xyz_t);
|
101
100
|
inheritate_type(llh_t);
|
@@ -106,6 +105,7 @@ class GPS_SinglePositioning : public SolverBaseT {
|
|
106
105
|
inheritate_type(prn_obs_t);
|
107
106
|
typedef typename base_t::measurement_t measurement_t;
|
108
107
|
inheritate_type(measurement_items_t);
|
108
|
+
typedef typename base_t::satellite_t satellite_t;
|
109
109
|
typedef typename base_t::range_error_t range_error_t;
|
110
110
|
typedef typename base_t::range_corrector_t range_corrector_t;
|
111
111
|
typedef typename base_t::range_correction_t range_correction_t;
|
@@ -119,11 +119,52 @@ class GPS_SinglePositioning : public SolverBaseT {
|
|
119
119
|
GPS_SinglePositioning_Options<float_t>, base_t> options_t;
|
120
120
|
|
121
121
|
protected:
|
122
|
-
const space_node_t &_space_node;
|
123
122
|
GPS_SinglePositioning_Options<float_t> _options;
|
124
123
|
|
125
124
|
public:
|
126
|
-
|
125
|
+
struct satellites_t {
|
126
|
+
const void *impl;
|
127
|
+
satellite_t (*impl_select)(const void *, const prn_t &, const gps_time_t &);
|
128
|
+
inline satellite_t select(const prn_t &prn, const gps_time_t &receiver_time) const {
|
129
|
+
return impl_select(impl, prn, receiver_time);
|
130
|
+
}
|
131
|
+
static satellite_t select_broadcast(
|
132
|
+
const void *ptr, const prn_t &prn, const gps_time_t &receiver_time){
|
133
|
+
// If this static function is defined in inner struct,
|
134
|
+
// C2440 error raises with VC2010
|
135
|
+
const typename space_node_t::satellites_t &sats(
|
136
|
+
reinterpret_cast<const space_node_t *>(ptr)->satellites());
|
137
|
+
const typename space_node_t::satellites_t::const_iterator it_sat(sats.find(prn));
|
138
|
+
if((it_sat == sats.end()) // has ephemeris?
|
139
|
+
|| (!it_sat->second.ephemeris().is_valid(receiver_time))){ // valid ephemeris?
|
140
|
+
return satellite_t::unavailable();
|
141
|
+
}
|
142
|
+
struct impl_t {
|
143
|
+
static inline const typename space_node_t::Satellite &sat(const void *ptr) {
|
144
|
+
return *reinterpret_cast<const typename space_node_t::Satellite *>(ptr);
|
145
|
+
}
|
146
|
+
static xyz_t position(const void *ptr, const gps_time_t &t, const float_t &pseudo_range) {
|
147
|
+
return sat(ptr).position(t, pseudo_range);
|
148
|
+
}
|
149
|
+
static xyz_t velocity(const void *ptr, const gps_time_t &t, const float_t &pseudo_range) {
|
150
|
+
return sat(ptr).velocity(t, pseudo_range);
|
151
|
+
}
|
152
|
+
static float_t clock_error(const void *ptr, const gps_time_t &t, const float_t &pseudo_range) {
|
153
|
+
return sat(ptr).clock_error(t, pseudo_range);
|
154
|
+
}
|
155
|
+
static float_t clock_error_dot(const void *ptr, const gps_time_t &t, const float_t &pseudo_range) {
|
156
|
+
return sat(ptr).clock_error_dot(t, pseudo_range);
|
157
|
+
}
|
158
|
+
};
|
159
|
+
satellite_t res = {
|
160
|
+
&(it_sat->second),
|
161
|
+
impl_t::position, impl_t::velocity,
|
162
|
+
impl_t::clock_error, impl_t::clock_error_dot};
|
163
|
+
return res;
|
164
|
+
}
|
165
|
+
satellites_t(const space_node_t &sn)
|
166
|
+
: impl(&sn), impl_select(select_broadcast) {}
|
167
|
+
} satellites;
|
127
168
|
|
128
169
|
struct klobuchar_t : public range_corrector_t {
|
129
170
|
const space_node_t &space_node;
|
@@ -134,6 +175,7 @@ class GPS_SinglePositioning : public SolverBaseT {
|
|
134
175
|
float_t *calculate(
|
135
176
|
const gps_time_t &t, const pos_t &usr_pos, const enu_t &sat_rel_pos,
|
136
177
|
float_t &buf) const {
|
178
|
+
if(!is_available(t)){return NULL;}
|
137
179
|
return &(buf = space_node.iono_correction(sat_rel_pos, usr_pos.llh, t));
|
138
180
|
}
|
139
181
|
} ionospheric_klobuchar;
|
@@ -185,7 +227,8 @@ class GPS_SinglePositioning : public SolverBaseT {
|
|
185
227
|
}
|
186
228
|
|
187
229
|
GPS_SinglePositioning(const space_node_t &sn)
|
188
|
-
: base_t(),
|
230
|
+
: base_t(), _options(available_options(options_t())),
|
231
|
+
satellites(sn),
|
189
232
|
ionospheric_klobuchar(sn), ionospheric_ntcm_gl(),
|
190
233
|
tropospheric_simplified(),
|
191
234
|
ionospheric_correction(), tropospheric_correction() {
|
@@ -309,27 +352,17 @@ class GPS_SinglePositioning : public SolverBaseT {
|
|
309
352
|
}
|
310
353
|
|
311
354
|
/**
|
312
|
-
*
|
355
|
+
* Select satellite by using PRN and time
|
313
356
|
*
|
314
357
|
* @param prn satellite number
|
315
358
|
* @param receiver_time receiver time
|
316
|
-
* @return (
|
317
|
-
* otherwise NULL.
|
359
|
+
* @return (satellite_t) If available, satellite.is_available() returning true is returned.
|
318
360
|
*/
|
319
|
-
|
320
|
-
const
|
361
|
+
satellite_t select_satellite(
|
362
|
+
const prn_t &prn,
|
321
363
|
const gps_time_t &receiver_time) const {
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
const typename space_node_t::satellites_t &sats(_space_node.satellites());
|
326
|
-
const typename space_node_t::satellites_t::const_iterator it_sat(sats.find(prn));
|
327
|
-
if((it_sat == sats.end()) // has ephemeris?
|
328
|
-
|| (!it_sat->second.ephemeris().is_valid(receiver_time))){ // valid ephemeris?
|
329
|
-
return NULL;
|
330
|
-
}
|
331
|
-
|
332
|
-
return &(it_sat->second);
|
364
|
+
if(_options.exclude_prn[prn]){return satellite_t::unavailable();}
|
365
|
+
return satellites.select(prn, receiver_time);
|
333
366
|
}
|
334
367
|
|
335
368
|
/**
|
@@ -359,8 +392,8 @@ class GPS_SinglePositioning : public SolverBaseT {
|
|
359
392
|
return res; // If no range entry, return with weight = 0
|
360
393
|
}
|
361
394
|
|
362
|
-
|
363
|
-
if(!sat){return res;} // If satellite is unavailable, return with weight = 0
|
395
|
+
satellite_t sat(select_satellite(prn, time_arrival));
|
396
|
+
if(!sat.is_available()){return res;} // If satellite is unavailable, return with weight = 0
|
364
397
|
|
365
398
|
residual_t residual = {
|
366
399
|
res.range_residual,
|
@@ -369,9 +402,9 @@ class GPS_SinglePositioning : public SolverBaseT {
|
|
369
402
|
};
|
370
403
|
|
371
404
|
res.range_corrected = range_corrected(
|
372
|
-
|
405
|
+
sat, range - receiver_error, time_arrival,
|
373
406
|
usr_pos, residual, range_error);
|
374
|
-
res.rate_relative_neg = rate_relative_neg(
|
407
|
+
res.rate_relative_neg = rate_relative_neg(sat, res.range_corrected, time_arrival, usr_vel,
|
375
408
|
res.los_neg[0], res.los_neg[1], res.los_neg[2]);
|
376
409
|
|
377
410
|
return res;
|
@@ -415,7 +448,7 @@ class GPS_SinglePositioning : public SolverBaseT {
|
|
415
448
|
float_t range;
|
416
449
|
if(!this->range(it->second, range)){continue;} // No range entry
|
417
450
|
|
418
|
-
if(!
|
451
|
+
if(!(select_satellite(it->first, receiver_time).is_available())){continue;} // No satellite
|
419
452
|
|
420
453
|
typename base_t::measurement2_t::value_type v = {
|
421
454
|
it->first, &(it->second), this}; // prn, measurement, solver
|
@@ -426,15 +459,6 @@ class GPS_SinglePositioning : public SolverBaseT {
|
|
426
459
|
measurement2, receiver_time, user_position_init, receiver_error_init,
|
427
460
|
typename base_t::user_pvt_opt_t(good_init, with_velocity));
|
428
461
|
}
|
429
|
-
|
430
|
-
xyz_t *satellite_position(
|
431
|
-
const prn_t &prn,
|
432
|
-
const gps_time_t &time,
|
433
|
-
xyz_t &res) const {
|
434
|
-
|
435
|
-
const satellite_t *sat(is_available(prn, time));
|
436
|
-
return sat ? &(res = sat->position(time)) : NULL;
|
437
|
-
}
|
438
462
|
};
|
439
463
|
|
440
464
|
#endif /* __GPS_SOLVER_H__ */
|
@@ -226,6 +226,47 @@ struct GPS_Solver_Base {
|
|
226
226
|
return res;
|
227
227
|
}
|
228
228
|
|
229
|
+
struct satellite_t {
|
230
|
+
const void *impl;
|
231
|
+
xyz_t (*impl_position)(const void *, const gps_time_t &, const float_t &);
|
232
|
+
xyz_t (*impl_velocity)(const void *, const gps_time_t &, const float_t &);
|
233
|
+
float_t (*impl_clock_error)(const void *, const gps_time_t &, const float_t &);
|
234
|
+
float_t (*impl_clock_error_dot)(const void *, const gps_time_t &, const float_t &);
|
235
|
+
inline bool is_available() const {
|
236
|
+
return impl != NULL;
|
237
|
+
}
|
238
|
+
inline xyz_t position(const gps_time_t &t, const float_t &pseudo_range = 0) const {
|
239
|
+
return impl_position(impl, t, pseudo_range);
|
240
|
+
}
|
241
|
+
inline xyz_t velocity(const gps_time_t &t, const float_t &pseudo_range = 0) const {
|
242
|
+
return impl_velocity(impl, t, pseudo_range);
|
243
|
+
}
|
244
|
+
inline float_t clock_error(const gps_time_t &t, const float_t &pseudo_range = 0) const {
|
245
|
+
return impl_clock_error(impl, t, pseudo_range);
|
246
|
+
}
|
247
|
+
inline float_t clock_error_dot(const gps_time_t &t, const float_t &pseudo_range = 0) const {
|
248
|
+
return impl_clock_error_dot(impl, t, pseudo_range);
|
249
|
+
}
|
250
|
+
static const satellite_t &unavailable() {
|
251
|
+
static const satellite_t res = {NULL};
|
252
|
+
return res;
|
253
|
+
}
|
254
|
+
};
|
255
|
+
|
256
|
+
/**
|
257
|
+
* Select satellite by using PRN and time
|
258
|
+
* This function should be overridden.
|
259
|
+
*
|
260
|
+
* @param prn satellite number
|
261
|
+
* @param receiver_time receiver time
|
262
|
+
* @return (satellite_t) If available, satellite.is_available() returning true is returned.
|
263
|
+
*/
|
264
|
+
virtual satellite_t select_satellite(
|
265
|
+
const prn_t &prn,
|
266
|
+
const gps_time_t &receiver_time) const {
|
267
|
+
return satellite_t::unavailable();
|
268
|
+
}
|
269
|
+
|
229
270
|
struct range_corrector_t {
|
230
271
|
virtual ~range_corrector_t() {}
|
231
272
|
virtual bool is_available(const gps_time_t &t) const {
|
@@ -838,21 +879,6 @@ protected:
|
|
838
879
|
}
|
839
880
|
|
840
881
|
public:
|
841
|
-
/**
|
842
|
-
* Calculate satellite position
|
843
|
-
*
|
844
|
-
* @param prn satellite number
|
845
|
-
* @param time GPS time
|
846
|
-
* @param res object to which results are stored
|
847
|
-
* @return If position is available, &res will be returned, otherwise NULL.
|
848
|
-
*/
|
849
|
-
virtual xyz_t *satellite_position(
|
850
|
-
const prn_t &prn,
|
851
|
-
const gps_time_t &time,
|
852
|
-
xyz_t &res) const {
|
853
|
-
return NULL;
|
854
|
-
}
|
855
|
-
|
856
882
|
/**
|
857
883
|
* Calculate User position/velocity with hint
|
858
884
|
* This is multi-constellation version,
|
@@ -882,8 +908,7 @@ public:
|
|
882
908
|
it != it_end; ++it){
|
883
909
|
typename measurement2_t::value_type v = {
|
884
910
|
it->first, &(it->second), &select(it->first)}; // prn, measurement, solver
|
885
|
-
|
886
|
-
if(!v.solver->satellite_position(v.prn, receiver_time, sat)){
|
911
|
+
if(!v.solver->select_satellite(v.prn, receiver_time).is_available()){
|
887
912
|
// pre-check satellite availability; remove it when its position is unknown
|
888
913
|
continue;
|
889
914
|
}
|
@@ -62,8 +62,6 @@ class RINEX_Reader {
|
|
62
62
|
typedef RINEX_Reader<U> self_t;
|
63
63
|
typedef std::map<std::string, std::vector<std::string> > header_t;
|
64
64
|
|
65
|
-
protected:
|
66
|
-
header_t _header;
|
67
65
|
struct src_stream_t : public std::istream {
|
68
66
|
src_stream_t(std::istream &is) : std::istream(is.rdbuf()) {}
|
69
67
|
/**
|
@@ -106,7 +104,11 @@ class RINEX_Reader {
|
|
106
104
|
}
|
107
105
|
return *this;
|
108
106
|
}
|
109
|
-
}
|
107
|
+
};
|
108
|
+
|
109
|
+
protected:
|
110
|
+
header_t _header;
|
111
|
+
src_stream_t src;
|
110
112
|
bool _has_next;
|
111
113
|
|
112
114
|
public:
|
@@ -198,7 +200,7 @@ class RINEX_Reader {
|
|
198
200
|
return true;
|
199
201
|
}
|
200
202
|
}
|
201
|
-
static bool
|
203
|
+
static bool f_pure(
|
202
204
|
std::string &buf, const int &offset, const int &length, void *value, const int &precision = 0, const bool &str2val = true){
|
203
205
|
if(str2val){
|
204
206
|
std::stringstream ss(buf.substr(offset, length));
|
@@ -209,22 +211,30 @@ class RINEX_Reader {
|
|
209
211
|
ss << std::setfill(' ') << std::right << std::setw(length)
|
210
212
|
<< std::setprecision(precision) << std::fixed
|
211
213
|
<< *(T *)value;
|
212
|
-
|
214
|
+
buf.replace(offset, length, ss.str());
|
215
|
+
return true;
|
216
|
+
}
|
217
|
+
}
|
218
|
+
static bool f(
|
219
|
+
std::string &buf, const int &offset, const int &length, void *value, const int &precision = 0, const bool &str2val = true){
|
220
|
+
bool res(f_pure(buf, offset, length, value, precision, str2val));
|
221
|
+
if((!str2val) && res){
|
213
222
|
if((*(T *)value) >= 0){
|
214
223
|
if((*(T *)value) < 1){
|
215
224
|
int i(length - precision - 2);
|
216
|
-
|
225
|
+
// 0.12345 => .12345
|
226
|
+
if(i >= 0){buf[i + offset] = ' ';}
|
217
227
|
}
|
218
228
|
}else{
|
219
229
|
if((*(T *)value) > -1){
|
220
230
|
int i(length - precision - 2);
|
221
|
-
|
222
|
-
if(
|
231
|
+
// -0.12345 => -.12345
|
232
|
+
if(i >= 0){buf[i + offset] = '-';}
|
233
|
+
if(--i >= 0){buf[i + offset] = ' ';}
|
223
234
|
}
|
224
235
|
}
|
225
|
-
buf.replace(offset, length, s);
|
226
|
-
return true;
|
227
236
|
}
|
237
|
+
return res;
|
228
238
|
}
|
229
239
|
static bool e(
|
230
240
|
std::string &buf, const int &offset, const int &length, void *value, const int &precision = 0, const bool &str2val = true){
|
@@ -268,6 +278,14 @@ class RINEX_Reader {
|
|
268
278
|
std::string &buf, const int &offset, const int &length, void *value, const int &opt = 0, const bool &str2val = true){
|
269
279
|
return conv_t<T, false>::d(buf, offset, length, value, opt, str2val);
|
270
280
|
}
|
281
|
+
static bool f_pure(
|
282
|
+
std::string &buf, const int &offset, const int &length, void *value, const int &precision = 0, const bool &str2val = true){
|
283
|
+
double v(*(T *)value);
|
284
|
+
bool res(
|
285
|
+
conv_t<double, false>::f_pure(buf, offset, length, &v, precision, str2val));
|
286
|
+
*(T *)value = static_cast<T>(v);
|
287
|
+
return res;
|
288
|
+
}
|
271
289
|
static bool f(
|
272
290
|
std::string &buf, const int &offset, const int &length, void *value, const int &precision = 0, const bool &str2val = true){
|
273
291
|
double v(*(T *)value);
|
@@ -2183,10 +2183,11 @@ template <typename T>
|
|
2183
2183
|
typename SBAS_SpaceNode<FloatT>::KnownSatellites::list_t
|
2184
2184
|
SBAS_SpaceNode<FloatT>::KnownSatellites::sort(T sorter){
|
2185
2185
|
static const typename SBAS_SpaceNode<FloatT>::RangingCode codes[] = {
|
2186
|
+
{120, 145, 01106, 5, "ASECNA (A-SBAS)"},
|
2186
2187
|
{121, 175, 01241, 5, "EGNOS (Eutelsat 5WB)"},
|
2187
2188
|
{122, 52, 00267, 143.5, "SPAN (INMARSAT 4F1)"},
|
2188
2189
|
{123, 21, 00232, 31.5, "EGNOS (ASTRA 5B)"},
|
2189
|
-
{124, 237, 01617, 0, "
|
2190
|
+
//{124, 237, 01617, 0, "(Reserved)"},
|
2190
2191
|
{125, 235, 01076, -16, "SDCM (Luch-5A)"},
|
2191
2192
|
{126, 886, 01764, 63.9, "EGNOS (INMARSAT 4F2)"},
|
2192
2193
|
{127, 657, 00717, 55, "GAGAN (GSAT-8)"},
|
@@ -2198,16 +2199,30 @@ typename SBAS_SpaceNode<FloatT>::KnownSatellites::list_t
|
|
2198
2199
|
{133, 603, 01731, -129, "WAAS (SES-15)"},
|
2199
2200
|
{134, 130, 00706, 91.5, "KASS (MEASAT-3D)"},
|
2200
2201
|
{135, 359, 01216, -125, "WAAS (Intelsat Galaxy 30)"},
|
2201
|
-
{136, 595, 00740, 5, "EGNOS (
|
2202
|
+
{136, 595, 00740, 5, "EGNOS (HOTBIRD 13G)"},
|
2202
2203
|
{137, 68, 01007, 127, "MSAS (QZS-3)"},
|
2203
2204
|
{138, 386, 00450, 107.3, "WAAS (ANIK F1R)"},
|
2205
|
+
//{139, 797, 00305, 0, "MSAS (QZS-7)"},
|
2204
2206
|
{140, 456, 01653, 95, "SDCM (Luch-5V)"},
|
2205
2207
|
{141, 499, 01411, 167, "SDCM (Luch-5A)"},
|
2208
|
+
//{142, 883, 01644, 0, "(Unallocated)"},
|
2206
2209
|
{143, 307, 01312, 110.5, "BDSBAS (G3)"},
|
2207
2210
|
{144, 127, 01060, 80, "BDSBAS (G2)"},
|
2208
|
-
{
|
2211
|
+
//{145, 211, 01560, 0, "(Unallocated)"},
|
2212
|
+
//{146, 121, 00035, 0, "(Unallocated)"},
|
2213
|
+
{147, 118, 00355, 5, "ASECNA (A-SBAS)"},
|
2209
2214
|
{148, 163, 00335, -24.8, "ASAL (ALCOMSAT-1)"},
|
2210
|
-
}
|
2215
|
+
//{149, 628, 01254, 0, "(Unallocated)"},
|
2216
|
+
//{150, 853, 01041, 0, "EGNOS"},
|
2217
|
+
//{151, 484, 00142, 0, "(Unallocated)"},
|
2218
|
+
//{152, 289, 01641, 0, "(Unallocated)"},
|
2219
|
+
//{153, 811, 01504, 0, "(Unallocated)"},
|
2220
|
+
//{154, 202, 00751, 0, "(Unallocated)"},
|
2221
|
+
//{155, 1021, 01774, 0, "(Unallocated)"},
|
2222
|
+
//{156, 463, 00107, 0, "(Unallocated)"},
|
2223
|
+
//{157, 568, 01153, 0, "(Unallocated)"},
|
2224
|
+
//{158, 904, 01542, 0, "(Unallocated)"},
|
2225
|
+
}; ///< @see https://www.gps.gov/technical/prn-codes/L1-CA-PRN-code-assignments-2021-Jun.pdf
|
2211
2226
|
list_t res;
|
2212
2227
|
res.reserve(sizeof(codes) / sizeof(codes[0]));
|
2213
2228
|
for(unsigned int i(0); i < sizeof(codes) / sizeof(codes[0]); ++i){
|
@@ -73,7 +73,6 @@ class SBAS_SinglePositioning : public SolverBaseT {
|
|
73
73
|
|
74
74
|
typedef SBAS_SpaceNode<float_t> space_node_t;
|
75
75
|
inheritate_type(gps_time_t);
|
76
|
-
typedef typename space_node_t::Satellite satellite_t;
|
77
76
|
|
78
77
|
inheritate_type(xyz_t);
|
79
78
|
inheritate_type(enu_t);
|
@@ -81,6 +80,7 @@ class SBAS_SinglePositioning : public SolverBaseT {
|
|
81
80
|
inheritate_type(pos_t);
|
82
81
|
|
83
82
|
typedef typename base_t::measurement_t measurement_t;
|
83
|
+
typedef typename base_t::satellite_t satellite_t;
|
84
84
|
typedef typename base_t::range_error_t range_error_t;
|
85
85
|
typedef typename base_t::range_corrector_t range_corrector_t;
|
86
86
|
typedef typename base_t::range_correction_t range_correction_t;
|
@@ -92,11 +92,52 @@ class SBAS_SinglePositioning : public SolverBaseT {
|
|
92
92
|
SBAS_SinglePositioning_Options<float_t>, base_t> options_t;
|
93
93
|
|
94
94
|
protected:
|
95
|
-
const space_node_t &_space_node;
|
96
95
|
SBAS_SinglePositioning_Options<float_t> _options;
|
97
96
|
|
98
97
|
public:
|
99
|
-
|
98
|
+
struct satellites_t {
|
99
|
+
const void *impl;
|
100
|
+
satellite_t (*impl_select)(const void *, const prn_t &, const gps_time_t &);
|
101
|
+
inline satellite_t select(const prn_t &prn, const gps_time_t &receiver_time) const {
|
102
|
+
return impl_select(impl, prn, receiver_time);
|
103
|
+
}
|
104
|
+
static satellite_t select_broadcast(
|
105
|
+
const void *ptr, const prn_t &prn, const gps_time_t &receiver_time){
|
106
|
+
const typename space_node_t::satellites_t &sats(
|
107
|
+
reinterpret_cast<const space_node_t *>(ptr)->satellites());
|
108
|
+
const typename space_node_t::satellites_t::const_iterator it_sat(sats.find(prn));
|
109
|
+
if((it_sat == sats.end()) // has ephemeris?
|
110
|
+
|| (!it_sat->second.ephemeris().is_valid(receiver_time))){ // valid ephemeris?
|
111
|
+
return satellite_t::unavailable();
|
112
|
+
}
|
113
|
+
struct impl_t {
|
114
|
+
static inline const typename space_node_t::Satellite &sat(const void *ptr) {
|
115
|
+
return *reinterpret_cast<const typename space_node_t::Satellite *>(ptr);
|
116
|
+
}
|
117
|
+
static xyz_t position(const void *ptr, const gps_time_t &t, const float_t &pseudo_range) {
|
118
|
+
return sat(ptr).ephemeris().constellation(t, pseudo_range, false).position;
|
119
|
+
}
|
120
|
+
static xyz_t velocity(const void *ptr, const gps_time_t &t, const float_t &pseudo_range) {
|
121
|
+
return sat(ptr).ephemeris().constellation(t, pseudo_range, true).velocity;
|
122
|
+
}
|
123
|
+
static float_t clock_error(const void *ptr, const gps_time_t &t, const float_t &pseudo_range) {
|
124
|
+
// Clock correction is taken into account in position()
|
125
|
+
return 0;
|
126
|
+
}
|
127
|
+
static float_t clock_error_dot(const void *ptr, const gps_time_t &t, const float_t &pseudo_range) {
|
128
|
+
// Clock rate error is taken in account in velocity()
|
129
|
+
return 0;
|
130
|
+
}
|
131
|
+
};
|
132
|
+
satellite_t res = {
|
133
|
+
&(it_sat->second),
|
134
|
+
impl_t::position, impl_t::velocity,
|
135
|
+
impl_t::clock_error, impl_t::clock_error_dot};
|
136
|
+
return res;
|
137
|
+
}
|
138
|
+
satellites_t(const space_node_t &sn)
|
139
|
+
: impl(&sn), impl_select(select_broadcast) {}
|
140
|
+
} satellites;
|
100
141
|
|
101
142
|
struct ionospheric_sbas_t : public range_corrector_t {
|
102
143
|
const space_node_t &space_node;
|
@@ -155,7 +196,8 @@ class SBAS_SinglePositioning : public SolverBaseT {
|
|
155
196
|
}
|
156
197
|
|
157
198
|
SBAS_SinglePositioning(const space_node_t &sn)
|
158
|
-
: base_t(),
|
199
|
+
: base_t(), _options(available_options(options_t())),
|
200
|
+
satellites(sn),
|
159
201
|
ionospheric_sbas(sn), tropospheric_sbas() {
|
160
202
|
|
161
203
|
// default ionospheric correction: Broadcasted IGP.
|
@@ -168,25 +210,17 @@ class SBAS_SinglePositioning : public SolverBaseT {
|
|
168
210
|
~SBAS_SinglePositioning(){}
|
169
211
|
|
170
212
|
/**
|
171
|
-
*
|
213
|
+
* Select satellite by using PRN and time
|
172
214
|
*
|
173
215
|
* @param prn satellite number
|
174
216
|
* @param receiver_time receiver time
|
175
|
-
* @return (
|
176
|
-
* otherwise NULL.
|
217
|
+
* @return (satellite_t) If available, satellite.is_available() returning true is returned.
|
177
218
|
*/
|
178
|
-
|
179
|
-
const
|
219
|
+
satellite_t select_satellite(
|
220
|
+
const prn_t &prn,
|
180
221
|
const gps_time_t &receiver_time) const {
|
181
|
-
|
182
|
-
|
183
|
-
const typename space_node_t::satellites_t::const_iterator it_sat(sats.find(prn));
|
184
|
-
if((it_sat == sats.end()) // has ephemeris?
|
185
|
-
|| (!it_sat->second.ephemeris().is_valid(receiver_time))){ // valid ephemeris?
|
186
|
-
return NULL;
|
187
|
-
}
|
188
|
-
|
189
|
-
return &(it_sat->second);
|
222
|
+
if(_options.exclude_prn[prn]){return satellite_t::unavailable();}
|
223
|
+
return satellites.select(prn, receiver_time);
|
190
224
|
}
|
191
225
|
|
192
226
|
/**
|
@@ -210,33 +244,28 @@ class SBAS_SinglePositioning : public SolverBaseT {
|
|
210
244
|
|
211
245
|
relative_property_t res = {0};
|
212
246
|
|
213
|
-
if(_options.exclude_prn[prn]){return res;}
|
214
|
-
|
215
247
|
float_t range;
|
216
248
|
range_error_t range_error;
|
217
249
|
if(!this->range(measurement, range, &range_error)){
|
218
250
|
return res; // If no range entry, return with weight = 0
|
219
251
|
}
|
220
252
|
|
221
|
-
|
222
|
-
if(!sat){return res;} // If satellite is unavailable, return with weight = 0
|
253
|
+
satellite_t sat(select_satellite(prn, time_arrival));
|
254
|
+
if(!sat.is_available()){return res;} // If satellite is unavailable, return with weight = 0
|
223
255
|
|
224
256
|
///< The following procedure is based on Appendix.S with modification
|
225
257
|
|
226
258
|
range -= receiver_error;
|
227
259
|
|
228
|
-
// Clock correction
|
229
|
-
|
230
|
-
|
231
|
-
|
260
|
+
// Clock error correction
|
261
|
+
range += ((range_error.unknown_flag & range_error_t::SATELLITE_CLOCK)
|
262
|
+
? (sat.clock_error(time_arrival, range) * GPS_SpaceNode<float_t>::light_speed)
|
263
|
+
: range_error.value[range_error_t::SATELLITE_CLOCK]);
|
232
264
|
|
233
265
|
// TODO WAAS long term clock correction (2.1.1.4.11)
|
234
266
|
|
235
|
-
// Calculate satellite position
|
236
|
-
|
237
|
-
sat->ephemeris().constellation(time_arrival, range));
|
238
|
-
|
239
|
-
const xyz_t &sat_pos(sat_pos_vel.position);
|
267
|
+
// Calculate satellite position
|
268
|
+
xyz_t sat_pos(sat.position(time_arrival, range));
|
240
269
|
float_t geometric_range(usr_pos.xyz.dist(sat_pos));
|
241
270
|
|
242
271
|
// Calculate residual with Sagnac correction (A.4.4.11)
|
@@ -283,24 +312,15 @@ class SBAS_SinglePositioning : public SolverBaseT {
|
|
283
312
|
|
284
313
|
res.range_corrected = range;
|
285
314
|
|
286
|
-
xyz_t rel_vel(
|
315
|
+
xyz_t rel_vel(sat.velocity(time_arrival, range) - usr_vel); // Calculate velocity
|
287
316
|
|
288
|
-
// Note: clock rate error is already accounted for in constellation()
|
289
317
|
res.rate_relative_neg = res.los_neg[0] * rel_vel.x()
|
290
318
|
+ res.los_neg[1] * rel_vel.y()
|
291
|
-
+ res.los_neg[2] * rel_vel.z()
|
319
|
+
+ res.los_neg[2] * rel_vel.z()
|
320
|
+
+ sat.clock_error_dot(time_arrival, range) * GPS_SpaceNode<float_t>::light_speed;
|
292
321
|
|
293
322
|
return res;
|
294
323
|
}
|
295
|
-
|
296
|
-
xyz_t *satellite_position(
|
297
|
-
const prn_t &prn,
|
298
|
-
const gps_time_t &time,
|
299
|
-
xyz_t &res) const {
|
300
|
-
|
301
|
-
const satellite_t *sat(is_available(prn, time));
|
302
|
-
return sat ? &(res = sat->ephemeris().constellation(time).position) : NULL;
|
303
|
-
}
|
304
324
|
};
|
305
325
|
|
306
326
|
#endif /* __SBAS_SOLVER_H__ */
|
@@ -1104,7 +1104,7 @@ struct GPS_RangeCorrector
|
|
1104
1104
|
%ignore glonass;
|
1105
1105
|
%ignore select_solver;
|
1106
1106
|
%ignore relative_property;
|
1107
|
-
%ignore
|
1107
|
+
%ignore select_satellite;
|
1108
1108
|
%ignore update_position_solution;
|
1109
1109
|
%ignore user_correctors_t;
|
1110
1110
|
%ignore user_correctors;
|
@@ -1201,47 +1201,17 @@ struct GPS_RangeCorrector
|
|
1201
1201
|
return super_t::update_position_solution(geomat, res);
|
1202
1202
|
}
|
1203
1203
|
template <>
|
1204
|
-
GPS_Solver<FloatT>::base_t::
|
1204
|
+
GPS_Solver<FloatT>::base_t::satellite_t GPS_Solver<FloatT>::select_satellite(
|
1205
1205
|
const GPS_Solver<FloatT>::base_t::prn_t &prn,
|
1206
|
-
const GPS_Solver<FloatT>::base_t::gps_time_t &time
|
1207
|
-
|
1208
|
-
|
1209
|
-
select_solver(prn).satellite_position(prn, time, buf));
|
1206
|
+
const GPS_Solver<FloatT>::base_t::gps_time_t &time) const {
|
1207
|
+
GPS_Solver<FloatT>::base_t::satellite_t res(
|
1208
|
+
select_solver(prn).select_satellite(prn, time));
|
1210
1209
|
#ifdef SWIGRUBY
|
1211
|
-
|
1212
|
-
static const VALUE key(ID2SYM(rb_intern("
|
1210
|
+
if(!res.is_available()){
|
1211
|
+
static const VALUE key(ID2SYM(rb_intern("relative_property")));
|
1213
1212
|
VALUE hook(rb_hash_lookup(hooks, key));
|
1214
|
-
if(NIL_P(hook)){
|
1215
|
-
|
1216
|
-
SWIG_From(int)(prn), // prn
|
1217
|
-
SWIG_NewPointerObj( // time
|
1218
|
-
new base_t::gps_time_t(time), $descriptor(GPS_Time<FloatT> *), SWIG_POINTER_OWN),
|
1219
|
-
(res // position (internally calculated)
|
1220
|
-
? SWIG_NewPointerObj(res, $descriptor(System_XYZ<FloatT, WGS84> *), 0)
|
1221
|
-
: Qnil)};
|
1222
|
-
VALUE res_hook(proc_call_throw_if_error(hook, sizeof(values) / sizeof(values[0]), values));
|
1223
|
-
if(NIL_P(res_hook)){ // unknown position
|
1224
|
-
res = NULL;
|
1225
|
-
break;
|
1226
|
-
}else if(RB_TYPE_P(res_hook, T_ARRAY) && (RARRAY_LEN(res_hook) == 3)){
|
1227
|
-
int i(0);
|
1228
|
-
for(; i < 3; ++i){
|
1229
|
-
VALUE v(RARRAY_AREF(res_hook, i));
|
1230
|
-
if(!SWIG_IsOK(swig::asval(v, &buf[i]))){break;}
|
1231
|
-
}
|
1232
|
-
if(i == 3){
|
1233
|
-
res = &buf;
|
1234
|
-
break;
|
1235
|
-
}
|
1236
|
-
}else if(SWIG_IsOK(SWIG_ConvertPtr(
|
1237
|
-
res_hook, (void **)&res, $descriptor(System_XYZ<FloatT, WGS84> *), 0))){
|
1238
|
-
res = &(buf = *res);
|
1239
|
-
break;
|
1240
|
-
}
|
1241
|
-
throw std::runtime_error(
|
1242
|
-
std::string("System_XYZ or [d * 3] is expected (d: " %str(FloatT) "), however ")
|
1243
|
-
.append(inspect_str(res_hook)));
|
1244
|
-
}while(false);
|
1213
|
+
if(!NIL_P(hook)){res.impl = this;}
|
1214
|
+
}
|
1245
1215
|
#endif
|
1246
1216
|
return res;
|
1247
1217
|
}
|
@@ -1481,10 +1451,9 @@ struct GPS_Solver
|
|
1481
1451
|
const typename base_t::gps_time_t &time_arrival,
|
1482
1452
|
const typename base_t::pos_t &usr_pos,
|
1483
1453
|
const typename base_t::xyz_t &usr_vel) const;
|
1484
|
-
virtual typename base_t::
|
1454
|
+
virtual typename base_t::satellite_t select_satellite(
|
1485
1455
|
const typename base_t::prn_t &prn,
|
1486
|
-
const typename base_t::gps_time_t &time
|
1487
|
-
typename base_t::xyz_t &res) const;
|
1456
|
+
const typename base_t::gps_time_t &time) const;
|
1488
1457
|
virtual bool update_position_solution(
|
1489
1458
|
const typename base_t::geometric_matrices_t &geomat,
|
1490
1459
|
typename base_t::user_pvt_t &res) const;
|
@@ -375,22 +375,6 @@ __RINEX_OBS_TEXT__
|
|
375
375
|
expect(mat).to respond_to(:resize!)
|
376
376
|
}
|
377
377
|
}
|
378
|
-
solver.hooks[:satellite_position] = proc{
|
379
|
-
i = 0
|
380
|
-
proc{|prn, time, pos|
|
381
|
-
expect(input[:measurement]).to include(prn)
|
382
|
-
expect(pos).to be_a_kind_of(Coordinate::XYZ).or eq(nil)
|
383
|
-
# System_XYZ or [x,y,z] or nil(= unknown position) are acceptable
|
384
|
-
case (i += 1) % 5
|
385
|
-
when 0
|
386
|
-
nil
|
387
|
-
when 1
|
388
|
-
pos.to_a
|
389
|
-
else
|
390
|
-
pos
|
391
|
-
end
|
392
|
-
}
|
393
|
-
}.call
|
394
378
|
pvt = solver.solve(
|
395
379
|
input[:measurement].collect{|prn, items|
|
396
380
|
items.collect{|k, v| [prn, k, v]}
|
File without changes
|
data/lib/gps_pvt/receiver.rb
CHANGED
@@ -4,6 +4,7 @@ Receiver class to be an top level interface to a user
|
|
4
4
|
=end
|
5
5
|
|
6
6
|
require_relative 'GPS'
|
7
|
+
require_relative 'util'
|
7
8
|
|
8
9
|
module GPS_PVT
|
9
10
|
class Receiver
|
@@ -547,22 +548,24 @@ class Receiver
|
|
547
548
|
$stderr.puts ", found packets are %s"%[ubx_kind.inspect]
|
548
549
|
end
|
549
550
|
|
550
|
-
def parse_rinex_nav(
|
551
|
+
def parse_rinex_nav(src)
|
552
|
+
fname = Util::get_txt(src)
|
551
553
|
items = [
|
552
554
|
@solver.gps_space_node,
|
553
555
|
@solver.sbas_space_node,
|
554
556
|
@solver.glonass_space_node,
|
555
557
|
].inject(0){|res, sn|
|
556
558
|
loaded_items = sn.send(:read, fname)
|
557
|
-
raise "Format error! (Not RINEX) #{
|
559
|
+
raise "Format error! (Not RINEX) #{src}" if loaded_items < 0
|
558
560
|
res + loaded_items
|
559
561
|
}
|
560
|
-
$stderr.puts "Read RINEX NAV file (%s): %d items."%[
|
562
|
+
$stderr.puts "Read RINEX NAV file (%s): %d items."%[src, items]
|
561
563
|
end
|
562
564
|
|
563
|
-
def parse_rinex_obs(
|
565
|
+
def parse_rinex_obs(src, &b)
|
566
|
+
fname = Util::get_txt(src)
|
564
567
|
after_run = b || proc{|pvt| puts pvt.to_s if pvt}
|
565
|
-
$stderr.print "Reading RINEX observation file (%s)"%[
|
568
|
+
$stderr.print "Reading RINEX observation file (%s)"%[src]
|
566
569
|
types = nil
|
567
570
|
glonass_freq = nil
|
568
571
|
count = 0
|
data/lib/gps_pvt/util.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'open-uri'
|
2
|
+
require 'tempfile'
|
3
|
+
require 'uri'
|
4
|
+
require 'zlib'
|
5
|
+
|
6
|
+
module GPS_PVT
|
7
|
+
module Util
|
8
|
+
class << self
|
9
|
+
def inflate(src)
|
10
|
+
Zlib::GzipReader.send(*(src.kind_of?(IO) ? [:new, src] : [:open, src]))
|
11
|
+
end
|
12
|
+
def get_txt(fname_or_uri)
|
13
|
+
is_uri = fname_or_uri.kind_of?(URI)
|
14
|
+
((is_uri && (RUBY_VERSION >= "2.5.0")) ? URI : Kernel) \
|
15
|
+
.send(:open, fname_or_uri){|src|
|
16
|
+
is_gz = (src.content_type =~ /gzip/) if is_uri
|
17
|
+
is_gz ||= (fname_or_uri.to_s =~ /\.gz$/)
|
18
|
+
is_file = src.kind_of?(File) || src.kind_of?(Tempfile)
|
19
|
+
|
20
|
+
return src.path if ((!is_gz) and is_file)
|
21
|
+
|
22
|
+
Tempfile::open(File::basename($0, '.*')){|dst|
|
23
|
+
dst.binmode
|
24
|
+
dst.write((is_gz ? inflate(is_file ? src.path : src) : src).read)
|
25
|
+
dst.rewind
|
26
|
+
dst.path
|
27
|
+
}
|
28
|
+
}
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
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.5.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-
|
11
|
+
date: 2022-05-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|
@@ -93,11 +93,12 @@ files:
|
|
93
93
|
- ext/ninja-scan-light/tool/swig/spec/GPS_spec.rb
|
94
94
|
- ext/ninja-scan-light/tool/swig/spec/SylphideMath_spec.rb
|
95
95
|
- gps_pvt.gemspec
|
96
|
+
- gps_pvt.rbs
|
96
97
|
- lib/gps_pvt.rb
|
97
98
|
- lib/gps_pvt/receiver.rb
|
98
99
|
- lib/gps_pvt/ubx.rb
|
100
|
+
- lib/gps_pvt/util.rb
|
99
101
|
- lib/gps_pvt/version.rb
|
100
|
-
- sig/gps_pvt.rbs
|
101
102
|
homepage: https://github.com/fenrir-naru/gps_pvt
|
102
103
|
licenses: []
|
103
104
|
metadata:
|