gps_pvt 0.10.1 → 0.10.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 +2 -2
- data/Rakefile +27 -16
- data/ext/gps_pvt/SylphideMath/SylphideMath_wrap.cxx +10 -10
- data/ext/ninja-scan-light/tool/navigation/GPS.h +22 -3
- data/ext/ninja-scan-light/tool/swig/Coordinate.i +6 -0
- data/ext/ninja-scan-light/tool/swig/SylphideMath.i +37 -0
- data/ext/ninja-scan-light/tool/swig/spec/SylphideMath_spec.rb +6 -4
- data/gps_pvt.gemspec +1 -0
- data/lib/gps_pvt/asn1/asn1.rb +34 -11
- data/lib/gps_pvt/asn1/asn1.y +112 -63
- data/lib/gps_pvt/ntrip.rb +6 -3
- data/lib/gps_pvt/receiver/almanac.rb +137 -0
- data/lib/gps_pvt/receiver/extension.rb +3 -6
- data/lib/gps_pvt/receiver.rb +1 -0
- data/lib/gps_pvt/supl.rb +162 -55
- data/lib/gps_pvt/upl/MAP-LCS-DataTypes-V17_4_0-Release17.asn +740 -0
- data/lib/gps_pvt/upl/RRLP-V17_0_0-Release17.asn +6 -1
- data/lib/gps_pvt/upl/upl.json.gz +0 -0
- data/lib/gps_pvt/upl/upl.rb +48 -0
- data/lib/gps_pvt/util.rb +8 -2
- data/lib/gps_pvt/version.rb +1 -1
- metadata +18 -2
data/lib/gps_pvt/supl.rb
CHANGED
@@ -16,6 +16,7 @@ class SUPL_Client
|
|
16
16
|
:port => 7275,
|
17
17
|
:debug => 0,
|
18
18
|
:protocol => [:lpp, :rrlp],
|
19
|
+
:req_data => [:ephemeris], # :almanac
|
19
20
|
}.merge(opts)
|
20
21
|
end
|
21
22
|
|
@@ -152,6 +153,16 @@ class SUPL_Client
|
|
152
153
|
cmd[:sessionID] = @session_id
|
153
154
|
proc{|posinit|
|
154
155
|
posinit[:sETCapabilities] = @capability
|
156
|
+
req_data = [
|
157
|
+
@opts[:req_data].find_index(:almanac) && :almanacRequested,
|
158
|
+
:utcModelRequested,
|
159
|
+
:ionosphericModelRequested,
|
160
|
+
:referenceLocationRequested,
|
161
|
+
:referenceTimeRequested,
|
162
|
+
:acquisitionAssistanceRequested,
|
163
|
+
:realTimeIntegrityRequested,
|
164
|
+
@opts[:req_data].find_index(:ephemeris) && :navigationModelRequested,
|
165
|
+
].compact
|
155
166
|
posinit[:requestedAssistData] = Hash[*([
|
156
167
|
:almanacRequested,
|
157
168
|
:utcModelRequested,
|
@@ -163,15 +174,7 @@ class SUPL_Client
|
|
163
174
|
:realTimeIntegrityRequested,
|
164
175
|
:navigationModelRequested,
|
165
176
|
].collect{|k|
|
166
|
-
[k,
|
167
|
-
:utcModelRequested,
|
168
|
-
:ionosphericModelRequested,
|
169
|
-
:referenceLocationRequested,
|
170
|
-
:referenceTimeRequested,
|
171
|
-
:acquisitionAssistanceRequested,
|
172
|
-
:realTimeIntegrityRequested,
|
173
|
-
:navigationModelRequested,
|
174
|
-
].include?(k)]
|
177
|
+
[k, req_data.include?(k)]
|
175
178
|
}.flatten(1))]
|
176
179
|
posinit[:requestedAssistData][:"ver2-RequestedAssistData-extension"] = {
|
177
180
|
:ganssRequestedCommonAssistanceDataList => {
|
@@ -185,18 +188,21 @@ class SUPL_Client
|
|
185
188
|
:ganssRequestedGenericAssistanceDataList => [
|
186
189
|
# SBAS
|
187
190
|
{:ganssId => 1, :ganssSBASid => [0, 1, 0], # MSAS
|
188
|
-
:ganssRealTimeIntegrity => true,
|
189
|
-
:ganssNavigationModelData => {:ganssWeek => 0, :ganssToe => 0, :"t-toeLimit" => 0},
|
191
|
+
:ganssRealTimeIntegrity => true,
|
190
192
|
:ganssReferenceMeasurementInfo => false, :ganssUTCModel => true, :ganssAuxiliaryInformation => false},
|
191
193
|
# QZSS
|
192
|
-
{:ganssId => 3, :ganssRealTimeIntegrity => true,
|
193
|
-
:ganssNavigationModelData => {:ganssWeek => 0, :ganssToe => 0, :"t-toeLimit" => 0},
|
194
|
+
{:ganssId => 3, :ganssRealTimeIntegrity => true,
|
194
195
|
:ganssReferenceMeasurementInfo => false, :ganssUTCModel => true, :ganssAuxiliaryInformation => false},
|
195
196
|
# GLONASS
|
196
|
-
{:ganssId => 4, :ganssRealTimeIntegrity => true,
|
197
|
-
:ganssNavigationModelData => {:ganssWeek => 0, :ganssToe => 0, :"t-toeLimit" => 0},
|
197
|
+
{:ganssId => 4, :ganssRealTimeIntegrity => true,
|
198
198
|
:ganssReferenceMeasurementInfo => false, :ganssUTCModel => true, :ganssAuxiliaryInformation => false},
|
199
|
-
]
|
199
|
+
].collect{|items|
|
200
|
+
items[:ganssAlmanac] = @opts[:req_data].include?(:almanac)
|
201
|
+
items[:ganssNavigationModelData] = {
|
202
|
+
:ganssWeek => 0, :ganssToe => 0, :"t-toeLimit" => 0
|
203
|
+
} if @opts[:req_data].include?(:ephemeris)
|
204
|
+
items
|
205
|
+
},
|
200
206
|
}
|
201
207
|
posinit[:requestedAssistData][:navigationModelData] = {
|
202
208
|
:gpsWeek => 0,
|
@@ -302,7 +308,25 @@ class SUPL_Client
|
|
302
308
|
:ephemL2Pflag
|
303
309
|
:ephemAODA
|
304
310
|
=end
|
305
|
-
|
311
|
+
|
312
|
+
ALM_KEY_TBL_RRLP = Hash[*({
|
313
|
+
:e => [:almanacE, -21],
|
314
|
+
:i0 => [:almanacKsii, -19, true],
|
315
|
+
:dot_Omega0 => [:almanacOmegaDot, -38, true],
|
316
|
+
:SV_health => :almanacSVhealth,
|
317
|
+
:sqrt_A => [:almanacAPowerHalf, -11],
|
318
|
+
:Omega0 => [:almanacOmega0, -23, true],
|
319
|
+
:omega => [:almanacW, -23, true],
|
320
|
+
:M0 => [:almanacM0, -23, true],
|
321
|
+
:a_f0 => [:almanacAF0, -20],
|
322
|
+
:a_f1 => [:almanacAF1, -38],
|
323
|
+
}.collect{|dst_k, (src_k, sf_pow2, sc2rad)|
|
324
|
+
sf_pow2 ||= 0
|
325
|
+
sf = sf_pow2 < 0 ? Rational(1, 1 << -sf_pow2) : (1 << sf_pow2)
|
326
|
+
sf = sf.to_f * GPS::GPS_SC2RAD if sc2rad
|
327
|
+
["#{dst_k}=".to_sym, [src_k, sf]]
|
328
|
+
}.flatten(1))]
|
329
|
+
|
306
330
|
def attach_rrlp(msg)
|
307
331
|
t_gps = proc{
|
308
332
|
week_rem, sec008 = [:gpsWeek, :gpsTOW23b].collect{|k| msg[:referenceTime][:gpsTime][k]}
|
@@ -337,10 +361,11 @@ class SUPL_Client
|
|
337
361
|
params
|
338
362
|
}
|
339
363
|
msg.define_singleton_method(:ephemeris){
|
340
|
-
self[:navigationModel]
|
364
|
+
next [] unless (model = self[:navigationModel])
|
365
|
+
model[:navModelList].collect{|sat|
|
341
366
|
eph = GPS::Ephemeris::new
|
342
|
-
eph.svid =
|
343
|
-
eph_src =
|
367
|
+
eph.svid = sat[:satelliteID] + 1
|
368
|
+
eph_src = sat[:satStatus][:newSatelliteAndModelUC]
|
344
369
|
EPH_KEY_TBL_RRLP.each{|dst_k, (src_k, sf)|
|
345
370
|
v = sf * eph_src[src_k]
|
346
371
|
eph.send(dst_k, v.kind_of?(Rational) ? v.to_f : v)
|
@@ -357,6 +382,30 @@ class SUPL_Client
|
|
357
382
|
eph
|
358
383
|
}
|
359
384
|
}
|
385
|
+
msg.define_singleton_method(:almanac){
|
386
|
+
next [] unless (model = self[:almanac])
|
387
|
+
week = self[:almanac][:alamanacWNa]
|
388
|
+
week += (t_gps.week >> 8) << 8
|
389
|
+
model[:almanacList].collect{|sat|
|
390
|
+
eph = GPS::Ephemeris::new
|
391
|
+
eph.svid = sat[:satelliteID] + 1
|
392
|
+
ALM_KEY_TBL_RRLP.each{|dst_k, (src_k, sf)|
|
393
|
+
v = sf * sat[src_k]
|
394
|
+
eph.send(dst_k, v.kind_of?(Rational) ? v.to_f : v)
|
395
|
+
}
|
396
|
+
eph.i0 = GPS::GPS_SC2RAD * 0.3 + eph.i0
|
397
|
+
eph.WN = week
|
398
|
+
eph.t_oc = eph.t_oe = sat[:alamanacToa] << 12
|
399
|
+
[:iodc, :t_GD, :a_f2, :iode, :c_rs, :delta_n,
|
400
|
+
:c_uc, :c_us, :c_ic, :c_is, :c_rc, :dot_i0, :iode_subframe3].each{|k|
|
401
|
+
eph.send("#{k}=", 0)
|
402
|
+
}
|
403
|
+
eph.URA_index = -1
|
404
|
+
#eph.fit_interval
|
405
|
+
eph
|
406
|
+
}
|
407
|
+
}
|
408
|
+
:alamanacToa # typo in TS
|
360
409
|
msg
|
361
410
|
end
|
362
411
|
|
@@ -412,6 +461,25 @@ class SUPL_Client
|
|
412
461
|
:N_T=, :p=, :delta_tau_n=, :P4=,
|
413
462
|
:tau_GPS=, :tau_c=, :day_of_year=, :year=, :n=, :freq_ch=
|
414
463
|
=end
|
464
|
+
|
465
|
+
ALM_KEY_TBL_LPP = Hash[*({
|
466
|
+
:e => [:E, -21],
|
467
|
+
:i0 => [:DeltaI, -19, true],
|
468
|
+
:dot_Omega0 => [:OMEGADOT, -38, true],
|
469
|
+
:SV_health => :SVHealth,
|
470
|
+
:sqrt_A => [:SqrtA, -11],
|
471
|
+
:Omega0 => [:OMEGAo, -23, true],
|
472
|
+
:omega => [:Omega, -23, true],
|
473
|
+
:M0 => [:Mo, -23, true],
|
474
|
+
:a_f0 => [:af0, -20],
|
475
|
+
:a_f1 => [:af1, -38],
|
476
|
+
}.collect{|dst_k, (src_k, sf_pow2, sc2rad)|
|
477
|
+
sf_pow2 ||= 0
|
478
|
+
sf = sf_pow2 < 0 ? Rational(1, 1 << -sf_pow2) : (1 << sf_pow2)
|
479
|
+
sf = sf.to_f * GPS::GPS_SC2RAD if sc2rad
|
480
|
+
["#{dst_k}=".to_sym,
|
481
|
+
[(src_k.kind_of?(Symbol) ? "navAlm#{src_k}" : src_k).to_sym, sf]]
|
482
|
+
}.flatten(1))]
|
415
483
|
|
416
484
|
def attach_lpp(msg)
|
417
485
|
t_gps = proc{|data|
|
@@ -460,9 +528,9 @@ class SUPL_Client
|
|
460
528
|
}.call
|
461
529
|
leap_seconds = iono_utc.delta_t_LS rescue t_gps.leap_seconds
|
462
530
|
msg.define_singleton_method(:iono_utc){iono_utc}
|
463
|
-
extract_gps_ephemeris = proc{|
|
531
|
+
extract_gps_ephemeris = proc{|model, sys|
|
464
532
|
offset = {:gps => 1, :qzss => 193}[sys]
|
465
|
-
|
533
|
+
model[:"gnss-SatelliteList"].collect{|v|
|
466
534
|
eph = GPS::Ephemeris::new
|
467
535
|
eph.svid = v[:svID][:"satellite-id"] + offset
|
468
536
|
eph_src = v[:"gnss-ClockModel"][:"nav-ClockModel"].merge(v[:"gnss-OrbitModel"][:"nav-KeplerianSet"])
|
@@ -489,42 +557,81 @@ class SUPL_Client
|
|
489
557
|
[:"provideAssistanceData-r9"][:"a-gnss-ProvideAssistanceData"] \
|
490
558
|
[:"gnss-GenericAssistData"]
|
491
559
|
res = [:gps, :qzss].collect{|k|
|
492
|
-
|
493
|
-
|
494
|
-
|
560
|
+
model = assist_data.find{|v| v[:"gnss-ID"][:"gnss-id"] == k}[:"gnss-NavigationModel"] rescue nil
|
561
|
+
next [] unless model
|
562
|
+
extract_gps_ephemeris.call(model, k)
|
495
563
|
}.flatten(1)
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
|
500
|
-
|
501
|
-
|
502
|
-
|
503
|
-
eph = GPS::Ephemeris_GLONASS::new
|
504
|
-
eph.svid = sat[:svID][:"satellite-id"] + 1
|
505
|
-
eph_src = sat[:"gnss-ClockModel"][:"glonass-ClockModel"].merge(
|
506
|
-
sat[:"gnss-OrbitModel"][:"glonass-ECEF"])
|
507
|
-
(EPH_KEY_TBL_LPP_GLO.collect{|dst_k, (src_k, sf)|
|
508
|
-
v = eph_src[src_k]
|
509
|
-
[dst_k, sf.send(sf.kind_of?(Proc) ? :call : :*, case v
|
510
|
-
when Array; Integer(v.join, 2)
|
511
|
-
when true; 1
|
512
|
-
when false; 0
|
513
|
-
else; v
|
514
|
-
end)]
|
515
|
-
} + utc_params_glo).each{|dst_k, v|
|
516
|
-
eph.send(dst_k, v.kind_of?(Rational) ? v.to_f : v)
|
564
|
+
proc{|assist_data_glo|
|
565
|
+
next unless assist_data_glo
|
566
|
+
next unless nav_model = assist_data_glo[:"gnss-NavigationModel"]
|
567
|
+
utc_params_glo = {
|
568
|
+
:tau_c= => [:tauC, Rational(1, 1 << 31)],
|
569
|
+
}.collect{|dst_k, (src_k, sf)|
|
570
|
+
[dst_k, sf * assist_data_glo[:"gnss-UTC-Model"][:utcModel3][src_k]]
|
517
571
|
}
|
518
|
-
|
519
|
-
|
520
|
-
|
521
|
-
|
522
|
-
|
523
|
-
|
524
|
-
|
525
|
-
|
572
|
+
res += nav_model[:"gnss-SatelliteList"].collect{|sat|
|
573
|
+
eph = GPS::Ephemeris_GLONASS::new
|
574
|
+
eph.svid = sat[:svID][:"satellite-id"] + 1
|
575
|
+
eph_src = sat[:"gnss-ClockModel"][:"glonass-ClockModel"].merge(
|
576
|
+
sat[:"gnss-OrbitModel"][:"glonass-ECEF"])
|
577
|
+
(EPH_KEY_TBL_LPP_GLO.collect{|dst_k, (src_k, sf)|
|
578
|
+
v = eph_src[src_k]
|
579
|
+
[dst_k, sf.send(sf.kind_of?(Proc) ? :call : :*, case v
|
580
|
+
when Array; Integer(v.join, 2)
|
581
|
+
when true; 1
|
582
|
+
when false; 0
|
583
|
+
else; v
|
584
|
+
end)]
|
585
|
+
} + utc_params_glo).each{|dst_k, v|
|
586
|
+
eph.send(dst_k, v.kind_of?(Rational) ? v.to_f : v)
|
587
|
+
}
|
588
|
+
eph.B_n = sat[:svHealth][0]
|
589
|
+
eph.F_T_index = Integer(sat[:svHealth][1..4].join, 2)
|
590
|
+
eph.t_b = Integer(sat[:iod][4..-1].join, 2) * 15 * 60
|
591
|
+
eph.set_date((t_gps + 3 * 60 * 60).c_tm(leap_seconds)) # UTC -> Moscow time
|
592
|
+
eph.N_T = eph.NA
|
593
|
+
eph.rehash(leap_seconds)
|
594
|
+
eph
|
595
|
+
}
|
596
|
+
}.call(assist_data.find{|v| v[:"gnss-ID"][:"gnss-id"] == :glonass})
|
526
597
|
res
|
527
598
|
}
|
599
|
+
extract_gps_almanac = proc{|alm, sys|
|
600
|
+
next [] unless alm
|
601
|
+
offset = {:gps => 1, :qzss => 193}[sys]
|
602
|
+
week = alm[:weekNumber] # optional but required for non-GLONASS
|
603
|
+
week += (t_gps.week >> 8) << 8
|
604
|
+
t_oa = alm[:toa] << 12 # optional but required for non-GLONASS
|
605
|
+
alm[:"gnss-AlmanacList"].collect{|v|
|
606
|
+
next unless v = v[:"keplerianNAV-Almanac"]
|
607
|
+
eph = GPS::Ephemeris::new
|
608
|
+
eph.svid = v[:svID][:"satellite-id"] + offset
|
609
|
+
ALM_KEY_TBL_LPP.each{|dst_k, (src_k, sf)|
|
610
|
+
v2 = sf * v[src_k]
|
611
|
+
eph.send(dst_k, v2.kind_of?(Rational) ? v2.to_f : v2)
|
612
|
+
}
|
613
|
+
eph.i0 = GPS::GPS_SC2RAD * 0.3 + eph.i0
|
614
|
+
eph.WN = week
|
615
|
+
eph.t_oc = eph.t_oe = t_oa
|
616
|
+
[:iodc, :t_GD, :a_f2, :iode, :c_rs, :delta_n,
|
617
|
+
:c_uc, :c_us, :c_ic, :c_is, :c_rc, :dot_i0, :iode_subframe3].each{|k|
|
618
|
+
eph.send("#{k}=", 0)
|
619
|
+
}
|
620
|
+
eph.URA_index = -1
|
621
|
+
#eph.fit_interval
|
622
|
+
eph
|
623
|
+
}.compact
|
624
|
+
}
|
625
|
+
msg.define_singleton_method(:almanac){
|
626
|
+
assist_data = self[:c1][:provideAssistanceData][:criticalExtensions][:c1] \
|
627
|
+
[:"provideAssistanceData-r9"][:"a-gnss-ProvideAssistanceData"] \
|
628
|
+
[:"gnss-GenericAssistData"]
|
629
|
+
[:gps, :qzss].collect{|k|
|
630
|
+
model = assist_data.find{|v| v[:"gnss-ID"][:"gnss-id"] == k}[:"gnss-Almanac"] rescue nil
|
631
|
+
next [] unless model
|
632
|
+
extract_gps_almanac.call(model, k)
|
633
|
+
}.flatten(1)
|
634
|
+
}
|
528
635
|
msg
|
529
636
|
end
|
530
637
|
end
|
@@ -537,7 +644,7 @@ OpenURI.class_eval{
|
|
537
644
|
options[:port] = target.port
|
538
645
|
URI.decode_www_form(target.query || "").each{|k, v|
|
539
646
|
case k = k.to_sym
|
540
|
-
when :protocol
|
647
|
+
when :protocol, :req_data
|
541
648
|
(options[k] ||= []) << v.to_sym
|
542
649
|
end
|
543
650
|
}
|