gps_pvt 0.1.4 → 0.2.0

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.
@@ -7,102 +7,126 @@ require_relative 'GPS'
7
7
 
8
8
  module GPS_PVT
9
9
  class Receiver
10
- OUTPUT_PVT_ITEMS = [[
11
- [:week, :itow_rcv, :year, :month, :mday, :hour, :min, :sec],
12
- proc{|pvt|
13
- [:week, :seconds, :c_tm].collect{|f| pvt.receiver_time.send(f)}.flatten
14
- }
15
- ]] + [[
16
- [:receiver_clock_error_meter, :longitude, :latitude, :height],
17
- proc{|pvt|
18
- next [nil] * 4 unless pvt.position_solved?
10
+ def self.pvt_items(opt = {})
11
+ opt = {
12
+ :system => [[:GPS, 1..32]],
13
+ :satellites => (1..32).to_a,
14
+ }.merge(opt)
15
+ [[
16
+ [:week, :itow_rcv, :year, :month, :mday, :hour, :min, :sec],
17
+ proc{|pvt|
18
+ [:week, :seconds, :c_tm].collect{|f| pvt.receiver_time.send(f)}.flatten
19
+ }
20
+ ]] + [[
21
+ [:receiver_clock_error_meter, :longitude, :latitude, :height, :rel_E, :rel_N, :rel_U],
22
+ proc{|pvt|
23
+ next [nil] * 7 unless pvt.position_solved?
24
+ [
25
+ pvt.receiver_error,
26
+ pvt.llh.lng / Math::PI * 180,
27
+ pvt.llh.lat / Math::PI * 180,
28
+ pvt.llh.alt,
29
+ ] + (pvt.rel_ENU.to_a rescue [nil] * 3)
30
+ }
31
+ ]] + [proc{
32
+ labels = [:g, :p, :h, :v, :t].collect{|k| "#{k}dop".to_sym}
19
33
  [
20
- pvt.receiver_error,
21
- pvt.llh.lng / Math::PI * 180,
22
- pvt.llh.lat / Math::PI * 180,
23
- pvt.llh.alt,
34
+ labels,
35
+ proc{|pvt|
36
+ next [nil] * 5 unless pvt.position_solved?
37
+ labels.collect{|k| pvt.send(k)}
38
+ }
24
39
  ]
25
- }
26
- ]] + [proc{
27
- labels = [:g, :p, :h, :v, :t].collect{|k| "#{k}dop".to_sym}
28
- [
29
- labels,
40
+ }.call] + [[
41
+ [:v_north, :v_east, :v_down, :receiver_clock_error_dot_ms],
30
42
  proc{|pvt|
31
- next [nil] * 5 unless pvt.position_solved?
32
- labels.collect{|k| pvt.send(k)}
43
+ next [nil] * 4 unless pvt.velocity_solved?
44
+ [:north, :east, :down].collect{|k| pvt.velocity.send(k)} \
45
+ + [pvt.receiver_error_rate]
33
46
  }
34
- ]
35
- }.call] + [[
36
- [:v_north, :v_east, :v_down, :receiver_clock_error_dot_ms],
37
- proc{|pvt|
38
- next [nil] * 4 unless pvt.velocity_solved?
39
- [:north, :east, :down].collect{|k| pvt.velocity.send(k)} \
40
- + [pvt.receiver_error_rate]
41
- }
42
- ]] + [
43
- [:used_satellites, proc{|pvt| pvt.used_satellites}],
44
- [:PRN, proc{|pvt|
45
- ("%32s"%[pvt.used_satellite_list.collect{|i|
46
- 1 << (i - 1)
47
- }.inject(0){|res, v| res | v}.to_s(2)]).scan(/.{8}/).collect{|str|
48
- str.gsub(' ', '0')
49
- }.join('_')
50
- }],
51
- ] + [[
52
- (1..32).collect{|prn|
53
- [:range_residual, :weight, :azimuth, :elevation, :slopeH, :slopeV].collect{|str| "#{str}(#{prn})"}
54
- }.flatten,
55
- proc{|pvt|
56
- next ([nil] * 6 * 32) unless pvt.position_solved?
57
- sats = pvt.used_satellite_list
58
- r, w = [:delta_r, :W].collect{|f| pvt.send(f)}
59
- (1..32).collect{|i|
60
- next ([nil] * 6) unless i2 = sats.index(i)
61
- [r[i2, 0], w[i2, i2]] +
62
- [:azimuth, :elevation].collect{|f|
63
- pvt.send(f)[i] / Math::PI * 180
64
- } + [pvt.slopeH[i], pvt.slopeV[i]]
65
- }.flatten
66
- },
67
- ]] + [[
68
- [:wssr, :wssr_sf, :weight_max,
69
- :slopeH_max, :slopeH_max_PRN, :slopeH_max_elevation,
70
- :slopeV_max, :slopeV_max_PRN, :slopeV_max_elevation],
71
- proc{|pvt|
72
- next [nil] * 9 unless fd = pvt.fd
73
- el_deg = [4, 6].collect{|i| pvt.elevation[fd[i]] / Math::PI * 180}
74
- fd[0..4] + [el_deg[0]] + fd[5..6] + [el_deg[1]]
75
- }
76
- ]] + [[
77
- [:wssr_FDE_min, :wssr_FDE_min_PRN, :wssr_FDE_2nd, :wssr_FDE_2nd_PRN],
78
- proc{|pvt|
79
- [:fde_min, :fde_2nd].collect{|f|
80
- info = pvt.send(f)
81
- next ([nil] * 2) if (!info) || info.empty?
82
- [info[0], info[-3]]
83
- }.flatten
84
- }
85
- ]]
47
+ ]] + [
48
+ [:used_satellites, proc{|pvt| pvt.used_satellites}],
49
+ ] + opt[:system].collect{|sys, range|
50
+ bit_flip = if range.kind_of?(Array) then
51
+ proc{|res, i|
52
+ res[i] = "1" if i = range.index(i)
53
+ res
54
+ }
55
+ else # expect Range
56
+ base_prn = range.min
57
+ proc{|res, i|
58
+ res[i - base_prn] = "1" if range.include?(i)
59
+ res
60
+ }
61
+ end
62
+ ["#{sys}_PRN", proc{|pvt|
63
+ pvt.used_satellite_list.inject("0" * range.size, &bit_flip) \
64
+ .scan(/.{1,8}/).join('_').reverse
65
+ }]
66
+ } + [[
67
+ opt[:satellites].collect{|prn, label|
68
+ [:range_residual, :weight, :azimuth, :elevation, :slopeH, :slopeV].collect{|str|
69
+ "#{str}(#{label || prn})"
70
+ }
71
+ }.flatten,
72
+ proc{|pvt|
73
+ next ([nil] * 6 * opt[:satellites].size) unless pvt.position_solved?
74
+ sats = pvt.used_satellite_list
75
+ r, w = [:delta_r, :W].collect{|f| pvt.send(f)}
76
+ opt[:satellites].collect{|i|
77
+ next ([nil] * 6) unless i2 = sats.index(i)
78
+ [r[i2, 0], w[i2, i2]] +
79
+ [:azimuth, :elevation].collect{|f|
80
+ pvt.send(f)[i] / Math::PI * 180
81
+ } + [pvt.slopeH[i], pvt.slopeV[i]]
82
+ }.flatten
83
+ },
84
+ ]] + [[
85
+ [:wssr, :wssr_sf, :weight_max,
86
+ :slopeH_max, :slopeH_max_PRN, :slopeH_max_elevation,
87
+ :slopeV_max, :slopeV_max_PRN, :slopeV_max_elevation],
88
+ proc{|pvt|
89
+ next [nil] * 9 unless fd = pvt.fd
90
+ el_deg = [4, 6].collect{|i| pvt.elevation[fd[i]] / Math::PI * 180}
91
+ fd[0..4] + [el_deg[0]] + fd[5..6] + [el_deg[1]]
92
+ }
93
+ ]] + [[
94
+ [:wssr_FDE_min, :wssr_FDE_min_PRN, :wssr_FDE_2nd, :wssr_FDE_2nd_PRN],
95
+ proc{|pvt|
96
+ [:fde_min, :fde_2nd].collect{|f|
97
+ info = pvt.send(f)
98
+ next ([nil] * 2) if (!info) || info.empty?
99
+ [info[0], info[-3]]
100
+ }.flatten
101
+ }
102
+ ]]
103
+ end
86
104
 
