Single Dish Radio Astronomy Software Tools

For an overview of SDRAST and the current status please visit https://sdrast.github.io/.

General Purpose Radio Telescope Monitor and Control

This is a collection of Python packages for using any fully sterable antenna and receiver as a radio telescope. The requirement is that the all the systems have their own controllers which can be operated with through a Python server using a standard communication protocol (e.g. sockets, USB, IEEE-488, RS-232, SNMP, etc.). The base package submodules provide superclasses for clients of these servers.

It is possible to use an existing monitor and control system as the server, as long as there is a way for it to accept commands and send responses using a standard protocol. In this case, the MonitorControl server which provides the gateway needs to be organized as a set of system servers using the same interface.

_images/overview.png

In this diagram, each client has a subclass which is specific to the server to which it interfaces. The client subclasses which used for a particular observing session are defined in a Python function called configuration(). There can be any number of configurations identified by a string context. Communication between clients and their servers uses the Pyro5 module.

The central server keeps track of what happens to a signal as it enters the telescope (antenna) and progresses to its final digital format for analysis. To achieve this there are three base superclasses.

_images/baseClasses.png

Each of the clients in the previous figure is a subclass of Device which operates on one or more Signalobjects that enter and leave via Port objects.

Operation

The central client works at the command line, using simulators for the antenna, receiver front end, and signal processing backend. True means that client is communicating with (simulated) hardware.:

In [1]: from MonitorControl.dss_server import DSSServer

In [2]: cs = DSSServer('WBDC2_K2',
                        config_args={'hardware': {'Antenna':True,
                                                  'FrontEnd':True,
                                                  'Backend':True}},
                  boresight_manager_kwargs=dict(reload=False, dump_cache=False))

In [3]: for device in cs.equipment.keys():
            print(device, "is", cs.equipment[device])

Antenna is DSN_Antenna "DSS-43"
FE_selector is None
FrontEnd is K_4ch "K"
Rx_selector is None
Receiver is WBDC2 "WBDC-2"
IF_switch is IFswitch "Patch Panel"
Backend is SAOclient "SAO spectrometer"
sampling_clock is None

In [4]: cs.equipment['Backend'].roachnames
Out[4]: ['roach1', 'roach2', 'roach3', 'roach4']

In [5]: cs.equipment['FrontEnd'].read_PMs()
Out[5]:
  [(1, 3.3588105790590205e-08),
   (2, 4.000051946785503e-08),
   (3, 5.2318605854014335e-08),
   (4, 4.906179322988035e-08)]

In [6]: cs.equipment['FrontEnd'].feed_states()
Out[6]: (False, True)

In [7]: cs.equipment['FrontEnd'].set_ND_on()

In [8]: cs.equipment['FrontEnd'].read_PMs()
Out[8]:
  [(1, 7.344903928672483e-08),
   (2, 8.764367036205836e-08),
   (3, 1.1014350435767278e-07),
   (4, 1.0521970259070695e-07)]

In [9]: cs.equipment['Backend'].hardware
Out[9]: <Pyro5.client.Proxy at 0x7fe5e5576e50; connected IPv6;
         for PYRO:backend@localhost:50004;
         owner <greenlet.greenlet object at 0x7fe5f40e8cb0>>

Clients are being developed for a GUI using Qt5. A web-based client using Flask and Flask Socket IO are also being developed.

Base Class Modules

These modules are all part of the base MonitorControl package.

MonitorControl Package

Monitor and Control of DSN radio astronomy equipment

In a very general sense, a configuration consists of Device sub-classes which operate on signals, and Ports at the Device inputs and outputs which transfer signals from one Device to another. Configurations defined for various situations are in the Configurations sub-module.

Devices may add to the properties of a signal. This is a typical sequence.

There are many ways a Device may characterize the data. Most common is power, or something which is proportional to the average of the square of the voltage samples. Cross-product averages may contain polarization information or fringe visibility. Because the output ports and signals must encode what kind of data they contain, a number of standard codes are defined for Device, Port and Signal objects which MUST be used in their names.

Classes:

MonitorControlError(RuntimeError)
Signal(object)                     -
Beam(Signal)                       - signal with both polarizations present
ComplexSignal(Signal)              - signal with both I and Q components
IF(Signal)                         - signal with no phase information (I or Q)
Spectrum(Signal)                   - digitized and usually transformed
Device(object)                     - generic object with Ports (in and/or out)
GainSection(Device)                - amplifiers, attenuators, filters, etc.
Switch(Device)                     - 1xN, Nx1, 2x2 switches
Port(object)                       - object which passes a Signal
Observatory(object)                - class for describing infrastructure
DeviceReadThread(threading.Thread) - gathers data

