Compare commits

...

10 Commits

Author SHA1 Message Date
Andrew
1a36aa217b dev: добавлена строка эффективности + добавлено сохранение UML в директорию 2024-11-13 12:35:00 +03:00
Andrew
7c09dde2d1 fix: окна настроек теперь отображаются корректно и обновляют все графики 2024-11-13 11:13:31 +03:00
Andrew
844aa4a78a fix: создание новой вкладки для MainWindow при появлении CSV файла теперь работает 2024-11-13 10:22:53 +03:00
Andrew
8f5a65405d dev: (не работает) добавлено открытие csv из папки 2024-11-12 19:26:38 +03:00
Andrew
ab56316930 dev: конец II идеального этапа совмещен с реальным 2024-11-12 18:23:22 +03:00
Andrew
2a7e8d641f fix: исправлена генегация V этапа в UML + добавлен допуск для II и II этапов в графиках 2024-11-12 17:45:25 +03:00
Andrew
8ad4fdd355 def: добавлена возможность отрисовывать несколько точек подряд 2024-11-12 16:52:40 +03:00
Andrew
b6b7de2fcb chore: без укакзания csv запускается в режиме демонстрации идеальных данных 2024-11-12 14:34:07 +03:00
Andrew
0587ca1a06 chore: переработана инициализация классов PlotWindow и UMLCreator 2024-11-12 13:46:36 +03:00
Andrew
40af0afda8 dev: начало этапа идеального графика совмещено с этапом в реальном 2024-11-12 13:26:16 +03:00
19 changed files with 481 additions and 3064 deletions

View File

@ -1,16 +1,16 @@
{
"dist_open_start_1" : 0.005,
"dist_open_start_2" : 0.005,
"dist_open_after_1" : 0.006,
"dist_open_after_2" : 0.006,
"dist_open_end_1" : 0.010,
"dist_open_end_2" : 0.050,
"dist_close_end_1" : 0.005,
"dist_close_end_2" : 0.005,
"time_wielding" : 1,
"time_command" : 0.060,
"time_robot_movement" : 0.2,
"object_thickness" : 4.5e-3,
"force_target" : 5000,
"force_capture" : 500
"dist_open_start_1": 0.005,
"dist_open_start_2": 0.005,
"dist_open_after_1": 0.006,
"dist_open_after_2": 0.006,
"dist_open_end_1": 0.01,
"dist_open_end_2": 0.05,
"dist_close_end_1": 0.005,
"dist_close_end_2": 0.005,
"time_wielding": 1,
"time_command": 0.06,
"time_robot_movement": 0.2,
"object_thickness": 0.0045,
"force_target": 5000,
"force_capture": 500
}

View File

@ -15,5 +15,9 @@
"position_start_2": 0.08,
"k_prop": 0.05,
"time_capture": 100000,
"UML_time_scaler": 1000
}
"UML_time_scaler": 1000,
"Closure_signal": "Closing",
"Squeeze_signal": "Squeeze",
"Welding_signal": "Welding",
"Release_signal": "Relief"
}

Binary file not shown.

View File

@ -1,3 +1,3 @@
from .plot_window import PlotWindow
from .plot_window import Plotter
from .settings_window import settingsWindow
from .app import app
from .app import tabWidgetGenerator

View File

