gps_pvt 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. checksums.yaml +7 -0
  2. data/.rspec +3 -0
  3. data/CHANGELOG.md +5 -0
  4. data/CODE_OF_CONDUCT.md +84 -0
  5. data/Gemfile +10 -0
  6. data/README.md +86 -0
  7. data/Rakefile +86 -0
  8. data/bin/console +15 -0
  9. data/bin/setup +8 -0
  10. data/ext/gps_pvt/Coordinate/Coordinate_wrap.cxx +6613 -0
  11. data/ext/gps_pvt/GPS/GPS_wrap.cxx +16019 -0
  12. data/ext/gps_pvt/SylphideMath/SylphideMath_wrap.cxx +21050 -0
  13. data/ext/gps_pvt/extconf.rb +70 -0
  14. data/ext/ninja-scan-light/tool/navigation/EGM.h +2971 -0
  15. data/ext/ninja-scan-light/tool/navigation/GPS.h +2432 -0
  16. data/ext/ninja-scan-light/tool/navigation/GPS_Solver.h +479 -0
  17. data/ext/ninja-scan-light/tool/navigation/GPS_Solver_Base.h +1081 -0
  18. data/ext/ninja-scan-light/tool/navigation/GPS_Solver_MultiFrequency.h +199 -0
  19. data/ext/ninja-scan-light/tool/navigation/GPS_Solver_RAIM.h +210 -0
  20. data/ext/ninja-scan-light/tool/navigation/MagneticField.h +928 -0
  21. data/ext/ninja-scan-light/tool/navigation/NTCM.h +211 -0
  22. data/ext/ninja-scan-light/tool/navigation/RINEX.h +1781 -0
  23. data/ext/ninja-scan-light/tool/navigation/WGS84.h +186 -0
  24. data/ext/ninja-scan-light/tool/navigation/coordinate.h +406 -0
  25. data/ext/ninja-scan-light/tool/param/bit_array.h +145 -0
  26. data/ext/ninja-scan-light/tool/param/complex.h +558 -0
  27. data/ext/ninja-scan-light/tool/param/matrix.h +4049 -0
  28. data/ext/ninja-scan-light/tool/param/matrix_fixed.h +665 -0
  29. data/ext/ninja-scan-light/tool/param/matrix_special.h +562 -0
  30. data/ext/ninja-scan-light/tool/param/quaternion.h +765 -0
  31. data/ext/ninja-scan-light/tool/param/vector3.h +651 -0
  32. data/ext/ninja-scan-light/tool/swig/Coordinate.i +177 -0
  33. data/ext/ninja-scan-light/tool/swig/GPS.i +1102 -0
  34. data/ext/ninja-scan-light/tool/swig/SylphideMath.i +1234 -0
  35. data/ext/ninja-scan-light/tool/swig/extconf.rb +5 -0
  36. data/ext/ninja-scan-light/tool/swig/makefile +53 -0
  37. data/ext/ninja-scan-light/tool/swig/spec/GPS_spec.rb +417 -0
  38. data/ext/ninja-scan-light/tool/swig/spec/SylphideMath_spec.rb +489 -0
  39. data/gps_pvt.gemspec +57 -0
  40. data/lib/gps_pvt/receiver.rb +375 -0
  41. data/lib/gps_pvt/ubx.rb +148 -0
  42. data/lib/gps_pvt/version.rb +5 -0
  43. data/lib/gps_pvt.rb +9 -0
  44. data/sig/gps_pvt.rbs +4 -0
  45. metadata +117 -0
