Compare commits

...

4 Commits

22 changed files with 654 additions and 263 deletions

View File

@ -1,16 +1,226 @@
{
"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.0,
"time_robot_movement": 0.2,
"object_thickness": 0.0045,
"force_target": 5000,
"force_capture": 500
"dist_open_start_1": [
0.005,
0.005,
0.005,
0.005,
0.005,
0.005,
0.005,
0.005,
0.005,
0.005,
0.005,
0.005,
0.005,
0.005
],
"dist_open_start_2": [
0.005,
0.005,
0.005,
0.005,
0.005,
0.005,
0.005,
0.005,
0.005,
0.005,
0.005,
0.005,
0.005,
0.005
],
"dist_open_after_1": [
0.006,
0.006,
0.006,
0.006,
0.006,
0.006,
0.006,
0.006,
0.006,
0.006,
0.006,
0.006,
0.006,
0.006
],
"dist_open_after_2": [
0.006,
0.006,
0.006,
0.006,
0.006,
0.006,
0.006,
0.006,
0.006,
0.006,
0.006,
0.006,
0.006,
0.006
],
"dist_open_end_1": [
0.01,
0.01,
0.01,
0.01,
0.01,
0.01,
0.01,
0.01,
0.01,
0.01,
0.01,
0.01,
0.01,
0.01
],
"dist_open_end_2": [
0.05,
0.05,
0.05,
0.05,
0.05,
0.05,
0.05,
0.05,
0.05,
0.05,
0.05,
0.05,
0.05,
0.05
],
"dist_close_end_1": [
0.005,
0.005,
0.005,
0.005,
0.005,
0.005,
0.005,
0.005,
0.005,
0.005,
0.005,
0.005,
0.005,
0.005
],
"dist_close_end_2": [
0.005,
0.005,
0.005,
0.005,
0.005,
0.005,
0.005,
0.005,
0.005,
0.005,
0.005,
0.005,
0.005,
0.005
],
"time_wielding": [
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0,
1.0
],
"time_command": [
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0
],
"time_robot_movement": [
0.2,
0.2,
0.2,
0.2,
0.2,
0.2,
0.2,
0.2,
0.2,
0.2,
0.2,
0.2,
0.2,
0.2
],
"object_thickness": [
0.0045,
0.0045,
0.0045,
0.0045,
0.0045,
0.0045,
0.0045,
0.0045,
0.0045,
0.0045,
0.0045,
0.0045,
0.0045,
0.0045
],
"force_target": [
4000.0,
5000.0,
5000.0,
5000.0,
5000.0,
5000.0,
5000.0,
5000.0,
5000.0,
5000.0,
5000.0,
5000.0,
5000.0,
5000.0
],
"force_capture": [
500.0,
500.0,
500.0,
500.0,
500.0,
500.0,
500.0,
500.0,
500.0,
500.0,
500.0,
500.0,
500.0,
500.0
]
}

View File

@ -1,22 +1,22 @@
{
"trace_storage_path": "D:/downloads/a22",
"monitor_update_period": 100,
"a_max_1": 5.41,
"v_max_1": 0.278,
"a_max_2": 35.81,
"v_max_2": 0.7,
"mass_1": 270,
"mass_2": 1,
"k_hardness_1": 2148570,
"k_hardness_2": 0,
"torque_max_1": 20,
"torque_max_2": 0,
"transmission_ratio_1": 0.00125,
"transmission_ratio_2": 1,
"position_start_1": 0.08,
"position_start_2": 0.08,
"k_prop": 0.05,
"time_capture": 100000,
"UML_time_scaler": 1000
"trace_storage_path": ["D:/downloads/a22"],
"monitor_update_period": [100],
"a_max_1": [5.41],
"v_max_1": [0.278],
"a_max_2": [35.81],
"v_max_2": [0.7],
"mass_1": [270],
"mass_2": [1],
"k_hardness_1": [2148570],
"k_hardness_2": [0],
"torque_max_1": [20],
"torque_max_2": [0],
"transmission_ratio_1": [0.00125],
"transmission_ratio_2": [1],
"position_start_1": [0.08],
"position_start_2": [0.08],
"k_prop": [0.05],
"time_capture": [100000],
"UML_time_scaler": [1000]
}

Binary file not shown.

View File