@ -3,77 +3,74 @@ import pyqtgraph as pg
from src.utils import read_json, DiagramParser
from src.uml import Request, UMLCreator
from src.OptAlgorithm import OptAlgorithm
from src.gui import PlotWindow, settingsWindow
from src.gui import Plotter, settingsWindow
class app:
def __init__(self):
self.parser = DiagramParser()
self.request_generator = Request(server_url='http://www.plantuml.com/plantuml/svg/')
self.operSettings = settingsWindow("params\operator_params.json", 'Operator', self._update_settings)
self.sysSettings = settingsWindow("params\system_params.json", 'System', self._update_settings)
self._load_preset()
def _get_ideal_timings(self, opt: OptAlgorithm) -> list[float]:
data = opt.Ts
ideal_time = [data['tclose'], data['tgrow'], opt.getMarkOpen()]
return ideal_time
def _load_preset(self):
class tabWidgetGenerator:
def __init__(self, directory_to_save):
self.UMLgenerator = Request(server_url='http://www.plantuml.com/plantuml/svg/')
self.uml_creator = UMLCreator(request_generator=self.UMLgenerator, path_to_save=directory_to_save)
self.operator_params = read_json("params/operator_params.json")
self.system_params = read_json("params/system_params.json")
self.operSettings = settingsWindow("params\operator_params.json", 'Operator', self._update)
self.sysSettings = settingsWindow("params\system_params.json", 'System', self._update)
self.opt_algorithm = OptAlgorithm(operator_config=self.operator_params, system_config=self.system_params)
self.ideal_times = self._get_ideal_timings(self.opt_algorithm)
self.paths = []
self.plotters = []
self.bool_dicts = []
self.float_dicts = []
self.timings_dicts = []
self.modes = []
self.names = []
self.parser.setData("trace_samples/2024_11_08-19_30_49.csv")
self.bool_dict = self.parser.getBoolDict()
self.float_dict = self.parser.getFloatDict()
def get_widget(self, path):
self.paths.append(path)
self.plotters.append(Plotter(show_settings_func=self._show_settings))
self._getParsedData(path)
self._update()
return self.plotters[-1].widget
def _get_ideal_timings(self, opt: OptAlgorithm) -> list[float]:
data = opt.Ts
ideal_time = [data['tclose'], data['tgrow'], opt.getMarkOpen(), data["tmovement"]]
return ideal_time
self.plotter = PlotWindow(operator_config=self.operator_params,
system_config=self.system_params,
opt=self.opt_algorithm,
bool_dict=self.bool_dict,
float_dict=self.float_dict,
show_settings_func=self._show_settings)
self.uml_creator = UMLCreator(operator_config=self.operator_params,
system_config=self.system_params,
request_generator=self.request_generator,
ideal_time=self.ideal_times,
bool_dict=self.bool_dict,
float_dict=self.float_dict)
self.uml_creator.update_uml(operator_config=self.operator_params,
system_config=self.system_params,
request_generator=self.request_generator,
ideal_time=self.ideal_times,
bool_dict=self.bool_dict,
float_dict=self.float_dict)
def _getParsedData(self, path):
self.names.append(path)
parser = DiagramParser(system_config=self.system_params)
parser.setData(path)
self.bool_dicts.append(parser.getBoolDict())
self.float_dicts.append(parser.getFloatDict())
self.timings_dicts.append(parser.getRealTimings())
self.modes.append(parser.getMode())
def _update_settings(self, _):
def _update(self, _ = None):
self.operator_params = self.operSettings.getParams()
self.system_params = self.sysSettings.getParams()
self.opt_algorithm = OptAlgorithm(operator_config=self.operator_params, system_config=self.system_params)
self.ideal_times = self._get_ideal_timings(self.opt_algorithm)
self.uml_creator.update_uml(system_config=self.system_params,
request_generator=self.request_generator,
ideal_time=self.ideal_times,
bool_dict=self.bool_dict,
float_dict=self.float_dict)
opt_algorithm = OptAlgorithm(operator_config=self.operator_params, system_config=self.system_params)
ideal_times = self._get_ideal_timings(opt_algorithm)
self.plotter.update_data(operator_config=self.operator_params,
for i in range (len(self.plotters)):
self.plotters[i].update_data(operator_config=self.operator_params,
system_config=self.system_params,
opt=self.opt_algorithm,
bool_dict=self.bool_dict,
float_dict=self.float_dict)
opt=opt_algorithm,
bool_dict=self.bool_dicts[i],
ideal_time=ideal_times,
float_dict=self.float_dicts[i],
mode = self.modes[i],
timings_dict=self.timings_dicts[i])
self.uml_creator.update_uml(operator_config=self.operator_params,
system_config=self.system_params,
ideal_time=ideal_times,
bool_dict=self.bool_dicts[i],
float_dict=self.float_dicts[i],
mode = self.modes[i],
timings_dict=self.timings_dicts[i],
name = self.names[i])
def _show_settings(self):
self.operSettings.show()
@ -82,5 +79,7 @@ class app:
if __name__ == '__main__':
pg.mkQApp("Plotting")
temp = app()
temp = tabWidgetGenerator()
widget = temp.get_widget("trace_samples/2024_11_08-19_30_49.csv")
widget.show()
pg.exec()

View File

