```python
# control_interface.py

import tkinter as tk
from tkinter import ttk, messagebox
import threading
import time

# Импортируем необходимые классы из проекта
from propulsion.plasma_propulsion import PlasmaThruster
from power_system.solar_power import SolarPanel
from power_system.energy_management import EnergyManager
from control_system.pid_controller import PIDController
from thermal_management.heat_transfer import HeatTransfer
from structural_analysis.stress_analysis import StressAnalysis
from utils.constants import G0, STEFAN_BOLTZMANN

# Реализация класса ToolTip
class ToolTip:
    """
    Создает всплывающую подсказку для данного виджета.
    """
    def __init__(self, widget, text='widget info'):
        self.widget = widget
        self.text = text
        self.tipwindow = None
        self.id = None
        self.x = self.y = 0
        widget.bind("<Enter>", self.show_tip)
        widget.bind("<Leave>", self.hide_tip)

    def show_tip(self, event=None):
        "Отображает подсказку"
        if self.tipwindow or not self.text:
            return
        x, y, cx, cy = self.widget.bbox("insert")
        x = x + self.widget.winfo_rootx() + 25
        y = y + self.widget.winfo_rooty() + 20
        self.tipwindow = tw = tk.Toplevel(self.widget)
        tw.wm_overrideredirect(True)  # Без рамки окна
        tw.wm_geometry(f"+{x}+{y}")
        label = tk.Label(tw, text=self.text, justify='left',
                         background="#ffffe0", relief='solid', borderwidth=1,
                         font=("tahoma", "8", "normal"))
        label.pack(ipadx=1)

    def hide_tip(self, event=None):
        "Скрывает подсказку"
        tw = self.tipwindow
        self.tipwindow = None
        if tw:
            tw.destroy()

class RocketControlInterface:
    def __init__(self, master):
        self.master = master
        master.title("Расширенное Управление Ракетой MHPEPS")

        # Создаем основную структуру интерфейса с использованием фреймов
        self.create_main_frames()

        # Инициализация систем
        self.initialize_systems()

        # Создание вкладок интерфейса внутри левого фрейма
        self.create_tabs()

        # Ракета на канвасе внутри правого фрейма
        self.create_rocket_visual()

        # Лог для отображения событий внутри левого фрейма
        self.create_log_panel()

        # Запуск симуляции
        self.running = True
        self.simulation_thread = threading.Thread(target=self.run_simulation, daemon=True)
        self.simulation_thread.start()

    def create_main_frames(self):
        """Создание основных фреймов для разделения интерфейса."""
        # Левый фрейм для вкладок и логов
        self.left_frame = ttk.Frame(self.master)
        self.left_frame.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)

        # Правый фрейм для визуализации ракеты
        self.right_frame = ttk.Frame(self.master)
        self.right_frame.pack(side=tk.RIGHT, fill=tk.BOTH, expand=True)

    def initialize_systems(self):
        """Инициализация всех модулей системы."""
        # Инициализация солнечной панели
        self.solar_panel = SolarPanel(area=1.0, efficiency=0.3)
        self.power_output = self.solar_panel.calculate_power_output()

        # Инициализация менеджера энергии
        self.energy_manager = EnergyManager(power_sources=[self.power_output])

        # Потребности в мощности для систем
        self.demands = [6000, 2000]  # Вт: [двигатель, вспомогательные системы]
        self.allocate_energy_initial()

        # Инициализация плазменного двигателя
        ion_mass = 2.18e-25  # кг
        self.thruster = PlasmaThruster(accelerating_voltage=1000, ion_mass=ion_mass)
        self.thruster.set_power(self.allocated_power_thruster)
        self.thrust = self.thruster.get_thrust()
        self.si = self.thruster.get_specific_impulse()

        # Инициализация PID-контроллера
        self.pid = PIDController(Kp=10.0, Ki=1.0, Kd=0.5, setpoint=self.thrust)

        # Инициализация анализа напряжений
        cross_section_area = 0.01  # м²
        young_modulus = 2e11       # Па
        yield_strength = 3e8       # Па
        self.stress_analysis = StressAnalysis(force=self.thrust, area=cross_section_area,
                                              young_modulus=young_modulus,
                                              yield_strength=yield_strength)

        # Инициализация теплопередачи
        self.thermal_conductivity = 400  # Вт/(м·К)
        self.heat_transfer_area = 2.0     # м²
        self.thickness = 0.1              # м
        self.temperature_diff = 500        # К
        self.heat_transfer = HeatTransfer(thermal_conductivity=self.thermal_conductivity,
                                          area=self.heat_transfer_area,
                                          thickness=self.thickness,
                                          temperature_diff=self.temperature_diff)
        self.conductive_heat = self.heat_transfer.conductive_heat_transfer()
        self.radiative_heat = self.heat_transfer.radiative_heat_transfer(emissivity=0.8,
                                                                           T_hot=1000,
                                                                           T_cold=300)

    def allocate_energy_initial(self):
        """Первоначальное распределение энергии между системами."""
        self.allocated = self.energy_manager.allocate_power(self.demands)
        self.allocated_power_thruster = self.allocated[0]
        self.allocated_power_aux = self.allocated[1]

    def create_tabs(self):
        """Создание вкладок внутри левого фрейма."""
        self.tab_control = ttk.Notebook(self.left_frame)
        self.tab_control.pack(expand=1, fill="both")

        # Вкладки
        self.tab_solar = ttk.Frame(self.tab_control)
        self.tab_energy = ttk.Frame(self.tab_control)
        self.tab_thruster = ttk.Frame(self.tab_control)
        self.tab_thermal = ttk.Frame(self.tab_control)
        self.tab_structural = ttk.Frame(self.tab_control)
        self.tab_pid = ttk.Frame(self.tab_control)

        self.tab_control.add(self.tab_solar, text='Солнечная Панель')
        self.tab_control.add(self.tab_energy, text='Управление Энергией')
        self.tab_control.add(self.tab_thruster, text='Плазменный Двигатель')
        self.tab_control.add(self.tab_thermal, text='Теплопередача')
        self.tab_control.add(self.tab_structural, text='Анализ Напряжений')
        self.tab_control.add(self.tab_pid, text='PID Контроллер')

        # Наполнение вкладок
        self.create_solar_tab()
        self.create_energy_tab()
        self.create_thruster_tab()
        self.create_thermal_tab()
        self.create_structural_tab()
        self.create_pid_tab()

    def create_solar_tab(self):
        """Создание вкладки для управления солнечной панелью."""
        # Солнечная Панель: настройка площади, КПД, инсоляции
        ttk.Label(self.tab_solar, text="Площадь панели (м²):").grid(row=0, column=0, padx=5, pady=5, sticky="w")
        self.solar_area_var = tk.DoubleVar(value=self.solar_panel.area)
        self.solar_area_entry = ttk.Entry(self.tab_solar, textvariable=self.solar_area_var)
        self.solar_area_entry.grid(row=0, column=1, padx=5, pady=5, sticky="ew")
        ToolTip(self.solar_area_entry, "Укажите площадь солнечной панели в квадратных метрах.")

        ttk.Label(self.tab_solar, text="КПД панели:").grid(row=1, column=0, padx=5, pady=5, sticky="w")
        self.solar_efficiency_var = tk.DoubleVar(value=self.solar_panel.efficiency)
        self.solar_efficiency_entry = ttk.Entry(self.tab_solar, textvariable=self.solar_efficiency_var)
        self.solar_efficiency_entry.grid(row=1, column=1, padx=5, pady=5, sticky="ew")
        ToolTip(self.solar_efficiency_entry, "КПД солнечной панели (например, 0.3 для 30%). Максимальное значение 1.0.")

        ttk.Label(self.tab_solar, text="Инсоляция (Вт/м²):").grid(row=2, column=0, padx=5, pady=5, sticky="w")
        self.solar_irradiance_var = tk.DoubleVar(value=self.solar_panel.irradiance)
        self.solar_irradiance_entry = ttk.Entry(self.tab_solar, textvariable=self.solar_irradiance_var)
        self.solar_irradiance_entry.grid(row=2, column=1, padx=5, pady=5, sticky="ew")
        ToolTip(self.solar_irradiance_entry, "Солнечная инсоляция в ваттах на квадратный метр (Вт/м²). Обычно около 1361 Вт/м².")

        self.update_solar_button = ttk.Button(self.tab_solar, text="Обновить Параметры",
                                              command=self.update_solar_parameters)
        self.update_solar_button.grid(row=3, column=0, columnspan=2, pady=10)
        ToolTip(self.update_solar_button, "Нажмите, чтобы применить изменения настроек солнечной панели.")

        # Отображение выходной мощности
        ttk.Label(self.tab_solar, text="Выходная мощность (Вт):").grid(row=4, column=0, padx=5, pady=5, sticky="w")
        self.power_output_label = ttk.Label(self.tab_solar, text=f"{self.power_output:.2f} Вт")
        self.power_output_label.grid(row=4, column=1, padx=5, pady=5, sticky="w")
        ToolTip(self.power_output_label, "Текущая выходная мощность солнечной панели на основе заданных параметров.")

        # Настройка сетки
        self.tab_solar.columnconfigure(1, weight=1)

    def create_energy_tab(self):
        """Создание вкладки для управления энергопотреблением."""
        # Энергетическое управление: распределение мощностей
        ttk.Label(self.tab_energy, text="Потребности в мощности (Вт):").grid(row=0, column=0, padx=5, pady=5, sticky="w")

        # Основной двигатель
        ttk.Label(self.tab_energy, text="Двигатель:").grid(row=1, column=0, padx=5, pady=5, sticky="w")
        self.energy_demand_thruster_var = tk.DoubleVar(value=self.demands[0])
        self.energy_demand_thruster_entry = ttk.Entry(self.tab_energy, textvariable=self.energy_demand_thruster_var)
        self.energy_demand_thruster_entry.grid(row=1, column=1, padx=5, pady=5, sticky="ew")
        ToolTip(self.energy_demand_thruster_entry, "Требуемая мощность для основного двигателя (Вт).")

        # Вспомогательные системы
        ttk.Label(self.tab_energy, text="Вспомогательные системы:").grid(row=2, column=0, padx=5, pady=5, sticky="w")
        self.energy_demand_aux_var = tk.DoubleVar(value=self.demands[1])
        self.energy_demand_aux_entry = ttk.Entry(self.tab_energy, textvariable=self.energy_demand_aux_var)
        self.energy_demand_aux_entry.grid(row=2, column=1, padx=5, pady=5, sticky="ew")
        ToolTip(self.energy_demand_aux_entry, "Требуемая мощность для вспомогательных систем (Вт).")

        self.allocate_energy_button = ttk.Button(self.tab_energy, text="Распределить Энергию",
                                                command=self.allocate_energy)
        self.allocate_energy_button.grid(row=3, column=0, columnspan=2, pady=10)
        ToolTip(self.allocate_energy_button, "Нажмите, чтобы распределить доступную мощность между системами.")

        # Отображение распределенной мощности
        ttk.Label(self.tab_energy, text="Распределенная мощность (Вт):").grid(row=4, column=0, padx=5, pady=5, sticky="w")
        ttk.Label(self.tab_energy, text="Двигатель:").grid(row=5, column=0, padx=5, pady=5, sticky="w")
        self.allocated_power_thruster_label = ttk.Label(self.tab_energy, text=f"{self.allocated_power_thruster:.2f} Вт")
        self.allocated_power_thruster_label.grid(row=5, column=1, padx=5, pady=5, sticky="w")
        ToolTip(self.allocated_power_thruster_label, "Мощность, выделенная для основного двигателя.")

        ttk.Label(self.tab_energy, text="Вспомогательные системы:").grid(row=6, column=0, padx=5, pady=5, sticky="w")
        self.allocated_power_aux_label = ttk.Label(self.tab_energy, text=f"{self.allocated_power_aux:.2f} Вт")
        self.allocated_power_aux_label.grid(row=6, column=1, padx=5, pady=5, sticky="w")
        ToolTip(self.allocated_power_aux_label, "Мощность, выделенная для вспомогательных систем.")

        # Настройка сетки
        self.tab_energy.columnconfigure(1, weight=1)

    def create_thruster_tab(self):
        """Создание вкладки для управления плазменным двигателем."""
        # Плазменный Двигатель: настройка напряжения ускорения и массового расхода
        ttk.Label(self.tab_thruster, text="Напряжение ускорения (В):").grid(row=0, column=0, padx=5, pady=5, sticky="w")
        self.thruster_voltage_var = tk.DoubleVar(value=self.thruster.accelerating_voltage)
        self.thruster_voltage_entry = ttk.Entry(self.tab_thruster, textvariable=self.thruster_voltage_var)
        self.thruster_voltage_entry.grid(row=0, column=1, padx=5, pady=5, sticky="ew")
        ToolTip(self.thruster_voltage_entry, "Напряжение ускорения ионов в плазменном двигателе (В).")

        # Массовый расход отображается и обновляется автоматически
        ttk.Label(self.tab_thruster, text="Массовый расход (кг/с):").grid(row=1, column=0, padx=5, pady=5, sticky="w")
        self.thruster_mass_flow_var = tk.DoubleVar(value=self.thruster.mass_flow_rate)
        self.thruster_mass_flow_entry = ttk.Entry(self.tab_thruster, textvariable=self.thruster_mass_flow_var, state='readonly')
        self.thruster_mass_flow_entry.grid(row=1, column=1, padx=5, pady=5, sticky="ew")
        ToolTip(self.thruster_mass_flow_entry, "Текущий массовый расход плазменного двигателя (кг/с). Изменяется автоматически.")

        self.update_thruster_button = ttk.Button(self.tab_thruster, text="Обновить Параметры",
                                                command=self.update_thruster_parameters)
        self.update_thruster_button.grid(row=2, column=0, columnspan=2, pady=10)
        ToolTip(self.update_thruster_button, "Нажмите, чтобы применить изменения настроек двигателя.")

        # Отображение тяги и удельного импульса
        ttk.Label(self.tab_thruster, text="Тяга двигателя (Н):").grid(row=3, column=0, padx=5, pady=5, sticky="w")
        self.thruster_thrust_label = ttk.Label(self.tab_thruster, text=f"{self.thrust:.4f} Н")
        self.thruster_thrust_label.grid(row=3, column=1, padx=5, pady=5, sticky="w")
        ToolTip(self.thruster_thrust_label, "Текущая тяга плазменного двигателя (Н).")

        ttk.Label(self.tab_thruster, text="Удельный импульс (с):").grid(row=4, column=0, padx=5, pady=5, sticky="w")
        self.thruster_si_label = ttk.Label(self.tab_thruster, text=f"{self.si:.2f} с")
        self.thruster_si_label.grid(row=4, column=1, padx=5, pady=5, sticky="w")
        ToolTip(self.thruster_si_label, "Текущий удельный импульс двигателя (с).")

        # Настройка сетки
        self.tab_thruster.columnconfigure(1, weight=1)

    def create_thermal_tab(self):
        """Создание вкладки для управления теплопередачей."""
        # Теплопередача: настройка теплопроводности, площади, толщины и разницы температур
        ttk.Label(self.tab_thermal, text="Теплопроводность (Вт/(м·К)):").grid(row=0, column=0, padx=5, pady=5, sticky="w")
        self.thermal_k_var = tk.DoubleVar(value=self.thermal_conductivity)
        self.thermal_k_entry = ttk.Entry(self.tab_thermal, textvariable=self.thermal_k_var)
        self.thermal_k_entry.grid(row=0, column=1, padx=5, pady=5, sticky="ew")
        ToolTip(self.thermal_k_entry, "Теплопроводность материала, используемого в системе (Вт/(м·К)).")

        ttk.Label(self.tab_thermal, text="Площадь (м²):").grid(row=1, column=0, padx=5, pady=5, sticky="w")
        self.thermal_area_var = tk.DoubleVar(value=self.heat_transfer_area)
        self.thermal_area_entry = ttk.Entry(self.tab_thermal, textvariable=self.thermal_area_var)
        self.thermal_area_entry.grid(row=1, column=1, padx=5, pady=5, sticky="ew")
        ToolTip(self.thermal_area_entry, "Площадь поверхности, через которую происходит теплопередача (м²).")

        ttk.Label(self.tab_thermal, text="Толщина (м):").grid(row=2, column=0, padx=5, pady=5, sticky="w")
        self.thermal_thickness_var = tk.DoubleVar(value=self.thickness)
        self.thermal_thickness_entry = ttk.Entry(self.tab_thermal, textvariable=self.thermal_thickness_var)
        self.thermal_thickness_entry.grid(row=2, column=1, padx=5, pady=5, sticky="ew")
        ToolTip(self.thermal_thickness_entry, "Толщина материала, через который происходит теплопередача (м).")

        ttk.Label(self.tab_thermal, text="Разница температур (К):").grid(row=3, column=0, padx=5, pady=5, sticky="w")
        self.thermal_delta_T_var = tk.DoubleVar(value=self.temperature_diff)
        self.thermal_delta_T_entry = ttk.Entry(self.tab_thermal, textvariable=self.thermal_delta_T_var)
        self.thermal_delta_T_entry.grid(row=3, column=1, padx=5, pady=5, sticky="ew")
        ToolTip(self.thermal_delta_T_entry, "Разница температур между горячей и холодной поверхностями (К).")

        self.update_thermal_button = ttk.Button(self.tab_thermal, text="Обновить Параметры",
                                               command=self.update_thermal_parameters)
        self.update_thermal_button.grid(row=4, column=0, columnspan=2, pady=10)
        ToolTip(self.update_thermal_button, "Нажмите, чтобы применить изменения настроек теплопередачи.")

        # Отображение теплопередачи
        ttk.Label(self.tab_thermal, text="Теплопередача по проводимости (Вт):").grid(row=5, column=0, padx=5, pady=5, sticky="w")
        self.thermal_cond_heat_label = ttk.Label(self.tab_thermal, text=f"{self.conductive_heat:.2e} Вт")
        self.thermal_cond_heat_label.grid(row=5, column=1, padx=5, pady=5, sticky="w")
        ToolTip(self.thermal_cond_heat_label, "Количество тепла, переданное по проводимости (Вт).")

        ttk.Label(self.tab_thermal, text="Теплопередача по излучению (Вт):").grid(row=6, column=0, padx=5, pady=5, sticky="w")
        self.thermal_rad_heat_label = ttk.Label(self.tab_thermal, text=f"{self.radiative_heat:.2e} Вт")
        self.thermal_rad_heat_label.grid(row=6, column=1, padx=5, pady=5, sticky="w")
        ToolTip(self.thermal_rad_heat_label, "Количество тепла, переданное по излучению (Вт).")

        # Настройка сетки
        self.tab_thermal.columnconfigure(1, weight=1)

    def create_structural_tab(self):
        """Создание вкладки для анализа напряжений."""
        # Анализ Напряжений: настройка площади, модуля Юнга и предела текучести
        ttk.Label(self.tab_structural, text="Площадь поперечного сечения (м²):").grid(row=0, column=0, padx=5, pady=5, sticky="w")
        self.structural_area_var = tk.DoubleVar(value=self.stress_analysis.area)
        self.structural_area_entry = ttk.Entry(self.tab_structural, textvariable=self.structural_area_var)
        self.structural_area_entry.grid(row=0, column=1, padx=5, pady=5, sticky="ew")
        ToolTip(self.structural_area_entry, "Площадь поперечного сечения конструкции (м²).")

        ttk.Label(self.tab_structural, text="Модуль Юнга (Па):").grid(row=1, column=0, padx=5, pady=5, sticky="w")
        self.structural_E_var = tk.DoubleVar(value=self.stress_analysis.E)
        self.structural_E_entry = ttk.Entry(self.tab_structural, textvariable=self.structural_E_var)
        self.structural_E_entry.grid(row=1, column=1, padx=5, pady=5, sticky="ew")
        ToolTip(self.structural_E_entry, "Модуль Юнга материала конструкции (Па).")

        ttk.Label(self.tab_structural, text="Предел текучести (Па):").grid(row=2, column=0, padx=5, pady=5, sticky="w")
        self.structural_yield_var = tk.DoubleVar(value=self.stress_analysis.sigma_y)
        self.structural_yield_entry = ttk.Entry(self.tab_structural, textvariable=self.structural_yield_var)
        self.structural_yield_entry.grid(row=2, column=1, padx=5, pady=5, sticky="ew")
        ToolTip(self.structural_yield_entry, "Предел текучести материала конструкции (Па).")

        self.update_structural_button = ttk.Button(self.tab_structural, text="Обновить Параметры",
                                                   command=self.update_structural_parameters)
        self.update_structural_button.grid(row=3, column=0, columnspan=2, pady=10)
        ToolTip(self.update_structural_button, "Нажмите, чтобы применить изменения настроек анализа напряжений.")

        # Отображение напряжения и состояния
        ttk.Label(self.tab_structural, text="Напряжение (Па):").grid(row=4, column=0, padx=5, pady=5, sticky="w")
        self.structural_stress_label = ttk.Label(self.tab_structural, text="-- Па", foreground="black")
        self.structural_stress_label.grid(row=4, column=1, padx=5, pady=5, sticky="w")
        ToolTip(self.structural_stress_label, "Текущее напряжение в конструкции (Па).")

        ttk.Label(self.tab_structural, text="Предел текучести превышен:").grid(row=5, column=0, padx=5, pady=5, sticky="w")
        self.structural_yielding_label = ttk.Label(self.tab_structural, text="--", foreground="black")
        self.structural_yielding_label.grid(row=5, column=1, padx=5, pady=5, sticky="w")
        ToolTip(self.structural_yielding_label, "Статус превышения предела текучести (Да/Нет).")

        # Настройка сетки
        self.tab_structural.columnconfigure(1, weight=1)

    def create_pid_tab(self):
        """Создание вкладки для управления PID-контроллером."""
        # PID Контроллер: настройка коэффициентов и заданной тяги
        ttk.Label(self.tab_pid, text="Kp:").grid(row=0, column=0, padx=5, pady=5, sticky="w")
        self.pid_Kp_var = tk.DoubleVar(value=self.pid.Kp)
        self.pid_Kp_entry = ttk.Entry(self.tab_pid, textvariable=self.pid_Kp_var)
        self.pid_Kp_entry.grid(row=0, column=1, padx=5, pady=5, sticky="ew")
        ToolTip(self.pid_Kp_entry, "Пропорциональный коэффициент PID-контроллера.")

        ttk.Label(self.tab_pid, text="Ki:").grid(row=1, column=0, padx=5, pady=5, sticky="w")
        self.pid_Ki_var = tk.DoubleVar(value=self.pid.Ki)
        self.pid_Ki_entry = ttk.Entry(self.tab_pid, textvariable=self.pid_Ki_var)
        self.pid_Ki_entry.grid(row=1, column=1, padx=5, pady=5, sticky="ew")
        ToolTip(self.pid_Ki_entry, "Интегральный коэффициент PID-контроллера.")

        ttk.Label(self.tab_pid, text="Kd:").grid(row=2, column=0, padx=5, pady=5, sticky="w")
        self.pid_Kd_var = tk.DoubleVar(value=self.pid.Kd)
        self.pid_Kd_entry = ttk.Entry(self.tab_pid, textvariable=self.pid_Kd_var)
        self.pid_Kd_entry.grid(row=2, column=1, padx=5, pady=5, sticky="ew")
        ToolTip(self.pid_Kd_entry, "Дифференциальный коэффициент PID-контроллера.")

        ttk.Label(self.tab_pid, text="Заданная тяга (Н):").grid(row=3, column=0, padx=5, pady=5, sticky="w")
        self.pid_setpoint_var = tk.DoubleVar(value=self.pid.setpoint)
        self.pid_setpoint_entry = ttk.Entry(self.tab_pid, textvariable=self.pid_setpoint_var)
        self.pid_setpoint_entry.grid(row=3, column=1, padx=5, pady=5, sticky="ew")
        ToolTip(self.pid_setpoint_entry, "Желаемая тяга двигателя (Н). PID-контроллер будет пытаться поддерживать эту тягу.")

        self.update_pid_button = ttk.Button(self.tab_pid, text="Обновить PID",
                                           command=self.update_pid_parameters)
        self.update_pid_button.grid(row=4, column=0, columnspan=2, pady=10)
        ToolTip(self.update_pid_button, "Нажмите, чтобы применить изменения настроек PID-контроллера.")

        # Отображение текущих коэффициентов PID
        ttk.Label(self.tab_pid, text="Текущие Kp:").grid(row=5, column=0, padx=5, pady=5, sticky="w")
        self.pid_current_Kp_label = ttk.Label(self.tab_pid, text=f"{self.pid.Kp:.2f}")
        self.pid_current_Kp_label.grid(row=5, column=1, padx=5, pady=5, sticky="w")
        ToolTip(self.pid_current_Kp_label, "Текущий пропорциональный коэффициент PID-контроллера.")

        ttk.Label(self.tab_pid, text="Текущие Ki:").grid(row=6, column=0, padx=5, pady=5, sticky="w")
        self.pid_current_Ki_label = ttk.Label(self.tab_pid, text=f"{self.pid.Ki:.2f}")
        self.pid_current_Ki_label.grid(row=6, column=1, padx=5, pady=5, sticky="w")
        ToolTip(self.pid_current_Ki_label, "Текущий интегральный коэффициент PID-контроллера.")

        ttk.Label(self.tab_pid, text="Текущие Kd:").grid(row=7, column=0, padx=5, pady=5, sticky="w")
        self.pid_current_Kd_label = ttk.Label(self.tab_pid, text=f"{self.pid.Kd:.2f}")
        self.pid_current_Kd_label.grid(row=7, column=1, padx=5, pady=5, sticky="w")
        ToolTip(self.pid_current_Kd_label, "Текущий дифференциальный коэффициент PID-контроллера.")

        # Настройка сетки
        self.tab_pid.columnconfigure(1, weight=1)

    def create_rocket_visual(self):
        """Создание визуализации ракеты внутри правого фрейма."""
        # Создание канваса для отображения ракеты
        self.canvas_width = 400
        self.canvas_height = 600
        self.canvas = tk.Canvas(self.right_frame, width=self.canvas_width, height=self.canvas_height, bg="black")
        self.canvas.pack(padx=10, pady=10)

        # Начальная позиция ракеты (нижняя часть канваса)
        self.rocket_x = self.canvas_width / 2
        self.rocket_y = self.canvas_height - 50  # Начальная Y позиция

        # Рисуем ракету как треугольник
        self.rocket = self.canvas.create_polygon(
            self.rocket_x, self.rocket_y - 40,
            self.rocket_x - 20, self.rocket_y + 20,
            self.rocket_x + 20, self.rocket_y + 20,
            fill="white"
        )

    def create_log_panel(self):
        """Создание панели логов внутри левого фрейма."""
        self.log_frame = ttk.LabelFrame(self.left_frame, text="Лог Симуляции")
        self.log_frame.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)

        self.log_text = tk.Text(self.log_frame, width=50, height=15, state='disabled')
        self.log_text.pack(padx=5, pady=5, fill=tk.BOTH, expand=True)

    def log_event(self, message):
        """Добавление сообщений в лог."""
        self.log_text.config(state='normal')
        self.log_text.insert(tk.END, f"{time.strftime('%H:%M:%S')} - {message}\n")
        self.log_text.see(tk.END)
        self.log_text.config(state='disabled')

    def update_solar_parameters(self):
        """Обновление параметров солнечной панели."""
        try:
            area = self.solar_area_var.get()
            efficiency = self.solar_efficiency_var.get()
            irradiance = self.solar_irradiance_var.get()

            # Валидация ввода
            errors = []
            if area <= 0:
                errors.append("Площадь панели должна быть положительной.")
            if not (0 < efficiency <= 1):
                errors.append("КПД панели должен быть между 0 и 1.")
            if irradiance <= 0:
                errors.append("Инсоляция должна быть положительной.")

            if errors:
                raise ValueError("\n".join(errors))

            self.solar_panel.area = area
            self.solar_panel.efficiency = efficiency
            self.solar_panel.irradiance = irradiance

            self.power_output = self.solar_panel.calculate_power_output()
            self.log_event(f"Солнечная панель обновлена: площадь={area} м², КПД={efficiency}, инсоляция={irradiance} Вт/м²")
            self.log_event(f"Новая выходная мощность: {self.power_output:.2f} Вт")

            # Обновление менеджера энергии
            self.energy_manager.power_sources = [self.power_output]
            self.allocate_energy()

        except ValueError as e:
            messagebox.showwarning("Ошибка Ввода", f"Неверные параметры солнечной панели:\n{e}")
            self.log_event(f"Ошибка обновления солнечной панели: {e}")

    def allocate_energy(self):
        """Распределение энергии между системами."""
        try:
            self.allocated = self.energy_manager.allocate_power(self.demands)
            self.allocated_power_thruster = self.allocated[0]
            self.allocated_power_aux = self.allocated[1]

            # Обновление отображаемых значений распределенной мощности
            self.allocated_power_thruster_label.config(text=f"{self.allocated_power_thruster:.2f} Вт")
            self.allocated_power_aux_label.config(text=f"{self.allocated_power_aux:.2f} Вт")

            # Обновление мощности двигателя
            self.thruster.set_power(self.allocated_power_thruster)
            self.thrust = self.thruster.get_thrust()
            self.si = self.thruster.get_specific_impulse()

            self.thruster_thrust_label.config(text=f"{self.thrust:.4f} Н")
            self.thruster_si_label.config(text=f"{self.si:.2f} с")

            # Добавление предупреждения, если выделенная мощность слишком мала для двигателя
            if self.allocated_power_thruster < 100:
                messagebox.showwarning("Предупреждение", "Выделенная мощность для двигателя слишком мала. Возможна снижение тяги или нестабильная работа.")
                self.log_event("Внимание: выделенная мощность для двигателя слишком мала.")

            # Добавление предупреждения, если выделенная мощность слишком большая
            if self.allocated_power_thruster > 8000:
                messagebox.showwarning("Предупреждение", "Выделенная мощность для двигателя слишком велика. Возможен перегрев или разрыв двигателя.")
                self.log_event("Внимание: выделенная мощность для двигателя слишком велика. Возможен разрыв двигателя.")

            self.log_event(f"Энергия распределена: двигатель={self.allocated_power_thruster:.2f} Вт, вспомогательные системы={self.allocated_power_aux:.2f} Вт")

        except ValueError as e:
            messagebox.showwarning("Ошибка Распределения Энергии", f"Невозможно распределить энергию:\n{e}")
            self.log_event(f"Ошибка распределения энергии: {e}")

    def update_thruster_parameters(self):
        """Обновление параметров плазменного двигателя."""
        try:
            voltage = self.thruster_voltage_var.get()
            mass_flow = self.thruster_mass_flow_var.get()

            # Валидация ввода
            errors = []
            if voltage <= 0:
                errors.append("Напряжение ускорения должно быть положительным.")
            if mass_flow < 0:
                errors.append("Массовый расход не может быть отрицательным.")

            if errors:
                raise ValueError("\n".join(errors))

            self.thruster.accelerating_voltage = voltage
            self.thruster.mass_flow_rate = mass_flow

            self.thruster.set_power(self.allocated_power_thruster)
            self.thrust = self.thruster.get_thrust()
            self.si = self.thruster.get_specific_impulse()

            self.thruster_thrust_label.config(text=f"{self.thrust:.4f} Н")
            self.thruster_si_label.config(text=f"{self.si:.2f} с")

            self.log_event(f"Плазменный двигатель обновлен: напряжение={voltage} В, массовый расход={mass_flow} кг/с")
            self.log_event(f"Новая тяга: {self.thrust:.4f} Н, удельный импульс: {self.si:.2f} с")

            # Добавление предупреждения при слишком большом массовом расходе
            if mass_flow > 1e-4:
                messagebox.showwarning("Предупреждение", "Массовый расход слишком велик. Возможен перегрев двигателя или истощение топлива.")
                self.log_event("Внимание: массовый расход слишком велик. Возможен перегрев двигателя или истощение топлива.")

        except ValueError as e:
            messagebox.showwarning("Ошибка Ввода", f"Неверные параметры двигателя:\n{e}")
            self.log_event(f"Ошибка обновления плазменного двигателя: {e}")

    def update_thermal_parameters(self):
        """Обновление параметров теплопередачи."""
        try:
            k = self.thermal_k_var.get()
            area = self.thermal_area_var.get()
            thickness = self.thermal_thickness_var.get()
            delta_T = self.thermal_delta_T_var.get()

            # Валидация ввода
            errors = []
            if k <= 0:
                errors.append("Теплопроводность должна быть положительной.")
            if area <= 0:
                errors.append("Площадь должна быть положительной.")
            if thickness <= 0:
                errors.append("Толщина должна быть положительной.")
            if delta_T < 0:
                errors.append("Разница температур не может быть отрицательной.")

            if errors:
                raise ValueError("\n".join(errors))

            self.thermal_conductivity = k
            self.heat_transfer.thermal_conductivity = k
            self.heat_transfer.area = area
            self.heat_transfer.thickness = thickness
            self.heat_transfer.delta_T = delta_T

            self.conductive_heat = self.heat_transfer.conductive_heat_transfer()
            self.radiative_heat = self.heat_transfer.radiative_heat_transfer(emissivity=0.8,
                                                                               T_hot=1000,
                                                                               T_cold=300)

            self.thermal_cond_heat_label.config(text=f"{self.conductive_heat:.2e} Вт")
            self.thermal_rad_heat_label.config(text=f"{self.radiative_heat:.2e} Вт")

            self.log_event(f"Теплопередача обновлена: k={k} Вт/(м·К), A={area} м², d={thickness} м, ΔT={delta_T} К")
            self.log_event(f"Новая теплопередача: проводимость={self.conductive_heat:.2e} Вт, излучение={self.radiative_heat:.2e} Вт")

            # Предупреждения при слишком высокой разнице температур
            if delta_T > 1000:
                messagebox.showwarning("Предупреждение", "Разница температур слишком велика. Возможен перегрев системы.")
                self.log_event("Внимание: разница температур слишком велика. Возможен перегрев системы.")

        except ValueError as e:
            messagebox.showwarning("Ошибка Ввода", f"Неверные параметры теплопередачи:\n{e}")
            self.log_event(f"Ошибка обновления теплопередачи: {e}")

    def update_structural_parameters(self):
        """Обновление параметров анализа напряжений."""
        try:
            area = self.structural_area_var.get()
            E = self.structural_E_var.get()
            sigma_y = self.structural_yield_var.get()

            # Валидация ввода
            errors = []
            if area <= 0:
                errors.append("Площадь поперечного сечения должна быть положительной.")
            if E <= 0:
                errors.append("Модуль Юнга должен быть положительным.")
            if sigma_y <= 0:
                errors.append("Предел текучести должен быть положительным.")

            if errors:
                raise ValueError("\n".join(errors))

            self.stress_analysis.area = area
            self.stress_analysis.E = E
            self.stress_analysis.sigma_y = sigma_y

            stress = self.stress_analysis.calculate_stress()
            yielding = self.stress_analysis.check_yielding()

            self.structural_stress_label.config(text=f"{stress:.2f} Па")

            if yielding:
                self.structural_yielding_label.config(text="Да", foreground="red")
                self.log_event("Внимание: напряжение превышает предел текучести. Возможна деформация конструкции.")
            else:
                self.structural_yielding_label.config(text="Нет", foreground="green")
                self.log_event("Напряжение в пределах допустимых значений.")

            self.log_event(f"Анализ напряжений обновлен: площадь={area} м², модуль Юнга={E} Па, предел текучести={sigma_y} Па")
            self.log_event(f"Текущее напряжение: {stress:.2f} Па, превышен предел текучести: {yielding}")

            # Предупреждения при слишком большом напряжении
            if stress > sigma_y * 0.9:
                messagebox.showwarning("Предупреждение", "Напряжение приближается к пределу текучести. Возможны повреждения конструкции.")
                self.log_event("Внимание: напряжение приближается к пределу текучести.")

        except ValueError as e:
            messagebox.showwarning("Ошибка Ввода", f"Неверные параметры анализа напряжений:\n{e}")
            self.log_event(f"Ошибка обновления анализа напряжений: {e}")

    def update_pid_parameters(self):
        """Обновление параметров PID-контроллера."""
        try:
            Kp = self.pid_Kp_var.get()
            Ki = self.pid_Ki_var.get()
            Kd = self.pid_Kd_var.get()
            setpoint = self.pid_setpoint_var.get()

            # Валидация ввода
            errors = []
            if Kp < 0:
                errors.append("Kp не может быть отрицательным.")
            if Ki < 0:
                errors.append("Ki не может быть отрицательным.")
            if Kd < 0:
                errors.append("Kd не может быть отрицательным.")
            if setpoint < 0:
                errors.append("Заданная тяга не может быть отрицательной.")

            if errors:
                raise ValueError("\n".join(errors))

            self.pid.Kp = Kp
            self.pid.Ki = Ki
            self.pid.Kd = Kd
            self.pid.setpoint = setpoint

            self.pid_current_Kp_label.config(text=f"{self.pid.Kp:.2f}")
            self.pid_current_Ki_label.config(text=f"{self.pid.Ki:.2f}")
            self.pid_current_Kd_label.config(text=f"{self.pid.Kd:.2f}")

            self.log_event(f"PID-Контроллер обновлен: Kp={Kp}, Ki={Ki}, Kd={Kd}, заданная тяга={setpoint} Н")

            # Предупреждение, если заданная тяга слишком велика
            if setpoint > 8000:
                messagebox.showwarning("Предупреждение", "Заданная тяга слишком велика. Возможен перегрев двигателя или разрыв конструкции.")
                self.log_event("Внимание: заданная тяга слишком велика.")

        except ValueError as e:
            messagebox.showwarning("Ошибка Ввода", f"Неверные параметры PID-контроллера:\n{e}")
            self.log_event(f"Ошибка обновления PID-Контроллера: {e}")

    def run_simulation(self):
        """Основной цикл симуляции."""
        while self.running:
            start_time = time.time()

            # Обновление мощности двигателя на основе распределения и PID-контроллера
            self.thruster.set_power(self.allocated_power_thruster)
            self.thrust = self.thruster.get_thrust()
            self.si = self.thruster.get_specific_impulse()

            # Обновление анализа напряжений
            self.stress_analysis.force = self.thrust
            try:
                stress = self.stress_analysis.calculate_stress()
                yielding = self.stress_analysis.check_yielding()
            except ValueError as e:
                stress = 0.0
                yielding = False

            # Обновление теплопередачи (предполагается статичной)
            # Можно сделать динамической, если задать зависимости

            # Обновление отображения тяги и удельного импульса
            self.master.after(0, self.update_thruster_labels)

            # Обновление анализа напряжений
            self.master.after(0, self.update_structural_labels)

            # Обновление распределенной мощности (например, на основе PID)
            # Здесь можно реализовать логику, где PID контролирует распределение мощности
            control = self.pid.update(self.thrust, dt=0.1)
            self.allocated_power_thruster += control * 0.1

            # Ограничение мощности: не меньше 0, не больше солнечной панели
            self.allocated_power_thruster = max(0.0, min(self.allocated_power_thruster, self.power_output))
            self.allocated_power_thruster = round(self.allocated_power_thruster, 2)
            self.allocated_power_thruster_label.config(text=f"{self.allocated_power_thruster:.2f} Вт")
            self.log_event(f"Выделенная мощность двигателя: {self.allocated_power_thruster:.2f} Вт")

            # Рекалькуляция распределенной мощности
            self.master.after(0, self.allocate_energy)

            # Обновление логов
            self.master.after(0, self.log_event, f"Актуальная тяга: {self.thrust:.4f} Н")
            self.master.after(0, self.log_event, f"Удельный импульс: {self.si:.2f} с")

            # Обновление положения ракеты
            self.master.after(0, self.update_rocket_position)

            # Задержка для симуляции реального времени (например, 0.1 секунда)
            elapsed = time.time() - start_time
            time_to_sleep = max(0.0, 0.1 - elapsed)
            time.sleep(time_to_sleep)

    def update_thruster_labels(self):
        """Обновление меток тяги и удельного импульса."""
        self.thruster_thrust_label.config(text=f"{self.thrust:.4f} Н")
        self.thruster_si_label.config(text=f"{self.si:.2f} с")

    def update_structural_labels(self):
        """Обновление меток напряжения и состояния."""
        try:
            stress = self.stress_analysis.calculate_stress()
            yielding = self.stress_analysis.check_yielding()
            self.structural_stress_label.config(text=f"{stress:.2f} Па")

            if yielding:
                self.structural_yielding_label.config(text="Да", foreground="red")
                self.log_event("Внимание: напряжение превышает предел текучести. Возможна деформация конструкции.")
            else:
                self.structural_yielding_label.config(text="Нет", foreground="green")
                self.log_event("Напряжение в пределах допустимых значений.")

            # Предупреждения при слишком большом напряжении
            if stress > self.stress_analysis.sigma_y * 0.9:
                messagebox.showwarning("Предупреждение", "Напряжение приближается к пределу текучести. Возможны повреждения конструкции.")
                self.log_event("Внимание: напряжение приближается к пределу текучести.")

        except ValueError:
            self.structural_stress_label.config(text="-- Па")
            self.structural_yielding_label.config(text="--")

    def allocate_energy(self):
        """Распределение энергии между системами."""
        try:
            # Энергия распределяется на основе потребностей и доступной мощности
            self.allocated = self.energy_manager.allocate_power(self.demands)
            self.allocated_power_thruster = self.allocated[0]
            self.allocated_power_aux = self.allocated[1]

            # Обновление отображаемых значений распределенной мощности
            self.allocated_power_thruster_label.config(text=f"{self.allocated_power_thruster:.2f} Вт")
            self.allocated_power_aux_label.config(text=f"{self.allocated_power_aux:.2f} Вт")

            # Обновление мощности двигателя
            self.thruster.set_power(self.allocated_power_thruster)
            self.thrust = self.thruster.get_thrust()
            self.si = self.thruster.get_specific_impulse()

            self.thruster_thrust_label.config(text=f"{self.thrust:.4f} Н")
            self.thruster_si_label.config(text=f"{self.si:.2f} с")

        except ValueError as e:
            messagebox.showwarning("Ошибка Распределения Энергии", f"Невозможно распределить энергию:\n{e}")
            self.log_event(f"Ошибка распределения энергии: {e}")

    def update_rocket_position(self):
        """Обновление позиции ракеты на канвасе на основе текущей тяги."""
        # Параметры для визуализации
        thrust_scale = 1e4  # Масштаб для отображения тяги
        dy = self.thrust * thrust_scale * 0.0001  # Смещение по Y

        # Ограничение позиции ракеты внутри канваса
        new_y = self.rocket_y + dy
        if new_y < 50:
            new_y = 50  # Верхняя граница
        elif new_y > self.canvas_height - 50:
            new_y = self.canvas_height - 50  # Нижняя граница

        # Расчет смещения
        delta_y = new_y - self.rocket_y
        self.canvas.move(self.rocket, 0, delta_y)
        self.rocket_y = new_y

    def stop_simulation(self):
        """Остановка симуляции и закрытие окна."""
        self.running = False
        self.master.destroy()


if __name__ == "__main__":
    root = tk.Tk()
    interface = RocketControlInterface(root)
    root.mainloop()
```
Исправь баг что окно с предупреждением флудит много раз, исправь баги и ошибки