diff --git a/tangostationcontrol/tangostationcontrol/beam/hba_tile.py b/tangostationcontrol/tangostationcontrol/beam/hba_tile.py
index 14475cf2ab561db97801758e471d032e0894ec42..9ab46e5bf544f652ef5790188016c1a7fcf3c487 100644
--- a/tangostationcontrol/tangostationcontrol/beam/hba_tile.py
+++ b/tangostationcontrol/tangostationcontrol/beam/hba_tile.py
@@ -1,9 +1,6 @@
 import numpy
 from math import sin, cos
 
-# Number of antenna dipoles in each HBA tile
-NUMBER_OF_ELEMENTS_PER_TILE = 16
-
 class HBATAntennaOffsets(object):
     """
         This class helps calculate the absolute offsets of the antennas within a tile,
diff --git a/tangostationcontrol/tangostationcontrol/clients/attribute_wrapper.py b/tangostationcontrol/tangostationcontrol/clients/attribute_wrapper.py
index ee898ff561ea916431a7100f098069c68b4e5a13..46589552326436c926c98750b91b9b42b8b52d4f 100644
--- a/tangostationcontrol/tangostationcontrol/clients/attribute_wrapper.py
+++ b/tangostationcontrol/tangostationcontrol/clients/attribute_wrapper.py
@@ -89,22 +89,26 @@ class attribute_wrapper(attribute):
         self.datatype = datatype
 
         if dims == (1,):
+            # scalar
             # Tango defines a scalar as having dimensions (1,0), see https://pytango.readthedocs.io/en/stable/server_api/attribute.html
             max_dim_x = 1
             max_dim_y = 0
             dtype = datatype
             shape = ()
         elif len(dims) == 1:
+            # spectrum
             max_dim_x = dims[0]
             max_dim_y = 0
             dtype = (datatype,)
             shape = (max_dim_x,)
         elif len(dims) == 2:
+            # image
             max_dim_x = dims[1]
             max_dim_y = dims[0]
             dtype = ((datatype,),)
             shape = (max_dim_y, max_dim_x)
         else:
+            # higher dimensional
             # >2D arrays collapse into the X and Y dimensions. The Y (major) dimension mirrors the first dimension given, the
             # rest collapses into the X (minor) dimension.
             max_dim_x = reduce(mul, dims[1:])
diff --git a/tangostationcontrol/tangostationcontrol/clients/statistics/client.py b/tangostationcontrol/tangostationcontrol/clients/statistics/client.py
index 8cbcffc445fc2d3124e11f1f1f42ced225860c23..8a99992ac699f2fd3a38db7dfa19662f808d44c3 100644
--- a/tangostationcontrol/tangostationcontrol/clients/statistics/client.py
+++ b/tangostationcontrol/tangostationcontrol/clients/statistics/client.py
@@ -20,12 +20,16 @@ logger = logging.getLogger()
 
 
 class StatisticsClient(AsyncCommClient):
+
+    # the maximum amount of packets unhandled packets the statistics client thread will queue
+    STATISTICS_CLIENT_QUEUE_SIZE = 1024
+
     """
       Collects statistics packets over UDP, forwards them to a StatisticsCollector,
       and provides a CommClient interface to expose points to a Device Server.
     """
 
-    def __init__(self, collector, udp_options, tcp_options, fault_func, event_loop=None, queuesize=1024):
+    def __init__(self, collector, udp_options, tcp_options, fault_func, event_loop=None, queuesize=STATISTICS_CLIENT_QUEUE_SIZE):
         """
         Create the statistics client and connect() to it and get the object node.
 
diff --git a/tangostationcontrol/tangostationcontrol/clients/udp_receiver.py b/tangostationcontrol/tangostationcontrol/clients/udp_receiver.py
index d07982f17cff4661dd441294614017781d5ce8a6..05252bfc6ef4504ac46ec9cf17a8434ccaaab9eb 100644
--- a/tangostationcontrol/tangostationcontrol/clients/udp_receiver.py
+++ b/tangostationcontrol/tangostationcontrol/clients/udp_receiver.py
@@ -8,6 +8,7 @@ import time
 from typing import List # not needed for python3.9+, where we can use the type "list[Queue]" directly
 
 from tangostationcontrol.clients.statistics.client_thread import StatisticsClientThread
+from tangostationcontrol.common.constants import MAX_ETH_FRAME_SIZE
 
 logger = logging.getLogger()
 
@@ -51,7 +52,7 @@ class UDPReceiver(Thread, StatisticsClientThread):
             # Number of packets we had to drop due to a full queue
             "nof_packets_dropped":   numpy.uint64(0),
             # Packets are at most 9000 bytes, the largest payload (well, MTU) of an Ethernet Jumbo frame
-            "last_packet":           numpy.zeros((9000,), dtype=numpy.uint8),
+            "last_packet":           numpy.zeros((MAX_ETH_FRAME_SIZE,), dtype=numpy.uint8),
             # Timestamp of when the last packet was received
             "last_packet_timestamp": numpy.uint64(0),
         }
@@ -89,7 +90,7 @@ class UDPReceiver(Thread, StatisticsClientThread):
 
         while self.stream_on:
             try:
-                packet, _, _, _ = self.sock.recvmsg(9000)
+                packet, _, _, _ = self.sock.recvmsg(MAX_ETH_FRAME_SIZE)
 
                 self.parameters["nof_packets_received"]  += numpy.uint64(1)
                 self.parameters["nof_bytes_received"]    += numpy.uint64(len(packet))
diff --git a/tangostationcontrol/tangostationcontrol/common/constants.py b/tangostationcontrol/tangostationcontrol/common/constants.py
new file mode 100644
index 0000000000000000000000000000000000000000..8a2dbb7bd75b281e411c3a73cc9686306f6d364b
--- /dev/null
+++ b/tangostationcontrol/tangostationcontrol/common/constants.py
@@ -0,0 +1,96 @@
+from tangostationcontrol.common.baselines import nr_baselines
+
+
+# number of FPGA processing nodes
+N_pn = 16
+
+# number of polarisations per antenna (X and y polarisations)
+N_pol = 2
+
+# antennas per FPGA
+A_pn = 6
+
+# signal inputs per FPGA ( A_pn * N_pol )
+S_pn = A_pn * N_pol
+
+# Highest number antennas we support
+MAX_ANTENNA = 96
+
+# Maximum number of antenna inputs we support (used to determine array sizes)
+MAX_INPUTS = 192
+
+# Number of tile elements (antenna dipoles) in each HBA tile
+N_elements = 16
+
+# number of RCU's per subrack
+N_rcu = 32
+
+# Number of antenna inputs per RCU
+N_rcu_inp = 3
+
+# number of hops that the data of the stream has traveled to reach the BSN aligner on this node
+P_sum = 2
+
+# the number of square correlator cells produced per FPGA for XST's (P_sq := N_pn // 2 + 1)
+P_sq = 9
+
+# total number of beamsets
+N_beamsets_max = 2
+# number of beamsets we control
+N_beamsets_ctrl = 1
+# The maximum amount of beamlets the SDP (and we) support
+N_beamlets_max = 976
+# number of actively controlled beamlets
+N_beamlets_ctrl = 488
+
+# Maximum number of subbands we support
+N_subbands = 512
+# Number of points per subband (the resolution)
+N_subband_res = 1024
+
+
+# main clock frequency's are 200MHz and 160MHz
+CLK_200_MHZ = 200_000_000
+CLK_160_MHZ = 160_000_000
+
+# Maximum number of subbands for which we collect XSTs simultaneously
+MAX_PARALLEL_SUBBANDS = 8
+# Expected block for XST's
+BLOCK_LENGTH = 12
+# Complex values are (real, imag).
+VALUES_PER_COMPLEX = 2
+# Max blocks for the BST statistics
+BST_MAX_BLOCKS = 2
+# Expected number of blocks: enough to cover all baselines without the conjugates (that is, the top-left triangle of the matrix).
+MAX_BLOCKS = nr_baselines(MAX_INPUTS // BLOCK_LENGTH)
+
+# UNB2 constants
+# number of uniboards in a subrack
+N_unb = 2
+# number of FPGA's in a uniboard
+N_fpga = 4
+# number of DDR modules per FPGA
+N_ddr = 2
+# number of QSFP tranceivers per uniboard
+N_qsfp = 24
+
+
+# the three spatial dimensions XYZ used a lot for PQR and ITRF coordinates.
+N_xyz = 3
+# amount of parameters needed for a pointing
+N_point_prop = 3
+# number of values for latitude/longitude coordinates
+N_latlong = 2
+
+
+# default subband we use because of its low RFI
+DEFAULT_SUBBAND = 102
+
+# Maximum array size to allocate for beam_device pointings,
+MAX_POINTINGS = N_beamlets_max
+
+# max size for a statistic packet
+MAX_ETH_FRAME_SIZE = 9000
+
+# The default polling period for polled attributes
+DEFAULT_POLLING_PERIOD = 1000
diff --git a/tangostationcontrol/tangostationcontrol/devices/antennafield.py b/tangostationcontrol/tangostationcontrol/devices/antennafield.py
index 8cb16b7fd54d24ec25cebe9d3e12f87c00da0871..b57d3b9622e74967a7b1adf3f3f3bf2ddfabd12a 100644
--- a/tangostationcontrol/tangostationcontrol/devices/antennafield.py
+++ b/tangostationcontrol/tangostationcontrol/devices/antennafield.py
@@ -18,11 +18,12 @@ from tango.server import device_property, attribute, command
 # Additional import
 from tangostationcontrol.common.type_checking import type_not_sequence
 from tangostationcontrol.common.entrypoint import entry
-from tangostationcontrol.devices.lofar_device import lofar_device
 from tangostationcontrol.common.lofar_logging import device_logging_to_python, log_exceptions
+from tangostationcontrol.common.constants import N_elements, MAX_ANTENNA, N_pol, N_xyz, N_latlong, N_rcu, N_rcu_inp
+from tangostationcontrol.devices.lofar_device import lofar_device
 from tangostationcontrol.devices.device_decorators import fault_on_error
 from tangostationcontrol.beam.geo import ETRS_to_ITRF, ITRF_to_GEO, GEO_to_GEOHASH
-from tangostationcontrol.beam.hba_tile import HBATAntennaOffsets, NUMBER_OF_ELEMENTS_PER_TILE
+from tangostationcontrol.beam.hba_tile import HBATAntennaOffsets
 
 import logging
 
@@ -30,10 +31,6 @@ logger = logging.getLogger()
 
 __all__ = ["AntennaField", "AntennaToRecvMapper", "main"]
 
-# Highest number of HBA tiles we support per AntennaField
-MAX_NUMBER_OF_HBAT = 96
-
-
 class AntennaUse(IntEnum):
     AUTO = 0  # use antenna only if its OK or SUSPICIOUS
     ON = 1    # force antenna to be on, regardless of quality
@@ -100,7 +97,7 @@ class AntennaField(lofar_device):
         doc="Name of each antenna",
         dtype='DevVarStringArray',
         mandatory=False,
-        default_value=[f'Antenna{n + 1}' for n in range(MAX_NUMBER_OF_HBAT)]
+        default_value=[f'Antenna{n + 1}' for n in range(MAX_ANTENNA)]
     )
 
     # ----- Antenna states
@@ -109,14 +106,14 @@ class AntennaField(lofar_device):
         doc="Operational quality state of each antenna",
         dtype='DevVarUShortArray',
         mandatory=False,
-        default_value=numpy.array([AntennaQuality.OK] * MAX_NUMBER_OF_HBAT)
+        default_value=numpy.array([AntennaQuality.OK] * MAX_ANTENNA)
     )
 
     Antenna_Use = device_property(
         doc="Operational State of each antenna",
         dtype='DevVarUShortArray',
         mandatory=False,
-        default_value=numpy.array([AntennaUse.AUTO] * MAX_NUMBER_OF_HBAT)
+        default_value=numpy.array([AntennaUse.AUTO] * MAX_ANTENNA)
     )
 
     # ----- Antenna properties
@@ -132,7 +129,7 @@ class AntennaField(lofar_device):
         doc="Whether to provide power to each antenna (False for noise sources)",
         dtype='DevVarBooleanArray',
         mandatory=False,
-        default_value=numpy.array([False] * MAX_NUMBER_OF_HBAT)
+        default_value=numpy.array([False] * MAX_ANTENNA)
     )
 
     # ----- Position information
@@ -178,7 +175,7 @@ class AntennaField(lofar_device):
         doc='Rotation of each tile in the PQ plane ("horizontal") in degrees.',
         dtype='DevVarFloatArray',
         mandatory=False,
-        default_value=[0.0] * MAX_NUMBER_OF_HBAT
+        default_value=[0.0] * MAX_ANTENNA
     )
 
     PQR_to_ETRS_rotation_matrix = device_property(
@@ -203,7 +200,7 @@ class AntennaField(lofar_device):
     Antenna_to_SDP_Mapping = device_property(
         dtype=(numpy.int32,),
         doc='The mapping of Antennas to FPGA input pairs. Each FPGA can handle 6 inputs, and SDP has 16 FPGAs. Each antenna is represented with a (fpga, input) value pair. The array is flattened, so must be reshaped upon use. An input=-1 means the antenna is unconnected.',
-        default_value=numpy.array([-1] * MAX_NUMBER_OF_HBAT * 2, dtype=numpy.int32)
+        default_value=numpy.array([-1] * MAX_ANTENNA * 2, dtype=numpy.int32)
     )
 
     SDP_device = device_property(
@@ -219,14 +216,14 @@ class AntennaField(lofar_device):
         dtype=(numpy.int32,),
         doc='The mapping of Antenna power lines to RECV mapping. Each RECV can handle 96 inputs. The Antenna number is the index and the value shows to which receiver device it is connected and on which input. The first integer is the input. The second integer is the RECV id. Example: [0, 3] = first receiver of property RECV_devices with input 3. -1 means that the Antenna is not connected. The property is stored in a one dimensional structure. It needs to be reshaped to a list of lists of two items.',
         mandatory=False,
-        default_value=[-1] * MAX_NUMBER_OF_HBAT * 2
+        default_value=[-1] * MAX_ANTENNA * 2
     )
 
     Control_to_RECV_mapping = device_property(
         dtype=(numpy.int32,),
         doc='The mapping of Antenna control lines to RECV mapping. Each RECV can handle 96 inputs. The Antenna number is the index and the value shows to which receiver device it is connected and on which input. The first integer is the input. The second interger is the RECV id. Example: [1, 3] = STAT/RECV/1 with input 3. -1 means that the Antenna is not connected. The property is stored in a one dimensional structure. It needs to be reshaped to a list of lists of two items.',
         mandatory=False,
-        default_value=[-1] * MAX_NUMBER_OF_HBAT * 2
+        default_value=[-1] * MAX_ANTENNA * 2
     )
 
     RECV_devices = device_property(
@@ -240,58 +237,59 @@ class AntennaField(lofar_device):
         dtype=str)
 
     Antenna_Names_R = attribute(access=AttrWriteType.READ,
-                                dtype=(str,), max_dim_x=MAX_NUMBER_OF_HBAT)
+                                dtype=(str,), max_dim_x=MAX_ANTENNA)
     Antenna_Quality_R = attribute(doc='The quality of each antenna. 0=OK, 1=SUSPICIOUS, 2=BROKEN, 3=BEYOND_REPAIR.',
-                                  dtype=(numpy.uint32,), max_dim_x=MAX_NUMBER_OF_HBAT)
+                                  dtype=(numpy.uint32,), max_dim_x=MAX_ANTENNA)
     Antenna_Use_R = attribute(
         doc='Whether each antenna should be used. 0=AUTO, 1=ON, 2=OFF. In AUTO mode, the antenna is used if it is not BROKEN or BEYOND_REPAIR.',
-        dtype=(numpy.uint32,), max_dim_x=MAX_NUMBER_OF_HBAT)
+        dtype=(numpy.uint32,), max_dim_x=MAX_ANTENNA)
     Antenna_Quality_str_R = attribute(doc='The quality of each antenna, as a string.',
-                                      dtype=(str,), max_dim_x=MAX_NUMBER_OF_HBAT)
+                                      dtype=(str,), max_dim_x=MAX_ANTENNA)
     Antenna_Use_str_R = attribute(doc='Whether each antenna should be used, as a string.',
-                                  dtype=(str,), max_dim_x=MAX_NUMBER_OF_HBAT)
+                                  dtype=(str,), max_dim_x=MAX_ANTENNA)
 
     Antenna_Usage_Mask_R = attribute(doc='Whether each antenna will be used.',
-                                     dtype=(bool,), max_dim_x=MAX_NUMBER_OF_HBAT)
+
+                                     dtype=(bool,), max_dim_x=MAX_ANTENNA)
 
     Antenna_to_SDP_Mapping_R = attribute(doc='To which (fpga, input) pair each antenna is connected. -1=unconnected.',
-                                         dtype=((numpy.int32,),), max_dim_x=2, max_dim_y=MAX_NUMBER_OF_HBAT)
+                                         dtype=((numpy.int32,),), max_dim_x=N_pol, max_dim_y=MAX_ANTENNA)
 
-    ANT_mask_RW = mapped_attribute("ANT_mask_RW", dtype=(bool,), max_dim_x=MAX_NUMBER_OF_HBAT,
+    ANT_mask_RW = mapped_attribute("ANT_mask_RW", dtype=(bool,), max_dim_x=MAX_ANTENNA,
                                    access=AttrWriteType.READ_WRITE)
-    RCU_PWR_ANT_on_R = mapped_attribute("RCU_PWR_ANT_on_R", dtype=(bool,), max_dim_x=MAX_NUMBER_OF_HBAT)
-    RCU_PWR_ANT_on_RW = mapped_attribute("RCU_PWR_ANT_on_RW", dtype=(bool,), max_dim_x=MAX_NUMBER_OF_HBAT,
+    RCU_PWR_ANT_on_R = mapped_attribute("RCU_PWR_ANT_on_R", dtype=(bool,), max_dim_x=MAX_ANTENNA)
+    RCU_PWR_ANT_on_RW = mapped_attribute("RCU_PWR_ANT_on_RW", dtype=(bool,), max_dim_x=MAX_ANTENNA,
                                          access=AttrWriteType.READ_WRITE)
     HBAT_BF_delay_steps_R = mapped_attribute("HBAT_BF_delay_steps_R", dtype=((numpy.int64,),),
-                                             max_dim_x=NUMBER_OF_ELEMENTS_PER_TILE * 2, max_dim_y=MAX_NUMBER_OF_HBAT)
+                                             max_dim_x=N_elements * N_pol, max_dim_y=MAX_ANTENNA)
     HBAT_BF_delay_steps_RW = mapped_attribute("HBAT_BF_delay_steps_RW", dtype=((numpy.int64,),),
-                                              max_dim_x=NUMBER_OF_ELEMENTS_PER_TILE * 2, max_dim_y=MAX_NUMBER_OF_HBAT,
+                                              max_dim_x=N_elements * N_pol, max_dim_y=MAX_ANTENNA,
                                               access=AttrWriteType.READ_WRITE)
-    HBAT_LED_on_R = mapped_attribute("HBAT_LED_on_R", dtype=((bool,),), max_dim_x=NUMBER_OF_ELEMENTS_PER_TILE * 2,
-                                     max_dim_y=MAX_NUMBER_OF_HBAT)
-    HBAT_LED_on_RW = mapped_attribute("HBAT_LED_on_RW", dtype=((bool,),), max_dim_x=NUMBER_OF_ELEMENTS_PER_TILE * 2,
-                                      max_dim_y=MAX_NUMBER_OF_HBAT, access=AttrWriteType.READ_WRITE)
+    HBAT_LED_on_R = mapped_attribute("HBAT_LED_on_R", dtype=((bool,),), max_dim_x=N_elements * N_pol,
+                                     max_dim_y=MAX_ANTENNA)
+    HBAT_LED_on_RW = mapped_attribute("HBAT_LED_on_RW", dtype=((bool,),), max_dim_x=N_elements * N_pol,
+                                      max_dim_y=MAX_ANTENNA, access=AttrWriteType.READ_WRITE)
     HBAT_PWR_LNA_on_R = mapped_attribute("HBAT_PWR_LNA_on_R", dtype=((bool,),),
-                                         max_dim_x=NUMBER_OF_ELEMENTS_PER_TILE * 2, max_dim_y=MAX_NUMBER_OF_HBAT)
+                                         max_dim_x=N_elements * N_pol, max_dim_y=MAX_ANTENNA)
     HBAT_PWR_LNA_on_RW = mapped_attribute("HBAT_PWR_LNA_on_RW", dtype=((bool,),),
-                                          max_dim_x=NUMBER_OF_ELEMENTS_PER_TILE * 2, max_dim_y=MAX_NUMBER_OF_HBAT,
+                                          max_dim_x=N_elements * N_pol, max_dim_y=MAX_ANTENNA,
                                           access=AttrWriteType.READ_WRITE)
