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.
@@ -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
@@ -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
- require_relative 'GPS'
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
- packet.slice(6 + 2, 40).each_slice(4).collect{|v|
560
- res = v.pack("C*").unpack("V")[0]
561
- (sys == :GPS) ? ((res & 0xFFFFFF) << 6) : res
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]).each_slice(4).collect{|v|
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'
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module GPS_PVT
4
- VERSION = "0.8.0"
4
+ VERSION = "0.8.1"
5
5
  end
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.0
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-09-13 00:00:00.000000000 Z
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