diff --git a/CAL/CalibrationCommon/lib/datacontainers/calibration_table.py b/CAL/CalibrationCommon/lib/datacontainers/calibration_table.py
index f55296d30da9fc60ebc43122b8bfd12e29320a0e..9d6569f7b767bf4ef7cd5455d82933c2baec042e 100644
--- a/CAL/CalibrationCommon/lib/datacontainers/calibration_table.py
+++ b/CAL/CalibrationCommon/lib/datacontainers/calibration_table.py
@@ -9,7 +9,9 @@ from typing import List
 
 from dataclasses import dataclass, asdict, field
 from h5py import File
-from numpy import empty as empty_ndarray, ndarray, fromiter as array_from_iter, float64, array_equal
+from numpy import empty as empty_ndarray, ndarray, fromiter as array_from_iter, float64,\
+    array_equal, arange, array
+from copy import deepcopy
 
 logger = logging.getLogger(__name__)
 
@@ -19,7 +21,9 @@ __FREQUENCIES = 512
 __FLOATS_PER_FREQUENCY = 2
 __N_ANTENNAS_DUTCH = 96
 __N_ANTENNAS_INTERNATIONAL = 192
-__CALIBRATION_TABLE_FILENAME_PATTERN = '*CalTable-???-???-???_???.dat'
+__CALIBRATION_TABLE_FILENAME_PATTERN = '**/*CalTable-???-???-???_???.dat'
+_MODE_TO_CLOCK = {1: 200, 3: 200, 5: 200, 6: 160, 7: 200}
+_MODE_TO_NYQ_ZONE = {1: 1, 3: 1, 5: 2, 6: 1, 7: 3}
 
 _ATTRIBUTE_NAME_TO_SERIALIZED_NAME = {
     'observation_station': 'CalTableHeader.Observation.Station',
@@ -41,6 +45,7 @@ class UnvalidFileException(Exception):
         self.message = message
 
 
+
 def _extract_header(fstream: BinaryIO):
     header = {}
     for i in range(__MAX_HEADER_LINES):
@@ -82,12 +87,10 @@ def parse_data(data_buffer):
     return complex_data
 
 
-@dataclass(init=True, repr=True, frozen=False, eq=True)
+@dataclass(init=True, repr=True, frozen=False)
 class CalibrationTable:
     observation_station: str
     observation_mode: int
-    observation_antennaset: str
-    observation_band: str
     observation_source: str
     observation_date: str
     calibration_version: int
@@ -97,6 +100,9 @@ class CalibrationTable:
     data: ndarray = field(compare=False)
     comment: str = ''
 
+    observation_antennaset: str = ''
+    observation_band: str = ''
+
     def __parse_attributes(self):
         self.observation_mode = int(self.observation_mode)
         self.calibration_version = int(self.calibration_version)
@@ -110,14 +116,41 @@ class CalibrationTable:
     def __post_init__(self):
         self.__parse_attributes()
 
+    def frequencies(self) -> ndarray:
+        subbands = arange(1, 513, 1.)
+        clock = _MODE_TO_CLOCK[self.observation_mode]
+        nyquist_zone = _MODE_TO_NYQ_ZONE[self.observation_mode]
+        frequencies = subbands * clock / 1024. + (nyquist_zone - 1) * clock / 2.
+        return frequencies
+
+    def derive_calibration_table_from_gain_fit(self,
+                                               observation_source: str,
+                                               observation_date: str,
+                                               calibration_name: str,
+                                               commment: str,
+                                               gains):
+        new_calibration_table = deepcopy(self)
+        new_calibration_table.observation_source = observation_source
+        new_calibration_table.observation_date = observation_date
+        new_calibration_table.calibration_name = calibration_name,
+        new_calibration_table.comment = commment
+
+        new_calibration_table.data = gains
+
     @staticmethod
     def load_from_file(file_path):
+        logger.info('loading file %s', file_path)
         with open(file_path, 'rb') as file_stream:
             header = _extract_header(file_stream)
-            data_raw = file_stream.read()
-
-        data = parse_data(data_raw)
-
+            data_raw = file_stream.read().rstrip(b'\n')
+        try:
+            data = parse_data(data_raw)
+        except Exception as e:
+
+            logger.error('error reading file %s', file_path)
+            logger.debug(data_raw)
+            logger.exception(e)
+            raise e
         calibration_table = CalibrationTable(**header,
                                              data=data)
         return calibration_table
@@ -158,6 +191,15 @@ class CalibrationTable:
             file_descriptor[uri].attrs[key] = value
         file_descriptor.flush()
 
+    @staticmethod
+    def load_from_hdf(file_descriptor: File, uri: str):
+        if uri not in file_descriptor:
+            raise ValueError('specified uri does not exist in %s' % file_descriptor.filename)
+
+        data = array(file_descriptor[uri])
+
+        return CalibrationTable(data=data, **dict(file_descriptor[uri].attrs.items()))
+
     def __eq__(self, other):
         return super().__eq__(other) and array_equal(self.data, other.data)
 
@@ -173,7 +215,7 @@ def read_calibration_tables_in_directory(directory_path: str):
     files = path.join(directory_path, __CALIBRATION_TABLE_FILENAME_PATTERN)
 
     return [CalibrationTable.load_from_file(file_path)
-            for file_path in glob(files, recursive=False)]
+            for file_path in glob(files, recursive=True)]
 
 
 def read_calibration_tables_per_station_mode(directory_path: str) -> Dict[Tuple[str, int],
diff --git a/CAL/CalibrationCommon/test/t_calibration_table.py b/CAL/CalibrationCommon/test/t_calibration_table.py
index 67e42b0075e75119a7810d75b3e3a8bbc2f47a5a..7c8be47319cb6976ebdc0bcb3e86fe31c99a6af7 100644
--- a/CAL/CalibrationCommon/test/t_calibration_table.py
+++ b/CAL/CalibrationCommon/test/t_calibration_table.py
@@ -6,7 +6,7 @@ from os import getcwd
 import logging
 from tempfile import NamedTemporaryFile
 from numpy.testing import assert_array_equal
-from numpy import array
+from numpy import array, linspace
 
 
 CALIBRATION_TABLE_FILENAME = 't_calibration_table.in_CalTable-401-HBA-110_190.dat'
@@ -49,6 +49,36 @@ class TestCalibrationTable(unittest.TestCase):
             )
             assert_array_equal(array(h5_file['/calibration_table']), test_calibration_table.data)
 
