gps_pvt 0.9.2 → 0.9.3
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 +1 -1
- data/ext/gps_pvt/Coordinate/Coordinate_wrap.cxx +31 -19
- data/ext/gps_pvt/GPS/GPS_wrap.cxx +577 -4113
- data/ext/gps_pvt/SylphideMath/SylphideMath_wrap.cxx +829 -2574
- data/ext/ninja-scan-light/tool/swig/Coordinate.i +12 -12
- data/ext/ninja-scan-light/tool/swig/GPS.i +88 -80
- data/ext/ninja-scan-light/tool/swig/SylphideMath.i +52 -32
- data/ext/ninja-scan-light/tool/swig/spec/GPS_spec.rb +1 -1
- data/ext/ninja-scan-light/tool/swig/spec/SylphideMath_spec.rb +8 -8
- data/lib/gps_pvt/receiver/rtcm3.rb +103 -22
- data/lib/gps_pvt/receiver.rb +1 -0
- data/lib/gps_pvt/rtcm3.rb +44 -0
- data/lib/gps_pvt/version.rb +1 -1
- metadata +2 -2
@@ -18,6 +18,13 @@ class Receiver
|
|
18
18
|
else; raise "reference time (#{ref_time}) should be GPS::Time or Time"
|
19
19
|
end
|
20
20
|
leap_sec = ref_time.leap_seconds
|
21
|
+
ref_pos = opt[:ref_pos] || if src_io.respond_to?(:property) then
|
22
|
+
Coordinate::LLH::new(*(src_io.property.values_at(:latitude, :longitude).collect{|v|
|
23
|
+
v.to_f / 180 * Math::PI
|
24
|
+
} + [0])).xyz
|
25
|
+
else
|
26
|
+
defined?(@base_station) ? @base_station : nil
|
27
|
+
end
|
21
28
|
after_run = b || proc{|pvt| puts pvt.to_s if pvt}
|
22
29
|
t_meas, meas = [nil, {}]
|
23
30
|
# meas := {msg_num => [[], ...]} due to duplicated observation such as 1074 and 1077
|
@@ -26,7 +33,9 @@ class Receiver
|
|
26
33
|
meas.sort.each{|k, values| # larger msg_num entries have higher priority
|
27
34
|
values.each{|prn_k_v| meas_.add(*prn_k_v)}
|
28
35
|
}
|
29
|
-
|
36
|
+
pvt = nil
|
37
|
+
after_run.call(pvt = run(meas_, t_meas), [meas_, ref_time = t_meas]) if t_meas
|
38
|
+
ref_pos = pvt.xyz if pvt && pvt.position_solved?
|
30
39
|
t_meas, meas = [nil, {}]
|
31
40
|
}
|
32
41
|
dt_threshold = GPS::Time::Seconds_week / 2
|
@@ -53,6 +62,63 @@ class Receiver
|
|
53
62
|
GPS::Time::new(ref_time.week, 0) + tod + 60 * 60 * 24 * ref_dow
|
54
63
|
end
|
55
64
|
}
|
65
|
+
restore_ranges = proc{
|
66
|
+
c_1ms = 299_792.458
|
67
|
+
threshold = c_1ms / 10 # 100 us =~ 30 km
|
68
|
+
cache = {} # {[sys, svid] => [range, t], ...}
|
69
|
+
get_rough = proc{|t, sys_svid_list|
|
70
|
+
sn_list = sys_svid_list.collect{|sys, svid|
|
71
|
+
case sys
|
72
|
+
when :GPS, :QZSS; @solver.gps_space_node
|
73
|
+
when :SBAS; @solver.sbas_space_node
|
74
|
+
when :GLONASS; @solver.glonass_space_node
|
75
|
+
end
|
76
|
+
}
|
77
|
+
critical{
|
78
|
+
sn_list.uniq.compact{|sn| sn.update_all_ephemeris(t)}
|
79
|
+
sys_svid_list.zip(sn_list).each{|(sys, svid), sn|
|
80
|
+
next unless sn
|
81
|
+
eph = sn.ephemeris(svid)
|
82
|
+
cache[[sys, svid]] = [if eph.valid?(t) then
|
83
|
+
sv_pos, clk_err = eph.constellation(t).values_at(0, 2)
|
84
|
+
sv_pos.dist(ref_pos) - (clk_err * c_1ms * 1E3)
|
85
|
+
end, t]
|
86
|
+
}
|
87
|
+
}
|
88
|
+
}
|
89
|
+
per_kind = proc{|t, sys_svid_list, ranges_rem|
|
90
|
+
get_rough.call(t, sys_svid_list.uniq.reject{|sys, svid|
|
91
|
+
next true unless sys
|
92
|
+
range, t2 = cache[[sys, svid]]
|
93
|
+
range && ((t2 - t).abs <= 60)
|
94
|
+
})
|
95
|
+
ranges_rem.zip(sys_svid_list).collect{|rem_in, (sys, svid)|
|
96
|
+
range_ref, t2 = cache[[sys, svid]]
|
97
|
+
next nil unless range_ref
|
98
|
+
q, rem_ref = range_ref.divmod(c_1ms)
|
99
|
+
delta = rem_in - rem_ref
|
100
|
+
res = if delta.abs <= threshold then
|
101
|
+
q * c_1ms + rem_in
|
102
|
+
elsif -delta + c_1ms <= threshold
|
103
|
+
(q - 1) * c_1ms + rem_in
|
104
|
+
elsif delta + c_1ms <= threshold
|
105
|
+
(q + 1) * c_1ms + rem_in
|
106
|
+
end
|
107
|
+
#p [sys, svid, q, rem_in, rem_ref, res]
|
108
|
+
(cache[[sys, svid]] = [res, t])[0]
|
109
|
+
}
|
110
|
+
}
|
111
|
+
proc{|t, sys_svid_list, ranges|
|
112
|
+
[
|
113
|
+
:pseudo_range, # for MT 1001/3/9/11, MSM1/3
|
114
|
+
:phase_range, # for MT 1003/11, MSM2/3
|
115
|
+
].each{|k|
|
116
|
+
next if ranges[k]
|
117
|
+
k_rem = "#{k}_rem".to_sym
|
118
|
+
ranges[k] = per_kind.call(t, sys_svid_list, ranges[k_rem]) if ranges[k_rem]
|
119
|
+
}
|
120
|
+
}
|
121
|
+
}.call
|
56
122
|
|
57
123
|
while packet = rtcm3.read_packet
|
58
124
|
msg_num = packet.message_number
|
@@ -66,15 +132,19 @@ class Receiver
|
|
66
132
|
when 1001..1004
|
67
133
|
t_meas2 = tow2t.call(parsed[2][0]) # DF004
|
68
134
|
ranges = parsed.ranges
|
69
|
-
|
70
|
-
[:sat, :pseudo_range, :phase_range, :cn].collect{|k|
|
71
|
-
ranges[k] || ([nil] * item_size)
|
72
|
-
}.transpose.each{|svid, pr, cpr, cn|
|
135
|
+
sys_svid_list = ranges[:sat].collect{|svid|
|
73
136
|
case svid
|
74
|
-
when 1..32;
|
75
|
-
when 40..58; svid
|
76
|
-
else;
|
137
|
+
when 1..32; [:GPS, svid]
|
138
|
+
when 40..58; [:SBAS, svid + 80]
|
139
|
+
else; [nil, svid]
|
77
140
|
end
|
141
|
+
}
|
142
|
+
restore_ranges.call(t_meas2, sys_svid_list, ranges)
|
143
|
+
item_size = sys_svid_list.size
|
144
|
+
([sys_svid_list] + [:pseudo_range, :phase_range, :cn].collect{|k|
|
145
|
+
ranges[k] || ([nil] * item_size)
|
146
|
+
}).transpose.each{|(sys, svid), pr, cpr, cn|
|
147
|
+
next unless sys
|
78
148
|
meas2 << [svid, :L1_PSEUDORANGE, pr] if pr
|
79
149
|
meas2 << [svid, :L1_CARRIER_PHASE, cpr / GPS::SpaceNode.L1_WaveLength] if cpr
|
80
150
|
meas2 << [svid, :L1_SIGNAL_STRENGTH_dBHz, cn] if cn
|
@@ -82,25 +152,34 @@ class Receiver
|
|
82
152
|
when 1009..1012
|
83
153
|
t_meas2 = utc2t.call(parsed[2][0] - 60 * 60 * 3) # DF034 UTC(SU)+3hr, time of day[sec]
|
84
154
|
ranges = parsed.ranges
|
85
|
-
|
86
|
-
[:sat, :freq_ch, :pseudo_range, :phase_range, :cn].collect{|k|
|
87
|
-
ranges[k] || ([nil] * item_size)
|
88
|
-
}.transpose.each{|svid, freq_ch, pr, cpr, cn|
|
155
|
+
sys_svid_list = ranges[:sat].collect{|svid|
|
89
156
|
case svid
|
90
|
-
when 1..24
|
157
|
+
when 1..24; [:GLONASS, svid]
|
158
|
+
when 40..58; [:SBAS, svid + 80]
|
159
|
+
else; [nil, svid]
|
160
|
+
end
|
161
|
+
}
|
162
|
+
restore_ranges.call(t_meas2, sys_svid_list, ranges)
|
163
|
+
item_size = sys_svid_list.size
|
164
|
+
([sys_svid_list] + [:freq_ch, :pseudo_range, :phase_range, :cn].collect{|k|
|
165
|
+
ranges[k] || ([nil] * item_size)
|
166
|
+
}).transpose.each{|(sys, svid), freq_ch, pr, cpr, cn|
|
167
|
+
case sys
|
168
|
+
when :GLONASS
|
91
169
|
svid += 0x100
|
92
170
|
freq = GPS::SpaceNode_GLONASS::L1_frequency(freq_ch)
|
93
171
|
len = GPS::SpaceNode_GLONASS.light_speed / freq
|
94
172
|
meas2 << [svid, :L1_FREQUENCY, freq]
|
95
173
|
meas2 << [svid, :L1_CARRIER_PHASE, cpr / len] if cpr
|
96
|
-
when
|
97
|
-
svid += 80 # SBAS
|
174
|
+
when :SBAS
|
98
175
|
meas2 << [svid, :L1_CARRIER_PHASE, cpr / GPS::SpaceNode.L1_WaveLength] if cpr
|
99
176
|
else; next
|
100
177
|
end
|
101
178
|
meas2 << [svid, :L1_PSEUDORANGE, pr] if pr
|
102
179
|
meas2 << [svid, :L1_SIGNAL_STRENGTH_dBHz, cn] if cn
|
103
180
|
}
|
181
|
+
when 1013
|
182
|
+
leap_sec = parsed[5][0]
|
104
183
|
when 1019, 1044
|
105
184
|
params = parsed.params
|
106
185
|
if msg_num == 1044
|
@@ -162,22 +241,24 @@ class Receiver
|
|
162
241
|
}.compact.flatten(1))]
|
163
242
|
}
|
164
243
|
end
|
165
|
-
sig_list, svid_offset = case msg_num / 10
|
244
|
+
sig_list, sys, svid_offset = case msg_num / 10
|
166
245
|
when 107 # GPS
|
167
246
|
[{2 => [:L1, GPS::SpaceNode.L1_WaveLength],
|
168
247
|
15 => [:L2CM, GPS::SpaceNode.L2_WaveLength],
|
169
|
-
16 => [:L2CL, GPS::SpaceNode.L2_WaveLength]}, 0]
|
248
|
+
16 => [:L2CL, GPS::SpaceNode.L2_WaveLength]}, :GPS, 0]
|
170
249
|
when 108 # GLONASS
|
171
|
-
[{2 => [:L1, nil]}, 0x100]
|
250
|
+
[{2 => [:L1, nil]}, :GLONASS, 0x100]
|
172
251
|
when 110 # SBAS
|
173
|
-
[{2 => [:L1, GPS::SpaceNode.L1_WaveLength]}, 120]
|
252
|
+
[{2 => [:L1, GPS::SpaceNode.L1_WaveLength]}, :SBAS, 120]
|
174
253
|
when 111 # QZSS
|
175
254
|
[{2 => [:L1, GPS::SpaceNode.L1_WaveLength],
|
176
255
|
15 => [:L2CM, GPS::SpaceNode.L2_WaveLength],
|
177
|
-
16 => [:L2CL, GPS::SpaceNode.L2_WaveLength]}, 192]
|
178
|
-
else; [{}, 0]
|
256
|
+
16 => [:L2CL, GPS::SpaceNode.L2_WaveLength]}, :QZSS, 192]
|
257
|
+
else; [{}, nil, 0]
|
179
258
|
end
|
180
|
-
|
259
|
+
sys_svid_list = ranges[:sat_sig].collect{|sat, sig| [sys, (sat + svid_offset) & 0xFF]}
|
260
|
+
restore_ranges.call(t_meas2, sys_svid_list, ranges)
|
261
|
+
item_size = sys_svid_list.size
|
181
262
|
[:sat_sig, :pseudo_range, :phase_range, :phase_range_rate, :cn].collect{|k|
|
182
263
|
ranges[k] || ([nil] * item_size)
|
183
264
|
}.transpose.each{|(svid, sig), pr, cpr, dr, cn|
|
data/lib/gps_pvt/receiver.rb
CHANGED
@@ -416,6 +416,7 @@ class Receiver
|
|
416
416
|
opt = options[0] || {}
|
417
417
|
case sys
|
418
418
|
when :GPS, :QZSS
|
419
|
+
return unless bcast_data.size == 10 # 8 for QZSS(SAIF)
|
419
420
|
return unless eph = @eph_list[prn]
|
420
421
|
sn = @solver.gps_space_node
|
421
422
|
subframe, iodc_or_iode = eph.parse(bcast_data)
|
data/lib/gps_pvt/rtcm3.rb
CHANGED
@@ -95,6 +95,13 @@ class RTCM3
|
|
95
95
|
48 => invalidate.call(num_gen.call(20, Rational(5, 10000)), 0x80000), # [m]
|
96
96
|
49 => 7,
|
97
97
|
50 => invalidate.call(unum_gen.call(8, Rational(1, 4)), 0), # [db-Hz]
|
98
|
+
51 => 16,
|
99
|
+
52 => 17,
|
100
|
+
53 => 5,
|
101
|
+
54 => 8,
|
102
|
+
55 => 12,
|
103
|
+
56 => 1,
|
104
|
+
57 => 16,
|
98
105
|
71 => 8,
|
99
106
|
76 => 10,
|
100
107
|
77 => proc{
|
@@ -237,12 +244,14 @@ class RTCM3
|
|
237
244
|
1001..1004 => (2..8).to_a,
|
238
245
|
1005 => [2, 3, 21, 22, 23, 24, 141, 25, 142, [1, 1], 26, 364, 27],
|
239
246
|
1009..1012 => [2, 3, 34, 5, 35, 36, 37],
|
247
|
+
1013 => [2, 3, 51, 52, 53, 54],
|
240
248
|
1019 => [2, 9, (76..79).to_a, 71, (81..103).to_a, 137].flatten, # 488 bits @see Table 3.5-21
|
241
249
|
1020 => [2, 38, 40, (104..136).to_a].flatten, # 360 bits @see Table 3.5-21
|
242
250
|
1043 => [2] + [:prn, :iodn, :tod, :ura,
|
243
251
|
[:xy] * 2, :z, [:dxy] * 2, :dz, [:ddxy] * 2, :ddz,
|
244
252
|
:agf0, :agf1].flatten.collect{|k| "SBAS_#{k}".to_sym}, # @see BNC Ntrip client RTCM3Decorder.cpp
|
245
253
|
1044 => [2, (429..457).to_a].flatten, # 485 bits
|
254
|
+
1070..1229 => [2, [:uint, 12], [:uint, 30], 393], # 55 bits part of messages will be overwritten
|
246
255
|
1071..1077 => [2, 3, 4, 393, 409, [1, 7], 411, 412, 417, 418, 394, 395], # 169 bits @see Table 3.5-78
|
247
256
|
1081..1087 => [2, 3, 416, 34, 393, 409, [1, 7], 411, 412, 417, 418, 394, 395], # 169 bits @see Table 3.5-93
|
248
257
|
1091..1097 => [2, 3, 248, 393, 409, [1, 7], 411, 412, 417, 418, 394, 395], # 169 bits @see Table 3.5-98
|
@@ -392,6 +401,29 @@ class RTCM3
|
|
392
401
|
end
|
393
402
|
SPEED_OF_LIGHT = 299_792_458
|
394
403
|
end
|
404
|
+
module MSM1_2_3
|
405
|
+
include MSM
|
406
|
+
def ranges
|
407
|
+
sats, cells, offset = property.values_at(:sats, :cells, :header_items)
|
408
|
+
nsat, ncell = [sats.size, cells.size]
|
409
|
+
res = {:sat_sig => cells}
|
410
|
+
range_rough = cells.collect{|sat, sig| # DF398
|
411
|
+
self[offset + sats.find_index(sat)][0]
|
412
|
+
}
|
413
|
+
add_proc = proc{|idx_cell|
|
414
|
+
values = self[offset + (nsat * 1) + (ncell * idx_cell), ncell]
|
415
|
+
next if values.empty?
|
416
|
+
k = {400 => :pseudo_range_rem, 401 => :phase_range_rem}[values[0][1]]
|
417
|
+
next unless k
|
418
|
+
res[k] = values.zip(range_rough).collect{|(v, df), v_base|
|
419
|
+
((v_base + v) * SPEED_OF_LIGHT) rescue nil
|
420
|
+
}
|
421
|
+
}
|
422
|
+
add_proc.call(0)
|
423
|
+
add_proc.call(1)
|
424
|
+
res
|
425
|
+
end
|
426
|
+
end
|
395
427
|
module MSM4_6
|
396
428
|
include MSM
|
397
429
|
def ranges
|
@@ -468,6 +500,9 @@ class RTCM3
|
|
468
500
|
1012 => (38..50).to_a,
|
469
501
|
}[msg_num]] * nsat).flatten), offset)
|
470
502
|
attributes << GLONASS_Observation
|
503
|
+
when 1013
|
504
|
+
add_proc.call(DataFrame.generate_prop(
|
505
|
+
((55..57).to_a * values[4]).flatten), 24 + mt[:bits_total])
|
471
506
|
when 1019
|
472
507
|
attributes << GPS_Ephemeris
|
473
508
|
when 1020
|
@@ -492,6 +527,15 @@ class RTCM3
|
|
492
527
|
add_proc.call(msm_sig, offset)
|
493
528
|
}
|
494
529
|
case msg_num % 10
|
530
|
+
when 1
|
531
|
+
attributes << MSM1_2_3
|
532
|
+
msm_proc.call([398], [400])
|
533
|
+
when 2
|
534
|
+
attributes << MSM1_2_3
|
535
|
+
msm_proc.call([398], [401, 402, 420])
|
536
|
+
when 3
|
537
|
+
attributes << MSM1_2_3
|
538
|
+
msm_proc.call([398], [400, 401, 402, 420])
|
495
539
|
when 4
|
496
540
|
attributes << MSM4_6
|
497
541
|
msm_proc.call([397, 398], [400, 401, 402, 420, 403])
|
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.9.
|
4
|
+
version: 0.9.3
|
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: 2023-
|
11
|
+
date: 2023-03-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rubyserial
|