dev: добавлены настройки, добавлено автоматическое обновление графиков

This commit is contained in:
Andrew 2024-11-25 17:20:00 +03:00
parent a04517a15d
commit 72b002dea3
19 changed files with 204 additions and 113 deletions

View File

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

Binary file not shown.

View File

@ -1,8 +0,0 @@
from src.utils.base.base import BaseIdealDataBuilder
import pandas as pd
class idealDataBuilder(BaseIdealDataBuilder):
def __init__(self,operator_config: dict, system_config: dict):
super().__init__(operator_config, system_config)
self.mul = 10000

View File

@ -19,3 +19,10 @@ class Mediator(BaseMediator):
if issubclass(source.__class__, BasePlotWidget):
self._controller.send_widgets(data)
def push_settings(self, data: list[dict]):
self._monitor.update_settings(data)
self._plot.update_settings(data)
self._monitor.force_all_dir()

View File

@ -26,3 +26,26 @@ class DirectoryMonitor(BaseDirectoryMonitor):
if not files:
self._files = []
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._init_state()
self.start()
def force_all_dir(self):
files = os.listdir(self._directory_path)
self._files = files
all_files = []
for x in self._files:
path = os.path.join(self._directory_path, x)
all_files.append(path)
if all_files:
logger.info(f"Plotting all files: {all_files}")
self._mediator.notify(self, all_files)
else:
logger.info(f"Failed pushing {str(all_files)}")

View File

@ -2,18 +2,25 @@ from datetime import datetime as dt
from PyQt5 import QtWidgets
from PyQt5.QtCore import Qt
from src.utils.base.base_widgets import BaseMainWindow
from src.utils.base.base import BaseMainWindow
from src.gui.settings_window import settingsWindow
class MainWindow(BaseMainWindow):
def __init__(self):
super().__init__()
self.initUI()
self.set_style(self)
self.settings_button.clicked.connect(self._show_settings)
self.operSettings = settingsWindow("params\operator_params.json", 'Operator', self._updater_trigger)
self.sysSettings = settingsWindow("params\system_params.json", 'System', self._updater_trigger)
def initUI(self) -> None:
self.tabWidget = QtWidgets.QTabWidget()
layout = QtWidgets.QVBoxLayout()
layout.addWidget(self.tabWidget)
self.settings_button = QtWidgets.QPushButton("Show settings")
self.settings_button.setFixedWidth(160)
layout.addWidget(self.settings_button)
self.setLayout(layout)
def show_plot_tabs(self, plot_widgets: list[QtWidgets.QWidget]) -> None:
@ -29,4 +36,20 @@ class MainWindow(BaseMainWindow):
if a0.key() == Qt.Key_F5:
self.clear()
def _show_settings(self):
self.operSettings.show()
self.sysSettings.show()
def push_settings(self) -> None:
self._updater_trigger()
def _updater_trigger(self) -> None:
self.tabWidget.clear()
operator_params = self.operSettings.getParams()
system_params = self.sysSettings.getParams()
self._mediator.push_settings(data=[operator_params, system_params])

View File

