gps_pvt 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- 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__
|