gps_pvt 0.8.0 → 0.8.1
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/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
|