gps_pvt 0.1.2 → 0.1.6
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 +31 -4
- data/exe/gps_pvt +46 -0
- data/lib/gps_pvt/receiver.rb +22 -45
- data/lib/gps_pvt/version.rb +1 -1
- metadata +5 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5f4007b50ab655503a9f52a09cccd613ba7f21463989067887a71d2e45449d51
|
4
|
+
data.tar.gz: 945ef479edd3fdec649d8a4dffe4ce8cadb4d7a20e927171fbd817020f689fb6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f42a861328b4f987061889268aaf2efbba1bf0c42f5cf6a830b97454ba45dc89d19203492366af2b3d746eb135e5a2553ee4bcff618fae0837c26f713015f0bf
|
7
|
+
data.tar.gz: 29b0e2e7e4eaf07bc8918a56942842763f4b4c3497986aabecea70a808a9d2c05289f1a07a2c5c745cb12358d622fc6d772e75dd7440e9063d5e517bcb76ac9f
|
data/README.md
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
GPS_PVT is a Ruby GPS (Global positioning system) PVT (position, velocity and time) solver. It accepts RINEX NAV and OBS files in addition to u-blox ubx format. Its significant features are easy to use with highly flexibility to customize internal solver behavior such as weight for each available satellite.
|
4
4
|
|
5
|
-
The PVT solution is obtained with a stand alone positioning (i.e. neither differential nor kinematic) with least square. Its main internal codes are derived from ones of [ninja-scan-light](https://github.com/fenrir-naru/ninja-scan-light) having capability to calculate tightly-coupled GNSS/INS integrated solution. These codes are written by C++, and wrapped by [SWIG](http://www.swig.org/).
|
5
|
+
The PVT solution is obtained with a stand alone positioning (i.e. neither differential nor kinematic) with application of least square to each snapshot. Its main internal codes are derived from ones of [ninja-scan-light](https://github.com/fenrir-naru/ninja-scan-light) having capability to calculate tightly-coupled GNSS/INS integrated solution. These codes are written by C++, and wrapped by [SWIG](http://www.swig.org/).
|
6
6
|
|
7
7
|
[](https://badge.fury.io/rb/gps_pvt)
|
8
8
|
[](https://github.com/fenrir-naru/gps_pvt/actions/workflows/main.yml)
|
@@ -27,6 +27,12 @@ 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, an attached executable is useful. After installation, type
|
31
|
+
|
32
|
+
$ gps_pvt RINEX_or_UBX_file(s)
|
33
|
+
|
34
|
+
For developer, this library will be used in the following:
|
35
|
+
|
30
36
|
```ruby
|
31
37
|
require 'gps_pvt'
|
32
38
|
|
@@ -40,7 +46,8 @@ receiver.parse_rinex_obs(rinex_obs_file)
|
|
40
46
|
|
41
47
|
# Or precise control of outputs
|
42
48
|
receiver.parse_rinex_obs(rinex_obs_file){|pvt, meas| # per epoch
|
43
|
-
meas # => measurement, array of [prn, key, value]; key is represented by GPS_PVT::GPS::Measurement::L1_PSEUDORANGE
|
49
|
+
meas.to_a # => measurement, array of [prn, key, value]; key is represented by GPS_PVT::GPS::Measurement::L1_PSEUDORANGE; instead of .to_a, .to_hash returns {prn => {key => value, ...}, ...}
|
50
|
+
|
44
51
|
pvt # => PVT solution, all properties are shown by pvt.methods
|
45
52
|
# for example
|
46
53
|
if(pvt.position_solved?){
|
@@ -53,6 +60,9 @@ receiver.parse_rinex_obs(rinex_obs_file){|pvt, meas| # per epoch
|
|
53
60
|
pvt.receiver_error_rate # clock error rate in m/s
|
54
61
|
}
|
55
62
|
pvt.used_satellite_list # array of used, i.e., visible and weight>0, satellite
|
63
|
+
pvt.azimuth # azimuth angle [rad] to used satellites in Hash {prn => value, ...}
|
64
|
+
pvt.elevation # elevation angle [rad]
|
65
|
+
|
56
66
|
pvt.G # design matrix in Earth-centered-Earth-fixed (ECEF); .to_a returns double array converted from matrix. its row corresponds to one of used_satellite_list
|
57
67
|
pvt.G_enu # design matrix in East-North-Up (ENU)
|
58
68
|
pvt.W # weight for each satellite
|
@@ -67,11 +77,28 @@ receiver.solver.options.include(prn) # Discard previous setting of exclusion
|
|
67
77
|
receiver.solver.hooks[:relative_property] = proc{|prn, rel_prop, rcv_e, t_arv, usr_pos, usr_vel|
|
68
78
|
# control weight per satellite per iteration
|
69
79
|
weight, range_c, range_r, rate_rel_neg, *los_neg = rel_prop # relative property
|
70
|
-
|
80
|
+
# rcv_e, t_arv, usr_pos, usr_vel are temporary solution of
|
81
|
+
# receiver clock error [m], time of arrival [s], user position and velocity in ECEF, respectively.
|
82
|
+
|
83
|
+
weight = 1 # same as default; identical weight for each visible satellite
|
71
84
|
# or weight based on elevation
|
72
85
|
# elv = GPS_PVT::Coordinate::ENU::relative_rel(GPS_PVT::Coordinate::XYZ::new(*los_neg), usr_pos).elevation
|
73
86
|
# weight = (Math::sin(elv)/0.8)**2
|
74
|
-
|
87
|
+
|
88
|
+
[weight, range_c, range_r, rate_rel_neg] + los_neg # must return relative property
|
89
|
+
}
|
90
|
+
|
91
|
+
# Dynamic customization of weight for each epoch
|
92
|
+
(class << receiver; self; end).instance_eval{ # do before parse_XXX
|
93
|
+
alias_method(:run_orig, :run)
|
94
|
+
define_method(:run){|meas, t_meas, &b|
|
95
|
+
meas # observation, same as the 2nd argument of parse_XXX
|
96
|
+
receiver.solver.hooks[:relative_property] = proc{|prn, rel_prop, rcv_e, t_arv, usr_pos, usr_vel|
|
97
|
+
# Do something based on meas, t_meas.
|
98
|
+
rel_prop
|
99
|
+
}
|
100
|
+
run_orig(meas, t_meas, &b)
|
101
|
+
}
|
75
102
|
}
|
76
103
|
```
|
77
104
|
|
data/exe/gps_pvt
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'gps_pvt'
|
4
|
+
|
5
|
+
# runnable quick example to solve PVT by using RINEX NAV/OBS or u-blox ubx
|
6
|
+
|
7
|
+
$stderr.puts <<__STRING__
|
8
|
+
Usage: #{__FILE__} GPS_file1 GPS_file2 ...
|
9
|
+
As GPS_file, rinex_nav(*.YYn), rinex_obs(*.YYo), and ubx(*.ubx) format are currently supported.
|
10
|
+
File format is automatically determined based on its extention described in above parentheses.
|
11
|
+
Note: YY = last two digit of year.
|
12
|
+
__STRING__
|
13
|
+
|
14
|
+
options = {}
|
15
|
+
|
16
|
+
# check options
|
17
|
+
ARGV.reject!{|arg|
|
18
|
+
next false unless arg =~ /^--([^=]+)=?/
|
19
|
+
options[$1.to_sym] = $'
|
20
|
+
true
|
21
|
+
}
|
22
|
+
|
23
|
+
# Check file existence
|
24
|
+
ARGV.each{|arg|
|
25
|
+
raise "File not found: #{arg}" unless File::exist?(arg)
|
26
|
+
}
|
27
|
+
|
28
|
+
rcv = GPS_PVT::Receiver::new(options)
|
29
|
+
|
30
|
+
puts GPS_PVT::Receiver::header
|
31
|
+
|
32
|
+
# parse RINEX NAV
|
33
|
+
ARGV.reject!{|arg|
|
34
|
+
next false unless arg =~ /\.\d{2}n$/
|
35
|
+
rcv.parse_rinex_nav(arg)
|
36
|
+
}
|
37
|
+
|
38
|
+
# other files
|
39
|
+
ARGV.each{|arg|
|
40
|
+
case arg
|
41
|
+
when /\.ubx$/
|
42
|
+
rcv.parse_ubx(arg)
|
43
|
+
when /\.\d{2}o$/
|
44
|
+
rcv.parse_rinex_obs(arg)
|
45
|
+
end
|
46
|
+
}
|
data/lib/gps_pvt/receiver.rb
CHANGED
@@ -1,5 +1,3 @@
|
|
1
|
-
#!/usr/bin/ruby
|
2
|
-
|
3
1
|
=begin
|
4
2
|
Receiver class to be an top level interface to a user
|
5
3
|
(The origin is ninja-scan-light/tool/misc/receiver_debug.rb)
|
@@ -140,15 +138,15 @@ class Receiver
|
|
140
138
|
end
|
141
139
|
|
142
140
|
def run(meas, t_meas)
|
143
|
-
|
144
|
-
|
145
|
-
sn.update_all_ephemeris(t_meas)
|
146
|
-
|
141
|
+
=begin
|
142
|
+
$stderr.puts "Measurement time: #{t_meas.to_a} (a.k.a #{"%d/%d/%d %d:%d:%d UTC"%[*t_meas.c_tm]})"
|
147
143
|
meas.to_a.collect{|prn, k, v| prn}.uniq.each{|prn|
|
148
|
-
eph =
|
144
|
+
eph = @solver.gps_space_node.ephemeris(prn)
|
149
145
|
$stderr.puts "XYZ(PRN:#{prn}): #{eph.constellation(t_meas)[0].to_a} (iodc: #{eph.iodc}, iode: #{eph.iode})"
|
150
|
-
}
|
146
|
+
}
|
147
|
+
=end
|
151
148
|
|
149
|
+
#@solver.gps_space_node.update_all_ephemeris(t_meas) # internally called in the following solver.solve
|
152
150
|
pvt = @solver.solve(meas, t_meas)
|
153
151
|
pvt.define_singleton_method(:to_s){
|
154
152
|
(OUTPUT_PVT_ITEMS.transpose[1].collect{|task|
|
@@ -244,9 +242,15 @@ class Receiver
|
|
244
242
|
{
|
245
243
|
:L1_PSEUDORANGE => [16, 8, "E"],
|
246
244
|
:L1_DOPPLER => [24, 4, "e"],
|
245
|
+
:L1_CARRIER_PHASE => [8, 8, "E"],
|
246
|
+
:L1_SIGNAL_STRENGTH_dBHz => [30, 1, "c"],
|
247
247
|
}.each{|k, prop|
|
248
248
|
meas.add(prn, GPS::Measurement.const_get(k), loader.call(*prop))
|
249
249
|
}
|
250
|
+
# bit 0 of RINEX LLI (loss of lock indicator) shows lost lock
|
251
|
+
# between previous and current observation, which maps negative lock seconds
|
252
|
+
meas.add(prn, GPS::Measurement::L1_LOCK_SEC,
|
253
|
+
(packet[6 + 31 + (i * 24)] & 0x01 == 0x01) ? -1 : 0)
|
250
254
|
}
|
251
255
|
after_run.call(run(meas, t_meas), [meas, t_meas])
|
252
256
|
when [0x02, 0x15] # RXM-RAWX
|
@@ -272,6 +276,12 @@ class Receiver
|
|
272
276
|
}],
|
273
277
|
:L1_DOPPLER => [32, 4, "e"],
|
274
278
|
:L1_DOPPLER_SIGMA => [45, 1, nil, proc{|v| 2E-3 * (v[0] & 0xF)}],
|
279
|
+
:L1_CARRIER_PHASE => [24, 8, "E", proc{|v| (trk_stat & 0x2 == 0x2) ? v : nil}],
|
280
|
+
:L1_CARRIER_PHASE_SIGMA => [44, 1, nil, proc{|v|
|
281
|
+
(trk_stat & 0x2 == 0x2) ? (0.004 * (v[0] & 0xF)) : nil
|
282
|
+
}],
|
283
|
+
:L1_SIGNAL_STRENGTH_dBHz => [42, 1],
|
284
|
+
:L1_LOCK_SEC => [40, 2, "v", proc{|v| 1E-3 * v}],
|
275
285
|
}.each{|k, prop|
|
276
286
|
next unless v = loader.call(*prop)
|
277
287
|
meas.add(svid, GPS::Measurement.const_get(k), v)
|
@@ -317,8 +327,12 @@ class Receiver
|
|
317
327
|
case type_
|
318
328
|
when "C1", "C1C"
|
319
329
|
[i, GPS::Measurement::L1_PSEUDORANGE]
|
330
|
+
when "L1", "L1C"
|
331
|
+
[i, GPS::Measurement::L1_CARRIER_PHASE]
|
320
332
|
when "D1", "D1C"
|
321
333
|
[i, GPS::Measurement::L1_DOPPLER]
|
334
|
+
when "S1", "S1C"
|
335
|
+
[i, GPS::Measurement::L1_SIGNAL_STRENGTH_dBHz]
|
322
336
|
else
|
323
337
|
nil
|
324
338
|
end
|
@@ -336,40 +350,3 @@ class Receiver
|
|
336
350
|
end
|
337
351
|
end
|
338
352
|
end
|
339
|
-
|
340
|
-
if __FILE__ == $0 then
|
341
|
-
# runnable quick example to solve PVT by using RINEX NAV/OBS or u-blox ubx
|
342
|
-
options = {}
|
343
|
-
|
344
|
-
# check options
|
345
|
-
ARGV.reject!{|arg|
|
346
|
-
next false unless arg =~ /^--([^=]+)=?/
|
347
|
-
options[$1.to_sym] = $'
|
348
|
-
true
|
349
|
-
}
|
350
|
-
|
351
|
-
# Check file existence
|
352
|
-
ARGV.each{|arg|
|
353
|
-
raise "File not found: #{arg}" unless File::exist?(arg)
|
354
|
-
}
|
355
|
-
|
356
|
-
rcv = GPS_PVT::Receiver::new(options)
|
357
|
-
|
358
|
-
puts GPS_PVT::Receiver::header
|
359
|
-
|
360
|
-
# parse RINEX NAV
|
361
|
-
ARGV.reject!{|arg|
|
362
|
-
next false unless arg =~ /\.\d{2}n$/
|
363
|
-
rcv.parse_rinex_nav(arg)
|
364
|
-
}
|
365
|
-
|
366
|
-
# other files
|
367
|
-
ARGV.each{|arg|
|
368
|
-
case arg
|
369
|
-
when /\.ubx$/
|
370
|
-
rcv.parse_ubx(arg)
|
371
|
-
when /\.\d{2}o$/
|
372
|
-
rcv.parse_rinex_obs(arg)
|
373
|
-
end
|
374
|
-
}
|
375
|
-
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.1.
|
4
|
+
version: 0.1.6
|
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: 2021-12-
|
11
|
+
date: 2021-12-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|
@@ -42,7 +42,8 @@ description: This module calculate PVT by using raw observation obtained from a
|
|
42
42
|
receiver
|
43
43
|
email:
|
44
44
|
- fenrir.naru@gmail.com
|
45
|
-
executables:
|
45
|
+
executables:
|
46
|
+
- gps_pvt
|
46
47
|
extensions:
|
47
48
|
- ext/gps_pvt/extconf.rb
|
48
49
|
extra_rdoc_files: []
|
@@ -55,6 +56,7 @@ files:
|
|
55
56
|
- Rakefile
|
56
57
|
- bin/console
|
57
58
|
- bin/setup
|
59
|
+
- exe/gps_pvt
|
58
60
|
- ext/gps_pvt/Coordinate/Coordinate_wrap.cxx
|
59
61
|
- ext/gps_pvt/GPS/GPS_wrap.cxx
|
60
62
|
- ext/gps_pvt/SylphideMath/SylphideMath_wrap.cxx
|