gps_pvt 0.2.0 → 0.3.0
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 +33 -6
- data/Rakefile +0 -0
- data/exe/gps_pvt +28 -19
- data/ext/gps_pvt/GPS/GPS_wrap.cxx +596 -467
- data/ext/gps_pvt/SylphideMath/SylphideMath_wrap.cxx +277 -14
- data/ext/ninja-scan-light/tool/navigation/GPS.h +8 -43
- data/ext/ninja-scan-light/tool/navigation/GPS_Solver.h +61 -147
- data/ext/ninja-scan-light/tool/navigation/GPS_Solver_Base.h +83 -22
- data/ext/ninja-scan-light/tool/navigation/RINEX.h +15 -5
- data/ext/ninja-scan-light/tool/navigation/SBAS.h +2 -2
- data/ext/ninja-scan-light/tool/navigation/SBAS_Solver.h +55 -78
- data/ext/ninja-scan-light/tool/param/bit_array.h +4 -3
- data/ext/ninja-scan-light/tool/swig/GPS.i +342 -103
- data/ext/ninja-scan-light/tool/swig/SylphideMath.i +53 -6
- data/ext/ninja-scan-light/tool/swig/spec/GPS_spec.rb +42 -6
- data/ext/ninja-scan-light/tool/swig/spec/SylphideMath_spec.rb +38 -4
- data/gps_pvt.gemspec +63 -0
- data/lib/gps_pvt/receiver.rb +86 -41
- data/lib/gps_pvt/version.rb +1 -1
- metadata +7 -6
@@ -221,7 +221,11 @@ __RINEX_OBS_TEXT__
|
|
221
221
|
f.path
|
222
222
|
},
|
223
223
|
}}
|
224
|
-
let(:solver){
|
224
|
+
let(:solver){
|
225
|
+
res = GPS::Solver::new
|
226
|
+
res.correction = {:gps_ionospheric => :klobuchar, :gps_tropospheric => :hopfield}
|
227
|
+
res
|
228
|
+
}
|
225
229
|
|
226
230
|
describe 'demo' do
|
227
231
|
it 'calculates position without any error' do
|
@@ -255,7 +259,6 @@ __RINEX_OBS_TEXT__
|
|
255
259
|
[:alpha, :beta].each{|k|
|
256
260
|
puts "Iono #{k}: #{sn.iono_utc.send(k)}"
|
257
261
|
}
|
258
|
-
puts solver.gps_options.ionospheric_models
|
259
262
|
|
260
263
|
meas.each{|prn, k, v|
|
261
264
|
eph = sn.ephemeris(prn)
|
@@ -336,11 +339,26 @@ __RINEX_OBS_TEXT__
|
|
336
339
|
|
337
340
|
it 'can be modified through hooks' do
|
338
341
|
sn = solver.gps_space_node
|
342
|
+
expect(solver.correction[:gps_ionospheric]).to include(:klobuchar)
|
343
|
+
expect(solver.correction[:gps_tropospheric]).to include(:hopfield)
|
344
|
+
expect{solver.correction = nil}.to raise_error(RuntimeError)
|
345
|
+
expect{solver.correction = {
|
346
|
+
:gps_ionospheric => [proc{|t, usr_pos, sat_pos|
|
347
|
+
expect(t).to be_a_kind_of(GPS::Time)
|
348
|
+
expect(usr_pos).to be_a_kind_of(Coordinate::XYZ) unless usr_pos
|
349
|
+
expect(sat_pos).to be_a_kind_of(Coordinate::ENU) unless sat_pos
|
350
|
+
false
|
351
|
+
}, :klobuchar, :no_correction],
|
352
|
+
:options => {:f_10_7 => 10},
|
353
|
+
}}.not_to raise_error
|
354
|
+
expect(solver.correction[:gps_ionospheric]).to include(:no_correction)
|
355
|
+
expect(solver.correction[:options][:f_10_7]).to eq(10)
|
339
356
|
sn.read(input[:rinex_nav])
|
340
357
|
t_meas = GPS::Time::new(1849, 172413)
|
341
358
|
sn.update_all_ephemeris(t_meas)
|
342
|
-
solver.hooks[:relative_property] = proc{|prn, rel_prop, rcv_e, t_arv, usr_pos, usr_vel|
|
359
|
+
solver.hooks[:relative_property] = proc{|prn, rel_prop, meas, rcv_e, t_arv, usr_pos, usr_vel|
|
343
360
|
expect(input[:measurement]).to include(prn)
|
361
|
+
expect(meas).to be_a_kind_of(Hash)
|
344
362
|
expect(t_arv).to be_a_kind_of(GPS::Time)
|
345
363
|
expect(usr_pos).to be_a_kind_of(Coordinate::XYZ)
|
346
364
|
expect(usr_vel).to be_a_kind_of(Coordinate::XYZ)
|
@@ -348,12 +366,30 @@ __RINEX_OBS_TEXT__
|
|
348
366
|
weight = 1
|
349
367
|
[weight, range_c, range_r, rate_rel_neg] + los_neg
|
350
368
|
}
|
351
|
-
solver.hooks[:update_position_solution] = proc{
|
352
|
-
|
369
|
+
solver.hooks[:update_position_solution] = proc{|mat_G, mat_W, mat_delta_r, temp_pvt|
|
370
|
+
expect(temp_pvt).to be_a_kind_of(GPS::PVT)
|
371
|
+
[mat_G, mat_W, mat_delta_r].each{|mat|
|
353
372
|
expect(mat).to be_a_kind_of(SylphideMath::MatrixD)
|
373
|
+
expect(mat.rows).to be >= temp_pvt.used_satellites
|
374
|
+
expect(mat).to respond_to(:resize!)
|
354
375
|
}
|
355
|
-
mat_G, mat_W, mat_delta_r = mats
|
356
376
|
}
|
377
|
+
solver.hooks[:satellite_position] = proc{
|
378
|
+
i = 0
|
379
|
+
proc{|prn, time, pos|
|
380
|
+
expect(input[:measurement]).to include(prn)
|
381
|
+
expect(pos).to be_a_kind_of(Coordinate::XYZ).or eq(nil)
|
382
|
+
# System_XYZ or [x,y,z] or nil(= unknown position) are acceptable
|
383
|
+
case (i += 1) % 5
|
384
|
+
when 0
|
385
|
+
nil
|
386
|
+
when 1
|
387
|
+
pos.to_a
|
388
|
+
else
|
389
|
+
pos
|
390
|
+
end
|
391
|
+
}
|
392
|
+
}.call
|
357
393
|
pvt = solver.solve(
|
358
394
|
input[:measurement].collect{|prn, items|
|
359
395
|
items.collect{|k, v| [prn, k, v]}
|
@@ -19,6 +19,12 @@ shared_examples 'Matrix' do
|
|
19
19
|
expect( mat_type::new(*params[:rc]).rows ).to equal(params[:rc][0])
|
20
20
|
expect( mat_type::new(*params[:rc]).columns ).to equal(params[:rc][1])
|
21
21
|
end
|
22
|
+
it 'declines negative number argument' do
|
23
|
+
[[-1, 1], [1, -1]].each{|sf|
|
24
|
+
r, c = params[:rc].zip(sf).collect{|v1, v2| v1 * v2}
|
25
|
+
expect{ mat_type::new(r, c) }.to raise_error(ArgumentError)
|
26
|
+
}
|
27
|
+
end
|
22
28
|
it 'accepts ([[]])' do
|
23
29
|
expect{ mat_type::new(compare_with) }.not_to raise_error
|
24
30
|
expect( mat_type::new(compare_with).rows ).to equal(params[:rc][0])
|
@@ -44,9 +50,11 @@ shared_examples 'Matrix' do
|
|
44
50
|
a.define_singleton_method(:[]){|i, j| raise(IndexError) if i != j; 0}
|
45
51
|
expect{ mat_type::new(a) }.to raise_error(IndexError)
|
46
52
|
|
47
|
-
|
48
|
-
|
49
|
-
|
53
|
+
[:row_size, :column_size].each{|f|
|
54
|
+
a = a_gen.call
|
55
|
+
a.define_singleton_method(f){-1}
|
56
|
+
expect{ mat_type::new(a) }.to raise_error(RuntimeError)
|
57
|
+
}
|
50
58
|
end
|
51
59
|
it 'is invoked with I, identity, unit' do
|
52
60
|
[:I, :identity, :unit].each{|f|
|
@@ -132,7 +140,7 @@ shared_examples 'Matrix' do
|
|
132
140
|
expect(mat[:square].sum).to eq(Matrix[*mat[:square].to_a].sum)
|
133
141
|
expect(mat[:not_square].sum).to eq(Matrix[*mat[:not_square].to_a].sum)
|
134
142
|
end
|
135
|
-
it '
|
143
|
+
it 'determinant, det' do
|
136
144
|
[:determinant, :det].each{|f|
|
137
145
|
#expect(mat[:square].send(f)).to eq(Matrix[*mat[:square].to_a].det)
|
138
146
|
expect{mat[:not_square].send(f)}.to raise_error(RuntimeError)
|
@@ -163,6 +171,15 @@ shared_examples 'Matrix' do
|
|
163
171
|
}
|
164
172
|
}
|
165
173
|
end
|
174
|
+
it 'is inaccessible and unchangeable with negative number arguments' do
|
175
|
+
[[-1, 0], [0, -1]].each{|i, j|
|
176
|
+
[[:[], i, j], [:[]=, i, j, 0]].each{|args|
|
177
|
+
expect{ mat[0].send(*args) }.to raise_error{|err|
|
178
|
+
expect(err).to be_a(RangeError).or be_a(ArgumentError)
|
179
|
+
}
|
180
|
+
}
|
181
|
+
}
|
182
|
+
end
|
166
183
|
end
|
167
184
|
|
168
185
|
describe 'elements' do
|
@@ -394,6 +411,23 @@ shared_examples 'Matrix' do
|
|
394
411
|
}
|
395
412
|
expect{mat[2] / mat[3]}.to raise_error(RuntimeError)
|
396
413
|
end
|
414
|
+
it 'have resize!' do
|
415
|
+
[-1, :sym].each{|arg|
|
416
|
+
[[arg, nil], [nil, arg]].each{|args|
|
417
|
+
expect{mat[0].resize!(*args)}.to raise_error{|err|
|
418
|
+
expect(err).to be_a(TypeError).or be_a(ArgumentError)
|
419
|
+
}
|
420
|
+
}
|
421
|
+
}
|
422
|
+
mat_orig = mat[0].to_a
|
423
|
+
r, c = [:rows, :columns].collect{|f| mat[0].send(f)}
|
424
|
+
expect(mat[0].resize!(r, c).to_a).to eq(mat_orig)
|
425
|
+
expect(mat[0].resize!(r, nil).to_a).to eq(mat_orig)
|
426
|
+
expect(mat[0].resize!(nil, c).to_a).to eq(mat_orig)
|
427
|
+
expect(mat[0].resize!(nil, nil).to_a).to eq(mat_orig)
|
428
|
+
expect(mat[0].resize!(r * 2, c * 2).to_a).to \
|
429
|
+
eq(Matrix::build(r * 2, c * 2){|i, j| (i < r && j < c) ? mat_orig[i][j] : 0}.to_a)
|
430
|
+
end
|
397
431
|
end
|
398
432
|
|
399
433
|
describe 'decomposition' do
|
data/gps_pvt.gemspec
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "lib/gps_pvt/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = "gps_pvt"
|
7
|
+
spec.version = GPS_PVT::VERSION
|
8
|
+
spec.authors = ["fenrir(M.Naruoka)"]
|
9
|
+
spec.email = ["fenrir.naru@gmail.com"]
|
10
|
+
|
11
|
+
spec.summary = "GPS position, velocity, and time (PVT) solver"
|
12
|
+
spec.description = "This module calculate PVT by using raw observation obtained from a GPS receiver"
|
13
|
+
spec.homepage = "https://github.com/fenrir-naru/gps_pvt"
|
14
|
+
spec.required_ruby_version = ">= 2.3.0"
|
15
|
+
|
16
|
+
#spec.metadata["allowed_push_host"] = "TODO: Set to your gem server 'https://example.com'"
|
17
|
+
|
18
|
+
spec.metadata["homepage_uri"] = spec.homepage
|
19
|
+
spec.metadata["source_code_uri"] = spec.homepage
|
20
|
+
#spec.metadata["changelog_uri"] = "TODO: Put your gem's CHANGELOG.md URL here."
|
21
|
+
|
22
|
+
spec.extensions = ["ext/gps_pvt/extconf.rb"]
|
23
|
+
|
24
|
+
# Specify which files should be added to the gem when it is released.
|
25
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
26
|
+
spec.files = Dir.chdir(File.expand_path(__dir__)) do
|
27
|
+
`git ls-files -z`.split("\x0").reject do |f|
|
28
|
+
(f == __FILE__) || f.match(%r{\A(?:(?:test|spec|features)/|\.(?:git|travis|circleci)|appveyor)})
|
29
|
+
end
|
30
|
+
end
|
31
|
+
spec.bindir = "exe"
|
32
|
+
spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
|
33
|
+
spec.require_paths = ["lib"]
|
34
|
+
|
35
|
+
spec.files += proc{
|
36
|
+
require 'pathname'
|
37
|
+
base_dir = Pathname::new(File::absolute_path(File.dirname(__FILE__)))
|
38
|
+
# get an array of submodule dirs by executing 'pwd' inside each submodule
|
39
|
+
`git submodule --quiet foreach pwd`.split($/).collect{|dir|
|
40
|
+
# issue git ls-files in submodule's directory
|
41
|
+
`git -C #{dir} ls-files -v`.split($/).collect{|f|
|
42
|
+
next nil unless f =~ /^H */ # consider git sparse checkout
|
43
|
+
# get relative path
|
44
|
+
f = Pathname::new(File::join(dir, $'))
|
45
|
+
begin
|
46
|
+
(f.relative? ? f : f.relative_path_from(base_dir)).to_s
|
47
|
+
rescue
|
48
|
+
# Patch for Windows drive letter problem
|
49
|
+
base_dir = Pathname::new(base_dir.to_s.sub(/^([^\/])+:\//){"/#{$1}/"})
|
50
|
+
f.relative_path_from(base_dir).to_s
|
51
|
+
end
|
52
|
+
}.compact
|
53
|
+
}.flatten
|
54
|
+
}.call
|
55
|
+
|
56
|
+
# Uncomment to register a new dependency of your gem
|
57
|
+
# spec.add_dependency "example-gem", "~> 1.0"
|
58
|
+
spec.add_development_dependency "rake"
|
59
|
+
spec.add_development_dependency "rake-compiler"
|
60
|
+
|
61
|
+
# For more information and examples about making a new gem, checkout our
|
62
|
+
# guide at: https://bundler.io/guides/creating_gem.html
|
63
|
+
end
|
data/lib/gps_pvt/receiver.rb
CHANGED
@@ -47,23 +47,31 @@ class Receiver
|
|
47
47
|
]] + [
|
48
48
|
[:used_satellites, proc{|pvt| pvt.used_satellites}],
|
49
49
|
] + opt[:system].collect{|sys, range|
|
50
|
-
|
51
|
-
|
50
|
+
range = range.kind_of?(Array) ? proc{
|
51
|
+
# check whether inputs can be converted to Range
|
52
|
+
next nil if range.empty?
|
53
|
+
a, b = range.minmax
|
54
|
+
((b - a) == (range.length - 1)) ? (a..b) : range
|
55
|
+
}.call : range
|
56
|
+
next nil unless range
|
57
|
+
bit_flip, label = case range
|
58
|
+
when Array
|
59
|
+
[proc{|res, i|
|
52
60
|
res[i] = "1" if i = range.index(i)
|
53
61
|
res
|
54
|
-
}
|
55
|
-
|
62
|
+
}, range.collect{|pen| pen & 0xFF}.reverse.join('+')]
|
63
|
+
when Range
|
56
64
|
base_prn = range.min
|
57
|
-
proc{|res, i|
|
65
|
+
[proc{|res, i|
|
58
66
|
res[i - base_prn] = "1" if range.include?(i)
|
59
67
|
res
|
60
|
-
}
|
68
|
+
}, [:max, :min].collect{|f| range.send(f) & 0xFF}.join('..')]
|
61
69
|
end
|
62
|
-
["#{sys}_PRN", proc{|pvt|
|
70
|
+
["#{sys}_PRN(#{label})", proc{|pvt|
|
63
71
|
pvt.used_satellite_list.inject("0" * range.size, &bit_flip) \
|
64
72
|
.scan(/.{1,8}/).join('_').reverse
|
65
73
|
}]
|
66
|
-
} + [[
|
74
|
+
}.compact + [[
|
67
75
|
opt[:satellites].collect{|prn, label|
|
68
76
|
[:range_residual, :weight, :azimuth, :elevation, :slopeH, :slopeV].collect{|str|
|
69
77
|
"#{str}(#{label || prn})"
|
@@ -73,12 +81,12 @@ class Receiver
|
|
73
81
|
next ([nil] * 6 * opt[:satellites].size) unless pvt.position_solved?
|
74
82
|
sats = pvt.used_satellite_list
|
75
83
|
r, w = [:delta_r, :W].collect{|f| pvt.send(f)}
|
76
|
-
opt[:satellites].collect{|
|
77
|
-
next ([nil] * 6) unless i2 = sats.index(
|
84
|
+
opt[:satellites].collect{|prn, label|
|
85
|
+
next ([nil] * 6) unless i2 = sats.index(prn)
|
78
86
|
[r[i2, 0], w[i2, i2]] +
|
79
87
|
[:azimuth, :elevation].collect{|f|
|
80
|
-
pvt.send(f)[
|
81
|
-
} + [pvt.slopeH[
|
88
|
+
pvt.send(f)[prn] / Math::PI * 180
|
89
|
+
} + [pvt.slopeH[prn], pvt.slopeV[prn]]
|
82
90
|
}.flatten
|
83
91
|
},
|
84
92
|
]] + [[
|
@@ -106,16 +114,19 @@ class Receiver
|
|
106
114
|
opt = {
|
107
115
|
:satellites => (1..32).to_a,
|
108
116
|
}.merge(opt)
|
117
|
+
keys = [:PSEUDORANGE, :RANGE_RATE, :DOPPLER, :FREQUENCY].collect{|k|
|
118
|
+
GPS::Measurement.const_get("L1_#{k}".to_sym)
|
119
|
+
}
|
109
120
|
[[
|
110
121
|
opt[:satellites].collect{|prn, label|
|
111
122
|
[:L1_range, :L1_rate].collect{|str| "#{str}(#{label || prn})"}
|
112
123
|
}.flatten,
|
113
124
|
proc{|meas|
|
114
|
-
meas_hash =
|
115
|
-
opt[:satellites].collect{|prn|
|
116
|
-
|
117
|
-
|
118
|
-
|
125
|
+
meas_hash = meas.to_hash
|
126
|
+
opt[:satellites].collect{|prn, label|
|
127
|
+
pr, rate, doppler, freq = keys.collect{|k| meas_hash[prn][k] rescue nil}
|
128
|
+
freq ||= GPS::SpaceNode.L1_Frequency
|
129
|
+
[pr, rate || ((doppler * GPS::SpaceNode::light_speed / freq) rescue nil)]
|
119
130
|
}
|
120
131
|
}
|
121
132
|
]]
|
@@ -130,11 +141,19 @@ class Receiver
|
|
130
141
|
|
131
142
|
def initialize(options = {})
|
132
143
|
@solver = GPS::Solver::new
|
133
|
-
@solver.hooks[:relative_property] = proc{|prn, rel_prop, rcv_e, t_arv, usr_pos, usr_vel|
|
144
|
+
@solver.hooks[:relative_property] = proc{|prn, rel_prop, meas, rcv_e, t_arv, usr_pos, usr_vel|
|
134
145
|
rel_prop[0] = 1 if rel_prop[0] > 0 # weight = 1
|
135
146
|
rel_prop
|
136
147
|
}
|
137
148
|
@debug = {}
|
149
|
+
solver_opts = [:gps_options, :sbas_options].collect{|target|
|
150
|
+
@solver.send(target)
|
151
|
+
}
|
152
|
+
solver_opts.each{|opt|
|
153
|
+
# default solver options
|
154
|
+
opt.elevation_mask = 0.0 / 180 * Math::PI # 0 deg (use satellite over horizon)
|
155
|
+
opt.residual_mask = 1E4 # 10 km (without residual filter, practically)
|
156
|
+
}
|
138
157
|
output_options = {
|
139
158
|
:system => [[:GPS, 1..32], [:QZSS, 193..202]],
|
140
159
|
:satellites => (1..32).to_a + (193..202).to_a, # [idx, ...] or [[idx, label], ...] is acceptable
|
@@ -148,7 +167,7 @@ class Receiver
|
|
148
167
|
when :weight
|
149
168
|
case v.to_sym
|
150
169
|
when :elevation # (same as underneath C++ library)
|
151
|
-
@solver.hooks[:relative_property] = proc{|prn, rel_prop, rcv_e, t_arv, usr_pos, usr_vel|
|
170
|
+
@solver.hooks[:relative_property] = proc{|prn, rel_prop, meas, rcv_e, t_arv, usr_pos, usr_vel|
|
152
171
|
if rel_prop[0] > 0 then
|
153
172
|
elv = Coordinate::ENU::relative_rel(
|
154
173
|
Coordinate::XYZ::new(*rel_prop[4..6]), usr_pos).elevation
|
@@ -160,6 +179,13 @@ class Receiver
|
|
160
179
|
when :identical # same as default
|
161
180
|
next true
|
162
181
|
end
|
182
|
+
when :elevation_mask_deg
|
183
|
+
raise "Unknown elevation mask angle: #{v}" unless elv_deg = (Float(v) rescue nil)
|
184
|
+
$stderr.puts "Elevation mask: #{elv_deg} deg"
|
185
|
+
solver_opts.each{|opt|
|
186
|
+
opt.elevation_mask = elv_deg / 180 * Math::PI # 0 deg (use satellite over horizon)
|
187
|
+
}
|
188
|
+
next true
|
163
189
|
when :base_station
|
164
190
|
crd, sys = v.split(/ *, */).collect.with_index{|item, i|
|
165
191
|
case item
|
@@ -193,9 +219,9 @@ class Receiver
|
|
193
219
|
sys, svid = case spec
|
194
220
|
when Integer
|
195
221
|
[nil, spec]
|
196
|
-
when
|
197
|
-
[$1.upcase.to_sym, (
|
198
|
-
when
|
222
|
+
when /^([a-zA-Z]+)(?::(-?\d+))?$/
|
223
|
+
[$1.upcase.to_sym, (Integer($2) rescue nil)]
|
224
|
+
when /^-?\d+$/
|
199
225
|
[nil, $&.to_i]
|
200
226
|
else
|
201
227
|
next false
|
@@ -206,27 +232,37 @@ class Receiver
|
|
206
232
|
else
|
207
233
|
(k == :with) ? :include : :exclude
|
208
234
|
end
|
209
|
-
|
210
|
-
|
211
|
-
[svid || ((1..32).to_a + (193..202).to_a)].flatten.each{
|
212
|
-
@solver.gps_options.send(mode, svid)
|
213
|
-
}
|
214
|
-
elsif (sys == :SBAS) || (svid && (120..158).include?(svid)) then
|
215
|
-
prns = [svid || (120..158).to_a].flatten
|
216
|
-
unless (i = output_options[:system].index{|sys, range| sys == :SBAS}) then
|
235
|
+
update_output = proc{|sys_target, prns, labels|
|
236
|
+
unless (i = output_options[:system].index{|sys, range| sys == sys_target}) then
|
217
237
|
i = -1
|
218
|
-
output_options[:system] << [
|
238
|
+
output_options[:system] << [sys_target, []]
|
219
239
|
else
|
220
|
-
output_options[:system][i].reject!{|prn| prns.include?(prn)}
|
240
|
+
output_options[:system][i][1].reject!{|prn| prns.include?(prn)}
|
221
241
|
end
|
222
242
|
output_options[:satellites].reject!{|prn, label| prns.include?(prn)}
|
223
243
|
if mode == :include then
|
224
244
|
output_options[:system][i][1] += prns
|
225
|
-
output_options[:
|
245
|
+
output_options[:system][i][1].sort!
|
246
|
+
output_options[:satellites] += (labels ? prns.zip(labels) : prns)
|
247
|
+
output_options[:satellites].sort!{|a, b| [a].flatten[0] <=> [b].flatten[0]}
|
226
248
|
end
|
249
|
+
}
|
250
|
+
check_sys_svid = proc{|sys_target, range_in_sys, offset|
|
251
|
+
next range_in_sys.include?(svid - (offset || 0)) unless sys # svid is specified without system
|
252
|
+
next false unless sys == sys_target
|
253
|
+
next true unless svid # All satellites in a target system (svid == nil)
|
254
|
+
range_in_sys.include?(svid)
|
255
|
+
}
|
256
|
+
if check_sys_svid.call(:GPS, 1..32) then
|
257
|
+
[svid || (1..32).to_a].flatten.each{|prn| @solver.gps_options.send(mode, prn)}
|
258
|
+
elsif check_sys_svid.call(:SBAS, 120..158) then
|
259
|
+
prns = [svid || (120..158).to_a].flatten
|
260
|
+
update_output.call(:SBAS, prns)
|
227
261
|
prns.each{|prn| @solver.sbas_options.send(mode, prn)}
|
262
|
+
elsif check_sys_svid.call(:QZSS, 193..202) then
|
263
|
+
[svid || (193..202).to_a].flatten.each{|prn| @solver.gps_options.send(mode, prn)}
|
228
264
|
else
|
229
|
-
|
265
|
+
raise "Unknown satellite: #{spec}"
|
230
266
|
end
|
231
267
|
$stderr.puts "#{mode.capitalize} satellite: #{[sys, svid].compact.join(':')}"
|
232
268
|
}
|
@@ -235,10 +271,6 @@ class Receiver
|
|
235
271
|
false
|
236
272
|
}
|
237
273
|
raise "Unknown receiver options: #{options.inspect}" unless options.empty?
|
238
|
-
proc{|opt|
|
239
|
-
opt.elevation_mask = 0.0 / 180 * Math::PI # 0 deg
|
240
|
-
opt.residual_mask = 1E4 # 10 km
|
241
|
-
}.call(@solver.gps_options)
|
242
274
|
@output = {
|
243
275
|
:pvt => Receiver::pvt_items(output_options),
|
244
276
|
:meas => Receiver::meas_items(output_options),
|
@@ -316,6 +348,11 @@ class Receiver
|
|
316
348
|
[:azimuth, :elevation, :slopeH, :slopeV].each{|k|
|
317
349
|
eval("define_method(:#{k}){@#{k} || self.post_solution(:@#{k})}")
|
318
350
|
}
|
351
|
+
define_method(:other_state){
|
352
|
+
# If a design matrix G has columns larger than 4,
|
353
|
+
# other states excluding position and time are estimated.
|
354
|
+
(self.G.rows <= 4) ? [] : (self.S * self.delta_r).transpose.to_a[0][4..-1]
|
355
|
+
}
|
319
356
|
}
|
320
357
|
|
321
358
|
proc{
|
@@ -477,8 +514,15 @@ class Receiver
|
|
477
514
|
end
|
478
515
|
|
479
516
|
def parse_rinex_nav(fname)
|
480
|
-
|
481
|
-
|
517
|
+
items = [
|
518
|
+
@solver.gps_space_node,
|
519
|
+
@solver.sbas_space_node,
|
520
|
+
].inject(0){|res, sn|
|
521
|
+
loaded_items = sn.send(:read, fname)
|
522
|
+
raise "Format error! (Not RINEX) #{fname}" if loaded_items < 0
|
523
|
+
res + loaded_items
|
524
|
+
}
|
525
|
+
$stderr.puts "Read RINEX NAV file (%s): %d items."%[fname, items]
|
482
526
|
end
|
483
527
|
|
484
528
|
def parse_rinex_obs(fname, &b)
|
@@ -515,7 +559,8 @@ class Receiver
|
|
515
559
|
when 'J'; prn += 192
|
516
560
|
else; next
|
517
561
|
end
|
518
|
-
|
562
|
+
types[sys] = (types[' '] || []) unless types[sys]
|
563
|
+
types[sys].each{|i, type_|
|
519
564
|
meas.add(prn, type_, v[i][0]) if v[i]
|
520
565
|
}
|
521
566
|
}
|
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.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- fenrir(M.Naruoka)
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-01
|
11
|
+
date: 2022-03-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|
@@ -89,6 +89,7 @@ files:
|
|
89
89
|
- ext/ninja-scan-light/tool/swig/makefile
|
90
90
|
- ext/ninja-scan-light/tool/swig/spec/GPS_spec.rb
|
91
91
|
- ext/ninja-scan-light/tool/swig/spec/SylphideMath_spec.rb
|
92
|
+
- gps_pvt.gemspec
|
92
93
|
- lib/gps_pvt.rb
|
93
94
|
- lib/gps_pvt/receiver.rb
|
94
95
|
- lib/gps_pvt/ubx.rb
|
@@ -99,7 +100,7 @@ licenses: []
|
|
99
100
|
metadata:
|
100
101
|
homepage_uri: https://github.com/fenrir-naru/gps_pvt
|
101
102
|
source_code_uri: https://github.com/fenrir-naru/gps_pvt
|
102
|
-
post_install_message:
|
103
|
+
post_install_message:
|
103
104
|
rdoc_options: []
|
104
105
|
require_paths:
|
105
106
|
- lib
|
@@ -114,8 +115,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
114
115
|
- !ruby/object:Gem::Version
|
115
116
|
version: '0'
|
116
117
|
requirements: []
|
117
|
-
rubygems_version: 3.
|
118
|
-
signing_key:
|
118
|
+
rubygems_version: 3.1.2
|
119
|
+
signing_key:
|
119
120
|
specification_version: 4
|
120
121
|
summary: GPS position, velocity, and time (PVT) solver
|
121
122
|
test_files: []
|