gps_pvt 0.1.2 → 0.1.6
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
[![Gem Version](https://badge.fury.io/rb/gps_pvt.svg)](https://badge.fury.io/rb/gps_pvt)
|
8
8
|
[![Ruby](https://github.com/fenrir-naru/gps_pvt/actions/workflows/main.yml/badge.svg)](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
|