@ -3,18 +3,21 @@ import pandas as pd
from typing import Union
from PyQt5.QtWidgets import QWidget
from src.utils.base.base import BaseMediator, BaseDirectoryMonitor, BaseDataConverter, BasePlotWidget
from src.utils.base.base import BaseMediator, BaseDirectoryMonitor, BaseDataConverter, BasePlotWidget, BasePointPassportFormer
class Mediator(BaseMediator):
def notify(self,
source: Union[BaseDirectoryMonitor, BaseDataConverter, BasePlotWidget],
data: Union[list[str], list[pd.DataFrame], list[QWidget]]):
source: Union[BaseDirectoryMonitor, BaseDataConverter, BasePointPassportFormer, BasePlotWidget],
data: Union[list[str], list[pd.DataFrame], list[list], list[QWidget]]):
if issubclass(source.__class__, BaseDirectoryMonitor):
self._converter.convert_data(data)
if issubclass(source.__class__, BaseDataConverter):
self._passportFormer.form_passports(data)
if issubclass(source.__class__, BasePointPassportFormer):
self._plot.build(data)
if issubclass(source.__class__, BasePlotWidget):
@ -22,7 +25,7 @@ class Mediator(BaseMediator):
def push_settings(self, settings: list[dict]):
self._monitor.update_settings(settings)
self._plot.update_settings(settings)
self._passportFormer.update_settings(settings)
self._monitor.force_all_dir()

View File

@ -29,8 +29,8 @@ class DirectoryMonitor(BaseDirectoryMonitor):
def update_settings(self, data: list[dict]) -> None:
self.stop()
operator_params, system_params = data
self._directory_path = system_params['trace_storage_path']
self._update_time = system_params['monitor_update_period']
self._directory_path = system_params['trace_storage_path'][0]
self._update_time = system_params['monitor_update_period'][0]
self._init_state()
self.start()

View File

@ -0,0 +1,63 @@
from src.utils.base.base import BasePointPassportFormer, BaseIdealDataBuilder
import pandas as pd
class idealDataBuilder(BaseIdealDataBuilder):
def get_closingDF(self) -> pd.DataFrame:
return self._get_data(self.Ts['tclose'], self.calcPhaseClose)
def get_compressionDF(self) -> pd.DataFrame:
return self._get_data(self.Ts['tgrow'], self.calcPhaseGrow)
def get_openingDF(self) -> pd.DataFrame:
return self._get_data(self.getMarkOpen(), self.calcPhaseOpen)
def get_oncomingDF(self) -> pd.DataFrame:
return self._get_data(self.Ts['tmovement'], self.calcPhaseMovement)
def get_weldingDF(self) -> pd.DataFrame:
data = []
X1, X2, V1, V2, F = self.calcPhaseGrow(self.Ts['tgrow'])
data.append({"time":0, "Posicion FE":X1,"Posicion ME":X2, "Rotor Speed FE":V1, "Rotor Speed ME":V2, "Force":F})
data.append({"time":self.welding_time, "Posicion FE":X1,"Posicion ME":X2, "Rotor Speed FE":V1, "Rotor Speed ME":V2, "Force":F})
return pd.DataFrame(data)
def get_ideal_timings(self) -> list[float]:
data = self.Ts
ideal_timings = [data['tclose'], data['tgrow'], self.welding_time, self.getMarkOpen(), data['tmovement']] # TODO: add data['tmovement'], Oncoming не учитывается в производительности
return ideal_timings
class PassportFormer(BasePointPassportFormer):
def form_passports(self, data: list[pd.DataFrame]) -> list[list[pd.DataFrame, dict, list]]:
return_data = [self._build_passports_pocket(dataframe) for dataframe in data]
self._mediator.notify(self, return_data)
def _build_passports_pocket(self, dataframe: pd.DataFrame) -> list[pd.DataFrame, dict, list]:
passports_pocket = []
events, point_quantity = self._filter_events(dataframe["time"], dataframe)
system_settings = {key: value[0] for key, value in self._params[1].items()}
for i in range(0, point_quantity):
if not dataframe["time"].isna().all():
operator_settings = {}
for key, value in self._params[0].items():
if len(value) > i:
operator_settings[key] = value[i]
else:
operator_settings[key] = value[0]
params_list = [operator_settings, system_settings]
ideal_data = self._build_ideal_data(idealDataBuilder=idealDataBuilder, params=params_list)
if i < point_quantity-1:
cut_time = events[self._stages[0]][0][i+1]
frame = dataframe[dataframe["time"] < cut_time]
dataframe = dataframe[dataframe["time"] >= cut_time]
else:
frame = dataframe
point_events = {key: [value[0][i], value[1][i]] for key, value in events.items()}
passports_pocket.append([frame, ideal_data, point_events])
return passports_pocket
def update_settings(self, params: list[dict, dict]):
self._params = params

View File

@ -45,7 +45,7 @@ class MainWindow(BaseMainWindow):
def keyPressEvent(self, a0):
if a0.key() == Qt.Key_F5:
self.clear()
pass
def _show_settings(self):
self.operSettings.show()

