gps_pvt 0.1.1
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 +7 -0
- data/.rspec +3 -0
- data/CHANGELOG.md +5 -0
- data/CODE_OF_CONDUCT.md +84 -0
- data/Gemfile +10 -0
- data/README.md +86 -0
- data/Rakefile +86 -0
- data/bin/console +15 -0
- data/bin/setup +8 -0
- data/ext/gps_pvt/Coordinate/Coordinate_wrap.cxx +6613 -0
- data/ext/gps_pvt/GPS/GPS_wrap.cxx +16019 -0
- data/ext/gps_pvt/SylphideMath/SylphideMath_wrap.cxx +21050 -0
- data/ext/gps_pvt/extconf.rb +70 -0
- data/ext/ninja-scan-light/tool/navigation/EGM.h +2971 -0
- data/ext/ninja-scan-light/tool/navigation/GPS.h +2432 -0
- data/ext/ninja-scan-light/tool/navigation/GPS_Solver.h +479 -0
- data/ext/ninja-scan-light/tool/navigation/GPS_Solver_Base.h +1081 -0
- data/ext/ninja-scan-light/tool/navigation/GPS_Solver_MultiFrequency.h +199 -0
- data/ext/ninja-scan-light/tool/navigation/GPS_Solver_RAIM.h +210 -0
- data/ext/ninja-scan-light/tool/navigation/MagneticField.h +928 -0
- data/ext/ninja-scan-light/tool/navigation/NTCM.h +211 -0
- data/ext/ninja-scan-light/tool/navigation/RINEX.h +1781 -0
- data/ext/ninja-scan-light/tool/navigation/WGS84.h +186 -0
- data/ext/ninja-scan-light/tool/navigation/coordinate.h +406 -0
- data/ext/ninja-scan-light/tool/param/bit_array.h +145 -0
- data/ext/ninja-scan-light/tool/param/complex.h +558 -0
- data/ext/ninja-scan-light/tool/param/matrix.h +4049 -0
- data/ext/ninja-scan-light/tool/param/matrix_fixed.h +665 -0
- data/ext/ninja-scan-light/tool/param/matrix_special.h +562 -0
- data/ext/ninja-scan-light/tool/param/quaternion.h +765 -0
- data/ext/ninja-scan-light/tool/param/vector3.h +651 -0
- data/ext/ninja-scan-light/tool/swig/Coordinate.i +177 -0
- data/ext/ninja-scan-light/tool/swig/GPS.i +1102 -0
- data/ext/ninja-scan-light/tool/swig/SylphideMath.i +1234 -0
- data/ext/ninja-scan-light/tool/swig/extconf.rb +5 -0
- data/ext/ninja-scan-light/tool/swig/makefile +53 -0
- data/ext/ninja-scan-light/tool/swig/spec/GPS_spec.rb +417 -0
- data/ext/ninja-scan-light/tool/swig/spec/SylphideMath_spec.rb +489 -0
- data/gps_pvt.gemspec +57 -0
- data/lib/gps_pvt/receiver.rb +375 -0
- data/lib/gps_pvt/ubx.rb +148 -0
- data/lib/gps_pvt/version.rb +5 -0
- data/lib/gps_pvt.rb +9 -0
- data/sig/gps_pvt.rbs +4 -0
- metadata +117 -0
@@ -0,0 +1,1781 @@
|
|
1
|
+
/*
|
2
|
+
* Copyright (c) 2017, 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 RINEX Loader, support RINEX 2 and 3
|
34
|
+
*
|
35
|
+
*/
|
36
|
+
|
37
|
+
#ifndef __RINEX_H__
|
38
|
+
#define __RINEX_H__
|
39
|
+
|
40
|
+
#include <istream>
|
41
|
+
#include <ostream>
|
42
|
+
#include <sstream>
|
43
|
+
#include <map>
|
44
|
+
#include <string>
|
45
|
+
#include <queue>
|
46
|
+
#include <vector>
|
47
|
+
#include <iomanip>
|
48
|
+
#include <ctime>
|
49
|
+
#include <exception>
|
50
|
+
#include <algorithm>
|
51
|
+
#include <cstddef>
|
52
|
+
#include <cstring>
|
53
|
+
|
54
|
+
#include "GPS.h"
|
55
|
+
|
56
|
+
template <class U = void>
|
57
|
+
class RINEX_Reader {
|
58
|
+
public:
|
59
|
+
typedef RINEX_Reader<U> self_t;
|
60
|
+
typedef std::map<std::string, std::vector<std::string> > header_t;
|
61
|
+
|
62
|
+
protected:
|
63
|
+
header_t _header;
|
64
|
+
struct src_stream_t : public std::istream {
|
65
|
+
src_stream_t(std::istream &is) : std::istream(is.rdbuf()) {}
|
66
|
+
/**
|
67
|
+
* getline() for multi-platform (in addition to \n, \r\n and \r are supported)
|
68
|
+
*
|
69
|
+
* @see https://stackoverflow.com/questions/6089231/getting-std-ifstream-to-handle-lf-cr-and-crlf
|
70
|
+
* @see https://en.cppreference.com/w/cpp/io/basic_istream/getline
|
71
|
+
* TODO gcount() mismatch
|
72
|
+
*/
|
73
|
+
std::istream& getline(
|
74
|
+
typename std::istream::char_type* s,
|
75
|
+
std::streamsize n){
|
76
|
+
std::streamsize i(1), consumed(0);
|
77
|
+
typename std::istream::sentry se(*this, true);
|
78
|
+
if((bool)se){
|
79
|
+
std::streambuf* sb(this->rdbuf());
|
80
|
+
for(; i < n; ++i){
|
81
|
+
int c(sb->sbumpc());
|
82
|
+
if(c == std::streambuf::traits_type::eof()){
|
83
|
+
this->setstate(std::ios::eofbit);
|
84
|
+
break;
|
85
|
+
}
|
86
|
+
++consumed;
|
87
|
+
if(c == '\n'){
|
88
|
+
break;
|
89
|
+
}else if(c == '\r'){
|
90
|
+
if(sb->sgetc() == '\n'){
|
91
|
+
sb->sbumpc();
|
92
|
+
++consumed;
|
93
|
+
}
|
94
|
+
break;
|
95
|
+
}
|
96
|
+
*(s++) = (typename std::istream::char_type)c;
|
97
|
+
}
|
98
|
+
}
|
99
|
+
if(((i == 1) && (consumed == 0)) || (i == n)){
|
100
|
+
this->setstate(std::ios::failbit);
|
101
|
+
}else{
|
102
|
+
*s = '\0';
|
103
|
+
}
|
104
|
+
return *this;
|
105
|
+
}
|
106
|
+
} src;
|
107
|
+
bool _has_next;
|
108
|
+
|
109
|
+
public:
|
110
|
+
struct version_type_t {
|
111
|
+
int version;
|
112
|
+
enum file_type_t {
|
113
|
+
FTYPE_UNKNOWN = 0,
|
114
|
+
FTYPE_OBSERVATION,
|
115
|
+
FTYPE_NAVIGATION,
|
116
|
+
FTYPE_METEOROLOGICAL,
|
117
|
+
} file_type;
|
118
|
+
enum sat_system_t {
|
119
|
+
SYS_UNKNOWN = 0,
|
120
|
+
SYS_GPS,
|
121
|
+
SYS_GLONASS,
|
122
|
+
SYS_GALILEO,
|
123
|
+
SYS_QZSS,
|
124
|
+
SYS_BDS,
|
125
|
+
SYS_IRNSS,
|
126
|
+
SYS_SBAS,
|
127
|
+
SYS_TRANSIT,
|
128
|
+
SYS_MIXED,
|
129
|
+
} sat_system;
|
130
|
+
version_type_t(
|
131
|
+
const int &ver = 0, const file_type_t &ftype = FTYPE_UNKNOWN, const sat_system_t &sys = SYS_UNKNOWN)
|
132
|
+
: version(ver), file_type(ftype), sat_system(sys) {}
|
133
|
+
void parse(const std::string &buf);
|
134
|
+
void dump(std::string &buf) const;
|
135
|
+
};
|
136
|
+
protected:
|
137
|
+
version_type_t version_type;
|
138
|
+
|
139
|
+
public:
|
140
|
+
RINEX_Reader(
|
141
|
+
std::istream &in,
|
142
|
+
std::string &(*modify_header)(std::string &, std::string &) = NULL)
|
143
|
+
: src(in), _has_next(false),
|
144
|
+
version_type() {
|
145
|
+
if(src.fail()){return;}
|
146
|
+
|
147
|
+
char buf[256];
|
148
|
+
|
149
|
+
// Read header
|
150
|
+
while(!src.eof()){
|
151
|
+
src.getline(buf, sizeof(buf));
|
152
|
+
|
153
|
+
std::string content(buf);
|
154
|
+
std::string label(content, 60, 20);
|
155
|
+
{
|
156
|
+
int real_length(label.find_last_not_of(' ') + 1);
|
157
|
+
if(real_length < (int)label.length()){
|
158
|
+
label = label.substr(0, real_length);
|
159
|
+
}
|
160
|
+
}
|
161
|
+
// std::cerr << label << " (" << label.length() << ")" << std::endl;
|
162
|
+
|
163
|
+
if(label.find("END OF HEADER") == 0){break;}
|
164
|
+
|
165
|
+
content = content.substr(0, 60);
|
166
|
+
if(modify_header){content = modify_header(label, content);}
|
167
|
+
_header[label].push_back(content);
|
168
|
+
}
|
169
|
+
|
170
|
+
// version and type extraction
|
171
|
+
for(const header_t::const_iterator it(_header.find("RINEX VERSION / TYPE"));
|
172
|
+
it != _header.end(); ){
|
173
|
+
version_type.parse(it->second.front());
|
174
|
+
break;
|
175
|
+
}
|
176
|
+
|
177
|
+
}
|
178
|
+
virtual ~RINEX_Reader(){_header.clear();}
|
179
|
+
header_t &header() {return _header;}
|
180
|
+
const header_t &header() const {return const_cast<self_t *>(this)->header();}
|
181
|
+
bool has_next() const {return _has_next;}
|
182
|
+
|
183
|
+
template <class T>
|
184
|
+
struct conv_t {
|
185
|
+
static void d(
|
186
|
+
std::string &buf, const int &offset, const int &length, void *value, const int &opt = 0, const bool &str2val = true){
|
187
|
+
if(str2val){
|
188
|
+
std::stringstream(buf.substr(offset, length)) >> *(T *)value;
|
189
|
+
}else{
|
190
|
+
std::stringstream ss;
|
191
|
+
ss << std::setfill(opt == 1 ? '0' : ' ') << std::right << std::setw(length) << *(T *)value;
|
192
|
+
buf.replace(offset, length, ss.str());
|
193
|
+
}
|
194
|
+
}
|
195
|
+
static void f(
|
196
|
+
std::string &buf, const int &offset, const int &length, void *value, const int &precision = 0, const bool &str2val = true){
|
197
|
+
if(str2val){
|
198
|
+
std::stringstream(buf.substr(offset, length)) >> *(T *)value;
|
199
|
+
}else{
|
200
|
+
std::stringstream ss;
|
201
|
+
ss << std::setfill(' ') << std::right << std::setw(length)
|
202
|
+
<< std::setprecision(precision) << std::fixed
|
203
|
+
<< *(T *)value;
|
204
|
+
std::string s(ss.str());
|
205
|
+
if((*(T *)value) >= 0){
|
206
|
+
if((*(T *)value) < 1){
|
207
|
+
int i(length - precision - 2);
|
208
|
+
if(i >= 0){s[i] = ' ';}
|
209
|
+
}
|
210
|
+
}else{
|
211
|
+
if((*(T *)value) > -1){
|
212
|
+
int i(length - precision - 2);
|
213
|
+
if(i >= 0){s[i] = '-';}
|
214
|
+
if(--i >= 0){s[i] = ' ';}
|
215
|
+
}
|
216
|
+
}
|
217
|
+
buf.replace(offset, length, s);
|
218
|
+
}
|
219
|
+
}
|
220
|
+
static void e(
|
221
|
+
std::string &buf, const int &offset, const int &length, void *value, const int &precision = 0, const bool &str2val = true){
|
222
|
+
if(str2val){
|
223
|
+
std::string s(buf.substr(offset, length));
|
224
|
+
std::string::size_type pos(s.find("D"));
|
225
|
+
if(pos != std::string::npos){
|
226
|
+
s.replace(pos, 1, "E");
|
227
|
+
}
|
228
|
+
std::stringstream(s) >> *(T *)value;
|
229
|
+
}else{
|
230
|
+
int w((std::max)(length, precision + 6)); // parentheses of std::max mitigates error C2589 under Windows VC
|
231
|
+
|
232
|
+
std::stringstream ss;
|
233
|
+
ss << std::setprecision(precision - 1) << std::scientific
|
234
|
+
<< ((*(T *)value) * 1E1);
|
235
|
+
std::string s(ss.str());
|
236
|
+
|
237
|
+
// -1.2345E+06 => -.12345E+06
|
238
|
+
int index(s[0] == '-' ? 1 : 0);
|
239
|
+
s[index + 1] = s[index + 0];
|
240
|
+
s[index + 0] = '.';
|
241
|
+
|
242
|
+
// -.12345E+06 => -.12345D+06
|
243
|
+
s[index + precision + 1] = 'D';
|
244
|
+
// If exponent portion digits are more than 2, then truncate it.
|
245
|
+
s.erase(index + precision + 3, s.size() - (index + precision + 5));
|
246
|
+
|
247
|
+
ss.str("");
|
248
|
+
ss << std::setfill(' ') << std::right << std::setw(w) << s;
|
249
|
+
buf.replace(offset, length, ss.str());
|
250
|
+
}
|
251
|
+
}
|
252
|
+
};
|
253
|
+
|
254
|
+
struct convert_item_t {
|
255
|
+
void (*func)(
|
256
|
+
std::string &buf, const int &offset, const int &length, void *value,
|
257
|
+
const int &opt, const bool &str2val);
|
258
|
+
int offset;
|
259
|
+
int length;
|
260
|
+
int value_offset;
|
261
|
+
int opt;
|
262
|
+
};
|
263
|
+
|
264
|
+
static void convert(const convert_item_t *items, const int &size, const std::string &buf, void *values){
|
265
|
+
// str => value
|
266
|
+
for(int i(0); i < size; ++i){
|
267
|
+
(*items[i].func)(
|
268
|
+
const_cast<std::string &>(buf), items[i].offset, items[i].length, (char *)values + items[i].value_offset,
|
269
|
+
items[i].opt, true);
|
270
|
+
}
|
271
|
+
}
|
272
|
+
template <int N>
|
273
|
+
static inline void convert(const convert_item_t (&items)[N], const std::string &buf, void *values){
|
274
|
+
convert(items, N, buf, values);
|
275
|
+
}
|
276
|
+
};
|
277
|
+
|
278
|
+
template <class U>
|
279
|
+
void RINEX_Reader<U>::version_type_t::parse(const std::string &buf){
|
280
|
+
int temp;
|
281
|
+
conv_t<int>::d(const_cast<std::string &>(buf), 0, 6, &temp);
|
282
|
+
version = temp * 100;
|
283
|
+
conv_t<int>::d(const_cast<std::string &>(buf), 7, 2, &temp);
|
284
|
+
version += temp;
|
285
|
+
switch(version / 100){
|
286
|
+
case 2:
|
287
|
+
switch(buf[20]){
|
288
|
+
case 'O':
|
289
|
+
file_type = FTYPE_OBSERVATION;
|
290
|
+
switch(buf[40]){
|
291
|
+
case ' ':
|
292
|
+
case 'G': sat_system = SYS_GPS; break;
|
293
|
+
case 'R': sat_system = SYS_GLONASS; break;
|
294
|
+
case 'S': sat_system = SYS_SBAS; break;
|
295
|
+
case 'M': sat_system = SYS_MIXED; break;
|
296
|
+
case 'T': sat_system = SYS_TRANSIT; break;
|
297
|
+
}
|
298
|
+
break;
|
299
|
+
case 'M': file_type = FTYPE_METEOROLOGICAL; break;
|
300
|
+
case 'N': file_type = FTYPE_NAVIGATION; sat_system = SYS_GPS; break;
|
301
|
+
case 'G': file_type = FTYPE_NAVIGATION; sat_system = SYS_GLONASS; break;
|
302
|
+
case 'H': file_type = FTYPE_NAVIGATION;
|
303
|
+
sat_system = SYS_SBAS; // TODO: Is geostational as SBAS?
|
304
|
+
break;
|
305
|
+
}
|
306
|
+
break;
|
307
|
+
case 3:
|
308
|
+
switch(buf[20]){
|
309
|
+
case 'O': file_type = FTYPE_OBSERVATION; break;
|
310
|
+
case 'N': file_type = FTYPE_NAVIGATION; break;
|
311
|
+
case 'M': file_type = FTYPE_METEOROLOGICAL; break;
|
312
|
+
}
|
313
|
+
if((file_type == FTYPE_OBSERVATION) || (file_type == FTYPE_NAVIGATION)){
|
314
|
+
switch(buf[40]){
|
315
|
+
case 'G': sat_system = SYS_GPS; break;
|
316
|
+
case 'R': sat_system = SYS_GLONASS; break;
|
317
|
+
case 'E': sat_system = SYS_GALILEO; break;
|
318
|
+
case 'J': sat_system = SYS_QZSS; break;
|
319
|
+
case 'C': sat_system = SYS_BDS; break;
|
320
|
+
case 'I': sat_system = SYS_IRNSS; break;
|
321
|
+
case 'S': sat_system = SYS_SBAS; break;
|
322
|
+
case 'M': sat_system = SYS_MIXED; break;
|
323
|
+
}
|
324
|
+
}
|
325
|
+
break;
|
326
|
+
}
|
327
|
+
}
|
328
|
+
template <class U>
|
329
|
+
void RINEX_Reader<U>::version_type_t::dump(std::string &buf) const {
|
330
|
+
int temp;
|
331
|
+
conv_t<int>::d(buf, 0, 6, &(temp = version / 100), 0, false);
|
332
|
+
if(version % 100 != 0){
|
333
|
+
buf[6] = '.';
|
334
|
+
conv_t<int>::d(buf, 7, 2, &(temp = version % 100), 1, false);
|
335
|
+
}
|
336
|
+
const char *type_str(NULL), *sys_str(NULL);
|
337
|
+
switch(version / 100){
|
338
|
+
case 2: {
|
339
|
+
switch(file_type){
|
340
|
+
case FTYPE_OBSERVATION: {
|
341
|
+
type_str = "OBSERVATION DATA";
|
342
|
+
switch(sat_system){
|
343
|
+
case SYS_GPS: sys_str = "G: GPS"; break;
|
344
|
+
case SYS_GLONASS: sys_str = "R: GLONASS"; break;
|
345
|
+
case SYS_SBAS: sys_str = "S: Geostat"; break;
|
346
|
+
case SYS_MIXED: sys_str = "M: MIXED"; break;
|
347
|
+
case SYS_TRANSIT: sys_str = "T: TRANSIT"; break;
|
348
|
+
default: break;
|
349
|
+
}
|
350
|
+
break;
|
351
|
+
}
|
352
|
+
case FTYPE_NAVIGATION:
|
353
|
+
switch(sat_system){
|
354
|
+
case SYS_GPS: type_str = "N: GPS NAV DATA"; break;
|
355
|
+
case SYS_GLONASS: type_str = "G: GLONASS NAV DATA"; break;
|
356
|
+
case SYS_SBAS: type_str = "H: GEO NAV MSG DATA"; break;
|
357
|
+
default: break;
|
358
|
+
}
|
359
|
+
break;
|
360
|
+
case FTYPE_METEOROLOGICAL: type_str = "METEOROLOGICAL DATA"; break;
|
361
|
+
default: break;
|
362
|
+
}
|
363
|
+
break;
|
364
|
+
}
|
365
|
+
case 3: {
|
366
|
+
switch(file_type){
|
367
|
+
case FTYPE_OBSERVATION: type_str = "OBSERVATION DATA"; break;
|
368
|
+
case FTYPE_NAVIGATION: type_str = "N: GNSS NAV DATA"; break;
|
369
|
+
case FTYPE_METEOROLOGICAL: type_str = "METEOROLOGICAL DATA"; break;
|
370
|
+
default: break;
|
371
|
+
}
|
372
|
+
if((file_type != FTYPE_OBSERVATION) && (file_type != FTYPE_NAVIGATION)){break;}
|
373
|
+
switch(sat_system){
|
374
|
+
case SYS_GPS: sys_str = "G: GPS"; break;
|
375
|
+
case SYS_GLONASS: sys_str = "R: GLONASS"; break;
|
376
|
+
case SYS_GALILEO: sys_str = "G: GALILEO"; break;
|
377
|
+
case SYS_QZSS: sys_str = "Q: QZSS"; break;
|
378
|
+
case SYS_BDS: sys_str = "B: BDS"; break;
|
379
|
+
case SYS_IRNSS: sys_str = "I: IRNSS"; break;
|
380
|
+
case SYS_SBAS: sys_str = "S: SBAS"; break;
|
381
|
+
case SYS_MIXED: sys_str = "M: MIXED"; break;
|
382
|
+
default: break;
|
383
|
+
}
|
384
|
+
break;
|
385
|
+
}
|
386
|
+
}
|
387
|
+
if(type_str){
|
388
|
+
int n(std::strlen(type_str));
|
389
|
+
buf.replace(20, n, type_str, n);
|
390
|
+
}
|
391
|
+
if(sys_str){
|
392
|
+
int n(std::strlen(sys_str));
|
393
|
+
buf.replace(40, n, sys_str, n);
|
394
|
+
}
|
395
|
+
}
|
396
|
+
|
397
|
+
|
398
|
+
template <class FloatT>
|
399
|
+
struct RINEX_NAV {
|
400
|
+
typedef GPS_SpaceNode<FloatT> space_node_t;
|
401
|
+
typedef typename space_node_t::Satellite::Ephemeris ephemeris_t;
|
402
|
+
struct message_t {
|
403
|
+
ephemeris_t eph;
|
404
|
+
std::tm t_oc_tm;
|
405
|
+
int t_oc_year4, t_oc_year2, t_oc_mon12;
|
406
|
+
FloatT t_oc_sec;
|
407
|
+
FloatT iodc_f, iode_f; // originally int type
|
408
|
+
FloatT t_oe_WN;
|
409
|
+
FloatT ura_meter;
|
410
|
+
FloatT SV_health_f;
|
411
|
+
FloatT t_ot; ///< Transmitting time [s]
|
412
|
+
FloatT fit_interval_hr;
|
413
|
+
FloatT dummy;
|
414
|
+
|
415
|
+
message_t() {}
|
416
|
+
message_t(const ephemeris_t &eph_)
|
417
|
+
: eph(eph_),
|
418
|
+
t_oc_tm(typename space_node_t::gps_time_t(eph.WN, eph.t_oc).c_tm()),
|
419
|
+
t_oc_year4(t_oc_tm.tm_year + 1900),
|
420
|
+
t_oc_year2(t_oc_tm.tm_year % 100),
|
421
|
+
t_oc_mon12(t_oc_tm.tm_mon + 1),
|
422
|
+
t_oc_sec(std::fmod(eph.t_oc, 60)),
|
423
|
+
iodc_f(eph.iodc), iode_f(eph.iode),
|
424
|
+
t_oe_WN(eph.WN),
|
425
|
+
ura_meter(ephemeris_t::URA_meter(eph.URA)),
|
426
|
+
SV_health_f(((eph.SV_health & 0x20) && (eph.SV_health & 0x1F == 0)) ? 1 : eph.SV_health),
|
427
|
+
t_ot(0), // TODO
|
428
|
+
fit_interval_hr(eph.fit_interval / (60 * 60)),
|
429
|
+
dummy(0) {
|
430
|
+
}
|
431
|
+
void update() {
|
432
|
+
typename space_node_t::gps_time_t t_oc(t_oc_tm);
|
433
|
+
t_oc += (t_oc_sec - t_oc_tm.tm_sec);
|
434
|
+
eph.WN = t_oc.week;
|
435
|
+
eph.t_oc = t_oc.seconds;
|
436
|
+
|
437
|
+
eph.iodc = iodc_f;
|
438
|
+
eph.iode = iode_f;
|
439
|
+
|
440
|
+
eph.URA = ephemeris_t::URA_index(ura_meter); // meter to index
|
441
|
+
|
442
|
+
/* @see ftp://igs.org/pub/data/format/rinex210.txt
|
443
|
+
* 6.7 Satellite Health
|
444
|
+
* RINEX Value: 0 Health OK
|
445
|
+
* RINEX Value: 1 Health not OK (bits 18-22 not stored)
|
446
|
+
* RINEX Value: >32 Health not OK (bits 18-22 stored)
|
447
|
+
*/
|
448
|
+
eph.SV_health = (unsigned int)SV_health_f;
|
449
|
+
if(eph.SV_health > 32){
|
450
|
+
eph.SV_health &= 0x3F; // 0b111111
|
451
|
+
}else if(eph.SV_health > 0){
|
452
|
+
eph.SV_health = 0x20; // 0b100000
|
453
|
+
}
|
454
|
+
|
455
|
+
// At least 4 hour validity, then, hours => seconds;
|
456
|
+
eph.fit_interval = ((fit_interval_hr < 4) ? 4 : fit_interval_hr) * 60 * 60;
|
457
|
+
}
|
458
|
+
};
|
459
|
+
};
|
460
|
+
|
461
|
+
template <class FloatT = double>
|
462
|
+
class RINEX_NAV_Reader : public RINEX_Reader<> {
|
463
|
+
protected:
|
464
|
+
typedef RINEX_NAV_Reader<FloatT> self_t;
|
465
|
+
typedef RINEX_Reader<> super_t;
|
466
|
+
public:
|
467
|
+
typedef typename RINEX_NAV<FloatT>::space_node_t space_node_t;
|
468
|
+
typedef typename RINEX_NAV<FloatT>::message_t message_t;
|
469
|
+
typedef typename space_node_t::Ionospheric_UTC_Parameters iono_utc_t;
|
470
|
+
|
471
|
+
static const typename super_t::convert_item_t eph0_v2[10], eph0_v3[10];
|
472
|
+
static const typename super_t::convert_item_t eph1_v2[4], eph1_v3[4];
|
473
|
+
static const typename super_t::convert_item_t eph2_v2[4], eph2_v3[4];
|
474
|
+
static const typename super_t::convert_item_t eph3_v2[4], eph3_v3[4];
|
475
|
+
static const typename super_t::convert_item_t eph4_v2[4], eph4_v3[4];
|
476
|
+
static const typename super_t::convert_item_t eph5_v2[4], eph5_v3[4];
|
477
|
+
static const typename super_t::convert_item_t eph6_v2[4], eph6_v3[4];
|
478
|
+
static const typename super_t::convert_item_t eph7_v2[2], eph7_v3[2];
|
479
|
+
|
480
|
+
protected:
|
481
|
+
message_t msg;
|
482
|
+
|
483
|
+
void seek_next_v2() {
|
484
|
+
char buf[256];
|
485
|
+
|
486
|
+
for(int i = 0; (i < 8) && (super_t::src.good()); i++){
|
487
|
+
if(super_t::src.getline(buf, sizeof(buf)).fail()){return;}
|
488
|
+
std::string line(buf);
|
489
|
+
|
490
|
+
switch(i){
|
491
|
+
case 0: {
|
492
|
+
super_t::convert(eph0_v2, line, &msg);
|
493
|
+
msg.t_oc_tm.tm_year = msg.t_oc_year2 + (msg.t_oc_year2 < 80 ? 100 : 0); // greater than 1980
|
494
|
+
msg.t_oc_tm.tm_mon = msg.t_oc_mon12 - 1; // month [0, 11]
|
495
|
+
msg.t_oc_tm.tm_sec = (int)msg.t_oc_sec;
|
496
|
+
break;
|
497
|
+
}
|
498
|
+
case 1: super_t::convert(eph1_v2, line, &msg); break;
|
499
|
+
case 2: super_t::convert(eph2_v2, line, &msg); break;
|
500
|
+
case 3: super_t::convert(eph3_v2, line, &msg); break;
|
501
|
+
case 4: super_t::convert(eph4_v2, line, &msg); break;
|
502
|
+
case 5: super_t::convert(eph5_v2, line, &msg); break;
|
503
|
+
case 6: super_t::convert(eph6_v2, line, &msg); break;
|
504
|
+
case 7: super_t::convert(eph7_v2, line, &msg); break;
|
505
|
+
}
|
506
|
+
}
|
507
|
+
msg.update();
|
508
|
+
super_t::_has_next = true;
|
509
|
+
}
|
510
|
+
|
511
|
+
void seek_next_v3() {
|
512
|
+
char buf[256];
|
513
|
+
|
514
|
+
for(int i = 0; (i < 8) && (super_t::src.good()); i++){
|
515
|
+
if(super_t::src.getline(buf, sizeof(buf)).fail()){return;}
|
516
|
+
std::string line(buf);
|
517
|
+
|
518
|
+
switch(i){
|
519
|
+
case 0: {
|
520
|
+
// if(line_data[0] != 'G'){} // TODO check GPS before parsing
|
521
|
+
super_t::convert(eph0_v3, line, &msg);
|
522
|
+
msg.t_oc_tm.tm_year = msg.t_oc_year4 - 1900; // tm_year base is 1900
|
523
|
+
msg.t_oc_tm.tm_mon = msg.t_oc_mon12 - 1; // month [0, 11]
|
524
|
+
msg.t_oc_sec = msg.t_oc_tm.tm_sec;
|
525
|
+
break;
|
526
|
+
}
|
527
|
+
case 1: super_t::convert(eph1_v3, line, &msg); break;
|
528
|
+
case 2: super_t::convert(eph2_v3, line, &msg); break;
|
529
|
+
case 3: super_t::convert(eph3_v3, line, &msg); break;
|
530
|
+
case 4: super_t::convert(eph4_v3, line, &msg); break;
|
531
|
+
case 5: super_t::convert(eph5_v3, line, &msg); break;
|
532
|
+
case 6: super_t::convert(eph6_v3, line, &msg); break;
|
533
|
+
case 7: super_t::convert(eph7_v3, line, &msg); break;
|
534
|
+
}
|
535
|
+
}
|
536
|
+
msg.update();
|
537
|
+
super_t::_has_next = true;
|
538
|
+
}
|
539
|
+
|
540
|
+
void seek_next() {
|
541
|
+
super_t::version_type.version >= 300 ? seek_next_v3() : seek_next_v2();
|
542
|
+
}
|
543
|
+
|
544
|
+
public:
|
545
|
+
RINEX_NAV_Reader(std::istream &in) : super_t(in) {
|
546
|
+
seek_next();
|
547
|
+
}
|
548
|
+
~RINEX_NAV_Reader(){}
|
549
|
+
|
550
|
+
typename space_node_t::Satellite::Ephemeris next() {
|
551
|
+
typename space_node_t::Satellite::Ephemeris current(msg.eph);
|
552
|
+
super_t::_has_next = false;
|
553
|
+
seek_next();
|
554
|
+
return current;
|
555
|
+
}
|
556
|
+
|
557
|
+
static const typename super_t::convert_item_t iono_alpha_v2[4];
|
558
|
+
static const typename super_t::convert_item_t iono_beta_v2[4];
|
559
|
+
static const typename super_t::convert_item_t utc_v2[4];
|
560
|
+
static const typename super_t::convert_item_t utc_leap_v2[1];
|
561
|
+
|
562
|
+
/**
|
563
|
+
* Obtain ionospheric delay coefficient and UTC parameters.
|
564
|
+
*
|
565
|
+
* @return true when successfully obtained, otherwise false
|
566
|
+
*/
|
567
|
+
bool extract_iono_utc_v2(GPS_SpaceNode<FloatT> &space_node) const {
|
568
|
+
iono_utc_t iono_utc;
|
569
|
+
bool alpha, beta, utc, leap;
|
570
|
+
super_t::header_t::const_iterator it;
|
571
|
+
|
572
|
+
if(alpha = ((it = _header.find("ION ALPHA")) != _header.end())){
|
573
|
+
super_t::convert(iono_alpha_v2, it->second.front(), &iono_utc);
|
574
|
+
}
|
575
|
+
|
576
|
+
if(beta = ((it = _header.find("ION BETA")) != _header.end())){
|
577
|
+
super_t::convert(iono_beta_v2, it->second.front(), &iono_utc);
|
578
|
+
}
|
579
|
+
|
580
|
+
if(utc = ((it = _header.find("DELTA-UTC: A0,A1,T,W")) != _header.end())){
|
581
|
+
super_t::convert(utc_v2, it->second.front(), &iono_utc);
|
582
|
+
}
|
583
|
+
|
584
|
+
if(leap = ((it = _header.find("LEAP SECONDS")) != _header.end())){
|
585
|
+
super_t::convert(utc_leap_v2, it->second.front(), &iono_utc);
|
586
|
+
}
|
587
|
+
|
588
|
+
space_node.update_iono_utc(iono_utc, alpha && beta, utc && leap);
|
589
|
+
return alpha && beta && utc && leap;
|
590
|
+
}
|
591
|
+
|
592
|
+
static const typename super_t::convert_item_t iono_alpha_v3[4];
|
593
|
+
static const typename super_t::convert_item_t iono_beta_v3[4];
|
594
|
+
static const typename super_t::convert_item_t utc_v3[4];
|
595
|
+
static const typename super_t::convert_item_t utc_leap_v301[4];
|
596
|
+
|
597
|
+
bool extract_iono_utc_v3(GPS_SpaceNode<FloatT> &space_node) const {
|
598
|
+
iono_utc_t iono_utc;
|
599
|
+
bool alpha(false), beta(false), utc(false), leap(false);
|
600
|
+
typedef super_t::header_t::const_iterator it_t;
|
601
|
+
typedef super_t::header_t::mapped_type::const_iterator it2_t;
|
602
|
+
|
603
|
+
it_t it;
|
604
|
+
|
605
|
+
if((it = _header.find("IONOSPHERIC CORR")) != _header.end()){
|
606
|
+
for(it2_t it2(it->second.begin()), it2_end(it->second.end()); it2 != it2_end; ++it2){
|
607
|
+
if(it2->find("GPSA") != it2->npos){
|
608
|
+
super_t::convert(iono_alpha_v3, *it2, &iono_utc);
|
609
|
+
alpha = true;
|
610
|
+
}else if(it2->find("GPSB") != it2->npos){
|
611
|
+
super_t::convert(iono_beta_v3, *it2, &iono_utc);
|
612
|
+
beta = true;
|
613
|
+
}
|
614
|
+
}
|
615
|
+
}
|
616
|
+
|
617
|
+
if((it = _header.find("TIME SYSTEM CORR")) != _header.end()){
|
618
|
+
for(it2_t it2(it->second.begin()), it2_end(it->second.end()); it2 != it2_end; ++it2){
|
619
|
+
if(it2->find("GPUT") == it2->npos){continue;}
|
620
|
+
super_t::convert(utc_v3, *it2, &iono_utc);
|
621
|
+
utc = true;
|
622
|
+
}
|
623
|
+
}
|
624
|
+
|
625
|
+
if((it = _header.find("LEAP SECONDS")) != _header.end()){
|
626
|
+
if(version_type.version >= 301){
|
627
|
+
super_t::convert(utc_leap_v301, it->second.front(), &iono_utc);
|
628
|
+
}else{
|
629
|
+
super_t::convert(utc_leap_v2, it->second.front(), &iono_utc);
|
630
|
+
}
|
631
|
+
leap = true;
|
632
|
+
}
|
633
|
+
|
634
|
+
space_node.update_iono_utc(iono_utc, alpha && beta, utc && leap);
|
635
|
+
return alpha && beta && utc && leap;
|
636
|
+
}
|
637
|
+
|
638
|
+
static int read_all(std::istream &in, space_node_t &space_node){
|
639
|
+
int res(-1);
|
640
|
+
RINEX_NAV_Reader reader(in);
|
641
|
+
(reader.version_type.version >= 300)
|
642
|
+
? reader.extract_iono_utc_v3(space_node)
|
643
|
+
: reader.extract_iono_utc_v2(space_node);
|
644
|
+
res++;
|
645
|
+
for(; reader.has_next(); ++res){
|
646
|
+
typename space_node_t::Satellite::Ephemeris eph(reader.next());
|
647
|
+
space_node.satellite(eph.svid).register_ephemeris(eph);
|
648
|
+
}
|
649
|
+
return res;
|
650
|
+
}
|
651
|
+
};
|
652
|
+
|
653
|
+
template <class FloatT>
|
654
|
+
struct RINEX_OBS {
|
655
|
+
struct epoch_flag_t {
|
656
|
+
std::tm epoch;
|
657
|
+
int epoch_year4, epoch_year2, epoch_mon12;
|
658
|
+
FloatT epoch_sec;
|
659
|
+
int flag;
|
660
|
+
int items_followed;
|
661
|
+
FloatT receiver_clock_error;
|
662
|
+
|
663
|
+
epoch_flag_t &operator=(const GPS_Time<FloatT> &t){
|
664
|
+
epoch = t.c_tm();
|
665
|
+
epoch_year4 = epoch.tm_year + 1900;
|
666
|
+
epoch_year2 = epoch.tm_year % 100;
|
667
|
+
epoch_mon12 = epoch.tm_mon + 1;
|
668
|
+
epoch_sec = std::fmod(t.seconds, 60);
|
669
|
+
return *this;
|
670
|
+
}
|
671
|
+
operator GPS_Time<FloatT>() const {
|
672
|
+
return GPS_Time<FloatT>(epoch) + (epoch_sec - epoch.tm_sec);
|
673
|
+
}
|
674
|
+
};
|
675
|
+
|
676
|
+
struct observation_t {
|
677
|
+
GPS_Time<FloatT> t_epoch;
|
678
|
+
FloatT receiver_clock_error;
|
679
|
+
struct record_t {
|
680
|
+
bool valid;
|
681
|
+
FloatT value;
|
682
|
+
int lli, ss; // if negative
|
683
|
+
};
|
684
|
+
typedef std::map<int, std::vector<record_t> > per_satellite_t;
|
685
|
+
per_satellite_t per_satellite;
|
686
|
+
|
687
|
+
observation_t &operator=(const epoch_flag_t &epoch_flag){
|
688
|
+
t_epoch = (GPS_Time<FloatT>)epoch_flag;
|
689
|
+
receiver_clock_error = epoch_flag.receiver_clock_error;
|
690
|
+
return *this;
|
691
|
+
}
|
692
|
+
operator epoch_flag_t() const {
|
693
|
+
epoch_flag_t res = {0};
|
694
|
+
res = t_epoch;
|
695
|
+
res.receiver_clock_error = receiver_clock_error;
|
696
|
+
return res;
|
697
|
+
}
|
698
|
+
};
|
699
|
+
};
|
700
|
+
|
701
|
+
template <class FloatT = double>
|
702
|
+
class RINEX_OBS_Reader : public RINEX_Reader<> {
|
703
|
+
protected:
|
704
|
+
typedef RINEX_OBS_Reader<FloatT> self_t;
|
705
|
+
typedef RINEX_Reader<> super_t;
|
706
|
+
public:
|
707
|
+
typedef typename RINEX_OBS<FloatT>::epoch_flag_t epoch_flag_t;
|
708
|
+
typedef typename RINEX_OBS<FloatT>::observation_t::record_t record_t;
|
709
|
+
|
710
|
+
static const typename super_t::convert_item_t epoch_flag_v2[9], epoch_flag_v3[9];
|
711
|
+
static const typename super_t::convert_item_t record_v2v3[3];
|
712
|
+
|
713
|
+
typedef typename RINEX_OBS<FloatT>::observation_t observation_t;
|
714
|
+
|
715
|
+
static int sys2serial(const char &c){
|
716
|
+
switch(c){
|
717
|
+
case ' ':
|
718
|
+
case 'G': return 0; // NAVSTAR
|
719
|
+
case 'R': return 0x100; break; // GLONASS
|
720
|
+
case 'E': return 0x200; break; // Galileo, since ver 2.11
|
721
|
+
case 'J': return 192; break; // QZSS, since ver 3.02, J01 = PRN193
|
722
|
+
case 'C': return 0x300; break; // BDS, since ver 3.02
|
723
|
+
case 'I': return 0x400; break; // IRNSS, since ver 3.03
|
724
|
+
case 'S': return 100; break; // SBAS, S20 = PRN120
|
725
|
+
default: return 0x800;
|
726
|
+
}
|
727
|
+
}
|
728
|
+
static char serial2sys(const int &serial, int &offset){
|
729
|
+
switch(serial & 0xF00){
|
730
|
+
case 0:
|
731
|
+
if(serial < 100){
|
732
|
+
offset = serial; return 'G'; // NAVSTAR
|
733
|
+
}else if(serial < 192){
|
734
|
+
offset = serial - 100; return 'S'; // SBAS, S20 = PRN120
|
735
|
+
}else{
|
736
|
+
offset = serial - 192; return 'J'; // QZSS, since ver 3.02, J01 = PRN193
|
737
|
+
}
|
738
|
+
break;
|
739
|
+
case 0x100: offset = serial - 0x100; return 'R'; // GLONASS
|
740
|
+
case 0x200: offset = serial - 0x200; return 'E'; // Galileo, since ver 2.11
|
741
|
+
case 0x300: offset = serial - 0x300; return 'C'; // BDS, since ver 3.02
|
742
|
+
case 0x400: offset = serial - 0x400; return 'I'; // IRNSS, since ver 3.03
|
743
|
+
}
|
744
|
+
offset = serial - 0x800; return ' '; // unknown
|
745
|
+
}
|
746
|
+
|
747
|
+
|
748
|
+
protected:
|
749
|
+
typedef std::map<char, std::vector<std::string> > obs_types_t;
|
750
|
+
obs_types_t obs_types;
|
751
|
+
observation_t obs;
|
752
|
+
static std::string &modify_header(std::string &label, std::string &content){
|
753
|
+
return content;
|
754
|
+
}
|
755
|
+
|
756
|
+
void seek_next_v2() {
|
757
|
+
char buf[256];
|
758
|
+
typedef std::vector<int> sat_list_t;
|
759
|
+
sat_list_t sat_list;
|
760
|
+
obs.per_satellite.clear();
|
761
|
+
|
762
|
+
while(true){
|
763
|
+
|
764
|
+
// Read lines for epoch
|
765
|
+
{
|
766
|
+
if(super_t::src.getline(buf, sizeof(buf)).fail()){return;}
|
767
|
+
std::string epoch_str(buf);
|
768
|
+
if((epoch_str.size() < 80) && (epoch_str.size() >= 32)){ // minimum 32 characters are required.
|
769
|
+
epoch_str.append(80 - epoch_str.size(), ' '); // add blank in case line is truncated
|
770
|
+
}
|
771
|
+
|
772
|
+
epoch_flag_t epoch_flag;
|
773
|
+
super_t::convert(epoch_flag_v2, epoch_str, &epoch_flag);
|
774
|
+
epoch_flag.epoch.tm_year = epoch_flag.epoch_year2 + (epoch_flag.epoch_year2 < 80 ? 100 : 0); // greater than 1980
|
775
|
+
epoch_flag.epoch.tm_mon = epoch_flag.epoch_mon12 - 1; // month [0, 11]
|
776
|
+
epoch_flag.epoch.tm_sec = (int)epoch_flag.epoch_sec;
|
777
|
+
obs = epoch_flag;
|
778
|
+
|
779
|
+
if(epoch_flag.flag >= 2){
|
780
|
+
for(int i(0); i < epoch_flag.items_followed; ++i){
|
781
|
+
if(super_t::src.getline(buf, sizeof(buf)).fail()){return;}
|
782
|
+
}
|
783
|
+
continue;
|
784
|
+
}
|
785
|
+
|
786
|
+
int prn;
|
787
|
+
for(int items(0), i(0); items < epoch_flag.items_followed; items++, i++){
|
788
|
+
if(i >= 12){ // if number of satellites is greater than 12, move to the next line
|
789
|
+
if(super_t::src.getline(buf, sizeof(buf)).fail()){return;}
|
790
|
+
epoch_str = std::string(buf);
|
791
|
+
i = 0;
|
792
|
+
}
|
793
|
+
super_t::template conv_t<int>::d(epoch_str, 33 + (i * 3), 2, &prn);
|
794
|
+
sat_list.push_back(prn + sys2serial(epoch_str[32 + (i * 3)]));
|
795
|
+
}
|
796
|
+
}
|
797
|
+
|
798
|
+
// Observation data per satellite
|
799
|
+
int types(obs_types[' '].size());
|
800
|
+
for(typename sat_list_t::const_iterator it(sat_list.begin()), it_end(sat_list.end());
|
801
|
+
it != it_end; ++it){
|
802
|
+
std::string obs_str;
|
803
|
+
for(int i(0), offset(80); i < types; i++, offset += 16){
|
804
|
+
if(offset >= 80){
|
805
|
+
if(super_t::src.getline(buf, sizeof(buf)).fail()){return;}
|
806
|
+
obs_str = std::string(buf);
|
807
|
+
if(obs_str.size() < 80){
|
808
|
+
obs_str.append(80 - obs_str.size(), ' '); // add blank in case line is truncated
|
809
|
+
}
|
810
|
+
offset = 0;
|
811
|
+
}
|
812
|
+
typename observation_t::record_t record = {false, 0};
|
813
|
+
std::string record_str(obs_str.substr(offset, 16));
|
814
|
+
if(record_str[10] == '.'){
|
815
|
+
record.valid = true;
|
816
|
+
super_t::convert(record_v2v3, record_str, &record);
|
817
|
+
}
|
818
|
+
obs.per_satellite[*it].push_back(record);
|
819
|
+
}
|
820
|
+
}
|
821
|
+
|
822
|
+
break;
|
823
|
+
}
|
824
|
+
|
825
|
+
super_t::_has_next = true;
|
826
|
+
}
|
827
|
+
|
828
|
+
void seek_next_v3() {
|
829
|
+
char buf[1024];
|
830
|
+
typedef std::vector<int> sat_list_t;
|
831
|
+
sat_list_t sat_list;
|
832
|
+
obs.per_satellite.clear();
|
833
|
+
|
834
|
+
while(true){
|
835
|
+
|
836
|
+
// Read lines for epoch
|
837
|
+
epoch_flag_t epoch_flag;
|
838
|
+
{
|
839
|
+
if(super_t::src.getline(buf, sizeof(buf)).fail()){return;}
|
840
|
+
std::string epoch_str(buf);
|
841
|
+
if((epoch_str.size() < 56) && (epoch_str.size() >= 35)){
|
842
|
+
epoch_str.append(56 - epoch_str.size(), ' ');
|
843
|
+
}
|
844
|
+
|
845
|
+
super_t::convert(epoch_flag_v3, epoch_str, &epoch_flag);
|
846
|
+
epoch_flag.epoch.tm_year = epoch_flag.epoch_year4 - 1900; // greater than 1980
|
847
|
+
epoch_flag.epoch.tm_mon = epoch_flag.epoch_mon12 - 1; // month [0, 11]
|
848
|
+
epoch_flag.epoch.tm_sec = (int)epoch_flag.epoch_sec;
|
849
|
+
obs = epoch_flag;
|
850
|
+
|
851
|
+
if(epoch_flag.flag >= 2){
|
852
|
+
for(int i(0); i < epoch_flag.items_followed; ++i){
|
853
|
+
if(super_t::src.getline(buf, sizeof(buf)).fail()){return;}
|
854
|
+
}
|
855
|
+
continue;
|
856
|
+
}
|
857
|
+
}
|
858
|
+
|
859
|
+
// Observation data per satellite
|
860
|
+
for(int i(0); i < epoch_flag.items_followed; ++i){
|
861
|
+
if(super_t::src.getline(buf, sizeof(buf)).fail()){return;}
|
862
|
+
std::string obs_str(buf);
|
863
|
+
int types(obs_types[obs_str[0]].size()), serial;
|
864
|
+
super_t::template conv_t<int>::d(obs_str, 1, 3, &serial);
|
865
|
+
serial += sys2serial(obs_str[0]);
|
866
|
+
do{
|
867
|
+
int truncated((3 + 16 * types) - obs_str.size());
|
868
|
+
if(truncated <= 0){break;}
|
869
|
+
obs_str.append(truncated, ' ');
|
870
|
+
}while(false);
|
871
|
+
for(int j(0), offset(3); j < types; j++, offset += 16){
|
872
|
+
typename observation_t::record_t record = {false, 0};
|
873
|
+
std::string record_str(obs_str.substr(offset, 16));
|
874
|
+
if(record_str[10] == '.'){
|
875
|
+
record.valid = true;
|
876
|
+
super_t::convert(record_v2v3, record_str, &record);
|
877
|
+
}
|
878
|
+
obs.per_satellite[serial].push_back(record);
|
879
|
+
}
|
880
|
+
}
|
881
|
+
|
882
|
+
break;
|
883
|
+
}
|
884
|
+
|
885
|
+
super_t::_has_next = true;
|
886
|
+
}
|
887
|
+
|
888
|
+
void seek_next(){
|
889
|
+
if(obs_types.size() == 0){return;}
|
890
|
+
switch(super_t::version_type.version / 100){
|
891
|
+
case 2: seek_next_v2(); break;
|
892
|
+
case 3: seek_next_v3(); break;
|
893
|
+
}
|
894
|
+
}
|
895
|
+
|
896
|
+
public:
|
897
|
+
RINEX_OBS_Reader(std::istream &in)
|
898
|
+
: super_t(in, self_t::modify_header),
|
899
|
+
obs_types() {
|
900
|
+
typedef super_t::header_t::const_iterator it_t;
|
901
|
+
typedef super_t::header_t::mapped_type::const_iterator it2_t;
|
902
|
+
it_t it;
|
903
|
+
switch(super_t::version_type.version / 100){
|
904
|
+
case 2: if((it = _header.find("# / TYPES OF OBSERV")) != _header.end()){
|
905
|
+
int types(0);
|
906
|
+
for(it2_t it2(it->second.begin()), it2_end(it->second.end()); it2 != it2_end; ++it2){
|
907
|
+
if(types == 0){super_t::conv_t<int>::d(const_cast<std::string &>(*it2), 0, 6, &types);}
|
908
|
+
for(int i(0); i < 9; ++i){
|
909
|
+
std::string param_name(it2->substr(6 * i + 10, 2));
|
910
|
+
if(param_name != " "){
|
911
|
+
obs_types[' '].push_back(param_name);
|
912
|
+
}
|
913
|
+
}
|
914
|
+
}
|
915
|
+
}
|
916
|
+
break;
|
917
|
+
case 3: if((it = _header.find("SYS / # / OBS TYPES")) != _header.end()){
|
918
|
+
int types(0); char sys;
|
919
|
+
for(it2_t it2(it->second.begin()), it2_end(it->second.end()); it2 != it2_end; ++it2){
|
920
|
+
if(types == 0){
|
921
|
+
sys = (*it2)[0];
|
922
|
+
super_t::conv_t<int>::d(const_cast<std::string &>(*it2), 3, 3, &types);
|
923
|
+
}
|
924
|
+
for(int i(0); i < 13; ++i){
|
925
|
+
std::string param_name(it2->substr(4 * i + 7, 3));
|
926
|
+
if(param_name == " "){continue;}
|
927
|
+
obs_types[sys].push_back(param_name);
|
928
|
+
if((int)(obs_types[sys].size()) >= types){
|
929
|
+
types = 0;
|
930
|
+
break;
|
931
|
+
}
|
932
|
+
}
|
933
|
+
}
|
934
|
+
}
|
935
|
+
break;
|
936
|
+
}
|
937
|
+
seek_next();
|
938
|
+
}
|
939
|
+
~RINEX_OBS_Reader(){}
|
940
|
+
|
941
|
+
observation_t next() {
|
942
|
+
observation_t current(obs);
|
943
|
+
super_t::_has_next = false;
|
944
|
+
seek_next();
|
945
|
+
return current;
|
946
|
+
}
|
947
|
+
/**
|
948
|
+
* Return index on data lines corresponding to specified label
|
949
|
+
* If not found, return -1.
|
950
|
+
*
|
951
|
+
*/
|
952
|
+
int observed_index(const std::string &label, const char &system = ' ') const {
|
953
|
+
obs_types_t::const_iterator it(obs_types.find(system));
|
954
|
+
if(it == obs_types.end()){return -1;}
|
955
|
+
int res(distance(it->second.begin(),
|
956
|
+
find(it->second.begin(), it->second.end(), label)));
|
957
|
+
return (res >= (int)(it->second.size()) ? -1 : res);
|
958
|
+
}
|
959
|
+
};
|
960
|
+
|
961
|
+
#define GEN_D(offset, length, container_type, container_member, value_type) \
|
962
|
+
{super_t::template conv_t<value_type>::d, offset, length, \
|
963
|
+
offsetof(container_type, container_member)}
|
964
|
+
#define GEN_I(offset, length, container_type, container_member, value_type) \
|
965
|
+
{super_t::template conv_t<value_type>::d, offset, length, \
|
966
|
+
offsetof(container_type, container_member), 1}
|
967
|
+
#define GEN_F(offset, length, precision, container_type, container_member) \
|
968
|
+
{super_t::template conv_t<FloatT>::f, offset, length, \
|
969
|
+
offsetof(container_type, container_member), precision}
|
970
|
+
#define GEN_E(offset, length, precision, container_type, container_member) \
|
971
|
+
{super_t::template conv_t<FloatT>::e, offset, length, \
|
972
|
+
offsetof(container_type, container_member), precision}
|
973
|
+
|
974
|
+
template <class FloatT>
|
975
|
+
const typename RINEX_NAV_Reader<FloatT>::convert_item_t RINEX_NAV_Reader<FloatT>::eph0_v2[] = {
|
976
|
+
GEN_D( 0, 2, message_t, eph.svid, int),
|
977
|
+
GEN_D( 3, 2, message_t, t_oc_year2, int),
|
978
|
+
GEN_D( 6, 2, message_t, t_oc_mon12, int),
|
979
|
+
GEN_D( 9, 2, message_t, t_oc_tm.tm_mday, int),
|
980
|
+
GEN_D(12, 2, message_t, t_oc_tm.tm_hour, int),
|
981
|
+
GEN_D(15, 2, message_t, t_oc_tm.tm_min, int),
|
982
|
+
GEN_F(17, 5, 1, message_t, t_oc_sec),
|
983
|
+
GEN_E(22, 19, 12, message_t, eph.a_f0),
|
984
|
+
GEN_E(41, 19, 12, message_t, eph.a_f1),
|
985
|
+
GEN_E(60, 19, 12, message_t, eph.a_f2),
|
986
|
+
};
|
987
|
+
template <class FloatT>
|
988
|
+
const typename RINEX_NAV_Reader<FloatT>::convert_item_t RINEX_NAV_Reader<FloatT>::eph0_v3[] = {
|
989
|
+
GEN_I( 1, 2, message_t, eph.svid, int),
|
990
|
+
GEN_I( 4, 4, message_t, t_oc_year4, int),
|
991
|
+
GEN_I( 9, 2, message_t, t_oc_mon12, int),
|
992
|
+
GEN_I(12, 2, message_t, t_oc_tm.tm_mday, int),
|
993
|
+
GEN_I(15, 2, message_t, t_oc_tm.tm_hour, int),
|
994
|
+
GEN_I(18, 2, message_t, t_oc_tm.tm_min, int),
|
995
|
+
GEN_I(21, 2, message_t, t_oc_tm.tm_sec, int),
|
996
|
+
GEN_E(23, 19, 12, message_t, eph.a_f0),
|
997
|
+
GEN_E(42, 19, 12, message_t, eph.a_f1),
|
998
|
+
GEN_E(61, 19, 12, message_t, eph.a_f2),
|
999
|
+
};
|
1000
|
+
|
1001
|
+
template <class FloatT>
|
1002
|
+
const typename RINEX_NAV_Reader<FloatT>::convert_item_t RINEX_NAV_Reader<FloatT>::eph1_v2[] = {
|
1003
|
+
GEN_E( 3, 19, 12, message_t, iode_f),
|
1004
|
+
GEN_E(22, 19, 12, message_t, eph.c_rs),
|
1005
|
+
GEN_E(41, 19, 12, message_t, eph.delta_n),
|
1006
|
+
GEN_E(60, 19, 12, message_t, eph.M0),
|
1007
|
+
};
|
1008
|
+
template <class FloatT>
|
1009
|
+
const typename RINEX_NAV_Reader<FloatT>::convert_item_t RINEX_NAV_Reader<FloatT>::eph1_v3[] = {
|
1010
|
+
GEN_E( 4, 19, 12, message_t, iode_f),
|
1011
|
+
GEN_E(23, 19, 12, message_t, eph.c_rs),
|
1012
|
+
GEN_E(42, 19, 12, message_t, eph.delta_n),
|
1013
|
+
GEN_E(61, 19, 12, message_t, eph.M0),
|
1014
|
+
};
|
1015
|
+
|
1016
|
+
template <class FloatT>
|
1017
|
+
const typename RINEX_NAV_Reader<FloatT>::convert_item_t RINEX_NAV_Reader<FloatT>::eph2_v2[] = {
|
1018
|
+
GEN_E( 3, 19, 12, message_t, eph.c_uc),
|
1019
|
+
GEN_E(22, 19, 12, message_t, eph.e),
|
1020
|
+
GEN_E(41, 19, 12, message_t, eph.c_us),
|
1021
|
+
GEN_E(60, 19, 12, message_t, eph.sqrt_A),
|
1022
|
+
};
|
1023
|
+
template <class FloatT>
|
1024
|
+
const typename RINEX_NAV_Reader<FloatT>::convert_item_t RINEX_NAV_Reader<FloatT>::eph2_v3[] = {
|
1025
|
+
GEN_E( 4, 19, 12, message_t, eph.c_uc),
|
1026
|
+
GEN_E(23, 19, 12, message_t, eph.e),
|
1027
|
+
GEN_E(42, 19, 12, message_t, eph.c_us),
|
1028
|
+
GEN_E(61, 19, 12, message_t, eph.sqrt_A),
|
1029
|
+
};
|
1030
|
+
|
1031
|
+
template <class FloatT>
|
1032
|
+
const typename RINEX_NAV_Reader<FloatT>::convert_item_t RINEX_NAV_Reader<FloatT>::eph3_v2[] = {
|
1033
|
+
GEN_E( 3, 19, 12, message_t, eph.t_oe),
|
1034
|
+
GEN_E(22, 19, 12, message_t, eph.c_ic),
|
1035
|
+
GEN_E(41, 19, 12, message_t, eph.Omega0),
|
1036
|
+
GEN_E(60, 19, 12, message_t, eph.c_is),
|
1037
|
+
};
|
1038
|
+
template <class FloatT>
|
1039
|
+
const typename RINEX_NAV_Reader<FloatT>::convert_item_t RINEX_NAV_Reader<FloatT>::eph3_v3[] = {
|
1040
|
+
GEN_E( 4, 19, 12, message_t, eph.t_oe),
|
1041
|
+
GEN_E(23, 19, 12, message_t, eph.c_ic),
|
1042
|
+
GEN_E(42, 19, 12, message_t, eph.Omega0),
|
1043
|
+
GEN_E(61, 19, 12, message_t, eph.c_is),
|
1044
|
+
};
|
1045
|
+
|
1046
|
+
template <class FloatT>
|
1047
|
+
const typename RINEX_NAV_Reader<FloatT>::convert_item_t RINEX_NAV_Reader<FloatT>::eph4_v2[] = {
|
1048
|
+
GEN_E( 3, 19, 12, message_t, eph.i0),
|
1049
|
+
GEN_E(22, 19, 12, message_t, eph.c_rc),
|
1050
|
+
GEN_E(41, 19, 12, message_t, eph.omega),
|
1051
|
+
GEN_E(60, 19, 12, message_t, eph.dot_Omega0),
|
1052
|
+
};
|
1053
|
+
template <class FloatT>
|
1054
|
+
const typename RINEX_NAV_Reader<FloatT>::convert_item_t RINEX_NAV_Reader<FloatT>::eph4_v3[] = {
|
1055
|
+
GEN_E( 4, 19, 12, message_t, eph.i0),
|
1056
|
+
GEN_E(23, 19, 12, message_t, eph.c_rc),
|
1057
|
+
GEN_E(42, 19, 12, message_t, eph.omega),
|
1058
|
+
GEN_E(61, 19, 12, message_t, eph.dot_Omega0),
|
1059
|
+
};
|
1060
|
+
|
1061
|
+
template <class FloatT>
|
1062
|
+
const typename RINEX_NAV_Reader<FloatT>::convert_item_t RINEX_NAV_Reader<FloatT>::eph5_v2[] = {
|
1063
|
+
GEN_E( 3, 19, 12, message_t, eph.dot_i0),
|
1064
|
+
GEN_E(22, 19, 12, message_t, dummy), // Codes on L2 channel
|
1065
|
+
GEN_E(41, 19, 12, message_t, t_oe_WN),
|
1066
|
+
GEN_E(60, 19, 12, message_t, dummy), // L2 P data flag
|
1067
|
+
};
|
1068
|
+
template <class FloatT>
|
1069
|
+
const typename RINEX_NAV_Reader<FloatT>::convert_item_t RINEX_NAV_Reader<FloatT>::eph5_v3[] = {
|
1070
|
+
GEN_E( 4, 19, 12, message_t, eph.dot_i0),
|
1071
|
+
GEN_E(23, 19, 12, message_t, dummy), // Codes on L2 channel
|
1072
|
+
GEN_E(42, 19, 12, message_t, t_oe_WN),
|
1073
|
+
GEN_E(61, 19, 12, message_t, dummy), // L2 P data flag
|
1074
|
+
};
|
1075
|
+
|
1076
|
+
template <class FloatT>
|
1077
|
+
const typename RINEX_NAV_Reader<FloatT>::convert_item_t RINEX_NAV_Reader<FloatT>::eph6_v2[] = {
|
1078
|
+
GEN_E( 3, 19, 12, message_t, ura_meter),
|
1079
|
+
GEN_E(22, 19, 12, message_t, SV_health_f),
|
1080
|
+
GEN_E(41, 19, 12, message_t, eph.t_GD),
|
1081
|
+
GEN_E(60, 19, 12, message_t, iodc_f),
|
1082
|
+
};
|
1083
|
+
template <class FloatT>
|
1084
|
+
const typename RINEX_NAV_Reader<FloatT>::convert_item_t RINEX_NAV_Reader<FloatT>::eph6_v3[] = {
|
1085
|
+
GEN_E( 4, 19, 12, message_t, ura_meter),
|
1086
|
+
GEN_E(23, 19, 12, message_t, SV_health_f),
|
1087
|
+
GEN_E(42, 19, 12, message_t, eph.t_GD),
|
1088
|
+
GEN_E(61, 19, 12, message_t, iodc_f),
|
1089
|
+
};
|
1090
|
+
|
1091
|
+
template <class FloatT>
|
1092
|
+
const typename RINEX_NAV_Reader<FloatT>::convert_item_t RINEX_NAV_Reader<FloatT>::eph7_v2[] = {
|
1093
|
+
GEN_E( 3, 19, 12, message_t, t_ot),
|
1094
|
+
GEN_E(22, 19, 12, message_t, fit_interval_hr),
|
1095
|
+
};
|
1096
|
+
template <class FloatT>
|
1097
|
+
const typename RINEX_NAV_Reader<FloatT>::convert_item_t RINEX_NAV_Reader<FloatT>::eph7_v3[] = {
|
1098
|
+
GEN_E( 4, 19, 12, message_t, t_ot),
|
1099
|
+
GEN_E(23, 19, 12, message_t, fit_interval_hr),
|
1100
|
+
};
|
1101
|
+
|
1102
|
+
template <class FloatT>
|
1103
|
+
const typename RINEX_NAV_Reader<FloatT>::convert_item_t RINEX_NAV_Reader<FloatT>::iono_alpha_v2[] = {
|
1104
|
+
GEN_E( 2, 12, 4, iono_utc_t, alpha[0]),
|
1105
|
+
GEN_E(14, 12, 4, iono_utc_t, alpha[1]),
|
1106
|
+
GEN_E(26, 12, 4, iono_utc_t, alpha[2]),
|
1107
|
+
GEN_E(38, 12, 4, iono_utc_t, alpha[3]),
|
1108
|
+
};
|
1109
|
+
|
1110
|
+
template <class FloatT>
|
1111
|
+
const typename RINEX_NAV_Reader<FloatT>::convert_item_t RINEX_NAV_Reader<FloatT>::iono_beta_v2[] = {
|
1112
|
+
GEN_E( 2, 12, 4, iono_utc_t, beta[0]),
|
1113
|
+
GEN_E(14, 12, 4, iono_utc_t, beta[1]),
|
1114
|
+
GEN_E(26, 12, 4, iono_utc_t, beta[2]),
|
1115
|
+
GEN_E(38, 12, 4, iono_utc_t, beta[3]),
|
1116
|
+
};
|
1117
|
+
|
1118
|
+
template <class FloatT>
|
1119
|
+
const typename RINEX_NAV_Reader<FloatT>::convert_item_t RINEX_NAV_Reader<FloatT>::utc_v2[] = {
|
1120
|
+
GEN_E( 3, 19, 12, iono_utc_t, A0),
|
1121
|
+
GEN_E( 22, 19, 12, iono_utc_t, A1),
|
1122
|
+
GEN_D( 41, 9, iono_utc_t, t_ot, int),
|
1123
|
+
GEN_D( 50, 9, iono_utc_t, WN_t, int),
|
1124
|
+
};
|
1125
|
+
|
1126
|
+
template <class FloatT>
|
1127
|
+
const typename RINEX_NAV_Reader<FloatT>::convert_item_t RINEX_NAV_Reader<FloatT>::utc_leap_v2[] = {
|
1128
|
+
GEN_D(0, 6, iono_utc_t, delta_t_LS, int),
|
1129
|
+
};
|
1130
|
+
|
1131
|
+
|
1132
|
+
template <class FloatT>
|
1133
|
+
const typename RINEX_NAV_Reader<FloatT>::convert_item_t RINEX_NAV_Reader<FloatT>::iono_alpha_v3[] = {
|
1134
|
+
GEN_E( 5, 12, 4, iono_utc_t, alpha[0]),
|
1135
|
+
GEN_E(17, 12, 4, iono_utc_t, alpha[1]),
|
1136
|
+
GEN_E(29, 12, 4, iono_utc_t, alpha[2]),
|
1137
|
+
GEN_E(41, 12, 4, iono_utc_t, alpha[3]),
|
1138
|
+
};
|
1139
|
+
|
1140
|
+
template <class FloatT>
|
1141
|
+
const typename RINEX_NAV_Reader<FloatT>::convert_item_t RINEX_NAV_Reader<FloatT>::iono_beta_v3[] = {
|
1142
|
+
GEN_E( 5, 12, 4, iono_utc_t, beta[0]),
|
1143
|
+
GEN_E(17, 12, 4, iono_utc_t, beta[1]),
|
1144
|
+
GEN_E(29, 12, 4, iono_utc_t, beta[2]),
|
1145
|
+
GEN_E(41, 12, 4, iono_utc_t, beta[3]),
|
1146
|
+
};
|
1147
|
+
|
1148
|
+
template <class FloatT>
|
1149
|
+
const typename RINEX_NAV_Reader<FloatT>::convert_item_t RINEX_NAV_Reader<FloatT>::utc_v3[] = {
|
1150
|
+
GEN_E( 5, 17, 10, iono_utc_t, A0),
|
1151
|
+
GEN_E(22, 16, 9, iono_utc_t, A1),
|
1152
|
+
GEN_D(39, 6, iono_utc_t, t_ot, int),
|
1153
|
+
GEN_D(46, 4, iono_utc_t, WN_t, int),
|
1154
|
+
};
|
1155
|
+
|
1156
|
+
template <class FloatT>
|
1157
|
+
const typename RINEX_NAV_Reader<FloatT>::convert_item_t RINEX_NAV_Reader<FloatT>::utc_leap_v301[] = {
|
1158
|
+
GEN_D( 0, 6, iono_utc_t, delta_t_LS, int),
|
1159
|
+
GEN_D( 6, 6, iono_utc_t, delta_t_LSF, int),
|
1160
|
+
GEN_D(12, 6, iono_utc_t, WN_LSF, int),
|
1161
|
+
GEN_D(18, 6, iono_utc_t, DN, int),
|
1162
|
+
};
|
1163
|
+
|
1164
|
+
template <class FloatT>
|
1165
|
+
const typename RINEX_OBS_Reader<FloatT>::convert_item_t RINEX_OBS_Reader<FloatT>::epoch_flag_v2[] = {
|
1166
|
+
GEN_I( 1, 2, epoch_flag_t, epoch_year2, int),
|
1167
|
+
GEN_D( 4, 2, epoch_flag_t, epoch_mon12, int),
|
1168
|
+
GEN_D( 7, 2, epoch_flag_t, epoch.tm_mday, int),
|
1169
|
+
GEN_D(10, 2, epoch_flag_t, epoch.tm_hour, int),
|
1170
|
+
GEN_D(13, 2, epoch_flag_t, epoch.tm_min, int),
|
1171
|
+
GEN_F(15, 11, 7, epoch_flag_t, epoch_sec),
|
1172
|
+
GEN_D(28, 1, epoch_flag_t, flag, int),
|
1173
|
+
GEN_D(29, 3, epoch_flag_t, items_followed, int), // Satellite(flag = 0/1) or Line number(except for 0/1)
|
1174
|
+
GEN_F(68, 12, 9, epoch_flag_t, receiver_clock_error),
|
1175
|
+
};
|
1176
|
+
|
1177
|
+
template <class FloatT>
|
1178
|
+
const typename RINEX_OBS_Reader<FloatT>::convert_item_t RINEX_OBS_Reader<FloatT>::epoch_flag_v3[] = {
|
1179
|
+
GEN_I( 2, 4, epoch_flag_t, epoch_year4, int),
|
1180
|
+
GEN_I( 7, 2, epoch_flag_t, epoch_mon12, int),
|
1181
|
+
GEN_I(10, 2, epoch_flag_t, epoch.tm_mday, int),
|
1182
|
+
GEN_I(13, 2, epoch_flag_t, epoch.tm_hour, int),
|
1183
|
+
GEN_I(16, 2, epoch_flag_t, epoch.tm_min, int),
|
1184
|
+
GEN_F(18, 11, 7, epoch_flag_t, epoch_sec),
|
1185
|
+
GEN_D(31, 1, epoch_flag_t, flag, int),
|
1186
|
+
GEN_D(32, 3, epoch_flag_t, items_followed, int), // Satellite(flag = 0/1) or Line number(except for 0/1)
|
1187
|
+
GEN_F(41, 15, 12, epoch_flag_t, receiver_clock_error),
|
1188
|
+
};
|
1189
|
+
|
1190
|
+
template <class FloatT>
|
1191
|
+
const typename RINEX_OBS_Reader<FloatT>::convert_item_t RINEX_OBS_Reader<FloatT>::record_v2v3[] = {
|
1192
|
+
GEN_F( 0, 14, 3, record_t, value),
|
1193
|
+
GEN_D(14, 1, record_t, lli, int),
|
1194
|
+
GEN_D(15, 1, record_t, ss, int),
|
1195
|
+
};
|
1196
|
+
|
1197
|
+
#undef GEN_D
|
1198
|
+
#undef GEN_I
|
1199
|
+
#undef GEN_F
|
1200
|
+
#undef GEN_E
|
1201
|
+
|
1202
|
+
template <class U = void>
|
1203
|
+
class RINEX_Writer {
|
1204
|
+
public:
|
1205
|
+
typedef typename RINEX_Reader<U>::version_type_t version_type_t;
|
1206
|
+
typedef struct {const char *key, *value;} header_item_t;
|
1207
|
+
|
1208
|
+
struct header_t : public std::vector<std::pair<std::string, std::string> > {
|
1209
|
+
typedef std::vector<std::pair<std::string, std::string> > super_t;
|
1210
|
+
|
1211
|
+
using super_t::operator[];
|
1212
|
+
struct bracket_accessor_t {
|
1213
|
+
header_t &header;
|
1214
|
+
typename super_t::value_type::first_type key;
|
1215
|
+
typename super_t::iterator it_head, it_tail;
|
1216
|
+
bracket_accessor_t(header_t &_header, const typename super_t::value_type::first_type &_key)
|
1217
|
+
: header(_header), key(_key), it_head(header.end()), it_tail(header.end()) {
|
1218
|
+
for(typename super_t::iterator it(header.begin()), it_end(header.end());
|
1219
|
+
it != it_end; ++it){
|
1220
|
+
if(it->first != key){continue;}
|
1221
|
+
it_head = it;
|
1222
|
+
break;
|
1223
|
+
}
|
1224
|
+
for(typename super_t::reverse_iterator it(header.rbegin()), it_end(header.rend());
|
1225
|
+
it != it_end; ++it){
|
1226
|
+
if(it->first != key){continue;}
|
1227
|
+
it_tail = it.base() - 1;
|
1228
|
+
break;
|
1229
|
+
}
|
1230
|
+
}
|
1231
|
+
/**
|
1232
|
+
* replace value corresponding to key with erase of other entries having the same key
|
1233
|
+
*/
|
1234
|
+
bracket_accessor_t &operator=(
|
1235
|
+
const typename super_t::value_type::second_type &value){
|
1236
|
+
if(it_head == header.end()){
|
1237
|
+
header.push_back(typename super_t::value_type(key, value));
|
1238
|
+
it_head = it_tail = header.rbegin().base();
|
1239
|
+
return *this;
|
1240
|
+
}
|
1241
|
+
it_head->second = value;
|
1242
|
+
for(; it_tail != it_head; --it_tail){
|
1243
|
+
if(it_tail->first == key){continue;}
|
1244
|
+
header.erase(it_tail);
|
1245
|
+
}
|
1246
|
+
return *this;
|
1247
|
+
}
|
1248
|
+
/**
|
1249
|
+
* add value corresponding to key after the last entry having the same key
|
1250
|
+
*/
|
1251
|
+
bracket_accessor_t &operator<<(
|
1252
|
+
const typename super_t::value_type::second_type &value){
|
1253
|
+
if(it_tail == header.end()){
|
1254
|
+
header.push_back(typename super_t::value_type(key, value));
|
1255
|
+
it_head = it_tail = header.rbegin().base();
|
1256
|
+
return *this;
|
1257
|
+
}
|
1258
|
+
header.insert(++it_tail, typename super_t::value_type(key, value));
|
1259
|
+
return *this;
|
1260
|
+
}
|
1261
|
+
};
|
1262
|
+
bracket_accessor_t operator[]( // mimic of std::map::operator[]=
|
1263
|
+
const typename super_t::value_type::first_type &key){
|
1264
|
+
return bracket_accessor_t(*this, key);
|
1265
|
+
}
|
1266
|
+
/**
|
1267
|
+
* @param mask Defualt key-value pairs; its order is preserved for ourputs
|
1268
|
+
* @param mask_size size of masked items
|
1269
|
+
*/
|
1270
|
+
header_t(
|
1271
|
+
const header_item_t *mandatory_items = NULL,
|
1272
|
+
const int &mandatory_item_size = 0)
|
1273
|
+
: super_t() {
|
1274
|
+
for(int i(0); i < mandatory_item_size; i++){
|
1275
|
+
super_t::push_back(typename super_t::value_type(
|
1276
|
+
mandatory_items[i].key, mandatory_items[i].value ? mandatory_items[i].value : ""));
|
1277
|
+
}
|
1278
|
+
}
|
1279
|
+
~header_t() {}
|
1280
|
+
friend std::ostream &operator<<(std::ostream &out, const header_t &header){
|
1281
|
+
std::stringstream ss;
|
1282
|
+
ss << std::setfill(' ') << std::left;
|
1283
|
+
for(header_t::const_iterator it(header.begin()), it_end(header.end());
|
1284
|
+
it != it_end; ++it){
|
1285
|
+
ss << std::setw(60) << it->second.substr(0, 60)
|
1286
|
+
<< std::setw(20) << it->first.substr(0, 20)
|
1287
|
+
<< std::endl;
|
1288
|
+
}
|
1289
|
+
ss << std::setw(60) << "" << std::setw(20) << "END OF HEADER" << std::endl;
|
1290
|
+
return out << ss.str();
|
1291
|
+
}
|
1292
|
+
};
|
1293
|
+
protected:
|
1294
|
+
version_type_t _version_type;
|
1295
|
+
header_t _header;
|
1296
|
+
std::ostream &dist;
|
1297
|
+
|
1298
|
+
void set_version_type(const version_type_t &version_type){
|
1299
|
+
_version_type = version_type;
|
1300
|
+
std::string buf(60, ' ');
|
1301
|
+
_version_type.dump(buf);
|
1302
|
+
_header["RINEX VERSION / TYPE"] = buf;
|
1303
|
+
}
|
1304
|
+
|
1305
|
+
public:
|
1306
|
+
typedef RINEX_Writer<U> self_t;
|
1307
|
+
RINEX_Writer(
|
1308
|
+
std::ostream &out,
|
1309
|
+
const header_item_t *header_mask = NULL,
|
1310
|
+
const int header_mask_size = 0)
|
1311
|
+
: _version_type(), _header(header_mask, header_mask_size), dist(out) {
|
1312
|
+
}
|
1313
|
+
virtual ~RINEX_Writer() {_header.clear();}
|
1314
|
+
|
1315
|
+
header_t &header(){return _header;}
|
1316
|
+
const header_t &header() const {return const_cast<self_t *>(this)->header();}
|
1317
|
+
|
1318
|
+
template <class FloatT>
|
1319
|
+
static std::string RINEX_Float(
|
1320
|
+
const FloatT &value, const int width = 19, const int precision = 12){
|
1321
|
+
std::string s;
|
1322
|
+
RINEX_Reader<U>::template conv_t<FloatT>::f(s, 0, width, &const_cast<FloatT &>(value), precision, false);
|
1323
|
+
return s;
|
1324
|
+
}
|
1325
|
+
template <class FloatT>
|
1326
|
+
static std::string RINEX_FloatD(
|
1327
|
+
const FloatT &value, const int width = 19, const int precision = 12){
|
1328
|
+
std::string s;
|
1329
|
+
RINEX_Reader<U>::template conv_t<FloatT>::e(s, 0, width, &const_cast<FloatT &>(value), precision, false);
|
1330
|
+
return s;
|
1331
|
+
}
|
1332
|
+
template <class T>
|
1333
|
+
static std::string RINEX_Value(const T &value, const int width = 6){
|
1334
|
+
std::string s;
|
1335
|
+
RINEX_Reader<U>::template conv_t<T>::d(s, 0, width, &const_cast<T &>(value), 0, false);
|
1336
|
+
return s;
|
1337
|
+
}
|
1338
|
+
|
1339
|
+
static void convert(
|
1340
|
+
const typename RINEX_Reader<U>::convert_item_t *items, const int &size,
|
1341
|
+
std::string &buf, const void *values){
|
1342
|
+
// value => string
|
1343
|
+
for(int i(0); i < size; ++i){
|
1344
|
+
(*items[i].func)(
|
1345
|
+
buf, items[i].offset, items[i].length, (char *)(const_cast<void *>(values)) + items[i].value_offset,
|
1346
|
+
items[i].opt, false);
|
1347
|
+
}
|
1348
|
+
}
|
1349
|
+
template <int N>
|
1350
|
+
static inline void convert(
|
1351
|
+
const typename RINEX_Reader<U>::convert_item_t (&items)[N], std::string &buf, const void *values){
|
1352
|
+
convert(items, N, buf, values);
|
1353
|
+
}
|
1354
|
+
|
1355
|
+
void pgm_runby_date(
|
1356
|
+
const std::string &pgm, const std::string &runby,
|
1357
|
+
const std::tm &t, const char *tz = "UTC"){
|
1358
|
+
// ex) "XXRINEXO V9.9 AIUB 19900912 124300 UTC"
|
1359
|
+
char buf[21] = {0};
|
1360
|
+
std::strftime(buf, sizeof(buf) - 1, "%Y%m%d %H%M%S", &t);
|
1361
|
+
std::sprintf(&buf[15], " %-4s", tz);
|
1362
|
+
std::stringstream ss;
|
1363
|
+
ss << std::setfill(' ') << std::left
|
1364
|
+
<< std::setw(20) << pgm.substr(0, 20)
|
1365
|
+
<< std::setw(20) << runby.substr(0, 20)
|
1366
|
+
<< buf;
|
1367
|
+
_header["PGM / RUN BY / DATE"] = ss.str();
|
1368
|
+
}
|
1369
|
+
};
|
1370
|
+
|
1371
|
+
template <class FloatT>
|
1372
|
+
class RINEX_NAV_Writer : public RINEX_Writer<> {
|
1373
|
+
public:
|
1374
|
+
typedef RINEX_NAV_Reader<FloatT> reader_t;
|
1375
|
+
typedef RINEX_NAV_Writer self_t;
|
1376
|
+
typedef RINEX_Writer<> super_t;
|
1377
|
+
protected:
|
1378
|
+
using super_t::_header;
|
1379
|
+
using super_t::dist;
|
1380
|
+
public:
|
1381
|
+
typedef typename RINEX_NAV<FloatT>::space_node_t space_node_t;
|
1382
|
+
typedef typename RINEX_NAV<FloatT>::message_t message_t;
|
1383
|
+
|
1384
|
+
static const typename super_t::header_item_t default_header[];
|
1385
|
+
static const int default_header_size;
|
1386
|
+
void iono_alpha(const space_node_t &space_node){
|
1387
|
+
std::string s(60, ' ');
|
1388
|
+
switch(super_t::_version_type.version / 100){
|
1389
|
+
case 2:
|
1390
|
+
super_t::convert(reader_t::iono_alpha_v2, s, &space_node.iono_utc());
|
1391
|
+
_header["ION ALPHA"] = s;
|
1392
|
+
break;
|
1393
|
+
case 3:
|
1394
|
+
super_t::convert(reader_t::iono_alpha_v3, s, &space_node.iono_utc());
|
1395
|
+
_header["IONOSPHERIC CORR"] << s.replace(0, 4, "GPSA", 4);
|
1396
|
+
break;
|
1397
|
+
}
|
1398
|
+
}
|
1399
|
+
void iono_beta(const space_node_t &space_node){
|
1400
|
+
std::string s(60, ' ');
|
1401
|
+
switch(super_t::_version_type.version / 100){
|
1402
|
+
case 2:
|
1403
|
+
super_t::convert(reader_t::iono_beta_v2, s, &space_node.iono_utc());
|
1404
|
+
_header["ION BETA"] = s;
|
1405
|
+
break;
|
1406
|
+
case 3:
|
1407
|
+
super_t::convert(reader_t::iono_beta_v3, s, &space_node.iono_utc());
|
1408
|
+
_header["IONOSPHERIC CORR"] << s.replace(0, 4, "GPSB", 4);
|
1409
|
+
break;
|
1410
|
+
}
|
1411
|
+
}
|
1412
|
+
void utc_params(const space_node_t &space_node){
|
1413
|
+
std::string s(60, ' ');
|
1414
|
+
switch(super_t::_version_type.version / 100){
|
1415
|
+
case 2:
|
1416
|
+
super_t::convert(reader_t::utc_v2, s, &space_node.iono_utc());
|
1417
|
+
_header["DELTA-UTC: A0,A1,T,W"] = s;
|
1418
|
+
break;
|
1419
|
+
case 3:
|
1420
|
+
super_t::convert(reader_t::utc_v3, s, &space_node.iono_utc());
|
1421
|
+
_header["TIME SYSTEM CORR"] << s.replace(0, 4, "GPUT", 4);
|
1422
|
+
break;
|
1423
|
+
}
|
1424
|
+
}
|
1425
|
+
void leap_seconds(const space_node_t &space_node){
|
1426
|
+
std::string s(60, ' ');
|
1427
|
+
if(super_t::_version_type.version >= 301){
|
1428
|
+
super_t::convert(reader_t::utc_leap_v301, s, &space_node.iono_utc());
|
1429
|
+
}else{
|
1430
|
+
super_t::convert(reader_t::utc_leap_v2, s, &space_node.iono_utc());
|
1431
|
+
}
|
1432
|
+
_header["LEAP SECONDS"] = s;
|
1433
|
+
}
|
1434
|
+
RINEX_NAV_Writer(std::ostream &out)
|
1435
|
+
: super_t(out, default_header, default_header_size) {}
|
1436
|
+
~RINEX_NAV_Writer(){}
|
1437
|
+
|
1438
|
+
self_t &operator<<(const message_t &msg){
|
1439
|
+
std::stringstream buf;
|
1440
|
+
switch(super_t::_version_type.version / 100){
|
1441
|
+
case 2:
|
1442
|
+
for(int i(0); i < 8; ++i){
|
1443
|
+
std::string s(80, ' ');
|
1444
|
+
switch(i){
|
1445
|
+
case 0: super_t::convert(reader_t::eph0_v2, s, &msg); break;
|
1446
|
+
case 1: super_t::convert(reader_t::eph1_v2, s, &msg); break;
|
1447
|
+
case 2: super_t::convert(reader_t::eph2_v2, s, &msg); break;
|
1448
|
+
case 3: super_t::convert(reader_t::eph3_v2, s, &msg); break;
|
1449
|
+
case 4: super_t::convert(reader_t::eph4_v2, s, &msg); break;
|
1450
|
+
case 5: super_t::convert(reader_t::eph5_v2, s, &msg); break;
|
1451
|
+
case 6: super_t::convert(reader_t::eph6_v2, s, &msg); break;
|
1452
|
+
case 7: super_t::convert(reader_t::eph7_v2, s, &msg); break;
|
1453
|
+
}
|
1454
|
+
buf << s << std::endl;
|
1455
|
+
}
|
1456
|
+
break;
|
1457
|
+
case 3:
|
1458
|
+
for(int i(0); i < 8; ++i){
|
1459
|
+
std::string s(80, ' ');
|
1460
|
+
switch(i){
|
1461
|
+
case 0: super_t::convert(reader_t::eph0_v3, s, &msg); s[0] = 'G'; break;
|
1462
|
+
case 1: super_t::convert(reader_t::eph1_v3, s, &msg); break;
|
1463
|
+
case 2: super_t::convert(reader_t::eph2_v3, s, &msg); break;
|
1464
|
+
case 3: super_t::convert(reader_t::eph3_v3, s, &msg); break;
|
1465
|
+
case 4: super_t::convert(reader_t::eph4_v3, s, &msg); break;
|
1466
|
+
case 5: super_t::convert(reader_t::eph5_v3, s, &msg); break;
|
1467
|
+
case 6: super_t::convert(reader_t::eph6_v3, s, &msg); break;
|
1468
|
+
case 7: super_t::convert(reader_t::eph7_v3, s, &msg); break;
|
1469
|
+
}
|
1470
|
+
buf << s << std::endl;
|
1471
|
+
}
|
1472
|
+
break;
|
1473
|
+
}
|
1474
|
+
dist << buf.str();
|
1475
|
+
return *this;
|
1476
|
+
}
|
1477
|
+
|
1478
|
+
protected:
|
1479
|
+
struct WriteAllFunctor {
|
1480
|
+
RINEX_NAV_Writer &w;
|
1481
|
+
int &counter;
|
1482
|
+
void operator()(const typename space_node_t::Satellite::Ephemeris &eph) {
|
1483
|
+
w << message_t(eph);
|
1484
|
+
counter++;
|
1485
|
+
}
|
1486
|
+
};
|
1487
|
+
|
1488
|
+
public:
|
1489
|
+
void set_version(
|
1490
|
+
const int &version,
|
1491
|
+
const super_t::version_type_t::sat_system_t &sys = super_t::version_type_t::SYS_GPS){
|
1492
|
+
super_t::set_version_type(typename super_t::version_type_t(
|
1493
|
+
version, super_t::version_type_t::FTYPE_NAVIGATION, sys));
|
1494
|
+
}
|
1495
|
+
|
1496
|
+
int write_all(const space_node_t &space_node, const int &version = 304){
|
1497
|
+
int res(-1);
|
1498
|
+
set_version(version);
|
1499
|
+
if(space_node.is_valid_iono_utc()){
|
1500
|
+
iono_alpha(space_node);
|
1501
|
+
iono_beta(space_node);
|
1502
|
+
utc_params(space_node);
|
1503
|
+
leap_seconds(space_node);
|
1504
|
+
}
|
1505
|
+
super_t::dist << header();
|
1506
|
+
res++;
|
1507
|
+
|
1508
|
+
WriteAllFunctor functor = {*this, res};
|
1509
|
+
for(typename space_node_t::satellites_t::const_iterator
|
1510
|
+
it(space_node.satellites().begin()), it_end(space_node.satellites().end());
|
1511
|
+
it != it_end; ++it){
|
1512
|
+
it->second.each_ephemeris(
|
1513
|
+
functor,
|
1514
|
+
space_node_t::Satellite::eph_list_t::EACH_ALL_INVERTED);
|
1515
|
+
}
|
1516
|
+
return res;
|
1517
|
+
}
|
1518
|
+
static int write_all(std::ostream &out, const space_node_t &space_node, const int &version = 304){
|
1519
|
+
RINEX_NAV_Writer writer(out);
|
1520
|
+
return writer.write_all(space_node, version);
|
1521
|
+
}
|
1522
|
+
};
|
1523
|
+
template <class FloatT>
|
1524
|
+
const typename RINEX_Writer<>::header_item_t RINEX_NAV_Writer<FloatT>::default_header[] = {
|
1525
|
+
{"RINEX VERSION / TYPE",
|
1526
|
+
" 2 NAVIGATION DATA"},
|
1527
|
+
{"PGM / RUN BY / DATE", NULL}};
|
1528
|
+
template <class FloatT>
|
1529
|
+
const int RINEX_NAV_Writer<FloatT>::default_header_size
|
1530
|
+
= sizeof(RINEX_NAV_Writer<FloatT>::default_header) / sizeof(RINEX_NAV_Writer<FloatT>::default_header[0]);
|
1531
|
+
|
1532
|
+
template <class FloatT>
|
1533
|
+
class RINEX_OBS_Writer : public RINEX_Writer<> {
|
1534
|
+
public:
|
1535
|
+
typedef typename RINEX_OBS<FloatT>::observation_t observation_t;
|
1536
|
+
typedef RINEX_OBS_Writer self_t;
|
1537
|
+
typedef RINEX_Writer<> super_t;
|
1538
|
+
typedef RINEX_OBS_Reader<FloatT> reader_t;
|
1539
|
+
protected:
|
1540
|
+
using super_t::RINEX_Float;
|
1541
|
+
using super_t::RINEX_FloatD;
|
1542
|
+
using super_t::RINEX_Value;
|
1543
|
+
using super_t::_header;
|
1544
|
+
using super_t::dist;
|
1545
|
+
public:
|
1546
|
+
void set_version(
|
1547
|
+
const int &version,
|
1548
|
+
const super_t::version_type_t::sat_system_t &sys = super_t::version_type_t::SYS_GPS){
|
1549
|
+
super_t::set_version_type(typename super_t::version_type_t(
|
1550
|
+
version, super_t::version_type_t::FTYPE_OBSERVATION, sys));
|
1551
|
+
}
|
1552
|
+
|
1553
|
+
static const header_item_t default_header[];
|
1554
|
+
static const int default_header_size;
|
1555
|
+
void maker_name(
|
1556
|
+
const std::string &name){
|
1557
|
+
_header["MARKER NAME"] = name.substr(0, 60);
|
1558
|
+
}
|
1559
|
+
void observer_agency(
|
1560
|
+
const std::string &observer, const std::string &agency){
|
1561
|
+
// ex) "BILL SMITH ABC INSTITUTE"
|
1562
|
+
std::stringstream ss;
|
1563
|
+
ss << std::setfill(' ') << std::left
|
1564
|
+
<< std::setw(20) << observer.substr(0, 20)
|
1565
|
+
<< std::setw(20) << agency.substr(0, 20);
|
1566
|
+
_header["OBSERVER / AGENCY"] = ss.str();
|
1567
|
+
}
|
1568
|
+
void receiver_spec(
|
1569
|
+
const std::string &num, const std::string &type, const std::string &vers){
|
1570
|
+
// ex) "X1234A123 XX ZZZ"
|
1571
|
+
std::stringstream ss;
|
1572
|
+
ss << std::setfill(' ') << std::left
|
1573
|
+
<< std::setw(20) << num.substr(0, 20)
|
1574
|
+
<< std::setw(20) << type.substr(0, 20)
|
1575
|
+
<< std::setw(20) << vers.substr(0, 20);
|
1576
|
+
_header["REC # / TYPE / VERS"] = ss.str();
|
1577
|
+
}
|
1578
|
+
void antenna_spec(
|
1579
|
+
const std::string &num, const std::string &type){
|
1580
|
+
// ex) "234 YY"
|
1581
|
+
std::stringstream ss;
|
1582
|
+
ss << std::setfill(' ') << std::left
|
1583
|
+
<< std::setw(20) << num.substr(0, 20)
|
1584
|
+
<< std::setw(20) << type.substr(0, 20);
|
1585
|
+
_header["ANT # / TYPE"] = ss.str();
|
1586
|
+
}
|
1587
|
+
void wavelength_fact(
|
1588
|
+
const int l1, const int l2){
|
1589
|
+
// ex) " 1 1"
|
1590
|
+
std::stringstream ss;
|
1591
|
+
ss << RINEX_Value(l1, 6) << RINEX_Value(l2, 6);
|
1592
|
+
_header["WAVELENGTH FACT L1/2"] = ss.str();
|
1593
|
+
}
|
1594
|
+
void approx_position(
|
1595
|
+
const FloatT &x, const FloatT &y, const FloatT &z){
|
1596
|
+
std::stringstream ss;
|
1597
|
+
ss << RINEX_Float(x, 14, 4)
|
1598
|
+
<< RINEX_Float(y, 14, 4)
|
1599
|
+
<< RINEX_Float(z, 14, 4);
|
1600
|
+
_header["APPROX POSITION XYZ"] = ss.str();
|
1601
|
+
}
|
1602
|
+
void antenna_delta_hew(
|
1603
|
+
const FloatT &h, const FloatT &e, const FloatT &w){
|
1604
|
+
std::stringstream ss;
|
1605
|
+
ss << RINEX_Float(h, 14, 4)
|
1606
|
+
<< RINEX_Float(e, 14, 4)
|
1607
|
+
<< RINEX_Float(w, 14, 4);
|
1608
|
+
_header["ANTENNA: DELTA H/E/W"] = ss.str();
|
1609
|
+
}
|
1610
|
+
void types_of_obs(
|
1611
|
+
const char *type_list[], const int list_size){
|
1612
|
+
std::stringstream ss;
|
1613
|
+
ss << RINEX_Value(list_size, 6);
|
1614
|
+
for(int i(0); i < list_size; i++){
|
1615
|
+
ss << RINEX_Value(
|
1616
|
+
std::string(type_list[i]).substr(0, 6), 6);
|
1617
|
+
}
|
1618
|
+
_header["# / TYPES OF OBSERV"] = ss.str();
|
1619
|
+
}
|
1620
|
+
void interval(const FloatT &seconds){
|
1621
|
+
std::stringstream ss;
|
1622
|
+
ss << RINEX_Float(seconds, 6, 4);
|
1623
|
+
_header["INTERVAL"] = ss.str();
|
1624
|
+
}
|
1625
|
+
void interval(const int seconds){
|
1626
|
+
std::stringstream ss;
|
1627
|
+
ss << RINEX_Value(seconds, 6);
|
1628
|
+
_header["INTERVAL"] = ss.str();
|
1629
|
+
}
|
1630
|
+
void insert_header_time_item(
|
1631
|
+
const char *label,
|
1632
|
+
const struct tm &t, const FloatT &rest_second = 0,
|
1633
|
+
const bool is_gps_time = true){
|
1634
|
+
std::stringstream ss;
|
1635
|
+
if(t.tm_year < 80){
|
1636
|
+
ss << RINEX_Value(2000 + t.tm_year, 6);
|
1637
|
+
}else{
|
1638
|
+
ss << RINEX_Value(1900 + t.tm_year, 6);
|
1639
|
+
}
|
1640
|
+
ss << RINEX_Value(t.tm_mon + 1, 6);
|
1641
|
+
ss << RINEX_Value(t.tm_mday, 6);
|
1642
|
+
ss << RINEX_Value(t.tm_hour, 6);
|
1643
|
+
ss << RINEX_Value(t.tm_min, 6);
|
1644
|
+
ss << RINEX_Float(rest_second + t.tm_sec, 12, 6);
|
1645
|
+
if(is_gps_time){
|
1646
|
+
ss << RINEX_Value("GPS", 9);
|
1647
|
+
}
|
1648
|
+
_header[label] = ss.str();
|
1649
|
+
}
|
1650
|
+
void insert_header_time_item(
|
1651
|
+
const char *label, const GPS_Time<FloatT> &t){
|
1652
|
+
FloatT sec_f(t.seconds), sec_i;
|
1653
|
+
sec_f = std::modf(sec_f, &sec_i);
|
1654
|
+
insert_header_time_item(label,
|
1655
|
+
t.c_tm(), sec_f, true);
|
1656
|
+
}
|
1657
|
+
void first_obs(
|
1658
|
+
const struct tm &t, const double rest_second = 0,
|
1659
|
+
const bool is_gps_time = true){
|
1660
|
+
insert_header_time_item("TIME OF FIRST OBS",
|
1661
|
+
t, rest_second, is_gps_time);
|
1662
|
+
}
|
1663
|
+
void first_obs(const GPS_Time<FloatT> &t){
|
1664
|
+
insert_header_time_item("TIME OF FIRST OBS", t);
|
1665
|
+
}
|
1666
|
+
void last_obs(
|
1667
|
+
const struct tm &t, const double rest_second = 0,
|
1668
|
+
const bool is_gps_time = true){
|
1669
|
+
insert_header_time_item("TIME OF LAST OBS",
|
1670
|
+
t, rest_second, is_gps_time);
|
1671
|
+
}
|
1672
|
+
void last_obs(const GPS_Time<FloatT> &t){
|
1673
|
+
insert_header_time_item("TIME OF LAST OBS", t);
|
1674
|
+
}
|
1675
|
+
RINEX_OBS_Writer(std::ostream &out)
|
1676
|
+
: super_t(out, default_header, default_header_size) {}
|
1677
|
+
~RINEX_OBS_Writer(){}
|
1678
|
+
self_t &operator<<(const observation_t &obs){
|
1679
|
+
if(obs.per_satellite.size() <= 0){return *this;}
|
1680
|
+
|
1681
|
+
typedef typename observation_t::per_satellite_t per_satellite_t;
|
1682
|
+
|
1683
|
+
std::stringstream top, rest;
|
1684
|
+
|
1685
|
+
std::string buf(80, ' ');
|
1686
|
+
int ver_major(super_t::_version_type.version / 100);
|
1687
|
+
{ // epoch
|
1688
|
+
typename RINEX_OBS<FloatT>::epoch_flag_t epoch_flag(obs);
|
1689
|
+
epoch_flag.items_followed = obs.per_satellite.size(); // Num. of satellites
|
1690
|
+
switch(ver_major){
|
1691
|
+
case 2: super_t::convert(reader_t::epoch_flag_v2, buf, &epoch_flag); break;
|
1692
|
+
case 3: super_t::convert(reader_t::epoch_flag_v3, buf, &epoch_flag); buf[0] = '>'; break;
|
1693
|
+
default: return *this;
|
1694
|
+
}
|
1695
|
+
}
|
1696
|
+
|
1697
|
+
int i(0);
|
1698
|
+
for(typename per_satellite_t::const_iterator
|
1699
|
+
it(obs.per_satellite.begin()), it_end(obs.per_satellite.end());
|
1700
|
+
it != it_end; ++it, ++i){ // Enumerate satellites
|
1701
|
+
|
1702
|
+
// If satellites are more than 12, then use the next line
|
1703
|
+
if((i == 12) && (ver_major == 2)){
|
1704
|
+
i = 0;
|
1705
|
+
top << buf << std::endl;
|
1706
|
+
buf = std::string(80, ' ');
|
1707
|
+
}
|
1708
|
+
|
1709
|
+
// Write PRN number to list
|
1710
|
+
{
|
1711
|
+
int serial(it->first), prn;
|
1712
|
+
char sys(reader_t::serial2sys(serial, prn));
|
1713
|
+
std::string sat_str(3, ' ');
|
1714
|
+
sat_str[0] = sys;
|
1715
|
+
reader_t::template conv_t<int>::d(sat_str, 1, 2, &prn, 1, false);
|
1716
|
+
switch(ver_major){
|
1717
|
+
case 2: buf.replace(32 + i * 3, 3, sat_str); break;
|
1718
|
+
case 3: rest << sat_str; break;
|
1719
|
+
}
|
1720
|
+
}
|
1721
|
+
|
1722
|
+
// Observation data
|
1723
|
+
int i2(5);
|
1724
|
+
for(typename per_satellite_t::mapped_type::const_iterator it2(it->second.begin()),
|
1725
|
+
it2_end(it->second.end());
|
1726
|
+
it2 != it2_end; ++it2){
|
1727
|
+
if((ver_major == 2) && (i2-- == 0)){
|
1728
|
+
i2 = 4;
|
1729
|
+
rest << std::endl;
|
1730
|
+
}
|
1731
|
+
std::string buf2(16, ' ');
|
1732
|
+
if(it2->valid){
|
1733
|
+
super_t::convert(reader_t::record_v2v3, buf2, &(*it2));
|
1734
|
+
if(it2->lli == 0){buf2[14] = ' ';}
|
1735
|
+
if(it2->ss == 0){buf2[15] = ' ';}
|
1736
|
+
}
|
1737
|
+
rest << buf2;
|
1738
|
+
}
|
1739
|
+
if(ver_major == 2){
|
1740
|
+
rest << std::string(16 * i2, ' ');
|
1741
|
+
}
|
1742
|
+
rest << std::endl;
|
1743
|
+
}
|
1744
|
+
top << buf << std::endl;
|
1745
|
+
|
1746
|
+
dist << top.str() << rest.str();
|
1747
|
+
return *this;
|
1748
|
+
}
|
1749
|
+
};
|
1750
|
+
template <class FloatT>
|
1751
|
+
const typename RINEX_Writer<>::header_item_t RINEX_OBS_Writer<FloatT>::default_header[] = {
|
1752
|
+
{"RINEX VERSION / TYPE",
|
1753
|
+
" 2 OBSERVATION DATA"},
|
1754
|
+
{"PGM / RUN BY / DATE",
|
1755
|
+
"XXRINEXO V9.9 AIUB 12-SEP-90 12:43"},
|
1756
|
+
{"COMMENT", NULL},
|
1757
|
+
{"MARKER NAME", "A 9080"},
|
1758
|
+
{"MARKER NUMBER", NULL},
|
1759
|
+
{"OBSERVER / AGENCY",
|
1760
|
+
"BILL SMITH ABC INSTITUTE"},
|
1761
|
+
{"REC # / TYPE / VERS",
|
1762
|
+
"X1234A123 XX ZZZ"},
|
1763
|
+
{"ANT # / TYPE", "234 YY"},
|
1764
|
+
{"APPROX POSITION XYZ",
|
1765
|
+
" -3947762.7496 3364399.8789 3699428.5111"},
|
1766
|
+
{"ANTENNA: DELTA H/E/W",
|
1767
|
+
" 0.0000 0.0000 0.0000"},
|
1768
|
+
{"WAVELENGTH FACT L1/2",
|
1769
|
+
" 1 1"},
|
1770
|
+
{"# / TYPES OF OBSERV",
|
1771
|
+
" 4 P1 L1 L2 P2"},
|
1772
|
+
{"INTERVAL", " 1"},
|
1773
|
+
{"TIME OF FIRST OBS", " 1990 3 24 13 10 36.000000"},
|
1774
|
+
{"TIME OF LAST OBS", NULL},
|
1775
|
+
{"# OF SATELLITES", NULL},
|
1776
|
+
{"PRN / # OF OBS", NULL}};
|
1777
|
+
template <class FloatT>
|
1778
|
+
const int RINEX_OBS_Writer<FloatT>::default_header_size
|
1779
|
+
= sizeof(RINEX_OBS_Writer<FloatT>::default_header) / sizeof(RINEX_OBS_Writer<FloatT>::default_header[0]);
|
1780
|
+
|
1781
|
+
#endif // __RINEX_H__
|