gps_pvt 0.9.4 → 0.10.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 +9 -7
- data/Rakefile +18 -1
- data/exe/gps2ubx +12 -5
- data/exe/gps_pvt +7 -2
- data/ext/gps_pvt/GPS/GPS_wrap.cxx +837 -52
- data/ext/ninja-scan-light/tool/navigation/GLONASS_Solver.h +11 -3
- data/ext/ninja-scan-light/tool/navigation/GPS.h +2 -1
- data/ext/ninja-scan-light/tool/navigation/GPS_Solver.h +20 -16
- data/ext/ninja-scan-light/tool/navigation/GPS_Solver_Base.h +84 -46
- data/ext/ninja-scan-light/tool/navigation/GPS_Solver_RAIM.h +2 -1
- data/ext/ninja-scan-light/tool/navigation/SBAS_Solver.h +10 -2
- data/ext/ninja-scan-light/tool/swig/GPS.i +76 -5
- data/ext/ninja-scan-light/tool/swig/spec/GPS_spec.rb +7 -7
- data/gps_pvt.gemspec +3 -2
- data/lib/gps_pvt/asn1/asn1.rb +888 -0
- data/lib/gps_pvt/asn1/asn1.y +903 -0
- data/lib/gps_pvt/asn1/per.rb +182 -0
- data/lib/gps_pvt/receiver/agps.rb +31 -0
- data/lib/gps_pvt/receiver/extension.rb +21 -0
- data/lib/gps_pvt/receiver/rtcm3.rb +2 -1
- data/lib/gps_pvt/receiver.rb +28 -20
- data/lib/gps_pvt/rtcm3.rb +17 -32
- data/lib/gps_pvt/supl.rb +567 -0
- data/lib/gps_pvt/ubx.rb +15 -0
- data/lib/gps_pvt/upl/LPP-V17_5_0-Release17.asn +6441 -0
- data/lib/gps_pvt/upl/RRLP-V17_0_0-Release17.asn +2780 -0
- data/lib/gps_pvt/upl/ULP-V2_0_6-20200720-D.asn +2185 -0
- data/lib/gps_pvt/upl/upl.json.gz +0 -0
- data/lib/gps_pvt/upl/upl.rb +99 -0
- data/lib/gps_pvt/util.rb +1 -0
- data/lib/gps_pvt/version.rb +1 -1
- metadata +26 -2
@@ -0,0 +1,182 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
|
3
|
+
module GPS_PVT
|
4
|
+
|
5
|
+
# @see ISO/IEC 8825-2:2003(E)
|
6
|
+
# @see http://www5d.biglobe.ne.jp/~stssk/asn1/per.html
|
7
|
+
module PER
|
8
|
+
module Basic_Unaligned
|
9
|
+
module Encoder
|
10
|
+
class <<self
|
11
|
+
def non_negative_binary_integer2(v, bits) # 10.3
|
12
|
+
"%0#{bits}b" % v
|
13
|
+
end
|
14
|
+
def non_negative_binary_integer(v, align = 1) # 10.3
|
15
|
+
non_negative_binary_integer2(
|
16
|
+
v, (Math::log2(v + 1) / align).ceil * align)
|
17
|
+
end
|
18
|
+
def twos_complement_binary_integer(v) # 10.4
|
19
|
+
if v >= 0 then
|
20
|
+
bits = ((Math::log2(v + 1) + 1) / 8).ceil * 8
|
21
|
+
"%0#{bits}b" % v
|
22
|
+
else
|
23
|
+
bits = ((Math::log2(-v) + 1) / 8).ceil * 8 - 1
|
24
|
+
"1%0#{bits}b" % (v + (1 << bits))
|
25
|
+
end
|
26
|
+
end
|
27
|
+
def constrainted_whole_number2(v, v_min, v_max) # 10.5.6
|
28
|
+
non_negative_binary_integer2(
|
29
|
+
v - v_min,
|
30
|
+
Math::log2(v_max - v_min + 1).ceil)
|
31
|
+
end
|
32
|
+
def constrainted_whole_number(v, v_range) # 10.5.6
|
33
|
+
constrainted_whole_number2(v, *v_range.minmax)
|
34
|
+
end
|
35
|
+
def normally_small_non_negative_whole_number(v, *len_enc) # 10.6
|
36
|
+
if v <= 63 then
|
37
|
+
"0%06b" % v # 10.6.1
|
38
|
+
else
|
39
|
+
"1#{semi_constrained_whole_number(v, 0, *len_enc)}" # 10.6.2
|
40
|
+
end
|
41
|
+
end
|
42
|
+
def semi_constrained_whole_number(v, v_min, *len_enc) # 10.7
|
43
|
+
len_enc = :length_otherwise if len_enc.empty?
|
44
|
+
bf = non_negative_binary_integer(v - v_min, 8).scan(/.{8}/)
|
45
|
+
with_length(bf.size, *len_enc).collect{|len_str, range|
|
46
|
+
len_str + bf[range].join
|
47
|
+
}.join
|
48
|
+
end
|
49
|
+
def unconstrained_whole_number(v, *len_enc) # 10.8
|
50
|
+
len_enc = :length_otherwise if len_enc.empty?
|
51
|
+
bf = twos_complement_binary_integer(v).scan(/.{8}/)
|
52
|
+
with_length(bf.size, *len_enc).collect{|len_str, range|
|
53
|
+
len_str + bf[range].join
|
54
|
+
}.join
|
55
|
+
end
|
56
|
+
def length_constrained_whole_number(len, len_range)
|
57
|
+
if len_range.max < 65536 then # 10.9.4.1
|
58
|
+
(len_range.min == len_range.max) ?
|
59
|
+
"" :
|
60
|
+
constrainted_whole_number(len, len_range)
|
61
|
+
else
|
62
|
+
length_otherwise(len)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
def length_normally_small_length(len) # 10.9.4.2 -> 10.9.3.4
|
66
|
+
if len <= 64 then
|
67
|
+
normally_small_non_negative_whole_number(len - 1)
|
68
|
+
else
|
69
|
+
len_enc, len_remain = length_otherwise(len)
|
70
|
+
len_enc = "1#{len_enc}"
|
71
|
+
len_remain ? [len_enc, len_remain] : len_enc
|
72
|
+
end
|
73
|
+
end
|
74
|
+
def length_otherwise(len) # 10.9.4.2 -> 10.9.3.5-8
|
75
|
+
if len <= 127 then # 10.9.3.6
|
76
|
+
non_negative_binary_integer2(len, 8)
|
77
|
+
elsif len < 16384 then # 10.9.3.7
|
78
|
+
"10#{non_negative_binary_integer2(len, 14)}"
|
79
|
+
else # 10.9.3.8
|
80
|
+
q, r = len.divmod(16384)
|
81
|
+
q2 = [q, 4].min
|
82
|
+
res = "11#{non_negative_binary_integer2(q2, 6)}"
|
83
|
+
((r == 0) && (q <= 4)) ? res : [res, len - (q2 * 16384)]
|
84
|
+
end
|
85
|
+
end
|
86
|
+
def with_length(len, *len_enc)
|
87
|
+
Enumerator::new{|y|
|
88
|
+
len_str, len_remain = len_enc[0].kind_of?(Symbol) ? send(len_enc[0], len, *len_enc[1..-1]) : len_enc
|
89
|
+
loop{
|
90
|
+
if len_remain then
|
91
|
+
y << [len_str, -len..-(len_remain+1)]
|
92
|
+
else
|
93
|
+
y << [len_str, -len..-1]
|
94
|
+
break
|
95
|
+
end
|
96
|
+
len_str, len_remain = length_otherwise(len = len_remain) # fragmentation
|
97
|
+
}
|
98
|
+
}
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
module Decoder
|
103
|
+
class <<self
|
104
|
+
def non_negative_binary_integer(str, bits) # 10.3
|
105
|
+
str.slice!(0, bits).to_i(2)
|
106
|
+
end
|
107
|
+
def twos_complement_binary_integer(str, bits) # 10.4
|
108
|
+
bits -= 1
|
109
|
+
case str.slice!(0)
|
110
|
+
when '0'; 0
|
111
|
+
when '1'; -(1 << bits)
|
112
|
+
end + non_negative_binary_integer(str, bits)
|
113
|
+
end
|
114
|
+
def constrainted_whole_number2(str, v_min, v_max) # 10.5.6
|
115
|
+
non_negative_binary_integer(
|
116
|
+
str,
|
117
|
+
Math::log2(v_max - v_min + 1).ceil) + v_min
|
118
|
+
end
|
119
|
+
def constrainted_whole_number(str, v_range) # 10.5.6
|
120
|
+
constrainted_whole_number2(str, *v_range.minmax)
|
121
|
+
end
|
122
|
+
def normally_small_non_negative_whole_number(str, *len_dec) # 10.6
|
123
|
+
case str.slice!(0)
|
124
|
+
when '0'; str.slice!(0, 6).to_i(2) # 10.6.1
|
125
|
+
when '1'; semi_constrained_whole_number(str, 0, *len_dec) # 10.6.2
|
126
|
+
end
|
127
|
+
end
|
128
|
+
def semi_constrained_whole_number(str, v_min, *len_dec) # 10.7
|
129
|
+
len_dec = :length_otherwise if len_dec.empty?
|
130
|
+
v_str = with_length(str, *len_dec).collect{|len_oct|
|
131
|
+
str.slice!(0, len_oct * 8)
|
132
|
+
}.join
|
133
|
+
non_negative_binary_integer(v_str, v_str.size) + v_min
|
134
|
+
end
|
135
|
+
def unconstrained_whole_number(str, *len_dec) # 10.8
|
136
|
+
len_dec = :length_otherwise if len_dec.empty?
|
137
|
+
v_str = with_length(str, *len_dec).collect{|len_oct|
|
138
|
+
str.slice!(0, len_oct * 8)
|
139
|
+
}.join
|
140
|
+
twos_complement_binary_integer(v_str, v_str.size)
|
141
|
+
end
|
142
|
+
def length_constrained_whole_number(str, len_range)
|
143
|
+
if len_range.max < 65536 then # 10.9.4.1
|
144
|
+
(len_range.min == len_range.max) ?
|
145
|
+
len_range.min :
|
146
|
+
constrainted_whole_number(str, len_range)
|
147
|
+
else
|
148
|
+
length_otherwise(str)
|
149
|
+
end
|
150
|
+
end
|
151
|
+
def length_normally_small_length(str) # 10.9.4.2 -> 10.9.3.4
|
152
|
+
case str.slice!(0)
|
153
|
+
when '0'; str.slice!(0, 6).to_i(2) + 1
|
154
|
+
when '1'; length_otherwise(str)
|
155
|
+
end
|
156
|
+
end
|
157
|
+
def length_otherwise(str) # 10.9.4.2 -> 10.9.3.5-8
|
158
|
+
case str.slice!(0)
|
159
|
+
when '0'; non_negative_binary_integer(str, 7) # 10.9.3.6
|
160
|
+
when '1';
|
161
|
+
case str.slice!(0)
|
162
|
+
when '0'; non_negative_binary_integer(str, 14) # 10.9.3.7
|
163
|
+
when '1'; [non_negative_binary_integer(str, 6) * (1 << 14), true] # 10.9.3.8
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
167
|
+
def with_length(str, *len_dec)
|
168
|
+
Enumerator::new{|y|
|
169
|
+
len, cnt = len_dec[0].kind_of?(Symbol) ? send(len_dec[0], str, *len_dec[1..-1]) : len_dec
|
170
|
+
loop{
|
171
|
+
y << len
|
172
|
+
break unless cnt
|
173
|
+
len, cnt = length_otherwise(str) # fragmentation
|
174
|
+
}
|
175
|
+
}
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
=begin
|
2
|
+
AGPS handler for receiver
|
3
|
+
=end
|
4
|
+
|
5
|
+
module GPS_PVT
|
6
|
+
class Receiver
|
7
|
+
def parse_supl(src, opt = {}, &b)
|
8
|
+
$stderr.print "A-GPS (%s) "%[src]
|
9
|
+
opt = {
|
10
|
+
:interval => 60 * 10, # 10 min.
|
11
|
+
}.merge(opt)
|
12
|
+
require_relative '../supl'
|
13
|
+
src_io = Util::open(src)
|
14
|
+
while data = src_io.get_assisted_data
|
15
|
+
data.ephemeris.each{|eph|
|
16
|
+
target = case eph
|
17
|
+
when GPS::Ephemeris; @solver.gps_space_node
|
18
|
+
when GPS::Ephemeris_GLONASS; @solver.glonass_space_node
|
19
|
+
when GPS::Ephemeris_SBAS; @solver.sbas_space_node
|
20
|
+
else nil
|
21
|
+
end
|
22
|
+
critical{target.register_ephemeris(eph.svid, eph)} if target
|
23
|
+
} if data.respond_to?(:ephemeris)
|
24
|
+
critical{
|
25
|
+
@solver.gps_space_node.update_iono_utc(data.iono_utc)
|
26
|
+
} if data.respond_to?(:iono_utc)
|
27
|
+
sleep(opt[:interval])
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -57,4 +57,25 @@ class Receiver
|
|
57
57
|
}
|
58
58
|
end
|
59
59
|
end
|
60
|
+
|
61
|
+
module GPS
|
62
|
+
|
63
|
+
[
|
64
|
+
Ionospheric_UTC_Parameters,
|
65
|
+
Ephemeris, Ephemeris_SBAS, Ephemeris_GLONASS,
|
66
|
+
].each{|cls|
|
67
|
+
cls.class_eval{
|
68
|
+
proc{|func_list|
|
69
|
+
func_list.select!{|func|
|
70
|
+
(/=$/ !~ func.to_s) && func_list.include?("#{func}=".to_sym)
|
71
|
+
}
|
72
|
+
define_method(:to_hash){
|
73
|
+
Hash[*(func_list.collect{|func|
|
74
|
+
[func, send(func)]
|
75
|
+
}.flatten(1))]
|
76
|
+
}
|
77
|
+
}.call(instance_methods(false))
|
78
|
+
}
|
79
|
+
}
|
80
|
+
end
|
60
81
|
end
|
@@ -195,7 +195,7 @@ class Receiver
|
|
195
195
|
when 1020
|
196
196
|
params = parsed.params
|
197
197
|
eph = GPS::Ephemeris_GLONASS::new
|
198
|
-
|
198
|
+
eph.F_T = 10 # [m], default to be overwritten
|
199
199
|
params.each{|k, v|
|
200
200
|
next if [:P3, :NA, :N_4].include?(k)
|
201
201
|
eph.send("#{k}=".to_sym, v)
|
@@ -205,6 +205,7 @@ class Receiver
|
|
205
205
|
? date_src \
|
206
206
|
: [(ref_time + 3 * 60 * 60).c_tm(leap_sec)])) # UTC -> Moscow time
|
207
207
|
}.call([:N_4, :NA].collect{|k| params[k]})
|
208
|
+
eph.N_T = params[:NA] || eph.NA unless params[:N_T] # N_T is available only for GLONASS-M
|
208
209
|
eph.rehash(leap_sec)
|
209
210
|
critical{
|
210
211
|
@solver.glonass_space_node.register_ephemeris(eph.svid, eph)
|
data/lib/gps_pvt/receiver.rb
CHANGED
@@ -38,20 +38,21 @@ class Receiver
|
|
38
38
|
] + (pvt.rel_ENU.to_a rescue [nil] * 3)
|
39
39
|
}
|
40
40
|
]] + [proc{
|
41
|
-
labels = [:g, :p, :h, :v, :t].collect{|k| "#{k}dop".to_sym}
|
41
|
+
labels = [:g, :p, :h, :v, :t].collect{|k| "#{k}dop".to_sym} \
|
42
|
+
+ [:h, :v, :t].collect{|k| "#{k}sigma".to_sym}
|
42
43
|
[
|
43
44
|
labels,
|
44
45
|
proc{|pvt|
|
45
|
-
next [nil] *
|
46
|
+
next [nil] * 8 unless pvt.position_solved?
|
46
47
|
labels.collect{|k| pvt.send(k)}
|
47
48
|
}
|
48
49
|
]
|
49
50
|
}.call] + [[
|
50
|
-
[:v_north, :v_east, :v_down, :receiver_clock_error_dot_ms],
|
51
|
+
[:v_north, :v_east, :v_down, :receiver_clock_error_dot_ms, :vel_sigma],
|
51
52
|
proc{|pvt|
|
52
53
|
next [nil] * 4 unless pvt.velocity_solved?
|
53
54
|
[:north, :east, :down].collect{|k| pvt.velocity.send(k)} \
|
54
|
-
+ [pvt.receiver_error_rate]
|
55
|
+
+ [pvt.receiver_error_rate, pvt.vel_sigma]
|
55
56
|
}
|
56
57
|
]] + [
|
57
58
|
[:used_satellites, proc{|pvt| pvt.used_satellites}],
|
@@ -135,7 +136,7 @@ class Receiver
|
|
135
136
|
opt[:satellites].collect{|prn, label|
|
136
137
|
pr, rate, doppler, freq = keys.collect{|k| meas_hash[prn][k] rescue nil}
|
137
138
|
freq ||= GPS::SpaceNode.L1_Frequency
|
138
|
-
[pr, rate || ((doppler * GPS::SpaceNode::light_speed / freq) rescue nil)]
|
139
|
+
[pr, rate || ((-doppler * GPS::SpaceNode::light_speed / freq) rescue nil)]
|
139
140
|
}
|
140
141
|
}
|
141
142
|
]]
|
@@ -324,25 +325,31 @@ class Receiver
|
|
324
325
|
end
|
325
326
|
|
326
327
|
GPS::Measurement.class_eval{
|
327
|
-
proc{
|
328
|
-
key2sym = []
|
329
|
-
GPS::Measurement.constants.each{|k|
|
330
|
-
i = GPS::Measurement.const_get(k)
|
331
|
-
key2sym[i] = k if i.kind_of?(Integer)
|
332
|
-
}
|
333
|
-
define_method(:to_a2){
|
334
|
-
to_a.collect{|prn, k, v| [prn, key2sym[k] || k, v]}
|
335
|
-
}
|
336
|
-
define_method(:to_hash2){
|
337
|
-
Hash[*(to_hash.collect{|prn, k_v|
|
338
|
-
[prn, Hash[*(k_v.collect{|k, v| [key2sym[k] || k, v]}.flatten(1))]]
|
339
|
-
}.flatten(1))]
|
340
|
-
}
|
341
|
-
}.call
|
342
328
|
add_orig = instance_method(:add)
|
343
329
|
define_method(:add){|prn, key, value|
|
344
330
|
add_orig.bind(self).call(prn, key.kind_of?(Symbol) ? GPS::Measurement.const_get(key) : key, value)
|
345
331
|
}
|
332
|
+
key2sym = GPS::Measurement.constants.inject([]){|res, k|
|
333
|
+
res[GPS::Measurement.const_get(k)] = k if /^L\d/ =~ k.to_s
|
334
|
+
res
|
335
|
+
}
|
336
|
+
define_method(:to_a2){
|
337
|
+
collect{|prn, k, v| [prn, key2sym[k] || k, v]}
|
338
|
+
}
|
339
|
+
cl_hash2 = Class::new(Hash){
|
340
|
+
define_method(:to_meas){
|
341
|
+
GPS::Measurement::new.tap{|res|
|
342
|
+
each{|prn, k_v|
|
343
|
+
k_v.each{|k, v| res.add(prn, k, v)}
|
344
|
+
}
|
345
|
+
}
|
346
|
+
}
|
347
|
+
}
|
348
|
+
define_method(:to_hash2){
|
349
|
+
cl_hash2::new.tap{|res|
|
350
|
+
each{|prn, k, v| (res[prn] ||= {})[key2sym[k] || k] = v}
|
351
|
+
}
|
352
|
+
}
|
346
353
|
}
|
347
354
|
|
348
355
|
def run(meas, t_meas, ref_pos = @base_station)
|
@@ -724,4 +731,5 @@ end
|
|
724
731
|
end
|
725
732
|
|
726
733
|
require_relative 'receiver/rtcm3'
|
734
|
+
require_relative 'receiver/agps'
|
727
735
|
require_relative 'receiver/extension'
|
data/lib/gps_pvt/rtcm3.rb
CHANGED
@@ -104,12 +104,7 @@ class RTCM3
|
|
104
104
|
57 => 16,
|
105
105
|
71 => 8,
|
106
106
|
76 => 10,
|
107
|
-
77 =>
|
108
|
-
idx2meter = [
|
109
|
-
2.40, 3.40, 4.85, 6.85, 9.65, 13.65, 24.00, 48.00,
|
110
|
-
96.00, 192.00, 384.00, 768.00, 1536.00, 3072.00, 6144.00]
|
111
|
-
[4, proc{|v| (v >= idx2meter.size) ? (idx2meter[-1] * 2) : idx2meter[v]}]
|
112
|
-
}.call, # [m]
|
107
|
+
77 => 4,
|
113
108
|
78 => 2,
|
114
109
|
79 => num_gen.call(14, Rational(sc2rad, 1 << 43)), # [rad/s]
|
115
110
|
81 => unum_gen.call(16, 1 << 4), # [sec]
|
@@ -137,7 +132,7 @@ class RTCM3
|
|
137
132
|
103 => 1,
|
138
133
|
104 => 1,
|
139
134
|
105 => 1,
|
140
|
-
106 =>
|
135
|
+
106 => 2,
|
141
136
|
107 => [12, proc{|v|
|
142
137
|
hh, mm, ss = [v >> 7, (v & 0x7E) >> 1, (v & 0x1) > 0 ? 30 : 0]
|
143
138
|
hh * 3600 + mm * 60 + ss # [sec]
|
@@ -156,15 +151,13 @@ class RTCM3
|
|
156
151
|
125 => num_sign_gen.call(5, Rational(1, 1 << 30)), # [sec], (M)
|
157
152
|
126 => 5, # [day]
|
158
153
|
127 => 1, # (M)
|
159
|
-
128 =>
|
160
|
-
|
161
|
-
}], # [m] (M)
|
162
|
-
129 => 11, # [day]
|
154
|
+
128 => 4, # (M)
|
155
|
+
129 => invalidate.call(unum_gen.call(11), 0), # [day]
|
163
156
|
130 => 2, # 1 => GLONASS-M, (M) fields are active
|
164
157
|
131 => 1,
|
165
|
-
132 => 11, # [day]
|
158
|
+
132 => invalidate.call(unum_gen.call(11), 0), # [day]
|
166
159
|
133 => num_sign_gen.call(32, Rational(1, 1 << 31)), # [sec]
|
167
|
-
134 => 5, # [4year], (M)
|
160
|
+
134 => invalidate.call(unum_gen.call(5), 0), # [4year], (M)
|
168
161
|
135 => num_sign_gen.call(22, Rational(1, 1 << 30)), # [sec], (M)
|
169
162
|
136 => 1, # (M)
|
170
163
|
137 => 1,
|
@@ -247,9 +240,11 @@ class RTCM3
|
|
247
240
|
1013 => [2, 3, 51, 52, 53, 54],
|
248
241
|
1019 => [2, 9, (76..79).to_a, 71, (81..103).to_a, 137].flatten, # 488 bits @see Table 3.5-21
|
249
242
|
1020 => [2, 38, 40, (104..136).to_a].flatten, # 360 bits @see Table 3.5-21
|
243
|
+
# @see BNC Ntrip client DecodeSBASEphemeris() of RTCM3Decorder.cpp
|
244
|
+
# https://software.rtcm-ntrip.org/browser/ntrip/trunk/BNC/src/RTCM3/RTCM3Decoder.cpp
|
250
245
|
1043 => [2] + [:prn, :iodn, :tod, :ura,
|
251
246
|
[:xy] * 2, :z, [:dxy] * 2, :dz, [:ddxy] * 2, :ddz,
|
252
|
-
:agf0, :agf1].flatten.collect{|k| "SBAS_#{k}".to_sym},
|
247
|
+
:agf0, :agf1].flatten.collect{|k| "SBAS_#{k}".to_sym},
|
253
248
|
1044 => [2, (429..457).to_a].flatten, # 485 bits
|
254
249
|
1070..1229 => [2, [:uint, 12], [:uint, 30], 393], # 55 bits part of messages will be overwritten
|
255
250
|
1071..1077 => [2, 3, 4, 393, 409, [1, 7], 411, 412, 417, 418, 394, 395], # 169 bits @see Table 3.5-78
|
@@ -311,7 +306,7 @@ class RTCM3
|
|
311
306
|
end
|
312
307
|
end
|
313
308
|
module GPS_Ephemeris
|
314
|
-
KEY2IDX = {:svid => 1, :WN => 2, :
|
309
|
+
KEY2IDX = {:svid => 1, :WN => 2, :URA_index => 3, :dot_i0 => 5, :iode => 6, :t_oc => 7,
|
315
310
|
:a_f2 => 8, :a_f1 => 9, :a_f0 => 10, :iodc => 11, :c_rs => 12, :delta_n => 13,
|
316
311
|
:M0 => 14, :c_uc => 15, :e => 16, :c_us => 17, :sqrt_A => 18, :t_oe => 19, :c_ic => 20,
|
317
312
|
:Omega0 => 21, :c_is => 22, :i0 => 23, :c_rc => 24, :omega => 25, :dot_Omega0 => 26,
|
@@ -319,22 +314,12 @@ class RTCM3
|
|
319
314
|
def params
|
320
315
|
# TODO WN is truncated to 0-1023
|
321
316
|
res = Hash[*(KEY2IDX.collect{|k, i| [k, self[i][0]]}.flatten(1))]
|
322
|
-
res[:fit_interval] = (
|
323
|
-
when 240..247; 8
|
324
|
-
when 248..255, 496; 14
|
325
|
-
when 497..503; 26
|
326
|
-
when 504..510; 50
|
327
|
-
when 511, 752..756; 74
|
328
|
-
when 757..763; 98
|
329
|
-
when 764..767, 1088..1010; 122
|
330
|
-
when 1011..1020; 146
|
331
|
-
else; 6
|
332
|
-
end) * 60 * 60
|
317
|
+
res[:fit_interval] = (self[29][0] != 0)
|
333
318
|
res
|
334
319
|
end
|
335
320
|
end
|
336
321
|
module SBAS_Ephemeris
|
337
|
-
KEY2IDX = {:svid => 1, :iodn => 2, :tod => 3, :
|
322
|
+
KEY2IDX = {:svid => 1, :iodn => 2, :tod => 3, :URA_index => 4,
|
338
323
|
:x => 5, :y => 6, :z => 7,
|
339
324
|
:dx => 8, :dy => 9, :dz => 10,
|
340
325
|
:ddx => 11, :ddy => 12, :ddz => 13,
|
@@ -349,18 +334,18 @@ class RTCM3
|
|
349
334
|
# TODO insufficient: :n => ?(String4); extra: :P3
|
350
335
|
# TODO generate time with t_b, N_T, NA, N_4
|
351
336
|
# TODO GPS.i is required to modify to generate EPhemeris_with_GPS_Time
|
352
|
-
k_i = {:svid => 1, :freq_ch => 2, :
|
337
|
+
k_i = {:svid => 1, :freq_ch => 2, :P1_index => 5, :t_k => 6, :B_n => 7, :P2 => 8, :t_b => 9,
|
353
338
|
:xn_dot => 10, :xn => 11, :xn_ddot => 12,
|
354
339
|
:yn_dot => 13, :yn => 14, :yn_ddot => 15,
|
355
340
|
:zn_dot => 16, :zn => 17, :zn_ddot => 18,
|
356
341
|
:P3 => 19, :gamma_n => 20, :p => 21, :tau_n => 23, :delta_tau_n => 24, :E_n => 25,
|
357
|
-
:P4 => 26, :
|
342
|
+
:P4 => 26, :F_T_index => 27, :N_T => 28, :M => 29}
|
358
343
|
k_i.merge!({:NA => 31, :tau_c => 32, :N_4 => 33, :tau_GPS => 34}) if self[30][0] == 1 # check DF131
|
359
344
|
res = Hash[*(k_i.collect{|k, i| [k, self[i][0]]}.flatten(1))]
|
360
345
|
res.reject!{|k, v|
|
361
346
|
case k
|
362
347
|
when :N_T; v == 0
|
363
|
-
when :p, :delta_tau_n, :P4, :
|
348
|
+
when :p, :delta_tau_n, :P4, :F_T_index, :N_4, :tau_GPS; true # TODO sometimes delta_tau_n is valid?
|
364
349
|
else; false
|
365
350
|
end
|
366
351
|
} if (res[:M] != 1) # check DF130
|
@@ -372,12 +357,12 @@ class RTCM3
|
|
372
357
|
:iode => 6, :c_rs => 7, :delta_n => 8, :M0 => 9, :c_uc => 10, :e => 11,
|
373
358
|
:c_us => 12, :sqrt_A => 13, :t_oe => 14, :c_ic => 15, :Omega0 => 16,
|
374
359
|
:c_is => 17, :i0 => 18, :c_rc => 19, :omega => 20, :dot_Omega0 => 21,
|
375
|
-
:dot_i0 => 22, :WN => 24, :
|
360
|
+
:dot_i0 => 22, :WN => 24, :URA_index => 25, :SV_health => 26,
|
376
361
|
:t_GD => 27, :iodc => 28}
|
377
362
|
def params
|
378
363
|
# TODO PRN = svid + 192, WN is truncated to 0-1023
|
379
364
|
res = Hash[*(KEY2IDX.collect{|k, i| [k, self[i][0]]}.flatten(1))]
|
380
|
-
res[:fit_interval] = (self[29]
|
365
|
+
res[:fit_interval] = (self[29][0] != 0)
|
381
366
|
res
|
382
367
|
end
|
383
368
|
end
|