gps_pvt 0.8.0 → 0.8.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Rakefile +1 -0
- data/exe/gps_pvt +1 -17
- data/exe/to_ubx +103 -8
- data/ext/gps_pvt/GPS/GPS_wrap.cxx +1136 -65
- data/ext/ninja-scan-light/tool/navigation/GLONASS.h +137 -9
- data/ext/ninja-scan-light/tool/navigation/GPS.h +301 -50
- data/ext/ninja-scan-light/tool/navigation/QZSS.h +48 -15
- data/ext/ninja-scan-light/tool/navigation/SBAS.h +106 -4
- data/ext/ninja-scan-light/tool/param/bit_array.h +53 -16
- data/ext/ninja-scan-light/tool/swig/GPS.i +228 -24
- data/ext/ninja-scan-light/tool/swig/spec/GPS_spec.rb +61 -0
- data/ext/ninja-scan-light/tool/util/bit_counter.h +84 -0
- data/lib/gps_pvt/receiver/extension.rb +51 -0
- data/lib/gps_pvt/receiver.rb +13 -8
- data/lib/gps_pvt/version.rb +1 -1
- metadata +4 -2
@@ -765,9 +765,70 @@ __RINEX_CLK_TEXT__
|
|
765
765
|
[:alpha, :beta].each{|k|
|
766
766
|
puts "Iono #{k}: #{sn.iono_utc.send(k)}"
|
767
767
|
}
|
768
|
+
proc{|raw|
|
769
|
+
expect(raw.size).to eq(10)
|
770
|
+
puts "Raw(IONO): #{raw.collect{|v| "0x%08X" % [v]}.join(', ')}"
|
771
|
+
iono2 = GPS::Ionospheric_UTC_Parameters::parse(raw)
|
772
|
+
[:alpha, :beta].collect{|f|
|
773
|
+
sn.iono_utc.send(f).zip(iono2.send(f))
|
774
|
+
}.flatten(1).zip([-30, -27, -24, -24, 11, 14, 16, 16]).each{|(a, b), sf|
|
775
|
+
expect(a).to be_within((2 ** sf) * 2).of(b)
|
776
|
+
}
|
777
|
+
[
|
778
|
+
[:A1, 2 ** -50], [:A0, 2 ** -30],
|
779
|
+
].each{|k, sf|
|
780
|
+
#p [k, sf.to_f, sn.iono_utc.send(k) - iono2.send(k), sn.iono_utc.send(k), iono2.send(k)]
|
781
|
+
expect(sn.iono_utc.send(k)).to be_within((sf || 1).to_f * 2).of(iono2.send(k))
|
782
|
+
}
|
783
|
+
}.call(sn.iono_utc.dump(t_meas))
|
768
784
|
|
769
785
|
meas.each{|prn, k, v|
|
770
786
|
eph = sn.ephemeris(prn)
|
787
|
+
expect(eph.valid?(t_meas)).to eq(true)
|
788
|
+
sc2rad = 3.1415926535898
|
789
|
+
proc{|raw|
|
790
|
+
expect(raw.size).to eq(30)
|
791
|
+
eph2 = GPS::Ephemeris::new
|
792
|
+
raw.each_slice(10).with_index{|subframe, i|
|
793
|
+
puts "Raw(PRN:#{prn},SF:#{i+1}): #{subframe.collect{|v| "0x%08X" % [v]}.join(', ')}"
|
794
|
+
eph2.parse(subframe)
|
795
|
+
}
|
796
|
+
expect(eph.WN % 1024).to be(eph2.WN % 1024)
|
797
|
+
[
|
798
|
+
#:URA,
|
799
|
+
:SV_health, :iodc,
|
800
|
+
[:t_GD, 2 ** -31], [:t_oc, 2 ** 4], # SF1
|
801
|
+
[:a_f0, 2 ** -31], [:a_f1, 2 ** -43], [:a_f2, 2 ** -55], # SF1
|
802
|
+
:iode, # SF2
|
803
|
+
[:c_rs, 2 ** -5], [:delta_n, sc2rad * 2 ** -43], # SF2
|
804
|
+
[:M0, sc2rad * 2 ** -31], [:c_uc, 2 ** -29], [:e, 2 ** -33], # SF2
|
805
|
+
[:c_us, 2 ** -29], [:sqrt_A, 2 ** -19], [:t_oe, 2 ** 4], # SF2
|
806
|
+
:fit_interval, # SF2
|
807
|
+
[:c_ic, 2 ** -29], [:Omega0, sc2rad * 2 ** -31], [:c_is, 2 ** -29], # SF3
|
808
|
+
[:i0, sc2rad * 2 ** -31], [:c_rc, 2 ** -5], [:omega, sc2rad * 2 ** -31], # SF3
|
809
|
+
[:dot_Omega0, sc2rad * 2 ** -43], [:dot_i0, sc2rad * 2 ** -43], # SF3
|
810
|
+
].each{|k, sf|
|
811
|
+
#p [k, sf.to_f, eph.send(k) - eph2.send(k), eph.send(k), eph2.send(k)]
|
812
|
+
expect(eph.send(k)).to be_within((sf || 1).to_f * 2).of(eph2.send(k))
|
813
|
+
}
|
814
|
+
}.call(eph.dump(t_meas))
|
815
|
+
proc{|raw| # Almanac -> Ephemeris
|
816
|
+
expect(raw.size).to eq(10)
|
817
|
+
puts "Raw(PRN:#{prn},Almanac): #{raw.collect{|v| "0x%08X" % [v]}.join(', ')}"
|
818
|
+
eph2 = GPS::Ephemeris::new
|
819
|
+
eph2.parse_almanac(raw)
|
820
|
+
[
|
821
|
+
:SV_health,
|
822
|
+
[:t_oc, 2 ** 12], [:a_f0, 2 ** -20], [:a_f1, 2 ** -38],
|
823
|
+
[:M0, sc2rad * 2 ** -23], [:e, 2 ** -21],
|
824
|
+
[:sqrt_A, 2 ** -11], [:t_oe, 2 ** 12],
|
825
|
+
[:Omega0, sc2rad * 2 ** -23], [:i0, sc2rad * 2 ** -19],
|
826
|
+
[:omega, sc2rad * 2 ** -23], [:dot_Omega0, sc2rad * 2 ** -38],
|
827
|
+
].each{|k, sf|
|
828
|
+
#p [k, sf.to_f, eph.send(k) - eph2.send(k), eph.send(k), eph2.send(k)]
|
829
|
+
expect(eph.send(k)).to be_within((sf || 1).to_f * 2).of(eph2.send(k))
|
830
|
+
}
|
831
|
+
}.call(eph.dump_almanac(t_meas))
|
771
832
|
puts "XYZ(PRN:#{prn}): #{eph.constellation(t_meas)[0].to_a} (iodc: #{eph.iodc}, iode: #{eph.iode})"
|
772
833
|
}
|
773
834
|
|
@@ -0,0 +1,84 @@
|
|
1
|
+
#ifndef __BIT_COUNTER__
|
2
|
+
#define __BIT_COUNTER__
|
3
|
+
|
4
|
+
#include <climits>
|
5
|
+
|
6
|
+
using namespace std;
|
7
|
+
|
8
|
+
/**
|
9
|
+
* Counting bits utility
|
10
|
+
*/
|
11
|
+
template <class T>
|
12
|
+
struct BitCounter {
|
13
|
+
|
14
|
+
static const int num_of_bits = CHAR_BIT * sizeof(T);
|
15
|
+
|
16
|
+
private:
|
17
|
+
template <int Interval>
|
18
|
+
static T make_mask(){
|
19
|
+
/*
|
20
|
+
* @see http://www.nminoru.jp/~nminoru/programming/bitcount.html
|
21
|
+
*
|
22
|
+
* 01010101010101010101010101010101 1 32
|
23
|
+
* 00110011001100110011001100110011 2 32
|
24
|
+
* 00001111000011110000111100001111 4 32
|
25
|
+
* 00000000111111110000000011111111 8 32
|
26
|
+
* 00000000000000001111111111111111 16 32
|
27
|
+
*/
|
28
|
+
|
29
|
+
T mask(1);
|
30
|
+
for(int i(1); i < Interval; i++){
|
31
|
+
mask <<= 1;
|
32
|
+
mask |= 0x01;
|
33
|
+
}
|
34
|
+
/*
|
35
|
+
// Equivalent to the following if T is built-in type
|
36
|
+
mask <<= Interval;
|
37
|
+
mask = (mask & (-mask)) - 1;
|
38
|
+
*/
|
39
|
+
|
40
|
+
T res(mask);
|
41
|
+
for(unsigned int i(1); i < num_of_bits / Interval / 2; i++){
|
42
|
+
res <<= Interval;
|
43
|
+
res <<= Interval;
|
44
|
+
res |= mask;
|
45
|
+
}
|
46
|
+
return res;
|
47
|
+
}
|
48
|
+
|
49
|
+
template <int Interval, class U = void>
|
50
|
+
struct count_loop {
|
51
|
+
static T run(T bits){
|
52
|
+
bits = count_loop<(Interval >> 1)>::run(bits);
|
53
|
+
static const T mask(make_mask<Interval>());
|
54
|
+
// bit shift and add operators are required at least
|
55
|
+
return (bits & mask) + ((bits >> Interval) & mask);
|
56
|
+
}
|
57
|
+
};
|
58
|
+
template <class U>
|
59
|
+
struct count_loop<1, U> {
|
60
|
+
static T run(T bits){
|
61
|
+
static const T mask(make_mask<1>());
|
62
|
+
return (bits & mask) + ((bits >> 1) & mask);
|
63
|
+
}
|
64
|
+
};
|
65
|
+
|
66
|
+
public:
|
67
|
+
/**
|
68
|
+
* Count bits in a value
|
69
|
+
* @param results
|
70
|
+
*/
|
71
|
+
static T count(const T &v) {
|
72
|
+
return count_loop<(num_of_bits >> 1)>::run(v);
|
73
|
+
}
|
74
|
+
|
75
|
+
/**
|
76
|
+
* Count rightmost zeros before the first one (Number of trailing zeros)
|
77
|
+
* @param bits results
|
78
|
+
*/
|
79
|
+
static T ntz(const T &v) {
|
80
|
+
return count((T)((~v) & (v - 1)));
|
81
|
+
}
|
82
|
+
};
|
83
|
+
|
84
|
+
#endif /* __BIT_COUNTER__ */
|
@@ -0,0 +1,51 @@
|
|
1
|
+
=begin
|
2
|
+
Receiver extension
|
3
|
+
=end
|
4
|
+
|
5
|
+
module GPS_PVT
|
6
|
+
class Receiver
|
7
|
+
|
8
|
+
# shortcut to access ephemeris registered in receiver
|
9
|
+
def ephemeris(t, sys, prn)
|
10
|
+
eph = case sys
|
11
|
+
when :GPS, :QZSS
|
12
|
+
critical{
|
13
|
+
@solver.gps_space_node.update_all_ephemeris(t)
|
14
|
+
@solver.gps_space_node.ephemeris(prn)
|
15
|
+
}
|
16
|
+
when :SBAS
|
17
|
+
critical{
|
18
|
+
@solver.sbas_space_node.update_all_ephemeris(t)
|
19
|
+
@solver.sbas_space_node.ephemeris(prn)
|
20
|
+
}
|
21
|
+
when :GLONASS
|
22
|
+
critical{
|
23
|
+
@solver.glonass_space_node.update_all_ephemeris(t)
|
24
|
+
@solver.glonass_space_node.ephemeris(prn)
|
25
|
+
}
|
26
|
+
else
|
27
|
+
return nil
|
28
|
+
end
|
29
|
+
return (eph.valid?(t) ? eph : nil)
|
30
|
+
end
|
31
|
+
|
32
|
+
def attach_online_ephemeris(uri_template = nil)
|
33
|
+
if (!uri_template) || (uri_template =~ /^\s*$/) then
|
34
|
+
uri_template = "ftp://gssc.esa.int/gnss/data/daily/%Y/brdc/BRDC00IGS_R_%Y%j0000_01D_MN.rnx.gz"
|
35
|
+
end
|
36
|
+
loader = proc{|t_meas|
|
37
|
+
utc = Time::utc(*t_meas.c_tm)
|
38
|
+
uri = URI::parse(utc.strftime(uri_template))
|
39
|
+
self.parse_rinex_nav(uri)
|
40
|
+
uri
|
41
|
+
}
|
42
|
+
run_orig = self.method(:run)
|
43
|
+
eph_list = {}
|
44
|
+
self.define_singleton_method(:run){|meas, t_meas, *args|
|
45
|
+
w_d = [t_meas.week, (t_meas.seconds.to_i / 86400)]
|
46
|
+
eph_list[w_d] ||= loader.call(t_meas)
|
47
|
+
run_orig.call(meas, t_meas, *args)
|
48
|
+
}
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
data/lib/gps_pvt/receiver.rb
CHANGED
@@ -3,7 +3,7 @@ Receiver class to be an top level interface to a user
|
|
3
3
|
(The origin is ninja-scan-light/tool/misc/receiver_debug.rb)
|
4
4
|
=end
|
5
5
|
|
6
|
-
|
6
|
+
require 'gps_pvt/GPS' # in case GPS.so is generated under ext/gps_pvt
|
7
7
|
require_relative 'util'
|
8
8
|
|
9
9
|
module GPS_PVT
|
@@ -523,6 +523,8 @@ class Receiver
|
|
523
523
|
v
|
524
524
|
}
|
525
525
|
sys, svid = gnss_serial.call(*loader.call(36, 2).reverse)
|
526
|
+
# sigID check to restrict signal to L1 if version(>0); @see UBX-18010854
|
527
|
+
next if (packet[6 + 13] != 0) && (loader.call(38, 1, "C") != 0)
|
526
528
|
case sys
|
527
529
|
when :GPS, :SBAS, :QZSS;
|
528
530
|
when :GLONASS
|
@@ -556,10 +558,13 @@ class Receiver
|
|
556
558
|
register_ephemeris(
|
557
559
|
t_meas,
|
558
560
|
sys, svid,
|
559
|
-
|
560
|
-
|
561
|
-
|
562
|
-
|
561
|
+
proc{|data|
|
562
|
+
case sys # adjust padding
|
563
|
+
when :GPS; data.collect!{|v| (v & 0xFFFFFF) << 6}
|
564
|
+
when :SBAS; data[7] <<= 6
|
565
|
+
end
|
566
|
+
data
|
567
|
+
}.call(packet.slice(6 + 2, 40).pack("C*").unpack("V*")))
|
563
568
|
when [0x02, 0x13] # RXM-SFRBX
|
564
569
|
sys, svid = gnss_serial.call(packet[6 + 1], packet[6])
|
565
570
|
opt = {}
|
@@ -567,9 +572,7 @@ class Receiver
|
|
567
572
|
register_ephemeris(
|
568
573
|
t_meas,
|
569
574
|
sys, svid,
|
570
|
-
packet.slice(6 + 8, 4 * packet[6 + 4]).
|
571
|
-
v.pack("C*").unpack("V")[0]
|
572
|
-
}, opt)
|
575
|
+
packet.slice(6 + 8, 4 * packet[6 + 4]).pack("C*").unpack("V*"), opt)
|
573
576
|
end
|
574
577
|
}
|
575
578
|
$stderr.puts ", found packets are %s"%[ubx_kind.inspect]
|
@@ -696,3 +699,5 @@ class Receiver
|
|
696
699
|
end
|
697
700
|
end
|
698
701
|
end
|
702
|
+
|
703
|
+
require_relative 'receiver/extension'
|
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.8.
|
4
|
+
version: 0.8.1
|
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-11-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rubyserial
|
@@ -112,11 +112,13 @@ files:
|
|
112
112
|
- ext/ninja-scan-light/tool/swig/makefile
|
113
113
|
- ext/ninja-scan-light/tool/swig/spec/GPS_spec.rb
|
114
114
|
- ext/ninja-scan-light/tool/swig/spec/SylphideMath_spec.rb
|
115
|
+
- ext/ninja-scan-light/tool/util/bit_counter.h
|
115
116
|
- ext/ninja-scan-light/tool/util/text_helper.h
|
116
117
|
- gps_pvt.gemspec
|
117
118
|
- gps_pvt.rbs
|
118
119
|
- lib/gps_pvt.rb
|
119
120
|
- lib/gps_pvt/receiver.rb
|
121
|
+
- lib/gps_pvt/receiver/extension.rb
|
120
122
|
- lib/gps_pvt/ubx.rb
|
121
123
|
- lib/gps_pvt/util.rb
|
122
124
|
- lib/gps_pvt/version.rb
|