gps_pvt 0.1.2 → 0.1.6

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 859eb4d8638d8ac33ffe0b070242da4a90e92427a49d3ecc8cca82850ad27921
4
- data.tar.gz: 6ddb0a60db3e9cf4adab2dd4bed0175ec86c8675c1223079a9801513e93f2769
3
+ metadata.gz: 5f4007b50ab655503a9f52a09cccd613ba7f21463989067887a71d2e45449d51
4
+ data.tar.gz: 945ef479edd3fdec649d8a4dffe4ce8cadb4d7a20e927171fbd817020f689fb6
5
5
  SHA512:
6
- metadata.gz: b7db4b42ef5175e1b90d95230bc40323d284f75bfa70a155d1dff0cc18ec8abf12b2b17990f2d59131dd32b2b6b718feab828a0d6f0650a5141304b43b0adfc8
7
- data.tar.gz: 49ee8add62f37aefbcf7ec5bbb154ab7b6dab0f30c0c7677193c80286ce4149b8aa9d7a626004fa5769b2fd7ae0ee823f511d7698a15571547b860895daee35c
6
+ metadata.gz: f42a861328b4f987061889268aaf2efbba1bf0c42f5cf6a830b97454ba45dc89d19203492366af2b3d746eb135e5a2553ee4bcff618fae0837c26f713015f0bf
7
+ data.tar.gz: 29b0e2e7e4eaf07bc8918a56942842763f4b4c3497986aabecea70a808a9d2c05289f1a07a2c5c745cb12358d622fc6d772e75dd7440e9063d5e517bcb76ac9f
data/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  GPS_PVT is a Ruby GPS (Global positioning system) PVT (position, velocity and time) solver. It accepts RINEX NAV and OBS files in addition to u-blox ubx format. Its significant features are easy to use with highly flexibility to customize internal solver behavior such as weight for each available satellite.
4
4
 
