Source code for baseband.mark4.file_info
# Licensed under the GPLv3 - see LICENSE
"""The Mark4FileReaderInfo property.
Includes information about what is needed to calcuate times,
number of tracks and offset of first header.
"""
from ..vlbi_base.file_info import VLBIFileReaderInfo, info_item
__all__ = ['Mark4FileReaderInfo']
[docs]class Mark4FileReaderInfo(VLBIFileReaderInfo):
"""Standardized information on Mark 4 file readers.
The ``info`` descriptor has a number of standard attributes, which are
determined from arguments passed in opening the file, from the first header
(``info.header0``) and from possibly scanning the file to determine the
duration of frames. This class has two additional attributes specific to
Mark 4 files (``ntrack`` and ``offset0``, see below).
Attributes
----------
format : str or `None`
File format, or `None` if the underlying file cannot be parsed.
frame_rate : `~astropy.units.Quantity`
Number of data frames per unit of time.
sample_rate : `~astropy.units.Quantity`
Complete samples per unit of time.
samples_per_frame : int
Number of complete samples in each frame.
sample_shape : tuple
Dimensions of each complete sample (e.g., ``(nchan,)``).
bps : int
Number of bits used to encode each elementary sample.
complex_data : bool
Whether the data are complex.
start_time : `~astropy.time.Time`
Time of the first complete sample.
ntrack : int
Number of "tape tracks" simulated in the disk file.
offset0 : int
Offset in bytes from the start of the file to the location of the
first header.
readable : bool
Whether the first sample could be read and decoded.
missing : dict
Entries are keyed by names of arguments that should be passed to
the file reader to obtain full information. The associated entries
explain why these arguments are needed. For Mark 4, the possible
entries are ``decade`` and ``ref_time``.
errors : dict
Any exceptions raised while trying to determine attributes. Keyed
by the attributes.
Examples
--------
The most common use is simply to print information::
>>> from baseband.data import SAMPLE_MARK4
>>> from baseband import mark4
>>> fh = mark4.open(SAMPLE_MARK4, 'rb')
>>> fh.info
File information:
format = mark4
number_of_frames = 2
frame_rate = 400.0 Hz
sample_rate = 32.0 MHz
samples_per_frame = 80000
sample_shape = (8,)
bps = 2
complex_data = False
readable = True
ntrack = 64
offset0 = 2696
<BLANKLINE>
missing: decade, ref_time: needed to infer full times.
<BLANKLINE>
checks: decodable: True
>>> fh.close()
>>> fh = mark4.open(SAMPLE_MARK4, 'rb', decade=2010)
>>> fh.info
File information:
format = mark4
number_of_frames = 2
frame_rate = 400.0 Hz
sample_rate = 32.0 MHz
samples_per_frame = 80000
sample_shape = (8,)
bps = 2
complex_data = False
start_time = 2014-06-16T07:38:12.475000000
readable = True
ntrack = 64
offset0 = 2696
<BLANKLINE>
checks: decodable: True
>>> fh.close()
"""
attr_names = (VLBIFileReaderInfo.attr_names[:-4]
+ ('ntrack', 'offset0')
+ VLBIFileReaderInfo.attr_names[-4:])
"""Attributes that the container provides."""
_header0_attrs = ('bps', 'samples_per_frame')
_parent_attrs = ('ntrack', 'decade', 'ref_time')
@info_item
def time_info(self):
"""Additional time info needed to get the start time."""
time_info = (self.decade, self.ref_time)
if time_info == (None, None):
self.missing['decade'] = self.missing['ref_time'] = (
"needed to infer full times.")
return None
return time_info
@info_item
def offset0(self):
"""Offset in bytes to the location of the first header."""
with self._parent.temporary_offset(0) as fh:
fh.find_header()
return fh.tell()
@info_item(needs='offset0')
def header0(self):
with self._parent.temporary_offset(self.offset0) as fh:
return fh.read_header()
@info_item(needs='header0')
def frame0(self):
with self._parent.temporary_offset(self.offset0) as fh:
return fh.read_frame()
@info_item(needs='header0')
def number_of_frames(self):
"""Total number of frames."""
with self._parent.temporary_offset(
-self.header0.frame_nbytes, 2) as fh:
fh.find_header(self.header0, forward=False)
number_of_frames = ((fh.tell() - self.offset0)
/ self.header0.frame_nbytes) + 1
if number_of_frames % 1 == 0:
return int(number_of_frames)
else:
self.warnings['number_of_frames'] = (
'file contains non-integer number ({}) of frames'
.format(number_of_frames))
return None
complex_data = False
@info_item(needs='header0')
def sample_shape(self):
"""Dimensions of each complete sample."""
return (self.header0.nchan,)
# Override just to replace what it "needs".
@info_item(needs=('header0', 'time_info'))
def start_time(self):
"""Time of the first sample."""
return super().start_time