gps_pvt 0.9.2 → 0.9.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +159 -3
- data/README.md +1 -1
- data/Rakefile +7 -0
- data/ext/gps_pvt/Coordinate/Coordinate_wrap.cxx +84 -38
- data/ext/gps_pvt/GPS/GPS_wrap.cxx +616 -4120
- data/ext/gps_pvt/SylphideMath/SylphideMath_wrap.cxx +5320 -3913
- data/ext/gps_pvt/extconf.rb +6 -5
- data/ext/ninja-scan-light/tool/navigation/GLONASS_Solver.h +1 -1
- data/ext/ninja-scan-light/tool/navigation/GPS.h +6 -2
- data/ext/ninja-scan-light/tool/navigation/GPS_Solver.h +1 -1
- data/ext/ninja-scan-light/tool/navigation/GPS_Solver_Base.h +3 -1
- data/ext/ninja-scan-light/tool/navigation/GPS_Solver_MultiFrequency.h +3 -0
- data/ext/ninja-scan-light/tool/navigation/RINEX.h +9 -9
- data/ext/ninja-scan-light/tool/navigation/SBAS_Solver.h +1 -1
- data/ext/ninja-scan-light/tool/navigation/coordinate.h +13 -6
- data/ext/ninja-scan-light/tool/param/matrix.h +1020 -247
- data/ext/ninja-scan-light/tool/param/matrix_fixed.h +26 -0
- data/ext/ninja-scan-light/tool/swig/Coordinate.i +12 -12
- data/ext/ninja-scan-light/tool/swig/GPS.i +94 -84
- data/ext/ninja-scan-light/tool/swig/SylphideMath.i +187 -64
- data/ext/ninja-scan-light/tool/swig/spec/GPS_spec.rb +1 -1
- data/ext/ninja-scan-light/tool/swig/spec/SylphideMath_spec.rb +123 -13
- data/gps_pvt.gemspec +2 -1
- data/lib/gps_pvt/ntrip.rb +1 -1
- data/lib/gps_pvt/receiver/rtcm3.rb +106 -24
- data/lib/gps_pvt/receiver.rb +19 -8
- data/lib/gps_pvt/rtcm3.rb +53 -4
- data/lib/gps_pvt/version.rb +1 -1
- metadata +17 -3
@@ -6,6 +6,8 @@ require 'SylphideMath.so'
|
|
6
6
|
require 'matrix'
|
7
7
|
|
8
8
|
shared_examples 'Matrix' do
|
9
|
+
let!(:tolerance){SylphideMath::tolerance}
|
10
|
+
after{SylphideMath::tolerance = tolerance}
|
9
11
|
let(:params){{
|
10
12
|
:rc => [8, 8],
|
11
13
|
:acceptable_delta => 1E-10,
|
@@ -53,7 +55,7 @@ shared_examples 'Matrix' do
|
|
53
55
|
[:row_size, :column_size].each{|f|
|
54
56
|
a = a_gen.call
|
55
57
|
a.define_singleton_method(f){-1}
|
56
|
-
expect{ mat_type::new(a) }.to raise_error(
|
58
|
+
expect{ mat_type::new(a) }.to raise_error(ArgumentError)
|
57
59
|
}
|
58
60
|
end
|
59
61
|
it 'is invoked with I, identity, unit' do
|
@@ -70,12 +72,12 @@ shared_examples 'Matrix' do
|
|
70
72
|
end
|
71
73
|
it 'sets its elements with [], [[]], Matrix' do
|
72
74
|
expect( mat_type::new(params[:rc][0], params[:rc][1], compare_with.flatten).to_a ).to eq(compare_with)
|
73
|
-
expect{ mat_type::new(params[:rc][0], params[:rc][1], compare_with.flatten[0..-2]) }.to raise_error(
|
75
|
+
expect{ mat_type::new(params[:rc][0], params[:rc][1], compare_with.flatten[0..-2]) }.to raise_error(ArgumentError)
|
74
76
|
expect( mat_type::new(params[:rc][0], params[:rc][1], compare_with.flatten + [gen_elm.call]).to_a ).to eq(compare_with)
|
75
|
-
expect{ mat_type::new(params[:rc][0], params[:rc][1], compare_with.flatten[0..-2] + [nil]) }.to raise_error(
|
77
|
+
expect{ mat_type::new(params[:rc][0], params[:rc][1], compare_with.flatten[0..-2] + [nil]) }.to raise_error(ArgumentError)
|
76
78
|
|
77
79
|
expect( mat_type::new(params[:rc][0], params[:rc][1], compare_with).to_a ).to eq(compare_with)
|
78
|
-
expect{ mat_type::new(params[:rc][0], params[:rc][1], compare_with[0..-2]) }.to raise_error(
|
80
|
+
expect{ mat_type::new(params[:rc][0], params[:rc][1], compare_with[0..-2]) }.to raise_error(ArgumentError)
|
79
81
|
expect( mat_type::new(params[:rc][0], params[:rc][1], compare_with + [params[:rc][1].times.map{gen_elm.call}]).to_a ).to eq(compare_with)
|
80
82
|
expect( mat_type::new(compare_with).to_a ).to eq(compare_with)
|
81
83
|
|
@@ -83,7 +85,7 @@ shared_examples 'Matrix' do
|
|
83
85
|
end
|
84
86
|
it 'sets its elements with {}' do
|
85
87
|
expect( mat_type::new(*params[:rc]){|i, j| compare_with[i][j]}.to_a ).to eq(compare_with)
|
86
|
-
expect{ mat_type::new(*params[:rc]){nil}.to_a }.to raise_error(
|
88
|
+
expect{ mat_type::new(*params[:rc]){nil}.to_a }.to raise_error(ArgumentError)
|
87
89
|
expect{ mat_type::new(compare_with){|i, j| compare_with[i][j]} }.to raise_error(ArgumentError)
|
88
90
|
expect{ mat_type::new(Matrix[*compare_with]){|i, j| compare_with[i][j]} }.to raise_error(ArgumentError)
|
89
91
|
|
@@ -92,17 +94,25 @@ shared_examples 'Matrix' do
|
|
92
94
|
end
|
93
95
|
|
94
96
|
describe 'property' do
|
95
|
-
let(:
|
96
|
-
:square => proc{
|
97
|
+
let(:mat_gen){{
|
98
|
+
:square => proc{|r| # example: [[1, 3, 6], [2, 5, 8], [4, 7, 9]]
|
97
99
|
k = 0
|
98
|
-
mat_type::new(
|
99
|
-
|
100
|
+
res = mat_type::new(r, r)
|
101
|
+
(r * 2 - 1).times{|ij|
|
102
|
+
(([ij - r + 1, 0].max)..([ij, r - 1].min)).each{|i| res[ij - i, i] = (k += 1)}
|
103
|
+
}
|
104
|
+
res
|
105
|
+
}
|
106
|
+
}}
|
107
|
+
let(:mat){{
|
108
|
+
:square => mat_gen[:square].call(params[:rc][0]),
|
100
109
|
:not_square => proc{
|
101
110
|
k = 0
|
102
111
|
mat_type::new(params[:rc][0], params[:rc][0] * 2){|i, j| k += 1}
|
103
112
|
}.call,
|
104
113
|
:diagonal => mat_type::new(params[:rc][0], params[:rc][0]){|i, j| i == j ? 1 : 0},
|
105
114
|
:symmetric => mat_type::new(params[:rc][0], params[:rc][0]){|i, j| i + j},
|
115
|
+
:unit => mat_type::I(params[:rc][0]),
|
106
116
|
}}
|
107
117
|
describe 'is checked with' do
|
108
118
|
it 'square?' do
|
@@ -117,12 +127,52 @@ shared_examples 'Matrix' do
|
|
117
127
|
expect(mat[:diagonal].diagonal?) .to eq(true)
|
118
128
|
expect(mat[:symmetric].diagonal?) .to eq(false)
|
119
129
|
end
|
130
|
+
it 'lower_triangular?' do
|
131
|
+
expect(mat[:square].lower_triangular?) .to eq(false)
|
132
|
+
expect(mat[:not_square].lower_triangular?) .to eq(false)
|
133
|
+
expect(mat[:diagonal].lower_triangular?) .to eq(true)
|
134
|
+
expect(mat[:symmetric].lower_triangular?) .to eq(false)
|
135
|
+
end
|
136
|
+
it 'upper_triangular?' do
|
137
|
+
expect(mat[:square].upper_triangular?) .to eq(false)
|
138
|
+
expect(mat[:not_square].upper_triangular?) .to eq(false)
|
139
|
+
expect(mat[:diagonal].upper_triangular?) .to eq(true)
|
140
|
+
expect(mat[:symmetric].upper_triangular?) .to eq(false)
|
141
|
+
end
|
120
142
|
it 'symmetric?' do
|
121
143
|
expect(mat[:square].symmetric?) .to eq(false)
|
122
144
|
expect(mat[:not_square].symmetric?) .to eq(false)
|
123
145
|
expect(mat[:diagonal].symmetric?) .to eq(true)
|
124
146
|
expect(mat[:symmetric].symmetric?) .to eq(true)
|
125
147
|
end
|
148
|
+
it 'hermitian?' do
|
149
|
+
expect(mat[:square].hermitian?) .to eq(false)
|
150
|
+
expect(mat[:not_square].hermitian?) .to eq(false)
|
151
|
+
expect(mat[:diagonal].hermitian?) .to eq(true)
|
152
|
+
expect(mat[:symmetric].hermitian?) .to eq(true)
|
153
|
+
end
|
154
|
+
it 'skew_symmetric?' do
|
155
|
+
expect(mat[:square].skew_symmetric?) .to eq(false)
|
156
|
+
expect(mat[:not_square].skew_symmetric?) .to eq(false)
|
157
|
+
expect(mat[:diagonal].skew_symmetric?) .to eq(true)
|
158
|
+
expect(mat[:symmetric].skew_symmetric?) .to eq(false)
|
159
|
+
end
|
160
|
+
it 'normal?' do
|
161
|
+
expect(mat[:square].normal?) .to eq(false)
|
162
|
+
expect(mat[:not_square].normal?) .to eq(false)
|
163
|
+
expect(mat[:diagonal].normal?) .to eq(true)
|
164
|
+
expect(mat[:symmetric].normal?) .to eq(true)
|
165
|
+
end
|
166
|
+
it 'orthogonal?' do
|
167
|
+
expect(mat[:square].orthogonal?) .to eq(false)
|
168
|
+
expect(mat[:not_square].orthogonal?).to eq(false)
|
169
|
+
expect(mat[:unit].orthogonal?) .to eq(true)
|
170
|
+
end
|
171
|
+
it 'unitary?' do
|
172
|
+
expect(mat[:square].unitary?) .to eq(false)
|
173
|
+
expect(mat[:not_square].unitary?) .to eq(false)
|
174
|
+
expect(mat[:unit].unitary?) .to eq(true)
|
175
|
+
end
|
126
176
|
it 'different_size?' do
|
127
177
|
mat.keys.combination(2).each{|mat1, mat2|
|
128
178
|
expect(mat[mat1].different_size?(mat[mat2])).to eq([mat1, mat2].include?(:not_square))
|
@@ -142,10 +192,40 @@ shared_examples 'Matrix' do
|
|
142
192
|
end
|
143
193
|
it 'determinant, det' do
|
144
194
|
[:determinant, :det].each{|f|
|
145
|
-
|
195
|
+
expect(mat[:square].send(f)).to eq(Matrix[*mat[:square].to_a].det)
|
146
196
|
expect{mat[:not_square].send(f)}.to raise_error(RuntimeError)
|
147
197
|
}
|
148
198
|
end
|
199
|
+
it 'rank' do
|
200
|
+
(5..8).each{|n|
|
201
|
+
orig = mat_gen[:square].call(n)
|
202
|
+
expect(orig.rank).to eq(Matrix[*orig.to_a].rank)
|
203
|
+
}
|
204
|
+
expect(mat[:symmetric].rank).to eq(Matrix[*mat[:symmetric].to_a].rank)
|
205
|
+
expect{mat[:not_square].rank}.to raise_error(RuntimeError)
|
206
|
+
end
|
207
|
+
it 'cofactor' do
|
208
|
+
SylphideMath::tolerance = 1E-10
|
209
|
+
(5..8).each{|n|
|
210
|
+
orig = mat_gen[:square].call(n)
|
211
|
+
cmp = Matrix[*orig.to_a]
|
212
|
+
orig.rows.times{|i|
|
213
|
+
orig.columns.times{|j|
|
214
|
+
a, b = [orig, cmp].collect{|item| item.cofactor(i, j)} #rescue next
|
215
|
+
expect((a - b).abs).to be < params[:acceptable_delta]
|
216
|
+
}
|
217
|
+
}
|
218
|
+
}
|
219
|
+
end
|
220
|
+
it 'adjugate' do
|
221
|
+
SylphideMath::tolerance = 1E-10
|
222
|
+
(5..8).each{|n|
|
223
|
+
orig = mat_gen[:square].call(n)
|
224
|
+
(Matrix[*orig.adjugate.to_a] - Matrix[*orig.to_a].adjugate).each{|v|
|
225
|
+
expect(v.abs).to be < params[:acceptable_delta]
|
226
|
+
}
|
227
|
+
}
|
228
|
+
end
|
149
229
|
end
|
150
230
|
end
|
151
231
|
|
@@ -257,6 +337,8 @@ shared_examples 'Matrix' do
|
|
257
337
|
expect(mat.adjoint.to_a).to eq(Matrix[*compare_with].conj.t.to_a)
|
258
338
|
end
|
259
339
|
it 'supports submatrix with partial' do
|
340
|
+
expect(mat.partial(params[:rc][0] - 1, params[:rc][1] - 1).to_a) \
|
341
|
+
.to eq(Matrix[*compare_with[0..-2].collect{|values| values[0..-2]}].to_a)
|
260
342
|
expect(mat.partial(params[:rc][0] - 1, params[:rc][1] - 1, 1, 1).to_a) \
|
261
343
|
.to eq(Matrix[*compare_with[1..-1].collect{|values| values[1..-1]}].to_a)
|
262
344
|
end
|
@@ -280,6 +362,14 @@ shared_examples 'Matrix' do
|
|
280
362
|
}
|
281
363
|
}
|
282
364
|
end
|
365
|
+
it 'generates minor matrix with first_minor' do
|
366
|
+
params[:rc][0].times{|i|
|
367
|
+
params[:rc][1].times{|j|
|
368
|
+
expect(mat.first_minor(i, j).to_a) \
|
369
|
+
.to eq(Matrix[*compare_with].first_minor(i, j).to_a)
|
370
|
+
}
|
371
|
+
}
|
372
|
+
end
|
283
373
|
end
|
284
374
|
|
285
375
|
describe 'iterator' do
|
@@ -310,6 +400,19 @@ shared_examples 'Matrix' do
|
|
310
400
|
}
|
311
401
|
}
|
312
402
|
end
|
403
|
+
it 'supports index, find_index' do
|
404
|
+
cnd = proc{|v| v.abs >= 0.5}
|
405
|
+
[:index, :find_index].each{|func|
|
406
|
+
opt.each{|k, indices|
|
407
|
+
expect(mat.send(*[func, k].compact, &cnd)).to eq(
|
408
|
+
indices.select{|i, j| cnd.call(compare_with[i][j])}.first)
|
409
|
+
indices.each{|i, j|
|
410
|
+
expect(mat.send(*[func, compare_with[i][j], k].compact)).to eq([i, j])
|
411
|
+
}
|
412
|
+
expect(mat.send(*[func, 1, k].compact)).to be(nil)
|
413
|
+
}
|
414
|
+
}
|
415
|
+
end
|
313
416
|
it 'supports map, collect, map_with_index, collect_with_index' do
|
314
417
|
[:map, :collect, :map_with_index, :collect_with_index].each{|func|
|
315
418
|
opt.each{|k, indices|
|
@@ -372,7 +475,7 @@ shared_examples 'Matrix' do
|
|
372
475
|
end
|
373
476
|
it 'have +(scalar)' do
|
374
477
|
expect((mat[0] + 1).to_a).to eq((Matrix[*compare_with[0]] + Matrix::unit(params[:rc][0])).to_a)
|
375
|
-
expect{mat[2] + 1}.to raise_error(
|
478
|
+
expect{mat[2] + 1}.to raise_error(ArgumentError)
|
376
479
|
end
|
377
480
|
it 'have +(mat)' do
|
378
481
|
[[0, 1], [2, 3]].each{|i, j|
|
@@ -381,7 +484,7 @@ shared_examples 'Matrix' do
|
|
381
484
|
end
|
382
485
|
it 'have -(scalar)' do
|
383
486
|
expect((mat[0] - 1).to_a).to eq((Matrix[*compare_with[0]] - Matrix::unit(params[:rc][0])).to_a)
|
384
|
-
expect{mat[2] - 1}.to raise_error(
|
487
|
+
expect{mat[2] - 1}.to raise_error(ArgumentError)
|
385
488
|
end
|
386
489
|
it 'have -(mat)' do
|
387
490
|
[[0, 1], [2, 3]].each{|i, j|
|
@@ -395,9 +498,16 @@ shared_examples 'Matrix' do
|
|
395
498
|
end
|
396
499
|
it 'have *(mat)' do
|
397
500
|
expect((mat[0] * mat[1]).to_a).to eq((Matrix[*compare_with[0]] * Matrix[*compare_with[1]]).to_a)
|
398
|
-
expect{mat[2] * mat[3]}.to raise_error(
|
501
|
+
expect{mat[2] * mat[3]}.to raise_error(ArgumentError)
|
399
502
|
expect((mat[2] * mat[3].t).to_a).to eq((Matrix[*compare_with[2]] * Matrix[*compare_with[3]].t).to_a)
|
400
503
|
end
|
504
|
+
it 'have entrywise_product(mat), a.k.a. .*(mat)' do
|
505
|
+
[:entrywise_product, :hadamard_product].each{|func|
|
506
|
+
[[0, 1], [2, 3]].each{|i, j|
|
507
|
+
expect((mat[i].send(func, mat[j])).to_a).to eq((Matrix[*compare_with[i]].send(func, Matrix[*compare_with[j]])).to_a)
|
508
|
+
}
|
509
|
+
} if Gem::Version::create(RUBY_VERSION) >= Gem::Version::create("2.5.0")
|
510
|
+
end
|
401
511
|
it 'have /(scalar)' do
|
402
512
|
expect((mat[0] / 2).to_a).to eq((Matrix[*compare_with[0]] / 2).to_a)
|
403
513
|
expect((mat[2] / 2).to_a).to eq((Matrix[*compare_with[2]] / 2).to_a)
|
data/gps_pvt.gemspec
CHANGED
@@ -17,7 +17,7 @@ Gem::Specification.new do |spec|
|
|
17
17
|
|
18
18
|
spec.metadata["homepage_uri"] = spec.homepage
|
19
19
|
spec.metadata["source_code_uri"] = spec.homepage
|
20
|
-
#spec.metadata["changelog_uri"] = "
|
20
|
+
#spec.metadata["changelog_uri"] = "#{spec.homepage}/blob/main/CHANGELOG.md"
|
21
21
|
|
22
22
|
spec.extensions = ["ext/gps_pvt/extconf.rb"]
|
23
23
|
|
@@ -63,6 +63,7 @@ Gem::Specification.new do |spec|
|
|
63
63
|
spec.add_development_dependency "rake-compiler"
|
64
64
|
spec.add_development_dependency "rspec", "~> 3.0"
|
65
65
|
spec.add_development_dependency "matrix" if GPS_PVT::version_compare(RUBY_VERSION, "3.1") >= 0
|
66
|
+
spec.add_development_dependency "github_changelog_generator"
|
66
67
|
|
67
68
|
# For more information and examples about making a new gem, checkout our
|
68
69
|
# guide at: https://bundler.io/guides/creating_gem.html
|
data/lib/gps_pvt/ntrip.rb
CHANGED
@@ -54,7 +54,7 @@ class Ntrip < Net::HTTP
|
|
54
54
|
llh0 = Coordinate::LLH::new(D2R * lat_deg, D2R * lng_deg, 0)
|
55
55
|
collect{|pt, prop|
|
56
56
|
llh = Coordinate::LLH::new(*([:latitude, :longitude].collect{|k| D2R * prop[k].to_f} + [0]))
|
57
|
-
[llh0.xyz.
|
57
|
+
[llh0.xyz.distance(llh.xyz), prop]
|
58
58
|
}.sort{|a, b| a[0] <=> b[0]} # return [distance, property]
|
59
59
|
end
|
60
60
|
end
|
@@ -18,6 +18,13 @@ class Receiver
|
|
18
18
|
else; raise "reference time (#{ref_time}) should be GPS::Time or Time"
|
19
19
|
end
|
20
20
|
leap_sec = ref_time.leap_seconds
|
21
|
+
ref_pos = opt[:ref_pos] || if src_io.respond_to?(:property) then
|
22
|
+
Coordinate::LLH::new(*(src_io.property.values_at(:latitude, :longitude).collect{|v|
|
23
|
+
v.to_f / 180 * Math::PI
|
24
|
+
} + [0])).xyz
|
25
|
+
else
|
26
|
+
defined?(@base_station) ? @base_station : nil
|
27
|
+
end
|
21
28
|
after_run = b || proc{|pvt| puts pvt.to_s if pvt}
|
22
29
|
t_meas, meas = [nil, {}]
|
23
30
|
# meas := {msg_num => [[], ...]} due to duplicated observation such as 1074 and 1077
|
@@ -26,7 +33,9 @@ class Receiver
|
|
26
33
|
meas.sort.each{|k, values| # larger msg_num entries have higher priority
|
27
34
|
values.each{|prn_k_v| meas_.add(*prn_k_v)}
|
28
35
|
}
|
29
|
-
|
36
|
+
pvt = nil
|
37
|
+
after_run.call(pvt = run(meas_, t_meas), [meas_, ref_time = t_meas]) if t_meas
|
38
|
+
ref_pos = pvt.xyz if pvt && pvt.position_solved?
|
30
39
|
t_meas, meas = [nil, {}]
|
31
40
|
}
|
32
41
|
dt_threshold = GPS::Time::Seconds_week / 2
|
@@ -53,6 +62,63 @@ class Receiver
|
|
53
62
|
GPS::Time::new(ref_time.week, 0) + tod + 60 * 60 * 24 * ref_dow
|
54
63
|
end
|
55
64
|
}
|
65
|
+
restore_ranges = proc{
|
66
|
+
c_1ms = 299_792.458
|
67
|
+
threshold = c_1ms / 10 # 100 us =~ 30 km
|
68
|
+
cache = {} # {[sys, svid] => [range, t], ...}
|
69
|
+
get_rough = proc{|t, sys_svid_list|
|
70
|
+
sn_list = sys_svid_list.collect{|sys, svid|
|
71
|
+
case sys
|
72
|
+
when :GPS, :QZSS; @solver.gps_space_node
|
73
|
+
when :SBAS; @solver.sbas_space_node
|
74
|
+
when :GLONASS; @solver.glonass_space_node
|
75
|
+
end
|
76
|
+
}
|
77
|
+
critical{
|
78
|
+
sn_list.uniq.compact{|sn| sn.update_all_ephemeris(t)}
|
79
|
+
sys_svid_list.zip(sn_list).each{|(sys, svid), sn|
|
80
|
+
next unless sn
|
81
|
+
eph = sn.ephemeris(svid)
|
82
|
+
cache[[sys, svid]] = [if eph.valid?(t) then
|
83
|
+
sv_pos, clk_err = eph.constellation(t).values_at(0, 2)
|
84
|
+
sv_pos.distance(ref_pos) - (clk_err * c_1ms * 1E3)
|
85
|
+
end, t]
|
86
|
+
}
|
87
|
+
}
|
88
|
+
}
|
89
|
+
per_kind = proc{|t, sys_svid_list, ranges_rem|
|
90
|
+
get_rough.call(t, sys_svid_list.uniq.reject{|sys, svid|
|
91
|
+
next true unless sys
|
92
|
+
range, t2 = cache[[sys, svid]]
|
93
|
+
range && ((t2 - t).abs <= 60)
|
94
|
+
})
|
95
|
+
ranges_rem.zip(sys_svid_list).collect{|rem_in, (sys, svid)|
|
96
|
+
range_ref, t2 = cache[[sys, svid]]
|
97
|
+
next nil unless range_ref
|
98
|
+
q, rem_ref = range_ref.divmod(c_1ms)
|
99
|
+
delta = rem_in - rem_ref
|
100
|
+
res = if delta.abs <= threshold then
|
101
|
+
q * c_1ms + rem_in
|
102
|
+
elsif -delta + c_1ms <= threshold
|
103
|
+
(q - 1) * c_1ms + rem_in
|
104
|
+
elsif delta + c_1ms <= threshold
|
105
|
+
(q + 1) * c_1ms + rem_in
|
106
|
+
end
|
107
|
+
#p [sys, svid, q, rem_in, rem_ref, res]
|
108
|
+
(cache[[sys, svid]] = [res, t])[0]
|
109
|
+
}
|
110
|
+
}
|
111
|
+
proc{|t, sys_svid_list, ranges|
|
112
|
+
[
|
113
|
+
:pseudo_range, # for MT 1001/3/9/11, MSM1/3
|
114
|
+
:phase_range, # for MT 1003/11, MSM2/3
|
115
|
+
].each{|k|
|
116
|
+
next if ranges[k]
|
117
|
+
k_rem = "#{k}_rem".to_sym
|
118
|
+
ranges[k] = per_kind.call(t, sys_svid_list, ranges[k_rem]) if ranges[k_rem]
|
119
|
+
}
|
120
|
+
}
|
121
|
+
}.call
|
56
122
|
|
57
123
|
while packet = rtcm3.read_packet
|
58
124
|
msg_num = packet.message_number
|
@@ -66,15 +132,19 @@ class Receiver
|
|
66
132
|
when 1001..1004
|
67
133
|
t_meas2 = tow2t.call(parsed[2][0]) # DF004
|
68
134
|
ranges = parsed.ranges
|
69
|
-
|
70
|
-
[:sat, :pseudo_range, :phase_range, :cn].collect{|k|
|
71
|
-
ranges[k] || ([nil] * item_size)
|
72
|
-
}.transpose.each{|svid, pr, cpr, cn|
|
135
|
+
sys_svid_list = ranges[:sat].collect{|svid|
|
73
136
|
case svid
|
74
|
-
when 1..32;
|
75
|
-
when 40..58; svid
|
76
|
-
else;
|
137
|
+
when 1..32; [:GPS, svid]
|
138
|
+
when 40..58; [:SBAS, svid + 80]
|
139
|
+
else; [nil, svid]
|
77
140
|
end
|
141
|
+
}
|
142
|
+
restore_ranges.call(t_meas2, sys_svid_list, ranges)
|
143
|
+
item_size = sys_svid_list.size
|
144
|
+
([sys_svid_list] + [:pseudo_range, :phase_range, :cn].collect{|k|
|
145
|
+
ranges[k] || ([nil] * item_size)
|
146
|
+
}).transpose.each{|(sys, svid), pr, cpr, cn|
|
147
|
+
next unless sys
|
78
148
|
meas2 << [svid, :L1_PSEUDORANGE, pr] if pr
|
79
149
|
meas2 << [svid, :L1_CARRIER_PHASE, cpr / GPS::SpaceNode.L1_WaveLength] if cpr
|
80
150
|
meas2 << [svid, :L1_SIGNAL_STRENGTH_dBHz, cn] if cn
|
@@ -82,25 +152,34 @@ class Receiver
|
|
82
152
|
when 1009..1012
|
83
153
|
t_meas2 = utc2t.call(parsed[2][0] - 60 * 60 * 3) # DF034 UTC(SU)+3hr, time of day[sec]
|
84
154
|
ranges = parsed.ranges
|
85
|
-
|
86
|
-
[:sat, :freq_ch, :pseudo_range, :phase_range, :cn].collect{|k|
|
87
|
-
ranges[k] || ([nil] * item_size)
|
88
|
-
}.transpose.each{|svid, freq_ch, pr, cpr, cn|
|
155
|
+
sys_svid_list = ranges[:sat].collect{|svid|
|
89
156
|
case svid
|
90
|
-
when 1..24
|
157
|
+
when 1..24; [:GLONASS, svid]
|
158
|
+
when 40..58; [:SBAS, svid + 80]
|
159
|
+
else; [nil, svid]
|
160
|
+
end
|
161
|
+
}
|
162
|
+
restore_ranges.call(t_meas2, sys_svid_list, ranges)
|
163
|
+
item_size = sys_svid_list.size
|
164
|
+
([sys_svid_list] + [:freq_ch, :pseudo_range, :phase_range, :cn].collect{|k|
|
165
|
+
ranges[k] || ([nil] * item_size)
|
166
|
+
}).transpose.each{|(sys, svid), freq_ch, pr, cpr, cn|
|
167
|
+
case sys
|
168
|
+
when :GLONASS
|
91
169
|
svid += 0x100
|
92
170
|
freq = GPS::SpaceNode_GLONASS::L1_frequency(freq_ch)
|
93
171
|
len = GPS::SpaceNode_GLONASS.light_speed / freq
|
94
172
|
meas2 << [svid, :L1_FREQUENCY, freq]
|
95
173
|
meas2 << [svid, :L1_CARRIER_PHASE, cpr / len] if cpr
|
96
|
-
when
|
97
|
-
svid += 80 # SBAS
|
174
|
+
when :SBAS
|
98
175
|
meas2 << [svid, :L1_CARRIER_PHASE, cpr / GPS::SpaceNode.L1_WaveLength] if cpr
|
99
176
|
else; next
|
100
177
|
end
|
101
178
|
meas2 << [svid, :L1_PSEUDORANGE, pr] if pr
|
102
179
|
meas2 << [svid, :L1_SIGNAL_STRENGTH_dBHz, cn] if cn
|
103
180
|
}
|
181
|
+
when 1013
|
182
|
+
leap_sec = parsed[5][0]
|
104
183
|
when 1019, 1044
|
105
184
|
params = parsed.params
|
106
185
|
if msg_num == 1044
|
@@ -162,25 +241,27 @@ class Receiver
|
|
162
241
|
}.compact.flatten(1))]
|
163
242
|
}
|
164
243
|
end
|
165
|
-
sig_list, svid_offset = case msg_num / 10
|
244
|
+
sig_list, sys, svid_offset = case msg_num / 10
|
166
245
|
when 107 # GPS
|
167
246
|
[{2 => [:L1, GPS::SpaceNode.L1_WaveLength],
|
168
247
|
15 => [:L2CM, GPS::SpaceNode.L2_WaveLength],
|
169
|
-
16 => [:L2CL, GPS::SpaceNode.L2_WaveLength]}, 0]
|
248
|
+
16 => [:L2CL, GPS::SpaceNode.L2_WaveLength]}, :GPS, 0]
|
170
249
|
when 108 # GLONASS
|
171
|
-
[{2 => [:L1, nil]}, 0x100]
|
250
|
+
[{2 => [:L1, nil]}, :GLONASS, 0x100]
|
172
251
|
when 110 # SBAS
|
173
|
-
[{2 => [:L1, GPS::SpaceNode.L1_WaveLength]}, 120]
|
252
|
+
[{2 => [:L1, GPS::SpaceNode.L1_WaveLength]}, :SBAS, 120]
|
174
253
|
when 111 # QZSS
|
175
254
|
[{2 => [:L1, GPS::SpaceNode.L1_WaveLength],
|
176
255
|
15 => [:L2CM, GPS::SpaceNode.L2_WaveLength],
|
177
|
-
16 => [:L2CL, GPS::SpaceNode.L2_WaveLength]}, 192]
|
178
|
-
else; [{}, 0]
|
256
|
+
16 => [:L2CL, GPS::SpaceNode.L2_WaveLength]}, :QZSS, 192]
|
257
|
+
else; [{}, nil, 0]
|
179
258
|
end
|
180
|
-
|
181
|
-
|
259
|
+
sys_svid_list = ranges[:sat_sig].collect{|sat, sig| [sys, (sat + svid_offset) & 0xFF]}
|
260
|
+
restore_ranges.call(t_meas2, sys_svid_list, ranges)
|
261
|
+
item_size = sys_svid_list.size
|
262
|
+
[:sat_sig, :pseudo_range, :phase_range, :phase_range_rate, :cn, :halfc_amb].collect{|k|
|
182
263
|
ranges[k] || ([nil] * item_size)
|
183
|
-
}.transpose.each{|(svid, sig), pr, cpr, dr, cn|
|
264
|
+
}.transpose.each{|(svid, sig), pr, cpr, dr, cn, amb|
|
184
265
|
prefix, len = sig_list[sig]
|
185
266
|
next unless prefix
|
186
267
|
proc{
|
@@ -193,6 +274,7 @@ class Receiver
|
|
193
274
|
meas2 << [svid, "#{prefix}_RANGE_RATE".to_sym, dr] if dr
|
194
275
|
meas2 << [svid, "#{prefix}_CARRIER_PHASE".to_sym, cpr / len] if cpr && len
|
195
276
|
meas2 << [svid, "#{prefix}_SIGNAL_STRENGTH_dBHz".to_sym, cn] if cn
|
277
|
+
meas2 << [svid, "#{prefix}_CARRIER_PHASE_AMBIGUITY_SCALE".to_sym, 0.5] if amb && (amb == 1)
|
196
278
|
}
|
197
279
|
else
|
198
280
|
#p({msg_num => parsed})
|
data/lib/gps_pvt/receiver.rb
CHANGED
@@ -416,6 +416,7 @@ class Receiver
|
|
416
416
|
opt = options[0] || {}
|
417
417
|
case sys
|
418
418
|
when :GPS, :QZSS
|
419
|
+
return unless bcast_data.size == 10 # 8 for QZSS(SAIF)
|
419
420
|
return unless eph = @eph_list[prn]
|
420
421
|
sn = @solver.gps_space_node
|
421
422
|
subframe, iodc_or_iode = eph.parse(bcast_data)
|
@@ -508,10 +509,12 @@ class Receiver
|
|
508
509
|
}.each{|k, prop|
|
509
510
|
meas.add(prn, k, loader.call(*prop))
|
510
511
|
}
|
512
|
+
lli = packet[6 + 31 + (i * 24)]
|
511
513
|
# bit 0 of RINEX LLI (loss of lock indicator) shows lost lock
|
512
514
|
# between previous and current observation, which maps negative lock seconds
|
513
|
-
meas.add(prn, :L1_LOCK_SEC,
|
514
|
-
|
515
|
+
meas.add(prn, :L1_LOCK_SEC, (lli & 0x01 == 0x01) ? -1 : 0)
|
516
|
+
# set bit 1 of LLI represents possibility of half cycle ambiguity
|
517
|
+
meas.add(prn, :L1_CARRIER_PHASE_AMBIGUITY_SCALE, 0.5) if (lli & 0x02 == 0x02)
|
515
518
|
}
|
516
519
|
after_run.call(run(meas, t_meas), [meas, t_meas])
|
517
520
|
when [0x02, 0x15] # RXM-RAWX
|
@@ -552,7 +555,13 @@ class Receiver
|
|
552
555
|
}],
|
553
556
|
:DOPPLER => [32, 4, "e"],
|
554
557
|
:DOPPLER_SIGMA => [45, 1, nil, proc{|v| 2E-3 * (1 << (v[0] & 0xF))}],
|
555
|
-
:CARRIER_PHASE => [24, 8, "E", proc{|v|
|
558
|
+
:CARRIER_PHASE => [24, 8, "E", proc{|v|
|
559
|
+
case (trk_stat & 0x6)
|
560
|
+
when 0x6; (trk_stat & 0x8 == 0x8) ? (v + 0.5) : v
|
561
|
+
when 0x2; meas.add(svid, "#{sigid}_CARRIER_PHASE_AMBIGUITY_SCALE".to_sym, 0.5); v
|
562
|
+
else; nil
|
563
|
+
end
|
564
|
+
}],
|
556
565
|
:CARRIER_PHASE_SIGMA => [44, 1, nil, proc{|v|
|
557
566
|
(trk_stat & 0x2 == 0x2) ? (0.004 * (v[0] & 0xF)) : nil
|
558
567
|
}],
|
@@ -628,7 +637,7 @@ class Receiver
|
|
628
637
|
'S' => :SIGNAL_STRENGTH_dBHz,
|
629
638
|
}[type_[0]]]
|
630
639
|
next nil unless sig_obs_type.all?
|
631
|
-
[i, sig_obs_type.join('_').to_sym]
|
640
|
+
[i, sig_obs_type.join('_').to_sym, *sig_obs_type]
|
632
641
|
}.compact]
|
633
642
|
}.flatten(1))]
|
634
643
|
|
@@ -643,8 +652,7 @@ class Receiver
|
|
643
652
|
}.call(item[:header]["GLONASS SLOT / FRQ #"])
|
644
653
|
|
645
654
|
meas = GPS::Measurement::new
|
646
|
-
item[:meas].each{|
|
647
|
-
sys, prn = k
|
655
|
+
item[:meas].each{|(sys, prn), v|
|
648
656
|
case sys
|
649
657
|
when 'G', ' '
|
650
658
|
when 'S'; prn += 100
|
@@ -661,8 +669,11 @@ class Receiver
|
|
661
669
|
else; next
|
662
670
|
end
|
663
671
|
types[sys] = (types[' '] || []) unless types[sys]
|
664
|
-
types[sys].each{|i, type_|
|
665
|
-
|
672
|
+
types[sys].each{|i, type_, sig_type, obs_type|
|
673
|
+
next unless v[i]
|
674
|
+
meas.add(prn, type_, v[i][0])
|
675
|
+
meas.add(prn, "#{sig_type}_CARRIER_PHASE_AMBIGUITY_SCALE".to_sym, 0.5) \
|
676
|
+
if (obs_type == :CARRIER_PHASE) && (v[i][1] & 0x2 == 0x2)
|
666
677
|
}
|
667
678
|
}
|
668
679
|
after_run.call(run(meas, t_meas), [meas, t_meas])
|
data/lib/gps_pvt/rtcm3.rb
CHANGED
@@ -95,6 +95,13 @@ class RTCM3
|
|
95
95
|
48 => invalidate.call(num_gen.call(20, Rational(5, 10000)), 0x80000), # [m]
|
96
96
|
49 => 7,
|
97
97
|
50 => invalidate.call(unum_gen.call(8, Rational(1, 4)), 0), # [db-Hz]
|
98
|
+
51 => 16,
|
99
|
+
52 => 17,
|
100
|
+
53 => 5,
|
101
|
+
54 => 8,
|
102
|
+
55 => 12,
|
103
|
+
56 => 1,
|
104
|
+
57 => 16,
|
98
105
|
71 => 8,
|
99
106
|
76 => 10,
|
100
107
|
77 => proc{
|
@@ -237,12 +244,14 @@ class RTCM3
|
|
237
244
|
1001..1004 => (2..8).to_a,
|
238
245
|
1005 => [2, 3, 21, 22, 23, 24, 141, 25, 142, [1, 1], 26, 364, 27],
|
239
246
|
1009..1012 => [2, 3, 34, 5, 35, 36, 37],
|
247
|
+
1013 => [2, 3, 51, 52, 53, 54],
|
240
248
|
1019 => [2, 9, (76..79).to_a, 71, (81..103).to_a, 137].flatten, # 488 bits @see Table 3.5-21
|
241
249
|
1020 => [2, 38, 40, (104..136).to_a].flatten, # 360 bits @see Table 3.5-21
|
242
250
|
1043 => [2] + [:prn, :iodn, :tod, :ura,
|
243
251
|
[:xy] * 2, :z, [:dxy] * 2, :dz, [:ddxy] * 2, :ddz,
|
244
252
|
:agf0, :agf1].flatten.collect{|k| "SBAS_#{k}".to_sym}, # @see BNC Ntrip client RTCM3Decorder.cpp
|
245
253
|
1044 => [2, (429..457).to_a].flatten, # 485 bits
|
254
|
+
1070..1229 => [2, [:uint, 12], [:uint, 30], 393], # 55 bits part of messages will be overwritten
|
246
255
|
1071..1077 => [2, 3, 4, 393, 409, [1, 7], 411, 412, 417, 418, 394, 395], # 169 bits @see Table 3.5-78
|
247
256
|
1081..1087 => [2, 3, 416, 34, 393, 409, [1, 7], 411, 412, 417, 418, 394, 395], # 169 bits @see Table 3.5-93
|
248
257
|
1091..1097 => [2, 3, 248, 393, 409, [1, 7], 411, 412, 417, 418, 394, 395], # 169 bits @see Table 3.5-98
|
@@ -392,6 +401,30 @@ class RTCM3
|
|
392
401
|
end
|
393
402
|
SPEED_OF_LIGHT = 299_792_458
|
394
403
|
end
|
404
|
+
module MSM1_2_3
|
405
|
+
include MSM
|
406
|
+
def ranges
|
407
|
+
sats, cells, offset = property.values_at(:sats, :cells, :header_items)
|
408
|
+
nsat, ncell = [sats.size, cells.size]
|
409
|
+
res = {:sat_sig => cells}
|
410
|
+
range_rough = cells.collect{|sat, sig| # DF398
|
411
|
+
self[offset + sats.find_index(sat)][0]
|
412
|
+
}
|
413
|
+
add_proc = proc{|idx_cell|
|
414
|
+
values = self[offset + (nsat * 1) + (ncell * idx_cell), ncell]
|
415
|
+
next if values.empty?
|
416
|
+
k = {400 => :pseudo_range_rem, 401 => :phase_range_rem}[values[0][1]]
|
417
|
+
next unless k
|
418
|
+
res[k] = values.zip(range_rough).collect{|(v, df), v_base|
|
419
|
+
((v_base + v) * SPEED_OF_LIGHT) rescue nil
|
420
|
+
}
|
421
|
+
}
|
422
|
+
add_proc.call(0)
|
423
|
+
add_proc.call(1)
|
424
|
+
res[:halfc_amb] = self[-ncell, ncell].transpose[0] if self[-1][1] == 420
|
425
|
+
res
|
426
|
+
end
|
427
|
+
end
|
395
428
|
module MSM4_6
|
396
429
|
include MSM
|
397
430
|
def ranges
|
@@ -401,14 +434,16 @@ class RTCM3
|
|
401
434
|
range_rough2 = self[offset + (nsat * 1), nsat] # DF398
|
402
435
|
range_fine = self[offset + (nsat * 2), ncell] # DF400/405
|
403
436
|
phase_fine = self[offset + (nsat * 2) + (ncell * 1), ncell] # DF401/406
|
437
|
+
halfc_amb = self[offset + (nsat * 2) + (ncell * 3), ncell] # DF420
|
404
438
|
cn = self[offset + (nsat * 2) + (ncell * 4), ncell] # DF403/408
|
405
|
-
Hash[*([:sat_sig, :pseudo_range, :phase_range, :cn].zip(
|
439
|
+
Hash[*([:sat_sig, :pseudo_range, :phase_range, :cn, :halfc_amb].zip(
|
406
440
|
[cells] + cells.collect.with_index{|(sat, sig), i|
|
407
441
|
i2 = sats.find_index(sat)
|
408
442
|
rough_ms = (range_rough2[i2][0] + range_rough[i2][0]) rescue nil
|
409
443
|
[(((range_fine[i][0] + rough_ms) * SPEED_OF_LIGHT) rescue nil),
|
410
444
|
(((phase_fine[i][0] + rough_ms) * SPEED_OF_LIGHT) rescue nil),
|
411
|
-
cn[i][0]
|
445
|
+
cn[i][0],
|
446
|
+
halfc_amb[i][0]]
|
412
447
|
}.transpose).flatten(1))]
|
413
448
|
end
|
414
449
|
end
|
@@ -422,16 +457,18 @@ class RTCM3
|
|
422
457
|
delta_rough = self[offset + (nsat * 3), nsat] # DF399
|
423
458
|
range_fine = self[offset + (nsat * 4), ncell] # DF400/405
|
424
459
|
phase_fine = self[offset + (nsat * 4) + (ncell * 1), ncell] # DF401/406
|
460
|
+
halfc_amb = self[offset + (nsat * 4) + (ncell * 3), ncell] # DF420
|
425
461
|
cn = self[offset + (nsat * 4) + (ncell * 4), ncell] # DF403/408
|
426
462
|
delta_fine = self[offset + (nsat * 4) + (ncell * 5), ncell] # DF404
|
427
|
-
Hash[*([:sat_sig, :pseudo_range, :phase_range, :phase_range_rate, :cn].zip(
|
463
|
+
Hash[*([:sat_sig, :pseudo_range, :phase_range, :phase_range_rate, :cn, :halfc_amb].zip(
|
428
464
|
[cells] + cells.collect.with_index{|(sat, sig), i|
|
429
465
|
i2 = sats.find_index(sat)
|
430
466
|
rough_ms = (range_rough2[i2][0] + range_rough[i2][0]) rescue nil
|
431
467
|
[(((range_fine[i][0] + rough_ms) * SPEED_OF_LIGHT) rescue nil),
|
432
468
|
(((phase_fine[i][0] + rough_ms) * SPEED_OF_LIGHT) rescue nil),
|
433
469
|
((delta_fine[i][0] + delta_rough[i2][0]) rescue nil),
|
434
|
-
cn[i][0]
|
470
|
+
cn[i][0],
|
471
|
+
halfc_amb[i][0]]
|
435
472
|
}.transpose).flatten(1))]
|
436
473
|
end
|
437
474
|
end
|
@@ -468,6 +505,9 @@ class RTCM3
|
|
468
505
|
1012 => (38..50).to_a,
|
469
506
|
}[msg_num]] * nsat).flatten), offset)
|
470
507
|
attributes << GLONASS_Observation
|
508
|
+
when 1013
|
509
|
+
add_proc.call(DataFrame.generate_prop(
|
510
|
+
((55..57).to_a * values[4]).flatten), 24 + mt[:bits_total])
|
471
511
|
when 1019
|
472
512
|
attributes << GPS_Ephemeris
|
473
513
|
when 1020
|
@@ -492,6 +532,15 @@ class RTCM3
|
|
492
532
|
add_proc.call(msm_sig, offset)
|
493
533
|
}
|
494
534
|
case msg_num % 10
|
535
|
+
when 1
|
536
|
+
attributes << MSM1_2_3
|
537
|
+
msm_proc.call([398], [400])
|
538
|
+
when 2
|
539
|
+
attributes << MSM1_2_3
|
540
|
+
msm_proc.call([398], [401, 402, 420])
|
541
|
+
when 3
|
542
|
+
attributes << MSM1_2_3
|
543
|
+
msm_proc.call([398], [400, 401, 402, 420])
|
495
544
|
when 4
|
496
545
|
attributes << MSM4_6
|
497
546
|
msm_proc.call([397, 398], [400, 401, 402, 420, 403])
|