diff --git a/dartwrf/obs/create_obsseq_out.py b/dartwrf/obs/create_obsseq_out.py
index 69e95e66fdbe6b02340e9b3f597e4559b1fdde3c..d01e1e869720778a37ac9f3b6ae250682b4bc2c8 100644
--- a/dartwrf/obs/create_obsseq_out.py
+++ b/dartwrf/obs/create_obsseq_out.py
@@ -63,14 +63,16 @@ def generate_obsseq_out(time):
     print('saved', f_oso)
     return oso
 
-def run_perfect_model_obs(nproc=12, verbose=True):
-    """Run the perfect_model_obs program to generate observations
+def run_perfect_model_obs(nproc=12):
+    """Run the ./perfect_model_obs program
+
+    Args:
+        nproc (int): number of processors to use
     
     Returns:
-        None
+        None, creates obs_seq.out
     """
-    if verbose:
-        print("generating observations - running ./perfect_model_obs")
+    print("running ./perfect_model_obs")
     os.chdir(cluster.dart_rundir)
 
     try_remove(cluster.dart_rundir + "/obs_seq.out")
diff --git a/dartwrf/obs/error_models.py b/dartwrf/obs/error_models.py
index 08c3236fbf24c8bb85fdd76d379adff6f964d51d..9ec0eae7ee641a267205feba6cb070aa9b369f91 100644
--- a/dartwrf/obs/error_models.py
+++ b/dartwrf/obs/error_models.py
@@ -3,15 +3,17 @@ from scipy.interpolate import interp1d
 
 def calc_obserr_WV(channel, Hx_nature, Hx_prior):
     """Calculate parametrized error (for assimilation)
+
     Args:
-        channel (str):              satellite channel
-        Hx_nature (np.array):       dim (observations)
-        Hx_prior (np.array):        dim (ensemble_members, observations)
+        channel (str):          satellite channel
+        Hx_nature (np.array):   H(x_nature) with dimension (observations)
+        Hx_prior (np.array):    H(x_prior) with dimension (ensemble_members, observations)
 
     Returns
-        np.array        Observation error std-deviation with dim (observations)
+        np.array        Observation error std-deviation with dimension (observations)
     """
-    assert channel in ['WV62', 'WV73']
+    if channel not in ['WV62', 'WV73']:
+        raise NotImplementedError("channel not implemented: " + channel)
     debug = False
 
     n_obs = len(Hx_nature)
@@ -21,13 +23,13 @@ def calc_obserr_WV(channel, Hx_nature, Hx_prior):
         bt_x_ens = Hx_prior[:, iobs]
         
         # compute Cloud impact for every pair (ensemble, truth)
-        CIs = [cloudimpact(channel, bt_x, bt_y) for bt_x in bt_x_ens]
+        CIs = [_cloudimpact(channel, bt_x, bt_y) for bt_x in bt_x_ens]
         mean_CI = np.mean(CIs)
 
         if channel == 'WV62':
-            oe_model = OE_model_harnisch_WV62(mean_CI)
+            oe_model = _OE_model_harnisch_WV62(mean_CI)
         elif channel == 'WV73':
-            oe_model = OE_model_harnisch_WV73(mean_CI)
+            oe_model = _OE_model_harnisch_WV73(mean_CI)
         
         if debug:
             print("BT_nature=", bt_y, "=> mean_CI=", mean_CI, "=> OE_assim=", oe_model)
@@ -36,7 +38,7 @@ def calc_obserr_WV(channel, Hx_nature, Hx_prior):
     return OEs
 
 
-def cloudimpact(channel, bt_mod, bt_obs):
+def _cloudimpact(channel, bt_mod, bt_obs):
     """
     follows Harnisch 2016, Figure 3
     """
@@ -53,7 +55,7 @@ def cloudimpact(channel, bt_mod, bt_obs):
     return ci
 
 
-def OE_model_harnisch_WV62(ci):
+def _OE_model_harnisch_WV62(ci):
     if ci >= 0 and ci < 7.5:
         # Kelvin, fit of Fig 7a, Harnisch 2016
         x_ci = [0, 2.5, 4.5, 5.5, 7.5]  # average cloud impact [K]
@@ -64,7 +66,7 @@ def OE_model_harnisch_WV62(ci):
         return 6.5
 
 
-def OE_model_harnisch_WV73(ci):
+def _OE_model_harnisch_WV73(ci):
     if ci >= 0 and ci < 16:
         # Kelvin, fit of Fig 7b, Harnisch 2016
         x_ci = [0, 5, 10.5, 13, 16]  # average cloud impact [K]
diff --git a/dartwrf/obs/obsseq.py b/dartwrf/obs/obsseq.py
index e108e70491dcf26489db1958fb24fbf4e865368c..19ee4d5e2620aa749c6102e033ddb2c25ff67519 100755
--- a/dartwrf/obs/obsseq.py
+++ b/dartwrf/obs/obsseq.py
@@ -57,9 +57,7 @@ def rad_to_degrees(rad):
 
 
 class ObsRecord(pd.DataFrame):
-    """Content of obsseq.ObsSeq instances
-    provides additional methods for pd.DataFrame
-    created inside an ObsSeq instance
+    """Basically a pd.DataFrame with additional methods
     """
     @property
     def _constructor(self):
