gps_pvt 0.7.0 → 0.8.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 +2 -2
- data/exe/gps_pvt +3 -2
- data/ext/gps_pvt/GPS/GPS_wrap.cxx +116 -1
- data/ext/ninja-scan-light/tool/navigation/GLONASS.h +4 -11
- data/ext/ninja-scan-light/tool/navigation/GLONASS_Solver.h +25 -13
- data/ext/ninja-scan-light/tool/navigation/GPS.h +21 -18
- data/ext/ninja-scan-light/tool/navigation/GPS_Solver.h +42 -25
- data/ext/ninja-scan-light/tool/navigation/GPS_Solver_Base.h +38 -17
- data/ext/ninja-scan-light/tool/navigation/GPS_Solver_RAIM.h +29 -1
- data/ext/ninja-scan-light/tool/navigation/RINEX.h +2 -6
- data/ext/ninja-scan-light/tool/navigation/SBAS.h +31 -3
- data/ext/ninja-scan-light/tool/navigation/SBAS_Solver.h +26 -14
- data/ext/ninja-scan-light/tool/navigation/SP3.h +3 -2
- data/ext/ninja-scan-light/tool/param/bit_array.h +2 -2
- data/ext/ninja-scan-light/tool/swig/GPS.i +29 -1
- data/ext/ninja-scan-light/tool/swig/spec/GPS_spec.rb +134 -13
- data/gps_pvt.gemspec +1 -0
- data/lib/gps_pvt/receiver.rb +82 -55
- data/lib/gps_pvt/util.rb +33 -1
- data/lib/gps_pvt/version.rb +1 -1
- metadata +16 -2
data/lib/gps_pvt/receiver.rb
CHANGED
@@ -19,6 +19,7 @@ class Receiver
|
|
19
19
|
opt = {
|
20
20
|
:system => [[:GPS, 1..32]],
|
21
21
|
:satellites => (1..32).to_a,
|
22
|
+
:FDE => true,
|
22
23
|
}.merge(opt)
|
23
24
|
[[
|
24
25
|
[:week, :itow_rcv, :year, :month, :mday, :hour, :min, :sec_rcv_UTC],
|
@@ -106,7 +107,7 @@ class Receiver
|
|
106
107
|
el_deg = [4, 6].collect{|i| pvt.elevation[fd[i]] / Math::PI * 180}
|
107
108
|
fd[0..4] + [el_deg[0]] + fd[5..6] + [el_deg[1]]
|
108
109
|
}
|
109
|
-
]] + [[
|
110
|
+
]] + (opt[:FDE] ? [[
|
110
111
|
[:wssr_FDE_min, :wssr_FDE_min_PRN, :wssr_FDE_2nd, :wssr_FDE_2nd_PRN],
|
111
112
|
proc{|pvt|
|
112
113
|
[:fde_min, :fde_2nd].collect{|f|
|
@@ -115,7 +116,7 @@ class Receiver
|
|
115
116
|
[info[0], info[-3]]
|
116
117
|
}.flatten
|
117
118
|
}
|
118
|
-
]]
|
119
|
+
]] : [])
|
119
120
|
end
|
120
121
|
|
121
122
|
def self.meas_items(opt = {})
|
@@ -149,11 +150,11 @@ class Receiver
|
|
149
150
|
|
150
151
|
def initialize(options = {})
|
151
152
|
@solver = GPS::Solver::new
|
152
|
-
@solver.
|
153
|
-
|
154
|
-
rel_prop
|
153
|
+
@solver.options = {
|
154
|
+
:skip_exclusion => true, # default is to skip fault exclusion calculation
|
155
155
|
}
|
156
156
|
@debug = {}
|
157
|
+
@semaphore = Mutex::new
|
157
158
|
solver_opts = [:gps_options, :sbas_options, :glonass_options].collect{|target|
|
158
159
|
@solver.send(target)
|
159
160
|
}
|
@@ -165,8 +166,10 @@ class Receiver
|
|
165
166
|
output_options = {
|
166
167
|
:system => [[:GPS, 1..32], [:QZSS, 193..202]],
|
167
168
|
:satellites => (1..32).to_a + (193..202).to_a, # [idx, ...] or [[idx, label], ...] is acceptable
|
169
|
+
:FDE => false,
|
168
170
|
}
|
169
171
|
options = options.reject{|k, v|
|
172
|
+
def v.to_b; !(self =~ /^(?:false|0|f|off)$/i); end
|
170
173
|
case k
|
171
174
|
when :debug
|
172
175
|
v = v.split(/,/)
|
@@ -174,7 +177,7 @@ class Receiver
|
|
174
177
|
next true
|
175
178
|
when :weight
|
176
179
|
case v.to_sym
|
177
|
-
when :elevation # (same as underneath C++ library)
|
180
|
+
when :elevation # (same as underneath C++ library except for ignoring broadcasted/calculated URA)
|
178
181
|
@solver.hooks[:relative_property] = proc{|prn, rel_prop, meas, rcv_e, t_arv, usr_pos, usr_vel|
|
179
182
|
if rel_prop[0] > 0 then
|
180
183
|
elv = Coordinate::ENU::relative_rel(
|
@@ -184,7 +187,11 @@ class Receiver
|
|
184
187
|
rel_prop
|
185
188
|
}
|
186
189
|
next true
|
187
|
-
when :identical # same
|
190
|
+
when :identical # treat each satellite range having same accuracy
|
191
|
+
@solver.hooks[:relative_property] = proc{|prn, rel_prop, meas, rcv_e, t_arv, usr_pos, usr_vel|
|
192
|
+
rel_prop[0] = 1 if rel_prop[0] > 0 # weight = 1
|
193
|
+
rel_prop
|
194
|
+
}
|
188
195
|
next true
|
189
196
|
end
|
190
197
|
when :elevation_mask_deg
|
@@ -280,6 +287,9 @@ class Receiver
|
|
280
287
|
$stderr.puts "#{mode.capitalize} satellite: #{[sys, svid].compact.join(':')}"
|
281
288
|
}
|
282
289
|
next true
|
290
|
+
when :fault_exclusion
|
291
|
+
@solver.options = {:skip_exclusion => !(output_options[:FDE] = v.to_b)}
|
292
|
+
next true
|
283
293
|
end
|
284
294
|
false
|
285
295
|
}
|
@@ -289,6 +299,24 @@ class Receiver
|
|
289
299
|
:meas => Receiver::meas_items(output_options),
|
290
300
|
}
|
291
301
|
end
|
302
|
+
|
303
|
+
def critical(&b)
|
304
|
+
begin
|
305
|
+
@semaphore.synchronize{b.call}
|
306
|
+
rescue ThreadError # recovery from deadlock
|
307
|
+
b.call
|
308
|
+
end
|
309
|
+
end
|
310
|
+
|
311
|
+
class << self
|
312
|
+
def make_critical(fname)
|
313
|
+
f_orig = instance_method(fname)
|
314
|
+
define_method(fname){|*args, &b|
|
315
|
+
critical{f_orig.bind(self).call(*args, &b)}
|
316
|
+
}
|
317
|
+
end
|
318
|
+
private :make_critical
|
319
|
+
end
|
292
320
|
|
293
321
|
GPS::Measurement.class_eval{
|
294
322
|
proc{
|
@@ -322,7 +350,7 @@ class Receiver
|
|
322
350
|
=end
|
323
351
|
|
324
352
|
#@solver.gps_space_node.update_all_ephemeris(t_meas) # internally called in the following solver.solve
|
325
|
-
pvt = @solver.solve(meas, t_meas)
|
353
|
+
pvt = critical{@solver.solve(meas, t_meas)}
|
326
354
|
pvt.define_singleton_method(:rel_ENU){
|
327
355
|
Coordinate::ENU::relative(xyz, ref_pos)
|
328
356
|
} if (ref_pos && pvt.position_solved?)
|
@@ -369,60 +397,59 @@ class Receiver
|
|
369
397
|
}
|
370
398
|
}
|
371
399
|
|
372
|
-
|
373
|
-
eph_list
|
400
|
+
def register_ephemeris(t_meas, sys, prn, bcast_data, *options)
|
401
|
+
@eph_list ||= Hash[*((1..32).to_a + (193..202).to_a).collect{|prn|
|
374
402
|
eph = GPS::Ephemeris::new
|
375
403
|
eph.svid = prn
|
376
404
|
[prn, eph]
|
377
405
|
}.flatten(1)]
|
378
|
-
eph_glonass_list
|
406
|
+
@eph_glonass_list ||= Hash[*(1..24).collect{|num|
|
379
407
|
eph = GPS::Ephemeris_GLONASS::new
|
380
408
|
eph.svid = num
|
381
409
|
[num, eph]
|
382
410
|
}.flatten(1)]
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
rescue
|
398
|
-
end
|
399
|
-
next
|
411
|
+
opt = options[0] || {}
|
412
|
+
case sys
|
413
|
+
when :GPS, :QZSS
|
414
|
+
return unless eph = @eph_list[prn]
|
415
|
+
sn = @solver.gps_space_node
|
416
|
+
subframe, iodc_or_iode = eph.parse(bcast_data)
|
417
|
+
if iodc_or_iode < 0 then
|
418
|
+
begin
|
419
|
+
sn.update_iono_utc(
|
420
|
+
GPS::Ionospheric_UTC_Parameters::parse(bcast_data))
|
421
|
+
[:alpha, :beta].each{|k|
|
422
|
+
$stderr.puts "Iono #{k}: #{sn.iono_utc.send(k)}"
|
423
|
+
} if false
|
424
|
+
rescue
|
400
425
|
end
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
when :SBAS
|
407
|
-
case @solver.sbas_space_node.decode_message(bcast_data[0..7], prn, t_meas)
|
408
|
-
when 26
|
409
|
-
['', "IGP broadcasted by PRN#{prn} @ #{Time::utc(*t_meas.c_tm)}",
|
410
|
-
@solver.sbas_space_node.ionospheric_grid_points(prn)].each{|str|
|
411
|
-
$stderr.puts str
|
412
|
-
} if @debug[:SBAS_IGP]
|
413
|
-
end if t_meas
|
414
|
-
when :GLONASS
|
415
|
-
next unless eph = eph_glonass_list[prn]
|
416
|
-
leap_sec = @solver.gps_space_node.is_valid_utc ?
|
417
|
-
@solver.gps_space_node.iono_utc.delta_t_LS :
|
418
|
-
GPS::Time::guess_leap_seconds(t_meas)
|
419
|
-
next unless eph.parse(bcast_data[0..3], leap_sec)
|
420
|
-
eph.freq_ch = opt[:freq_ch] || 0
|
421
|
-
@solver.glonass_space_node.register_ephemeris(prn, eph)
|
426
|
+
return
|
427
|
+
end
|
428
|
+
if t_meas and eph.consistent? then
|
429
|
+
eph.WN = ((t_meas.week / 1024).to_i * 1024) + (eph.WN % 1024)
|
430
|
+
sn.register_ephemeris(prn, eph)
|
422
431
|
eph.invalidate
|
423
432
|
end
|
424
|
-
|
425
|
-
|
433
|
+
when :SBAS
|
434
|
+
case @solver.sbas_space_node.decode_message(bcast_data[0..7], prn, t_meas)
|
435
|
+
when 26
|
436
|
+
['', "IGP broadcasted by PRN#{prn} @ #{Time::utc(*t_meas.c_tm)}",
|
437
|
+
@solver.sbas_space_node.ionospheric_grid_points(prn)].each{|str|
|
438
|
+
$stderr.puts str
|
439
|
+
} if @debug[:SBAS_IGP]
|
440
|
+
end if t_meas
|
441
|
+
when :GLONASS
|
442
|
+
return unless eph = @eph_glonass_list[prn]
|
443
|
+
leap_sec = @solver.gps_space_node.is_valid_utc ?
|
444
|
+
@solver.gps_space_node.iono_utc.delta_t_LS :
|
445
|
+
GPS::Time::guess_leap_seconds(t_meas)
|
446
|
+
return unless eph.parse(bcast_data[0..3], leap_sec)
|
447
|
+
eph.freq_ch = opt[:freq_ch] || 0
|
448
|
+
@solver.glonass_space_node.register_ephemeris(prn, eph)
|
449
|
+
eph.invalidate
|
450
|
+
end
|
451
|
+
end
|
452
|
+
make_critical :register_ephemeris
|
426
453
|
|
427
454
|
def parse_ubx(ubx_fname, &b)
|
428
455
|
$stderr.print "Reading UBX file (%s) "%[ubx_fname]
|
@@ -555,7 +582,7 @@ class Receiver
|
|
555
582
|
@solver.sbas_space_node,
|
556
583
|
@solver.glonass_space_node,
|
557
584
|
].inject(0){|res, sn|
|
558
|
-
loaded_items = sn.send(:read, fname)
|
585
|
+
loaded_items = critical{sn.send(:read, fname)}
|
559
586
|
raise "Format error! (Not RINEX) #{src}" if loaded_items < 0
|
560
587
|
res + loaded_items
|
561
588
|
}
|
@@ -639,7 +666,7 @@ class Receiver
|
|
639
666
|
next unless /^SYS_(?!SYSTEMS)(.*)/ =~ sys.to_s
|
640
667
|
idx, sys_name = [@sp3.class.const_get(sys), $1]
|
641
668
|
next unless sats[idx] > 0
|
642
|
-
next unless @sp3.push(@solver, idx)
|
669
|
+
next unless critical{@sp3.push(@solver, idx)}
|
643
670
|
$stderr.puts "Change ephemeris source of #{sys_name} to SP3"
|
644
671
|
}
|
645
672
|
end
|
@@ -647,7 +674,7 @@ class Receiver
|
|
647
674
|
def attach_antex(src)
|
648
675
|
fname = Util::get_txt(src)
|
649
676
|
raise "Specify SP3 before ANTEX application!" unless @sp3
|
650
|
-
applied_items = @sp3.apply_antex(fname)
|
677
|
+
applied_items = critical{@sp3.apply_antex(fname)}
|
651
678
|
raise "Format error! (Not ANTEX) #{src}" unless applied_items >= 0
|
652
679
|
$stderr.puts "SP3 correction with ANTEX file (%s): %d items have been processed."%[src, applied_items]
|
653
680
|
end
|
@@ -663,7 +690,7 @@ class Receiver
|
|
663
690
|
next unless /^SYS_(?!SYSTEMS)(.*)/ =~ sys.to_s
|
664
691
|
idx, sys_name = [@clk.class.const_get(sys), $1]
|
665
692
|
next unless sats[idx] > 0
|
666
|
-
next unless @clk.push(@solver, idx)
|
693
|
+
next unless critical{@clk.push(@solver, idx)}
|
667
694
|
$stderr.puts "Change clock error source of #{sys_name} to RINEX clock"
|
668
695
|
}
|
669
696
|
end
|
data/lib/gps_pvt/util.rb
CHANGED
@@ -1,7 +1,39 @@
|
|
1
|
-
require 'open-uri'
|
2
1
|
require 'tempfile'
|
3
2
|
require 'uri'
|
4
3
|
|
4
|
+
proc{
|
5
|
+
# port[:baudrate], baudrate default is 115200
|
6
|
+
Serial.class_eval{
|
7
|
+
const_set(:SPEC,
|
8
|
+
if RubySerial::ON_WINDOWS then
|
9
|
+
%r{^(?:\\\\.\\)?(COM\d+)(?::(\d+))?$}
|
10
|
+
elsif RubySerial::ON_LINUX then
|
11
|
+
%r{^(/dev/tty[^:]+)(?::(\d+))?$}
|
12
|
+
else
|
13
|
+
nil
|
14
|
+
end)
|
15
|
+
}
|
16
|
+
Serial.class_eval{
|
17
|
+
read_orig = instance_method(:read)
|
18
|
+
define_method(:read){|len|
|
19
|
+
buf = ''
|
20
|
+
f = read_orig.bind(self)
|
21
|
+
buf += f.call(len - buf.size) while buf.size < len
|
22
|
+
buf
|
23
|
+
}
|
24
|
+
def eof?; false; end
|
25
|
+
}
|
26
|
+
Kernel.instance_eval{
|
27
|
+
open_orig = method(:open)
|
28
|
+
define_method(:open){|*args, &b|
|
29
|
+
return open_orig.call(*args, &b) unless Serial::SPEC =~ args[0]
|
30
|
+
Serial::new($1, $2 ? $2.to_i : 115200)
|
31
|
+
}
|
32
|
+
}
|
33
|
+
}.call if require 'rubyserial'
|
34
|
+
|
35
|
+
require 'open-uri'
|
36
|
+
|
5
37
|
module GPS_PVT
|
6
38
|
module Util
|
7
39
|
class << self
|
data/lib/gps_pvt/version.rb
CHANGED
metadata
CHANGED
@@ -1,15 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: gps_pvt
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.8.0
|
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: 2022-
|
11
|
+
date: 2022-09-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rubyserial
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
13
27
|
- !ruby/object:Gem::Dependency
|
14
28
|
name: rake
|
15
29
|
requirement: !ruby/object:Gem::Requirement
|