5
- The PVT solution is obtained with a stand alone positioning (i.e. neither differential nor kinematic) with least square. Its main internal codes are derived from ones of [ninja-scan-light](https://github.com/fenrir-naru/ninja-scan-light) having capability to calculate tightly-coupled GNSS/INS integrated solution. These codes are written by C++, and wrapped by [SWIG](http://www.swig.org/).
5
+ The PVT solution is obtained with a stand alone positioning (i.e. neither differential nor kinematic) with application of least square to each snapshot. Its main internal codes are derived from ones of [ninja-scan-light](https://github.com/fenrir-naru/ninja-scan-light) having capability to calculate tightly-coupled GNSS/INS integrated solution. These codes are written by C++, and wrapped by [SWIG](http://www.swig.org/).
6
6
 
7
7
  [![Gem Version](https://badge.fury.io/rb/gps_pvt.svg)](https://badge.fury.io/rb/gps_pvt)
8
8
  [![Ruby](https://github.com/fenrir-naru/gps_pvt/actions/workflows/main.yml/badge.svg)](https://github.com/fenrir-naru/gps_pvt/actions/workflows/main.yml)
@@ -27,6 +27,12 @@ For Windows users, this gem requires Devkit because of native compilation.
27
27
 
28
28
  ## Usage
29
29
 
30
+ For user who just generate PVT solution, an attached executable is useful. After installation, type
31
+
32
+ $ gps_pvt RINEX_or_UBX_file(s)
33
+
34
+ For developer, this library will be used in the following:
35
+
30
36
  ```ruby
31
37
  require 'gps_pvt'
32
38
 
@@ -40,7 +46,8 @@ receiver.parse_rinex_obs(rinex_obs_file)
40
46
 
41
47
  # Or precise control of outputs
42
48
  receiver.parse_rinex_obs(rinex_obs_file){|pvt, meas| # per epoch
43
- meas # => measurement, array of [prn, key, value]; key is represented by GPS_PVT::GPS::Measurement::L1_PSEUDORANGE
49
+ meas.to_a # => measurement, array of [prn, key, value]; key is represented by GPS_PVT::GPS::Measurement::L1_PSEUDORANGE; instead of .to_a, .to_hash returns {prn => {key => value, ...}, ...}
50
+
44
51
  pvt # => PVT solution, all properties are shown by pvt.methods
45
52
  # for example
46
53
  if(pvt.position_solved?){
@@ -53,6 +60,9 @@ receiver.parse_rinex_obs(rinex_obs_file){|pvt, meas| # per epoch
53
60
  pvt.receiver_error_rate # clock error rate in m/s
54
61
  }
55
62
  pvt.used_satellite_list # array of used, i.e., visible and weight>0, satellite
63
+ pvt.azimuth # azimuth angle [rad] to used satellites in Hash {prn => value, ...}
64
+ pvt.elevation # elevation angle [rad]
65
+
56
66
  pvt.G # design matrix in Earth-centered-Earth-fixed (ECEF); .to_a returns double array converted from matrix. its row corresponds to one of used_satellite_list
57
67
  pvt.G_enu # design matrix in East-North-Up (ENU)
58
68
  pvt.W # weight for each satellite
@@ -67,11 +77,28 @@ receiver.solver.options.include(prn) # Discard previous setting of exclusion
67
77
  receiver.solver.hooks[:relative_property] = proc{|prn, rel_prop, rcv_e, t_arv, usr_pos, usr_vel|
68
78
  # control weight per satellite per iteration
69
79
  weight, range_c, range_r, rate_rel_neg, *los_neg = rel_prop # relative property
70
- weight = 1 # default; same weight
80
+ # rcv_e, t_arv, usr_pos, usr_vel are temporary solution of
81
+ # receiver clock error [m], time of arrival [s], user position and velocity in ECEF, respectively.
82
+
83
+ weight = 1 # same as default; identical weight for each visible satellite
71
84
  # or weight based on elevation
72
85
  # elv = GPS_PVT::Coordinate::ENU::relative_rel(GPS_PVT::Coordinate::XYZ::new(*los_neg), usr_pos).elevation
73
86
  # weight = (Math::sin(elv)/0.8)**2
74
- [weight, range_c, range_r, rate_rel_neg] + los_neg
87
+
88
+ [weight, range_c, range_r, rate_rel_neg] + los_neg # must return relative property
89
+ }
90
+
91
+ # Dynamic customization of weight for each epoch
92
+ (class << receiver; self; end).instance_eval{ # do before parse_XXX
93
+ alias_method(:run_orig, :run)
94
+ define_method(:run){|meas, t_meas, &b|
95
+ meas # observation, same as the 2nd argument of parse_XXX
96
+ receiver.solver.hooks[:relative_property] = proc{|prn, rel_prop, rcv_e, t_arv, usr_pos, usr_vel|
97
+ # Do something based on meas, t_meas.
98
+ rel_prop
99
+ }
100
+ run_orig(meas, t_meas, &b)
101
+ }
75
102
  }
76
103
  ```
77
104
 
data/exe/gps_pvt ADDED
@@ -0,0 +1,46 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'gps_pvt'
4
+
5
+ # runnable quick example to solve PVT by using RINEX NAV/OBS or u-blox ubx
6
+
7
+ $stderr.puts <<__STRING__
8
+ Usage: #{__FILE__} GPS_file1 GPS_file2 ...
9
+ As GPS_file, rinex_nav(*.YYn), rinex_obs(*.YYo), and ubx(*.ubx) format are currently supported.
10
+ File format is automatically determined based on its extention described in above parentheses.
11
+ Note: YY = last two digit of year.
12
+ __STRING__
13
+
14
+ options = {}
15
+
16
+ # check options
17
+ ARGV.reject!{|arg|
18
+ next false unless arg =~ /^--([^=]+)=?/
19
+ options[$1.to_sym] = $'
20
+ true
21
+ }
22
+
23
+ # Check file existence
24
+ ARGV.each{|arg|
25
+ raise "File not found: #{arg}" unless File::exist?(arg)
26
+ }
27
+
28
+ rcv = GPS_PVT::Receiver::new(options)
29
+
30
+ puts GPS_PVT::Receiver::header
31
+
32
+ # parse RINEX NAV
33
+ ARGV.reject!{|arg|
34
+ next false unless arg =~ /\.\d{2}n$/
35
+ rcv.parse_rinex_nav(arg)
36
+ }
37
+
38
+ # other files
39
+ ARGV.each{|arg|
40
+ case arg
41
+ when /\.ubx$/
42
+ rcv.parse_ubx(arg)
43
+ when /\.\d{2}o$/
44
+ rcv.parse_rinex_obs(arg)
45
+ end
46
+ }
@@ -1,5 +1,3 @@
1
- #!/usr/bin/ruby
2
-
3
1
  =begin
4
2
  Receiver class to be an top level interface to a user
5
3
  (The origin is ninja-scan-light/tool/misc/receiver_debug.rb)
@@ -140,15 +138,15 @@ class Receiver
140
138
  end
141
139
 
142
140
  def run(meas, t_meas)
143
- #$stderr.puts "Measurement time: #{t_meas.to_a} (a.k.a #{"%d/%d/%d %d:%d:%d UTC"%[*t_meas.c_tm]})"
144
- sn = @solver.gps_space_node
145
- sn.update_all_ephemeris(t_meas)
146
-
141
+ =begin
142
+ $stderr.puts "Measurement time: #{t_meas.to_a} (a.k.a #{"%d/%d/%d %d:%d:%d UTC"%[*t_meas.c_tm]})"
147
143
  meas.to_a.collect{|prn, k, v| prn}.uniq.each{|prn|
148
- eph = sn.ephemeris(prn)
144
+ eph = @solver.gps_space_node.ephemeris(prn)
149
145
  $stderr.puts "XYZ(PRN:#{prn}): #{eph.constellation(t_meas)[0].to_a} (iodc: #{eph.iodc}, iode: #{eph.iode})"
150
- } if false
146
+ }
147
+ =end
151
148
 
149
+ #@solver.gps_space_node.update_all_ephemeris(t_meas) # internally called in the following solver.solve
152
150
  pvt = @solver.solve(meas, t_meas)
153
151
  pvt.define_singleton_method(:to_s){
154
152
  (OUTPUT_PVT_ITEMS.transpose[1].collect{|task|
@@ -244,9 +242,15 @@ class Receiver
244
242
  {
245
243
  :L1_PSEUDORANGE => [16, 8, "E"],
246
244
  :L1_DOPPLER => [24, 4, "e"],
245
+ :L1_CARRIER_PHASE => [8, 8, "E"],
246
+ :L1_SIGNAL_STRENGTH_dBHz => [30, 1, "c"],
247
247
  }.each{|k, prop|
248
248
  meas.add(prn, GPS::Measurement.const_get(k), loader.call(*prop))
249
249
  }
250
+ # bit 0 of RINEX LLI (loss of lock indicator) shows lost lock
251
+ # between previous and current observation, which maps negative lock seconds
252
+ meas.add(prn, GPS::Measurement::L1_LOCK_SEC,
253
+ (packet[6 + 31 + (i * 24)] & 0x01 == 0x01) ? -1 : 0)
250
254
  }
251
255
  after_run.call(run(meas, t_meas), [meas, t_meas])
252
256
  when [0x02, 0x15] # RXM-RAWX
@@ -272,6 +276,12 @@ class Receiver
272
276
  }],
273
277
  :L1_DOPPLER => [32, 4, "e"],
274
278
  :L1_DOPPLER_SIGMA => [45, 1, nil, proc{|v| 2E-3 * (v[0] & 0xF)}],
279
+ :L1_CARRIER_PHASE => [24, 8, "E", proc{|v| (trk_stat & 0x2 == 0x2) ? v : nil}],
280
+ :L1_CARRIER_PHASE_SIGMA => [44, 1, nil, proc{|v|
281
+ (trk_stat & 0x2 == 0x2) ? (0.004 * (v[0] & 0xF)) : nil
282
+ }],
283
+ :L1_SIGNAL_STRENGTH_dBHz => [42, 1],
284
+ :L1_LOCK_SEC => [40, 2, "v", proc{|v| 1E-3 * v}],
275
285
  }.each{|k, prop|
276
286
  next unless v = loader.call(*prop)
277
287
  meas.add(svid, GPS::Measurement.const_get(k), v)
@@ -317,8 +327,12 @@ class Receiver
317
327
  case type_
318
328
  when "C1", "C1C"
319
329
  [i, GPS::Measurement::L1_PSEUDORANGE]
330
+ when "L1", "L1C"
331
+ [i, GPS::Measurement::L1_CARRIER_PHASE]
320
332
  when "D1", "D1C"
321
333
  [i, GPS::Measurement::L1_DOPPLER]
334
+ when "S1", "S1C"
335
+ [i, GPS::Measurement::L1_SIGNAL_STRENGTH_dBHz]
322
336
  else
323
337
  nil
324
338
  end
@@ -336,40 +350,3 @@ class Receiver
336
350
  end
337
351
  end
338
352
  end
339
-
340
- if __FILE__ == $0 then
341
- # runnable quick example to solve PVT by using RINEX NAV/OBS or u-blox ubx
342
- options = {}
343
-
344
- # check options
345
- ARGV.reject!{|arg|
346
- next false unless arg =~ /^--([^=]+)=?/
347
- options[$1.to_sym] = $'
348
- true
349
- }
350
-
351
- # Check file existence
352
- ARGV.each{|arg|
353
- raise "File not found: #{arg}" unless File::exist?(arg)
354
- }
355
-
356
- rcv = GPS_PVT::Receiver::new(options)
357
-
358
- puts GPS_PVT::Receiver::header
359
-
360
- # parse RINEX NAV
361
- ARGV.reject!{|arg|
362
- next false unless arg =~ /\.\d{2}n$/
363
- rcv.parse_rinex_nav(arg)
364
- }
365
-
366
- # other files
367
- ARGV.each{|arg|
368
- case arg
369
- when /\.ubx$/
370
- rcv.parse_ubx(arg)
371
- when /\.\d{2}o$/
372
- rcv.parse_rinex_obs(arg)
373
- end
374
- }
375
- end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module GPS_PVT
4
- VERSION = "0.1.2"
4
+ VERSION = "0.1.6"
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.1.2
4
+ version: 0.1.6
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: 2021-12-21 00:00:00.000000000 Z
11
+ date: 2021-12-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -42,7 +42,8 @@ description: This module calculate PVT by using raw observation obtained from a
42
42
  receiver
43
43
  email:
44
44
  - fenrir.naru@gmail.com
45
- executables: []
45
+ executables:
46
+ - gps_pvt
46
47
  extensions:
47
48
  - ext/gps_pvt/extconf.rb
48
49
  extra_rdoc_files: []
@@ -55,6 +56,7 @@ files:
55
56
  - Rakefile
56
57
  - bin/console
57
58
  - bin/setup
59
+ - exe/gps_pvt
58
60
  - ext/gps_pvt/Coordinate/Coordinate_wrap.cxx
59
61
  - ext/gps_pvt/GPS/GPS_wrap.cxx
60
62
  - ext/gps_pvt/SylphideMath/SylphideMath_wrap.cxx