2020年11月23日 星期一

AEDT當中如何產生表格視窗

 以下是一個簡單的程式碼產生表格視窗,各位可以在3D Layout的Toolkits/Reports底下找到許多用表格視窗顯示結果的toolkit:

import sys
from System.IO import Path

sys.path.append(Path.Combine(oDesktop.GetSysLibDirectory(), r'Toolkits', r'Lib'))
from TableViewForm import TableViewForm

Table = []
for i in range(100):
Table.append([str(i).zfill(3), str(i), str(i**2)])

tvf = TableViewForm(['ID', 'N', 'N*N'], Table)
tvf.Text = 'Net List Report'
tvf.Show()

(圖一)AEDT表格視窗

(圖二)3D Layout支援表格視窗的toolkits


在AEDT訊息視窗顯示進度條

進度條可以讓使用者可以更容易的知道目前工作的進度。以下程式碼為一個簡單的範例:

oDesktop.ClearMessages('', '', 2)
import time
import threading

t0 = time.time()

def func(x, result):
data = []

for j in range(x, x + 1000):
data.append(j)
x = sum(data)
result.append(str(x))

def progressbar(x):
if 0 <= x <= 100:
i = x // 2
j = x % 2
if j == 0:
AddWarningMessage(u"\u2588" * (i) + u"\u2581" * (50 - i) + '[{:4}%]'.format(x))
else:
AddWarningMessage(u"\u2588" * (i) + u"\u2585" + u"\u2581" * (49 - i) + '[{:4}%]'.format(x))
else:
pass

result = []
threads = []
for i in range(101):
t = threading.Thread(target=func, args=(i, result))
t.start()
threads.append(t)
progressbar(i)

for i in threads:
t.join()

AddWarningMessage(str(result))
AddWarningMessage(str(time.time() - t0) + '(secs)')
(圖一)進度條範例


2020年11月22日 星期日

如何在AEDT訊息視窗顯示正確的計算進度

在AEDT編寫自動化程式,我們會習慣在程式碼當中利用AddWarningMessage()來顯示進度。一開始的進度顯示正常,但是到後段顯示會中斷,直到完成計算訊息視窗才會一口氣將後段的所有訊息一次列出來。這就失去了進度顯示的意義。比方說下面一段程式碼到了60%,訊息視窗就停止更新,等到全部計算完畢才一次將70%-100%訊息列印出來:

oDesktop.ClearMessages('', '', 2)
import time

t0 = time.time()
result = []
for i in range(10):
data = []

for j in range(i, i + 1000000):
data.append(j)
x = sum(data)
AddWarningMessage('{}\n'.format(x))
AddWarningMessage('{}%\n'.format((i + 1) * 10))
result.append(str(x))

AddWarningMessage(str(result))
AddWarningMessage(str(time.time() - t0) + '(secs)')

我們可以透過Threading的方式解決這個問題,訊息視窗會按照正常的進度輸出訊息:

oDesktop.ClearMessages('', '', 2)
import time
import threading

t0 = time.time()

def func(x, result):
data = []

for j in range(x, x + 1000000):
data.append(j)
x = sum(data)
AddWarningMessage('{}\n'.format(x))
result.append(str(x))

result = []
for i in range(10):
t = threading.Thread(target=func, args=(i, result))
t.start()
t.join()
AddWarningMessage('{}%\n'.format((i + 1) * 10))

AddWarningMessage(str(result))
AddWarningMessage(str(time.time() - t0) + '(secs)')
(圖一) 顯示計算進度


2020年11月15日 星期日

如何取得Q3D的net及其類別和net上面的物件名

編寫Q3D自動化程式需要取得設計當中的net name及類別(signal, ground, floating)。也必須知道物件所對應的net名稱。底下程式碼可以取得以上所提到的資訊:

oProject = oDesktop.GetActiveProject()
oDesign = oProject.GetActiveDesign()
oEditor = oDesign.SetActiveEditor('3D Modeler')
oModule = oDesign.GetModule('BoundarySetup')
x = oModule.GetExcitations()
info = zip(x[0::2], x[1::2])
AddWarningMessage(str(info))

signal_nets = [i for i, j in info if j=='SignalNet']

result = {}
for s in signal_nets:
result[s] = []
for i in oModule.GetExcitationAssignment(s):
objname = oEditor.GetObjectNameByID(int(i))
result[s].append(objname)

AddWarningMessage(str(result))
(圖一)輸出net名稱及其類型,輸出net所包括的物件名




如何在ACT當中將設計名稱加到下拉選單當中

當我們在App Builder建立了選單之後,可以輸出.xml及.py檔。在.xml當中<step>層級底下加入<onrefresh></onrefresh>標籤,並在當中呼叫RefreshChoice函數。

combobox.xml的內容

