2024-11-25 14:01:09 +03:00
|
|
|
from __future__ import annotations
|
|
|
|
|
|
|
|
|
|
import os
|
|
|
|
|
from typing import Optional, Union
|
|
|
|
|
|
|
|
|
|
import pandas as pd
|
|
|
|
|
from PyQt5.QtCore import QThread, QObject, QTimer
|
2024-11-25 17:20:00 +03:00
|
|
|
from PyQt5.QtWidgets import QWidget, QTabWidget
|
2024-11-25 14:01:09 +03:00
|
|
|
from src.OptAlgorithm import OptAlgorithm
|
|
|
|
|
import pandas as pd
|
2024-12-03 17:21:22 +03:00
|
|
|
import pandas as pd
|
|
|
|
|
import numpy as np
|
|
|
|
|
|
|
|
|
|
|
2024-11-25 14:01:09 +03:00
|
|
|
|
|
|
|
|
|
|
|
|
|
class BaseMediator:
|
|
|
|
|
def __init__(self,
|
|
|
|
|
monitor: BaseDirectoryMonitor,
|
|
|
|
|
converter: BaseDataConverter,
|
2024-12-04 20:01:30 +03:00
|
|
|
passportFormer: BasePointPassportFormer,
|
2024-11-25 14:01:09 +03:00
|
|
|
plot: BasePlotWidget,
|
2024-11-26 18:16:55 +03:00
|
|
|
controller: BaseController):
|
2024-11-25 14:01:09 +03:00
|
|
|
self._monitor = monitor
|
|
|
|
|
self._monitor.mediator = self
|
|
|
|
|
self._converter = converter
|
|
|
|
|
self._converter.mediator = self
|
2024-12-04 20:01:30 +03:00
|
|
|
self._passportFormer = passportFormer
|
|
|
|
|
self._passportFormer.mediator = self
|
2024-11-25 14:01:09 +03:00
|
|
|
self._plot = plot
|
|
|
|
|
self._plot.mediator = self
|
|
|
|
|
self._controller = controller
|
2024-11-26 18:16:55 +03:00
|
|
|
self._controller.mediator = self
|
2024-11-25 14:01:09 +03:00
|
|
|
|
|
|
|
|
def notify(self,
|
2024-12-04 20:01:30 +03:00
|
|
|
source: Union[BaseDirectoryMonitor, BaseDataConverter, BasePointPassportFormer, BasePlotWidget],
|
|
|
|
|
data: Union[list[str], list[pd.DataFrame], list[list], list[QWidget]]):
|
2024-11-25 17:20:00 +03:00
|
|
|
...
|
|
|
|
|
def push_settings (self, data: list[dict]):
|
2024-11-25 14:01:09 +03:00
|
|
|
...
|
|
|
|
|
|
|
|
|
|
class BaseDirectoryMonitor:
|
|
|
|
|
|
|
|
|
|
update_timer = QTimer()
|
|
|
|
|
|
|
|
|
|
def __init__(self,
|
|
|
|
|
mediator: Optional[BaseMediator] = None):
|
|
|
|
|
super().__init__()
|
2024-11-25 17:20:00 +03:00
|
|
|
self._directory_path = None
|
|
|
|
|
self._update_time = None
|
2024-11-25 14:01:09 +03:00
|
|
|
|
|
|
|
|
self._mediator = mediator
|
2024-11-25 17:20:00 +03:00
|
|
|
|
2024-11-25 14:01:09 +03:00
|
|
|
|
|
|
|
|
@property
|
|
|
|
|
def directory_path(self) -> str:
|
|
|
|
|
return self._directory_path
|
|
|
|
|
|
|
|
|
|
@property
|
|
|
|
|
def update_time(self) -> int:
|
|
|
|
|
return self._update_time
|
|
|
|
|
|
|
|
|
|
@property
|
|
|
|
|
def files(self) -> list[str]:
|
|
|
|
|
return self._files
|
|
|
|
|
|
|
|
|
|
@property
|
|
|
|
|
def mediator(self) -> BaseMediator:
|
|
|
|
|
return self._mediator
|
|
|
|
|
|
|
|
|
|
@mediator.setter
|
|
|
|
|
def mediator(self, mediator: BaseMediator) -> None:
|
|
|
|
|
self._mediator = mediator
|
|
|
|
|
|
|
|
|
|
def _init_state(self):
|
|
|
|
|
files = os.listdir(self._directory_path)
|
|
|
|
|
self._files = files
|
|
|
|
|
|
|
|
|
|
def start(self):
|
|
|
|
|
self.update_timer.start(self._update_time)
|
|
|
|
|
|
2024-11-25 17:20:00 +03:00
|
|
|
def stop(self):
|
|
|
|
|
self.update_timer.stop()
|
|
|
|
|
|
|
|
|
|
def update_settings(self, data: list[dict]) -> None:
|
|
|
|
|
...
|
|
|
|
|
|
|
|
|
|
def force_all_dir(self):
|
|
|
|
|
...
|
|
|
|
|
|
2024-11-25 14:01:09 +03:00
|
|
|
class BaseDataConverter:
|
|
|
|
|
def __init__(self, mediator: Optional[BaseMediator] = None):
|
|
|
|
|
self._mediator = mediator
|
|
|
|
|
|
|
|
|
|
@property
|
|
|
|
|
def mediator(self) -> BaseMediator:
|
|
|
|
|
return self._mediator
|
|
|
|
|
|
|
|
|
|
@mediator.setter
|
|
|
|
|
def mediator(self, mediator: BaseMediator) -> None:
|
|
|
|
|
self._mediator = mediator
|
|
|
|
|
|
|
|
|
|
def convert_data(self, files: list[str]) -> None:
|
|
|
|
|
...
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class BasePlotWidget:
|
|
|
|
|
def __init__(self,
|
2024-11-25 17:20:00 +03:00
|
|
|
mediator: Optional[BaseMediator] = None):
|
2024-11-25 14:01:09 +03:00
|
|
|
super().__init__()
|
|
|
|
|
self._mediator = mediator
|
2024-12-03 17:21:22 +03:00
|
|
|
|
2024-11-25 14:01:09 +03:00
|
|
|
|
|
|
|
|
self._stage_colors = {
|
|
|
|
|
"Closing": [208, 28, 31, 100],
|
|
|
|
|
"Squeeze": [45, 51, 89, 150],
|
2024-12-05 12:02:07 +03:00
|
|
|
"Welding": [64, 64, 64, 100],
|
2024-12-02 12:09:31 +03:00
|
|
|
"Relief": [0, 134, 88, 100],
|
2024-12-05 12:02:07 +03:00
|
|
|
"Oncomming": [255, 79, 0, 100]
|
2024-11-25 14:01:09 +03:00
|
|
|
}
|
|
|
|
|
self._plt_channels = {
|
|
|
|
|
"Electrode Force, N & Welding Current, kA": {
|
|
|
|
|
"Settings": {
|
|
|
|
|
"zoom": False,
|
2024-12-02 11:04:15 +03:00
|
|
|
"stages": True,
|
2024-12-04 20:01:30 +03:00
|
|
|
"performance": True,
|
|
|
|
|
"ideals": True
|
2024-11-25 14:01:09 +03:00
|
|
|
},
|
|
|
|
|
"Real_signals": [
|
|
|
|
|
{
|
|
|
|
|
"name": "Electrode Force, N ME",
|
|
|
|
|
"pen": 'r',
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"name": "Electrode Force, N FE",
|
|
|
|
|
"pen": 'w',
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"name": "Welding Current ME",
|
|
|
|
|
"pen": "y",
|
|
|
|
|
}
|
|
|
|
|
],
|
|
|
|
|
"Ideal_signals": [
|
|
|
|
|
{
|
|
|
|
|
"name": "Force",
|
|
|
|
|
"pen": {'color': 'g', 'width':3},
|
|
|
|
|
}
|
|
|
|
|
]
|
|
|
|
|
},
|
2024-12-05 11:19:55 +03:00
|
|
|
"Electrode Posicion, mm": {
|
2024-11-25 14:01:09 +03:00
|
|
|
"Settings": {
|
2024-12-05 11:19:55 +03:00
|
|
|
"zoom": False,
|
|
|
|
|
"stages": True,
|
2024-12-04 20:01:30 +03:00
|
|
|
"performance": False,
|
|
|
|
|
"ideals": True
|
2024-11-25 14:01:09 +03:00
|
|
|
},
|
|
|
|
|
"Real_signals": [
|
|
|
|
|
{
|
2024-12-05 11:19:55 +03:00
|
|
|
"name": "Rotor Position, mm ME",
|
2024-11-25 14:01:09 +03:00
|
|
|
"pen": 'r',
|
|
|
|
|
},
|
|
|
|
|
{
|
2024-12-05 11:19:55 +03:00
|
|
|
"name": "Rotor Position, mm FE",
|
2024-11-25 14:01:09 +03:00
|
|
|
"pen": 'w',
|
|
|
|
|
}
|
|
|
|
|
],
|
|
|
|
|
"Ideal_signals": [
|
|
|
|
|
{
|
2024-12-05 11:19:55 +03:00
|
|
|
"name": "Posicion ME",
|
|
|
|
|
"pen": {'color': 'g', 'width':3},
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"name": "Posicion ME",
|
|
|
|
|
"pen": {'color': 'b', 'width':3},
|
2024-11-25 14:01:09 +03:00
|
|
|
}
|
|
|
|
|
]
|
|
|
|
|
},
|
|
|
|
|
"Electrode Speed, mm/s": {
|
|
|
|
|
"Settings": {
|
|
|
|
|
"zoom": False,
|
2024-12-02 11:04:15 +03:00
|
|
|
"stages": True,
|
2024-12-04 20:01:30 +03:00
|
|
|
"performance": False,
|
|
|
|
|
"ideals": True
|
2024-11-25 14:01:09 +03:00
|
|
|
},
|
|
|
|
|
"Real_signals": [
|
|
|
|
|
{
|
|
|
|
|
"name": "Rotor Speed, mm/s ME",
|
|
|
|
|
"pen": 'r',
|
|
|
|
|
"zoom": False
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"name": "Rotor Speed, mm/s FE",
|
|
|
|
|
"pen": 'w',
|
|
|
|
|
"zoom": False
|
|
|
|
|
}
|
|
|
|
|
],
|
|
|
|
|
"Ideal_signals": [
|
|
|
|
|
{
|
|
|
|
|
"name": "Rotor Speed ME",
|
|
|
|
|
"pen": {'color': 'y', 'width':3},
|
|
|
|
|
"zoom": False
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"name": "Rotor Speed FE",
|
|
|
|
|
"pen": {'color': 'g', 'width':3},
|
|
|
|
|
"zoom": False
|
|
|
|
|
}
|
|
|
|
|
]
|
|
|
|
|
},
|
|
|
|
|
}
|
2024-12-03 17:21:22 +03:00
|
|
|
|
2024-11-25 14:01:09 +03:00
|
|
|
@property
|
|
|
|
|
def mediator(self) -> BaseMediator:
|
|
|
|
|
return self._mediator
|
|
|
|
|
|
|
|
|
|
@mediator.setter
|
|
|
|
|
def mediator(self, mediator: BaseMediator) -> None:
|
|
|
|
|
self._mediator = mediator
|
2024-11-25 17:20:00 +03:00
|
|
|
|
|
|
|
|
@property
|
|
|
|
|
def opt(self) -> BaseIdealDataBuilder:
|
|
|
|
|
return self._opt
|
|
|
|
|
|
|
|
|
|
@opt.setter
|
|
|
|
|
def opt(self, opt: BaseIdealDataBuilder):
|
|
|
|
|
self._opt = opt
|
2024-11-25 14:01:09 +03:00
|
|
|
|
|
|
|
|
def build(self, data: list[pd.DataFrame]) -> list[QWidget]:
|
|
|
|
|
...
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class BaseController(QObject):
|
|
|
|
|
|
|
|
|
|
def send_widgets(self, widgets: list[QWidget]) -> None:
|
|
|
|
|
...
|
|
|
|
|
|
2024-11-26 18:16:55 +03:00
|
|
|
def push_settings(self, settings: list[dict]) -> None:
|
|
|
|
|
...
|
2024-11-25 14:01:09 +03:00
|
|
|
|
2024-11-25 17:20:00 +03:00
|
|
|
|
2024-11-25 14:01:09 +03:00
|
|
|
class BaseIdealDataBuilder(OptAlgorithm):
|
2024-12-04 20:01:30 +03:00
|
|
|
|
2024-12-03 17:21:22 +03:00
|
|
|
def __init__(self, params: list[dict]):
|
|
|
|
|
operator_params, system_params = params
|
2024-11-25 17:20:00 +03:00
|
|
|
self.mul = system_params['time_capture']
|
2024-12-02 11:04:15 +03:00
|
|
|
self.welding_time = operator_params['time_wielding']
|
2024-11-25 17:20:00 +03:00
|
|
|
super().__init__(operator_params, system_params)
|
2024-11-25 14:01:09 +03:00
|
|
|
|
|
|
|
|
def _get_data(self, end_timestamp:float, func:function) -> pd.DataFrame:
|
|
|
|
|
data = []
|
|
|
|
|
for i in range (0, int(end_timestamp*self.mul)):
|
|
|
|
|
time = i/self.mul
|
|
|
|
|
X1, X2, V1, V2, F = func(time)
|
|
|
|
|
data.append({"time":time, "Posicion FE":X1*1000,"Posicion ME":X2*1000, "Rotor Speed FE":V1*1000, "Rotor Speed ME":V2*1000, "Force":F})
|
|
|
|
|
return pd.DataFrame(data)
|
|
|
|
|
|
|
|
|
|
def get_closingDF(self) -> pd.DataFrame:
|
2024-11-25 17:20:00 +03:00
|
|
|
...
|
2024-11-25 14:01:09 +03:00
|
|
|
|
|
|
|
|
def get_compressionDF(self) -> pd.DataFrame:
|
2024-11-25 17:20:00 +03:00
|
|
|
...
|
2024-11-25 14:01:09 +03:00
|
|
|
|
|
|
|
|
def get_openingDF(self) -> pd.DataFrame:
|
2024-11-25 17:20:00 +03:00
|
|
|
...
|
2024-11-25 14:01:09 +03:00
|
|
|
|
|
|
|
|
def get_tmovementDF(self) -> pd.DataFrame:
|
2024-11-25 17:20:00 +03:00
|
|
|
...
|
2024-11-25 14:01:09 +03:00
|
|
|
|
2024-12-02 11:04:15 +03:00
|
|
|
def get_weldingDF(self) -> pd.DataFrame:
|
2024-11-25 17:20:00 +03:00
|
|
|
...
|
2024-12-02 12:09:31 +03:00
|
|
|
|
|
|
|
|
def get_oncomingDF(self) -> pd.DataFrame:
|
|
|
|
|
...
|
2024-11-25 14:01:09 +03:00
|
|
|
|
|
|
|
|
def get_ideal_timings(self) -> list[float, float, float, float]:
|
2024-11-25 17:20:00 +03:00
|
|
|
...
|
|
|
|
|
|
2024-12-02 11:04:15 +03:00
|
|
|
def get_cycle_time(self) -> float:
|
|
|
|
|
result = sum(self.get_ideal_timings())
|
|
|
|
|
return result
|
2024-11-25 14:01:09 +03:00
|
|
|
|
2024-11-25 17:20:00 +03:00
|
|
|
class BaseMainWindow(QWidget):
|
|
|
|
|
def __init__(self,
|
2024-11-26 18:16:55 +03:00
|
|
|
controller: Optional[BaseController] = None):
|
2024-11-25 17:20:00 +03:00
|
|
|
super().__init__()
|
2024-11-26 18:16:55 +03:00
|
|
|
self._controller = controller
|
2024-11-26 18:28:05 +03:00
|
|
|
...
|
2024-11-25 17:20:00 +03:00
|
|
|
|
|
|
|
|
@property
|
2024-11-26 18:16:55 +03:00
|
|
|
def controller(self) -> BaseController:
|
|
|
|
|
return self._controller
|
2024-11-25 17:20:00 +03:00
|
|
|
|
2024-11-26 18:16:55 +03:00
|
|
|
@controller.setter
|
|
|
|
|
def controller(self, controller: BaseController) -> None:
|
|
|
|
|
self._controller = controller
|
2024-11-25 17:20:00 +03:00
|
|
|
|
|
|
|
|
def set_style(self, object: Union[QTabWidget, QWidget]) -> None:
|
|
|
|
|
object.setStyleSheet("""
|
|
|
|
|
QWidget {
|
|
|
|
|
background-color: #0D1117;
|
|
|
|
|
font-family: "Segoe UI", sans-serif;
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
}
|
|
|
|
|
QMessageBox {
|
|
|
|
|
background-color: #161B22;
|
|
|
|
|
font-family: "Segoe UI", sans-serif;
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
}
|
|
|
|
|
QPushButton {
|
|
|
|
|
background-color: #FFCC00;
|
|
|
|
|
color: #0D1117;
|
|
|
|
|
padding: 12px 25px;
|
|
|
|
|
border: 2px solid #E6B800;
|
|
|
|
|
border-radius: 8px;
|
|
|
|
|
font-family: "Segoe UI", sans-serif;
|
|
|
|
|
font-size: 16px;
|
|
|
|
|
font-weight: bold;
|
|
|
|
|
}
|
|
|
|
|
QPushButton:hover:!disabled {
|
|
|
|
|
background-color: #FFD700;
|
|
|
|
|
}
|
|
|
|
|
QPushButton:disabled {
|
|
|
|
|
background-color: #555555;
|
|
|
|
|
color: #cccccc;
|
|
|
|
|
border: none;
|
|
|
|
|
}
|
|
|
|
|
QLabel {
|
|
|
|
|
color: #ffffff;
|
|
|
|
|
font-size: 16px;
|
|
|
|
|
font-weight: bold;
|
|
|
|
|
font-family: "Segoe UI", sans-serif;
|
|
|
|
|
}
|
2024-12-02 18:41:02 +03:00
|
|
|
""")
|
|
|
|
|
|
2024-12-03 17:21:22 +03:00
|
|
|
class BasePointPassportFormer:
|
2024-12-04 20:01:30 +03:00
|
|
|
|
|
|
|
|
def __init__(self,
|
|
|
|
|
mediator: Optional[BaseMediator] = None):
|
|
|
|
|
self._mediator = mediator
|
2024-12-03 17:21:22 +03:00
|
|
|
self._clear_stage = "Welding"
|
|
|
|
|
self._stages = [
|
|
|
|
|
"Closing",
|
|
|
|
|
"Squeeze",
|
|
|
|
|
"Welding",
|
2024-12-05 07:31:48 +03:00
|
|
|
"Relief",
|
|
|
|
|
"Oncomming"
|
2024-12-03 17:21:22 +03:00
|
|
|
]
|
2024-12-05 11:19:55 +03:00
|
|
|
self._tesla_stages = [
|
|
|
|
|
"Tesla squeeze",
|
|
|
|
|
"Tesla closing",
|
|
|
|
|
"Tesla welding",
|
|
|
|
|
"Tesla oncomming_relief"
|
|
|
|
|
]
|
2024-12-03 17:21:22 +03:00
|
|
|
|
|
|
|
|
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,
|
2024-12-04 20:01:30 +03:00
|
|
|
dataframe: pd.DataFrame) -> list[dict[list[float]], int]:
|
2024-12-03 17:21:22 +03:00
|
|
|
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]]
|
2024-12-04 20:01:30 +03:00
|
|
|
return events, point_quantity
|
2024-12-03 17:21:22 +03:00
|
|
|
|
2024-12-04 20:01:30 +03:00
|
|
|
def _build_ideal_data(self,
|
2024-12-03 17:21:22 +03:00
|
|
|
idealDataBuilder: Optional[BaseIdealDataBuilder] = None,
|
2024-12-04 20:01:30 +03:00
|
|
|
params: list[dict] = None) -> dict:
|
2024-12-03 17:21:22 +03:00
|
|
|
self.opt = idealDataBuilder(params)
|
|
|
|
|
|
2024-12-04 20:01:30 +03:00
|
|
|
stage_ideals = {
|
2024-12-03 17:21:22 +03:00
|
|
|
"Closing": self._opt.get_closingDF(),
|
|
|
|
|
"Squeeze": self._opt.get_compressionDF(),
|
|
|
|
|
"Welding": self._opt.get_weldingDF(),
|
|
|
|
|
"Relief": self._opt.get_openingDF(),
|
2024-12-04 20:01:30 +03:00
|
|
|
"Oncomming": self._opt.get_oncomingDF(),
|
2024-12-05 12:02:07 +03:00
|
|
|
"Ideal cycle": self._opt.get_cycle_time(),
|
|
|
|
|
"Ideal timings": self._opt.get_ideal_timings()
|
2024-12-03 17:21:22 +03:00
|
|
|
}
|
2024-12-04 20:01:30 +03:00
|
|
|
return stage_ideals
|
|
|
|
|
|
|
|
|
|
def form_passports(self) -> list[list[pd.DataFrame, dict, list]]:
|
|
|
|
|
...
|
2024-12-03 17:21:22 +03:00
|
|
|
|
2024-12-04 20:01:30 +03:00
|
|
|
def update_settings(self, params: list) -> None:
|
2024-12-03 17:21:22 +03:00
|
|
|
...
|
2024-12-04 20:01:30 +03:00
|
|
|
|
2024-12-03 17:21:22 +03:00
|
|
|
|
|
|
|
|
@property
|
|
|
|
|
def opt(self) -> BaseIdealDataBuilder:
|
|
|
|
|
return self._opt
|
|
|
|
|
|
|
|
|
|
@opt.setter
|
|
|
|
|
def opt(self, opt: BaseIdealDataBuilder):
|
2024-12-04 20:01:30 +03:00
|
|
|
self._opt = opt
|
|
|
|
|
|
|
|
|
|
@property
|
|
|
|
|
def mediator(self) -> BaseMediator:
|
|
|
|
|
return self._mediator
|
|
|
|
|
|
|
|
|
|
@mediator.setter
|
|
|
|
|
def mediator(self, mediator: BaseMediator) -> None:
|
|
|
|
|
self._mediator = mediator
|