source: ntrip/trunk/BNC/RTCM/RTCM2.cpp@ 247

Last change on this file since 247 was 247, checked in by mervart, 18 years ago

* empty log message *

File size: 24.0 KB
Line 
1//------------------------------------------------------------------------------
2//
3// RTCM2.cpp
4//
5// Purpose:
6//
7// Module for extraction of RTCM2 messages
8//
9// Notes:
10//
11// - The host computer is assumed to use little endian (Intel) byte order
12//
13// Last modified:
14//
15// 2006/09/17 OMO Created
16// 2006/09/19 OMO Fixed getHeader() methods
17// 2006/09/21 OMO Reduced phase ambiguity to 2^23 cycles
18// 2006/10/05 OMO Specified const'ness of various member functions
19// 2006/10/13 LMV Fixed resolvedPhase to handle missing C1 range
20//
21// (c) DLR/GSOC
22//
23//------------------------------------------------------------------------------
24
25#include <cmath>
26#include <fstream>
27#include <iomanip>
28#include <iostream>
29#include <string>
30#include <vector>
31
32#include "RTCM2.h"
33
34
35using namespace std;
36
37
38// GPS constants
39
40const double c_light = 299792458.0; // Speed of light [m/s]; IAU 1976
41const double f_L1 = 1575.42e6; // L1 frequency [Hz] (10.23MHz*154)
42const double f_L2 = 1227.60e6; // L2 frequency [Hz] (10.23MHz*120)
43
44const double lambda_L1 = c_light/f_L1; // L1 wavelength [m] (0.1903m)
45const double lambda_L2 = c_light/f_L2; // L2 wavelength [m]
46
47//
48// Bits for message availability checks
49//
50
51const int bit_L1rngGPS = 0;
52const int bit_L2rngGPS = 1;
53const int bit_L1cphGPS = 2;
54const int bit_L2cphGPS = 3;
55const int bit_L1rngGLO = 4;
56const int bit_L2rngGLO = 5;
57const int bit_L1cphGLO = 6;
58const int bit_L2cphGLO = 7;
59
60
61//
62// namespace rtcm2
63//
64
65namespace rtcm2 {
66
67
68//------------------------------------------------------------------------------
69//
70// class ThirtyBitWord (implementation)
71//
72// Purpose:
73//
74// Handling of RTCM2 30bit words
75//
76//------------------------------------------------------------------------------
77
78// Constructor
79
80ThirtyBitWord::ThirtyBitWord() : W(0) {
81};
82
83// Clear entire 30-bit word and 2-bit parity from previous word
84
85void ThirtyBitWord::clear() {
86 W = 0;
87};
88
89// Failure indicator for input operations
90
91bool ThirtyBitWord::fail() const {
92 return failure;
93};
94
95// Parity check
96
97bool ThirtyBitWord::validParity() const {
98
99 // Parity stuff
100
101 static const unsigned int PARITY_25 = 0xBB1F3480;
102 static const unsigned int PARITY_26 = 0x5D8F9A40;
103 static const unsigned int PARITY_27 = 0xAEC7CD00;
104 static const unsigned int PARITY_28 = 0x5763E680;
105 static const unsigned int PARITY_29 = 0x6BB1F340;
106 static const unsigned int PARITY_30 = 0x8B7A89C0;
107
108 // Look-up table for parity of eight bit bytes
109 // (parity=0 if the number of 0s and 1s is equal, else parity=1)
110 static unsigned char byteParity[] = {
111 0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0,1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1,
112 1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1,0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0,
113 1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1,0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0,
114 0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0,1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1,
115 1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1,0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0,
116 0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0,1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1,
117 0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0,1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1,
118 1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1,0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0
119 };
120
121 // Local variables
122
123 unsigned int t, w, p;
124
125 // The sign of the data is determined by the D30* parity bit
126 // of the previous data word. If D30* is set, invert the data
127 // bits D01..D24 to obtain the d01..d24 (but leave all other
128 // bits untouched).
129
130 w = W;
131 if ( w & 0x40000000 ) w ^= 0x3FFFFFC0;
132
133 // Compute the parity of the sign corrected data bits d01..d24
134 // as described in the ICD-GPS-200
135
136 t = w & PARITY_25;
137 p = ( byteParity[t &0xff] ^ byteParity[(t>> 8)&0xff] ^
138 byteParity[(t>>16)&0xff] ^ byteParity[(t>>24) ] );
139
140 t = w & PARITY_26;
141 p = (p<<1) |
142 ( byteParity[t &0xff] ^ byteParity[(t>> 8)&0xff] ^
143 byteParity[(t>>16)&0xff] ^ byteParity[(t>>24) ] );
144
145 t = w & PARITY_27;
146 p = (p<<1) |
147 ( byteParity[t &0xff] ^ byteParity[(t>> 8)&0xff] ^
148 byteParity[(t>>16)&0xff] ^ byteParity[(t>>24) ] );
149
150 t = w & PARITY_28;
151 p = (p<<1) |
152 ( byteParity[t &0xff] ^ byteParity[(t>> 8)&0xff] ^
153 byteParity[(t>>16)&0xff] ^ byteParity[(t>>24) ] );
154
155 t = w & PARITY_29;
156 p = (p<<1) |
157 ( byteParity[t &0xff] ^ byteParity[(t>> 8)&0xff] ^
158 byteParity[(t>>16)&0xff] ^ byteParity[(t>>24) ] );
159
160 t = w & PARITY_30;
161 p = (p<<1) |
162 ( byteParity[t &0xff] ^ byteParity[(t>> 8)&0xff] ^
163 byteParity[(t>>16)&0xff] ^ byteParity[(t>>24) ] );
164
165 return ( (W!=0) && ((W &0x3f) == p));
166
167};
168
169
170// Check preamble
171
172bool ThirtyBitWord::isHeader() const {
173
174 const unsigned char Preamble = 0x66;
175
176 unsigned char b = (value()>>22) & 0xFF;
177
178 return ( b==Preamble );
179
180};
181
182
183// Return entire 32-bit (current word and previous parity)
184
185unsigned int ThirtyBitWord::all() const {
186 return W;
187};
188
189
190// Return sign-corrected 30-bit (or zero if parity mismatch)
191
192unsigned int ThirtyBitWord::value() const {
193
194 unsigned int w = W;
195
196 if (validParity()) {
197 // Return data and current parity bits. Invert data bits if D30*
198 // is set and discard old parity bits.
199 if ( w & 0x40000000 ) w ^= 0x3FFFFFC0;
200 return (w & 0x3FFFFFFF);
201 }
202 else {
203 // Error; invalid parity
204 return 0;
205 };
206
207};
208
209
210
211// Append a byte with six data bits
212
213void ThirtyBitWord::append(unsigned char b) {
214
215 // Look up table for swap (left-right) of 6 data bits
216 static const unsigned char
217 swap[] = {
218 0,32,16,48, 8,40,24,56, 4,36,20,52,12,44,28,60,
219 2,34,18,50,10,42,26,58, 6,38,22,54,14,46,30,62,
220 1,33,17,49, 9,41,25,57, 5,37,21,53,13,45,29,61,
221 3,35,19,51,11,43,27,59, 7,39,23,55,15,47,31,63
222 };
223
224 // Bits 7 and 6 (of 0..7) must be "01" for valid data bytes
225 if ( (b & 0x40) != 0x40 ) {
226 failure = true;
227 return;
228 };
229
230 // Swap bits 0..5 to restore proper bit order for 30bit words
231 b = swap[ b & 0x3f];
232
233 // Fill word
234 W = ( (W <<6) | (b & 0x3f) ) ;
235
236};
237
238
239// Get next 30bit word from string
240
241void ThirtyBitWord::get(string& buf) {
242
243 // Check if string is long enough
244
245 if (buf.size()<5) {
246 failure = true;
247 return;
248 };
249
250 // Process 5 bytes and remove them from the input
251
252 for (int i=0; i<5; i++) append(buf[i]);
253 buf.erase(0,5);
254
255 failure = false;
256
257};
258
259// Get next 30bit word from file
260
261void ThirtyBitWord::get(istream& inp) {
262
263 unsigned char b;
264
265 for (int i=0; i<5; i++) {
266 inp >> b;
267 if (inp.fail()) { clear(); return; };
268 append(b);
269 };
270
271 failure = false;
272
273};
274
275// Get next header word from string
276
277void ThirtyBitWord::getHeader(string& buf) {
278
279 unsigned int W_old = W;
280 unsigned int i;
281
282 i=0;
283 while (!isHeader() || i<5 ) {
284 // Check if string is long enough; if not restore old word and exit
285 if (buf.size() == 0 || buf.size()-1<i) {
286 W = W_old;
287 failure = true;
288 return;
289 };
290 // Process byte
291 append(buf[i]); i++;
292 };
293
294 // Remove processed bytes from buffer
295
296 buf.erase(0,i);
297
298 failure = false;
299
300};
301
302// Get next header word from file
303
304void ThirtyBitWord::getHeader(istream& inp) {
305
306 unsigned char b;
307 unsigned int i;
308
309 i=0;
310 while ( !isHeader() || i<5 ) {
311 inp >> b;
312 if (inp.fail()) { clear(); return; };
313 append(b); i++;
314 };
315
316 failure = false;
317
318};
319
320
321//------------------------------------------------------------------------------
322//
323// RTCM2packet (class implementation)
324//
325// Purpose:
326//
327// A class for handling RTCM2 data packets
328//
329//------------------------------------------------------------------------------
330
331// Constructor
332
333RTCM2packet::RTCM2packet() {
334 clear();
335};
336
337// Initialization
338
339void RTCM2packet::clear() {
340
341 W.clear();
342
343 H1=0;
344 H2=0;
345
346 DW.resize(0,0);
347
348};
349
350// Complete packet, valid parity
351
352bool RTCM2packet::valid() const {
353
354 // The methods for creating a packet (get,">>") ensure
355 // that a packet has a consistent number of data words
356 // and a valid parity in all header and data words.
357 // Therefore a packet is either empty or valid.
358
359 return (H1!=0);
360
361};
362
363
364//
365// Gets the next packet from the buffer
366//
367
368void RTCM2packet::getPacket(std::string& buf) {
369
370 int n;
371 ThirtyBitWord W_old = W;
372 string buf_old = buf;
373
374 // Try to read a full packet. If the input buffer is too short
375 // clear all data and restore the latest 30-bit word prior to
376 // the getPacket call. The empty header word will indicate
377 // an invalid message, which signals an unsuccessful getPacket()
378 // call.
379
380 W.getHeader(buf);
381 H1 = W.value();
382 if (W.fail()) { clear(); W=W_old; buf=buf_old; return; }
383
384 W.get(buf);
385 H2 = W.value();
386 if (W.fail()) { clear(); W=W_old; buf=buf_old; return; }
387
388 n = nDataWords();
389 DW.resize(n);
390 for (int i=0; i<n; i++) {
391 W.get(buf);
392 DW[i] = W.value();
393 if (W.fail()) { clear(); W=W_old; buf=buf_old; return; }
394 };
395
396 return;
397
398};
399
400
401//
402// Gets the next packet from the input stream
403//
404
405void RTCM2packet::getPacket(std::istream& inp) {
406
407 int n;
408
409 W.getHeader(inp);
410 H1 = W.value();
411 if (W.fail()) { clear(); return; }
412
413 W.get(inp);
414 H2 = W.value();
415 if (W.fail()) { clear(); return; }
416
417 n = nDataWords();
418 DW.resize(n);
419 for (int i=0; i<n; i++) {
420 W.get(inp);
421 DW[i] = W.value();
422 if (W.fail()) { clear(); return; }
423 };
424
425 return;
426
427};
428
429//
430// Input operator
431//
432// Reads an RTCM3 packet from the input stream.
433//
434
435istream& operator >> (istream& is, RTCM2packet& p) {
436
437 p.getPacket(is);
438
439 return is;
440
441};
442
443// Access methods
444
445unsigned int RTCM2packet::header1() const {
446 return H1;
447};
448
449unsigned int RTCM2packet::header2() const {
450 return H2;
451};
452
453unsigned int RTCM2packet::dataWord(int i) const {
454 if ( (unsigned int)i < DW.size() ) {
455 return DW[i];
456 }
457 else {
458 return 0;
459 }
460};
461
462unsigned int RTCM2packet::msgType() const {
463 return ( H1>>16 & 0x003F );
464};
465
466unsigned int RTCM2packet::stationID() const {
467 return ( H1>> 6 & 0x03FF );
468};
469
470unsigned int RTCM2packet::modZCount() const {
471 return ( H2>>17 & 0x01FFF );
472};
473
474unsigned int RTCM2packet::seqNumber() const {
475 return ( H2>>14 & 0x0007 );
476};
477
478unsigned int RTCM2packet::nDataWords() const {
479 return ( H2>> 9 & 0x001F );
480};
481
482unsigned int RTCM2packet::staHealth() const {
483 return ( H2>> 6 & 0x0003 );
484};
485
486
487//
488// Get unsigned bit field
489//
490// Bits are numbered from left (msb) to right (lsb) starting at bit 0
491//
492
493unsigned int RTCM2packet::getUnsignedBits ( unsigned int start,
494 unsigned int n ) const {
495
496 unsigned int iFirst = start/24; // Index of first data word
497 unsigned int iLast = (start+n-1)/24; // Index of last data word
498 unsigned int bitField = 0;
499 unsigned int tmp;
500
501 // Checks
502
503 if (n>32) {
504 cerr << "Error: can't handle >32 bits in RTCM2packet::getUnsignedBits"
505 << endl;
506 return 0; // exit(-1);
507 };
508
509 if ( 24*DW.size() < start+n-1 ) {
510 cerr << "Error: Packet too short in RTCM2packet::getUnsignedBits" << endl;
511 return 0; // exit(-1);
512 }
513
514 // Handle initial data word
515 // Get all data bits. Strip parity and unwanted leading bits.
516 // Store result in 24 lsb bits of tmp.
517
518 tmp = (DW[iFirst]>>6) & 0xFFFFFF;
519 tmp = ( ( tmp << start%24) & 0xFFFFFF ) >> start%24 ;
520
521 // Handle central data word
522
523 if ( iFirst<iLast ) {
524 bitField = tmp;
525 for (unsigned int iWord=iFirst+1; iWord<iLast; iWord++) {
526 tmp = (DW[iWord]>>6) & 0xFFFFFF;
527 bitField = (bitField << 24) | tmp;
528 };
529 tmp = (DW[iLast]>>6) & 0xFFFFFF;
530 };
531
532 // Handle last data word
533
534 tmp = tmp >> (23-(start+n-1)%24);
535 bitField = (bitField << ((start+n-1)%24+1)) | tmp;
536
537 // Done
538
539 return bitField;
540
541};
542
543//
544// Get signed bit field
545//
546// Bits are numbered from left (msb) to right (lsb) starting at bit 0
547//
548
549int RTCM2packet::getBits ( unsigned int start,
550 unsigned int n ) const {
551
552
553 // Checks
554
555 if (n>32) {
556 cerr << "Error: can't handle >32 bits in RTCM2packet::getBits"
557 << endl;
558 return 0; // exit(-1);
559 };
560
561 if ( 24*DW.size() < start+n-1 ) {
562 cerr << "Error: Packet too short in RTCM2packet::getBits" << endl;
563 return 0; // exit(-1);
564 }
565
566 return ((int)(getUnsignedBits(start,n)<<(32-n))>>(32-n));
567
568};
569
570
571//------------------------------------------------------------------------------
572//
573// RTCM2_03 (class implementation)
574//
575// Purpose:
576//
577// A class for handling RTCM 2 GPS Reference Station Parameters messages
578//
579//------------------------------------------------------------------------------
580
581void RTCM2_03::extract(const RTCM2packet& P) {
582
583 // Check validity and packet type
584
585 validMsg = (P.valid());
586 if (!validMsg) return;
587
588 validMsg = (P.ID()==03);
589 if (!validMsg) return;
590
591 // Antenna reference point coordinates
592
593 x = P.getBits( 0,32)*0.01; // X [m]
594 y = P.getBits(32,32)*0.01; // Y [m]
595 z = P.getBits(64,32)*0.01; // Z [m]
596
597};
598
599//------------------------------------------------------------------------------
600//
601// RTCM2_23 (class implementation)
602//
603// Purpose:
604//
605// A class for handling RTCM 2 Antenna Type Definition messages
606//
607//------------------------------------------------------------------------------
608
609void RTCM2_23::extract(const RTCM2packet& P) {
610
611 int nad, nas;
612
613 // Check validity and packet type
614
615 validMsg = (P.valid());
616 if (!validMsg) return;
617
618 validMsg = (P.ID()==23);
619 if (!validMsg) return;
620
621 // Antenna descriptor
622 antType = "";
623 nad = P.getUnsignedBits(3,5);
624 for (int i=0;i<nad;i++)
625 antType += (char)P.getUnsignedBits(8+i*8,8);
626
627 // Optional antenna serial numbers
628 if (P.getUnsignedBits(2,1)==1) {
629 nas = P.getUnsignedBits(19+8*nad,5);
630 antSN = "";
631 for (int i=0;i<nas;i++)
632 antSN += (char)P.getUnsignedBits(24+8*nas+i*8,8);
633 };
634
635};
636
637
638//------------------------------------------------------------------------------
639//
640// RTCM2_24 (class implementation)
641//
642// Purpose:
643//
644// A class for handling RTCM 2 Reference Station Antenna
645// Reference Point Parameter messages
646//
647//------------------------------------------------------------------------------
648
649void RTCM2_24::extract(const RTCM2packet& P) {
650
651 double dx,dy,dz;
652
653 // Check validity and packet type
654
655 validMsg = (P.valid());
656 if (!validMsg) return;
657
658 validMsg = (P.ID()==24);
659 if (!validMsg) return;
660
661 // System indicator
662
663 isGPS = (P.getUnsignedBits(118,1)==0);
664 isGLONASS = (P.getUnsignedBits(118,1)==1);
665
666 // Antenna reference point coordinates
667
668 x = 64.0*P.getBits( 0,32);
669 y = 64.0*P.getBits(40,32);
670 z = 64.0*P.getBits(80,32);
671 dx = P.getUnsignedBits( 32,6);
672 dy = P.getUnsignedBits( 72,6);
673 dz = P.getUnsignedBits(112,6);
674 x = 0.0001*( x + (x<0? -dx:+dx) );
675 y = 0.0001*( y + (y<0? -dy:+dy) );
676 z = 0.0001*( z + (z<0? -dz:+dz) );
677
678 // Antenna Height
679
680 if (P.getUnsignedBits(119,1)==1) {
681 h= P.getUnsignedBits(120,18)*0.0001;
682 };
683
684
685};
686
687
688//------------------------------------------------------------------------------
689//
690// RTCM2_Obs (class definition)
691//
692// Purpose:
693//
694// A class for handling blocks of RTCM2 18 & 19 packets that need to be
695// combined to get a complete set of measurements
696//
697// Notes:
698//
699// The class collects L1/L2 code and phase measurements for GPS and GLONASS.
700// Since the Multiple Message Indicator is inconsistently handled by various
701// receivers we simply require code and phase on L1 and L2 for a complete
702// set ob observations at a given epoch. GLONASS observations are optional,
703// but all four types (code+phase,L1+L2) must be provided, if at least one
704// is given. Also, the GLONASS message must follow the corresponding GPS
705// message.
706//
707//------------------------------------------------------------------------------
708
709// Constructor
710
711RTCM2_Obs::RTCM2_Obs() {
712
713 clear();
714
715};
716
717// Reset entire block
718
719void RTCM2_Obs::clear() {
720
721 secs=0.0; // Seconds of hour (GPS time)
722 nSat=0; // Number of space vehicles
723 PRN.resize(0); // Pseudorange [m]
724 rng_C1.resize(0); // Pseudorange [m]
725 rng_P1.resize(0); // Pseudorange [m]
726 rng_P2.resize(0); // Pseudorange [m]
727 cph_L1.resize(0); // Carrier phase [m]
728 cph_L2.resize(0); // Carrier phase [m]
729
730 availability.reset(); // Message status flags
731 pendingMsg = true; // Multiple message indicator
732
733};
734
735// Availability checks
736
737bool RTCM2_Obs::anyGPS() const {
738
739 return availability.test(bit_L1rngGPS) ||
740 availability.test(bit_L2rngGPS) ||
741 availability.test(bit_L1cphGPS) ||
742 availability.test(bit_L2cphGPS);
743
744};
745
746bool RTCM2_Obs::anyGLONASS() const {
747
748 return availability.test(bit_L1rngGLO) ||
749 availability.test(bit_L2rngGLO) ||
750 availability.test(bit_L1cphGLO) ||
751 availability.test(bit_L2cphGLO);
752
753};
754
755bool RTCM2_Obs::allGPS() const {
756
757 return availability.test(bit_L1rngGPS) &&
758 availability.test(bit_L2rngGPS) &&
759 availability.test(bit_L1cphGPS) &&
760 availability.test(bit_L2cphGPS);
761
762};
763
764bool RTCM2_Obs::allGLONASS() const {
765
766 return availability.test(bit_L1rngGLO) &&
767 availability.test(bit_L2rngGLO) &&
768 availability.test(bit_L1cphGLO) &&
769 availability.test(bit_L2cphGLO);
770
771};
772
773// Validity
774
775bool RTCM2_Obs::valid() const {
776
777 return ( allGPS() && (allGLONASS() || !anyGLONASS()) && !pendingMsg );
778
779};
780
781
782//
783// Extract RTCM2 18 & 19 messages and store relevant data for future use
784//
785
786void RTCM2_Obs::extract(const RTCM2packet& P) {
787
788 bool isGPS,isCAcode,isL1,isOth;
789 int NSat,idx;
790 int sid,prn;
791 double t,rng,cph;
792
793 // Check validity and packet type
794
795 if (!P.valid()) return;
796
797 // Clear previous data if block was already complete
798
799 if (valid()) clear();
800
801 // Process carrier phase message
802
803 if ( P.ID()==18 ) {
804
805 // Number of satellites in current message
806 NSat = (P.nDataWords()-1)/2;
807
808 // Current epoch (mod 3600 sec)
809 t = 0.6*P.modZCount()
810 + P.getUnsignedBits(4,20)*1.0e-6;
811
812 // Frequency (exit if neither L1 nor L2)
813 isL1 = ( P.getUnsignedBits(0,1)==0 );
814 isOth = ( P.getUnsignedBits(1,1)==1 );
815 if (isOth) return;
816
817 // Constellation (for first satellite in message)
818 isGPS = ( P.getUnsignedBits(26,1)==0 );
819
820 // Multiple Message Indicator (only checked for first satellite)
821 pendingMsg = ( P.getUnsignedBits(24,1)==1 );
822
823 // Handle epoch: store epoch of first GPS message and
824 // check consistency of subsequent messages. GLONASS time tags
825 // are different and have to be ignored
826 if (isGPS) {
827 if ( nSat==0 ) {
828 secs = t; // Store epoch
829 }
830 else if (t!=secs) {
831 clear(); secs = t; // Clear all data, then store epoch
832 };
833 };
834
835 // Discard GLONASS obseravtions if no prior GPS observations
836 // are available
837 if (!isGPS && !anyGPS() ) return;
838
839 // Set availability flags
840
841 if ( isL1 && isGPS) availability.set(bit_L1cphGPS);
842 if (!isL1 && isGPS) availability.set(bit_L2cphGPS);
843 if ( isL1 && !isGPS) availability.set(bit_L1cphGLO);
844 if (!isL1 && !isGPS) availability.set(bit_L2cphGLO);
845
846 // Process all satellites
847
848 for (int iSat=0;iSat<NSat;iSat++){
849
850 // Code type
851 isCAcode = ( P.getUnsignedBits(iSat*48+25,1)==0 );
852
853 // Satellite
854 sid = P.getUnsignedBits(iSat*48+27,5);
855 prn = (isGPS? sid : sid+200 );
856
857 // Carrier phase measurement (mod 2^23 [cy]; sign matched to range)
858 cph = -P.getBits(iSat*48+40,32)/256.0;
859
860 // Is this a new PRN?
861 idx=-1;
862 for (unsigned int i=0;i<PRN.size();i++) {
863 if (PRN[i]==prn) { idx=i; break; };
864 };
865 if (idx==-1) {
866 // Insert new sat at end of list
867 nSat++; idx = nSat-1;
868 PRN.push_back(prn);
869 rng_C1.push_back(0.0);
870 rng_P1.push_back(0.0);
871 rng_P2.push_back(0.0);
872 cph_L1.push_back(0.0);
873 cph_L2.push_back(0.0);
874 };
875
876 // Store measurement
877 if (isL1) {
878 cph_L1[idx] = cph;
879 }
880 else {
881 cph_L2[idx] = cph;
882 };
883
884 };
885
886 };
887
888
889 // Process pseudorange message
890
891 if ( P.ID()==19 ) {
892
893 // Number of satellites in current message
894 NSat = (P.nDataWords()-1)/2;
895
896 // Current epoch (mod 3600 sec)
897 t = 0.6*P.modZCount()
898 + P.getUnsignedBits(4,20)*1.0e-6;
899
900 // Frequency (exit if neither L1 nor L2)
901 isL1 = ( P.getUnsignedBits(0,1)==0 );
902 isOth = ( P.getUnsignedBits(1,1)==1 );
903 if (isOth) return;
904
905 // Constellation (for first satellite in message)
906 isGPS = ( P.getUnsignedBits(26,1)==0 );
907
908 // Multiple Message Indicator (only checked for first satellite)
909 pendingMsg = ( P.getUnsignedBits(24,1)==1 );
910
911 // Handle epoch: store epoch of first GPS message and
912 // check consistency of subsequent messages. GLONASS time tags
913 // are different and have to be ignored
914 if (isGPS) {
915 if ( nSat==0 ) {
916 secs = t; // Store epoch
917 }
918 else if (t!=secs) {
919 clear(); secs = t; // Clear all data, then store epoch
920 };
921 };
922
923 // Discard GLONASS obseravtions if nor prior GPS observations
924 // are available
925 if (!isGPS && !anyGPS() ) return;
926
927 // Set availability flags
928 if ( isL1 && isGPS) availability.set(bit_L1rngGPS);
929 if (!isL1 && isGPS) availability.set(bit_L2rngGPS);
930 if ( isL1 && !isGPS) availability.set(bit_L1rngGLO);
931 if (!isL1 && !isGPS) availability.set(bit_L2rngGLO);
932
933 // Process all satellites
934
935 for (int iSat=0;iSat<NSat;iSat++){
936
937 // Code type
938 isCAcode = ( P.getUnsignedBits(iSat*48+25,1)==0 );
939
940 // Satellite
941 sid = P.getUnsignedBits(iSat*48+27,5);
942 prn = (isGPS? sid : sid+200 );
943
944 // Pseudorange measurement [m]
945 rng = P.getUnsignedBits(iSat*48+40,32)*0.02;
946
947 // Is this a new PRN?
948 idx=-1;
949 for (unsigned int i=0;i<PRN.size();i++) {
950 if (PRN[i]==prn) { idx=i; break; };
951 };
952 if (idx==-1) {
953 // Insert new sat at end of list
954 nSat++; idx = nSat-1;
955 PRN.push_back(prn);
956 rng_C1.push_back(0.0);
957 rng_P1.push_back(0.0);
958 rng_P2.push_back(0.0);
959 cph_L1.push_back(0.0);
960 cph_L2.push_back(0.0);
961 };
962
963 // Store measurement
964 if (isL1) {
965 if (isCAcode) rng_C1[idx] = rng;
966 rng_P1[idx] = rng;
967 }
968 else {
969 rng_P2[idx] = rng;
970 };
971
972 };
973
974 };
975
976};
977
978//
979// Resolution of 2^24 cy carrier phase ambiguity
980// caused by 32-bit data field restrictions
981//
982// Note: the RTCM standard specifies an ambiguity of +/-2^23 cy.
983// However, numerous receivers generate data in the +/-2^22 cy range.
984// A reduced ambiguity of 2^23 cy appears compatible with both cases.
985//
986
987double RTCM2_Obs::resolvedPhase_L1(int i) const {
988
989//const double ambig = pow(2.0,24); // as per RTCM2 spec
990 const double ambig = pow(2.0,23); // used by many receivers
991
992 double rng;
993 double n;
994
995 if (!valid() || i<0 || i>nSat-1) return 0.0;
996
997 rng = rng_C1[i];
998 if (rng==0.0) rng = rng_P1[i];
999 if (rng==0.0) return 0.0;
1000
1001 n = floor( (rng/lambda_L1-cph_L1[i]) / ambig + 0.5 );
1002
1003 return cph_L1[i] + n*ambig;
1004
1005};
1006
1007double RTCM2_Obs::resolvedPhase_L2(int i) const {
1008
1009//const double ambig = pow(2.0,24); // as per RTCM2 spec
1010 const double ambig = pow(2.0,23); // used by many receivers
1011
1012 double rng;
1013 double n;
1014
1015 if (!valid() || i<0 || i>nSat-1) return 0.0;
1016
1017 rng = rng_C1[i];
1018 if (rng==0.0) rng = rng_P1[i];
1019 if (rng==0.0) return 0.0;
1020
1021 n = floor( (rng/lambda_L2-cph_L2[i]) / ambig + 0.5 );
1022
1023 return cph_L2[i] + n*ambig;
1024
1025};
1026
1027//
1028// Resolution of epoch using reference date (GPS week and secs)
1029//
1030
1031void RTCM2_Obs::resolveEpoch (int refWeek, double refSecs,
1032 int& epochWeek, double& epochSecs ) const {
1033
1034 const double secsPerWeek = 604800.0;
1035
1036 epochWeek = refWeek;
1037 epochSecs = secs + 3600.0*(floor((refSecs-secs)/3600.0+0.5));
1038
1039 if (epochSecs<0 ) { epochWeek--; epochSecs+=secsPerWeek; };
1040 if (epochSecs>secsPerWeek) { epochWeek++; epochSecs-=secsPerWeek; };
1041
1042};
1043
1044}; // End of namespace rtcm2
Note: See TracBrowser for help on using the repository browser.