gps_pvt 0.5.1 → 0.6.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,1189 @@
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 SP3 Reader/Writer, support ver.D
34
+ *
35
+ */
36
+
37
+ #ifndef __SP3_H__
38
+ #define __SP3_H__
39
+
40
+ #include <ctime>
41
+ #include <cstring>
42
+ #include <map>
43
+ #include <set>
44
+ #include <algorithm>
45
+ #include <stdexcept>
46
+
47
+ #include "util/text_helper.h"
48
+ #include "GPS.h"
49
+ #include "GPS_Solver_Base.h"
50
+
51
+ #include "param/vector3.h"
52
+ #include "algorithm/interpolate.h"
53
+
54
+ template <class FloatT>
55
+ struct SP3_Product {
56
+ struct prop_t {
57
+ Vector3<FloatT> xyz;
58
+ FloatT clk;
59
+ };
60
+ struct per_satellite_t {
61
+ typedef std::map<GPS_Time<FloatT>, prop_t> history_t;
62
+ history_t pos_history;
63
+ history_t vel_history;
64
+
65
+ static const struct interpolate_cnd_t {
66
+ std::size_t max_epochs; ///< maximum number of epochs used for interpolation
67
+ FloatT max_delta_t; ///< maximum acceptable absolute time difference between t and epoch
68
+ } interpolate_cnd_default;
69
+
70
+ mutable struct {
71
+ struct target_t {
72
+
73
+ typedef typename std::vector<std::pair<GPS_Time<FloatT>, prop_t> > buf_t;
74
+ buf_t buf;
75
+ GPS_Time<FloatT> t0;
76
+ std::vector<FloatT> dt;
77
+ bool updated_full_cnd;
78
+
79
+ target_t() : t0(0, 0), updated_full_cnd(false) {}
80
+
81
+ /**
82
+ * update interpolation source
83
+ * @param force_update If true, update is forcibly performed irrespective of current state
84
+ * @param cnd condition for source data selection
85
+ */
86
+ target_t &update(
87
+ const GPS_Time<FloatT> &t, const history_t &history,
88
+ const bool &force_update = false,
89
+ const interpolate_cnd_t &cnd = interpolate_cnd_default){
90
+
91
+ FloatT t_diff(t0 - t);
92
+ if((!force_update)
93
+ && ((std::abs(t_diff) <= 10)
94
+ || ((dt.size() >= 2)
95
+ && (std::abs(t_diff + dt[0]) <= std::abs(t_diff + dt[1])))) ){
96
+ return *this;
97
+ }
98
+
99
+ // If the 1st and 2nd nearest epochs are changed, then recalculate interpolation targets.
100
+ struct {
101
+ const GPS_Time<FloatT> &t_base;
102
+ bool operator()(
103
+ const typename history_t::value_type &rhs,
104
+ const typename history_t::value_type &lhs) const {
105
+ return std::abs(rhs.first - t_base) < std::abs(lhs.first - t_base);
106
+ }
107
+ } cmp = {(t0 = t)};
108
+
109
+ buf.resize(cnd.max_epochs);
110
+ dt.clear();
111
+ // extract t where t0-dt <= t <= t0+dt, then sort by ascending order of |t-t0|
112
+ for(typename buf_t::const_iterator
113
+ it(buf.begin()),
114
+ it_end(std::partial_sort_copy(
115
+ history.lower_bound(t - cnd.max_delta_t),
116
+ history.upper_bound(t + cnd.max_delta_t),
117
+ buf.begin(), buf.end(), cmp));
118
+ it != it_end; ++it){
119
+ dt.push_back(it->first - t0);
120
+ }
121
+ updated_full_cnd = (dt.size() >= cnd.max_epochs);
122
+
123
+ return *this;
124
+ }
125
+
126
+ template <class Ty, class Ty_Array>
127
+ Ty interpolate(
128
+ const GPS_Time<FloatT> &t, const Ty_Array &y,
129
+ Ty *derivative = NULL) const {
130
+ int order(dt.size() - 1);
131
+ do{
132
+ if(order > 0){break;}
133
+ if((order == 0) && (!derivative)){return y[0];}
134
+ throw std::range_error("Insufficient records for interpolation");
135
+ }while(false);
136
+ std::vector<Ty> y_buf(order), dy_buf(order);
137
+ interpolate_Neville(
138
+ dt, y, t - t0, y_buf, order,
139
+ &dy_buf, derivative ? 1 : 0);
140
+ if(derivative){*derivative = dy_buf[0];}
141
+ return y_buf[0];
142
+ }
143
+ Vector3<FloatT> interpolate_xyz(
144
+ const GPS_Time<FloatT> &t,
145
+ Vector3<FloatT> *derivative = NULL) const {
146
+ struct second_iterator : public buf_t::const_iterator {
147
+ second_iterator(const typename buf_t::const_iterator &it)
148
+ : buf_t::const_iterator(it) {}
149
+ const Vector3<FloatT> &operator[](const int &n) const {
150
+ return buf_t::const_iterator::operator[](n).second.xyz;
151
+ }
152
+ } xyz(buf.begin());
153
+ return interpolate(t, xyz, derivative);
154
+ }
155
+ FloatT interpolate_clk(
156
+ const GPS_Time<FloatT> &t,
157
+ FloatT *derivative = NULL) const {
158
+ struct second_iterator : public buf_t::const_iterator {
159
+ second_iterator(const typename buf_t::const_iterator &it)
160
+ : buf_t::const_iterator(it) {}
161
+ const FloatT &operator[](const int &n) const {
162
+ return buf_t::const_iterator::operator[](n).second.clk;
163
+ }
164
+ } clk(buf.begin());
165
+ return interpolate(t, clk, derivative);
166
+ }
167
+ } pos_clk, vel_rate;
168
+ } subset;
169
+
170
+ /**
171
+ * Precheck whether interpolate can be fully performed or not
172
+ *
173
+ * @return (bool) If interpolation condition is fully satisfied, then true is returned.
174
+ */
175
+ bool precheck(const GPS_Time<FloatT> &t) const {
176
+ // Only position/clock is checked, because velocity/rate can be calculated based on pos/clk.
177
+ subset.pos_clk.update(t, pos_history);
178
+ return subset.pos_clk.updated_full_cnd;
179
+ }
180
+
181
+ typename GPS_SpaceNode<FloatT>::SatelliteProperties::constellation_t
182
+ constellation(
183
+ const GPS_Time<FloatT> &t,
184
+ bool with_velocity = true) const {
185
+ typename GPS_SpaceNode<FloatT>::SatelliteProperties::constellation_t res;
186
+ if(with_velocity){
187
+ try{
188
+ res.velocity = subset.vel_rate.update(t, vel_history).interpolate_xyz(t);
189
+ with_velocity = false;
190
+ }catch(std::range_error &){}
191
+ }
192
+ Vector3<FloatT> vel;
193
+ res.position = subset.pos_clk.update(t, pos_history)
194
+ .interpolate_xyz(t, with_velocity ? &vel : NULL); // velocity fallback to use position
195
+ if(with_velocity){res.velocity = vel;}
196
+ return res;
197
+ }
198
+ typename GPS_SpaceNode<FloatT>::xyz_t position(
199
+ const GPS_Time<FloatT> &t) const {
200
+ return constellation(t, false).position;
201
+ }
202
+ typename GPS_SpaceNode<FloatT>::xyz_t velocity(
203
+ const GPS_Time<FloatT> &t) const {
204
+ return constellation(t, true).velocity;
205
+ }
206
+ FloatT clock_error(const GPS_Time<FloatT> &t) const {
207
+ return subset.pos_clk.update(t, pos_history).interpolate_clk(t);
208
+ }
209
+ FloatT clock_error_dot(const GPS_Time<FloatT> &t) const {
210
+ try{
211
+ return subset.vel_rate.update(t, vel_history).interpolate_clk(t);
212
+ }catch(std::range_error &){
213
+ FloatT res;
214
+ subset.pos_clk.update(t, pos_history).interpolate_clk(t, &res);
215
+ return res;
216
+ }
217
+ }
218
+
219
+ operator typename GPS_Solver_Base<FloatT>::satellite_t() const {
220
+ typedef typename GPS_Solver_Base<FloatT>::gps_time_t gt_t;
221
+ typedef typename GPS_Solver_Base<FloatT>::float_t float_t;
222
+ typedef typename GPS_Solver_Base<FloatT>::xyz_t xyz_t;
223
+ struct impl_t {
224
+ static inline const per_satellite_t &sat(const void *ptr) {
225
+ return *reinterpret_cast<const per_satellite_t *>(ptr);
226
+ }
227
+ static xyz_t position(const void *ptr, const gt_t &t_tx, const float_t &dt_transit) {
228
+ return sat(ptr).position(t_tx).after(dt_transit);
229
+ }
230
+ static xyz_t velocity(const void *ptr, const gt_t &t_tx, const float_t &dt_transit) {
231
+ return sat(ptr).velocity(t_tx).after(dt_transit);
232
+ }
233
+ static float_t clock_error(const void *ptr, const gt_t &t_tx) {
234
+ return sat(ptr).clock_error(t_tx);
235
+ }
236
+ static float_t clock_error_dot(const void *ptr, const gt_t &t_tx) {
237
+ return sat(ptr).clock_error_dot(t_tx);
238
+ }
239
+ };
240
+ typename GPS_Solver_Base<FloatT>::satellite_t res = {
241
+ this,
242
+ impl_t::position, impl_t::velocity,
243
+ impl_t::clock_error, impl_t::clock_error_dot
244
+ };
245
+ return res;
246
+ }
247
+ };
248
+ typedef std::map<int, per_satellite_t> satellites_t;
249
+ satellites_t satellites;
250
+
251
+ typedef std::set<GPS_Time<FloatT> > epochs_t;
252
+ epochs_t epochs() const {
253
+ epochs_t res;
254
+ struct time_iterator : public per_satellite_t::history_t::const_iterator {
255
+ time_iterator(
256
+ const typename per_satellite_t::history_t::const_iterator &it)
257
+ : per_satellite_t::history_t::const_iterator(it) {}
258
+ GPS_Time<FloatT> operator*() const {
259
+ return (*this)->first;
260
+ }
261
+ };
262
+ for(typename satellites_t::const_iterator
263
+ it(satellites.begin()), it_end(satellites.end());
264
+ it != it_end; ++it){
265
+ res.insert(
266
+ time_iterator(it->second.pos_history.begin()),
267
+ time_iterator(it->second.pos_history.end()));
268
+ res.insert(
269
+ time_iterator(it->second.vel_history.begin()),
270
+ time_iterator(it->second.vel_history.end()));
271
+ }
272
+ return res;
273
+ }
274
+
275
+ bool has_position() const {
276
+ for(typename satellites_t::const_iterator
277
+ it(satellites.begin()), it_end(satellites.end());
278
+ it != it_end; ++it){
279
+ if(!it->second.pos_history.empty()){return true;};
280
+ }
281
+ return false;
282
+ }
283
+ bool has_velocity() const {
284
+ for(typename satellites_t::const_iterator
285
+ it(satellites.begin()), it_end(satellites.end());
286
+ it != it_end; ++it){
287
+ if(!it->second.vel_history.empty()){return true;};
288
+ }
289
+ return false;
290
+ }
291
+
292
+ typename GPS_Solver_Base<FloatT>::satellite_t select(
293
+ const int &sat_id, const GPS_Time<FloatT> &t) const {
294
+ do{
295
+ typename satellites_t::const_iterator it(satellites.find(sat_id));
296
+ if(it == satellites.end()){break;}
297
+ if(!it->second.precheck(t)){break;}
298
+ return it->second;
299
+ }while(false);
300
+ return GPS_Solver_Base<FloatT>::satellite_t::unavailable();
301
+ }
302
+
303
+ enum system_t {
304
+ SYSTEM_GPS = (int)'\0' << 8,
305
+ SYSTEM_SBAS = SYSTEM_GPS,
306
+ SYSTEM_QZSS = SYSTEM_GPS,
307
+ SYSTEM_GLONASS = (int)'R' << 8,
308
+ SYSTEM_LEO = (int)'L' << 8,
309
+ SYSTEM_GALILEO = (int)'E' << 8,
310
+ SYSTEM_BEIDOU = (int)'C' << 8,
311
+ SYSTEM_IRNSS = (int)'I' << 8,
312
+ };
313
+
314
+ #define gen_func(sys) \
315
+ static typename GPS_Solver_Base<FloatT>::satellite_t select_ ## sys( \
316
+ const void *ptr, const int &prn, const GPS_Time<FloatT> &receiver_time){ \
317
+ return reinterpret_cast<const SP3_Product<FloatT> *>(ptr) \
318
+ ->select(prn + SYSTEM_ ## sys, receiver_time); \
319
+ }
320
+ gen_func(GPS);
321
+ gen_func(GLONASS);
322
+ gen_func(LEO);
323
+ gen_func(GALILEO);
324
+ gen_func(BEIDOU);
325
+ gen_func(IRNSS);
326
+ #undef gen_fun
327
+
328
+ /**
329
+ * push SP3 product to satellite selector
330
+ *
331
+ * @param slct satellite selector having impl and impl_select members
332
+ * @param sys target system, default is GPS
333
+ * @return (bool) If push is successfully performed, true will be returned.
334
+ */
335
+ template <class SelectorT>
336
+ bool push(SelectorT &slct, const system_t &sys = SYSTEM_GPS) const {
337
+ switch(sys){
338
+ case SYSTEM_GPS: // SBAS and QZSS are identically treated as GPS.
339
+ //case SYSTEM_SBAS:
340
+ //case SYSTEM_QZSS:
341
+ slct.impl_select = select_GPS; break;
342
+ case SYSTEM_GLONASS: slct.impl_select = select_GLONASS; break;
343
+ case SYSTEM_LEO: slct.impl_select = select_LEO; break;
344
+ case SYSTEM_GALILEO: slct.impl_select = select_GALILEO; break;
345
+ case SYSTEM_BEIDOU: slct.impl_select = select_BEIDOU; break;
346
+ case SYSTEM_IRNSS: slct.impl_select = select_IRNSS; break;
347
+ default: return false;
348
+ }
349
+ slct.impl = this;
350
+ return true;
351
+ }
352
+
353
+ struct satellite_count_t {
354
+ int gps, sbas, qzss, glonass, leo, galileo, beidou, irnss, unknown;
355
+ };
356
+ satellite_count_t satellite_count() const {
357
+ satellite_count_t res = {0};
358
+ for(typename satellites_t::const_iterator
359
+ it(satellites.begin()), it_end(satellites.end());
360
+ it != it_end; ++it){
361
+ switch(it->first & 0xFF00){
362
+ case SYSTEM_GPS: {
363
+ int id(it->first & 0xFF);
364
+ if(id < 100){++res.gps;}
365
+ else if(id < 192){++res.sbas;}
366
+ else{++res.qzss;}
367
+ break;
368
+ }
369
+ case SYSTEM_GLONASS: ++res.glonass; break;
370
+ case SYSTEM_LEO: ++res.leo; break;
371
+ case SYSTEM_GALILEO: ++res.galileo; break;
372
+ case SYSTEM_BEIDOU: ++res.beidou; break;
373
+ case SYSTEM_IRNSS: ++res.irnss; break;
374
+ default: ++res.unknown; break;
375
+ }
376
+ }
377
+ return res;
378
+ }
379
+ };
380
+
381
+ template <class FloatT>
382
+ const typename SP3_Product<FloatT>::per_satellite_t::interpolate_cnd_t
383
+ SP3_Product<FloatT>::per_satellite_t::interpolate_cnd_default = {
384
+ 9, // max_epochs
385
+ 60 * 60 * 2, // max_delta_t, default is 2 hr = 15 min interval records; (2 hr * 2 / (9 - 1) = 15 min)
386
+ };
387
+
388
+ template <class FloatT>
389
+ class SP3_Reader {
390
+ protected:
391
+ typename TextHelper<>::crlf_stream_t src;
392
+ public:
393
+ struct l1_t {
394
+ char version_symbol[2];
395
+ char pos_or_vel_flag[1];
396
+ int year_start;
397
+ int month_start;
398
+ int day_of_month_st;
399
+ int hour_start;
400
+ int minute_start;
401
+ FloatT second_start;
402
+ int number_of_epochs;
403
+ char data_used[5];
404
+ char coordinate_sys[5];
405
+ char orbit_type[3];
406
+ char agency[4];
407
+ l1_t &operator=(const GPS_Time<FloatT> &t) {
408
+ std::tm t_(t.c_tm());
409
+ year_start = t_.tm_year + 1900;
410
+ month_start = t_.tm_mon + 1;
411
+ day_of_month_st = t_.tm_mday;
412
+ hour_start = t_.tm_hour;
413
+ minute_start = t_.tm_min;
414
+ second_start = (t.seconds - (int)t.seconds) + t_.tm_sec;
415
+ return *this;
416
+ }
417
+ };
418
+ struct l2_t {
419
+ char symbols[2];
420
+ int gps_week;
421
+ FloatT seconds_of_week;
422
+ FloatT epoch_interval;
423
+ int mod_jul_day_st;
424
+ FloatT fractional_day;
425
+ };
426
+ struct l3_11_t {
427
+ char symbols[2];
428
+ int number_of_sats;
429
+ int sat_id[17];
430
+ };
431
+ struct l12_20_t {
432
+ char symbols[2];
433
+ int sat_accuracy[17];
434
+ };
435
+ struct l21_22_t {
436
+ char symbols[2];
437
+ char file_type[2];
438
+ char _2_characters[2];
439
+ char time_system[3];
440
+ char _3_characters[3];
441
+ char _4_characters[4][4];
442
+ char _5_characters[4][5];
443
+ };
444
+ struct l23_24_t {
445
+ char symbols[2];
446
+ FloatT base_for_pos_vel;
447
+ FloatT base_for_clk_rate;
448
+ FloatT _14_column_float;
449
+ FloatT _18_column_float;
450
+ };
451
+ struct l25_26_t {
452
+ char symbols[2];
453
+ int _4_column_int[4];
454
+ int _6_column_int[4];
455
+ int _9_column_int;
456
+ };
457
+ struct comment_t {
458
+ char symbols[2];
459
+ char comment[77];
460
+ };
461
+ struct epoch_t {
462
+ char symbols[2];
463
+ int year_start;
464
+ int month_start;
465
+ int day_of_month_st;
466
+ int hour_start;
467
+ int minute_start;
468
+ FloatT second_start;
469
+ std::tm c_tm() const {
470
+ std::tm res = {
471
+ (int)second_start,
472
+ minute_start,
473
+ hour_start,
474
+ day_of_month_st,
475
+ month_start - 1,
476
+ year_start - 1900,
477
+ };
478
+ std::mktime(&res);
479
+ return res;
480
+ }
481
+ operator GPS_Time<FloatT>() const {
482
+ return GPS_Time<FloatT>(c_tm(), second_start - (int)second_start);
483
+ }
484
+ epoch_t &operator=(const GPS_Time<FloatT> &t) {
485
+ std::tm t_(t.c_tm());
486
+ year_start = t_.tm_year + 1900;
487
+ month_start = t_.tm_mon + 1;
488
+ day_of_month_st = t_.tm_mday;
489
+ hour_start = t_.tm_hour;
490
+ minute_start = t_.tm_min;
491
+ second_start = (t.seconds - (int)t.seconds) + t_.tm_sec;
492
+ return *this;
493
+ }
494
+ };
495
+ struct position_clock_t {
496
+ char symbol[1];
497
+ int vehicle_id;
498
+ FloatT coordinate_km[3];
499
+ FloatT clock_us;
500
+ bool has_sdev;
501
+ int sdev_b_n_mm[3];
502
+ int c_sdev_b_n_psec;
503
+ char clock_event_flag[1];
504
+ char clock_pred_flag[1];
505
+ char maneuver_flag[1];
506
+ char orbit_pred_flag[1];
507
+ };
508
+ struct position_clock_correlation_t {
509
+ char symbols[2];
510
+ int sdev_mm[3];
511
+ int clk_sdev_psec;
512
+ int xy_correlation;
513
+ int xz_correlation;
514
+ int xc_correlation;
515
+ int yz_correlation;
516
+ int yc_correlation;
517
+ int zc_correlation;
518
+ };
519
+ struct velocity_rate_t {
520
+ char symbol[1];
521
+ int vehicle_id;
522
+ FloatT velocity_dm_s[3];
523
+ FloatT clock_rate_chg_100ps_s; // 10^-4 microseconds/second = 100 ps/s
524
+ bool has_sdev;
525
+ int vel_sdev_100nm_s[3];
526
+ int clkrate_sdev_10_4_ps_s; // 10^-4 ps/s
527
+ };
528
+ struct velocity_rate_correlation_t {
529
+ char symbols[2];
530
+ int vel_sdev_100nm_s[3];
531
+ int clkrate_sdev_10_4_ps_s;
532
+ int xy_correlation;
533
+ int xz_correlation;
534
+ int xc_correlation;
535
+ int yz_correlation;
536
+ int yc_correlation;
537
+ int zc_correlation;
538
+ };
539
+ struct parsed_t {
540
+ enum {
541
+ UNKNOWN,
542
+ L1,
543
+ L2,
544
+ L3_11,
545
+ L12_20,
546
+ L21_22,
547
+ L23_24,
548
+ L25_26,
549
+ COMMENT,
550
+ EPOCH,
551
+ POSITION_CLOCK,
552
+ POSITION_CLOCK_CORRELATION,
553
+ VELOCITY_RATE,
554
+ VELOCITY_RATE_CORRELATION,
555
+ PARSED_ITEMS,
556
+ } type;
557
+ union {
558
+ struct l1_t l1;
559
+ struct l2_t l2;
560
+ struct l3_11_t l3_11;
561
+ struct l12_20_t l12_20;
562
+ struct l21_22_t l21_22;
563
+ struct l23_24_t l23_24;
564
+ struct l25_26_t l25_26;
565
+ struct comment_t comment;
566
+ struct epoch_t epoch;
567
+ struct position_clock_t position_clock;
568
+ struct position_clock_correlation_t position_clock_correlation;
569
+ struct velocity_rate_t velocity_rate;
570
+ struct velocity_rate_correlation_t velocity_rate_correlation;
571
+ } item;
572
+ };
573
+
574
+ static const typename TextHelper<>::convert_item_t
575
+ l1_items[13],
576
+ l2_items[6],
577
+ l3_11_items[19],
578
+ l12_20_items[18],
579
+ l21_22_items[13],
580
+ l23_24_items[5],
581
+ l25_26_items[10],
582
+ comment_items[2],
583
+ epoch_items[7],
584
+ position_clock_items[14],
585
+ position_clock_correlation_items[11],
586
+ velocity_rate_items[10],
587
+ velocity_rate_correlation_items[11];
588
+
589
+ SP3_Reader(std::istream &in) : src(in) {}
590
+
591
+ bool has_next() {
592
+ return !(src.eof() || src.fail());
593
+ }
594
+
595
+ parsed_t parse_line() {
596
+ parsed_t res = {parsed_t::UNKNOWN, {0}};
597
+
598
+ char buf[0x100] = {0};
599
+ src.getline(buf, sizeof(buf));
600
+ std::string line(buf);
601
+
602
+ switch(buf[0]){
603
+ case '#':
604
+ switch(buf[1]){
605
+ case '#':
606
+ TextHelper<>::str2val(l2_items, line, &res.item);
607
+ res.type = parsed_t::L2;
608
+ break;
609
+ default:
610
+ TextHelper<>::str2val(l1_items, line, &res.item);
611
+ res.type = parsed_t::L1;
612
+ break;
613
+ }
614
+ break;
615
+ case '+':
616
+ switch(buf[1]){
617
+ case ' ':
618
+ TextHelper<>::str2val(l3_11_items, line, &res.item);
619
+ res.type = parsed_t::L3_11;
620
+ break;
621
+ case '+':
622
+ TextHelper<>::str2val(l12_20_items, line, &res.item);
623
+ res.type = parsed_t::L12_20;
624
+ break;
625
+ }
626
+ break;
627
+ case '%':
628
+ switch(buf[1]){
629
+ case 'c':
630
+ TextHelper<>::str2val(l21_22_items, line, &res.item);
631
+ res.type = parsed_t::L21_22;
632
+ break;
633
+ case 'f':
634
+ TextHelper<>::str2val(l23_24_items, line, &res.item);
635
+ res.type = parsed_t::L23_24;
636
+ break;
637
+ case 'i':
638
+ TextHelper<>::str2val(l25_26_items, line, &res.item);
639
+ res.type = parsed_t::L25_26;
640
+ break;
641
+ }
642
+ break;
643
+ case '/':
644
+ res.type = parsed_t::COMMENT; // TODO
645
+ break;
646
+ case '*':
647
+ TextHelper<>::str2val(epoch_items, line, &res.item);
648
+ res.type = parsed_t::EPOCH;
649
+ break;
650
+ case 'P':
651
+ res.item.position_clock.has_sdev = (line.length() > 60);
652
+ TextHelper<>::str2val(
653
+ position_clock_items,
654
+ (res.item.position_clock.has_sdev ? 14 : 6),
655
+ line, &res.item);
656
+ res.type = parsed_t::POSITION_CLOCK;
657
+ break;
658
+ case 'V':
659
+ res.item.velocity_rate.has_sdev = (line.length() > 60);
660
+ TextHelper<>::str2val(
661
+ velocity_rate_items,
662
+ (res.item.velocity_rate.has_sdev ? 10 : 6),
663
+ line, &res.item);
664
+ res.type = parsed_t::VELOCITY_RATE;
665
+ break;
666
+ case 'E':
667
+ switch(buf[1]){
668
+ case 'P':
669
+ TextHelper<>::str2val(position_clock_correlation_items, line, &res.item);
670
+ res.type = parsed_t::POSITION_CLOCK_CORRELATION;
671
+ break;
672
+ case 'V':
673
+ TextHelper<>::str2val(velocity_rate_correlation_items, line, &res.item);
674
+ res.type = parsed_t::VELOCITY_RATE_CORRELATION;
675
+ break;
676
+ }
677
+ break;
678
+ }
679
+
680
+ return res;
681
+ }
682
+
683
+ struct conv_t {
684
+ /**
685
+ * @param value satellite identifier. For GPS, SBAS, and QZSS, it is PRN number.
686
+ * For other satellite systems, it is ((prefix_char << 8) | satellite_number)
687
+ * like 20993 = ((82 << 8) | 1) indicating R01 (because 'R' = 82.
688
+ */
689
+ static bool sat_id(
690
+ std::string &buf, const int &offset, const int &length, void *value,
691
+ const int &opt = 0, const bool &str2val = true){
692
+ // format: a letter followed by a 2-digit integer between 01 and 99.
693
+ if(str2val){
694
+ if(!TextHelper<>::template format_t<int>::d(
695
+ buf, offset + 1, length - 1, value, opt, true)){
696
+ return false;
697
+ }
698
+ switch(buf[offset]){
699
+ case 'G': break; // GPS
700
+ case 'S': // Satellite-Based Augmentation System (SBAS) satellites
701
+ *static_cast<int *>(value) += 100; break;
702
+ case 'J': // QZSS, nn=PRN-192, ex) J01 => PRN=193
703
+ *static_cast<int *>(value) += 192; break;
704
+ case 'R': // GLONASS
705
+ case 'L': // Low-Earth Orbiting (LEO) satellites
706
+ case 'E': // Galileo
707
+ case 'C': // BeiDou
708
+ case 'I': // IRNSS
709
+ *static_cast<int *>(value) += ((int)buf[offset] << 8); break;
710
+ case ' ':
711
+ *static_cast<int *>(value) = 0; break; // TODO
712
+ default:
713
+ return false; // unsupported
714
+ }
715
+ return true;
716
+ }else{
717
+ int digit2(*static_cast<int *>(value));
718
+ if(digit2 < 0){return false;}
719
+ char prefix((char)((digit2 >> 8) & 0xFF));
720
+ do{
721
+ if(digit2 == 0){
722
+ prefix = ' ';
723
+ break;
724
+ }
725
+ if(digit2 <= 32){ // GPS
726
+ prefix = 'G';
727
+ break;
728
+ }
729
+ if(digit2 < 120){return false;}
730
+ if(digit2 <= 158){ // SBAS
731
+ prefix = 'S';
732
+ digit2 -= 100;
733
+ break;
734
+ }
735
+ if(digit2 < 193){return false;}
736
+ if(digit2 <= 206){ // QZSS
737
+ prefix = 'J';
738
+ digit2 -= 192;
739
+ break;
740
+ }
741
+ switch(prefix){
742
+ case 'R': // GLONASS
743
+ case 'L': // Low-Earth Orbiting (LEO) satellites
744
+ case 'E': // Galileo
745
+ case 'C': // BeiDou
746
+ case 'I': // IRNSS
747
+ digit2 &= 0xFF;
748
+ break;
749
+ default:
750
+ return false; // unsupported
751
+ }
752
+ }while(false);
753
+ buf[offset] = prefix;
754
+ return TextHelper<>::template format_t<int>::d(
755
+ buf, offset + 1, length - 1, &digit2, digit2 > 0 ? 1 : 0, false);
756
+ }
757
+ }
758
+ };
759
+
760
+ static int read_all(std::istream &in, SP3_Product<FloatT> &dst) {
761
+ SP3_Reader<FloatT> src(in);
762
+ typedef SP3_Product<FloatT> dst_t;
763
+ int res(0);
764
+ struct buf_t {
765
+ dst_t &dst;
766
+ int &res;
767
+ epoch_t epoch;
768
+ enum {
769
+ TS_UNKNOWN,
770
+ TS_GPS,
771
+ TS_UTC
772
+ } time_system;
773
+ struct pv_t {
774
+ position_clock_t pos;
775
+ velocity_rate_t vel;
776
+ pv_t(){pos.symbol[0] = vel.symbol[0] = 0;}
777
+ };
778
+ typedef std::map<int, pv_t> entries_t;
779
+ entries_t entries;
780
+ buf_t(dst_t &dst_, int &res_) : dst(dst_), res(res_), time_system(TS_UNKNOWN), entries(){
781
+ epoch.symbols[0] = 0;
782
+ }
783
+ void flush(){
784
+ if(!epoch.symbols[0]){return;}
785
+ GPS_Time<FloatT> gpst(epoch);
786
+ if(time_system == TS_UTC){
787
+ gpst += GPS_Time<FloatT>::guess_leap_seconds(gpst);
788
+ }
789
+ for(typename entries_t::const_iterator it(entries.begin()), it_end(entries.end());
790
+ it != it_end; ++it){
791
+ if(it->second.pos.symbol[0]){
792
+ typename dst_t::prop_t prop = {
793
+ Vector3<FloatT>(it->second.pos.coordinate_km) * 1E3,
794
+ it->second.pos.clock_us * 1E-6,
795
+ };
796
+ dst.satellites[it->first].pos_history.insert(std::make_pair(gpst, prop));
797
+ }
798
+ if(it->second.vel.symbol[0]){
799
+ typename dst_t::prop_t prop = {
800
+ Vector3<FloatT>(it->second.vel.velocity_dm_s) * 1E-1,
801
+ it->second.vel.clock_rate_chg_100ps_s * 1E-10,
802
+ };
803
+ dst.satellites[it->first].vel_history.insert(std::make_pair(gpst, prop));
804
+ }
805
+ ++res;
806
+ }
807
+ entries.clear();
808
+ }
809
+ } buf(dst, res);
810
+ while(src.has_next()){
811
+ parsed_t parsed(src.parse_line());
812
+ switch(parsed.type){
813
+ case parsed_t::L21_22: // check time system
814
+ if(buf.time_system != buf_t::TS_UNKNOWN){break;}
815
+ if(std::strncmp(parsed.item.l21_22.time_system, "GPS", 3) == 0){
816
+ buf.time_system = buf_t::TS_GPS;
817
+ }else if(std::strncmp(parsed.item.l21_22.time_system, "UTC", 3) == 0){
818
+ buf.time_system = buf_t::TS_UTC;
819
+ }
820
+ break;
821
+ case parsed_t::EPOCH:
822
+ buf.flush();
823
+ buf.epoch = parsed.item.epoch;
824
+ break;
825
+ case parsed_t::POSITION_CLOCK: {
826
+ int sat_id(parsed.item.position_clock.vehicle_id);
827
+ buf.entries[sat_id].pos = parsed.item.position_clock;
828
+ break;
829
+ }
830
+ case parsed_t::VELOCITY_RATE: {
831
+ int sat_id(parsed.item.velocity_rate.vehicle_id);
832
+ buf.entries[sat_id].vel = parsed.item.velocity_rate;
833
+ break;
834
+ }
835
+ default: break;
836
+ }
837
+ }
838
+ buf.flush();
839
+ return res;
840
+ }
841
+ };
842
+
843
+ #define GEN_C(offset, length, container_type, container_member) \
844
+ {TextHelper<>::template format_t<char>::c, offset, length, \
845
+ offsetof(container_type, container_member), 0}
846
+ #define GEN_I(offset, length, container_type, container_member) \
847
+ {TextHelper<>::template format_t<int>::d, offset, length, \
848
+ offsetof(container_type, container_member), 0}
849
+ #define GEN_I2(offset, length, container_type, container_member) \
850
+ {TextHelper<>::template format_t<int>::d_blank, offset, length, \
851
+ offsetof(container_type, container_member), 0}
852
+ #define GEN_E(offset, length, container_type, container_member, precision) \
853
+ {TextHelper<>::template format_t<FloatT>::f, offset, length, \
854
+ offsetof(container_type, container_member), precision}
855
+ #define GEN_sat(offset, length, container_type, container_member) \
856
+ {SP3_Reader<FloatT>::conv_t::sat_id, offset, length, \
857
+ offsetof(container_type, container_member)}
858
+
859
+ template <class FloatT>
860
+ const typename TextHelper<>::convert_item_t SP3_Reader<FloatT>::l1_items[13] = {
861
+ GEN_C(0, 2, l1_t, version_symbol),
862
+ GEN_C(2, 1, l1_t, pos_or_vel_flag),
863
+ GEN_I(3, 4, l1_t, year_start),
864
+ GEN_I(8, 2, l1_t, month_start),
865
+ GEN_I(11, 2, l1_t, day_of_month_st),
866
+ GEN_I(14, 2, l1_t, hour_start),
867
+ GEN_I(17, 2, l1_t, minute_start),
868
+ GEN_E(20, 11, l1_t, second_start, 8),
869
+ GEN_I(32, 7, l1_t, number_of_epochs),
870
+ GEN_C(40, 5, l1_t, data_used),
871
+ GEN_C(46, 5, l1_t, coordinate_sys),
872
+ GEN_C(52, 3, l1_t, orbit_type),
873
+ GEN_C(56, 4, l1_t, agency),
874
+ };
875
+ template <class FloatT>
876
+ const typename TextHelper<>::convert_item_t SP3_Reader<FloatT>::l2_items[6] = {
877
+ GEN_C(0, 2, l2_t, symbols),
878
+ GEN_I(3, 4, l2_t, gps_week),
879
+ GEN_E(8, 15, l2_t, seconds_of_week, 8),
880
+ GEN_E(24, 14, l2_t, epoch_interval, 8),
881
+ GEN_I(39, 5, l2_t, mod_jul_day_st),
882
+ GEN_E(45, 15, l2_t, fractional_day, 13),
883
+ };
884
+ template <class FloatT>
885
+ const typename TextHelper<>::convert_item_t SP3_Reader<FloatT>::l3_11_items[19] = {
886
+ GEN_C(0, 2, l3_11_t, symbols),
887
+ GEN_I2(3, 3, l3_11_t, number_of_sats),
888
+ GEN_sat(9, 3, l3_11_t, sat_id[0]),
889
+ GEN_sat(12, 3, l3_11_t, sat_id[1]),
890
+ GEN_sat(15, 3, l3_11_t, sat_id[2]),
891
+ GEN_sat(18, 3, l3_11_t, sat_id[3]),
892
+ GEN_sat(21, 3, l3_11_t, sat_id[4]),
893
+ GEN_sat(24, 3, l3_11_t, sat_id[5]),
894
+ GEN_sat(27, 3, l3_11_t, sat_id[6]),
895
+ GEN_sat(30, 3, l3_11_t, sat_id[7]),
896
+ GEN_sat(33, 3, l3_11_t, sat_id[8]),
897
+ GEN_sat(36, 3, l3_11_t, sat_id[9]),
898
+ GEN_sat(39, 3, l3_11_t, sat_id[10]),
899
+ GEN_sat(42, 3, l3_11_t, sat_id[11]),
900
+ GEN_sat(45, 3, l3_11_t, sat_id[12]),
901
+ GEN_sat(48, 3, l3_11_t, sat_id[13]),
902
+ GEN_sat(51, 3, l3_11_t, sat_id[14]),
903
+ GEN_sat(54, 3, l3_11_t, sat_id[15]),
904
+ GEN_sat(57, 3, l3_11_t, sat_id[16]),
905
+ };
906
+ template <class FloatT>
907
+ const typename TextHelper<>::convert_item_t SP3_Reader<FloatT>::l12_20_items[18] = {
908
+ GEN_C(0, 2, l12_20_t, symbols),
909
+ GEN_I(9, 3, l12_20_t, sat_accuracy[0]),
910
+ GEN_I(12, 3, l12_20_t, sat_accuracy[1]),
911
+ GEN_I(15, 3, l12_20_t, sat_accuracy[2]),
912
+ GEN_I(18, 3, l12_20_t, sat_accuracy[3]),
913
+ GEN_I(21, 3, l12_20_t, sat_accuracy[4]),
914
+ GEN_I(24, 3, l12_20_t, sat_accuracy[5]),
915
+ GEN_I(27, 3, l12_20_t, sat_accuracy[6]),
916
+ GEN_I(30, 3, l12_20_t, sat_accuracy[7]),
917
+ GEN_I(33, 3, l12_20_t, sat_accuracy[8]),
918
+ GEN_I(36, 3, l12_20_t, sat_accuracy[9]),
919
+ GEN_I(39, 3, l12_20_t, sat_accuracy[10]),
920
+ GEN_I(42, 3, l12_20_t, sat_accuracy[11]),
921
+ GEN_I(45, 3, l12_20_t, sat_accuracy[12]),
922
+ GEN_I(48, 3, l12_20_t, sat_accuracy[13]),
923
+ GEN_I(51, 3, l12_20_t, sat_accuracy[14]),
924
+ GEN_I(54, 3, l12_20_t, sat_accuracy[15]),
925
+ GEN_I(57, 3, l12_20_t, sat_accuracy[16]),
926
+ };
927
+ template <class FloatT>
928
+ const typename TextHelper<>::convert_item_t SP3_Reader<FloatT>::l21_22_items[13] = {
929
+ GEN_C(0, 2, l21_22_t, symbols),
930
+ GEN_C(3, 2, l21_22_t, file_type),
931
+ GEN_C(6, 2, l21_22_t, _2_characters),
932
+ GEN_C(9, 3, l21_22_t, time_system),
933
+ GEN_C(13, 3, l21_22_t, _3_characters),
934
+ GEN_C(17, 4, l21_22_t, _4_characters[0]),
935
+ GEN_C(22, 4, l21_22_t, _4_characters[1]),
936
+ GEN_C(27, 4, l21_22_t, _4_characters[2]),
937
+ GEN_C(32, 4, l21_22_t, _4_characters[3]),
938
+ GEN_C(37, 5, l21_22_t, _5_characters[0]),
939
+ GEN_C(43, 5, l21_22_t, _5_characters[1]),
940
+ GEN_C(49, 5, l21_22_t, _5_characters[2]),
941
+ GEN_C(55, 5, l21_22_t, _5_characters[3]),
942
+ };
943
+ template <class FloatT>
944
+ const typename TextHelper<>::convert_item_t SP3_Reader<FloatT>::l23_24_items[5] = {
945
+ GEN_C(0, 2, l23_24_t, symbols),
946
+ GEN_E(3, 10, l23_24_t, base_for_pos_vel, 7),
947
+ GEN_E(14, 12, l23_24_t, base_for_clk_rate, 9),
948
+ GEN_E(27, 14, l23_24_t, _14_column_float, 11),
949
+ GEN_E(42, 18, l23_24_t, _18_column_float, 15),
950
+ };
951
+ template <class FloatT>
952
+ const typename TextHelper<>::convert_item_t SP3_Reader<FloatT>::l25_26_items[10] = {
953
+ GEN_C(0, 2, l25_26_t, symbols),
954
+ GEN_I(3, 4, l25_26_t, _4_column_int[0]),
955
+ GEN_I(8, 4, l25_26_t, _4_column_int[1]),
956
+ GEN_I(13, 4, l25_26_t, _4_column_int[2]),
957
+ GEN_I(18, 4, l25_26_t, _4_column_int[3]),
958
+ GEN_I(23, 6, l25_26_t, _6_column_int[0]),
959
+ GEN_I(30, 6, l25_26_t, _6_column_int[1]),
960
+ GEN_I(37, 6, l25_26_t, _6_column_int[2]),
961
+ GEN_I(44, 6, l25_26_t, _6_column_int[3]),
962
+ GEN_I(51, 9, l25_26_t, _9_column_int),
963
+ };
964
+ template <class FloatT>
965
+ const typename TextHelper<>::convert_item_t SP3_Reader<FloatT>::comment_items[2] = {
966
+ GEN_C(0, 2, comment_t, symbols),
967
+ GEN_C(3, 57, comment_t, comment),
968
+ };
969
+ template <class FloatT>
970
+ const typename TextHelper<>::convert_item_t SP3_Reader<FloatT>::epoch_items[7] = {
971
+ GEN_C(0, 2, epoch_t, symbols),
972
+ GEN_I(3, 4, epoch_t, year_start),
973
+ GEN_I(8, 2, epoch_t, month_start),
974
+ GEN_I(11, 2, epoch_t, day_of_month_st),
975
+ GEN_I(14, 2, epoch_t, hour_start),
976
+ GEN_I(17, 2, epoch_t, minute_start),
977
+ GEN_E(20, 11, epoch_t, second_start, 8),
978
+ };
979
+ template <class FloatT>
980
+ const typename TextHelper<>::convert_item_t SP3_Reader<FloatT>::position_clock_items[14] = {
981
+ GEN_C(0, 1, position_clock_t, symbol),
982
+ GEN_sat(1, 3, position_clock_t, vehicle_id),
983
+ GEN_E(4, 14, position_clock_t, coordinate_km[0], 6),
984
+ GEN_E(18, 14, position_clock_t, coordinate_km[1], 6),
985
+ GEN_E(32, 14, position_clock_t, coordinate_km[2], 6),
986
+ GEN_E(46, 14, position_clock_t, clock_us, 6),
987
+ GEN_I(61, 2, position_clock_t, sdev_b_n_mm[0]),
988
+ GEN_I(64, 2, position_clock_t, sdev_b_n_mm[1]),
989
+ GEN_I(67, 2, position_clock_t, sdev_b_n_mm[2]),
990
+ GEN_I(70, 3, position_clock_t, c_sdev_b_n_psec),
991
+ GEN_C(74, 1, position_clock_t, clock_event_flag),
992
+ GEN_C(75, 1, position_clock_t, clock_pred_flag),
993
+ GEN_C(78, 1, position_clock_t, maneuver_flag),
994
+ GEN_C(79, 1, position_clock_t, orbit_pred_flag),
995
+ };
996
+ template <class FloatT>
997
+ const typename TextHelper<>::convert_item_t SP3_Reader<FloatT>::position_clock_correlation_items[11] = {
998
+ GEN_C(0, 2, position_clock_correlation_t, symbols),
999
+ GEN_I(4, 4, position_clock_correlation_t, sdev_mm[0]),
1000
+ GEN_I(9, 4, position_clock_correlation_t, sdev_mm[1]),
1001
+ GEN_I(14, 4, position_clock_correlation_t, sdev_mm[2]),
1002
+ GEN_I(19, 7, position_clock_correlation_t, clk_sdev_psec),
1003
+ GEN_I(27, 8, position_clock_correlation_t, xy_correlation),
1004
+ GEN_I(36, 8, position_clock_correlation_t, xz_correlation),
1005
+ GEN_I(45, 8, position_clock_correlation_t, xc_correlation),
1006
+ GEN_I(54, 8, position_clock_correlation_t, yz_correlation),
1007
+ GEN_I(63, 8, position_clock_correlation_t, yc_correlation),
1008
+ GEN_I(72, 8, position_clock_correlation_t, zc_correlation),
1009
+ };
1010
+ template <class FloatT>
1011
+ const typename TextHelper<>::convert_item_t SP3_Reader<FloatT>::velocity_rate_items[10] = {
1012
+ GEN_C(0, 1, velocity_rate_t, symbol),
1013
+ GEN_sat(1, 3, velocity_rate_t, vehicle_id),
1014
+ GEN_E(4, 14, velocity_rate_t, velocity_dm_s[0], 6),
1015
+ GEN_E(18, 14, velocity_rate_t, velocity_dm_s[1], 6),
1016
+ GEN_E(32, 14, velocity_rate_t, velocity_dm_s[2], 6),
1017
+ GEN_E(46, 14, velocity_rate_t, clock_rate_chg_100ps_s, 6),
1018
+ GEN_I(61, 2, velocity_rate_t, vel_sdev_100nm_s[0]),
1019
+ GEN_I(64, 2, velocity_rate_t, vel_sdev_100nm_s[1]),
1020
+ GEN_I(67, 2, velocity_rate_t, vel_sdev_100nm_s[2]),
1021
+ GEN_I(70, 3, velocity_rate_t, clkrate_sdev_10_4_ps_s),
1022
+ };
1023
+ template <class FloatT>
1024
+ const typename TextHelper<>::convert_item_t SP3_Reader<FloatT>::velocity_rate_correlation_items[11] = {
1025
+ GEN_C(0, 2, velocity_rate_correlation_t, symbols),
1026
+ GEN_I(4, 4, velocity_rate_correlation_t, vel_sdev_100nm_s[0]),
1027
+ GEN_I(9, 4, velocity_rate_correlation_t, vel_sdev_100nm_s[1]),
1028
+ GEN_I(14, 4, velocity_rate_correlation_t, vel_sdev_100nm_s[2]),
1029
+ GEN_I(19, 7, velocity_rate_correlation_t, clkrate_sdev_10_4_ps_s),
1030
+ GEN_I(27, 8, velocity_rate_correlation_t, xy_correlation),
1031
+ GEN_I(36, 8, velocity_rate_correlation_t, xz_correlation),
1032
+ GEN_I(45, 8, velocity_rate_correlation_t, xc_correlation),
1033
+ GEN_I(54, 8, velocity_rate_correlation_t, yz_correlation),
1034
+ GEN_I(63, 8, velocity_rate_correlation_t, yc_correlation),
1035
+ GEN_I(72, 8, velocity_rate_correlation_t, zc_correlation),
1036
+ };
1037
+
1038
+ #undef GEN_C
1039
+ #undef GEN_I
1040
+ #undef GEN_I2
1041
+ #undef GEN_E
1042
+ #undef GEN_sat
1043
+
1044
+ template <class FloatT>
1045
+ class SP3_Writer {
1046
+ public:
1047
+ typedef SP3_Reader<FloatT> reader_t;
1048
+ static std::string print_line(const typename reader_t::parsed_t &parsed){
1049
+ static const struct {
1050
+ const typename TextHelper<>::convert_item_t *items;
1051
+ int items_num;
1052
+ const char *symbol;
1053
+ } table[reader_t::parsed_t::PARSED_ITEMS] = {
1054
+ {0}, // UNKNOWN
1055
+ #define MAKE_ENTRY(k, str) \
1056
+ {reader_t::k, sizeof(reader_t::k) / sizeof(reader_t::k[0]), str}
1057
+ MAKE_ENTRY(l1_items, "#"), // L1
1058
+ MAKE_ENTRY(l2_items, "##"), // L2
1059
+ MAKE_ENTRY(l3_11_items, "+ "), // L3_11
1060
+ MAKE_ENTRY(l12_20_items, "++"), // L12_20
1061
+ MAKE_ENTRY(l21_22_items, "%c"), // L21_22
1062
+ MAKE_ENTRY(l23_24_items, "%f"), // L23_24
1063
+ MAKE_ENTRY(l25_26_items, "%i"), // L25_26
1064
+ MAKE_ENTRY(comment_items, "/"), // COMMENT
1065
+ MAKE_ENTRY(epoch_items, "*"), // EPOCH
1066
+ MAKE_ENTRY(position_clock_items, "P"), // POSITION_CLOCK
1067
+ MAKE_ENTRY(position_clock_correlation_items, "EP"), // POSITION_CLOCK_CORRELATION
1068
+ MAKE_ENTRY(velocity_rate_items, "V"), // VELOCITY_RATE
1069
+ MAKE_ENTRY(velocity_rate_correlation_items, "EV"), // VELOCITY_RATE_CORRELATION
1070
+ #undef MAKE_ENTRY
1071
+ };
1072
+
1073
+ int res_length(60);
1074
+ int items_num(table[parsed.type].items_num);
1075
+ switch(parsed.type){
1076
+ case reader_t::parsed_t::POSITION_CLOCK:
1077
+ if(parsed.item.position_clock.has_sdev){res_length = 80;}
1078
+ else{items_num = 6;}
1079
+ break;
1080
+ case reader_t::parsed_t::VELOCITY_RATE:
1081
+ if(parsed.item.velocity_rate.has_sdev){res_length = 80;}
1082
+ else{items_num = 6;}
1083
+ break;
1084
+ case reader_t::parsed_t::POSITION_CLOCK_CORRELATION:
1085
+ case reader_t::parsed_t::VELOCITY_RATE_CORRELATION:
1086
+ res_length = 80;
1087
+ break;
1088
+ default:
1089
+ break;
1090
+ }
1091
+ std::string res(res_length, ' ');
1092
+ if((items_num <= 0)
1093
+ || (!TextHelper<>::val2str(table[parsed.type].items, items_num, res, &parsed.item))){
1094
+ return std::string();
1095
+ }
1096
+ res.replace(0, std::strlen(table[parsed.type].symbol), table[parsed.type].symbol);
1097
+ return res;
1098
+ }
1099
+
1100
+ static void dump_default(
1101
+ std::ostream &out, typename reader_t::parsed_t &item){
1102
+ out << print_line(item) << std::endl;
1103
+ }
1104
+
1105
+ static int write_all(
1106
+ std::ostream &out, const SP3_Product<FloatT> &src,
1107
+ void (*dump)(
1108
+ std::ostream &, typename reader_t::parsed_t &) = dump_default) {
1109
+ typedef SP3_Product<FloatT> src_t;
1110
+ typedef typename src_t::epochs_t epochs_t;
1111
+ epochs_t epochs(src.epochs());
1112
+ if(epochs.empty()){return 0;}
1113
+ { // 1st line
1114
+ typename reader_t::parsed_t header = {reader_t::parsed_t::L1};
1115
+ header.item.l1 = *epochs.begin();
1116
+ header.item.l1.number_of_epochs = epochs.size();
1117
+ header.item.l1.pos_or_vel_flag[0] = src.has_velocity() ? 'V' : 'P';
1118
+ dump(out, header);
1119
+ }
1120
+ { // 2nd line
1121
+ typename reader_t::parsed_t first_epoch = {reader_t::parsed_t::L2};
1122
+ GPS_Time<FloatT> t0(*epochs.begin());
1123
+ first_epoch.item.l2.gps_week = t0.week;
1124
+ first_epoch.item.l2.seconds_of_week = t0.seconds;
1125
+ first_epoch.item.l2.epoch_interval
1126
+ = (epochs.size() > 1) ? (*(++(epochs.begin())) - t0) : 0;
1127
+ FloatT day_of_week(t0.seconds / 86400);
1128
+ first_epoch.item.l2.mod_jul_day_st
1129
+ = 44244 + (t0.week * 7) + (int)day_of_week;
1130
+ first_epoch.item.l2.fractional_day
1131
+ = day_of_week - (int)day_of_week;
1132
+ dump(out, first_epoch);
1133
+ }
1134
+ typedef typename src_t::satellites_t sats_t;
1135
+ { // 3rd line
1136
+ int sats(src.satellites.size());
1137
+ typename reader_t::parsed_t sat_list = {reader_t::parsed_t::L3_11};
1138
+ sat_list.item.l3_11.number_of_sats = sats;
1139
+ typename sats_t::const_iterator
1140
+ it(src.satellites.begin()), it_end(src.satellites.end());
1141
+ int lines((sats + 16) / 17);
1142
+ for(int i(lines < 5 ? 5 : lines); i > 0; --i){
1143
+ for(int j(0); j < 17; ++j){
1144
+ sat_list.item.l3_11.sat_id[j] = ((it == it_end) ? 0 : (it++)->first);
1145
+ }
1146
+ dump(out, sat_list);
1147
+ sat_list.item.l3_11.number_of_sats = 0;
1148
+ }
1149
+ }
1150
+ typename reader_t::parsed_t
1151
+ pos = {reader_t::parsed_t::POSITION_CLOCK},
1152
+ vel = {reader_t::parsed_t::VELOCITY_RATE},
1153
+ time = {reader_t::parsed_t::EPOCH};
1154
+ pos.item.position_clock.has_sdev = false;
1155
+ vel.item.velocity_rate.has_sdev = false;
1156
+ int entries(0);
1157
+ for(typename epochs_t::const_iterator it(epochs.begin()), it_end(epochs.end());
1158
+ it != it_end; ++it){
1159
+ time.item.epoch = *it;
1160
+ dump(out, time);
1161
+ for(typename sats_t::const_iterator
1162
+ it2(src.satellites.begin()), it2_end(src.satellites.end());
1163
+ it2 != it2_end; ++it2){
1164
+ typename src_t::per_satellite_t::history_t::const_iterator it_entry;
1165
+ if((it_entry = it2->second.pos_history.find(*it))
1166
+ == it2->second.pos_history.end()){continue;}
1167
+ ++entries;
1168
+ pos.item.position_clock.vehicle_id = it2->first;
1169
+ for(int i(0); i < 3; ++i){
1170
+ pos.item.position_clock.coordinate_km[i] = it_entry->second.xyz[i] * 1E-3;
1171
+ }
1172
+ pos.item.position_clock.clock_us = it_entry->second.clk * 1E6;
1173
+ dump(out, pos);
1174
+ if((it_entry = it2->second.vel_history.find(*it))
1175
+ == it2->second.vel_history.end()){continue;}
1176
+ vel.item.velocity_rate.vehicle_id = it2->first;
1177
+ for(int i(0); i < 3; ++i){
1178
+ vel.item.velocity_rate.velocity_dm_s[i] = it_entry->second.xyz[i] * 1E1;
1179
+ }
1180
+ vel.item.velocity_rate.clock_rate_chg_100ps_s = it_entry->second.clk * 1E10;
1181
+ dump(out, vel);
1182
+ }
1183
+ }
1184
+ return entries;
1185
+ }
1186
+ };
1187
+
1188
+
1189
+ #endif /* #define __SP3_H__ */