From c954c1ea52e848c788d88acb9272ac952f6f2f53 Mon Sep 17 00:00:00 2001
From: Jan David Mol <mol@astron.nl>
Date: Fri, 7 Oct 2022 10:42:13 +0200
Subject: [PATCH] L2SS-1006: Move Antenna_Type as a property of AntennaField
 instead of SDP

---
 CDB/stations/DTS_ConfigDb.json                |  3 +
 CDB/stations/DTS_Outside_ConfigDb.json        |  9 ++-
 .../devices/antennafield.py                   | 43 ++++++++++--
 .../devices/sdp/beamlet.py                    | 14 ++--
 .../tangostationcontrol/devices/sdp/sdp.py    | 68 ++++++++++++-------
 .../devices/test_device_antennafield.py       | 14 ++++
 .../default/devices/test_device_beamlet.py    |  7 +-
 .../devices/test_device_digitalbeam.py        |  8 +--
 .../devices/test_device_observation.py        |  2 +-
 .../recv_cluster/test_recv_cluster.py         |  8 +++
 .../test/devices/test_beamlet_device.py       | 19 +++---
 11 files changed, 144 insertions(+), 51 deletions(-)

diff --git a/CDB/stations/DTS_ConfigDb.json b/CDB/stations/DTS_ConfigDb.json
index 65e87c4f5..f2c36a66f 100644
--- a/CDB/stations/DTS_ConfigDb.json
+++ b/CDB/stations/DTS_ConfigDb.json
@@ -147,6 +147,9 @@
                 "AntennaField": {
                     "STAT/AntennaField/1": {
                         "properties": {
+                            "Antenna_Type": [
+                                "HBA"
+                            ],
                             "RECV_devices": [
                                 "STAT/RECV/1"
                             ],
diff --git a/CDB/stations/DTS_Outside_ConfigDb.json b/CDB/stations/DTS_Outside_ConfigDb.json
index 485fd4388..ce52a70b9 100644
--- a/CDB/stations/DTS_Outside_ConfigDb.json
+++ b/CDB/stations/DTS_Outside_ConfigDb.json
@@ -172,6 +172,9 @@
                 "AntennaField": {
                     "STAT/AntennaField/2": {
                         "properties": {
+                            "Antenna_Type": [
+                                "HBA"
+                            ],
                             "RECV_devices": [
                                 "STAT/RECV/1"
                             ],
@@ -229,6 +232,9 @@
                     },
                     "STAT/AntennaField/1": {
                         "properties": {
+                            "Antenna_Type": [
+                                "LBA"
+                            ],
                             "RECV_devices": [
                                 "STAT/RECV/1"
                             ],
@@ -344,9 +350,6 @@
                 "SDP": {
                     "STAT/SDP/1": {
                         "properties": {
-                            "AntennaType": [
-                                "LBA"
-                            ],
                             "OPC_Server_Name": [
                                 "10.99.0.250"
                             ],
diff --git a/tangostationcontrol/tangostationcontrol/devices/antennafield.py b/tangostationcontrol/tangostationcontrol/devices/antennafield.py
index 72f1993fe..8cb16b7fd 100644
--- a/tangostationcontrol/tangostationcontrol/devices/antennafield.py
+++ b/tangostationcontrol/tangostationcontrol/devices/antennafield.py
@@ -121,6 +121,13 @@ class AntennaField(lofar_device):
 
     # ----- Antenna properties
 
+    Antenna_Type = device_property(
+        doc="Type of antenna in this field (LBA or HBA)",
+        dtype='DevString',
+        mandatory=False,
+        default_value = "LBA"
+    )
+
     Antenna_Needs_Power = device_property(
         doc="Whether to provide power to each antenna (False for noise sources)",
         dtype='DevVarBooleanArray',
@@ -229,6 +236,9 @@ class AntennaField(lofar_device):
         default_value=[]
     )
 
+    Antenna_Type_R = attribute(doc='The type of antenna in this field (LBA or HBA).',
+        dtype=str)
+
     Antenna_Names_R = attribute(access=AttrWriteType.READ,
                                 dtype=(str,), max_dim_x=MAX_NUMBER_OF_HBAT)
     Antenna_Quality_R = attribute(doc='The quality of each antenna. 0=OK, 1=SUSPICIOUS, 2=BROKEN, 3=BEYOND_REPAIR.',
@@ -308,6 +318,9 @@ class AntennaField(lofar_device):
         doc='Number of Antennas in this field',
         dtype=numpy.int32)
 
+    def read_Antenna_Type_R(self):
+        return self.Antenna_Type
+
     def read_Antenna_Names_R(self):
         return self.Antenna_Names
 
@@ -468,7 +481,16 @@ class AntennaField(lofar_device):
 
     @log_exceptions()
     def _prepare_hardware(self):
-        usage_mask = self.read_attribute('Antenna_Usage_Mask_R')
+        # Configure the devices that process our antennas
+        self.configure_recv()
+        self.configure_sdp()
+
+    # --------
+    # Commands
+    # --------
+    @command()
+    def configure_recv(self):
+        """ Configure RECV to process our antennas. """
 
         # Disable controlling the tiles that fall outside the mask
         # WARN: Needed in configure_for_initialise but Tango does not allow to write attributes in INIT state
@@ -477,9 +499,22 @@ class AntennaField(lofar_device):
         # Turn on power to antennas that need it (and due to the ANT_mask, that we're using)
         self.proxy.write_attribute('RCU_PWR_ANT_on_RW', self.Antenna_Needs_Power)
 
-    # --------
-    # Commands
-    # --------
+    @command()
+    def configure_sdp(self):
+        """ Configure SDP to process our antennas. """
+
+        # Upload which antenna type we're using
+
+        # read-modify-write on [fpga][(input, polarisation)]
+        sdp_antenna_type = numpy.array(self.sdp_proxy.antenna_type_RW, dtype=object)
+        for fpga_nr, input_nr in self.read_attribute("Antenna_to_SDP_Mapping_R"):
+            # set for x polarisation
+            sdp_antenna_type[fpga_nr, input_nr * 2 + 0] = self.Antenna_Type
+            # set for y polarisation
+            sdp_antenna_type[fpga_nr, input_nr * 2 + 1] = self.Antenna_Type
+
+        self.sdp_proxy.antenna_type_RW = tuple(sdp_antenna_type)
+
     @command(dtype_in=DevVarFloatArray, dtype_out=DevVarLongArray)
     def calculate_HBAT_bf_delay_steps(self, delays: numpy.ndarray):
         num_tiles = self.read_nr_antennas_R()
diff --git a/tangostationcontrol/tangostationcontrol/devices/sdp/beamlet.py b/tangostationcontrol/tangostationcontrol/devices/sdp/beamlet.py
index e09ca0968..44532e9c4 100644
--- a/tangostationcontrol/tangostationcontrol/devices/sdp/beamlet.py
+++ b/tangostationcontrol/tangostationcontrol/devices/sdp/beamlet.py
@@ -318,14 +318,14 @@ class Beamlet(opcua_device):
         return bf_weights.reshape(orig_shape)
 
     @staticmethod
-    def _subband_frequencies(subbands: numpy.ndarray, clock: int, nyquist_zone: int) -> numpy.ndarray:
+    def _subband_frequencies(subbands: numpy.ndarray, clock: int, nyquist_zones: numpy.ndarray) -> numpy.ndarray:
         """ Obtain the frequencies of each subband, given a clock and an antenna type. """
 
         subband_width = clock / 1024
-        base_subband  = nyquist_zone * 512
+        base_subbands = nyquist_zones * 512
 
         # broadcast clock across frequencies
-        frequencies = (subbands + base_subband) * subband_width
+        frequencies = (subbands + base_subbands) * subband_width
 
         return frequencies
 
@@ -338,7 +338,13 @@ class Beamlet(opcua_device):
 
         # obtain which subband is selected for each input and beamlet
         beamlet_subbands = self.read_attribute("FPGA_beamlet_subband_select_RW") # (fpga_nr, [input_nr][pol][beamlet_nr])
-        return self._subband_frequencies(beamlet_subbands, self.sdp_proxy.clock_RW, self.sdp_proxy.nyquist_zone_R)
+        nyquist_zones    = self.sdp_proxy.nyquist_zone_R # (fpga_nr, [input_nr][pol])
+
+        # repeat nyquist zone for all beamlets, to match the shape of beamlet_subbands
+        nyquist_zones    = numpy.repeat(nyquist_zones, self.N_BEAMLETS_CTRL, axis=1)
+
+        # compute the frequency of each beamlet for each input
+        return self._subband_frequencies(beamlet_subbands, self.sdp_proxy.clock_RW, nyquist_zones)
 
     @staticmethod
     def _calculate_bf_weights(delays: numpy.ndarray, beamlet_frequencies: numpy.ndarray):
diff --git a/tangostationcontrol/tangostationcontrol/devices/sdp/sdp.py b/tangostationcontrol/tangostationcontrol/devices/sdp/sdp.py
index 88191f1cc..64d6b9461 100644
--- a/tangostationcontrol/tangostationcontrol/devices/sdp/sdp.py
+++ b/tangostationcontrol/tangostationcontrol/devices/sdp/sdp.py
@@ -32,13 +32,6 @@ class SDP(opcua_device):
     # Device Properties
     # -----------------
 
-    AntennaType = device_property(
-        doc='Antenna type (LBA or HBA) we control',
-        dtype='DevString',
-        mandatory=False,
-        default_value = "HBA"
-    )
-
     TR_fpga_mask_RW_default = device_property(
         dtype='DevVarBooleanArray',
         mandatory=False,
@@ -186,15 +179,36 @@ class SDP(opcua_device):
 
     FPGA_bst_offload_bsn_R = attribute_wrapper(comms_annotation=["FPGA_bst_offload_bsn_R"], datatype=numpy.int64, dims=(N_pn, N_beamsets_ctrl))
 
-    antenna_type_R = attribute(doc='Type of antenna (LBA or HBA) attached to the FPGAs',
-                               dtype=str, fget=lambda self: self.AntennaType)
-    nyquist_zone_R = attribute(doc='Nyquist zone of the input frequencies',
-                               dtype=numpy.uint32, fisallowed="is_attribute_access_allowed",
+    antenna_type_RW = attribute(doc='Type of antenna (LBA or HBA) attached to each input of the FPGAs',
+                                 dtype=((str,),), max_dim_y=N_pn, max_dim_x=S_pn,
+                                 access=AttrWriteType.READ_WRITE, fisallowed="is_attribute_access_allowed")
+    nyquist_zone_R = attribute(doc='Nyquist zone of each input.',
+                               dtype=((numpy.uint32,),), max_dim_y=N_pn, max_dim_x=S_pn,
+                               fisallowed="is_attribute_access_allowed",
                                polling_period=1000, abs_change=1)
     clock_RW = attribute(doc='Configured sampling clock (Hz)',
                          dtype=numpy.uint32, access=AttrWriteType.READ_WRITE, fisallowed="is_attribute_access_allowed",
                          polling_period=1000, abs_change=1)
 
+    def read_antenna_type_RW(self):
+        return self._antenna_type
+
+    def write_antenna_type_RW(self, value):
+        # use numpy for easy processing
+        value = numpy.array(value)
+
+        # validate shape
+        if value.shape != (self.N_pn, self.S_pn):
+            raise ValueError(f"Dimension mismatch. Expected ({self.N_pn}, {self.S_pn}), got {value.shape}.")
+
+        # validate content
+        for val in value.flatten():
+            if val not in ["LBA", "HBA"]:
+                raise ValueError(f"Unsupported antenna type: {val}. Must be one of [LBA, HBA].")
+
+        # adopt new value
+        self._antenna_type = value
+
     def _nyquist_zone(self, clock):
         """ Return the Nyquist zone for the given clock (in Hz).
 
@@ -203,7 +217,7 @@ class SDP(opcua_device):
 
             NOTE: Only 160 and 200 MHz clocks are supported. """
 
-        # (AntennaType, clockMHz) -> Nyquist zone
+        # (antenna type, clockMHz) -> Nyquist zone
         nyquist_zones = {
            ("LBA", 160): 0,
            ("LBA", 200): 0,
@@ -211,17 +225,17 @@ class SDP(opcua_device):
            ("HBA", 200): 2,
         }
 
-        try:
-            return nyquist_zones[(self.AntennaType), clock // 1000000]
-        except KeyError:
-            raise ValueError(f"Could not determine Nyquist zone for antenna type {self.AntennaType} with clock {clock} Hz")
+        def antenna_type_to_nyquist_zone(antenna_type):
+            try:
+                return nyquist_zones[(antenna_type, clock // 1_000_000)]
+            except KeyError:
+                # sane default
+                return 0
+
+        return numpy.vectorize(antenna_type_to_nyquist_zone)(self._antenna_type)
 
     def read_nyquist_zone_R(self):
-        try:
-            return self._nyquist_zone(self.read_attribute("clock_RW"))
-        except ValueError:
-            # Supply a sane default for computations in tests until L2SDP-725 allows us to read back the set clock
-            return 0
+        return self._nyquist_zone(self.read_attribute("clock_RW"))
 
     def read_clock_RW(self):
         # We can only return a single value, so we assume the FPGA is configured coherently. Which is something
@@ -240,8 +254,8 @@ class SDP(opcua_device):
         # Tell all FPGAs to use this clock
         self.proxy.FPGA_pps_expected_cnt_RW = [clock] * self.N_pn
 
-        # Also update the packet headers
-        self.proxy.FPGA_sdp_info_nyquist_sampling_zone_index_RW = [self._nyquist_zone(clock)] * self.N_pn
+        # Also update the packet headers. We assume the first Nyquist zone of each FPGA is representative
+        self.proxy.FPGA_sdp_info_nyquist_sampling_zone_index_RW = self._nyquist_zone(clock)[:,0]
 
     # ----------
     # Summarising Attributes
@@ -274,6 +288,14 @@ class SDP(opcua_device):
     # overloaded functions
     # --------
 
+    def configure_for_initialise(self):
+        super().configure_for_initialise()
+
+        # Store which type of antenna is connected to each input.
+        #
+        # We need to be told this by AntennaField, through configure_for_antennafield.
+        self._antenna_type = numpy.array([["LBA"] * self.S_pn] * self.N_pn, dtype=str)
+
     def _prepare_hardware(self):
         # FPGAs that are actually reachable and we care about
         wait_for = ~(self.read_attribute("TR_fpga_communication_error_R")) & self.read_attribute("TR_fpga_mask_R")
diff --git a/tangostationcontrol/tangostationcontrol/integration_test/default/devices/test_device_antennafield.py b/tangostationcontrol/tangostationcontrol/integration_test/default/devices/test_device_antennafield.py
index d8e72fc1f..24e2c1191 100644
--- a/tangostationcontrol/tangostationcontrol/integration_test/default/devices/test_device_antennafield.py
+++ b/tangostationcontrol/tangostationcontrol/integration_test/default/devices/test_device_antennafield.py
@@ -24,9 +24,11 @@ class TestAntennaFieldDevice(AbstractTestBases.TestDeviceBase):
             "Power_to_RECV_mapping": [1, 1, 1, 0] + [-1] * 92
         })
         self.recv_proxy = self.setup_recv_proxy()
+        self.sdp_proxy = self.setup_sdp_proxy()
 
         self.addCleanup(self.restore_antennafield)
         self.addCleanup(self.shutdown_recv)
+        self.addCleanup(self.shutdown_sdp)
 
     def restore_antennafield(self):
         self.proxy.put_property({
@@ -40,6 +42,11 @@ class TestAntennaFieldDevice(AbstractTestBases.TestDeviceBase):
         recv_proxy = TestDeviceProxy("STAT/RECV/1")
         recv_proxy.off()
 
+    @staticmethod
+    def shutdown_sdp():
+        sdp_proxy = TestDeviceProxy("STAT/SDP/1")
+        sdp_proxy.off()
+
     def setup_recv_proxy(self):
         # setup RECV
         recv_proxy = TestDeviceProxy("STAT/RECV/1")
@@ -48,6 +55,13 @@ class TestAntennaFieldDevice(AbstractTestBases.TestDeviceBase):
         recv_proxy.set_defaults()
         return recv_proxy
 
+    def setup_sdp_proxy(self):
+        # setup SDP
+        sdp_proxy = TestDeviceProxy("STAT/SDP/1")
+        sdp_proxy.off()
+        sdp_proxy.warm_boot()
+        return sdp_proxy
+
     def test_property_recv_devices_has_one_receiver(self):
         result = self.proxy.get_property("RECV_devices")
         self.assertSequenceEqual(result["RECV_devices"], ["STAT/RECV/1"])
diff --git a/tangostationcontrol/tangostationcontrol/integration_test/default/devices/test_device_beamlet.py b/tangostationcontrol/tangostationcontrol/integration_test/default/devices/test_device_beamlet.py
index 108491bca..6aa67918d 100644
--- a/tangostationcontrol/tangostationcontrol/integration_test/default/devices/test_device_beamlet.py
+++ b/tangostationcontrol/tangostationcontrol/integration_test/default/devices/test_device_beamlet.py
@@ -30,12 +30,17 @@ class TestDeviceBeamlet(AbstractTestBases.TestDeviceBase):
 
         super().test_device_read_all_attributes()
 
-    def setup_sdp(self):
+    def setup_sdp(self, antenna_type="HBA", clock=200_000_000):
         # setup SDP, on which this device depends
         sdp_proxy = TestDeviceProxy("STAT/SDP/1")
         sdp_proxy.off()
         sdp_proxy.warm_boot()
         sdp_proxy.set_defaults()
+
+        # setup the frequencies as expected in the test
+        sdp_proxy.antenna_type_RW = [[antenna_type] * 12] * 16
+        sdp_proxy.clock_RW = clock
+
         return sdp_proxy
 
     def test_pointing_to_zenith(self):
diff --git a/tangostationcontrol/tangostationcontrol/integration_test/default/devices/test_device_digitalbeam.py b/tangostationcontrol/tangostationcontrol/integration_test/default/devices/test_device_digitalbeam.py
index 3c48ad0ad..9a7d22306 100644
--- a/tangostationcontrol/tangostationcontrol/integration_test/default/devices/test_device_digitalbeam.py
+++ b/tangostationcontrol/tangostationcontrol/integration_test/default/devices/test_device_digitalbeam.py
@@ -87,8 +87,8 @@ class TestDeviceDigitalBeam(AbstractTestBases.TestDeviceBase):
             TestDeviceProxy.test_device_turn_off, self.antennafield_iden
         )
 
-        self.setup_antennafield_proxy(self.antenna_qualities_ok, self.antenna_use_ok)
         self.sdp_proxy = self.setup_sdp_proxy()
+        self.setup_antennafield_proxy(self.antenna_qualities_ok, self.antenna_use_ok)
 
         self.beamlet_proxy = self.initialise_beamlet_proxy()
         self.beamlet_proxy.on()
@@ -126,8 +126,8 @@ class TestDeviceDigitalBeam(AbstractTestBases.TestDeviceBase):
             TestDeviceProxy.test_device_turn_off, self.antennafield_iden
         )
 
-        self.setup_antennafield_proxy(self.antenna_qualities_ok, self.antenna_use_ok)
         self.sdp_proxy = self.setup_sdp_proxy()
+        self.setup_antennafield_proxy(self.antenna_qualities_ok, self.antenna_use_ok)
 
         self.beamlet_proxy = self.initialise_beamlet_proxy()
         self.beamlet_proxy.subband_select_RW = numpy.array(list(range(317)) + [316] + list(range(318,488)), dtype=numpy.uint32)
@@ -160,8 +160,8 @@ class TestDeviceDigitalBeam(AbstractTestBases.TestDeviceBase):
             TestDeviceProxy.test_device_turn_off, self.antennafield_iden
         )
 
-        self.setup_antennafield_proxy(self.antenna_qualities_ok, self.antenna_use_ok)
         self.setup_sdp_proxy()
+        self.setup_antennafield_proxy(self.antenna_qualities_ok, self.antenna_use_ok)
 
         self.proxy.initialise()
         self.proxy.Tracking_enabled_RW = False
@@ -190,8 +190,8 @@ class TestDeviceDigitalBeam(AbstractTestBases.TestDeviceBase):
             TestDeviceProxy.test_device_turn_off, self.antennafield_iden
         )
 
-        self.setup_antennafield_proxy(self.antenna_qualities_ok, self.antenna_use_ok)
         self.setup_sdp_proxy()
+        self.setup_antennafield_proxy(self.antenna_qualities_ok, self.antenna_use_ok)
 
         self.proxy.initialise()
         self.proxy.Tracking_enabled_RW = False
diff --git a/tangostationcontrol/tangostationcontrol/integration_test/default/devices/test_device_observation.py b/tangostationcontrol/tangostationcontrol/integration_test/default/devices/test_device_observation.py
index fb931b7dc..46c77246e 100644
--- a/tangostationcontrol/tangostationcontrol/integration_test/default/devices/test_device_observation.py
+++ b/tangostationcontrol/tangostationcontrol/integration_test/default/devices/test_device_observation.py
@@ -37,9 +37,9 @@ class TestDeviceObservation(AbstractTestBases.TestDeviceBase):
         super().setUp("STAT/Observation/1")
         self.VALID_JSON = TestObservationBase.VALID_JSON
         self.recv_proxy = self.setup_recv_proxy()
+        self.sdp_proxy = self.setup_sdp_proxy()
         self.antennafield_proxy = self.setup_antennafield_proxy()
         self.beamlet_proxy = self.setup_beamlet_proxy()
-        self.sdp_proxy = self.setup_sdp_proxy()
         self.digitalbeam_proxy = self.setup_digitalbeam_proxy()
         self.tilebeam_proxy = self.setup_tilebeam_proxy()
 
diff --git a/tangostationcontrol/tangostationcontrol/integration_test/recv_cluster/test_recv_cluster.py b/tangostationcontrol/tangostationcontrol/integration_test/recv_cluster/test_recv_cluster.py
index 6c7aad92b..92db0ffbf 100644
--- a/tangostationcontrol/tangostationcontrol/integration_test/recv_cluster/test_recv_cluster.py
+++ b/tangostationcontrol/tangostationcontrol/integration_test/recv_cluster/test_recv_cluster.py
@@ -35,6 +35,14 @@ class TestRecvCluster(base.IntegrationTestCase):
         antenna_field_proxies = []
         recv_proxies = []
 
+        # SDP must be ready before AntennaField
+        sdp_proxy = TestDeviceProxy("STAT/SDP/1")
+        sdp_proxy.off()
+        self.assertTrue(sdp_proxy.state() is DevState.OFF)
+        sdp_proxy.warm_boot()
+        sdp_proxy.set_defaults()
+        self.assertTrue(sdp_proxy.state() is DevState.ON)
+
         # Beam / Recv 1,2,3,4
         for i in range(1, 5):
             recv_proxies.append(TestDeviceProxy(f"STAT/RECV/{i}"))
diff --git a/tangostationcontrol/tangostationcontrol/test/devices/test_beamlet_device.py b/tangostationcontrol/tangostationcontrol/test/devices/test_beamlet_device.py
index e7b82ec29..ff43c4ada 100644
--- a/tangostationcontrol/tangostationcontrol/test/devices/test_beamlet_device.py
+++ b/tangostationcontrol/tangostationcontrol/test/devices/test_beamlet_device.py
@@ -97,38 +97,35 @@ class TestBeamletDevice(base.TestCase):
           [0, 1, 102],
         ])
 
-        clocks = numpy.array([
-          200 * 1000000,
-          160 * 1000000
-        ])
-
-        subband_width = 200e6 / 1024
+        nyquist_zones_0 = numpy.zeros(subbands.shape)
+        nyquist_zones_1 = numpy.ones(subbands.shape)
+        nyquist_zones_2 = numpy.ones(subbands.shape) * 2
 
         # for reference values, see https://proxy.lofar.eu/rtsm/tests/
 
-        lba_frequencies = Beamlet._subband_frequencies(subbands, 160 * 1000000, 0)
+        lba_frequencies = Beamlet._subband_frequencies(subbands, 160 * 1000000, nyquist_zones_0)
         self.assertAlmostEqual(lba_frequencies[0][0],  0.0000000e6)
         self.assertAlmostEqual(lba_frequencies[0][1],  0.1562500e6)
         self.assertAlmostEqual(lba_frequencies[0][2], 15.9375000e6)
 
-        lba_frequencies = Beamlet._subband_frequencies(subbands, 200 * 1000000, 0)
+        lba_frequencies = Beamlet._subband_frequencies(subbands, 200 * 1000000, nyquist_zones_0)
         self.assertAlmostEqual(lba_frequencies[0][0],  0.0000000e6)
         self.assertAlmostEqual(lba_frequencies[0][1],  0.1953125e6)
         self.assertAlmostEqual(lba_frequencies[0][2], 19.9218750e6)
 
         # Nyquist zone 1 is not used in 160 MHz
 
-        hba_low_frequencies = Beamlet._subband_frequencies(subbands, 200 * 1000000, 1)
+        hba_low_frequencies = Beamlet._subband_frequencies(subbands, 200 * 1000000, nyquist_zones_1)
         self.assertAlmostEqual(hba_low_frequencies[0][0], 100.0000000e6)
         self.assertAlmostEqual(hba_low_frequencies[0][1], 100.1953125e6)
         self.assertAlmostEqual(hba_low_frequencies[0][2], 119.9218750e6)
 
-        hba_high_frequencies = Beamlet._subband_frequencies(subbands, 160 * 1000000, 2)
+        hba_high_frequencies = Beamlet._subband_frequencies(subbands, 160 * 1000000, nyquist_zones_2)
         self.assertAlmostEqual(hba_high_frequencies[0][0], 160.0000000e6)
         self.assertAlmostEqual(hba_high_frequencies[0][1], 160.1562500e6)
         self.assertAlmostEqual(hba_high_frequencies[0][2], 175.9375000e6)
 
-        hba_high_frequencies = Beamlet._subband_frequencies(subbands, 200 * 1000000, 2)
+        hba_high_frequencies = Beamlet._subband_frequencies(subbands, 200 * 1000000, nyquist_zones_2)
         self.assertAlmostEqual(hba_high_frequencies[0][0], 200.0000000e6)
         self.assertAlmostEqual(hba_high_frequencies[0][1], 200.1953125e6)
         self.assertAlmostEqual(hba_high_frequencies[0][2], 219.9218750e6)
-- 
GitLab