soc format Ron Muellerschoen Jet Propulsion Laboratory California Institute of Technology
background Designed to transport 1 Hz GPS data with minimal bandwidth over the Open Internet, July 1999 –“soc” from socket, which is the interface at the application layer –format stable since January, 2000 (when SNR numbers added) –follows little-endian byte order (PC order) Transport layer is UDP, so format does not include: –sync bits –checksum or CRC Efficient compression of 5 GPS observable (CA, P1, P2, L1,L2) down to 14 bytes and a nibble –1 mm range resolution –.02 mm phase resolution Total size per station per 1 Hz epoch: –17+21*n_GPS bytes
soc attributes contains edit flags (or epochs) for cycle slips stand alone time-tag per epoch minimum representation of receiver’s clock solution 3 SNR numbers unique site id modulo 12 hour sequence number flags: –receiver type –GPS health flag simple structure –8 byte header –9 byte overhead ( timetag, number of gps, etc. ) –21 data bytes per gps
soc format header (8 bytes) –unsigned short typemax value 2^16 -1 type 0 - request for replay of packet, to remote site type 1 - receiver data, from remote site type 3 - broadcast ephemeris, from remote site type 4 - heartbeat, among data collectors type 5 - “will”, among data collectors –unsigned short lengthmax value –unsigned short seqnummax value ( 12 hours ) –unsigned short site idmax value 65535
type 1 - receiver data overhead ( 9 bytes ) –unsigned int gps_minutes4 bytes minutes past 6-jan-1980, good until year –unsigned short gps_millisecs2 bytes good for seconds –short navt2 bytes units of 10*meters range +/-327,680 meters –unsigned char sats_and_status1 byte bits 7-4 indicates number of sats less 1 (max of 16) bits 1-3 indicate receiver type ( max of 7 ) bit 0 reserved for health status
type 1 - receiver data data bytes ( 21 per gps ) –unsigned char prn 0 to 2551 byte –unsigned short epoch_seq 0 to bytes 10 hour non-ambiguous phase epoch –char ca_range[5]5 bytes highest 4 bits of first memory location are status bits next 36 bits contain the ca_range in mm. –most significant bytes are now in lowest memory location »highest bits of byte are most significant »think big-endian order 2^36 -1 possible values, min 0, max 68, kms –unsigned char snr (for ca_range)0 to 2551 byte –L2_block6 bytes –L1_block6 bytes
L1 & L2 block: overview L1 and L2 block ( 6 bytes each ) –first 2 bytes and 2 bits for range range units in mms 2*(2^17 - 1) possible values dynamic range <= meters –next 6 bits and 2 bytes for phase Phase units in 0.02 mms 2*(2^21- 1) possible values dynamic range <= meters –extended w/ overflow bits to meters –last byte unsigned char snr0 to 255
L1 & L2 block: compression Align L2/L1 to within integer wavelength of P2/P1 w/ editor L2_block first: range_2 = P2 - CA_range Like: R I - (R I) ~ I <= m. phase_2 = L2 - CA_range *range_2 Like: R I - (R I) I ~ 0 <= m. L1_block second: range_1 = P1 - CA_range Like: R I - (R I) ~ 0 (ca-p code bias) <= m. phase_1 = L1 - CA_range *range_2 Like: R I - (R I) I ~ 0 <= m.
L1 & L2 block: initial point Align L1 to integer wavelength of P1 w/ data editor N_L1 = floor( (P1 - L1) / ) at start of phase arc L1 += N_L1 * for a phase connected arc But P1-L1 ~ R I - ( R I + L1_phase_bias ) ~ 3.09 I - L1_phase_bias Must subtract also from N_L1: N_L1 -= floor(3.09*(P2-P1)/ ) Likewise for L2 N_L2 = floor( (P2 - L2) / ) at start of phase arc L2 += N_L2 * for a phase connected arc But P2-L2 ~ R I - ( R I + L2_phase_bias ) ~ 5.09 I - L2_phase_bias Must subtract also from N_L2: N_L2 -= floor(5.09*(P2-P1)/ )
/* If phase break, then re-adjust the cycle count of the phase to align closer to the range. */ if ( (ll[0] == 1) || (ll[1] == 1) || force_break[SiteIDm1][prnj] ) { adjustct[SiteIDm1][0][prnj] = ((p1 - l1*LAML1) / LAML1) + 0.5; adjustct[SiteIDm1][1][prnj] = ((p2 - l2*LAML2) / LAML2) + 0.5; adjustct[SiteIDm1][0][prnj] = floor( adjustct[SiteIDm1][0][prnj] ); adjustct[SiteIDm1][1][prnj] = floor( adjustct[SiteIDm1][1][prnj] ); ll[0] = 1; ll[1] = 1; force_break[SiteIDm1][prnj] = false; /* further adjust for dynamic range, want only bias portion */ if ( send_to_socket ) { first_iono = p2 - p1; /* all in units of meters */ l1_adjust = floor( ALPHA1*first_iono/LAML1 +.5 ); l2_adjust = floor( ALPHA2*first_iono/LAML2 +.5 ); adjustct[SiteIDm1][0][prnj] -= l1_adjust; adjustct[SiteIDm1][1][prnj] -= l2_adjust; } /* Add integer cycles to L1 and L2 to align closer to the range. */ l1 += adjustct[SiteIDm1][0][prnj]; l2 += adjustct[SiteIDm1][1][prnj]; initial point, for example