gps_pvt 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.rspec +3 -0
- data/CHANGELOG.md +5 -0
- data/CODE_OF_CONDUCT.md +84 -0
- data/Gemfile +10 -0
- data/README.md +86 -0
- data/Rakefile +86 -0
- data/bin/console +15 -0
- data/bin/setup +8 -0
- data/ext/gps_pvt/Coordinate/Coordinate_wrap.cxx +6613 -0
- data/ext/gps_pvt/GPS/GPS_wrap.cxx +16019 -0
- data/ext/gps_pvt/SylphideMath/SylphideMath_wrap.cxx +21050 -0
- data/ext/gps_pvt/extconf.rb +70 -0
- data/ext/ninja-scan-light/tool/navigation/EGM.h +2971 -0
- data/ext/ninja-scan-light/tool/navigation/GPS.h +2432 -0
- data/ext/ninja-scan-light/tool/navigation/GPS_Solver.h +479 -0
- data/ext/ninja-scan-light/tool/navigation/GPS_Solver_Base.h +1081 -0
- data/ext/ninja-scan-light/tool/navigation/GPS_Solver_MultiFrequency.h +199 -0
- data/ext/ninja-scan-light/tool/navigation/GPS_Solver_RAIM.h +210 -0
- data/ext/ninja-scan-light/tool/navigation/MagneticField.h +928 -0
- data/ext/ninja-scan-light/tool/navigation/NTCM.h +211 -0
- data/ext/ninja-scan-light/tool/navigation/RINEX.h +1781 -0
- data/ext/ninja-scan-light/tool/navigation/WGS84.h +186 -0
- data/ext/ninja-scan-light/tool/navigation/coordinate.h +406 -0
- data/ext/ninja-scan-light/tool/param/bit_array.h +145 -0
- data/ext/ninja-scan-light/tool/param/complex.h +558 -0
- data/ext/ninja-scan-light/tool/param/matrix.h +4049 -0
- data/ext/ninja-scan-light/tool/param/matrix_fixed.h +665 -0
- data/ext/ninja-scan-light/tool/param/matrix_special.h +562 -0
- data/ext/ninja-scan-light/tool/param/quaternion.h +765 -0
- data/ext/ninja-scan-light/tool/param/vector3.h +651 -0
- data/ext/ninja-scan-light/tool/swig/Coordinate.i +177 -0
- data/ext/ninja-scan-light/tool/swig/GPS.i +1102 -0
- data/ext/ninja-scan-light/tool/swig/SylphideMath.i +1234 -0
- data/ext/ninja-scan-light/tool/swig/extconf.rb +5 -0
- data/ext/ninja-scan-light/tool/swig/makefile +53 -0
- data/ext/ninja-scan-light/tool/swig/spec/GPS_spec.rb +417 -0
- data/ext/ninja-scan-light/tool/swig/spec/SylphideMath_spec.rb +489 -0
- data/gps_pvt.gemspec +57 -0
- data/lib/gps_pvt/receiver.rb +375 -0
- data/lib/gps_pvt/ubx.rb +148 -0
- data/lib/gps_pvt/version.rb +5 -0
- data/lib/gps_pvt.rb +9 -0
- data/sig/gps_pvt.rbs +4 -0
- metadata +117 -0
@@ -0,0 +1,479 @@
|
|
1
|
+
/**
|
2
|
+
* @file GPS solver
|
3
|
+
* - Mainly, single positioning
|
4
|
+
*
|
5
|
+
*/
|
6
|
+
|
7
|
+
/*
|
8
|
+
* Copyright (c) 2016, M.Naruoka (fenrir)
|
9
|
+
* All rights reserved.
|
10
|
+
*
|
11
|
+
* Redistribution and use in source and binary forms, with or without modification,
|
12
|
+
* are permitted provided that the following conditions are met:
|
13
|
+
*
|
14
|
+
* - Redistributions of source code must retain the above copyright notice,
|
15
|
+
* this list of conditions and the following disclaimer.
|
16
|
+
* - Redistributions in binary form must reproduce the above copyright notice,
|
17
|
+
* this list of conditions and the following disclaimer in the documentation
|
18
|
+
* and/or other materials provided with the distribution.
|
19
|
+
* - Neither the name of the naruoka.org nor the names of its contributors
|
20
|
+
* may be used to endorse or promote products derived from this software
|
21
|
+
* without specific prior written permission.
|
22
|
+
*
|
23
|
+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
24
|
+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
25
|
+
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
26
|
+
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS
|
27
|
+
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
|
28
|
+
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
29
|
+
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
30
|
+
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
31
|
+
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
32
|
+
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
33
|
+
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
34
|
+
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
35
|
+
*
|
36
|
+
*/
|
37
|
+
|
38
|
+
#ifndef __GPS_SOLVER_H__
|
39
|
+
#define __GPS_SOLVER_H__
|
40
|
+
|
41
|
+
#include <utility>
|
42
|
+
#include <vector>
|
43
|
+
#include <exception>
|
44
|
+
|
45
|
+
#include <cmath>
|
46
|
+
|
47
|
+
#include "param/bit_array.h"
|
48
|
+
|
49
|
+
#include "GPS.h"
|
50
|
+
#include "GPS_Solver_Base.h"
|
51
|
+
#include "NTCM.h"
|
52
|
+
|
53
|
+
template <class FloatT>
|
54
|
+
struct GPS_Solver_GeneralOptions {
|
55
|
+
FloatT elevation_mask;
|
56
|
+
FloatT residual_mask;
|
57
|
+
|
58
|
+
enum ionospheric_model_t {
|
59
|
+
IONOSPHERIC_KLOBUCHAR,
|
60
|
+
IONOSPHERIC_NTCM_GL,
|
61
|
+
IONOSPHERIC_NONE, // which allows no correction
|
62
|
+
IONOSPHERIC_MODELS,
|
63
|
+
IONOSPHERIC_SKIP = IONOSPHERIC_MODELS, // which means delegating the next slot
|
64
|
+
};
|
65
|
+
ionospheric_model_t ionospheric_models[IONOSPHERIC_MODELS]; // lower index means having higher priority
|
66
|
+
|
67
|
+
int count_ionospheric_models() const {
|
68
|
+
int res(0);
|
69
|
+
for(int i(0); i < sizeof(ionospheric_models) / sizeof(ionospheric_models[0]); ++i){
|
70
|
+
if(ionospheric_models[i] != IONOSPHERIC_SKIP){res++;}
|
71
|
+
}
|
72
|
+
return res;
|
73
|
+
}
|
74
|
+
|
75
|
+
FloatT f_10_7;
|
76
|
+
|
77
|
+
GPS_Solver_GeneralOptions()
|
78
|
+
: elevation_mask(0), // elevation mask default is 0 [deg]
|
79
|
+
residual_mask(30), // range residual mask is 30 [m]
|
80
|
+
f_10_7(-1) {
|
81
|
+
for(int i(0); i < sizeof(ionospheric_models) / sizeof(ionospheric_models[0]); ++i){
|
82
|
+
ionospheric_models[i] = IONOSPHERIC_SKIP;
|
83
|
+
}
|
84
|
+
// default: broadcasted Klobuchar parameters are at least required for solution.
|
85
|
+
ionospheric_models[0] = IONOSPHERIC_KLOBUCHAR;
|
86
|
+
}
|
87
|
+
|
88
|
+
bool insert_ionospheric_model(const ionospheric_model_t &model, const int &index = 0) {
|
89
|
+
if((index < 0)
|
90
|
+
|| (index >= sizeof(ionospheric_models) / sizeof(ionospheric_models[0]))){
|
91
|
+
return false;
|
92
|
+
}
|
93
|
+
|
94
|
+
// shift, then replace
|
95
|
+
for(int i(index), j(i + 1); j < sizeof(ionospheric_models) / sizeof(ionospheric_models[0]); ++i, ++j){
|
96
|
+
ionospheric_models[j] = ionospheric_models[i];
|
97
|
+
}
|
98
|
+
ionospheric_models[index] = model;
|
99
|
+
|
100
|
+
return true;
|
101
|
+
}
|
102
|
+
};
|
103
|
+
|
104
|
+
template <class FloatT>
|
105
|
+
struct GPS_SinglePositioning_Options : public GPS_Solver_GeneralOptions<FloatT> {
|
106
|
+
|
107
|
+
// PRN ranges from 1 to 256 (including GPS compatible systems such as QZSS)
|
108
|
+
typename GPS_Solver_Base<FloatT>::options_t::template exclude_prn_t<1, 256> exclude_prn;
|
109
|
+
|
110
|
+
GPS_SinglePositioning_Options()
|
111
|
+
: GPS_Solver_GeneralOptions<FloatT>(), exclude_prn() {
|
112
|
+
|
113
|
+
}
|
114
|
+
};
|
115
|
+
|
116
|
+
template <class FloatT, class SolverBaseT = GPS_Solver_Base<FloatT> >
|
117
|
+
class GPS_SinglePositioning : public SolverBaseT {
|
118
|
+
private:
|
119
|
+
GPS_SinglePositioning<FloatT> &operator=(const GPS_SinglePositioning<FloatT> &);
|
120
|
+
public:
|
121
|
+
typedef GPS_SinglePositioning<FloatT> self_t;
|
122
|
+
typedef SolverBaseT base_t;
|
123
|
+
|
124
|
+
#if defined(__GNUC__) && (__GNUC__ < 5)
|
125
|
+
#define inheritate_type(x) typedef typename base_t::x x;
|
126
|
+
#else
|
127
|
+
#define inheritate_type(x) using typename base_t::x;
|
128
|
+
#endif
|
129
|
+
|
130
|
+
inheritate_type(float_t);
|
131
|
+
inheritate_type(matrix_t);
|
132
|
+
inheritate_type(prn_t);
|
133
|
+
|
134
|
+
typedef typename base_t::space_node_t space_node_t;
|
135
|
+
inheritate_type(gps_time_t);
|
136
|
+
typedef typename space_node_t::Satellite satellite_t;
|
137
|
+
|
138
|
+
inheritate_type(xyz_t);
|
139
|
+
inheritate_type(llh_t);
|
140
|
+
inheritate_type(enu_t);
|
141
|
+
|
142
|
+
inheritate_type(pos_t);
|
143
|
+
|
144
|
+
inheritate_type(prn_obs_t);
|
145
|
+
typedef typename base_t::measurement_t measurement_t;
|
146
|
+
inheritate_type(measurement_items_t);
|
147
|
+
typedef typename base_t::range_error_t range_error_t;
|
148
|
+
|
149
|
+
inheritate_type(relative_property_t);
|
150
|
+
inheritate_type(geometric_matrices_t);
|
151
|
+
inheritate_type(user_pvt_t);
|
152
|
+
#undef inheritate_type
|
153
|
+
|
154
|
+
typedef typename GPS_Solver_Base<float_t>::options_t::template merge_t<
|
155
|
+
GPS_SinglePositioning_Options<float_t>, base_t> options_t;
|
156
|
+
|
157
|
+
protected:
|
158
|
+
const space_node_t &_space_node;
|
159
|
+
GPS_SinglePositioning_Options<float_t> _options;
|
160
|
+
|
161
|
+
public:
|
162
|
+
const space_node_t &space_node() const {return _space_node;}
|
163
|
+
|
164
|
+
/**
|
165
|
+
* Check availability of ionospheric models
|
166
|
+
* If a model is completely unavailable, it will be replaced to IONOSPHERIC_SKIP.
|
167
|
+
* It implies that when a model has conditional applicability (such as SBAS), it will be retained.
|
168
|
+
*
|
169
|
+
* @return (int) number of (possibly) available models
|
170
|
+
*/
|
171
|
+
int filter_ionospheric_models(GPS_SinglePositioning_Options<float_t> &opt) const {
|
172
|
+
|
173
|
+
int available_models(0);
|
174
|
+
|
175
|
+
for(int i(0); i < sizeof(opt.ionospheric_models) / sizeof(opt.ionospheric_models[0]); ++i){
|
176
|
+
switch(opt.ionospheric_models[i]){
|
177
|
+
case options_t::IONOSPHERIC_KLOBUCHAR:
|
178
|
+
// check whether Klobuchar parameters alpha and beta have been already received
|
179
|
+
if(_space_node.is_valid_iono()){break;}
|
180
|
+
opt.ionospheric_models[i] = options_t::IONOSPHERIC_SKIP;
|
181
|
+
continue;
|
182
|
+
case options_t::IONOSPHERIC_NTCM_GL:
|
183
|
+
if(opt.f_10_7 >= 0){break;}
|
184
|
+
// check F10.7 has been already configured
|
185
|
+
opt.ionospheric_models[i] = options_t::IONOSPHERIC_SKIP;
|
186
|
+
continue;
|
187
|
+
case options_t::IONOSPHERIC_SKIP:
|
188
|
+
continue;
|
189
|
+
}
|
190
|
+
available_models++;
|
191
|
+
}
|
192
|
+
|
193
|
+
return available_models;
|
194
|
+
}
|
195
|
+
|
196
|
+
options_t available_options() const {
|
197
|
+
return options_t(base_t::available_options(), _options);
|
198
|
+
}
|
199
|
+
|
200
|
+
options_t available_options(const options_t &opt_wish) const {
|
201
|
+
GPS_SinglePositioning_Options<float_t> opt(opt_wish);
|
202
|
+
filter_ionospheric_models(opt);
|
203
|
+
return options_t(base_t::available_options(opt_wish), opt);
|
204
|
+
}
|
205
|
+
|
206
|
+
options_t update_options(const options_t &opt_wish){
|
207
|
+
filter_ionospheric_models(_options = opt_wish);
|
208
|
+
return options_t(base_t::update_options(opt_wish), _options);
|
209
|
+
}
|
210
|
+
|
211
|
+
GPS_SinglePositioning(const space_node_t &sn)
|
212
|
+
: base_t(), _space_node(sn), _options() {
|
213
|
+
filter_ionospheric_models(_options);
|
214
|
+
}
|
215
|
+
|
216
|
+
~GPS_SinglePositioning(){}
|
217
|
+
|
218
|
+
struct residual_t {
|
219
|
+
float_t &residual;
|
220
|
+
float_t &los_neg_x;
|
221
|
+
float_t &los_neg_y;
|
222
|
+
float_t &los_neg_z;
|
223
|
+
float_t &weight;
|
224
|
+
};
|
225
|
+
|
226
|
+
/**
|
227
|
+
* Get corrected range in accordance with current status
|
228
|
+
*
|
229
|
+
* @param sat satellite
|
230
|
+
* @param range "corrected" pseudo range subtracted by (temporal solution of) receiver clock error in meter
|
231
|
+
* @param time_arrival time when signal arrive at receiver
|
232
|
+
* @param usr_pos (temporal solution of) user position
|
233
|
+
* @param residual calculated residual with line of site vector, and weight;
|
234
|
+
* When weight is equal to or less than zero, the calculated results should not be used.
|
235
|
+
* @param error Some correction can be overwritten. If its unknown_flag is zero,
|
236
|
+
* corrections will be skipped as possible. @see range_errors_t
|
237
|
+
* @return (float_t) corrected range just including delay, and excluding receiver/satellite error.
|
238
|
+
*/
|
239
|
+
float_t range_corrected(
|
240
|
+
const satellite_t &sat,
|
241
|
+
float_t range,
|
242
|
+
const gps_time_t &time_arrival,
|
243
|
+
const pos_t &usr_pos,
|
244
|
+
residual_t &residual,
|
245
|
+
const range_error_t &error = range_error_t::not_corrected) const {
|
246
|
+
|
247
|
+
// Clock error correction
|
248
|
+
range += ((error.unknown_flag & range_error_t::SATELLITE_CLOCK)
|
249
|
+
? (sat.clock_error(time_arrival, range) * space_node_t::light_speed)
|
250
|
+
: error.value[range_error_t::SATELLITE_CLOCK]);
|
251
|
+
|
252
|
+
// Calculate satellite position
|
253
|
+
xyz_t sat_pos(sat.position(time_arrival, range));
|
254
|
+
float_t geometric_range(usr_pos.xyz.dist(sat_pos));
|
255
|
+
|
256
|
+
// Calculate residual
|
257
|
+
residual.residual = range - geometric_range;
|
258
|
+
|
259
|
+
// Setup design matrix
|
260
|
+
residual.los_neg_x = -(sat_pos.x() - usr_pos.xyz.x()) / geometric_range;
|
261
|
+
residual.los_neg_y = -(sat_pos.y() - usr_pos.xyz.y()) / geometric_range;
|
262
|
+
residual.los_neg_z = -(sat_pos.z() - usr_pos.xyz.z()) / geometric_range;
|
263
|
+
|
264
|
+
enu_t relative_pos(enu_t::relative(sat_pos, usr_pos.xyz));
|
265
|
+
|
266
|
+
if(error.unknown_flag & range_error_t::MASK_IONOSPHERIC){
|
267
|
+
// Ionospheric model selection, the fall back is no correction
|
268
|
+
bool iono_model_hit(false);
|
269
|
+
for(int i(0); i < sizeof(_options.ionospheric_models) / sizeof(_options.ionospheric_models[0]); ++i){
|
270
|
+
switch(_options.ionospheric_models[i]){
|
271
|
+
case options_t::IONOSPHERIC_KLOBUCHAR:
|
272
|
+
residual.residual += _space_node.iono_correction(relative_pos, usr_pos.llh, time_arrival);
|
273
|
+
break;
|
274
|
+
case options_t::IONOSPHERIC_NTCM_GL: {
|
275
|
+
// TODO f_10_7 setup, optimization (mag_model etc.)
|
276
|
+
typename space_node_t::pierce_point_res_t pp(_space_node.pierce_point(relative_pos, usr_pos.llh));
|
277
|
+
residual.residual -= space_node_t::tec2delay(
|
278
|
+
_space_node.slant_factor(relative_pos)
|
279
|
+
* NTCM_GL_Generic<float_t>::tec_vert(
|
280
|
+
pp.latitude, pp.longitude,
|
281
|
+
time_arrival.year(), _options.f_10_7));
|
282
|
+
break;
|
283
|
+
}
|
284
|
+
case options_t::IONOSPHERIC_NONE:
|
285
|
+
break;
|
286
|
+
default:
|
287
|
+
continue;
|
288
|
+
}
|
289
|
+
iono_model_hit = true;
|
290
|
+
break;
|
291
|
+
}
|
292
|
+
}else{
|
293
|
+
residual.residual += error.value[range_error_t::IONOSPHERIC];
|
294
|
+
}
|
295
|
+
|
296
|
+
// Tropospheric
|
297
|
+
residual.residual += (error.unknown_flag & range_error_t::MASK_TROPOSPHERIC)
|
298
|
+
? _space_node.tropo_correction(relative_pos, usr_pos.llh)
|
299
|
+
: error.value[range_error_t::TROPOSPHERIC];
|
300
|
+
|
301
|
+
// Setup weight
|
302
|
+
if(std::abs(residual.residual) > _options.residual_mask){
|
303
|
+
// If residual is too big, gently exclude it by decreasing its weight.
|
304
|
+
residual.weight = 1E-8;
|
305
|
+
}else{
|
306
|
+
|
307
|
+
float_t elv(relative_pos.elevation());
|
308
|
+
if(elv < _options.elevation_mask){
|
309
|
+
residual.weight = 0; // exclude it when elevation is less than threshold
|
310
|
+
}else{
|
311
|
+
/* elevation weight based on "GPS���p�v���O���~���O"
|
312
|
+
* elevation[deg] : 90 53 45 30 15 10 5
|
313
|
+
* sigma(s) : 0.80 1.00 1.13 1.60 3.09 4.61 9.18
|
314
|
+
* weight(s^-2) : 1.56 1.00 0.78 0.39 0.10 0.05 0.01
|
315
|
+
*/
|
316
|
+
residual.weight = std::pow(sin(elv)/0.8, 2); // weight=1 @ elv=53[deg]
|
317
|
+
if(residual.weight < 1E-3){residual.weight = 1E-3;}
|
318
|
+
}
|
319
|
+
}
|
320
|
+
|
321
|
+
return range;
|
322
|
+
}
|
323
|
+
|
324
|
+
/**
|
325
|
+
* Get relative rate (negative polarity) in accordance with current status
|
326
|
+
*
|
327
|
+
* @param sat satellite
|
328
|
+
* @param range "corrected" pseudo range subtracted by (temporal solution of) receiver clock error in meter
|
329
|
+
* @param time_arrival time when signal arrive at receiver
|
330
|
+
* @param usr_vel (temporal solution of) user velocity
|
331
|
+
* @param los_neg_x line of site X
|
332
|
+
* @param los_neg_y line of site Y
|
333
|
+
* @param los_neg_z line of site Z
|
334
|
+
* @return (float_t) relative rate.
|
335
|
+
*/
|
336
|
+
float_t rate_relative_neg(
|
337
|
+
const satellite_t &sat,
|
338
|
+
const float_t &range,
|
339
|
+
const gps_time_t &time_arrival,
|
340
|
+
const xyz_t &usr_vel,
|
341
|
+
const float_t &los_neg_x, const float_t &los_neg_y, const float_t &los_neg_z) const {
|
342
|
+
|
343
|
+
xyz_t rel_vel(sat.velocity(time_arrival, range) - usr_vel); // Calculate velocity
|
344
|
+
return los_neg_x * rel_vel.x()
|
345
|
+
+ los_neg_y * rel_vel.y()
|
346
|
+
+ los_neg_z * rel_vel.z()
|
347
|
+
+ sat.clock_error_dot(time_arrival, range) * space_node_t::light_speed; // considering clock rate error
|
348
|
+
}
|
349
|
+
|
350
|
+
/**
|
351
|
+
* Check availability of a satellite with which observation is associated
|
352
|
+
*
|
353
|
+
* @param prn satellite number
|
354
|
+
* @param receiver_time receiver time
|
355
|
+
* @return (const satellite_t *) If available, const pointer to satellite is returned,
|
356
|
+
* otherwise NULL.
|
357
|
+
*/
|
358
|
+
const satellite_t *is_available(
|
359
|
+
const typename space_node_t::satellites_t::key_type &prn,
|
360
|
+
const gps_time_t &receiver_time) const {
|
361
|
+
|
362
|
+
if(_options.exclude_prn[prn]){return NULL;}
|
363
|
+
|
364
|
+
const typename space_node_t::satellites_t &sats(_space_node.satellites());
|
365
|
+
const typename space_node_t::satellites_t::const_iterator it_sat(sats.find(prn));
|
366
|
+
if((it_sat == sats.end()) // has ephemeris?
|
367
|
+
|| (!it_sat->second.ephemeris().is_valid(receiver_time))){ // valid ephemeris?
|
368
|
+
return NULL;
|
369
|
+
}
|
370
|
+
|
371
|
+
return &(it_sat->second);
|
372
|
+
}
|
373
|
+
|
374
|
+
/**
|
375
|
+
* Calculate relative range and rate information to a satellite
|
376
|
+
*
|
377
|
+
* @param prn satellite number
|
378
|
+
* @param measurement measurement (per satellite) containing pseudo range
|
379
|
+
* @param receiver_error (temporal solution of) receiver clock error in meter
|
380
|
+
* @param time_arrival time when signal arrive at receiver
|
381
|
+
* @param usr_pos (temporal solution of) user position
|
382
|
+
* @param usr_vel (temporal solution of) user velocity
|
383
|
+
* @return (relative_property_t) relative information
|
384
|
+
*/
|
385
|
+
relative_property_t relative_property(
|
386
|
+
const prn_t &prn,
|
387
|
+
const typename measurement_t::mapped_type &measurement,
|
388
|
+
const float_t &receiver_error,
|
389
|
+
const gps_time_t &time_arrival,
|
390
|
+
const pos_t &usr_pos,
|
391
|
+
const xyz_t &usr_vel) const {
|
392
|
+
|
393
|
+
relative_property_t res = {0};
|
394
|
+
|
395
|
+
float_t range;
|
396
|
+
range_error_t range_error;
|
397
|
+
if(!this->range(measurement, range, &range_error)){
|
398
|
+
return res; // If no range entry, return with weight = 0
|
399
|
+
}
|
400
|
+
|
401
|
+
const satellite_t *sat(is_available(prn, time_arrival));
|
402
|
+
if(!sat){return res;} // If satellite is unavailable, return with weight = 0
|
403
|
+
|
404
|
+
residual_t residual = {
|
405
|
+
res.range_residual,
|
406
|
+
res.los_neg[0], res.los_neg[1], res.los_neg[2],
|
407
|
+
res.weight,
|
408
|
+
};
|
409
|
+
|
410
|
+
res.range_corrected = range_corrected(
|
411
|
+
*sat, range - receiver_error, time_arrival,
|
412
|
+
usr_pos, residual, range_error);
|
413
|
+
res.rate_relative_neg = rate_relative_neg(*sat, res.range_corrected, time_arrival, usr_vel,
|
414
|
+
res.los_neg[0], res.los_neg[1], res.los_neg[2]);
|
415
|
+
|
416
|
+
return res;
|
417
|
+
|
418
|
+
}
|
419
|
+
|
420
|
+
/**
|
421
|
+
* Calculate User position/velocity with hint
|
422
|
+
* This is optimized version for GPS-only constellation
|
423
|
+
*
|
424
|
+
* @param res (out) calculation results and matrices used for calculation
|
425
|
+
* @param measurement PRN, pseudo-range, pseudo-range rate information
|
426
|
+
* @param receiver_time receiver time at measurement
|
427
|
+
* @param user_position_init initial solution of user position in XYZ meters and LLH
|
428
|
+
* @param receiver_error_init initial solution of receiver clock error in meters
|
429
|
+
* @param good_init if true, initial position and clock error are goodly guessed.
|
430
|
+
* @param with_velocity if true, perform velocity estimation.
|
431
|
+
* @see update_ephemeris(), register_ephemeris
|
432
|
+
*/
|
433
|
+
void user_pvt(
|
434
|
+
user_pvt_t &res,
|
435
|
+
const measurement_t &measurement,
|
436
|
+
const gps_time_t &receiver_time,
|
437
|
+
const pos_t &user_position_init,
|
438
|
+
const float_t &receiver_error_init,
|
439
|
+
const bool &good_init = true,
|
440
|
+
const bool &with_velocity = true) const {
|
441
|
+
|
442
|
+
res.receiver_time = receiver_time;
|
443
|
+
|
444
|
+
if(_options.count_ionospheric_models() == 0){
|
445
|
+
res.error_code = user_pvt_t::ERROR_INVALID_IONO_MODEL;
|
446
|
+
return;
|
447
|
+
}
|
448
|
+
|
449
|
+
typename base_t::measurement2_t measurement2;
|
450
|
+
measurement2.reserve(measurement.size());
|
451
|
+
for(typename measurement_t::const_iterator it(measurement.begin()), it_end(measurement.end());
|
452
|
+
it != it_end; ++it){
|
453
|
+
|
454
|
+
float_t range;
|
455
|
+
if(!this->range(it->second, range)){continue;} // No range entry
|
456
|
+
|
457
|
+
if(!is_available(it->first, receiver_time)){continue;} // No satellite
|
458
|
+
|
459
|
+
typename base_t::measurement2_t::value_type v = {
|
460
|
+
it->first, &(it->second), this}; // prn, measurement, solver
|
461
|
+
measurement2.push_back(v);
|
462
|
+
}
|
463
|
+
base_t::user_pvt(
|
464
|
+
res,
|
465
|
+
measurement2, receiver_time, user_position_init, receiver_error_init,
|
466
|
+
typename base_t::user_pvt_opt_t(good_init, with_velocity));
|
467
|
+
}
|
468
|
+
|
469
|
+
xyz_t *satellite_position(
|
470
|
+
const prn_t &prn,
|
471
|
+
const gps_time_t &time,
|
472
|
+
xyz_t &res) const {
|
473
|
+
|
474
|
+
const satellite_t *sat(is_available(prn, time));
|
475
|
+
return sat ? &(res = sat->position(time)) : NULL;
|
476
|
+
}
|
477
|
+
};
|
478
|
+
|
479
|
+
#endif /* __GPS_SOLVER_H__ */
|