@@ -68,18 +66,31 @@ class ObsRecord(pd.DataFrame):
         return ObsRecord
 
     def get_prior_Hx(self):
-        """Return prior Hx array (n_obs, n_ens)"""
+        """Retrieve H(x_prior) for all ensemble members
+        
+        Returns:
+            np.array (n_obs, n_ens)
+        """
         return self._get_model_Hx('prior')
 
     def get_posterior_Hx(self):
-        """Return posterior Hx array (n_obs, n_ens)"""
+        """Retrieve H(x_posterior) for all ensemble members
+        
+        Returns:
+            np.array (n_obs, n_ens)
+        """
         return self._get_model_Hx('posterior')
 
     def get_truth_Hx(self):
+        """Retrieve H(x_truth)
+
+        Returns:
+            np.array (n_obs,)
+        """
         return self['truth'].values
 
     def _get_model_Hx(self, what):
-        """Return ensemble member info
+        """Retrieve a subset of the obs-sequence table, e.g. H(x_prior)
 
         Args:
             self (pd.DataFrame):      usually self.self
@@ -106,6 +117,11 @@ class ObsRecord(pd.DataFrame):
         return Hx.values
 
     def get_lon_lat(self):
+        """Retrieve longitude and latitude of observations
+
+        Returns:
+            pd.DataFrame (n_obs, 2)
+        """
         lats = np.empty(len(self), np.float32)
         lons = lats.copy()
 
@@ -120,13 +136,13 @@ class ObsRecord(pd.DataFrame):
 
         return pd.DataFrame(index=self.index, data=dict(lat=lats, lon=lons))
 
-    def get_from_cartesian_grid(self, i, j, k):
+    def _get_from_cartesian_grid(self, i, j, k):
         """Get the observation using cartesian grid indices (ix, iy, iz)
         """
         # find indices of observations within pandas.DataFrame
         return self.iloc[self.i_obs_grid[i, j, k].ravel()]
 
-    def determine_nlayers(self):
+    def _determine_nlayers(self):
         nlayers = 1  # first guess
         from dartwrf.exp_config import exp
 
@@ -203,7 +219,7 @@ class ObsRecord(pd.DataFrame):
             print("window (#obs in x/y)=", win_obs)
 
         # superob in case of multiple layers, only implemented for single obstype
-        nlayers = self.determine_nlayers()
+        nlayers = self._determine_nlayers()
         
         # indices of observations (starting from 0)
         i_obs_grid = self.index.values  
@@ -237,7 +253,7 @@ class ObsRecord(pd.DataFrame):
                         print("obs indices box=", i_obs_grid[i : i + win_obs, j : j + win_obs, k])
 
                     # find observations within superob window
