用AI 自动寻找仿真目标解

📅 2026/6/30 23:02:37
用AI 自动寻找仿真目标解
日常仿真中为了得到某个特定的解我们往往需要对仿真模型不停地修改参数、静等仿真、肉眼看波形、手动记数据。周而复始枯燥无味妥妥地把自动活成了仿真工具人。那么我们能不能让AI帮助我们自动去试凑、自动收敛、甚至把波形、图片和数据表格整整齐齐地直接交到我们手里呢今天我们就以上一期的模型AI仿真入门——用Python 实现PLECS参数扫描和自动化仿真继续探索AI仿真的高阶玩法。我们不需要懂复杂的编程算法只需要给我们的AI助理下达以下核心需求1.我的硬件电路是一个闭环LLC变换器输入电压V_DC380V输出电压V_out_desired12V。2.我的寻优任务请帮我用经典的 0.618 黄金分割法自动寻找使原边谐振电流有效值RMS精确达到2A的负载电阻值R_o。初步评估范围0.3~2Ω自适应规则如果发现目标电流超出了这个区间请程序自动扩张边界直到找到解为止。3.我的数据产出要求仿真完后将每次尝试的开关频率、电流峰值、有效值RMS记录到 Excel 表格中将仿真全过程的彩色波形以原生.trace 文件格式保存便于我们在 PLECS 中二次载入和复核将最终目标解的波形截取最稳定的 5 个周期自动保存为无损图片格式。下载AI帮我们生成的Python代码并双击运行可以看到命令行开始运行如果电脑无法联网可以先在手机上与AI对话大模型沟通将生成的Python代码导入电脑端。仿真计算不需要联网不需要人工干预运行完毕后我们的文件夹下就自动静静躺着以下这些刚出炉的成果文件import xmlrpc.client import os import csv import time import re print(--- 启动 LLC 0.618 黄金分割闭环寻优算法 (高阶整改版) ---) current_dir os.path.dirname(os.path.abspath(__file__)) model_file_name 方案2.plecs model_name 方案2 scope_path f{model_name}/Scope1 model_path os.path.join(current_dir, model_file_name) # # 寻优核心参数配置 # target_rms 2.0 # 目标原边电流有效值RMS为 2.0 A tolerance 0.01 # 寻优允许误差 (A) max_iterations 12 # 最大迭代步数 # 用户初始评估的区间 [0.3, 2.0] low_r 0.3 high_r 2.0 v_dc_val 380.0 v_out_desired_val 48.0 t_sim 0.05 # gold_ratio 0.6180339887 def estimate_frequency(time_list, value_list): 通过过零检测算法高精度计算开关频率 crossings [] for idx in range(1, len(value_list)): if value_list[idx-1] 0 value_list[idx]: t1, t2 time_list[idx-1], time_list[idx] v1, v2 value_list[idx-1], value_list[idx] t_zero t1 - v1 * (t2 - t1) / (v2 - v1) crossings.append(t_zero) if len(crossings) 2: periods [crossings[i] - crossings[i-1] for i in range(1, len(crossings))] avg_period sum(periods) / len(periods) return 1.0 / avg_period return 0.0 def run_simulation(r_val): 运行单次仿真并提取电流、频率、峰值和RMS opts { ModelVars: { V_DC: v_dc_val, R_o: r_val, V_out_desired: v_out_desired_val }, SolverOpts: { StopTime: t_sim } } res plecs.simulate(model_name, opts) time_data res[Time] curr_data res[Values][0] n len(curr_data) steady_curr curr_data[-int(n*0.2):] steady_time time_data[-int(n*0.2):] peak max(abs(x) for x in steady_curr) rms (sum(x**2 for x in steady_curr) / len(steady_curr))**0.5 freq estimate_frequency(steady_time, steady_curr) return peak, rms, freq, curr_data, time_data try: server xmlrpc.client.ServerProxy(http://localhost:1080/RPC2) plecs server.plecs plecs.load(model_path) print([成功] 模型已加载。) print(正在清空 Scope1 历史轨迹...) plecs.scope(scope_path, ClearTraces) # --- 1. 自适应边界检查与扩张 --- print(\n[第一阶段] 正在验证初始区间阻抗范围...) _, rms_low, _, _, _ run_simulation(low_r) _, rms_high, _, _, _ run_simulation(high_r) print(f - 初始边界下界 R_o {low_r:.3f} Ω 时电流有效值(RMS)为 {rms_low:.3f} A) print(f - 初始边界上界 R_o {high_r:.3f} Ω 时电流有效值(RMS)为 {rms_high:.3f} A) while rms_low target_rms: low_r low_r / 2.0 print(f [边界下界扩张] 目标 RMS{target_rms}A 超出范围下界扩张至 R_o {low_r:.3f} Ω) _, rms_low, _, _, _ run_simulation(low_r) if low_r 0.05: break while rms_high target_rms: high_r high_r * 1.5 print(f [边界上界扩张] 目标 RMS{target_rms}A 超出范围上界扩张至 R_o {high_r:.3f} Ω) _, rms_high, _, _, _ run_simulation(high_r) print(f最终寻优包络区间已确定为: [{low_r:.3f} Ω, {high_r:.3f} Ω]\n) # --- 2. 0.618 黄金分割算法主循环 --- print([第二阶段] 启动 0.618 黄金分割收敛算法...) a low_r b high_r x1 b - gold_ratio * (b - a) x2 a gold_ratio * (b - a) peak1, rms1, freq1, wave1, time_axis1 run_simulation(x1) peak2, rms2, freq2, wave2, time_axis2 run_simulation(x2) f1 abs(rms1 - target_rms) f2 abs(rms2 - target_rms) # 初始化时域数据结构 waveforms_dict {} waveforms_dict[fTime_Ro_{x1:.3f}Ohm] time_axis1 waveforms_dict[fWave_Ro_{x1:.3f}Ohm] wave1 waveforms_dict[fTime_Ro_{x2:.3f}Ohm] time_axis2 waveforms_dict[fWave_Ro_{x2:.3f}Ohm] wave2 summary_data [ [x1, freq1, peak1, rms1], [x2, freq2, peak2, rms2] ] plecs.scope(scope_path, HoldTrace, fR_o{x1:.3f} Ohm) plecs.scope(scope_path, HoldTrace, fR_o{x2:.3f} Ohm) opt_r None opt_wave [] opt_time [] freq_opt 0 rms_opt 0 for i in range(max_iterations): print(f迭代步 [{i1:02d}]: 搜索区间 [{a:.3f}, {b:.3f}]) print(f - 尝试点 x1 {x1:.3f} Ω, RMS 误差 {f1:.3f} A) print(f - 尝试点 x2 {x2:.3f} Ω, RMS 误差 {f2:.3f} A) if abs(b - a) 0.005 or min(f1, f2) tolerance: if f1 f2: opt_r x1 opt_wave wave1 opt_time time_axis1 freq_opt freq1 rms_opt rms1 else: opt_r x2 opt_wave wave2 opt_time time_axis2 freq_opt freq2 rms_opt rms2 print(f\n[寻优成功] 算法已收敛在阻值 R_o {opt_r:.3f} Ω 下电流有效值(RMS)最接近 2.0 A。) break if f1 f2: b x2 x2 x1 f2 f1 x1 b - gold_ratio * (b - a) peak1, rms1, freq1, wave1, time_axis1 run_simulation(x1) f1 abs(rms1 - target_rms) waveforms_dict[fTime_Ro_{x1:.3f}Ohm] time_axis1 waveforms_dict[fWave_Ro_{x1:.3f}Ohm] wave1 summary_data.append([x1, freq1, peak1, rms1]) plecs.scope(scope_path, HoldTrace, fR_o{x1:.3f} Ohm) else: a x1 x1 x2 f1 f2 x2 a gold_ratio * (b - a) peak2, rms2, freq2, wave2, time_axis2 run_simulation(x2) f2 abs(rms2 - target_rms) waveforms_dict[fTime_Ro_{x2:.3f}Ohm] time_axis2 waveforms_dict[fWave_Ro_{x2:.3f}Ohm] wave2 summary_data.append([x2, freq2, peak2, rms2]) plecs.scope(scope_path, HoldTrace, fR_o{x2:.3f} Ohm) time.sleep(0.1) # --- 3. 自动输出示波器 Trace 及 交互式 HTML 网页波形图 --- print(\n[第三阶段] 正在向本地输出示波器截图及 Trace 文件...) # 3.1 导出 Trace 轨迹文件 trace_path os.path.join(current_dir, 方案2_最佳阻值波形对比.trace) plecs.scope(scope_path, SaveTraces, trace_path) print(f √ 原生 Trace 文件已成功保存为: {os.path.basename(trace_path)}) # 3.2 自适应截取最后 5 个周期的时域细节 if freq_opt 1000: t_period 1.0 / freq_opt t_display 5 * t_period t_start_plot opt_time[-1] - t_display plot_indices [idx for idx, t in enumerate(opt_time) if t t_start_plot] plot_time [opt_time[idx] for idx in plot_indices] plot_wave [opt_wave[idx] for idx in plot_indices] else: plot_time opt_time[-150:] plot_wave opt_wave[-150:] # 【避坑整改核心】直接使用 str(t) 和 str(w) 进行转换绝不进行四舍五入。 # 这样可以保留 15-17 位完整的纳秒级/皮秒级浮点数精度彻底消除阶梯状条纹 time_str_list , .join(str(t) for t in plot_time) wave_str_list , .join(str(w) for w in plot_wave) html_path os.path.join(current_dir, 方案2_最佳阻值波形图_交互式.html) html_content f!DOCTYPE html html head meta charsetutf-8 titleLLC 最佳阻值波形图 (交互式分析)/title !-- 引入 Plotly.js 绘图引擎 -- script srchttps://cdn.plot.ly/plotly-2.24.1.min.js/script style body {{ font-family: Arial, sans-serif; margin: 20px; background-color: #f5f5f5; }} #chart {{ width: 100%; height: 550px; background-color: white; border-radius: 8px; box-shadow: 0 4px 6px rgba(0,0,0,0.1); }} .info-box {{ margin-bottom: 15px; padding: 12px; background-color: #e3f2fd; border-left: 5px solid #2196f3; border-radius: 4px; }} /style /head body div classinfo-box h3 stylemargin: 0 0 8px 0;LLC 最佳阻值原边电流波形 (交互式分析)/h3 p stylemargin: 4px 0;b最优电阻 R_o:/b {opt_r:.4f} Ω | b工作频率:/b {freq_opt/1000:.1f} kHz | b电流有效值 (RMS):/b {rms_opt:.3f} A/p p stylemargin: 4px 0; color: #555; font-size: 13px; b操作指南:/b ① 鼠标在图表上b框选/b即可局部放大双击图表任何位置恢复默认② 鼠标指针滑过曲线时会b自动显示当前点的时间与电流精确数值/b。/p /div div idchart/div script var trace {{ x: [{time_str_list}], y: [{wave_str_list}], mode: linesmarkers, marker: {{ size: 3, color: red }}, line: {{ color: red, width: 1.5 }}, name: R_o {opt_r:.3f} Ohm, type: scatter }}; var layout {{ title: LLC 谐振原边电流波形细节 (5 周期稳定段), xaxis: {{ title: Time (s), showgrid: true, tickformat: .9f }}, yaxis: {{ title: Current (A), showgrid: true }}, hovermode: closest, margin: {{ t: 50, b: 50, l: 60, r: 30 }} }}; Plotly.newPlot(chart, [trace], layout); /script /body /html with open(html_path, w, encodingutf-8) as f: f.write(html_content) print(f √ 交互式网页波形图已生成: {os.path.basename(html_path)}) print( (重要提示: 双击此 HTML 即可在浏览器中打开鼠标划过即可精准读取波形坐标和局部放大)) # 3.3 经典 PNG 图片备份 try: import matplotlib.pyplot as plt plt.figure(figsize(10, 4.5)) plt.plot(plot_time, plot_wave, r-o, linewidth1.5, markersize3, labelfR_o {opt_r:.3f} Ohm (Optimum)) plt.title(fLLC Resonant Current (5 Steady-State Cycles | Opt R_o: {opt_r:.3f} Ohm), fontsize11) plt.xlabel(Time (s), fontsize10) plt.ylabel(Current (A), fontsize10) plt.grid(True, whichboth, ls--) plt.legend(locupper right) png_path os.path.join(current_dir, 方案2_最佳阻值波形图_Python绘制.png) plt.savefig(png_path, dpi150, bbox_inchestight) plt.close() except ImportError: pass # --- 4. 安全保存数据添加 Excel 占用保护 --- print(\n[第四阶段] 正在将测试数据写入 CSV 文件...) sum_csv_path os.path.join(current_dir, 方案2_寻优结果汇总.csv) wave_csv_path os.path.join(current_dir, 方案2_动态扫频波形数据.csv) try: # 4.1 写入汇总数据 with open(sum_csv_path, modew, newline, encodingutf-8) as f: writer csv.writer(f) writer.writerow([R_o (Ohm), Est_Switching_Frequency (Hz), Current_Peak (A), Current_RMS (A)]) for row in summary_data: writer.writerow([round(row[0], 4), round(row[1], 1), round(row[2], 3), round(row[3], 3)]) print(f √ 指标汇总表已成功写入: {os.path.basename(sum_csv_path)}) # 4.2 写入波形数据 with open(wave_csv_path, modew, newline, encodingutf-8) as f: writer csv.writer(f) headers list(waveforms_dict.keys()) writer.writerow(headers) max_len max(len(waveforms_dict[h]) for h in headers) for r_idx in range(max_len): row [] for h in headers: if r_idx len(waveforms_dict[h]): row.append(waveforms_dict[h][r_idx]) else: row.append() writer.writerow(row) print(f √ 扫频时域数据库已成功写入: {os.path.basename(wave_csv_path)}) print(\n) print([大功告成] 所有数据、网页图、Trace 文件已全部生成就绪) except PermissionError: print(\n !*60) print([⚠️ 严重错误] 数据写入失败Permission denied 拒绝访问) print(f 详细原因你的电脑当前正用 Excel 打开着 {os.path.basename(sum_csv_path)} 或另一张数据表。) print( 解决办法请立刻关闭 Excel 窗口然后重新双击运行本脚本) print(!*60) except Exception as e: print(f\n[错误] 运行失败: {e}) print(-----------------------------------------) input(按回车键退出...)