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

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

* empty log message *

File size: 23.8 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()<i+1) {
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 throw("Error: can't handle >32 bits in RTCM2packet::getUnsignedBits");
505 };
506
507 if ( 24*DW.size() < start+n-1 ) {
508 throw("Error: Packet too short in RTCM2packet::getUnsignedBits");
509 }
510
511 // Handle initial data word
512 // Get all data bits. Strip parity and unwanted leading bits.
513 // Store result in 24 lsb bits of tmp.
514
515 tmp = (DW[iFirst]>>6) & 0xFFFFFF;
516 tmp = ( ( tmp << start%24) & 0xFFFFFF ) >> start%24 ;
517
518 // Handle central data word
519
520 if ( iFirst<iLast ) {
521 bitField = tmp;
522 for (unsigned int iWord=iFirst+1; iWord<iLast; iWord++) {
523 tmp = (DW[iWord]>>6) & 0xFFFFFF;
524 bitField = (bitField << 24) | tmp;
525 };
526 tmp = (DW[iLast]>>6) & 0xFFFFFF;
527 };
528
529 // Handle last data word
530
531 tmp = tmp >> (23-(start+n-1)%24);
532 bitField = (bitField << ((start+n-1)%24+1)) | tmp;
533
534 // Done
535
536 return bitField;
537
538};
539
540//
541// Get signed bit field
542//
543// Bits are numbered from left (msb) to right (lsb) starting at bit 0
544//
545
546int RTCM2packet::getBits ( unsigned int start,
547 unsigned int n ) const {
548
549
550 // Checks
551
552 if (n>32) {
553 throw("Error: can't handle >32 bits in RTCM2packet::getBits");
554 };
555
556 if ( 24*DW.size() < start+n-1 ) {
557 throw("Error: Packet too short in RTCM2packet::getBits");
558 }
559
560 return ((int)(getUnsignedBits(start,n)<<(32-n))>>(32-n));
561
562};
563
564
565//------------------------------------------------------------------------------
566//
567// RTCM2_03 (class implementation)
568//
569// Purpose:
570//
571// A class for handling RTCM 2 GPS Reference Station Parameters messages
572//
573//------------------------------------------------------------------------------
574
575void RTCM2_03::extract(const RTCM2packet& P) {
576
577 // Check validity and packet type
578
579 validMsg = (P.valid());
580 if (!validMsg) return;
581
582 validMsg = (P.ID()==03);
583 if (!validMsg) return;
584
585 // Antenna reference point coordinates
586
587 x = P.getBits( 0,32)*0.01; // X [m]
588 y = P.getBits(32,32)*0.01; // Y [m]
589 z = P.getBits(64,32)*0.01; // Z [m]
590
591};
592
593//------------------------------------------------------------------------------
594//
595// RTCM2_23 (class implementation)
596//
597// Purpose:
598//
599// A class for handling RTCM 2 Antenna Type Definition messages
600//
601//------------------------------------------------------------------------------
602
603void RTCM2_23::extract(const RTCM2packet& P) {
604
605 int nad, nas;
606
607 // Check validity and packet type
608
609 validMsg = (P.valid());
610 if (!validMsg) return;
611
612 validMsg = (P.ID()==23);
613 if (!validMsg) return;
614
615 // Antenna descriptor
616 antType = "";
617 nad = P.getUnsignedBits(3,5);
618 for (int i=0;i<nad;i++)
619 antType += (char)P.getUnsignedBits(8+i*8,8);
620
621 // Optional antenna serial numbers
622 if (P.getUnsignedBits(2,1)==1) {
623 nas = P.getUnsignedBits(19+8*nad,5);
624 antSN = "";
625 for (int i=0;i<nas;i++)
626 antSN += (char)P.getUnsignedBits(24+8*nas+i*8,8);
627 };
628
629};
630
631
632//------------------------------------------------------------------------------
633//
634// RTCM2_24 (class implementation)
635//
636// Purpose:
637//
638// A class for handling RTCM 2 Reference Station Antenna
639// Reference Point Parameter messages
640//
641//------------------------------------------------------------------------------
642
643void RTCM2_24::extract(const RTCM2packet& P) {
644
645 double dx,dy,dz;
646
647 // Check validity and packet type
648
649 validMsg = (P.valid());
650 if (!validMsg) return;
651
652 validMsg = (P.ID()==24);
653 if (!validMsg) return;
654
655 // System indicator
656
657 isGPS = (P.getUnsignedBits(118,1)==0);
658 isGLONASS = (P.getUnsignedBits(118,1)==1);
659
660 // Antenna reference point coordinates
661
662 x = 64.0*P.getBits( 0,32);
663 y = 64.0*P.getBits(40,32);
664 z = 64.0*P.getBits(80,32);
665 dx = P.getUnsignedBits( 32,6);
666 dy = P.getUnsignedBits( 72,6);
667 dz = P.getUnsignedBits(112,6);
668 x = 0.0001*( x + (x<0? -dx:+dx) );
669 y = 0.0001*( y + (y<0? -dy:+dy) );
670 z = 0.0001*( z + (z<0? -dz:+dz) );
671
672 // Antenna Height
673
674 if (P.getUnsignedBits(119,1)==1) {
675 h= P.getUnsignedBits(120,18)*0.0001;
676 };
677
678
679};
680
681
682//------------------------------------------------------------------------------
683//
684// RTCM2_Obs (class definition)
685//
686// Purpose:
687//
688// A class for handling blocks of RTCM2 18 & 19 packets that need to be
689// combined to get a complete set of measurements
690//
691// Notes:
692//
693// The class collects L1/L2 code and phase measurements for GPS and GLONASS.
694// Since the Multiple Message Indicator is inconsistently handled by various
695// receivers we simply require code and phase on L1 and L2 for a complete
696// set ob observations at a given epoch. GLONASS observations are optional,
697// but all four types (code+phase,L1+L2) must be provided, if at least one
698// is given. Also, the GLONASS message must follow the corresponding GPS
699// message.
700//
701//------------------------------------------------------------------------------
702
703// Constructor
704
705RTCM2_Obs::RTCM2_Obs() {
706
707 clear();
708
709};
710
711// Reset entire block
712
713void RTCM2_Obs::clear() {
714
715 secs=0.0; // Seconds of hour (GPS time)
716 nSat=0; // Number of space vehicles
717 PRN.resize(0); // Pseudorange [m]
718 rng_C1.resize(0); // Pseudorange [m]
719 rng_P1.resize(0); // Pseudorange [m]
720 rng_P2.resize(0); // Pseudorange [m]
721 cph_L1.resize(0); // Carrier phase [m]
722 cph_L2.resize(0); // Carrier phase [m]
723
724 availability.reset(); // Message status flags
725 pendingMsg = true; // Multiple message indicator
726
727};
728
729// Availability checks
730
731bool RTCM2_Obs::anyGPS() const {
732
733 return availability.test(bit_L1rngGPS) ||
734 availability.test(bit_L2rngGPS) ||
735 availability.test(bit_L1cphGPS) ||
736 availability.test(bit_L2cphGPS);
737
738};
739
740bool RTCM2_Obs::anyGLONASS() const {
741
742 return availability.test(bit_L1rngGLO) ||
743 availability.test(bit_L2rngGLO) ||
744 availability.test(bit_L1cphGLO) ||
745 availability.test(bit_L2cphGLO);
746
747};
748
749bool RTCM2_Obs::allGPS() const {
750
751 return availability.test(bit_L1rngGPS) &&
752 availability.test(bit_L2rngGPS) &&
753 availability.test(bit_L1cphGPS) &&
754 availability.test(bit_L2cphGPS);
755
756};
757
758bool RTCM2_Obs::allGLONASS() const {
759
760 return availability.test(bit_L1rngGLO) &&
761 availability.test(bit_L2rngGLO) &&
762 availability.test(bit_L1cphGLO) &&
763 availability.test(bit_L2cphGLO);
764
765};
766
767// Validity
768
769bool RTCM2_Obs::valid() const {
770
771 return ( allGPS() && (allGLONASS() || !anyGLONASS()) && !pendingMsg );
772
773};
774
775
776//
777// Extract RTCM2 18 & 19 messages and store relevant data for future use
778//
779
780void RTCM2_Obs::extract(const RTCM2packet& P) {
781
782 bool isGPS,isCAcode,isL1,isOth;
783 int NSat,idx;
784 int sid,prn;
785 double t,rng,cph;
786
787 // Check validity and packet type
788
789 if (!P.valid()) return;
790
791 // Clear previous data if block was already complete
792
793 if (valid()) clear();
794
795 // Process carrier phase message
796
797 if ( P.ID()==18 ) {
798
799 // Number of satellites in current message
800 NSat = (P.nDataWords()-1)/2;
801
802 // Current epoch (mod 3600 sec)
803 t = 0.6*P.modZCount()
804 + P.getUnsignedBits(4,20)*1.0e-6;
805
806 // Frequency (exit if neither L1 nor L2)
807 isL1 = ( P.getUnsignedBits(0,1)==0 );
808 isOth = ( P.getUnsignedBits(1,1)==1 );
809 if (isOth) return;
810
811 // Constellation (for first satellite in message)
812 isGPS = ( P.getUnsignedBits(26,1)==0 );
813
814 // Multiple Message Indicator (only checked for first satellite)
815 pendingMsg = ( P.getUnsignedBits(24,1)==1 );
816
817 // Handle epoch: store epoch of first GPS message and
818 // check consistency of subsequent messages. GLONASS time tags
819 // are different and have to be ignored
820 if (isGPS) {
821 if ( nSat==0 ) {
822 secs = t; // Store epoch
823 }
824 else if (t!=secs) {
825 clear(); secs = t; // Clear all data, then store epoch
826 };
827 };
828
829 // Discard GLONASS obseravtions if no prior GPS observations
830 // are available
831 if (!isGPS && !anyGPS() ) return;
832
833 // Set availability flags
834
835 if ( isL1 && isGPS) availability.set(bit_L1cphGPS);
836 if (!isL1 && isGPS) availability.set(bit_L2cphGPS);
837 if ( isL1 && !isGPS) availability.set(bit_L1cphGLO);
838 if (!isL1 && !isGPS) availability.set(bit_L2cphGLO);
839
840 // Process all satellites
841
842 for (int iSat=0;iSat<NSat;iSat++){
843
844 // Code type
845 isCAcode = ( P.getUnsignedBits(iSat*48+25,1)==0 );
846
847 // Satellite
848 sid = P.getUnsignedBits(iSat*48+27,5);
849 prn = (isGPS? sid : sid+200 );
850
851 // Carrier phase measurement (mod 2^23 [cy]; sign matched to range)
852 cph = -P.getBits(iSat*48+40,32)/256.0;
853
854 // Is this a new PRN?
855 idx=-1;
856 for (unsigned int i=0;i<PRN.size();i++) {
857 if (PRN[i]==prn) { idx=i; break; };
858 };
859 if (idx==-1) {
860 // Insert new sat at end of list
861 nSat++; idx = nSat-1;
862 PRN.push_back(prn);
863 rng_C1.push_back(0.0);
864 rng_P1.push_back(0.0);
865 rng_P2.push_back(0.0);
866 cph_L1.push_back(0.0);
867 cph_L2.push_back(0.0);
868 };
869
870 // Store measurement
871 if (isL1) {
872 cph_L1[idx] = cph;
873 }
874 else {
875 cph_L2[idx] = cph;
876 };
877
878 };
879
880 };
881
882
883 // Process pseudorange message
884
885 if ( P.ID()==19 ) {
886
887 // Number of satellites in current message
888 NSat = (P.nDataWords()-1)/2;
889
890 // Current epoch (mod 3600 sec)
891 t = 0.6*P.modZCount()
892 + P.getUnsignedBits(4,20)*1.0e-6;
893
894 // Frequency (exit if neither L1 nor L2)
895 isL1 = ( P.getUnsignedBits(0,1)==0 );
896 isOth = ( P.getUnsignedBits(1,1)==1 );
897 if (isOth) return;
898
899 // Constellation (for first satellite in message)
900 isGPS = ( P.getUnsignedBits(26,1)==0 );
901
902 // Multiple Message Indicator (only checked for first satellite)
903 pendingMsg = ( P.getUnsignedBits(24,1)==1 );
904
905 // Handle epoch: store epoch of first GPS message and
906 // check consistency of subsequent messages. GLONASS time tags
907 // are different and have to be ignored
908 if (isGPS) {
909 if ( nSat==0 ) {
910 secs = t; // Store epoch
911 }
912 else if (t!=secs) {
913 clear(); secs = t; // Clear all data, then store epoch
914 };
915 };
916
917 // Discard GLONASS obseravtions if nor prior GPS observations
918 // are available
919 if (!isGPS && !anyGPS() ) return;
920
921 // Set availability flags
922 if ( isL1 && isGPS) availability.set(bit_L1rngGPS);
923 if (!isL1 && isGPS) availability.set(bit_L2rngGPS);
924 if ( isL1 && !isGPS) availability.set(bit_L1rngGLO);
925 if (!isL1 && !isGPS) availability.set(bit_L2rngGLO);
926
927 // Process all satellites
928
929 for (int iSat=0;iSat<NSat;iSat++){
930
931 // Code type
932 isCAcode = ( P.getUnsignedBits(iSat*48+25,1)==0 );
933
934 // Satellite
935 sid = P.getUnsignedBits(iSat*48+27,5);
936 prn = (isGPS? sid : sid+200 );
937
938 // Pseudorange measurement [m]
939 rng = P.getUnsignedBits(iSat*48+40,32)*0.02;
940
941 // Is this a new PRN?
942 idx=-1;
943 for (unsigned int i=0;i<PRN.size();i++) {
944 if (PRN[i]==prn) { idx=i; break; };
945 };
946 if (idx==-1) {
947 // Insert new sat at end of list
948 nSat++; idx = nSat-1;
949 PRN.push_back(prn);
950 rng_C1.push_back(0.0);
951 rng_P1.push_back(0.0);
952 rng_P2.push_back(0.0);
953 cph_L1.push_back(0.0);
954 cph_L2.push_back(0.0);
955 };
956
957 // Store measurement
958 if (isL1) {
959 if (isCAcode) rng_C1[idx] = rng;
960 rng_P1[idx] = rng;
961 }
962 else {
963 rng_P2[idx] = rng;
964 };
965
966 };
967
968 };
969
970};
971
972//
973// Resolution of 2^24 cy carrier phase ambiguity
974// caused by 32-bit data field restrictions
975//
976// Note: the RTCM standard specifies an ambiguity of +/-2^23 cy.
977// However, numerous receivers generate data in the +/-2^22 cy range.
978// A reduced ambiguity of 2^23 cy appears compatible with both cases.
979//
980
981double RTCM2_Obs::resolvedPhase_L1(int i) const {
982
983//const double ambig = pow(2.0,24); // as per RTCM2 spec
984 const double ambig = pow(2.0,23); // used by many receivers
985
986 double rng;
987 double n;
988
989 if (!valid() || i<0 || i>nSat-1) return 0.0;
990
991 rng = rng_C1[i];
992 if (rng==0.0) rng = rng_P1[i];
993 if (rng==0.0) return 0.0;
994
995 n = floor( (rng/lambda_L1-cph_L1[i]) / ambig + 0.5 );
996
997 return cph_L1[i] + n*ambig;
998
999};
1000
1001double RTCM2_Obs::resolvedPhase_L2(int i) const {
1002
1003//const double ambig = pow(2.0,24); // as per RTCM2 spec
1004 const double ambig = pow(2.0,23); // used by many receivers
1005
1006 double rng;
1007 double n;
1008
1009 if (!valid() || i<0 || i>nSat-1) return 0.0;
1010
1011 rng = rng_C1[i];
1012 if (rng==0.0) rng = rng_P1[i];
1013 if (rng==0.0) return 0.0;
1014
1015 n = floor( (rng/lambda_L2-cph_L2[i]) / ambig + 0.5 );
1016
1017 return cph_L2[i] + n*ambig;
1018
1019};
1020
1021//
1022// Resolution of epoch using reference date (GPS week and secs)
1023//
1024
1025void RTCM2_Obs::resolveEpoch (int refWeek, double refSecs,
1026 int& epochWeek, double& epochSecs ) const {
1027
1028 const double secsPerWeek = 604800.0;
1029
1030 epochWeek = refWeek;
1031 epochSecs = secs + 3600.0*(floor((refSecs-secs)/3600.0+0.5));
1032
1033 if (epochSecs<0 ) { epochWeek--; epochSecs+=secsPerWeek; };
1034 if (epochSecs>secsPerWeek) { epochWeek++; epochSecs-=secsPerWeek; };
1035
1036};
1037
1038}; // End of namespace rtcm2
Note: See TracBrowser for help on using the repository browser.