diff --git a/.gitignore b/.gitignore
index cda7e3a37b6607b3b9360a049121d38774cecebe..ac7199b53782ed72cb611b38524cbc18216dfea4 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,6 @@
+build
+dist
+
 # ignore results 
 *.csv
 *.mat
@@ -31,4 +34,6 @@ dymosim*
 __pycache__
 
 # ignore jupyter notebook files
-.ipynb_checkpoints
\ No newline at end of file
+.ipynb_checkpoints
+
+.eggs
\ No newline at end of file
diff --git a/dataprocessing/__init__.py b/dataprocessing/__init__.py
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..ffc05b2550467dbaaf3036d94a2536a0ff1d9de2 100644
--- a/dataprocessing/__init__.py
+++ b/dataprocessing/__init__.py
@@ -0,0 +1 @@
+__all__ = ["readtools", "plottools", "timeseries"]
\ No newline at end of file
diff --git a/dataprocessing/dpsim.py b/dataprocessing/dpsim.py
index e56cb5ff54e9f7f5cf8332474d241f008d72a269..67d0f82b4a0878b470f84b6f7bf2fcb249f6668c 100644
--- a/dataprocessing/dpsim.py
+++ b/dataprocessing/dpsim.py
@@ -1,5 +1,6 @@
 from dataprocessing.readtools import *
 from dataprocessing.timeseries import *
+from dataprocessing.plottools import *
 
 def get_node_voltage_phasors(dpsim_timeseries_list):
     """Calculate voltage phasors of all nodes
@@ -24,7 +25,7 @@ def get_node_emt_voltages(timeseries_list, freq):
     """
     voltages_list = {}
     for name, ts in timeseries_list.items():
-        ts_emt = ts.dynphasor_shift_to_emt(ts.name, freq)
+        ts_emt = ts.frequency_shift(ts.name, freq)
         voltages_list[ts.name] = ts_emt
 
     return voltages_list
diff --git a/dataprocessing/readtools.py b/dataprocessing/readtools.py
index 99eba9f9b0ebddc793bf7ee58ecd895bb5d4aa9c..9226ff6e751782972e6a27977d3aaa9e10f0fbfb 100644
--- a/dataprocessing/readtools.py
+++ b/dataprocessing/readtools.py
@@ -56,24 +56,51 @@ def read_timeseries_PLECS(filename, timeseries_names=None):
 
 def read_timeseries_simulink(filename, timeseries_names=None):
     pd_df = pd.read_csv(filename)
-    timeseries_list = []
+    timeseries_list = {}
+    cmpl_result_columns = []
+    real_result_columns = []
+
     if timeseries_names is None:
-        # No trajectory names specified, thus read in all
-        timeseries_names = list(pd_df.columns.values)
-        timeseries_names.remove('time')
-        for name in timeseries_names:
-            timeseries_list.append(TimeSeries(name, pd_df['time'].values, pd_df[name].values))
+        # No column names specified, thus read in all and strip off spaces
+        pd_df.rename(columns=lambda x: x.strip(), inplace=True)
+        column_names = list(pd_df.columns.values)
+
+        # Remove timestamps column name and store separately
+        column_names.remove('time')
+        timestamps = pd_df.iloc[:, 0]
+
+        # Find real and complex variable names
+        real_string = '.real'
+        imaginary_string = '.imag'
+        for column in column_names:
+            if real_string in column:
+                tmp = column.replace(real_string, '')
+                cmpl_result_columns.append(tmp)
+                #print("Found complex variable: " + tmp)
+            elif not imaginary_string in column:
+                real_result_columns.append(column)
+                #print("Found real variable: " + column)
+
+        for column in real_result_columns:
+            timeseries_list[column] = TimeSeries(column, timestamps, pd_df[column])
+
+        for column in cmpl_result_columns:
+            timeseries_list[column] = TimeSeries(column, timestamps,
+                np.vectorize(complex)(pd_df[column + real_string],
+                pd_df[column + imaginary_string]))
+
     else:
         # Read in specified time series
-        for name in timeseries_names:
-            timeseries_list.append(TimeSeries(name, pd_df['time'].values, pd_df[name].values))
+        print('cannot read specified columns yet')
 
-    print('Simulink results column names: ' + str(timeseries_names))
-    print('Simulink results number: ' + str(len(timeseries_list)))
+    print('Simulink results real column names: ' + str(real_result_columns))
+    print('Simulink results complex column names: ' + str(cmpl_result_columns))
+    print('Simulink results variable number: ' + str(len(timeseries_list)))
+    print('Simulink results length: ' + str(len(timestamps)))
 
     return timeseries_list
 