View File

@ -6,34 +6,6 @@ from numpy import floating
from typing import Optional, Any, NamedTuple
from src.utils.base.base import BasePlotWidget
from src.utils.base.base import BaseIdealDataBuilder
class idealDataBuilder(BaseIdealDataBuilder):
def get_closingDF(self) -> pd.DataFrame:
return self._get_data(self.Ts['tclose'], self.calcPhaseClose)
def get_compressionDF(self) -> pd.DataFrame:
return self._get_data(self.Ts['tgrow'], self.calcPhaseGrow)
def get_openingDF(self) -> pd.DataFrame:
return self._get_data(self.getMarkOpen(), self.calcPhaseOpen)
def get_oncomingDF(self) -> pd.DataFrame:
return self._get_data(self.Ts['tmovement'], self.calcPhaseMovement)
def get_weldingDF(self) -> pd.DataFrame:
data = []
X1, X2, V1, V2, F = self.calcPhaseGrow(self.Ts['tgrow'])
data.append({"time":0, "Posicion FE":X1,"Posicion ME":X2, "Rotor Speed FE":V1, "Rotor Speed ME":V2, "Force":F})
data.append({"time":self.welding_time, "Posicion FE":X1,"Posicion ME":X2, "Rotor Speed FE":V1, "Rotor Speed ME":V2, "Force":F})
return pd.DataFrame(data)
def get_ideal_timings(self) -> list[float, float, float, float]:
data = self.Ts
ideal_timings = [data['tclose'], data['tgrow'], self.welding_time, self.getMarkOpen()] # TODO: add data['tmovement'], Oncoming не учитывается в производительности
return ideal_timings
class ProcessStage(NamedTuple):
mean_value: floating[Any]
@ -43,14 +15,13 @@ class ProcessStage(NamedTuple):
class PlotWidget(BasePlotWidget):
def _create_curve_ideal(self,
stage: str,
signal: str,
signal: str,
ideal_data: pd.DataFrame,
start_timestamp: float,
finish_timestamp: float) -> Optional[pg.PlotDataItem]:
data = self._stage_ideals[stage]
if start_timestamp and finish_timestamp:
plot = pg.PlotDataItem(x=start_timestamp+data["time"], y=data[signal["name"]], pen=signal["pen"])
plot = pg.PlotDataItem(x=start_timestamp+ideal_data["time"], y=ideal_data[signal["name"]], pen=signal["pen"])
return plot
return None
@ -64,19 +35,6 @@ class PlotWidget(BasePlotWidget):
region.setBrush(pg.mkBrush(self._stage_colors[stage]))
return region
return None
def _get_timestamp(self,
stage: str,
times: pd.Series,
dataframe: pd.DataFrame) -> Optional[list[float]]:
stage_diff = np.diff(dataframe[stage])
start_index = np.where(stage_diff == 1)[0]
finish_index = np.where(stage_diff == -1)[0]
if start_index.size:
start_timestamp = times[start_index[0]]
finish_timestamp = times[finish_index[0]] if finish_index.size else times[len(times) - 1]
return start_timestamp, finish_timestamp
return None
@staticmethod
def _init_plot_widget(title: str) -> tuple[pg.PlotWidget, pg.LegendItem]:
@ -90,110 +48,109 @@ class PlotWidget(BasePlotWidget):
stage: str,
dataframe: pd.DataFrame,
signal_name: str) -> Optional[ProcessStage]:
if stage in self._stages:
stage_diff = np.diff(dataframe[stage])
start_index = np.where(stage_diff == 1)[0]
finish_index = np.where(stage_diff == -1)[0]
data = dataframe[signal_name] if signal_name in dataframe.columns.tolist() else []
if data.size and start_index.size:
start = start_index[0]
finish = finish_index[0] if finish_index.size else (len(data) - 1)
data_slice = data[start:finish]
mean = np.mean(data_slice)
return ProcessStage(mean_value=mean, start_index=int(start), finish_index=int(finish))
return None
def _build_widget(self, dataframe: pd.DataFrame) -> QWidget:
stage_diff = np.diff(dataframe[stage])
start_index = np.where(stage_diff == 1)[0]
finish_index = np.where(stage_diff == -1)[0]
data = dataframe[signal_name] if signal_name in dataframe.columns.tolist() else []
if data.size and start_index.size:
start = start_index[0]
finish = finish_index[0] if finish_index.size else (len(data) - 1)
data_slice = data[start:finish]
mean = np.mean(data_slice)
return ProcessStage(mean_value=mean, start_index=int(start), finish_index=int(finish))
return None
def _build_widget(self, data: list[pd.DataFrame, dict, list]) -> QWidget:
widget = QWidget()
layout = QVBoxLayout()
time_axis = dataframe["time"]
dataframe_headers = dataframe.columns.tolist()
for channel, description in self._plt_channels.items():
performance_list = []
df_continuous = pd.DataFrame({})
plot_widget, legend = self._init_plot_widget(title=channel)
settings = description["Settings"]
if settings["stages"] and all([stage in dataframe_headers for stage in self._stages]):
for stage in self._stages:
start_timestamp, finish_timestamp = self._get_timestamp(stage, time_axis, dataframe)
region = self._create_stage_region(stage, start_timestamp, finish_timestamp)
if region:
plot_widget.addItem(region)
for signal in description["Ideal_signals"]:
ideal_plot = self._create_curve_ideal(stage, signal, start_timestamp, finish_timestamp)
if ideal_plot:
plot_widget.addItem(ideal_plot)
for dataframe, ideal_data, events in data:
df_continuous = pd.concat([df_continuous, dataframe], axis=0)
dataframe_headers = dataframe.columns.tolist()
stages = events.keys()
end_timestamp = time_axis[len(time_axis) - 1]
region = self._create_stage_region("Oncoming", finish_timestamp, end_timestamp)
if region:
plot_widget.addItem(region)
if settings["stages"] and all([stage in dataframe_headers for stage in stages]):
for stage in stages:
start_t, end_t = events[stage]
region = self._create_stage_region(stage, start_t, end_t)
if region:
plot_widget.addItem(region)
for signal in description["Ideal_signals"]:
ideal_plot = self._create_curve_ideal("Oncoming", signal, finish_timestamp, end_timestamp)
if ideal_plot:
plot_widget.addItem(ideal_plot)
if settings["ideals"]:
for stage in stages:
for signal in description["Ideal_signals"]:
curve = self._create_curve_ideal(signal, ideal_data[stage], events[stage][0], events[stage][1])
if curve:
plot_widget.addItem(curve)
if settings["performance"] and all([stage in dataframe_headers for stage in self._stages]):
delta_timestamp = 0
for stage in self._stages:
start_timestamp, finish_timestamp = self._get_timestamp(stage, time_axis, dataframe)
delta_timestamp += finish_timestamp - start_timestamp
if settings["performance"]:
ideal_delta = ideal_data["Ideal cycle"]
delta = 0
for stage in stages:
delta += events[stage][1] - events[stage][0]
performance = ideal_delta/delta*100
performance_list.append(performance)
ideal_delta = self._opt.get_cycle_time()
performance = round(ideal_delta/delta_timestamp*100, 2)
performance_label = QLabel(f"Performance = {performance} %")
layout.addWidget(performance_label)
if settings["zoom"]:
pass
"""if max(time_axis) < 5.0:
stages = [self.get_stage_info("Welding",
dataframe,
signal["name"]) for signal in description["Real_signals"]]
if stages:
means_raw = [stage.mean_value for stage in stages]
mean = max(means_raw)
start = time_axis[stages[0].start_index]
finish = time_axis[stages[0].finish_index]
if settings["zoom"]:
if max(time_axis) < 5.0:
stages = [self.get_stage_info("Welding",
dataframe,
signal["name"]) for signal in description["Real_signals"]]
if stages:
means_raw = [stage.mean_value for stage in stages]
mean = max(means_raw)
start = time_axis[stages[0].start_index]
finish = time_axis[stages[0].finish_index]
overshoot = pg.BarGraphItem(x0=0,
y0=mean - mean * 0.05,
height=mean * 0.05 * 2,
width=start,
brush=pg.mkBrush([0, 250, 0, 100]))
plot_widget.addItem(overshoot)
overshoot = pg.BarGraphItem(x0=0,
y0=mean - mean * 0.05,
height=mean * 0.05 * 2,
width=start,
stable = pg.BarGraphItem(x0=start,
y0=mean - mean * 0.015,
height=mean * 0.015 * 2,
width=finish - start,
brush=pg.mkBrush([0, 250, 0, 100]))
plot_widget.addItem(overshoot)
plot_widget.addItem(stable)
stable = pg.BarGraphItem(x0=start,
y0=mean - mean * 0.015,
height=mean * 0.015 * 2,
width=finish - start,
brush=pg.mkBrush([0, 250, 0, 100]))
plot_widget.addItem(stable)
plot_widget.setYRange(mean - 260, mean + 260)
plot_widget.setInteractive(False)
else:
max_value = min([max(dataframe[signal["name"]]) for signal in description["Real_signals"]])
region = pg.LinearRegionItem([max_value - max_value * 0.015,
max_value + max_value * 0.015],
movable=False,
orientation="horizontal")
plot_widget.setYRange(mean - 260, mean + 260)
plot_widget.setInteractive(False)
else:
max_value = min([max(dataframe[signal["name"]]) for signal in description["Real_signals"]])
region = pg.LinearRegionItem([max_value - max_value * 0.015,
max_value + max_value * 0.015],
movable=False,
orientation="horizontal")
region.setBrush(pg.mkBrush([0, 250, 0, 100]))
plot_widget.setYRange(max_value - 200, max_value + 200)
plot_widget.setXRange(3.5, 4.5)
plot_widget.addItem(region)
plot_widget.setInteractive(False)
region.setBrush(pg.mkBrush([0, 250, 0, 100]))
plot_widget.setYRange(max_value - 200, max_value + 200)
plot_widget.setXRange(3.5, 4.5)
plot_widget.addItem(region)
plot_widget.setInteractive(False)"""
for signal in description["Real_signals"]:
if signal["name"] in dataframe_headers:
plot = plot_widget.plot(time_axis, dataframe[signal["name"]], pen=signal["pen"])
plot = plot_widget.plot(df_continuous["time"], df_continuous[signal["name"]], pen=signal["pen"])
legend.addItem(plot, signal["name"])
if settings["performance"]:
performance_list = np.array(performance_list)
performance_label = QLabel(f"""Performance: best = {round(performance_list.max(),2)} %, worse = {round(performance_list.min(),2)} %, average = {round(performance_list.mean(),2)}%""")
layout.addWidget(performance_label)
layout.addWidget(plot_widget)
widget.setLayout(layout)
@ -203,8 +160,5 @@ class PlotWidget(BasePlotWidget):
widgets = [self._build_widget(data_sample) for data_sample in data]
self._mediator.notify(self, widgets)
def update_settings(self, data: list[dict]):
self._initIdealBuilder(idealDataBuilder=idealDataBuilder, data=data)

