gps_pvt 0.6.4 → 0.7.2
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 -1
- data/Rakefile +1 -0
- data/exe/gps_pvt +4 -2
- data/ext/gps_pvt/GPS/GPS_wrap.cxx +993 -296
- data/ext/gps_pvt/SylphideMath/SylphideMath_wrap.cxx +2 -3
- data/ext/ninja-scan-light/tool/navigation/ANTEX.h +1 -1
- data/ext/ninja-scan-light/tool/navigation/GLONASS.h +4 -11
- data/ext/ninja-scan-light/tool/navigation/GLONASS_Solver.h +25 -13
- data/ext/ninja-scan-light/tool/navigation/GPS.h +21 -18
- data/ext/ninja-scan-light/tool/navigation/GPS_Solver.h +42 -25
- data/ext/ninja-scan-light/tool/navigation/GPS_Solver_Base.h +44 -23
- data/ext/ninja-scan-light/tool/navigation/GPS_Solver_RAIM.h +29 -1
- data/ext/ninja-scan-light/tool/navigation/MagneticField.h +4 -3
- data/ext/ninja-scan-light/tool/navigation/NTCM.h +1 -1
- data/ext/ninja-scan-light/tool/navigation/RINEX.h +31 -20
- data/ext/ninja-scan-light/tool/navigation/RINEX_Clock.h +458 -0
- data/ext/ninja-scan-light/tool/navigation/SBAS.h +34 -6
- data/ext/ninja-scan-light/tool/navigation/SBAS_Solver.h +26 -14
- data/ext/ninja-scan-light/tool/navigation/SP3.h +51 -43
- data/ext/ninja-scan-light/tool/param/bit_array.h +2 -2
- data/ext/ninja-scan-light/tool/param/quaternion.h +2 -2
- data/ext/ninja-scan-light/tool/param/vector3.h +2 -2
- data/ext/ninja-scan-light/tool/swig/GPS.i +124 -52
- data/ext/ninja-scan-light/tool/swig/SylphideMath.i +1 -2
- data/ext/ninja-scan-light/tool/swig/spec/GPS_spec.rb +134 -13
- data/lib/gps_pvt/receiver.rb +32 -7
- data/lib/gps_pvt/version.rb +1 -1
- metadata +3 -2
@@ -658,6 +658,73 @@ __ANTEX_TEXT__
|
|
658
658
|
# https://files.igs.org/pub/station/general/igs14.atx
|
659
659
|
f.path
|
660
660
|
},
|
661
|
+
:rinex_clk => Tempfile::open{|f|
|
662
|
+
f.write(<<-__RINEX_CLK_TEXT__)
|
663
|
+
3.00 C RINEX VERSION / TYPE
|
664
|
+
CCLOCK IGSACC @ NOAA NGS PGM / RUN BY / DATE
|
665
|
+
GPS week: 1849 Day: 2 MJD: 57189 COMMENT
|
666
|
+
THE COMBINED CLOCKS ARE A WEIGHTED AVERAGE OF: COMMENT
|
667
|
+
cod emr esa gfz grg jpl COMMENT
|
668
|
+
THE FOLLOWING REFERENCE CLOCKS WERE USED BY ACs: COMMENT
|
669
|
+
WSRT AMC2 BRUX HRAO COMMENT
|
670
|
+
THE COMBINED CLOCKS ARE ALIGNED TO GPS TIME COMMENT
|
671
|
+
USING THE SATELLITE BROADCAST EPHEMERIDES COMMENT
|
672
|
+
All clocks have been re-aligned to the IGS time scale: IGST COMMENT
|
673
|
+
16 LEAP SECONDS
|
674
|
+
1 AS # / TYPES OF DATA
|
675
|
+
IGS IGSACC @ NOAA NGS ANALYSIS CENTER
|
676
|
+
6 # OF SOLN SATS
|
677
|
+
G12 G18 G24 G25 G29 G31 PRN LIST
|
678
|
+
G igs08_1848.atx SYS / PCVS APPLIED
|
679
|
+
END OF HEADER
|
680
|
+
AS G12 2015 06 15 23 45 0.000000 2 3.017937472687e-04 1.069824072610e-11
|
681
|
+
AS G18 2015 06 15 23 45 0.000000 2 4.096815344517e-04 9.225410060960e-12
|
682
|
+
AS G24 2015 06 15 23 45 0.000000 2 -4.998574751545e-05 2.372704308220e-11
|
683
|
+
AS G25 2015 06 15 23 45 0.000000 2 -2.290169594092e-06 1.683218228880e-11
|
684
|
+
AS G29 2015 06 15 23 45 0.000000 2 6.168866864097e-04 1.206217360840e-11
|
685
|
+
AS G31 2015 06 15 23 45 0.000000 2 3.128244102077e-04 2.173867579920e-11
|
686
|
+
AS G12 2015 06 15 23 50 0.000000 2 3.017948525918e-04 1.300769315700e-11
|
687
|
+
AS G18 2015 06 15 23 50 0.000000 2 4.096823340968e-04 8.242414325510e-12
|
688
|
+
AS G24 2015 06 15 23 50 0.000000 2 -4.998578937856e-05 3.095238106380e-11
|
689
|
+
AS G25 2015 06 15 23 50 0.000000 2 -2.291410963946e-06 2.242880773880e-11
|
690
|
+
AS G29 2015 06 15 23 50 0.000000 2 6.168873857128e-04 1.695910016600e-11
|
691
|
+
AS G31 2015 06 15 23 50 0.000000 2 3.128241216228e-04 1.904362802980e-11
|
692
|
+
AS G12 2015 06 15 23 55 0.000000 2 3.017958412577e-04 1.171495359430e-11
|
693
|
+
AS G18 2015 06 15 23 55 0.000000 2 4.096833491457e-04 1.008770038860e-11
|
694
|
+
AS G24 2015 06 15 23 55 0.000000 2 -4.998596967628e-05 2.600074192880e-11
|
695
|
+
AS G25 2015 06 15 23 55 0.000000 2 -2.292650290468e-06 2.671557682290e-11
|
696
|
+
AS G29 2015 06 15 23 55 0.000000 2 6.168880208367e-04 1.729095211710e-11
|
697
|
+
AS G31 2015 06 15 23 55 0.000000 2 3.128236493567e-04 1.807462018720e-11
|
698
|
+
AS G12 2015 06 16 00 00 0.000000 2 3.017967728708e-04 1.000801049580e-11
|
699
|
+
AS G18 2015 06 16 00 00 0.000000 2 4.096840539308e-04 1.041670195750e-11
|
700
|
+
AS G24 2015 06 16 00 00 0.000000 2 -4.998614775959e-05 1.699628132880e-11
|
701
|
+
AS G25 2015 06 16 00 00 0.000000 2 -2.293760646361e-06 1.805118466830e-11
|
702
|
+
AS G29 2015 06 16 00 00 0.000000 2 6.168886213338e-04 2.220055594770e-11
|
703
|
+
AS G31 2015 06 16 00 00 0.000000 2 3.128233311248e-04 1.215284180360e-11
|
704
|
+
AS G12 2015 06 16 00 05 0.000000 2 3.017980078016e-04 1.152529430320e-11
|
705
|
+
AS G18 2015 06 16 00 05 0.000000 2 4.096851745816e-04 1.517949585220e-11
|
706
|
+
AS G24 2015 06 16 00 05 0.000000 2 -4.998569129850e-05 1.987308774570e-11
|
707
|
+
AS G25 2015 06 16 00 05 0.000000 2 -2.295014987154e-06 1.568891027900e-11
|
708
|
+
AS G29 2015 06 16 00 05 0.000000 2 6.168894672506e-04 1.906237292480e-11
|
709
|
+
AS G31 2015 06 16 00 05 0.000000 2 3.128231387506e-04 1.007829428500e-11
|
710
|
+
AS G12 2015 06 16 00 10 0.000000 2 3.017987334831e-04 8.726251168980e-12
|
711
|
+
AS G18 2015 06 16 00 10 0.000000 2 4.096859333261e-04 1.403166740100e-11
|
712
|
+
AS G24 2015 06 16 00 10 0.000000 2 -4.998597422529e-05 1.727695888430e-11
|
713
|
+
AS G25 2015 06 16 00 10 0.000000 2 -2.296262879345e-06 1.460867818340e-11
|
714
|
+
AS G29 2015 06 16 00 10 0.000000 2 6.168900483001e-04 1.556536485070e-11
|
715
|
+
AS G31 2015 06 16 00 10 0.000000 2 3.128226535741e-04 1.258498073020e-11
|
716
|
+
AS G12 2015 06 16 00 15 0.000000 2 3.017999301583e-04 1.006627990480e-11
|
717
|
+
AS G18 2015 06 16 00 15 0.000000 2 4.096864636193e-04 1.460541676660e-11
|
718
|
+
AS G24 2015 06 16 00 15 0.000000 2 -4.998605241609e-05 1.970841363000e-11
|
719
|
+
AS G25 2015 06 16 00 15 0.000000 2 -2.297477664413e-06 1.598459869060e-11
|
720
|
+
AS G29 2015 06 16 00 15 0.000000 2 6.168906691983e-04 1.729396319140e-11
|
721
|
+
AS G31 2015 06 16 00 15 0.000000 2 3.128222195893e-04 1.358710059900e-11
|
722
|
+
__RINEX_CLK_TEXT__
|
723
|
+
# modified version. original data are
|
724
|
+
# https://cddis.nasa.gov/archive/gnss/products/1849/igs1849[12].clk.Z
|
725
|
+
# mirrored: ftp://garner.ucsd.edu/pub/products/1849/igs1849[12].clk.Z
|
726
|
+
f.path
|
727
|
+
},
|
661
728
|
}}
|
662
729
|
let(:solver){
|
663
730
|
res = GPS::Solver::new
|
@@ -733,20 +800,20 @@ __ANTEX_TEXT__
|
|
733
800
|
expect(pvt.position_solved?).to be(true)
|
734
801
|
expect(pvt.receiver_time.to_a).to eq([1849, 172413])
|
735
802
|
expect(pvt.llh.to_a).to eq([:lat, :lng, :alt].collect{|k| pvt.llh.send(k)})
|
736
|
-
expect(pvt.llh.lat / Math::PI * 180).to be_within(1E-
|
737
|
-
expect(pvt.llh.lng / Math::PI * 180).to be_within(1E-
|
738
|
-
expect(pvt.llh.alt) .to be_within(1E-
|
739
|
-
expect(pvt.receiver_error).to be_within(1E-
|
740
|
-
expect(pvt.gdop).to be_within(1E-
|
741
|
-
expect(pvt.pdop).to be_within(1E-
|
742
|
-
expect(pvt.hdop).to be_within(1E-
|
743
|
-
expect(pvt.vdop).to be_within(1E-
|
744
|
-
expect(pvt.tdop).to be_within(1E-
|
803
|
+
expect(pvt.llh.lat / Math::PI * 180).to be_within(1E-3).of(35.7) # latitude
|
804
|
+
expect(pvt.llh.lng / Math::PI * 180).to be_within(1E-3).of(139.542) # longitude
|
805
|
+
expect(pvt.llh.alt) .to be_within(1E-1).of(104.3) # altitude
|
806
|
+
expect(pvt.receiver_error).to be_within(1E-1).of(1259087.8)
|
807
|
+
expect(pvt.gdop).to be_within(1E-2).of(2.42)
|
808
|
+
expect(pvt.pdop).to be_within(1E-2).of(2.17)
|
809
|
+
expect(pvt.hdop).to be_within(1E-2).of(1.11)
|
810
|
+
expect(pvt.vdop).to be_within(1E-2).of(1.87)
|
811
|
+
expect(pvt.tdop).to be_within(1E-2).of(1.08)
|
745
812
|
expect(pvt.velocity.to_a).to eq([:e, :n, :u].collect{|k| pvt.velocity.send(k)})
|
746
|
-
expect(pvt.velocity.north).to be_within(1E-
|
747
|
-
expect(pvt.velocity.east) .to be_within(1E-
|
748
|
-
expect(pvt.velocity.down) .to be_within(1E-
|
749
|
-
expect(pvt.receiver_error_rate).to be_within(1E-
|
813
|
+
expect(pvt.velocity.north).to be_within(1E-2).of(-0.86) # north
|
814
|
+
expect(pvt.velocity.east) .to be_within(1E-2).of(-1.10) # east
|
815
|
+
expect(pvt.velocity.down) .to be_within(1E-2).of(-0.22) # down
|
816
|
+
expect(pvt.receiver_error_rate).to be_within(1E-2).of(-1061.86)
|
750
817
|
expect(pvt.G.rows).to eq(6)
|
751
818
|
expect(pvt.W.rows).to eq(6)
|
752
819
|
expect(pvt.delta_r.rows).to eq(6)
|
@@ -778,6 +845,10 @@ __ANTEX_TEXT__
|
|
778
845
|
|
779
846
|
it 'can be modified through hooks' do
|
780
847
|
sn = solver.gps_space_node
|
848
|
+
expect(solver.options).to be_a_kind_of(Hash)
|
849
|
+
expect(solver.options.keys).to include(:skip_exclusion)
|
850
|
+
expect{solver.options = {:skip_exclusion => true}}.not_to raise_error
|
851
|
+
expect(solver.options[:skip_exclusion]).to eq(true)
|
781
852
|
expect(solver.correction[:gps_ionospheric]).to include(:klobuchar)
|
782
853
|
expect(solver.correction[:gps_tropospheric]).to include(:hopfield)
|
783
854
|
expect{solver.correction = nil}.to raise_error(RuntimeError)
|
@@ -937,5 +1008,55 @@ __ANTEX_TEXT__
|
|
937
1008
|
puts ([:lat, :lng].collect{|f| pvt.llh.send(f) / Math::PI * 180} + [pvt.llh.alt]).inspect
|
938
1009
|
}
|
939
1010
|
end
|
1011
|
+
it 'calculates satellite clock error based on RINEX clock' do
|
1012
|
+
clk, sn = [GPS::RINEX_Clock::new, solver.gps_space_node]
|
1013
|
+
expect(clk.read(input[:rinex_clk])).to eq(6 * 7)
|
1014
|
+
proc{|sats|
|
1015
|
+
expect(sats.kind_of?(Array)).to eq(true)
|
1016
|
+
expect(sats[clk.class::SYS_GPS]).to eq(6)
|
1017
|
+
}.call(clk.satellites)
|
1018
|
+
sn.read(input[:rinex_nav])
|
1019
|
+
t0 = GPS::Time::new(1849, 172800)
|
1020
|
+
sn.update_all_ephemeris(t0)
|
1021
|
+
(-5..5).step(1){|dt_min|
|
1022
|
+
t = t0 + (dt_min * 60)
|
1023
|
+
[12, 18, 24, 25, 29, 31].each{|sat_id|
|
1024
|
+
eph = sn.ephemeris(sat_id).constellation(t)
|
1025
|
+
expect(clk.clock_error(sat_id, t)).to be_within(1E-7).of(eph[2]) # 100 ns
|
1026
|
+
expect(clk.clock_error_dot(sat_id, t)).to be_within(1E-10).of(eph[3]) # 100 ps
|
1027
|
+
}
|
1028
|
+
}
|
1029
|
+
end
|
1030
|
+
it 'calculates position without any error with RINEX NAV and CLK' do
|
1031
|
+
sn = solver.gps_space_node
|
1032
|
+
sn.read(input[:rinex_nav])
|
1033
|
+
clk = GPS::RINEX_Clock::new
|
1034
|
+
clk.read(input[:rinex_clk])
|
1035
|
+
expect(clk.push(solver, clk.class::SYS_GPS)).to eq(true)
|
1036
|
+
GPS::RINEX_Observation::read(input[:rinex_obs]){|item|
|
1037
|
+
t_meas = item[:time]
|
1038
|
+
sn.update_all_ephemeris(t_meas)
|
1039
|
+
meas = GPS::Measurement::new
|
1040
|
+
types = (item[:meas_types]['G'] || item[:meas_types][' ']).collect.with_index{|type_, i|
|
1041
|
+
type_ = {
|
1042
|
+
"C1" => :L1_PSEUDORANGE,
|
1043
|
+
"D1" => :L1_RANGE_RATE,
|
1044
|
+
}[type_]
|
1045
|
+
type_ && [i, GPS::Measurement::const_get(type_)]
|
1046
|
+
}.compact
|
1047
|
+
item[:meas].each{|k, v|
|
1048
|
+
sys, prn = k
|
1049
|
+
next unless sys == 'G' # GPS only
|
1050
|
+
types.each{|i, type_|
|
1051
|
+
meas.add(prn, type_, v[i][0]) if v[i]
|
1052
|
+
}
|
1053
|
+
}
|
1054
|
+
pvt = solver.solve(meas, t_meas)
|
1055
|
+
expect(pvt.position_solved?).to eq(true)
|
1056
|
+
[-3952590.4754, 3360273.8926, 3697987.2632].zip(pvt.xyz.to_a).each{|a, b|
|
1057
|
+
expect(a).to be_within(1E+2).of(b) # 10 m
|
1058
|
+
}
|
1059
|
+
}
|
1060
|
+
end
|
940
1061
|
end
|
941
1062
|
end
|
data/lib/gps_pvt/receiver.rb
CHANGED
@@ -19,6 +19,7 @@ class Receiver
|
|
19
19
|
opt = {
|
20
20
|
:system => [[:GPS, 1..32]],
|
21
21
|
:satellites => (1..32).to_a,
|
22
|
+
:FDE => true,
|
22
23
|
}.merge(opt)
|
23
24
|
[[
|
24
25
|
[:week, :itow_rcv, :year, :month, :mday, :hour, :min, :sec_rcv_UTC],
|
@@ -106,7 +107,7 @@ class Receiver
|
|
106
107
|
el_deg = [4, 6].collect{|i| pvt.elevation[fd[i]] / Math::PI * 180}
|
107
108
|
fd[0..4] + [el_deg[0]] + fd[5..6] + [el_deg[1]]
|
108
109
|
}
|
109
|
-
]] + [[
|
110
|
+
]] + (opt[:FDE] ? [[
|
110
111
|
[:wssr_FDE_min, :wssr_FDE_min_PRN, :wssr_FDE_2nd, :wssr_FDE_2nd_PRN],
|
111
112
|
proc{|pvt|
|
112
113
|
[:fde_min, :fde_2nd].collect{|f|
|
@@ -115,7 +116,7 @@ class Receiver
|
|
115
116
|
[info[0], info[-3]]
|
116
117
|
}.flatten
|
117
118
|
}
|
118
|
-
]]
|
119
|
+
]] : [])
|
119
120
|
end
|
120
121
|
|
121
122
|
def self.meas_items(opt = {})
|
@@ -149,9 +150,8 @@ class Receiver
|
|
149
150
|
|
150
151
|
def initialize(options = {})
|
151
152
|
@solver = GPS::Solver::new
|
152
|
-
@solver.
|
153
|
-
|
154
|
-
rel_prop
|
153
|
+
@solver.options = {
|
154
|
+
:skip_exclusion => true, # default is to skip fault exclusion calculation
|
155
155
|
}
|
156
156
|
@debug = {}
|
157
157
|
solver_opts = [:gps_options, :sbas_options, :glonass_options].collect{|target|
|
@@ -165,8 +165,10 @@ class Receiver
|
|
165
165
|
output_options = {
|
166
166
|
:system => [[:GPS, 1..32], [:QZSS, 193..202]],
|
167
167
|
:satellites => (1..32).to_a + (193..202).to_a, # [idx, ...] or [[idx, label], ...] is acceptable
|
168
|
+
:FDE => false,
|
168
169
|
}
|
169
170
|
options = options.reject{|k, v|
|
171
|
+
def v.to_b; !(self =~ /^(?:false|0|f|off)$/i); end
|
170
172
|
case k
|
171
173
|
when :debug
|
172
174
|
v = v.split(/,/)
|
@@ -174,7 +176,7 @@ class Receiver
|
|
174
176
|
next true
|
175
177
|
when :weight
|
176
178
|
case v.to_sym
|
177
|
-
when :elevation # (same as underneath C++ library)
|
179
|
+
when :elevation # (same as underneath C++ library except for ignoring broadcasted/calculated URA)
|
178
180
|
@solver.hooks[:relative_property] = proc{|prn, rel_prop, meas, rcv_e, t_arv, usr_pos, usr_vel|
|
179
181
|
if rel_prop[0] > 0 then
|
180
182
|
elv = Coordinate::ENU::relative_rel(
|
@@ -184,7 +186,11 @@ class Receiver
|
|
184
186
|
rel_prop
|
185
187
|
}
|
186
188
|
next true
|
187
|
-
when :identical # same
|
189
|
+
when :identical # treat each satellite range having same accuracy
|
190
|
+
@solver.hooks[:relative_property] = proc{|prn, rel_prop, meas, rcv_e, t_arv, usr_pos, usr_vel|
|
191
|
+
rel_prop[0] = 1 if rel_prop[0] > 0 # weight = 1
|
192
|
+
rel_prop
|
193
|
+
}
|
188
194
|
next true
|
189
195
|
end
|
190
196
|
when :elevation_mask_deg
|
@@ -280,6 +286,9 @@ class Receiver
|
|
280
286
|
$stderr.puts "#{mode.capitalize} satellite: #{[sys, svid].compact.join(':')}"
|
281
287
|
}
|
282
288
|
next true
|
289
|
+
when :fault_exclusion
|
290
|
+
@solver.options = {:skip_exclusion => !(output_options[:FDE] = v.to_b)}
|
291
|
+
next true
|
283
292
|
end
|
284
293
|
false
|
285
294
|
}
|
@@ -651,5 +660,21 @@ class Receiver
|
|
651
660
|
raise "Format error! (Not ANTEX) #{src}" unless applied_items >= 0
|
652
661
|
$stderr.puts "SP3 correction with ANTEX file (%s): %d items have been processed."%[src, applied_items]
|
653
662
|
end
|
663
|
+
|
664
|
+
def attach_rinex_clk(src)
|
665
|
+
fname = Util::get_txt(src)
|
666
|
+
@clk ||= GPS::RINEX_Clock::new
|
667
|
+
read_items = @clk.read(fname)
|
668
|
+
raise "Format error! (Not RINEX clock) #{src}" if read_items < 0
|
669
|
+
$stderr.puts "Read RINEX clock file (%s): %d items."%[src, read_items]
|
670
|
+
sats = @clk.satellites
|
671
|
+
@clk.class.constants.each{|sys|
|
672
|
+
next unless /^SYS_(?!SYSTEMS)(.*)/ =~ sys.to_s
|
673
|
+
idx, sys_name = [@clk.class.const_get(sys), $1]
|
674
|
+
next unless sats[idx] > 0
|
675
|
+
next unless @clk.push(@solver, idx)
|
676
|
+
$stderr.puts "Change clock error source of #{sys_name} to RINEX clock"
|
677
|
+
}
|
678
|
+
end
|
654
679
|
end
|
655
680
|
end
|
data/lib/gps_pvt/version.rb
CHANGED
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.
|
4
|
+
version: 0.7.2
|
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: 2022-
|
11
|
+
date: 2022-09-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|
@@ -78,6 +78,7 @@ files:
|
|
78
78
|
- ext/ninja-scan-light/tool/navigation/NTCM.h
|
79
79
|
- ext/ninja-scan-light/tool/navigation/QZSS.h
|
80
80
|
- ext/ninja-scan-light/tool/navigation/RINEX.h
|
81
|
+
- ext/ninja-scan-light/tool/navigation/RINEX_Clock.h
|
81
82
|
- ext/ninja-scan-light/tool/navigation/SBAS.h
|
82
83
|
- ext/ninja-scan-light/tool/navigation/SBAS_Solver.h
|
83
84
|
- ext/ninja-scan-light/tool/navigation/SP3.h
|