87
- OUTPUT_MEAS_ITEMS = [[
88
- (1..32).collect{|prn|
89
- [:L1_range, :L1_rate].collect{|str| "#{str}(#{prn})"}
90
- }.flatten,
91
- proc{|meas|
92
- meas_hash = Hash[*(meas.collect{|prn, k, v| [[prn, k], v]}.flatten(1))]
93
- (1..32).collect{|prn|
94
- [:L1_PSEUDORANGE, [:L1_DOPPLER, GPS::SpaceNode.L1_WaveLength]].collect{|k, sf|
95
- meas_hash[[prn, GPS::Measurement.const_get(k)]] * (sf || 1) rescue nil
105
+ def self.meas_items(opt = {})
106
+ opt = {
107
+ :satellites => (1..32).to_a,
108
+ }.merge(opt)
109
+ [[
110
+ opt[:satellites].collect{|prn, label|
111
+ [:L1_range, :L1_rate].collect{|str| "#{str}(#{label || prn})"}
112
+ }.flatten,
113
+ proc{|meas|
114
+ meas_hash = Hash[*(meas.collect{|prn, k, v| [[prn, k], v]}.flatten(1))]
115
+ opt[:satellites].collect{|prn|
116
+ [:L1_PSEUDORANGE, [:L1_DOPPLER, GPS::SpaceNode.L1_WaveLength]].collect{|k, sf|
117
+ meas_hash[[prn, GPS::Measurement.const_get(k)]] * (sf || 1) rescue nil
118
+ }
96
119
  }
97
120
  }
98
- }
99
- ]]
100
-
101
- def self.header
102
- (OUTPUT_PVT_ITEMS + OUTPUT_MEAS_ITEMS).transpose[0].flatten.join(',')
121
+ ]]
122
+ end
123
+
124
+ def header
125
+ (@output[:pvt] + @output[:meas]).transpose[0].flatten.join(',')
103
126
  end
104
127
 
105
128
  attr_accessor :solver
129
+ attr_accessor :base_station
106
130
 
107
131
  def initialize(options = {})
108
132
  @solver = GPS::Solver::new
@@ -110,8 +134,17 @@ class Receiver
110
134
  rel_prop[0] = 1 if rel_prop[0] > 0 # weight = 1
111
135
  rel_prop
112
136
  }
137
+ @debug = {}
138
+ output_options = {
139
+ :system => [[:GPS, 1..32], [:QZSS, 193..202]],
140
+ :satellites => (1..32).to_a + (193..202).to_a, # [idx, ...] or [[idx, label], ...] is acceptable
141
+ }
113
142
  options = options.reject{|k, v|
114
143
  case k
144
+ when :debug
145
+ v = v.split(/,/)
146
+ @debug[v[0].upcase.to_sym] = v[1..-1]
147
+ next true
115
148
  when :weight
116
149
  case v.to_sym
117
150
  when :elevation # (same as underneath C++ library)
@@ -127,6 +160,77 @@ class Receiver
127
160
  when :identical # same as default
128
161
  next true
129
162
  end
163
+ when :base_station
164
+ crd, sys = v.split(/ *, */).collect.with_index{|item, i|
165
+ case item
166
+ when /^([\+-]?\d+\.?\d*)([XYZNEDU]?)$/ # ex) meter[X], degree[N]
167
+ [$1.to_f, ($2 + "XY?"[i])[0]]
168
+ when /^([\+-]?\d+)_(?:(\d+)_(\d+\.?\d*)|(\d+\.?\d*))([NE])$/ # ex) deg_min_secN
169
+ [$1.to_f + ($2 || $4).to_f / 60 + ($3 || 0).to_f / 3600, $5]
170
+ else
171
+ raise "Unknown coordinate spec.: #{item}"
172
+ end
173
+ }.transpose
174
+ raise "Unknown base station: #{v}" if crd.size != 3
175
+ @base_station = case (sys = sys.join.to_sym)
176
+ when :XYZ, :XY?
177
+ Coordinate::XYZ::new(*crd)
178
+ when :NED, :ENU, :NE?, :EN? # :NE? => :NEU, :EN? => :ENU
179
+ (0..1).each{|i| crd[i] *= (Math::PI / 180)}
180
+ ([:NED, :NE?].include?(sys) ?
181
+ Coordinate::LLH::new(crd[0], crd[1], crd[2] * (:NED == sys ? -1 : 1)) :
182
+ Coordinate::LLH::new(crd[1], crd[0], crd[2])).xyz
183
+ else
184
+ raise "Unknown coordinate system: #{sys}"
185
+ end
186
+ $stderr.puts "Base station (LLH): #{
187
+ llh = @base_station.llh.to_a
188
+ llh[0..1].collect{|rad| rad / Math::PI * 180} + [llh[2]]
189
+ }"
190
+ next true
191
+ when :with, :without
192
+ [v].flatten.each{|spec| # array is acceptable
193
+ sys, svid = case spec
194
+ when Integer
195
+ [nil, spec]
196
+ when /([a-zA-Z]+)(?::(-?\d+))?/
197
+ [$1.upcase.to_sym, (Integre($2) rescue nil)]
198
+ when /-?\d+/
199
+ [nil, $&.to_i]
200
+ else
201
+ next false
202
+ end
203
+ mode = if svid && (svid < 0) then
204
+ svid *= -1
205
+ (k == :with) ? :exclude : :include
206
+ else
207
+ (k == :with) ? :include : :exclude
208
+ end
209
+ if (sys == :GPS) || (sys == :QZSS) \
210
+ || (svid && ((1..32).include?(svid) || (193..202).include?(svid))) then
211
+ [svid || ((1..32).to_a + (193..202).to_a)].flatten.each{
212
+ @solver.gps_options.send(mode, svid)
213
+ }
214
+ elsif (sys == :SBAS) || (svid && (120..158).include?(svid)) then
215
+ prns = [svid || (120..158).to_a].flatten
216
+ unless (i = output_options[:system].index{|sys, range| sys == :SBAS}) then
217
+ i = -1
218
+ output_options[:system] << [:SBAS, []]
219
+ else
220
+ output_options[:system][i].reject!{|prn| prns.include?(prn)}
221
+ end
222
+ output_options[:satellites].reject!{|prn, label| prns.include?(prn)}
223
+ if mode == :include then
224
+ output_options[:system][i][1] += prns
225
+ output_options[:satellites] += prns
226
+ end
227
+ prns.each{|prn| @solver.sbas_options.send(mode, prn)}
228
+ else
229
+ next false
230
+ end
231
+ $stderr.puts "#{mode.capitalize} satellite: #{[sys, svid].compact.join(':')}"
232
+ }
233
+ next true
130
234
  end
131
235
  false
132
236
  }
