2022年7月28日 星期四

PyAEDT修改金屬層Etching及Roughness屬性


from pyaedt import Hfss3dLayout

hfss = Hfss3dLayout(specified_version='2022.2')

layers = {}
for i, obj in hfss.modeler.layers.layers.items():
x = hfss.modeler.layers.layers[i]
layers[x.name] = obj

layers['TOP'].useetch = True
layers['TOP'].etch = 1.1
layers['TOP'].thickness = 5e-5

layers['TOP'].user = True
layers['TOP'].NR = 0.7
layers['TOP'].SHRatio = 3.0

layers['TOP'].update_stackup_layer()

 


2022年7月20日 星期三

取出Q3D Matrix資料並輸出.tsv到EXCEL檢視

可一次取出所有design variations, 6個物理量(DCR, DCL, ACR, ACL, C, G),Original及所有Reduced Matrix的所有sources組合隨頻率變化的數值。

from pyaedt import Q3d
from itertools import product


class matrix:
def __init__(self):
q3d = Q3d()
self.design_name = q3d.design_name

categories = ['DCR Matrix', 'ACR Matrix', 'DCL Matrix', 'ACL Matrix', 'C Matrix', 'G Matrix']
solution = q3d.nominal_sweep
matrix_list = q3d.odesign.GetChildObject('Reduce Matrix').GetChildNames()

variations = q3d.available_variations.variations()
self.variations = [i.replace(':=', '') for i in variations[0][::2]]
variations_value = []

for i in variations:
x = []
for j in i[1::2]:
x.append(j[0])
variations_value.append(x)

self.result = {}
for matrix in matrix_list:
quantities = []

for category in categories:
quantities += q3d.post.available_report_quantities(report_category="Matrix",
display_type="Data Table",
solution=solution,
quantities_category=category,
context=matrix)

for v, va in zip(variations, variations_value):
for q in quantities:
data = q3d.post.get_solution_data_per_variation(soltype="Matrix",
setup_sweep_name=solution,
ctxt=matrix,
sweeps=["Freq:=", ["All"]] + v,
expression=q
)
self.result[tuple(va + [q, matrix])] = (data.data_real(), data.units_data[q])
self.freq = data.primary_sweep_values
self.freq_unit = data.units_sweeps['Freq']

q3d.release_desktop(False, False)

def export_csv(self, csv_path):
with open(csv_path, 'w') as f:
f.writelines('\t'.join(
self.variations + ['Quantity', 'Matrix'] + [str(i) + self.freq_unit for i in self.freq] + ['Unit\n']))
for key, value in self.result.items():
line = '\t'.join(list(key) + [str(i) for i in value[0]] + [value[1]]) + '\n'
f.writelines(line)


m1 = matrix()
m1.export_csv('d:/demo/matrix.tsv')




2022年7月19日 星期二

Q3D輸出Partia/Mutual/Loop直流電感(DCL)


from pyaedt import Q3d

q3d = Q3d()
q3d.change_validation_settings(skip_intersections=True)

q3d['height'] = '10mm'
q3d['length'] = '100mm-2*height'

x = q3d.create_setup('mysetup')
y = x.add_sweep('mysweep')
y.props['RangeStart'] = '0GHz'
y.props['RangeEnd'] = '1GHz'
y.props['RangeStep'] = '0.1GHz'
y.update()

x1 = q3d.modeler.create_polyline([(0, 0, '1mm'),
(0, 0, 'height'),
(0, 'length', 'height'),
(0, 'length', '1mm')],
xsection_type='Circle',
xsection_bend_type='5mm')

_, x2 = q3d.modeler.duplicate_and_mirror(x1, (0, 0, 0), (0, 0, 1))
q3d.assign_net([x1], net_name='net_top', net_type='signal')
q3d.assign_net([x2[0]], net_name='net_bot', net_type='signal')

face = q3d.modeler.get_faceid_from_position((0, 0, '1mm'))
q3d.assign_source_to_objectface(face, source_name='top_source', net_name='net_top')

face = q3d.modeler.get_faceid_from_position((0, 'length', '1mm'))
q3d.assign_sink_to_objectface(face, sink_name='top_sink', net_name='net_top')

face = q3d.modeler.get_faceid_from_position((0, 0, '-1mm'))
q3d.assign_source_to_objectface(face, source_name='bot_source', net_name='net_bot')

face = q3d.modeler.get_faceid_from_position((0, 'length', '-1mm'))
q3d.assign_sink_to_objectface(face, sink_name='bot_sink', net_name='net_bot')

oModule = q3d.odesign.GetModule("ReduceMatrix")
oModule.InsertRM("ReturnPathMatrix", "ReturnPath(\'top_source\')")

result = {}
for h in ['5mm', '10mm', '15mm', '20mm', '25mm']:
q3d['height'] = h

q3d.analyze_nominal(num_cores=4)

data = q3d.post.get_solution_data('DCL(net_bot:bot_source,net_bot:bot_source)')
partial_L = data.data_real()[0]

data = q3d.post.get_solution_data('DCL(net_top:top_source,net_bot:bot_source)')
mutual_L = data.data_real()[0]