@ -6,15 +6,42 @@ 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_tmovementDF(self) -> pd.DataFrame:
return self._get_data(self.Ts['tmovement'], self.calcPhaseMovement)
def get_weldingDF(self, end_time: float) -> 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":end_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.getMarkOpen(), data["tmovement"]]
return ideal_timings
class ProcessStage(NamedTuple):
mean_value: floating[Any]
start_index: int
finish_index: int
class PlotWidget(BasePlotWidget):
class PlotWidget(BasePlotWidget):
def _create_stage_ideal(self,
stage: str,
signal: str,
@ -23,7 +50,7 @@ class PlotWidget(BasePlotWidget):
stage_diff = np.diff(dataframe[stage])
start_index = np.where(stage_diff == 1)[0]
finish_index = np.where(stage_diff == -1)[0]
data = self._stage_ideals[stage]()
data = self._stage_ideals[stage]
if start_index.size:
start_timestamp = times[start_index[0]]
@ -32,7 +59,6 @@ class PlotWidget(BasePlotWidget):
return plot
return None
def _create_stage_region(self,
stage: str,
times: pd.Series,
@ -50,7 +76,7 @@ class PlotWidget(BasePlotWidget):
return None
@staticmethod
def _init_plot_widget(title: str) -> (pg.PlotWidget, pg.LegendItem):
def _init_plot_widget(title: str) -> tuple[pg.PlotWidget, pg.LegendItem]:
plot_widget = pg.PlotWidget(title=title)
plot_widget.showGrid(x=True, y=True)
legend = pg.LegendItem((80, 60), offset=(70, 20))
@ -155,4 +181,8 @@ 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

@ -17,10 +17,10 @@ class settingsWindow(QtWidgets.QWidget):
self._init_ui()
self.params.sigTreeStateChanged.connect(upd_func)
def load_settings(self):
def load_settings(self) -> None:
self.data = read_json(self.settingsPath)
def write_settings(self):
def write_settings(self) -> None:
self.getParams()
write_json(self.settingsPath, self.data)
@ -31,7 +31,7 @@ class settingsWindow(QtWidgets.QWidget):
params.append({'name': 'Save', 'type': 'action'})
return params
def _init_ui(self):
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)

View File

@ -7,7 +7,6 @@ from src.gui.mainGui import MainWindow
from src.controller.monitor import DirectoryMonitor
from src.controller.mediator import Mediator
from src.controller.converter import DataConverter
from src.controller.ideal_data_builder import idealDataBuilder
from src.gui.plotter import PlotWidget
from src.controller.controller import Controller
from src.utils.json_tools import read_json
@ -15,17 +14,13 @@ from src.utils.json_tools import read_json
def main():
app = QtWidgets.QApplication(sys.argv)
operator_params = read_json("params/operator_params.json")
system_params = read_json("params/system_params.json")
monitor = DirectoryMonitor(system_params['trace_storage_path'], system_params['monitor_update_period'])
monitor = DirectoryMonitor()
data_converter = DataConverter()
ideal_data_builder = idealDataBuilder(operator_params, system_params)
plot_widget_builder = PlotWidget(idealDataBuilder=ideal_data_builder)
plot_widget_builder = PlotWidget()
controller = Controller()
mediator = Mediator(monitor, data_converter, plot_widget_builder, controller)
monitor.start()
window = MainWindow()
mediator = Mediator(monitor, data_converter, plot_widget_builder, controller, window)
window.push_settings()
window.show()
controller.signal_widgets.connect(window.show_plot_tabs)

View File

@ -5,7 +5,7 @@ from typing import Optional, Union
import pandas as pd
from PyQt5.QtCore import QThread, QObject, QTimer
from PyQt5.QtWidgets import QWidget
from PyQt5.QtWidgets import QWidget, QTabWidget
from src.OptAlgorithm import OptAlgorithm
import pandas as pd
@ -15,7 +15,8 @@ class BaseMediator:
monitor: BaseDirectoryMonitor,
converter: BaseDataConverter,
plot: BasePlotWidget,
controller: BaseController):
controller: BaseController,
window: BaseMainWindow):
self._monitor = monitor
self._monitor.mediator = self
self._converter = converter
@ -23,30 +24,28 @@ class BaseMediator:
self._plot = plot
self._plot.mediator = self
self._controller = controller
self._window = window
self._window.mediator = self
def notify(self,
source: Union[BaseDirectoryMonitor, BaseDataConverter, BasePlotWidget],
data: Union[list[str], list[pd.DataFrame], list[QWidget]]):
source: Union[BaseDirectoryMonitor, BaseDataConverter, BasePlotWidget, BaseMainWindow],
data: Union[list[str], list[pd.DataFrame], list[QWidget], list[dict]]):
...
def push_settings (self, data: list[dict]):
...
class BaseDirectoryMonitor:
update_timer = QTimer()
def __init__(self,
directory_path: str,
update_time: int,
mediator: Optional[BaseMediator] = None):
super().__init__()
self._directory_path = None
self._update_time = None
self._directory_path = directory_path
self._update_time = update_time
self._mediator = mediator
self._files: list[str] = []
self._init_state()
@property
def directory_path(self) -> str:
@ -75,6 +74,15 @@ class BaseDirectoryMonitor:
def start(self):
self.update_timer.start(self._update_time)
def stop(self):
self.update_timer.stop()
def update_settings(self, data: list[dict]) -> None:
...
def force_all_dir(self):
...
class BaseDataConverter:
def __init__(self, mediator: Optional[BaseMediator] = None):
self._mediator = mediator
@ -93,11 +101,9 @@ class BaseDataConverter:
class BasePlotWidget:
def __init__(self,
mediator: Optional[BaseMediator] = None,
idealDataBuilder: Optional[BaseIdealDataBuilder] = None):
mediator: Optional[BaseMediator] = None):
super().__init__()
self._mediator = mediator
self._opt = idealDataBuilder
self._stages = [
"Relief",
@ -112,13 +118,6 @@ class BasePlotWidget:
"Welding": [247, 183, 24, 100],
"Relief": [0, 134, 88, 100]
}
self._stage_ideals = {
"Closing": self._opt.get_closingDF,
"Squeeze": self._opt.get_compressionDF,
"Welding": self._opt.get_weldingDF,
"Relief": self._opt.get_openingDF
}
self._plt_channels = {
"Electrode Force, N & Welding Current, kA": {
"Settings": {
@ -199,7 +198,17 @@ 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(end_time=data[0]['time_wielding']),
"Relief": self._opt.get_openingDF()
}
@property
def mediator(self) -> BaseMediator:
return self._mediator
@ -207,10 +216,20 @@ class BasePlotWidget:
@mediator.setter
def mediator(self, mediator: BaseMediator) -> None:
self._mediator = mediator
@property
def opt(self) -> BaseIdealDataBuilder:
return self._opt
@opt.setter
def opt(self, opt: BaseIdealDataBuilder):
self._opt = opt
def build(self, data: list[pd.DataFrame]) -> list[QWidget]:
...
def update_settings(self, data: list[dict]) -> None:
...
class BaseController(QObject):
@ -218,8 +237,13 @@ class BaseController(QObject):
...
# FIXME: WeldingDF показывает только 1 секунду
class BaseIdealDataBuilder(OptAlgorithm):
def __init__(self, data: list[dict]):
operator_params, system_params = data
self.mul = system_params['time_capture']
super().__init__(operator_params, system_params)
def _get_data(self, end_timestamp:float, func:function) -> pd.DataFrame:
data = []
@ -230,26 +254,74 @@ class BaseIdealDataBuilder(OptAlgorithm):
return pd.DataFrame(data)
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_tmovementDF(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":1, "Posicion FE":X1,"Posicion ME":X2, "Rotor Speed FE":V1, "Rotor Speed ME":V2, "Force":F})
return pd.DataFrame(data)
def get_weldingDF(self, end_time: float) -> pd.DataFrame:
...
def get_ideal_timings(self) -> list[float, float, float, float]:
data = self.Ts
ideal_timings = [data['tclose'], data['tgrow'], self.getMarkOpen(), data["tmovement"]]
return ideal_timings
...
def update_settings(self, data: list[dict]) -> None:
...
class BaseMainWindow(QWidget):
def __init__(self,
mediator: Optional[BaseMediator] = None):
super().__init__()
self._mediator = mediator
@property
def mediator(self) -> BaseMediator:
return self._mediator
@mediator.setter
def mediator(self, mediator: BaseMediator) -> None:
self._mediator = mediator
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;
}
""")

View File

@ -1,47 +0,0 @@
from __future__ import annotations
import os
from typing import Optional, Union
import pandas as pd
from PyQt5.QtWidgets import QTabWidget, QWidget, QVBoxLayout
class BaseMainWindow(QWidget):
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;
}
""")