本文介绍了一个基于PyQt5的无刷电机(BLDC)驱动控制仿真平台。该系统采用Python开发,结合Matplotlib实现数据可视化,主要功能包括: 电机仿真模块:可模拟电机转速、电流、扭矩和温度等参数,支持FOC(磁场定向控制)和BLDC(方波控制)两种算法 性能分析模块:提供效率参数、扭矩参数分析及FFT频谱分析 文档资料模块:包含电机控制原理和技术文档 代码查看器:支持导入、编辑和保存C控制代码 系统采用模块化设计,包含GUI界面、仿真引擎和数据可视化组件,能够直观展示电机运行状态和性能指标。
代码
import sys
import os
import numpy as np
from PyQt5.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout, QLabel, QPushButton, QTextEdit, QFileDialog, QTabWidget, QSlider, QSpinBox, QComboBox, QProgressBar, QSplitter, QMessageBox, QGridLayout, QGroupBox, QTreeWidget, QTreeWidgetItem,QTextBrowser)
from PyQt5.QtGui import QIcon, QFont
from PyQt5.QtCore import Qt, QTimer
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.figure import Figure
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['Microsoft YaHei'] # 设置中文字体
plt.rcParams['axes.unicode_minus'] = False # 解决负号显示问题
import subprocess
import tempfileclass MotorSimulationWidget(QWidget):def __init__(self, parent=None):super().__init__(parent)# 主图表:电机性能self.figure = Figure(figsize=(8, 6), dpi=100)self.canvas = FigureCanvas(self.figure)self.figure.set_facecolor('#f0f0f0')# 子图表:相电流波形self.phase_figure = Figure(figsize=(8, 3), dpi=100)self.phase_canvas = FigureCanvas(self.phase_figure)self.phase_figure.set_facecolor('#f0f0f0')# 初始化仿真数据self.time = np.linspace(0, 10, 1000)self.speed = np.zeros(1000)self.current = np.zeros(1000)self.torque = np.zeros(1000)self.temp = np.zeros(1000)self.phase_u = np.zeros(1000)self.phase_v = np.zeros(1000)self.phase_w = np.zeros(1000)self.last_loaded_file = ""self.algorithm_type = "FOC"layout = QVBoxLayout()layout.addWidget(self.canvas, 30) # 70%空间给主图表layout.addWidget(self.phase_canvas, 30) # 30%空间给相电流图表self.setLayout(layout)# 初始绘制self.reset_data()def get_simulation_data(self):"""返回当前仿真数据"""return {'time': self.time,'speed': self.speed,'current': self.current,'torque': self.torque,'temperature': self.temp,'phase_u': self.phase_u,'phase_v': self.phase_v,'phase_w': self.phase_w}def reset_data(self):"""重置仿真数据"""self.speed = np.zeros(1000)self.current = np.zeros(1000)self.torque = np.zeros(1000)self.temp = np.zeros(1000)self.phase_u = np.zeros(1000)self.phase_v = np.zeros(1000)self.phase_w = np.zeros(1000)self.update_plots()def update_plots(self):"""更新图表"""self.figure.clear()self.phase_figure.clear()# 主图表 - 电机性能ax = self.figure.add_subplot(111)ax.set_facecolor('#f0f0f0')ax.grid(True, linestyle='--', alpha=0.6)ax.plot(self.time, self.speed, 'b-', linewidth=2, label='Speed (RPM)')ax.plot(self.time, self.current * 100, 'g-', linewidth=2, label='Current (x100 A)')ax.plot(self.time, self.torque * 10, 'r-', linewidth=2, label='Torque (x10 N·m)')ax.plot(self.time, self.temp / 10, 'm-', linewidth=2, label='Temp (°C /10)')ax.set_title(f'BLDC Motor Performance ({self.algorithm_type} Control)')ax.set_xlabel('Time (s)')ax.set_ylabel('Value')ax.legend(loc='upper right')# 子图表 - 相电流波形ax_phase = self.phase_figure.add_subplot(111)ax_phase.set_facecolor('#f0f0f0')ax_phase.grid(True, linestyle='--', alpha=0.6)ax_phase.plot(self.time, self.phase_u, 'r-', linewidth=1, label='U Phase')ax_phase.plot(self.time, self.phase_v, 'g-', linewidth=1, label='V Phase')ax_phase.plot(self.time, self.phase_w, 'b-', linewidth=1, label='W Phase')ax_phase.set_title('Phase Currents')ax_phase.set_xlabel('Time (s)')ax_phase.set_ylabel('Current (A)')ax_phase.legend(loc='upper right')self.canvas.draw()self.phase_canvas.draw()def generate_data(self, sim_time):"""生成仿真数据到指定时间点"""if sim_time < 0 or sim_time > 10:return# 找到当前时间对应的索引idx = int(sim_time * 100) # 1000个点覆盖10秒,每0.01秒一个点# 确保索引不超出范围if idx >= len(self.time):returnt = sim_time# 计算当前时间点的值# 启动阶段 (0-2秒)if t <= 2:speed = 1000 * t / 2current = 10 - 8 * t / 2torque = 8 - 6 * t / 2temp = 30 + 20 * t / 2# 稳态运行 (2-5秒)elif t <= 5:speed = 1000current = 2torque = 2temp = 50 + 20 * (t - 2) / 3# 负载增加 (5-7秒)elif t <= 7:speed = 1000 - 200 * (t - 5) / 2current = 2 + 3 * (t - 5) / 2torque = 2 + 3 * (t - 5) / 2temp = 70 + 20 * (t - 5) / 2# 制动阶段 (7-10秒)else:speed = 800 - 800 * (t - 7) / 3current = 5 - 4 * (t - 7) / 3torque = 5 - 4 * (t - 7) / 3temp = 90 - 30 * (t - 7) / 3# 添加噪声使数据更真实noise_scale = 0.1 * t if t < 5 else 0.3 # 随时间增加噪声speed += np.random.normal(0, 15 * noise_scale)current += np.random.normal(0, 0.2 * noise_scale)torque += np.random.normal(0, 0.3 * noise_scale)temp += np.random.normal(0, 1 * noise_scale)# 更新数据数组中的当前点self.speed[idx] = speedself.current[idx] = currentself.torque[idx] = torqueself.temp[idx] = temp# 生成相电流freq = 5 # 5Hz基础频率phase_scale = current * 0.8 # 电流幅值缩放# 根据控制算法调整波形if self.algorithm_type == "FOC":# FOC - 正弦波self.phase_u[idx] = phase_scale * np.sin(2 * np.pi * freq * t)self.phase_v[idx] = phase_scale * np.sin(2 * np.pi * freq * t + 2*np.pi/3)self.phase_w[idx] = phase_scale * np.sin(2 * np.pi * freq * t + 4*np.pi/3)elif self.algorithm_type == "BLDC":# BLDC - 方波angle = (freq * t * 6) % 6self.phase_u[idx] = phase_scale if angle < 3 else -phase_scaleself.phase_v[idx] = phase_scale if 2 <= angle < 5 else -phase_scaleself.phase_w[idx] = phase_scale if (angle < 1 or angle >= 4) else -phase_scaleelse: # 正弦波控制self.phase_u[idx] = phase_scale * np.sin(2 * np.pi * freq * t)self.phase_v[idx] = phase_scale * np.sin(2 * np.pi * freq * t + 2*np.pi/3)self.phase_w[idx] = phase_scale * np.sin(2 * np.pi * freq * t + 4*np.pi/3)# 更新图表显示到当前时间点self.update_plots()def simulate_from_file(self, filename, algorithm_type):"""从C文件启动仿真"""self.last_loaded_file = os.path.basename(filename)self.algorithm_type = algorithm_type.split(' ')[0] # 取第一个单词作为算法类型self.reset_data()return f"已加载 {self.last_loaded_file} ({algorithm_type})"class BLDCControlSimulator(QMainWindow):def __init__(self):super().__init__()self.setWindowTitle("TianQi AI - 无刷电机驱动仿真平台")self.setGeometry(100, 100, 1200, 800)# 设置窗口图标try:self.setWindowIcon(QIcon("bldc_icon.png"))except:pass# 创建主部件和布局central_widget = QWidget()self.setCentralWidget(central_widget)main_layout = QVBoxLayout(central_widget)# 创建标签页self.tab_widget = QTabWidget()main_layout.addWidget(self.tab_widget)# 创建各标签页self.create_simulation_tab()self.create_analysis_tab()self.create_documentation_tab()self.create_code_viewer_tab()# 创建状态栏self.status_bar = self.statusBar()self.progress_bar = QProgressBar()self.progress_bar.setFixedWidth(250)self.progress_bar.setRange(0, 100)self.progress_bar.setValue(0)self.status_bar.addPermanentWidget(self.progress_bar)self.status_bar.showMessage("就绪 | 点击 '导入C文件' 开始仿真")# 初始化仿真定时器self.sim_timer = QTimer()self.sim_timer.timeout.connect(self.update_simulation)self.sim_time = 0self.sim_running = False# 温度监控self.current_temp = 30self.peak_temp = 30# 标签页创建函数保持不变(使用之前的实现)def create_simulation_tab(self):"""创建仿真标签页"""sim_tab = QWidget()layout = QVBoxLayout(sim_tab)# 标题header = QLabel("无刷电机(BLDC)驱动控制仿真平台")header.setStyleSheet("font-size: 20px; font-weight: bold; color: #0047AB; margin: 10px;")layout.addWidget(header)# 仿真图表部件self.sim_widget = MotorSimulationWidget()layout.addWidget(self.sim_widget, 80)# 控制面板control_panel = QWidget()control_layout = QHBoxLayout(control_panel)# 文件导入区域file_box = QWidget()file_layout = QVBoxLayout(file_box)file_label = QLabel("控制算法导入")file_label.setStyleSheet("font-weight: bold;")self.file_path_label = QLabel("尚未加载任何文件")self.file_path_label.setWordWrap(True)self.file_path_label.setStyleSheet("color: #555555; padding: 2px; border: 1px solid #cccccc; border-radius: 3px;")# 导入按钮import_btn = QPushButton("导入C文件")import_btn.clicked.connect(self.import_file)import_btn.setStyleSheet("background-color: #4CAF50; color: white; padding: 8px; border-radius: 4px;")file_layout.addWidget(file_label)file_layout.addWidget(self.file_path_label)file_layout.addWidget(import_btn)# 控制算法设置区域algo_box = QWidget()algo_layout = QVBoxLayout(algo_box)algo_label = QLabel("控制算法设置")algo_label.setStyleSheet("font-weight: bold;")# 算法选择algo_type_layout = QHBoxLayout()algo_type_layout.addWidget(QLabel("算法类型:"))self.algo_combo = QComboBox()self.algo_combo.addItems(["FOC (磁场定向控制)", "BLDC (方波控制)", "正弦波控制"])self.algo_combo.setStyleSheet("padding: 5px;")algo_type_layout.addWidget(self.algo_combo)# 仿真速度控制speed_layout = QHBoxLayout()speed_layout.addWidget(QLabel("仿真速度:"))self.speed_slider = QSlider(Qt.Horizontal)self.speed_slider.setMinimum(1)self.speed_slider.setMaximum(10)self.speed_slider.setValue(5)self.speed_slider.valueChanged.connect(self.update_speed_label)speed_layout.addWidget(self.speed_slider)self.speed_label = QLabel("5x")self.speed_label.setStyleSheet("min-width: 40px;")speed_layout.addWidget(self.speed_label)# 操作按钮btn_layout = QHBoxLayout()self.start_btn = QPushButton("开始仿真")self.start_btn.setStyleSheet("background-color: #2196F3; color: white; padding: 8px; border-radius: 4px;")self.start_btn.clicked.connect(self.start_simulation)stop_btn = QPushButton("停止仿真")stop_btn.setStyleSheet("background-color: #F44336; color: white; padding: 8px; border-radius: 4px;")stop_btn.clicked.connect(self.stop_simulation)reset_btn = QPushButton("重置")reset_btn.setStyleSheet("padding: 8px; border-radius: 4px;")reset_btn.clicked.connect(self.reset_simulation)btn_layout.addWidget(self.start_btn)btn_layout.addWidget(stop_btn)btn_layout.addWidget(reset_btn)# 温度监控temp_layout = QHBoxLayout()temp_layout.addWidget(QLabel("电机温度:"))self.temp_display = QLabel("30°C")self.temp_display.setStyleSheet("font-weight: bold; color: #E91E63; font-size: 16px;")temp_layout.addStretch(1)temp_layout.addWidget(QLabel("峰值温度:"))self.peak_temp_display = QLabel("30°C")self.peak_temp_display.setStyleSheet("font-weight: bold; color: #D32F2F; font-size: 16px;")# 布局组装algo_layout.addWidget(algo_label)algo_layout.addLayout(algo_type_layout)algo_layout.addLayout(speed_layout)algo_layout.addLayout(btn_layout)algo_layout.addLayout(temp_layout)control_layout.addWidget(file_box, 40)control_layout.addWidget(algo_box, 60)layout.addWidget(control_panel, 20)self.tab_widget.addTab(sim_tab, "电机仿真")def create_analysis_tab(self):"""创建性能分析标签页"""analysis_tab = QWidget()layout = QVBoxLayout(analysis_tab)# 标题header = QLabel("性能参数分析")header.setStyleSheet("font-size: 18px; font-weight: bold; color: #0047AB; margin: 10px;")layout.addWidget(header)# 参数网格布局param_widget = QWidget()param_layout = QHBoxLayout(param_widget)# 效率参数区域eff_group = QGroupBox("效率参数")eff_layout = QVBoxLayout(eff_group)# 效率参数项eff_params = [("系统效率", "92%", "#388E3C"),("电流谐波失真(THD)", "4.5%", "#F57C00"),("开关损耗", "85W", "#D32F2F"),("热损耗", "65W", "#7B1FA2"),("最大功率点", "86%", "#0288D1")]for name, value, color in eff_params:param_row = QWidget()row_layout = QHBoxLayout(param_row)name_label = QLabel(name)value_label = QLabel(value)value_label.setStyleSheet(f"color: {color}; font-weight: bold; font-size: 14px;")row_layout.addWidget(name_label, 60)row_layout.addWidget(value_label, 40)eff_layout.addWidget(param_row)# 扭矩参数区域torque_group = QGroupBox("扭矩参数")torque_layout = QVBoxLayout(torque_group)# 扭矩参数项torque_params = [("平均扭矩", "2.5 N·m", "#1976D2"),("扭矩波动", "0.8 N·m", "#5D4037"),("启动扭矩", "4.2 N·m", "#0097A7"),("转矩响应时间", "15 ms", "#00796B"),("最大扭矩", "5.6 N·m", "#689F38")]for name, value, color in torque_params:param_row = QWidget()row_layout = QHBoxLayout(param_row)name_label = QLabel(name)value_label = QLabel(value)value_label.setStyleSheet(f"color: {color}; font-weight: bold; font-size: 14px;")row_layout.addWidget(name_label, 60)row_layout.addWidget(value_label, 40)torque_layout.addWidget(param_row)param_layout.addWidget(eff_group)param_layout.addWidget(torque_group)layout.addWidget(param_widget, 40)# 波形分析区域waveform_group = QGroupBox("波形分析")waveform_layout = QVBoxLayout(waveform_group)# 波形分析图形self.waveform_figure = Figure(figsize=(10, 4), dpi=100)self.waveform_figure.set_facecolor('#f0f0f0')self.waveform_canvas = FigureCanvas(self.waveform_figure)# 创建分析控制按钮analyze_btn = QPushButton("开始波形分析")analyze_btn.setStyleSheet("background-color: #9C27B0; color: white; padding: 8px; border-radius: 4px;")analyze_btn.clicked.connect(self.run_analysis)waveform_layout.addWidget(self.waveform_canvas, 80)waveform_layout.addWidget(analyze_btn, 20)layout.addWidget(waveform_group, 60)self.tab_widget.addTab(analysis_tab, "性能分析")# 初始化波形分析图self.init_waveform_analysis()def init_waveform_analysis(self):"""初始化波形分析图"""ax = self.waveform_figure.add_subplot(111)ax.set_facecolor('#f0f0f0')ax.grid(True, linestyle='--', alpha=0.6)ax.set_title("FFT分析 - 频谱特性")ax.set_xlabel("频率 (Hz)")ax.set_ylabel("幅值")self.waveform_canvas.draw()def run_analysis(self):"""运行波形分析"""# 这里暂时使用示例数据,实际应用中会使用仿真数据try:ax = self.waveform_figure.get_axes()[0]ax.clear()# 生成示例频谱数据freq = np.arange(0, 100, 0.1)amplitude = np.exp(-(freq-10)**2/(2*5**2)) + 0.6*np.exp(-(freq-30)**2/(2*8**2)) + 0.3*np.exp(-(freq-60)**2/(2*12**2))amplitude += 0.1 * np.random.randn(len(freq))ax.plot(freq, amplitude, 'b-', linewidth=1.5)ax.set_title("FFT分析 - 频谱特性")ax.set_xlabel("频率 (Hz)")ax.set_ylabel("幅值")ax.grid(True, linestyle='--', alpha=0.6)# 标记主要频率分量ax.annotate('基波频率', xy=(10, 1), xytext=(20, 0.8),arrowprops=dict(facecolor='black', shrink=0.05))ax.annotate('谐波分量', xy=(30, 0.6), xytext=(40, 0.75),arrowprops=dict(facecolor='black', shrink=0.05))self.waveform_canvas.draw()self.status_bar.showMessage("波形分析完成 | FFT频谱计算成功")except Exception as e:self.status_bar.showMessage(f"波形分析错误: {str(e)}")def create_documentation_tab(self):"""创建文档标签页"""doc_tab = QWidget()layout = QVBoxLayout(doc_tab)# 标题header = QLabel("无刷电机控制原理与文档")header.setStyleSheet("font-size: 18px; font-weight: bold; color: #0047AB; margin: 10px;")layout.addWidget(header)# 创建分割区域splitter = QSplitter(Qt.Horizontal)# 文档目录树doc_tree = QTreeWidget()doc_tree.setHeaderLabels(["文档目录"])# 文档结构basic_item = QTreeWidgetItem(doc_tree, ["基本概念"])QTreeWidgetItem(basic_item, ["无刷电机工作原理"])QTreeWidgetItem(basic_item, ["霍尔传感器原理"])QTreeWidgetItem(basic_item, ["电机驱动基础"])foc_item = QTreeWidgetItem(doc_tree, ["FOC控制算法"])QTreeWidgetItem(foc_item, ["Clark变换原理"])QTreeWidgetItem(foc_item, ["Park变换原理"])QTreeWidgetItem(foc_item, ["空间矢量调制(SVPWM)"])advanced_item = QTreeWidgetItem(doc_tree, ["高级控制技术"])QTreeWidgetItem(advanced_item, ["无传感器控制算法"])QTreeWidgetItem(advanced_item, ["电机参数辨识"])QTreeWidgetItem(advanced_item, ["振动抑制技术"])for i in range(doc_tree.topLevelItemCount()):doc_tree.expandItem(doc_tree.topLevelItem(i))# 文档内容显示doc_text = QTextBrowser()doc_text.setOpenExternalLinks(True)doc_text.setStyleSheet("background-color: #ffffff; padding: 10px; border: 1px solid #cccccc;")# 初始文档内容initial_doc = """<h2>无刷直流电机(BLDC)控制基础</h2><p>无刷直流电机是一种采用电子换向代替机械换向的电机。它具有以下优点:</p><ul><li>高效率:无机械换向损耗</li><li>高功率密度:体积小、出力大</li><li>长寿命:无电刷磨损</li><li>低噪声:电子换向平稳安静</li></ul><h3>基本控制方法</h3><p><b>方波控制:</b> 梯形波控制,简单易实现</p><p><b>FOC控制:</b> 磁场定向控制,高效平稳</p><p><b>正弦波控制:</b> 介于方波和FOC之间</p><h3>学习资源</h3><p>推荐参考资料:</p><ul><li><a href='https://www.st.com/resource/en/application_note/dm00035939.pdf'>STM32 FOC电机控制库</a></li><li><a href='https://www.ti.com/lit/ml/slyp173/slyp173.pdf'>TI无刷直流电机控制指南</a></li><li><a href='https://github.com/simplefoc/Arduino-FOC'>Arduino FOC项目</a></li></ul>"""doc_text.setHtml(initial_doc)splitter.addWidget(doc_tree)splitter.addWidget(doc_text)splitter.setSizes([200, 600])# 目录点击事件doc_tree.itemClicked.connect(lambda item, text=doc_text: self.show_doc_content(item, text))layout.addWidget(splitter)self.tab_widget.addTab(doc_tab, "文档资料")def show_doc_content(self, title):"""显示文档具体内容"""content = {'基本概念': {'无刷电机工作原理': '<h2>工作原理</h2><p>通过霍尔传感器检测转子位置...</p>','霍尔传感器原理': '<h2>霍尔效应</h2><p>利用霍尔元件检测磁场变化...</p>'},'FOC控制算法': {'Clark变换原理': '<h2>三相转两相</h2><p>将三相坐标系转换为静止两相坐标系...</p>','Park变换原理': '<h2>坐标旋转</h2><p>将静止坐标系转换为旋转坐标系...</p>'}}# 遍历文档结构查找匹配内容for category in content.values():if title in category:return category[title]# 添加默认返回内容return f'<h3>{title}</h3><p style="color:#666">文档内容正在编写中,预计下个版本发布</p>'def show_doc_content(self, item, text_browser):"""显示选中的文档内容"""if item.parent() is None: # 顶级目录项returndoc_title = item.text(0)content = ""if doc_title == "无刷电机工作原理":content = """<h2>无刷电机工作原理</h2><p>无刷电机通过电子换相器按顺序给线圈通电,产生旋转磁场带动永磁体转子旋转。</p><p><img src='https://upload.wikimedia.org/wikipedia/commons/thumb/5/54/BrushlessDC_motor_animation.gif/220px-BrushlessDC_motor_animation.gif' width='200'></p>"""elif doc_title == "FOC控制算法":content = """<h2>磁场定向控制(FOC)</h2><p>FOC通过将三相电流转换到两相旋转坐标系(dq坐标系),实现对转矩和磁链的解耦控制。</p><p>主要步骤:</p><ol><li>Clarke变换:三相静止abc坐标系 → 两相静止αβ坐标系</li><li>Park变换:静止αβ坐标系 → 旋转dq坐标系</li><li>PID调节器:分别控制d轴和q轴电流</li><li>反Park变换:dq坐标系 → αβ坐标系</li><li>SVPWM:产生三相PWM波驱动电机</li></ol>"""# 其他文档内容... else:content = f"<h2>{doc_title}</h2><p>文档内容正在建设中...</p>"text_browser.setHtml(content)def create_code_viewer_tab(self):"""创建代码查看器标签页"""code_tab = QWidget()layout = QVBoxLayout(code_tab)# 标题header = QLabel("控制代码查看器")header.setStyleSheet("font-size: 18px; font-weight: bold; color: #0047AB; margin: 10px;")layout.addWidget(header)# 创建带有行号的代码编辑区self.code_editor = QTextEdit()self.code_editor.setFont(QFont("Consolas", 10))self.code_editor.setStyleSheet("background-color: #f8f8f8; border: 1px solid #cccccc;")# 添加代码行号self.code_editor.setLineWrapMode(QTextEdit.NoWrap)# 加载示例代码example_code = """// 无刷电机FOC控制示例代码
#include "bldc_foc.h"// 电机参数
Motor motor = {.pole_pairs = 7,.resistance = 0.8,.inductance = 0.0012,.kv = 180
};void setup() {foc_init(&motor); // 初始化FOC控制器foc_set_pwm_frequency(20000); // 20kHz PWM
}void loop() {// 读取目标速度 (0-1000 RPM)float target_speed = get_target_speed(); // FOC控制循环foc_control_loop(target_speed);// 温度保护if (motor.temperature > 85) {foc_set_output(0); // 超温停机}
}"""self.code_editor.setPlainText(example_code)# 代码控制区域control_box = QWidget()control_layout = QHBoxLayout(control_box)save_btn = QPushButton("保存代码")save_btn.setStyleSheet("background-color: #4CAF50; color: white; padding: 8px; border-radius: 4px;")save_btn.clicked.connect(self.save_code)compile_btn = QPushButton("编译代码")compile_btn.setStyleSheet("background-color: #2196F3; color: white; padding: 8px; border-radius: 4px;")format_btn = QPushButton("格式化代码")format_btn.setStyleSheet("padding: 8px; border-radius: 4px;")format_btn.clicked.connect(self.format_code)control_layout.addWidget(save_btn)control_layout.addWidget(compile_btn)control_layout.addWidget(format_btn)control_layout.addStretch(1)layout.addWidget(self.code_editor, 90)layout.addWidget(control_box, 10)self.tab_widget.addTab(code_tab, "代码查看器")def import_file(self):"""导入C控制文件"""options = QFileDialog.Options()file_name, _ = QFileDialog.getOpenFileName(self, "导入电机控制文件", "", "C/C++ Files (*.c *.cpp *.h *.hpp);;All Files (*)", options=options)if file_name:self.file_path_label.setText(file_name)try:with open(file_name, 'r') as file:content = file.read()self.code_editor.setPlainText(content)# 启动仿真algo_type = self.algo_combo.currentText()status = self.sim_widget.simulate_from_file(file_name, algo_type)self.status_bar.showMessage(f"已加载: {os.path.basename(file_name)} | {status}")self.progress_bar.setValue(10) # 进度10%except Exception as e:QMessageBox.critical(self, "文件导入错误", f"无法导入文件:\n{str(e)}")def update_speed_label(self, value):"""更新仿真速度标签"""self.speed_label.setText(f"{value}x")def start_simulation(self):"""开始仿真"""if not self.sim_running:self.sim_running = Trueself.start_btn.setText("仿真运行中...")self.start_btn.setStyleSheet("background-color: #FF9800; color: white;")self.sim_time = 0# 设置定时器间隔 (x1.0对应100ms, 倍速减少间隔)interval = 100 // self.speed_slider.value()self.sim_timer.start(interval)self.status_bar.showMessage("仿真启动 | 正在模拟电机运行状态")self.progress_bar.setValue(0)def stop_simulation(self):"""停止仿真"""self.sim_running = Falseself.sim_timer.stop()self.start_btn.setText("开始仿真")self.start_btn.setStyleSheet("background-color: #2196F3; color: white;")self.status_bar.showMessage("仿真已停止 | 分析当前数据")self.progress_bar.setValue(100)def reset_simulation(self):"""重置仿真"""self.stop_simulation()self.sim_time = 0self.sim_widget.reset_data()self.current_temp = 30self.peak_temp = 30self.temp_display.setText(f"{self.current_temp}°C")self.peak_temp_display.setText(f"{self.peak_temp}°C")self.status_bar.showMessage("仿真已重置 | 准备重新开始")self.progress_bar.setValue(0)def update_simulation(self):"""定时更新仿真"""if self.sim_time < 10:# 更新仿真时间 (步长0.1秒)self.sim_time += 0.1self.sim_widget.generate_data(self.sim_time)# 更新温度显示temp = self.sim_widget.temp[int(self.sim_time * 10)] # 每0.1秒一个数据点self.current_temp = int(temp)if self.current_temp > self.peak_temp:self.peak_temp = self.current_temp# 温度警告颜色temp_style = "font-weight: bold; font-size: 16px;"if self.current_temp > 80:temp_style += "color: #D32F2F;"elif self.current_temp > 70:temp_style += "color: #F57C00;"else:temp_style += "color: #388E3C;"self.temp_display.setStyleSheet(temp_style)self.temp_display.setText(f"{self.current_temp}°C")self.peak_temp_display.setText(f"{self.peak_temp}°C")# 更新进度条 (每0.1秒更新10%)progress = int(self.sim_time * 10)if progress > 100:progress = 100self.progress_bar.setValue(progress)# 更新状态栏status_message = f"仿真运行中 | 时间: {self.sim_time:.1f}s | 速度: {self.speed_slider.value()}x | 温度: {self.current_temp}°C"self.status_bar.showMessage(status_message)# 每隔1秒更新性能参数if int(self.sim_time * 10) % 10 == 0:self.update_performance_params()else:self.stop_simulation()self.status_bar.showMessage("仿真完成 | 达到最大仿真时间10秒")def update_performance_params(self):"""更新性能分析标签页的参数显示"""try:# 获取最新仿真数据sim_data = self.sim_widget.get_simulation_data()# 更新效率参数eff_widget = self.tab_widget.widget(0) # 分析标签页for i in range(1, 6): # 效率参数前5项row_widget = eff_widget.findChildren(QWidget)[0].layout().itemAt(i-1).widget()value_label = row_widget.layout().itemAt(1).widget()value = value_label.text().strip('%')# 根据仿真数据动态调整value = float(value) + np.random.uniform(-0.5, 0.5)value_label.setText(f"{max(80, min(100, value)):.1f}%")# 更新扭矩参数for i in range(6, 11): # 扭矩参数后5项row_widget = eff_widget.findChildren(QWidget)[0].layout().itemAt(i-1).widget()value_label = row_widget.layout().itemAt(1).widget()base_value = float(value_label.text().split()[0])# 根据仿真数据动态调整value = base_value + np.random.uniform(-0.1, 0.1)value_label.setText(f"{value:.2f} N·m")except Exception as e:print(f"更新参数错误: {e}")def save_code(self):"""保存代码文件"""options = QFileDialog.Options()file_name, _ = QFileDialog.getSaveFileName(self, "保存代码文件", "", "C Files (*.c);;All Files (*)", options=options)if file_name:try:with open(file_name, 'w') as file:content = self.code_editor.toPlainText()file.write(content)self.status_bar.showMessage(f"代码已保存: {os.path.basename(file_name)}")QMessageBox.information(self, "保存成功", "代码文件保存成功!")except Exception as e:QMessageBox.critical(self, "保存错误", f"无法保存文件:\n{str(e)}")def format_code(self):"""使用clang-format进行专业代码格式化"""try:# 临时保存代码内容text = self.code_editor.toPlainText()with tempfile.NamedTemporaryFile(mode='w', delete=False, suffix='.c') as tmp:tmp.write(text)tmp_path = tmp.name# 使用项目根目录的.clang-format配置clang_format = os.path.join(os.getcwd(), '.clang-format')cmd = f'clang-format -style=file -i "{tmp_path}"'# 执行格式化命令subprocess.run(cmd, shell=True, check=True)# 读取格式化后的内容with open(tmp_path, 'r') as f:formatted = f.read()self.code_editor.setPlainText(formatted)self.status_bar.showMessage("代码已使用clang-format格式化")except subprocess.CalledProcessError:QMessageBox.warning(self, "格式错误", "请安装clang-format并添加到PATH环境变量")except Exception as e:QMessageBox.critical(self, "格式化错误", f"{str(e)}")finally:if 'tmp_path' in locals():os.remove(tmp_path)# 保留原有简单格式化作为fallbackdef simple_format_code(self):"""简单格式化代码"""text = self.code_editor.toPlainText()# 简单格式化 - 缩进和大括号对齐formatted = ""indent_level = 0for line in text.splitlines():line = line.strip()if line.startswith('}') and indent_level > 0:indent_level -= 1indent = " " * indent_levelformatted += indent + line + "\n"if line.endswith('{'):indent_level += 1self.code_editor.setPlainText(formatted)self.status_bar.showMessage("代码格式化完成")# 主程序入口
if __name__ == "__main__":app = QApplication(sys.argv)# 添加字体配置font = QFont('Microsoft YaHei', 10)app.setFont(font)app.setStyle('Fusion') # 使用Fusion样式# 设置全局样式app.setStyleSheet("""QMainWindow {background-color: #f5f5f5;}QGroupBox {font-weight: bold;border: 1px solid #cccccc;border-radius: 6px;margin-top: 1ex;}QGroupBox::title {subcontrol-origin: margin;left: 10px;padding: 0 3px;}QPushButton {border-radius: 4px;padding: 6px;}QFont{font-family: "Microsoft YaHei";font-size: 9pt;}""")window = BLDCControlSimulator()window.show()sys.exit(app.exec())
运行结果

