diff --git a/dataprocessing/readtools.py b/dataprocessing/readtools.py index eeaee0a82cea109115bc14b8a2a350cf899997d1..e33c462154671bd998195351e71ee849d3e488b1 100644 --- a/dataprocessing/readtools.py +++ b/dataprocessing/readtools.py @@ -30,7 +30,7 @@ def read_timeseries_Modelica(filename, timeseries_names=None, is_regex=False): timeseries.append(TimeSeries(name, sim(name).times(), sim(name).values())) print('Modelica results column names: ' + str(timeseries_names)) - print('Modelica results number: ' + str(len(timeseries_list))) + print('Modelica results number: ' + str(len(timeseries_names))) return timeseries @@ -86,23 +86,25 @@ def read_timeseries_dpsim_real(filename, timeseries_names=None): if timeseries_names is None: # No column names specified, thus read in all and strip spaces pd_df.rename(columns=lambda x: x.strip(), inplace=True) - column_names = list(pd_df.columns.values) + timeseries_names = list(pd_df.columns.values) + timeseries_names.remove('time') + #else: + # # Read in specified column names + # pd_df = pd.read_csv(filename, names=timeseries_names) - # Remove timestamps column name and store separately - column_names.remove('time') - timestamps = pd_df.iloc[:,0] + # store columns of interest in list of timeseries + # note: timestamps must be given in first column of csv file + timestamps = pd_df.iloc[:, 0] + for name in timeseries_names: + timeseries_list.append(TimeSeries(name, timestamps, pd_df[name].values)) - for name in column_names: - timeseries_list.append(TimeSeries(name, timestamps, pd_df[name].values)) - else: - # Read in specified time series - print('no column names specified yet') - - print('DPsim results column names: ' + str(column_names)) + print('DPsim results column names: ' + str(timeseries_names)) print('DPsim results number: ' + str(len(timeseries_list))) + print('DPsim results timestamps number: ' + str(len(timestamps))) return timeseries_list + 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. @@ -120,15 +122,15 @@ def read_timeseries_dpsim_cmpl(filename, timeseries_names=None): # Remove timestamps column name and store separately column_names.remove('time') - timestamps = pd_df.iloc[:,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 = 'n'+ str(node_index) + ts_name = 'n' + str(node_index) timeseries_list.append( - TimeSeries(ts_name, timestamps, np.vectorize(complex)(pd_df.iloc[:,node_index],pd_df.iloc[:,node_index + node_number]))) + TimeSeries(ts_name, timestamps, np.vectorize(complex)(pd_df.iloc[:, node_index], pd_df.iloc[:, node_index + node_number]))) else: break node_index = node_index + 1 @@ -141,6 +143,7 @@ def read_timeseries_dpsim_cmpl(filename, timeseries_names=None): 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. @@ -162,11 +165,11 @@ def read_timeseries_dpsim_cmpl_separate(filename, timeseries_names=None): node_index = 1 for column in column_names: if node_index <= node_number: - node_name = 'node '+ str(node_index) +' Re' - timeseries_list.append(TimeSeries(node_name, timestamps, 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 '+ str(node_index - node_number) +' Im' - timeseries_list.append(TimeSeries(node_name, timestamps, 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: diff --git a/dataprocessing/timeseries.py b/dataprocessing/timeseries.py index 424e4b0256d65ed71fd7f833cb0dbf7f2915c81b..8ab1966433c2e4611acb41ff2530e91f9aa8a932 100644 --- a/dataprocessing/timeseries.py +++ b/dataprocessing/timeseries.py @@ -43,6 +43,19 @@ class TimeSeries: """ return np.sqrt((TimeSeries.diff('diff', ts1, ts2).values ** 2).mean()) + @staticmethod + def norm_rmse(ts1, ts2): + """ Calculate root mean square error between two time series, + normalized using the mean value of both mean values of ts1 and ts2 + """ + if np.mean(np.array(ts1.values.mean(),ts2.values.mean())) != 0: + nrmse = np.sqrt((TimeSeries.diff('diff', ts1, ts2).values ** 2).mean())/np.mean(np.array(ts1.values.mean(),ts2.values.mean())) + is_norm = True + else: + nrmse = np.sqrt((TimeSeries.diff('diff', ts1, ts2).values ** 2).mean()) + is_norm = False + return (nrmse,is_norm) + @staticmethod def diff(name, ts1, ts2): """Returns difference between values of two Timeseries objects. @@ -67,6 +80,18 @@ class TimeSeries: - self.values.imag*np.sin(2*np.pi*freq*self.time)) return ts_shift + def calc_freq_spectrum(self): + """ Calculates frequency spectrum of the time series using FFT + :param name: name of returned time series + :param freq: shift frequency + :return: new timeseries with shifted time domain values + """ + Ts = self.time[1]-self.time[0] + fft_values = np.fft.fft(self.values) + freqs_num = int(len(fft_values)/2) + fft_freqs = np.fft.fftfreq(len(fft_values),d=Ts) + return fft_freqs[:freqs_num], np.abs(fft_values[:freqs_num])/freqs_num + def interpolate_cmpl(self, name, timestep): """ Not tested yet! Interpolates complex timeseries with timestep @@ -132,5 +157,5 @@ class TimeSeries: 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()) + ts_abs = TimeSeries(name, ts_real.time, np.absolute(ts_complex)) return ts_abs \ No newline at end of file diff --git a/examples/CompareResults/compare_modelica_distaix.py b/examples/CompareResults/compare_modelica_distaix.py new file mode 100644 index 0000000000000000000000000000000000000000..ead439ad4dcf2518577f8a8cfa7b9df4212a8b17 --- /dev/null +++ b/examples/CompareResults/compare_modelica_distaix.py @@ -0,0 +1,27 @@ +from dataprocessing.readtools import * +from dataprocessing.plottools import * +import matplotlib.pyplot as plt +from plottingtools.config import * +import numpy as np + +# Comparison of P, Q and delta for 3rd order Synchronous Generator +syngen_modelica_1us = read_timeseries_Modelica( + r"\\tsclient\N\Research\German Public\ACS0049_SINERGIEN_bsc\Data\WorkData\SimulationResults\SynchronousGenerator\DP\Modelica\SinglePhase\SMIB_3rdOrderModel_PmStep_ThetaVolt0_Euler_1us.mat", + timeseries_names=["synchronousGenerator_Park.P", "synchronousGenerator_Park.Q", "synchronousGenerator_Park.delta", "synchronousGenerator_Park.i.re", "synchronousGenerator_Park.i.im"]) +syngen_distaix = read_timeseries_dpsim_real( + r"\\tsclient\N\Research\German Public\ACS0050_Swarmgrid_tis\Data\WorkData\AP5\simulation-results\distaix_syngen_power_step\10ms\agent_3.csv", + timeseries_names=["P [W]", "Q [var]", "delta [rad]", "i.re [A]", "i.im [A]"]) + +num_vars = 5 +subplot_title_list = ["P [W]\n", "Q [var]\n", "delta [rad]\n", "i.re [A]", "i.im [A]"] +plt.figure(1, figsize=(12, 8)) +for i in range(num_vars): + plt.subplot(num_vars, 1, i + 1) + set_timeseries_labels(syngen_modelica_1us, ["Modelica 1us", "Modelica 1us", "Modelica 1us", "Modelica 1us", "Modelica 1us"]) + plt.plot(syngen_modelica_1us[i].time, syngen_modelica_1us[i].values, label=syngen_modelica_1us[i].label) + set_timeseries_labels(syngen_distaix, ["DistAIX 10ms", "DistAIX 10ms", "DistAIX 10ms", "DistAIX 10ms", "DistAIX 10ms"]) + plt.plot(syngen_distaix[i].time, syngen_distaix[i].values, label=syngen_distaix[i].label, linestyle=':') + plt.legend() + plt.xlim([0, 30]) + plt.ylabel(subplot_title_list[i]) +plt.show(block=True) diff --git a/examples/Distaix/read_distaix_examples.py b/examples/Distaix/read_distaix_examples.py new file mode 100644 index 0000000000000000000000000000000000000000..f10131e4d6a99a380f446c2c89bae52919117b08 --- /dev/null +++ b/examples/Distaix/read_distaix_examples.py @@ -0,0 +1,13 @@ +from dataprocessing.readtools import * +from dataprocessing.plottools import * +import matplotlib.pyplot as plt + +# Example 1: read in single variable included in the Modelica results file +agent3_i_re = read_timeseries_dpsim_real( + r"\\tsclient\N\Research\German Public\ACS0050_Swarmgrid_tis\Data\WorkData\AP5\simulation-results\distaix_syngen_power_const\agent_3.csv", + timeseries_names=["i.re [A]"]) +plt.figure(1, figsize=(12, 8)) +set_timeseries_labels(agent3_i_re[0], "Agent 1 Ireal") +plt.plot(agent3_i_re[0].time, agent3_i_re[0].values, label=agent3_i_re[0].label) +plt.legend() +plt.show(block=True)