View File

@ -1,55 +1,103 @@
import pyqtgraph as pg
from pyqtgraph.Qt import QtWidgets
from pyqtgraph.parametertree import Parameter, ParameterTree
from PyQt5.QtWidgets import QWidget, QTableWidget, QVBoxLayout, QTableWidgetItem, QLabel, QPushButton, QLineEdit, QHBoxLayout
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QIntValidator
from src.utils.json_tools import read_json, write_json
from src.gui import qt_settings as qts
class settingsWindow(QtWidgets.QWidget):
class settingsWindow(QWidget):
def __init__(self, path: str, name: str, upd_func):
super(settingsWindow, self).__init__()
self.settingsPath = path
self.name = name
self.data = {}
self.params = None
self._settingsPath = path
self._name = name
self._data = {}
self._upd_func = upd_func
self.load_settings()
self._init_ui()
self.params.sigTreeStateChanged.connect(upd_func)
def load_settings(self) -> None:
self.data = read_json(self.settingsPath)
self._data = read_json(self._settingsPath)
def write_settings(self) -> None:
self.getParams()
write_json(self.settingsPath, self.data)
write_json(self._settingsPath, self._data)
def getParams(self) -> dict:
return self._data
def _getTreeStructure(self) -> list:
params = []
for key, value in self.data.items():
params.append({'name': str(key), 'type': type(value).__name__, 'value': value})
params.append({'name': 'Save', 'type': 'action'})
return params
def _init_ui(self) -> None:
temp = self._getTreeStructure()
self.params = Parameter.create(name=self.name, type='group', children=temp)
self.params.param('Save').sigActivated.connect(self.write_settings)
save_button = QPushButton()
restore_button = QPushButton()
save_button.setText("Save")
restore_button.setText("Restore")
self._num_points = QLineEdit()
self._num_points.setPlaceholderText("Enter the number of welding points")
self._num_points.setValidator(QIntValidator())
control_layout = QHBoxLayout()
control_layout.addWidget(save_button)
control_layout.addWidget(restore_button)
control_layout.addWidget(self._num_points)
ParamsTree = ParameterTree()
ParamsTree.setParameters(self.params, showTop=True)
layout = QtWidgets.QGridLayout()
layout.addWidget(ParamsTree, 0,0)
save_button.pressed.connect(self._save)
restore_button.pressed.connect(self._restore)
self._num_points.editingFinished.connect(self._expand)
self._param_table = QTableWidget()
self._param_table.setColumnCount(2)
self._param_table.setRowCount(len(self._data))
for i, (key, items) in enumerate(self._data.items()):
self._param_table.setItem(i, 0, QTableWidgetItem(key))
self._param_table.setItem(i, 1, QTableWidgetItem(str(items[0])))
layout = QVBoxLayout()
header = QLabel(self._name)
layout.addWidget(header)
layout.addLayout(control_layout)
layout.addWidget(self._param_table)
self.setLayout(layout)
self.setStyleSheet(qts.white_style)
# self.show()
#self.show()
def getParams(self) -> dict:
self.data = {}
for p in self.params:
if p.name() != 'Save':
self.data[p.name()] = p.value()
return self.data
def _save(self) -> dict:
self._data = {}
for i in range(self._param_table.rowCount()):
key = self._param_table.item(i, 0).text()
data = []
for j in range(1, self._param_table.columnCount()):
param = self._param_table.item(i, j).text()
if key != "trace_storage_path":
param = float(param)
data.append(param)
self._data[key] = data
self.write_settings()
self._upd_func()
def _restore(self) -> None:
self._param_table.setRowCount(len(self._data))
self._param_table.setColumnCount(len(self._data[self._data.keys()[0]]))
for i, (key, items) in enumerate(self._data.items()):
self._param_table.setItem(i, 0, QTableWidgetItem(key))
for j, item in enumerate(items):
self._param_table.setItem(i, j+1, QTableWidgetItem(str(item)))
def _expand(self) -> None:
param=int(self._num_points.text())
prev_columns = self._param_table.columnCount()
self._param_table.setColumnCount(param+1)
if prev_columns < param+1:
for i in range(prev_columns, param+1):
for j, (key, items) in enumerate(self._data.items()):
self._param_table.setItem(j, i, QTableWidgetItem(str(items[-1])))
if __name__ == '__main__':
app = pg.mkQApp("Parameter Tree Example")