-    HBAT_PWR_on_R = mapped_attribute("HBAT_PWR_on_R", dtype=((bool,),), max_dim_x=NUMBER_OF_ELEMENTS_PER_TILE * 2,
-                                     max_dim_y=MAX_NUMBER_OF_HBAT)
-    HBAT_PWR_on_RW = mapped_attribute("HBAT_PWR_on_RW", dtype=((bool,),), max_dim_x=NUMBER_OF_ELEMENTS_PER_TILE * 2,
-                                      max_dim_y=MAX_NUMBER_OF_HBAT, access=AttrWriteType.READ_WRITE)
-    RCU_band_select_RW = mapped_attribute("RCU_band_select_RW", dtype=(numpy.int64,), max_dim_x=MAX_NUMBER_OF_HBAT,
+    HBAT_PWR_on_R = mapped_attribute("HBAT_PWR_on_R", dtype=((bool,),), max_dim_x=N_elements * N_pol,
+                                     max_dim_y=MAX_ANTENNA)
+    HBAT_PWR_on_RW = mapped_attribute("HBAT_PWR_on_RW", dtype=((bool,),), max_dim_x=N_elements * N_pol,
+                                      max_dim_y=MAX_ANTENNA, access=AttrWriteType.READ_WRITE)
+    RCU_band_select_RW = mapped_attribute("RCU_band_select_RW", dtype=(numpy.int64,), max_dim_x=MAX_ANTENNA,
                                           access=AttrWriteType.READ_WRITE)
 
     # ----- Position information
 
     Antenna_Field_Reference_ITRF_R = attribute(access=AttrWriteType.READ,
                                                doc='Absolute reference position of antenna field, in ITRF (XYZ)',
-                                               dtype=(numpy.float64,), max_dim_x=3)
+                                               dtype=(numpy.float64,), max_dim_x=N_xyz)
 
     Antenna_Field_Reference_GEO_R = attribute(access=AttrWriteType.READ,
                                               doc='Absolute reference position of antenna field, in latitude/longitude (degrees)',
-                                              dtype=(numpy.float64,), max_dim_x=2)
+                                              dtype=(numpy.float64,), max_dim_x=N_latlong)
 
     Antenna_Field_Reference_GEOHASH_R = attribute(access=AttrWriteType.READ,
                                                   doc='Absolute reference position of antenna field, as a geohash string',
@@ -299,20 +297,20 @@ class AntennaField(lofar_device):
 
     HBAT_antenna_ITRF_offsets_R = attribute(access=AttrWriteType.READ,
                                             doc='For each tile, the offsets of the antennas within that, in ITRF ("iHBADeltas"). True shape: nrtiles x 16 x 3.',
-                                            dtype=((numpy.float64,),), max_dim_x=NUMBER_OF_ELEMENTS_PER_TILE * 3,
-                                            max_dim_y=96)
+                                            dtype=((numpy.float64,),), max_dim_x=MAX_ANTENNA * N_xyz,
+                                            max_dim_y=MAX_ANTENNA)
 
     Antenna_Reference_ITRF_R = attribute(access=AttrWriteType.READ,
                                          doc='Absolute reference position of each tile, in ITRF (XYZ)',
-                                         dtype=((numpy.float64,),), max_dim_x=3, max_dim_y=MAX_NUMBER_OF_HBAT)
+                                         dtype=((numpy.float64,),), max_dim_x=N_xyz, max_dim_y=MAX_ANTENNA)
 
     Antenna_Reference_GEO_R = attribute(access=AttrWriteType.READ,
                                         doc='Absolute reference position of each tile, in latitude/longitude (degrees)',
-                                        dtype=((numpy.float64,),), max_dim_x=2, max_dim_y=MAX_NUMBER_OF_HBAT)
+                                        dtype=((numpy.float64,),), max_dim_x=N_latlong, max_dim_y=MAX_ANTENNA)
 
     Antenna_Reference_GEOHASH_R = attribute(access=AttrWriteType.READ,
                                             doc='Absolute reference position of each tile, as geohash strings',
-                                            dtype=(str,), max_dim_x=MAX_NUMBER_OF_HBAT, )
+                                            dtype=(str,), max_dim_x=MAX_ANTENNA, )
 
     nr_antennas_R = attribute(
         doc='Number of Antennas in this field',
@@ -363,10 +361,10 @@ class AntennaField(lofar_device):
     def read_Antenna_Field_Reference_ITRF_R(self):
         # provide ITRF field coordinates if they were configured
         if self.Antenna_Field_Reference_ITRF:
-            return numpy.array(self.Antenna_Field_Reference_ITRF).reshape(3)
+            return numpy.array(self.Antenna_Field_Reference_ITRF).reshape(N_xyz)
 
         # calculate them from ETRS coordinates if not, using the configured ITRF reference
-        ETRS_coordinates = numpy.array(self.Antenna_Field_Reference_ETRS).reshape(3)
+        ETRS_coordinates = numpy.array(self.Antenna_Field_Reference_ETRS).reshape(N_xyz)
         return ETRS_to_ITRF(ETRS_coordinates, self.ITRF_Reference_Frame, self.ITRF_Reference_Epoch)
 
     def read_Antenna_Field_Reference_GEO_R(self):
@@ -391,9 +389,9 @@ class AntennaField(lofar_device):
             tiles lie on the same plane in ITRF. """
 
         # the relative offsets between the elements is fixed in HBAT_base_antenna_offsets
-        base_antenna_offsets = numpy.array(self.HBAT_base_antenna_offsets).reshape(NUMBER_OF_ELEMENTS_PER_TILE, 3)
+        base_antenna_offsets = numpy.array(self.HBAT_base_antenna_offsets).reshape(N_elements, N_xyz)
 
-        PQR_to_ETRS_rotation_matrix = numpy.array(self.PQR_to_ETRS_rotation_matrix).reshape(3, 3)
+        PQR_to_ETRS_rotation_matrix = numpy.array(self.PQR_to_ETRS_rotation_matrix).reshape(N_xyz, N_xyz)
 
         # each tile has its own rotation angle, resulting in different offsets per tile
         all_offsets = numpy.array(
@@ -403,15 +401,16 @@ class AntennaField(lofar_device):
                 PQR_to_ETRS_rotation_matrix)
                 for angle_deg in self.HBAT_PQR_rotation_angles_deg])
 
-        return all_offsets.reshape(-1, NUMBER_OF_ELEMENTS_PER_TILE * 3)
+        return all_offsets.reshape(-1, N_elements * N_xyz)
 
     def read_Antenna_Reference_ITRF_R(self):
         # provide ITRF coordinates if they were configured
         if self.Antenna_Reference_ITRF:
-            return numpy.array(self.Antenna_Reference_ITRF).reshape(-1, 3)
+            return numpy.array(self.Antenna_Reference_ITRF).reshape(-1, N_xyz)
 
         # calculate them from ETRS coordinates if not, using the configured ITRF reference
-        ETRS_coordinates = numpy.array(self.Antenna_Reference_ETRS).reshape(-1, 3)
+        ETRS_coordinates = numpy.array(self.Antenna_Reference_ETRS).reshape(-1, N_xyz)
+        
         return ETRS_to_ITRF(ETRS_coordinates, self.ITRF_Reference_Frame, self.ITRF_Reference_Epoch)
 
     def read_Antenna_Reference_GEO_R(self):
@@ -519,10 +518,10 @@ class AntennaField(lofar_device):
     def calculate_HBAT_bf_delay_steps(self, delays: numpy.ndarray):
         num_tiles = self.read_nr_antennas_R()
 
-        delays = delays.reshape(num_tiles, NUMBER_OF_ELEMENTS_PER_TILE)
+        delays = delays.reshape(num_tiles, N_elements)
 
-        result_values = numpy.zeros((num_tiles, NUMBER_OF_ELEMENTS_PER_TILE * 2), dtype=numpy.int64)
-        control_mapping = numpy.reshape(self.Control_to_RECV_mapping, (-1, 2))
+        result_values = numpy.zeros((num_tiles, N_elements * N_pol), dtype=numpy.int64)
+        control_mapping = numpy.reshape(self.Control_to_RECV_mapping, (-1, N_pol))
 
         for recv_idx, recv_proxy in enumerate(self.recv_proxies):
             # collect all delays for this recv_proxy
@@ -536,7 +535,7 @@ class AntennaField(lofar_device):
             # convert them into delay steps
             flatten_delay_steps = numpy.array(recv_proxy.calculate_HBAT_bf_delay_steps(recv_delays.flatten()),
                                               dtype=numpy.int64)
-            delay_steps = numpy.reshape(flatten_delay_steps, (-1, NUMBER_OF_ELEMENTS_PER_TILE * 2))
+            delay_steps = numpy.reshape(flatten_delay_steps, (-1, N_elements * N_pol))
 
             # write back into same positions we collected them from
             result_values[recv_result_indices] = delay_steps
@@ -545,16 +544,17 @@ class AntennaField(lofar_device):
 
 
 class AntennaToRecvMapper(object):
-    _VALUE_MAP_NONE_96 = numpy.full(96, None)
-    _VALUE_MAP_NONE_96_32 = numpy.full((96, 32), None)
+
+    _VALUE_MAP_NONE_96 = numpy.full(MAX_ANTENNA, None)
+    _VALUE_MAP_NONE_96_32 = numpy.full((MAX_ANTENNA, N_rcu), None)
 
     def __init__(self, control_to_recv_mapping, power_to_recv_mapping, number_of_receivers):
         number_of_antennas = len(control_to_recv_mapping)
 
         # Reduce memory footprint of default values by creating single instance of
         # common fields
-        value_map_ant_32_int = numpy.zeros([number_of_antennas, 32], dtype=numpy.int64)
-        value_map_ant_32_bool = numpy.full((number_of_antennas, 32), False)
+        value_map_ant_32_int = numpy.zeros([number_of_antennas, N_rcu], dtype=numpy.int64)
+        value_map_ant_32_bool = numpy.full((number_of_antennas, N_rcu), False)
         value_map_ant_bool = numpy.full(number_of_antennas, False)
 
         self._control_mapping = control_to_recv_mapping
@@ -584,16 +584,16 @@ class AntennaToRecvMapper(object):
             "RCU_band_select_RW": AntennaToRecvMapper._VALUE_MAP_NONE_96,
         }
         self._reshape_attributes_in = {
-            "HBAT_BF_delay_steps_RW": (96, 32),
-            "RCU_PWR_ANT_on_R": (96,),
-            "RCU_PWR_ANT_on_RW": (96,),
-            "RCU_band_select_RW": (96,),
+            "HBAT_BF_delay_steps_RW": (MAX_ANTENNA, N_rcu),
+            "RCU_PWR_ANT_on_R": (MAX_ANTENNA,),
+            "RCU_PWR_ANT_on_RW": (MAX_ANTENNA,),
+            "RCU_band_select_RW": (MAX_ANTENNA,),
         }
         self._reshape_attributes_out = {
-            "HBAT_BF_delay_steps_RW": (96, 32),
-            "RCU_PWR_ANT_on_R": (32, 3),
-            "RCU_PWR_ANT_on_RW": (32, 3),
-            "RCU_band_select_RW": (32, 3),
+            "HBAT_BF_delay_steps_RW": (MAX_ANTENNA, N_rcu),
+            "RCU_PWR_ANT_on_R": (N_rcu, N_rcu_inp),
+            "RCU_PWR_ANT_on_RW": (N_rcu, N_rcu_inp),
+            "RCU_band_select_RW": (N_rcu, N_rcu_inp),
         }
 
     def map_read(self, mapped_attribute: str, recv_results: List[any]) -> List[any]:
diff --git a/tangostationcontrol/tangostationcontrol/devices/apsct.py b/tangostationcontrol/tangostationcontrol/devices/apsct.py
index f2bf1fa4d7af436807fd74c9649627ffa4593bb3..d39289c6f959cf92457d696a58fe021a5d3eda07 100644
--- a/tangostationcontrol/tangostationcontrol/devices/apsct.py
+++ b/tangostationcontrol/tangostationcontrol/devices/apsct.py
@@ -22,6 +22,7 @@ from tangostationcontrol.clients.attribute_wrapper import attribute_wrapper
 from tangostationcontrol.common.entrypoint import entry
 from tangostationcontrol.common.lofar_logging import device_logging_to_python
 from tangostationcontrol.common.states import DEFAULT_COMMAND_STATES
+from tangostationcontrol.common.constants import DEFAULT_POLLING_PERIOD
 from tangostationcontrol.devices.device_decorators import only_in_states
 from tangostationcontrol.devices.opcua_device import opcua_device
 
@@ -101,7 +102,7 @@ class APSCT(opcua_device):
                 self.read_attribute("APSCT_PLL_160MHz_locked_R") and self.read_attribute("APSCT_PLL_160MHz_error_R")]
         return any(errors)
 
-    APSCT_TEMP_error_R            = attribute(dtype=bool, fisallowed="is_attribute_access_allowed", polling_period=1000)
+    APSCT_TEMP_error_R            = attribute(dtype=bool, fisallowed="is_attribute_access_allowed", polling_period=DEFAULT_POLLING_PERIOD)
     APSCT_VOUT_error_R            = attribute(dtype=bool, fisallowed="is_attribute_access_allowed")
 
     def read_APSCT_TEMP_error_R(self):
diff --git a/tangostationcontrol/tangostationcontrol/devices/apspu.py b/tangostationcontrol/tangostationcontrol/devices/apspu.py
index 70536471bf6238e009c258444956b440b2d6cf23..08ee51fa8d968a3fcb5aed86809294a4471ed081 100644
--- a/tangostationcontrol/tangostationcontrol/devices/apspu.py
+++ b/tangostationcontrol/tangostationcontrol/devices/apspu.py
@@ -21,6 +21,7 @@ from tangostationcontrol.common.entrypoint import entry
 from tangostationcontrol.clients.attribute_wrapper import attribute_wrapper
 from tangostationcontrol.devices.opcua_device import opcua_device
 from tangostationcontrol.common.lofar_logging import device_logging_to_python
+from tangostationcontrol.common.constants import DEFAULT_POLLING_PERIOD
 
 __all__ = ["APSPU", "main"]
 
@@ -77,7 +78,7 @@ class APSPU(opcua_device):
                or self.alarm_val("APSPU_FAN3_RPM_R"))
 
     APSPU_IOUT_error_R          = attribute(dtype=bool, fisallowed="is_attribute_access_allowed")
-    APSPU_TEMP_error_R          = attribute(dtype=bool, fisallowed="is_attribute_access_allowed", polling_period=1000)
+    APSPU_TEMP_error_R          = attribute(dtype=bool, fisallowed="is_attribute_access_allowed", polling_period=DEFAULT_POLLING_PERIOD)
     APSPU_VOUT_error_R          = attribute(dtype=bool, fisallowed="is_attribute_access_allowed")
 
     def read_APSPU_IOUT_error_R(self):
diff --git a/tangostationcontrol/tangostationcontrol/devices/beam_device.py b/tangostationcontrol/tangostationcontrol/devices/beam_device.py
index 03349211b468c1556ed234a1ac81b2774ba359da..dc2ee888d21726ea3fdefc99b471e0d076e8ab67 100644
--- a/tangostationcontrol/tangostationcontrol/devices/beam_device.py
+++ b/tangostationcontrol/tangostationcontrol/devices/beam_device.py
@@ -21,6 +21,7 @@ from tango import AttrWriteType, DebugIt, DevVarStringArray, DevVarDoubleArray,
 # Additional import
 from tangostationcontrol.common.entrypoint import entry
 from tangostationcontrol.common.measures import get_measures_directory, get_available_measures_directories, download_measures, use_measures_directory, restart_python
+from tangostationcontrol.common.constants import MAX_POINTINGS, N_point_prop
 from tangostationcontrol.common.lofar_logging import log_exceptions
 from tangostationcontrol.common.states import DEFAULT_COMMAND_STATES
 from tangostationcontrol.devices.device_decorators import TimeIt, only_in_states, fault_on_error
@@ -69,19 +70,15 @@ class beam_device(lofar_device):
     # Attributes
     # ----------
 
-    # Maximum array size to allocate for the pointings,
-    # which must be enough for all derived classes.
-    #
     # The actual number of pointings for this device
     # will be stored as self._num_pointings.
-    MAX_POINTINGS = 1024
 
     Pointing_direction_R = attribute(access=AttrWriteType.READ,
-        dtype=((str,),), max_dim_x=3, max_dim_y=MAX_POINTINGS,
+        dtype=((str,),), max_dim_x=N_point_prop, max_dim_y=MAX_POINTINGS,
         fget=lambda self: self._pointing_direction_r)
 
     Pointing_direction_RW = attribute(access=AttrWriteType.READ_WRITE,
-        dtype=((str,),), max_dim_x=3, max_dim_y=MAX_POINTINGS,
+        dtype=((str,),), max_dim_x=N_point_prop, max_dim_y=MAX_POINTINGS,
         fget=lambda self: self._pointing_direction_rw)
 
     Pointing_direction_str_R = attribute(access=AttrWriteType.READ,
@@ -227,13 +224,13 @@ class beam_device(lofar_device):
     def configure_for_initialise(self, num_pointings):
         super().configure_for_initialise()
 
-        if not (0 < num_pointings <= self.MAX_POINTINGS):
-            raise ValueError(f"beam_device is configured to support 0 - {self.MAX_POINTINGS} pointings, but {num_pointings} were requested")
+        if not (0 < num_pointings <= MAX_POINTINGS):
+            raise ValueError(f"beam_device is configured to support 0 - {MAX_POINTINGS} pointings, but {num_pointings} were requested")
 
         # Initialise tracking control
         self._num_pointings            = num_pointings
         self._pointing_timestamp_r     = numpy.zeros(num_pointings, dtype=numpy.double)
-        self._pointing_direction_r     = numpy.zeros((num_pointings, 3), dtype="<U32")
+        self._pointing_direction_r     = numpy.zeros((num_pointings, N_point_prop), dtype="<U32")
         self._pointing_direction_rw    = numpy.array([["AZELGEO","0deg","90deg"]] * num_pointings, dtype="<U32")
         self._tracking_enabled_rw      = self.Tracking_enabled_RW_default
 
diff --git a/tangostationcontrol/tangostationcontrol/devices/boot.py b/tangostationcontrol/tangostationcontrol/devices/boot.py
index 42ce74d74c7efc6ca27d4b4ef8a53988441fd04a..6e40c0446ecb2aacde464bae7650c511c6409c0b 100644
--- a/tangostationcontrol/tangostationcontrol/devices/boot.py
+++ b/tangostationcontrol/tangostationcontrol/devices/boot.py
@@ -25,9 +25,9 @@ import numpy
 from tangostationcontrol.devices.device_decorators import only_in_states
 
 from tangostationcontrol.common.entrypoint import entry
-from tangostationcontrol.devices.lofar_device import lofar_device
 from tangostationcontrol.common.lofar_logging import device_logging_to_python, log_exceptions
 from tangostationcontrol.common.states import OPERATIONAL_STATES
+from tangostationcontrol.devices.lofar_device import lofar_device
 
 import logging
 logger = logging.getLogger()
@@ -52,6 +52,7 @@ class DevicesInitialiser(object):
         the start() method, and progress can be followed by inspecting the
         members progress (0-100), status (string), and is_running() (bool).
     """
+
     def __init__(self, device_names, reboot=False, initialise_hardware=True, proxy_timeout=60.0):
         self.reboot = reboot
         self.initialise_hardware = initialise_hardware
@@ -213,6 +214,10 @@ class DevicesInitialiser(object):
 
 @device_logging_to_python()
 class Boot(lofar_device):
+
+    # maximum number of devices boot.py supports
+    MAX_BOOT_DEVICES = 128
+
     # -----------------
     # Device Properties
     # -----------------
@@ -260,8 +265,8 @@ class Boot(lofar_device):
     booting_R = attribute(dtype=bool, access=AttrWriteType.READ, fget=lambda self: self.initialiser.is_running(), doc="Whether booting is in progress.")
     progress_R = attribute(dtype=numpy.int32, access=AttrWriteType.READ, fget=lambda self: numpy.int32(self.initialiser.progress), doc="Percentage of devices that was initialised")
     status_R = attribute(dtype=str, access=AttrWriteType.READ, fget=lambda self: self.initialiser.status, doc="Description of current boot activity")
-    initialised_devices_R = attribute(dtype=(str,), max_dim_x=128, access=AttrWriteType.READ, fget=lambda self: [name for name,initialised in self.initialiser.device_initialised.items() if initialised], doc="Which devices were initialised succesfully")
-    uninitialised_devices_R = attribute(dtype=(str,), max_dim_x=128, access=AttrWriteType.READ, fget=lambda self: [name for name,initialised in self.initialiser.device_initialised.items() if not initialised], doc="Which devices have not been initialised or failed to initialise")
+    initialised_devices_R = attribute(dtype=(str,), max_dim_x=MAX_BOOT_DEVICES, access=AttrWriteType.READ, fget=lambda self: [name for name, initialised in self.initialiser.device_initialised.items() if initialised], doc="Which devices were initialised succesfully")
+    uninitialised_devices_R = attribute(dtype=(str,), max_dim_x=MAX_BOOT_DEVICES, access=AttrWriteType.READ, fget=lambda self: [name for name, initialised in self.initialiser.device_initialised.items() if not initialised], doc="Which devices have not been initialised or failed to initialise")
 
     # --------
     # overloaded functions
diff --git a/tangostationcontrol/tangostationcontrol/devices/ccd.py b/tangostationcontrol/tangostationcontrol/devices/ccd.py
index b17184d29c2ffdbead1dc1a72e086c5d07b6dea3..ae95b6657ad96bbe8089062ba9aaf8df6c35a01d 100644
--- a/tangostationcontrol/tangostationcontrol/devices/ccd.py
+++ b/tangostationcontrol/tangostationcontrol/devices/ccd.py
@@ -22,6 +22,7 @@ from tangostationcontrol.clients.attribute_wrapper import attribute_wrapper
 from tangostationcontrol.common.entrypoint import entry
 from tangostationcontrol.common.lofar_logging import device_logging_to_python
 from tangostationcontrol.common.states import DEFAULT_COMMAND_STATES
+from tangostationcontrol.common.constants import DEFAULT_POLLING_PERIOD
 from tangostationcontrol.devices.device_decorators import only_in_states
 from tangostationcontrol.devices.opcua_device import opcua_device
 
@@ -91,7 +92,7 @@ class CCD(opcua_device):
                 not self.read_attribute("CCD_PLL_locked_R")]
         return any(errors)
 
-    CCD_TEMP_error_R            = attribute(dtype=bool, fisallowed="is_attribute_access_allowed", polling_period=1000)
+    CCD_TEMP_error_R            = attribute(dtype=bool, fisallowed="is_attribute_access_allowed", polling_period=DEFAULT_POLLING_PERIOD)
     CCD_VOUT_error_R            = attribute(dtype=bool, fisallowed="is_attribute_access_allowed")
 
     def read_CCD_TEMP_error_R(self):
diff --git a/tangostationcontrol/tangostationcontrol/devices/lofar_device.py b/tangostationcontrol/tangostationcontrol/devices/lofar_device.py
index b3b9d2bfa469d19f8aa58b4e7b253b015c18e438..662c3303289549f74495d1179a718bcdaa7ab939 100644
--- a/tangostationcontrol/tangostationcontrol/devices/lofar_device.py
+++ b/tangostationcontrol/tangostationcontrol/devices/lofar_device.py
@@ -390,7 +390,7 @@ class lofar_device(Device, metaclass=DeviceMeta):
                     # 2D array -> reshape 1D default
                     default_value = numpy.array(default_value).reshape(max_dim_y, max_dim_x)
 
-                # set the attribute to the configured default
+                # set the attribute to the configured default. Shorten after 150 characters
                 logger.debug(textwrap.shorten(f"Setting attribute {name} to {default_value}", 150))
                 self.proxy.write_attribute(name, default_value)
             except Exception as e:
diff --git a/tangostationcontrol/tangostationcontrol/devices/observation.py b/tangostationcontrol/tangostationcontrol/devices/observation.py
index 56b55a40288d7f483cc04f3185cfbc51ebabdc91..cae2bd23855efab552b98521fe338986fb09e5e0 100644
--- a/tangostationcontrol/tangostationcontrol/devices/observation.py
+++ b/tangostationcontrol/tangostationcontrol/devices/observation.py
@@ -14,12 +14,11 @@ import numpy
 from tangostationcontrol.common.entrypoint import entry
 from tangostationcontrol.common.lofar_logging import device_logging_to_python
 from tangostationcontrol.common.lofar_logging import log_exceptions
+from tangostationcontrol.common.constants import DEFAULT_POLLING_PERIOD, MAX_ANTENNA, N_beamlets_ctrl, N_point_prop
 from tangostationcontrol.devices.device_decorators import fault_on_error
 from tangostationcontrol.devices.device_decorators import only_when_on
 from tangostationcontrol.devices.device_decorators import only_in_states
 from tangostationcontrol.devices.lofar_device import lofar_device
-from tangostationcontrol.devices.antennafield import MAX_NUMBER_OF_HBAT
-from tangostationcontrol.devices.sdp.digitalbeam import DigitalBeam
 
 from datetime import datetime
 from json import loads
@@ -41,20 +40,18 @@ class Observation(lofar_device):
     The lifecycle of instances of this device is controlled by ObservationControl
     """
 
-    NUM_MAX_HBAT = MAX_NUMBER_OF_HBAT
-    MAX_INPUTS = DigitalBeam.MAX_INPUTS
-    NUM_BEAMLETS = DigitalBeam.NUM_BEAMLETS
+
 
     # Attributes
-    observation_running_R = attribute(dtype=numpy.float64, access=AttrWriteType.READ, polling_period=1000, period=1000,
+    observation_running_R = attribute(dtype=numpy.float64, access=AttrWriteType.READ, polling_period=DEFAULT_POLLING_PERIOD, period=DEFAULT_POLLING_PERIOD,
                                       rel_change="1.0")
     observation_id_R = attribute(dtype=numpy.int64, access=AttrWriteType.READ)
     stop_time_R = attribute(dtype=numpy.float64, access=AttrWriteType.READ)
-    antenna_mask_R = attribute(dtype=(numpy.int64,), max_dim_x=NUM_MAX_HBAT, access=AttrWriteType.READ)
+    antenna_mask_R = attribute(dtype=(numpy.int64,), max_dim_x=MAX_ANTENNA, access=AttrWriteType.READ)
     filter_R = attribute(dtype=numpy.str, access=AttrWriteType.READ)
-    saps_subband_R = attribute(dtype=((numpy.uint32,),), max_dim_x=MAX_INPUTS, max_dim_y=NUM_BEAMLETS, access=AttrWriteType.READ)
-    saps_pointing_R = attribute(dtype=((numpy.str,),), max_dim_x=3, max_dim_y=NUM_BEAMLETS, access=AttrWriteType.READ)
-    tile_beam_R = attribute(dtype=(numpy.str,), max_dim_x=3, access=AttrWriteType.READ)
+    saps_subband_R = attribute(dtype=((numpy.uint32,),), max_dim_x=N_beamlets_ctrl, max_dim_y=N_beamlets_ctrl, access=AttrWriteType.READ)
+    saps_pointing_R = attribute(dtype=((numpy.str,),), max_dim_x=N_point_prop, max_dim_y=N_beamlets_ctrl, access=AttrWriteType.READ)
+    tile_beam_R = attribute(dtype=(numpy.str,), max_dim_x=N_point_prop, access=AttrWriteType.READ)
     first_beamlet_R = attribute(dtype=numpy.int64, access=AttrWriteType.READ)
 
     observation_settings_RW = attribute(dtype=str, access=AttrWriteType.READ_WRITE)
@@ -246,8 +243,8 @@ class Observation(lofar_device):
             retrieve the RCU band from filter name, returning the correct format for 
             AntennaField device
         """
-        ANT_mask_RW = [False] * self.NUM_MAX_HBAT
-        RCU_band_select_RW = [0] * self.NUM_MAX_HBAT
+        ANT_mask_RW = [False] * MAX_ANTENNA
+        RCU_band_select_RW = [0] * MAX_ANTENNA
         rcu_band = self.recv_proxy.get_rcu_band_from_filter(filter_name)
         for a in antenna_mask:
             ANT_mask_RW[a] = True
@@ -273,10 +270,10 @@ class Observation(lofar_device):
 
     def _apply_saps_antenna_select(self, antenna_mask:list):
         """ Convert an array of antenna indexes into a boolean select array"""
-        antenna_select = numpy.array([[False] * self.NUM_BEAMLETS] * self._num_inputs)
+        antenna_select = numpy.array([[False] * N_beamlets_ctrl] * self._num_inputs)
         first_beamlet = numpy.array(self.read_first_beamlet_R(), dtype=numpy.int64)
         for a in antenna_mask:
-            for i in range(first_beamlet, self.NUM_BEAMLETS):
+            for i in range(first_beamlet, N_beamlets_ctrl):
                 antenna_select[a,i] = True
         return antenna_select
 
diff --git a/tangostationcontrol/tangostationcontrol/devices/psoc.py b/tangostationcontrol/tangostationcontrol/devices/psoc.py
index 0c83360c78b570f27da96fcb3e8316f0cdd72334..31e1393cec0c5ab09633fa8566fc8deef956b13a 100644
--- a/tangostationcontrol/tangostationcontrol/devices/psoc.py
+++ b/tangostationcontrol/tangostationcontrol/devices/psoc.py
@@ -32,6 +32,10 @@ __all__ = ["PSOC", "main"]
 
 @device_logging_to_python()
 class PSOC(snmp_device):
+
+    # number of sockets the psoc has
+    PSOC_SOCKETS = 8
+
     # -----------------
     # Device Properties
     # -----------------
@@ -43,7 +47,7 @@ class PSOC(snmp_device):
     # ----------
     # Attributes
     # ----------
-    sockets_state_R = attribute_wrapper(comms_annotation={"mib": "PowerNet-MIB", "name": "sPDUOutletCtl", "index": 1}, dims=(8,), datatype=str)
+    sockets_state_R = attribute_wrapper(comms_annotation={"mib": "PowerNet-MIB", "name": "sPDUOutletCtl", "index": 1}, dims=(PSOC_SOCKETS,), datatype=str)
     master_state_R = attribute_wrapper(comms_annotation={"mib": "PowerNet-MIB", "name": "sPDUMasterState"}, datatype=str)
     current_load_R = attribute_wrapper(comms_annotation={"mib": "PowerNet-MIB", "name": "rPDULoadStatusLoad", "index": 1}, datatype=numpy.int64)
     uptime_R = attribute_wrapper(comms_annotation={"mib": "SNMPv2-MIB", "name": "sysUpTime"}, datatype=numpy.int64)
@@ -52,14 +56,12 @@ class PSOC(snmp_device):
     # overloaded functions
     # --------
 
-    PSOC_NOF_SOCKETS = 8
-
     @log_exceptions()
     def configure_for_initialise(self):
         """ user code here. is called when the state is set to STANDBY """
 
         # make sure all sockets are named
-        if len(self.PSOC_sockets) != self.PSOC_NOF_SOCKETS:
+        if len(self.PSOC_sockets) != self.PSOC_SOCKETS:
             raise Exception(
                 f"At least {self.PSOC_NOF_SOCKETS} names are required to be given. You can simply leave any unused sockets as empty strings")
         else:
diff --git a/tangostationcontrol/tangostationcontrol/devices/recv.py b/tangostationcontrol/tangostationcontrol/devices/recv.py
index cfbb7a9f014c8d6337f125ac517e07f49ba0cf09..3c1b81ae137fdf93646b11b8b0fc061c475503b2 100644
--- a/tangostationcontrol/tangostationcontrol/devices/recv.py
+++ b/tangostationcontrol/tangostationcontrol/devices/recv.py
@@ -23,6 +23,7 @@ import numpy
 from tangostationcontrol.common.entrypoint import entry
 from tangostationcontrol.common.lofar_logging import device_logging_to_python
 from tangostationcontrol.common.states import DEFAULT_COMMAND_STATES
+from tangostationcontrol.common.constants import N_rcu, N_elements, N_pol, N_rcu_inp, DEFAULT_POLLING_PERIOD
 from tangostationcontrol.clients.attribute_wrapper import attribute_wrapper
 from tangostationcontrol.devices.device_decorators import only_in_states
 from tangostationcontrol.devices.opcua_device import opcua_device
@@ -56,31 +57,31 @@ class RECV(opcua_device):
     ANT_mask_RW_default = device_property(
         dtype='DevVarBooleanArray',
         mandatory=False,
-        default_value=[True] * 96
+        default_value=[True] * N_rcu * N_rcu_inp
     )
 
     RCU_mask_RW_default = device_property(
         dtype='DevVarBooleanArray',
         mandatory=False,
-        default_value=[True] * 32
+        default_value=[True] * N_rcu
     )
 
     RCU_attenuator_dB_RW_default = device_property(
         dtype='DevVarLong64Array',
         mandatory=False,
-        default_value=[0] * 96
+        default_value=[0] * N_rcu * N_rcu_inp
     )
 
     RCU_band_select_RW_default = device_property(
         dtype='DevVarLong64Array',
         mandatory=False,
-        default_value=[0] * 96
+        default_value=[0] * N_rcu * N_rcu_inp
     )
 
     RCU_PWR_ANT_on_RW_default = device_property(
         dtype='DevVarBooleanArray',
         mandatory=False,
-        default_value=[False] * 96
+        default_value=[False] * N_rcu * N_rcu_inp
         # turn power off by default in test setups, f.e. to prevent blowing up the noise sources
     )
 
@@ -132,69 +133,70 @@ class RECV(opcua_device):
         doc='Signal input delay calibration values for the elements within a tile.',
         dtype='DevVarFloatArray',
         mandatory=False,
-        default_value=numpy.zeros((32,), dtype=numpy.float64)
+        default_value=numpy.zeros((N_rcu,), dtype=numpy.float64)
     )
 
     # ----------
     # Attributes
     # ----------