@@ -0,0 +1,5 @@
1
+ require "mkmf"
2
+ cflags = " -Wall -I../../.."
3
+ $CFLAGS += cflags
4
+ $CPPFLAGS += cflags if RUBY_VERSION >= "2.0.0"
5
+ $LOCAL_LIBS += " -lstdc++ "
@@ -0,0 +1,53 @@
1
+ SWIG = swig
2
+ SWIGFLAGS = -c++ -ruby $(shell if [ -n "$$MSYSTEM" ]; then echo -D__MINGW__; fi)
3
+ INCLUDES = -I../
4
+ BUILD_DIR = build_SWIG
5
+
6
+ RUBY = ruby
7
+ RUBY_CONF = extconf.rb
8
+
9
+ SRCS = $(shell ls *.i)
10
+
11
+ PACKAGES = $(SRCS:.i=.so)
12
+
13
+ all : $(BUILD_DIR) depend $(PACKAGES)
14
+
15
+ depend : INCLUDES+=-I$(shell echo $${MSYSTEM_PREFIX:-/usr})/include/
16
+
17
+ # �w�b�_�[�t�@�C���̈ˑ��֌W
18
+ depend : $(SRCS)
19
+ if [ -f $(BUILD_DIR)/depend.inc ]; then rm -f $(BUILD_DIR)/depend.inc; fi
20
+ for i in $^; do\
21
+ $(SWIG) $(SWIGFLAGS) $(INCLUDES) -MM -MP $$i | sed -e 's/[^\.]*\.cxx/$$\(BUILD_DIR\)\/&/g' >> $(BUILD_DIR)/depend.inc;\
22
+ done
23
+
24
+ -include $(BUILD_DIR)/depend.inc
25
+
26
+ $(PACKAGES) : $(patsubst %,$(BUILD_DIR)/%,$(PACKAGES))
27
+
28
+ $(BUILD_DIR)/BoostDistributions_wrap.cxx : INCLUDES+=-I$(shell echo $${MSYSTEM_PREFIX:-/usr})/include/
29
+
30
+ $(BUILD_DIR)/%_wrap.cxx : %.i
31
+ $(SWIG) $(SWIGFLAGS) $(INCLUDES) -o $@ $<
32
+
33
+ $(BUILD_DIR)/%.so : PACKAGE = $(shell echo $@ | sed -e 's/^$(BUILD_DIR)\/\([^\.]*\)\.so/\1/g')
34
+ $(BUILD_DIR)/%.so : $(BUILD_DIR)/%_wrap.cxx $(RUBY_CONF)
35
+ echo "building $(PACKAGE) ..."
36
+ if ! [ -d $(BUILD_DIR)/$(PACKAGE) ]; then mkdir $(BUILD_DIR)/$(PACKAGE); fi
37
+ cp $(RUBY_CONF) $(BUILD_DIR)/$(PACKAGE)/
38
+ cp $(BUILD_DIR)/$(PACKAGE)_wrap.cxx $(BUILD_DIR)/$(PACKAGE)/
39
+ cd $(BUILD_DIR)/$(PACKAGE); \
40
+ echo 'create_makefile("$(PACKAGE)")' >> $(RUBY_CONF); \
41
+ $(RUBY) $(RUBY_CONF); \
42
+ make; \
43
+ cp *.so ../
44
+
45
+ $(BUILD_DIR) :
46
+ mkdir $@
47
+
48
+ clean :
49
+ rm -rf $(BUILD_DIR)/*
50
+
51
+ run : all
52
+
53
+ .PHONY : clean all depend
@@ -0,0 +1,417 @@
1
+ require 'rspec'
2
+
3
+ require 'tempfile'
4
+
5
+ $: << File::join(File::dirname(__FILE__), '..', 'build_SWIG')
6
+ require 'GPS.so'
7
+
8
+ describe 'GPS solver' do
9
+ let(:input){{
10
+ :rinex_nav => Tempfile::open{|f|
11
+ if true then
12
+ f.write(<<-__RINEX_NAV_TEXT__)
13
+ 2.10 N: GPS NAV DATA RINEX VERSION / TYPE
14
+ teqc 2013Mar15 BKG Frankfurt 20150617 00:16:14UTCPGM / RUN BY / DATE
15
+ Linux 2.4.21-27.ELsmp|Opteron|gcc -static|Linux x86_64|=+ COMMENT
16
+ 2.10 N: GPS NAV DATA COMMENT
17
+ teqc 2008Feb15 20150617 00:10:22UTCCOMMENT
18
+ Linux 2.4.20-8|Pentium IV|gcc -static|Linux|486/DX+ COMMENT
19
+ 1.3970D-08 2.2352D-08 -1.1921D-07 -1.1921D-07 ION ALPHA
20
+ 1.1059D+05 1.6384D+05 -6.5536D+04 -5.2429D+05 ION BETA
21
+ 3.725290298462D-09 1.509903313490D-14 319488 1849 DELTA-UTC: A0,A1,T,W
22
+ 16 LEAP SECONDS
23
+ Concatenated RINEX files (28/) COMMENT
24
+ Original file name: brdc1670.15n COMMENT
25
+ END OF HEADER
26
+ 31 15 6 16 0 0 0.0 3.128303214908D-04-1.136868377216D-12 0.000000000000D+00
27
+ 7.800000000000D+01 1.292812500000D+02 4.074098273975D-09 1.410690806649D+00
28
+ 6.768852472305D-06 8.027532137930D-03 4.271045327187D-06 5.153535821915D+03
29
+ 1.728000000000D+05 9.872019290924D-08 8.650894583569D-01 8.940696716309D-08
30
+ 9.750288799237D-01 3.013750000000D+02-5.268559212524D-01-8.036049019412D-09
31
+ 3.664438352852D-10 1.000000000000D+00 1.849000000000D+03 0.000000000000D+00
32
+ 2.000000000000D+00 0.000000000000D+00-1.350417733192D-08 7.800000000000D+01
33
+ 1.663560000000D+05 4.000000000000D+00
34
+ 24 15 6 16 0 0 0.0-4.998780786991D-05-5.684341886081D-13 0.000000000000D+00
35
+ 9.000000000000D+01 1.401250000000D+02 4.642336229081D-09 2.380519254182D+00
36
+ 7.258728146553D-06 3.228595596738D-03 3.971159458160D-06 5.153673912048D+03
37
+ 1.728000000000D+05-2.980232238770D-08 8.160388274984D-01-1.490116119385D-08
38
+ 9.533772739559D-01 2.969375000000D+02 3.612098431884D-01-8.379634759709D-09
39
+ 4.025167664390D-10 1.000000000000D+00 1.849000000000D+03 0.000000000000D+00
40
+ 2.900000000000D+00 0.000000000000D+00 2.328306436539D-09 9.000000000000D+01
41
+ 1.656600000000D+05 4.000000000000D+00
42
+ 12 15 6 16 0 0 0.0 3.018006682396D-04 3.183231456205D-12 0.000000000000D+00
43
+ 9.000000000000D+01-8.984375000000D+01 4.146244136282D-09 1.019955493515D+00
44
+ -4.906207323074D-06 5.596161005087D-03 2.166256308556D-06 5.153664655685D+03
45
+ 1.728000000000D+05-3.352761268616D-08 1.926955253672D+00 9.685754776001D-08
46
+ 9.895896897770D-01 3.531562500000D+02 6.166481681571D-01-8.222842514396D-09
47
+ -2.525105180766D-10 1.000000000000D+00 1.849000000000D+03 0.000000000000D+00
48
+ 2.000000000000D+00 0.000000000000D+00-1.210719347000D-08 9.000000000000D+01
49
+ 1.708800000000D+05 4.000000000000D+00
50
+ 25 15 6 16 0 0 0.0-2.291053533554D-06-4.206412995700D-12 0.000000000000D+00
51
+ 4.300000000000D+01-8.231250000000D+01 4.456614188797D-09 3.514302168106D-01
52
+ -4.393979907036D-06 4.659408819862D-03 1.480802893639D-06 5.153666315079D+03
53
+ 1.728000000000D+05 0.000000000000D+00 1.880081553172D+00 1.080334186554D-07
54
+ 9.780612252959D-01 3.641250000000D+02 7.406192694225D-01-8.389992700586D-09
55
+ -1.742929689463D-10 1.000000000000D+00 1.849000000000D+03 0.000000000000D+00
56
+ 2.000000000000D+00 0.000000000000D+00 5.587935447693D-09 4.300000000000D+01
57
+ 1.728000000000D+05
58
+ 18 15 6 15 23 59 44.0 4.096841439605D-04 2.955857780762D-12 0.000000000000D+00
59
+ 0.000000000000D+00-2.200000000000D+01 5.964177003340D-09-4.658085121885D-01
60
+ -1.063570380211D-06 1.631921075750D-02 5.243346095085D-06 5.153597631454D+03
61
+ 1.727840000000D+05-9.499490261078D-08-1.282443549024D+00 1.769512891769D-07
62
+ 9.246030417022D-01 2.601875000000D+02-1.955724914307D+00-8.981445541829D-09
63
+ -4.760912596834D-10 1.000000000000D+00 1.849000000000D+03 0.000000000000D+00
64
+ 2.000000000000D+00 0.000000000000D+00-1.117587089539D-08 0.000000000000D+00
65
+ 1.696560000000D+05 4.000000000000D+00
66
+ 29 15 6 16 0 0 0.0 6.168931722641D-04 2.273736754432D-12 0.000000000000D+00
67
+ 7.300000000000D+01-1.041875000000D+02 4.061597753278D-09 5.907941646969D-01
68
+ -5.280598998070D-06 1.195417135023D-03 1.201778650284D-05 5.153755130768D+03
69
+ 1.728000000000D+05 9.313225746155D-09 2.981267878597D+00-1.303851604462D-08
70
+ 9.739471617229D-01 1.573125000000D+02-5.419126340021D-01-7.659961925303D-09
71
+ 2.107230631757D-10 1.000000000000D+00 1.849000000000D+03 0.000000000000D+00
72
+ 2.000000000000D+00 0.000000000000D+00-9.778887033463D-09 7.300000000000D+01
73
+ 1.656180000000D+05 4.000000000000D+00
74
+ __RINEX_NAV_TEXT__
75
+ else # equivalent
76
+ open(File::join(File::dirname(__FILE__), "..", "..", "test_log", "brdc1670.15n"), 'r'){|io|
77
+ while (str = io.readline)
78
+ f.puts("%-80s"%[str.chomp])
79
+ break if str =~ /END OF HEADER/
80
+ end
81
+ while !io.eof?
82
+ entry = 8.times.collect{io.readline}
83
+ next unless entry[0] =~ /^([ \d]\d) /
84
+ prn = $1.to_i
85
+ next unless entry[6] =~ /(\d\.\d{12})D([+-]\d{2})\s*$/
86
+ iode = ($1.to_f * (10 ** $2.to_i)).to_i
87
+ next unless [[12, 90], [18, 0], [24, 90], [25, 43], [29, 73], [31, 78]] \
88
+ .include?([prn, iode])
89
+ entry.each{|str|
90
+ f.print("%-80s\n"%[str.chomp])
91
+ }
92
+ end
93
+ }
94
+ end
95
+ f.path
96
+ },
97
+ :measurement => proc{
98
+ l1p = GPS::Measurement::L1_PSEUDORANGE
99
+ l1d = GPS::Measurement::L1_RANGE_RATE
100
+ {
101
+ 12 => {l1p => 23707858.8131, l1d => -466.953123206},
102
+ 18 => {l1p => 25319310.9754, l1d => -453.797772239},
103
+ 24 => {l1p => 25683081.3903, l1d => -579.768048832},
104
+ 25 => {l1p => 21551698.5927, l1d => -847.86674626},
105
+ 29 => {l1p => 23637198.3968, l1d => -1560.30646593},
106
+ 31 => {l1p => 23707474.1231, l1d => -1423.67588761},
107
+ }
108
+ }.call,
109
+ :rinex_obs => Tempfile::open{|f|
110
+ if true then
111
+ f.write(<<-__RINEX_OBS_TEXT__)
112
+ 2.11 OBSERVATION DATA M (MIXED) RINEX VERSION / TYPE
113
+ BINEX2RINEX 1.00 GSI, JAPAN 20150617 18:30:58UTCPGM / RUN BY / DATE
114
+ 0228 MARKER NAME
115
+ GSI, JAPAN GEOSPATIAL INFORMATION AUTHORITY OF JAPAOBSERVER / AGENCY
116
+ 00000 TRIMBLE NETR9 4.93,26/NOV/2014 REC # / TYPE / VERS
117
+ TRM59800.80 GSI ANT # / TYPE
118
+ -3952590.4754 3360273.8926 3697987.2632 APPROX POSITION XYZ
119
+ 0.0000 0.0000 0.0000 ANTENNA: DELTA H/E/N
120
+ 1 1 WAVELENGTH FACT L1/2
121
+ 6 L1 C1 L2 P2 S1 S2 # / TYPES OF OBSERV
122
+ 2015 6 16 0 0 0.0000000 GPS TIME OF FIRST OBS
123
+ 30.000 INTERVAL
124
+ 16 LEAP SECONDS
125
+ smtt on - smooth time tag (ms jumps in phase and range) COMMENT
126
+ END OF HEADER
127
+ 15 6 16 0 0 0.0000000 0 13R04R14G22G18G25G14R03G12R13G29R23R24 0.000000000
128
+ G26
129
+ 107962537.996 8 20161244.813 83970896.187 7 20161248.340 53.100
130
+ 45.700
131
+ 108292688.703 7 20315410.305 84227597.491 6 20315417.836 44.900
132
+ 38.600
133
+ 120164532.762 7 22866559.250 93634735.08845 22866565.0164 44.800
134
+ 31.9004
135
+ 127657315.100 5 24292417.195 99473356.27642 24292426.4844 33.000
136
+ 16.9004
137
+ 107108718.011 8 20382088.883 83461307.35447 20382098.2114 52.700
138
+ 44.8004
139
+ 106665594.451 8 20297781.844 83116060.16147 20297788.3284 48.500
140
+ 43.6004
141
+ 112247722.253 8 20968815.328 87303792.973 7 20968819.930 48.200
142
+ 43.900
143
+ 119180856.024 7 22679363.352 92868240.86845 22679370.8554 46.000
144
+ 34.4004
145
+ 113219403.456 7 21202362.125 88059583.077 7 21202366.582 43.300
146
+ 42.600
147
+ 116573807.952 8 22183256.359 90836814.38846 22183263.8554 48.000
148
+ 37.2004
149
+ 118068213.681 8 22071607.477 91830908.595 5 22071616.434 48.300
150
+ 34.300
151
+ 122821571.168 6 22968227.047 95527813.562 5 22968231.008 41.000
152
+ 33.400
153
+ 126887720.863 7 24145939.008 98873654.81144 24145951.6954 42.000
154
+ 24.8004
155
+ 15 6 16 0 0 30.0000000 0 13R04R14G22G18G25G14R03G12R13G29R23R24 0.000000000
156
+ G26
157
+ 107953906.562 8 20159632.578 83964182.831 7 20159636.547 52.900
158
+ 45.500
159
+ 108275524.990 7 20312191.531 84214247.928 6 20312198.477 46.000
160
+ 37.900
161
+ 120243117.022 7 22881512.617 93695969.52045 22881519.3444 43.200
162
+ 30.0004
163
+ 127752623.271 5 24310554.234 99547622.25842 24310562.6254 34.300
164
+ 14.8004
165
+ 107148475.172 8 20389654.469 83492286.95147 20389663.6914 53.000
166
+ 44.7004
167
+ 106649633.973 8 20294744.781 83103623.41147 20294751.4144 49.800
168
+ 44.5004
169
+ 112354437.822 8 20988750.797 87386793.909 7 20988756.371 48.000
170
+ 44.200
171
+ 119276901.051 7 22697639.727 92943081.07945 22697647.7704 47.500
172
+ 34.6004
173
+ 113277695.919 7 21213278.297 88104921.616 7 21213283.438 43.800
174
+ 42.700
175
+ 116499708.794 8 22169155.719 90779074.87246 22169163.7704 48.500
176
+ 37.6004
177
+ 118027431.830 8 22063984.773 91799189.430 5 22063991.707 49.300
178
+ 35.100
179
+ 122710898.974 6 22947531.234 95441735.252 5 22947536.609 40.900
180
+ 33.600
181
+ 126789541.785 6 24127256.484 98797151.68444 24127268.9224 41.900
182
+ 25.3004
183
+ 15 6 16 0 1 0.0000000 0 13R04R14G22G18G25G14R03G12R13G29R23R24 0.000000000
184
+ G26
185
+ 107946098.362 8 20158174.969 83958109.762 7 20158178.289 53.200
186
+ 44.900
187
+ 108258590.494 7 20309014.148 84201076.653 6 20309021.145 46.000
188
+ 38.700
189
+ 120321906.821 7 22896506.344 93757364.10145 22896512.2934 44.600
190
+ 30.2004
191
+ 127847866.993 6 24328677.648 99621838.11742 24328687.3954 37.300
192
+ 16.9004
193
+ 107188670.264 8 20397303.531 83523607.79247 20397312.3054 53.700
194
+ 44.3004
195
+ 106634143.554 8 20291797.133 83091552.94947 20291803.6724 49.900
196
+ 44.0004
197
+ 112461605.174 7 21008771.203 87470146.236 7 21008775.176 47.500
198
+ 43.900
199
+ 119373111.958 8 22715948.289 93018050.54445 22715955.9534 48.100
200
+ 34.1004
201
+ 113336078.148 7 21224212.609 88150329.998 7 21224216.957 43.000
202
+ 42.500
203
+ 116425964.067 7 22155122.617 90721611.48746 22155131.1914 46.200
204
+ 37.6004
205
+ 117987330.119 7 22056486.641 91767999.260 5 22056494.809 46.900
206
+ 34.500
207
+ 122600398.977 6 22926865.672 95355790.881 5 22926871.977 39.700
208
+ 32.500
209
+ 126691542.694 6 24108607.188 98720788.84544 24108620.5234 41.700
210
+ 24.8004
211
+ __RINEX_OBS_TEXT__
212
+ else # equivalent
213
+ # GEONET Setagaya from https://terras.gsi.go.jp/data_service.php#11/35.663712/139.630394
214
+ open(File::join(File::dirname(__FILE__), "..", "..", "test_log", "02281670.15o"), 'r'){|io|
215
+ 99.times{|i|
216
+ break unless str = io.readline
217
+ f.write(str)
218
+ }
219
+ }
220
+ end
221
+ f.path
222
+ },
223
+ }}
224
+ let(:solver){GPS::Solver::new}
225
+
226
+ describe 'demo' do
227
+ it 'calculates position without any error' do
228
+ sn = solver.gps_space_node
229
+ puts "RINEX NAV read: %d items."%[sn.read(input[:rinex_nav])]
230
+ meas = GPS::Measurement::new
231
+ input[:measurement].each{|prn, items|
232
+ items.each{|k, v|
233
+ meas.add(prn, k, v)
234
+ }
235
+ }
236
+ expect(meas.to_hash).to eq(proc{|array|
237
+ res = {}
238
+ array.each{|prn, k, v|
239
+ (res[prn][k] = v) rescue (res[prn] = {k => v})
240
+ }
241
+ res
242
+ }.call(meas.to_a))
243
+ expect(GPS::Measurement::new(meas.to_a).to_a.sort).to eq(meas.to_a.sort) # accept [[prn, k, v], ...]
244
+ expect(GPS::Measurement::new(meas.to_hash).to_a.sort).to eq(meas.to_a.sort) # accept {prn => {k => v, ...}, ...}
245
+ expect{GPS::Measurement::new({:sym => {1 => 2}})}.to raise_error
246
+ expect{GPS::Measurement::new({1 => {:sym => 2}})}.to raise_error
247
+ expect{GPS::Measurement::new({1 => [2, 3]})}.to raise_error
248
+
249
+ t_meas = GPS::Time::new(1849, 172413)
250
+ puts "Measurement time: #{t_meas.to_a} (a.k.a #{"%d/%d/%d %02d:%02d:%02d UTC"%[*t_meas.c_tm]})"
251
+ expect(t_meas.c_tm).to eq([2015, 6, 15, 23, 53, 33])
252
+
253
+ sn.update_all_ephemeris(t_meas)
254
+
255
+ [:alpha, :beta].each{|k|
256
+ puts "Iono #{k}: #{sn.iono_utc.send(k)}"
257
+ }
258
+ puts solver.gps_options.ionospheric_models
259
+
260
+ meas.each{|prn, k, v|
261
+ eph = sn.ephemeris(prn)
262
+ puts "XYZ(PRN:#{prn}): #{eph.constellation(t_meas)[0].to_a} (iodc: #{eph.iodc}, iode: #{eph.iode})"
263
+ }
264
+
265
+ run_solver = proc{
266
+ pvt = solver.solve(meas, t_meas)
267
+ [
268
+ :error_code,
269
+ :position_solved?,
270
+ [:receiver_time, proc{|v| v.to_a}],
271
+ :used_satellite_list,
272
+ [:llh, proc{|llh| llh.to_a.zip([180.0 / Math::PI] * 2 + [1]).collect{|v, sf| v * sf}}],
273
+ :receiver_error,
274
+ [:velocity, proc{|xyz| xyz.to_a}],
275
+ :receiver_error_rate,
276
+ [:G_enu, proc{|mat| mat.to_s}],
277
+ :fd,
278
+ :fde_min,
279
+ :fde_2nd,
280
+ ].each{|fun, task|
281
+ task ||= proc{|v| v}
282
+ puts "pvt.#{fun}: #{task.call(pvt.send(fun))}"
283
+ }
284
+ pvt
285
+ }
286
+
287
+ puts "Normal solution ..."
288
+ pvt = run_solver.call
289
+ puts
290
+
291
+ expect(pvt.position_solved?).to be(true)
292
+ expect(pvt.receiver_time.to_a).to eq([1849, 172413])
293
+ expect(pvt.llh.to_a).to eq([:lat, :lng, :alt].collect{|k| pvt.llh.send(k)})
294
+ expect(pvt.llh.lat / Math::PI * 180).to be_within(1E-9).of(35.6992591268) # latitude
295
+ expect(pvt.llh.lng / Math::PI * 180).to be_within(1E-9).of(139.541502292) # longitude
296
+ expect(pvt.llh.alt) .to be_within(1E-4).of(104.279402455) # altitude
297
+ expect(pvt.receiver_error).to be_within(1E-4).of(1259087.83603)
298
+ expect(pvt.gdop).to be_within(1E-10).of(3.83282723293)
299
+ expect(pvt.pdop).to be_within(1E-10).of(3.30873220653)
300
+ expect(pvt.hdop).to be_within(1E-10).of(2.05428293774)
301
+ expect(pvt.vdop).to be_within(1E-10).of(2.59376761222)
302
+ expect(pvt.tdop).to be_within(1E-10).of(1.9346461648)
303
+ expect(pvt.velocity.to_a).to eq([:e, :n, :u].collect{|k| pvt.velocity.send(k)})
304
+ expect(pvt.velocity.north).to be_within(1E-7).of(-0.839546227836) # north
305
+ expect(pvt.velocity.east) .to be_within(1E-7).of(-1.05805616381) # east
306
+ expect(pvt.velocity.down) .to be_within(1E-7).of(-0.12355474006) # down
307
+ expect(pvt.receiver_error_rate).to be_within(1E-7).of(-1061.92654151)
308
+ expect(pvt.G.rows).to eq(6)
309
+ expect(pvt.W.rows).to eq(6)
310
+ expect(pvt.delta_r.rows).to eq(6)
311
+ expect(pvt.G_enu.rows).to eq(6)
312
+ expect(Math::sqrt(pvt.C[3, 3])).to be_within(1E-10).of(pvt.tdop)
313
+ expect(Math::sqrt(pvt.C_enu[2, 2])).to be_within(1E-10).of(pvt.vdop)
314
+ pvt.S.to_a.flatten.zip(
315
+ ((pvt.G.t * pvt.W * pvt.G).inv * (pvt.G.t * pvt.W)).to_a.flatten).each{|a, b|
316
+ expect(a).to be_within(1E-10).of(b)
317
+ }
318
+ pvt.S_enu.to_a.flatten.zip(
319
+ ((pvt.G_enu.t * pvt.W * pvt.G_enu).inv * (pvt.G_enu.t * pvt.W)).to_a.flatten).each{|a, b|
320
+ expect(a).to be_within(1E-10).of(b)
321
+ }
322
+ expect([:rows, :columns].collect{|f| pvt.slope_HV_enu.send(f)}).to eq([6, 2])
323
+ expect(pvt.used_satellites).to eq(6)
324
+ expect(pvt.used_satellite_list).to eq([12,18, 24, 25, 29, 31])
325
+
326
+ meas.each{|prn, k, v|
327
+ solver.gps_options.exclude(prn)
328
+ puts "Excluded(PRN: #{solver.gps_options.excluded.join(', ')}) solution ..."
329
+ run_solver.call
330
+ solver.gps_options.excluded.each{|prn|
331
+ solver.gps_options.include(prn)
332
+ }
333
+ puts
334
+ }
335
+ end
336
+
337
+ it 'can be modified through hooks' do
338
+ sn = solver.gps_space_node
339
+ sn.read(input[:rinex_nav])
340
+ t_meas = GPS::Time::new(1849, 172413)
341
+ sn.update_all_ephemeris(t_meas)
342
+ solver.hooks[:relative_property] = proc{|prn, rel_prop, rcv_e, t_arv, usr_pos, usr_vel|
343
+ expect(input[:measurement]).to include(prn)
344
+ expect(t_arv).to be_a_kind_of(GPS::Time)
345
+ expect(usr_pos).to be_a_kind_of(Coordinate::XYZ)
346
+ expect(usr_vel).to be_a_kind_of(Coordinate::XYZ)
347
+ weight, range_c, range_r, rate_rel_neg, *los_neg = rel_prop
348
+ weight = 1
349
+ [weight, range_c, range_r, rate_rel_neg] + los_neg
350
+ }
351
+ solver.hooks[:update_position_solution] = proc{|*mats|
352
+ mats.each{|mat|
353
+ expect(mat).to be_a_kind_of(SylphideMath::MatrixD)
354
+ }
355
+ mat_G, mat_W, mat_delta_r = mats
356
+ }
357
+ pvt = solver.solve(
358
+ input[:measurement].collect{|prn, items|
359
+ items.collect{|k, v| [prn, k, v]}
360
+ }.flatten(1),
361
+ t_meas)
362
+ expect(pvt.W).to eq(SylphideMath::MatrixD::I(pvt.W.rows))
363
+ end
364
+
365
+ it 'calculates position without any error with RINEX obs file' do
366
+ sn = solver.gps_space_node
367
+ puts "RINEX NAV read: %d items."%[sn.read(input[:rinex_nav])]
368
+ GPS::RINEX_Observation::read(input[:rinex_obs]){|item|
369
+ t_meas = item[:time]
370
+ puts "Measurement time: #{t_meas.to_a} (a.k.a #{"%d/%d/%d %02d:%02d:%02d UTC"%[*t_meas.c_tm]})"
371
+ sn.update_all_ephemeris(t_meas)
372
+
373
+ meas = GPS::Measurement::new
374
+ types = (item[:meas_types]['G'] || item[:meas_types][' ']).collect.with_index{|type_, i|
375
+ case type_
376
+ when "C1"
377
+ [i, GPS::Measurement::L1_PSEUDORANGE]
378
+ when "D1"
379
+ [i, GPS::Measurement::L1_RANGE_RATE]
380
+ else
381
+ nil
382
+ end
383
+ }.compact
384
+ item[:meas].each{|k, v|
385
+ sys, prn = k
386
+ next unless sys == 'G' # GPS only
387
+ types.each{|i, type_|
388
+ meas.add(prn, type_, v[i][0]) if v[i]
389
+ }
390
+ }
391
+
392
+ pvt = solver.solve(meas, t_meas)
393
+ expect(pvt.position_solved?).to eq(true)
394
+
395
+ puts pvt.llh.to_a.zip([180.0 / Math::PI] * 2 + [1]).collect{|v, sf| v * sf}.inspect
396
+ if approx_pos = proc{
397
+ next false unless res = item[:header].select{|k, v| k =~ /APPROX POSITION XYZ/}.values[0]
398
+ next false unless res = res.collect{|item|
399
+ item.scan(/([+-]?\d+(?:\.\d+)?)\s*/).flatten
400
+ }.reject{|item|
401
+ item.empty?
402
+ }[0]
403
+ Coordinate::XYZ::new(*(res.collect{|str| str.to_f}))
404
+ }.call then
405
+ approx_pos.to_a.zip(pvt.xyz.to_a).each{|a, b|
406
+ expect(a).to be_within(1E+1).of(b) # 10 m
407
+ }
408
+ end
409
+
410
+ pvt.used_satellite_list.each{|prn|
411
+ eph = sn.ephemeris(prn)
412
+ puts "XYZ(PRN:#{prn}): #{eph.constellation(t_meas)[0].to_a} (iodc: #{eph.iodc}, iode: #{eph.iode})"
413
+ }
414
+ }
415
+ end
416
+ end
417
+ end