The module functions are:

ClassInstance     - provides a specific subclass object for a template class
valid_property    - forces signal properties to follow a naming convention
show_port_sources - print diagnostic information about ports
link_ports        - connect an upstream port with downstream port(s)
oldest_ancestor   - finds the top parent of the candidate
find_source       - upstream object belong to a specified class

Functions

ClassInstance(templateClass, subclass, …)

This creates an instance of the specified sub-class

find_source(device, source_class)

link_ports(inputs, outputs)

Connect an upstream port with downstream port(s).

oldest_ancestor(candidate)

finds the top parent of the candidate

show_port_sources(ports, header, loglevel)

Helper method to print diagnostic information about ports.

valid_property(keylist, ptype[, abort])

All entries must have a substr matching an entry in the signal property list.

Classes

ActionThread

alias of MonitorControl.DeviceReadThread

Beam(name)

Signal class for radiation arriving at a feed.

ComplexSignal(parent_signal[, pol, name])

ComplexSignal class for an RF output from an orthomode or polarizer.

Device(name[, inputs, output_names, active, …])

Superclass for anything that receives, processes and outputs a signal.

DeviceReadThread(actor, action[, name, suspend])

One thread in a multi-threaded, multiple device instrument

GainSection(name[, inputs, output_names, …])

Any device which increases or decreases the power level without changing the frequency and possible splits the signal.

IF(parent[, IF_type])

Electrical signal out of a receiver, suitable for detection or digitization.

MonitorControlError(args, message)

Error handler for this module

Observatory(name[, LO])

Defines the Observatory class.

Port(parent, name[, source, signal])

Class for a signal port in an Device.

Signal([name, parent_signal, beam, pol, IF_type])

Class for type of signal passing through a Port object.

Spectrum(parent[, name, num_chans])

Switch(name[, inputs, output_names, stype, …])

Three basic switch types are recognized: “1xN”, “Nx1” and “2x2”.

Class Inheritance Diagram

Inheritance diagram of MonitorControl.DeviceReadThread, MonitorControl.Beam, MonitorControl.ComplexSignal, MonitorControl.Device, MonitorControl.DeviceReadThread, MonitorControl.GainSection, MonitorControl.IF, MonitorControl.MonitorControlError, MonitorControl.Observatory, MonitorControl.Port, MonitorControl.Signal, MonitorControl.Spectrum, MonitorControl.Switch

MonitorControl.Antenna Package

Classes

Antenna(obs[, dss, LO, active, hardware])

A subclass of Telescope that can connect to a server that is currently running.

Telescope(obs[, dss, LO, active])

Defines the Telescope class.

Class Inheritance Diagram

Inheritance diagram of MonitorControl.Antenna.Antenna, MonitorControl.Antenna.Telescope

MonitorControl.FrontEnds Package

Superclass for receiver front ends

Classes

FrontEnd(name[, inputs, output_names, active])

Device which converts EM radiation to electrical signals.

Class Inheritance Diagram

Inheritance diagram of MonitorControl.FrontEnds.FrontEnd

MonitorControl.Receivers Package

Module for controlling and monitoring DSN science receivers

This has the highest Receiver superclass which described the functionality of a generic receiver.

Classes

Receiver(name[, inputs, output_names, active])

Device which converts RF signals to IF signals for detection or digitization

Class Inheritance Diagram

Inheritance diagram of MonitorControl.Receivers.Receiver

MonitorControl.BackEnds Package

Superclass for backend devices

Classes:

Backend(Device) which has private class
  DSProc(Device), which has private class
    Channel(Device)
Processor(Device)

Functions

freq_to_chan(frequency, bandwidth, n_chans)

Returns the channel number where a given frequency is to be found.

get_freq_array(bandwidth, n_chans)

Create an array of frequencies for the channels of a backend

get_smoothed_bandshape(spectrum[, degree, …])

Do a Gaussian smoothing of the spectrum and then fit a polynomial.

Classes

Backend(name[, inputs, output_names, …])

Defines the Backend class, some assembly of DSP hardware.

Processor(parent, name[, inputs, …])

Data processing device (computer) which provides additional processing

Class Inheritance Diagram

