From e37c99cf7b21ab7a5a6f80af005e580f5e3b015b Mon Sep 17 00:00:00 2001 From: Jan David Mol <mol@astron.nl> Date: Fri, 4 Aug 2023 14:44:46 +0200 Subject: [PATCH 01/11] L2SS-1470: Expose settings for both polarisations in RCU_band_select_R(W) --- .../tangostationcontrol/devices/antennafield.py | 10 ++++++---- .../devices/base_device_classes/mapper.py | 17 ++++++++++++++--- 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/tangostationcontrol/tangostationcontrol/devices/antennafield.py b/tangostationcontrol/tangostationcontrol/devices/antennafield.py index b83f34e6b..546e4315c 100644 --- a/tangostationcontrol/tangostationcontrol/devices/antennafield.py +++ b/tangostationcontrol/tangostationcontrol/devices/antennafield.py @@ -510,13 +510,15 @@ class AntennaField(LOFARDevice): ) RCU_band_select_R = MappedAttribute( "RCU_band_select_R", - dtype=(numpy.int64,), - max_dim_x=MAX_ANTENNA, + dtype=((numpy.int64,),), + max_dim_x=N_pol, + max_dim_y=MAX_ANTENNA, ) RCU_band_select_RW = MappedAttribute( "RCU_band_select_RW", - dtype=(numpy.int64,), - max_dim_x=MAX_ANTENNA, + dtype=((numpy.int64,),), + max_dim_x=N_pol, + max_dim_y=MAX_ANTENNA, access=AttrWriteType.READ_WRITE, ) RCU_attenuator_dB_R = MappedAttribute( diff --git a/tangostationcontrol/tangostationcontrol/devices/base_device_classes/mapper.py b/tangostationcontrol/tangostationcontrol/devices/base_device_classes/mapper.py index efddb1bd2..064bba36a 100644 --- a/tangostationcontrol/tangostationcontrol/devices/base_device_classes/mapper.py +++ b/tangostationcontrol/tangostationcontrol/devices/base_device_classes/mapper.py @@ -328,8 +328,12 @@ class AntennaToRecvMapper(AntennaMapper): "HBAT_PWR_on_RW": value_map_ant_32_bool, "RCU_PWR_ANT_on_R": value_map_ant_bool, "RCU_PWR_ANT_on_RW": value_map_ant_bool, - "RCU_band_select_R": numpy.zeros(number_of_antennas, dtype=numpy.int64), - "RCU_band_select_RW": numpy.zeros(number_of_antennas, dtype=numpy.int64), + "RCU_band_select_R": numpy.zeros( + (number_of_antennas, N_pol), dtype=numpy.int64 + ), + "RCU_band_select_RW": numpy.zeros( + (number_of_antennas, N_pol), dtype=numpy.int64 + ), "RCU_attenuator_dB_R": numpy.zeros( (number_of_antennas, N_pol), dtype=numpy.int64 ), @@ -354,6 +358,8 @@ class AntennaToRecvMapper(AntennaMapper): self._reshape_attributes_in = mapped_dimensions self._reshape_attributes_in["RCU_attenuator_dB_R"] = ((MAX_ANTENNA * N_pol),) self._reshape_attributes_in["RCU_attenuator_dB_RW"] = ((MAX_ANTENNA * N_pol),) + self._reshape_attributes_in["RCU_band_select_R"] = ((MAX_ANTENNA * N_pol),) + self._reshape_attributes_in["RCU_band_select_RW"] = ((MAX_ANTENNA * N_pol),) self._reshape_attributes_in["RCU_PCB_ID_R"] = (MAX_ANTENNA,) self._reshape_attributes_in["RCU_PCB_version_R"] = (MAX_ANTENNA,) @@ -366,6 +372,8 @@ class AntennaToRecvMapper(AntennaMapper): # Attributes which need to be reshaped with a copy of their values, # because RECV original dimension < AntennaField mapped dimension self._fill_attributes_in = { + "RCU_band_select_R": N_pol, + "RCU_band_select_RW": N_pol, "RCU_attenuator_dB_R": N_pol, "RCU_attenuator_dB_RW": N_pol, "RCU_PCB_ID_R": N_rcu_inp, @@ -375,7 +383,8 @@ class AntennaToRecvMapper(AntennaMapper): # Attributes which need to be reshaped with removing a part of their duplicated # values because RECV original dimension < Antennafield mapped dimension self._empty_attributes_out = { - "RCU_attenuator_dB_RW": (N_rcu * N_rcu_inp, N_pol) + "RCU_band_select_RW": (N_rcu * N_rcu_inp, N_pol), + "RCU_attenuator_dB_RW": (N_rcu * N_rcu_inp, N_pol), } def _init_masked_value_write(self, mapped_dimensions: dict): @@ -398,6 +407,8 @@ class AntennaToRecvMapper(AntennaMapper): double_mapping = [ "RCU_attenuator_dB_R", "RCU_attenuator_dB_RW", + "RCU_band_select_R", + "RCU_band_select_RW", "RCU_PCB_ID_R", "RCU_PCB_version_R", ] -- GitLab From b8fbe893779fa32f9e6b924ddb5a057320bae5c4 Mon Sep 17 00:00:00 2001 From: Jan David Mol <mol@astron.nl> Date: Fri, 4 Aug 2023 15:10:31 +0200 Subject: [PATCH 02/11] L2SS-1470: Handle different RCU bands per polarisation --- .../tangostationcontrol/common/calibration.py | 13 +++------- .../devices/antennafield.py | 25 +++++++++++++------ 2 files changed, 21 insertions(+), 17 deletions(-) diff --git a/tangostationcontrol/tangostationcontrol/common/calibration.py b/tangostationcontrol/tangostationcontrol/common/calibration.py index 1c98b7dbc..c0147b3a8 100644 --- a/tangostationcontrol/tangostationcontrol/common/calibration.py +++ b/tangostationcontrol/tangostationcontrol/common/calibration.py @@ -256,7 +256,7 @@ def calibrate_RCU_attenuator_dB(antenna_field: DeviceProxy): # ----------------------------------------------------------- # Correct for signal loss in the cables - signal_delay_loss = antenna_field.Antenna_Cables_Loss_R + signal_delay_loss = antenna_field.Antenna_Cables_Loss_R.flatten() # return coarse attenuation to apply (weakest signal # gets 0 attenuation). @@ -266,14 +266,9 @@ def calibrate_RCU_attenuator_dB(antenna_field: DeviceProxy): rcu_attenuator_db += antenna_field.Field_Attenuation_R # apply on antenna field - antenna_field.RCU_attenuator_dB_RW = ( - numpy.tile( - numpy.array(rcu_attenuator_db, dtype=numpy.int64).flatten(), - N_pol, - ) - .reshape(N_pol, antenna_field.nr_antennas_R) - .T - ) + antenna_field.RCU_attenuator_dB_RW = rcu_attenuator_db.reshape( + antenna_field.nr_antennas_R, N_pol + ).astype(numpy.int64) def loss_compensation(losses_dB: numpy.ndarray): diff --git a/tangostationcontrol/tangostationcontrol/devices/antennafield.py b/tangostationcontrol/tangostationcontrol/devices/antennafield.py index 546e4315c..c040dfdf2 100644 --- a/tangostationcontrol/tangostationcontrol/devices/antennafield.py +++ b/tangostationcontrol/tangostationcontrol/devices/antennafield.py @@ -393,9 +393,10 @@ class AntennaField(LOFARDevice): unit="s", ) Antenna_Cables_Loss_R = attribute( - doc="Loss caused by the cable between antenna and RCU, in dB.", + doc="Loss caused by the cable between antenna and RCU, in dB, for either polarisation.", dtype=(numpy.float64,), - max_dim_x=MAX_ANTENNA, + max_dim_x=N_pol, + max_dim_y=MAX_ANTENNA, unit="dB", ) @@ -701,8 +702,8 @@ class AntennaField(LOFARDevice): def read_Frequency_Band_RW(self): antenna_type = self.Antenna_Type - # fetch settings from RECV - rcu_band_select = self.read_attribute("RCU_band_select_RW") + # fetch settings from RECV, use X polarisation for reference + rcu_band_select = self.read_attribute("RCU_band_select_RW")[:, 0] # fetch settings from SDP clock = self.sdpfirmware_proxy.clock_RW @@ -742,11 +743,16 @@ class AntennaField(LOFARDevice): These do not: {val} and {value[0, 0]}." ) - # apply settings on RECV - self.proxy.RCU_band_select_RW = numpy.vectorize( + # convert into settings for RECV + RCU_band_select_per_polarisation = numpy.vectorize( lambda band: bands[band].rcu_band )(value) + # apply same setting for both polarisations on RECV + self.proxy.RCU_band_select_RW = numpy.dstack( + (RCU_band_select_per_polarisation, RCU_band_select_per_polarisation) + )[0] + # apply settings on SDP self.sdpfirmware_proxy.clock_RW = bands[value[0]].clock @@ -792,9 +798,12 @@ class AntennaField(LOFARDevice): # Return 0 loss for them instead. return numpy.array( [ - cable_types[cable].get_loss(self.Antenna_Type, rcu_band) + [ + cable_types[cable].get_loss(self.Antenna_Type, rcu_band[0]), + cable_types[cable].get_loss(self.Antenna_Type, rcu_band[1]), + ] if recv > 0 - else 0 + else [0, 0] for recv, cable, rcu_band in zip(recvs, self.Antenna_Cables, rcu_bands) ] ) -- GitLab From 8c3a022411e5e8d27e7b94fac505638ae3fd1c4a Mon Sep 17 00:00:00 2001 From: Jan David Mol <mol@astron.nl> Date: Fri, 4 Aug 2023 15:14:05 +0200 Subject: [PATCH 03/11] L2SS-1470: Support different RCU bands per polarisation --- .../tangostationcontrol/devices/antennafield.py | 7 ++++--- .../tangostationcontrol/devices/observation.py | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/tangostationcontrol/tangostationcontrol/devices/antennafield.py b/tangostationcontrol/tangostationcontrol/devices/antennafield.py index c040dfdf2..3bfddc9fd 100644 --- a/tangostationcontrol/tangostationcontrol/devices/antennafield.py +++ b/tangostationcontrol/tangostationcontrol/devices/antennafield.py @@ -371,9 +371,10 @@ class AntennaField(LOFARDevice): return numpy.array(self.RECV_Devices) Frequency_Band_RW = attribute( - doc="The selected frequency band of each antenna.", + doc="The selected frequency band of each polarisation of each antenna.", dtype=(str,), - max_dim_x=MAX_ANTENNA, + max_dim_x=N_pol, + max_dim_y=MAX_ANTENNA, access=AttrWriteType.READ_WRITE, ) @@ -703,7 +704,7 @@ class AntennaField(LOFARDevice): antenna_type = self.Antenna_Type # fetch settings from RECV, use X polarisation for reference - rcu_band_select = self.read_attribute("RCU_band_select_RW")[:, 0] + rcu_band_select = self.read_attribute("RCU_band_select_RW") # fetch settings from SDP clock = self.sdpfirmware_proxy.clock_RW diff --git a/tangostationcontrol/tangostationcontrol/devices/observation.py b/tangostationcontrol/tangostationcontrol/devices/observation.py index 1af565875..2bb92b80d 100644 --- a/tangostationcontrol/tangostationcontrol/devices/observation.py +++ b/tangostationcontrol/tangostationcontrol/devices/observation.py @@ -315,7 +315,7 @@ class Observation(LOFARDevice): # convert numpy.array(dtype=str) to list[str] to avoid crash in DeviceProxy # see https://gitlab.com/tango-controls/pytango/-/issues/492 - return (numpy.array([filter_name] * MAX_ANTENNA).tolist(),) + return (numpy.array([[filter_name, filter_name]] * MAX_ANTENNA).tolist(),) def _apply_saps_subbands(self, sap_subbands: list): """Convert an array of subbands into the correct format for Beamlet device""" -- GitLab From 4beb753d0666c0ad871f27932afc16ef74b8e348 Mon Sep 17 00:00:00 2001 From: Jan David Mol <mol@astron.nl> Date: Fri, 4 Aug 2023 15:15:37 +0200 Subject: [PATCH 04/11] L2SS-1470: Only upload settings for the correct number of antennas --- .../tangostationcontrol/devices/observation.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tangostationcontrol/tangostationcontrol/devices/observation.py b/tangostationcontrol/tangostationcontrol/devices/observation.py index 2bb92b80d..341302d50 100644 --- a/tangostationcontrol/tangostationcontrol/devices/observation.py +++ b/tangostationcontrol/tangostationcontrol/devices/observation.py @@ -16,6 +16,7 @@ from tangostationcontrol.common.constants import ( MAX_ANTENNA, N_beamlets_ctrl, N_point_prop, + N_pol, ) from tangostationcontrol.common.entrypoint import entry from tangostationcontrol.common.lofar_logging import device_logging_to_python @@ -313,9 +314,11 @@ class Observation(LOFARDevice): AntennaField device """ + nr_antennas = self.antennafield_proxy.nr_antennas_R + # convert numpy.array(dtype=str) to list[str] to avoid crash in DeviceProxy # see https://gitlab.com/tango-controls/pytango/-/issues/492 - return (numpy.array([[filter_name, filter_name]] * MAX_ANTENNA).tolist(),) + return (numpy.array([[filter_name] * N_pol] * nr_antennas).tolist(),) def _apply_saps_subbands(self, sap_subbands: list): """Convert an array of subbands into the correct format for Beamlet device""" -- GitLab From a0e5fa213ed1dcd7e87e8c5f47c2a63c7296afd0 Mon Sep 17 00:00:00 2001 From: Jan David Mol <mol@astron.nl> Date: Fri, 4 Aug 2023 16:48:02 +0200 Subject: [PATCH 05/11] L2SS-1470: Fixed tests --- .../test/devices/test_antennafield_device.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tangostationcontrol/test/devices/test_antennafield_device.py b/tangostationcontrol/test/devices/test_antennafield_device.py index da91e7d26..840b47c6b 100644 --- a/tangostationcontrol/test/devices/test_antennafield_device.py +++ b/tangostationcontrol/test/devices/test_antennafield_device.py @@ -208,7 +208,7 @@ class TestAntennaToRecvMapper(base.TestCase): } mapper = AntennaToRecvMapper(recv_mapping, RECV_MAPPED_ATTRS, 3) receiver_values = [[0] * MAX_ANTENNA, [0] * MAX_ANTENNA, [0] * MAX_ANTENNA] - expected = [0] * DEFAULT_N_HBA_TILES + expected = [[0, 0]] * DEFAULT_N_HBA_TILES actual = mapper.map_read("RCU_band_select_RW", receiver_values) numpy.testing.assert_equal(expected, actual) @@ -712,7 +712,10 @@ class TestAntennaToRecvMapper(base.TestCase): mapper = AntennaToRecvMapper(recv_mapping, RECV_MAPPED_ATTRS, 1) set_values = [1, 0] + [None] * (DEFAULT_N_HBA_TILES - 2) - expected = [[[0, 1, None]] + [[None, None, None]] * (N_rcu - 1)] + expected = [ + [[[None, 0], [None, 1], [None, None]]] + + [[[None, None], [None, None], [None, None]]] * (N_rcu - 1) + ] actual = mapper.map_write("RCU_band_select_RW", set_values) numpy.testing.assert_equal(expected, actual) -- GitLab From e384dc62258103553dd18ef58d6c9fd63de14d4b Mon Sep 17 00:00:00 2001 From: Jan David Mol <mol@astron.nl> Date: Fri, 4 Aug 2023 16:49:45 +0200 Subject: [PATCH 06/11] Bump version --- README.md | 1 + tangostationcontrol/VERSION | 2 +- tangostationcontrol/test/devices/test_antennafield_device.py | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 5cfefc5ca..bf330a2d0 100644 --- a/README.md +++ b/README.md @@ -115,6 +115,7 @@ Next change the version in the following places: # Release Notes +* 0.20.5 Manage both polarisations in RCU_band_select_R(W), Antenna_Loss_R, and Frequency_Band_RW * 0.20.4 Collapse AbstractHierarchyDevice and AbstractHierarchy into one class * 0.20.3 Fix application of Field_Attenuation_R * 0.20.2 Support only one parent in hierarchies diff --git a/tangostationcontrol/VERSION b/tangostationcontrol/VERSION index 6dd46024a..1b619f348 100644 --- a/tangostationcontrol/VERSION +++ b/tangostationcontrol/VERSION @@ -1 +1 @@ -0.20.4 +0.20.5 diff --git a/tangostationcontrol/test/devices/test_antennafield_device.py b/tangostationcontrol/test/devices/test_antennafield_device.py index 840b47c6b..ea72b4091 100644 --- a/tangostationcontrol/test/devices/test_antennafield_device.py +++ b/tangostationcontrol/test/devices/test_antennafield_device.py @@ -711,7 +711,7 @@ class TestAntennaToRecvMapper(base.TestCase): } mapper = AntennaToRecvMapper(recv_mapping, RECV_MAPPED_ATTRS, 1) - set_values = [1, 0] + [None] * (DEFAULT_N_HBA_TILES - 2) + set_values = [[1, 1], [0, 0]] + [[None, None]] * (DEFAULT_N_HBA_TILES - 2) expected = [ [[[None, 0], [None, 1], [None, None]]] + [[[None, None], [None, None], [None, None]]] * (N_rcu - 1) -- GitLab From 93070f38b5095de21159b7c3aff551bc0e89059c Mon Sep 17 00:00:00 2001 From: Jan David Mol <mol@astron.nl> Date: Fri, 4 Aug 2023 17:07:32 +0200 Subject: [PATCH 07/11] L2SS-1470: Removed unnecessary flatten+reshape --- .../tangostationcontrol/common/calibration.py | 8 +++----- .../test/devices/test_antennafield_device.py | 5 +---- 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/tangostationcontrol/tangostationcontrol/common/calibration.py b/tangostationcontrol/tangostationcontrol/common/calibration.py index c0147b3a8..2bf56dd30 100644 --- a/tangostationcontrol/tangostationcontrol/common/calibration.py +++ b/tangostationcontrol/tangostationcontrol/common/calibration.py @@ -256,7 +256,7 @@ def calibrate_RCU_attenuator_dB(antenna_field: DeviceProxy): # ----------------------------------------------------------- # Correct for signal loss in the cables - signal_delay_loss = antenna_field.Antenna_Cables_Loss_R.flatten() + signal_delay_loss = antenna_field.Antenna_Cables_Loss_R # return coarse attenuation to apply (weakest signal # gets 0 attenuation). @@ -266,9 +266,7 @@ def calibrate_RCU_attenuator_dB(antenna_field: DeviceProxy): rcu_attenuator_db += antenna_field.Field_Attenuation_R # apply on antenna field - antenna_field.RCU_attenuator_dB_RW = rcu_attenuator_db.reshape( - antenna_field.nr_antennas_R, N_pol - ).astype(numpy.int64) + antenna_field.RCU_attenuator_dB_RW = rcu_attenuator_db.astype(numpy.int64) def loss_compensation(losses_dB: numpy.ndarray): @@ -295,7 +293,7 @@ def loss_compensation(losses_dB: numpy.ndarray): # correct for the coarse loss by dampening the signals to line up. input_attenuation_integer_dB = ( - max(signal_attenuation_integer_dB) - signal_attenuation_integer_dB + numpy.max(signal_attenuation_integer_dB) - signal_attenuation_integer_dB ) # compute the remainder, as a scaling factor diff --git a/tangostationcontrol/test/devices/test_antennafield_device.py b/tangostationcontrol/test/devices/test_antennafield_device.py index ea72b4091..12edfafef 100644 --- a/tangostationcontrol/test/devices/test_antennafield_device.py +++ b/tangostationcontrol/test/devices/test_antennafield_device.py @@ -712,10 +712,7 @@ class TestAntennaToRecvMapper(base.TestCase): mapper = AntennaToRecvMapper(recv_mapping, RECV_MAPPED_ATTRS, 1) set_values = [[1, 1], [0, 0]] + [[None, None]] * (DEFAULT_N_HBA_TILES - 2) - expected = [ - [[[None, 0], [None, 1], [None, None]]] - + [[[None, None], [None, None], [None, None]]] * (N_rcu - 1) - ] + expected = [[[0, 1, None]] + [[None, None, None]] * (N_rcu - 1)] actual = mapper.map_write("RCU_band_select_RW", set_values) numpy.testing.assert_equal(expected, actual) -- GitLab From aebce44f9407b96d48a0f754ab49fe0c2af45067 Mon Sep 17 00:00:00 2001 From: Jan David Mol <mol@astron.nl> Date: Fri, 4 Aug 2023 18:33:10 +0200 Subject: [PATCH 08/11] Try to fix setting the frequency bands --- .../tangostationcontrol/devices/observation.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/tangostationcontrol/tangostationcontrol/devices/observation.py b/tangostationcontrol/tangostationcontrol/devices/observation.py index 341302d50..af767e7cc 100644 --- a/tangostationcontrol/tangostationcontrol/devices/observation.py +++ b/tangostationcontrol/tangostationcontrol/devices/observation.py @@ -315,10 +315,7 @@ class Observation(LOFARDevice): """ nr_antennas = self.antennafield_proxy.nr_antennas_R - - # convert numpy.array(dtype=str) to list[str] to avoid crash in DeviceProxy - # see https://gitlab.com/tango-controls/pytango/-/issues/492 - return (numpy.array([[filter_name] * N_pol] * nr_antennas).tolist(),) + return (numpy.array([[filter_name] * N_pol] * nr_antennas),) def _apply_saps_subbands(self, sap_subbands: list): """Convert an array of subbands into the correct format for Beamlet device""" -- GitLab From cd68ea600a1cac1bee79b469ad99521f940382d8 Mon Sep 17 00:00:00 2001 From: Jan David Mol <mol@astron.nl> Date: Fri, 4 Aug 2023 19:37:52 +0200 Subject: [PATCH 09/11] Fix dimensions --- .../devices/test_device_antennafield.py | 13 ++++++++----- .../devices/antennafield.py | 19 +++++++------------ 2 files changed, 15 insertions(+), 17 deletions(-) diff --git a/tangostationcontrol/integration_test/default/devices/test_device_antennafield.py b/tangostationcontrol/integration_test/default/devices/test_device_antennafield.py index 6411150bb..43f75791b 100644 --- a/tangostationcontrol/integration_test/default/devices/test_device_antennafield.py +++ b/tangostationcontrol/integration_test/default/devices/test_device_antennafield.py @@ -317,7 +317,7 @@ class TestAntennaFieldDevice(AbstractTestBases.TestDeviceBase): try: antennafield_proxy.write_attribute( - "RCU_band_select_RW", [True] * MAX_ANTENNA + "RCU_band_select_RW", [[True, True]] * MAX_ANTENNA ) numpy.testing.assert_equal( numpy.array([[True] * N_rcu_inp] * N_rcu), @@ -339,8 +339,11 @@ class TestAntennaFieldDevice(AbstractTestBases.TestDeviceBase): for antenna_type in ["HBA"]: properties = { "Antenna_Type": [antenna_type], - "Control_to_RECV_mapping": [1, 1, 1, 0] + [-1, -1] * (CS001_TILES - 2), - "Antenna_to_SDP_Mapping": [0, 1, 0, 0] + [-1, -1] * (CS001_TILES - 2), + "Control_to_RECV_mapping": [1, 1] + + [-1, -1] * (CS001_TILES - 1), + "Power_to_RECV_mapping": [1, 0] + [-1, -1] * (CS001_TILES - 1), + "Antenna_to_SDP_Mapping": [0, 1, 0, 0] + + [-1, -1] * (CS001_TILES - 2), } antennafield_proxy = self.proxy @@ -356,7 +359,7 @@ class TestAntennaFieldDevice(AbstractTestBases.TestDeviceBase): self.sdp_proxy.write_attribute("nyquist_zone_RW", [[0] * S_pn] * N_pn) antennafield_proxy.write_attribute( - "Frequency_Band_RW", [band.name] * CS001_TILES + "Frequency_Band_RW", [[band.name, band.name]] * CS001_TILES ) # Wait for Tango attributes updating time.sleep(1) @@ -390,6 +393,6 @@ class TestAntennaFieldDevice(AbstractTestBases.TestDeviceBase): # test whether reading back results in the same band for our inputs numpy.testing.assert_equal( numpy.array([band.name, band.name]), - antennafield_proxy.read_attribute("Frequency_Band_RW").value[:2], + antennafield_proxy.read_attribute("Frequency_Band_RW").value[0], err_msg=f"{band.name}", ) diff --git a/tangostationcontrol/tangostationcontrol/devices/antennafield.py b/tangostationcontrol/tangostationcontrol/devices/antennafield.py index 3bfddc9fd..8d7396811 100644 --- a/tangostationcontrol/tangostationcontrol/devices/antennafield.py +++ b/tangostationcontrol/tangostationcontrol/devices/antennafield.py @@ -372,7 +372,7 @@ class AntennaField(LOFARDevice): Frequency_Band_RW = attribute( doc="The selected frequency band of each polarisation of each antenna.", - dtype=(str,), + dtype=((str,),), max_dim_x=N_pol, max_dim_y=MAX_ANTENNA, access=AttrWriteType.READ_WRITE, @@ -737,25 +737,20 @@ class AntennaField(LOFARDevice): ) if ( - bands[val].clock != bands[value[0]].clock - ): # NB: "value[0] in bands" holds at this point + bands[val].clock != bands[value[0, 0]].clock + ): # NB: "value[0,0] in bands" holds at this point raise ValueError( f"All frequency bands must use the same clock. \ These do not: {val} and {value[0, 0]}." ) # convert into settings for RECV - RCU_band_select_per_polarisation = numpy.vectorize( + self.proxy.RCU_band_select_RW = numpy.vectorize( lambda band: bands[band].rcu_band )(value) - # apply same setting for both polarisations on RECV - self.proxy.RCU_band_select_RW = numpy.dstack( - (RCU_band_select_per_polarisation, RCU_band_select_per_polarisation) - )[0] - # apply settings on SDP - self.sdpfirmware_proxy.clock_RW = bands[value[0]].clock + self.sdpfirmware_proxy.clock_RW = bands[value[0, 0]].clock # read-modify-write on [fpga][(input, polarisation)] sdp_nyquist_zone = numpy.full((N_pn, A_pn * N_pol), None) @@ -768,11 +763,11 @@ class AntennaField(LOFARDevice): # set for x polarisation sdp_nyquist_zone[fpga_nr, input_nr * 2 + 0] = bands[ - value[antenna_nr] + value[antenna_nr, 0] ].nyquist_zone # set for y polarisation sdp_nyquist_zone[fpga_nr, input_nr * 2 + 1] = bands[ - value[antenna_nr] + value[antenna_nr, 1] ].nyquist_zone self.atomic_read_modify_write_attribute( -- GitLab From d364d3bff7d377d103a3e4bda918a48183a4f689 Mon Sep 17 00:00:00 2001 From: Jan David Mol <mol@astron.nl> Date: Sun, 6 Aug 2023 14:33:17 +0200 Subject: [PATCH 10/11] Fixes --- .../devices/test_device_antennafield.py | 32 ++++++++++------- .../devices/test_device_observation.py | 11 +++--- .../tangostationcontrol/common/calibration.py | 35 +++++++++++-------- .../devices/antennafield.py | 2 +- .../test/common/test_calibration.py | 2 +- 5 files changed, 49 insertions(+), 33 deletions(-) diff --git a/tangostationcontrol/integration_test/default/devices/test_device_antennafield.py b/tangostationcontrol/integration_test/default/devices/test_device_antennafield.py index 43f75791b..bc4f4dada 100644 --- a/tangostationcontrol/integration_test/default/devices/test_device_antennafield.py +++ b/tangostationcontrol/integration_test/default/devices/test_device_antennafield.py @@ -29,7 +29,12 @@ class TestAntennaFieldDevice(AbstractTestBases.TestDeviceBase): super().setUp("STAT/AntennaField/HBA0") self.proxy.put_property( { - "Power_to_RECV_mapping": [1, 1, 1, 0] + [-1] * ((CS001_TILES * 2) - 4), + "Power_to_RECV_mapping": numpy.array( + [[1, x * 2 + 0] for x in range(MAX_ANTENNA // 2)] + ).flatten(), + "Control_to_RECV_mapping": numpy.array( + [[1, x * 2 + 1] for x in range(MAX_ANTENNA // 2)] + ).flatten(), } ) self.recv_proxy = self.setup_recv_proxy() @@ -300,10 +305,12 @@ class TestAntennaFieldDevice(AbstractTestBases.TestDeviceBase): """Verify small RECV device attribute changed all inputs mapped""" mapping_properties = { - "Power_to_RECV_mapping": [-1, -1] * CS001_TILES, - "Control_to_RECV_mapping": - # [1, 0, 1, 1, 1, 2, 1, x ... 1, 95] - numpy.array([[1, x] for x in range(0, MAX_ANTENNA)]).flatten(), + "Power_to_RECV_mapping": numpy.array( # X maps on power + [[1, x * 2 + 1] for x in range(MAX_ANTENNA // 2)] + ).flatten(), + "Control_to_RECV_mapping": numpy.array( # Y maps on control + [[1, x * 2 + 0] for x in range(MAX_ANTENNA // 2)] + ).flatten(), } antennafield_proxy = self.proxy @@ -311,22 +318,23 @@ class TestAntennaFieldDevice(AbstractTestBases.TestDeviceBase): antennafield_proxy.put_property(mapping_properties) antennafield_proxy.boot() - self.recv_proxy.write_attribute( - "RCU_band_select_RW", [[False] * N_rcu_inp] * N_rcu - ) + self.recv_proxy.write_attribute("RCU_band_select_RW", [[0] * N_rcu_inp] * N_rcu) try: antennafield_proxy.write_attribute( - "RCU_band_select_RW", [[True, True]] * MAX_ANTENNA + # [X, Y] + "RCU_band_select_RW", + [[1, 2]] * MAX_ANTENNA, ) numpy.testing.assert_equal( - numpy.array([[True] * N_rcu_inp] * N_rcu), - self.recv_proxy.read_attribute("RCU_band_select_RW").value, + # [Power, Control] + numpy.array([2, 1] * (MAX_ANTENNA // 2)), + self.recv_proxy.read_attribute("RCU_band_select_RW").value.flatten(), ) finally: # Always restore recv again self.recv_proxy.write_attribute( - "RCU_band_select_RW", [[False] * N_rcu_inp] * N_rcu + "RCU_band_select_RW", [[0] * N_rcu_inp] * N_rcu ) # Verify device did not enter FAULT state diff --git a/tangostationcontrol/integration_test/default/devices/test_device_observation.py b/tangostationcontrol/integration_test/default/devices/test_device_observation.py index f6b304da8..634b0f222 100644 --- a/tangostationcontrol/integration_test/default/devices/test_device_observation.py +++ b/tangostationcontrol/integration_test/default/devices/test_device_observation.py @@ -112,12 +112,14 @@ class TestDeviceObservation(AbstractTestBases.TestDeviceBase): def setup_antennafield_proxy(self): # setup AntennaField antennafield_proxy = TestDeviceProxy("STAT/AntennaField/HBA0") - control_mapping = [[1, i] for i in range(CS001_TILES)] + power_mapping = [[1, i * 2 + 0] for i in range(CS001_TILES)] + control_mapping = [[1, i * 2 + 1] for i in range(CS001_TILES)] antenna_qualities = numpy.array([AntennaQuality.OK] * MAX_ANTENNA) antenna_use = numpy.array([AntennaUse.AUTO] * MAX_ANTENNA) antennafield_proxy.put_property( { "Antenna_Type": ["HBA"], + "Power_to_RECV_mapping": numpy.array(power_mapping).flatten(), "Control_to_RECV_mapping": numpy.array(control_mapping).flatten(), "Antenna_to_SDP_Mapping": self.ANTENNA_TO_SDP_MAPPING, "Antenna_Quality": antenna_qualities, @@ -241,16 +243,17 @@ class TestDeviceObservation(AbstractTestBases.TestDeviceBase): self.setup_stationmanager_proxy() self.setup_recv_proxy() antennafield_proxy = self.setup_antennafield_proxy() - antennafield_proxy.RCU_band_select_RW = [0] * CS001_TILES + antennafield_proxy.RCU_band_select_RW = [[0, 0]] * CS001_TILES self.assertListEqual( - antennafield_proxy.RCU_band_select_RW.tolist(), [0] * CS001_TILES + antennafield_proxy.RCU_band_select_RW.tolist(), + [[0, 0]] * CS001_TILES, ) self.proxy.off() self.proxy.observation_settings_RW = self.VALID_JSON self.proxy.Initialise() self.proxy.On() expected_bands = [ - 2 + [2, 2] ] * CS001_TILES # we request every antenna to be in this band, regardless of mask self.assertListEqual( antennafield_proxy.RCU_band_select_RW.tolist(), expected_bands diff --git a/tangostationcontrol/tangostationcontrol/common/calibration.py b/tangostationcontrol/tangostationcontrol/common/calibration.py index 2bf56dd30..9cf13f644 100644 --- a/tangostationcontrol/tangostationcontrol/common/calibration.py +++ b/tangostationcontrol/tangostationcontrol/common/calibration.py @@ -120,13 +120,8 @@ class CalibrationManager: is_hba = antenna_type.upper() != "LBA" - for antenna_nr, rcu_band in enumerate(rcu_bands): - fpga_nr, input_nr = antenna_to_sdp_mapping[antenna_nr] - antenna_name = antenna_names[antenna_nr] - - if input_nr == -1: - # skip unconnected antennas - continue + def get_antenna_calibration(antenna_name: str, rcu_band: int): + """Return the calibration values for the given antenna and RCU band.""" calibration_filename = os.path.join( self._tmp_dir.name, @@ -143,19 +138,29 @@ class CalibrationManager: f"Expected calibration table for station {self._station_name}, but got {table.observation_station} in calibration file {calibration_filename}" ) - if antenna_name not in table.antennas: + try: + return table.antennas[antenna_name] + except KeyError: raise ValueError( f"Could not find calibration values for field {antennafield_name} antenna {antenna_name} (index {antenna_nr}) in calibration file {calibration_filename}" ) - # set weights, converted from complex to packed uint32 - fpga_subband_weights[fpga_nr, input_nr, 0] = complex_to_weights( - table.antennas[antenna_name].x - ) + for antenna_nr, (rcu_band_x, rcu_band_y) in enumerate(rcu_bands): + fpga_nr, input_nr = antenna_to_sdp_mapping[antenna_nr] + antenna_name = antenna_names[antenna_nr] - fpga_subband_weights[fpga_nr, input_nr, 1] = complex_to_weights( - table.antennas[antenna_name].y - ) + if input_nr == -1: + # skip unconnected antennas + continue + + # set weights, converted from complex to packed uint32 + fpga_subband_weights[fpga_nr, input_nr, 0] = complex_to_weights( + get_antenna_calibration(antenna_name, rcu_band_x).x + ) + + fpga_subband_weights[fpga_nr, input_nr, 1] = complex_to_weights( + get_antenna_calibration(antenna_name, rcu_band_y).y + ) # TODO(L2SS-1312): This should use atomic_read_modify_write sdp.FPGA_subband_weights_RW = fpga_subband_weights.reshape( diff --git a/tangostationcontrol/tangostationcontrol/devices/antennafield.py b/tangostationcontrol/tangostationcontrol/devices/antennafield.py index 8d7396811..3477e4787 100644 --- a/tangostationcontrol/tangostationcontrol/devices/antennafield.py +++ b/tangostationcontrol/tangostationcontrol/devices/antennafield.py @@ -395,7 +395,7 @@ class AntennaField(LOFARDevice): ) Antenna_Cables_Loss_R = attribute( doc="Loss caused by the cable between antenna and RCU, in dB, for either polarisation.", - dtype=(numpy.float64,), + dtype=((numpy.float64,),), max_dim_x=N_pol, max_dim_y=MAX_ANTENNA, unit="dB", diff --git a/tangostationcontrol/test/common/test_calibration.py b/tangostationcontrol/test/common/test_calibration.py index 159c088f7..40cb48f5f 100644 --- a/tangostationcontrol/test/common/test_calibration.py +++ b/tangostationcontrol/test/common/test_calibration.py @@ -74,7 +74,7 @@ class TestCalibrationManager(base.TestCase): ).reshape(-1, 2), Antenna_Names_R=[f"T{n + 1}" for n in range(2)], Antenna_Type_R="HBA", - RCU_band_select_RW=numpy.array([1, 2]), + RCU_band_select_RW=numpy.array([[1, 1], [2, 2]]), **{"name.return_value": "Stat/AntennaField/TEST"}, ) subband_weights = numpy.array([[SDP_UNIT_WEIGHT] * S_pn * N_subbands] * N_pn) -- GitLab From d5087d47a0b6ed400931f4bd8f55bef4a5d14bf9 Mon Sep 17 00:00:00 2001 From: Jan David Mol <mol@astron.nl> Date: Mon, 7 Aug 2023 13:49:41 +0200 Subject: [PATCH 11/11] Fix black --- .../default/devices/test_device_antennafield.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/tangostationcontrol/integration_test/default/devices/test_device_antennafield.py b/tangostationcontrol/integration_test/default/devices/test_device_antennafield.py index bc4f4dada..d79c50d30 100644 --- a/tangostationcontrol/integration_test/default/devices/test_device_antennafield.py +++ b/tangostationcontrol/integration_test/default/devices/test_device_antennafield.py @@ -347,11 +347,9 @@ class TestAntennaFieldDevice(AbstractTestBases.TestDeviceBase): for antenna_type in ["HBA"]: properties = { "Antenna_Type": [antenna_type], - "Control_to_RECV_mapping": [1, 1] - + [-1, -1] * (CS001_TILES - 1), + "Control_to_RECV_mapping": [1, 1] + [-1, -1] * (CS001_TILES - 1), "Power_to_RECV_mapping": [1, 0] + [-1, -1] * (CS001_TILES - 1), - "Antenna_to_SDP_Mapping": [0, 1, 0, 0] - + [-1, -1] * (CS001_TILES - 2), + "Antenna_to_SDP_Mapping": [0, 1, 0, 0] + [-1, -1] * (CS001_TILES - 2), } antennafield_proxy = self.proxy -- GitLab