Transcript SOC Format

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 type
max 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 length max value 65535
– unsigned short seqnum max value 43200 ( 12 hours )
– unsigned short site id max value 65535
type 1 - receiver data
• overhead ( 9 bytes )
– unsigned int
gps_minutes
4 bytes
• minutes past 6-jan-1980, good until year 10151
– unsigned short gps_millisecs
2 bytes
• good for 65.535 seconds
– short
navt
2 bytes
• units of 10*meters
• range +/-327,680 meters
– unsigned char sats_and_status
1 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 255
1 byte
– unsigned short epoch_seq
0 to 35999
2 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,719.476735 kms
– unsigned char snr (for ca_range)
0 to 255
1 byte
– L2_block
6 bytes
– L1_block
6 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 <= 131.071 meters
– next 6 bits and 2 bytes for phase
• Phase units in 0.02 mms
• 2*(2^21- 1) possible values
• dynamic range <= 41.94302 meters
– extended w/ overflow bits to 83.88606 meters
– last byte
• unsigned char snr 0 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 + 2.54 I - (R + 1.54 I) ~ I
<= 131.071 m.
phase_2 = L2 - CA_range + 4.09*range_2
Like: R - 2.54 I - (R + 1.54 I) + 4.09 I ~ 0
<= 83.88606 m.
• L1_block second:
range_1 = P1 - CA_range
Like: R + 1.54 I - (R + 1.54 I) ~ 0 (ca-p code bias) <= 131.071 m.
phase_1 = L1 - CA_range + 3.09*range_2
Like: R - 1.54 I - (R + 1.54 I) + 3.09 I ~ 0
<= 83.88606 m.
L1 & L2 block: initial point
• Align L1 to integer wavelength of P1 w/ data editor
N_L1 = floor( (P1 - L1) / 0.190 + 0.5) at start of phase arc
L1 += N_L1 * 0.190 for a phase connected arc
But P1-L1 ~ R+ 1.54 I - ( R - 1.54 I + L1_phase_bias )
~ 3.09 I - L1_phase_bias
Must subtract also from N_L1:
N_L1 -= floor(3.09*(P2-P1)/0.190 + 0.5)
• Likewise for L2
N_L2 = floor( (P2 - L2) / 0.244 + 0.5) at start of phase arc
L2 += N_L2 * 0.244 for a phase connected arc
But P2-L2 ~ R+ 2.54 I - ( R - 2.54 I + L2_phase_bias )
~ 5.09 I - L2_phase_bias
Must subtract also from N_L2:
N_L2 -= floor(5.09*(P2-P1)/0.244 + 0.5)
initial point, for example
/*
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];