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_1": 0.005,
"dist_open_start_2" : 0.005, "dist_open_start_2": 0.005,
"dist_open_after_1" : 0.006, "dist_open_after_1": 0.006,
"dist_open_after_2" : 0.006, "dist_open_after_2": 0.006,
"dist_open_end_1" : 0.010, "dist_open_end_1": 0.01,
"dist_open_end_2" : 0.050, "dist_open_end_2": 0.05,
"dist_close_end_1" : 0.005, "dist_close_end_1": 0.005,
"dist_close_end_2" : 0.005, "dist_close_end_2": 0.005,
"time_wielding" : 1, "time_wielding": 1,
"time_command" : 0.060, "time_command": 0.06,
"time_robot_movement" : 0.2, "time_robot_movement": 0.2,
"object_thickness" : 4.5e-3, "object_thickness": 0.0045,
"force_target" : 5000, "force_target": 5000,
"force_capture" : 500 "force_capture": 500
} }

View File

@ -15,5 +15,9 @@
"position_start_2": 0.08, "position_start_2": 0.08,
"k_prop": 0.05, "k_prop": 0.05,
"time_capture": 100000, "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 .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.utils import read_json, DiagramParser
from src.uml import Request, UMLCreator from src.uml import Request, UMLCreator
from src.OptAlgorithm import OptAlgorithm from src.OptAlgorithm import OptAlgorithm
from src.gui import PlotWindow, settingsWindow from src.gui import Plotter, settingsWindow
class app: class tabWidgetGenerator:
def __init__(self): def __init__(self, directory_to_save):
self.UMLgenerator = Request(server_url='http://www.plantuml.com/plantuml/svg/')
self.parser = DiagramParser() self.uml_creator = UMLCreator(request_generator=self.UMLgenerator, path_to_save=directory_to_save)
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):
self.operator_params = read_json("params/operator_params.json") self.operator_params = read_json("params/operator_params.json")
self.system_params = read_json("params/system_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.paths = []
self.ideal_times = self._get_ideal_timings(self.opt_algorithm) 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") def get_widget(self, path):
self.bool_dict = self.parser.getBoolDict() self.paths.append(path)
self.float_dict = self.parser.getFloatDict() 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, def _getParsedData(self, path):
system_config=self.system_params, self.names.append(path)
opt=self.opt_algorithm, parser = DiagramParser(system_config=self.system_params)
bool_dict=self.bool_dict, parser.setData(path)
float_dict=self.float_dict, self.bool_dicts.append(parser.getBoolDict())
show_settings_func=self._show_settings) self.float_dicts.append(parser.getFloatDict())
self.timings_dicts.append(parser.getRealTimings())
self.uml_creator = UMLCreator(operator_config=self.operator_params, self.modes.append(parser.getMode())
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 _update_settings(self, _): def _update(self, _ = None):
self.operator_params = self.operSettings.getParams() self.operator_params = self.operSettings.getParams()
self.system_params = self.sysSettings.getParams() self.system_params = self.sysSettings.getParams()
self.opt_algorithm = OptAlgorithm(operator_config=self.operator_params, system_config=self.system_params) opt_algorithm = OptAlgorithm(operator_config=self.operator_params, system_config=self.system_params)
self.ideal_times = self._get_ideal_timings(self.opt_algorithm) ideal_times = self._get_ideal_timings(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)
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, system_config=self.system_params,
opt=self.opt_algorithm, opt=opt_algorithm,
bool_dict=self.bool_dict, bool_dict=self.bool_dicts[i],
float_dict=self.float_dict) 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): def _show_settings(self):
self.operSettings.show() self.operSettings.show()
@ -82,5 +79,7 @@ class app:
if __name__ == '__main__': if __name__ == '__main__':
pg.mkQApp("Plotting") pg.mkQApp("Plotting")
temp = app() temp = tabWidgetGenerator()
widget = temp.get_widget("trace_samples/2024_11_08-19_30_49.csv")
widget.show()
pg.exec() pg.exec()

View File

