gps_pvt 0.9.2 → 0.9.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
- after_run.call(run(meas_, t_meas), [meas_, ref_time = t_meas]) if t_meas
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.dist(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
- item_size = ranges[:sat].size
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; # GPS
75
- when 40..58; svid += 80 # SBAS
76
- else; next
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
- item_size = ranges[:sat].size
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 # GLONASS
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 40..58
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,22 +241,24 @@ 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
- item_size = ranges[:sat_sig].size
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
181
262
  [:sat_sig, :pseudo_range, :phase_range, :phase_range_rate, :cn].collect{|k|
182
263
  ranges[k] || ([nil] * item_size)
183
264
  }.transpose.each{|(svid, sig), pr, cpr, dr, cn|
@@ -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)
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,29 @@ 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
425
+ end
426
+ end
395
427
  module MSM4_6
396
428
  include MSM
397
429
  def ranges
@@ -468,6 +500,9 @@ class RTCM3
468
500
  1012 => (38..50).to_a,
469
501
  }[msg_num]] * nsat).flatten), offset)
470
502
  attributes << GLONASS_Observation
503
+ when 1013
504
+ add_proc.call(DataFrame.generate_prop(
505
+ ((55..57).to_a * values[4]).flatten), 24 + mt[:bits_total])
471
506
  when 1019
472
507
  attributes << GPS_Ephemeris
473
508
  when 1020
@@ -492,6 +527,15 @@ class RTCM3
492
527
  add_proc.call(msm_sig, offset)
493
528
  }
494
529
  case msg_num % 10
530
+ when 1
531
+ attributes << MSM1_2_3
532
+ msm_proc.call([398], [400])
533
+ when 2
534
+ attributes << MSM1_2_3
535
+ msm_proc.call([398], [401, 402, 420])
536
+ when 3
537
+ attributes << MSM1_2_3
538
+ msm_proc.call([398], [400, 401, 402, 420])
495
539
  when 4
496
540
  attributes << MSM4_6
497
541
  msm_proc.call([397, 398], [400, 401, 402, 420, 403])
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module GPS_PVT
4
- VERSION = "0.9.2"
4
+ VERSION = "0.9.3"
5
5
 
6
6
  def GPS_PVT.version_compare(a, b)
7
7
  Gem::Version::new(a) <=> Gem::Version::new(b)
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.9.2
4
+ version: 0.9.3
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: 2023-02-13 00:00:00.000000000 Z
11
+ date: 2023-03-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rubyserial