@@ -135,9 +239,35 @@ class Receiver
135
239
  opt.elevation_mask = 0.0 / 180 * Math::PI # 0 deg
136
240
  opt.residual_mask = 1E4 # 10 km
137
241
  }.call(@solver.gps_options)
242
+ @output = {
243
+ :pvt => Receiver::pvt_items(output_options),
244
+ :meas => Receiver::meas_items(output_options),
245
+ }
138
246
  end
139
247
 
140
- def run(meas, t_meas)
248
+ GPS::Measurement.class_eval{
249
+ proc{
250
+ key2sym = []
251
+ GPS::Measurement.constants.each{|k|
252
+ i = GPS::Measurement.const_get(k)
253
+ key2sym[i] = k if i.kind_of?(Integer)
254
+ }
255
+ define_method(:to_a2){
256
+ to_a.collect{|prn, k, v| [prn, key2sym[k] || k, v]}
257
+ }
258
+ define_method(:to_hash2){
259
+ Hash[*(to_hash.collect{|prn, k_v|
260
+ [prn, Hash[*(k_v.collect{|k, v| [key2sym[k] || k, v]}.flatten(1))]]
261
+ }.flatten(1))]
262
+ }
263
+ }.call
264
+ alias_method(:add_orig, :add)
265
+ define_method(:add){|prn, key, value|
266
+ add_orig(prn, key.kind_of?(Symbol) ? GPS::Measurement.const_get(key) : key, value)
267
+ }
268
+ }
269
+
270
+ def run(meas, t_meas, ref_pos = @base_station)
141
271
  =begin