Inheritance diagram of MonitorControl.BackEnds.Backend, MonitorControl.BackEnds.Processor

MonitorControl.Configurations Package

This package describes equipment configurations used in DSN radio astronomy.

Nested dict ‘cfg’ is keyed the DSN stations, then the DSN receivers and then the polarizations which are available at the inputs of the VLBI DAT matrix switch, which will also be the DTO matrix switch. This dict can edited easily if more IFs become available, simply replacing the appropriate 0 with the input number. If there is no key, that IF does not exist.

References

http://deepspace.jpl.nasa.gov/dsndocs/810-005/302/302C.pdf

Attachment to e-mail from Alina Bedrossian on 03/21/2017 at 09:16 AM gives this assignment:

Antenna Type  Switch  CDSCC     GDSCC   MDSCC
    BWG1            1     34_S1         24_S1   54_S1
                    2     34_X1         26_S1   54_X1
                    3     34_Ka1        15_X1   54_Ka1
    BWG2            4     35_X1         25_X1   55_X1
                    5     35_Ka1        25_Ka1  55_Ka1
    BWG3            6     36_S1         15_S1   65_S1
                    7     36_X1         26_X1   65_X1
                    8     36_Ka1        26_Ka1  63_X2
    70-m            9     43_S1         14_S1   63_S1
                   10     43_X1         14_X1   63_X1
    AUX            11     AUX1          AUX1    AUX1
                   12     AUX2          AUX2    AUX2

Functions

station_configuration(context[, hardware, …])

Returns the Observatory instance and equipment dict for a context

Context Modules

Antenna

MonitorControl.Antenna.DSN Package

Classes

CallbackHandler()

DSN_Antenna(obs[, dss, LO, active, hardware])

A subclass of Telescope that can connect to a server that is currently running.

Class Inheritance Diagram

Inheritance diagram of MonitorControl.Antenna.DSN.CallbackHandler, MonitorControl.Antenna.DSN.DSN_Antenna

MonitorControl.Antenna.DSN.simulator Package

Provides a class to act a bit like an NMC

Classes

FakeAntenna([site, dss])

antenna simulator

Class Inheritance Diagram

Inheritance diagram of MonitorControl.Antenna.DSN.simulator.FakeAntenna

Front Ends

MonitorControl.FrontEnds.DSN Package

Descriptions of DSN front ends without monitor and control functions

Classes

DSN_fe(name[, inputs, output_names])

Class for DSN front ends with no M&C functions

Class Inheritance Diagram

Inheritance diagram of MonitorControl.FrontEnds.DSN.DSN_fe

MonitorControl.FrontEnds.K_band Package

K_4ch - client module for K_4ch front end class

This provides a superclass with code common to both WBDC versions

sub-package implements control and monitoring of the K-band front end using a LabJack

Signals

These are the signals monitored or controlled by the LabJack:

FIO  IO   type   description
---  --   ----   -----------
  0   0    DO    feed 1 load control (pulsed high-low-high)
  1   1    DO    feed 2 load control (pulsed high-low-high)
  2   2    DO    amp 1 bias control (pulsed high-low-high)
  3   3    DO    amp 2 bias control (pulsed high-low-high)
  4   4    DO    phase-cal (high = True = on)
  5   5    DO    phase-cal rail (high = True = 4 MHz, low = 1 MHz)
  6   6    DI    controls LabJack TickDAC
  7   7    DI    controls LabJack TickDAC

EIO  IO   type   description
---  --   ----   -----------
  0   8    DI    amp 1 bias on (high = True, low = False)
  1   9    DI    amp 2 bias on
  2  10    AIN   -12 V
  3  11    AIN   +12 V
  4  12    AIN    +5 V
  5  13    AIN    +8 V
  6  14    AIN   Lambda supply
  7  15    DO    ND control

CIO  IO   type   description
---  --   ----   -----------
  0  16    DI    feed 1 in load
  1  17    DI    feed 2 in load
  2  18    DI    feed 1 on sky
  3  19    DI    feed 2 on sky

Classes

K_4ch(name[, inputs, output_names, hardware])

The 4-channel downconverter with four inputs for two pols and two feeds.

Class Inheritance Diagram

Inheritance diagram of MonitorControl.FrontEnds.K_band.K_4ch

Receivers

MonitorControl.Receivers.DSN Package

DSN receiver descriptions with no monitor and control functions

Classes

DSN_rx(name[, inputs, output_names])

