gps_pvt 0.1.7 → 0.2.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 +13 -2
- data/Rakefile +2 -0
- data/exe/gps_pvt +32 -23
- data/ext/gps_pvt/Coordinate/Coordinate_wrap.cxx +5 -3
- data/ext/gps_pvt/GPS/GPS_wrap.cxx +4444 -671
- data/ext/gps_pvt/SylphideMath/SylphideMath_wrap.cxx +284 -19
- data/ext/ninja-scan-light/tool/navigation/GPS.h +12 -46
- data/ext/ninja-scan-light/tool/navigation/GPS_Solver.h +61 -100
- data/ext/ninja-scan-light/tool/navigation/GPS_Solver_Base.h +87 -25
- data/ext/ninja-scan-light/tool/navigation/QZSS.h +62 -0
- data/ext/ninja-scan-light/tool/navigation/RINEX.h +335 -27
- data/ext/ninja-scan-light/tool/navigation/SBAS.h +2330 -0
- data/ext/ninja-scan-light/tool/navigation/SBAS_Solver.h +306 -0
- data/ext/ninja-scan-light/tool/param/bit_array.h +4 -3
- data/ext/ninja-scan-light/tool/swig/GPS.i +429 -138
- data/ext/ninja-scan-light/tool/swig/SylphideMath.i +53 -6
- data/ext/ninja-scan-light/tool/swig/spec/GPS_spec.rb +37 -6
- data/ext/ninja-scan-light/tool/swig/spec/SylphideMath_spec.rb +38 -4
- data/gps_pvt.gemspec +63 -0
- data/lib/gps_pvt/receiver.rb +281 -140
- data/lib/gps_pvt/version.rb +1 -1
- metadata +7 -3
@@ -405,11 +405,12 @@ struct GPS_Time {
|
|
405
405
|
}
|
406
406
|
|
407
407
|
// process remaining 4 years
|
408
|
-
int
|
408
|
+
int doy[] = {
|
409
409
|
leap_year ? 366 : 365,
|
410
410
|
365, 365, 365,
|
411
411
|
is_leap_year(year + 4) ? 366 : 365,
|
412
412
|
};
|
413
|
+
std::size_t doy_i(0);
|
413
414
|
for(; doy_i < sizeof(doy) / sizeof(doy[0]); ++doy_i){
|
414
415
|
if(days <= doy[doy_i]){break;}
|
415
416
|
days -= doy[doy_i];
|
@@ -525,6 +526,9 @@ class GPS_SpaceNode {
|
|
525
526
|
return res;
|
526
527
|
}
|
527
528
|
static const float_t gamma_L1_L2;
|
529
|
+
static const float_t gamma_per_L1(const float_t &freq){
|
530
|
+
return std::pow(L1_Frequency / freq, 2);
|
531
|
+
}
|
528
532
|
|
529
533
|
protected:
|
530
534
|
static float_t rad2sc(const float_t &rad) {return rad / M_PI;}
|
@@ -2051,6 +2055,7 @@ if(std::abs(TARGET - eph.TARGET) > raw_t::sf[raw_t::SF_ ## TARGET]){break;}
|
|
2051
2055
|
* @param height_over_ellipsoid
|
2052
2056
|
* @see spherically single layer approach, for example,
|
2053
2057
|
* Eq.(3) of "Ionospheric Range Error Correction Models" by N. Jakowski
|
2058
|
+
* @see DO-229D A4.4.10.4 Eq.(A-42) is equivalent
|
2054
2059
|
*/
|
2055
2060
|
static float_t slant_factor(
|
2056
2061
|
const enu_t &relative_pos,
|
@@ -2089,8 +2094,7 @@ if(std::abs(TARGET - eph.TARGET) > raw_t::sf[raw_t::SF_ ## TARGET]){break;}
|
|
2089
2094
|
// Elevation and azimuth
|
2090
2095
|
float_t el(relative_pos.elevation()),
|
2091
2096
|
az(relative_pos.azimuth());
|
2092
|
-
float_t sc_el(rad2sc(el))
|
2093
|
-
sc_az(rad2sc(az));
|
2097
|
+
float_t sc_el(rad2sc(el));
|
2094
2098
|
|
2095
2099
|
// Pierce point (PP stands for the earth projection of the Pierce point)
|
2096
2100
|
// (the following equation is based on GPS ICD)
|
@@ -2150,37 +2154,17 @@ if(std::abs(TARGET - eph.TARGET) > raw_t::sf[raw_t::SF_ ## TARGET]){break;}
|
|
2150
2154
|
usr.llh(),
|
2151
2155
|
t);
|
2152
2156
|
}
|
2153
|
-
|
2154
|
-
struct IonospericCorrection {
|
2155
|
-
const GPS_SpaceNode<float_t> &space_node;
|
2156
|
-
float_t operator()(
|
2157
|
-
const enu_t &relative_pos,
|
2158
|
-
const llh_t &usrllh,
|
2159
|
-
const gps_time_t &t) const {
|
2160
|
-
return space_node.iono_correction(relative_pos, usrllh, t);
|
2161
|
-
}
|
2162
|
-
float_t operator()(
|
2163
|
-
const xyz_t &sat,
|
2164
|
-
const xyz_t &usr,
|
2165
|
-
const gps_time_t &t) const {
|
2166
|
-
return space_node.iono_correction(sat, usr, t);
|
2167
|
-
}
|
2168
|
-
};
|
2169
|
-
IonospericCorrection iono_correction() const {
|
2170
|
-
IonospericCorrection res = {*this};
|
2171
|
-
return res;
|
2172
|
-
}
|
2173
2157
|
|
2174
2158
|
/**
|
2175
|
-
* Calculate correction value in accordance with tropospheric model
|
2159
|
+
* Calculate correction value in accordance with tropospheric Hopfield model
|
2176
2160
|
*
|
2177
2161
|
* @param relative_pos satellite position (relative position, NEU)
|
2178
2162
|
* @param usrllh user position (absolute position, LLH)
|
2179
2163
|
* @return correction in meters
|
2180
2164
|
*/
|
2181
|
-
float_t tropo_correction(
|
2165
|
+
static float_t tropo_correction(
|
2182
2166
|
const enu_t &relative_pos,
|
2183
|
-
const llh_t &usrllh)
|
2167
|
+
const llh_t &usrllh){
|
2184
2168
|
|
2185
2169
|
// Elevation (rad)
|
2186
2170
|
float_t el(relative_pos.elevation());
|
@@ -2290,31 +2274,13 @@ if(std::abs(TARGET - eph.TARGET) > raw_t::sf[raw_t::SF_ ## TARGET]){break;}
|
|
2290
2274
|
* @param usr user position (absolute position, XYZ)
|
2291
2275
|
* @return correction in meters
|
2292
2276
|
*/
|
2293
|
-
float_t tropo_correction(
|
2277
|
+
static float_t tropo_correction(
|
2294
2278
|
const xyz_t &sat,
|
2295
|
-
const xyz_t &usr)
|
2279
|
+
const xyz_t &usr) {
|
2296
2280
|
return tropo_correction(
|
2297
2281
|
enu_t::relative(sat, usr),
|
2298
2282
|
usr.llh());
|
2299
2283
|
}
|
2300
|
-
|
2301
|
-
struct TropospericCorrection {
|
2302
|
-
const GPS_SpaceNode<float_t> &space_node;
|
2303
|
-
float_t operator()(
|
2304
|
-
const enu_t &relative_pos,
|
2305
|
-
const llh_t &usrllh) const {
|
2306
|
-
return space_node.tropo_correction(relative_pos, usrllh);
|
2307
|
-
}
|
2308
|
-
float_t operator()(
|
2309
|
-
const xyz_t &sat,
|
2310
|
-
const xyz_t &usr) const {
|
2311
|
-
return space_node.tropo_correction(sat, usr);
|
2312
|
-
}
|
2313
|
-
};
|
2314
|
-
TropospericCorrection tropo_correction() const {
|
2315
|
-
TropospericCorrection res = {*this};
|
2316
|
-
return res;
|
2317
|
-
}
|
2318
2284
|
};
|
2319
2285
|
|
2320
2286
|
template <class FloatT>
|
@@ -43,6 +43,7 @@
|
|
43
43
|
#include <exception>
|
44
44
|
|
45
45
|
#include <cmath>
|
46
|
+
#include <cstddef>
|
46
47
|
|
47
48
|
#include "param/bit_array.h"
|
48
49
|
|
@@ -55,49 +56,10 @@ struct GPS_Solver_GeneralOptions {
|
|
55
56
|
FloatT elevation_mask;
|
56
57
|
FloatT residual_mask;
|
57
58
|
|
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
59
|
GPS_Solver_GeneralOptions()
|
78
60
|
: elevation_mask(0), // elevation mask default is 0 [deg]
|
79
|
-
residual_mask(30)
|
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
|
-
}
|
61
|
+
residual_mask(30) { // range residual mask is 30 [m]
|
87
62
|
|
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
63
|
}
|
102
64
|
};
|
103
65
|
|
@@ -145,6 +107,8 @@ class GPS_SinglePositioning : public SolverBaseT {
|
|
145
107
|
typedef typename base_t::measurement_t measurement_t;
|
146
108
|
inheritate_type(measurement_items_t);
|
147
109
|
typedef typename base_t::range_error_t range_error_t;
|
110
|
+
typedef typename base_t::range_corrector_t range_corrector_t;
|
111
|
+
typedef typename base_t::range_correction_t range_correction_t;
|
148
112
|
|
149
113
|
inheritate_type(relative_property_t);
|
150
114
|
inheritate_type(geometric_matrices_t);
|
@@ -161,37 +125,50 @@ class GPS_SinglePositioning : public SolverBaseT {
|
|
161
125
|
public:
|
162
126
|
const space_node_t &space_node() const {return _space_node;}
|
163
127
|
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
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++;
|
128
|
+
struct klobuchar_t : public range_corrector_t {
|
129
|
+
const space_node_t &space_node;
|
130
|
+
klobuchar_t(const space_node_t &sn) : range_corrector_t(), space_node(sn) {}
|
131
|
+
bool is_available(const gps_time_t &t) const {
|
132
|
+
return space_node.is_valid_iono();
|
133
|
+
}
|
134
|
+
float_t *calculate(
|
135
|
+
const gps_time_t &t, const pos_t &usr_pos, const enu_t &sat_rel_pos,
|
136
|
+
float_t &buf) const {
|
137
|
+
return &(buf = space_node.iono_correction(sat_rel_pos, usr_pos.llh, t));
|
191
138
|
}
|
139
|
+
} ionospheric_klobuchar;
|
192
140
|
|
193
|
-
|
194
|
-
|
141
|
+
struct ntcm_gl_t : public range_corrector_t {
|
142
|
+
float_t f_10_7;
|
143
|
+
ntcm_gl_t() : range_corrector_t(), f_10_7(-1) {}
|
144
|
+
bool is_available(const gps_time_t &t) const {
|
145
|
+
return f_10_7 >= 0;
|
146
|
+
}
|
147
|
+
float_t *calculate(
|
148
|
+
const gps_time_t &t, const pos_t &usr_pos, const enu_t &sat_rel_pos,
|
149
|
+
float_t &buf) const {
|
150
|
+
if(!is_available(t)){return NULL;}
|
151
|
+
typename space_node_t::pierce_point_res_t pp(
|
152
|
+
space_node_t::pierce_point(sat_rel_pos, usr_pos.llh));
|
153
|
+
return &(buf = -space_node_t::tec2delay(space_node_t::slant_factor(sat_rel_pos)
|
154
|
+
* NTCM_GL_Generic<float_t>::tec_vert(
|
155
|
+
pp.latitude, pp.longitude, t.year(), f_10_7)));
|
156
|
+
}
|
157
|
+
} ionospheric_ntcm_gl;
|
158
|
+
|
159
|
+
struct tropospheric_simplified_t : public range_corrector_t {
|
160
|
+
tropospheric_simplified_t() : range_corrector_t() {}
|
161
|
+
bool is_available(const gps_time_t &t) const {
|
162
|
+
return true;
|
163
|
+
}
|
164
|
+
float_t *calculate(
|
165
|
+
const gps_time_t &t, const pos_t &usr_pos, const enu_t &sat_rel_pos,
|
166
|
+
float_t &buf) const {
|
167
|
+
return &(buf = space_node_t::tropo_correction(sat_rel_pos, usr_pos.llh));
|
168
|
+
}
|
169
|
+
} tropospheric_simplified;
|
170
|
+
|
171
|
+
range_correction_t ionospheric_correction, tropospheric_correction;
|
195
172
|
|
196
173
|
options_t available_options() const {
|
197
174
|
return options_t(base_t::available_options(), _options);
|
@@ -199,18 +176,26 @@ class GPS_SinglePositioning : public SolverBaseT {
|
|
199
176
|
|
200
177
|
options_t available_options(const options_t &opt_wish) const {
|
201
178
|
GPS_SinglePositioning_Options<float_t> opt(opt_wish);
|
202
|
-
filter_ionospheric_models(opt);
|
203
179
|
return options_t(base_t::available_options(opt_wish), opt);
|
204
180
|
}
|
205
181
|
|
206
182
|
options_t update_options(const options_t &opt_wish){
|
207
|
-
|
183
|
+
_options = opt_wish;
|
208
184
|
return options_t(base_t::update_options(opt_wish), _options);
|
209
185
|
}
|
210
186
|
|
211
187
|
GPS_SinglePositioning(const space_node_t &sn)
|
212
|
-
: base_t(), _space_node(sn), _options()
|
213
|
-
|
188
|
+
: base_t(), _space_node(sn), _options(available_options(options_t())),
|
189
|
+
ionospheric_klobuchar(sn), ionospheric_ntcm_gl(),
|
190
|
+
tropospheric_simplified(),
|
191
|
+
ionospheric_correction(), tropospheric_correction() {
|
192
|
+
|
193
|
+
// default ionospheric correction:
|
194
|
+
// Broadcasted Klobuchar parameters are at least required for solution.
|
195
|
+
ionospheric_correction.push_front(&ionospheric_klobuchar);
|
196
|
+
|
197
|
+
// default troposheric correction: simplified
|
198
|
+
tropospheric_correction.push_front(&tropospheric_simplified);
|
214
199
|
}
|
215
200
|
|
216
201
|
~GPS_SinglePositioning(){}
|
@@ -264,38 +249,14 @@ class GPS_SinglePositioning : public SolverBaseT {
|
|
264
249
|
enu_t relative_pos(enu_t::relative(sat_pos, usr_pos.xyz));
|
265
250
|
|
266
251
|
if(error.unknown_flag & range_error_t::MASK_IONOSPHERIC){
|
267
|
-
|
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
|
-
}
|
252
|
+
residual.residual += ionospheric_correction(time_arrival, usr_pos, relative_pos);
|
292
253
|
}else{
|
293
254
|
residual.residual += error.value[range_error_t::IONOSPHERIC];
|
294
255
|
}
|
295
256
|
|
296
257
|
// Tropospheric
|
297
258
|
residual.residual += (error.unknown_flag & range_error_t::MASK_TROPOSPHERIC)
|
298
|
-
?
|
259
|
+
? tropospheric_correction(time_arrival, usr_pos, relative_pos)
|
299
260
|
: error.value[range_error_t::TROPOSPHERIC];
|
300
261
|
|
301
262
|
// Setup weight
|
@@ -441,7 +402,7 @@ class GPS_SinglePositioning : public SolverBaseT {
|
|
441
402
|
|
442
403
|
res.receiver_time = receiver_time;
|
443
404
|
|
444
|
-
if(
|
405
|
+
if(!ionospheric_correction.select(receiver_time)){
|
445
406
|
res.error_code = user_pvt_t::ERROR_INVALID_IONO_MODEL;
|
446
407
|
return;
|
447
408
|
}
|
@@ -38,6 +38,8 @@
|
|
38
38
|
#include <vector>
|
39
39
|
#include <map>
|
40
40
|
#include <utility>
|
41
|
+
#include <deque>
|
42
|
+
#include <algorithm>
|
41
43
|
|
42
44
|
#include <cmath>
|
43
45
|
#include <cstring>
|
@@ -101,6 +103,7 @@ struct GPS_Solver_Base {
|
|
101
103
|
L1_RANGE_RATE_SIGMA,
|
102
104
|
L1_SIGNAL_STRENGTH_dBHz,
|
103
105
|
L1_LOCK_SEC,
|
106
|
+
L1_FREQUENCY,
|
104
107
|
MEASUREMENT_ITEMS_PREDEFINED,
|
105
108
|
};
|
106
109
|
};
|
@@ -202,9 +205,9 @@ struct GPS_Solver_Base {
|
|
202
205
|
virtual const float_t *rate(
|
203
206
|
const typename measurement_t::mapped_type &values, float_t &buf) const {
|
204
207
|
const float_t *res;
|
205
|
-
if(res = find_value(values, measurement_items_t::L1_RANGE_RATE, buf)){
|
208
|
+
if((res = find_value(values, measurement_items_t::L1_RANGE_RATE, buf))){
|
206
209
|
|
207
|
-
}else if(res = find_value(values, measurement_items_t::L1_DOPPLER, buf)){
|
210
|
+
}else if((res = find_value(values, measurement_items_t::L1_DOPPLER, buf))){
|
208
211
|
// Fall back to doppler
|
209
212
|
buf *= -space_node_t::L1_WaveLength();
|
210
213
|
}
|
@@ -214,15 +217,62 @@ struct GPS_Solver_Base {
|
|
214
217
|
virtual const float_t *rate_sigma(
|
215
218
|
const typename measurement_t::mapped_type &values, float_t &buf) const {
|
216
219
|
const float_t *res;
|
217
|
-
if(res = find_value(values, measurement_items_t::L1_RANGE_RATE_SIGMA, buf)){
|
220
|
+
if((res = find_value(values, measurement_items_t::L1_RANGE_RATE_SIGMA, buf))){
|
218
221
|
|
219
|
-
}else if(res = find_value(values, measurement_items_t::L1_DOPPLER_SIGMA, buf)){
|
222
|
+
}else if((res = find_value(values, measurement_items_t::L1_DOPPLER_SIGMA, buf))){
|
220
223
|
// Fall back to doppler
|
221
224
|
buf *= space_node_t::L1_WaveLength();
|
222
225
|
}
|
223
226
|
return res;
|
224
227
|
}
|
225
228
|
|
229
|
+
struct range_corrector_t {
|
230
|
+
virtual ~range_corrector_t() {}
|
231
|
+
virtual bool is_available(const gps_time_t &t) const {
|
232
|
+
return false;
|
233
|
+
}
|
234
|
+
virtual float_t *calculate(
|
235
|
+
const gps_time_t &t, const pos_t &usr_pos, const enu_t &sat_rel_pos,
|
236
|
+
float_t &buf) const = 0;
|
237
|
+
};
|
238
|
+
static const struct no_correction_t : public range_corrector_t {
|
239
|
+
bool is_available(const gps_time_t &t) const {
|
240
|
+
return true;
|
241
|
+
}
|
242
|
+
float_t *calculate(
|
243
|
+
const gps_time_t &t, const pos_t &usr_pos, const enu_t &sat_rel_pos,
|
244
|
+
float_t &buf) const {
|
245
|
+
return &(buf = 0);
|
246
|
+
}
|
247
|
+
} no_correction;
|
248
|
+
struct range_correction_t : public std::deque<const range_corrector_t *> {
|
249
|
+
typedef std::deque<const range_corrector_t *> super_t;
|
250
|
+
range_correction_t() : super_t() {}
|
251
|
+
const range_corrector_t *select(const gps_time_t &t) const {
|
252
|
+
for(typename super_t::const_iterator it(super_t::begin()), it_end(super_t::end());
|
253
|
+
it != it_end; ++it){
|
254
|
+
if((*it)->is_available(t)){return *it;}
|
255
|
+
}
|
256
|
+
return NULL;
|
257
|
+
}
|
258
|
+
float_t operator()(
|
259
|
+
const gps_time_t &t, const pos_t &usr_pos, const enu_t &sat_rel_pos) const {
|
260
|
+
float_t res;
|
261
|
+
for(typename super_t::const_iterator it(super_t::begin()), it_end(super_t::end());
|
262
|
+
it != it_end; ++it){
|
263
|
+
if((*it)->calculate(t, usr_pos, sat_rel_pos, res)){return res;}
|
264
|
+
}
|
265
|
+
return 0;
|
266
|
+
}
|
267
|
+
void remove(const typename super_t::value_type &v){
|
268
|
+
std::remove(super_t::begin(), super_t::end(), v);
|
269
|
+
}
|
270
|
+
void add(const typename super_t::value_type &v){
|
271
|
+
remove(v);
|
272
|
+
super_t::push_front(v);
|
273
|
+
}
|
274
|
+
};
|
275
|
+
|
226
276
|
/**
|
227
277
|
* Select appropriate solver, this is provision for GNSS extension
|
228
278
|
* @param prn satellite number
|
@@ -308,8 +358,9 @@ struct GPS_Solver_Base {
|
|
308
358
|
case ERROR_VELOCITY_INSUFFICIENT_SATELLITES:
|
309
359
|
case ERROR_VELOCITY_LS:
|
310
360
|
return true;
|
361
|
+
default:
|
362
|
+
return false;
|
311
363
|
}
|
312
|
-
return false;
|
313
364
|
}
|
314
365
|
bool velocity_solved() const {
|
315
366
|
return error_code == ERROR_NO;
|
@@ -394,10 +445,11 @@ protected:
|
|
394
445
|
* @return transformed design matrix G'
|
395
446
|
*/
|
396
447
|
static matrix_t rotate_G(const MatrixT &G_, const matrix_t &rotation_matrix){
|
397
|
-
|
398
|
-
res
|
399
|
-
|
400
|
-
|
448
|
+
unsigned int r(G_.rows()), c(G_.columns()); // Normally c=4
|
449
|
+
matrix_t res(r, c);
|
450
|
+
res.partial(r, 3).replace(
|
451
|
+
G_.partial(r, 3) * rotation_matrix.transpose());
|
452
|
+
res.partial(r, c - 3, 0, 3).replace(G_.partial(r, c - 3, 0, 3));
|
401
453
|
return res;
|
402
454
|
}
|
403
455
|
|
@@ -424,14 +476,16 @@ protected:
|
|
424
476
|
* @see rotate_G
|
425
477
|
*/
|
426
478
|
static matrix_t rotate_C(const matrix_t &C, const matrix_t &rotation_matrix){
|
427
|
-
|
479
|
+
unsigned int n(C.rows()); // Normally n=4
|
480
|
+
matrix_t res(n, n);
|
428
481
|
res.partial(3, 3).replace( // upper left
|
429
482
|
rotation_matrix * C.partial(3, 3) * rotation_matrix.transpose());
|
430
|
-
res.partial(3,
|
431
|
-
rotation_matrix * C.partial(3,
|
432
|
-
res.partial(
|
433
|
-
C.partial(
|
434
|
-
res(3,
|
483
|
+
res.partial(3, n - 3, 0, 3).replace( // upper right
|
484
|
+
rotation_matrix * C.partial(3, n - 3, 0, 3));
|
485
|
+
res.partial(n - 3, 3, 3, 0).replace( // lower left
|
486
|
+
C.partial(n - 3, 3, 3, 0) * rotation_matrix.transpose());
|
487
|
+
res.partial(n - 3, n - 3, 3, 3).replace( // lower right
|
488
|
+
C.partial(n - 3, n - 3, 3, 3));
|
435
489
|
return res;
|
436
490
|
}
|
437
491
|
/**
|
@@ -469,11 +523,10 @@ protected:
|
|
469
523
|
* @see rotate_G
|
470
524
|
*/
|
471
525
|
static matrix_t rotate_S(const matrix_t &S, const matrix_t &rotation_matrix){
|
472
|
-
|
473
|
-
res
|
474
|
-
|
475
|
-
|
476
|
-
}
|
526
|
+
unsigned int r(S.rows()), c(S.columns()); // Normally r=4
|
527
|
+
matrix_t res(r, c);
|
528
|
+
res.partial(3, c).replace(rotation_matrix * S.partial(3, c));
|
529
|
+
res.partial(r - 3, c, 3, 0).replace(S.partial(r - 3, c, 3, 0));
|
477
530
|
return res;
|
478
531
|
}
|
479
532
|
/**
|
@@ -536,7 +589,7 @@ protected:
|
|
536
589
|
partial_t partial(unsigned int size) const {
|
537
590
|
if(size >= G.rows()){size = G.rows();}
|
538
591
|
return partial_t(
|
539
|
-
G.partial(size,
|
592
|
+
G.partial(size, G.columns()), W.partial(size, size), delta_r.partial(size, 1));
|
540
593
|
}
|
541
594
|
typedef linear_solver_t<typename MatrixT::circular_t> exclude_t;
|
542
595
|
exclude_t exclude(const unsigned int &row) const {
|
@@ -544,14 +597,16 @@ protected:
|
|
544
597
|
if(size >= 1){size--;}
|
545
598
|
// generate matrices having circular view
|
546
599
|
return exclude_t(
|
547
|
-
G.circular(offset, 0, size,
|
600
|
+
G.circular(offset, 0, size, G.columns()),
|
548
601
|
W.circular(offset, offset, size, size),
|
549
602
|
delta_r.circular(offset, 0, size, 1));
|
550
603
|
}
|
551
604
|
template <class MatrixT2>
|
552
605
|
void copy_G_W_row(const linear_solver_t<MatrixT2> &src,
|
553
606
|
const unsigned int &i_src, const unsigned int &i_dst){
|
554
|
-
|
607
|
+
unsigned int c_dst(G.columns()), c_src(src.G.columns()),
|
608
|
+
c(c_dst > c_src ? c_src : c_dst); // Normally c=4
|
609
|
+
for(unsigned int j(0); j < c; ++j){
|
555
610
|
G(i_dst, j) = src.G(i_src, j);
|
556
611
|
}
|
557
612
|
W(i_dst, i_dst) = src.W(i_src, i_src);
|
@@ -560,9 +615,12 @@ protected:
|
|
560
615
|
|
561
616
|
struct geometric_matrices_t : public linear_solver_t<matrix_t> {
|
562
617
|
typedef linear_solver_t<matrix_t> super_t;
|
563
|
-
geometric_matrices_t(
|
618
|
+
geometric_matrices_t(
|
619
|
+
const unsigned int &capacity,
|
620
|
+
const unsigned int &estimate_system_differences = 0)
|
564
621
|
: super_t(
|
565
|
-
matrix_t(capacity, 4
|
622
|
+
matrix_t(capacity, 4 + estimate_system_differences),
|
623
|
+
matrix_t(capacity, capacity), matrix_t(capacity, 1)) {
|
566
624
|
for(unsigned int i(0); i < capacity; ++i){
|
567
625
|
super_t::G(i, 3) = 1;
|
568
626
|
}
|
@@ -1035,6 +1093,10 @@ const typename GPS_Solver_Base<FloatT>::range_error_t
|
|
1035
1093
|
{0},
|
1036
1094
|
};
|
1037
1095
|
|
1096
|
+
template <class FloatT>
|
1097
|
+
const typename GPS_Solver_Base<FloatT>::no_correction_t
|
1098
|
+
GPS_Solver_Base<FloatT>::no_correction;
|
1099
|
+
|
1038
1100
|
template <class FloatT, class PVT_BaseT = typename GPS_Solver_Base<FloatT>::user_pvt_t>
|
1039
1101
|
struct GPS_PVT_Debug : public PVT_BaseT {
|
1040
1102
|
typename GPS_Solver_Base<FloatT>::matrix_t G, W, delta_r;
|
@@ -0,0 +1,62 @@
|
|
1
|
+
/*
|
2
|
+
* Copyright (c) 2021, M.Naruoka (fenrir)
|
3
|
+
* All rights reserved.
|
4
|
+
*
|
5
|
+
* Redistribution and use in source and binary forms, with or without modification,
|
6
|
+
* are permitted provided that the following conditions are met:
|
7
|
+
*
|
8
|
+
* - Redistributions of source code must retain the above copyright notice,
|
9
|
+
* this list of conditions and the following disclaimer.
|
10
|
+
* - Redistributions in binary form must reproduce the above copyright notice,
|
11
|
+
* this list of conditions and the following disclaimer in the documentation
|
12
|
+
* and/or other materials provided with the distribution.
|
13
|
+
* - Neither the name of the naruoka.org nor the names of its contributors
|
14
|
+
* may be used to endorse or promote products derived from this software
|
15
|
+
* without specific prior written permission.
|
16
|
+
*
|
17
|
+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
18
|
+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
19
|
+
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
20
|
+
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS
|
21
|
+
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
|
22
|
+
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
23
|
+
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
24
|
+
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
25
|
+
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
26
|
+
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
27
|
+
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
28
|
+
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
29
|
+
*
|
30
|
+
*/
|
31
|
+
|
32
|
+
#ifndef __QZSS_H__
|
33
|
+
#define __QZSS_H__
|
34
|
+
|
35
|
+
/** @file
|
36
|
+
* @brief QZSS ICD definitions
|
37
|
+
*/
|
38
|
+
|
39
|
+
#include "GPS.h"
|
40
|
+
#include <limits>
|
41
|
+
|
42
|
+
template <class FloatT>
|
43
|
+
struct QZSS_LNAV_Ephemeris_Raw : public GPS_SpaceNode<FloatT>::Satellite::Ephemeris::raw_t {
|
44
|
+
typedef typename GPS_SpaceNode<FloatT>::Satellite::Ephemeris eph_t;
|
45
|
+
typedef typename eph_t::raw_t super_t;
|
46
|
+
|
47
|
+
operator eph_t() const {
|
48
|
+
eph_t res(super_t::operator eph_t());
|
49
|
+
res.fit_interval = super_t::fit_interval_flag
|
50
|
+
? (std::numeric_limits<FloatT>::max)()
|
51
|
+
: (2 * 60 * 60); // Fit interval (ICD:4.1.2.4 Subframe 2); should be zero
|
52
|
+
return res;
|
53
|
+
};
|
54
|
+
|
55
|
+
QZSS_LNAV_Ephemeris_Raw &operator=(const eph_t &eph){
|
56
|
+
super_t::operator=(eph);
|
57
|
+
super_t::fit_interval_flag = (eph.fit_interval > 2 * 60 * 60);
|
58
|
+
return *this;
|
59
|
+
}
|
60
|
+
};
|
61
|
+
|
62
|
+
#endif /* __QZSS_H__ */
|