gps_pvt 0.1.1

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.
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