gps_pvt 0.10.3 → 0.10.4
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/exe/gps2ubx +111 -17
- data/lib/gps_pvt/pvt.rb +83 -0
- data/lib/gps_pvt/receiver.rb +1 -1
- data/lib/gps_pvt/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 60413c3add439fa66e0ff908f43f0049ad306fcefca50e2c485bc28790597143
|
4
|
+
data.tar.gz: 788f430151ca35a95abd4f96e4f30239e9f53768014af9ddc5897305b25b7fb9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9c0ddc7d6a4f589cf3b3692eacde62405c78890f20cadf5abde07d189ae35bda83fd0b9e905728e4fecaf111aeee14bfb615166ef72d355fcac1a3368330ee89
|
7
|
+
data.tar.gz: 457d23f7e4032549961e499638403b3d01d681a8051231616ee2dde5183967c119028bd2a4475f2fe1c1e3ae2ffda61729162ced5d30b33113bfe21c161c188e
|
data/exe/gps2ubx
CHANGED
@@ -3,6 +3,7 @@
|
|
3
3
|
require 'gps_pvt'
|
4
4
|
require 'uri'
|
5
5
|
require 'gps_pvt/ubx'
|
6
|
+
require 'gps_pvt/pvt'
|
6
7
|
|
7
8
|
# Convert file(s) to ubx format
|
8
9
|
# TODO currently only RINEX observation file is supported.
|
@@ -25,6 +26,7 @@ options = []
|
|
25
26
|
misc_options = {
|
26
27
|
:broadcast_data => false,
|
27
28
|
:ubx_rawx => false,
|
29
|
+
:ubx_nav => false,
|
28
30
|
:eph_interval => 60 * 5,
|
29
31
|
}
|
30
32
|
|
@@ -32,7 +34,7 @@ misc_options = {
|
|
32
34
|
files = ARGV.collect{|arg|
|
33
35
|
next [arg, nil] unless arg =~ /^--([^=]+)=?/
|
34
36
|
k, v = [$1.downcase.to_sym, $']
|
35
|
-
next [v, k] if [:rinex_nav, :rinex_obs, :ubx, :rtcm3].include?(k) # file type
|
37
|
+
next [v, k] if [:rinex_nav, :rinex_obs, :ubx, :rtcm3, :pvt_csv].include?(k) # file type
|
36
38
|
options << [$1.to_sym, $']
|
37
39
|
nil
|
38
40
|
}.compact
|
@@ -43,6 +45,7 @@ files.collect!{|fname, ftype|
|
|
43
45
|
when /\.\d{2}[nhqg](?:\.gz)?$/; :rinex_nav
|
44
46
|
when /\.\d{2}o(?:\.gz)?$/; :rinex_obs
|
45
47
|
when /\.ubx$/; :ubx
|
48
|
+
when /\.csv$/; misc_options[:ubx_nav] = true; :pvt_csv
|
46
49
|
end
|
47
50
|
if (!(uri = URI::parse(fname)).instance_of?(URI::Generic) rescue false) then
|
48
51
|
ftype ||= case uri
|
@@ -57,7 +60,7 @@ files.collect!{|fname, ftype|
|
|
57
60
|
|
58
61
|
options.reject!{|opt|
|
59
62
|
case opt[0]
|
60
|
-
when :ubx_rawx, :broadcast_data, :eph_interval
|
63
|
+
when :ubx_rawx, :ubx_nav, :broadcast_data, :eph_interval
|
61
64
|
misc_options[opt[0]] = opt[1]
|
62
65
|
true
|
63
66
|
when :online_ephemeris
|
@@ -70,10 +73,13 @@ options.reject!{|opt|
|
|
70
73
|
|
71
74
|
rcv = GPS_PVT::Receiver::new(options)
|
72
75
|
|
73
|
-
|
74
|
-
rcv.
|
75
|
-
|
76
|
-
|
76
|
+
outputs = Queue::new # [[time, item1, item2, ...], ...]
|
77
|
+
rcv.instance_eval{
|
78
|
+
nav_task = misc_options[:ubx_nav] ? method(:run) : proc{}
|
79
|
+
define_singleton_method(:run){|meas, t_meas, *args|
|
80
|
+
outputs << [t_meas, meas, nav_task.call(meas, t_meas, *args)].compact
|
81
|
+
nil
|
82
|
+
}
|
77
83
|
}
|
78
84
|
|
79
85
|
proc{|src|
|
@@ -106,6 +112,9 @@ threads = files.collect{|fname, ftype|
|
|
106
112
|
when :rtcm3; proc{rcv.parse_rtcm3(fname){}}
|
107
113
|
when :supl; proc{rcv.parse_supl(fname)}
|
108
114
|
when :rinex_nav; proc{}
|
115
|
+
when :pvt_csv; proc{GPS_PVT::GPS::PVT_minimal::parse_csv(fname){|t, pvt|
|
116
|
+
outputs << [t, pvt]
|
117
|
+
}}
|
109
118
|
end
|
110
119
|
case fname
|
111
120
|
when URI::Ntrip, URI::Supl; Thread::new(&task)
|
@@ -113,9 +122,9 @@ threads = files.collect{|fname, ftype|
|
|
113
122
|
end
|
114
123
|
}.compact
|
115
124
|
|
116
|
-
|
125
|
+
outputs = proc{
|
117
126
|
tmp = []
|
118
|
-
tmp <<
|
127
|
+
tmp << outputs.pop until outputs.empty?
|
119
128
|
tmp
|
120
129
|
}.call.sort!{|a, b| b[0] <=> a[0]} if threads.empty? # Sort by measurement time
|
121
130
|
|
@@ -124,7 +133,7 @@ gen_gpstime = proc{
|
|
124
133
|
tmpl = [0xB5, 0x62, 0x01, 0x20, 16, 0]
|
125
134
|
gpst = GPS_PVT::GPS::Time
|
126
135
|
t_next = gpst::new(*gpst::leap_second_events.find{|wn, sec, leap| leap == 1}[0..1])
|
127
|
-
proc{|t_meas
|
136
|
+
proc{|t_meas|
|
128
137
|
next nil if t_meas < t_next
|
129
138
|
t_next = t_meas + 60 # 1 min. interval
|
130
139
|
ubx = tmpl.clone
|
@@ -374,17 +383,102 @@ gen_rawx = proc{|t_meas, meas| # Convert to RXM-RAWX(0x15)
|
|
374
383
|
GPS_PVT::UBX::update(ubx).pack("C*")
|
375
384
|
}
|
376
385
|
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
386
|
+
gen_nav = proc{|t_meas, pvt|
|
387
|
+
t_msec = (t_meas.seconds * 1E3).round
|
388
|
+
packet = []
|
389
|
+
|
390
|
+
proc{ # Convert to NAV-SOL (0x01-0x06)
|
391
|
+
ubx_sol = [0xB5, 0x62, 0x01, 0x06, 52, 0]
|
392
|
+
ubx_sol += [
|
393
|
+
t_msec,
|
394
|
+
0, # frac
|
395
|
+
t_meas.week, # week
|
396
|
+
if (pvt.position_solved? and pvt.velocity_solved?) then
|
397
|
+
[
|
398
|
+
0x03, # 3D-Fix
|
399
|
+
0x0D, # GPSfixOK, WKNSET, TOWSET
|
400
|
+
pvt.xyz.to_a.collect{|v| (v * 1E2).to_i}, # ECEF_XYZ [cm]
|
401
|
+
(Math::sqrt((pvt.hsigma ** 2) + (pvt.vsigma ** 2)) * 1E2).to_i, # 3D pos accuracy [cm]
|
402
|
+
(pvt.velocity.absolute(pvt.xyz) - pvt.xyz).to_a.collect{|v| (v * 1E2).to_i}, # ECEF_VXYZ [cm/s]
|
403
|
+
(pvt.vel_sigma * 1E2).to_i, # Speed accuracy [cm/s]
|
404
|
+
(pvt.pdop * 1E2).to_i, # PDOP [0.01]
|
405
|
+
]
|
406
|
+
else
|
407
|
+
[
|
408
|
+
0, # 3D-Fix
|
409
|
+
0x08, # TOWSET
|
410
|
+
[0] * 3, # ECEF_XYZ [cm]
|
411
|
+
0, # 3D pos accuracy [cm]
|
412
|
+
[0] * 3, # ECEF_VXYZ [cm/s]
|
413
|
+
0, # Speed accuracy [cm/s]
|
414
|
+
0, # PDOP
|
415
|
+
]
|
416
|
+
end,
|
417
|
+
0,
|
418
|
+
pvt.used_satellites,
|
419
|
+
0].flatten.pack('V2vc2l<3Vl<3VvC2V').unpack('C*')
|
420
|
+
packet += GPS_PVT::UBX::update(ubx_sol + [0, 0])
|
421
|
+
}.call
|
422
|
+
|
423
|
+
# Convert to NAV-POSLLH (0x01-0x02)
|
424
|
+
if pvt.position_solved? then
|
425
|
+
llh = pvt.llh
|
426
|
+
ubx_posllh = [0xB5, 0x62, 0x01, 0x02, 28, 0]
|
427
|
+
ubx_posllh += [
|
428
|
+
t_msec,
|
429
|
+
(llh.lng / Math::PI * 180 * 1E7).to_i, # Longitude [1E-7 deg]
|
430
|
+
(llh.lat / Math::PI * 180 * 1E7).to_i, # Latitude [1E-7 deg]
|
431
|
+
(llh.alt * 1E3).to_i, # WGS-84 altitude [mm]
|
432
|
+
(llh.alt * 1E3).to_i, # mean sea level TODO fix
|
433
|
+
(pvt.hsigma * 1E3).to_i, # HAcc [mm]
|
434
|
+
(pvt.vsigma * 1E3).to_i, # VAcc [mm]
|
435
|
+
].pack('V*').unpack("C*")
|
436
|
+
packet += GPS_PVT::UBX::update(ubx_posllh + [0, 0])
|
437
|
+
end
|
438
|
+
|
439
|
+
# Convert to NAV-VELNED (0x01-0x12)
|
440
|
+
if pvt.velocity_solved? then
|
441
|
+
vel = pvt.velocity
|
442
|
+
ubx_velned = [0xB5, 0x62, 0x01, 0x12, 36, 0]
|
443
|
+
ubx_velned += [
|
444
|
+
t_msec,
|
445
|
+
(vel.n * 1E2).to_i, # N speed [cm/s]
|
446
|
+
(vel.e * 1E2).to_i, # E speed [cm/s]
|
447
|
+
(vel.d * 1E2).to_i, # D speed [cm/s]
|
448
|
+
(vel.distance * 1E2).to_i, # 3D speed [cm/s]
|
449
|
+
(vel.horizontal * 1E2).to_i, # 2D speed [cm/s]
|
450
|
+
(vel.azimuth / Math::PI * 180 * 1E5).to_i, # Heading [1E-5 deg]
|
451
|
+
(pvt.vel_sigma * 1E2).to_i, # sAcc speed accuracy [cm/s]
|
452
|
+
(2 * 1E5).to_i, # cAcc heading accuracy [1E-5 deg] TODO
|
453
|
+
].pack('V*').unpack("C*")
|
454
|
+
packet += GPS_PVT::UBX::update(ubx_velned + [0, 0])
|
455
|
+
end
|
456
|
+
|
457
|
+
(gen_gpstime.call(t_meas) || '') + packet.pack('C*')
|
458
|
+
}
|
459
|
+
|
460
|
+
gen_list = Hash[*({
|
461
|
+
:Measurement => proc{
|
462
|
+
gen_ary = []
|
463
|
+
gen_ary << gen_gpstime unless misc_options[:ubx_rawx]
|
464
|
+
gen_ary << (misc_options[:ubx_rawx] ? gen_sfrbx : gen_sfrb) if misc_options[:broadcast_data]
|
465
|
+
gen_ary << (misc_options[:ubx_rawx] ? gen_rawx : gen_raw)
|
466
|
+
proc{|t_meas, meas|
|
467
|
+
meas = meas.to_hash
|
468
|
+
gen_ary.collect{|gen| gen.call(t_meas, meas)}.join
|
469
|
+
}
|
470
|
+
}.call,
|
471
|
+
:PVT => gen_nav,
|
472
|
+
:PVT_minimal => gen_nav,
|
473
|
+
}.collect{|k, v| [GPS_PVT::GPS.const_get(k), v]}.flatten(1))]
|
381
474
|
STDOUT.binmode
|
382
475
|
|
383
476
|
task_dump = proc{
|
384
|
-
until
|
385
|
-
t_meas,
|
386
|
-
|
387
|
-
|
477
|
+
until outputs.empty? do
|
478
|
+
t_meas, *items = outputs.pop
|
479
|
+
items.each{|item|
|
480
|
+
print gen_list[item.class].call(t_meas, item)
|
481
|
+
}
|
388
482
|
end
|
389
483
|
}
|
390
484
|
if threads.empty? then
|
data/lib/gps_pvt/pvt.rb
ADDED
@@ -0,0 +1,83 @@
|
|
1
|
+
require 'gps_pvt/GPS'
|
2
|
+
require 'gps_pvt/Coordinate'
|
3
|
+
|
4
|
+
module GPS_PVT
|
5
|
+
class GPS::PVT_minimal
|
6
|
+
def initialize
|
7
|
+
# GLOBAL POSITIONING SYSTEM STANDARD POSITIONING SERVICE
|
8
|
+
# PERFORMANCE STANDARD 5th edition (Apr. 2020) 3.8
|
9
|
+
@hsigma = 8.0 # 95%
|
10
|
+
@vsigma = 13.0 # 95%
|
11
|
+
@pdop = 6.0 # 98% global
|
12
|
+
@vel_sigma = 0.2 # 85%
|
13
|
+
@use_satellites = 0 # unknown
|
14
|
+
end
|
15
|
+
def position_solved?; @xyz || @llh; end
|
16
|
+
def velocity_solved?; @velocity; end
|
17
|
+
def xyz; @xyz || @llh.xyz; end
|
18
|
+
def llh; @xyz ? @xyz.llh : @llh; end
|
19
|
+
def xyz=(args); @xyz = Coordinate::XYZ::new(*args); end
|
20
|
+
def llh=(args); @llh = Coordinate::LLH::new(*args); end
|
21
|
+
def velocity=(args); @velocity = Coordinate::ENU::new(*args); end
|
22
|
+
attr_reader :velocity
|
23
|
+
attr_accessor :hsigma, :vsigma, :pdop, :vel_sigma, :used_satellites
|
24
|
+
class <<self
|
25
|
+
def parse_csv(csv_fname, &b)
|
26
|
+
require_relative 'util'
|
27
|
+
$stderr.puts "Reading CSV file (%s) "%[csv_fname]
|
28
|
+
io = open(Util::get_txt(csv_fname), 'r')
|
29
|
+
|
30
|
+
header = io.readline.chomp.split(/ *, */)
|
31
|
+
idx_table = [
|
32
|
+
:week, [:tow, /^i?t(?:ime_)?o(?:f_)?w(?:eek)?/],
|
33
|
+
:year, :month, :mday, :hour, :min, [:sec, /^sec/],
|
34
|
+
[:lng, /^(?:long(?:itude)?|lng)/], [:lat, /^lat(?:itude)/],
|
35
|
+
[:alt, /^(?:alt(?:itude)?|h(?:$|eight|_))/], # assumption: [deg], [deg], [m]
|
36
|
+
:x, :y, :z, # ECEF xyz
|
37
|
+
:hsigma, :vsigma, :pdop,
|
38
|
+
[:vn, /^v(?:el)?_?n(?:orth)?/], [:ve, /^v(?:el)?_?e(?:ast)?/],
|
39
|
+
[:vd, /^v(?:el)?_?d(?:own)?/], [:vu, /^v(?:el)?_?u(?:p)?/],
|
40
|
+
:vx, :vy, :vz, # ECEF xyz
|
41
|
+
[:vel_sigma, /^v(?:el)?_sigma/],
|
42
|
+
[:used_satellites, /^(?:used_)?sat(?:ellite)?s/],
|
43
|
+
].collect{|k, re|
|
44
|
+
re ||= k.to_s
|
45
|
+
idx = header.find_index{|str| re === str}
|
46
|
+
idx && [k, idx]
|
47
|
+
}.compact
|
48
|
+
enum = Enumerator::new{|y|
|
49
|
+
io.each_line{|line|
|
50
|
+
values = line.chomp.split(/ *, */)
|
51
|
+
items = Hash[*(idx_table.collect{|k, idx|
|
52
|
+
v = values[idx]
|
53
|
+
(v == '') ? nil : [k, (Integer(v) rescue Float(v))]
|
54
|
+
}.compact.flatten(1))]
|
55
|
+
if items.include?(:week) then
|
56
|
+
t = GPS::Time::new(items[:week], items[:tow])
|
57
|
+
else
|
58
|
+
# UTC assumption, thus leap seconds must be added.
|
59
|
+
t = GPS::Time::new([:year, :month, :mday, :hour, :min, :sec].collect{|k| items[k]})
|
60
|
+
t += GPS::Time::guess_leap_seconds(t)
|
61
|
+
end
|
62
|
+
pvt = GPS::PVT_minimal::new
|
63
|
+
if items.include?(:lat) then
|
64
|
+
pvt.llh = ([:lat, :lng].collect{|k| Math::PI / 180 * items[k]} + [items[:alt]])
|
65
|
+
elsif items.include?(:xyz) then
|
66
|
+
pvt.xyz = [:x, :y, :z].collect{|k| items[k]}
|
67
|
+
end
|
68
|
+
if items.include?(:vn) then
|
69
|
+
pvt.velocity = ([:vn, :ve].collect{|k| items[k]} + [items[:vu] || -items[:vd]])
|
70
|
+
elsif items.include?(:vx) then
|
71
|
+
pvt.velocity = Coordinate::ENU::relative_rel(
|
72
|
+
Coordinate::XYZ::new(*([:vx, :vy, :vz].collect{|k| items[k]})),
|
73
|
+
pvt.llh)
|
74
|
+
end
|
75
|
+
[:pdop, :hsigma, :vsigma, :vel_sigma, :used_satellites].each{|k| pvt.send("#{k}=", items[k])}
|
76
|
+
y.yield(t, pvt)
|
77
|
+
}
|
78
|
+
}
|
79
|
+
b ? enum.each{|*res| b.call(*res)} : enum
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
data/lib/gps_pvt/receiver.rb
CHANGED
@@ -50,7 +50,7 @@ class Receiver
|
|
50
50
|
}.call] + [[
|
51
51
|
[:v_north, :v_east, :v_down, :receiver_clock_error_dot_ms, :vel_sigma],
|
52
52
|
proc{|pvt|
|
53
|
-
next [nil] *
|
53
|
+
next [nil] * 5 unless pvt.velocity_solved?
|
54
54
|
[:north, :east, :down].collect{|k| pvt.velocity.send(k)} \
|
55
55
|
+ [pvt.receiver_error_rate, pvt.vel_sigma]
|
56
56
|
}
|
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.10.
|
4
|
+
version: 0.10.4
|
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: 2024-
|
11
|
+
date: 2024-12-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rubyserial
|
@@ -180,6 +180,7 @@ files:
|
|
180
180
|
- lib/gps_pvt/asn1/asn1.y
|
181
181
|
- lib/gps_pvt/asn1/per.rb
|
182
182
|
- lib/gps_pvt/ntrip.rb
|
183
|
+
- lib/gps_pvt/pvt.rb
|
183
184
|
- lib/gps_pvt/receiver.rb
|
184
185
|
- lib/gps_pvt/receiver/agps.rb
|
185
186
|
- lib/gps_pvt/receiver/almanac.rb
|