gps_pvt 0.8.1 → 0.8.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +22 -7
- data/exe/gps_pvt +1 -1
- data/exe/to_ubx +92 -29
- data/ext/gps_pvt/GPS/GPS_wrap.cxx +398 -187
- data/ext/ninja-scan-light/tool/navigation/GLONASS_Solver.h +5 -3
- data/ext/ninja-scan-light/tool/navigation/GPS_Solver.h +5 -3
- data/ext/ninja-scan-light/tool/navigation/GPS_Solver_MultiFrequency.h +1 -0
- data/ext/ninja-scan-light/tool/navigation/SBAS_Solver.h +5 -3
- data/ext/ninja-scan-light/tool/swig/GPS.i +54 -8
- data/ext/ninja-scan-light/tool/swig/spec/GPS_spec.rb +7 -0
- data/lib/gps_pvt/receiver/extension.rb +16 -7
- data/lib/gps_pvt/receiver.rb +38 -26
- data/lib/gps_pvt/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e2f23806309c4244499a91877edba1a5dfacb1a9108596527dffad650c9cd9ee
|
4
|
+
data.tar.gz: dc33e31c739a79dc7e7c28ad0d6f404b65788499dfa2f53f9b93edae7b589e7e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2a3ec484712ccbd06b99a08a672ef20980d68e5f1670b07b093f1d6e4d0480dce974cbe8a181ecb0e8d6074cc60c1c122778113e962625f57b41a7a85b61fc4a
|
7
|
+
data.tar.gz: 5368619df05a35b6295702e3ad64958aab84e92652b01747f31b5bb98974243ac56a5b4fc25bde1075109bd4d586eac14bf64e1c2ac6b5a31d9bc990ece92fd7
|
data/README.md
CHANGED
@@ -27,7 +27,7 @@ For Windows users, this gem requires Devkit because of native compilation.
|
|
27
27
|
|
28
28
|
## Usage
|
29
29
|
|
30
|
-
### For user who just generate PVT solution
|
30
|
+
### For user who just wants to generate PVT solution
|
31
31
|
An attached executable is useful. After installation, type
|
32
32
|
|
33
33
|
$ gps_pvt file_or_URI(s)
|
@@ -36,12 +36,12 @@ The format of file is automatically determined with its extension, such as .ubx
|
|
36
36
|
|
37
37
|
| specification | recoginized as |
|
38
38
|
----|----
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
39
|
+
| <a name=opt_rinex_nav>--rinex_nav=file_or_URI</a> | [RINEX](https://www.igs.org/wg/rinex/#documents-formats) navigation file |
|
40
|
+
| <a name=opt_rinex_obs>--rinex_obs=file_or_URI</a> | [RINEX](https://www.igs.org/wg/rinex/#documents-formats) observation file |
|
41
|
+
| <a name=opt_ubx>--ubx=file_or_URI</a> | [U-blox](https://www.u-blox.com/) dedicated format |
|
42
42
|
| --sp3=file_or_URI | [Standard Product 3 Orbit Format](https://files.igs.org/pub/data/format/sp3c.txt) (supported gps_pvt version >= 0.6.0) |
|
43
43
|
| --antex=file_or_URI | [Antenna Exchange Format](https://igs.org/wg/antenna#files) (supported gps_pvt version >= 0.6.0) |
|
44
|
-
| --rinex_clk=file_or_URI | [RINEX clock](https://files.igs.org/pub/data/format/rinex_clock304.txt) file
|
44
|
+
| --rinex_clk=file_or_URI | [RINEX clock](https://files.igs.org/pub/data/format/rinex_clock304.txt) file (supported gps_pvt version >= 0.7.0) |
|
45
45
|
|
46
46
|
Since version 0.2.0, SBAS and QZSS are supported in addition to GPS. Since version 0.4.0, GLONASS is also available. QZSS ranging is activated in default, however, SBAS is just utilized for ionospheric correction. GLONASS is also turned off by default. If you want to activate SBAS or GLONASS ranging, "--with=(system or PRN)" options are used with gps_pvt executable like
|
47
47
|
|
@@ -49,13 +49,13 @@ Since version 0.2.0, SBAS and QZSS are supported in addition to GPS. Since versi
|
|
49
49
|
|
50
50
|
Additionally, the following command options *--key=value* are available.
|
51
51
|
|
52
|
-
| key | value | comment |
|
52
|
+
| key | value | comment | since |
|
53
53
|
----|----|----|----
|
54
54
|
| base_station | 3 \* (numeric+coordinate) | base position used for relative ENU position calculation. XYZ, NEU formats are acceptable. *ex1) --base_station=0X,0Y,0Z*, *ex2) --base_station=12.34N,56.789E,0U* | v0.1.7 |
|
55
55
|
| elevation_mask_deg | numeric | satellite elevation mask specified in degrees. *ex) --elevation_mask_deg=10* | v0.3.0 |
|
56
56
|
| 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 |
|
57
57
|
| end_time | time string | end time to perform solution. Its format is the same as start_time. | v0.3.3 |
|
58
|
-
| online_ephemeris | | based on observation,
|
58
|
+
| <a name=opt_online_ephemeris>online_ephemeris</a> | URL string | based on observation, ephemeris which is previously broadcasted from satellite and currently published online will automatically be loaded. If value is not given, the default source "ftp://gssc.esa.int/gnss/data/daily/%Y/brdc/BRDC00IGS_R_%Y%j0000_01D_MN.rnx.gz" is used. The value string is converted with [strftime](https://docs.ruby-lang.org/en/master/strftime_formatting_rdoc.html) before actual use. | v0.8.1 |
|
59
59
|
|
60
60
|
### For developer
|
61
61
|
|
@@ -148,6 +148,21 @@ receiver.solver.correction = { # provide by using a Hash
|
|
148
148
|
}
|
149
149
|
```
|
150
150
|
|
151
|
+
## Additional utilities
|
152
|
+
|
153
|
+
### [to_ubx](exe/to_ubx)
|
154
|
+
|
155
|
+
Utility to convert observation into u-blox ubx format and dump standard input. After installation of gps_pvt, to type
|
156
|
+
|
157
|
+
$ to_ubx file_or_URI(s) (options) > out.ubx
|
158
|
+
|
159
|
+
saves resultant into out.ubx by using redirection. The shared options with gps_pvt executable are [rinex_obs](#opt_rinex_obs), [rinex_nav](#opt_rinex_nav), [ubx](#opt_ubx), and [online_ephemeris](#opt_online_ephemeris). In addition, the following options are available.
|
160
|
+
|
161
|
+
| key | value | comment | since |
|
162
|
+
----|----|----|----
|
163
|
+
| ubx_rawx | | Change output packet types to UBX-RAWX from its default UBX-RAW. | v0.8.1 |
|
164
|
+
| broadcast_data | | In addition to observation, ephemeris is inserted by using UBX-SFRB packets. If ubx_rawx option is specified, UBX-SFRBX is used instead of UBX-SFRB. | v0.8.1 |
|
165
|
+
|
151
166
|
## Development
|
152
167
|
|
153
168
|
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake` to build library and run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
data/exe/gps_pvt
CHANGED
data/exe/to_ubx
CHANGED
@@ -40,6 +40,7 @@ files.collect!{|fname, ftype|
|
|
40
40
|
ftype ||= case fname
|
41
41
|
when /\.\d{2}[nhqg](?:\.gz)?$/; :rinex_nav
|
42
42
|
when /\.\d{2}o(?:\.gz)?$/; :rinex_obs
|
43
|
+
when /\.ubx$/; :ubx
|
43
44
|
else
|
44
45
|
raise "Format cannot be guessed, use --(format, ex. rinex_obs)=#{fname}"
|
45
46
|
end
|
@@ -55,9 +56,12 @@ files.collect!{|fname, ftype|
|
|
55
56
|
|
56
57
|
options.reject!{|opt|
|
57
58
|
case opt[0]
|
58
|
-
when :ubx_rawx, :
|
59
|
+
when :ubx_rawx, :broadcast_data, :eph_interval
|
59
60
|
misc_options[opt[0]] = opt[1]
|
60
61
|
true
|
62
|
+
when :online_ephemeris
|
63
|
+
(misc_options[opt[0]] ||= []) << opt[1]
|
64
|
+
true
|
61
65
|
else
|
62
66
|
false
|
63
67
|
end
|
@@ -74,6 +78,17 @@ proc{|src|
|
|
74
78
|
rcv.attach_online_ephemeris(src) if src
|
75
79
|
}.call(misc_options[:online_ephemeris])
|
76
80
|
|
81
|
+
proc{
|
82
|
+
cache = nil
|
83
|
+
rcv.define_singleton_method(:leap_seconds){|t_meas|
|
84
|
+
cache ||= if self.solver.gps_space_node.is_valid_utc then
|
85
|
+
self.solver.gps_space_node.iono_utc.delta_t_LS
|
86
|
+
else
|
87
|
+
t_meas.leap_seconds
|
88
|
+
end
|
89
|
+
}
|
90
|
+
}.call
|
91
|
+
|
77
92
|
# parse RINEX NAV
|
78
93
|
files.each{|fname, ftype|
|
79
94
|
case ftype
|
@@ -84,14 +99,37 @@ files.each{|fname, ftype|
|
|
84
99
|
# other files
|
85
100
|
files.each{|fname, ftype|
|
86
101
|
case ftype
|
102
|
+
when :ubx; rcv.parse_ubx(fname){}
|
87
103
|
when :rinex_obs; rcv.parse_rinex_obs(fname){}
|
88
104
|
end
|
89
105
|
}
|
90
106
|
|
91
107
|
obs.sort!{|a, b| a[0] <=> b[0]} # Sort by measurement time
|
92
108
|
|
93
|
-
#
|
94
|
-
|
109
|
+
# Time packet for solution of leap seconds
|
110
|
+
gen_gpstime = proc{
|
111
|
+
tmpl = [0xB5, 0x62, 0x01, 0x20, 16, 0]
|
112
|
+
gpst = GPS_PVT::GPS::Time
|
113
|
+
t_next = gpst::new(*gpst::leap_second_events.find{|wn, sec, leap| leap == 1}[0..1])
|
114
|
+
proc{|t_meas, meas|
|
115
|
+
next nil if t_meas < t_next
|
116
|
+
t_next = t_meas + 60 # 1 min. interval
|
117
|
+
ubx = tmpl.clone
|
118
|
+
t_sec = t_meas.seconds
|
119
|
+
t_msec = (t_sec * 1E3).round
|
120
|
+
t_nsec = ((t_sec * 1E3 - t_msec) * 1E6).round
|
121
|
+
leap = rcv.leap_seconds(t_meas)
|
122
|
+
ubx += [
|
123
|
+
t_msec, # ITOW ms GPS Millisecond time of Week
|
124
|
+
t_nsec, # Frac ns Nanoseconds remainder of rounded ms above, range -500000 .. 500000
|
125
|
+
t_meas.week, # week - GPS week (GPS time)
|
126
|
+
leap || 0, # LeapS s Leap Seconds (GPS-UTC)
|
127
|
+
leap ? 0x07 : 0x03, # validity bit field (0x01=ToW, 0x02=WN, 0x04=UTC)
|
128
|
+
10000, # TAcc ns Time Accuracy Estimate
|
129
|
+
].pack("Vl<vcCV").unpack("C*")
|
130
|
+
GPS_PVT::UBX::update(ubx + [0, 0]).pack("C*")
|
131
|
+
}
|
132
|
+
}.call
|
95
133
|
|
96
134
|
gen_sfrb, gen_sfrbx = proc{
|
97
135
|
cache = {}
|
@@ -236,13 +274,14 @@ gen_rawx = proc{|t_meas, meas| # Convert to RXM-RAWX(0x15)
|
|
236
274
|
ubx = [0xB5, 0x62, 0x02, 0x15, 0, 0]
|
237
275
|
ubx += [t_meas.seconds, t_meas.week].pack("Ev").unpack("C*")
|
238
276
|
ubx += [0] * 6
|
239
|
-
|
277
|
+
gen_packet = proc{|sys, svid, sig, items|
|
240
278
|
res = [0] * 32
|
241
279
|
setter = proc{|value, offset, len, str, pre_proc|
|
242
280
|
array = case value
|
243
281
|
when Array; value
|
244
282
|
when Symbol
|
245
|
-
[
|
283
|
+
k = [sig, value].join('_').to_sym
|
284
|
+
[items[GPS_PVT::GPS::Measurement.const_get(k)]]
|
246
285
|
else
|
247
286
|
next nil
|
248
287
|
end
|
@@ -251,55 +290,79 @@ gen_rawx = proc{|t_meas, meas| # Convert to RXM-RAWX(0x15)
|
|
251
290
|
array = array.pack(str).unpack("C*") if str
|
252
291
|
res[offset - 16, len] = array
|
253
292
|
}
|
254
|
-
sys, svid = case sat
|
255
|
-
when 1..32 # GPS
|
256
|
-
[0, sat]
|
257
|
-
when 120..158 # SBAS
|
258
|
-
[1, sat]
|
259
|
-
when 193..202 # QZSS
|
260
|
-
[5, sat]
|
261
|
-
when (0x100 + 1)..(0x100 + 32) # GLONASS
|
262
|
-
setter.call(:L1_FREQUENCY,
|
263
|
-
39, 1, nil, proc{|v| v.replace([(v[0] ? glonass_freq_ch.call(v[0]) : 0) + 7])} )
|
264
|
-
[6, sat - 0x100]
|
265
|
-
else
|
266
|
-
next nil # TODO Galileo, Beidou, ...
|
267
|
-
end
|
268
|
-
setter.call([sys, svid], 36, 2)
|
269
293
|
|
294
|
+
setter.call([sys, svid], 36, 2)
|
295
|
+
|
270
296
|
trk_stat = 0
|
271
|
-
setter.call(:
|
297
|
+
setter.call(:PSEUDORANGE,
|
272
298
|
16, 8, "E", proc{|v| v[0] ? (trk_stat |= 0x1) : v.clear})
|
273
|
-
setter.call(:
|
299
|
+
setter.call(:PSEUDORANGE_SIGMA,
|
274
300
|
43, 1, nil, proc{|v|
|
275
301
|
b = (Math::log2(v[0] / 1E-2).to_i & 0xF) rescue 0x8
|
276
302
|
v.replace((trk_stat & 0x1 == 0x1) ? [b] : [])
|
277
303
|
})
|
278
|
-
setter.call(:
|
279
|
-
setter.call(:
|
304
|
+
setter.call(:DOPPLER, 32, 4, "e") rescue next nil
|
305
|
+
setter.call(:DOPPLER_SIGMA,
|
280
306
|
45, 1, nil, proc{|v| v.replace(v[0] ? [Math::log2(v[0] / 2E-3).to_i & 0xF] : [0x8])})
|
281
|
-
setter.call(:
|
307
|
+
setter.call(:CARRIER_PHASE,
|
282
308
|
24, 8, "E", proc{|v| v[0] ? (trk_stat |= 0x2) : v.clear})
|
283
|
-
setter.call(:
|
309
|
+
setter.call(:CARRIER_PHASE_SIGMA,
|
284
310
|
44, 1, nil, proc{|v|
|
285
311
|
b = ((v[0] / 0.004).to_i & 0xF) rescue 0x8
|
286
312
|
v.replace((trk_stat & 0x2 == 0x2) ? [b] : [])
|
287
313
|
})
|
288
|
-
setter.call(:
|
314
|
+
setter.call(:SIGNAL_STRENGTH_dBHz,
|
289
315
|
42, 1, nil, proc{|v| v.replace(v[0] ? [v[0].to_i] : [])})
|
290
|
-
setter.call(:
|
316
|
+
setter.call(:LOCK_SEC,
|
291
317
|
40, 2, "v", proc{|v| v.replace(v[0] ? [(v[0] / 1E-3).to_i] : [])})
|
292
318
|
setter.call([trk_stat], 46, 1)
|
319
|
+
res.define_singleton_method(:set, &setter)
|
293
320
|
|
294
321
|
res
|
322
|
+
}
|
323
|
+
meas_ubx = meas.inject([]){|packets, (sat, items)|
|
324
|
+
case sat
|
325
|
+
when 1..32 # GPS
|
326
|
+
packets << gen_packet.call(0, sat, :L1, items)
|
327
|
+
packets += {:L2CL => 3, :L2CM => 4}.collect{|sig, sigid|
|
328
|
+
next nil unless packet = gen_packet.call(0, sat, sig, items)
|
329
|
+
packet[38 - 16] = sigid
|
330
|
+
packet
|
331
|
+
}
|
332
|
+
when 120..158 # SBAS
|
333
|
+
packets << gen_packet.call(1, sat, :L1, items)
|
334
|
+
when 193..202 # QZSS
|
335
|
+
packets << gen_packet.call(5, sat, :L1, items)
|
336
|
+
packets += {:L2CL => 5, :L2CM => 4}.collect{|sig, sigid|
|
337
|
+
next nil unless packet = gen_packet.call(5, sat, sig, items)
|
338
|
+
packet[38 - 16] = sigid
|
339
|
+
packet
|
340
|
+
}
|
341
|
+
when (0x100 + 1)..(0x100 + 32) # GLONASS
|
342
|
+
packet = gen_packet.call(6, sat - 0x100, :L1, items)
|
343
|
+
packet.set(:FREQUENCY,
|
344
|
+
39, 1, nil,
|
345
|
+
proc{|v| v.replace([(v[0] ? glonass_freq_ch.call(v[0]) : 0) + 7])} ) if packet
|
346
|
+
packets << packet
|
347
|
+
else
|
348
|
+
# TODO Galileo, Beidou, ...
|
349
|
+
end
|
295
350
|
}.compact
|
351
|
+
|
352
|
+
proc{|ls| # leap seconds
|
353
|
+
next unless ls
|
354
|
+
ubx[6 + 10] = ls
|
355
|
+
ubx[6 + 12] |= 0x01
|
356
|
+
}.call(rcv.leap_seconds(t_meas))
|
296
357
|
ubx[6 + 11] = meas_ubx.size
|
297
|
-
ubx
|
358
|
+
ubx[6 + 13] = 1 # version
|
359
|
+
ubx += meas_ubx.flatten
|
298
360
|
ubx += [0, 0]
|
299
361
|
GPS_PVT::UBX::update(ubx).pack("C*")
|
300
362
|
}
|
301
363
|
|
302
364
|
gen_list = []
|
365
|
+
gen_list << gen_gpstime unless misc_options[:ubx_rawx]
|
303
366
|
gen_list << (misc_options[:ubx_rawx] ? gen_sfrbx : gen_sfrb) if misc_options[:broadcast_data]
|
304
367
|
gen_list << (misc_options[:ubx_rawx] ? gen_rawx : gen_raw)
|
305
368
|
STDOUT.binmode
|