

在工程设计、求解计算的过程中,往往存在大量重复性的工作,这些工作不仅耗时耗力,而且容易出错。为了提高工作效率,减少人为错误,我们希望这些重复性工作能够被计算机自动完成,从而让工程师从繁重的重复性劳动中解放出来,将更多的精力投入到创造性的工作中。
CST Studio Suite® 提供了 Python 编程接口,也提供了在 Python 环境中执行 VB 脚本的接口。并且,在 CST Studio Suite 2024 中,CST Python Libraries 的特性得到了更新。
现在,我们将使用 Jupyter Notebook 连接到 CST Studio Suite,通过一个演示案例,完成脚本控制建立模型、查看结果等工作,并在 Python 中进行更多自动化任务。
文章共分为5个部分,分别介绍以下内容:
本期为第 3 篇文章,详细介绍如何使用 Python 控制 CST 仿真、读取结果以及绘图。
在此前的两篇文章中,我们分享了搭建 Python 测试环境的流程,并完成了建模、求解器设置等工作。
现在,我们尝试使用 Python 命令启动求解器,对模型进行求解计算,并绘制计算结果。

求解器为T求解器,频率范围8-10GHz
本文后续的流程基于上一篇文章《控制 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)
allow_interactive=True运行结果
在这里,我们使用 Python 读取本次仿真的结果,并进行绘图,分别绘制“场”的结果和“路”的结果。
后处理需要用到IPython库,请确保IPython安装且工作正常。
在场的仿真中,我们通过左侧的 Navigation Tree 导航到仿真结果中。我们也可以使用 Python 对场的仿真结果进行后处理。

在GUI中查看“场”的结果
为了在 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
转存结果
下面进行图像绘制。
%matplotlib inline
plt.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)) 
S11幅度和相位
查看时域激励的入射信号和反射信号。
%matplotlib inline
plt.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 在原理图中进行后处理(即查看路的结果)。

在GUI中查看“路”的结果
运行下面代码,将外部端口连接到 Python 环境(即 Jupyter Notebook 项目)中,并进行端口设置。
prj_schematic = mws_project.schematic
prj_external_port = prj_schematic.ExternalPort
prj_block = prj_schematic.Block
prj_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 ports
connections = [[0 for x in range(3)] for y in range(2)]
connections[0][0] = "Block"
connections[0][1] = "MWSSCHEM1"
connections[0][2] = 0
connections[1][0] = "Externalport"
connections[1][1] = "1"
connections[1][2] = 0
prj_net.Reset()
prj_net.AddComponentPorts("", connections, False)
prj_net.Apply()
connections[0][0] = "Block"
connections[0][1] = "MWSSCHEM1"
connections[0][2] = 1
connections[1][0] = "Externalport"
connections[1][1] = "2"
connections[1][2] = 0
prj_net.Reset()
prj_net.AddComponentPorts("", connections, False)
prj_net.Apply()
connections[0][0] = "Block"
connections[0][1] = "MWSSCHEM1"
connections[0][2] = 2
connections[1][0] = "Externalport"
connections[1][1] = "3"
connections[1][2] = 0
prj_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”。

在GUI中设置外部端口
现在,外部端口已经定义并连接完毕,让我们快速设置并执行 Z 参数任务。
# set up S-parameter task
prj_sim_task = prj_schematic.SimulationTask
# create task
prj_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 impedance
prj_sim_task.SetResultOption("Z-Parameters", "On (Parametric)")
# and update
prj_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 inline
plt.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()
Z参数
%matplotlib notebook 替换成 %matplotlib inline 。原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。