gps_pvt 0.1.7 → 0.2.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,306 @@
1
+ /**
2
+ * @file SBAS solver
3
+ *
4
+ */
5
+
6
+ /*
7
+ * Copyright (c) 2020, M.Naruoka (fenrir)
8
+ * All rights reserved.
9
+ *
10
+ * Redistribution and use in source and binary forms, with or without modification,
11
+ * are permitted provided that the following conditions are met:
12
+ *
13
+ * - Redistributions of source code must retain the above copyright notice,
14
+ * this list of conditions and the following disclaimer.
15
+ * - Redistributions in binary form must reproduce the above copyright notice,
16
+ * this list of conditions and the following disclaimer in the documentation
17
+ * and/or other materials provided with the distribution.
18
+ * - Neither the name of the naruoka.org nor the names of its contributors
19
+ * may be used to endorse or promote products derived from this software
20
+ * without specific prior written permission.
21
+ *
22
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
24
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS
26
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
27
+ * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
28
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
31
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
33
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34
+ *
35
+ */
36
+
37
+ #ifndef __SBAS_SOLVER_H__
38
+ #define __SBAS_SOLVER_H__
39
+
40
+ #include "SBAS.h"
41
+ #include "GPS_Solver_Base.h"
42
+ #include "GPS_Solver.h"
43
+
44
+ #include <cstddef>
45
+
46
+ template <class FloatT>
47
+ struct SBAS_SinglePositioning_Options : public GPS_Solver_GeneralOptions<FloatT> {
48
+ typedef GPS_Solver_GeneralOptions<FloatT> super_t;
49
+
50
+ typename GPS_Solver_Base<FloatT>::options_t::template exclude_prn_t<120, 158> exclude_prn; // SBAS PRN ranges from 120 to 158
51
+ SBAS_SinglePositioning_Options()
52
+ : super_t(), exclude_prn() {
53
+ exclude_prn.set(true); // SBAS ranging is default off.
54
+ }
55
+ };
56
+
57
+ template <class FloatT, class SolverBaseT = GPS_Solver_Base<FloatT> >
58
+ class SBAS_SinglePositioning : public SolverBaseT {
59
+ private:
60
+ SBAS_SinglePositioning<FloatT> &operator=(const SBAS_SinglePositioning<FloatT> &);
61
+ public:
62
+ typedef SBAS_SinglePositioning<FloatT> self_t;
63
+ typedef SolverBaseT base_t;
64
+
65
+ #if defined(__GNUC__) && (__GNUC__ < 5)
66
+ #define inheritate_type(x) typedef typename base_t::x x;
67
+ #else
68
+ #define inheritate_type(x) using typename base_t::x;
69
+ #endif
70
+
71
+ inheritate_type(float_t);
72
+ inheritate_type(prn_t);
73
+
74
+ typedef SBAS_SpaceNode<float_t> space_node_t;
75
+ inheritate_type(gps_time_t);
76
+ typedef typename space_node_t::Satellite satellite_t;
77
+
78
+ inheritate_type(xyz_t);
79
+ inheritate_type(enu_t);
80
+
81
+ inheritate_type(pos_t);
82
+
83
+ typedef typename base_t::measurement_t measurement_t;
84
+ typedef typename base_t::range_error_t range_error_t;
85
+ typedef typename base_t::range_corrector_t range_corrector_t;
86
+ typedef typename base_t::range_correction_t range_correction_t;
87
+
88
+ inheritate_type(relative_property_t);
89
+ #undef inheritate_type
90
+
91
+ typedef typename GPS_Solver_Base<float_t>::options_t::template merge_t<
92
+ SBAS_SinglePositioning_Options<float_t>, base_t> options_t;
93
+
94
+ protected:
95
+ const space_node_t &_space_node;
96
+ SBAS_SinglePositioning_Options<float_t> _options;
97
+
98
+ public:
99
+ const space_node_t &space_node() const {return _space_node;}
100
+
101
+ struct ionospheric_sbas_t : public range_corrector_t {
102
+ const space_node_t &space_node;
103
+ ionospheric_sbas_t(const space_node_t &sn) : range_corrector_t(), space_node(sn) {}
104
+ bool is_available(const gps_time_t &t) const {
105
+ return true;
106
+ }
107
+ float_t *calculate(
108
+ const gps_time_t &t, const pos_t &usr_pos, const enu_t &sat_rel_pos,
109
+ float_t &buf) const {
110
+
111
+ // placeholder of checking availability and performing correction
112
+ typedef typename space_node_t::available_satellites_t sats_t;
113
+ sats_t sats(space_node.available_satellites(usr_pos.llh.longitude()));
114
+
115
+ typename space_node_t::IonosphericGridPoints::PointProperty prop;
116
+ for(typename sats_t::const_iterator it(sats.begin()); it != sats.end(); ++it){
117
+ prop = it->second
118
+ ->ionospheric_grid_points().iono_correction(sat_rel_pos, usr_pos.llh);
119
+ if(prop.is_available()){
120
+ return &(buf = prop.delay);
121
+ }
122
+ break; // TODO The nearest satellite is only checked
123
+ }
124
+ return NULL;
125
+ }
126
+ } ionospheric_sbas;
127
+
128
+ struct tropospheric_sbas_t : public range_corrector_t {
129
+ tropospheric_sbas_t() : range_corrector_t() {}
130
+ bool is_available(const gps_time_t &t) const {
131
+ return true;
132
+ }
133
+ float_t *calculate(
134
+ const gps_time_t &t, const pos_t &usr_pos, const enu_t &sat_rel_pos,
135
+ float_t &buf) const {
136
+ return &(buf = space_node_t::tropo_correction(
137
+ t.year(), sat_rel_pos, usr_pos.llh));
138
+ }
139
+ } tropospheric_sbas;
140
+
141
+ range_correction_t ionospheric_correction, tropospheric_correction;
142
+
143
+ options_t available_options() const {
144
+ return options_t(base_t::available_options(), _options);
145
+ }
146
+
147
+ options_t available_options(const options_t &opt_wish) const {
148
+ SBAS_SinglePositioning_Options<float_t> opt(opt_wish);
149
+ return options_t(base_t::available_options(opt_wish), opt);
150
+ }
151
+
152
+ options_t update_options(const options_t &opt_wish){
153
+ _options = opt_wish;
154
+ return options_t(base_t::update_options(opt_wish), _options);
155
+ }
156
+
157
+ SBAS_SinglePositioning(const space_node_t &sn)
158
+ : base_t(), _space_node(sn), _options(available_options(options_t())),
159
+ ionospheric_sbas(sn), tropospheric_sbas() {
160
+
161
+ // default ionospheric correction: Broadcasted IGP.
162
+ ionospheric_correction.push_front(&ionospheric_sbas);
163
+
164
+ // default troposheric correction: SBAS
165
+ tropospheric_correction.push_front(&tropospheric_sbas);
166
+ }
167
+
168
+ ~SBAS_SinglePositioning(){}
169
+
170
+ /**
171
+ * Check availability of a satellite with which observation is associated
172
+ *
173
+ * @param prn satellite number
174
+ * @param receiver_time receiver time
175
+ * @return (const satellite_t *) If available, const pointer to satellite is returned,
176
+ * otherwise NULL.
177
+ */
178
+ const satellite_t *is_available(
179
+ const typename space_node_t::satellites_t::key_type &prn,
180
+ const gps_time_t &receiver_time) const {
181
+
182
+ const typename space_node_t::satellites_t &sats(_space_node.satellites());
183
+ const typename space_node_t::satellites_t::const_iterator it_sat(sats.find(prn));
184
+ if((it_sat == sats.end()) // has ephemeris?
185
+ || (!it_sat->second.ephemeris().is_valid(receiver_time))){ // valid ephemeris?
186
+ return NULL;
187
+ }
188
+
189
+ return &(it_sat->second);
190
+ }
191
+
192
+ /**
193
+ * Calculate relative range and rate information to a satellite
194
+ *
195
+ * @param prn satellite number
196
+ * @param measurement measurement (per satellite) containing pseudo range
197
+ * @param receiver_error (temporal solution of) receiver clock error in meter
198
+ * @param time_arrival time when signal arrive at receiver
199
+ * @param usr_pos (temporal solution of) user position
200
+ * @param usr_vel (temporal solution of) user velocity
201
+ * @return (relative_property_t) relative information
202
+ */
203
+ relative_property_t relative_property(
204
+ const prn_t &prn,
205
+ const typename measurement_t::mapped_type &measurement,
206
+ const float_t &receiver_error,
207
+ const gps_time_t &time_arrival,
208
+ const pos_t &usr_pos,
209
+ const xyz_t &usr_vel) const {
210
+
211
+ relative_property_t res = {0};
212
+
213
+ if(_options.exclude_prn[prn]){return res;}
214
+
215
+ float_t range;
216
+ range_error_t range_error;
217
+ if(!this->range(measurement, range, &range_error)){
218
+ return res; // If no range entry, return with weight = 0
219
+ }
220
+
221
+ const satellite_t *sat(is_available(prn, time_arrival));
222
+ if(!sat){return res;} // If satellite is unavailable, return with weight = 0
223
+
224
+ ///< The following procedure is based on Appendix.S with modification
225
+
226
+ range -= receiver_error;
227
+
228
+ // Clock correction will be performed in the following constellation()
229
+ if(!(range_error.unknown_flag & range_error_t::SATELLITE_CLOCK)){
230
+ range += range_error.value[range_error_t::SATELLITE_CLOCK];
231
+ }
232
+
233
+ // TODO WAAS long term clock correction (2.1.1.4.11)
234
+
235
+ // Calculate satellite position and velocity
236
+ typename space_node_t::SatelliteProperties::constellation_t sat_pos_vel(
237
+ sat->ephemeris().constellation(time_arrival, range));
238
+
239
+ const xyz_t &sat_pos(sat_pos_vel.position);
240
+ float_t geometric_range(usr_pos.xyz.dist(sat_pos));
241
+
242
+ // Calculate residual with Sagnac correction (A.4.4.11)
243
+ res.range_residual = range
244
+ + space_node_t::sagnac_correction(sat_pos, usr_pos.xyz)
245
+ - geometric_range;
246
+
247
+ // Setup design matrix
248
+ res.los_neg[0] = -(sat_pos.x() - usr_pos.xyz.x()) / geometric_range;
249
+ res.los_neg[1] = -(sat_pos.y() - usr_pos.xyz.y()) / geometric_range;
250
+ res.los_neg[2] = -(sat_pos.z() - usr_pos.xyz.z()) / geometric_range;
251
+
252
+ enu_t relative_pos(enu_t::relative(sat_pos, usr_pos.xyz));
253
+
254
+ // Tropospheric (2.1.4.10.3, A.4.2.4)
255
+ res.range_residual += (range_error.unknown_flag & range_error_t::MASK_TROPOSPHERIC)
256
+ ? tropospheric_correction(time_arrival, usr_pos, relative_pos)
257
+ : range_error.value[range_error_t::TROPOSPHERIC];
258
+
259
+ // Ionospheric (2.1.4.10.2, A.4.4.10.4)
260
+ if(range_error.unknown_flag & range_error_t::MASK_IONOSPHERIC){
261
+ res.range_residual += ionospheric_correction(time_arrival, usr_pos, relative_pos);
262
+ }else{
263
+ res.range_residual += range_error.value[range_error_t::IONOSPHERIC];
264
+ }
265
+
266
+ // TODO Fast corrections (2.1.1.4.12)
267
+
268
+ // TODO Setup weight
269
+ if(std::abs(res.range_residual) > _options.residual_mask){
270
+ // If residual is too big, gently exclude it by decreasing its weight.
271
+ res.weight = 1E-8;
272
+ }else{
273
+
274
+ float_t elv(relative_pos.elevation());
275
+ if(elv < _options.elevation_mask){
276
+ res.weight = 0; // exclude it when elevation is less than threshold
277
+ }else{
278
+ // elevation weight based on "GPS���p�v���O���~���O" @see GPS_Solver.h
279
+ res.weight = std::pow(sin(elv)/0.8, 2);
280
+ if(res.weight < 1E-3){res.weight = 1E-3;}
281
+ }
282
+ }
283
+
284
+ res.range_corrected = range;
285
+
286
+ xyz_t rel_vel(sat_pos_vel.velocity - usr_vel); // Calculate velocity
287
+
288
+ // Note: clock rate error is already accounted for in constellation()
289
+ res.rate_relative_neg = res.los_neg[0] * rel_vel.x()
290
+ + res.los_neg[1] * rel_vel.y()
291
+ + res.los_neg[2] * rel_vel.z();
292
+
293
+ return res;
294
+ }
295
+
296
+ xyz_t *satellite_position(
297
+ const prn_t &prn,
298
+ const gps_time_t &time,
299
+ xyz_t &res) const {
300
+
301
+ const satellite_t *sat(is_available(prn, time));
302
+ return sat ? &(res = sat->ephemeris().constellation(time).position) : NULL;
303
+ }
304
+ };
305
+
306
+ #endif /* __SBAS_SOLVER_H__ */
@@ -60,6 +60,7 @@ struct const_div_t<denom, denom, log2, 0> {
60
60
  template <int MAX_SIZE, class ContainerT = unsigned char>
61
61
  struct BitArray {
62
62
  static const int bits_per_addr = (int)sizeof(ContainerT) * CHAR_BIT;
63
+ static const int max_size = MAX_SIZE;
63
64
  ContainerT buf[(MAX_SIZE + bits_per_addr - 1) / bits_per_addr];
64
65
  void set(const bool &new_bit = false) {
65
66
  std::memset(buf, (new_bit ? (~0) : 0), sizeof(buf));
@@ -128,14 +129,14 @@ struct BitArray {
128
129
  std::vector<int> res;
129
130
  int idx(0);
130
131
  static const const_div_t<bits_per_addr> qr(MAX_SIZE);
131
- int rem(qr.rem);
132
- for(int i(0); i < qr.quot; ++i, idx += bits_per_addr){
132
+ int rem(qr.rem), i(0);
133
+ for(; i < qr.quot; ++i, idx += bits_per_addr){
133
134
  int idx2(idx);
134
135
  for(ContainerT temp(buf[i]); temp > 0; temp >>= 1, ++idx2){
135
136
  if(temp & 0x1){res.push_back(idx2);}
136
137
  }
137
138
  }
138
- for(ContainerT temp(buf[qr.quot + 1]); (temp > 0) && (rem > 0); --rem, ++idx, temp >>= 1){
139
+ for(ContainerT temp(buf[i]); (temp > 0) && (rem > 0); --rem, ++idx, temp >>= 1){
139
140
  if(temp & 0x1){res.push_back(idx);}
140
141
  }
141
142
  return res;