gps_pvt 0.1.7 → 0.2.3
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/README.md +13 -2
- data/Rakefile +2 -0
- data/exe/gps_pvt +32 -23
- data/ext/gps_pvt/Coordinate/Coordinate_wrap.cxx +5 -3
- data/ext/gps_pvt/GPS/GPS_wrap.cxx +4444 -671
- data/ext/gps_pvt/SylphideMath/SylphideMath_wrap.cxx +284 -19
- data/ext/ninja-scan-light/tool/navigation/GPS.h +12 -46
- data/ext/ninja-scan-light/tool/navigation/GPS_Solver.h +61 -100
- data/ext/ninja-scan-light/tool/navigation/GPS_Solver_Base.h +87 -25
- data/ext/ninja-scan-light/tool/navigation/QZSS.h +62 -0
- data/ext/ninja-scan-light/tool/navigation/RINEX.h +335 -27
- data/ext/ninja-scan-light/tool/navigation/SBAS.h +2330 -0
- data/ext/ninja-scan-light/tool/navigation/SBAS_Solver.h +306 -0
- data/ext/ninja-scan-light/tool/param/bit_array.h +4 -3
- data/ext/ninja-scan-light/tool/swig/GPS.i +429 -138
- data/ext/ninja-scan-light/tool/swig/SylphideMath.i +53 -6
- data/ext/ninja-scan-light/tool/swig/spec/GPS_spec.rb +37 -6
- data/ext/ninja-scan-light/tool/swig/spec/SylphideMath_spec.rb +38 -4
- data/gps_pvt.gemspec +63 -0
- data/lib/gps_pvt/receiver.rb +281 -140
- data/lib/gps_pvt/version.rb +1 -1
- metadata +7 -3
@@ -238,6 +238,23 @@ INSTANTIATE_COMPLEX(double, D);
|
|
238
238
|
|
239
239
|
#undef INSTANTIATE_COMPLEX
|
240
240
|
|
241
|
+
#if defined(SWIGRUBY)
|
242
|
+
/* Work around of miss detection of negative value on Windows Ruby (devkit).
|
243
|
+
* This results from SWIG_AsVal(unsigned int) depends on SWIG_AsVal(unsigned long),
|
244
|
+
* and sizeof(long) == sizeof(int).
|
245
|
+
*/
|
246
|
+
%fragment("check_value"{unsigned int}, "header"){
|
247
|
+
inline bool is_lt_zero_after_asval(const unsigned int &i){
|
248
|
+
return ((sizeof(unsigned int) == sizeof(unsigned long)) && ((UINT_MAX >> 1) <= i));
|
249
|
+
}
|
250
|
+
void raise_if_lt_zero_after_asval(const unsigned int &i){
|
251
|
+
if(is_lt_zero_after_asval(i)){
|
252
|
+
SWIG_exception(SWIG_ValueError, "Expected positive value.");
|
253
|
+
}
|
254
|
+
}
|
255
|
+
}
|
256
|
+
#endif
|
257
|
+
|
241
258
|
#define DO_NOT_INSTANTIATE_SCALAR_MATRIX
|
242
259
|
#define USE_MATRIX_VIEW_FILTER
|
243
260
|
|
@@ -949,6 +966,7 @@ MAKE_TO_S(Matrix_Frozen)
|
|
949
966
|
}
|
950
967
|
#if defined(SWIGRUBY)
|
951
968
|
%fragment(SWIG_AsVal_frag(unsigned int));
|
969
|
+
%fragment("check_value"{unsigned int});
|
952
970
|
Matrix(const void *replacer){
|
953
971
|
const SWIG_Object *value(static_cast<const SWIG_Object *>(replacer));
|
954
972
|
static const ID id_r(rb_intern("row_size")), id_c(rb_intern("column_size"));
|
@@ -959,13 +977,10 @@ MAKE_TO_S(Matrix_Frozen)
|
|
959
977
|
MatrixUtil::replace(res, replacer);
|
960
978
|
return new Matrix<T, Array2D_Type, ViewType>(res);
|
961
979
|
}else if(value && rb_respond_to(*value, id_r) && rb_respond_to(*value, id_c)){
|
962
|
-
|
963
|
-
* can not detect less than zero in Windows Ruby devkit.
|
964
|
-
*/
|
965
|
-
int r, c;
|
980
|
+
unsigned int r, c;
|
966
981
|
VALUE v_r(rb_funcall(*value, id_r, 0, 0)), v_c(rb_funcall(*value, id_c, 0, 0));
|
967
|
-
if(!SWIG_IsOK(SWIG_AsVal(int)(v_r, &r)) || (r
|
968
|
-
|| !SWIG_IsOK(SWIG_AsVal(int)(v_c, &c)) || (c
|
982
|
+
if(!SWIG_IsOK(SWIG_AsVal(unsigned int)(v_r, &r)) || is_lt_zero_after_asval(r)
|
983
|
+
|| !SWIG_IsOK(SWIG_AsVal(unsigned int)(v_c, &c)) || is_lt_zero_after_asval(c)){
|
969
984
|
throw std::runtime_error(
|
970
985
|
std::string("Unexpected length [")
|
971
986
|
.append(inspect_str(v_r)).append(", ")
|
@@ -1147,6 +1162,8 @@ INSTANTIATE_MATRIX_EIGEN2(type, ctype, Array2D_Dense<type >, MatView_pt);
|
|
1147
1162
|
#endif
|
1148
1163
|
|
1149
1164
|
%define INSTANTIATE_MATRIX(type, suffix)
|
1165
|
+
%typemap(check, fragment="check_value"{unsigned int})
|
1166
|
+
const unsigned int & "raise_if_lt_zero_after_asval(*$1);"
|
1150
1167
|
#if !defined(DO_NOT_INSTANTIATE_SCALAR_MATRIX)
|
1151
1168
|
%extend Matrix_Frozen<type, Array2D_ScaledUnit<type >, MatViewBase> {
|
1152
1169
|
const Matrix_Frozen<type, Array2D_ScaledUnit<type >, MatViewBase> &transpose() const {
|
@@ -1200,6 +1217,35 @@ INSTANTIATE_MATRIX_PARTIAL(type, Array2D_Dense<type >, MatView_pt, MatView_pt);
|
|
1200
1217
|
%template(Matrix_Frozen ## suffix ## _pt) Matrix_Frozen<type, Array2D_Dense<type >, MatView_pt>;
|
1201
1218
|
#endif
|
1202
1219
|
|
1220
|
+
%extend Matrix<type, Array2D_Dense<type > > {
|
1221
|
+
#if defined(SWIGRUBY)
|
1222
|
+
%bang resize;
|
1223
|
+
#endif
|
1224
|
+
%typemap(in, fragment="check_value"{unsigned int})
|
1225
|
+
unsigned int *r_p (unsigned int temp), unsigned int *c_p (unsigned int temp) {
|
1226
|
+
if(SWIG_IsOK(SWIG_AsVal(unsigned int)($input, &temp))){
|
1227
|
+
#if defined(SWIGRUBY)
|
1228
|
+
raise_if_lt_zero_after_asval(temp);
|
1229
|
+
#endif
|
1230
|
+
$1 = &temp;
|
1231
|
+
}
|
1232
|
+
#if defined(SWIGRUBY)
|
1233
|
+
else if(NIL_P($input)){$1 = NULL;}
|
1234
|
+
#endif
|
1235
|
+
else{SWIG_exception(SWIG_TypeError, "$*1_ltype is expected");}
|
1236
|
+
}
|
1237
|
+
Matrix<type, Array2D_Dense<type > > &resize(
|
1238
|
+
const unsigned int *r_p, const unsigned int *c_p){
|
1239
|
+
unsigned int r(r_p ? *r_p : $self->rows()), c(c_p ? *c_p : self->columns());
|
1240
|
+
Matrix<type, Array2D_Dense<type > > mat_new(r, c);
|
1241
|
+
unsigned int r_min(r), c_min(c);
|
1242
|
+
if(r_min > $self->rows()){r_min = $self->rows();}
|
1243
|
+
if(c_min > $self->columns()){c_min = $self->columns();}
|
1244
|
+
mat_new.partial(r_min, c_min).replace($self->partial(r_min, c_min), false);
|
1245
|
+
return (*($self) = mat_new);
|
1246
|
+
}
|
1247
|
+
};
|
1248
|
+
|
1203
1249
|
%template(Matrix ## suffix) Matrix<type, Array2D_Dense<type > >;
|
1204
1250
|
#if defined(SWIGRUBY)
|
1205
1251
|
%fragment("init"{Matrix<type, Array2D_Dense<type > >}, "init") {
|
@@ -1212,6 +1258,7 @@ INSTANTIATE_MATRIX_PARTIAL(type, Array2D_Dense<type >, MatView_pt, MatView_pt);
|
|
1212
1258
|
}
|
1213
1259
|
%fragment("init"{Matrix<type, Array2D_Dense<type > >});
|
1214
1260
|
#endif
|
1261
|
+
%typemap(check) const unsigned int &;
|
1215
1262
|
%enddef
|
1216
1263
|
|
1217
1264
|
INSTANTIATE_MATRIX(double, D);
|
@@ -221,7 +221,11 @@ __RINEX_OBS_TEXT__
|
|
221
221
|
f.path
|
222
222
|
},
|
223
223
|
}}
|
224
|
-
let(:solver){
|
224
|
+
let(:solver){
|
225
|
+
res = GPS::Solver::new
|
226
|
+
res.correction = {:gps_ionospheric => :klobuchar, :gps_tropospheric => :hopfield}
|
227
|
+
res
|
228
|
+
}
|
225
229
|
|
226
230
|
describe 'demo' do
|
227
231
|
it 'calculates position without any error' do
|
@@ -255,7 +259,6 @@ __RINEX_OBS_TEXT__
|
|
255
259
|
[:alpha, :beta].each{|k|
|
256
260
|
puts "Iono #{k}: #{sn.iono_utc.send(k)}"
|
257
261
|
}
|
258
|
-
puts solver.gps_options.ionospheric_models
|
259
262
|
|
260
263
|
meas.each{|prn, k, v|
|
261
264
|
eph = sn.ephemeris(prn)
|
@@ -336,11 +339,21 @@ __RINEX_OBS_TEXT__
|
|
336
339
|
|
337
340
|
it 'can be modified through hooks' do
|
338
341
|
sn = solver.gps_space_node
|
342
|
+
expect(solver.correction[:gps_ionospheric]).to include(:klobuchar)
|
343
|
+
expect(solver.correction[:gps_tropospheric]).to include(:hopfield)
|
344
|
+
expect{solver.correction = nil}.to raise_error(RuntimeError)
|
345
|
+
expect{solver.correction = {
|
346
|
+
:gps_ionospheric => [:klobuchar, :no_correction],
|
347
|
+
:options => {:f_10_7 => 10},
|
348
|
+
}}.not_to raise_error
|
349
|
+
expect(solver.correction[:gps_ionospheric]).to include(:no_correction)
|
350
|
+
expect(solver.correction[:options][:f_10_7]).to eq(10)
|
339
351
|
sn.read(input[:rinex_nav])
|
340
352
|
t_meas = GPS::Time::new(1849, 172413)
|
341
353
|
sn.update_all_ephemeris(t_meas)
|
342
|
-
solver.hooks[:relative_property] = proc{|prn, rel_prop, rcv_e, t_arv, usr_pos, usr_vel|
|
354
|
+
solver.hooks[:relative_property] = proc{|prn, rel_prop, meas, rcv_e, t_arv, usr_pos, usr_vel|
|
343
355
|
expect(input[:measurement]).to include(prn)
|
356
|
+
expect(meas).to be_a_kind_of(Hash)
|
344
357
|
expect(t_arv).to be_a_kind_of(GPS::Time)
|
345
358
|
expect(usr_pos).to be_a_kind_of(Coordinate::XYZ)
|
346
359
|
expect(usr_vel).to be_a_kind_of(Coordinate::XYZ)
|
@@ -348,12 +361,30 @@ __RINEX_OBS_TEXT__
|
|
348
361
|
weight = 1
|
349
362
|
[weight, range_c, range_r, rate_rel_neg] + los_neg
|
350
363
|
}
|
351
|
-
solver.hooks[:update_position_solution] = proc{
|
352
|
-
|
364
|
+
solver.hooks[:update_position_solution] = proc{|mat_G, mat_W, mat_delta_r, temp_pvt|
|
365
|
+
expect(temp_pvt).to be_a_kind_of(GPS::PVT)
|
366
|
+
[mat_G, mat_W, mat_delta_r].each{|mat|
|
353
367
|
expect(mat).to be_a_kind_of(SylphideMath::MatrixD)
|
368
|
+
expect(mat.rows).to be >= temp_pvt.used_satellites
|
369
|
+
expect(mat).to respond_to(:resize!)
|
354
370
|
}
|
355
|
-
mat_G, mat_W, mat_delta_r = mats
|
356
371
|
}
|
372
|
+
solver.hooks[:satellite_position] = proc{
|
373
|
+
i = 0
|
374
|
+
proc{|prn, time, pos|
|
375
|
+
expect(input[:measurement]).to include(prn)
|
376
|
+
expect(pos).to be_a_kind_of(Coordinate::XYZ).or eq(nil)
|
377
|
+
# System_XYZ or [x,y,z] or nil(= unknown position) are acceptable
|
378
|
+
case (i += 1) % 5
|
379
|
+
when 0
|
380
|
+
nil
|
381
|
+
when 1
|
382
|
+
pos.to_a
|
383
|
+
else
|
384
|
+
pos
|
385
|
+
end
|
386
|
+
}
|
387
|
+
}.call
|
357
388
|
pvt = solver.solve(
|
358
389
|
input[:measurement].collect{|prn, items|
|
359
390
|
items.collect{|k, v| [prn, k, v]}
|
@@ -19,6 +19,12 @@ shared_examples 'Matrix' do
|
|
19
19
|
expect( mat_type::new(*params[:rc]).rows ).to equal(params[:rc][0])
|
20
20
|
expect( mat_type::new(*params[:rc]).columns ).to equal(params[:rc][1])
|
21
21
|
end
|
22
|
+
it 'declines negative number argument' do
|
23
|
+
[[-1, 1], [1, -1]].each{|sf|
|
24
|
+
r, c = params[:rc].zip(sf).collect{|v1, v2| v1 * v2}
|
25
|
+
expect{ mat_type::new(r, c) }.to raise_error(ArgumentError)
|
26
|
+
}
|
27
|
+
end
|
22
28
|
it 'accepts ([[]])' do
|
23
29
|
expect{ mat_type::new(compare_with) }.not_to raise_error
|
24
30
|
expect( mat_type::new(compare_with).rows ).to equal(params[:rc][0])
|
@@ -44,9 +50,11 @@ shared_examples 'Matrix' do
|
|
44
50
|
a.define_singleton_method(:[]){|i, j| raise(IndexError) if i != j; 0}
|
45
51
|
expect{ mat_type::new(a) }.to raise_error(IndexError)
|
46
52
|
|
47
|
-
|
48
|
-
|
49
|
-
|
53
|
+
[:row_size, :column_size].each{|f|
|
54
|
+
a = a_gen.call
|
55
|
+
a.define_singleton_method(f){-1}
|
56
|
+
expect{ mat_type::new(a) }.to raise_error(RuntimeError)
|
57
|
+
}
|
50
58
|
end
|
51
59
|
it 'is invoked with I, identity, unit' do
|
52
60
|
[:I, :identity, :unit].each{|f|
|
@@ -132,7 +140,7 @@ shared_examples 'Matrix' do
|
|
132
140
|
expect(mat[:square].sum).to eq(Matrix[*mat[:square].to_a].sum)
|
133
141
|
expect(mat[:not_square].sum).to eq(Matrix[*mat[:not_square].to_a].sum)
|
134
142
|
end
|
135
|
-
it '
|
143
|
+
it 'determinant, det' do
|
136
144
|
[:determinant, :det].each{|f|
|
137
145
|
#expect(mat[:square].send(f)).to eq(Matrix[*mat[:square].to_a].det)
|
138
146
|
expect{mat[:not_square].send(f)}.to raise_error(RuntimeError)
|
@@ -163,6 +171,15 @@ shared_examples 'Matrix' do
|
|
163
171
|
}
|
164
172
|
}
|
165
173
|
end
|
174
|
+
it 'is inaccessible and unchangeable with negative number arguments' do
|
175
|
+
[[-1, 0], [0, -1]].each{|i, j|
|
176
|
+
[[:[], i, j], [:[]=, i, j, 0]].each{|args|
|
177
|
+
expect{ mat[0].send(*args) }.to raise_error{|err|
|
178
|
+
expect(err).to be_a(RangeError).or be_a(ArgumentError)
|
179
|
+
}
|
180
|
+
}
|
181
|
+
}
|
182
|
+
end
|
166
183
|
end
|
167
184
|
|
168
185
|
describe 'elements' do
|
@@ -394,6 +411,23 @@ shared_examples 'Matrix' do
|
|
394
411
|
}
|
395
412
|
expect{mat[2] / mat[3]}.to raise_error(RuntimeError)
|
396
413
|
end
|
414
|
+
it 'have resize!' do
|
415
|
+
[-1, :sym].each{|arg|
|
416
|
+
[[arg, nil], [nil, arg]].each{|args|
|
417
|
+
expect{mat[0].resize!(*args)}.to raise_error{|err|
|
418
|
+
expect(err).to be_a(TypeError).or be_a(ArgumentError)
|
419
|
+
}
|
420
|
+
}
|
421
|
+
}
|
422
|
+
mat_orig = mat[0].to_a
|
423
|
+
r, c = [:rows, :columns].collect{|f| mat[0].send(f)}
|
424
|
+
expect(mat[0].resize!(r, c).to_a).to eq(mat_orig)
|
425
|
+
expect(mat[0].resize!(r, nil).to_a).to eq(mat_orig)
|
426
|
+
expect(mat[0].resize!(nil, c).to_a).to eq(mat_orig)
|
427
|
+
expect(mat[0].resize!(nil, nil).to_a).to eq(mat_orig)
|
428
|
+
expect(mat[0].resize!(r * 2, c * 2).to_a).to \
|
429
|
+
eq(Matrix::build(r * 2, c * 2){|i, j| (i < r && j < c) ? mat_orig[i][j] : 0}.to_a)
|
430
|
+
end
|
397
431
|
end
|
398
432
|
|
399
433
|
describe 'decomposition' do
|
data/gps_pvt.gemspec
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "lib/gps_pvt/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = "gps_pvt"
|
7
|
+
spec.version = GPS_PVT::VERSION
|
8
|
+
spec.authors = ["fenrir(M.Naruoka)"]
|
9
|
+
spec.email = ["fenrir.naru@gmail.com"]
|
10
|
+
|
11
|
+
spec.summary = "GPS position, velocity, and time (PVT) solver"
|
12
|
+
spec.description = "This module calculate PVT by using raw observation obtained from a GPS receiver"
|
13
|
+
spec.homepage = "https://github.com/fenrir-naru/gps_pvt"
|
14
|
+
spec.required_ruby_version = ">= 2.3.0"
|
15
|
+
|
16
|
+
#spec.metadata["allowed_push_host"] = "TODO: Set to your gem server 'https://example.com'"
|
17
|
+
|
18
|
+
spec.metadata["homepage_uri"] = spec.homepage
|
19
|
+
spec.metadata["source_code_uri"] = spec.homepage
|
20
|
+
#spec.metadata["changelog_uri"] = "TODO: Put your gem's CHANGELOG.md URL here."
|
21
|
+
|
22
|
+
spec.extensions = ["ext/gps_pvt/extconf.rb"]
|
23
|
+
|
24
|
+
# Specify which files should be added to the gem when it is released.
|
25
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
26
|
+
spec.files = Dir.chdir(File.expand_path(__dir__)) do
|
27
|
+
`git ls-files -z`.split("\x0").reject do |f|
|
28
|
+
(f == __FILE__) || f.match(%r{\A(?:(?:test|spec|features)/|\.(?:git|travis|circleci)|appveyor)})
|
29
|
+
end
|
30
|
+
end
|
31
|
+
spec.bindir = "exe"
|
32
|
+
spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
|
33
|
+
spec.require_paths = ["lib"]
|
34
|
+
|
35
|
+
spec.files += proc{
|
36
|
+
require 'pathname'
|
37
|
+
base_dir = Pathname::new(File::absolute_path(File.dirname(__FILE__)))
|
38
|
+
# get an array of submodule dirs by executing 'pwd' inside each submodule
|
39
|
+
`git submodule --quiet foreach pwd`.split($/).collect{|dir|
|
40
|
+
# issue git ls-files in submodule's directory
|
41
|
+
`git -C #{dir} ls-files -v`.split($/).collect{|f|
|
42
|
+
next nil unless f =~ /^H */ # consider git sparse checkout
|
43
|
+
# get relative path
|
44
|
+
f = Pathname::new(File::join(dir, $'))
|
45
|
+
begin
|
46
|
+
(f.relative? ? f : f.relative_path_from(base_dir)).to_s
|
47
|
+
rescue
|
48
|
+
# Patch for Windows drive letter problem
|
49
|
+
base_dir = Pathname::new(base_dir.to_s.sub(/^([^\/])+:\//){"/#{$1}/"})
|
50
|
+
f.relative_path_from(base_dir).to_s
|
51
|
+
end
|
52
|
+
}.compact
|
53
|
+
}.flatten
|
54
|
+
}.call
|
55
|
+
|
56
|
+
# Uncomment to register a new dependency of your gem
|
57
|
+
# spec.add_dependency "example-gem", "~> 1.0"
|
58
|
+
spec.add_development_dependency "rake"
|
59
|
+
spec.add_development_dependency "rake-compiler"
|
60
|
+
|
61
|
+
# For more information and examples about making a new gem, checkout our
|
62
|
+
# guide at: https://bundler.io/guides/creating_gem.html
|
63
|
+
end
|