Class for DSN receivers with no M&C functions

Class Inheritance Diagram

Inheritance diagram of MonitorControl.Receivers.DSN.DSN_rx

MonitorControl.Receivers.WBDC Package

WBDC - module for Wide Band Down Converter receiver classes

Overview

There are two versions of the wideband down-converter

WBDC1 has two RF sections after the band-splitting filters, one for 22 and 24 GHz, two switch-selectable LOs and one IF section.

WBDC2 has five RF sections and five IF sections.

The sections, as well as feed switching, polarization selection, etc. are basically the same.

Input Switching

The first stage of the WBDC allows the down-converter groups to be switched between the two feeds.

Polarization Conversion

After the band-selecting RF filters, the linearly polarized signals from each feed can be switched into a quadrature hybrid to be converted to cicular polarizations.

Sideband Separation

The down-conversion produces complex outputs (i.e. a pair of signals I and Q). There are switches which can direct each I/Q pair into a quadrature hybrid to convert them to an upper and lower sideband pair.

WARNING! RFsection method _rename_beam is very dependent on the naming convention used, specifically, the length of the names.

Classes

WBDC_base(name[, inputs, output_names, active])

Base class for a DSN K-band wideband down-converter.

Class Inheritance Diagram

Inheritance diagram of MonitorControl.Receivers.WBDC.WBDC_base

Back Ends

MonitorControl.BackEnds.DSN Package

Classes

WVSRbackend(name, collector[, inputs, …])

Class Inheritance Diagram

Inheritance diagram of MonitorControl.BackEnds.DSN.WVSRbackend

MonitorControl.BackEnds.ROACH1 Package

Functions

adc_cnt_mv_scale_factor([atten_gain, fe_gain])

Raw ADC count to mV.

roach_name_adaptor(func)

If we send the number of the roach instead of the roach name, it will still work.

MonitorControl.BackEnds.ROACH1.SAOclient Module

Python Pyro client for ROACH1 firmware

Notes

This works with a Pyro5 server for ROACH1. It’s relatively independent of the firmware on the ROACH1. There is a server simulator derived from the hardware server for the 32K 1000MHz spectrometer firmware.

Classes

SAOclient(name[, inputs, output_names, hardware])

SAO 32K-channel spectrometer client

Class Inheritance Diagram

Inheritance diagram of MonitorControl.BackEnds.ROACH1.SAOclient.SAOclient

MonitorControl.BackEnds.ROACH1.simulator Module

This simulates a multi-ROACH backend using the TAMS firmare.

The basic program behavior is to create a SAObackend object. This is the parent for SAOfwif (SAO firmware interface) objects, one for each ROACH. The SAOfwif class is a subclass of the DeviceReadThread class.

Each SAOfwif object has one or more Channel objects (one for ROACH1, four for ROACH2) which convert IF signals into 32K power spectra.

Because conversion to 4-channel firmware is pending, a number of SAOfwif methods should be eventually converted to SAOfwif.Channel methods.

Each SAOfwif object initializes its channel(s) and simulates the ROACH’s firmware initialization which consists of:

* setting the FFT shift register,
* setting the gain of the RF sections of the ADC channels,
* setting the accumulation (integration) time as a number of accumulations,
* configures the firmware,
* starts the thread, providing it with an 'action' method,
* immediately suspends the thread,
* sets the scan number to 1.

The SAObackend'``method ``start() is invoked by a client. For each ROACH it:

* resumes the thread,
* invokes the client's callback handler to provide the start time,
* sets the number of accumulated spectra to zero.

The SAOfwif method action() increments the number of accumulations and checks to see if it exceeds exceeds the specified number of accumulations for a scan. If not it:

* waits for the accumulation to be completed,
* puts the accumulation (spectrum) on the combiner queue.

If the number of accumulations exceeds the specified maximum it:

* suspends the threat,
* sets the number of accumulations to 0,
* increments the scan number.

Note therefore that a scan consists of some specified number of accumulations (integrations) each of which is written as a record, that is, as a row in a 2D numpy array. It is the job of the client to start a new scan which resumes the thread.

Scan and Record Numbers

Scan and record numbers are integers or three digit strings starting with “001”. Each ROACH has its own copy of the scan number.

Record numbers are initialized to 0 when the SAOfwif object is created. It is incremented each time action() is entered.

Scan numbers are initialized as 0. The The scan numbers are updated in the SAObackend method action() when a scan is completed. (It’s better to think of action() as an SAOfwif method provided by the parent SAObackend.)

