gps_pvt 0.4.0 → 0.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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:
|