import math
import pandas as pd
import numpy as np
import scipy.io as scio
import matplotlib.pyplot as plt
import os, sys
import re
import xlsxwriter
class Analysis():
"""
This is a class for comparing and analyzing the tset data of TEST, PSCAD and PSSE.
Analysis class includes three groups of data and analysis functions of different test items :
VRT, frequency response, reactive power injection, small disturbance of voltage and frequency,
climbing test, etc.
"""
def __init__(self, path):
self.Filename_list = []
self.file_dict = {}
self.plotOption = ['k:', 'r:', 'b-.']
self.item = ['Field Test', 'PSCAD', 'PSSE']
self.offset1 = 2
self.offset2 = 2
self.File_TEST = []
self.File_PSSE = []
self.File_PSCAD = []
# self.File_TEST, self.File_PSSE, self.File_PSCAD = self.file_search(path)
self.file_search(path)
self.Frequency_UP = ['50.0', '50.10', '51.00', '51.9', '51.00', '50.1', '50.00']
self.TargetVaule_Inc = [1.0, 0.98, 0.62, 0.26, 0.62, 0.98, 1.0]
self.Frequency_dwn = ['50', '49.85', '48.80', '47.60', '48.80', '49.85', '50.00']
self.TargetVaule_dec = [0.50, 0.52, 0.94, 1.0, 0.94, 0.52, 0.50]
def analysis_VRT(self, savepath, threshold_L=0.978, threshold_H=1.02, SensitiveVaribleIndex=1):
"""
高低穿工况数据分析,并输出分析结果图与结果表
:param savepath: 分析结果的保存路径
threshold_L: 低穿工况判断阈值
threshold_H: 高穿工况判断阈值
SensitiveVaribleIndex: 作为判断的数据列下标
:output: 在提供的保存路径下输出高低穿分析结果
"""
Data = []
Plotoffset1 = []
Plotoffset2 = []
Tsam = []
Indexlabel = []
mrow = []
ncolumn = []
axeX = []
IndexPlotStart = []
IndexPlotDuring = []
IndexPlotEnd = []
IndexforSave = []
data2save = []
Data_Max_Value = np.ones(12) * (-np.inf)
Data_Min_Value = np.ones(12) * (np.inf)
Index_Offset = 0 # 从第1列开始数(已默认+1),正序电压在第n列SensitiveVaribleIndex=n-1
# Index_Offset = 0
######################################## 高低穿起始和截止下标判断 ########################################
for filename in self.Filename_list:
csv_path = self.file_dict.get(filename) + '\\' + filename
data = pd.read_csv(csv_path).dropna().values
row, col = data.shape
for k in range(1+Index_Offset, col):
a = np.around(np.max(data[0:, k]) + 0.05, 1)
b = np.around(np.min(data[0:, k]) - 0.05, 1)
Data_Max_Value[k - 1 - Index_Offset] = max(a, Data_Max_Value[k - 1 - Index_Offset])
Data_Min_Value[k - 1 - Index_Offset] = min(b, Data_Min_Value[k - 1 - Index_Offset])
Data.append(data)
PosVoltMIndexLess09 = self._rangecheck(data[0:, SensitiveVaribleIndex], '<', threshold_L, 0.01)
PosVoltMIndexMore11 = self._rangecheck(data[0:, SensitiveVaribleIndex], '>', threshold_H, 0.01)
LVRTduration = PosVoltMIndexLess09[1] - PosVoltMIndexLess09[0]
HVRTduration = PosVoltMIndexMore11[1] - PosVoltMIndexMore11[0]
tsam = round(data[20, 0] - data[19, 0], 5)
Plotoffset1.append(self.offset1 / tsam)
Plotoffset2.append(self.offset2 / tsam)
Tsam.append(tsam)
tduration = 0.05 / tsam
tstableoffset = int(0.5 / tsam)
row, col = data.shape
mrow.append(row)
ncolumn.append(col)
if ((HVRTduration > tduration) and (LVRTduration > tduration)):
LHVRT = 3
Indexlabel.append(PosVoltMIndexLess09)
Indexlabel.append(PosVoltMIndexMore11)
elif (HVRTduration > tduration):
if (PosVoltMIndexMore11[0] > tstableoffset):
LHVRT = 2
Indexlabel.append(PosVoltMIndexMore11)
else:
print('Data is not enough before fault')
LHVRT = 0
elif (LVRTduration > tduration):
if (PosVoltMIndexLess09[0] > tstableoffset):
LHVRT = 1
Indexlabel.append(PosVoltMIndexLess09)
else:
print('Data is not enough before fault')
LHVRT = 0
else:
LHVRT = 0
if min(ncolumn)-Index_Offset > 6:
VaribleNum = min(ncolumn) - 6 - Index_Offset
else:
VaribleNum = min(ncolumn) - 1 - Index_Offset
for i in range(Data.__len__()):
if (LHVRT == 1):
Plotoffset1[i] = min(Indexlabel[i][0], Plotoffset1[i])
if (Indexlabel[i][0] > Indexlabel[i][1]):
print('Warning ' + str(len(Data)) + ' no event found!')
elif (LHVRT == 2):
Plotoffset1[i] = min(Indexlabel[i][0], Plotoffset1[i])
if (Indexlabel[i][0] > Indexlabel[i][1]):
print('Warning ' + str(len(Data)) + ' no event found!')
elif (LHVRT == 3):
Plotoffset1[i] = min(Indexlabel[2 * i + 1][0], min(Indexlabel[2 * i][0], Plotoffset1[i]))
if ((Indexlabel[2 * i + 1][0] > Indexlabel[2 * i + 1][1]) or (
Indexlabel[2 * i][0] > Indexlabel[2 * i][1])):
print('Warning ' + str(len(Data)) + ' no event found!')
else:
pass
try:
IndexPlotStart.append(max(int(Indexlabel[i][0] - Plotoffset1[i]), 1))
IndexPlotEnd.append(min(int(Indexlabel[i][1] + Plotoffset2[i]), mrow[i] - 1))
IndexPlotDuring.append(int(Indexlabel[i][0] + 0.65 * (Indexlabel[i][1] - Indexlabel[i][0])))
IndexforSave.append([IndexPlotStart[i], IndexPlotDuring[i], IndexPlotEnd[i]])
axeX.append(Data[i][IndexPlotStart[i]: IndexPlotEnd[i], 0] - Data[i][IndexPlotStart[i], 0])
except Exception as e:
print(e)
continue
finally:
pass
######################################### 异常数据处理 ##############################################
# Data[1][Indexlabel[1][0]:Indexlabel[1][0]+200, 2] = (Data[1][Indexlabel[1][0]:Indexlabel[1][0]+200, 2] - 1.0) * 0.5 + 1.0
# Data[1][Indexlabel[1][1] + 20:Indexlabel[1][1] + 300, 4] = np.minimum(Data[1][Indexlabel[1][1] + 20:Indexlabel[1][1] + 300, 4], 1)
# Data[1][Indexlabel[1][0]:Indexlabel[1][0]+200, 4] = Data[1][Indexlabel[1][0]:Indexlabel[1][0]+200, 2] / Data[1][Indexlabel[1][0]:Indexlabel[1][0]+200, 1]
######################################### 绘制结果图和结果表 #########################################
ytext_Pos = ['U+/pu', 'P+/pu', 'Q+/pu', 'Ip+/pu', 'Iq+/pu']
ytext_Neg = ['U-/pu', 'P-/pu', 'Q-/pu', 'Ip-/pu', 'Iq-/pu']
ylimit_Pos = [[Data_Min_Value[0] - 0.05, Data_Max_Value[0] + 0.05],
[Data_Min_Value[1] - 0.1, Data_Max_Value[1] + 0.1],
[Data_Min_Value[2] - 0.1, Data_Max_Value[2] + 0.1],
[Data_Min_Value[3] - 0.1, Data_Max_Value[3] + 0.1],
[Data_Min_Value[4] - 0.1, Data_Max_Value[4] + 0.1]]
ylimit_Neg = [[Data_Min_Value[5] - 0.05, Data_Max_Value[5] + 0.05],
[Data_Min_Value[6] - 0.1, Data_Max_Value[6] + 0.1],
[Data_Min_Value[7] - 0.1, Data_Max_Value[7] + 0.1],
[Data_Min_Value[8] - 0.1, Data_Max_Value[8] + 0.1],
[Data_Min_Value[9] - 0.1, Data_Max_Value[9] + 0.1]]
ManualOffset = [[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]]
legendtext = ['RTLAB', 'ADPSS', 'PSSE']
fig_Pos = plt.figure(1, [10, 12])
for i in range(Data.__len__()):
save = []
for j in range(VaribleNum):
data_item_Pos = []
data_item_Neg = []
for k in range(IndexforSave[i].__len__()):
## 添加正序数据
data_item_Pos.append(Data[i][IndexforSave[i][k], j + 1 + Index_Offset])
## 添加负序数据
row_idx = IndexforSave[i][k]
col_idx = j + 6 + Index_Offset
if (row_idx < Data[i].shape[0] and col_idx < Data[i].shape[1]):
data_item_Neg.append(Data[i][row_idx, col_idx])
else:
data_item_Neg.append('/')
save.append(data_item_Pos)
save.append(data_item_Neg)
axf = plt.subplot(VaribleNum, 1, j + 1)
plt.plot(axeX[i] + ManualOffset[i][j], Data[i][IndexPlotStart[i]:IndexPlotEnd[i], j + 1 + Index_Offset],
self.plotOption[i],
linewidth=2,
label=legendtext[i]) # self.item[i]
plt.ylabel(ytext_Pos[j], fontdict={'size': 16})
plt.margins(x=0)
plt.ylim(ylimit_Pos[j])
plt.grid(axis='both', linestyle='-.')
plt.legend(loc="upper right")
data2save.append(save)
plt.xlabel('t/s', fontdict={'size': 16})
# plt.show()
filename = self.Filename_list[1].replace('_PSCAD.csv', '')
fig_Pos.savefig(savepath + filename + '_Pos.png')
plt.close()
# fig_Neg = plt.figure(1, [10, 12])
# for i in range(min(Data.__len__(), 2)):
# for j in range(VaribleNum):
# axf = plt.subplot(VaribleNum, 1, j + 1)
# plt.plot(axeX[i] + ManualOffset[i][j], Data[i][IndexPlotStart[i]:IndexPlotEnd[i], j + 6 + Index_Offset],
# self.plotOption[i],
# linewidth=2,
# label=self.item[i])
# plt.ylabel(ytext_Neg[j], fontdict={'size': 16})
# plt.margins(x=0)
# plt.ylim(ylimit_Neg[j])
# plt.grid(axis='both', linestyle='-.')
# plt.legend(loc="upper right")
#
# plt.xlabel('t/s', fontdict={'size': 16})
# plt.show()
# fig_Neg.savefig(savepath + filename + '_Neg.png')
# plt.close()
rowname = ['U+', 'U-', 'P+', 'P-', 'Q+', 'Q-', 'Ip+', 'Ip-', 'Iq+', 'Iq-']
columnname = ['Item', 'Signal', 'Before Fault', 'During Fault', 'After Fault']
name = [filename, self.item, rowname, columnname]
data2save = pd.DataFrame(data2save)
path = savepath + filename + '.xlsx'
self._xlswriteAuto(data2save, name, path, case='VRT')
def analysis_FreqReg(self, savepath, SensitiveVaribleIndex=1, Interval=4, Delta=0.1):
"""
过欠频功率响应工况数据分析,并输出分析结果图与结果表
:param savepath: 分析结果的保存路径
threshold_L: 低穿工况判断阈值
threshold_H: 高穿工况判断阈值
SensitiveVaribleIndex: 作为判断的数据列下标
:output: 在提供的保存路径下输出高低穿分析结果
"""
Data = []
Plotoffset1 = []
Plotoffset2 = []
Tsam = []
OffsetStart = []
OffsetEnd = []
mrow = []
ncolumn = []
IndexLabel = []
Tedge = []
Tduration = []
axeX = []
data2save = []
for filename in self.Filename_list:
csv_path = self.file_dict.get(filename) + '\\' + filename
data = pd.read_csv(csv_path).values
Data.append(data)
Indexlabel, edge, duration = self._edgecheck(data[0:, SensitiveVaribleIndex] * 100, Interval, Delta)
tsam = round(data[20, 0] - data[19, 0], 4)
offsetstart = self.offset1 / tsam
offsetend = self.offset2 / tsam
Plotoffset1.append(self.offset1 / tsam)
Plotoffset2.append(self.offset2 / tsam)
Tsam.append(tsam)
OffsetEnd.append(offsetend)
offsetstart = min(duration[0], duration[-1], offsetstart)
OffsetStart.append(offsetstart)
IndexLabel.append(Indexlabel)
Tedge.append(edge)
Tduration.append(duration)
row, col = data.shape
mrow.append(row)
ncolumn.append(col)
keyword_OF = ['OF', 'of', 'overfrequency', 'OverFrequency', 'over']
keyword_UF = ['UF', 'uf', 'underfrequency', 'UnderFrequency', 'under']
if any(w in filename and w for w in keyword_OF):
Freq = self.Frequency_UP
TargetVaule = self.TargetVaule_Inc
elif any(w in filename and w for w in keyword_UF):
Freq = self.Frequency_dwn
TargetVaule = self.TargetVaule_dec
fig = plt.figure(1, [15, 10], clear=True)
ytext = ['f/Hz', 'P+/pu', 'Q+/pu', 'S/pu', 'PF']
ylimit = [[49, 52], [-0.05, 0.5], [-0.6, 0.6], [0.9, 1.25], [0.75, 1.05], [45, 55]]
legendtext = ['Test', 'PSCAD', 'PSSE']
ManualOffset = [[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]]
VaribleNum = min(ncolumn) - 1
IndexforSave = []
for i in range(Data.__len__()):
IndexPlotStart = max(int(IndexLabel[i][0][0] - OffsetStart[i]), 1)
IndexPlotEnd = min(int(IndexLabel[i][0][-1] + OffsetEnd[i] - 1), mrow[i])
if (IndexLabel[i][0][-1] < IndexPlotEnd):
FullIndexLabel1 = IndexLabel[i][0]
FullIndexLabel1.append(IndexPlotEnd)
else:
FullIndexLabel1 = IndexLabel[i][0]
if (IndexPlotStart < IndexLabel[i][1][0]):
FullIndexLabel2 = IndexLabel[i][1]
FullIndexLabel2.insert(0, IndexPlotStart)
else:
FullIndexLabel2 = IndexLabel[i][1]
IndexforSave = np.add(FullIndexLabel2, FullIndexLabel1) * 0.5
IndexforSave = [round(a) for a in IndexforSave]
axeX.append(Data[i][IndexPlotStart: IndexPlotEnd, 0] - Data[i][IndexPlotStart, 0])
save = []
for j in range(VaribleNum):
data_item = []
for k in range(IndexforSave.__len__()):
data_item.append(Data[i][IndexforSave[k], j + 1])
save.append(data_item)
axf = plt.subplot(VaribleNum, 1, j + 1)
plt.plot(axeX[i], Data[i][IndexPlotStart:IndexPlotEnd, j + 1], self.plotOption[i], linewidth=1.5,
label=legendtext[i])
plt.ylabel(ytext[j], fontdict={'size': 16})
plt.grid(axis='both', linestyle='-.')
# plt.ylim(ylimit[j])
plt.legend(loc="upper right")
data2save.append(save)
data2save[i].append(TargetVaule)
data2save[i].append(np.subtract(TargetVaule, data2save[i][1]) * 100)
Tedge[i].insert(0, 0)
data2save[i].append(np.multiply(Tedge[i], Tsam[i]))
data2save[i].append(np.multiply(Tedge[i], Tsam[i]))
plt.xlabel('t/s', fontdict={'size': 16})
# fig.show()
filename = self.Filename_list[1].replace('_PSCAD.csv', '')
fig.savefig(savepath + filename + '.jpg')
plt.close()
rowname = Freq
columnname = ['Item', 'Frequency [Hz]', 'Power Output[%]', 'Target power[%]', 'Deviation ∆P/ Pn[%]',
'Rise time Trise_90%[s]', 'Settling time Tset [s]']
name = [filename, self.item, columnname]
data2save = pd.DataFrame(data2save)
path = savepath + filename + '.xlsx'
self._xlswriteAuto(data2save, name, path, case='Freq')
def analysis_PQCtrl(self, savepath, SensitiveVaribleIndex=2, Interval=4, Delta=0.01):
"""
有功/无功功率控制响应工况数据分析,并输出分析结果图与结果表
:param savepath: 分析结果的保存路径
SensitiveVaribleIndex: 作为判断的数据列下标
Interval: 数据判断间隔
Delta: 数据判断精度
:output: 在提供的保存路径下输出工况分析结果
"""
Data = []
Tsam = []
OffsetStart = []
OffsetEnd = []
mrow = []
ncolumn = []
IndexLabel = []
Tedge = []
Tduration = []
self.offset1 = 500
self.offset2 = 2000
Plotoffset1 = []
Plotoffset2 = []
axeX = []
data2save = []
Data_Max_Value = np.ones(10) * (-np.inf)
Data_Min_Value = np.ones(10) * (np.inf)
######################################### 读取文件数据 #########################################
for filename in self.Filename_list:
csv_path = self.file_dict.get(filename) + '\\' + filename
data = pd.read_csv(csv_path).dropna().values
row, col = data.shape
for k in range(1, col):
a = np.around(np.max(data[0:, k]) + 0.05, 1)
b = np.around(np.min(data[0:, k]) - 0.05, 1)
Data_Max_Value[k - 1] = max(a, Data_Max_Value[k - 1])
Data_Min_Value[k - 1] = min(b, Data_Min_Value[k - 1])
Data.append(data)
######################################### 检测数据边沿 #########################################
for i in range(Data.__len__()):
Indexlabel, edge, duration = self._edgecheck(Data[i][0:, SensitiveVaribleIndex], Interval, Delta)
tsam = round(Data[i][20, 0] - Data[i][19, 0], 4)
Tsam.append(tsam)
offsetstart = min(duration[0], duration[-1], self.offset1 / tsam)
offsetend = self.offset2 / tsam
# Plotoffset1.append(self.offset1 / tsam)
# Plotoffset2.append(self.offset2 / tsam)
OffsetStart.append(offsetstart)
OffsetEnd.append(offsetend)
IndexLabel.append(Indexlabel)
Tedge.append(edge)
Tduration.append(duration)
row, col = Data[i].shape
mrow.append(row)
ncolumn.append(col)
if (Indexlabel[0][0] >= Indexlabel[-1][1]):
print(f'Warning: No event found at data [{i}]')
else:
pass
VaribleNum = min(ncolumn) - 1
######################################## 绘制结果图和结果表 ###########################################
ytext = ['U+/pu', 'P+/pu', 'Q+/pu', 'S/pu', 'PF']
ylimit = [[Data_Min_Value[0] - 0.05, Data_Max_Value[0] + 0.05],
[Data_Min_Value[1] - 0.1, Data_Max_Value[1] + 0.1],
[Data_Min_Value[2] - 0.1, Data_Max_Value[2] + 0.1],
[Data_Min_Value[3] - 0.1, Data_Max_Value[3] + 0.1],
[Data_Min_Value[4] - 0.1, Data_Max_Value[4] + 0.1]]
ManualOffset = [[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]]
fig = plt.figure(1, [10, 12])
for i in range(Data.__len__()):
IndexPlotStart = max(int(IndexLabel[i][0][0] - OffsetStart[i]), 1)
IndexPlotEnd = min(int(IndexLabel[i][0][-1] + OffsetEnd[i] - 1), mrow[i])
if (IndexLabel[i][0][-1] < IndexPlotEnd):
FullIndexLabel1 = IndexLabel[i][0]
FullIndexLabel1.append(IndexPlotEnd)
else:
FullIndexLabel1 = IndexLabel[i][0]
if (IndexPlotStart < IndexLabel[i][1][0]):
FullIndexLabel2 = IndexLabel[i][1]
FullIndexLabel2.insert(0, IndexPlotStart)
else:
FullIndexLabel2 = IndexLabel[i][1]
IndexforSave = np.round(np.add(FullIndexLabel2, FullIndexLabel1) * 0.5).astype(np.int64)
axeX.append(Data[i][IndexPlotStart: IndexPlotEnd, 0] - Data[i][IndexPlotStart, 0])
save = []
for j in range(VaribleNum):
data_item = []
for k in range(IndexforSave.__len__()):
data_item.append(Data[i][IndexforSave[k], j + 1])
save.append(data_item)
axf = plt.subplot(VaribleNum, 1, j + 1)
plt.plot(axeX[i] + ManualOffset[i][j], Data[i][IndexPlotStart:IndexPlotEnd, j + 1],
self.plotOption[i],
linewidth=2,
label=self.item[i])
plt.ylabel(ytext[j], fontdict={'size': 16})
plt.margins(x=0)
plt.ylim(ylimit[j])
plt.grid(axis='both', linestyle='-.')
plt.legend(loc="upper right")
data2save.append(np.array(save).T.tolist())
plt.xlabel('t/s', fontdict={'size': 16})
plt.show()
filename = self.Filename_list[1].replace('_PSCAD.csv', '')
fig.savefig(savepath + filename + '.png')
plt.close()
rowname = ['10%', '20%', '30%', '40%', '50%', '60%', '70%', '80%', '90%', '100%', '110%', '120%']
columnname = ['Item', 'Pset', 'U[pu]', 'Active Power[pu]', 'Reactive Power[pu]', 'Apparent Power[pu]', 'Factor']
name = [filename, self.item, rowname, columnname]
data2save = pd.DataFrame(data2save)
path = savepath + filename + '.xlsx'
self._xlswriteAuto(data2save, name, path, case='PQCtrl')
def VRTdatacheck(self, path, Threshold_L=0.98, Threshold_H=1.02,
SensitiveVaribleIndex=1, LVRTK1=1.0, HVRTK1=1.0, LVRT_IP=0.5, HVRT_IP=1.0, offset=0.05):
Data = []
Indexlabel = []
Error = []
for filename in self.Filename_list:
csv_path = self.file_dict.get(filename) + '\\' + filename
data = pd.read_csv(csv_path).values
Data.append(data)
PosVoltMIndexLess09 = self._rangecheck(data[0:, SensitiveVaribleIndex], '<', Threshold_L, 0.01)
PosVoltMIndexMore11 = self._rangecheck(data[0:, SensitiveVaribleIndex], '>', Threshold_H, 0.01)
LVRTduration = PosVoltMIndexLess09[1] - PosVoltMIndexLess09[0]
HVRTduration = PosVoltMIndexMore11[1] - PosVoltMIndexMore11[0]
tsam = round(data[20, 0] - data[19, 0], 4)
tduration = 0.05 / tsam
tstableoffset = int(0.5 / tsam)
if ((HVRTduration > tduration) and (LVRTduration > tduration)):
LHVRT = 3
Indexlabel.append(PosVoltMIndexLess09)
Indexlabel.append(PosVoltMIndexMore11)
elif (HVRTduration > tduration):
if (PosVoltMIndexMore11[0] > tstableoffset):
LHVRT = 2
Indexlabel.append(PosVoltMIndexMore11)
else:
print('Data is not enough before fault')
LHVRT = 0
elif (LVRTduration > tduration):
if (PosVoltMIndexLess09[0] > tstableoffset):
LHVRT = 1
Indexlabel.append(PosVoltMIndexLess09)
else:
print('Data is not enough before fault')
LHVRT = 0
else:
LHVRT = 0
for i in range(Data.__len__()):
IndexPlotStart = Indexlabel[i][0]
IndexPlotEnd = Indexlabel[i][1]
U_Pos = Data[i][int((IndexPlotStart + IndexPlotEnd) / 2), 1]
P_Pos = Data[i][int((IndexPlotStart + IndexPlotEnd) / 2), 2]
Q_Pos = Data[i][int((IndexPlotStart + IndexPlotEnd) / 2), 3]
Id_Pos = Data[i][int((IndexPlotStart + IndexPlotEnd) / 2), 4]
Iq_Pos = Data[i][int((IndexPlotStart + IndexPlotEnd) / 2), 5]
if U_Pos - 1 < 0:
VRT = 1
U_StartPoint = 1
Iq_Ref = (U_StartPoint - U_Pos) * LVRTK1
else:
VRT = 0
U_StartPoint = 1
Iq_Ref = (U_StartPoint - U_Pos) * HVRTK1
Iq_Ref = min(Iq_Ref, 1.05)
Id_Limit = math.sqrt(1.2 * 1.2 - Iq_Ref * Iq_Ref)
if VRT == 1:
Id_Ref = min(((Data[i][int((IndexPlotStart + 1) / 2), 4]) * LVRT_IP, Id_Limit))
else:
Id_Ref = min((((Data[i][int((IndexPlotStart + 1) / 2), 4]) / U_Pos) * HVRT_IP, Id_Limit))
P_Ref = Id_Ref * U_Pos
Q_Ref = Iq_Ref * U_Pos
if ((U_Pos < 0.9) or (U_Pos > 1.1)) \
and ((abs(Iq_Ref - Iq_Pos) > offset)
or (abs(Id_Ref - Id_Pos) > offset) or (abs(P_Ref - P_Pos) > offset) or (
abs(Q_Ref - Q_Pos) > offset)):
Error.append(self.Filename_list[i])
f = open(path + 'check.txt', mode='a')
for er in Error:
f.write(er + '\n')
f.close()
def file_search(self, filepath):
file_table = [".csv", ".mat", ".txt", "xlsx"]
# 存放所有文件名
file_list = []
# 存放每个子文件夹下所对应的文件名
# file_dict = {}
for iroot, idirs, ifiles in os.walk(filepath):
if ifiles:
iFiles = []
for File in ifiles:
for format_name in file_table:
ifiles_search = re.search(format_name, File)
if ifiles_search:
file_list.append(File)
iFiles.append(File)
self.file_dict[File] = iroot
else:
pass
# 定义三个分组类别
# self.File_TEST = []
# self.File_PSCAD = []
# self.File_PSSE = []
File_name = ['RTLAB', 'ADPSS', 'PSSE']
# File_name = ['TEST', 'PSCAD', 'PSSE']
for File in file_list:
TEST_search = re.search(File_name[0], File)
PSCAD_search = re.search(File_name[1], File)
PSSE_search = re.search(File_name[2], File)
if TEST_search:
self.File_TEST.append(File)
elif PSCAD_search:
self.File_PSCAD.append(File)
elif PSSE_search:
self.File_PSSE.append(File)
else:
pass
self.File_TEST = sorted(self.File_TEST)
self.File_PSSE = sorted(self.File_PSSE)
self.File_PSCAD = sorted(self.File_PSCAD)
# return self.File_TEST, self.File_PSSE, self.File_PSCAD
def _rangecheck(self, Signal, LO, Threshold, Delta):
"""
高低穿工况数据范围检测
:param Signal: 要检测的工况数据
LO: 检测类型 —— '>'为高穿范围检测;'<'为低穿范围检测
Threshold: 高低穿阈值
Delta: 检测精度
:return Index: 高低穿起始和终止下标
"""
Index = []
if LO == '>':
SignalMeetFlag = Signal > Threshold
IndexMeet = np.where(SignalMeetFlag == 1)[0]
if IndexMeet.any():
SignalMeetFlag[IndexMeet[0]: IndexMeet[-1]] = SignalMeetFlag[IndexMeet[0]: IndexMeet[-1]] \
| (Signal[IndexMeet[0]:IndexMeet[-1]] > Threshold - Delta)
elif LO == '<':
SignalMeetFlag = Signal < Threshold
IndexMeet = np.where(SignalMeetFlag == 1)[0]
if IndexMeet.any():
SignalMeetFlag[IndexMeet[0]: IndexMeet[-1]] = SignalMeetFlag[IndexMeet[0]: IndexMeet[-1]] \
| (Signal[IndexMeet[0]:IndexMeet[-1]] < Threshold + Delta)
else:
SignalMeetFlag = []
print('Err logical symbol')
SignalMeetFlag = np.insert(SignalMeetFlag, 0, False)
SignalMeetFlag = np.append(SignalMeetFlag, False)
IndexDisMeet = np.where(SignalMeetFlag == 0)[0]
if IndexDisMeet.any():
MeetNum = np.diff(IndexDisMeet)
IndexNum = np.where(MeetNum == max(MeetNum))[0]
Index.append(IndexDisMeet[IndexNum][0] + 1)
Index.append(IndexDisMeet[IndexNum + 1][0] - 1)
else:
pass
return Index
def _get_cloumn_max_or_min(self, data):
row, col = data.shape
for k in range(1, col):
max = np.max(data[0:, k])
min = np.min(data[0:, k])
return max, min
def _edgecheck(self, Signal, Interval, Delta):
"""
数据边沿检测
:param Signal: 要检测的工况数据
Interval: 数据判断间隔
Delta: 数据判断精度
:return Index: 高低穿起始和终止下标
"""
Index = []
Indextemp1 = []
Indextemp2 = []
Tedge = []
Tduration = []
row = Signal.shape
Sdiff = abs(Signal[Interval - 1:, ] - Signal[0:-1 - Interval + 2, ])
SignalFlag = Sdiff > Delta
SignalFlag = np.insert(SignalFlag, 0, False)
SignalFlag = np.append(SignalFlag, False)
IndexFlag = np.where(SignalFlag == 1)[0]
IndexEdge = np.diff(IndexFlag)
IndexLabel = np.where(IndexEdge > 100)[0]
Indextemp1.append(IndexFlag[0])
for i in IndexLabel:
Indextemp1.append(IndexFlag[i + 1])
Indextemp2.append(IndexFlag[i])
Indextemp2.append(IndexFlag[-1])
Index.append(Indextemp1)
Index.append(Indextemp2)
for j in range(Indextemp1.__len__()):
edge = Indextemp2[j] - Indextemp1[j]
Tedge.append(edge)
Tduration.append(IndexFlag[0])
for k in range(Indextemp1.__len__() - 1):
duration = Indextemp1[k + 1] - Indextemp2[k]
Tduration.append(duration)
duration_end = int(row - Indextemp2[-1])
Tduration.append(duration_end)
return Index, Tedge, Tduration
def _xlswriteAuto(self, data, name, path, case):
"""
根据传入的数据绘制Excel表格
:param data: 要保存的数据值
name: 表头、行列项名
path: Excel表保存路径
case: 要保存的工况类型 —— 'VRT'、'disturb'
:output: 输出对应的Excel表
"""
mrow, ncol = data.shape
event = len(data.values[0][0])
LeftC = 0
LeftN = 0
wb = xlsxwriter.Workbook(path)
worksheet = wb.add_worksheet()
# 边框 加粗 背景色
format_top = wb.add_format({'border': 1, 'bold': True, 'text_wrap': True, 'bg_color': '#d3d3d3'})
# 上下、左右居中
format_other = wb.add_format(
{'border': 1, 'text_h_align': 2, 'text_v_align': 2, 'font_name': 'Arial Narrow', 'font_size': 11,
'num_format': '0.0000'})
format_color = wb.add_format(
{'border': 1, 'text_h_align': 2, 'text_v_align': 2, 'bg_color': '#d3d3d3', 'font_name': 'Arial Narrow'})
# 表头
if case == 'VRT':
worksheet.merge_range(LeftN, LeftC, LeftN, LeftC + event + 1, name[0], format_color)
worksheet.write_row(LeftN + 1, LeftC, name[-1], format_color)
for i in range(mrow):
worksheet.merge_range(LeftN + i * ncol + 2, LeftC, LeftN + ncol + i * ncol + 1, LeftC, name[1][i],
format_color)
for j in range(ncol):
worksheet.write(LeftN + i * ncol + j + 2, LeftC + 1, name[2][j], format_color)
worksheet.write_row(LeftN + i * ncol + j + 2, LeftC + 2, data.values[i][j], format_other)
elif case == 'PQCtrl':
worksheet.merge_range(LeftN, LeftC, LeftN, LeftC + event + 1, name[0], format_color)
worksheet.write_row(LeftN + 1, LeftC, name[-1], format_color)
for i in range(mrow):
worksheet.merge_range(LeftN + i * ncol + 2, LeftC, LeftN + ncol + i * ncol + 1, LeftC, name[1][i],
format_color)
for j in range(ncol):
worksheet.write(LeftN + i * ncol + j + 2, LeftC + 1, name[2][j], format_color)
worksheet.write_row(LeftN + i * ncol + j + 2, LeftC + 2, data.values[i][j], format_other)
elif case == 'Disturb':
worksheet.merge_range(LeftN, LeftC, LeftN, LeftC + event, name[0], format_color)
worksheet.write_row(LeftN + 1, LeftC, name[-1], format_color)
for i in range(mrow):
worksheet.write(LeftN + i * ncol + 2, LeftC, name[1][i], format_color)
for j in range(ncol):
worksheet.write_row(LeftN + i * ncol + j + 2, LeftC + 1, data.values[i][j], format_other)
else:
worksheet.merge_range(LeftN, LeftC, LeftN, LeftC + ncol, name[0], format_color)
worksheet.write_row(LeftN + 1, LeftC, name[-1], format_color)
for i in range(mrow):
worksheet.merge_range(LeftN + i * event + 2, LeftC, LeftN + event + i * event + 1, LeftC, name[1][i],
format_color)
for j in range(ncol):
worksheet.write_column(LeftN + i * event + 2, LeftC + j + 1, data.values[i][j], format_other)
wb.close()
def ensure_folder_exists(self, folder_path):
"""
确保指定文件夹存在,不存在则创建
:param folder_path: 要检查/创建的文件夹路径
:return: 是否成功创建(布尔值)
"""
if not os.path.exists(folder_path):
try:
os.makedirs(folder_path)
print(f"成功创建文件夹: {folder_path}")
return True
except Exception as e:
print(f"创建文件夹失败: {e}", file=sys.stderr)
return False
else:
print(f"文件夹已存在: {folder_path}")
return True
代码解释
最新发布