View File

@ -7,6 +7,7 @@ from src.controller.mediator import Mediator
from src.controller.converter import DataConverter
from src.gui.plotter import PlotWidget
from src.controller.controller import Controller
from src.controller.passportFormer import PassportFormer
def main():
@ -15,8 +16,9 @@ def main():
data_converter = DataConverter()
plot_widget_builder = PlotWidget()
controller = Controller()
passport_former = PassportFormer()
window = MainWindow(controller)
mediator = Mediator(monitor, data_converter, plot_widget_builder, controller)
mediator = Mediator(monitor, data_converter, passport_former, plot_widget_builder, controller)
window.show()
controller.signal_widgets.connect(window.show_plot_tabs)

View File

@ -2,6 +2,7 @@ from typing import Optional
import os
import numpy as np
import pandas as pd
from intervaltree import Interval, IntervalTree
from roboter import RobotPerformance, TWC_Performance
@ -10,8 +11,25 @@ class PerformanceProcessor:
def calc_performance(self, path, df):
robot = RobotPerformance()
TWC = TWC_Performance()
rob_df = robot.job(path)
TWC_df = TWC.job(df)
point_tree, movement_tree, dialog_tree = robot.job(path)
closing_tree, squeeze_tree, relief_tree = TWC.job(df)
dialog_inPoint = point_tree & dialog_tree
dialog_inMovement = movement_tree & dialog_tree
closing_inPoint = point_tree & closing_tree
closing_inMovement = movement_tree & closing_tree
squeeze_inPoint = point_tree & squeeze_tree
squeeze_inMovement = movement_tree & squeeze_tree
relief_inPoint = point_tree & relief_tree
relief_inMovement = movement_tree & relief_tree
@ -20,4 +38,5 @@ if __name__ == "__main__":
robot = RobotPerformance()
#TWC = TWC_Performance()
result = robot.job(path)
print (result)
print (result[0])
print (result[1])

