gps_pvt 0.1.2 → 0.1.6

Sign up to get free protection for your applications and to get access to all the features.
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