Metadata

The SAOfwif object creates an HDF5 file when it is initialised. The firmware register data which do not change are attrs of the top level of the HDF5 hierarchy. The SAObackend method start(N) will start a new scan of N records for each ROACH. Scans are at the second level of the HDF5 hierarchy. The attrs of the scan level of the file are those firmware registers which do not change during a scan. Each record is written to disk as it is acquired. The attrs of the record level are the register values which change all the time, and also time in seconds.

Example

Creating a backend server at the command line:

from MonitorControl.BackEnds.ROACH1.SAOfwif import SAObackend
be = SAObackend("SAO spectrometer",
                roachlist=["sao64k-1", "sao64k-2", "sao64k-3", "sao64k-4"])

Functions

create_arg_parser()

logtime()

main(server_cls)

starts logging, creates a server_cls object, launches the server object

nowgmt()

Classes

RoachCombiner([parent, dsplist])

subclass with meaningful process_data method

SAObackend(name[, roaches, roachlist, …])

A simulated multi-ROACH 32k-channel x 4-IF spectrometer

SAOfwif([parent, roach, template, …])

Class for one ROACH with SAO 32K spectrometer firmware

SAOspecServer(name[, roachlist, logpath, …])

Pyro server for the SAO back end

Class Inheritance Diagram

Inheritance diagram of MonitorControl.BackEnds.ROACH1.simulator.RoachCombiner, MonitorControl.BackEnds.ROACH1.simulator.SAObackend, MonitorControl.BackEnds.ROACH1.simulator.SAOfwif, MonitorControl.BackEnds.ROACH1.simulator.SAOspecServer

Configurations

MonitorControl.Configurations.CDSCC Package

Configuration information for CDSCC

dict ‘cfg’ is a structure which contains all the receivers and polarization channels of DSN telemetry, tracking and control receivers.

dict ‘feed’ contains all the feed names and positions

References

https://deepspace.jpl.nasa.gov/dsndocs/810-005/101/101F.pdf https://deepspace.jpl.nasa.gov/dsndocs/810-005/302/302C.pdf

Notes on beam efficiency

In [1]: from MonitorControl.Configurations.CDSCC import * In [2]: from Radio_Astronomy import *

In [3]: forward_gain(0.766, pi*35**2, 300./8400) Out[3]: 74.63040657733823 In [4]: forward_gain(0.72, pi*35**2, 300./8400) Out[4]: 74.36144384532489

In [5]: antenna_solid_angle(0.766, pi*35**2, 300./8400) Out[5]: 4.3268237639205843e-07 In [6]: antenna_solid_angle(0.72, pi*35**2, 300./8400) Out[6]: 4.603259726615511e-07

The measured HPBW is 0.032 deg

In [7]: beam_solid_angle(pi*0.032/180,pi*0.032/180) Out[7]: 3.5247890878359627e-07

In [8]: beam_efficiency(4.3268237639205843e-07,3.5247890878359627e-07) Out[8]: 0.8146366203374346 In [9]: beam_efficiency(4.603259726615511e-07,3.5247890878359627e-07) Out[9]: 0.7657158833458915

Functions

rel_gain43(elev)

Reference: report attached to e-mail from Shinji 05/24/2015 07:26 AM filed in Canberra/Calibration

MonitorControl.Configurations.GDSCC Package

Configurations at the Goldstone Complex

Nested dict ‘cfg’ is keyed the DSN stations, then the DSN receivers and then the polarizations which are available at the inputs of the VLBI DAT matrix switch, which will also be the DTO matrix switch. This dict can edited easily if more IFs become available, simply replacing the appropriate 0 with the input number. If there is no key, that IF does not exist.

References

http://deepspace.jpl.nasa.gov/dsndocs/810-005/302/302C.pdf

The following are from cable tracing and table from Larry (DVP-DTO.jpg):

24SR  -> J1A  ->  2
14SR  -> J2A  ->  4
      -> J3A  ->
      -> J4A  ->  8
      -> J5A  -> 10
      -> J6A  ->  6
26XR  -> J7A  -> 18
26KaR -> J8A  -> 20
      -> J9A  ->
14XR  -> J10A ->
      -> J11A ->
      -> J12A -> 24

Functions

make_switch_inputs(rx)

Identifies the signals going into the IF switch

Indices and tables

Last revised by Tom Kuiper 2020 Aug 3.