@ -1,5 +1,6 @@
import pyqtgraph as pg import pyqtgraph as pg
from pyqtgraph.Qt import QtWidgets from pyqtgraph.Qt import QtWidgets
from PyQt5.QtCore import Qt
import numpy as np import numpy as np
from src.gui import qt_settings as qts 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 from src.OptAlgorithm import OptAlgorithm
class PlotWindow: class Plotter:
def __init__(self, def __init__(self, show_settings_func):
system_config : dict,
operator_config: dict,
opt: OptAlgorithm,
bool_dict: dict,
float_dict: dict, show_settings_func):
pg.setConfigOptions(antialias=True) 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.alpha = 100 #[0-255 прозрачность фона]
self._getIdealTimings()
self._init_ui() self._init_ui()
self.settings_button.clicked.connect(show_settings_func) self.settings_button.clicked.connect(show_settings_func)
@ -31,15 +20,22 @@ class PlotWindow:
system_config : dict, system_config : dict,
operator_config: dict, operator_config: dict,
opt: OptAlgorithm, opt: OptAlgorithm,
ideal_time: list[float],
bool_dict: dict, bool_dict: dict,
float_dict: dict): float_dict: dict,
timings_dict: dict,
mode: bool):
self.opt = opt self.opt = opt
self.bool_dict = bool_dict self.bool_dict = bool_dict
self.float_dict = float_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.scaler = int(system_config['UML_time_scaler'])
self.WeldTime = operator_config['time_wielding'] #[sec] self.WeldTime = operator_config['time_wielding'] #[sec]
self._getIdealTimings() self.WeldData = self.opt.calcPhaseGrow(self.idealTime[1])
self._updatePlots() self._updatePlots()
def _init_ui(self): def _init_ui(self):
self.widget = QtWidgets.QWidget() self.widget = QtWidgets.QWidget()
@ -53,7 +49,15 @@ class PlotWindow:
layout.addWidget(self.win) layout.addWidget(self.win)
self.settings_button = QtWidgets.QPushButton("Show settings") self.settings_button = QtWidgets.QPushButton("Show settings")
self.settings_button.setFixedWidth(160) 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.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') #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.p11.setAutoVisible(x=False, y=True)
self.p12.setAutoVisible(x=False, y=True) self.p12.setAutoVisible(x=False, y=True)
self.p13.setAutoVisible(x=False, y=True) self.p13.setAutoVisible(x=False, y=True)
self._updatePlots()
self.widget.setStyleSheet(qts.dark_style) self.widget.setStyleSheet(qts.dark_style)
self.widget.show()
def _init_graph(self, title, Yname, Yunits, Xname, Xunits): def _init_graph(self, title, Yname, Yunits, Xname, Xunits):
plot = self.win.addPlot(title = title) plot = self.win.addPlot(title = title)
@ -95,40 +97,125 @@ class PlotWindow:
self.p13.clear() self.p13.clear()
self.l13.clear() self.l13.clear()
self._plotRealData() if not self.theor_mode:
times = np.arange(20000)/10 self._plotRealData()
self._plotIdealData(times) 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): def _plotRealData(self):
for i, (key, dat) in enumerate(self.float_dict.items()): for i, (key, dat) in enumerate(self.float_dict.items()):
@ -146,62 +233,46 @@ class PlotWindow:
self.l13.addItem(curve, key) self.l13.addItem(curve, key)
return dat[0] return dat[0]
def _plotIdealData(self, times): def _plotIdealData(self, time, data):
data = self._form_idealdatGraph(times) 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)
x_fe = pg.PlotDataItem(times, data[0]*1000, pen=pg.mkPen(color=qts.colors[8], width=2), name='x_fe', 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)
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_me = pg.PlotDataItem(time, data[3]*1000, pen=pg.mkPen(color=qts.colors[9], width=2), name='v_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) f = pg.PlotDataItem(time, data[4], pen=pg.mkPen(color=qts.colors[8], width=2), name='f', 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)
self.p11.addItem(f) self.p11.addItem(f)
self.l11.addItem(f, 'Ideal force') #self.l11.addItem(f, 'Ideal force')
self.p12.addItem(x_fe) 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.p12.addItem(x_me)
self.l12.addItem(x_me, 'ME POS') #self.l12.addItem(x_me, 'ME POS')
self.p13.addItem(v_fe) 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.p13.addItem(v_me)
self.l13.addItem(v_me, 'ME VEL') #self.l13.addItem(v_me, 'ME VEL')
self._addBackgroundSplitter() #self._addBackgroundSplitter()
self._addEquidistances(times, data) #self._addEquidistances(time, data)
def _addBackgroundSplitter(self): def _addBackgroundSplitter(self, x, color):
alpha = self.alpha alpha = self.alpha
y01 = np.array([10000, 10000]) y01 = np.array([10000, 10000])
y0_1 = np.array([-10000, -10000]) y0_1 = np.array([-10000, -10000])
for i, _ in enumerate(self.x_splitter): a01 = pg.PlotDataItem(x, y01, pen=pg.mkPen(color=qts.colors[8], width=2), name=' ')
a01 = pg.PlotDataItem(_, 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=' ')
a0_1 = pg.PlotDataItem(_, y0_1, pen=pg.mkPen(color=qts.colors[8], width=2), name=' ') bg1 = pg.FillBetweenItem(a01, a0_1, color+(alpha,))
bg1 = pg.FillBetweenItem(a01, a0_1, qts.RGBA[i]+(alpha,)) bg2 = pg.FillBetweenItem(a01, a0_1, color+(alpha,))
bg2 = pg.FillBetweenItem(a01, a0_1, qts.RGBA[i]+(alpha,)) bg3 = pg.FillBetweenItem(a01, a0_1, color+(alpha,))
bg3 = pg.FillBetweenItem(a01, a0_1, qts.RGBA[i]+(alpha,)) self.p11.addItem(bg1)
self.p11.addItem(bg1) self.p12.addItem(bg2)
self.p12.addItem(bg2) self.p13.addItem(bg3)
self.p13.addItem(bg3)
self.p11.setYRange(-1000, 5000) self.p11.setYRange(-1000, 5000)
self.p12.setYRange(-50, 250) self.p12.setYRange(-50, 250)
self.p13.setYRange(-400, 400) 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): def _makeFiller(self, x1, y1, x2, y2, color):
alpha = self.alpha alpha = self.alpha
eq1 = pg.PlotDataItem(x1, y1, pen=pg.mkPen(color='#000000', width=1)) eq1 = pg.PlotDataItem(x1, y1, pen=pg.mkPen(color='#000000', width=1))
@ -210,11 +281,7 @@ class PlotWindow:
return eq1, eq2, bg return eq1, eq2, bg
def _calculate_equidistant(self, x, y, percent, splitter, color): def _calculate_equidistant(self, x, y, percent, 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]
if len(x) != len(y): if len(x) != len(y):
raise ValueError("x и y должны быть одного размера") raise ValueError("x и y должны быть одного размера")
distance = max(y)/100*percent distance = max(y)/100*percent
@ -224,19 +291,17 @@ class PlotWindow:
y_eq2 = [] y_eq2 = []
for i in range(0, len(x) - 1): 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]
dx = x[i + 1] - x[i] length = np.sqrt(dx ** 2 + dy ** 2)
dy = y[i + 1] - y[i] sinA = dy/length
length = np.sqrt(dx ** 2 + dy ** 2) sinB = dx/length
sinA = dy/length
sinB = dx/length nx = -sinA*distance
ny = sinB*distance
nx = -sinA*distance x_eq1.append(x[i] + nx)
ny = sinB*distance y_eq1.append(y[i] + ny)
x_eq1.append(x[i] + nx) x_eq2.append(x[i] - nx)
y_eq1.append(y[i] + ny) y_eq2.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) 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 = [ colors = [
'#FF6F61', # яркий коралловый '#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(): def main():
pg.mkQApp("Plotting") directory_to_watch = "D:/downloads/a22"
temp = app()
pg.exec() 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() main()

View File

@ -2,40 +2,49 @@ from src.uml.request_generator import Request
class UMLCreator: class UMLCreator:
def __init__(self, def __init__(self, request_generator: Request, path_to_save: str):
system_config: dict,
operator_config: dict,
request_generator: Request,
ideal_time: list[float],
bool_dict: dict,
float_dict: dict):
self._request_generator = request_generator self._request_generator = request_generator
self._ideal_time = ideal_time self.path_to_save = path_to_save
self.bool_dict = bool_dict
self.float_dict = float_dict
self.scaler = int(system_config['UML_time_scaler'])
self.WeldTime = operator_config['time_wielding']
def _build_data(self): def _build_data(self):
sig = [ real_data = []
"Closing", ideal_data = []
"Relief", if not self.theor_mode:
"Squeeze",
"Welding" for key, items in self.timings_dict.items():
] if key == 'closure': ideal_time = self._ideal_time[0]
closure = [self.bool_dict[sig[0]][1][0], self.bool_dict[sig[0]][2][0]] elif key == 'compression': ideal_time = self._ideal_time[1]
compression = [self.bool_dict[sig[2]][1][0], self.bool_dict[sig[2]][2][0]] elif key == 'welding': ideal_time = self.WeldTime
opening = [self.bool_dict[sig[1]][1][0], self.bool_dict[sig[1]][-1][0]] 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 = [ else:
[closure[0]*self.scaler, 'closure #green'], real_data = []
[closure[1]*self.scaler, '{-}'], ideal_data = [
[compression[0]*self.scaler+0.0001, 'compression #green'], [0.0, 'closure #yellow'],
[compression[1]*self.scaler, 'welding #green'], [self._ideal_time[0] * self.scaler, '{-}'],
[opening[0]*self.scaler+0.0001, 'opening #green'], [(self._ideal_time[0] + 0.0001) * self.scaler, 'compression #yellow'],
[opening[1]*self.scaler, '{-}'], [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 = [ client_data = [
[0.0 * self.scaler, 'closure'], [0.0 * self.scaler, 'closure'],
@ -48,31 +57,15 @@ class UMLCreator:
[0.300 * self.scaler, '{-}'], [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 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: 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) self._request_generator.addLineStyle('biba', 'red', 2)
for i, [signal, changes] in enumerate(bool_data.items()): 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.addConcise('RD', 'Real data')
self._request_generator.setTimestamps('RD', real_data) self._request_generator.setTimestamps('RD', real_data)
self._request_generator.addConcise('CD', 'Client data') else: self.name = self.path_to_save + '/Ideal'
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()
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: except Exception as e:
print(f"SVG generate error: {e}") print(f"SVG generate error: {e}")
def update_uml(self, def update_uml(self,
operator_config: dict, operator_config: dict,
system_config : dict, system_config : dict,
request_generator: Request,
ideal_time: list[float], ideal_time: list[float],
bool_dict: dict, 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._ideal_time = ideal_time
self.bool_dict = bool_dict self.bool_dict = bool_dict
self.float_dict = float_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.scaler = int(system_config['UML_time_scaler'])
self.WeldTime = operator_config['time_wielding'] self.WeldTime = operator_config['time_wielding']

View File

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

View File

@ -2,28 +2,60 @@ import pandas as pd
import numpy as np import numpy as np
class DiagramParser: class DiagramParser:
def __init__(self): def __init__(self, system_config: dict):
self.data = pd.DataFrame({}) 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): 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): for signalName in self.data.columns:
boolDict = {} if type (self.data[signalName].iloc[0]) == np.float64:
for signalName in self.data.columns: self.floatDict[signalName] = self._getFloatChanges(signalName)
if type (self.data[signalName].iloc[0]) == np.bool:
boolDict[signalName] = self._getBoolChanges(signalName) for key, items in self.boolDict.items():
return boolDict if key == self.signals[0]: name = "closure"
elif key == self.signals[1]: name = "compression"
def getFloatDict (self): elif key == self.signals[2]: name = "welding"
floatDict = {} elif key == self.signals[3]: name = "opening"
for signalName in self.data.columns:
if type (self.data[signalName].iloc[0]) == np.float64:
floatDict[signalName] = self._getFloatChanges(signalName)
return floatDict
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'] timeCode = self.data['time']
signal_values = self.data[signalName] signal_values = self.data[signalName]
changes = [] changes = []
@ -38,7 +70,7 @@ class DiagramParser:
return changes return changes
def _getFloatChanges(self, signalName): def _getFloatChanges(self, signalName) -> list:
timeCode = self.data['time'] timeCode = self.data['time']
signal_values = self.data[signalName] signal_values = self.data[signalName]
changes = [] changes = []

File diff suppressed because it is too large Load Diff