diff --git a/fishbook/reproclasses.py b/fishbook/reproclasses.py
index 5b0f934..883da38 100644
--- a/fishbook/reproclasses.py
+++ b/fishbook/reproclasses.py
@@ -47,7 +47,9 @@ def gaussian_kernel(sigma, dt):
 
 
 class BaselineData:
-
+    """
+    Class representing the Baseline data that has been recorded within a given Dataset.
+    """
     def __init__(self, dataset: Dataset):
         self.__spike_data = []
         self.__eod_data = []
@@ -284,20 +286,43 @@ class BaselineData:
         return np.asarray(data)
 
 
-class BoltzmannFit():
-    def __init__(self, xvalues: np.ndarray, yvalues: np.ndarray):
+class BoltzmannFit:
+    """
+    Class representing a fit of a Boltzmann function to some data.
+    """
+
+    def __init__(self, xvalues: np.ndarray, yvalues: np.ndarray, initial_params=None):
+        """
+        Constructor. Takes the x and the y data and tries to fit a Boltzmann to it.
+
+        :param xvalues: numpy array of x (e.g. contrast) values
+        :param yvalues: numpy array of y (e.g. firing rate) values
+        :param initial_params: list of initial parameters, default None to autogenerate
+        """
         assert(len(xvalues) == len(yvalues))
         self.__xvals = xvalues
         self.__yvals = yvalues
         self.__fit_params = None
+        self.__initial_params = initial_params
         self.__x_sorted = np.unique(self.__xvals)
         self.__y_avg = None
         self.__y_err = None
         self.__do_fit()
 
     @staticmethod
-    def boltzmann(x, f_max, slope, inflection):
-        y = f_max / (1 + np.exp(-slope * (x - inflection)))
+    def boltzmann(x, y_max, slope, inflection):
+        """
+        The underlying Boltzmann function.
+        .. math::
+            f(x) = y_max / \exp{-slope*(x-inflection}
+
+        :param x: The x values.
+        :param y_max: The maximum value.
+        :param slope: The slope parameter k
+        :param inflection: the position of the inflection point.
+        :return: the y values.
+        """
+        y = y_max / (1 + np.exp(-slope * (x - inflection)))
         return y
 
     def __do_fit(self):
@@ -306,14 +331,27 @@ class BoltzmannFit():
         for i, c in enumerate(self.__x_sorted):
             self.__y_avg[i] = np.mean(self.__yvals[self.__xvals == c])
             self.__y_err[i] = np.std(self.__yvals[self.__xvals == c])
-        self.__fit_params, _ = curve_fit(self.boltzmann, self.__x_sorted, self.__y_avg, [np.max(self.__y_avg), 0, 0])
+        if self.__initial_params:
+            p = self.__initial_params
+        else:
+            p = [np.max(self.__y_avg), 0, 0]
+        self.__fit_params, _ = curve_fit(self.boltzmann, self.__x_sorted, self.__y_avg, p)
 
     @property
-    def slope(self):
+    def slope(self) -> float:
+        """
+        The slope of the linear part of the Boltzmann, i.e.
+        .. math::
+            s = f_max \cdot k / 4
+        :return: the slope.
+        """
         return self.__fit_params[0] * self.__fit_params[1] / 4
 
     @property
     def parameters(self):
+        """ fit parameters
+        :return: The fit parameters.
+        """
         return self.__fit_params
 
     @property
@@ -331,7 +369,18 @@ class BoltzmannFit():
 
 
 class FIData:
+    """
+    Class representing the data recorded with the relacs FI-Curve repro. The instance will load the data upon
+    construction which may take a while.
+    FI Data offers convenient access to the spike and local EOD data as well as offers conveince methods to get the
+    firing rate and also to fit a Boltzmann function to the the FI curve.
+    """
     def __init__(self, dataset: Dataset):
+        """
+        Constructor.
+
+        :param dataset: The dataset entity for which the fi curve repro data should be loaded.
+        """
         self.__spike_data = []
         self.__contrasts = []
         self.__eod_data = []
@@ -414,7 +463,7 @@ class FIData:
         b = f.blocks[0]
 
         mt = None
-        for i in tqdm(range(len(stimuli))):
+        for i in tqdm(range(len(stimuli)), desc="Loading data"):
             s = stimuli[i]
             if not mt or mt.id != s.multi_tag_id:
                 mt = b.multi_tags[s.multi_tag_id]
@@ -427,29 +476,62 @@ class FIData:
         f.close()
         return spikes, contrasts, eods, time
 
+    def __read_spikes_from_directory(self, repro = RePro):
+
+        pass
+
     @property
-    def size(self):
+    def size(self) -> int:
+        """
+        The number of recorded trials
+
+        :return: An integer with the number of trials.
+        """
         return len(self.__spike_data)
 
     def spikes(self, index=-1):
+        """
+        The spike times recorded in the specified trial(s)
+
+        :param index: the index of the trial. Default of -1 indicates that all data should be returned.
+        :return:
+        """
         if 0 <= index < self.size:
             return self.__spike_data[index]
         else:
             return self.__spike_data
 
     def eod(self, index=-1):
+        """
+        The local eod (including the stimulus) measurement of the selected trial(s).
+
+        :param index: the index of the trial. Default of -1 indicates that all data should be returned.
+        :return: Either two vectors representing time and the local eod or two lists of such vectors
+        """
         if 0 <= index < self.size:
             return self.__eod_times[index], self.__eod_data[index]
         else:
             return self.__eod_times, self.__eod_data
 
     def contrast(self, index=-1):
+        """
+        The stimulus contrast used in the respective trial(s).
+        \
+        :param index:  the index of the trial. Default of -1 indicates that all data should be returned.
+        :return: Either a single scalar representing the contrast, or a list of such scalars, one entry for each trial.
+        """
         if 0 <= index < self.size:
             return self.__contrasts[index]
         else:
             return self.__contrasts
 
     def time_axis(self, index=-1):
+        """
+        Get the time axis of a single trial or a list of time-vectors for all trials.
+
+        :param index: the index of the trial. Default of -1 indicates that all data should be returned.
+        :return: Either a single vector representing time, or a list of such vectors, one for each trial.
+        """
         if 0 <= index < self.size:
             return self.__eod_times[index]
         else:
@@ -475,10 +557,13 @@ class FIData:
 
     def boltzmann_fit(self, start_time=0.01, end_time=0.05, kernel_width=0.005):
         """
+        Extracts the average firing rate within a time window from the averaged across trial firing rate.
+        The analysis time window is specified by the start_time and end_time parameters. Firing rate is estimated by
+        convolution with a Gaussian kernel of a given width. All parameters are given in 's'.
 
-        :param start_time:
-        :param end_time:
-        :param kernel_width:
+        :param start_time: the start of the analysis window.
+        :param end_time: the end of the analysis window.
+        :param kernel_width: standard deviation of the Gaussian kernel used for firing rate estimation.
         :return: object of type BoltzmannFit
         """
         contrasts = np.zeros(self.size)