@ -1,5 +1,6 @@
import pyqtgraph as pg
from pyqtgraph.Qt import QtWidgets
from PyQt5.QtCore import Qt
import numpy as np
from src.gui import qt_settings as qts
@ -7,22 +8,10 @@ from src.gui import qt_settings as qts
from src.OptAlgorithm import OptAlgorithm
class PlotWindow:
def __init__(self,
system_config : dict,
operator_config: dict,
opt: OptAlgorithm,
bool_dict: dict,
float_dict: dict, show_settings_func):
class Plotter:
def __init__(self, show_settings_func):
pg.setConfigOptions(antialias=True)
self.opt = opt
self.bool_dict = bool_dict
self.float_dict = float_dict
self.scaler = int(system_config['UML_time_scaler'])
self.WeldTime = operator_config['time_wielding'] #[sec]
self.alpha = 100 #[0-255 прозрачность фона]
self._getIdealTimings()
self._init_ui()
self.settings_button.clicked.connect(show_settings_func)
@ -31,15 +20,22 @@ class PlotWindow:
system_config : dict,
operator_config: dict,
opt: OptAlgorithm,
ideal_time: list[float],
bool_dict: dict,
float_dict: dict):
float_dict: dict,
timings_dict: dict,
mode: bool):
self.opt = opt
self.bool_dict = bool_dict
self.float_dict = float_dict
self.timings_dict = timings_dict
self.idealTime = ideal_time
self.theor_mode = mode
self.scaler = int(system_config['UML_time_scaler'])
self.WeldTime = operator_config['time_wielding'] #[sec]
self._getIdealTimings()
self.WeldData = self.opt.calcPhaseGrow(self.idealTime[1])
self._updatePlots()
def _init_ui(self):
self.widget = QtWidgets.QWidget()
@ -53,7 +49,15 @@ class PlotWindow:
layout.addWidget(self.win)
self.settings_button = QtWidgets.QPushButton("Show settings")
self.settings_button.setFixedWidth(160)
layout.addWidget(self.settings_button)
info_layout = QtWidgets.QHBoxLayout()
layout.addLayout(info_layout)
info_layout.addWidget(self.settings_button, alignment = Qt.AlignLeft)
info_layout.setSpacing(20)
self.efficiency = QtWidgets.QLabel()
info_layout.addWidget(self.efficiency, alignment = Qt.AlignRight)
self.p11, self.l11 = self._init_graph('Electrode force, closure', 'Force', 'N', 'Time', 'ms')
#self.p21, _ = self._init_graph('Electrode force, compression', 'Force', 'N', 'Time', 'ms')
@ -74,9 +78,7 @@ class PlotWindow:
self.p11.setAutoVisible(x=False, y=True)
self.p12.setAutoVisible(x=False, y=True)
self.p13.setAutoVisible(x=False, y=True)
self._updatePlots()
self.widget.setStyleSheet(qts.dark_style)
self.widget.show()
def _init_graph(self, title, Yname, Yunits, Xname, Xunits):
plot = self.win.addPlot(title = title)
@ -95,40 +97,125 @@ class PlotWindow:
self.p13.clear()
self.l13.clear()
self._plotRealData()
times = np.arange(20000)/10
self._plotIdealData(times)
if not self.theor_mode:
self._plotRealData()
self._form_idealdatGraph()
self._calcOurScore()
def _calcOurScore (self):
success = []
start = np.array(self.timings_dict["closure"])[:, 0]
end = np.array(self.timings_dict["opening"])[:, 1]
points_timings = end-start
ideal_time = sum(self.idealTime[:3])+self.WeldTime
for point in points_timings:
success.append(int(ideal_time/point * 100))
if len(success) > 1:
maxS = max(success)
minS = min(success)
average = int(sum(success[:])/len(success))
self.efficiency.setText(f'Efficiency Maximum: {maxS}%, Average: {average}%, Minimum: {minS}%' )
else:
self.efficiency.setText(f'Efficiency Maximum: {success[0]}' )
self.efficiency.setStyleSheet(qts.BigSuccessLabel)
def _form_idealdatGraph(self):
if self.theor_mode:
self.timings_dict["closure"] = [[0, self.idealTime[0]]]
self.timings_dict["compression"] = [[self.idealTime[0], sum(self.idealTime[:2])]]
self.timings_dict["welding"] = [[sum(self.idealTime[:2]), sum(self.idealTime[:2])+self.WeldTime]]
self.timings_dict["opening"] = [[sum(self.idealTime[:2])+self.WeldTime, sum(self.idealTime[:3])+self.WeldTime]]
delta = 10 #points_per_ms
for key, items in self.timings_dict.items():
for item in items:
item_data = []
time_data = []
if key == 'closure':
ideal_time = self.idealTime[0]
calc = self.opt.calcPhaseClose
color = qts.RGBA[0]
for i in range(0, int(ideal_time*self.scaler)*delta):
time = i/delta
item_data.append(calc(time/self.scaler))
time_data.append(time+item[0]*self.scaler)
#print (item_data[-1], time_data[-1])
self._plotIdealData(np.array(time_data), np.array(item_data).T)
self._addBackgroundSplitter([item[0]*self.scaler,item[0]*self.scaler + time], color)
elif key == 'compression':
ideal_time = self.idealTime[1]
calc = self.opt.calcPhaseGrow
color = qts.RGBA[1]
for i in range(int(ideal_time*self.scaler)*delta, 0, -1):
time = i/delta
item_data.append(calc(time/self.scaler))
time_data.append(item[1]*self.scaler-(ideal_time*self.scaler-time))
#print (item_data[-1], time_data[-1])
self._plotIdealData(np.array(time_data), np.array(item_data).T)
self._addBackgroundSplitter([(item[1]-ideal_time)*self.scaler, item[1]*self.scaler], color)
temp = item_data[0][4]
x = [time_data[0], time_data[-1], time_data[-1]-0.0001]
y = [temp, temp, temp]
a1, b1, c1 = self._calculate_equidistant(x, y, 2.5, 3)
self.p11.addItem(a1)
self.p11.addItem(b1)
self.p11.addItem(c1)
elif key == 'welding':
ideal_time = self.WeldTime
calc = self._returnWeldData
color = qts.RGBA[2]
for i in range(0, int(ideal_time*self.scaler)*delta):
time = i/delta
item_data.append(calc(time/self.scaler))
time_data.append(time+item[0]*self.scaler)
#print (item_data[-1], time_data[-1])
self._plotIdealData(np.array(time_data), np.array(item_data).T)
self._addBackgroundSplitter([item[0]*self.scaler,item[0]*self.scaler + time], color)
x = [time_data[0], time_data[-1], time_data[-1]+0.0001]
y = [item_data[0][4], item_data[0][4], item_data[0][4]]
a1, b1, c1 = self._calculate_equidistant(x, y, 0.75, 3)
self.p11.addItem(a1)
self.p11.addItem(b1)
self.p11.addItem(c1)
elif key == 'opening':
calc = self.opt.calcPhaseOpen
ideal_time = self.idealTime[2]
ideal_closure = self.idealTime[3]
color = qts.RGBA[3]
color_closure = qts.RGBA[4]
for i in range(0, int(ideal_time*self.scaler)*delta):
time = i/delta
item_data.append(calc(time/self.scaler))
time_data.append(time+item[0]*self.scaler)
#print (item_data[-1], time_data[-1])
self._plotIdealData(np.array(time_data), np.array(item_data).T)
self._addBackgroundSplitter([item[0]*self.scaler,item[0]*self.scaler + time], color)
item_data = []
time_data = []
for i in range(0, int(ideal_closure*self.scaler)*delta):
time = i/delta
item_data.append(self.opt.calcPhaseMovement(time/self.scaler))
time_data.append(time+item[1]*self.scaler)
self._plotIdealData(np.array(time_data), np.array(item_data).T)
self._addBackgroundSplitter([item[1]*self.scaler,item[1]*self.scaler + time], color_closure)
def _returnWeldData(self, _):
return self.WeldData
def _getIdealTimings(self):
data = self.opt.Ts
self.idealTime = [data['tclose'], data['tgrow'], self.opt.getMarkOpen(), data["tmovement"]]
def _form_idealdatGraph(self, times):
self.idealPhase0 = (self.idealTime[0])*self.scaler #Подъезд
self.idealPhase1 = (self.idealTime[0]+ self.idealTime[1])*self.scaler #Сжатие
self.idealPhase2 = (self.idealTime[0]+ self.idealTime[1] + self.WeldTime)*self.scaler #Сварка
self.idealPhase3 = (self.idealTime[0]+ self.idealTime[1] + self.idealTime[2] + self.WeldTime)*self.scaler #Разъезд
self.idealPhase4 = (sum(self.idealTime[:4]) + self.WeldTime)*self.scaler #Последнее смыкание #TODO добавить идеальное время вместо 0.25
self.x_splitter = np.array([[0, self.idealPhase0],
[self.idealPhase0, self.idealPhase1],
[self.idealPhase1, self.idealPhase2],
[self.idealPhase2, self.idealPhase3],
[self.idealPhase3, self.idealPhase4]])
data = []
for time in times:
if time <= self.idealPhase0:
x_fe, x_me, v_fe, v_me, f = self.opt.calcPhaseClose(time/self.scaler)
elif time <= self.idealPhase1:
x_fe, x_me, v_fe, v_me, f = self.opt.calcPhaseGrow(time/self.scaler-self.idealTime[0])
elif time <= self.idealPhase2:
x_fe, x_me, v_fe, v_me, f = data[-1]
elif time <= self.idealPhase3:
x_fe, x_me, v_fe, v_me, f = self.opt.calcPhaseOpen(time/self.scaler-self.idealTime[0]-self.idealTime[1]-self.WeldTime)
else:
x_fe, x_me, v_fe, v_me, f = self.opt.calcPhaseMovement(time/self.scaler-sum(self.idealTime[:3])-self.WeldTime)
data.append([x_fe, x_me, v_fe, v_me, f])
data = np.array(data).T
return data
def _plotRealData(self):
for i, (key, dat) in enumerate(self.float_dict.items()):
@ -146,62 +233,46 @@ class PlotWindow:
self.l13.addItem(curve, key)
return dat[0]
def _plotIdealData(self, times):
data = self._form_idealdatGraph(times)
x_fe = pg.PlotDataItem(times, data[0]*1000, pen=pg.mkPen(color=qts.colors[8], width=2), name='x_fe', autoDownsample=True, downsample=True)
x_me = pg.PlotDataItem(times, data[1]*1000, pen=pg.mkPen(color=qts.colors[9], width=2), name='x_me', autoDownsample=True, downsample=True)
v_fe = pg.PlotDataItem(times, data[2]*1000, pen=pg.mkPen(color=qts.colors[8], width=2), name='v_fe', autoDownsample=True, downsample=True)
v_me = pg.PlotDataItem(times, data[3]*1000, pen=pg.mkPen(color=qts.colors[9], width=2), name='v_me', autoDownsample=True, downsample=True)
f = pg.PlotDataItem(times, data[4], pen=pg.mkPen(color=qts.colors[8], width=2), name='f', autoDownsample=True, downsample=True)
def _plotIdealData(self, time, data):
x_fe = pg.PlotDataItem(time, data[0]*1000, pen=pg.mkPen(color=qts.colors[8], width=2), name='x_fe', autoDownsample=True, downsample=True)
x_me = pg.PlotDataItem(time, data[1]*1000, pen=pg.mkPen(color=qts.colors[9], width=2), name='x_me', autoDownsample=True, downsample=True)
v_fe = pg.PlotDataItem(time, data[2]*1000, pen=pg.mkPen(color=qts.colors[8], width=2), name='v_fe', autoDownsample=True, downsample=True)
v_me = pg.PlotDataItem(time, data[3]*1000, pen=pg.mkPen(color=qts.colors[9], width=2), name='v_me', autoDownsample=True, downsample=True)
f = pg.PlotDataItem(time, data[4], pen=pg.mkPen(color=qts.colors[8], width=2), name='f', autoDownsample=True, downsample=True)
self.p11.addItem(f)
self.l11.addItem(f, 'Ideal force')
#self.l11.addItem(f, 'Ideal force')
self.p12.addItem(x_fe)
self.l12.addItem(x_fe, 'FE POS')
#self.l12.addItem(x_fe, 'FE POS')
self.p12.addItem(x_me)
self.l12.addItem(x_me, 'ME POS')
#self.l12.addItem(x_me, 'ME POS')
self.p13.addItem(v_fe)
self.l13.addItem(v_fe, 'FE VEL')
#self.l13.addItem(v_fe, 'FE VEL')
self.p13.addItem(v_me)
self.l13.addItem(v_me, 'ME VEL')
self._addBackgroundSplitter()
self._addEquidistances(times, data)
#self.l13.addItem(v_me, 'ME VEL')
#self._addBackgroundSplitter()
#self._addEquidistances(time, data)
def _addBackgroundSplitter(self):
def _addBackgroundSplitter(self, x, color):
alpha = self.alpha
y01 = np.array([10000, 10000])
y0_1 = np.array([-10000, -10000])
for i, _ in enumerate(self.x_splitter):
a01 = pg.PlotDataItem(_, y01, pen=pg.mkPen(color=qts.colors[8], width=2), name=' ')
a0_1 = pg.PlotDataItem(_, y0_1, pen=pg.mkPen(color=qts.colors[8], width=2), name=' ')
bg1 = pg.FillBetweenItem(a01, a0_1, qts.RGBA[i]+(alpha,))
bg2 = pg.FillBetweenItem(a01, a0_1, qts.RGBA[i]+(alpha,))
bg3 = pg.FillBetweenItem(a01, a0_1, qts.RGBA[i]+(alpha,))
self.p11.addItem(bg1)
self.p12.addItem(bg2)
self.p13.addItem(bg3)
a01 = pg.PlotDataItem(x, y01, pen=pg.mkPen(color=qts.colors[8], width=2), name=' ')
a0_1 = pg.PlotDataItem(x, y0_1, pen=pg.mkPen(color=qts.colors[8], width=2), name=' ')
bg1 = pg.FillBetweenItem(a01, a0_1, color+(alpha,))
bg2 = pg.FillBetweenItem(a01, a0_1, color+(alpha,))
bg3 = pg.FillBetweenItem(a01, a0_1, color+(alpha,))
self.p11.addItem(bg1)
self.p12.addItem(bg2)
self.p13.addItem(bg3)
self.p11.setYRange(-1000, 5000)
self.p12.setYRange(-50, 250)
self.p13.setYRange(-400, 400)
def _addEquidistances(self, times, data):
a1, b1, c1 = self._calculate_equidistant('fill', max(data[4]), 2.5, self.x_splitter[1], 3)
self.p11.addItem(a1)
self.p11.addItem(b1)
self.p11.addItem(c1)
a1, b1, c1 = self._calculate_equidistant(times, data[4], 0.75, self.x_splitter[2], 3)
self.p11.addItem(a1)
self.p11.addItem(b1)
self.p11.addItem(c1)
def _makeFiller(self, x1, y1, x2, y2, color):
alpha = self.alpha
eq1 = pg.PlotDataItem(x1, y1, pen=pg.mkPen(color='#000000', width=1))
@ -210,11 +281,7 @@ class PlotWindow:
return eq1, eq2, bg
def _calculate_equidistant(self, x, y, percent, splitter, color):
if str(x) == 'fill':
x = [splitter[0]+0.001, splitter[0]+0.002, splitter[1]-0.002, splitter[1]-0.001]
y = [y, y, y, y]
def _calculate_equidistant(self, x, y, percent, color):
if len(x) != len(y):
raise ValueError("x и y должны быть одного размера")
distance = max(y)/100*percent
@ -224,19 +291,17 @@ class PlotWindow:
y_eq2 = []
for i in range(0, len(x) - 1):
if splitter[0]<= x[i] and x[i] <= splitter[1]:
dx = x[i + 1] - x[i]
dy = y[i + 1] - y[i]
length = np.sqrt(dx ** 2 + dy ** 2)
sinA = dy/length
sinB = dx/length
nx = -sinA*distance
ny = sinB*distance
x_eq1.append(x[i] + nx)
y_eq1.append(y[i] + ny)
x_eq2.append(x[i] - nx)
y_eq2.append(y[i] - ny)
dx = x[i + 1] - x[i]
dy = y[i + 1] - y[i]
length = np.sqrt(dx ** 2 + dy ** 2)
sinA = dy/length
sinB = dx/length
nx = -sinA*distance
ny = sinB*distance
x_eq1.append(x[i] + nx)
y_eq1.append(y[i] + ny)
x_eq2.append(x[i] - nx)
y_eq2.append(y[i] - ny)
return self._makeFiller(np.array(x_eq1), np.array(y_eq1), np.array(x_eq2), np.array(y_eq2), color)

