Commit 20ab9a9b authored by Markus Mirz's avatar Markus Mirz

improved processing of complex data and moved calc functions to Timeseries

parent 3ffe6cb4
import matplotlib.pyplot as plt
import numpy as np
from .timeseries import *
def diff(name, ts1, ts2):
""" Calculate difference.
Assumes the same time steps for both timeseries.
"""
ts_diff = TimeSeries(name, ts1.time, (ts1.values - ts2.values))
return ts_diff
def scale_ts(name, ts, factor):
""" Scale timeseries.
Assumes the same time steps for both timeseries.
"""
ts_scaled = TimeSeries(name, ts.time, ts.values * factor)
return ts_scaled
def complex_abs(name, real, imag):
""" Calculate absolute value of complex variable.
Assumes the same time steps for both timeseries.
"""
ts_abs = TimeSeries(name, real.time, np.sqrt(real.values ** 2 + imag.values ** 2))
return ts_abs
def dyn_phasor_shift_to_emt(name, real, imag, freq):
""" Shift dynamic phasor values to EMT by frequency freq.
Assumes the same time steps for both timeseries.
"""
ts_shift = TimeSeries(name, real.time, real.values*np.cos(2*np.pi*freq*real.time) - imag.values*np.sin(2*np.pi*freq*real.time))
return ts_shift
def check_node_number_comp(ts_comp, node):
"""
Check if node number is available in complex time series.
:param ts_comp: complex time series
:param node: node number to be checked
:return: true if node number is available, false if out of range
"""
ts_comp_length = len(ts_comp)
im_offset = int(ts_comp_length / 2)
if im_offset <= node or node < 0:
print('Complex node not available')
return false
else:
return true
def check_node_number(ts, node):
"""
Check if node number is available in time series.
:param ts: time series
:param node: node number to be checked
:return: true if node number is available, false if out of range
"""
ts_length = len(ts)
if ts_length <= node or node < 0:
print('Node not available')
return false
else:
return true
......@@ -31,16 +31,38 @@ def read_timeseries_PLECS(filename, timeseries_names=None):
timeseries_list.append(TimeSeries(name, pd_df['Time'].values, pd_df[name].values))
return timeseries_list
def read_timeseries_DPsim(filename, timeseries_names=None):
pd_df = pd.read_csv(filename)
def read_timeseries_dpsim_real(filename, header=None, timeseries_names=None):
"""Reads real time series data from DPsim log file which may have a header.
Timeseries names are assigned according to the header names if available.
:param filename: name of the csv file that has the data
:param header: specifies if the log file has a header
:param timeseries_names: column names which should be read
:return: list of Timeseries objects
"""
timeseries_list = []
if header is True:
pd_df = pd.read_csv(filename)
else:
pd_df = pd.read_csv(filename, header=None)
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))
column_names = list(pd_df.columns.values)
# Remove timestamps column name and store separately
column_names.remove(0)
timestamps = pd_df.iloc[:,0]
if header is True:
for name in column_names:
timeseries_list.append(TimeSeries(name, timestamps, pd_df[name].values))
else:
node_number = int(len(column_names))
node_index = 1
for column in column_names:
ts_name = 'node ' + str(node_index)
timeseries_list.append(TimeSeries(ts_name, timestamps, pd_df.iloc[:, column]))
node_index = node_index + 1
else:
# Read in specified time series
print('no column names specified yet')
......@@ -51,23 +73,68 @@ def read_timeseries_DPsim(filename, timeseries_names=None):
print(result.name)
return timeseries_list
def read_timeseries_DPsim_node_values(filename, timeseries_names=None):
def read_timeseries_dpsim_cmpl(filename, timeseries_names=None):
"""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
:param timeseries_names: column name which should be read
:return: list of Timeseries objects
"""
pd_df = pd.read_csv(filename, header=None)
timeseries_list = []
if timeseries_names is None:
# No trajectory names specified, thus read in all
column_names = list(pd_df.columns.values)
# Remove timestamps column name and store separately
column_names.remove(0)
timestamps = pd_df.iloc[:,0]
# Calculate number of network nodes since array is [real, imag]
node_number = int(len(column_names) / 2)
node_index = 1
for column in column_names:
if node_index <= node_number:
ts_name = 'node '+ str(node_index)
timeseries_list.append(TimeSeries(ts_name, timestamps, np.vectorize(complex)(pd_df.iloc[:,column],pd_df.iloc[:,column + node_number])))
else:
break
node_index = node_index + 1
else:
# Read in specified time series
print('cannot read specified columns yet')
print('DPsim results file length:')
print(len(timeseries_list))
for result in timeseries_list:
print(result.name)
return timeseries_list
def read_timeseries_dpsim_cmpl_separate(filename, timeseries_names=None):
"""Deprecated - Reads complex time series data from DPsim log file. Real and
imaginary part are stored separately.
:param filename: name of the csv file that has the data
:param timeseries_names: column name which should be read
:return: list of Timeseries objects
"""
pd_df = pd.read_csv(filename, header=None)
timeseries_list = []
if timeseries_names is None:
# No trajectory names specified, thus read in all
column_names = list(pd_df.columns.values)
# Remove timestamps column name and store separately
column_names.remove(0)
timestamps = pd_df.iloc[:, 0]
# Calculate number of network nodes since array is [real, imag]
node_number = int(len(column_names) / 2)
node_index = 1
for column in column_names:
if node_index <= node_number:
node_name = node_index
timeseries_list.append(TimeSeries('node '+ str(node_name) +' Re', pd_df.iloc[:,0], pd_df.iloc[:,column]))
node_name = 'node '+ str(node_index) +' Re'
timeseries_list.append(TimeSeries(node_name, timestamps, pd_df.iloc[:,column]))
else:
node_name = node_index - node_number
timeseries_list.append(TimeSeries('node '+ str(node_name) +' Im', pd_df.iloc[:,0], pd_df.iloc[:,column]))
node_name = 'node '+ str(node_index - node_number) +' Im'
timeseries_list.append(TimeSeries(node_name, timestamps, pd_df.iloc[:,column]))
node_index = node_index + 1
else:
......
import numpy as np
class TimeSeries:
"""Stores data from different simulation sources.
A TimeSeries object always consists of timestamps and datapoints.
"""
def __init__(self, name, time, values, label=""):
self.time = np.array(time)
self.values = np.array(values)
self.name = name
self.label = name
\ No newline at end of file
self.label = name
@staticmethod
def diff(name, ts1, ts2):
"""Returns difference between values of two Timeseries objects.
Assumes the same time steps for both timeseries.
"""
ts_diff = TimeSeries(name, ts1.time, (ts1.values - ts2.values))
return ts_diff
def scale_ts(self, name, factor):
"""Returns scaled timeseries.
Assumes the same time steps for both timeseries.
"""
ts_scaled = TimeSeries(name, self.time, self.values * factor)
return ts_scaled
@staticmethod
def complex_abs_dep(name, ts_real, ts_imag):
""" Calculate absolute value of complex variable.
Assumes the same time steps for both timeseries.
"""
ts_abs = TimeSeries(name, ts_real.time, np.sqrt(ts_real.values ** 2 + ts_imag.values ** 2))
return ts_abs
@staticmethod
def complex_abs(name, ts_real, ts_imag):
""" Calculate absolute value of complex variable.
Assumes the same time steps for both timeseries.
"""
ts_complex = np.vectorize(complex)(ts_real.values, ts_imag.values)
ts_abs = TimeSeries(name, ts_real.time, ts_complex.abs())
return ts_abs
def abs(self, name):
""" Calculate absolute value of complex variable.
Assumes the same time steps for both timeseries.
"""
ts_abs = TimeSeries(name, self.time, self.values.abs())
return ts_abs
def complex_phase(name, ts_real, ts_imag):
""" Calculate absolute value of complex variable.
Assumes the same time steps for both timeseries.
"""
ts_complex = np.vectorize(complex)(ts_real.values, ts_imag.values)
ts_abs = TimeSeries(name, ts_real.time, ts_complex.phase())
return ts_abs
@staticmethod
def dyn_phasor_shift_to_emt(name, real, imag, freq):
""" Shift dynamic phasor values to EMT by frequency freq.
Assumes the same time steps for both timeseries.
"""
ts_shift = TimeSeries(name, real.time, real.values*np.cos(2*np.pi*freq*real.time) - imag.values*np.sin(2*np.pi*freq*real.time))
return ts_shift
@staticmethod
def check_node_number_comp(ts_comp, node):
"""
Check if node number is available in complex time series.
:param ts_comp: complex time series
:param node: node number to be checked
:return: true if node number is available, false if out of range
"""
ts_comp_length = len(ts_comp)
im_offset = int(ts_comp_length / 2)
if im_offset <= node or node < 0:
print('Complex node not available')
return false
else:
return true
@staticmethod
def check_node_number(ts, node):
"""
Check if node number is available in time series.
:param ts: time series
:param node: node number to be checked
:return: true if node number is available, false if out of range
"""
ts_length = len(ts)
if ts_length <= node or node < 0:
print('Node not available')
return false
else:
return true
\ No newline at end of file
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment