gps_pvt 0.6.4 → 0.7.2

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.
@@ -76,6 +76,7 @@ class RINEX_Reader {
76
76
  FTYPE_OBSERVATION,
77
77
  FTYPE_NAVIGATION,
78
78
  FTYPE_METEOROLOGICAL,
79
+ FTYPE_CLOCK,
79
80
  } file_type;
80
81
  enum sat_system_t {
81
82
  SYS_UNKNOWN = 0,
@@ -89,6 +90,19 @@ class RINEX_Reader {
89
90
  SYS_TRANSIT,
90
91
  SYS_MIXED,
91
92
  } sat_system;
93
+ static sat_system_t char2sys_v3(const char &c){
94
+ switch(c){
95
+ case 'G': return SYS_GPS;
96
+ case 'R': return SYS_GLONASS;
97
+ case 'E': return SYS_GALILEO;
98
+ case 'J': return SYS_QZSS;
99
+ case 'C': return SYS_BDS;
100
+ case 'I': return SYS_IRNSS;
101
+ case 'S': return SYS_SBAS;
102
+ case 'M': return SYS_MIXED;
103
+ }
104
+ return SYS_UNKNOWN;
105
+ }
92
106
  version_type_t(
93
107
  const int &ver = 0, const file_type_t &ftype = FTYPE_UNKNOWN, const sat_system_t &sys = SYS_UNKNOWN)
94
108
  : version(ver), file_type(ftype), sat_system(sys) {}
@@ -105,7 +119,7 @@ class RINEX_Reader {
105
119
  : src(in), _has_next(false),
106
120
  version_type() {
107
121
  if(src.fail()){return;}
108
-
122
+
109
123
  char buf[256];
110
124
 
111
125
  // Read header
@@ -135,7 +149,13 @@ class RINEX_Reader {
135
149
  version_type.parse(it->second.front());
136
150
  break;
137
151
  }
138
-
152
+ }
153
+ RINEX_Reader(
154
+ std::istream &in,
155
+ void (RINEX_Reader::*read_header)())
156
+ : src(in), _has_next(false),
157
+ version_type() {
158
+ (this->*read_header)();
139
159
  }
140
160
  virtual ~RINEX_Reader(){_header.clear();}
141
161
  header_t &header() {return _header;}
@@ -235,6 +255,7 @@ void RINEX_Reader<U>::version_type_t::parse(const std::string &buf){
235
255
  case 'H': file_type = FTYPE_NAVIGATION;
236
256
  sat_system = SYS_SBAS; // TODO: Is geostational as SBAS?
237
257
  break;
258
+ case 'C': file_type = FTYPE_CLOCK; break;
238
259
  }
239
260
  break;
240
261
  case 3:
@@ -242,18 +263,12 @@ void RINEX_Reader<U>::version_type_t::parse(const std::string &buf){
242
263
  case 'O': file_type = FTYPE_OBSERVATION; break;
243
264
  case 'N': file_type = FTYPE_NAVIGATION; break;
244
265
  case 'M': file_type = FTYPE_METEOROLOGICAL; break;
266
+ case 'C': file_type = FTYPE_CLOCK; break;
245
267
  }
246
- if((file_type == FTYPE_OBSERVATION) || (file_type == FTYPE_NAVIGATION)){
247
- switch(buf[40]){
248
- case 'G': sat_system = SYS_GPS; break;
249
- case 'R': sat_system = SYS_GLONASS; break;
250
- case 'E': sat_system = SYS_GALILEO; break;
251
- case 'J': sat_system = SYS_QZSS; break;
252
- case 'C': sat_system = SYS_BDS; break;
253
- case 'I': sat_system = SYS_IRNSS; break;
254
- case 'S': sat_system = SYS_SBAS; break;
255
- case 'M': sat_system = SYS_MIXED; break;
256
- }
268
+ if((file_type == FTYPE_OBSERVATION)
269
+ || (file_type == FTYPE_NAVIGATION)
270
+ || (file_type == FTYPE_CLOCK)){
271
+ sat_system = char2sys_v3(buf[40]);
257
272
  }
258
273
  break;
259
274
  }
@@ -306,7 +321,7 @@ void RINEX_Reader<U>::version_type_t::dump(std::string &buf) const {
306
321
  switch(sat_system){
307
322
  case SYS_GPS: sys_str = "G: GPS"; break;
308
323
  case SYS_GLONASS: sys_str = "R: GLONASS"; break;
309
- case SYS_GALILEO: sys_str = "G: GALILEO"; break;
324
+ case SYS_GALILEO: sys_str = "E: GALILEO"; break;
310
325
  case SYS_QZSS: sys_str = "Q: QZSS"; break;
311
326
  case SYS_BDS: sys_str = "B: BDS"; break;
312
327
  case SYS_IRNSS: sys_str = "I: IRNSS"; break;
@@ -338,7 +353,6 @@ struct RINEX_NAV {
338
353
  int t_oc_year4, t_oc_year2, t_oc_mon12;
339
354
  FloatT t_oc_sec;
340
355
  FloatT t_oe_WN;
341
- FloatT ura_meter;
342
356
  FloatT t_ot; ///< Transmitting time [s]
343
357
  FloatT fit_interval_hr;
344
358
  FloatT dummy;
@@ -352,7 +366,6 @@ struct RINEX_NAV {
352
366
  t_oc_mon12(t_oc_tm.tm_mon + 1),
353
367
  t_oc_sec(std::fmod(eph.t_oc, 60)),
354
368
  t_oe_WN(eph.WN),
355
- ura_meter(ephemeris_t::URA_meter(eph.URA)),
356
369
  t_ot(0), // TODO
357
370
  fit_interval_hr(eph.fit_interval / (60 * 60)),
358
371
  dummy(0) {
@@ -363,8 +376,6 @@ struct RINEX_NAV {
363
376
  eph.WN = t_oc.week;
364
377
  eph.t_oc = t_oc.seconds;
365
378
 
366
- eph.URA = ephemeris_t::URA_index(ura_meter); // meter to index
367
-
368
379
  /* @see ftp://igs.org/pub/data/format/rinex210.txt
369
380
  * 6.7 Satellite Health
370
381
  * RINEX Value: 0 Health OK
@@ -1419,14 +1430,14 @@ const typename RINEX_NAV_Reader<FloatT>::convert_item_t RINEX_NAV_Reader<FloatT>
1419
1430
 
1420
1431
  template <class FloatT>
1421
1432
  const typename RINEX_NAV_Reader<FloatT>::convert_item_t RINEX_NAV_Reader<FloatT>::eph6_v2[] = {
1422
- GEN_E ( 3, 19, 12, message_t, ura_meter),
1433
+ GEN_E ( 3, 19, 12, message_t, eph.URA),
1423
1434
  GEN_E2(22, 19, 12, message_t, eph.SV_health, unsigned int),
1424
1435
  GEN_E (41, 19, 12, message_t, eph.t_GD),
1425
1436
  GEN_E2(60, 19, 12, message_t, eph.iodc, int),
1426
1437
  };
1427
1438
  template <class FloatT>
1428
1439
  const typename RINEX_NAV_Reader<FloatT>::convert_item_t RINEX_NAV_Reader<FloatT>::eph6_v3[] = {
1429
- GEN_E ( 4, 19, 12, message_t, ura_meter),
1440
+ GEN_E ( 4, 19, 12, message_t, eph.URA),
1430
1441
  GEN_E2(23, 19, 12, message_t, eph.SV_health, unsigned int),
1431
1442
  GEN_E (42, 19, 12, message_t, eph.t_GD),
1432
1443
  GEN_E2(61, 19, 12, message_t, eph.iodc, int),
@@ -0,0 +1,458 @@
1
+ /*
2
+ * Copyright (c) 2022, 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
+ /** @file
33
+ * @brief Loader of RINEX Clock extension, support versions are 3 including 3.04
34
+ */
35
+
36
+ #ifndef __RINEX_CLOCK__
37
+ #define __RINEX_CLOCK__
38
+
39
+ #include <cstring>
40
+ #include <cctype>
41
+ #include <string>
42
+
43
+ #include "RINEX.h"
44
+ #include "GPS.h"
45
+ #include "algorithm/interpolate.h"
46
+ #include "GPS_Solver_Base.h"
47
+
48
+ template <class FloatT>
49
+ struct RINEX_CLK {
50
+ struct record_t {
51
+ char type[2], name[9];
52
+ std::tm epoch;
53
+ int epoch_year4, epoch_mon12;
54
+ FloatT epoch_sec;
55
+ int items_followed;
56
+ bool valid[6];
57
+ union {
58
+ FloatT array[6];
59
+ struct {
60
+ FloatT bias, bias_sigma, rate, rate_sigma, acc, acc_sigma;
61
+ } v;
62
+ } values;
63
+
64
+ GPS_Time<FloatT> get_epoch() const {
65
+ return GPS_Time<FloatT>(epoch) + (epoch_sec - epoch.tm_sec);
66
+ }
67
+ record_t &set_epoch(const GPS_Time<FloatT> &t){
68
+ epoch = t.c_tm();
69
+ epoch_year4 = epoch.tm_year + 1900;
70
+ epoch_mon12 = epoch.tm_mon + 1;
71
+ epoch_sec = std::fmod(t.seconds, 60);
72
+ return *this;
73
+ }
74
+
75
+ std::string get_name() const {
76
+ std::string res;
77
+ for(std::size_t i(0); i < sizeof(name); ++i){
78
+ if(!std::isgraph(name[i])){break;}
79
+ res.push_back(name[i]);
80
+ }
81
+ return res;
82
+ }
83
+ record_t &set_name(const std::string &str){
84
+ std::memset(name, ' ', sizeof(name));
85
+ str.copy(name, str.size() > sizeof(name) ? sizeof(name) : str.size());
86
+ return *this;
87
+ }
88
+ };
89
+
90
+ struct per_node_t {
91
+ std::map<GPS_Time<FloatT>, FloatT> bias;
92
+ typedef InterpolatableSet<GPS_Time<FloatT>, FloatT, FloatT> interpolator_t;
93
+ static const typename interpolator_t::condition_t interpolator_cnd_default;
94
+ mutable struct {
95
+ interpolator_t bias;
96
+ } subset;
97
+ bool precheck(const GPS_Time<FloatT> &t) const {
98
+ subset.bias.update(t, bias, interpolator_cnd_default);
99
+ return subset.bias.ready;
100
+ }
101
+ FloatT clock_error(const GPS_Time<FloatT> &t) const {
102
+ return subset.bias.update(t, bias, interpolator_cnd_default).interpolate(t);
103
+ }
104
+ FloatT clock_error_dot(const GPS_Time<FloatT> &t) const {
105
+ FloatT res;
106
+ subset.bias.update(t, bias, interpolator_cnd_default).interpolate(t, &res);
107
+ return res;
108
+ }
109
+ };
110
+ struct satellites_t {
111
+ typedef std::map<int, per_node_t> buf_t; // prn => per_node_t
112
+ buf_t buf;
113
+
114
+ enum system_t {
115
+ SYSTEM_GPS,
116
+ SYSTEM_SBAS,
117
+ SYSTEM_QZSS,
118
+ SYSTEM_GLONASS,
119
+ SYSTEM_GALILEO,
120
+ SYSTEM_BEIDOU,
121
+ SYSTEM_IRNSS,
122
+ NUM_OF_SYSTEMS,
123
+ };
124
+
125
+ static const int offset_list[NUM_OF_SYSTEMS];
126
+
127
+ protected:
128
+
129
+ typedef typename GPS_Solver_Base<FloatT>::satellite_t sat_t;
130
+
131
+ mutable struct per_system_t {
132
+ struct {
133
+ const satellites_t *sats;
134
+ } clk_rate;
135
+ struct {
136
+ const void *impl;
137
+ sat_t (*impl_select)(const void *, const int &, const GPS_Time<FloatT> &);
138
+ } pos_vel;
139
+ system_t sys;
140
+ } per_system[NUM_OF_SYSTEMS];
141
+
142
+ static sat_t select(
143
+ const void *ptr, const int &prn, const GPS_Time<FloatT> &receiver_time){
144
+ const per_system_t *ptr_sys(reinterpret_cast<const per_system_t *>(ptr));
145
+
146
+ // retrieve position/velocity supplier
147
+ sat_t res(
148
+ ptr_sys->pos_vel.impl_select(ptr_sys->pos_vel.impl, prn, receiver_time));
149
+
150
+ int sat_id((prn & 0xFF) + offset_list[ptr_sys->sys]);
151
+
152
+ // check clock_error/clock_error_dot availability
153
+ typename buf_t::const_iterator it(ptr_sys->clk_rate.sats->buf.find(sat_id));
154
+ if((it == ptr_sys->clk_rate.sats->buf.end()) || !it->second.precheck(receiver_time)){
155
+ // unavailable case
156
+ static const sat_t &unavailable(sat_t::unavailable());
157
+ res.impl_t = unavailable.impl_t;
158
+ res.impl_clock_error = unavailable.impl_clock_error;
159
+ res.impl_clock_error_dot = unavailable.impl_clock_error_dot;
160
+ return res;
161
+ }
162
+
163
+ struct impl_t {
164
+ static inline const per_node_t &sat(const void *ptr) {
165
+ return *reinterpret_cast<const per_node_t *>(ptr);
166
+ }
167
+ static typename GPS_Solver_Base<FloatT>::float_t clock_error(
168
+ const void *ptr, const GPS_Time<FloatT> &t_tx) {
169
+ return sat(ptr).clock_error(t_tx);
170
+ }
171
+ static typename GPS_Solver_Base<FloatT>::float_t clock_error_dot(
172
+ const void *ptr, const GPS_Time<FloatT> &t_tx) {
173
+ return sat(ptr).clock_error_dot(t_tx);
174
+ }
175
+ };
176
+ res.impl_t = &(it->second);
177
+ res.impl_clock_error = impl_t::clock_error;
178
+ res.impl_clock_error_dot = impl_t::clock_error_dot;
179
+ return res;
180
+ }
181
+
182
+ public:
183
+
184
+ template <class SelectorT>
185
+ bool push(SelectorT &slct, const system_t &sys = SYSTEM_GPS) const {
186
+ if(sys >= NUM_OF_SYSTEMS){return false;}
187
+ per_system[sys].clk_rate.sats = this;
188
+ per_system[sys].sys = sys;
189
+ if(slct.impl_select != select){
190
+ per_system[sys].pos_vel.impl = slct.impl;
191
+ per_system[sys].pos_vel.impl_select = slct.impl_select;
192
+ }
193
+ slct.impl_select = select;
194
+ slct.impl = &per_system[sys];
195
+ return true;
196
+ }
197
+
198
+ struct count_t {
199
+ int gps, sbas, qzss, glonass, galileo, beidou, irnss, unknown;
200
+ };
201
+ count_t count() const {
202
+ count_t res = {0};
203
+ for(typename buf_t::const_iterator it(buf.begin()), it_end(buf.end());
204
+ it != it_end; ++it){
205
+ switch((char)(it->first >> 8)){
206
+ case '\0': {
207
+ int id(it->first & 0xFF);
208
+ if(id < 100){++res.gps;}
209
+ else if(id < 192){++res.sbas;}
210
+ else{++res.qzss;}
211
+ break;
212
+ }
213
+ case 'R': ++res.glonass; break;
214
+ case 'E': ++res.galileo; break;
215
+ case 'C': ++res.beidou; break;
216
+ case 'I': ++res.irnss; break;
217
+ default: ++res.unknown; break;
218
+ }
219
+ }
220
+ return res;
221
+ }
222
+ };
223
+ typedef std::map<std::string, per_node_t> collection_t; // satellites + receivers, name => per_node_t
224
+ };
225
+
226
+ template <class FloatT>
227
+ const typename RINEX_CLK<FloatT>::per_node_t::interpolator_t::condition_t
228
+ RINEX_CLK<FloatT>::per_node_t::interpolator_cnd_default = {
229
+ 5, // max_x_size
230
+ 60 * 60 * 2, // subset.cnd.max_dx_range
231
+ };
232
+
233
+ template <class FloatT>
234
+ const int RINEX_CLK<FloatT>::satellites_t::offset_list[NUM_OF_SYSTEMS] = {
235
+ 0, 0, 0, // GPS, SBAS, QZSS
236
+ (int)'R' << 8, // GLONASS
237
+ (int)'E' << 8, // GALILEO
238
+ (int)'C' << 8, // BEIDOU
239
+ (int)'I' << 8, // IRNSS,
240
+ };
241
+
242
+ template <class FloatT = double>
243
+ class RINEX_CLK_Reader : public RINEX_Reader<> {
244
+ protected:
245
+ typedef RINEX_Reader<> super_t;
246
+ public:
247
+ typedef typename RINEX_CLK<FloatT>::record_t record_t;
248
+ static const typename super_t::convert_item_t head_v3[7];
249
+ static const typename super_t::convert_item_t head_v304[7];
250
+
251
+ protected:
252
+ record_t record;
253
+
254
+ void read_header(){
255
+ if(super_t::src.fail()){return;}
256
+
257
+ char buf[256];
258
+ int label_offset(60);
259
+
260
+ // Read header
261
+ for(int line(0); !super_t::src.eof(); ++line){
262
+ super_t::src.getline(buf, sizeof(buf));
263
+
264
+ std::string content(buf);
265
+
266
+ if(line == 0){ // Check version and type extraction
267
+ switch(content.find("RINEX VERSION / TYPE")){
268
+ case 60:
269
+ super_t::version_type.parse(content);
270
+ break;
271
+ case 65: {
272
+ double temp(0);
273
+ super_t::conv_t<double>::f(content, 0, 4, &temp, 2);
274
+ super_t::version_type.version = (int)(temp * 100);
275
+ if(super_t::version_type.version != 304){return;}
276
+ if(content[21] != 'C'){return;}
277
+ super_t::version_type.file_type
278
+ = super_t::version_type_t::FTYPE_CLOCK;
279
+ super_t::version_type.sat_system
280
+ = super_t::version_type_t::char2sys_v3(content[42]);
281
+ label_offset = 65;
282
+ break;
283
+ }
284
+ default: // includes std::string::npos:
285
+ return;
286
+ }
287
+ }
288
+
289
+ std::string label(content, label_offset, 20);
290
+ {
291
+ int real_length(label.find_last_not_of(' ') + 1);
292
+ if(real_length < (int)label.length()){
293
+ label = label.substr(0, real_length);
294
+ }
295
+ }
296
+
297
+ if(label.find("END OF HEADER") == 0){break;}
298
+
299
+ _header[label].push_back(content.substr(0, label_offset));
300
+ }
301
+ }
302
+
303
+ public:
304
+ void seek_next() {
305
+ super_t::_has_next = false;
306
+
307
+ char buf[1024];
308
+ std::string str;
309
+ bool v304(super_t::version_type.version == 304);
310
+ while(true){
311
+ if(super_t::src.getline(buf, sizeof(buf)).fail()){return;}
312
+ str.assign(buf);
313
+ if(str.size() < (v304 ? 45 : 37)){continue;}
314
+ str.copy(record.type, 2);
315
+ if((std::memcmp(record.type, "AR", 2) == 0)
316
+ || (std::memcmp(record.type, "AS", 2) == 0)
317
+ || (std::memcmp(record.type, "CR", 2) == 0)
318
+ || (std::memcmp(record.type, "DR", 2) == 0)
319
+ || (std::memcmp(record.type, "MS", 2) == 0)){
320
+ break;
321
+ }
322
+ }
323
+ std::memset(record.name, ' ', sizeof(record.name));
324
+ str.copy(record.name, v304 ? 9 : 4, 3);
325
+ v304 ? super_t::convert(head_v304, str, &record) : super_t::convert(head_v3, str, &record);
326
+ record.epoch.tm_year = record.epoch_year4 - 1900; // greater than 1980
327
+ record.epoch.tm_mon = record.epoch_mon12 - 1; // month [0, 11]
328
+ record.epoch.tm_sec = (int)record.epoch_sec;
329
+
330
+ for(int i(0), j(2), k(v304 ? 45 : 40); i < 6; ++i, ++j, k += (v304 ? 21 : 20)){
331
+ record.valid[i] = false;
332
+ if(i >= record.items_followed){continue;}
333
+ if(j % 4 == 0){
334
+ j = 0; k = 3;
335
+ if(super_t::src.getline(buf, sizeof(buf)).fail()){break;}
336
+ str.assign(buf);
337
+ }
338
+ if(!super_t::template conv_t<FloatT>::e_dot_head(
339
+ str, k, 19, &record.values.array[i], 12)){break;}
340
+ record.valid[i] = true;
341
+ }
342
+
343
+ super_t::_has_next = true;
344
+ }
345
+
346
+ RINEX_CLK_Reader(std::istream &in)
347
+ : super_t(in, static_cast<void(super_t::*)()>(
348
+ &RINEX_CLK_Reader::read_header)) {
349
+ seek_next();
350
+ }
351
+ ~RINEX_CLK_Reader(){}
352
+
353
+ void next() {
354
+ seek_next();
355
+ }
356
+
357
+ protected:
358
+ static int read_all(
359
+ std::istream &in,
360
+ void *buf, bool (*callback)(void *, const record_t &)){
361
+ RINEX_CLK_Reader reader(in);
362
+ if(reader.version_type.file_type != version_type_t::FTYPE_CLOCK){
363
+ return -1;
364
+ }
365
+ int res(0);
366
+ for(; reader.has_next(); reader.next()){
367
+ if(!reader.record.valid[0]){continue;}
368
+ if(!callback(buf, reader.record)){continue;}
369
+ ++res;
370
+ }
371
+ return res;
372
+ }
373
+
374
+ public:
375
+ static int read_all(
376
+ std::istream &in,
377
+ typename RINEX_CLK<FloatT>::satellites_t &dst){
378
+ struct func_t {
379
+ static bool add(void *ptr, const record_t &record){
380
+ typename RINEX_CLK<FloatT>::satellites_t &dst(
381
+ *reinterpret_cast<typename RINEX_CLK<FloatT>::satellites_t *>(ptr));
382
+ if((record.type[0] != 'A') || (record.type[1] != 'S')){return false;}
383
+ int offset(0);
384
+ char sys(record.name[0]);
385
+ switch(sys){
386
+ case 'G': break; // GPS
387
+ case 'R': offset = (int)'R' << 8; break; // GLONASS
388
+ case 'E': offset = (int)'E' << 8; break; // Galileo
389
+ case 'C': offset = (int)'C' << 8; break; // BeiDou
390
+ case 'J': offset = 192; break; // QZSS
391
+ case 'S': offset = 100; break; // SBAS
392
+ case 'I': offset = (int)'I' << 8; break; // IRNSS
393
+ default: return false;
394
+ }
395
+ if(record.name[1] < '0' || record.name[1] > '9'
396
+ || record.name[2] < '0' || record.name[2] > '9'){return false;}
397
+ int idx((record.name[1] - '0') * 10 + (record.name[2] - '0') + offset);
398
+ dst.buf[idx].bias[record.get_epoch()] = record.values.v.bias;
399
+ return true;
400
+ }
401
+ };
402
+ return read_all(in, &dst, func_t::add);
403
+ }
404
+
405
+ static int read_all(
406
+ std::istream &in,
407
+ typename RINEX_CLK<FloatT>::collection_t &dst){
408
+ struct func_t {
409
+ static bool add(void *ptr, const record_t &record){
410
+ typename RINEX_CLK<FloatT>::collection_t &dst(
411
+ *reinterpret_cast<typename RINEX_CLK<FloatT>::collection_t *>(ptr));
412
+ dst[record.get_name()].bias[record.get_epoch()] = record.values.v.bias;
413
+ return true;
414
+ }
415
+ };
416
+ return read_all(in, &dst, func_t::add);
417
+ }
418
+ };
419
+
420
+ #define GEN_D(offset, length, container_type, container_member, value_type) \
421
+ {super_t::template conv_t<value_type>::d, offset, length, \
422
+ offsetof(container_type, container_member)}
423
+ #define GEN_I(offset, length, container_type, container_member, value_type) \
424
+ {super_t::template conv_t<value_type>::d, offset, length, \
425
+ offsetof(container_type, container_member), 1}
426
+ #define GEN_F2(offset, length, precision, container_type, container_member, value_type) \
427
+ {super_t::template conv_t<value_type>::f_dot_head, offset, length, \
428
+ offsetof(container_type, container_member), precision}
429
+ #define GEN_F(offset, length, precision, container_type, container_member) \
430
+ GEN_F2(offset, length, precision, container_type, container_member, FloatT)
431
+
432
+ template <class FloatT>
433
+ const typename RINEX_CLK_Reader<FloatT>::convert_item_t RINEX_CLK_Reader<FloatT>::head_v3[] = {
434
+ GEN_I( 8, 4, record_t, epoch_year4, int),
435
+ GEN_I(13, 2, record_t, epoch_mon12, int),
436
+ GEN_I(16, 2, record_t, epoch.tm_mday, int),
437
+ GEN_I(19, 2, record_t, epoch.tm_hour, int),
438
+ GEN_I(22, 2, record_t, epoch.tm_min, int),
439
+ GEN_F(24, 10, 6, record_t, epoch_sec),
440
+ GEN_D(34, 3, record_t, items_followed, int),
441
+ };
442
+
443
+ template <class FloatT>
444
+ const typename RINEX_CLK_Reader<FloatT>::convert_item_t RINEX_CLK_Reader<FloatT>::head_v304[] = {
445
+ GEN_I(13, 4, record_t, epoch_year4, int),
446
+ GEN_I(18, 2, record_t, epoch_mon12, int),
447
+ GEN_I(21, 2, record_t, epoch.tm_mday, int),
448
+ GEN_I(24, 2, record_t, epoch.tm_hour, int),
449
+ GEN_I(27, 2, record_t, epoch.tm_min, int),
450
+ GEN_F(29, 9, 6, record_t, epoch_sec),
451
+ GEN_D(40, 2, record_t, items_followed, int),
452
+ };
453
+
454
+ #undef GEN_D
455
+ #undef GEN_I
456
+ #undef GEN_F
457
+
458
+ #endif /* __RINEX_CLOCK__ */
@@ -1387,16 +1387,16 @@ sf[SF_ ## TARGET] * msg_t::TARGET(buf)
1387
1387
 
1388
1388
  // the first line
1389
1389
  out << " ";
1390
- for(int j(0); j < sizeof(igp.properties[0]) / sizeof(igp.properties[0][0]); ++j){
1390
+ for(std::size_t j(0); j < sizeof(igp.properties[0]) / sizeof(igp.properties[0][0]); ++j){
1391
1391
  int lng(position_index_t::idx2lng(j));
1392
1392
  out << (lng == 0 ? '0' : (lng % 90 == 0 ? '|' : (lng % 30 == 0 ? '+' : ' ')));
1393
1393
  }
1394
1394
  out << std::endl;
1395
1395
 
1396
- for(int i(0); i < sizeof(igp.properties) / sizeof(igp.properties[0]); ++i){
1396
+ for(std::size_t i(0); i < sizeof(igp.properties) / sizeof(igp.properties[0]); ++i){
1397
1397
  out.width(4);
1398
1398
  out << position_index_t::idx2lat(i) << ' ';
1399
- for(int j(0); j < sizeof(igp.properties[0]) / sizeof(igp.properties[0][0]); ++j){
1399
+ for(std::size_t j(0); j < sizeof(igp.properties[0]) / sizeof(igp.properties[0][0]); ++j){
1400
1400
  if(!igp.properties[i][j].is_available()){
1401
1401
  out << ' ';
1402
1402
  }else{
@@ -1711,7 +1711,7 @@ sf[SF_ ## TARGET] * msg_t::TARGET(buf)
1711
1711
  uint_t WN; ///< Week number
1712
1712
 
1713
1713
  float_t t_0; ///< Time of applicability (s) <= time of a week
1714
- int_t URA; ///< User range accuracy (index)
1714
+ float_t URA; ///< User range accuracy (m)
1715
1715
  float_t x, y, z; ///< ECEF position (m)
1716
1716
  float_t dx, dy, dz; ///< ECEF velocity (m/s)
1717
1717
  float_t ddx, ddy, ddz; ///< ECEF acceleration (m/s^2)
@@ -1804,6 +1804,15 @@ sf[SF_ ## TARGET] * msg_t::TARGET(buf)
1804
1804
  return res;
1805
1805
  }
1806
1806
 
1807
+ static const float_t URA_table[15];
1808
+
1809
+ inline static float_t URA_meter(const int_t &index){
1810
+ return gps_space_node_t::SatelliteProperties::Ephemeris::URA_meter(index, URA_table);
1811
+ }
1812
+ inline static int_t URA_index(const float_t &meter){
1813
+ return gps_space_node_t::SatelliteProperties::Ephemeris::URA_index(meter, URA_table);
1814
+ }
1815
+
1807
1816
  struct raw_t {
1808
1817
  u8_t svid; ///< Satellite number
1809
1818
 
@@ -1850,7 +1859,7 @@ sf[SF_ ## TARGET] * msg_t::TARGET(buf)
1850
1859
  converted.svid = svid;
1851
1860
  converted.WN = 0; // Week number (must be configured later) @see adjust_time
1852
1861
 
1853
- converted.URA = URA;
1862
+ converted.URA = URA_meter(URA);
1854
1863
  CONVERT(t_0); // Time of a day => time of a week (must be configured later) @see adjust_time
1855
1864
  CONVERT2(x, xy); CONVERT2(y, xy); CONVERT(z);
1856
1865
  CONVERT2(dx, dxy); CONVERT2(dy, dxy); CONVERT(dz);
@@ -1869,7 +1878,7 @@ sf[SF_ ## TARGET] * msg_t::TARGET(buf)
1869
1878
  #define CONVERT(TARGET) CONVERT2(TARGET, TARGET)
1870
1879
  svid = eph.svid;
1871
1880
 
1872
- URA = eph.URA;
1881
+ URA = URA_index(eph.URA);
1873
1882
  CONVERT3(t_0, std::fmod(t_0, gps_time_t::seconds_day), t_0);
1874
1883
  CONVERT2(x, xy); CONVERT2(y, xy); CONVERT(z);
1875
1884
  CONVERT2(dx, dxy); CONVERT2(dy, dxy); CONVERT(dz);
@@ -2350,4 +2359,23 @@ const typename SBAS_SpaceNode<FloatT>::float_t SBAS_SpaceNode<FloatT>::UTC_Param
2350
2359
 
2351
2360
  #undef POWER_2
2352
2361
 
2362
+ template <class FloatT>
2363
+ const typename SBAS_SpaceNode<FloatT>::float_t SBAS_SpaceNode<FloatT>::SatelliteProperties::Ephemeris::URA_table[] = {
2364
+ 2,
2365
+ 2.8,
2366
+ 4,
2367
+ 5.7,
2368
+ 8,
2369
+ 11.3,
2370
+ 16,
2371
+ 32,
2372
+ 64,
2373
+ 128,
2374
+ 256,
2375
+ 512,
2376
+ 1024,
2377
+ 2048,
2378
+ 4096,
2379
+ };
2380
+
2353
2381
  #endif /* __SBAS_H__ */