From 059abdc5e6becb8e3e8ae27cbded6b4e83dd60d4 Mon Sep 17 00:00:00 2001 From: "nazarchuk.as" Date: Fri, 11 Nov 2022 21:02:11 +0300 Subject: [PATCH] add flow window --- Automation/Abstract_window.py | 47 +++ Automation/Analisis_data.py | 149 +++++++ Automation/Main.py | 374 +++--------------- Automation/Main_experiment_window.py | 211 ++++++++++ .../Abstract_window.cpython-39.pyc | Bin 0 -> 1845 bytes .../__pycache__/Analisis_data.cpython-39.pyc | Bin 0 -> 4981 bytes .../Main_experiment_window.cpython-39.pyc | Bin 0 -> 6645 bytes Automation/j/Chart.png | Bin 11416 -> 10461 bytes Automation/j/Induction_data.csv | 1 + Automation/j/data.csv | 5 +- 10 files changed, 465 insertions(+), 322 deletions(-) create mode 100644 Automation/Abstract_window.py create mode 100644 Automation/Analisis_data.py create mode 100644 Automation/Main_experiment_window.py create mode 100644 Automation/__pycache__/Abstract_window.cpython-39.pyc create mode 100644 Automation/__pycache__/Analisis_data.cpython-39.pyc create mode 100644 Automation/__pycache__/Main_experiment_window.cpython-39.pyc create mode 100644 Automation/j/Induction_data.csv diff --git a/Automation/Abstract_window.py b/Automation/Abstract_window.py new file mode 100644 index 0000000..7a034ef --- /dev/null +++ b/Automation/Abstract_window.py @@ -0,0 +1,47 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +Created on Fri Nov 11 19:52:27 2022 + +@author: anna +""" + +from PyQt6.QtWidgets import (QMainWindow, + QMenu) + +from PyQt6.QtGui import QAction + +class AbstractWindow(QMainWindow): + def __init__(self): + super().__init__() + self.create_actions() + self.create_menuBar() + + def create_menuBar(self): + menuBar = self.menuBar() + self.fileMenu = QMenu("&Файл", self) + menuBar.addMenu(self.fileMenu) + self.helpMenu = QMenu("&Помощь") + menuBar.addMenu(self.helpMenu) + self.fileMenu.addAction(self.exitAction) + self.helpMenu.addAction(self.helpContentAction) + self.helpMenu.addAction(self.aboutAction) + + def create_actions(self): + self.exitAction = QAction("&Выход", self) + self.exitAction.triggered.connect(self.exit_click) + self.helpContentAction = QAction("&Инструкция", self) + self.helpContentAction.triggered.connect(self.help_click) + self.aboutAction = QAction("&О программе", self) + self.aboutAction.triggered.connect(self.about_click) + + def exit_click(self): + self.close() + + def help_click(self): + print('Help') + # TODO + + def about_click(self): + print('About') + # TODO \ No newline at end of file diff --git a/Automation/Analisis_data.py b/Automation/Analisis_data.py new file mode 100644 index 0000000..c1f6b79 --- /dev/null +++ b/Automation/Analisis_data.py @@ -0,0 +1,149 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +Created on Fri Nov 11 19:49:57 2022 + +@author: anna +""" +import csv +import numpy as np +import matplotlib.pyplot as plt +from scipy.optimize import curve_fit + +class Data: + def __init__(self, x=[], y=[], xlabel='', ylabel='', caption='', xerr=None, + yerr=None, through_0=0, data_filename='', color=None, + centering=None, size=15, coefficient=[0.9, 1.1], saving=None): + self.x = x + self.y = y + self.xlabel = xlabel + self.ylabel = ylabel + self.caption = caption + self.xerr=xerr + self.yerr=yerr + self.make_errors(xerr, yerr) + self.through_0 = through_0 + if not color: + self.color = ['limegreen', 'indigo'] + else: + self.color = color + self.centering = centering + self.size = size + self.coefficient = coefficient + self.data_filename=data_filename + self.saving=saving + + def make_errors(self, xerr=None, yerr=None): + if not xerr: xerr=self.xerr + if not yerr: yerr=self.yerr + if not xerr: xerr=0 + if not yerr: yerr=0 + if not yerr or type(yerr) == float or type(yerr) == int: + self.yerr = [yerr for _ in self.y] + else: + self.yerr = yerr + if not xerr or type(xerr) == float or type(xerr) == int: + self.xerr = [xerr for _ in self.x] + else: + self.xerr = xerr + + def read_csv(self): + with open(self.data_filename) as file: + reader = list(csv.reader(file)) + data = np.array(reader) + dic=[] + for i in range(len(data[0])): + micro_data = [] + for j in range(len(data)): + micro_data.append(data[j][i]) + dic.append(micro_data) + data=dic + dic = {} + for i in range(len(data)): + dic[data[i][0]] = np.array(data[i][1:]).astype(np.float) + data = dic + self.data=data + + def make_point_grafic(self): + self.make_errors() + if self.xerr[1] != 0 or self.yerr[1] != 0: + plt.errorbar(self.x, self.y, yerr=self.yerr, xerr=self.xerr, linewidth=4, + linestyle='', label=self.caption, color=self.color[0], + ecolor=self.color[0], elinewidth=1, capsize=3.4, + capthick=1.4) + else: + plt.scatter(self.x, self.y, linewidth=0.005, label=self.caption, + color=self.color[0], edgecolor='black', s=self.size) + + if not self.centering: + plt.xlabel(self.xlabel) + plt.ylabel(self.ylabel) + else: + self.ax = plt.gca() + self.ax.spines['top'].set_visible(False) + self.ax.spines['right'].set_visible(False) + self.ax.spines['bottom'].set_position('zero') + self.ax.spines['left'].set_position('zero') + self.ax.set_xlabel(self.ylabel, labelpad=-180, fontsize=14) + self.ax.set_ylabel(self.xlabel, labelpad=-260, + rotation=0, fontsize=14) + + def make_line_grafic(self, k, b): + if min(self.x) > 0: + xmin = min(self.x)*self.coefficient[0] + else: + xmin = min(self.x)*self.coefficient[1] + + if max(self.x) > 0: + xmax = max(self.x)*self.coefficient[1] + else: + xmax = max(self.x)*self.coefficient[0] + x = np.arange(xmin, xmax, (xmax-xmin)/10000) + plt.plot(x, k*x+b, label=self.caption, linewidth=2.4, + linestyle='-', color=self.color[1]) + + def make_grafic(self, named_by_points=True): + self.make_errors() + if named_by_points: + cap_point = self.caption + line_point = None + else: + line_point = self.caption + cap_point = None + self.make_point_grafic() + + k, b, sigma = self.approx() + sigma[0] = abs(k*((sigma[0]/k)**2+(np.mean(self.yerr)/np.mean(self.y))**2 + + (np.mean(self.xerr)/np.mean(self.x))**2)**0.5) + if (b != 0): + sigma[1] = abs(b*((sigma[1]/b)**2+(np.mean(self.yerr)/np.mean(self.y))**2 + + (np.mean(self.xerr)/np.mean(self.x))**2)**0.5) + else: + sigma[1] = 0 + + self.make_line_grafic(k, b) + plt.legend() + if self.saving: + plt.savefig(self.saving) + return k, b, sigma + + def approx(self): + if self.yerr[0] != 0: + sigma_y = [1/i**2 for i in self.y] + else: + sigma_y = np.array([1 for _ in self.y]) + if self.through_0 == 0: + def f(x, k): + return k*x + k, sigma = curve_fit(f, xdata=self.x, ydata=self.y, sigma=sigma_y) + sigma = np.sqrt(np.diag(sigma)) + return k[0], 0, [sigma[0], 0] + else: + def f(x, k, b): + return x*k + b + k, sigma = curve_fit(f, xdata=self.x, ydata=self.y, sigma=sigma_y) + sigma_b = np.sqrt(sigma[1][1]) + b = k[1] + k = k[0] + sigma = np.sqrt(sigma[0][0]) + return k, b, [sigma, sigma_b] diff --git a/Automation/Main.py b/Automation/Main.py index 28f5640..abd2e01 100644 --- a/Automation/Main.py +++ b/Automation/Main.py @@ -1,11 +1,7 @@ import os import sys import csv -import numpy as np -import matplotlib.pyplot as plt -from scipy.optimize import curve_fit import time -import pandas as pd from PyQt6 import QtCore from PyQt6.QtGui import QAction, QIcon, QPixmap from PyQt6.QtWidgets import (QHBoxLayout, @@ -36,42 +32,8 @@ from PyQt6.QtWidgets import (QHBoxLayout, QHeaderView, QTextBrowser, ) - - -class AbstractWindow(QMainWindow): - def __init__(self): - super().__init__() - self.create_actions() - self.create_menuBar() - - def create_menuBar(self): - menuBar = self.menuBar() - self.fileMenu = QMenu("&Файл", self) - menuBar.addMenu(self.fileMenu) - self.helpMenu = QMenu("&Помощь") - menuBar.addMenu(self.helpMenu) - self.fileMenu.addAction(self.exitAction) - self.helpMenu.addAction(self.helpContentAction) - self.helpMenu.addAction(self.aboutAction) - - def create_actions(self): - self.exitAction = QAction("&Выход", self) - self.exitAction.triggered.connect(self.exit_click) - self.helpContentAction = QAction("&Инструкция", self) - self.helpContentAction.triggered.connect(self.help_click) - self.aboutAction = QAction("&О программе", self) - self.aboutAction.triggered.connect(self.about_click) - - def exit_click(self): - self.close() - - def help_click(self): - print('Help') - # TODO - - def about_click(self): - print('About') - # TODO +from Abstract_window import AbstractWindow +from Main_experiment_window import * class Start: @@ -99,9 +61,12 @@ class Start: if self.number == 21: self.window.close() self.window = MainExperimentChartWindow(self) - if self.number == 10: - pass + self.window.close() + self.window = FlowWindow(self) + if self.number == 0: + self.window.close() + self.window = StartWindow(self) self.draw() @@ -150,58 +115,31 @@ class StartWindow(AbstractWindow): self.lineEdit.setReadOnly(True) -class ThreadData(QtCore.QThread): - signal = QtCore.pyqtSignal(str) - +class FlowWindow(AbstractWindow): def __init__(self, parent): - QtCore.QThread.__init__(self) - self.running = False - self.parent = parent - - def run(self): - self.running = True - while self.running: - self.parent.no_data() - self.sleep(1) - - -class MainExperimentDataWindow(AbstractWindow): - def __init__(self, parent): - # TODO : clean code super().__init__() - - self.setWindowTitle('Основной эксперимент. Получение данных') - self.start_time = round(time.time()*1000) self.parent = parent - self.data_thread = ThreadData(self) - self.resize(1400, 800) - - # make masthead - self.parent.dataname = 'data.csv' - head_1 = 'I_0,mA' - head_2 = 'U_34,mV' - head_3 = 't,s' - with open(os.path.join(self.parent.folder, self.parent.dataname), 'w') as file: - wr = csv.writer(file) - wr.writerow([head_1, head_2, head_3]) - + self.parent = parent self.centralwidget = QWidget() + self.resize(1400, 800) self.setCentralWidget(self.centralwidget) + grid_layout = QGridLayout(self.centralwidget) self.start = QPushButton('Старт') self.start.clicked.connect(self.start_clicked) - self.start.setEnabled(False) + self.start.setEnabled(True) - self.stop = QPushButton('Стоп') - self.stop.clicked.connect(self.stop_clicked) - self.stop.setEnabled(False) + self.lineEdit = QLineEdit(placeholderText='Индукция B, мТл') + self.lineEdit.returnPressed.connect(self.enter_value) + self.lineEdit.setReadOnly(True) - self.next = QPushButton(self) - self.next.setIcon(QIcon('arrow.png')) - self.next.setEnabled(False) - self.next.clicked.connect(self.next_clicked) - - grid_layout = QGridLayout(self.centralwidget) + self.parent.flow_dataname = 'Induction_data.csv' + head_1 = 'B,mTl' + head_2 = 'U,mV' + head_3 = 't,s' + with open(os.path.join(self.parent.folder, self.parent.flow_dataname), 'w') as file: + wr = csv.writer(file) + wr.writerow([head_1, head_2, head_3]) self.table = QTableWidget(self) # Create a self.table self.table.setColumnCount(3) # Set three columns @@ -217,249 +155,49 @@ class MainExperimentDataWindow(AbstractWindow): self.table.setItem(0, 1, QTableWidgetItem("Text in column 2")) self.table.setItem(0, 2, QTableWidgetItem("Text in column 3")) self.table.resizeColumnsToContents() - - self.lineEdit = QLineEdit(placeholderText='Введите что-то') - self.lineEdit.returnPressed.connect(self.enter_smth) - - # Adding the table to the grid - grid_layout.addWidget(self.table, 0, 0, -1, 1) - grid_layout.addWidget(self.lineEdit, 0, 2, -1, -1) - grid_layout.addWidget(self.next, 2, 2, -1, -1) - grid_layout.addWidget(self.start, 1, 2) - grid_layout.addWidget(self.stop, 1, 3) - - self.parent.draw() - - def enter_smth(self): - # TODO - self.parent.smth = self.lineEdit.text() - self.start.setEnabled(True) - self.lineEdit.setReadOnly(True) - - def start_clicked(self): - self.stop.setEnabled(True) - self.start.setEnabled(False) - if not self.data_thread.isRunning(): - self.data_thread.start() - - def no_data(self): - current_time = round(time.time()*1000) - v = str((current_time-self.start_time)/60) - a = v - t = str(current_time-self.start_time) - with open(os.path.join(self.parent.folder, self.parent.dataname), 'a') as file: - wr = csv.writer(file) - wr.writerow([v, a, str(current_time-self.start_time)]) - self.table.insertRow(self.table.rowCount()) - self.table.setItem(self.table.rowCount()-1, 0, QTableWidgetItem(v)) - self.table.setItem(self.table.rowCount()-1, 1, QTableWidgetItem(a)) - self.table.setItem(self.table.rowCount()-1, 2, QTableWidgetItem(t)) - - def stop_clicked(self): - self.data_thread.running = False - self.stop.setEnabled(False) - self.next.setEnabled(True) + + self.next = QPushButton(self) + self.next.setIcon(QIcon('arrow.png')) + self.next.setEnabled(False) + self.next.clicked.connect(self.next_clicked) + + grid_layout.addWidget(self.start, 0, 0) + grid_layout.addWidget(self.lineEdit, 1, 0) + grid_layout.addWidget(self.table, 1, 3) + grid_layout.addWidget(self.next, 2, 0) + def next_clicked(self): - self.parent.number = 21 + self.parent.number = 20 self.parent.change_number() + - def take_data(self): - # measure voltage and current - volt_name = os.path.join('/dev', 'usbtmc1') - f_volt = open(volt_name, 'w') - f_volt.write('Measure:Voltage:DC?\n') - f_volt.close() - amp_name = os.path.join('/dev', 'usbtmc2') - f_amp = open(amp_name, 'w') - f_amp.write('Measure:Current:DC?\n') - f_amp.close() + def start_clicked(self): + self.start.setEnabled(False) + self.start_time = round(time.time()*1000) + self.lineEdit.setReadOnly(False) + self.next.setEnabled(True) - f_volt = open(volt_name, 'r') - v = f_volt.read(15) - f_amp = open(amp_name, 'r') - a = f_amp.read(15) - f_volt.close() - f_amp.close() + def enter_value(self): + self.lineEdit.setReadOnly(True) + self.get_data() + self.lineEdit.clear() + self.lineEdit.setReadOnly(False) + + def get_data(self): current_time = round(time.time()*1000) - with open(os.path.join(self.parent.folder, self.parent.dataname), 'a') as file: + b = self.lineEdit.text() + u = str((current_time-self.start_time)/60) + t = str(current_time-self.start_time) + with open(os.path.join(self.parent.folder, self.parent.flow_dataname), 'a') as file: wr = csv.writer(file) - wr.writerow([v, a, str(current_time-self.start_time)]) + wr.writerow([b, u, str(t)]) + self.table.insertRow(self.table.rowCount()) + self.table.setItem(self.table.rowCount()-1, 0, QTableWidgetItem(b)) + self.table.setItem(self.table.rowCount()-1, 1, QTableWidgetItem(u)) + self.table.setItem(self.table.rowCount()-1, 2, QTableWidgetItem(t)) -class MainExperimentChartWindow(AbstractWindow): - def __init__(self, parent): - super().__init__() - - self.parent = parent - self.parent.chartname = 'Chart' - self.parent.data = Data(data_filename=os.path.join(self.parent.folder, self.parent.dataname), - saving=os.path.join(self.parent.folder, self.parent.chartname)) - self.parent.data.read_csv() - self.parent.data.x=self.parent.data.data['I_0,mA'] - self.parent.data.y=self.parent.data.data['U_34,mV'] - self.parent.data.make_grafic() - - self.setWindowTitle('Основной эксперимент. Обработка данных') - self.resize(1400, 800) - - self.centralwidget = QWidget() - self.setCentralWidget(self.centralwidget) - - pixmap = QPixmap(os.path.join(self.parent.folder, self.parent.chartname)) - self.label = QLabel(self) - self.label.setPixmap(pixmap) - self.label.resize(pixmap.width(), pixmap.height()) - - self.text = QTextBrowser() - self.text.setText('text') - - self.hbox_layout = QGridLayout(self.centralwidget) - self.hbox_layout.addWidget(self.label, 0, 0) - self.hbox_layout.addWidget(self.text, 0, 1) - - - - - -class Data: - def __init__(self, x=[], y=[], xlabel='', ylabel='', caption='', xerr=None, - yerr=None, through_0=0, data_filename='', color=None, - centering=None, size=15, coefficient=[0.9, 1.1], saving=None): - self.x = x - self.y = y - self.xlabel = xlabel - self.ylabel = ylabel - self.caption = caption - self.xerr=xerr - self.yerr=yerr - self.make_errors(xerr, yerr) - self.through_0 = through_0 - if not color: - self.color = ['limegreen', 'indigo'] - else: - self.color = color - self.centering = centering - self.size = size - self.coefficient = coefficient - self.data_filename=data_filename - self.saving=saving - - def make_errors(self, xerr=None, yerr=None): - if not xerr: xerr=self.xerr - if not yerr: yerr=self.yerr - if not xerr: xerr=0 - if not yerr: yerr=0 - if not yerr or type(yerr) == float or type(yerr) == int: - self.yerr = [yerr for _ in self.y] - else: - self.yerr = yerr - if not xerr or type(xerr) == float or type(xerr) == int: - self.xerr = [xerr for _ in self.x] - else: - self.xerr = xerr - - def read_csv(self): - with open(self.data_filename) as file: - reader = list(csv.reader(file)) - data = np.array(reader) - dic=[] - for i in range(len(data[0])): - micro_data = [] - for j in range(len(data)): - micro_data.append(data[j][i]) - dic.append(micro_data) - data=dic - dic = {} - for i in range(len(data)): - dic[data[i][0]] = np.array(data[i][1:]).astype(np.float) - data = dic - self.data=data - - def make_point_grafic(self): - self.make_errors() - if self.xerr[1] != 0 or self.yerr[1] != 0: - plt.errorbar(self.x, self.y, yerr=self.yerr, xerr=self.xerr, linewidth=4, - linestyle='', label=self.caption, color=self.color[0], - ecolor=self.color[0], elinewidth=1, capsize=3.4, - capthick=1.4) - else: - plt.scatter(self.x, self.y, linewidth=0.005, label=self.caption, - color=self.color[0], edgecolor='black', s=self.size) - - if not self.centering: - plt.xlabel(self.xlabel) - plt.ylabel(self.ylabel) - else: - self.ax = plt.gca() - self.ax.spines['top'].set_visible(False) - self.ax.spines['right'].set_visible(False) - self.ax.spines['bottom'].set_position('zero') - self.ax.spines['left'].set_position('zero') - self.ax.set_xlabel(self.ylabel, labelpad=-180, fontsize=14) - self.ax.set_ylabel(self.xlabel, labelpad=-260, - rotation=0, fontsize=14) - - def make_line_grafic(self, k, b): - if min(self.x) > 0: - xmin = min(self.x)*self.coefficient[0] - else: - xmin = min(self.x)*self.coefficient[1] - - if max(self.x) > 0: - xmax = max(self.x)*self.coefficient[1] - else: - xmax = max(self.x)*self.coefficient[0] - x = np.arange(xmin, xmax, (xmax-xmin)/10000) - plt.plot(x, k*x+b, label=self.caption, linewidth=2.4, - linestyle='-', color=self.color[1]) - - def make_grafic(self, named_by_points=True): - self.make_errors() - if named_by_points: - cap_point = self.caption - line_point = None - else: - line_point = self.caption - cap_point = None - self.make_point_grafic() - - k, b, sigma = self.approx() - sigma[0] = abs(k*((sigma[0]/k)**2+(np.mean(self.yerr)/np.mean(self.y))**2 + - (np.mean(self.xerr)/np.mean(self.x))**2)**0.5) - if (b != 0): - sigma[1] = abs(b*((sigma[1]/b)**2+(np.mean(self.yerr)/np.mean(self.y))**2 + - (np.mean(self.xerr)/np.mean(self.x))**2)**0.5) - else: - sigma[1] = 0 - - self.make_line_grafic(k, b) - plt.legend() - if self.saving: - plt.savefig(self.saving) - return k, b, sigma - - def approx(self): - if self.yerr[0] != 0: - sigma_y = [1/i**2 for i in self.y] - else: - sigma_y = np.array([1 for _ in self.y]) - if self.through_0 == 0: - def f(x, k): - return k*x - k, sigma = curve_fit(f, xdata=self.x, ydata=self.y, sigma=sigma_y) - sigma = np.sqrt(np.diag(sigma)) - return k[0], 0, [sigma[0], 0] - else: - def f(x, k, b): - return x*k + b - k, sigma = curve_fit(f, xdata=self.x, ydata=self.y, sigma=sigma_y) - sigma_b = np.sqrt(sigma[1][1]) - b = k[1] - k = k[0] - sigma = np.sqrt(sigma[0][0]) - return k, b, [sigma, sigma_b] - start = Start() diff --git a/Automation/Main_experiment_window.py b/Automation/Main_experiment_window.py new file mode 100644 index 0000000..ae2a150 --- /dev/null +++ b/Automation/Main_experiment_window.py @@ -0,0 +1,211 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +Created on Fri Nov 11 20:00:45 2022 + +@author: anna +""" +import os +import csv +import time +from PyQt6 import QtCore +from PyQt6.QtGui import QIcon, QPixmap +from PyQt6.QtWidgets import (QHBoxLayout, + QApplication, + QCheckBox, + QComboBox, + QDateEdit, + QDateTimeEdit, + QDial, + QDoubleSpinBox, + QFontComboBox, + QLabel, + QLCDNumber, + QLineEdit, + QMainWindow, + QProgressBar, + QPushButton, + QRadioButton, + QSlider, + QSpinBox, + QTimeEdit, + QVBoxLayout, + QWidget, + QTableWidget, + QGridLayout, + QMenu, + QTableWidgetItem, + QHeaderView, + QTextBrowser, + ) +from Analisis_data import Data +from Abstract_window import AbstractWindow + +class ThreadData(QtCore.QThread): + signal = QtCore.pyqtSignal(str) + + def __init__(self, parent): + QtCore.QThread.__init__(self) + self.running = False + self.parent = parent + + def run(self): + self.running = True + while self.running: + self.parent.no_data() + self.sleep(1) + + +class MainExperimentDataWindow(AbstractWindow): + def __init__(self, parent): + # TODO : clean code + super().__init__() + + self.setWindowTitle('Основной эксперимент. Получение данных') + self.start_time = round(time.time()*1000) + self.parent = parent + self.data_thread = ThreadData(self) + self.resize(1400, 800) + + # make masthead + self.parent.dataname = 'data.csv' + head_1 = 'I_0,mA' + head_2 = 'U_34,mV' + head_3 = 't,s' + with open(os.path.join(self.parent.folder, self.parent.dataname), 'w') as file: + wr = csv.writer(file) + wr.writerow([head_1, head_2, head_3]) + + self.centralwidget = QWidget() + self.setCentralWidget(self.centralwidget) + + self.start = QPushButton('Старт') + self.start.clicked.connect(self.start_clicked) + self.start.setEnabled(False) + + self.stop = QPushButton('Стоп') + self.stop.clicked.connect(self.stop_clicked) + self.stop.setEnabled(False) + + self.next = QPushButton(self) + self.next.setIcon(QIcon('arrow.png')) + self.next.setEnabled(False) + self.next.clicked.connect(self.next_clicked) + + grid_layout = QGridLayout(self.centralwidget) + + self.table = QTableWidget(self) # Create a self.table + self.table.setColumnCount(3) # Set three columns + self.table.setRowCount(0) + + self.table.setHorizontalHeaderLabels([head_1, head_2, head_3]) + + header = self.table.horizontalHeader() + header.setSectionResizeMode(0, QHeaderView.ResizeMode.Stretch) + header.setSectionResizeMode(1, QHeaderView.ResizeMode.Stretch) + header.setSectionResizeMode(2, QHeaderView.ResizeMode.Stretch) + self.table.setItem(0, 0, QTableWidgetItem("Text in column 1")) + self.table.setItem(0, 1, QTableWidgetItem("Text in column 2")) + self.table.setItem(0, 2, QTableWidgetItem("Text in column 3")) + self.table.resizeColumnsToContents() + + self.lineEdit = QLineEdit(placeholderText='Введите что-то') + self.lineEdit.returnPressed.connect(self.enter_smth) + + # Adding the table to the grid + grid_layout.addWidget(self.table, 0, 0, -1, 1) + grid_layout.addWidget(self.lineEdit, 0, 2, -1, -1) + grid_layout.addWidget(self.next, 2, 2, -1, -1) + grid_layout.addWidget(self.start, 1, 2) + grid_layout.addWidget(self.stop, 1, 3) + + self.parent.draw() + + def enter_smth(self): + # TODO + self.parent.smth = self.lineEdit.text() + self.start.setEnabled(True) + self.lineEdit.setReadOnly(True) + + def start_clicked(self): + self.stop.setEnabled(True) + self.start_time = round(time.time()*1000) + self.start.setEnabled(False) + if not self.data_thread.isRunning(): + self.data_thread.start() + + def no_data(self): + current_time = round(time.time()*1000) + v = str((current_time-self.start_time)/60) + a = v + t = str(current_time-self.start_time) + with open(os.path.join(self.parent.folder, self.parent.dataname), 'a') as file: + wr = csv.writer(file) + wr.writerow([v, a, str(current_time-self.start_time)]) + self.table.insertRow(self.table.rowCount()) + self.table.setItem(self.table.rowCount()-1, 0, QTableWidgetItem(v)) + self.table.setItem(self.table.rowCount()-1, 1, QTableWidgetItem(a)) + self.table.setItem(self.table.rowCount()-1, 2, QTableWidgetItem(t)) + + def stop_clicked(self): + self.data_thread.running = False + self.stop.setEnabled(False) + self.next.setEnabled(True) + + def next_clicked(self): + self.parent.number = 21 + self.parent.change_number() + + def take_data(self): + # measure voltage and current + volt_name = os.path.join('/dev', 'usbtmc1') + f_volt = open(volt_name, 'w') + f_volt.write('Measure:Voltage:DC?\n') + f_volt.close() + amp_name = os.path.join('/dev', 'usbtmc2') + f_amp = open(amp_name, 'w') + f_amp.write('Measure:Current:DC?\n') + f_amp.close() + + f_volt = open(volt_name, 'r') + v = f_volt.read(15) + f_amp = open(amp_name, 'r') + a = f_amp.read(15) + f_volt.close() + f_amp.close() + current_time = round(time.time()*1000) + with open(os.path.join(self.parent.folder, self.parent.dataname), 'a') as file: + wr = csv.writer(file) + wr.writerow([v, a, str(current_time-self.start_time)]) + +class MainExperimentChartWindow(AbstractWindow): + def __init__(self, parent): + super().__init__() + + self.parent = parent + self.parent.chartname = 'Chart' + self.parent.data = Data(data_filename=os.path.join(self.parent.folder, self.parent.dataname), + saving=os.path.join(self.parent.folder, self.parent.chartname)) + self.parent.data.read_csv() + self.parent.data.x=self.parent.data.data['I_0,mA'] + self.parent.data.y=self.parent.data.data['U_34,mV'] + self.parent.data.make_grafic() + + self.setWindowTitle('Основной эксперимент. Обработка данных') + self.resize(1400, 800) + + self.centralwidget = QWidget() + self.setCentralWidget(self.centralwidget) + + pixmap = QPixmap(os.path.join(self.parent.folder, self.parent.chartname)) + self.label = QLabel(self) + self.label.setPixmap(pixmap) + self.label.resize(pixmap.width(), pixmap.height()) + + self.text = QTextBrowser() + self.text.setText('text') + + self.hbox_layout = QGridLayout(self.centralwidget) + self.hbox_layout.addWidget(self.label, 0, 0) + self.hbox_layout.addWidget(self.text, 0, 1) + diff --git a/Automation/__pycache__/Abstract_window.cpython-39.pyc b/Automation/__pycache__/Abstract_window.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f2060b34726a7acd8177980399f97b61d975ac20 GIT binary patch literal 1845 zcmb7_&5zqe6u@Wv5j#$@-AaY>Rg}|8KCoe<0_qB(ZWmE5jfi>x9_%T4Z2rW4e9Va8gDc3?e)<)V`AL$fjJv7GV$fV>l;RZMN2sec` z(?<>7xJq1Wa^BgL!b=73#!>ez8FUBn2i>)`?%IX*SNiMy*Sh_e`+di`=w<0nEZ4hU z6nV~HV2`+3*&1H)g6Q2K;_=PW99|Jo=F-v{Zun^sM?UUa{OGliya^LQMihM3?vgEv ze(%{Mo$K7#BO~yWH()fm#cdcHyvZFHE#Bg7811{nAfqPu-zk?it|h7T{Iv4Irwayg zu0cb)$&1jXWJdPs0ik3{_O*J{apdGGIiv&ED9t3>6|%G$3!)%ptX%RHAOV?^#Dl-{%kV z`}u?7^WsalSz0wGiMLSNTR|u=PfE+v46PBvfDIIYuNbC7&+^`u(sfgxF zE$>>K)q<1Vl zl#;*A|0q5#J}K@Lv;4Q>v;3FhtL$l|`L3J)S=@oGKSF;G*x%28cAFBP2Z=k%W-5d2 zZ6O6OEkBMT;ina0$k)KXA5n^Fb=#1r8MszyF~(ybET4Mk_Aq^QbqFsu-xg^i@#3o2p*2@s&Vnj^@z)Cm YRe7Vq(tf=P;Gynhq literal 0 HcmV?d00001 diff --git a/Automation/__pycache__/Analisis_data.cpython-39.pyc b/Automation/__pycache__/Analisis_data.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..bfae543d7f18238a43df86073271d51d9bfca306 GIT binary patch literal 4981 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 Zf3+dyZj=YSK_fECxGbAK0_*tC;2-IrJt6=A literal 0 HcmV?d00001 diff --git a/Automation/__pycache__/Main_experiment_window.cpython-39.pyc b/Automation/__pycache__/Main_experiment_window.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d8944de50922d5d5996565811cef7c2414c1a9d7 GIT binary patch literal 6645 zcmb7I-E-Skb_YNJ1V2T|vOa9tp+Dl7i6dLKlkU3Pt!+6@(%M?n);e9ZGaQ(JB{Bq{ zT!5C%p=P#mb~9}!-I+f0r8B!!-}092)Sd0N$^Hw}>wWD@_1ee0Y=7qfqA17OY01IC zz2}~LaqhY2^E#zcUcoQ-v!MC)2}SuY>Wu$%bgtuxz6Ed!`NMZ_U>Dov|}` zXF9rX*oI0pddKv$cGkCSi~B|==jZLbU$6^)(JuNWyX2ScvOi%@_!Yb2Pui3Ils)Ai zv5)xE_OyT0KI+fdGybeS>(AM9{=7Z!AG447$L-_(g1z9Muuu3W?UVj%_G^CCuKK6! zQ~qiDw137v;5_W9JjNbH~jPVc~yB|aVV$ZFHLG`w1Rae3%)upBCX{ zo`v057V9@QHae}Q6SqK>t1qv6&5tom&Cq`oCe2%5^&fcx%in1Q$s&dNU8fa%)C$~i z6a3s0;hONG=%ypU>b-8XezP0LV6Ird@3^fn?Pco^IxQC~S@pfo=ISHH3iXHkd(759 zYPoA3ZFbcGn`y65e_yoRR1QY{t`~G=Wt`%}*z-wRo`df^Yv*Db0GrergzR}b$aqmZMT5%aqv;Yt*ZFQjam2H)judg&ReS*5HU>$AccFhnp2TG8v zD6K}L6|~|;LuN%c2wK6KG&daK1u-;6kG#%fL7aZ6i1T=T`~8dSq3>NJ6}!0N^c>M# z?|yvoMmG+9)|-oTfDP~Ih9{sILEPBn!(7~WCeC91MLdxSpr}RFRC`DE_qDjkNK>Wp z^hfQ{28j{gl+st)iZ~63&2B3y`h$$C(WXB!d8?U~)m@rf)5Ys}@g8J02pcX$D2=G& zc^hA<;td+3jU}Llmdrp7SJ8+p00mr{YF_P?$2bMSN-amC3mo5r=<xrzB0xGb3=@X(*PInu)r)euUQ7;n!p|S zk$~tI-2vFssn3?%LA;35-k(p|$fp;d;PbuGM2H|OSA+X`-xwXNiq@y>m&=!%_( z#!SdLI?(q<=SdovYWBDu=I~(>7jY8(93!#vTp6h8(ZE&H(ZrcpAL!ePt4%A%Fy=$|h^Y3TnGJn@m|P@u*%zJ3&I zPBX7FZk~CZ1!lHAH<-u!7>!VWaNI4VR7Iv*0CpjzI+0Q>>{F%tI|-_jgV*A!TYAnC z;eNUnwbK<&@!F)`)6dndYTiHh7?kBhb#Y094WHS>#O?o6(bR%?}%wF8DXT z&HlJ?J*nhQI6O9Dx9`xDl-FlH~~U zSmI59T{5m-g+ffV6;zvHr|SpRrSD)ae+P4=dkj;D|A4K&0PDZOmtRzOKF8~uw+SFb zO>A_Wrneq;5XlhwgPEBW;SF7LX_sFXvGxA zlXti&=CK!9Y9f#br?Z)a?h062PB2OM7DtH6V5VfYi4^8z&qX5)0LCwuI!Ok>Nl+v!NY@VFHBi}z9RL2sLibpG;nC5?8E2@=D z(gs%RojNRr{U34;vPL*74rX|3NT`&yJ}{Dy#v@4D$gQO*)@m&)9%B-01xk}79y-ZZ z+y_=Xq#;%i$nr-)=b3n$&>Zy{aOhtLu8)U9zoM0qE%nYEx{LkuJ3M!~$t%)6(qOE` znL%bO80*-Jfl&^aXq$uVwi5l2TgJ$t>MN__T`YCGW{HpR=KTm-Tr3l~MSwT@9$GTj zitZ;_Bg2C zYm{!ZGjm8ljuS@fYg?IpEHHYk#|G^jbXGgZkP?gx5{#=zFbad>D8VRExE-H;NUHI- z^B8A(k_&!aj8Z*bxsDg0ehFEa0R6S$_yw`w186YqhxSRri9n!)RI=ormL8)g@oT=dcqNXf-~_A zrUxdOmyNA~1%HrZe~?8vk`~MDTsx1G&$SD%^*r0U6&DAkKCPYW=TLAMeKVfulV7OJ z!FL>D>;E%u>wF-Em7adl^`6LVH+mHN%_Z^2kWp{?uIEHu;az(ec4BAEyLM~&PxE^; zm-mO46I)4!Rk1sP$!ySUHMPl?t&}WR8k{~!quB`~nX#alb*LfBT&_!f;6x;InTQF#TBbFzB z3%Cj!dGGY01~Xc)RuFWzATAMDB0#H)bpjM+1UV5w)+k8R#TNjwl%^$3uhZE}P1x-S zB4OY24q9|#Q5gW%d)+dvtW~lMOBXcO#B<=6Nqc-7^Qu~$Yik{~bwRR$E~KgK?~d_Fi+qffjR+l_=4118Xdlz&7lZMu884ES}v*rWb&=G z^;o<{q{K8A9#lJWF(eD?kHV*E+AmrdM*!lhHQt4}!S~IAt%~i7O^deqZ+N0b00q}u zCM3phalyzkl@ojDq@aof z?hO<{mMkb)6&8UU0g9WVK%hvVM1W32Oc0>zO-vG)B0$xym?m(P0A&MWmcSeVK3pnJ zlQMOIT9kfq5y=NAOE+*4*@{{byJFTXIk9(bonF|AQ#9ucfzt%Y*Re>(WH&lWY5gF% a{`?`kDB?&r$bVD1Q&HmuuF@tdz5fO5(WROI literal 0 HcmV?d00001 diff --git a/Automation/j/Chart.png b/Automation/j/Chart.png index 892572e4f048d8d1f638c7f466c02b9e81a2be2f..1e52bf391fd4f8fbc3684b14073797ed9fa66c4a 100644 GIT binary patch literal 10461 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