-    ANT_mask_RW = attribute_wrapper(comms_annotation=["ANT_mask_RW"], datatype=bool, dims=(96,),
+
+    ANT_mask_RW = attribute_wrapper(comms_annotation=["ANT_mask_RW"], datatype=bool, dims=(N_rcu * N_rcu_inp,),
                                     access=AttrWriteType.READ_WRITE)
 
     # The HBAT beamformer delays represent 32 delays for each of the 96 inputs.
     # The 32 delays deconstruct as delays[polarisation][dipole], and each delay is the number of 'delay steps' to apply (0.5ns for HBAT1).
     HBAT_BF_delay_steps_R = attribute_wrapper(comms_annotation=["HBAT_BF_delay_steps_R"], datatype=numpy.int64,
-                                              dims=(96, 16, 2))
+                                              dims=(N_rcu * N_rcu_inp, N_elements, N_pol))
     HBAT_BF_delay_steps_RW = attribute_wrapper(comms_annotation=["HBAT_BF_delay_steps_RW"], datatype=numpy.int64,
-                                               dims=(96, 16, 2), access=AttrWriteType.READ_WRITE)
-    HBAT_LED_on_R = attribute_wrapper(comms_annotation=["HBAT_LED_on_R"], datatype=bool, dims=(96, 16, 2))
-    HBAT_LED_on_RW = attribute_wrapper(comms_annotation=["HBAT_LED_on_RW"], datatype=bool, dims=(96, 16, 2),
+                                               dims=(N_rcu * N_rcu_inp, N_elements, N_pol), access=AttrWriteType.READ_WRITE)
+    HBAT_LED_on_R = attribute_wrapper(comms_annotation=["HBAT_LED_on_R"], datatype=bool, dims=(N_rcu * N_rcu_inp, N_elements, N_pol))
+    HBAT_LED_on_RW = attribute_wrapper(comms_annotation=["HBAT_LED_on_RW"], datatype=bool, dims=(N_rcu * N_rcu_inp, N_elements, N_pol),
                                        access=AttrWriteType.READ_WRITE)
