CST-Python实例教程三:仿真并绘制结果
前言
在工程设计、求解计算的过程中,往往存在大量重复性的工作,这些工作不仅耗时耗力,而且容易出错。为了提高工作效率,减少人为错误,我们希望这些重复性工作能够被计算机自动完成,从而让工程师从繁重的重复性劳动中解放出来,将更多的精力投入到创造性的工作中。
CST Studio Suite(R) 提供了 Python 编程接口,也提供了在 Python 环境中执行 VB 脚本的接口。并且,在 CST Studio Suite 2024 中,CST Python Libraries 的特性得到了更新。
广州浦信系统技术有限公司发布的 CST Studio Suite(R) Python Automation and Scripting 系列文章,将会为您详细介绍使用 Jupyter Notebook 连接到 CST Studio Suite 进行脚本控制与自动化仿真的方方面面。
现在,我们将使用 Jupyter Notebook 连接到 CST Studio Suite,通过一个演示案例,完成脚本控制建立模型、查看结果等工作,并在 Python 中进行更多自动化任务。
文章共分为5个部分,分别介绍以下内容:
搭建 Python 环境
控制 CST 建模
仿真并绘制结果
仿真优化
外部后处理
本期为第 3 篇文章,详细介绍如何使用 Python 控制 CST 仿真、读取结果以及绘图。
一、准备工作
在此前的两篇文章中,我们分享了搭建 Python 测试环境的流程,并完成了建模、求解器设置等工作。
现在,我们尝试使用 Python 命令启动求解器,对模型进行求解计算,并绘制计算结果。
本文后续的流程基于上一篇文章《控制 CST 建模》的模型操作,如果您保留了该模型,可以关联文件后基于该模型继续操作。如果您未保留上一次的 CST 工程,请参考上述文章中的步骤重新建模。
二、求解
运行求解
完成建模及求解器设置等工作后,即可进行求解计算。
运行下面代码,求解器就会开始求解计算,可以打开软件窗口查看仿真进度条。
mws_project.model3d.run_solver()
默认情况下,仿真结束时,命令run_solver()
才会返回 Python 环境。
如果需要定时返回 Python 环境,可以根据任务需要,在这里设置返回 Python 环境的超时时间。
保存结果
单元格执行后,等到求解器运行结束,即可运行以下代码保存项目。
mws_project.save()
项目保存在此前手动设定的路径中,如果未调整路径,默认保存在当前用户的TEMP
文件夹中,即C:\Users\<Users>\AppData\Local\Temp
访问结果
为了访问本次仿真的结果,我们使用了cst.results
库。
result_project = cst.results.ProjectFile(tmp + r"\CST_TEST.cst")
若直接运行上述代码,会出现报错,提示该项目已被打开。
这是因为:在默认的情况下,当前在 CST Studio Suite 中打开的项目的结果,无法被外部访问。
要访问结果,我们需要做一些措施:
可以使用
mws_project.close()
关闭项目,在工程文件被关闭的状态下访问仿真结果。或者使用
allow_interactive=True
参数取消访问限制。
以下为使用 allow_interactive=True
的命令:
result_project = cst.results.ProjectFile(tmp + r"\CST_TEST.cst", allow_interactive=True)
三、后处理
在这里,我们使用 Python 读取本次仿真的结果,并进行绘图,分别绘制“场”的结果和“路”的结果。
后处理需要用到IPython
库,请确保IPython
安装且工作正常。
绘制场的结果
在场的仿真中,我们通过左侧的 Navigation Tree 导航到仿真结果中。我们也可以使用 Python 对场的仿真结果进行后处理。
为了在 Python 中进行进一步的后处理,我们现在将选定的结果加载到 Python 变量中。
s11 = result_project.get_3d().get_result_item("1D Results\S-Parameters\S1,1")TD_in = result_project.get_3d().get_result_item("1D Results\Port signals\i1")TD_ref = result_project.get_3d().get_result_item("1D Results\Port signals\o1,1")
可以使用 Python 中的type()
函数检查结果类型(如int
、str
、list
等)。
type(TD_in)
显示仿真结果的数据类型为:_cst_results.ResultItem
由于这是一种相当特殊的格式,我们需要将结果提取出来,并存储到一个标准数组中,这样就可以对数据执行 FFT、IFFT 等运算操作。
运行以下代码转存数据。
ss = np.asarray([s11.get_xdata() , s11.get_ydata()])tt = np.asarray([TD_in.get_xdata() , TD_in.get_ydata()])tt2 = np.asarray([TD_ref.get_xdata() , TD_ref.get_ydata()])ss[0,:].real
下面进行图像绘制。
S参数(幅度相位)
%matplotlib inlineplt.figure(figsize=(9,5))plt.plot(s11.get_xdata(),20*np.log10(np.absolute(np.asarray(s11.get_ydata()))))plt.title('S-Parameter Magnitude')plt.ylabel('Mag in dB')plt.xlabel('Freq. in GHz')plt.grid(True)plt.ylim((-38,-18))plt.xlim((8,10))plt.figure(figsize=(9,5))plt.plot(s11.get_xdata(),np.angle(np.asarray(s11.get_ydata()),deg=True))plt.title('S-Parameter Phase')plt.ylabel('Phase in deg')plt.xlabel('Freq. in GHz')plt.grid(True)plt.ylim((-180,180))plt.xlim((8,10))
时域信号
查看时域激励的入射信号和反射信号。
%matplotlib inlineplt.ion()plt.figure(figsize=(9,5))plt.plot(TD_in.get_xdata(),TD_in.get_ydata())plt.title('TD In ')plt.ylabel('Amp')plt.xlabel('Time in ns')plt.grid(True)plt.figure(figsize=(9,5))plt.plot(TD_ref.get_xdata(),TD_ref.get_ydata())plt.title('TD ref ')plt.ylabel('Amp')plt.xlabel('Time in ns')plt.grid(True)
频域转换
将时域信号进行快速傅里叶变换,并绘制图像,查看信号的频域分布。
td_fft=np.fft.fft(tt,n=10*len(tt[0]),axis=1)td2_fft=np.fft.fft(tt2,n=10*len(tt2[0]),axis=1)freq = np.fft.fftfreq(10*len(tt2[0]), tt2[0,1] - tt2[0,0])plt.figure(figsize=(9,5))plt.xlabel('Freq. in GHz')plt.title('FFT of TD In & TD_ref ')plt.grid(True)plt.ylim((0,0.5))plt.xlim((6,12))plt.plot(freq,abs(td_fft[1])*(tt[0,1] - tt[0,0]))plt.plot(freq,abs(td2_fft[1])*(tt2[0,1] - tt2[0,0]))
绘制原理图结果
到目前为止,我们只研究了场的仿真结果。当然,我们也可以使用 Python 在原理图中进行后处理(即查看路的结果)。
设置外部端口
运行下面代码,将外部端口连接到 Python 环境(即 Jupyter Notebook 项目)中,并进行端口设置。
prj_schematic = mws_project.schematicprj_external_port = prj_schematic.ExternalPortprj_block = prj_schematic.Blockprj_net = prj_schematic.Net# Set up external ports...prj_external_port.Reset()prj_external_port.Name("1")prj_external_port.Position(49850, 49950)prj_external_port.Create()prj_external_port.Reset()prj_external_port.Name("2")prj_external_port.Position(49850, 50020)prj_external_port.Create()prj_external_port.Reset()prj_external_port.Name("3")prj_external_port.Position(50325, 49950)prj_external_port.Create()# Connect external portsconnections = [[0 for x in range(3)] for y in range(2)]connections[0][0] = "Block"connections[0][1] = "MWSSCHEM1"connections[0][2] = 0connections[1][0] = "Externalport"connections[1][1] = "1"connections[1][2] = 0prj_net.Reset()prj_net.AddComponentPorts("", connections, False)prj_net.Apply()connections[0][0] = "Block"connections[0][1] = "MWSSCHEM1"connections[0][2] = 1connections[1][0] = "Externalport"connections[1][1] = "2"connections[1][2] = 0prj_net.Reset()prj_net.AddComponentPorts("", connections, False)prj_net.Apply()connections[0][0] = "Block"connections[0][1] = "MWSSCHEM1"connections[0][2] = 2connections[1][0] = "Externalport"connections[1][1] = "3"connections[1][2] = 0prj_net.Reset()prj_net.AddComponentPorts("", connections, False)prj_net.Apply()
当然,更有效的方法是直接调用相应的宏,会产生同样的端口设置效果,而且会快很多。
prj_schematic.RunMacro("Construct\Add Ports to all pins of a block")
这一步对应的 GUI 操作流程如下图所示:首先切换到原理图界面,随后在 VBA Marcos 中选择“Construct”,打开“Add Ports to all pins of a block”。
计算Z参数
现在,外部端口已经定义并连接完毕,让我们快速设置并执行 Z 参数任务。
# set up S-parameter taskprj_sim_task = prj_schematic.SimulationTask# create taskprj_sim_task.Reset()prj_sim_task.Type("S-Parameters")prj_sim_task.Name("ZPara1")prj_sim_task.SetProperty("maximum frequency range", "True")prj_sim_task.Create()# request Z-parameters and set port impedanceprj_sim_task.SetResultOption("Z-Parameters", "On (Parametric)")# and updateprj_sim_task.Update()
结果绘图
使用绘制场的结果时相同的基本方法,可以获得 Z 参数结果。
z11_schem = result_project.get_schematic().get_result_item(r"Tasks\ZPara1\Z-Parameters\Z1,1")z11 = np.transpose(np.asarray([z11_schem.get_xdata(), z11_schem.get_ydata()]))%matplotlib inlineplt.figure(figsize=(9,5))plt.plot(z11[:,0].real, np.abs(z11[:,1]))plt.title('Z-Parameter Magnitude')plt.ylabel('Magnitude (linear)')plt.xlabel('Freq. in GHz')plt.grid(True)plt.xlim((8,10))plt.semilogy()
总结
场的结果和路的结果,对应的操作对象不同,因此需要分别编写程序绘制。
在测试过程中,如遇到 IPython 相关的警告或报错,可以考虑将
%matplotlib notebook
替换成%matplotlib inline
。