View File

@ -233,7 +233,13 @@ QPushButton:disabled {
}
"""
BigSuccessLabel = """
QLabel {
color: #ffffff;
font-size: 26px;
font-weight: bold;
font-family: "Segoe UI", sans-serif;
}"""
colors = [
'#FF6F61', # яркий коралловый

View File

@ -1,12 +1,115 @@
import pyqtgraph as pg
import sys
import os
import time
from PyQt5.QtWidgets import (
QApplication,
QMainWindow,
QTabWidget,
QWidget,
QVBoxLayout,
QLabel,
)
from PyQt5.QtCore import Qt, QThread, pyqtSignal, QObject, QFileSystemWatcher
from PyQt5.QtGui import QIcon
from src.gui import qt_settings as qts
# Импортируйте ваш класс `app` здесь
# Предполагается, что класс `app` предоставляет интерфейс для отображения данных
# Если `app` не предоставляет виджет, возможно, потребуется его модифицировать
from src.gui.app import tabWidgetGenerator
class DirectoryWatcher(QObject):
file_created = pyqtSignal(str)
def __init__(self, directory_path):
super().__init__()
self.directory_path = directory_path
self.watcher = QFileSystemWatcher()
self.watcher.addPath(self.directory_path)
self.existing_files = set(os.listdir(self.directory_path))
self.watcher.directoryChanged.connect(self.on_directory_changed)
def on_directory_changed(self, _):
try:
current_files = set(os.listdir(self.directory_path))
new_files = current_files - self.existing_files
self.existing_files = current_files
for file in new_files:
if file.lower().endswith(".csv"):
full_path = os.path.join(self.directory_path, file)
self.file_created.emit(full_path)
except Exception as e:
print(f"Ошибка при обработке изменений директории: {e}")
class MainWindow(QMainWindow):
def __init__(self, directory_to_watch):
super().__init__()
self.setWindowTitle("Мониторинг CSV-файлов")
self.setGeometry(100, 100, 800, 600)
self.tabs = QTabWidget()
self.tabs.setStyleSheet(qts.dark_style)
self.tabGen = tabWidgetGenerator(directory_to_watch)
self.handle_new_file()
self.setCentralWidget(self.tabs)
# self.setWindowIcon(QIcon("path_to_icon.png"))
self.start_directory_watcher(directory_to_watch)
def start_directory_watcher(self, directory_path):
self.watcher_thread = QThread()
self.watcher = DirectoryWatcher(directory_path)
self.watcher.moveToThread(self.watcher_thread)
self.watcher.file_created.connect(self.handle_new_file)
self.watcher_thread.started.connect(self.watcher.on_directory_changed)
self.watcher_thread.start()
def handle_new_file(self, file_path = None):
time.sleep(0.2)
if file_path:
file_name = os.path.basename(file_path)
else:
file_path = None
file_name = 'Ideal'
tab_widget = self.tabGen.get_widget(path=file_path)
tab = QWidget()
layout = QVBoxLayout()
layout.addWidget(tab_widget)
label = QLabel(f"{file_name}")
label.setAlignment(Qt.AlignCenter)
layout.addWidget(label)
tab.setLayout(layout)
self.tabs.addTab(tab, file_name)
def closeEvent(self, event):
self.watcher_thread.quit()
self.watcher_thread.wait()
event.accept()
from src.gui import app
def main():
pg.mkQApp("Plotting")
temp = app()
pg.exec()
directory_to_watch = "D:/downloads/a22"
if not os.path.isdir(directory_to_watch):
print(f"Директория не найдена: {directory_to_watch}")
sys.exit(1)
app_instance = QApplication(sys.argv)
window = MainWindow(directory_to_watch)
window.show()
sys.exit(app_instance.exec_())
if __name__ == '__main__':
if __name__ == "__main__":
main()

View File

@ -2,40 +2,49 @@ from src.uml.request_generator import Request
class UMLCreator:
def __init__(self,
system_config: dict,
operator_config: dict,
request_generator: Request,
ideal_time: list[float],
bool_dict: dict,
float_dict: dict):
def __init__(self, request_generator: Request, path_to_save: str):
self._request_generator = request_generator
self._ideal_time = ideal_time
self.bool_dict = bool_dict
self.float_dict = float_dict
self.scaler = int(system_config['UML_time_scaler'])
self.WeldTime = operator_config['time_wielding']
self.path_to_save = path_to_save
def _build_data(self):
sig = [
"Closing",
"Relief",
"Squeeze",
"Welding"
]
closure = [self.bool_dict[sig[0]][1][0], self.bool_dict[sig[0]][2][0]]
compression = [self.bool_dict[sig[2]][1][0], self.bool_dict[sig[2]][2][0]]
opening = [self.bool_dict[sig[1]][1][0], self.bool_dict[sig[1]][-1][0]]
real_data = []
ideal_data = []
if not self.theor_mode:
for key, items in self.timings_dict.items():
if key == 'closure': ideal_time = self._ideal_time[0]
elif key == 'compression': ideal_time = self._ideal_time[1]
elif key == 'welding': ideal_time = self.WeldTime
elif key == 'opening': ideal_time = self._ideal_time[2]
for item in items:
real_data.append([item[0]*self.scaler+0.0001, str(key) + '#green'])
real_data.append([item[1]*self.scaler, '{-}'])
if key == 'compression':
ideal_data.append([(item[1]-ideal_time)*self.scaler, str(key) + '#yellow'])
ideal_data.append([(item[1]-0.0001)*self.scaler, '{-}'])
else:
ideal_data.append([item[0]*self.scaler+0.0001, str(key) + '#yellow'])
ideal_data.append([(item[0]+ideal_time)*self.scaler, '{-}'])
if key == 'opening':
ideal_data.append([item[1]*self.scaler+0.0001, 'coming #yellow'])
ideal_data.append([(item[1]+self._ideal_time[3])*self.scaler, '{-}'])
real_data = [
[closure[0]*self.scaler, 'closure #green'],
[closure[1]*self.scaler, '{-}'],
[compression[0]*self.scaler+0.0001, 'compression #green'],
[compression[1]*self.scaler, 'welding #green'],
[opening[0]*self.scaler+0.0001, 'opening #green'],
[opening[1]*self.scaler, '{-}'],
]
else:
real_data = []
ideal_data = [
[0.0, 'closure #yellow'],
[self._ideal_time[0] * self.scaler, '{-}'],
[(self._ideal_time[0] + 0.0001) * self.scaler, 'compression #yellow'],
[sum(self._ideal_time[:2]) * self.scaler, '{-}'],
[(sum(self._ideal_time[:2])+ 0.0001) * self.scaler, 'welding #yellow'],
[(sum(self._ideal_time[:2]) + self.WeldTime)*self.scaler, '{-}'],
[(sum(self._ideal_time[:2]) + 0.0001 + self.WeldTime) * self.scaler, 'opening #yellow'],
[(sum(self._ideal_time[:3]) + self.WeldTime) * self.scaler, 'coming #yellow'],
[(sum(self._ideal_time[:4]) + self.WeldTime) * self.scaler, '{-}'],
]
client_data = [
[0.0 * self.scaler, 'closure'],
@ -48,31 +57,15 @@ class UMLCreator:
[0.300 * self.scaler, '{-}'],
]
ideal_data = [
[0.0 * self.scaler, 'closure #yellow'],
[self._ideal_time[0] * self.scaler, '{-}'],
[(self._ideal_time[0] + 0.0001) * self.scaler, 'compression #yellow'],
[(self._ideal_time[0] + self._ideal_time[1]) * self.scaler, '{-}'],
[(self._ideal_time[0] + self._ideal_time[1]+ 0.0001) * self.scaler, 'welding #yellow'],
[(self._ideal_time[0] + self._ideal_time[1] + self.WeldTime)*self.scaler, '{-}'],
[(self._ideal_time[0] + self._ideal_time[1] + 0.0001 + self.WeldTime) * self.scaler, 'opening #yellow'],
[(self._ideal_time[0] + self._ideal_time[1] + self._ideal_time[2] + self.WeldTime) * self.scaler, '{-}'],
]
return real_data, client_data, ideal_data, self.bool_dict
def _get_time(self, signals = '', states = ''):
res = []
for i, sig in enumerate(signals):
if states: state = states[i]
else: state = 'high'
index1 = next ((i for i, _ in enumerate(self.bool_dict[sig]) if _[1]==state), -1)
time = self.bool_dict[sig][index1][0]
res.append(time)
return res
def _generate_svg(self, real_data, client_data, ideal_data, bool_data) -> None:
try:
self._request_generator.clear()
self._request_generator.clear()
self._request_generator.appendStr('scale 25 as 50 pixels')
if not self.theor_mode:
self._request_generator.addLineStyle('biba', 'red', 2)
for i, [signal, changes] in enumerate(bool_data.items()):
@ -85,28 +78,33 @@ class UMLCreator:
self._request_generator.addConcise('RD', 'Real data')
self._request_generator.setTimestamps('RD', real_data)
self._request_generator.addConcise('CD', 'Client data')
self._request_generator.setTimestamps('CD', client_data)
self._request_generator.addConcise('ID', 'Ideal data')
self._request_generator.setTimestamps('ID', ideal_data)
self._request_generator.generateSVG()
else: self.name = self.path_to_save + '/Ideal'
self._request_generator.addConcise('CD', 'Client data')
self._request_generator.setTimestamps('CD', client_data)
self._request_generator.addConcise('ID', 'Ideal data')
self._request_generator.setTimestamps('ID', ideal_data)
try:
self._request_generator.generateSVG(self.name)
except Exception as e:
print(f"SVG generate error: {e}")
def update_uml(self,
operator_config: dict,
system_config : dict,
request_generator: Request,
ideal_time: list[float],
bool_dict: dict,
float_dict: dict):
float_dict: dict,
timings_dict: dict,
mode: bool,
name:str):
self._request_generator = request_generator
self._ideal_time = ideal_time
self.bool_dict = bool_dict
self.float_dict = float_dict
self.timings_dict = timings_dict
self.theor_mode = mode
self.name = name
self.scaler = int(system_config['UML_time_scaler'])
self.WeldTime = operator_config['time_wielding']

View File

@ -48,10 +48,10 @@ class Request:
def addLineStyle(self, name, color = 'green', thicknes = 1):
self.lineStyles[name] = [f'LineColor {color}', f'LineThickness {thicknes}']
def generateSVG(self):
self._compileUML()
filename = abspath('UML.txt')
self.server.processes_file(filename, outfile='UML.svg')
def generateSVG(self, name):
self._compileUML(name)
filename = abspath(f'{name}.txt')
self.server.processes_file(filename, outfile=f'{name}.svg')
#result = self.server.processes(self.stringUML)
#return result
@ -78,12 +78,11 @@ class Request:
self.reqArr.append('}')
self.reqArr.append('</style>')
self.reqArr.append('scale 10 as 50 pixels')
def _addVariables(self):
for var in self.variables: self.reqArr.append(str(var))
def _compileUML(self):
def _compileUML(self, name):
self._addHeader()
self._addVariables()
@ -93,7 +92,7 @@ class Request:
self._endUML()
self.stringUML = [line + '\n' for line in self.reqArr]
with open('UML.txt', 'w', encoding='utf-8') as file:
with open(f'{name}.txt', 'w', encoding='utf-8') as file:
file.writelines(self.stringUML)

View File

@ -2,28 +2,60 @@ import pandas as pd
import numpy as np
class DiagramParser:
def __init__(self):
def __init__(self, system_config: dict):
self.data = pd.DataFrame({})
self.signals = [system_config["Closure_signal"],
system_config["Squeeze_signal"],
system_config["Welding_signal"],
system_config["Release_signal"]]
self.boolDict = {}
self.floatDict = {}
self.timingsDict = {}
self.theor_mode = False
def setData(self, path):
self.data = pd.read_csv(path)
if not path:
self.theor_mode = True
else:
self.data = pd.read_csv(path)
for signalName in self.data.columns:
if type (self.data[signalName].iloc[0]) == np.bool:
self.boolDict[signalName] = self._getBoolChanges(signalName)
def getBoolDict (self):
boolDict = {}
for signalName in self.data.columns:
if type (self.data[signalName].iloc[0]) == np.bool:
boolDict[signalName] = self._getBoolChanges(signalName)
return boolDict
def getFloatDict (self):
floatDict = {}
for signalName in self.data.columns:
if type (self.data[signalName].iloc[0]) == np.float64:
floatDict[signalName] = self._getFloatChanges(signalName)
return floatDict
for signalName in self.data.columns:
if type (self.data[signalName].iloc[0]) == np.float64:
self.floatDict[signalName] = self._getFloatChanges(signalName)
for key, items in self.boolDict.items():
if key == self.signals[0]: name = "closure"
elif key == self.signals[1]: name = "compression"
elif key == self.signals[2]: name = "welding"
elif key == self.signals[3]: name = "opening"
self.timingsDict[name] = []
len_items = len(items)
for i, item in enumerate(items):
if item[1] == 'high':
if i < len_items-1:
self.timingsDict[name].append([items[i][0], items[i+1][0]])
else:
self.timingsDict[name].append([items[i][0], items[i][0]+0.01])
def getBoolDict (self) -> dict:
return self.boolDict
def _getBoolChanges(self, signalName):
def getFloatDict (self) -> dict:
return self.floatDict
def getRealTimings(self) -> dict:
return self.timingsDict
def getMode(self) -> bool:
return self.theor_mode
def _getBoolChanges(self, signalName) -> list:
timeCode = self.data['time']
signal_values = self.data[signalName]
changes = []
@ -38,7 +70,7 @@ class DiagramParser:
return changes
def _getFloatChanges(self, signalName):
def _getFloatChanges(self, signalName) -> list:
timeCode = self.data['time']
signal_values = self.data[signalName]
changes = []

File diff suppressed because it is too large Load Diff