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, "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,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): if issubclass(source.__class__, BasePlotWidget):
self._controller.send_widgets(data) 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: if not files:
self._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 import QtWidgets
from PyQt5.QtCore import Qt 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): class MainWindow(BaseMainWindow):
def __init__(self): def __init__(self):
super().__init__() super().__init__()
self.initUI() self.initUI()
self.set_style(self) 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: def initUI(self) -> None:
self.tabWidget = QtWidgets.QTabWidget() self.tabWidget = QtWidgets.QTabWidget()
layout = QtWidgets.QVBoxLayout() layout = QtWidgets.QVBoxLayout()
layout.addWidget(self.tabWidget) layout.addWidget(self.tabWidget)
self.settings_button = QtWidgets.QPushButton("Show settings")
self.settings_button.setFixedWidth(160)
layout.addWidget(self.settings_button)
self.setLayout(layout) self.setLayout(layout)
def show_plot_tabs(self, plot_widgets: list[QtWidgets.QWidget]) -> None: def show_plot_tabs(self, plot_widgets: list[QtWidgets.QWidget]) -> None:
@ -29,4 +36,20 @@ class MainWindow(BaseMainWindow):
if a0.key() == Qt.Key_F5: if a0.key() == Qt.Key_F5:
self.clear() 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 typing import Optional, Any, NamedTuple
from src.utils.base.base import BasePlotWidget 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): class ProcessStage(NamedTuple):
mean_value: floating[Any] mean_value: floating[Any]
start_index: int start_index: int
finish_index: int finish_index: int
class PlotWidget(BasePlotWidget):
class PlotWidget(BasePlotWidget):
def _create_stage_ideal(self, def _create_stage_ideal(self,
stage: str, stage: str,
signal: str, signal: str,
@ -23,7 +50,7 @@ class PlotWidget(BasePlotWidget):
stage_diff = np.diff(dataframe[stage]) stage_diff = np.diff(dataframe[stage])
start_index = np.where(stage_diff == 1)[0] start_index = np.where(stage_diff == 1)[0]
finish_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: if start_index.size:
start_timestamp = times[start_index[0]] start_timestamp = times[start_index[0]]
@ -32,7 +59,6 @@ class PlotWidget(BasePlotWidget):
return plot return plot
return None return None
def _create_stage_region(self, def _create_stage_region(self,
stage: str, stage: str,
times: pd.Series, times: pd.Series,
@ -50,7 +76,7 @@ class PlotWidget(BasePlotWidget):
return None return None
@staticmethod @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 = pg.PlotWidget(title=title)
plot_widget.showGrid(x=True, y=True) plot_widget.showGrid(x=True, y=True)
legend = pg.LegendItem((80, 60), offset=(70, 20)) 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] widgets = [self._build_widget(data_sample) for data_sample in data]
self._mediator.notify(self, widgets) 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._init_ui()
self.params.sigTreeStateChanged.connect(upd_func) self.params.sigTreeStateChanged.connect(upd_func)
def load_settings(self): def load_settings(self) -> None:
self.data = read_json(self.settingsPath) self.data = read_json(self.settingsPath)
def write_settings(self): def write_settings(self) -> None:
self.getParams() self.getParams()
write_json(self.settingsPath, self.data) write_json(self.settingsPath, self.data)
@ -31,7 +31,7 @@ class settingsWindow(QtWidgets.QWidget):
params.append({'name': 'Save', 'type': 'action'}) params.append({'name': 'Save', 'type': 'action'})
return params return params
def _init_ui(self): def _init_ui(self) -> None:
temp = self._getTreeStructure() temp = self._getTreeStructure()
self.params = Parameter.create(name=self.name, type='group', children=temp) self.params = Parameter.create(name=self.name, type='group', children=temp)
self.params.param('Save').sigActivated.connect(self.write_settings) 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.monitor import DirectoryMonitor
from src.controller.mediator import Mediator from src.controller.mediator import Mediator
from src.controller.converter import DataConverter from src.controller.converter import DataConverter
from src.controller.ideal_data_builder import idealDataBuilder
from src.gui.plotter import PlotWidget from src.gui.plotter import PlotWidget
from src.controller.controller import Controller from src.controller.controller import Controller
from src.utils.json_tools import read_json from src.utils.json_tools import read_json
@ -15,17 +14,13 @@ from src.utils.json_tools import read_json
def main(): def main():
app = QtWidgets.QApplication(sys.argv) app = QtWidgets.QApplication(sys.argv)
operator_params = read_json("params/operator_params.json") monitor = DirectoryMonitor()
system_params = read_json("params/system_params.json")
monitor = DirectoryMonitor(system_params['trace_storage_path'], system_params['monitor_update_period'])
data_converter = DataConverter() data_converter = DataConverter()
ideal_data_builder = idealDataBuilder(operator_params, system_params) plot_widget_builder = PlotWidget()
plot_widget_builder = PlotWidget(idealDataBuilder=ideal_data_builder)
controller = Controller() controller = Controller()
mediator = Mediator(monitor, data_converter, plot_widget_builder, controller)
monitor.start()
window = MainWindow() window = MainWindow()
mediator = Mediator(monitor, data_converter, plot_widget_builder, controller, window)
window.push_settings()
window.show() window.show()
controller.signal_widgets.connect(window.show_plot_tabs) controller.signal_widgets.connect(window.show_plot_tabs)

View File

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