-    HBAT_PWR_LNA_on_R = attribute_wrapper(comms_annotation=["HBAT_PWR_LNA_on_R"], datatype=bool, dims=(96, 16, 2))
-    HBAT_PWR_LNA_on_RW = attribute_wrapper(comms_annotation=["HBAT_PWR_LNA_on_RW"], datatype=bool, dims=(96, 16, 2),
+    HBAT_PWR_LNA_on_R = attribute_wrapper(comms_annotation=["HBAT_PWR_LNA_on_R"], datatype=bool, dims=(N_rcu * N_rcu_inp, N_elements, N_pol))
+    HBAT_PWR_LNA_on_RW = attribute_wrapper(comms_annotation=["HBAT_PWR_LNA_on_RW"], datatype=bool, dims=(N_rcu * N_rcu_inp, N_elements, N_pol),
                                            access=AttrWriteType.READ_WRITE)
-    HBAT_PWR_on_R = attribute_wrapper(comms_annotation=["HBAT_PWR_on_R"], datatype=bool, dims=(96, 16, 2))
-    HBAT_PWR_on_RW = attribute_wrapper(comms_annotation=["HBAT_PWR_on_RW"], datatype=bool, dims=(96, 16, 2),
+    HBAT_PWR_on_R = attribute_wrapper(comms_annotation=["HBAT_PWR_on_R"], datatype=bool, dims=(N_rcu * N_rcu_inp, N_elements, N_pol))
+    HBAT_PWR_on_RW = attribute_wrapper(comms_annotation=["HBAT_PWR_on_RW"], datatype=bool, dims=(N_rcu * N_rcu_inp, N_elements, N_pol),
                                        access=AttrWriteType.READ_WRITE)
-    RCU_ADC_locked_R = attribute_wrapper(comms_annotation=["RCU_ADC_locked_R"], datatype=bool, dims=(32, 3))
+    RCU_ADC_locked_R = attribute_wrapper(comms_annotation=["RCU_ADC_locked_R"], datatype=bool, dims=(N_rcu, N_rcu_inp))
     RCU_attenuator_dB_R = attribute_wrapper(comms_annotation=["RCU_attenuator_dB_R"], datatype=numpy.int64,
-                                            dims=(32, 3))
+                                            dims=(N_rcu, N_rcu_inp))
     RCU_attenuator_dB_RW = attribute_wrapper(comms_annotation=["RCU_attenuator_dB_RW"], datatype=numpy.int64,
-                                             dims=(32, 3), access=AttrWriteType.READ_WRITE)
-    RCU_band_select_R = attribute_wrapper(comms_annotation=["RCU_band_select_R"], datatype=numpy.int64, dims=(32, 3))
-    RCU_band_select_RW = attribute_wrapper(comms_annotation=["RCU_band_select_RW"], datatype=numpy.int64, dims=(32, 3),
+                                             dims=(N_rcu, N_rcu_inp), access=AttrWriteType.READ_WRITE)
+    RCU_band_select_R = attribute_wrapper(comms_annotation=["RCU_band_select_R"], datatype=numpy.int64, dims=(N_rcu, N_rcu_inp))
+    RCU_band_select_RW = attribute_wrapper(comms_annotation=["RCU_band_select_RW"], datatype=numpy.int64, dims=(N_rcu, N_rcu_inp),
                                            access=AttrWriteType.READ_WRITE)
-    RCU_DTH_freq_R = attribute_wrapper(comms_annotation=["RCU_DTH_freq_R"], datatype=numpy.int64, dims=(32, 3))
-    RCU_DTH_freq_RW = attribute_wrapper(comms_annotation=["RCU_DTH_freq_RW"], datatype=numpy.int64, dims=(32, 3),
+    RCU_DTH_freq_R = attribute_wrapper(comms_annotation=["RCU_DTH_freq_R"], datatype=numpy.int64, dims=(N_rcu, N_rcu_inp))
+    RCU_DTH_freq_RW = attribute_wrapper(comms_annotation=["RCU_DTH_freq_RW"], datatype=numpy.int64, dims=(N_rcu, N_rcu_inp),
                                         access=AttrWriteType.READ_WRITE)
-    RCU_DTH_on_R = attribute_wrapper(comms_annotation=["RCU_DTH_on_R"], datatype=bool, dims=(32, 3))
-    RCU_LED_green_on_R = attribute_wrapper(comms_annotation=["RCU_LED_green_on_R"], datatype=bool, dims=(32,))
-    RCU_LED_green_on_RW = attribute_wrapper(comms_annotation=["RCU_LED_green_on_RW"], datatype=bool, dims=(32,),
+    RCU_DTH_on_R = attribute_wrapper(comms_annotation=["RCU_DTH_on_R"], datatype=bool, dims=(N_rcu, N_rcu_inp))
+    RCU_LED_green_on_R = attribute_wrapper(comms_annotation=["RCU_LED_green_on_R"], datatype=bool, dims=(N_rcu,))
+    RCU_LED_green_on_RW = attribute_wrapper(comms_annotation=["RCU_LED_green_on_RW"], datatype=bool, dims=(N_rcu,),
                                             access=AttrWriteType.READ_WRITE)
-    RCU_LED_red_on_R = attribute_wrapper(comms_annotation=["RCU_LED_red_on_R"], datatype=bool, dims=(32,))
-    RCU_LED_red_on_RW = attribute_wrapper(comms_annotation=["RCU_LED_red_on_RW"], datatype=bool, dims=(32,),
+    RCU_LED_red_on_R = attribute_wrapper(comms_annotation=["RCU_LED_red_on_R"], datatype=bool, dims=(N_rcu,))
+    RCU_LED_red_on_RW = attribute_wrapper(comms_annotation=["RCU_LED_red_on_RW"], datatype=bool, dims=(N_rcu,),
                                           access=AttrWriteType.READ_WRITE)
-    RCU_mask_RW = attribute_wrapper(comms_annotation=["RCU_mask_RW"], datatype=bool, dims=(32,),
+    RCU_mask_RW = attribute_wrapper(comms_annotation=["RCU_mask_RW"], datatype=bool, dims=(N_rcu,),
                                     access=AttrWriteType.READ_WRITE)
-    RCU_PCB_ID_R = attribute_wrapper(comms_annotation=["RCU_PCB_ID_R"], datatype=numpy.int64, dims=(32,))
-    RCU_PCB_number_R = attribute_wrapper(comms_annotation=["RCU_PCB_number_R"], datatype=str, dims=(32,))
-    RCU_PCB_version_R = attribute_wrapper(comms_annotation=["RCU_PCB_version_R"], datatype=str, dims=(32,))
-    RCU_PWR_1V8_R = attribute_wrapper(comms_annotation=["RCU_PWR_1V8_R"], datatype=numpy.float64, dims=(32,))
-    RCU_PWR_2V5_R = attribute_wrapper(comms_annotation=["RCU_PWR_2V5_R"], datatype=numpy.float64, dims=(32,))
-    RCU_PWR_3V3_R = attribute_wrapper(comms_annotation=["RCU_PWR_3V3_R"], datatype=numpy.float64, dims=(32,))
-    RCU_PWR_ANALOG_on_R = attribute_wrapper(comms_annotation=["RCU_PWR_ANALOG_on_R"], datatype=bool, dims=(32,))
+    RCU_PCB_ID_R = attribute_wrapper(comms_annotation=["RCU_PCB_ID_R"], datatype=numpy.int64, dims=(N_rcu,))
+    RCU_PCB_number_R = attribute_wrapper(comms_annotation=["RCU_PCB_number_R"], datatype=str, dims=(N_rcu,))
+    RCU_PCB_version_R = attribute_wrapper(comms_annotation=["RCU_PCB_version_R"], datatype=str, dims=(N_rcu,))
+    RCU_PWR_1V8_R = attribute_wrapper(comms_annotation=["RCU_PWR_1V8_R"], datatype=numpy.float64, dims=(N_rcu,))
+    RCU_PWR_2V5_R = attribute_wrapper(comms_annotation=["RCU_PWR_2V5_R"], datatype=numpy.float64, dims=(N_rcu,))
+    RCU_PWR_3V3_R = attribute_wrapper(comms_annotation=["RCU_PWR_3V3_R"], datatype=numpy.float64, dims=(N_rcu,))
+    RCU_PWR_ANALOG_on_R = attribute_wrapper(comms_annotation=["RCU_PWR_ANALOG_on_R"], datatype=bool, dims=(N_rcu,))
     RCU_PWR_ANT_IOUT_R = attribute_wrapper(comms_annotation=["RCU_PWR_ANT_IOUT_R"], datatype=numpy.float64,
-                                           dims=(32, 3))
-    RCU_PWR_ANT_on_R = attribute_wrapper(comms_annotation=["RCU_PWR_ANT_on_R"], datatype=bool, dims=(32, 3))
-    RCU_PWR_ANT_on_RW = attribute_wrapper(comms_annotation=["RCU_PWR_ANT_on_RW"], datatype=bool, dims=(32, 3),
+                                           dims=(N_rcu, N_rcu_inp))
+    RCU_PWR_ANT_on_R = attribute_wrapper(comms_annotation=["RCU_PWR_ANT_on_R"], datatype=bool, dims=(N_rcu, N_rcu_inp))
+    RCU_PWR_ANT_on_RW = attribute_wrapper(comms_annotation=["RCU_PWR_ANT_on_RW"], datatype=bool, dims=(N_rcu, N_rcu_inp),
                                           access=AttrWriteType.READ_WRITE)
-    RCU_PWR_ANT_VIN_R = attribute_wrapper(comms_annotation=["RCU_PWR_ANT_VIN_R"], datatype=numpy.float64, dims=(32, 3))
+    RCU_PWR_ANT_VIN_R = attribute_wrapper(comms_annotation=["RCU_PWR_ANT_VIN_R"], datatype=numpy.float64, dims=(N_rcu, N_rcu_inp))
     RCU_PWR_ANT_VOUT_R = attribute_wrapper(comms_annotation=["RCU_PWR_ANT_VOUT_R"], datatype=numpy.float64,
-                                           dims=(32, 3))
-    RCU_PWR_DIGITAL_on_R = attribute_wrapper(comms_annotation=["RCU_PWR_DIGITAL_on_R"], datatype=bool, dims=(32,))
-    RCU_PWR_good_R = attribute_wrapper(comms_annotation=["RCU_PWR_good_R"], datatype=bool, dims=(32,))
-    RCU_TEMP_R = attribute_wrapper(comms_annotation=["RCU_TEMP_R"], datatype=numpy.float64, dims=(32,))
-    RECVTR_I2C_error_R = attribute_wrapper(comms_annotation=["RECVTR_I2C_error_R"], datatype=numpy.int64, dims=(32,))
+                                           dims=(N_rcu, N_rcu_inp))
+    RCU_PWR_DIGITAL_on_R = attribute_wrapper(comms_annotation=["RCU_PWR_DIGITAL_on_R"], datatype=bool, dims=(N_rcu,))
+    RCU_PWR_good_R = attribute_wrapper(comms_annotation=["RCU_PWR_good_R"], datatype=bool, dims=(N_rcu,))
+    RCU_TEMP_R = attribute_wrapper(comms_annotation=["RCU_TEMP_R"], datatype=numpy.float64, dims=(N_rcu,))
+    RECVTR_I2C_error_R = attribute_wrapper(comms_annotation=["RECVTR_I2C_error_R"], datatype=numpy.int64, dims=(N_rcu,))
     RECVTR_monitor_rate_RW = attribute_wrapper(comms_annotation=["RECVTR_monitor_rate_RW"], datatype=numpy.int64,
                                                access=AttrWriteType.READ_WRITE)
     RECVTR_translator_busy_R = attribute_wrapper(comms_annotation=["RECVTR_translator_busy_R"], datatype=bool)
@@ -202,14 +204,14 @@ class RECV(opcua_device):
     # ----------
     # Summarising Attributes
     # ----------
-    RCU_LED_colour_R = attribute(dtype=(numpy.uint32,), max_dim_x=32, fisallowed="is_attribute_access_allowed")
+    RCU_LED_colour_R = attribute(dtype=(numpy.uint32,), max_dim_x=N_rcu, fisallowed="is_attribute_access_allowed")
 
     def read_RCU_LED_colour_R(self):
         return (2 * self.read_attribute("RCU_LED_green_on_R") + 4 * self.read_attribute("RCU_LED_red_on_R")).astype(
             numpy.uint32)
 
-    RCU_error_R = attribute(dtype=(bool,), max_dim_x=32, fisallowed="is_attribute_access_allowed")
-    ANT_error_R = attribute(dtype=(bool,), max_dim_x=96, fisallowed="is_attribute_access_allowed")
+    RCU_error_R = attribute(dtype=(bool,), max_dim_x=N_rcu, fisallowed="is_attribute_access_allowed")
+    ANT_error_R = attribute(dtype=(bool,), max_dim_x=N_rcu * N_rcu_inp, fisallowed="is_attribute_access_allowed")
 
     def read_RCU_error_R(self):
         return self.read_attribute("RCU_mask_RW") & (
@@ -222,10 +224,10 @@ class RECV(opcua_device):
             ~self.read_attribute("RCU_ADC_locked_R").flatten()
         )
 
-    RECV_IOUT_error_R = attribute(dtype=(bool,), max_dim_x=96, fisallowed="is_attribute_access_allowed")
-    RECV_TEMP_error_R = attribute(dtype=(bool,), max_dim_x=32, fisallowed="is_attribute_access_allowed",
-                                  polling_period=1000)
-    RECV_VOUT_error_R = attribute(dtype=(bool,), max_dim_x=32, fisallowed="is_attribute_access_allowed")
+    RECV_IOUT_error_R = attribute(dtype=(bool,), max_dim_x=N_rcu * N_rcu_inp, fisallowed="is_attribute_access_allowed")
+    RECV_TEMP_error_R = attribute(dtype=(bool,), max_dim_x=N_rcu, fisallowed="is_attribute_access_allowed",
+                                  polling_period=DEFAULT_POLLING_PERIOD)
+    RECV_VOUT_error_R = attribute(dtype=(bool,), max_dim_x=N_rcu, fisallowed="is_attribute_access_allowed")
 
     def read_RECV_IOUT_error_R(self):
         return self.read_attribute("ANT_mask_RW") & (
@@ -242,7 +244,7 @@ class RECV(opcua_device):
         return (self.read_attribute("ANT_mask_RW") & (
                 self.alarm_val("RCU_PWR_ANT_VIN_R").flatten()
                 | self.alarm_val("RCU_PWR_ANT_VOUT_R").flatten()
-        )).reshape(32, 3).any(axis=1) | (self.read_attribute("RCU_mask_RW") & (
+        )).reshape(N_rcu,N_rcu_inp).any(axis=1) | (self.read_attribute("RCU_mask_RW") & (
                 self.alarm_val("RCU_PWR_1V8_R")
                 | self.alarm_val("RCU_PWR_2V5_R")
                 | self.alarm_val("RCU_PWR_3V3_R")
@@ -280,7 +282,7 @@ class RECV(opcua_device):
         # Save actual mask values
         RCU_mask = self.proxy.RCU_mask_RW
         # Set the mask to all Trues
-        self.RCU_mask_RW = [True] * 32
+        self.RCU_mask_RW = [True] * N_rcu
         # Turn off the RCUs
         self.RCU_off()
         self.wait_attribute("RECVTR_translator_busy_R", False, self.RCU_On_Off_timeout)
@@ -296,7 +298,7 @@ class RECV(opcua_device):
         which is a value per tile per dipole per polarisation.
         """
         # Duplicate delay values per polarisation
-        polarised_delays = numpy.repeat(delays, 2, axis=1)  # output dims -> 96x32
+        polarised_delays = numpy.repeat(delays, N_pol, axis=1)  # output dims -> 96x32
 
         # Add signal input delay
         calibrated_delays = numpy.add(polarised_delays, self.HBAT_signal_input_delays)
@@ -318,7 +320,7 @@ class RECV(opcua_device):
         """ converts a signal path delay (in seconds) to an analog beam weight """
 
         # Reshape the flattened input array, into whatever how many tiles we get
-        delays = numpy.array(delays).reshape(-1, 16)
+        delays = numpy.array(delays).reshape(-1, N_elements)
 
         # Calculate the beam weight array
         HBAT_bf_delay_steps = self._calculate_HBAT_bf_delay_steps(delays)
diff --git a/tangostationcontrol/tangostationcontrol/devices/sdp/beamlet.py b/tangostationcontrol/tangostationcontrol/devices/sdp/beamlet.py
index 44532e9c4ce54340b0b5d3446e32aa06a7e7d21f..5fd05975cc88c0828e3166ef65fd589174a15896 100644
--- a/tangostationcontrol/tangostationcontrol/devices/sdp/beamlet.py
+++ b/tangostationcontrol/tangostationcontrol/devices/sdp/beamlet.py
@@ -14,9 +14,9 @@ from tango import AttrWriteType, DevVarFloatArray, DevVarULongArray, DeviceProxy
 # Additional import
 from tangostationcontrol.common.entrypoint import entry
 from tangostationcontrol.common.lofar_logging import log_exceptions
+from tangostationcontrol.common.constants import N_pn, A_pn, N_pol, N_beamlets_ctrl, N_beamsets_ctrl, P_sum, N_subband_res, N_subbands, DEFAULT_SUBBAND
 from tangostationcontrol.clients.attribute_wrapper import attribute_wrapper
 from tangostationcontrol.devices.opcua_device import opcua_device
-from tangostationcontrol.devices.sdp.sdp import SDP
 
 import numpy
 from functools import lru_cache
@@ -29,16 +29,6 @@ logger = logging.getLogger()
 
 class Beamlet(opcua_device):
 
-    # List of OPC-UA CP for BF beamlets
-    S_PN = SDP.S_pn
-    N_PN = SDP.N_pn
-    A_PN = 6
-    N_POL = 2
-    N_BEAMLETS_CTRL = 488
-    N_BEAMSETS_CTRL = SDP.N_beamsets_ctrl
-    N_POL_BF = 2
-    P_SUM = 2   # number of hops that the data of the stream has traveled to reach the BSN aligner on this node
-
     # -----------------
     # Device Properties
     # -----------------
@@ -76,25 +66,25 @@ class Beamlet(opcua_device):
     FPGA_beamlet_output_enable_RW_default = device_property(
         dtype='DevVarBooleanArray',
         mandatory=False,
-        default_value=[False] * 16
+        default_value=[False] * N_pn
     )
 
     FPGA_beamlet_output_scale_RW_default = device_property(
         dtype='DevVarDoubleArray',
         mandatory=False,
-        default_value=[1.0] * 16
+        default_value=[1.0] * N_pn
     )
 
     FPGA_bf_weights_xy_yx_RW_default = device_property(
         dtype='DevVarULongArray',
         mandatory=False,
-        default_value = [0] * N_PN * A_PN * N_POL * N_BEAMLETS_CTRL
+        default_value =[0] * N_pn * A_pn * N_pol * N_beamlets_ctrl
     )
 
     subband_select_RW_default = device_property(
         dtype='DevVarULongArray',
         mandatory=False,
-        default_value = [102] * N_BEAMLETS_CTRL
+        default_value =[DEFAULT_SUBBAND] * N_beamlets_ctrl
     )
 
     FIRST_DEFAULT_SETTINGS = [
@@ -112,90 +102,90 @@ class Beamlet(opcua_device):
     # Attributes
     # ----------
 
-    FPGA_beamlet_output_enable_R = attribute_wrapper(comms_annotation=["FPGA_beamlet_output_enable_R"], datatype=bool, dims=(N_PN,))
-    FPGA_beamlet_output_enable_RW = attribute_wrapper(comms_annotation=["FPGA_beamlet_output_enable_RW"], datatype=bool, dims=(N_PN,), access=AttrWriteType.READ_WRITE)   
+    FPGA_beamlet_output_enable_R = attribute_wrapper(comms_annotation=["FPGA_beamlet_output_enable_R"], datatype=bool, dims=(N_pn,))
+    FPGA_beamlet_output_enable_RW = attribute_wrapper(comms_annotation=["FPGA_beamlet_output_enable_RW"], datatype=bool, dims=(N_pn,), access=AttrWriteType.READ_WRITE)   
     
-    FPGA_beamlet_output_hdr_eth_source_mac_R = attribute_wrapper(comms_annotation=["FPGA_beamlet_output_hdr_eth_source_mac_R"], datatype=str, dims=(N_PN,))
-    FPGA_beamlet_output_hdr_eth_source_mac_RW = attribute_wrapper(comms_annotation=["FPGA_beamlet_output_hdr_eth_source_mac_RW"], datatype=str, dims=(N_PN,), access=AttrWriteType.READ_WRITE)
-    FPGA_beamlet_output_hdr_ip_source_address_R = attribute_wrapper(comms_annotation=["FPGA_beamlet_output_hdr_ip_source_address_R"], datatype=str, dims=(N_PN,))
-    FPGA_beamlet_output_hdr_ip_source_address_RW = attribute_wrapper(comms_annotation=["FPGA_beamlet_output_hdr_ip_source_address_RW"], datatype=str, dims=(N_PN,), access=AttrWriteType.READ_WRITE)
-    FPGA_beamlet_output_hdr_udp_source_port_R = attribute_wrapper(comms_annotation=["FPGA_beamlet_output_hdr_udp_source_port_R"], datatype=numpy.uint16, dims=(N_PN,))
-    FPGA_beamlet_output_hdr_udp_source_port_RW = attribute_wrapper(comms_annotation=["FPGA_beamlet_output_hdr_udp_source_port_RW"], datatype=numpy.uint16, dims=(N_PN,), access=AttrWriteType.READ_WRITE)
+    FPGA_beamlet_output_hdr_eth_source_mac_R = attribute_wrapper(comms_annotation=["FPGA_beamlet_output_hdr_eth_source_mac_R"], datatype=str, dims=(N_pn,))
+    FPGA_beamlet_output_hdr_eth_source_mac_RW = attribute_wrapper(comms_annotation=["FPGA_beamlet_output_hdr_eth_source_mac_RW"], datatype=str, dims=(N_pn,), access=AttrWriteType.READ_WRITE)
+    FPGA_beamlet_output_hdr_ip_source_address_R = attribute_wrapper(comms_annotation=["FPGA_beamlet_output_hdr_ip_source_address_R"], datatype=str, dims=(N_pn,))
+    FPGA_beamlet_output_hdr_ip_source_address_RW = attribute_wrapper(comms_annotation=["FPGA_beamlet_output_hdr_ip_source_address_RW"], datatype=str, dims=(N_pn,), access=AttrWriteType.READ_WRITE)
+    FPGA_beamlet_output_hdr_udp_source_port_R = attribute_wrapper(comms_annotation=["FPGA_beamlet_output_hdr_udp_source_port_R"], datatype=numpy.uint16, dims=(N_pn,))
+    FPGA_beamlet_output_hdr_udp_source_port_RW = attribute_wrapper(comms_annotation=["FPGA_beamlet_output_hdr_udp_source_port_RW"], datatype=numpy.uint16, dims=(N_pn,), access=AttrWriteType.READ_WRITE)
     
-    FPGA_beamlet_output_hdr_eth_destination_mac_R = attribute_wrapper(comms_annotation=["FPGA_beamlet_output_hdr_eth_destination_mac_R"], datatype=str, dims=(N_PN,))
-    FPGA_beamlet_output_hdr_eth_destination_mac_RW = attribute_wrapper(comms_annotation=["FPGA_beamlet_output_hdr_eth_destination_mac_RW"], datatype=str, dims=(N_PN,), access=AttrWriteType.READ_WRITE)
-    FPGA_beamlet_output_hdr_ip_destination_address_R = attribute_wrapper(comms_annotation=["FPGA_beamlet_output_hdr_ip_destination_address_R"], datatype=str, dims=(N_PN,))
-    FPGA_beamlet_output_hdr_ip_destination_address_RW = attribute_wrapper(comms_annotation=["FPGA_beamlet_output_hdr_ip_destination_address_RW"], datatype=str, dims=(N_PN,), access=AttrWriteType.READ_WRITE)
-    FPGA_beamlet_output_hdr_udp_destination_port_R = attribute_wrapper(comms_annotation=["FPGA_beamlet_output_hdr_udp_destination_port_R"], datatype=numpy.uint16, dims=(N_PN,))
-    FPGA_beamlet_output_hdr_udp_destination_port_RW = attribute_wrapper(comms_annotation=["FPGA_beamlet_output_hdr_udp_destination_port_RW"], datatype=numpy.uint16, dims=(N_PN,), access=AttrWriteType.READ_WRITE)
+    FPGA_beamlet_output_hdr_eth_destination_mac_R = attribute_wrapper(comms_annotation=["FPGA_beamlet_output_hdr_eth_destination_mac_R"], datatype=str, dims=(N_pn,))
+    FPGA_beamlet_output_hdr_eth_destination_mac_RW = attribute_wrapper(comms_annotation=["FPGA_beamlet_output_hdr_eth_destination_mac_RW"], datatype=str, dims=(N_pn,), access=AttrWriteType.READ_WRITE)
+    FPGA_beamlet_output_hdr_ip_destination_address_R = attribute_wrapper(comms_annotation=["FPGA_beamlet_output_hdr_ip_destination_address_R"], datatype=str, dims=(N_pn,))
+    FPGA_beamlet_output_hdr_ip_destination_address_RW = attribute_wrapper(comms_annotation=["FPGA_beamlet_output_hdr_ip_destination_address_RW"], datatype=str, dims=(N_pn,), access=AttrWriteType.READ_WRITE)
+    FPGA_beamlet_output_hdr_udp_destination_port_R = attribute_wrapper(comms_annotation=["FPGA_beamlet_output_hdr_udp_destination_port_R"], datatype=numpy.uint16, dims=(N_pn,))
+    FPGA_beamlet_output_hdr_udp_destination_port_RW = attribute_wrapper(comms_annotation=["FPGA_beamlet_output_hdr_udp_destination_port_RW"], datatype=numpy.uint16, dims=(N_pn,), access=AttrWriteType.READ_WRITE)
     
-    FPGA_beamlet_output_scale_R = attribute_wrapper(comms_annotation=["FPGA_beamlet_output_scale_R"], datatype=numpy.double, dims=(N_PN,))
-    FPGA_beamlet_output_scale_RW = attribute_wrapper(comms_annotation=["FPGA_beamlet_output_scale_RW"], datatype=numpy.double, dims=(N_PN,), access=AttrWriteType.READ_WRITE)
-    FPGA_beamlet_output_bsn_R = attribute_wrapper(comms_annotation=["FPGA_beamlet_output_bsn_R"], datatype=numpy.int64, dims=(N_PN, N_BEAMSETS_CTRL))
+    FPGA_beamlet_output_scale_R = attribute_wrapper(comms_annotation=["FPGA_beamlet_output_scale_R"], datatype=numpy.double, dims=(N_pn,))
+    FPGA_beamlet_output_scale_RW = attribute_wrapper(comms_annotation=["FPGA_beamlet_output_scale_RW"], datatype=numpy.double, dims=(N_pn,), access=AttrWriteType.READ_WRITE)
+    FPGA_beamlet_output_bsn_R = attribute_wrapper(comms_annotation=["FPGA_beamlet_output_bsn_R"], datatype=numpy.int64, dims=(N_pn, N_beamsets_ctrl))
 
-    FPGA_beamlet_output_nof_packets_R = attribute_wrapper(comms_annotation=["FPGA_beamlet_output_nof_packets_R"], datatype=numpy.int32, dims=(N_PN, N_BEAMSETS_CTRL))
-    FPGA_beamlet_output_nof_valid_R = attribute_wrapper(comms_annotation=["FPGA_beamlet_output_nof_valid_R"], datatype=numpy.int32, dims=(N_PN, N_BEAMSETS_CTRL))
+    FPGA_beamlet_output_nof_packets_R = attribute_wrapper(comms_annotation=["FPGA_beamlet_output_nof_packets_R"], datatype=numpy.int32, dims=(N_pn, N_beamsets_ctrl))
+    FPGA_beamlet_output_nof_valid_R = attribute_wrapper(comms_annotation=["FPGA_beamlet_output_nof_valid_R"], datatype=numpy.int32, dims=(N_pn, N_beamsets_ctrl))
 
-    # boolean[N_PN][N_BEAMSETS_CTRL]
-    FPGA_beamlet_output_ready_R = attribute_wrapper(comms_annotation=["FPGA_beamlet_output_ready_R"], datatype=bool, dims=(N_PN, N_BEAMSETS_CTRL))
-    # boolean[N_PN][N_BEAMSETS_CTRL]
-    FPGA_beamlet_output_xon_R = attribute_wrapper(comms_annotation=["FPGA_beamlet_output_xon_R"], datatype=bool, dims=(N_PN, N_BEAMSETS_CTRL))
+    # boolean[N_pn][N_beamsets_ctrl]
+    FPGA_beamlet_output_ready_R = attribute_wrapper(comms_annotation=["FPGA_beamlet_output_ready_R"], datatype=bool, dims=(N_pn, N_beamsets_ctrl))
+    # boolean[N_pn][N_beamsets_ctrl]
+    FPGA_beamlet_output_xon_R = attribute_wrapper(comms_annotation=["FPGA_beamlet_output_xon_R"], datatype=bool, dims=(N_pn, N_beamsets_ctrl))
 
-    # uint16[N_PN][A_PN][N_POL][N_BEAMLETS_CTRL]
+    # uint16[N_pn][A_PN][N_POL][N_beamsets_ctrl]
     # Select subband per dual-polarisation beamlet.
     # 0 for antenna polarization X in beamlet polarization X,
     # 1 for antenna polarization Y in beamlet polarization Y.
-    FPGA_beamlet_subband_select_R = attribute_wrapper(comms_annotation=["FPGA_beamlet_subband_select_R"], datatype=numpy.uint32, dims=(N_PN, A_PN, N_POL, N_BEAMLETS_CTRL))
-    FPGA_beamlet_subband_select_RW = attribute_wrapper(comms_annotation=["FPGA_beamlet_subband_select_RW"], datatype=numpy.uint32, dims=(N_PN, A_PN, N_POL, N_BEAMLETS_CTRL), access=AttrWriteType.READ_WRITE)
+    FPGA_beamlet_subband_select_R = attribute_wrapper(comms_annotation=["FPGA_beamlet_subband_select_R"], datatype=numpy.uint32, dims=(N_pn, A_pn, N_pol, N_beamlets_ctrl))
+    FPGA_beamlet_subband_select_RW = attribute_wrapper(comms_annotation=["FPGA_beamlet_subband_select_RW"], datatype=numpy.uint32, dims=(N_pn, A_pn, N_pol, N_beamlets_ctrl), access=AttrWriteType.READ_WRITE)
 
-    # uint32[N_PN][N_beamset_ctrl]
-    FPGA_bf_ring_nof_transport_hops_R = attribute_wrapper(comms_annotation=["FPGA_bf_ring_nof_transport_hops_R"], datatype=numpy.uint32, dims=(N_PN, N_BEAMSETS_CTRL))
-    FPGA_bf_ring_nof_transport_hops_RW = attribute_wrapper(comms_annotation=["FPGA_bf_ring_nof_transport_hops_RW"], datatype=numpy.uint32, dims=(N_PN, N_BEAMSETS_CTRL), access=AttrWriteType.READ_WRITE)
+    # uint32[N_pn][N_beamset_ctrl]
+    FPGA_bf_ring_nof_transport_hops_R = attribute_wrapper(comms_annotation=["FPGA_bf_ring_nof_transport_hops_R"], datatype=numpy.uint32, dims=(N_pn, N_beamsets_ctrl))
+    FPGA_bf_ring_nof_transport_hops_RW = attribute_wrapper(comms_annotation=["FPGA_bf_ring_nof_transport_hops_RW"], datatype=numpy.uint32, dims=(N_pn, N_beamsets_ctrl), access=AttrWriteType.READ_WRITE)
 
-    # cint16[N_PN][A_PN][N_POL][N_BEAMLETS_CTRL]
-    # Co-polarization BF weights. The N_POL = 2 parameter index is:
+    # cint16[N_pn][A_pn][N_pol][N_beamlets_ctrl]
+    # Co-polarization BF weights. The N_pol = 2 parameter index is:
     # 0 for antenna polarization X in beamlet polarization X,
     # 1 for antenna polarization Y in beamlet polarization Y.
-    FPGA_bf_weights_xx_yy_R = attribute_wrapper(comms_annotation=["FPGA_bf_weights_xx_yy_R"], datatype=numpy.uint32, dims=(N_PN, A_PN, N_POL, N_BEAMLETS_CTRL))
-    FPGA_bf_weights_xx_yy_RW = attribute_wrapper(comms_annotation=["FPGA_bf_weights_xx_yy_RW"], datatype=numpy.uint32, dims=(N_PN, A_PN, N_POL, N_BEAMLETS_CTRL), access=AttrWriteType.READ_WRITE)
+    FPGA_bf_weights_xx_yy_R = attribute_wrapper(comms_annotation=["FPGA_bf_weights_xx_yy_R"], datatype=numpy.uint32, dims=(N_pn, A_pn, N_pol, N_beamlets_ctrl))
+    FPGA_bf_weights_xx_yy_RW = attribute_wrapper(comms_annotation=["FPGA_bf_weights_xx_yy_RW"], datatype=numpy.uint32, dims=(N_pn, A_pn, N_pol, N_beamlets_ctrl), access=AttrWriteType.READ_WRITE)
 
-    # cint16[N_PN][A_PN][N_POL][N_BEAMLETS_CTRL]
-    # Cross-polarization BF weights. The N_POL = 2 parameter index is (note that index pol in range 0:N_POL-1 is the antenna polarization, so index !pol is the beamlet polarization):
+    # cint16[N_pn][A_pn][N_pol][N_beamlets_ctrl]
+    # Cross-polarization BF weights. The N_pol = 2 parameter index is (note that index pol in range 0:N_pol-1 is the antenna polarization, so index !pol is the beamlet polarization):
     # 0 for antenna polarization X in beamlet polarization Y,
     # 1 for antenna polarization Y in beamlet polarization X.
-    FPGA_bf_weights_xy_yx_R = attribute_wrapper(comms_annotation=["FPGA_bf_weights_xy_yx_R"], datatype=numpy.uint32, dims=(A_PN * N_POL * N_BEAMLETS_CTRL, N_PN))
-    FPGA_bf_weights_xy_yx_RW = attribute_wrapper(comms_annotation=["FPGA_bf_weights_xy_yx_RW"], datatype=numpy.uint32, dims=(A_PN * N_POL * N_BEAMLETS_CTRL, N_PN), access=AttrWriteType.READ_WRITE)
+    FPGA_bf_weights_xy_yx_R = attribute_wrapper(comms_annotation=["FPGA_bf_weights_xy_yx_R"], datatype=numpy.uint32, dims=(A_pn * N_pol * N_beamlets_ctrl, N_pn))
+    FPGA_bf_weights_xy_yx_RW = attribute_wrapper(comms_annotation=["FPGA_bf_weights_xy_yx_RW"], datatype=numpy.uint32, dims=(A_pn * N_pol * N_beamlets_ctrl, N_pn), access=AttrWriteType.READ_WRITE)
 
-    # cint16[N_PN][N_POL_BF][A_PN][N_POL][N_BEAMLETS_CTRL]
+    # cint16[N_pn][N_pol][A_pn][N_pol][N_beamlets_ctrl]
     # Full Jones matrix of BF weights.
-    FPGA_bf_weights_xx_xy_yx_yy_R = attribute_wrapper(comms_annotation=["FPGA_bf_weights_xx_xy_yx_yy_R"], datatype=numpy.uint32, dims=(N_PN, N_POL_BF, A_PN, N_POL, N_BEAMLETS_CTRL))
-    FPGA_bf_weights_xx_xy_yx_yy_RW = attribute_wrapper(comms_annotation=["FPGA_bf_weights_xx_xy_yx_yy_RW"], datatype=numpy.uint32, dims=(N_PN, N_POL_BF, A_PN, N_POL, N_BEAMLETS_CTRL), access=AttrWriteType.READ_WRITE)
+    FPGA_bf_weights_xx_xy_yx_yy_R = attribute_wrapper(comms_annotation=["FPGA_bf_weights_xx_xy_yx_yy_R"], datatype=numpy.uint32, dims=(N_pn, N_pol, A_pn, N_pol, N_beamlets_ctrl))
+    FPGA_bf_weights_xx_xy_yx_yy_RW = attribute_wrapper(comms_annotation=["FPGA_bf_weights_xx_xy_yx_yy_RW"], datatype=numpy.uint32, dims=(N_pn, N_pol, A_pn, N_pol, N_beamlets_ctrl), access=AttrWriteType.READ_WRITE)
 
-    # cint16[N_PN][A_PN][N_BEAMLETS_CTRL]
+    # cint16[N_pn][A_pn][N_beamlets_ctrl]
     # BF weights for separate access to respectively w_xx, w_xy, w_yx, and w_yy.
-    FPGA_bf_weights_xx_R = attribute_wrapper(comms_annotation=["FPGA_bf_weights_xx_R"], datatype=numpy.uint32, dims=(N_PN, A_PN, N_BEAMLETS_CTRL))
-    FPGA_bf_weights_xx_RW = attribute_wrapper(comms_annotation=["FPGA_bf_weights_xx_RW"], datatype=numpy.uint32, dims=(N_PN, A_PN * N_BEAMLETS_CTRL), access=AttrWriteType.READ_WRITE)
-    FPGA_bf_weights_xy_R = attribute_wrapper(comms_annotation=["FPGA_bf_weights_xy_R"], datatype=numpy.uint32, dims=(N_PN, A_PN, N_BEAMLETS_CTRL))
-    FPGA_bf_weights_xy_RW = attribute_wrapper(comms_annotation=["FPGA_bf_weights_xy_RW"], datatype=numpy.uint32, dims=(N_PN, A_PN, N_BEAMLETS_CTRL), access=AttrWriteType.READ_WRITE)
-    FPGA_bf_weights_yx_R = attribute_wrapper(comms_annotation=["FPGA_bf_weights_yx_R"], datatype=numpy.uint32, dims=(N_PN, A_PN, N_BEAMLETS_CTRL))
-    FPGA_bf_weights_yx_RW = attribute_wrapper(comms_annotation=["FPGA_bf_weights_yx_RW"], datatype=numpy.uint32, dims=(N_PN, A_PN, N_BEAMLETS_CTRL), access=AttrWriteType.READ_WRITE)
-    FPGA_bf_weights_yy_R = attribute_wrapper(comms_annotation=["FPGA_bf_weights_yy_R"], datatype=numpy.uint32, dims=(N_PN, A_PN, N_BEAMLETS_CTRL))
-    FPGA_bf_weights_yy_RW = attribute_wrapper(comms_annotation=["FPGA_bf_weights_yy_RW"], datatype=numpy.uint32, dims=(N_PN, A_PN, N_BEAMLETS_CTRL), access=AttrWriteType.READ_WRITE)
+    FPGA_bf_weights_xx_R = attribute_wrapper(comms_annotation=["FPGA_bf_weights_xx_R"], datatype=numpy.uint32, dims=(N_pn, A_pn, N_beamlets_ctrl))
+    FPGA_bf_weights_xx_RW = attribute_wrapper(comms_annotation=["FPGA_bf_weights_xx_RW"], datatype=numpy.uint32, dims=(N_pn, A_pn * N_beamlets_ctrl), access=AttrWriteType.READ_WRITE)
+    FPGA_bf_weights_xy_R = attribute_wrapper(comms_annotation=["FPGA_bf_weights_xy_R"], datatype=numpy.uint32, dims=(N_pn, A_pn, N_beamlets_ctrl))
+    FPGA_bf_weights_xy_RW = attribute_wrapper(comms_annotation=["FPGA_bf_weights_xy_RW"], datatype=numpy.uint32, dims=(N_pn, A_pn, N_beamlets_ctrl), access=AttrWriteType.READ_WRITE)
+    FPGA_bf_weights_yx_R = attribute_wrapper(comms_annotation=["FPGA_bf_weights_yx_R"], datatype=numpy.uint32, dims=(N_pn, A_pn, N_beamlets_ctrl))
+    FPGA_bf_weights_yx_RW = attribute_wrapper(comms_annotation=["FPGA_bf_weights_yx_RW"], datatype=numpy.uint32, dims=(N_pn, A_pn, N_beamlets_ctrl), access=AttrWriteType.READ_WRITE)
+    FPGA_bf_weights_yy_R = attribute_wrapper(comms_annotation=["FPGA_bf_weights_yy_R"], datatype=numpy.uint32, dims=(N_pn, A_pn, N_beamlets_ctrl))
+    FPGA_bf_weights_yy_RW = attribute_wrapper(comms_annotation=["FPGA_bf_weights_yy_RW"], datatype=numpy.uint32, dims=(N_pn, A_pn, N_beamlets_ctrl), access=AttrWriteType.READ_WRITE)
 
     # boolean[N_pn][N_beamsets_ctrl][P_sum]
-    FPGA_bf_rx_align_stream_enable_R = attribute_wrapper(comms_annotation=["FPGA_bf_rx_align_stream_enable_R"], datatype=bool, dims=(N_PN, N_BEAMSETS_CTRL, P_SUM))
-    FPGA_bf_rx_align_stream_enable_RW = attribute_wrapper(comms_annotation=["FPGA_bf_rx_align_stream_enable_RW"], datatype=bool, dims=(N_PN, N_BEAMSETS_CTRL, P_SUM), access=AttrWriteType.READ_WRITE)
+    FPGA_bf_rx_align_stream_enable_R = attribute_wrapper(comms_annotation=["FPGA_bf_rx_align_stream_enable_R"], datatype=bool, dims=(N_pn, N_beamsets_ctrl, P_sum))
+    FPGA_bf_rx_align_stream_enable_RW = attribute_wrapper(comms_annotation=["FPGA_bf_rx_align_stream_enable_RW"], datatype=bool, dims=(N_pn, N_beamsets_ctrl, P_sum), access=AttrWriteType.READ_WRITE)
 
     # int64[N_pn][N_beamsets_ctrl][P_sum]
-    FPGA_bf_rx_align_bsn_R = attribute_wrapper(comms_annotation=["FPGA_bf_rx_align_bsn_R"], datatype=numpy.int64, dims=(N_PN, N_BEAMSETS_CTRL, P_SUM))
+    FPGA_bf_rx_align_bsn_R = attribute_wrapper(comms_annotation=["FPGA_bf_rx_align_bsn_R"], datatype=numpy.int64, dims=(N_pn, N_beamsets_ctrl, P_sum))
 
     #int32[N_pn][N_beamsets_ctrl][P_sum]
-    FPGA_bf_rx_align_nof_packets_R = attribute_wrapper(comms_annotation=["FPGA_bf_rx_align_nof_packets_R"], datatype=numpy.int32, dims=(N_PN, N_BEAMSETS_CTRL, P_SUM))
-    FPGA_bf_rx_align_nof_valid_R = attribute_wrapper(comms_annotation=["FPGA_bf_rx_align_nof_valid_R"], datatype=numpy.int32, dims=(N_PN, N_BEAMSETS_CTRL, P_SUM))
-    FPGA_bf_rx_align_latency_R = attribute_wrapper(comms_annotation=["FPGA_bf_rx_align_latency_R"], datatype=numpy.int32, dims=(N_PN, N_BEAMSETS_CTRL, P_SUM))
-    FPGA_bf_rx_align_nof_replaced_packets_R = attribute_wrapper(comms_annotation=["FPGA_bf_rx_align_nof_replaced_packets_R"], datatype=numpy.int32, dims=(N_PN, N_BEAMSETS_CTRL, P_SUM))
+    FPGA_bf_rx_align_nof_packets_R = attribute_wrapper(comms_annotation=["FPGA_bf_rx_align_nof_packets_R"], datatype=numpy.int32, dims=(N_pn, N_beamsets_ctrl, P_sum))
+    FPGA_bf_rx_align_nof_valid_R = attribute_wrapper(comms_annotation=["FPGA_bf_rx_align_nof_valid_R"], datatype=numpy.int32, dims=(N_pn, N_beamsets_ctrl, P_sum))
+    FPGA_bf_rx_align_latency_R = attribute_wrapper(comms_annotation=["FPGA_bf_rx_align_latency_R"], datatype=numpy.int32, dims=(N_pn, N_beamsets_ctrl, P_sum))
+    FPGA_bf_rx_align_nof_replaced_packets_R = attribute_wrapper(comms_annotation=["FPGA_bf_rx_align_nof_replaced_packets_R"], datatype=numpy.int32, dims=(N_pn, N_beamsets_ctrl, P_sum))
 
-    subband_select_RW = attribute(dtype=(numpy.uint32,), max_dim_x=N_BEAMLETS_CTRL, access=AttrWriteType.READ_WRITE, fisallowed="is_attribute_access_allowed")
+    subband_select_RW = attribute(dtype=(numpy.uint32,), max_dim_x=N_beamlets_ctrl, access=AttrWriteType.READ_WRITE, fisallowed="is_attribute_access_allowed")
 
     def read_subband_select_RW(self):
         # We can only return a single value, so we assume the FPGA is configured coherently. Which is something
@@ -209,14 +199,14 @@ class Beamlet(opcua_device):
             return self.subband_select_RW_default
 
         # We return the first setting within the mask. Convert into actual shape for a single FPGA
-        mask_for_all_inputs = subbands_in_mask[0].reshape(self.A_PN, self.N_POL, self.N_BEAMLETS_CTRL)
+        mask_for_all_inputs = subbands_in_mask[0].reshape(A_pn, N_pol, N_beamlets_ctrl)
 
         # Return the first setting (antenna, pol) within this FPGA
         return mask_for_all_inputs[0,0]
 
     def write_subband_select_RW(self, subbands):
         # Use the same subband for all inputs and polarisations of a beamlet
-        self.proxy.FPGA_beamlet_subband_select_RW = numpy.tile(subbands, (self.N_PN, self.A_PN * self.N_POL))
+        self.proxy.FPGA_beamlet_subband_select_RW = numpy.tile(subbands, (N_pn, A_pn * N_pol))
 
         self.cache_clear()
 
@@ -321,8 +311,8 @@ class Beamlet(opcua_device):
     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_subbands = nyquist_zones * 512
+        subband_width = clock / N_subband_res
+        base_subbands = nyquist_zones * N_subbands
 
         # broadcast clock across frequencies
         frequencies = (subbands + base_subbands) * subband_width
@@ -341,7 +331,7 @@ class Beamlet(opcua_device):
         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)
+        nyquist_zones    = numpy.repeat(nyquist_zones, 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)
@@ -372,7 +362,7 @@ class Beamlet(opcua_device):
         """ converts a difference in delays (in seconds) to a FPGA weight (in complex number) """
 
         # Calculate the FPGA weight array
-        delays = delays.reshape(self.N_PN, self.A_PN * self.N_POL * self.N_BEAMLETS_CTRL)
+        delays = delays.reshape(N_pn, A_pn * N_pol * N_beamlets_ctrl)
         beamlet_frequencies = self._beamlet_frequencies()
         bf_weights = self._calculate_bf_weights(delays, beamlet_frequencies)
 
diff --git a/tangostationcontrol/tangostationcontrol/devices/sdp/bst.py b/tangostationcontrol/tangostationcontrol/devices/sdp/bst.py
index 19504e7087884e0ce1b677387e76543f7abb5c6f..af885a5f4cd5f5c1c6602928385765bd2e75d55c 100644
--- a/tangostationcontrol/tangostationcontrol/devices/sdp/bst.py
+++ b/tangostationcontrol/tangostationcontrol/devices/sdp/bst.py
@@ -20,6 +20,7 @@ from lofar_station_client.statistics.collector import BSTCollector
 
 # Own imports
 from tangostationcontrol.common.entrypoint import entry
+from tangostationcontrol.common.constants import N_pn, BST_MAX_BLOCKS, N_beamlets_max
 from tangostationcontrol.clients.attribute_wrapper import attribute_wrapper
 from tangostationcontrol.clients.opcua_client import OPCUAConnection
 from tangostationcontrol.clients.statistics.client import StatisticsClient
@@ -52,7 +53,7 @@ class BST(Statistics):
     FPGA_bst_offload_enable_RW_default = device_property(
         dtype='DevVarBooleanArray',
         mandatory=False,
-        default_value=[True] * 16
+        default_value=[True] * N_pn
     )
 
     FIRST_DEFAULT_SETTINGS = [
@@ -69,33 +70,33 @@ class BST(Statistics):
     # ----------
 
     # FPGA control points for BSTs
-    FPGA_bst_offload_enable_RW = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_bst_offload_enable_RW"], datatype=bool, dims=(16,), access=AttrWriteType.READ_WRITE)
-    FPGA_bst_offload_enable_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_bst_offload_enable_R"], datatype=bool, dims=(16,))
-    FPGA_bst_offload_hdr_eth_destination_mac_RW = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_bst_offload_hdr_eth_destination_mac_RW"], datatype=str, dims=(16,), access=AttrWriteType.READ_WRITE)
-    FPGA_bst_offload_hdr_eth_destination_mac_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_bst_offload_hdr_eth_destination_mac_R"], datatype=str, dims=(16,))
-    FPGA_bst_offload_hdr_ip_destination_address_RW = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_bst_offload_hdr_ip_destination_address_RW"], datatype=str, dims=(16,), access=AttrWriteType.READ_WRITE)
-    FPGA_bst_offload_hdr_ip_destination_address_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_bst_offload_hdr_ip_destination_address_R"], datatype=str, dims=(16,))
-    FPGA_bst_offload_hdr_udp_destination_port_RW = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_bst_offload_hdr_udp_destination_port_RW"], datatype=numpy.uint16, dims=(16,), access=AttrWriteType.READ_WRITE)
-    FPGA_bst_offload_hdr_udp_destination_port_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_bst_offload_hdr_udp_destination_port_R"], datatype=numpy.uint16, dims=(16,))
-    FPGA_bst_offload_bsn_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_bst_offload_bsn_R"], datatype=numpy.int64, dims=(16,))
-
-    FPGA_bst_offload_nof_packets_R = attribute_wrapper(comms_annotation=["FPGA_bst_offload_nof_packets_R"], datatype=numpy.int32, dims=(16,))
-    FPGA_bst_offload_nof_valid_R = attribute_wrapper(comms_annotation=["FPGA_bst_offload_nof_valid_R"], datatype=numpy.int32, dims=(16,))
+    FPGA_bst_offload_enable_RW = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_bst_offload_enable_RW"], datatype=bool, dims=(N_pn,), access=AttrWriteType.READ_WRITE)
+    FPGA_bst_offload_enable_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_bst_offload_enable_R"], datatype=bool, dims=(N_pn,))
+    FPGA_bst_offload_hdr_eth_destination_mac_RW = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_bst_offload_hdr_eth_destination_mac_RW"], datatype=str, dims=(N_pn,), access=AttrWriteType.READ_WRITE)
+    FPGA_bst_offload_hdr_eth_destination_mac_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_bst_offload_hdr_eth_destination_mac_R"], datatype=str, dims=(N_pn,))
+    FPGA_bst_offload_hdr_ip_destination_address_RW = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_bst_offload_hdr_ip_destination_address_RW"], datatype=str, dims=(N_pn,), access=AttrWriteType.READ_WRITE)
+    FPGA_bst_offload_hdr_ip_destination_address_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_bst_offload_hdr_ip_destination_address_R"], datatype=str, dims=(N_pn,))
+    FPGA_bst_offload_hdr_udp_destination_port_RW = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_bst_offload_hdr_udp_destination_port_RW"], datatype=numpy.uint16, dims=(N_pn,), access=AttrWriteType.READ_WRITE)
+    FPGA_bst_offload_hdr_udp_destination_port_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_bst_offload_hdr_udp_destination_port_R"], datatype=numpy.uint16, dims=(N_pn,))
+    FPGA_bst_offload_bsn_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_bst_offload_bsn_R"], datatype=numpy.int64, dims=(N_pn,))
+
+    FPGA_bst_offload_nof_packets_R = attribute_wrapper(comms_annotation=["FPGA_bst_offload_nof_packets_R"], datatype=numpy.int32, dims=(N_pn,))
+    FPGA_bst_offload_nof_valid_R = attribute_wrapper(comms_annotation=["FPGA_bst_offload_nof_valid_R"], datatype=numpy.int32, dims=(N_pn,))
 
     # number of packets with valid payloads
-    nof_valid_payloads_R    = attribute_wrapper(comms_id=StatisticsClient, comms_annotation={"type": "statistics", "parameter": "nof_valid_payloads"}, dims=(BSTCollector.MAX_FPGAS,), datatype=numpy.uint64)
+    nof_valid_payloads_R    = attribute_wrapper(comms_id=StatisticsClient, comms_annotation={"type": "statistics", "parameter": "nof_valid_payloads"}, dims=(N_pn,), datatype=numpy.uint64)
     # number of packets with invalid payloads
-    nof_payload_errors_R    = attribute_wrapper(comms_id=StatisticsClient, comms_annotation={"type": "statistics", "parameter": "nof_payload_errors"}, dims=(BSTCollector.MAX_FPGAS,), datatype=numpy.uint64)
+    nof_payload_errors_R    = attribute_wrapper(comms_id=StatisticsClient, comms_annotation={"type": "statistics", "parameter": "nof_payload_errors"}, dims=(N_pn,), datatype=numpy.uint64)
     # latest BSTs
-    bst_R                   = attribute_wrapper(comms_id=StatisticsClient, comms_annotation={"type": "statistics", "parameter": "bst_values"}, dims=(BSTCollector.MAX_BLOCKS, BSTCollector.MAX_BEAMLETS), datatype=numpy.uint64)
+    bst_R                   = attribute_wrapper(comms_id=StatisticsClient, comms_annotation={"type": "statistics", "parameter": "bst_values"}, dims=(BST_MAX_BLOCKS, N_beamlets_max), datatype=numpy.uint64)
     # reported timestamp
     # for each row in the latest BSTs
-    bst_timestamp_R         = attribute_wrapper(comms_id=StatisticsClient, comms_annotation={"type": "statistics", "parameter": "bst_timestamps"}, dims=(BSTCollector.MAX_BLOCKS,), datatype=numpy.uint64)
+    bst_timestamp_R         = attribute_wrapper(comms_id=StatisticsClient, comms_annotation={"type": "statistics", "parameter": "bst_timestamps"}, dims=(BST_MAX_BLOCKS,), datatype=numpy.uint64)
 
     # ----------
     # Summarising Attributes
     # ----------
-    FPGA_processing_error_R      = attribute(dtype=(bool,), max_dim_x=16)
+    FPGA_processing_error_R      = attribute(dtype=(bool,), max_dim_x=N_pn)
 
     def read_FPGA_processing_error_R(self):
         return self.sdp_proxy.TR_fpga_mask_RW & (
diff --git a/tangostationcontrol/tangostationcontrol/devices/sdp/digitalbeam.py b/tangostationcontrol/tangostationcontrol/devices/sdp/digitalbeam.py
index c3603ce957a9f9a44c616a347d53fecd9afcc5bd..0d8ae821e74ed2e6da552cd0399efcc0ac246f76 100644
--- a/tangostationcontrol/tangostationcontrol/devices/sdp/digitalbeam.py
+++ b/tangostationcontrol/tangostationcontrol/devices/sdp/digitalbeam.py
@@ -13,8 +13,8 @@ from tango.server import attribute, AttrWriteType, device_property
 
 # Additional import
 from tangostationcontrol.common.entrypoint import entry
+from tangostationcontrol.common.constants import N_beamlets_ctrl, MAX_ANTENNA, N_xyz, A_pn, N_pn, N_pol
 from tangostationcontrol.devices.beam_device import beam_device
-from tangostationcontrol.devices.sdp.beamlet import Beamlet
 from tangostationcontrol.devices.device_decorators import TimeIt
 from tangostationcontrol.common.lofar_logging import log_exceptions
 from tangostationcontrol.beam.delays import Delays
@@ -43,12 +43,6 @@ class DigitalBeam(beam_device):
         disabled in the mask will get a weight of 0.
     """
 
-    MAX_INPUTS = 96
-    NUM_BEAMLETS = 488
-
-    # number of antennas connected to each FPGA in SDP
-    A_pn = 6
-
     # -----------------
     # Device Properties
     # -----------------
@@ -75,10 +69,10 @@ class DigitalBeam(beam_device):
         dtype=numpy.float64, fget=lambda self: self._delays.statistics["last"] or 0)
 
     input_select_RW = attribute(doc='Selection of inputs to use for forming each beamlet. Allows selecting broken antennas.',
-                                  dtype=((bool,),), max_dim_x=NUM_BEAMLETS, max_dim_y=MAX_INPUTS, access=AttrWriteType.READ_WRITE, fisallowed="is_attribute_access_allowed")
+                                dtype=((bool,),), max_dim_x=N_beamlets_ctrl, max_dim_y=MAX_ANTENNA, access=AttrWriteType.READ_WRITE, fisallowed="is_attribute_access_allowed")
 
     antenna_select_RW = attribute(doc='Selection of antennas desired to use for forming each beamlet (= a subset of input_select of the configured antennas). Unselects broken antennas.',
-                                  dtype=((bool,),), max_dim_x=NUM_BEAMLETS, max_dim_y=MAX_INPUTS, access=AttrWriteType.READ_WRITE, fisallowed="is_attribute_access_allowed")
+                                  dtype=((bool,),), max_dim_x=N_beamlets_ctrl, max_dim_y=MAX_ANTENNA, access=AttrWriteType.READ_WRITE, fisallowed="is_attribute_access_allowed")
 
     nr_inputs_R = attribute(doc='Number of configured inputs from the associated antenna field.',
                                   dtype=numpy.uint32, fget="nr_inputs")
@@ -96,11 +90,11 @@ class DigitalBeam(beam_device):
 
     def read_antenna_select_RW(self):
         # select only the rows from self.__input_select for which a mapping onto antennas is defined.
-        antenna_select = [[False] * self.NUM_BEAMLETS] * self.nr_inputs()
+        antenna_select = [[False] * N_beamlets_ctrl] * self.nr_inputs()
 
         for antenna_nr, (fpga_nr, input_nr) in enumerate(self.antennafield_proxy.Antenna_to_SDP_Mapping_R):
             if input_nr >= 0:
-                antenna_select[antenna_nr] = self._input_select[fpga_nr * self.A_pn + input_nr]
+                antenna_select[antenna_nr] = self._input_select[fpga_nr * A_pn + input_nr]
 
         return antenna_select
 
@@ -113,10 +107,10 @@ class DigitalBeam(beam_device):
             if input_nr >= 0:
                 if antenna_usage_mask[antenna_nr]:
                     # use antenna for the beamlets as supplied by the client
-                    self._input_select[fpga_nr * self.A_pn + input_nr] = antennas[antenna_nr]
+                    self._input_select[fpga_nr * A_pn + input_nr] = antennas[antenna_nr]
                 else:
                     # do not use antenna for any beamlet
-                    self._input_select[fpga_nr * self.A_pn + input_nr] = False
+                    self._input_select[fpga_nr * A_pn + input_nr] = False
 
     # ----------
     # Summarising Attributes
@@ -128,7 +122,7 @@ class DigitalBeam(beam_device):
 
     @log_exceptions()
     def configure_for_initialise(self):
-        super().configure_for_initialise(self.NUM_BEAMLETS)
+        super().configure_for_initialise(N_beamlets_ctrl)
 
         # Set a reference of RECV device that is correlated to this BEAM device
         util = Util.instance()
@@ -142,14 +136,15 @@ class DigitalBeam(beam_device):
 
         # Retrieve positions from RECV device
         reference_itrf = self.antennafield_proxy.Antenna_Field_Reference_ITRF_R
-        antenna_itrf   = self.antennafield_proxy.Antenna_Reference_ITRF_R.reshape(-1, 3)
+        antenna_itrf   = self.antennafield_proxy.Antenna_Reference_ITRF_R.reshape(-1, N_xyz)
 
         # Generate positions for all FPGA inputs.
         # Use reference position for any missing antennas so they always get a delay of 0
-        input_itrf = numpy.array([reference_itrf] * self.MAX_INPUTS)
+        input_itrf = numpy.array([reference_itrf] * MAX_ANTENNA)
         for antenna_nr, (fpga_nr, input_nr) in enumerate(self.antennafield_proxy.Antenna_to_SDP_Mapping_R):
             if input_nr >= 0:
-                input_itrf[fpga_nr * self.A_pn + input_nr] = antenna_itrf[antenna_nr]
+                input_itrf[fpga_nr * A_pn + input_nr] = antenna_itrf[antenna_nr]
+
 
         # a delay calculator
         self.delay_calculator = Delays(reference_itrf)
@@ -158,8 +153,8 @@ class DigitalBeam(beam_device):
         self.relative_input_positions = input_itrf - reference_itrf
 
         # use all antennas in the mapping for all beamlets, unless specified otherwise
-        self.write_input_select_RW(numpy.zeros((self.MAX_INPUTS, self.NUM_BEAMLETS), dtype=bool))
-        self.write_antenna_select_RW(numpy.ones((self.nr_inputs(), self.NUM_BEAMLETS), dtype=bool))
+        self.write_input_select_RW(numpy.zeros((MAX_ANTENNA, N_beamlets_ctrl), dtype=bool))
+        self.write_antenna_select_RW(numpy.ones((self.nr_inputs(), N_beamlets_ctrl), dtype=bool))
 
     # --------
     # internal functions
@@ -173,7 +168,7 @@ class DigitalBeam(beam_device):
         Returns delays[antenna][beamlet]
         """
 
-        delays = numpy.zeros((self.MAX_INPUTS, self.NUM_BEAMLETS), dtype=numpy.float64)
+        delays = numpy.zeros((MAX_ANTENNA, N_beamlets_ctrl), dtype=numpy.float64)
 
         d = self.delay_calculator
         d.set_measure_time(timestamp)
@@ -187,7 +182,7 @@ class DigitalBeam(beam_device):
         """ Converts an array with dimensions [antenna][beamlet] -> [fpga_nr][input_nr][pol_nr][beamlet]
             by repeating the values for both polarisations. """
 
-        assert arr.shape == (self.MAX_INPUTS, self.NUM_BEAMLETS)
+        assert arr.shape == (MAX_ANTENNA, N_beamlets_ctrl)
 
         # Each antenna maps on [fpga_nr][input_nr][0] and [fpga_nr][input_nr][1], and we work
         # with [antenna][beamlet], so we have to interleave copies of the input array per beamlet
@@ -201,7 +196,7 @@ class DigitalBeam(beam_device):
         result = result.reshape(result.shape[0] * 2, result.shape[1] // 2)
 
         # cast into (fpga_nr, [input_nr][pol_nr][beamlet])
-        result = result.reshape((Beamlet.N_PN, Beamlet.A_PN * Beamlet.N_POL * Beamlet.N_BEAMLETS_CTRL))
+        result = result.reshape((N_pn, A_pn * N_pol * N_beamlets_ctrl))
 
         return result
 
@@ -218,7 +213,7 @@ class DigitalBeam(beam_device):
         fpga_delays = self._map_inputs_on_polarised_inputs(antenna_delays)
 
         beam_weights = self.beamlet_proxy.calculate_bf_weights(fpga_delays.flatten())
-        beam_weights = beam_weights.reshape((Beamlet.N_PN, Beamlet.A_PN * Beamlet.N_POL * Beamlet.N_BEAMLETS_CTRL))
+        beam_weights = beam_weights.reshape((N_pn, A_pn * N_pol * N_beamlets_ctrl))
 
         return beam_weights
 
diff --git a/tangostationcontrol/tangostationcontrol/devices/sdp/sdp.py b/tangostationcontrol/tangostationcontrol/devices/sdp/sdp.py
index 64d6b94610604ac850ca40aaf8a11cfda82d43c9..ded37fe8b296445aa3a7a0a82a44b1ce41a5742a 100644
--- a/tangostationcontrol/tangostationcontrol/devices/sdp/sdp.py
+++ b/tangostationcontrol/tangostationcontrol/devices/sdp/sdp.py
@@ -20,6 +20,7 @@ from tangostationcontrol.clients.attribute_wrapper import attribute_wrapper
 from tangostationcontrol.devices.opcua_device import opcua_device
 from tangostationcontrol.common.entrypoint import entry
 from tangostationcontrol.common.lofar_logging import device_logging_to_python
+from tangostationcontrol.common.constants import S_pn, N_pn, CLK_200_MHZ, CLK_160_MHZ, N_subband_res, N_subbands, DEFAULT_SUBBAND, N_beamsets_ctrl, DEFAULT_POLLING_PERIOD
 
 import numpy
 
@@ -28,6 +29,7 @@ __all__ = ["SDP", "main"]
 
 @device_logging_to_python()
 class SDP(opcua_device):
+
     # -----------------
     # Device Properties
     # -----------------
@@ -35,19 +37,19 @@ class SDP(opcua_device):
     TR_fpga_mask_RW_default = device_property(
         dtype='DevVarBooleanArray',
         mandatory=False,
-        default_value=[True] * 16
+        default_value=[True] * N_pn
     )
 
     FPGA_processing_enable_RW_default = device_property(
         dtype='DevVarBooleanArray',
         mandatory=False,
-        default_value=[True] * 16
+        default_value=[True] * N_pn
     )
 
     FPGA_wg_enable_RW_default = device_property(
         dtype='DevVarBooleanArray',
         mandatory=False,
-        default_value=[[False] * 12] * 16
+        default_value=[[False] * S_pn] * N_pn
     )
 
     # If we enable the waveform generator, we want some sane defaults.
@@ -55,44 +57,44 @@ class SDP(opcua_device):
     FPGA_wg_amplitude_RW_default = device_property(
         dtype='DevVarDoubleArray',
         mandatory=False,
-        default_value=[[0.1] * 12] * 16
+        default_value=[[0.1] * S_pn] * N_pn
     )
 
     FPGA_wg_frequency_RW_default = device_property(
         dtype='DevVarDoubleArray',
         mandatory=False,
         # Emit a signal on subband 102
-        default_value=[[102 * 200e6/1024] * 12] * 16
+        default_value=[[DEFAULT_SUBBAND * CLK_200_MHZ / N_subband_res] * S_pn] * N_pn
     )
 
     FPGA_wg_phase_RW_default = device_property(
         dtype='DevVarDoubleArray',
         mandatory=False,
-        default_value=[[0.0] * 12] * 16
+        default_value=[[0.0] * S_pn] * N_pn
     )
 
     FPGA_sdp_info_station_id_RW_default = device_property(
         dtype='DevVarULongArray',
         mandatory=False,
-        default_value=[0] * 16
+        default_value=[0] * N_pn
     )
 
     FPGA_signal_input_samples_delay_RW_default = device_property(
         dtype='DevVarULongArray',
         mandatory=False,
-        default_value=[[0] * 12] * 16
+        default_value=[[0] * S_pn] * N_pn
     )
 
     FPGA_subband_weights_RW_default = device_property(
         dtype='DevVarULongArray',
         mandatory=False,
-        default_value=[[8192] * 12 * 512] * 16
+        default_value=[[8192] * S_pn * N_subbands] * N_pn
     )
 
     clock_RW_default = device_property(
         dtype='DevULong',
         mandatory=False,
-        default_value = 200 * 1000000
+        default_value = CLK_200_MHZ
     )
 
     TRANSLATOR_DEFAULT_SETTINGS = [
@@ -103,11 +105,6 @@ class SDP(opcua_device):
     # Attributes
     # ----------
 
-    # TODO(needs to not be statically declared as this can change depending on the station and configuration)
-    S_pn = 12 # Number of ADC signal inputs per Processing Node (PN) FPGA.
-    N_pn = 16 # Number of FPGAs per antenna band that is controlled via the SC - SDP interface.
-    N_beamsets_ctrl = 1
-
     FPGA_firmware_version_R = attribute_wrapper(comms_annotation=["FPGA_firmware_version_R"], datatype=str, dims=(N_pn,))
     FPGA_boot_image_R = attribute_wrapper(comms_annotation=["FPGA_boot_image_R"], datatype=numpy.int32, dims=(N_pn,), doc="Active FPGA image (0=factory, 1=user)")
     FPGA_boot_image_RW = attribute_wrapper(comms_annotation=["FPGA_boot_image_RW"], datatype=numpy.int32, dims=(N_pn,), access=AttrWriteType.READ_WRITE)
@@ -127,8 +124,8 @@ class SDP(opcua_device):
     FPGA_ring_use_cable_to_next_rn_RW = attribute_wrapper(comms_annotation=["FPGA_ring_use_cable_to_next_rn_RW"], datatype=bool, dims=(N_pn,), access=AttrWriteType.READ_WRITE)
     FPGA_ring_use_cable_to_previous_rn_R = attribute_wrapper(comms_annotation=["FPGA_ring_use_cable_to_previous_rn_R"], datatype=bool, dims=(N_pn,))
     FPGA_ring_use_cable_to_previous_rn_RW = attribute_wrapper(comms_annotation=["FPGA_ring_use_cable_to_previous_rn_RW"], datatype=bool, dims=(N_pn,), access=AttrWriteType.READ_WRITE)
-    FPGA_scrap_R = attribute_wrapper(comms_annotation=["FPGA_scrap_R"], datatype=numpy.int32, dims=(N_pn, 512))
-    FPGA_scrap_RW = attribute_wrapper(comms_annotation=["FPGA_scrap_RW"], datatype=numpy.int32, dims=(N_pn, 512), access=AttrWriteType.READ_WRITE)
+    FPGA_scrap_R = attribute_wrapper(comms_annotation=["FPGA_scrap_R"], datatype=numpy.int32, dims=(N_pn, N_subbands))
+    FPGA_scrap_RW = attribute_wrapper(comms_annotation=["FPGA_scrap_RW"], datatype=numpy.int32, dims=(N_pn, N_subbands), access=AttrWriteType.READ_WRITE)
     FPGA_sdp_info_antenna_band_index_R = attribute_wrapper(comms_annotation=["FPGA_sdp_info_antenna_band_index_R"], datatype=numpy.uint32, dims=(N_pn,))
     FPGA_sdp_info_block_period_R = attribute_wrapper(comms_annotation=["FPGA_sdp_info_block_period_R"], datatype=numpy.uint32, dims=(N_pn,))
     FPGA_sdp_info_f_adc_R = attribute_wrapper(comms_annotation=["FPGA_sdp_info_f_adc_R"], datatype=numpy.uint32, dims=(N_pn,))
@@ -139,8 +136,8 @@ class SDP(opcua_device):
     FPGA_sdp_info_observation_id_RW = attribute_wrapper(comms_annotation=["FPGA_sdp_info_observation_id_RW"], datatype=numpy.uint32, dims=(N_pn,), access=AttrWriteType.READ_WRITE)
     FPGA_sdp_info_station_id_R = attribute_wrapper(comms_annotation=["FPGA_sdp_info_station_id_R"], datatype=numpy.uint32, dims=(N_pn,))
     FPGA_sdp_info_station_id_RW = attribute_wrapper(comms_annotation=["FPGA_sdp_info_station_id_RW"], datatype=numpy.uint32, dims=(N_pn,), access=AttrWriteType.READ_WRITE)
-    FPGA_subband_weights_R = attribute_wrapper(comms_annotation=["FPGA_subband_weights_R"], datatype=numpy.uint32, dims=(N_pn, S_pn, 512))
-    FPGA_subband_weights_RW = attribute_wrapper(comms_annotation=["FPGA_subband_weights_RW"], datatype=numpy.uint32, dims=(N_pn, S_pn, 512), access=AttrWriteType.READ_WRITE)
+    FPGA_subband_weights_R = attribute_wrapper(comms_annotation=["FPGA_subband_weights_R"], datatype=numpy.uint32, dims=(N_pn, S_pn, N_subbands))
+    FPGA_subband_weights_RW = attribute_wrapper(comms_annotation=["FPGA_subband_weights_RW"], datatype=numpy.uint32, dims=(N_pn, S_pn, N_subbands), access=AttrWriteType.READ_WRITE)
     FPGA_time_since_last_pps_R = attribute_wrapper(comms_annotation=["FPGA_time_since_last_pps_R"], datatype=numpy.float_, dims=(N_pn,))
     FPGA_temp_R = attribute_wrapper(comms_annotation=["FPGA_temp_R"], datatype=numpy.float_, dims=(N_pn,))
     FPGA_wg_amplitude_R = attribute_wrapper(comms_annotation=["FPGA_wg_amplitude_R"], datatype=numpy.float_, dims=(N_pn, S_pn))
@@ -159,7 +156,7 @@ class SDP(opcua_device):
     TR_sdp_config_nof_fpgas_R = attribute_wrapper(comms_annotation=["TR_sdp_config_nof_fpgas_R"], datatype=numpy.uint32)
     TR_software_version_R = attribute_wrapper(comms_annotation=["TR_software_version_R"], datatype=str)
     TR_start_time_R = attribute_wrapper(comms_annotation=["TR_start_time_R"], datatype=numpy.int64)
-    TR_tod_R = attribute_wrapper(comms_annotation=["TR_tod_R"], datatype=numpy.int64, dims=(2,))
+    TR_tod_R = attribute_wrapper(comms_annotation=["TR_tod_R"], datatype=numpy.int64, dims=(2,))     # struct of (time_t, int64)
     TR_tod_pps_delta_R = attribute_wrapper(comms_annotation=["TR_tod_pps_delta_R"], datatype=numpy.double)
 
     # OPC-UA MP only points for AIT
@@ -185,10 +182,10 @@ class SDP(opcua_device):
     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)
+                               polling_period=DEFAULT_POLLING_PERIOD, 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)
+                         polling_period=DEFAULT_POLLING_PERIOD, abs_change=1)
 
     def read_antenna_type_RW(self):
         return self._antenna_type
@@ -198,8 +195,8 @@ class SDP(opcua_device):
         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}.")
+        if value.shape != (N_pn, S_pn):
+            raise ValueError(f"Dimension mismatch. Expected ({N_pn}, {S_pn}), got {value.shape}.")
 
         # validate content
         for val in value.flatten():
@@ -248,11 +245,11 @@ class SDP(opcua_device):
         return numpy.uint32(clocks_in_mask[0]) if clocks_in_mask else self.clock_RW_default
 
     def write_clock_RW(self, clock):
-        if clock not in (160*1000000, 200*1000000):
+        if clock not in (CLK_160_MHZ, CLK_200_MHZ):
             raise ValueError(f"Unsupported clock frequency: {clock}")
 
         # Tell all FPGAs to use this clock
-        self.proxy.FPGA_pps_expected_cnt_RW = [clock] * self.N_pn
+        self.proxy.FPGA_pps_expected_cnt_RW = [clock] * 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]
@@ -260,9 +257,9 @@ class SDP(opcua_device):
     # ----------
     # Summarising Attributes
     # ----------
-    FPGA_error_R                 = attribute(dtype=(bool,), max_dim_x=16, fisallowed="is_attribute_access_allowed")
-    FPGA_processing_error_R      = attribute(dtype=(bool,), max_dim_x=16, fisallowed="is_attribute_access_allowed")
-    FPGA_input_error_R           = attribute(dtype=(bool,), max_dim_x=16, fisallowed="is_attribute_access_allowed")
+    FPGA_error_R                 = attribute(dtype=(bool,), max_dim_x=N_pn, fisallowed="is_attribute_access_allowed")
+    FPGA_processing_error_R      = attribute(dtype=(bool,), max_dim_x=N_pn, fisallowed="is_attribute_access_allowed")
+    FPGA_input_error_R           = attribute(dtype=(bool,), max_dim_x=N_pn, fisallowed="is_attribute_access_allowed")
 
     def read_FPGA_error_R(self):
         return self.read_attribute("TR_fpga_mask_R") & (
@@ -294,14 +291,14 @@ class SDP(opcua_device):
         # 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)
+        self._antenna_type = numpy.array([["LBA"] * S_pn] * 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")
 
         # Order the correct firmare to be loaded 
-        self.proxy.FPGA_boot_image_RW = [1] * self.N_pn
+        self.proxy.FPGA_boot_image_RW = [1] * N_pn
 
         # Wait for the firmware to be loaded (ignoring masked out elements)
         self.wait_attribute("FPGA_boot_image_R", lambda attr: ((attr == 1) | ~wait_for).all(), 60)
@@ -311,9 +308,9 @@ class SDP(opcua_device):
         # Save actual mask values
         TR_fpga_mask = self.proxy.TR_fpga_mask_RW
         # Set the mask to all Trues
-        self.TR_fpga_mask_RW = [True] * 16
+        self.TR_fpga_mask_RW = [True] * N_pn
         # Boot the boot image firmware
-        self.FPGA_boot_image_RW = [0] * self.N_pn
+        self.FPGA_boot_image_RW = [0] * N_pn
         # Restore the mask
         self.TR_fpga_mask_RW = TR_fpga_mask
 
diff --git a/tangostationcontrol/tangostationcontrol/devices/sdp/sst.py b/tangostationcontrol/tangostationcontrol/devices/sdp/sst.py
index 73a8054882d5dd29c4fecc971c3605880cd2a866..52faf1a74030a5a443baa25456969cf2d1ce2d42 100644
--- a/tangostationcontrol/tangostationcontrol/devices/sdp/sst.py
+++ b/tangostationcontrol/tangostationcontrol/devices/sdp/sst.py
@@ -17,6 +17,7 @@ from tango import AttrWriteType
 
 # Additional import
 from tangostationcontrol.common.entrypoint import entry
+from tangostationcontrol.common.constants import N_pn, MAX_INPUTS, N_subbands
 from tangostationcontrol.clients.attribute_wrapper import attribute_wrapper
 from tangostationcontrol.clients.opcua_client import OPCUAConnection
 from tangostationcontrol.clients.statistics.client import StatisticsClient
@@ -54,13 +55,13 @@ class SST(Statistics):
     FPGA_sst_offload_enable_RW_default = device_property(
         dtype='DevVarBooleanArray',
         mandatory=False,
-        default_value=[True] * 16
+        default_value=[True] * N_pn
     )
 
     FPGA_sst_offload_weighted_subbands_RW_default = device_property(
         dtype='DevVarBooleanArray',
         mandatory=False,
-        default_value=[True] * 16
+        default_value=[True] * N_pn
     )
 
     FIRST_DEFAULT_SETTINGS = [
@@ -79,39 +80,39 @@ class SST(Statistics):
     # ----------
 
     # FPGA control points for SSTs
-    FPGA_sst_offload_enable_RW = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_sst_offload_enable_RW"], datatype=bool, dims=(16,), access=AttrWriteType.READ_WRITE)
-    FPGA_sst_offload_enable_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_sst_offload_enable_R"], datatype=bool, dims=(16,))
-    FPGA_sst_offload_hdr_eth_destination_mac_RW = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_sst_offload_hdr_eth_destination_mac_RW"], datatype=str, dims=(16,), access=AttrWriteType.READ_WRITE)
-    FPGA_sst_offload_hdr_eth_destination_mac_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_sst_offload_hdr_eth_destination_mac_R"], datatype=str, dims=(16,))
-    FPGA_sst_offload_hdr_ip_destination_address_RW = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_sst_offload_hdr_ip_destination_address_RW"], datatype=str, dims=(16,), access=AttrWriteType.READ_WRITE)
-    FPGA_sst_offload_hdr_ip_destination_address_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_sst_offload_hdr_ip_destination_address_R"], datatype=str, dims=(16,))
-    FPGA_sst_offload_hdr_udp_destination_port_RW = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_sst_offload_hdr_udp_destination_port_RW"], datatype=numpy.uint16, dims=(16,), access=AttrWriteType.READ_WRITE)
-    FPGA_sst_offload_hdr_udp_destination_port_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_sst_offload_hdr_udp_destination_port_R"], datatype=numpy.uint16, dims=(16,))
-    FPGA_sst_offload_bsn_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_sst_offload_bsn_R"], datatype=numpy.int64, dims=(16,))
-    FPGA_sst_offload_weighted_subbands_RW = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_sst_offload_weighted_subbands_RW"], datatype=bool, dims=(16,), access=AttrWriteType.READ_WRITE)
-    FPGA_sst_offload_weighted_subbands_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_sst_offload_weighted_subbands_R"], datatype=bool, dims=(16,))
-
-    FPGA_sst_offload_nof_packets_R = attribute_wrapper(comms_annotation=["FPGA_sst_offload_nof_packets_R"], datatype=numpy.int32, dims=(16,))
-    FPGA_sst_offload_nof_valid_R = attribute_wrapper(comms_annotation=["FPGA_sst_offload_nof_valid_R"], datatype=numpy.int32, dims=(16,))
+    FPGA_sst_offload_enable_RW = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_sst_offload_enable_RW"], datatype=bool, dims=(N_pn,), access=AttrWriteType.READ_WRITE)
+    FPGA_sst_offload_enable_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_sst_offload_enable_R"], datatype=bool, dims=(N_pn,))
+    FPGA_sst_offload_hdr_eth_destination_mac_RW = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_sst_offload_hdr_eth_destination_mac_RW"], datatype=str, dims=(N_pn,), access=AttrWriteType.READ_WRITE)
+    FPGA_sst_offload_hdr_eth_destination_mac_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_sst_offload_hdr_eth_destination_mac_R"], datatype=str, dims=(N_pn,))
+    FPGA_sst_offload_hdr_ip_destination_address_RW = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_sst_offload_hdr_ip_destination_address_RW"], datatype=str, dims=(N_pn,), access=AttrWriteType.READ_WRITE)
+    FPGA_sst_offload_hdr_ip_destination_address_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_sst_offload_hdr_ip_destination_address_R"], datatype=str, dims=(N_pn,))
+    FPGA_sst_offload_hdr_udp_destination_port_RW = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_sst_offload_hdr_udp_destination_port_RW"], datatype=numpy.uint16, dims=(N_pn,), access=AttrWriteType.READ_WRITE)
+    FPGA_sst_offload_hdr_udp_destination_port_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_sst_offload_hdr_udp_destination_port_R"], datatype=numpy.uint16, dims=(N_pn,))
+    FPGA_sst_offload_bsn_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_sst_offload_bsn_R"], datatype=numpy.int64, dims=(N_pn,))
+    FPGA_sst_offload_weighted_subbands_RW = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_sst_offload_weighted_subbands_RW"], datatype=bool, dims=(N_pn,), access=AttrWriteType.READ_WRITE)
+    FPGA_sst_offload_weighted_subbands_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_sst_offload_weighted_subbands_R"], datatype=bool, dims=(N_pn,))
+
+    FPGA_sst_offload_nof_packets_R = attribute_wrapper(comms_annotation=["FPGA_sst_offload_nof_packets_R"], datatype=numpy.int32, dims=(N_pn,))
+    FPGA_sst_offload_nof_valid_R = attribute_wrapper(comms_annotation=["FPGA_sst_offload_nof_valid_R"], datatype=numpy.int32, dims=(N_pn,))
 
     # number of packets with valid payloads
-    nof_valid_payloads_R    = attribute_wrapper(comms_id=StatisticsClient, comms_annotation={"type": "statistics", "parameter": "nof_valid_payloads"}, dims=(StationSSTCollector.MAX_FPGAS,), datatype=numpy.uint64)
+    nof_valid_payloads_R    = attribute_wrapper(comms_id=StatisticsClient, comms_annotation={"type": "statistics", "parameter": "nof_valid_payloads"}, dims=(N_pn,), datatype=numpy.uint64)
     # number of packets with invalid payloads
-    nof_payload_errors_R    = attribute_wrapper(comms_id=StatisticsClient, comms_annotation={"type": "statistics", "parameter": "nof_payload_errors"}, dims=(StationSSTCollector.MAX_FPGAS,), datatype=numpy.uint64)
+    nof_payload_errors_R    = attribute_wrapper(comms_id=StatisticsClient, comms_annotation={"type": "statistics", "parameter": "nof_payload_errors"}, dims=(N_pn,), datatype=numpy.uint64)
     # latest SSTs
-    sst_R                   = attribute_wrapper(comms_id=StatisticsClient, comms_annotation={"type": "statistics", "parameter": "sst_values"}, dims=(StationSSTCollector.MAX_INPUTS, StationSSTCollector.MAX_SUBBANDS), datatype=numpy.uint64)
+    sst_R                   = attribute_wrapper(comms_id=StatisticsClient, comms_annotation={"type": "statistics", "parameter": "sst_values"}, dims=(MAX_INPUTS, N_subbands), datatype=numpy.uint64)
     # reported timestamp
     # for each row in the latest SSTs
-    sst_timestamp_R         = attribute_wrapper(comms_id=StatisticsClient, comms_annotation={"type": "statistics", "parameter": "sst_timestamps"}, dims=(StationSSTCollector.MAX_INPUTS,), datatype=numpy.uint64)
+    sst_timestamp_R         = attribute_wrapper(comms_id=StatisticsClient, comms_annotation={"type": "statistics", "parameter": "sst_timestamps"}, dims=(MAX_INPUTS,), datatype=numpy.uint64)
     # integration interval for each row in the latest SSTs
-    integration_interval_R  = attribute_wrapper(comms_id=StatisticsClient, comms_annotation={"type": "statistics", "parameter": "integration_intervals"}, dims=(StationSSTCollector.MAX_INPUTS,), datatype=numpy.float32)
+    integration_interval_R  = attribute_wrapper(comms_id=StatisticsClient, comms_annotation={"type": "statistics", "parameter": "integration_intervals"}, dims=(MAX_INPUTS,), datatype=numpy.float32)
     # whether the subband data was calibrated by the SDP (that is, were subband weights applied)
-    subbands_calibrated_R   = attribute_wrapper(comms_id=StatisticsClient, comms_annotation={"type": "statistics", "parameter": "subbands_calibrated"}, dims=(StationSSTCollector.MAX_INPUTS,), datatype=bool)
+    subbands_calibrated_R   = attribute_wrapper(comms_id=StatisticsClient, comms_annotation={"type": "statistics", "parameter": "subbands_calibrated"}, dims=(MAX_INPUTS,), datatype=bool)
 
     # ----------
     # Summarising Attributes
     # ----------
-    FPGA_processing_error_R      = attribute(dtype=(bool,), max_dim_x=16)
+    FPGA_processing_error_R      = attribute(dtype=(bool,), max_dim_x=N_pn)
 
     def read_FPGA_processing_error_R(self):
         return self.sdp_proxy.TR_fpga_mask_RW & (
diff --git a/tangostationcontrol/tangostationcontrol/devices/sdp/statistics.py b/tangostationcontrol/tangostationcontrol/devices/sdp/statistics.py
index 1581b695bf35e1f5ead27b292d134f29da62a5be..8e2bc497a752176a96bbd7d996448a15fac36c78 100644
--- a/tangostationcontrol/tangostationcontrol/devices/sdp/statistics.py
+++ b/tangostationcontrol/tangostationcontrol/devices/sdp/statistics.py
@@ -22,6 +22,7 @@ from tangostationcontrol.clients.statistics.client import StatisticsClient
 from tangostationcontrol.clients.attribute_wrapper import attribute_wrapper
 from tangostationcontrol.devices.opcua_device import opcua_device
 from tangostationcontrol.common.lofar_logging import log_exceptions
+from tangostationcontrol.common.constants import MAX_ETH_FRAME_SIZE
 
 import logging
 
@@ -39,6 +40,9 @@ class Statistics(opcua_device):
     def STATISTICS_COLLECTOR_CLASS(self):
         raise NotImplementedError
 
+    # Maximum number of supported simultaneous replicator clients
+    MAX_STATISTICS_CLIENTS = 128
+
     # -----------------
     # Device Properties
     # -----------------
@@ -63,7 +67,7 @@ class Statistics(opcua_device):
     # number of UDP packets that were dropped because we couldn't keep up with processing
     nof_packets_dropped_R   = attribute_wrapper(comms_id=StatisticsClient, comms_annotation={"type": "udp", "parameter": "nof_packets_dropped"}, datatype=numpy.uint64)
     # last packet we processed
-    last_packet_R           = attribute_wrapper(comms_id=StatisticsClient, comms_annotation={"type": "udp", "parameter": "last_packet"}, dims=(9000,), datatype=numpy.uint8)
+    last_packet_R           = attribute_wrapper(comms_id=StatisticsClient, comms_annotation={"type": "udp", "parameter": "last_packet"}, dims=(MAX_ETH_FRAME_SIZE,), datatype=numpy.uint8)
     # when last packet was received
     last_packet_timestamp_R = attribute_wrapper(comms_id=StatisticsClient, comms_annotation={"type": "udp", "parameter": "last_packet_timestamp"}, datatype=numpy.uint64)
 
@@ -72,7 +76,7 @@ class Statistics(opcua_device):
     queue_collector_fill_percentage_R = attribute_wrapper(comms_id=StatisticsClient, comms_annotation={"type": "queue", "parameter": "collector_fill_percentage"}, datatype=numpy.uint64)
     queue_replicator_fill_percentage_R = attribute_wrapper(comms_id=StatisticsClient, comms_annotation={"type": "queue", "parameter": "replicator_fill_percentage"}, datatype=numpy.uint64)
 
-    replicator_clients_R = attribute_wrapper(comms_id=StatisticsClient, comms_annotation={"type": "replicator", "parameter": "clients"}, dims=(128,), datatype=str)
+    replicator_clients_R = attribute_wrapper(comms_id=StatisticsClient, comms_annotation={"type": "replicator", "parameter": "clients"}, dims=(MAX_STATISTICS_CLIENTS,), datatype=str)
     replicator_nof_bytes_sent_R = attribute_wrapper(comms_id=StatisticsClient, comms_annotation={"type": "replicator", "parameter": "nof_bytes_sent"}, datatype=numpy.uint64)
 
     replicator_nof_packets_sent_R = attribute_wrapper(comms_id=StatisticsClient, comms_annotation={"type": "replicator", "parameter": "nof_packets_sent"}, datatype=numpy.uint64)
@@ -83,7 +87,7 @@ class Statistics(opcua_device):
     # number of invalid (non-SST) packets received
     nof_invalid_packets_R   = attribute_wrapper(comms_id=StatisticsClient, comms_annotation={"type": "statistics", "parameter": "nof_invalid_packets"}, datatype=numpy.uint64)
     # last packet that could not be parsed
-    last_invalid_packet_R   = attribute_wrapper(comms_id=StatisticsClient, comms_annotation={"type": "statistics", "parameter": "last_invalid_packet"}, dims=(9000,), datatype=numpy.uint8)
+    last_invalid_packet_R   = attribute_wrapper(comms_id=StatisticsClient, comms_annotation={"type": "statistics", "parameter": "last_invalid_packet"}, dims=(MAX_ETH_FRAME_SIZE,), datatype=numpy.uint8)
     # what the last exception was
     last_invalid_packet_exception_R = attribute_wrapper(comms_id=StatisticsClient, comms_annotation={"type": "statistics", "parameter": "last_invalid_packet_exception"}, datatype=str)
 
diff --git a/tangostationcontrol/tangostationcontrol/devices/sdp/xst.py b/tangostationcontrol/tangostationcontrol/devices/sdp/xst.py
index dec4acfb4d5ea9837a133db3474a008bd57983be..f39bbb3843377f77229e4a91f3fcde23443f3ad0 100644
--- a/tangostationcontrol/tangostationcontrol/devices/sdp/xst.py
+++ b/tangostationcontrol/tangostationcontrol/devices/sdp/xst.py
@@ -19,6 +19,7 @@ from lofar_station_client.statistics.collector import XSTCollector
 
 # Additional import
 from tangostationcontrol.common.entrypoint import entry
+from tangostationcontrol.common.constants import N_pn, P_sq, DEFAULT_SUBBAND, MAX_PARALLEL_SUBBANDS, MAX_BLOCKS, BLOCK_LENGTH, VALUES_PER_COMPLEX, MAX_INPUTS
 from tangostationcontrol.clients.attribute_wrapper import attribute_wrapper
 from tangostationcontrol.clients.opcua_client import OPCUAConnection
 from tangostationcontrol.clients.statistics.client import StatisticsClient
@@ -56,25 +57,25 @@ class XST(Statistics):
     FPGA_xst_processing_enable_RW_default = device_property(
         dtype='DevVarBooleanArray',
         mandatory=False,
-        default_value=[True] * 16
+        default_value=[True] * N_pn
     )
 
     FPGA_xst_subband_select_RW_default = device_property(
         dtype='DevVarULongArray',
         mandatory=False,
-        default_value=[[0,102,0,0,0,0,0,0]] * 16
+        default_value=[[0,DEFAULT_SUBBAND,0,0,0,0,0,0]] * N_pn
     )
 
     FPGA_xst_integration_interval_RW_default = device_property(
         dtype='DevVarDoubleArray',
         mandatory=False,
-        default_value=[1.0] * 16
+        default_value=[1.0] * N_pn
     )
 
     FPGA_xst_offload_enable_RW_default = device_property(
         dtype='DevVarBooleanArray',
         mandatory=False,
-        default_value=[True] * 16
+        default_value=[True] * N_pn
     )
 
     FIRST_DEFAULT_SETTINGS = [
@@ -94,132 +95,129 @@ class XST(Statistics):
     # ----------
 
     # FPGA control points for XSTs
-    FPGA_xst_integration_interval_RW = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_integration_interval_RW"], datatype=numpy.double, dims=(16,), access=AttrWriteType.READ_WRITE)
-    FPGA_xst_integration_interval_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_integration_interval_R"], datatype=numpy.double, dims=(16,))
-    FPGA_xst_offload_enable_RW = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_offload_enable_RW"], datatype=bool, dims=(16,), access=AttrWriteType.READ_WRITE)
-    FPGA_xst_offload_enable_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_offload_enable_R"], datatype=bool, dims=(16,))
-    FPGA_xst_offload_hdr_eth_destination_mac_RW = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_offload_hdr_eth_destination_mac_RW"], datatype=str, dims=(16,), access=AttrWriteType.READ_WRITE)
-    FPGA_xst_offload_hdr_eth_destination_mac_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_offload_hdr_eth_destination_mac_R"], datatype=str, dims=(16,))
-    FPGA_xst_offload_hdr_ip_destination_address_RW = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_offload_hdr_ip_destination_address_RW"], datatype=str, dims=(16,), access=AttrWriteType.READ_WRITE)
-    FPGA_xst_offload_hdr_ip_destination_address_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_offload_hdr_ip_destination_address_R"], datatype=str, dims=(16,))
-    FPGA_xst_offload_hdr_udp_destination_port_RW = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_offload_hdr_udp_destination_port_RW"], datatype=numpy.uint16, dims=(16,), access=AttrWriteType.READ_WRITE)
-    FPGA_xst_offload_hdr_udp_destination_port_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_offload_hdr_udp_destination_port_R"], datatype=numpy.uint16, dims=(16,))
-    FPGA_xst_offload_bsn_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_offload_bsn_R"], datatype=numpy.int64, dims=(16,))
-    FPGA_xst_processing_enable_RW = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_processing_enable_RW"], datatype=bool, dims=(16,), access=AttrWriteType.READ_WRITE)
-    FPGA_xst_processing_enable_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_processing_enable_R"], datatype=bool, dims=(16,))
-    FPGA_xst_subband_select_RW = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_subband_select_RW"], datatype=numpy.uint32, dims=(8,16), access=AttrWriteType.READ_WRITE)
-    FPGA_xst_subband_select_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_subband_select_R"], datatype=numpy.uint32, dims=(8,16))
-
-    FPGA_xst_offload_nof_crosslets_RW = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_offload_nof_crosslets_RW"], datatype=numpy.uint32, dims=(16,), access=AttrWriteType.READ_WRITE)
-    FPGA_xst_offload_nof_crosslets_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_offload_nof_crosslets_R"], datatype=numpy.uint32, dims=(16,))
-    FPGA_xst_ring_nof_transport_hops_RW = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_ring_nof_transport_hops_RW"], datatype=numpy.uint32, dims=(16,), access=AttrWriteType.READ_WRITE)
-    FPGA_xst_ring_nof_transport_hops_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_ring_nof_transport_hops_R"], datatype=numpy.uint32, dims=(16,))
-
-    FPGA_xst_offload_nof_packets_R = attribute_wrapper(comms_annotation=["FPGA_xst_offload_nof_packets_R"], datatype=numpy.int32, dims=(16,))
-    FPGA_xst_offload_nof_valid_R = attribute_wrapper(comms_annotation=["FPGA_xst_offload_nof_valid_R"], datatype=numpy.int32, dims=(16,))
-
-    N_PN = 16   # Number of FPGAs per antenna band that is controlled via the SC - SDP interface.
-    P_SQ = 9
-
-    FPGA_xst_ring_rx_clear_total_counts_RW = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_ring_rx_clear_total_counts_RW"], datatype=bool, dims=(N_PN,), access=AttrWriteType.READ_WRITE)
-    FPGA_xst_ring_rx_clear_total_counts_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_ring_rx_clear_total_counts_R"], datatype=bool, dims=(N_PN,))
-    FPGA_xst_rx_align_stream_enable_RW = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_rx_align_stream_enable_RW"], datatype=bool, dims=(N_PN,P_SQ), access=AttrWriteType.READ_WRITE)
-    FPGA_xst_rx_align_stream_enable_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_rx_align_stream_enable_R"], datatype=bool, dims=(N_PN,P_SQ))
-    FPGA_xst_ring_rx_total_nof_packets_received_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_ring_rx_total_nof_packets_received_R"], datatype=numpy.uint32, dims=(N_PN,))
-    FPGA_xst_ring_rx_total_nof_packets_discarded_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_ring_rx_total_nof_packets_discarded_R"], datatype=numpy.uint32, dims=(N_PN,))
-    FPGA_xst_ring_rx_total_nof_sync_received_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_ring_rx_total_nof_sync_received_R"], datatype=numpy.uint32, dims=(N_PN,))
-    FPGA_xst_ring_rx_total_nof_sync_discarded_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_ring_rx_total_nof_sync_discarded_R"], datatype=numpy.uint32, dims=(N_PN,))
-    FPGA_xst_ring_rx_bsn_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_ring_rx_bsn_R"], datatype=numpy.int64, dims=(N_PN, N_PN))
-    FPGA_xst_ring_rx_nof_packets_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_ring_rx_nof_packets_R"], datatype=numpy.int32, dims=(N_PN, N_PN))
-    FPGA_xst_ring_rx_nof_valid_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_ring_rx_nof_valid_R"], datatype=numpy.int32, dims=(N_PN, N_PN))
-    FPGA_xst_ring_rx_latency_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_ring_rx_latency_R"], datatype=numpy.int32, dims=(N_PN, N_PN))
-    FPGA_xst_rx_align_bsn_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_rx_align_bsn_R"], datatype=numpy.int64, dims=(N_PN,P_SQ))
-    FPGA_xst_rx_align_nof_packets_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_rx_align_nof_packets_R"], datatype=numpy.int32, dims=(N_PN,P_SQ))
-    FPGA_xst_rx_align_nof_valid_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_rx_align_nof_valid_R"], datatype=numpy.int32, dims=(N_PN,P_SQ))
-    FPGA_xst_rx_align_latency_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_rx_align_latency_R"], datatype=numpy.int32, dims=(N_PN,P_SQ))
-    FPGA_xst_rx_align_nof_replaced_packets_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_rx_align_nof_replaced_packets_R"], datatype=numpy.int32, dims=(N_PN,P_SQ))
-    FPGA_xst_aligned_bsn_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_aligned_bsn_R"], datatype=numpy.int64, dims=(N_PN,))
-    FPGA_xst_aligned_nof_packets_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_aligned_nof_packets_R"], datatype=numpy.int32, dims=(N_PN,))
-    FPGA_xst_aligned_nof_valid_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_aligned_nof_valid_R"], datatype=numpy.int32, dims=(N_PN,))
-    FPGA_xst_aligned_latency_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_aligned_latency_R"], datatype=numpy.int32, dims=(N_PN,))
-    FPGA_xst_ring_tx_bsn_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_ring_tx_bsn_R"], datatype=numpy.int64, dims=(N_PN,N_PN))
-    FPGA_xst_ring_tx_nof_packets_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_ring_tx_nof_packets_R"], datatype=numpy.int32, dims=(N_PN,N_PN))
-    FPGA_xst_ring_tx_nof_valid_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_ring_tx_nof_valid_R"], datatype=numpy.int32, dims=(N_PN,N_PN))
-    FPGA_xst_ring_tx_latency_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_ring_tx_latency_R"], datatype=numpy.int32, dims=(N_PN,N_PN))
+    FPGA_xst_integration_interval_RW = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_integration_interval_RW"], datatype=numpy.double, dims=(N_pn,), access=AttrWriteType.READ_WRITE)
+    FPGA_xst_integration_interval_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_integration_interval_R"], datatype=numpy.double, dims=(N_pn,))
+    FPGA_xst_offload_enable_RW = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_offload_enable_RW"], datatype=bool, dims=(N_pn,), access=AttrWriteType.READ_WRITE)
+    FPGA_xst_offload_enable_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_offload_enable_R"], datatype=bool, dims=(N_pn,))
+    FPGA_xst_offload_hdr_eth_destination_mac_RW = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_offload_hdr_eth_destination_mac_RW"], datatype=str, dims=(N_pn,), access=AttrWriteType.READ_WRITE)
+    FPGA_xst_offload_hdr_eth_destination_mac_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_offload_hdr_eth_destination_mac_R"], datatype=str, dims=(N_pn,))
+    FPGA_xst_offload_hdr_ip_destination_address_RW = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_offload_hdr_ip_destination_address_RW"], datatype=str, dims=(N_pn,), access=AttrWriteType.READ_WRITE)
+    FPGA_xst_offload_hdr_ip_destination_address_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_offload_hdr_ip_destination_address_R"], datatype=str, dims=(N_pn,))
+    FPGA_xst_offload_hdr_udp_destination_port_RW = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_offload_hdr_udp_destination_port_RW"], datatype=numpy.uint16, dims=(N_pn,), access=AttrWriteType.READ_WRITE)
+    FPGA_xst_offload_hdr_udp_destination_port_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_offload_hdr_udp_destination_port_R"], datatype=numpy.uint16, dims=(N_pn,))
+    FPGA_xst_offload_bsn_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_offload_bsn_R"], datatype=numpy.int64, dims=(N_pn,))
+    FPGA_xst_processing_enable_RW = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_processing_enable_RW"], datatype=bool, dims=(N_pn,), access=AttrWriteType.READ_WRITE)
+    FPGA_xst_processing_enable_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_processing_enable_R"], datatype=bool, dims=(N_pn,))
+    FPGA_xst_subband_select_RW = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_subband_select_RW"], datatype=numpy.uint32, dims=(MAX_PARALLEL_SUBBANDS,N_pn), access=AttrWriteType.READ_WRITE)
+    FPGA_xst_subband_select_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_subband_select_R"], datatype=numpy.uint32, dims=(MAX_PARALLEL_SUBBANDS,N_pn))
+
+    FPGA_xst_offload_nof_crosslets_RW = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_offload_nof_crosslets_RW"], datatype=numpy.uint32, dims=(N_pn,), access=AttrWriteType.READ_WRITE)
+    FPGA_xst_offload_nof_crosslets_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_offload_nof_crosslets_R"], datatype=numpy.uint32, dims=(N_pn,))
+    FPGA_xst_ring_nof_transport_hops_RW = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_ring_nof_transport_hops_RW"], datatype=numpy.uint32, dims=(N_pn,), access=AttrWriteType.READ_WRITE)
+    FPGA_xst_ring_nof_transport_hops_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_ring_nof_transport_hops_R"], datatype=numpy.uint32, dims=(N_pn,))
+
+    FPGA_xst_offload_nof_packets_R = attribute_wrapper(comms_annotation=["FPGA_xst_offload_nof_packets_R"], datatype=numpy.int32, dims=(N_pn,))
+    FPGA_xst_offload_nof_valid_R = attribute_wrapper(comms_annotation=["FPGA_xst_offload_nof_valid_R"], datatype=numpy.int32, dims=(N_pn,))
+
+    FPGA_xst_ring_rx_clear_total_counts_RW = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_ring_rx_clear_total_counts_RW"], datatype=bool, dims=(N_pn,), access=AttrWriteType.READ_WRITE)
+    FPGA_xst_ring_rx_clear_total_counts_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_ring_rx_clear_total_counts_R"], datatype=bool, dims=(N_pn,))
+    FPGA_xst_rx_align_stream_enable_RW = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_rx_align_stream_enable_RW"], datatype=bool, dims=(N_pn,P_sq), access=AttrWriteType.READ_WRITE)
+    FPGA_xst_rx_align_stream_enable_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_rx_align_stream_enable_R"], datatype=bool, dims=(N_pn,P_sq))
+    FPGA_xst_ring_rx_total_nof_packets_received_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_ring_rx_total_nof_packets_received_R"], datatype=numpy.uint32, dims=(N_pn,))
+    FPGA_xst_ring_rx_total_nof_packets_discarded_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_ring_rx_total_nof_packets_discarded_R"], datatype=numpy.uint32, dims=(N_pn,))
+    FPGA_xst_ring_rx_total_nof_sync_received_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_ring_rx_total_nof_sync_received_R"], datatype=numpy.uint32, dims=(N_pn,))
+    FPGA_xst_ring_rx_total_nof_sync_discarded_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_ring_rx_total_nof_sync_discarded_R"], datatype=numpy.uint32, dims=(N_pn,))
+    FPGA_xst_ring_rx_bsn_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_ring_rx_bsn_R"], datatype=numpy.int64, dims=(N_pn, N_pn))
+    FPGA_xst_ring_rx_nof_packets_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_ring_rx_nof_packets_R"], datatype=numpy.int32, dims=(N_pn, N_pn))
+    FPGA_xst_ring_rx_nof_valid_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_ring_rx_nof_valid_R"], datatype=numpy.int32, dims=(N_pn, N_pn))
+    FPGA_xst_ring_rx_latency_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_ring_rx_latency_R"], datatype=numpy.int32, dims=(N_pn, N_pn))
+    FPGA_xst_rx_align_bsn_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_rx_align_bsn_R"], datatype=numpy.int64, dims=(N_pn,P_sq))
+    FPGA_xst_rx_align_nof_packets_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_rx_align_nof_packets_R"], datatype=numpy.int32, dims=(N_pn,P_sq))
+    FPGA_xst_rx_align_nof_valid_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_rx_align_nof_valid_R"], datatype=numpy.int32, dims=(N_pn,P_sq))
+    FPGA_xst_rx_align_latency_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_rx_align_latency_R"], datatype=numpy.int32, dims=(N_pn,P_sq))
+    FPGA_xst_rx_align_nof_replaced_packets_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_rx_align_nof_replaced_packets_R"], datatype=numpy.int32, dims=(N_pn,P_sq))
+    FPGA_xst_aligned_bsn_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_aligned_bsn_R"], datatype=numpy.int64, dims=(N_pn,))
+    FPGA_xst_aligned_nof_packets_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_aligned_nof_packets_R"], datatype=numpy.int32, dims=(N_pn,))
+    FPGA_xst_aligned_nof_valid_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_aligned_nof_valid_R"], datatype=numpy.int32, dims=(N_pn,))
+    FPGA_xst_aligned_latency_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_aligned_latency_R"], datatype=numpy.int32, dims=(N_pn,))
+    FPGA_xst_ring_tx_bsn_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_ring_tx_bsn_R"], datatype=numpy.int64, dims=(N_pn,N_pn))
+    FPGA_xst_ring_tx_nof_packets_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_ring_tx_nof_packets_R"], datatype=numpy.int32, dims=(N_pn,N_pn))
+    FPGA_xst_ring_tx_nof_valid_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_ring_tx_nof_valid_R"], datatype=numpy.int32, dims=(N_pn,N_pn))
+    FPGA_xst_ring_tx_latency_R = attribute_wrapper(comms_id=OPCUAConnection, comms_annotation=["FPGA_xst_ring_tx_latency_R"], datatype=numpy.int32, dims=(N_pn,N_pn))
 
     # number of packets with valid payloads
-    nof_valid_payloads_R    = attribute_wrapper(comms_id=StatisticsClient, comms_annotation={"type": "statistics", "parameter": "nof_valid_payloads"}, dims=(XSTCollector.MAX_FPGAS,), datatype=numpy.uint64)
+    nof_valid_payloads_R    = attribute_wrapper(comms_id=StatisticsClient, comms_annotation={"type": "statistics", "parameter": "nof_valid_payloads"}, dims=(N_pn,), datatype=numpy.uint64)
     # number of packets with invalid payloads
-    nof_payload_errors_R    = attribute_wrapper(comms_id=StatisticsClient, comms_annotation={"type": "statistics", "parameter": "nof_payload_errors"}, dims=(XSTCollector.MAX_FPGAS,), datatype=numpy.uint64)
+    nof_payload_errors_R    = attribute_wrapper(comms_id=StatisticsClient, comms_annotation={"type": "statistics", "parameter": "nof_payload_errors"}, dims=(N_pn,), datatype=numpy.uint64)
     # latest XSTs
-    xst_blocks_R            = attribute_wrapper(comms_id=StatisticsClient, comms_annotation={"type": "statistics", "parameter": "xst_blocks", "reshape": True}, dims=(XSTCollector.MAX_PARALLEL_SUBBANDS, XSTCollector.MAX_BLOCKS, XSTCollector.BLOCK_LENGTH, XSTCollector.BLOCK_LENGTH, XSTCollector.VALUES_PER_COMPLEX), datatype=numpy.int64)
+    xst_blocks_R            = attribute_wrapper(comms_id=StatisticsClient, comms_annotation={"type": "statistics", "parameter": "xst_blocks", "reshape": True}, dims=(MAX_PARALLEL_SUBBANDS, MAX_BLOCKS, BLOCK_LENGTH, BLOCK_LENGTH, VALUES_PER_COMPLEX), datatype=numpy.int64)
     # whether the values in the block are conjugated and transposed
-    xst_conjugated_R        = attribute_wrapper(comms_id=StatisticsClient, comms_annotation={"type": "statistics", "parameter": "xst_conjugated", "reshape": True}, dims=(XSTCollector.MAX_PARALLEL_SUBBANDS, XSTCollector.MAX_BLOCKS), datatype=bool)
+    xst_conjugated_R        = attribute_wrapper(comms_id=StatisticsClient, comms_annotation={"type": "statistics", "parameter": "xst_conjugated", "reshape": True}, dims=(MAX_PARALLEL_SUBBANDS, MAX_BLOCKS), datatype=bool)
     # reported timestamp for each subband in the latest XSTs
-    xst_timestamp_R         = attribute_wrapper(comms_id=StatisticsClient, comms_annotation={"type": "statistics", "parameter": "xst_timestamps"}, dims=(XSTCollector.MAX_PARALLEL_SUBBANDS,), datatype=numpy.uint64)
+    xst_timestamp_R         = attribute_wrapper(comms_id=StatisticsClient, comms_annotation={"type": "statistics", "parameter": "xst_timestamps"}, dims=(MAX_PARALLEL_SUBBANDS,), datatype=numpy.uint64)
     # which subband the XSTs describe
-    xst_subbands_R          = attribute_wrapper(comms_id=StatisticsClient, comms_annotation={"type": "statistics", "parameter": "xst_subbands"}, dims=(XSTCollector.MAX_PARALLEL_SUBBANDS,), datatype=numpy.uint16)
+    xst_subbands_R          = attribute_wrapper(comms_id=StatisticsClient, comms_annotation={"type": "statistics", "parameter": "xst_subbands"}, dims=(MAX_PARALLEL_SUBBANDS,), datatype=numpy.uint16)
     # integration interval for each subband in the latest XSTs
-    xst_integration_interval_R  = attribute_wrapper(comms_id=StatisticsClient, comms_annotation={"type": "statistics", "parameter": "xst_integration_intervals"}, dims=(XSTCollector.MAX_PARALLEL_SUBBANDS,), datatype=numpy.float32)
+    xst_integration_interval_R  = attribute_wrapper(comms_id=StatisticsClient, comms_annotation={"type": "statistics", "parameter": "xst_integration_intervals"}, dims=(MAX_PARALLEL_SUBBANDS,), datatype=numpy.float32)
 
     # xst_R, but as a matrix of subband x (input x input)
-    xst_real_R              = attribute(max_dim_x=XSTCollector.MAX_INPUTS * XSTCollector.MAX_INPUTS, max_dim_y=XSTCollector.MAX_PARALLEL_SUBBANDS, dtype=((numpy.float32,),))
-    xst_imag_R              = attribute(max_dim_x=XSTCollector.MAX_INPUTS * XSTCollector.MAX_INPUTS, max_dim_y=XSTCollector.MAX_PARALLEL_SUBBANDS, dtype=((numpy.float32,),))
-    xst_power_R             = attribute(max_dim_x=XSTCollector.MAX_INPUTS * XSTCollector.MAX_INPUTS, max_dim_y=XSTCollector.MAX_PARALLEL_SUBBANDS, dtype=((numpy.float32,),))
-    xst_phase_R             = attribute(max_dim_x=XSTCollector.MAX_INPUTS * XSTCollector.MAX_INPUTS, max_dim_y=XSTCollector.MAX_PARALLEL_SUBBANDS, dtype=((numpy.float32,),))
+    xst_real_R              = attribute(max_dim_x=MAX_INPUTS * MAX_INPUTS, max_dim_y=MAX_PARALLEL_SUBBANDS, dtype=((numpy.float32,),))
+    xst_imag_R              = attribute(max_dim_x=MAX_INPUTS * MAX_INPUTS, max_dim_y=MAX_PARALLEL_SUBBANDS, dtype=((numpy.float32,),))
+    xst_power_R             = attribute(max_dim_x=MAX_INPUTS * MAX_INPUTS, max_dim_y=MAX_PARALLEL_SUBBANDS, dtype=((numpy.float32,),))
+    xst_phase_R             = attribute(max_dim_x=MAX_INPUTS * MAX_INPUTS, max_dim_y=MAX_PARALLEL_SUBBANDS, dtype=((numpy.float32,),))
 
     def read_xst_real_R(self):
-        return numpy.real(self.statistics_client.collector.xst_values()).reshape(XSTCollector.MAX_PARALLEL_SUBBANDS, XSTCollector.MAX_INPUTS * XSTCollector.MAX_INPUTS)
+        return numpy.real(self.statistics_client.collector.xst_values()).reshape(MAX_PARALLEL_SUBBANDS, MAX_INPUTS * MAX_INPUTS)
 
     def read_xst_imag_R(self):
-        return numpy.imag(self.statistics_client.collector.xst_values()).reshape(XSTCollector.MAX_PARALLEL_SUBBANDS, XSTCollector.MAX_INPUTS * XSTCollector.MAX_INPUTS)
+        return numpy.imag(self.statistics_client.collector.xst_values()).reshape(MAX_PARALLEL_SUBBANDS, MAX_INPUTS * MAX_INPUTS)
 
     def read_xst_power_R(self):
-        return numpy.abs(self.statistics_client.collector.xst_values()).reshape(XSTCollector.MAX_PARALLEL_SUBBANDS, XSTCollector.MAX_INPUTS * XSTCollector.MAX_INPUTS)
+        return numpy.abs(self.statistics_client.collector.xst_values()).reshape(MAX_PARALLEL_SUBBANDS, MAX_INPUTS * MAX_INPUTS)
 
     def read_xst_phase_R(self):
-        return numpy.angle(self.statistics_client.collector.xst_values()).reshape(XSTCollector.MAX_PARALLEL_SUBBANDS, XSTCollector.MAX_INPUTS * XSTCollector.MAX_INPUTS)
+        return numpy.angle(self.statistics_client.collector.xst_values()).reshape(MAX_PARALLEL_SUBBANDS, MAX_INPUTS * MAX_INPUTS)
 
     # xst_R, but as a matrix of input x input, for each specific subband index
-    xst_0_real_R            = attribute(max_dim_x=XSTCollector.MAX_INPUTS, max_dim_y=XSTCollector.MAX_INPUTS, dtype=((numpy.float32,),), fget = lambda self: self.read_xst_N_real_R(0))
-    xst_0_imag_R            = attribute(max_dim_x=XSTCollector.MAX_INPUTS, max_dim_y=XSTCollector.MAX_INPUTS, dtype=((numpy.float32,),), fget = lambda self: self.read_xst_N_imag_R(0))
-    xst_0_power_R           = attribute(max_dim_x=XSTCollector.MAX_INPUTS, max_dim_y=XSTCollector.MAX_INPUTS, dtype=((numpy.float32,),), fget = lambda self: self.read_xst_N_power_R(0))
-    xst_0_phase_R           = attribute(max_dim_x=XSTCollector.MAX_INPUTS, max_dim_y=XSTCollector.MAX_INPUTS, dtype=((numpy.float32,),), fget = lambda self: self.read_xst_N_phase_R(0))
-
-    xst_1_real_R            = attribute(max_dim_x=XSTCollector.MAX_INPUTS, max_dim_y=XSTCollector.MAX_INPUTS, dtype=((numpy.float32,),), fget = lambda self: self.read_xst_N_real_R(1))
-    xst_1_imag_R            = attribute(max_dim_x=XSTCollector.MAX_INPUTS, max_dim_y=XSTCollector.MAX_INPUTS, dtype=((numpy.float32,),), fget = lambda self: self.read_xst_N_imag_R(1))
-    xst_1_power_R           = attribute(max_dim_x=XSTCollector.MAX_INPUTS, max_dim_y=XSTCollector.MAX_INPUTS, dtype=((numpy.float32,),), fget = lambda self: self.read_xst_N_power_R(1))
-    xst_1_phase_R           = attribute(max_dim_x=XSTCollector.MAX_INPUTS, max_dim_y=XSTCollector.MAX_INPUTS, dtype=((numpy.float32,),), fget = lambda self: self.read_xst_N_phase_R(1))
-
-    xst_2_real_R            = attribute(max_dim_x=XSTCollector.MAX_INPUTS, max_dim_y=XSTCollector.MAX_INPUTS, dtype=((numpy.float32,),), fget = lambda self: self.read_xst_N_real_R(2))
-    xst_2_imag_R            = attribute(max_dim_x=XSTCollector.MAX_INPUTS, max_dim_y=XSTCollector.MAX_INPUTS, dtype=((numpy.float32,),), fget = lambda self: self.read_xst_N_imag_R(2))
-    xst_2_power_R           = attribute(max_dim_x=XSTCollector.MAX_INPUTS, max_dim_y=XSTCollector.MAX_INPUTS, dtype=((numpy.float32,),), fget = lambda self: self.read_xst_N_power_R(2))
-    xst_2_phase_R           = attribute(max_dim_x=XSTCollector.MAX_INPUTS, max_dim_y=XSTCollector.MAX_INPUTS, dtype=((numpy.float32,),), fget = lambda self: self.read_xst_N_phase_R(2))
-
-    xst_3_real_R            = attribute(max_dim_x=XSTCollector.MAX_INPUTS, max_dim_y=XSTCollector.MAX_INPUTS, dtype=((numpy.float32,),), fget = lambda self: self.read_xst_N_real_R(3))
-    xst_3_imag_R            = attribute(max_dim_x=XSTCollector.MAX_INPUTS, max_dim_y=XSTCollector.MAX_INPUTS, dtype=((numpy.float32,),), fget = lambda self: self.read_xst_N_imag_R(3))
-    xst_3_power_R           = attribute(max_dim_x=XSTCollector.MAX_INPUTS, max_dim_y=XSTCollector.MAX_INPUTS, dtype=((numpy.float32,),), fget = lambda self: self.read_xst_N_power_R(3))
-    xst_3_phase_R           = attribute(max_dim_x=XSTCollector.MAX_INPUTS, max_dim_y=XSTCollector.MAX_INPUTS, dtype=((numpy.float32,),), fget = lambda self: self.read_xst_N_phase_R(3))
-
-    xst_4_real_R            = attribute(max_dim_x=XSTCollector.MAX_INPUTS, max_dim_y=XSTCollector.MAX_INPUTS, dtype=((numpy.float32,),), fget = lambda self: self.read_xst_N_real_R(4))
-    xst_4_imag_R            = attribute(max_dim_x=XSTCollector.MAX_INPUTS, max_dim_y=XSTCollector.MAX_INPUTS, dtype=((numpy.float32,),), fget = lambda self: self.read_xst_N_imag_R(4))
-    xst_4_power_R           = attribute(max_dim_x=XSTCollector.MAX_INPUTS, max_dim_y=XSTCollector.MAX_INPUTS, dtype=((numpy.float32,),), fget = lambda self: self.read_xst_N_power_R(4))
-    xst_4_phase_R           = attribute(max_dim_x=XSTCollector.MAX_INPUTS, max_dim_y=XSTCollector.MAX_INPUTS, dtype=((numpy.float32,),), fget = lambda self: self.read_xst_N_phase_R(4))
-
-    xst_5_real_R            = attribute(max_dim_x=XSTCollector.MAX_INPUTS, max_dim_y=XSTCollector.MAX_INPUTS, dtype=((numpy.float32,),), fget = lambda self: self.read_xst_N_real_R(5))
-    xst_5_imag_R            = attribute(max_dim_x=XSTCollector.MAX_INPUTS, max_dim_y=XSTCollector.MAX_INPUTS, dtype=((numpy.float32,),), fget = lambda self: self.read_xst_N_imag_R(5))
-    xst_5_power_R           = attribute(max_dim_x=XSTCollector.MAX_INPUTS, max_dim_y=XSTCollector.MAX_INPUTS, dtype=((numpy.float32,),), fget = lambda self: self.read_xst_N_power_R(5))
-    xst_5_phase_R           = attribute(max_dim_x=XSTCollector.MAX_INPUTS, max_dim_y=XSTCollector.MAX_INPUTS, dtype=((numpy.float32,),), fget = lambda self: self.read_xst_N_phase_R(5))
-
-    xst_6_real_R            = attribute(max_dim_x=XSTCollector.MAX_INPUTS, max_dim_y=XSTCollector.MAX_INPUTS, dtype=((numpy.float32,),), fget = lambda self: self.read_xst_N_real_R(6))
-    xst_6_imag_R            = attribute(max_dim_x=XSTCollector.MAX_INPUTS, max_dim_y=XSTCollector.MAX_INPUTS, dtype=((numpy.float32,),), fget = lambda self: self.read_xst_N_imag_R(6))
-    xst_6_power_R           = attribute(max_dim_x=XSTCollector.MAX_INPUTS, max_dim_y=XSTCollector.MAX_INPUTS, dtype=((numpy.float32,),), fget = lambda self: self.read_xst_N_power_R(6))
-    xst_6_phase_R           = attribute(max_dim_x=XSTCollector.MAX_INPUTS, max_dim_y=XSTCollector.MAX_INPUTS, dtype=((numpy.float32,),), fget = lambda self: self.read_xst_N_phase_R(6))
-
-    xst_7_real_R            = attribute(max_dim_x=XSTCollector.MAX_INPUTS, max_dim_y=XSTCollector.MAX_INPUTS, dtype=((numpy.float32,),), fget = lambda self: self.read_xst_N_real_R(7))
-    xst_7_imag_R            = attribute(max_dim_x=XSTCollector.MAX_INPUTS, max_dim_y=XSTCollector.MAX_INPUTS, dtype=((numpy.float32,),), fget = lambda self: self.read_xst_N_imag_R(7))
-    xst_7_power_R           = attribute(max_dim_x=XSTCollector.MAX_INPUTS, max_dim_y=XSTCollector.MAX_INPUTS, dtype=((numpy.float32,),), fget = lambda self: self.read_xst_N_power_R(7))
-    xst_7_phase_R           = attribute(max_dim_x=XSTCollector.MAX_INPUTS, max_dim_y=XSTCollector.MAX_INPUTS, dtype=((numpy.float32,),), fget = lambda self: self.read_xst_N_phase_R(7))
+    xst_0_real_R            = attribute(max_dim_x=MAX_INPUTS, max_dim_y=MAX_INPUTS, dtype=((numpy.float32,),), fget = lambda self: self.read_xst_N_real_R(0))
+    xst_0_imag_R            = attribute(max_dim_x=MAX_INPUTS, max_dim_y=MAX_INPUTS, dtype=((numpy.float32,),), fget = lambda self: self.read_xst_N_imag_R(0))
+    xst_0_power_R           = attribute(max_dim_x=MAX_INPUTS, max_dim_y=MAX_INPUTS, dtype=((numpy.float32,),), fget = lambda self: self.read_xst_N_power_R(0))
+    xst_0_phase_R           = attribute(max_dim_x=MAX_INPUTS, max_dim_y=MAX_INPUTS, dtype=((numpy.float32,),), fget = lambda self: self.read_xst_N_phase_R(0))
+
+    xst_1_real_R            = attribute(max_dim_x=MAX_INPUTS, max_dim_y=MAX_INPUTS, dtype=((numpy.float32,),), fget = lambda self: self.read_xst_N_real_R(1))
+    xst_1_imag_R            = attribute(max_dim_x=MAX_INPUTS, max_dim_y=MAX_INPUTS, dtype=((numpy.float32,),), fget = lambda self: self.read_xst_N_imag_R(1))
+    xst_1_power_R           = attribute(max_dim_x=MAX_INPUTS, max_dim_y=MAX_INPUTS, dtype=((numpy.float32,),), fget = lambda self: self.read_xst_N_power_R(1))
+    xst_1_phase_R           = attribute(max_dim_x=MAX_INPUTS, max_dim_y=MAX_INPUTS, dtype=((numpy.float32,),), fget = lambda self: self.read_xst_N_phase_R(1))
+
+    xst_2_real_R            = attribute(max_dim_x=MAX_INPUTS, max_dim_y=MAX_INPUTS, dtype=((numpy.float32,),), fget = lambda self: self.read_xst_N_real_R(2))
+    xst_2_imag_R            = attribute(max_dim_x=MAX_INPUTS, max_dim_y=MAX_INPUTS, dtype=((numpy.float32,),), fget = lambda self: self.read_xst_N_imag_R(2))
+    xst_2_power_R           = attribute(max_dim_x=MAX_INPUTS, max_dim_y=MAX_INPUTS, dtype=((numpy.float32,),), fget = lambda self: self.read_xst_N_power_R(2))
+    xst_2_phase_R           = attribute(max_dim_x=MAX_INPUTS, max_dim_y=MAX_INPUTS, dtype=((numpy.float32,),), fget = lambda self: self.read_xst_N_phase_R(2))
+
+    xst_3_real_R            = attribute(max_dim_x=MAX_INPUTS, max_dim_y=MAX_INPUTS, dtype=((numpy.float32,),), fget = lambda self: self.read_xst_N_real_R(3))
+    xst_3_imag_R            = attribute(max_dim_x=MAX_INPUTS, max_dim_y=MAX_INPUTS, dtype=((numpy.float32,),), fget = lambda self: self.read_xst_N_imag_R(3))
+    xst_3_power_R           = attribute(max_dim_x=MAX_INPUTS, max_dim_y=MAX_INPUTS, dtype=((numpy.float32,),), fget = lambda self: self.read_xst_N_power_R(3))
+    xst_3_phase_R           = attribute(max_dim_x=MAX_INPUTS, max_dim_y=MAX_INPUTS, dtype=((numpy.float32,),), fget = lambda self: self.read_xst_N_phase_R(3))
+
+    xst_4_real_R            = attribute(max_dim_x=MAX_INPUTS, max_dim_y=MAX_INPUTS, dtype=((numpy.float32,),), fget = lambda self: self.read_xst_N_real_R(4))
+    xst_4_imag_R            = attribute(max_dim_x=MAX_INPUTS, max_dim_y=MAX_INPUTS, dtype=((numpy.float32,),), fget = lambda self: self.read_xst_N_imag_R(4))
+    xst_4_power_R           = attribute(max_dim_x=MAX_INPUTS, max_dim_y=MAX_INPUTS, dtype=((numpy.float32,),), fget = lambda self: self.read_xst_N_power_R(4))
+    xst_4_phase_R           = attribute(max_dim_x=MAX_INPUTS, max_dim_y=MAX_INPUTS, dtype=((numpy.float32,),), fget = lambda self: self.read_xst_N_phase_R(4))
+
+    xst_5_real_R            = attribute(max_dim_x=MAX_INPUTS, max_dim_y=MAX_INPUTS, dtype=((numpy.float32,),), fget = lambda self: self.read_xst_N_real_R(5))
+    xst_5_imag_R            = attribute(max_dim_x=MAX_INPUTS, max_dim_y=MAX_INPUTS, dtype=((numpy.float32,),), fget = lambda self: self.read_xst_N_imag_R(5))
+    xst_5_power_R           = attribute(max_dim_x=MAX_INPUTS, max_dim_y=MAX_INPUTS, dtype=((numpy.float32,),), fget = lambda self: self.read_xst_N_power_R(5))
+    xst_5_phase_R           = attribute(max_dim_x=MAX_INPUTS, max_dim_y=MAX_INPUTS, dtype=((numpy.float32,),), fget = lambda self: self.read_xst_N_phase_R(5))
+
+    xst_6_real_R            = attribute(max_dim_x=MAX_INPUTS, max_dim_y=MAX_INPUTS, dtype=((numpy.float32,),), fget = lambda self: self.read_xst_N_real_R(6))
+    xst_6_imag_R            = attribute(max_dim_x=MAX_INPUTS, max_dim_y=MAX_INPUTS, dtype=((numpy.float32,),), fget = lambda self: self.read_xst_N_imag_R(6))
+    xst_6_power_R           = attribute(max_dim_x=MAX_INPUTS, max_dim_y=MAX_INPUTS, dtype=((numpy.float32,),), fget = lambda self: self.read_xst_N_power_R(6))
+    xst_6_phase_R           = attribute(max_dim_x=MAX_INPUTS, max_dim_y=MAX_INPUTS, dtype=((numpy.float32,),), fget = lambda self: self.read_xst_N_phase_R(6))
+
+    xst_7_real_R            = attribute(max_dim_x=MAX_INPUTS, max_dim_y=MAX_INPUTS, dtype=((numpy.float32,),), fget = lambda self: self.read_xst_N_real_R(7))
+    xst_7_imag_R            = attribute(max_dim_x=MAX_INPUTS, max_dim_y=MAX_INPUTS, dtype=((numpy.float32,),), fget = lambda self: self.read_xst_N_imag_R(7))
+    xst_7_power_R           = attribute(max_dim_x=MAX_INPUTS, max_dim_y=MAX_INPUTS, dtype=((numpy.float32,),), fget = lambda self: self.read_xst_N_power_R(7))
+    xst_7_phase_R           = attribute(max_dim_x=MAX_INPUTS, max_dim_y=MAX_INPUTS, dtype=((numpy.float32,),), fget = lambda self: self.read_xst_N_phase_R(7))
 
     def read_xst_N_real_R(self, subband_idx):
         return numpy.real(self.statistics_client.collector.xst_values([subband_idx])[0])
@@ -236,7 +234,7 @@ class XST(Statistics):
     # ----------
     # Summarising Attributes
     # ----------
-    FPGA_processing_error_R      = attribute(dtype=(bool,), max_dim_x=16)
+    FPGA_processing_error_R      = attribute(dtype=(bool,), max_dim_x=N_pn)
 
     def read_FPGA_processing_error_R(self):
         return self.sdp_proxy.TR_fpga_mask_RW & (
diff --git a/tangostationcontrol/tangostationcontrol/devices/temperature_manager.py b/tangostationcontrol/tangostationcontrol/devices/temperature_manager.py
index 777343c80492bd03de0f84c21d5f1a1c29e09b90..8947e440364ac38d6da1fdd7ef5182018c91de9b 100644
--- a/tangostationcontrol/tangostationcontrol/devices/temperature_manager.py
+++ b/tangostationcontrol/tangostationcontrol/devices/temperature_manager.py
@@ -9,6 +9,7 @@
 
 # Additional import
 from tangostationcontrol.common.entrypoint import entry
+from tangostationcontrol.common.constants import DEFAULT_POLLING_PERIOD
 from tangostationcontrol.devices.lofar_device import lofar_device
 from tangostationcontrol.common.lofar_logging import device_logging_to_python, log_exceptions
 
@@ -121,7 +122,7 @@ class TemperatureManager(lofar_device):
             dev_attr.proxy.unsubscribe_event(dev_attr.subscription_id)
             del dev_attr
 
-    is_alarming_R = attribute(dtype=bool, polling_period=1000, fisallowed="is_attribute_access_allowed")
+    is_alarming_R = attribute(dtype=bool, polling_period=DEFAULT_POLLING_PERIOD, fisallowed="is_attribute_access_allowed")
 
     def read_is_alarming_R(self):
         # return whether any of the devices are alarming
diff --git a/tangostationcontrol/tangostationcontrol/devices/tilebeam.py b/tangostationcontrol/tangostationcontrol/devices/tilebeam.py
index 8c35b22d2655338b9e23d47cc670b497b0a4dddb..c5442354f3ba06b46d8c0bc62f87f1fccb4adb34 100644
--- a/tangostationcontrol/tangostationcontrol/devices/tilebeam.py
+++ b/tangostationcontrol/tangostationcontrol/devices/tilebeam.py
@@ -16,8 +16,8 @@ from tango import Util
 # Additional import
 from tangostationcontrol.common.entrypoint import entry
 from tangostationcontrol.common.lofar_logging import device_logging_to_python, log_exceptions
+from tangostationcontrol.common.constants import N_xyz, N_elements, N_pol
 from tangostationcontrol.beam.delays import Delays
-from tangostationcontrol.beam.hba_tile import NUMBER_OF_ELEMENTS_PER_TILE
 from tangostationcontrol.devices.beam_device import beam_device
 from tangostationcontrol.devices.device_decorators import TimeIt
 
@@ -58,7 +58,7 @@ class TileBeam(beam_device):
 
         # Retrieve positions from AntennaField device
         Antenna_Reference_itrf = self.antennafield_proxy.Antenna_Reference_itrf_R
-        HBAT_antenna_itrf_offsets = self.antennafield_proxy.HBAT_antenna_itrf_offsets_R.reshape(self._nr_tiles, NUMBER_OF_ELEMENTS_PER_TILE, 3)
+        HBAT_antenna_itrf_offsets = self.antennafield_proxy.HBAT_antenna_itrf_offsets_R.reshape(self._nr_tiles, N_elements, N_xyz)
 
         # a delay calculator for each tile
         self.HBAT_delay_calculators = [Delays(reference_itrf) for reference_itrf in Antenna_Reference_itrf]
@@ -77,7 +77,7 @@ class TileBeam(beam_device):
         Returns delays[tile][element]
         """
 
-        delays = numpy.zeros((self._nr_tiles, NUMBER_OF_ELEMENTS_PER_TILE), dtype=numpy.float64)
+        delays = numpy.zeros((self._nr_tiles, N_elements), dtype=numpy.float64)
 
         for tile in range(self._nr_tiles):
             # initialise delay calculator
@@ -107,7 +107,7 @@ class TileBeam(beam_device):
     @TimeIt()
     def _apply_weights(self, pointing_direction: numpy.array, timestamp: datetime.datetime, bf_delay_steps: numpy.array):
         # Write weights to RECV through the AntennaToRecvMapper
-        self.antennafield_proxy.HBAT_bf_delay_steps_RW = bf_delay_steps.reshape(self._nr_tiles, NUMBER_OF_ELEMENTS_PER_TILE * 2)
+        self.antennafield_proxy.HBAT_bf_delay_steps_RW = bf_delay_steps.reshape(self._nr_tiles, N_elements * N_pol)
 
         # Record where we now point to, now that we've updated the weights.
         # Only the entries within the mask have been updated
diff --git a/tangostationcontrol/tangostationcontrol/devices/unb2.py b/tangostationcontrol/tangostationcontrol/devices/unb2.py
index b64b86b0e344d0b6642fb6364ff31ae983fbece9..28716a92e666d48bb0780340e1f243f21e5b765e 100644
--- a/tangostationcontrol/tangostationcontrol/devices/unb2.py
+++ b/tangostationcontrol/tangostationcontrol/devices/unb2.py
@@ -17,6 +17,7 @@ from tango import AttrWriteType, DebugIt
 # Additional import
 
 from tangostationcontrol.common.entrypoint import entry
+from tangostationcontrol.common.constants import N_unb, N_fpga, N_ddr, N_qsfp, DEFAULT_POLLING_PERIOD
 from tangostationcontrol.clients.attribute_wrapper import attribute_wrapper
 from tangostationcontrol.devices.opcua_device import opcua_device
 from tangostationcontrol.common.lofar_logging import device_logging_to_python
@@ -29,6 +30,7 @@ __all__ = ["UNB2", "main"]
 
 @device_logging_to_python()
 class UNB2(opcua_device):
+
     # -----------------
     # Device Properties
     # -----------------
@@ -36,7 +38,7 @@ class UNB2(opcua_device):
     UNB2_mask_RW_default = device_property(
         dtype='DevVarBooleanArray',
         mandatory=False,
-        default_value=[True] * 2
+        default_value=[True] * N_unb
     )
 
     UNB2TR_monitor_rate_RW_default = device_property(
@@ -58,75 +60,70 @@ class UNB2(opcua_device):
     # Attributes
     # ----------
 
-    N_UNB = 2
-    N_FPGA = 4
-    N_DDR = 2
-    N_QSFP = 6
-
     TRANSLATOR_DEFAULT_SETTINGS = [
         'UNB2_mask_RW',
         'UNB2TR_monitor_rate_RW'
     ]
 
-    UNB2TR_I2C_bus_DDR4_error_R  = attribute_wrapper(comms_annotation=["UNB2TR_I2C_bus_DDR4_error_R"],datatype=numpy.int64  , dims=(2,4))
-    UNB2TR_I2C_bus_error_R       = attribute_wrapper(comms_annotation=["UNB2TR_I2C_bus_error_R"    ],datatype=numpy.int64  , dims=(2,))
-    UNB2TR_I2C_bus_FPGA_PS_error_R = attribute_wrapper(comms_annotation=["UNB2TR_I2C_bus_FPGA_PS_error_R"],datatype=numpy.int64  , dims=(2,4))
-    UNB2TR_I2C_bus_PS_error_R    = attribute_wrapper(comms_annotation=["UNB2TR_I2C_bus_PS_error_R" ],datatype=numpy.int64  , dims=(2,))
-    UNB2TR_I2C_bus_QSFP_error_R  = attribute_wrapper(comms_annotation=["UNB2TR_I2C_bus_QSFP_error_R"],datatype=numpy.int64  , dims=(2,24))
+    UNB2TR_I2C_bus_DDR4_error_R  = attribute_wrapper(comms_annotation=["UNB2TR_I2C_bus_DDR4_error_R"], datatype=numpy.int64, dims=(N_unb, N_fpga))
+    UNB2TR_I2C_bus_error_R       = attribute_wrapper(comms_annotation=["UNB2TR_I2C_bus_error_R"    ], datatype=numpy.int64, dims=(N_unb,))
+    UNB2TR_I2C_bus_FPGA_PS_error_R = attribute_wrapper(comms_annotation=["UNB2TR_I2C_bus_FPGA_PS_error_R"], datatype=numpy.int64, dims=(N_unb, N_fpga))
+    UNB2TR_I2C_bus_PS_error_R    = attribute_wrapper(comms_annotation=["UNB2TR_I2C_bus_PS_error_R" ], datatype=numpy.int64, dims=(N_unb,))
+    UNB2TR_I2C_bus_QSFP_error_R  = attribute_wrapper(comms_annotation=["UNB2TR_I2C_bus_QSFP_error_R"], datatype=numpy.int64, dims=(N_unb, N_qsfp))
     UNB2TR_monitor_rate_RW       = attribute_wrapper(comms_annotation=["UNB2TR_monitor_rate_RW"    ],datatype=numpy.int64  , access=AttrWriteType.READ_WRITE)
     UNB2TR_translator_busy_R     = attribute_wrapper(comms_annotation=["UNB2TR_translator_busy_R"  ],datatype=bool)
-    UNB2_DC_DC_48V_12V_IOUT_R    = attribute_wrapper(comms_annotation=["UNB2_DC_DC_48V_12V_IOUT_R" ],datatype=numpy.float64, dims=(2,))
-    UNB2_DC_DC_48V_12V_TEMP_R    = attribute_wrapper(comms_annotation=["UNB2_DC_DC_48V_12V_TEMP_R" ],datatype=numpy.float64, dims=(2,))
-    UNB2_DC_DC_48V_12V_VIN_R     = attribute_wrapper(comms_annotation=["UNB2_DC_DC_48V_12V_VIN_R"  ],datatype=numpy.float64, dims=(2,))
-    UNB2_DC_DC_48V_12V_VOUT_R    = attribute_wrapper(comms_annotation=["UNB2_DC_DC_48V_12V_VOUT_R" ],datatype=numpy.float64, dims=(2,))
-    UNB2_FPGA_DDR4_SLOT_TEMP_R   = attribute_wrapper(comms_annotation=["UNB2_FPGA_DDR4_SLOT_TEMP_R"],datatype=numpy.float64, dims=(2,8))
-    UNB2_FPGA_POL_CORE_IOUT_R    = attribute_wrapper(comms_annotation=["UNB2_FPGA_POL_CORE_IOUT_R" ],datatype=numpy.float64, dims=(2,4))
-    UNB2_FPGA_POL_CORE_TEMP_R    = attribute_wrapper(comms_annotation=["UNB2_FPGA_POL_CORE_TEMP_R" ],datatype=numpy.float64, dims=(2,4))
-    UNB2_FPGA_POL_CORE_VOUT_R    = attribute_wrapper(comms_annotation=["UNB2_FPGA_POL_CORE_VOUT_R" ],datatype=numpy.float64, dims=(2,4))
-    UNB2_FPGA_POL_ERAM_IOUT_R    = attribute_wrapper(comms_annotation=["UNB2_FPGA_POL_ERAM_IOUT_R" ],datatype=numpy.float64, dims=(2,4))
-    UNB2_FPGA_POL_ERAM_TEMP_R    = attribute_wrapper(comms_annotation=["UNB2_FPGA_POL_ERAM_TEMP_R" ],datatype=numpy.float64, dims=(2,4))
-    UNB2_FPGA_POL_ERAM_VOUT_R    = attribute_wrapper(comms_annotation=["UNB2_FPGA_POL_ERAM_VOUT_R" ],datatype=numpy.float64, dims=(2,4))
-    UNB2_FPGA_POL_HGXB_IOUT_R    = attribute_wrapper(comms_annotation=["UNB2_FPGA_POL_HGXB_IOUT_R" ],datatype=numpy.float64, dims=(2,4))
-    UNB2_FPGA_POL_HGXB_TEMP_R    = attribute_wrapper(comms_annotation=["UNB2_FPGA_POL_HGXB_TEMP_R" ],datatype=numpy.float64, dims=(2,4))
-    UNB2_FPGA_POL_HGXB_VOUT_R    = attribute_wrapper(comms_annotation=["UNB2_FPGA_POL_HGXB_VOUT_R" ],datatype=numpy.float64, dims=(2,4))
-    UNB2_FPGA_POL_PGM_IOUT_R     = attribute_wrapper(comms_annotation=["UNB2_FPGA_POL_PGM_IOUT_R"  ],datatype=numpy.float64, dims=(2,4))
-    UNB2_FPGA_POL_PGM_TEMP_R     = attribute_wrapper(comms_annotation=["UNB2_FPGA_POL_PGM_TEMP_R"  ],datatype=numpy.float64, dims=(2,4))
-    UNB2_FPGA_POL_PGM_VOUT_R     = attribute_wrapper(comms_annotation=["UNB2_FPGA_POL_PGM_VOUT_R"  ],datatype=numpy.float64, dims=(2,4))
-    UNB2_FPGA_POL_RXGXB_IOUT_R   = attribute_wrapper(comms_annotation=["UNB2_FPGA_POL_RXGXB_IOUT_R"],datatype=numpy.float64, dims=(2,4))
-    UNB2_FPGA_POL_RXGXB_TEMP_R   = attribute_wrapper(comms_annotation=["UNB2_FPGA_POL_RXGXB_TEMP_R"],datatype=numpy.float64, dims=(2,4))
-    UNB2_FPGA_POL_RXGXB_VOUT_R   = attribute_wrapper(comms_annotation=["UNB2_FPGA_POL_RXGXB_VOUT_R"],datatype=numpy.float64, dims=(2,4))
-    UNB2_FPGA_POL_TXGXB_IOUT_R   = attribute_wrapper(comms_annotation=["UNB2_FPGA_POL_TXGXB_IOUT_R"],datatype=numpy.float64, dims=(2,4))
-    UNB2_FPGA_POL_TXGXB_TEMP_R   = attribute_wrapper(comms_annotation=["UNB2_FPGA_POL_TXGXB_TEMP_R"],datatype=numpy.float64, dims=(2,4))
-    UNB2_FPGA_POL_TXGXB_VOUT_R   = attribute_wrapper(comms_annotation=["UNB2_FPGA_POL_TXGXB_VOUT_R"],datatype=numpy.float64, dims=(2,4))
-    UNB2_FPGA_QSFP_CAGE_LOS_R    = attribute_wrapper(comms_annotation=["UNB2_FPGA_QSFP_CAGE_LOS_R" ],datatype=numpy.int64  , dims=(2,24))
-    UNB2_FPGA_QSFP_CAGE_TEMP_R   = attribute_wrapper(comms_annotation=["UNB2_FPGA_QSFP_CAGE_TEMP_R"],datatype=numpy.float64, dims=(2,24))
-    UNB2_Front_Panel_LED_colour_R = attribute_wrapper(comms_annotation=["UNB2_Front_Panel_LED_colour_R"],datatype=numpy.int64  , dims=(2,))
-    UNB2_Front_Panel_LED_colour_RW = attribute_wrapper(comms_annotation=["UNB2_Front_Panel_LED_colour_RW"],datatype=numpy.int64  , dims=(2,), access=AttrWriteType.READ_WRITE)
-    UNB2_mask_RW                 = attribute_wrapper(comms_annotation=["UNB2_mask_RW"              ],datatype=bool, dims=(2,), access=AttrWriteType.READ_WRITE)
-    UNB2_PCB_ID_R                = attribute_wrapper(comms_annotation=["UNB2_PCB_ID_R"             ],datatype=numpy.int64  , dims=(2,))
-    UNB2_PCB_number_R            = attribute_wrapper(comms_annotation=["UNB2_PCB_number_R"         ],datatype=str          , dims=(2,))
-    UNB2_PCB_version_R           = attribute_wrapper(comms_annotation=["UNB2_PCB_version_R"        ],datatype=str          , dims=(2,))
-    UNB2_POL_CLOCK_IOUT_R        = attribute_wrapper(comms_annotation=["UNB2_POL_CLOCK_IOUT_R"     ],datatype=numpy.float64, dims=(2,))
-    UNB2_POL_CLOCK_TEMP_R        = attribute_wrapper(comms_annotation=["UNB2_POL_CLOCK_TEMP_R"     ],datatype=numpy.float64, dims=(2,))
-    UNB2_POL_CLOCK_VOUT_R        = attribute_wrapper(comms_annotation=["UNB2_POL_CLOCK_VOUT_R"     ],datatype=numpy.float64, dims=(2,))
-    UNB2_POL_QSFP_N01_IOUT_R     = attribute_wrapper(comms_annotation=["UNB2_POL_QSFP_N01_IOUT_R"  ],datatype=numpy.float64, dims=(2,))
-    UNB2_POL_QSFP_N01_TEMP_R     = attribute_wrapper(comms_annotation=["UNB2_POL_QSFP_N01_TEMP_R"  ],datatype=numpy.float64, dims=(2,))
-    UNB2_POL_QSFP_N01_VOUT_R     = attribute_wrapper(comms_annotation=["UNB2_POL_QSFP_N01_VOUT_R"  ],datatype=numpy.float64, dims=(2,))
-    UNB2_POL_QSFP_N23_IOUT_R     = attribute_wrapper(comms_annotation=["UNB2_POL_QSFP_N23_IOUT_R"  ],datatype=numpy.float64, dims=(2,))
-    UNB2_POL_QSFP_N23_TEMP_R     = attribute_wrapper(comms_annotation=["UNB2_POL_QSFP_N23_TEMP_R"  ],datatype=numpy.float64, dims=(2,))
-    UNB2_POL_QSFP_N23_VOUT_R     = attribute_wrapper(comms_annotation=["UNB2_POL_QSFP_N23_VOUT_R"  ],datatype=numpy.float64, dims=(2,))
-    UNB2_POL_SWITCH_1V2_IOUT_R   = attribute_wrapper(comms_annotation=["UNB2_POL_SWITCH_1V2_IOUT_R"],datatype=numpy.float64, dims=(2,))
-    UNB2_POL_SWITCH_1V2_TEMP_R   = attribute_wrapper(comms_annotation=["UNB2_POL_SWITCH_1V2_TEMP_R"],datatype=numpy.float64, dims=(2,))
-    UNB2_POL_SWITCH_1V2_VOUT_R   = attribute_wrapper(comms_annotation=["UNB2_POL_SWITCH_1V2_VOUT_R"],datatype=numpy.float64, dims=(2,))
-    UNB2_POL_SWITCH_PHY_IOUT_R   = attribute_wrapper(comms_annotation=["UNB2_POL_SWITCH_PHY_IOUT_R"],datatype=numpy.float64, dims=(2,))
-    UNB2_POL_SWITCH_PHY_TEMP_R   = attribute_wrapper(comms_annotation=["UNB2_POL_SWITCH_PHY_TEMP_R"],datatype=numpy.float64, dims=(2,))
-    UNB2_POL_SWITCH_PHY_VOUT_R   = attribute_wrapper(comms_annotation=["UNB2_POL_SWITCH_PHY_VOUT_R"],datatype=numpy.float64, dims=(2,))
-    UNB2_PWR_on_R                = attribute_wrapper(comms_annotation=["UNB2_PWR_on_R"             ],datatype=bool, dims=(2,))
+    UNB2_DC_DC_48V_12V_IOUT_R    = attribute_wrapper(comms_annotation=["UNB2_DC_DC_48V_12V_IOUT_R" ], datatype=numpy.float64, dims=(N_unb,))
+    UNB2_DC_DC_48V_12V_TEMP_R    = attribute_wrapper(comms_annotation=["UNB2_DC_DC_48V_12V_TEMP_R" ], datatype=numpy.float64, dims=(N_unb,))
+    UNB2_DC_DC_48V_12V_VIN_R     = attribute_wrapper(comms_annotation=["UNB2_DC_DC_48V_12V_VIN_R"  ], datatype=numpy.float64, dims=(N_unb,))
+    UNB2_DC_DC_48V_12V_VOUT_R    = attribute_wrapper(comms_annotation=["UNB2_DC_DC_48V_12V_VOUT_R" ], datatype=numpy.float64, dims=(N_unb,))
+    UNB2_FPGA_DDR4_SLOT_TEMP_R   = attribute_wrapper(comms_annotation=["UNB2_FPGA_DDR4_SLOT_TEMP_R"], datatype=numpy.float64, dims=(N_unb, N_fpga * N_ddr))
+    UNB2_FPGA_POL_CORE_IOUT_R    = attribute_wrapper(comms_annotation=["UNB2_FPGA_POL_CORE_IOUT_R" ], datatype=numpy.float64, dims=(N_unb, N_fpga))
+    UNB2_FPGA_POL_CORE_TEMP_R    = attribute_wrapper(comms_annotation=["UNB2_FPGA_POL_CORE_TEMP_R" ], datatype=numpy.float64, dims=(N_unb, N_fpga))
+    UNB2_FPGA_POL_CORE_VOUT_R    = attribute_wrapper(comms_annotation=["UNB2_FPGA_POL_CORE_VOUT_R" ], datatype=numpy.float64, dims=(N_unb, N_fpga))
+    UNB2_FPGA_POL_ERAM_IOUT_R    = attribute_wrapper(comms_annotation=["UNB2_FPGA_POL_ERAM_IOUT_R" ], datatype=numpy.float64, dims=(N_unb, N_fpga))
+    UNB2_FPGA_POL_ERAM_TEMP_R    = attribute_wrapper(comms_annotation=["UNB2_FPGA_POL_ERAM_TEMP_R" ], datatype=numpy.float64, dims=(N_unb, N_fpga))
+    UNB2_FPGA_POL_ERAM_VOUT_R    = attribute_wrapper(comms_annotation=["UNB2_FPGA_POL_ERAM_VOUT_R" ], datatype=numpy.float64, dims=(N_unb, N_fpga))
+    UNB2_FPGA_POL_HGXB_IOUT_R    = attribute_wrapper(comms_annotation=["UNB2_FPGA_POL_HGXB_IOUT_R" ], datatype=numpy.float64, dims=(N_unb, N_fpga))
+    UNB2_FPGA_POL_HGXB_TEMP_R    = attribute_wrapper(comms_annotation=["UNB2_FPGA_POL_HGXB_TEMP_R" ], datatype=numpy.float64, dims=(N_unb, N_fpga))
+    UNB2_FPGA_POL_HGXB_VOUT_R    = attribute_wrapper(comms_annotation=["UNB2_FPGA_POL_HGXB_VOUT_R" ], datatype=numpy.float64, dims=(N_unb, N_fpga))
+    UNB2_FPGA_POL_PGM_IOUT_R     = attribute_wrapper(comms_annotation=["UNB2_FPGA_POL_PGM_IOUT_R"  ], datatype=numpy.float64, dims=(N_unb, N_fpga))
+    UNB2_FPGA_POL_PGM_TEMP_R     = attribute_wrapper(comms_annotation=["UNB2_FPGA_POL_PGM_TEMP_R"  ], datatype=numpy.float64, dims=(N_unb, N_fpga))
+    UNB2_FPGA_POL_PGM_VOUT_R     = attribute_wrapper(comms_annotation=["UNB2_FPGA_POL_PGM_VOUT_R"  ], datatype=numpy.float64, dims=(N_unb, N_fpga))
+    UNB2_FPGA_POL_RXGXB_IOUT_R   = attribute_wrapper(comms_annotation=["UNB2_FPGA_POL_RXGXB_IOUT_R"], datatype=numpy.float64, dims=(N_unb, N_fpga))
+    UNB2_FPGA_POL_RXGXB_TEMP_R   = attribute_wrapper(comms_annotation=["UNB2_FPGA_POL_RXGXB_TEMP_R"], datatype=numpy.float64, dims=(N_unb, N_fpga))
+    UNB2_FPGA_POL_RXGXB_VOUT_R   = attribute_wrapper(comms_annotation=["UNB2_FPGA_POL_RXGXB_VOUT_R"], datatype=numpy.float64, dims=(N_unb, N_fpga))
+    UNB2_FPGA_POL_TXGXB_IOUT_R   = attribute_wrapper(comms_annotation=["UNB2_FPGA_POL_TXGXB_IOUT_R"], datatype=numpy.float64, dims=(N_unb, N_fpga))
+    UNB2_FPGA_POL_TXGXB_TEMP_R   = attribute_wrapper(comms_annotation=["UNB2_FPGA_POL_TXGXB_TEMP_R"], datatype=numpy.float64, dims=(N_unb, N_fpga))
+    UNB2_FPGA_POL_TXGXB_VOUT_R   = attribute_wrapper(comms_annotation=["UNB2_FPGA_POL_TXGXB_VOUT_R"], datatype=numpy.float64, dims=(N_unb, N_fpga))
+    UNB2_FPGA_QSFP_CAGE_LOS_R    = attribute_wrapper(comms_annotation=["UNB2_FPGA_QSFP_CAGE_LOS_R" ], datatype=numpy.int64, dims=(N_unb, N_qsfp))
+    UNB2_FPGA_QSFP_CAGE_TEMP_R   = attribute_wrapper(comms_annotation=["UNB2_FPGA_QSFP_CAGE_TEMP_R"], datatype=numpy.float64, dims=(N_unb, N_qsfp))
+    UNB2_Front_Panel_LED_colour_R = attribute_wrapper(comms_annotation=["UNB2_Front_Panel_LED_colour_R"], datatype=numpy.int64, dims=(N_unb,))
+    UNB2_Front_Panel_LED_colour_RW = attribute_wrapper(comms_annotation=["UNB2_Front_Panel_LED_colour_RW"], datatype=numpy.int64, dims=(N_unb,), access=AttrWriteType.READ_WRITE)
+    UNB2_mask_RW                 = attribute_wrapper(comms_annotation=["UNB2_mask_RW"              ], datatype=bool, dims=(N_unb,), access=AttrWriteType.READ_WRITE)
+    UNB2_PCB_ID_R                = attribute_wrapper(comms_annotation=["UNB2_PCB_ID_R"             ], datatype=numpy.int64, dims=(N_unb,))
+    UNB2_PCB_number_R            = attribute_wrapper(comms_annotation=["UNB2_PCB_number_R"         ], datatype=str, dims=(N_unb,))
+    UNB2_PCB_version_R           = attribute_wrapper(comms_annotation=["UNB2_PCB_version_R"        ], datatype=str, dims=(N_unb,))
+    UNB2_POL_CLOCK_IOUT_R        = attribute_wrapper(comms_annotation=["UNB2_POL_CLOCK_IOUT_R"     ], datatype=numpy.float64, dims=(N_unb,))
+    UNB2_POL_CLOCK_TEMP_R        = attribute_wrapper(comms_annotation=["UNB2_POL_CLOCK_TEMP_R"     ], datatype=numpy.float64, dims=(N_unb,))
+    UNB2_POL_CLOCK_VOUT_R        = attribute_wrapper(comms_annotation=["UNB2_POL_CLOCK_VOUT_R"     ], datatype=numpy.float64, dims=(N_unb,))
+    UNB2_POL_QSFP_N01_IOUT_R     = attribute_wrapper(comms_annotation=["UNB2_POL_QSFP_N01_IOUT_R"  ], datatype=numpy.float64, dims=(N_unb,))
+    UNB2_POL_QSFP_N01_TEMP_R     = attribute_wrapper(comms_annotation=["UNB2_POL_QSFP_N01_TEMP_R"  ], datatype=numpy.float64, dims=(N_unb,))
+    UNB2_POL_QSFP_N01_VOUT_R     = attribute_wrapper(comms_annotation=["UNB2_POL_QSFP_N01_VOUT_R"  ], datatype=numpy.float64, dims=(N_unb,))
+    UNB2_POL_QSFP_N23_IOUT_R     = attribute_wrapper(comms_annotation=["UNB2_POL_QSFP_N23_IOUT_R"  ], datatype=numpy.float64, dims=(N_unb,))
+    UNB2_POL_QSFP_N23_TEMP_R     = attribute_wrapper(comms_annotation=["UNB2_POL_QSFP_N23_TEMP_R"  ], datatype=numpy.float64, dims=(N_unb,))
+    UNB2_POL_QSFP_N23_VOUT_R     = attribute_wrapper(comms_annotation=["UNB2_POL_QSFP_N23_VOUT_R"  ], datatype=numpy.float64, dims=(N_unb,))
+    UNB2_POL_SWITCH_1V2_IOUT_R   = attribute_wrapper(comms_annotation=["UNB2_POL_SWITCH_1V2_IOUT_R"], datatype=numpy.float64, dims=(N_unb,))
+    UNB2_POL_SWITCH_1V2_TEMP_R   = attribute_wrapper(comms_annotation=["UNB2_POL_SWITCH_1V2_TEMP_R"], datatype=numpy.float64, dims=(N_unb,))
+    UNB2_POL_SWITCH_1V2_VOUT_R   = attribute_wrapper(comms_annotation=["UNB2_POL_SWITCH_1V2_VOUT_R"], datatype=numpy.float64, dims=(N_unb,))
+    UNB2_POL_SWITCH_PHY_IOUT_R   = attribute_wrapper(comms_annotation=["UNB2_POL_SWITCH_PHY_IOUT_R"], datatype=numpy.float64, dims=(N_unb,))
+    UNB2_POL_SWITCH_PHY_TEMP_R   = attribute_wrapper(comms_annotation=["UNB2_POL_SWITCH_PHY_TEMP_R"], datatype=numpy.float64, dims=(N_unb,))
+    UNB2_POL_SWITCH_PHY_VOUT_R   = attribute_wrapper(comms_annotation=["UNB2_POL_SWITCH_PHY_VOUT_R"], datatype=numpy.float64, dims=(N_unb,))
+    UNB2_PWR_on_R                = attribute_wrapper(comms_annotation=["UNB2_PWR_on_R"             ], datatype=bool, dims=(N_unb,))
 
     # ----------
     # Summarising Attributes
     # ----------
-    UNB2_error_R                  = attribute(dtype=(bool,), max_dim_x=2, fisallowed="is_attribute_access_allowed")
+    UNB2_error_R                  = attribute(dtype=(bool,), max_dim_x=N_unb, fisallowed="is_attribute_access_allowed")
 
     def read_UNB2_error_R(self):
         return self.read_attribute("UNB2_mask_RW") & (
@@ -137,9 +134,9 @@ class UNB2(opcua_device):
                | (self.read_attribute("UNB2TR_I2C_bus_QSFP_error_R") > 0).any(axis=1)
                )
 
-    UNB2_IOUT_error_R          = attribute(dtype=(bool,), max_dim_x=2, fisallowed="is_attribute_access_allowed")
-    UNB2_TEMP_error_R          = attribute(dtype=(bool,), max_dim_x=2, fisallowed="is_attribute_access_allowed", polling_period=1000)
-    UNB2_VOUT_error_R          = attribute(dtype=(bool,), max_dim_x=2, fisallowed="is_attribute_access_allowed")
+    UNB2_IOUT_error_R          = attribute(dtype=(bool,), max_dim_x=N_unb, fisallowed="is_attribute_access_allowed")
+    UNB2_TEMP_error_R          = attribute(dtype=(bool,), max_dim_x=N_unb, fisallowed="is_attribute_access_allowed", polling_period=DEFAULT_POLLING_PERIOD)
+    UNB2_VOUT_error_R          = attribute(dtype=(bool,), max_dim_x=N_unb, fisallowed="is_attribute_access_allowed")
 
     def read_UNB2_IOUT_error_R(self):
         return self.read_attribute("UNB2_mask_RW") & (
@@ -208,7 +205,7 @@ class UNB2(opcua_device):
         # Save actual mask values
         UNB2_mask = self.proxy.UNB2_mask_RW
         # Set the mask to all Trues
-        self.UNB2_mask_RW = [True] * 2
+        self.UNB2_mask_RW = [True] * N_unb
         # Turn off the uniboards
         self.UNB2_off()
         self.wait_attribute("UNB2TR_translator_busy_R", False, self.UNB2_On_Off_timeout)
diff --git a/tangostationcontrol/tangostationcontrol/test/clients/test_client.py b/tangostationcontrol/tangostationcontrol/test/clients/test_client.py
index 4f3a0c5d2eda256bc089ebd58c4dbc587beb08cd..8bf63cd8dfe4f77938d5cdca5c037cb0b69d3791 100644
--- a/tangostationcontrol/tangostationcontrol/test/clients/test_client.py
+++ b/tangostationcontrol/tangostationcontrol/test/clients/test_client.py
@@ -11,7 +11,7 @@ logger = logging.getLogger()
 class test_client(CommClient):
     """
     this class provides an example implementation of a comms_client.
-    Durirng initialisation it creates a correctly shaped zero filled value. on read that value is returned and on write its modified.
+    During initialisation it creates a correctly shaped zero filled value. on read that value is returned and on write its modified.
     """
 
     def start(self):