data = q3d.post.get_solution_data_per_variation(soltype="Matrix",
setup_sweep_name='mysetup : mysweep',
ctxt="ReturnPathMatrix",
sweeps=None,
expression="DCL(net_bot:bot_source,net_bot:bot_source)")
loop_L = data.data_real()[0]
result[h] = (partial_L, mutual_L, loop_L)

 





2022年7月17日 星期日

Q3D輸出Touchstone及SPICE模型

 

from pyaedt import Q3d
import string, random

design_name = ''.join(random.sample(string.ascii_lowercase, 10))

q3d = Q3d(designname=design_name)
q3d.change_validation_settings(skip_intersections=True)

faces = {}
q3d.modeler.delete(q3d.modeler.object_list)

x1 = q3d.modeler.create_box((-10, 0, 0), (20, 1, 1), matname='copper')
x2 = q3d.modeler.create_box((0, 0, 0), (1, 10, 1), matname='copper')
q3d.modeler.unite([x1, x2])
q3d.assign_net([x1], net_name='net_a', net_type='signal')
faces['net_a'] = [x1.top_face_x, x1.bottom_face_x, x1.top_face_y]

x3 = q3d.modeler.create_box((-10, -2, 0), (15, 1, 1), matname='copper')
x4 = q3d.modeler.create_box((-5, -2, 0), (1, 1, 5), matname='copper')
q3d.modeler.unite([x3, x4])
q3d.assign_net([x3], net_name='net_b', net_type='signal')
faces['net_b'] = [x3.top_face_x, x3.bottom_face_x, x3.top_face_z]

case = {'net_a': ['source', 'source', 'sink'],
'net_b': ['source', 'source', 'sink']}

for net in case:
for face, _type, name in zip(faces[net], case[net], ['_A', '_B', '_C']):
if _type == 'source':
q3d.assign_source_to_objectface(face, source_name=net + name, net_name=net)
if _type == 'sink':
q3d.assign_sink_to_objectface(face, sink_name=net + name, net_name=net)

x = q3d.create_setup()
y = x.add_sweep()
y.props['RangeStart'] = '0GHz'
y.props['RangeEnd'] = '1GHz'
y.props['RangeStep'] = '0.1GHz'
y.update()

q3d.analyze_nominal(num_cores=4)

data = q3d.post.get_solution_data('C(net_a,net_a)')
freqs = [1e9 * i for i in data.primary_sweep_values]

q3d.odesign.ExportNetworkData("", q3d.nominal_sweep, f"D:/demo/{design_name}.s6p", "Original", 50, freqs, "MagPhase", 0)

for freq in freqs:
q3d.oanalysis.ExportCircuit(q3d.nominal_sweep, "", f"D:/demo/{design_name}_{freq}.cir",
[
"NAME:CircuitData",
"MatrixName:=" , "Original",
"NumberOfCells:=" , "1",
"UserHasChangedSettings:=", True,
"IncludeCap:=" , True,
"IncludeCond:=" , True,
[
"NAME:CouplingLimits",
"CouplingLimitType:=" , "None"
],
"IncludeDCR:=" , False,
"IncudeDCL:=" , False,
"IncludeACR:=" , False,
"IncludeACL:=" , True,
"ADDResistance:=" , True,
"ParsePinNames:=" , False,
"IncludeCPP:=" , False,
[
"NAME:CPPInfo",
"PackageType:=" , "wirebond dieup",
"RelativeCS:=" , "",
"LengthUnits:=" , "mm",
[
"NAME:Pins"
]
]
], q3d.project_name, freq)

2022年7月16日 星期六

將Q3D匯出的cir檔案轉成TouchStone檔案

 

import re, os
from pyaedt import Circuit

circuit = Circuit(non_graphical=True, new_desktop_session='True', close_on_exit=True)


def cirtosnp(cir_path, fstart='0GHz', fstop='1GHz', fpoints=1001):
with open(cir_path) as f:
text = f.readlines()

ports = re.findall(r'\*\snode\s(\d+)\s+(.*)', '\n'.join(text))
snp_path = cir_path.replace('.cir', f'.s{len(ports)}p')
netlist = f'.inc "{cir_path}"\n\n'

for line in text:
if line.startswith('.subckt'):
_, cmp, *num = line.strip().split()
break

temp = ' '.join([i[1] for i in ports])
netlist += f'x1 {temp} {cmp}\n'
netlist_path = os.path.join(circuit.temp_directory, 'temp.cir')

with open(netlist_path, 'w') as f:
f.write(netlist)
circuit.add_netlist_datablock(netlist_path)

for port_id, port_name in ports:
circuit.modeler.components.create_interface_port(port_name)

setup1 = circuit.create_setup()
setup1.props["SweepDefinition"]["Data"] = f"LINC {fstart} {fstop} {fpoints}"
circuit.analyze_nominal()
circuit.export_touchstone(file_name=snp_path)
circuit.close_project()


cirtosnp("D:\demo\yqopvgihel_400000000.0.cir")

EDB建立PinGroup

為U2A5建立GND PinGroup,儲存之後匯入EDB from pyaedt import Edb edb = Edb(edbpath= r"D:\demo\Galileo_G87173_20454.aedb" , edbversion= '20...