Differences
This shows you the differences between two versions of the page.
| Both sides previous revision Previous revision Next revision | Previous revision | ||
| public:documents:raw_olap_data_formats [2011-02-11 14:50] – Jan David Mol | public:documents:raw_olap_data_formats [2017-03-08 15:27] (current) – external edit 127.0.0.1 | ||
|---|---|---|---|
| Line 1: | Line 1: | ||
| - | ===== Raw OLAP data formats ==== | + | ===== Raw OLAP data formats |
| - | OLAP produces several data formats, which are intended to be replaced by their final format, such as HDF5. The formats below are not officially supported and subject | + | OLAP produces several data formats, which are intended to be replaced by their final format, such as HDF5. |
| + | |||
| + | ===== After 2011-10-24 ===== | ||
| + | |||
| + | Files adhere to the following naming scheme: '' | ||
| + | |||
| + | - '' | ||
| + | - '' | ||
| + | - '' | ||
| + | - '' | ||
| + | |||
| + | The stokes numbers | ||
| + | |||
| + | - Complex Voltages: | ||
| + | - z = 0 -> Xr (X polarisation, | ||
| + | - z = 1 -> Xi (X polarisation, | ||
| + | - z = 2 -> Yr (Y polarisation, | ||
| + | - z = 3 -> Yi (Y polarisation, | ||
| + | - Coherent/ | ||
| + | - z = 0 -> I | ||
| + | - z = 1 -> Q | ||
| + | - z = 2 -> U | ||
| + | - z = 3 -> V | ||
| + | |||
| + | The data is encoded as follows. Each .raw file is a multiple of the following structure. All data is written as big-endian 32-bit IEEE floats. | ||
| + | |||
| + | < | ||
| + | struct block { | ||
| + | float sample[SUBBANDS][CHANNELS]; | ||
| + | }; | ||
| + | </ | ||
| + | |||
| + | The constants used can be derived from the parset: | ||
| + | |||
| + | < | ||
| + | SUBBANDS = len(parset[" | ||
| + | |||
| + | if (complex voltages || coherent stokes) { | ||
| + | |||
| + | CHANNELS = parset[" | ||
| + | if (CHANNELS == 0) CHANNELS = parset[" | ||
| + | |||
| + | } elif (incoherent stokes) { | ||
| + | |||
| + | CHANNELS = parset[" | ||
| + | if (CHANNELS == 0) CHANNELS = parset[" | ||
| + | |||
| + | } | ||
| + | </ | ||
| + | |||
| + | The sampling rate can be derived as follows: | ||
| + | |||
| + | < | ||
| + | # clock frequency (f.e. 200 MHz) | ||
| + | clock_hz = parset[" | ||
| + | |||
| + | # subband frequency (f.e. 195 kHz) | ||
| + | base_subband_hz = clock_hz / 1024 | ||
| + | |||
| + | # channel frequency (f.e. 763 Hz) | ||
| + | base_nrchannels = parset[" | ||
| + | base_channel_hz = base_subband_hz / base_nrchannels | ||
| + | |||
| + | if(complex voltages || coherent stokes) { | ||
| + | cs_temporalintegration = parset[" | ||
| + | |||
| + | sample_hz = base_channel_hz / cs_temporalintegration | ||
| + | |||
| + | } elif(incoherent stokes) { | ||
| + | |||
| + | is_temporalintegration = parset[" | ||
| + | |||
| + | sample_hz = base_channel_hz / is_temporalintegration | ||
| + | } | ||
| + | |||
| + | </ | ||
| + | |||
| + | ===== Before 2011-10-24 ===== | ||
| Data can be recorded as either complex voltages (yielding X and Y polarisations) or one or more stokes. In either case, a sequence of blocks will be stored, each of which consists of a header and data. The header is defined as: | Data can be recorded as either complex voltages (yielding X and Y polarisations) or one or more stokes. In either case, a sequence of blocks will be stored, each of which consists of a header and data. The header is defined as: | ||
| Line 18: | Line 95: | ||
| |Lxxxxx_Byyy_S0_bf.raw|X polarisations of beam yyy of observation xxxxx| | |Lxxxxx_Byyy_S0_bf.raw|X polarisations of beam yyy of observation xxxxx| | ||
| |Lxxxxx_Byyy_S1_bf.raw|Y polarisations of beam yyy of observation xxxxx| | |Lxxxxx_Byyy_S1_bf.raw|Y polarisations of beam yyy of observation xxxxx| | ||
| + | |||
| + | Proposed is the following scheme: | ||
| + | |||
| + | |Lxxxxx_Byyy_S0_bf.raw|X polarisation (real part) of beam yyy of observation xxxxx| | ||
| + | |Lxxxxx_Byyy_S1_bf.raw|X polarisation (imaginary part) of beam yyy of observation xxxxx| | ||
| + | |Lxxxxx_Byyy_S2_bf.raw|Y polarisation (real part) of beam yyy of observation xxxxx| | ||
| + | |Lxxxxx_Byyy_S3_bf.raw|Y polarisation (imaginary part) of beam yyy of observation xxxxx| | ||
| Each file is a sequence of blocks of the following structure: | Each file is a sequence of blocks of the following structure: | ||
| Line 24: | Line 108: | ||
| struct block { | struct block { | ||
| struct header header; | struct header header; | ||
| + | |||
| + | /* each block contains SAMPLES samples. The data structure is two samples larger (|2) for | ||
| + | | ||
| + | and immediately discarded. Time should just be incremented SAMPLES samples per block. */ | ||
| /* big endian */ | /* big endian */ | ||
| Line 32: | Line 120: | ||
| // 2010-06-29 release and earlier stored data per subband instead of per beam: | // 2010-06-29 release and earlier stored data per subband instead of per beam: | ||
| fcomplex voltages[BEAMS][CHANNELS][SAMPLES|2][POLARIZATIONS]; | fcomplex voltages[BEAMS][CHANNELS][SAMPLES|2][POLARIZATIONS]; | ||
| - | */ | + | */ |
| }; | }; | ||
| </ | </ | ||
| Line 52: | Line 140: | ||
| <code C> | <code C> | ||
| + | // Since 2011-10-24, Stokes are just a continuous stream of samples: | ||
| + | struct block { | ||
| + | float stokes[SAMPLES][SUBBANDS][CHANNELS]; | ||
| + | }; | ||
| + | |||
| + | // Before 2011-10-24: | ||
| struct block { | struct block { | ||
| struct header header; | struct header header; | ||
| + | |||
| + | /* each block contains SAMPLES samples. The data structure is two samples larger (|2) for | ||
| + | | ||
| + | and immediately discarded. Time should just be incremented SAMPLES samples per block. */ | ||
| /* big endian */ | /* big endian */ | ||
| Line 82: | Line 180: | ||
| struct block { | struct block { | ||
| struct header header; | struct header header; | ||
| + | |||
| + | /* each block contains SAMPLES samples. The data structure is two samples larger (|2) for | ||
| + | | ||
| + | and immediately discarded. Time should just be incremented SAMPLES samples per block. */\ | ||
| /* big endian */ | /* big endian */ | ||
| Line 111: | Line 213: | ||
| A BFRaw file starts with a file header containing the configuration: | A BFRaw file starts with a file header containing the configuration: | ||
| - | < | + | < |
| struct file_header | struct file_header | ||
| { | { | ||
| Line 141: | Line 243: | ||
| After the file header, there is a series of blocks until the end of file, configured using values from the file header: | After the file header, there is a series of blocks until the end of file, configured using values from the file header: | ||
| - | </code> | + | < |
| struct block | struct block | ||
| // 0x2913D852 | // 0x2913D852 | ||
| uint32_t | uint32_t | ||
| - | | + | |
| + | // per-SAP information (up to 8 SAPs can be defined, but typically only 1 is used) | ||
| + | |||
| + | // number of samples the signal is shifted to align the station beam to the reference | ||
| + | // phase center (=Observation.referencePhaseCenter in the parset) | ||
| + | | ||
| // Padding to circumvent 8-byte alignment | // Padding to circumvent 8-byte alignment | ||
| uint8_t | uint8_t | ||
| + | |||
| + | // the sub-sample delay which still has to be compensated for (in seconds), | ||
| + | // at the beginning and at the end of the block | ||
| double | double | ||
| double | double | ||
| - | // Compatible with TimeStamp class. | + | // Compatible with TimeStamp class (see below) |
| int64_t | int64_t | ||
| struct marshalledFlags | struct marshalledFlags | ||
| { | { | ||
| + | // up to 16 ranges of flagged samples within this block | ||
| uint32_t | uint32_t | ||
| struct range | struct range | ||
| Line 163: | Line 274: | ||
| } flags[8]; | } flags[8]; | ||
| - | std:: | + | std:: |
| + | | ||
| }; | }; | ||
| </ | </ | ||
| - | /* write routine */ | + | To convert a TimeStamp-compatible int64_t to a C-readable timestamp, use |
| - | std::string stationName = itsPS-> | + | <code C> |
| - | + | /* clockspeed is in Hz */ | |
| - | vector< | + | int64 nanoseconds |
| - | | + | |
| - | | + | |
| - | | + | |
| - | BFRawFormat | + | |
| - | + | ||
| - | if (!itsFileHeaderWritten) { | + | |
| - | if (nrSubbands > 62) | + | |
| - | THROW(IONProcException, | + | |
| - | + | ||
| - | memset(& | + | |
| - | + | ||
| - | bfraw_data.header.magic | + | |
| - | bfraw_data.header.bitsPerSample | + | |
| - | bfraw_data.header.nrPolarizations | + | |
| - | bfraw_data.header.nrSubbands | + | |
| - | bfraw_data.header.nrSamplesPerSubband = itsNrSamplesPerSubband; | + | |
| - | bfraw_data.header.sampleRate | + | |
| - | + | ||
| - | strncpy(bfraw_data.header.station, | + | |
| - | memcpy(bfraw_data.header.subbandFrequencies, | + | |
| - | + | ||
| - | for (unsigned beam = 0; beam < itsNrBeams; beam ++) | + | |
| - | memcpy(bfraw_data.header.beamDirections[beam], | + | |
| - | itsRawDataStream-> | + | |
| - | itsFileHeaderWritten = true; | + | |
| - | } | + | |
| - | + | ||
| - | memset(& | + | |
| - | + | ||
| - | bfraw_data.block_header.magic = 0x2913D852; | + | |
| - | + | ||
| - | for (unsigned beam = 0; beam < itsNrBeams; beam ++) { | + | |
| - | bfraw_data.block_header.coarseDelayApplied[beam] | + | |
| - | bfraw_data.block_header.fineDelayRemainingAtBegin[beam] | + | |
| - | bfraw_data.block_header.fineDelayRemainingAfterEnd[beam] = itsFineDelaysAfterEnd[beam][0]; | + | |
| - | bfraw_data.block_header.time[beam] | + | |
| - | + | ||
| - | | + | |
| - | // the flags from multiple RSP boards --- use the flags of RSP board 0 | + | |
| - | itsFlags[0][beam].marshall(reinterpret_cast< | + | |
| - | } | + | |
| - | + | ||
| - | itsRawDataStream-> | + | |
| - | for (unsigned subband | + | struct timespec ts; |
| - | | + | ts.tv_sec |
| + | ts.tv_nsec = nanoseconds % 1000000000ULL; | ||
| </ | </ | ||