gps_pvt 0.2.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- 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: []
|