Devices ============ .. _boot: Boot --------- The ``boot == DeviceProxy("LTS/Boot/1")`` device is responsible for (re)starting and initialising the other devices. Devices which are not reachable, for example because their docker container is explicitly stopped, are skipped during initialisation. This device provides the following commands: :initialise_station(): Stop and start the other devices in the correct order, set their default values, and command them to initialise their hardware. This procedure runs asynchronously, causing this command to return immediately. Initialisation is aborted if an error is encountered. :returns: ``None`` The initialisation process can subsequently be followed through monitoring the following attributes: :initialising_R: Whether the initialisation procedure is still ongoing. :type: ``bool`` :initialisation_progress_R: Percentage completeness of the initialisation procedure. Each succesfully configured device increments progress. :type: ``int`` :initialisation_status_R: A description of what the device is currently trying to do. If an error occurs, this will hint towards the cause. :type: ``str`` A useful pattern is thus to call ``initialise_station()``, wait for ``initialising_R == False``, and then check whether the initalisation was succesful, if ``initialisation_progress_R == 100``. If a device fails to initialise, most likely the :doc:`../interfaces/logs` will need to be consulted. .. _docker: Docker --------- The ``docker == DeviceProxy("LTS/Docker/1")`` device controls the docker containers. It allows starting and stopping them, and querying whether they are running. Each container is represented by two attributes: :_R: Returns whether the container is running. :type: ``bool`` :_RW: Set to ``True`` to start the container, and to ``False`` to stop it. :type: ``bool`` .. warning:: Do *not* stop the ``tango`` container, as doing so cripples the Tango infrastructure, leaving the station inoperable. It is also not wise to stop the ``device_docker`` container, as doing so would render this device unreachable. RECV ---------- The ``recv == DeviceProxy("LTS/RECV/1")`` device controls the RCUs, the LBA antennas, and HBA tiles. Central to its operation are the masks (see also :ref:`attribute-masks`): :RCU_mask_RW: Controls which RCUs will actually be configured when attributes referring to RCUs are written. :type: ``bool[N_RCUs]`` :Ant_mask_RW: Controls which antennas will actually be configured when attributes referring to antennas are written. :type: ``bool[N_RCUs][N_antennas_per_RCU]`` Typically, ``N_RCUs == 32``, and ``N_antennas_per_RCU == 3``. SDP ----------- The ``sdp == DeviceProxy("LTS/SDP/1")``` device controls the digital signal processing in SDP, performed by the firmware on the FPGAs on the Uniboards. Central to its operation is the mask (see also :ref:`attribute-masks`): :TR_fpga_mask_RW: Controls which FPGAs will actually be configured when attributes referring to FPGAs are written. :type: ``bool[N_fpgas]`` Typically, ``N_fpgas == 16``. SST and XST ----------- The ``sst == DeviceProxy("LTS/SST/1")`` and ``xst == DeviceProxy("LTS/XST/1")`` devices manages the SSTs (subband statistics) and XSTs (crosslet statistics), respectively. The statistics are emitted piece-wise through UDP packets by the FPGAs on the Uniboards in SDP. By default, each device configures the statistics to be streamed to itself (the device), from where the user can obtain them. The statistics are exposed in two ways, as: - *Attributes*, representing the most recently received values, - *TCP stream*, to allow the capture and recording of the statistics over any period of time. SST Statistics attributes ````````````````````````` The SSTs represent the amplitude of the signal in each subband, for each antenna, as an integer value. They are exposed through the following attributes: :sst_R: Amplitude of each subband, from each antenna. :type: ``uint64[N_ant][N_subbands]`` :sst_timestamp_R: Timestamp of the data, per antenna. :type: ``uint64[N_ant]`` :integration_interval_R: Timespan over which the SSTs were integrated, per antenna. :type: ``float32[N_ant]`` :subbands_calibrated_R: Whether the subband data was calibrated using the subband weights. :type: ``bool[N_ant]`` Typically, ``N_ant == 192``, and ``N_subbands == 512``. XST Statistics attributes ````````````````````````` The XSTs represent the cross-correlations between each pair of antennas, as complex values. The phases and amplitudes of the XSTs represent the phase and amplitude difference between the antennas, respectively. They are exposed as a matrix ``xst[a][b]``, of which only the triangle ``a<=b`` is filled, as the cross-correlation between antenna pairs ``(b,a)`` is equal to the complex conjugate of the cross-correlation of ``(a,b)``. The other triangle contains incidental values, but will be mostly 0. Complex values which cannot be represented in Tango attributes. Instead, the XST matrix is exposed as both their carthesian and polar parts: :xst_power_R, xst_phase_R: Amplitude and phase of the crosslet statistics. :type: ``float32[N_ant][N_ant]`` :xst_real_R, xst_imag_R: Real and imaginary parts of the crosslet statistics. :type: ``float32[N_ant][N_ant]`` :xst_timestamp_R: Timestamp of each block. :type: ``int64[N_blocks]`` :integration_interval_R: Timespan over which the XSTs were integrated, for each block. :type: ``float32[N_blocks]`` Typically, ``N_ant == 192``, and ``N_blocks == 136``. The metadata refers to the *blocks*, which are emitted by the FPGAs to represent the XSTs between 12 x 12 consecutive antennas. The following code converts block numbers to the indices of the first antenna pair in a block:: from common.baselines import baseline_from_index def first_antenna_pair(block_nr: int) -> int: coarse_a, coarse_b = baseline_from_index(block_nr) return (coarse_a * 12, coarse_b * 12) Conversely, to calculate the block index for an antenna pair ``(a,b)``, use:: from common.baselines import baseline_index def block_nr(a: int, b: int) -> int: return baseline_index(a // 12, b // 12) TCP stream `````````` The TCP stream interface allows a user to subscribe to the statistics packet streams, combined into a single TCP stream. The statistics will be streamed until the user disconnects, or the device is turned off. Any number of subscribers is supported, as bandwidth allows. Simply connect to the following port: +----------+----------------+ | Device | TCP end point | +==========+================+ | SST | localhost:5101 | +----------+----------------+ | XST | localhost:5102 | +----------+----------------+ The easiest way to capture this stream is to use our ``statistics_writer``, which will capture the statistics and store them in HDF5 file(s). The writer: - computes packet boundaries, - processes the data of each packet, and stores their values into the matrix relevant for the mode, - stores a matrix per timestamp, - stores packet header information per timestamp, as HDF5 attributes, - writes to a new file at a configurable interval. To run the writer:: cd devices/statistics_writer python3 statistics_writer.py --mode SST --host localhost The correct port will automatically be chosen, depending on the given mode. See also ``statistics_writer.py -h`` for more information. The writer can also parse a statistics stream stored in a file. This allows the stream to be captured and processed independently. Capturing the stream can for example be done using ``netcat``:: nc localhost 5101 > SST-packets.bin