Broadband systems use modulation techniques to reduce the effect of noise in the environment. Broadband transmission employs multiple channel unidirectional transmission using a combination of phase and amplitude modulation.
Please visit our website for more information on this topic.
Baseband is a digital signal transmitted on the medium using one of the signal codes like NRZ, RZ Manchester biphase-M code, etc. called baseband transmission.
These are the following differences between Broadband and Baseband transmission.
Baseband transmission:
Broadband transmission:
Login
to comment...
For most file formats, one can simply import baseband and use baseband.open
to access the file. This gives one a filehandle from which one can read
decoded samples:
For other file formats, a bit more information is needed. Below, we cover the basics of inspecting files, reading from and writing to files, converting from one format to another, and diagnosing problems. We assume that Baseband as well as numpy and the astropy.units module have been imported:
The one format for which file_info works a bit differently is GSB , as this format requires separate time-stamp and raw data files. Only the timestamp file can be inspected usefully.
The information is gleaned from info properties on the various file and stream readers (see below).
The same function will also tell you when more information is needed. For instance, for Mark 5B files one needs the number of channels used, as well as (roughly) when the data were taken:
Baseband allows you to quickly determine basic properties of a file, including what format it is, using the baseband.file_info function. For instance, it shows that the sample VDIF file that comes with Baseband is very short (sample files can all be found in the baseband.data module):
As shown at the very start, files can be opened with the general
baseband.open function. This will try to determine the file type using
file_info, load the corresponding baseband module, and then open
the file using that modules master input/output function.
Generally, if one knows the file type, one might as well work with the
corresponding module directly. For instance, to explicitly use the DADA
reader to open the sample DADA file included in Baseband, one can use the DADA
modules open function:
>>>
from
baseband
import
dada
>>>
from
baseband.data
import
SAMPLE_DADA
>>>
fh
=
dada
.
open
(
SAMPLE_DADA
,
'rs'
)
>>>
fh
.
read
(
3
)
array([[ -38.-38.j, -38.-38.j],
[ -38.-38.j, -40. +0.j],
[-105.+60.j, 85.-15.j]], dtype=complex64)
>>>
fh
.
close
()
In general, file I/O and data manipulation use the same syntax across all file
formats. When opening Mark 4 and Mark 5B files, however, some additional
arguments may need to be passed (as was the case above for inspecting a Mark
5B file, and indeed this is a good way to find out what is needed).
Notes on such features and quirks of individual formats can be
found in the API entries of their open functions, and within the
Specific file format documentation.
For the rest of this section, we will stick to VDIF files.
By giving the openers a 'rs' flag, which is the default, we open files in
stream reader mode, where a file is accessed as if it were a stream of
samples. For VDIF, open will then return an instance of
VDIFStreamReader, which wraps a raw data file with
methods to decode the binary data frames and seek to and read data
samples. To decode the first 12 samples into a ndarray, we would
use the read method:
>>>
from
baseband
import
vdif
>>>
from
baseband.data
import
SAMPLE_VDIF
>>>
fh
=
vdif
.
open
(
SAMPLE_VDIF
,
'rs'
)
>>>
d
=
fh
.
read
(
12
)
>>>
type
(
d
)
<... 'numpy.ndarray'>
>>>
d
.
shape
(12, 8)
>>>
d
[:,
0
]
.
astype
(
int
)
# First thread.
array([-1, -1, 3, -1, 1, -1, 3, -1, 1, 3, -1, 1])
As discussed in detail in the VDIF section, VDIF files are
sequences of data frames, each of which is comprised of a header (which
holds information like the time at which the data was taken) and a
payload, or block of data. Multiple concurrent time streams can be
stored within a single frame; each of these is called a channel.
Moreover, groups of channels can be stored over multiple frames, each of which
is called a thread. Our sample file is an 8-thread, single-channel
file (8 concurrent time streams with 1 stream per frame), and in the example
above, fh.read decoded the first 12 samples from all 8 threads, mapping
thread number to the second axis of the decoded data array. Reading files with
multiple threads and channels will produce 3-dimensional arrays.
fh includes shape, size and ndim, which give the shape, total
number of elements and dimensionality of the files entire dataset if it was
decoded into an array. The number of complete samples - the set of samples
from all available threads and channels for one point in time - in the file is
given by the first element in shape:
>>>
fh
.
shape
# Shape of all data from the file in decoded array form.
(, 8)
>>>
fh
.
shape
[
0
]
# Number of complete samples.
>>>
fh
.
size
>>>
fh
.
ndim
2
The shape of a single complete sample, including names indicating the meaning of shape dimensions, is retrievable using:
>>>
fh
.
sample_shape
SampleShape(nthread=8)
By default, dimensions of length unity are squeezed, or removed from the
sample shape. To retain them, we can pass squeeze=False to
open:
>>>
fhns
=
vdif
.
open
(
SAMPLE_VDIF
,
'rs'
,
squeeze
=
False
)
>>>
fhns
.
sample_shape
# Sample shape now keeps channel dimension.
SampleShape(nthread=8, nchan=1)
>>>
fhns
.
ndim
# fh.shape and fh.ndim also change with squeezing.
3
>>>
d2
=
fhns
.
read
(
12
)
>>>
d2
.
shape
# Decoded data has channel dimension.
(12, 8, 1)
>>>
fhns
.
close
()
Basic information about the file is obtained by either by fh.info or simply
fh itself:
>>>
fh
.
info
VDIFStream information:
start_time = -06-16T05:56:07.
stop_time = -06-16T05:56:07.
sample_rate = 32.0 MHz
shape = (, 8)
format = vdif
bps = 2
complex_data = False
verify = fix
readable = True
checks: decodable: True
continuous: no obvious gaps
VDIFFile information:
edv = 3
number_of_frames = 16
thread_ids = [0, 1, 2, 3, 4, 5, 6, 7]
number_of_framesets = 2
frame_rate = .0 Hz
samples_per_frame =
sample_shape = (8, 1)
>>>
fh
<VDIFStreamReader name=... offset=12
sample_rate=32.0 MHz, samples_per_frame=,
sample_shape=SampleShape(nthread=8),
bps=2, complex_data=False, edv=3, station=,
start_time=-06-16T05:56:07.>
Not coincidentally, the first is identical to what we found above using file_info.
The filehandle itself also shows the offset, the current location of the
sample file pointer. Above, it is at 12 since we have read in 12 (complete)
samples. If we called fh.read (12) again we would get the next 12 samples.
If we instead called fh.read(), it would read from the pointers current
position to the end of the file. If we wanted all the data in one array, we
would move the file pointer back to the start of file, using fh.seek,
before reading:
>>>
fh
.
seek
(
0
)
# Seek to sample 0. Seek returns its offset in counts.
0
>>>
d_complete
=
fh
.
read
()
>>>
d_complete
.
shape
(, 8)
We can also move the pointer with respect to the end of file by passing 2
as a second argument:
>>>
fh
.
seek
(
-
100
,
2
)
# Second arg is 0 (start of file) by default.
>>>
d_end
=
fh
.
read
(
100
)
>>>
assert
np
.
array_equal
(
d_complete
[
-
100
:],
d_end
)
-100 means 100 samples before the end of file, so d_end is equal to
the last 100 entries of d_complete. Baseband only keeps the most recently
accessed data frame in memory, making it possible to analyze (normally large)
files through selective decoding using seek and read.
Note
As with file pointers in general, fh.seek will not return an error if
one seeks beyond the end of file. Attempting to read beyond
the end of file, however, will result in an EOFError.
To determine where the pointer is located, we use fh.tell():
>>>
fh
.
tell
()
>>>
fh
.
close
()
Caution should be used when decoding large blocks of data using fh.read.
For typical files, the resulting arrays are far too large to hold in memory.
We can use seek and tell with units of time rather than samples. To do
this with tell, we can pass an appropriate astropy.units.Unit object to
its optional unit parameter:
>>>
fh
=
vdif
.
open
(
HUAXUN Product Page
SAMPLE_VDIF
,
'rs'
)
>>>
fh
.
seek
(
)
>>>
fh
.
tell
(
unit
=
u
.
ms
)
<Quantity 1.25 ms>
Passing the string 'time' reports the pointers location in absolute time:
>>>
fh
.
tell
(
unit
=
'time'
)
<Time object: scale='utc' format='isot' value=-06-16T05:56:07.>
We can also pass an absolute astropy.time.Time, or a positive or negative time
difference TimeDelta or astropy.units.Quantity to seek.
If the offset is a Time object, the second argument to seek is
ignored.:
>>>
from
astropy.time.core
import
TimeDelta
>>>
from
astropy.time
import
Time
>>>
fh
.
seek
(
TimeDelta
(
-
5e-4
,
format
=
'sec'
),
2
)
# Seek -0.5 ms from end.
>>>
fh
.
seek
(
0.25
*
u
.
ms
,
1
)
# Seek 0.25 ms from current position.
>>>
# Seek to specific time.
>>>
fh
.
seek
(
Time
(
'-06-16T05:56:07.'
))
We can retrieve the time of the first sample in the file using start_time,
the time immediately after the last sample using stop_time, and the time
of the pointers current location (equivalent to fh.tell(unit='time'))
using time:
>>>
fh
.
start_time
<Time object: scale='utc' format='isot' value=-06-16T05:56:07.>
>>>
fh
.
stop_time
<Time object: scale='utc' format='isot' value=-06-16T05:56:07.>
>>>
fh
.
time
<Time object: scale='utc' format='isot' value=-06-16T05:56:07.>
>>>
fh
.
close
()
The first header of the file is stored as the header0 attribute of the
stream reader object; it gives direct access to header properties via keyword
lookup:
>>>
with
vdif
.
open
(
SAMPLE_VDIF
,
'rs'
)
as
fh
:
...
header0
=
fh
.
header0
>>>
header0
[
'frame_length'
]
629
The full list of keywords is available by printing out header0:
>>>
header0
<VDIFHeader3 invalid_data: False,
legacy_mode: False,
seconds: ,
_1_30_2: 0,
ref_epoch: 28,
frame_nr: 0,
vdif_version: 1,
lg2_nchan: 0,
frame_length: 629,
complex_data: False,
bits_per_sample: 1,
thread_id: 1,
station_id: ,
edv: 3,
sampling_unit: True,
sampling_rate: 16,
sync_pattern: 0xacabfeed,
loif_tuning: ,
_7_28_4: 15,
dbe_unit: 2,
if_nr: 0,
subband: 1,
sideband: True,
major_rev: 1,
minor_rev: 5,
personality: 131>
A number of derived properties, such as the time (as a Time
object), are also available through the header object:
>>>
header0
.
time
<Time object: scale='utc' format='isot' value=-06-16T05:56:07.>
These are listed in the API for each header class. For example, the sample VDIF files headers are of class:
>>>
type
(
header0
)
<class 'baseband.vdif.header.VDIFHeader3'>
and so its attributes can be found here.
By default, fh.read() returns complete samples, i.e. with all
available threads, polarizations or channels. If we were only interested in
decoding a subset of the complete sample, we can select specific
components by passing indexing objects to the subset keyword in open. For
example, if we only wanted thread 3 of the sample VDIF file:
>>>
fh
=
vdif
.
open
(
SAMPLE_VDIF
,
'rs'
,
subset
=
3
)
>>>
fh
.
sample_shape
()
>>>
d
=
fh
.
read
(
)
>>>
d
.
shape
(,)
>>>
fh
.
subset
(3,)
>>>
fh
.
close
()
Since by default data are squeezed, one obtains a data stream with just a
single dimension. If one would like to keep all information, one has to pass
squeeze=False and also make subset a list (or slice):
>>>
fh
=
vdif
.
open
(
SAMPLE_VDIF
,
'rs'
,
subset
=
[
3
],
squeeze
=
False
)
>>>
fh
.
sample_shape
SampleShape(nthread=1, nchan=1)
>>>
d
=
fh
.
read
(
)
>>>
d
.
shape
(, 1, 1)
>>>
fh
.
close
()
Data with multi-dimensional samples can be subset by passing a tuple of
indexing objects with the same dimensional ordering as the (possibly squeezed)
sample shape; in the case of the sample VDIF with squeeze=False, this is
threads, then channels. For example, if we wished to select threads 1 and 3,
and channel 0:
>>>
fh
=
vdif
.
open
(
SAMPLE_VDIF
,
'rs'
,
subset
=
([
1
,
3
],
0
),
squeeze
=
False
)
>>>
fh
.
sample_shape
SampleShape(nthread=2)
>>>
fh
.
close
()
Generally, subset accepts any object that can be used to index a
numpy.ndarray, including advanced indexing (as done above, with
subset=([1, 3], 0)). If possible, slices should be used instead
of list of integers, since indexing with them returns a view rather
than a copy and thus avoid unnecessary processing and memory allocation.
(An exception to this is VDIF threads, where the subset is used to selectively
read specific threads, and thus is not used for actual slicing of the data.)
For more NEW AND USED BASEBANDinformation, please contact us. We will provide professional answers.