-def read_timeseries_dpsim(filename, timeseries_names=None):
+def read_timeseries_dpsim(filename, timeseries_names=None, print_status=True):
     """Reads complex time series data from DPsim log file. Real and
     imaginary part are stored in one complex variable.
     :param filename: name of the csv file that has the data
@@ -132,9 +159,39 @@ def read_timeseries_dpsim(filename, timeseries_names=None):
         # Read in specified time series
         print('cannot read specified columns yet')
 
-    print('DPsim results real column names: ' + str(real_result_columns))
-    print('DPsim results complex column names: ' + str(cmpl_result_columns))
-    print('DPsim results variable number: ' + str(len(timeseries_list)))
-    print('DPsim results length: ' + str(len(timestamps)))
+    if print_status :
+        print('DPsim results real column names: ' + str(real_result_columns))
+        print('DPsim results complex column names: ' + str(cmpl_result_columns))
+        print('DPsim results variable number: ' + str(len(timeseries_list)))
+        print('DPsim results length: ' + str(len(timestamps)))
 
     return timeseries_list
+
+def read_dpsim_log(log_path):
+    log_file = open(log_path, "r")
+    log_lines = [line for line in log_file]
+    log_file.close()
+
+    # Sectionize
+    log_sections = {'init':[], 'none':[], 'sysmat_stamp':[], 'sysmat_final':[], 'sourcevec_stamp':[], 'sourcevec_final':[], 'ludecomp':[]}
+    section = 'init'
+    for line_pos in range(len(log_lines)):
+        if re.search('DEBUG: Stamping .+ into system matrix:', log_lines[line_pos]):
+            section = 'sysmat_stamp'
+        elif re.search('INFO: System matrix:', log_lines[line_pos]):
+            section = 'sysmat_final'
+        elif re.search('DEBUG: Stamping .+ into source vector:', log_lines[line_pos]):
+            section = 'sourcevec_stamp'
+        elif re.search('INFO: Right side vector:', log_lines[line_pos]):
+            section = 'sourcevec_final'
+        elif re.search('INFO: LU decomposition:', log_lines[line_pos]):
+            section = 'ludecomp'
+        elif re.search('INFO: Number of network simulation nodes:', log_lines[line_pos]):
+            section = 'none'
+        elif re.search('INFO: Added .+ to simulation.', log_lines[line_pos]):
+            section = 'none'
+        elif re.search('INFO: Initial switch status:', log_lines[line_pos]):
+            section = 'none'
+        log_sections[section].append(line_pos)
+
+    return log_lines, log_sections
diff --git a/dataprocessing/timeseries.py b/dataprocessing/timeseries.py
index 300c0b5c8759e679a84b73299df0e0c281e0fa93..d94ca4131aa165c18def7c276507d0810fa05e7f 100644
--- a/dataprocessing/timeseries.py
+++ b/dataprocessing/timeseries.py
@@ -37,6 +37,31 @@ class TimeSeries:
         ts_phase = TimeSeries(name, self.time, phase_values)
         return ts_phase
 
+    def phasor(self, name):
+        """Calculate phasor of complex time series and return dict with abs and phase.
+        """
+        ts_abs = ts.abs(ts.name + '_abs')
+        ts_phase = ts.phase(ts.name + '_phase')
+        ts_phasor = {}
+        ts_phasor['abs'] = ts_abs
+        ts_phasor['phase'] = ts_phase
+        
+        return ts_phasor
+
+    @staticmethod
+    def frequency_shift_list(timeseries_list, freq):
+        """Calculate shifted frequency results of all time series
+        :param timeseries_list: timeseries list retrieved from dpsim results
+        :param freq: frequency by which the timeseries should be shifted
+        :return: list of shifted time series
+        """
+        result_list = {}
+        for name, ts in timeseries_list.items():
+            ts_emt = ts.frequency_shift(ts.name, freq)
+            result_list[ts.name] = ts_emt
+
+        return result_list
+
     @staticmethod
     def rmse(ts1, ts2):
         """ Calculate root mean square error between two time series
@@ -69,7 +94,7 @@ class TimeSeries:
             ts_diff = TimeSeries(name, time, (interp_vals_ts2 - interp_vals_ts1))
         return ts_diff
 
-    def dynphasor_shift_to_emt(self, name, freq):
+    def frequency_shift(self, name, freq):
         """ Shift dynamic phasor values to EMT by frequency freq.
             Assumes the same time steps for both timeseries.
         :param name: name of returned time series