+    def test_loading_to_hdf(self):
+        with NamedTemporaryFile('w+b') as temp_file:
+            h5_file = H5File(temp_file.name, 'w')
+            test_calibration_table = CalibrationTable.load_from_file(CALIBRATION_TABLE_FILENAME)
+
+            test_calibration_table.store_to_hdf(h5_file, '/calibration_table')
+            h5_file.close()
+            h5_file = H5File(temp_file.name, 'r')
+            caltable = CalibrationTable.load_from_hdf(file_descriptor=h5_file,
+                                                      uri='/calibration_table')
+            self.assertEqual(caltable, test_calibration_table)
+
+    def test_loading_to_hdf_raise_value_error(self):
+        with NamedTemporaryFile('w+b') as temp_file:
+            h5_file = H5File(temp_file.name, 'w')
+            h5_file.close()
+            h5_file = H5File(temp_file.name, 'r')
+            with self.assertRaises(ValueError):
+                caltable = CalibrationTable.load_from_hdf(file_descriptor=h5_file,
+                                                      uri='/calibration_table')
+
+    def test_frequency_generation(self):
+        test_calibration_table = CalibrationTable.load_from_file(CALIBRATION_TABLE_FILENAME)
+        sb = linspace(1, 512, 512)
+        clock = 200
+        nyq = 2
+
+        expected_frequency_array = freq = clock / 1024 * sb + (nyq-1) * clock / 2.
+        assert_array_equal(expected_frequency_array, test_calibration_table.frequencies())
+
     def test_list_calibration_tables_in_path(self):
         calibration_tables = read_calibration_tables_in_directory(getcwd())
         self.assertEqual(len(calibration_tables), 1)