Overview

The RcalEmulatorDevice is a Tango Device designed to provide real-time calibration (RCal) emulator for the Square Kilometre Array (SKA) LOW CBF testing purpose.

It emulates the generation of Jones calibration matrices for multiple beams, stations, and frequencies, and streams the results with associated metadata.

This device supports configuration of calibration parameters, execution of the calibration emulator, and integration with Kafka for data transport.

Attributes

Attribute Name

Type

Description

kafka_address

String

URL and port number of the Kafka server to which calibration data is sent.

list_of_frequencies

Array[int]

List of SPS frequencies used during calibration. Configurable via configure_rcal.

list_of_stations

Array[String]

List of stations/substations included in calibration. Configurable via configure_rcal.

rotate_degrees

Float

Rotation angle (in degrees) applied to both X and Y polarisations.

list_of_beams

Array[Int]

List of PST beams to be calibrated. Configurable via configure_rcal.

updating_period

Float

Period (in seconds) at which calibration matrices are generated and sent.

max_message

Integer

Max Message size proxy where Kafka message_max_bytes=max_message * 2^20.

generations

String

Read-only JSON list of the registered output generations. Managed via add_rcal_generation / clear_rcal_generations.

Commands

configure_rcal

Input: JSON string

Output: Tango Result → Ok if configuration done, else FAILED.

Description:

Configures the lists of SPS frequencies, stations, and PST beams.

Example JSON:

{
    "frequencies": [64, 65],
    "stations": ["1/1", "2/1"],
    "beams": [1, 2]
}

start_calibration

Input: Topic name

Output: Tango Result

Description:

Starts the calibration emulator. Once started, the device will generate and send Jones matrices every updating_period seconds.

Workflow:

  1. Prepare one Jones matrix per beam:

    • If cal_count % 2 == 0 → use identity matrix.

    • Else → apply rotation matrix with rotate_degrees.

  2. Attach metadata to the calibration data.

  3. Send calibration results to Kafka as an xarray.DataArray.

stop_calibration

Input: None

Output: Tango Result

Description:

Stops the calibration process. Allow for one full updating period before restarting.

add_rcal_generation

Input: JSON string

Output: Tango Result → Ok if the generation was registered, else FAILED.

Description:

Registers one output generation. The emulator can hold any number of generations, each an independent typed stream with its own Kafka topic. Each generation produces one Kafka message per beam every updating_period.

type selects the data product and defaults to "pst" when omitted:

  • pst — requires beams; publishes one gain table per PST beam, one Kafka message per beam on <topic>_beam_<beam> (the default, backward-compatible product).

  • pss — requires pss_beams; publishes one Kafka message per update period to a single topic (<topic>) containing a station_jones plus the beam_jones for all PSS beams.

Generations may be added while calibration is running; new ones are picked up on the next update period.

Example PST JSON:

{
    "type": "pst",
    "topic": "cal_pst",
    "frequencies": [64, 65],
    "stations": ["1/1", "2/1"],
    "beams": [1, 2]
}

Example PSS JSON:

{
    "type": "pss",
    "topic": "cal_pss",
    "frequencies": [64, 65],
    "stations": ["1/1", "2/1"],
    "pss_beams": [187, 188, 189],
    "beam_rotations": [0, 45, 90]
}

beam_rotations is optional; when given it must have one angle (degrees) per entry in pss_beams.

If no generation is registered, start_calibration synthesises a single default PST generation from the configure_rcal lists and the topic passed to it, preserving the original single-stream behaviour.

clear_rcal_generations

Input: None

Output: Tango Result

Description:

Removes all registered output generations.

Data Format

The calibration results are sent as an xarray.DataArray object:

xarray_to_return = xarray.DataArray(
    data,
    coords={
        "antenna": list_of_stations,
        "frequency": list_of_frequencies,
        "polarisation": polarisations.split(","),  # e.g., ["XX", "XY", "YX", "YY"]
    },
    attrs={
        "cal_interval_start": interval_start_time,
        "cal_interval_end": interval_end_time,
        "cal_count": count,
    },
)
  • data contains the generated Jones matrices.

  • coords provide mapping to beams, stations, frequencies, and polarisations.

  • attrs carry timing and counter metadata for traceability.

PSS data format

A pss generation instead sends the whole xarray.Dataset as a single message on one topic (<topic>). It carries a shared station_jones and a beam_jones spanning every PSS beam, using the receptor1/receptor2 convention (values ["X", "Y"]). beam_jones follows the same identity/rotation toggle as station_jones but with an optional per-beam rotation angle (beam_rotations, one degree value per pss beam): on even solutions every beam is the identity, on odd solutions beam i is rotated by beam_rotations[i]. When beam_rotations is omitted every beam falls back to the global rotate_degrees (station_jones always uses the global value):

<xarray.Dataset>
Dimensions:        (antenna, frequency, receptor1: 2, receptor2: 2,
                    pss_beam_id)
Data variables:
    station_jones  (antenna, frequency, receptor1, receptor2) complex64
    beam_jones     (pss_beam_id, frequency, receptor1, receptor2) complex64

Note

Unit tests in this repository do not connect to Kafka; they verify dataset shapes and generation registration only. A live Kafka round-trip test belongs in the integration repository, where the Kafka deployment is in scope.

Example Workflow

  1. Configure the device:

    json_config = '{"frequencies": [64, 65], "stations": ["1/1", "2/1"], "beams": [1, 2]}'
    rcal = tango.DeviceProxy(f"{TANGO_DB_HOST}/low-cbf/rcal/0")
    rcal.configure_rcal(json_config)
    
  2. Adjust attributes if necessary:

    rcal.rotate_degrees = 45.0
    rcal.kafka_address = "test-kafka.rcal-jou008.svc.cluster.local:9092"
    rcal.updating_period = 10.0
    
  3. Start calibration:

    rcal.start_calibration("my-topic")
    
  4. Receive results:

    Jones matrices are received every updating_period seconds in the Kafka stream.

Example Workflow (multiple / PSS generations)

To publish several typed streams at once, register each with add_rcal_generation and then start the emulator (the topic passed to start_calibration is ignored once generations are registered):

rcal = tango.DeviceProxy(f"{TANGO_DB_HOST}/low-cbf/rcal/0")
rcal.add_rcal_generation(
    '{"type": "pst", "topic": "cal_pst", "frequencies": [64, 65], '
    '"stations": ["1/1", "2/1"], "beams": [1, 2]}'
)
rcal.add_rcal_generation(
    '{"type": "pss", "topic": "cal_pss", "frequencies": [64, 65], '
    '"stations": ["1/1", "2/1"], "pss_beams": [187, 188, 189]}'
)
rcal.start_calibration("unused")