gps_pvt 0.1.1 → 0.1.5

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: db616707d74b61691f2d968fe2034c513333d300257f72a6968df7c6a538f07b
4
- data.tar.gz: 875638b4fb9378dc1928ba532e868138373174a1bc8316f7852a88867f52b43d
3
+ metadata.gz: 8dda091173f9531e0afccd9bab371f7fab0f6c6b82c1f7332fb99cbae81bb3cb
4
+ data.tar.gz: 01173b782d6848634840b6cb2946fd4cf9874ba191cb8acb0f8e072b4e17d67b
5
5
  SHA512:
6
- metadata.gz: 77e3567bbc1a124faa29b78f9e2f745c6713d5b81f5b7204432ba64134d1914fd93bed6b11e6e047e6dd50dd42372df8deba379b7940a74b65dedddc2aac3156
7
- data.tar.gz: 171c292e462856f0f4f566954311d393063dd1b2864b15dbeab887c4eafb84875a95b7e242010de17652a281665c0e7bffaa1833a4e89971d8d55a5997138a37
6
+ metadata.gz: d756b85034c18bcc2069d2da6b06e1949ff868f33fd57c3c72f8a8a4e4eafa49185128cf1f5a10e35bafbef3d11d130386d3ce1996b21487bc61fb445eba2df0
7
+ data.tar.gz: 26c00d4f6743a07327a57354d83ac8c565f20548748c718855a6476924a7959a3e7fac3c1b7707f7cb1cf1a324bbefa7ab8a68479b7988ae1c87a6627aca93b3
data/README.md CHANGED
@@ -1,86 +1,117 @@
1
- # GPS_PVT
2
-
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
-
5
- The PVT solution is obtained with a stand alone positioning (i.e. neither differential nor kinematic) with lease 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/).
6
-
7
- ## Installation
8
-
9
- Add this line to your application's Gemfile:
10
-
11
- ```ruby
12
- gem 'gps_pvt'
13
- ```
14
-
15
- And then execute:
16
-
17
- $ bundle install
18
-
19
- Or install it yourself as:
20
-
21
- $ gem install gps_pvt
22
-
23
- ## Usage
24
-
25
- ```ruby
26
- require 'gps_pvt'
27
-
28
- receiver = GPS_PVT::Receiver::new
29
- receiver.parse_rinex_nav(rinex_nav_file)
30
-
31
- # For generate solution in CSV format
32
- puts GPS_PVT::Receiver::header
33
- receiver.parse_rinex_obs(rinex_obs_file)
34
-
35
- # receiver.parse_ubx(ubx_file) # same as above for ubx file including RXM-RAW(X) and RXM-SFRB(X)
36
-
37
- # Or precise control of outputs
38
- receiver.parse_rinex_obs(rinex_obs_file){|pvt, meas| # per epoch
39
- meas # => measurement, array of [prn, key, value]; key is represented by GPS_PVT::GPS::Measurement::L1_PSEUDORANGE
40
- pvt # => PVT solution, all properties are shown by pvt.methods
41
- # for example
42
- if(pvt.position_solved?){
43
- pvt.receiver_time # receiver time; .to_a => [GPS week, seconds], .c_tm => [year, month, day, hour, min, sec] without leap second consideration
44
- [:lat, :lng, :alt].collect{|f| pvt.llh.send(f)} # latitude[rad], longitude[rad], WGS-84 altitude[m]
45
- pvt.receiver_error # receiver clock error in meter
46
- [:g, :p, :h, :v, :t].collect{|k| pvt.send("#{k}dop".to_sym)} # various DOP, dilution of precision
47
- if(pvt.velocity_solved?){
48
- [:north, east, :down].collect{|dir| pvt.velocity.send(dir)} # speed in north/east/down [m/s]
49
- pvt.receiver_error_rate # clock error rate in m/s
50
- }
51
- pvt.used_satellite_list # array of used, i.e., visible and weight>0, satellite
52
- 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
53
- pvt.G_enu # design matrix in East-North-Up (ENU)
54
- pvt.W # weight for each satellite
55
- pvt.delta_r # residual of pseudo range
56
- pvt.S # (delta position) = S * (residual) in last iteration in ECEF
57
- }
58
- }
59
-
60
- # Customize solution
61
- receiver.solver.options.exclude(prn) # Exclude satellite; the default is to use every satellite if visible
62
- receiver.solver.options.include(prn) # Discard previous setting of exclusion
63
- receiver.solver.hooks[:relative_property] = proc{|prn, rel_prop, rcv_e, t_arv, usr_pos, usr_vel|
64
- # control weight per satellite per iteration
65
- weight, range_c, range_r, rate_rel_neg, *los_neg = rel_prop # relative property
66
- weight = 1 # default; same weight
67
- # or weight based on elevation
68
- # elv = GPS_PVT::Coordinate::ENU::relative_rel(GPS_PVT::Coordinate::XYZ::new(*los_neg), usr_pos).elevation
69
- # weight = (Math::sin(elv)/0.8)**2
70
- [weight, range_c, range_r, rate_rel_neg] + los_neg
71
- }
72
- ```
73
-
74
- ## Development
75
-
76
- After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake` to build library and run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
77
-
78
- To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
79
-
80
- ## Contributing
81
-
82
- Bug reports and pull requests are welcome on GitHub at https://github.com/fenrir-naru/gps_pvt. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/fenrir-naru/gps_pvt/blob/master/CODE_OF_CONDUCT.md).
83
-
84
- ## Code of Conduct
85
-
86
- Everyone interacting in the GPS_PVT project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/fenrir-naru/gps_pvt/blob/master/CODE_OF_CONDUCT.md).
1
+ # GPS_PVT
2
+
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
+
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
+
7
+ [![Gem Version](https://badge.fury.io/rb/gps_pvt.svg)](https://badge.fury.io/rb/gps_pvt)
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)
9
+
10
+ ## Installation
11
+
12
+ Add this line to your application's Gemfile:
13
+
14
+ ```ruby
15
+ gem 'gps_pvt'
16
+ ```
17
+
18
+ And then execute:
19
+
20
+ $ bundle install
21
+
22
+ Or install it yourself as:
23
+
24
+ $ gem install gps_pvt
25
+
26
+ For Windows users, this gem requires Devkit because of native compilation.
27
+
28
+ ## Usage
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
+
36
+ ```ruby
37
+ require 'gps_pvt'
38
+
39
+ receiver = GPS_PVT::Receiver::new
40
+ receiver.parse_rinex_nav(rinex_nav_file) # This is required before parsing RINEX obs file (For ubx, skippable)
41
+
42
+ # For generate solution in CSV format
43
+ puts GPS_PVT::Receiver::header
44
+ receiver.parse_rinex_obs(rinex_obs_file)
45
+ # receiver.parse_ubx(ubx_file) # same as above for ubx file including RXM-RAW(X) and RXM-SFRB(X)
46
+
47
+ # Or precise control of outputs
48
+ receiver.parse_rinex_obs(rinex_obs_file){|pvt, meas| # per epoch
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
+
51
+ pvt # => PVT solution, all properties are shown by pvt.methods
52
+ # for example
53
+ if(pvt.position_solved?){
54
+ pvt.receiver_time # receiver time; .to_a => [GPS week, seconds], .c_tm => [year, month, day, hour, min, sec] without leap second consideration
55
+ [:lat, :lng, :alt].collect{|f| pvt.llh.send(f)} # latitude[rad], longitude[rad], WGS-84 altitude[m]
56
+ pvt.receiver_error # receiver clock error in meter
57
+ [:g, :p, :h, :v, :t].collect{|k| pvt.send("#{k}dop".to_sym)} # various DOP, dilution of precision
58
+ if(pvt.velocity_solved?){
59
+ [:north, east, :down].collect{|dir| pvt.velocity.send(dir)} # speed in north/east/down [m/s]
60
+ pvt.receiver_error_rate # clock error rate in m/s
61
+ }
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
+
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
67
+ pvt.G_enu # design matrix in East-North-Up (ENU)
68
+ pvt.W # weight for each satellite
69
+ pvt.delta_r # residual of pseudo range
70
+ pvt.S # (delta position) = S * (residual) in last iteration in ECEF
71
+ }
72
+ }
73
+
74
+ # Customize solution
75
+ receiver.solver.options.exclude(prn) # Exclude satellite; the default is to use every satellite if visible
76
+ receiver.solver.options.include(prn) # Discard previous setting of exclusion
77
+ receiver.solver.hooks[:relative_property] = proc{|prn, rel_prop, rcv_e, t_arv, usr_pos, usr_vel|
78
+ # control weight per satellite per iteration
79
+ weight, range_c, range_r, rate_rel_neg, *los_neg = rel_prop # relative property
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
84
+ # or weight based on elevation
85
+ # elv = GPS_PVT::Coordinate::ENU::relative_rel(GPS_PVT::Coordinate::XYZ::new(*los_neg), usr_pos).elevation
86
+ # weight = (Math::sin(elv)/0.8)**2
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
+ }
102
+ }
103
+ ```
104
+
105
+ ## Development
106
+
107
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake` to build library and run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
108
+
109
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
110
+
111
+ ## Contributing
112
+
113
+ Bug reports and pull requests are welcome on GitHub at https://github.com/fenrir-naru/gps_pvt. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/fenrir-naru/gps_pvt/blob/master/CODE_OF_CONDUCT.md).
114
+
115
+ ## Code of Conduct
116
+
117
+ Everyone interacting in the GPS_PVT project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/fenrir-naru/gps_pvt/blob/master/CODE_OF_CONDUCT.md).
data/Rakefile CHANGED
@@ -1,86 +1,86 @@
1
- # frozen_string_literal: true
2
-
3
- require "bundler/gem_tasks"
4
- require "rspec/core/rake_task"
5
-
6
- RSpec::Core::RakeTask.new(:spec)
7
-
8
- require "rake/extensiontask"
9
-
10
- Rake::ExtensionTask.new("gps_pvt") do |ext|
11
- ext.lib_dir = "lib/gps_pvt"
12
- end
13
-
14
- namespace :git do
15
- namespace :submodules do
16
- desc "Initialize git submodules"
17
- task :init do
18
- sh "git submodule init"
19
- # for sparse-checkout; @see https://stackoverflow.com/a/59521050/15992898
20
- `git config --file .gitmodules --name-only --get-regexp path`.lines.each{|str|
21
- # list submodule; @see https://stackoverflow.com/a/23490756/15992898
22
- next unless str =~ /submodule\.(.+)\.path/
23
- repo_dir = $1
24
- sh "git clone -n #{`git config submodule.#{repo_dir}.url`.chomp} #{repo_dir}"
25
- }
26
- {
27
- 'ext/ninja-scan-light' => [
28
- "sparse-checkout init", # same as "git -C #{repo} config core.sparseCheckout true"
29
- # same as #{repo}/.git/info/sparse-checkout
30
- "sparse-checkout set" + (<<-__SPARSE_PATTERNS__).lines.collect{|str| str.chomp.gsub(/^ */, ' ')}.join,
31
- /tool/param/
32
- /tool/navigation/GPS*
33
- /tool/navigation/coordinate.h
34
- /tool/navigation/EGM.h
35
- /tool/navigation/MagneticField.h
36
- /tool/navigation/NTCM.h
37
- /tool/navigation/RINEX.h
38
- /tool/navigation/WGS84.h
39
- /tool/swig/SylphideMath.i
40
- /tool/swig/GPS.i
41
- /tool/swig/Coordinate.i
42
- /tool/swig/makefile
43
- /tool/swig/extconf.rb
44
- /tool/swig/spec/GPS_spec.rb
45
- /tool/swig/spec/SylphideMath_spec.rb
46
- __SPARSE_PATTERNS__
47
- ]
48
- }.each{|repo, commands|
49
- commands.each{|str| sh "git -C #{repo} #{str}"}
50
- }
51
- sh "git submodule absorbgitdirs" # Move #{repo}/.git to .git/modules/#{repo}/.git
52
- sh "git submodule update"
53
- # if already checked out, then git -C #{repo} read-tree -mu HEAD
54
- end
55
- end
56
- end
57
-
58
-
59
- desc "Generate SWIG wrapper codes"
60
- task :swig do
61
- swig_dir = File::join(File::dirname(__FILE__), 'ext', 'ninja-scan-light', 'tool', 'swig')
62
- out_base_dir = File::join(File::dirname(__FILE__), 'ext', 'gps_pvt')
63
- Dir::chdir(swig_dir){
64
- Dir::glob("*.i"){|src|
65
- mod_name = File::basename(src, '.*')
66
- out_dir = File::join(out_base_dir, mod_name)
67
- sh "mkdir -p #{out_dir}"
68
- wrapper = File::join(out_dir, "#{mod_name}_wrap.cxx")
69
- sh [:make, :clean, wrapper,
70
- "BUILD_DIR=#{out_dir}",
71
- "SWIGFLAGS='-c++ -ruby -prefix \"GPS_PVT::\"#{" -D__MINGW__" if ENV["MSYSTEM"]}'"].join(' ')
72
- lines = open(wrapper, 'r').read.lines.collect{|line|
73
- line.sub(/rb_require\(\"([^\"]+)\"\)/){ # from camel to underscore downcase style
74
- "rb_require(\"#{$1.sub('GPS_PVT', 'gps_pvt')}\")"
75
- }
76
- }
77
- open(wrapper, 'w').write(lines.join)
78
- }
79
- }
80
- end
81
-
82
- file "ext/ninja-scan-light/tool" do |t|
83
- Rake::Task["git:submodules:init"].invoke
84
- end
85
-
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ require "rspec/core/rake_task"
5
+
6
+ RSpec::Core::RakeTask.new(:spec)
7
+
8
+ require "rake/extensiontask"
9
+
10
+ Rake::ExtensionTask.new("gps_pvt") do |ext|
11
+ ext.lib_dir = "lib/gps_pvt"
12
+ end
13
+
14
+ namespace :git do
15
+ namespace :submodules do
16
+ desc "Initialize git submodules"
17
+ task :init do
18
+ sh "git submodule init"
19
+ # for sparse-checkout; @see https://stackoverflow.com/a/59521050/15992898
20
+ `git config --file .gitmodules --name-only --get-regexp path`.lines.each{|str|
21
+ # list submodule; @see https://stackoverflow.com/a/23490756/15992898
22
+ next unless str =~ /submodule\.(.+)\.path/
23
+ repo_dir = $1
24
+ sh "git clone -n #{`git config submodule.#{repo_dir}.url`.chomp} #{repo_dir}"
25
+ }
26
+ {
27
+ 'ext/ninja-scan-light' => [
28
+ "sparse-checkout init", # same as "git -C #{repo} config core.sparseCheckout true"
29
+ # same as #{repo}/.git/info/sparse-checkout
30
+ "sparse-checkout set" + (<<-__SPARSE_PATTERNS__).lines.collect{|str| str.chomp.gsub(/^ */, ' ')}.join,
31
+ /tool/param/
32
+ /tool/navigation/GPS*
33
+ /tool/navigation/coordinate.h
34
+ /tool/navigation/EGM.h
35
+ /tool/navigation/MagneticField.h
36
+ /tool/navigation/NTCM.h
37
+ /tool/navigation/RINEX.h
38
+ /tool/navigation/WGS84.h
39
+ /tool/swig/SylphideMath.i
40
+ /tool/swig/GPS.i
41
+ /tool/swig/Coordinate.i
42
+ /tool/swig/makefile
43
+ /tool/swig/extconf.rb
44
+ /tool/swig/spec/GPS_spec.rb
45
+ /tool/swig/spec/SylphideMath_spec.rb
46
+ __SPARSE_PATTERNS__
47
+ ]
48
+ }.each{|repo, commands|
49
+ commands.each{|str| sh "git -C #{repo} #{str}"}
50
+ }
51
+ sh "git submodule absorbgitdirs" # Move #{repo}/.git to .git/modules/#{repo}/.git
52
+ sh "git submodule update"
53
+ # if already checked out, then git -C #{repo} read-tree -mu HEAD
54
+ end
55
+ end
56
+ end
57
+
58
+
59
+ desc "Generate SWIG wrapper codes"
60
+ task :swig do
61
+ swig_dir = File::join(File::dirname(__FILE__), 'ext', 'ninja-scan-light', 'tool', 'swig')
62
+ out_base_dir = File::join(File::dirname(__FILE__), 'ext', 'gps_pvt')
63
+ Dir::chdir(swig_dir){
64
+ Dir::glob("*.i"){|src|
65
+ mod_name = File::basename(src, '.*')
66
+ out_dir = File::join(out_base_dir, mod_name)
67
+ sh "mkdir -p #{out_dir}"
68
+ wrapper = File::join(out_dir, "#{mod_name}_wrap.cxx")
69
+ sh [:make, :clean, wrapper,
70
+ "BUILD_DIR=#{out_dir}",
71
+ "SWIGFLAGS='-c++ -ruby -prefix \"GPS_PVT::\"#{" -D__MINGW__" if ENV["MSYSTEM"]}'"].join(' ')
72
+ lines = open(wrapper, 'r').read.lines.collect{|line|
73
+ line.sub(/rb_require\(\"([^\"]+)\"\)/){ # from camel to underscore downcase style
74
+ "rb_require(\"#{$1.sub('GPS_PVT', 'gps_pvt')}\")"
75
+ }
76
+ }
77
+ open(wrapper, 'w').write(lines.join)
78
+ }
79
+ }
80
+ end
81
+
82
+ file "ext/ninja-scan-light/tool" do |t|
83
+ Rake::Task["git:submodules:init"].invoke
84
+ end
85
+
86
86
  task :default => ["ext/ninja-scan-light/tool", :compile, :spec]
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
+ }