View File

@ -5,6 +5,8 @@ import os
import numpy as np
import pandas as pd
from intervaltree import Interval, IntervalTree
class BasePerformanceFactory(ABC):
@ -88,16 +90,35 @@ class BaseProduct(ABC):
stage_diff = np.diff(dataframe[signal])
start_idx = np.where(stage_diff == 1)
finish_idx = np.where(stage_diff == -1)
return start_idx, finish_idx
return start_idx[0], finish_idx[0]
def operation(self, dataframe: pd.DataFrame) -> pd.DataFrame:
all_idx = np.array([])
for signal in self._signals:
def _find_events(self,
dataframe: pd.DataFrame,
signals: list[str]) -> Optional[dict[dict[pd.Series]]]:
intervals = {}
end_time = 0
for signal in signals:
start_idx, finish_idx = np.array(self._find_indexes(signal, dataframe))
all_idx = np.hstack([all_idx, start_idx[0], finish_idx[0]])
all_idx = np.sort(np.array(all_idx, dtype="int64"))
result = dataframe.loc[all_idx, self._signals + ["time"]]
return result
start_series = dataframe.loc[start_idx, "time"].reset_index(drop=True)
end_series = dataframe.loc[finish_idx, "time"].reset_index(drop=True)
end_series.fillna(end_time)
intervals[signal] = {"rise": start_series,
"fall": end_series}
return intervals
def _form_intervals(self,
start: pd.Series,
end: pd.Series) -> IntervalTree:
if len(start) != len(end):
for i in range(1, len(end)):
if end[i-1] > start[i]:
start = start.drop(i).reset_index(drop=True)
tree = IntervalTree(Interval(start[i], end[i], i) for i in range(len (start)))
return tree
@abstractmethod
def operation(self):
...
class RobotPerformance(BasePerformanceFactory):
@ -105,33 +126,18 @@ class RobotPerformance(BasePerformanceFactory):
def factory_method(self) -> BaseProduct:
return RobotDF()
def job(self, path) -> pd.DataFrame:
def job(self, path) -> list[pd.DataFrame]:
product = self.factory_method()
dataframe = self._get_file_data(path)
rob_df = product.operation(dataframe)
in_point, in_moving, in_dialog = False, False, False
for index, row in rob_df.iterrows():
if row["$OUT3012"] == 1:
if not in_point:
in_point = True
start_point = row["time"]
else:
in_point = False
time_in_point = row["time"] - start_point
return rob_df
class TWC_Performance(BasePerformanceFactory):
def factory_method(self) -> BaseProduct:
return TWC_DF()
def job(self, TWC_DF: pd.DataFrame) -> pd.DataFrame:
def job(self, TWC_DF: pd.DataFrame) -> list[pd.DataFrame]:
product = self.factory_method()
result = product.operation(TWC_DF)
return result
@ -145,6 +151,13 @@ class RobotDF(BaseProduct):
"$OUT3003"
]
def operation(self, dataframe: pd.DataFrame) -> list[IntervalTree]:
events = self._find_events(dataframe, self._signals)
point_tree = self._form_intervals(start=events["$OUT3012"]["rise"], end=events["$OUT3012"]["fall"])
movement_tree = self._form_intervals(start=events["$OUT3003"]["fall"], end=events["$OUT3012"]["rise"])
dialog_tree = []
return point_tree, movement_tree, dialog_tree
class TWC_DF(BaseProduct):
def __init__(self):
@ -155,6 +168,13 @@ class TWC_DF(BaseProduct):
"Relief"
]
def operation(self, dataframe: pd.DataFrame) -> list[IntervalTree]:
events = self._find_events(dataframe, self._signals)
closing_tree = self._form_intervals(start=events["Closing"]["rise"], end=events["Closing"]["fall"])
squeeze_tree = self._form_intervals(start=events["Squeeze"]["rise"], end=events["Squeeze"]["fall"])
relief_tree = self._form_intervals(start=events["Relief"]["rise"], end=events["Relief"]["fall"])
return closing_tree, squeeze_tree, relief_tree

