diff --git a/calculations/doe.py b/calculations/doe.py index bd8420f..cac8410 100644 --- a/calculations/doe.py +++ b/calculations/doe.py @@ -53,7 +53,7 @@ def calculate_factor_levels( else: # "ед." # Конвертируем абсолютный шаг в проценты low = calc_amount(factor.percentage) - factor.step - high = calc_amount(factor.percentage) + factor.step + high = calc_amount(factor.center) + factor.step # ВОЗВРАЩАЕМ НОВЫЙ ОБЪЕКТ FactorData return FactorData( @@ -72,6 +72,12 @@ def calculate_all_factors_levels(factors: List['FactorData'], **kwargs) -> List[ """Рассчитывает уровни для всех факторов""" return [calculate_factor_levels(f, **kwargs) for f in factors] +def get_active_factors(factors): + return [f for f in factors if f['step'] != 0] + +def get_inactive_factors(factors): + return [f for f in factors if f['step'] == 0] + def generate_factorial_design( factors: List[Dict], center_points: int = 3, @@ -159,6 +165,7 @@ def generate_factorial_design( # Добавление центральных точек for i in range(center_points): center_experiment = {} + for j in range(k): center_experiment[f"Фактор_{j+1}"] = { 'coded': 0, diff --git a/gui.py b/gui.py index 5a11742..45d5eeb 100644 --- a/gui.py +++ b/gui.py @@ -28,6 +28,8 @@ from calculations.doe import ( generate_factorial_design, analyze_experiment, calculate_factor_levels, + get_active_factors, + get_inactive_factors, FACTOR_TYPES ) # Импорт моделей для JSON @@ -439,7 +441,7 @@ class MainWindow(QMainWindow): step_item = self.factors_table.item(row, 4) high_item = self.factors_table.item(row, 6) low_item = self.factors_table.item(row, 7) - unit_item = self.factors_table.item(row, 8) + unit_item = self.factors_table.cellWidget(row, 8) step_combo = self.factors_table.cellWidget(row, 5) if not all([name_item, center_item, high_item, low_item]): @@ -457,7 +459,7 @@ class MainWindow(QMainWindow): 'center': float(center_text), 'high': float(high_text), 'low': float(low_text), - 'unit': unit_item.text() if unit_item else "", + 'unit': unit_item.currentText() if unit_item else "г", 'step': float(step_item.text()) if step_item and step_item.text() else 0, 'step_type': step_combo.currentText() if step_combo else "ед." } @@ -524,11 +526,14 @@ class MainWindow(QMainWindow): layout.addWidget(self.design_info) return tab - + def _generate_design(self): """Генерирует план эксперимента""" - factors = self._get_factors_from_table() - + all_factors = self._get_factors_from_table() + factors = get_active_factors(all_factors) + # Выбираем только те факторы, шаг которых не равен нулю + i_factors = get_inactive_factors(all_factors) + # Отдельно сохраняем неактивные факторы if len(factors) == 0: QMessageBox.warning(self, "Предупреждение", "Добавьте хотя бы один фактор!") return @@ -539,27 +544,24 @@ class MainWindow(QMainWindow): center_points=self.center_points_spin.value(), randomize=self.randomize_check.isChecked() ) - self.generated_design = design n_exp = len(design) n_factors = len(factors) - + n_i_factors = len(i_factors) self.design_matrix.setRowCount(n_exp) - self.design_matrix.setColumnCount(n_factors + 2) - headers = ["№"] + [f['name'] for f in factors] + ["Тип"] + self.design_matrix.setColumnCount(n_factors + 3) + headers = [f['name'] for f in factors] + [f['name'] for f in i_factors] + ["Растворитель"] +["Тип"] +["Отклик"] self.design_matrix.setHorizontalHeaderLabels(headers) for exp_idx, exp in enumerate(design): - self.design_matrix.setItem(exp_idx, 0, QTableWidgetItem(str(exp_idx + 1))) for f_idx in range(n_factors): - key = f"Фактор_{f_idx + 1}" + key = f"Фактор_{f_idx+1}" if key not in exp: continue value = exp[key]['natural'] unit = factors[f_idx]['unit'] - display = self._format_number(value) if unit: display += f" {unit}" @@ -567,14 +569,25 @@ class MainWindow(QMainWindow): item = QTableWidgetItem(display) if exp.get('is_center', False): item.setBackground(QColor(255, 255, 200)) - self.design_matrix.setItem(exp_idx, f_idx + 1, item) - + self.design_matrix.setItem(exp_idx, f_idx, item) + if n_i_factors>0: + for f_idx in range(n_i_factors): + value = i_factors[f_idx]['center'] + unit = i_factors[f_idx]['unit'] + display = self._format_number(value) + if unit: + display += f" {unit}" + item = QTableWidgetItem(display) + + item.setBackground(QColor(255, 255, 200)) + self.design_matrix.setItem(exp_idx, n_factors + f_idx, item) + if exp.get('is_center', False): type_item = QTableWidgetItem(f"Центр #{exp['center_num']}") type_item.setBackground(QColor(255, 255, 200)) else: type_item = QTableWidgetItem("Факторная") - self.design_matrix.setItem(exp_idx, n_factors + 1, type_item) + self.design_matrix.setItem(exp_idx, n_factors+n_i_factors, type_item) self.design_matrix.resizeColumnsToContents() @@ -600,7 +613,7 @@ class MainWindow(QMainWindow): self.results_table.setHorizontalHeaderLabels(["№ опыта", "Результат"]) for i in range(n_experiments): - self.results_table.setItem(i, 0, QTableWidgetItem(str(i + 1))) + self.results_table.setItem(i, 0, QTableWidgetItem(str(i))) def _export_design_csv(self): """Экспортирует матрицу планирования в CSV""" diff --git a/main.py b/main.py index cf4c6dc..f66d3a3 100644 --- a/main.py +++ b/main.py @@ -1,6 +1,11 @@ # main.py """ Биохимический помощник - точка входа в приложение +TODO: +- Добавить информацию о количестве раствора в DOE +- Не считать фактор, если его шаг 0 ОК +- Добавить столбец в матрицу планирования с информацией о количестве добавленного растворителя, учитывая все реагенты +- Начать делать анализ """ import sys