<!-- autogenerated by XmlWriter ( 15/11/2020 05:32:32 ) -->
<extension name="combobox">
<imagedirectory>.</imagedirectory>
<guid>b39d25c3-456b-47db-93fa-31e4f172e169</guid>
<script src="IDEGeneratedMain.py" />
<wizard name="cb" caption="cb" version="1" context="ElectronicsDesktop">
<step name="Step_1" version="0" caption="Step_1">
<property control="select" name="design" caption="design" persistent="False" parameterizable="False">
<attributes options="Refresh" />
</property>

<callbacks>
<onrefresh>RefreshChoice</onrefresh>
</callbacks>
</step>
</wizard>
</extension>
在.py檔當中,定義RefreshChoice函數,當中讀取專案底下所有的設計並加到下拉選單當中。
IDEGeneratedMain.py的內容
def onupdateStep(step):
pass

def RefreshChoice(step):
Designs_Field = step.Properties["design"]
Designs_Field.Options.Clear()

ActiveProject = oDesktop.GetActiveProject()
DesignList = ActiveProject.GetTopDesignList()
if len(DesignList) != 0:
ActiveDesign = ActiveProject.GetActiveDesign()

for design in DesignList:
Designs_Field.Options.Add(design)

當啟動ACT之後,點一下下拉選單的Refresh選項之後,下拉選單便會更新加入所有的設計名稱。
(圖一)下拉選單在Refresh之後會加入所有設計的名稱


2020年11月6日 星期五

如何取得3D Layout的database?

在開發3D Layout的自動化程式,某些時候我們需要取得Layout的一些訊息,偏偏函式庫不提供對應的函數,這時候就只能透過EDB的函式庫來抓取。但是如何才能從AEDT函式連結到專案對應到的EDB呢?這時候就可以透過下面指令來達成:

DB = edb.Database.Attach(int(oProject.GetEDBHandle()))

當中GetEDBHandle()可以取得現在開啟當中的Project對應到的資料庫編號,此時用edb.Database.Attach()輸入編號便可以返回資料庫物件做資料的抓取了。以下範例便是透過EDB抓到3D Layout所有的net及net連接的元件及pin,並將其輸出到AEDT的訊息視窗。
import clr

clr.AddReference('Ansys.Ansoft.Edb')
clr.AddReference('Ansys.Ansoft.SimSetupData')
import Ansys.Ansoft.Edb as edb

import ScriptEnv

ScriptEnv.Initialize("Ansoft.ElectronicsDesktop")
oDesktop.RestoreWindow()
oProject = oDesktop.GetActiveProject()
oDesign = oProject.GetActiveDesign()
oEditor = oDesign.GetActiveEditor()

def getNetInfo():
DB = edb.Database.Attach(int(oProject.GetEDBHandle()))
cells = list(DB.TopCircuitCells)

for i in cells:
if i.GetName() == (oDesign.GetName() if ';' not in oDesign.GetName() else oDesign.GetName().split(';')[1]):
layout = i.GetLayout()
break

net_info = {}
for n in layout.Nets:
netname = n.GetName()
net_info[netname] = {}
for i in n.PadstackInstances:
if len(i.GetName()) == 0:
continue
try:
net_info[netname][i.GetComponent().GetName()] += [i.GetName()]
except:
net_info[netname][i.GetComponent().GetName()] = [i.GetName()]

return net_info

AddWarningMessage(str(getNetInfo())) 


(圖一) 輸出net, net連接到的元件及pin


2020年11月2日 星期一

如何利用EDB庫取得PCB上Via及Pin的相關訊息

這些訊息包含via/pin的名稱、歸屬的net-name、padstack的類型,位置XY座標及旋轉角度。

import clr, os, sys, System, json
AnsysEM_Path = 'C:/Program Files/AnsysEM/AnsysEM20.2/Win64/'
sys.path.append(AnsysEM_Path)
os.environ['PATH'] += ';' + AnsysEM_Path

clr.AddReference('Ansys.Ansoft.Edb')
clr.AddReference('Ansys.Ansoft.SimSetupData')
import Ansys.Ansoft.Edb as edb

edb.Database.SetRunAsStandAlone(True)

DB = edb.Database.Open('D:/demo/test.aedb', False)

cell = list(DB.TopCircuitCells)
layout = cell[0].GetLayout()
data = []

for i in layout.PadstackInstances:
pad_name = i.GetName()
cmp_name = i.GetComponent().GetName()
net_name = i.GetNet().GetName()
padstacktype = i.GetPadstackDef().GetName()
_, location, angle = i.GetPositionAndRotationValue()

if cmp_name:
pad_name = cmp_name + '-' + pad_name

data.append((pad_name, net_name, padstacktype, str(location), str(angle)))
with open('d:/demo/pcb.log', 'w') as f:
json.dump(data, f, indent=4)

(圖一) 輸出的pin及via相關訊息