View File

@ -8,26 +8,33 @@ from PyQt5.QtCore import QThread, QObject, QTimer
from PyQt5.QtWidgets import QWidget, QTabWidget
from src.OptAlgorithm import OptAlgorithm
import pandas as pd
import pandas as pd
import numpy as np
class BaseMediator:
def __init__(self,
monitor: BaseDirectoryMonitor,
converter: BaseDataConverter,
passportFormer: BasePointPassportFormer,
plot: BasePlotWidget,
controller: BaseController):
self._monitor = monitor
self._monitor.mediator = self
self._converter = converter
self._converter.mediator = self
self._passportFormer = passportFormer
self._passportFormer.mediator = self
self._plot = plot
self._plot.mediator = self
self._controller = controller
self._controller.mediator = self
def notify(self,
source: Union[BaseDirectoryMonitor, BaseDataConverter, BasePlotWidget, BaseMainWindow],
data: Union[list[str], list[pd.DataFrame], list[QWidget], list[dict]]):
source: Union[BaseDirectoryMonitor, BaseDataConverter, BasePointPassportFormer, BasePlotWidget],
data: Union[list[str], list[pd.DataFrame], list[list], list[QWidget]]):
...
def push_settings (self, data: list[dict]):
...
@ -102,27 +109,22 @@ class BasePlotWidget:
mediator: Optional[BaseMediator] = None):
super().__init__()
self._mediator = mediator
self._stages = [
"Closing",
"Squeeze",
"Welding",
"Relief"
]
self._stage_colors = {
"Closing": [208, 28, 31, 100],
"Squeeze": [45, 51, 89, 150],
"Welding": [247, 183, 24, 100],
"Relief": [0, 134, 88, 100],
"Oncoming": [222, 184, 135, 100]
"Oncomming": [222, 184, 135, 100]
}
self._plt_channels = {
"Electrode Force, N & Welding Current, kA": {
"Settings": {
"zoom": False,
"stages": True,
"performance": True
"performance": True,
"ideals": True
},
"Real_signals": [
{
@ -149,7 +151,8 @@ class BasePlotWidget:
"Settings": {
"zoom": True,
"stages": False,
"performance": False
"performance": False,
"ideals": True
},
"Real_signals": [
{
@ -172,7 +175,8 @@ class BasePlotWidget:
"Settings": {
"zoom": False,
"stages": True,
"performance": False
"performance": False,
"ideals": True
},
"Real_signals": [
{
@ -200,18 +204,7 @@ class BasePlotWidget:
]
},
}
def _initIdealBuilder(self,
idealDataBuilder: Optional[BaseIdealDataBuilder] = None,
data: list[dict] = None):
self.opt = idealDataBuilder(data)
self._stage_ideals = {
"Closing": self._opt.get_closingDF(),
"Squeeze": self._opt.get_compressionDF(),
"Welding": self._opt.get_weldingDF(),
"Relief": self._opt.get_openingDF(),
"Oncoming": self._opt.get_oncomingDF()
}
@property
def mediator(self) -> BaseMediator:
return self._mediator
@ -231,8 +224,6 @@ class BasePlotWidget:
def build(self, data: list[pd.DataFrame]) -> list[QWidget]:
...
def update_settings(self, data: list[dict]) -> None:
...
class BaseController(QObject):
@ -243,10 +234,10 @@ class BaseController(QObject):
...
# FIXME: WeldingDF показывает только 1 секунду
class BaseIdealDataBuilder(OptAlgorithm):
def __init__(self, data: list[dict]):
operator_params, system_params = data
def __init__(self, params: list[dict]):
operator_params, system_params = params
self.mul = system_params['time_capture']
self.welding_time = operator_params['time_wielding']
super().__init__(operator_params, system_params)
@ -337,4 +328,85 @@ class BaseMainWindow(QWidget):
}
""")
class BasePointPassportFormer:
def __init__(self,
mediator: Optional[BaseMediator] = None):
self._mediator = mediator
self._clear_stage = "Welding"
self._stages = [
"Closing",
"Squeeze",
"Welding",
"Relief",
"Oncomming"
]
def _find_indexes(self,
signal: str,
dataframe: pd.DataFrame) -> list[list[float], list[float]]:
stage_diff = np.diff(dataframe[signal])
start_idx = np.where(stage_diff == 1)
finish_idx = np.where(stage_diff == -1)
return start_idx[0], finish_idx[0]
def _find_events(self,
signal: str,
times:pd.Series,
dataframe: pd.DataFrame) -> list[list[float]]:
start_idx, finish_idx = self._find_indexes(signal, dataframe)
start_list = times.loc[start_idx].tolist()
end_list = times.loc[finish_idx].tolist()
if len(start_list) - len(end_list) == 1:
end_list.append(float(times[len(times)-1]))
return start_list, end_list
def _filter_events(self,
times: pd.Series,
dataframe: pd.DataFrame) -> list[dict[list[float]], int]:
events = {}
if self._clear_stage in self._stages:
start_list, end_list = self._find_events(self._clear_stage, times, dataframe)
point_quantity = len(start_list)
for stage in self._stages:
start_list, end_list = self._find_events(stage, times, dataframe)
events[stage] = [start_list[:point_quantity], end_list[:point_quantity]]
return events, point_quantity
def _build_ideal_data(self,
idealDataBuilder: Optional[BaseIdealDataBuilder] = None,
params: list[dict] = None) -> dict:
self.opt = idealDataBuilder(params)
stage_ideals = {
"Closing": self._opt.get_closingDF(),
"Squeeze": self._opt.get_compressionDF(),
"Welding": self._opt.get_weldingDF(),
"Relief": self._opt.get_openingDF(),
"Oncomming": self._opt.get_oncomingDF(),
"Ideal cycle": self._opt.get_cycle_time()
}
return stage_ideals
def form_passports(self) -> list[list[pd.DataFrame, dict, list]]:
...
def update_settings(self, params: list) -> None:
...
@property
def opt(self) -> BaseIdealDataBuilder:
return self._opt
@opt.setter
def opt(self, opt: BaseIdealDataBuilder):
self._opt = opt
@property
def mediator(self) -> BaseMediator:
return self._mediator
@mediator.setter
def mediator(self, mediator: BaseMediator) -> None:
self._mediator = mediator

BIN
weldingSpotPerformance.7z Normal file

Binary file not shown.