CST-Python實(shí)例教程三:仿真并繪制結(jié)果
前言
在工程設(shè)計(jì)、求解計(jì)算的過程中,往往存在大量重復(fù)性的工作,這些工作不僅耗時(shí)耗力,而且容易出錯(cuò)。為了提高工作效率,減少人為錯(cuò)誤,我們希望這些重復(fù)性工作能夠被計(jì)算機(jī)自動(dòng)完成,從而讓工程師從繁重的重復(fù)性勞動(dòng)中解放出來,將更多的精力投入到創(chuàng)造性的工作中。
CST Studio Suite(R) 提供了 Python 編程接口,也提供了在 Python 環(huán)境中執(zhí)行 VB 腳本的接口。并且,在 CST Studio Suite 2024 中,CST Python Libraries 的特性得到了更新。
廣州浦信系統(tǒng)技術(shù)有限公司發(fā)布的 CST Studio Suite(R) Python Automation and Scripting 系列文章,將會(huì)為您詳細(xì)介紹使用 Jupyter Notebook 連接到 CST Studio Suite 進(jìn)行腳本控制與自動(dòng)化仿真的方方面面。
現(xiàn)在,我們將使用 Jupyter Notebook 連接到 CST Studio Suite,通過一個(gè)演示案例,完成腳本控制建立模型、查看結(jié)果等工作,并在 Python 中進(jìn)行更多自動(dòng)化任務(wù)。
文章共分為5個(gè)部分,分別介紹以下內(nèi)容:
搭建 Python 環(huán)境
控制 CST 建模
仿真并繪制結(jié)果
仿真優(yōu)化
外部后處理
本期為第 3 篇文章,詳細(xì)介紹如何使用 Python 控制 CST 仿真、讀取結(jié)果以及繪圖。
一、準(zhǔn)備工作
在此前的兩篇文章中,我們分享了搭建 Python 測試環(huán)境的流程,并完成了建模、求解器設(shè)置等工作。
現(xiàn)在,我們嘗試使用 Python 命令啟動(dòng)求解器,對(duì)模型進(jìn)行求解計(jì)算,并繪制計(jì)算結(jié)果。
本文后續(xù)的流程基于上一篇文章《控制 CST 建?!返哪P筒僮?,如果您保留了該模型,可以關(guān)聯(lián)文件后基于該模型繼續(xù)操作。如果您未保留上一次的 CST 工程,請(qǐng)參考上述文章中的步驟重新建模。
二、求解
運(yùn)行求解
完成建模及求解器設(shè)置等工作后,即可進(jìn)行求解計(jì)算。
運(yùn)行下面代碼,求解器就會(huì)開始求解計(jì)算,可以打開軟件窗口查看仿真進(jìn)度條。
mws_project.model3d.run_solver()
默認(rèn)情況下,仿真結(jié)束時(shí),命令run_solver()
才會(huì)返回 Python 環(huán)境。
如果需要定時(shí)返回 Python 環(huán)境,可以根據(jù)任務(wù)需要,在這里設(shè)置返回 Python 環(huán)境的超時(shí)時(shí)間。
保存結(jié)果
單元格執(zhí)行后,等到求解器運(yùn)行結(jié)束,即可運(yùn)行以下代碼保存項(xiàng)目。
mws_project.save()
項(xiàng)目保存在此前手動(dòng)設(shè)定的路徑中,如果未調(diào)整路徑,默認(rèn)保存在當(dāng)前用戶的TEMP
文件夾中,即C:\Users\<Users>\AppData\Local\Temp
訪問結(jié)果
為了訪問本次仿真的結(jié)果,我們使用了cst.results
庫。
result_project = cst.results.ProjectFile(tmp + r"\CST_TEST.cst")
若直接運(yùn)行上述代碼,會(huì)出現(xiàn)報(bào)錯(cuò),提示該項(xiàng)目已被打開。
這是因?yàn)椋涸谀J(rèn)的情況下,當(dāng)前在 CST Studio Suite 中打開的項(xiàng)目的結(jié)果,無法被外部訪問。
要訪問結(jié)果,我們需要做一些措施:
可以使用
mws_project.close()
關(guān)閉項(xiàng)目,在工程文件被關(guān)閉的狀態(tài)下訪問仿真結(jié)果。或者使用
allow_interactive=True
參數(shù)取消訪問限制。
以下為使用 allow_interactive=True
的命令:
result_project = cst.results.ProjectFile(tmp + r"\CST_TEST.cst", allow_interactive=True)
三、后處理
在這里,我們使用 Python 讀取本次仿真的結(jié)果,并進(jìn)行繪圖,分別繪制“場”的結(jié)果和“路”的結(jié)果。
后處理需要用到IPython
庫,請(qǐng)確保IPython
安裝且工作正常。
繪制場的結(jié)果
在場的仿真中,我們通過左側(cè)的 Navigation Tree 導(dǎo)航到仿真結(jié)果中。我們也可以使用 Python 對(duì)場的仿真結(jié)果進(jìn)行后處理。
為了在 Python 中進(jìn)行進(jìn)一步的后處理,我們現(xiàn)在將選定的結(jié)果加載到 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()
函數(shù)檢查結(jié)果類型(如int
、str
、list
等)。
type(TD_in)
顯示仿真結(jié)果的數(shù)據(jù)類型為:_cst_results.ResultItem
由于這是一種相當(dāng)特殊的格式,我們需要將結(jié)果提取出來,并存儲(chǔ)到一個(gè)標(biāo)準(zhǔn)數(shù)組中,這樣就可以對(duì)數(shù)據(jù)執(zhí)行 FFT、IFFT 等運(yùn)算操作。
運(yùn)行以下代碼轉(zhuǎn)存數(shù)據(jù)。
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
下面進(jìn)行圖像繪制。
S參數(shù)(幅度相位)
%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))
時(shí)域信號(hào)
查看時(shí)域激勵(lì)的入射信號(hào)和反射信號(hào)。
%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)
頻域轉(zhuǎn)換
將時(shí)域信號(hào)進(jìn)行快速傅里葉變換,并繪制圖像,查看信號(hào)的頻域分布。
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]))
繪制原理圖結(jié)果
到目前為止,我們只研究了場的仿真結(jié)果。當(dāng)然,我們也可以使用 Python 在原理圖中進(jìn)行后處理(即查看路的結(jié)果)。
設(shè)置外部端口
運(yùn)行下面代碼,將外部端口連接到 Python 環(huán)境(即 Jupyter Notebook 項(xiàng)目)中,并進(jìn)行端口設(shè)置。
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()
當(dāng)然,更有效的方法是直接調(diào)用相應(yīng)的宏,會(huì)產(chǎn)生同樣的端口設(shè)置效果,而且會(huì)快很多。
prj_schematic.RunMacro("Construct\Add Ports to all pins of a block")
這一步對(duì)應(yīng)的 GUI 操作流程如下圖所示:首先切換到原理圖界面,隨后在 VBA Marcos 中選擇“Construct”,打開“Add Ports to all pins of a block”。
計(jì)算Z參數(shù)
現(xiàn)在,外部端口已經(jīng)定義并連接完畢,讓我們快速設(shè)置并執(zhí)行 Z 參數(shù)任務(wù)。
# 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()
結(jié)果繪圖
使用繪制場的結(jié)果時(shí)相同的基本方法,可以獲得 Z 參數(shù)結(jié)果。
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()
總結(jié)
場的結(jié)果和路的結(jié)果,對(duì)應(yīng)的操作對(duì)象不同,因此需要分別編寫程序繪制。
在測試過程中,如遇到 IPython 相關(guān)的警告或報(bào)錯(cuò),可以考慮將
%matplotlib notebook
替換成%matplotlib inline
。