142
272
  $stderr.puts "Measurement time: #{t_meas.to_a} (a.k.a #{"%d/%d/%d %d:%d:%d UTC"%[*t_meas.c_tm]})"
143
273
  meas.to_a.collect{|prn, k, v| prn}.uniq.each{|prn|
@@ -148,10 +278,14 @@ class Receiver
148
278
 
149
279
  #@solver.gps_space_node.update_all_ephemeris(t_meas) # internally called in the following solver.solve
150
280
  pvt = @solver.solve(meas, t_meas)
281
+ pvt.define_singleton_method(:rel_ENU){
282
+ Coordinate::ENU::relative(xyz, ref_pos)
283
+ } if (ref_pos && pvt.position_solved?)
284
+ output = @output
151
285
  pvt.define_singleton_method(:to_s){
152
- (OUTPUT_PVT_ITEMS.transpose[1].collect{|task|
286
+ (output[:pvt].transpose[1].collect{|task|
153
287
  task.call(pvt)
154
- } + OUTPUT_MEAS_ITEMS.transpose[1].collect{|task|
288
+ } + output[:meas].transpose[1].collect{|task|
155
289
  task.call(meas)
156
290
  }).flatten.join(',')
157
291
  }
@@ -172,7 +306,7 @@ class Receiver
172
306
  self.instance_variable_set(k, Hash[*(sats.zip(values).flatten(1))])
173
307
  }
174
308
  [:@slopeH, :@slopeV] \
175
- .zip((self.slope_HV_enu.to_a.transpose rescue [nil, nil])) \
309
+ .zip((self.fd ? self.slope_HV_enu.to_a.transpose : [nil, nil])) \
176
310
  .each{|k, values|
177
311
  self.instance_variable_set(k,
178
312
  Hash[*(values ? sats.zip(values).flatten(1) : [])])
@@ -185,30 +319,41 @@ class Receiver
185
319
  }
186
320
 
187
321
  proc{
188
- eph_list = Hash[*(1..32).collect{|prn|
322
+ eph_list = Hash[*((1..32).to_a + (193..202).to_a).collect{|prn|
189
323
  eph = GPS::Ephemeris::new
190
324
  eph.svid = prn
191
325
  [prn, eph]
192
326
  }.flatten(1)]
193
- define_method(:register_ephemeris){|t_meas, prn, bcast_data|
194
- next unless eph = eph_list[prn]
195
- sn = @solver.gps_space_node
196
- subframe, iodc_or_iode = eph.parse(bcast_data)
197
- if iodc_or_iode < 0 then
198
- begin
199
- sn.update_iono_utc(
200
- GPS::Ionospheric_UTC_Parameters::parse(bcast_data))
201
- [:alpha, :beta].each{|k|
202
- $stderr.puts "Iono #{k}: #{sn.iono_utc.send(k)}"
203
- } if false
204
- rescue
327
+ define_method(:register_ephemeris){|t_meas, sys, prn, bcast_data|
328
+ case sys
329
+ when :GPS, :QZSS
330
+ next unless eph = eph_list[prn]
331
+ sn = @solver.gps_space_node
332
+ subframe, iodc_or_iode = eph.parse(bcast_data)
333
+ if iodc_or_iode < 0 then
334
+ begin
335
+ sn.update_iono_utc(
336
+ GPS::Ionospheric_UTC_Parameters::parse(bcast_data))
337
+ [:alpha, :beta].each{|k|
338
+ $stderr.puts "Iono #{k}: #{sn.iono_utc.send(k)}"
339
+ } if false
340
+ rescue
341
+ end
342
+ next
343
+ end
344
+ if t_meas and eph.consistent? then
345
+ eph.WN = ((t_meas.week / 1024).to_i * 1024) + (eph.WN % 1024)
346
+ sn.register_ephemeris(prn, eph)
347
+ eph.invalidate
348
+ end
349
+ when :SBAS
350
+ case @solver.sbas_space_node.decode_message(bcast_data[0..7], prn, t_meas)
351
+ when 26
352
+ ['', "IGP broadcasted by PRN#{prn} @ #{Time::utc(*t_meas.c_tm)}",
353
+ @solver.sbas_space_node.ionospheric_grid_points(prn)].each{|str|
354
+ $stderr.puts str
355
+ } if @debug[:SBAS_IGP]
205
356
  end
206
- next
207
- end
208
- if t_meas and eph.consistent? then
209
- eph.WN = ((t_meas.week / 1024).to_i * 1024) + (eph.WN % 1024)
210
- sn.register_ephemeris(prn, eph)
211
- eph.invalidate
212
357
  end
213
358
  }
214
359
  }.call
@@ -222,6 +367,24 @@ class Receiver
222
367
 
223
368
  after_run = b || proc{|pvt| puts pvt.to_s}
224
369
 
370
+ gnss_serial = proc{|svid, sys|
371
+ if sys then # new numbering
372
+ sys = [:GPS, :SBAS, :Galileo, :BeiDou, :IMES, :QZSS, :GLONASS][sys] if sys.kind_of?(Integer)
373
+ case sys
374
+ when :QZSS; svid += 192
375
+ end
376
+ else # old numbering
377
+ sys = case svid
378
+ when 1..32; :GPS
379
+ when 120..158; :SBAS
380
+ when 193..202; :QZSS
381
+ when 65..96; svid -= 64; :GLONASS
382
+ when 255; :GLONASS
383
+ end
384
+ end
385
+ [sys, svid]
386
+ }
387
+
225
388
  t_meas = nil
226
389
  ubx.each_packet.with_index(1){|packet, i|
227
390
  $stderr.print '.' if i % 1000 == 0
@@ -245,11 +408,11 @@ class Receiver
245
408
  :L1_CARRIER_PHASE => [8, 8, "E"],
246
409
  :L1_SIGNAL_STRENGTH_dBHz => [30, 1, "c"],
247
410
  }.each{|k, prop|
248
- meas.add(prn, GPS::Measurement.const_get(k), loader.call(*prop))
411
+ meas.add(prn, k, loader.call(*prop))
249
412
  }
250
413
  # bit 0 of RINEX LLI (loss of lock indicator) shows lost lock
251
414
  # between previous and current observation, which maps negative lock seconds
252
- meas.add(prn, GPS::Measurement::L1_LOCK_SEC,
415
+ meas.add(prn, :L1_LOCK_SEC,
253
416
  (packet[6 + 31 + (i * 24)] & 0x01 == 0x01) ? -1 : 0)
254
417
  }
255
418
  after_run.call(run(meas, t_meas), [meas, t_meas])
@@ -266,8 +429,11 @@ class Receiver
266
429
  v = post.call(v) if post
267
430
  v
268
431
  }
269
- next unless (gnss = loader.call(36, 1)[0]) == 0
270
- svid = loader.call(37, 1)[0]
432
+ sys, svid = gnss_serial.call(*loader.call(36, 2).reverse)
433
+ case sys
434
+ when :GPS, :QZSS;
435
+ else; next
436
+ end
271
437
  trk_stat = loader.call(46, 1)[0]
272
438
  {
273
439
  :L1_PSEUDORANGE => [16, 8, "E", proc{|v| (trk_stat & 0x1 == 0x1) ? v : nil}],
@@ -280,26 +446,28 @@ class Receiver
280
446
  :L1_CARRIER_PHASE_SIGMA => [44, 1, nil, proc{|v|
281
447
  (trk_stat & 0x2 == 0x2) ? (0.004 * (v[0] & 0xF)) : nil
282
448
  }],
283
- :L1_SIGNAL_STRENGTH_dBHz => [42, 1],
449
+ :L1_SIGNAL_STRENGTH_dBHz => [42, 1, "C"],
284
450
  :L1_LOCK_SEC => [40, 2, "v", proc{|v| 1E-3 * v}],
285
451
  }.each{|k, prop|
286
452
  next unless v = loader.call(*prop)
287
- meas.add(svid, GPS::Measurement.const_get(k), v)
453
+ meas.add(svid, k, v)
288
454
  }
289
455
  }
290
456
  after_run.call(run(meas, t_meas), [meas, t_meas])
291
457
  when [0x02, 0x11] # RXM-SFRB
458
+ sys, svid = gnss_serial.call(packet[6 + 1])
292
459
  register_ephemeris(
293
460
  t_meas,
294
- packet[6 + 1],
461
+ sys, svid,
295
462
  packet.slice(6 + 2, 40).each_slice(4).collect{|v|
296
- (v.pack("C*").unpack("V")[0] & 0xFFFFFF) << 6
463
+ res = v.pack("C*").unpack("V")[0]
464
+ (sys == :GPS) ? ((res & 0xFFFFFF) << 6) : res
297
465
  })
298
466
  when [0x02, 0x13] # RXM-SFRBX
299
- next unless (gnss = packet[6]) == 0
467
+ sys, svid = gnss_serial.call(packet[6 + 1], packet[6])
300
468
  register_ephemeris(
301
469
  t_meas,
302
- packet[6 + 1],
470
+ sys, svid,
303
471
  packet.slice(6 + 8, 4 * packet[6 + 4]).each_slice(4).collect{|v|
304
472
  v.pack("C*").unpack("V")[0]
305
473
  })
@@ -321,22 +489,33 @@ class Receiver
321
489
  GPS::RINEX_Observation::read(fname){|item|
322
490
  $stderr.print '.' if (count += 1) % 1000 == 0
323
491
  t_meas = item[:time]
324
-
492
+
493
+ types ||= Hash[*(item[:meas_types].collect{|sys, values|
494
+ [sys, values.collect.with_index{|type_, i|
495
+ case type_
496
+ when "C1", "C1C"
497
+ [i, :L1_PSEUDORANGE]
498
+ when "L1", "L1C"
499
+ [i, :L1_CARRIER_PHASE]
500
+ when "D1", "D1C"
501
+ [i, :L1_DOPPLER]
502
+ when "S1", "S1C"
503
+ [i, :L1_SIGNAL_STRENGTH_dBHz]
504
+ else
505
+ nil
506
+ end
507
+ }.compact]
508
+ }.flatten(1))]
509
+
325
510
  meas = GPS::Measurement::new
326
- types ||= (item[:meas_types]['G'] || item[:meas_types][' ']).collect.with_index{|type_, i|
327
- case type_
328
- when "C1", "C1C"
329
- [i, GPS::Measurement::L1_PSEUDORANGE]
330
- when "D1", "D1C"
331
- [i, GPS::Measurement::L1_DOPPLER]
332
- else
333
- nil
334
- end
335
- }.compact
336
511
  item[:meas].each{|k, v|
337
512
  sys, prn = k
338
- next unless sys == 'G' # GPS only
339
- types.each{|i, type_|
513
+ case sys
514
+ when 'G', ' '
515
+ when 'J'; prn += 192
516
+ else; next
517
+ end
518
+ (types[sys] || []).each{|i, type_|
340
519
  meas.add(prn, type_, v[i][0]) if v[i]
341
520
  }
342
521
  }
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module GPS_PVT
4
- VERSION = "0.1.4"
4
+ VERSION = "0.2.0"
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.4
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - fenrir(M.Naruoka)
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-12-22 00:00:00.000000000 Z
11
+ date: 2022-01-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -69,7 +69,10 @@ files:
69
69
  - ext/ninja-scan-light/tool/navigation/GPS_Solver_RAIM.h
70
70
  - ext/ninja-scan-light/tool/navigation/MagneticField.h
71
71
  - ext/ninja-scan-light/tool/navigation/NTCM.h
72
+ - ext/ninja-scan-light/tool/navigation/QZSS.h
72
73
  - ext/ninja-scan-light/tool/navigation/RINEX.h
74
+ - ext/ninja-scan-light/tool/navigation/SBAS.h
75
+ - ext/ninja-scan-light/tool/navigation/SBAS_Solver.h
73
76
  - ext/ninja-scan-light/tool/navigation/WGS84.h
74
77
  - ext/ninja-scan-light/tool/navigation/coordinate.h
75
78
  - ext/ninja-scan-light/tool/param/bit_array.h
@@ -86,7 +89,6 @@ files:
86
89
  - ext/ninja-scan-light/tool/swig/makefile
87
90
  - ext/ninja-scan-light/tool/swig/spec/GPS_spec.rb
88
91
  - ext/ninja-scan-light/tool/swig/spec/SylphideMath_spec.rb
89
- - gps_pvt.gemspec
90
92
  - lib/gps_pvt.rb
91
93
  - lib/gps_pvt/receiver.rb
92
94
  - lib/gps_pvt/ubx.rb
@@ -97,7 +99,7 @@ licenses: []
97
99
  metadata:
98
100
  homepage_uri: https://github.com/fenrir-naru/gps_pvt
99
101
  source_code_uri: https://github.com/fenrir-naru/gps_pvt
100
- post_install_message:
102
+ post_install_message:
101
103
  rdoc_options: []
102
104
  require_paths:
103
105
  - lib
@@ -112,8 +114,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
112
114
  - !ruby/object:Gem::Version
113
115
  version: '0'
114
116
  requirements: []
115
- rubygems_version: 3.1.2
116
- signing_key:
117
+ rubygems_version: 3.0.3
118
+ signing_key:
117
119
  specification_version: 4
118
120
  summary: GPS position, velocity, and time (PVT) solver
119
121
  test_files: []