-                    obs_box = self.get_from_cartesian_grid(slice(i, i + win_obs),
+                    obs_box = self._get_from_cartesian_grid(slice(i, i + win_obs),
                                                            slice(j, j + win_obs),
                                                            k)
 
@@ -245,10 +261,10 @@ class ObsRecord(pd.DataFrame):
                     # save boundary of box to list, for plotting later
                     eps = dx_obs_lat_deg/2  # for plotting
                     eps2 = eps*0.8  # for plotting
-                    lat1, lon1 = self.get_from_cartesian_grid(i, j, k).get_lon_lat().values[0]
-                    lat2, lon2 = self.get_from_cartesian_grid(i+win_obs-1, j, k).get_lon_lat().values[0]
-                    lat3, lon3 = self.get_from_cartesian_grid(i, j+win_obs-1, k).get_lon_lat().values[0]
-                    lat4, lon4 = self.get_from_cartesian_grid(i+win_obs-1, j+win_obs-1, k).get_lon_lat().values[0]
+                    lat1, lon1 = self._get_from_cartesian_grid(i, j, k).get_lon_lat().values[0]
+                    lat2, lon2 = self._get_from_cartesian_grid(i+win_obs-1, j, k).get_lon_lat().values[0]
+                    lat3, lon3 = self._get_from_cartesian_grid(i, j+win_obs-1, k).get_lon_lat().values[0]
+                    lat4, lon4 = self._get_from_cartesian_grid(i+win_obs-1, j+win_obs-1, k).get_lon_lat().values[0]
 
                     boxes.append(([lat1-eps2, lat2+eps2, lat3-eps2, lat4+eps2],
                                 [lon1-eps, lon2-eps, lon3+eps, lon4+eps]))
@@ -317,16 +333,17 @@ class ObsSeq(object):
     def __init__(self, filepath):
         self.ascii = open(filepath, "r").readlines()
 
-        self.get_preamble_content()
-        self.read_preamble()
+        self._get_preamble_content()
+        self._read_preamble()
 
         self.df = ObsRecord(self.to_pandas())
 
     def __str__(self):
         return self.df.__str__()
 
-    def get_preamble_content(self):
+    def _get_preamble_content(self):
         """Split the obs_seq.out file into two parts
+
         1) First lines of obs_seq.out file until the first observation message
         2) Observation contents
         """
@@ -339,7 +356,7 @@ class ObsSeq(object):
         self.preamble = self.ascii[:i]
         self.content = self.ascii[i:]
 
-    def read_preamble(self):
+    def _read_preamble(self):
         """Defines 
         self.obstypes (tuple(kind_nr, kind_descriptor)) for each obs type
         """
@@ -394,7 +411,7 @@ class ObsSeq(object):
 
         self.keys_for_values = keys
 
-    def obs_to_dict(self):
+    def _obs_to_dict(self):
         """Convert an obs_seq.out file to a dictionary"""
         obs_begin_str = "OBS  "
 
@@ -495,7 +512,7 @@ class ObsSeq(object):
     def to_pandas(self):
         """Create pd.DataFrame with rows=observations
         """
-        obs_dict_list = self.obs_to_dict()
+        obs_dict_list = self._obs_to_dict()
 
         # convert to pandas.DataFrame
         # each observation is one line
diff --git a/dartwrf/obs/obsseq_2dim.py b/dartwrf/obs/obsseq_2dim.py
index 7239906206672579edf2320578784032fc0bec3a..40afa4a7c51999d5a518d73fc3405d6d16cf2be0 100755
--- a/dartwrf/obs/obsseq_2dim.py
+++ b/dartwrf/obs/obsseq_2dim.py
@@ -14,18 +14,23 @@ Example:
 """
 
 from copy import copy
-import os, sys, shutil, warnings
-import time as time_module
+import os, sys, warnings
 import datetime as dt
 import numpy as np
 
 from dartwrf.server_config import cluster
 from dartwrf import utils
-from dartwrf import assim_synth_obs as aso
 from dartwrf.obs import obsseq
 
 def _get_n_obs_per_layer(oso):     
-     """Get number of observations per layer"""
+     """Determine number of observations per layer from obsseq.ObsSeq object
+
+     Args:
+          oso (obsseq.ObsSeq): obsseq object
+
+     Returns:
+          int
+     """
      height_all = np.array([a[2] for a in oso.df.loc3d])
 
      height_first = height_all[0]