Skip to content
Snippets Groups Projects
Commit f158e5fa authored by Jan David Mol's avatar Jan David Mol
Browse files

L2SS-601: Allow enabling/disabling of beam tracking to allow explicit testing...

L2SS-601: Allow enabling/disabling of beam tracking to allow explicit testing of setting the pointing without the beam tracker overriding us
parent 97bcd435
No related branches found
No related tags found
No related merge requests found
...@@ -67,6 +67,14 @@ class Beam(lofar_device): ...@@ -67,6 +67,14 @@ class Beam(lofar_device):
dtype=(numpy.double,), max_dim_x=96, dtype=(numpy.double,), max_dim_x=96,
fget=lambda self: self._hbat_pointing_timestamp_r) fget=lambda self: self._hbat_pointing_timestamp_r)
HBAT_tracking_enabled_R = attribute(access=AttrWriteType.READ,
dtype=numpy.bool,
fget=lambda self: self.HBAT_beam_tracker.is_alive())
HBAT_tracking_enabled_RW = attribute(access=AttrWriteType.READ_WRITE,
dtype=numpy.bool,
fget=lambda self: self._hbat_tracking_enabled_rw)
# Directory where the casacore measures that we use, reside. We configure ~/.casarc to # Directory where the casacore measures that we use, reside. We configure ~/.casarc to
# use the symlink /opt/IERS/current, which we switch to the actual set of files to use. # use the symlink /opt/IERS/current, which we switch to the actual set of files to use.
measures_directory_R = attribute(dtype=str, access=AttrWriteType.READ, fget = lambda self: get_measures_directory()) measures_directory_R = attribute(dtype=str, access=AttrWriteType.READ, fget = lambda self: get_measures_directory())
...@@ -86,6 +94,9 @@ class Beam(lofar_device): ...@@ -86,6 +94,9 @@ class Beam(lofar_device):
self._hbat_pointing_direction_r = numpy.zeros((96,3), dtype="<U32") self._hbat_pointing_direction_r = numpy.zeros((96,3), dtype="<U32")
self._hbat_pointing_direction_rw = numpy.array([["AZELGEO","0deg","90deg"]] * 96, dtype="<U32") self._hbat_pointing_direction_rw = numpy.array([["AZELGEO","0deg","90deg"]] * 96, dtype="<U32")
# Initialise tracking control
self._hbat_tracking_enabled_rw = True
# Set a reference of RECV device # Set a reference of RECV device
self.recv_proxy = DeviceProxy("STAT/RECV/1") self.recv_proxy = DeviceProxy("STAT/RECV/1")
...@@ -107,15 +118,15 @@ class Beam(lofar_device): ...@@ -107,15 +118,15 @@ class Beam(lofar_device):
super().configure_for_on() super().configure_for_on()
# Start beam tracking thread # Start beam tracking thread
if self._hbat_tracking_enabled_rw:
self.HBAT_beam_tracker.start() self.HBAT_beam_tracker.start()
@log_exceptions @log_exceptions
def configure_for_off(self): def configure_for_off(self):
super().configure_for_off()
# Stop thread object # Stop thread object
self.HBAT_beam_tracker.stop() self.HBAT_beam_tracker.stop()
self.HBAT_beam_tracker = None
super().configure_for_off()
# -------- # --------
# internal functions # internal functions
...@@ -132,6 +143,15 @@ class Beam(lofar_device): ...@@ -132,6 +143,15 @@ class Beam(lofar_device):
# force update across tiles if pointing changes # force update across tiles if pointing changes
self.HBAT_beam_tracker.force_update() self.HBAT_beam_tracker.force_update()
logger.info("Pointing direction update requested")
def write_HBAT_tracking_enabled_RW(self, value):
self._hbat_tracking_enabled_rw = value
if value:
self.HBAT_beam_tracker.start()
else:
self.HBAT_beam_tracker.stop()
def _HBAT_delays(self, pointing_direction: numpy.array, timestamp: datetime.datetime = datetime.datetime.now()): def _HBAT_delays(self, pointing_direction: numpy.array, timestamp: datetime.datetime = datetime.datetime.now()):
""" """
...@@ -225,6 +245,7 @@ class Beam(lofar_device): ...@@ -225,6 +245,7 @@ class Beam(lofar_device):
@command(dtype_in=DevVarStringArray) @command(dtype_in=DevVarStringArray)
@DebugIt() @DebugIt()
@log_exceptions()
@only_in_states([DevState.ON]) @only_in_states([DevState.ON])
def HBAT_set_pointing(self, pointing_direction: list, timestamp: datetime.datetime = datetime.datetime.now()): def HBAT_set_pointing(self, pointing_direction: list, timestamp: datetime.datetime = datetime.datetime.now()):
""" """
...@@ -275,7 +296,7 @@ class BeamTracker(): ...@@ -275,7 +296,7 @@ class BeamTracker():
""" Object that encapsulates a Thread, resposible for beam tracking operations """ """ Object that encapsulates a Thread, resposible for beam tracking operations """
def __init__(self, device: lofar_device): def __init__(self, device: lofar_device):
self.thread = Thread(target=self._update_HBAT_pointing_direction) self.thread = None
self.device = device self.device = device
# Condition to trigger a forced update or early abort # Condition to trigger a forced update or early abort
...@@ -284,12 +305,17 @@ class BeamTracker(): ...@@ -284,12 +305,17 @@ class BeamTracker():
def start(self): def start(self):
""" Starts the Beam Tracking thread """ """ Starts the Beam Tracking thread """
if self.thread:
# already started
return
self.done = False self.done = False
self.thread = Thread(target=self._update_HBAT_pointing_direction, name=f"BeamTracker of {self.device.get_name()}")
self.thread.start() self.thread.start()
def is_alive(self): def is_alive(self):
""" Returns True just before the Thread run() method starts until just after the Thread run() method terminates. """ """ Returns True just before the Thread run() method starts until just after the Thread run() method terminates. """
return self.thread.is_alive() return self.thread and self.thread.is_alive()
def force_update(self): def force_update(self):
""" Force the pointing to be updated. """ """ Force the pointing to be updated. """
...@@ -301,6 +327,9 @@ class BeamTracker(): ...@@ -301,6 +327,9 @@ class BeamTracker():
def stop(self): def stop(self):
""" Stops the Beam Tracking loop """ """ Stops the Beam Tracking loop """
if not self.thread:
return
self.done = True self.done = True
self.force_update() self.force_update()
...@@ -310,6 +339,8 @@ class BeamTracker(): ...@@ -310,6 +339,8 @@ class BeamTracker():
if self.is_alive(): if self.is_alive():
logger.error("BeamTracking Thread did not properly terminate") logger.error("BeamTracking Thread did not properly terminate")
self.thread = None
def _get_sleep_time(self): def _get_sleep_time(self):
""" Computes the sleep time (in seconds) that needs to be waited for the next beam tracking update """ """ Computes the sleep time (in seconds) that needs to be waited for the next beam tracking update """
now = datetime.datetime.now().timestamp() now = datetime.datetime.now().timestamp()
...@@ -325,12 +356,14 @@ class BeamTracker(): ...@@ -325,12 +356,14 @@ class BeamTracker():
else: else:
return sleep_time return sleep_time
@log_exceptions()
def _update_HBAT_pointing_direction(self): def _update_HBAT_pointing_direction(self):
""" Updates the beam weights using a fixed interval of time """ """ Updates the beam weights using a fixed interval of time """
# Check if flag beamtracking is true # Check if flag beamtracking is true
with self.update_lock: with self.update_lock:
while not self.done: while not self.done:
# TODO: Occasionally this still gets called when the beam device is in OFF?
self.device.HBAT_set_pointing(numpy.array(self.device.proxy.HBAT_pointing_direction_RW).flatten()) self.device.HBAT_set_pointing(numpy.array(self.device.proxy.HBAT_pointing_direction_RW).flatten())
# sleep until the next update, or when interrupted (this releases the lock, allowing for notification) # sleep until the next update, or when interrupted (this releases the lock, allowing for notification)
......
...@@ -68,6 +68,7 @@ class TestDeviceBeam(AbstractTestBases.TestDeviceBase): ...@@ -68,6 +68,7 @@ class TestDeviceBeam(AbstractTestBases.TestDeviceBase):
self.proxy.Initialise() self.proxy.Initialise()
self.assertEqual(DevState.STANDBY, self.proxy.state()) self.assertEqual(DevState.STANDBY, self.proxy.state())
self.proxy.set_defaults() self.proxy.set_defaults()
self.proxy.HBAT_tracking_enabled_RW = False
self.proxy.on() self.proxy.on()
self.assertEqual(DevState.ON, self.proxy.state()) self.assertEqual(DevState.ON, self.proxy.state())
...@@ -90,6 +91,7 @@ class TestDeviceBeam(AbstractTestBases.TestDeviceBase): ...@@ -90,6 +91,7 @@ class TestDeviceBeam(AbstractTestBases.TestDeviceBase):
recv_proxy = self.setup_recv_proxy() recv_proxy = self.setup_recv_proxy()
self.proxy.initialise() self.proxy.initialise()
self.proxy.HBAT_tracking_enabled_RW = False
self.proxy.on() self.proxy.on()
# Point to Zenith # Point to Zenith
...@@ -101,11 +103,40 @@ class TestDeviceBeam(AbstractTestBases.TestDeviceBase): ...@@ -101,11 +103,40 @@ class TestDeviceBeam(AbstractTestBases.TestDeviceBase):
numpy.testing.assert_equal(calculated_HBAT_delay_steps, expected_HBAT_delay_steps) numpy.testing.assert_equal(calculated_HBAT_delay_steps, expected_HBAT_delay_steps)
def test_pointing_across_horizon(self):
# setup RECV as well
recv_proxy = self.setup_recv_proxy()
self.proxy.initialise()
self.proxy.HBAT_tracking_enabled_RW = False
self.proxy.on()
# point at north on the horizon
self.proxy.HBAT_set_pointing(["AZELGEO","0deg","0deg"] * 96)
# obtain delays of the X polarisation of all the elements of the first tile
north_beam_delay_steps = recv_proxy.HBAT_BF_delay_steps_RW[0].reshape(2,4,4)[0]
# delays must differ under rotation, or our test will give a false positive
self.assertNotEqual(north_beam_delay_steps.tolist(), numpy.rot90(north_beam_delay_steps).tolist())
for angle in (90,180,270):
# point at angle degrees (90=E, 180=S, 270=W)
self.proxy.HBAT_set_pointing(["AZELGEO",f"{angle}deg","0deg"] * 96)
# obtain delays of the X polarisation of all the elements of the first tile
angled_beam_delay_steps = recv_proxy.HBAT_BF_delay_steps_RW[0].reshape(2,4,4)[0]
expected_delay_steps = numpy.rot90(north_beam_delay_steps, k=-(angle/90))
self.assertListEqual(expected_delay_steps.tolist(), angled_beam_delay_steps.tolist(), msg=f"angle={angle}")
def test_delays_same_as_LOFAR_ref_pointing(self): def test_delays_same_as_LOFAR_ref_pointing(self):
# setup RECV as well # setup RECV as well
recv_proxy = self.setup_recv_proxy() recv_proxy = self.setup_recv_proxy()
self.proxy.initialise() self.proxy.initialise()
self.proxy.HBAT_tracking_enabled_RW = False
self.proxy.on() self.proxy.on()
# Point to LOFAR 1 ref pointing (0.929342, 0.952579, J2000) # Point to LOFAR 1 ref pointing (0.929342, 0.952579, J2000)
...@@ -131,3 +162,24 @@ class TestDeviceBeam(AbstractTestBases.TestDeviceBase): ...@@ -131,3 +162,24 @@ class TestDeviceBeam(AbstractTestBases.TestDeviceBase):
expected_HBAT_delay_steps = numpy.array([24, 25, 27, 29, 17, 18, 20, 21, 10, 11, 13, 14, 3, 4, 5, 7] * 2, dtype=numpy.int64) expected_HBAT_delay_steps = numpy.array([24, 25, 27, 29, 17, 18, 20, 21, 10, 11, 13, 14, 3, 4, 5, 7] * 2, dtype=numpy.int64)
numpy.testing.assert_equal(calculated_HBAT_delay_steps[0], expected_HBAT_delay_steps) numpy.testing.assert_equal(calculated_HBAT_delay_steps[0], expected_HBAT_delay_steps)
numpy.testing.assert_equal(calculated_HBAT_delay_steps[48], expected_HBAT_delay_steps) numpy.testing.assert_equal(calculated_HBAT_delay_steps[48], expected_HBAT_delay_steps)
def test_beam_tracking(self):
# setup RECV as well
recv_proxy = self.setup_recv_proxy()
self.proxy.initialise()
self.proxy.on()
# check if we're really tracking
self.assertTrue(self.proxy.HBAT_tracking_enabled_R)
# point somewhere
new_pointings = [("J2000",f"{tile}deg","0deg") for tile in range(96)]
self.proxy.HBAT_pointing_direction_RW = new_pointings
# wait for tracking thread to pick up and set. should be almost instant
time.sleep(0.5)
# check pointing
self.assertListEqual(new_pointings, list(self.proxy.HBAT_pointing_direction_R))
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment