Reader

High level use

The module rdi_reader provides a class PD0() that provides a starting point to read the binary PD0 files. Typically an instance of PD0() is created

pd0 = PD0()

where no arguments to PD0() are accepted.

The PD0() class defines a read() method, that reads in an entire PD0 file and returns its binary contents. Note that at this instance the whole file is contained in memory. Although binary files can be large, it is not expected that a file would not fit in memory.

To parse the binary data, the PD0() class defines a process() method, which takes one filename, or a list of filenames, and starts reading the binary data. The data are then sent into the pipeline, that is to be defined before the process() method is called. The process() method is implemented as a lazy data generator, that is, only so much data is read that is required to send all the information of a ensemble down the pipeline. The benefit is of this approach is that, the binary files can be huge, without the need to worry about memory issues.

A typical use of the PD0() reader class, thus is

pd0 = PDO()

:
# Define a pipe line
:
pd0.process(list_of_pd0_filenames)

Decoding of PD0 binaries

For an in-depth description of the binary format of PD0 files, the reader is referred to the manual provided by the manufacturer. Here, the principle of operation is described only.

The decoding of a ping is taken care of by the Ensemble class. The constructor takes a chunk of binary data as input, and optionally a dictionary of data offsets. Data offsets are pointers to positions in the binary data that mark the beginning of a particular block of information, such as the variable leader block. The start of these blocks are marked by bytes with a specific value. The offsets of a given instrument and setup are thought to be constant, so that they can be determined once and supplied as argument to the constructor. This could potentially break the processing of data files generated by different instruments, so that the default approach is that the offsets are determined for every ping. If processing speed is paramount, then reusing data offsets can be used to reduce the number of CPU cycles used.

The only method a user may call is the decode() method, which sequentially decodes each block identified by the data offsets. Each decoded block is a dictionary where each key is assigned the value or values stored in the corresponding field of the binary block of data. The method returns a dictionary with keys that correspond to the names of the data blocks (fixed_leader, variable_leader, etc.) the values of which are dictionaries returned by each block decoding. See the following example:

>>> ens = Ensemble(data_chunk)
>>> ens.keys()
dict_keys(['fixed_leader', 'variable_leader', 'velocity', 'correlation', 'echo', 'percent_good', 'bottom_track'])
>>> ens['fixed_leader']
OrderedDict([('CPU_ver', 34),
           ('CPU_rev', 17),
           ('Sys_Freq', '600 kHz'),
           ('Beam_Pattern', 'Convex'),
           ('Sensor_Cfg', 'Sensor Cfg #1'),
           ('Xdcr_Head', 'Xdxr Head attached'),
           ('Xdcr_Facing', 'Down'),
           ('Beam_Angle', '30 Degree'),
           ('Beam_Cfg', '4 Beam Janus'),
           ('Real_Data', 'True'),
           ('N_Beams', 4),
           ('N_Cells', 30),
           ('N_PingsPerEns', 10),
           ('DepthCellSize', 2.0),
           ('Blank', 0.88),
           ('WaterMode', 1),
           ('CorrThresshold', 64),
           ('Code_Repts', 26),
           ('MinPG', 0),
           ('ErrVelThreshold', 2.0),
           ('TimeBetweenPings', '00:00.00'),
           ('RawCoordXrfm', 31),
           ('CoordXfrm', 'Earth'),
           ('CoordXfrmOptions', 'Bin Mapping|3 Beam|Tilts'),
           ('Vel_field1', 'East'),
           ('Vel_field2', 'North'),
           ('Vel_field3', 'Up'),
           ('Vel_field4', 'Error'),
           ('EA', 0.0),
           ('EB', 0.0),
           ('Sensors',
            'Uses ET from transducer temperature sensor|Calculates EC (speed of sound) from ED, ES, and ET'),
           ('Sensors_Avail', ''),
           ('FirstBin', 2.9),
           ('XmtLength', 1.98),
           ('WL_Start', 80),
           ('WL_End', 160),
           ('FalseTargetThreshold', 50),
           ('LagDistance', 0.07),
           ('CPUBoardSerial', '00 00 00 00 00 00 00 00'),
           ('Bandwidth', 'BB'),
           ('XmtPower', 0),
           ('SystemSerialNumber', 672774)])

The data structure returned by the decode() method thus allows for easy access of the information contained in the binary data chunk.