Skip to content

Commit

Permalink
Improved Stackup Class (#1775)
Browse files Browse the repository at this point in the history
* Improved Stackup Class

* Improved Stackup Class

* Update pyaedt/modeler/stackup_3d.py

Fix the documentation build warnings.

* Fixed multiple bugs in H3dLayout stackup

* Fixed multiple bugs in H3dLayout stackup

* Fixed bug

* Fixed bug

* Apply suggestions from code review

Co-authored-by: Maxime Rey <[email protected]>
Co-authored-by: Kathy Pippert <[email protected]>

* Added Example

* Improved Unit Test

* Improved Unit Test

* Improved Unit Test

* Improved Unit Test

* Update pyaedt/application/Analysis.py

Co-authored-by: Alberto Di Maria <[email protected]>

* Improved Unit Test

Co-authored-by: maxcapodi78 <Shark78>
Co-authored-by: Maxime Rey <[email protected]>
Co-authored-by: Kathy Pippert <[email protected]>
Co-authored-by: Alberto Di Maria <[email protected]>
  • Loading branch information
4 people authored Oct 5, 2022
1 parent 54ae21e commit 19b9674
Show file tree
Hide file tree
Showing 13 changed files with 3,177 additions and 330 deletions.
2,588 changes: 2,588 additions & 0 deletions _unittest/example_models/T40/SMA_RF_Jack.a3dcomp

Large diffs are not rendered by default.

8 changes: 8 additions & 0 deletions _unittest/test_16_3d_stackup.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ def test_01_create_stackup(self):
self.st.dielectic_x_postion = "10mm"
gnd = self.st.add_ground_layer("gnd1")
self.st.add_dielectric_layer("diel1", thickness=1)
assert self.st.thickness.value == 1.035e-3
lay1 = self.st.add_signal_layer("lay1", thickness=0.07)
self.st.add_dielectric_layer("diel2", thickness=1.2)
top = self.st.add_signal_layer("top")
Expand Down Expand Up @@ -67,6 +68,13 @@ def test_03_padstackline(self):
assert p1.set_stop_layer("top")
p1.set_all_pad_value(1)
p1.set_all_antipad_value(3)
assert p1.padstacks_by_layer["top"].layer_name == "top"
assert p1.padstacks_by_layer["top"].pad_radius == 1
assert p1.padstacks_by_layer["top"].antipad_radius == 3
p1.padstacks_by_layer["top"].pad_radius = 2
p1.padstacks_by_layer["top"].antipad_radius = 2.5
assert p1.padstacks_by_layer["top"].pad_radius == 2
assert p1.padstacks_by_layer["top"].antipad_radius == 2.5
p1.num_sides = 8
assert p1.num_sides == 8
via = p1.add_via(50, 50)
Expand Down
50 changes: 25 additions & 25 deletions _unittest/test_40_3dlayout_edb.py
Original file line number Diff line number Diff line change
Expand Up @@ -209,31 +209,6 @@ def test_08_merge(self):
assert (comp.location[1] - 0.2) < tol
hfss3d.close_project(saveproject=False)

@pytest.mark.skipif(
config["NonGraphical"] and config["desktopVersion"] < "2023.1",
reason="Not running in non graphical mode. Tested only in Linux machine",
)
def test_09_3dplacement(self): # pragma: no cover
assert len(self.aedtapp.modeler.components_3d) == 2
tol = 1e-12
encrypted_model_path = os.path.join(local_path, "example_models", test_subfolder, "connector.a3dcomp")
comp = self.aedtapp.modeler.place_3d_component(
encrypted_model_path, 4, placement_layer="TOP", component_name="my_connector", pos_x=0.001, pos_y=0.002
)
if config["desktopVersion"] > "2022.2":
assert (comp.location[0] - 1) < tol
assert (comp.location[1] - 2) < tol
else:
assert (comp.location[0] - 0.001) < tol
assert (comp.location[1] - 0.002) < tol
assert comp.angle == "0deg"
assert comp.placement_layer == "TOP"
comp.placement_layer = "bottom"
assert comp.placement_layer == "BOTTOM"
comp.angle = "10deg"
assert comp.angle == "10deg"
assert comp.component_name == "my_connector"

def test_10_change_stackup(self):
assert self.aedtapp.modeler.layers.change_stackup_type("Multizone", 4)
assert len(self.aedtapp.modeler.layers.zones) == 3
Expand Down Expand Up @@ -265,3 +240,28 @@ def test_14_set_solderball(self):
assert not self.aedtapp.modeler.components["U3B2"].solderball_enabled
assert not self.aedtapp.modeler.components["L3A1"].set_solderball(None)
assert self.aedtapp.modeler.components["J1"].set_solderball("Sph")

def test_15_3dplacement(self):
self.aedtapp.insert_design("placement_3d")
l1 = self.aedtapp.modeler.layers.add_layer("BOTTOM", "signal", thickness="5mil")
self.aedtapp.modeler.layers.add_layer("diel", "dielectric", thickness="121mil", material="FR4_epoxy")
self.aedtapp.modeler.layers.add_layer("TOP", "signal", thickness="5mil", isnegative=True)
tol = 1e-12
encrypted_model_path = os.path.join(local_path, "example_models", test_subfolder, "SMA_RF_Jack.a3dcomp")
comp = self.aedtapp.modeler.place_3d_component(
encrypted_model_path, 1, placement_layer="TOP", component_name="my_connector", pos_x=0.001, pos_y=0.002
)
if config["desktopVersion"] > "2022.2":
assert (comp.location[0] - 1) < tol
assert (comp.location[1] - 2) < tol
else:
assert (comp.location[0] - 0.001) < tol
assert (comp.location[1] - 0.002) < tol
assert comp.angle == "0deg"
assert comp.placement_layer == "TOP"
comp.placement_layer = "bottom"
assert comp.placement_layer == "BOTTOM"
comp.angle = "10deg"
assert comp.angle == "10deg"
assert comp.component_name == "my_connector"
assert len(self.aedtapp.modeler.components_3d) == 1
15 changes: 7 additions & 8 deletions _unittest/test_41_3dlayout_modeler.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ def test_02_stackup(self):
assert s1.top_bottom == "top"
s1.top_bottom = "neither"

assert s1.thickness == "0.035mm"
assert s1.thickness == "0.035mm" or s1.thickness == 3.5e-5
assert s1.material == "iron"
assert s1.use_etch is False
assert s1.user is False
Expand Down Expand Up @@ -155,7 +155,7 @@ def test_02_stackup(self):
layername="Diel3", layertype="dielectric", thickness="1.0mm", elevation="0.035mm", material="plexiglass"
)
assert d1.material == "plexiglass"
assert d1.thickness == "1.0mm"
assert d1.thickness == "1.0mm" or d1.thickness == 1e-3
assert d1.transparency == 60
d1.material = "fr4_epoxy"
d1.transparency = 23
Expand All @@ -173,26 +173,21 @@ def test_02_stackup(self):
assert s2.name == "Top"
assert s2.type == "signal"
assert s2.material == "copper"
assert s2.thickness == 3.5e-5
assert s2.thickness == "0.035mm" or s2.thickness == 3.5e-5
assert s2.IsNegative is True
s2.is_negative = False
assert s2.IsNegative is False

self.aedtapp.modeler.layers.refresh_all_layers()
s1 = self.aedtapp.modeler.layers.layers[self.aedtapp.modeler.layers.layer_id("Bottom")]
assert s1.thickness == "0.035mm" or s1.thickness == 3.5e-5
assert s1.material == "copper"
assert s1.fill_material == "glass"
assert s1.use_etch is True
assert s1.etch == 1.2
assert s1.user is True
assert s1.usp is True
assert s1.hfssSp["dt"] == 1
assert s1.planaremSp["ifg"] is True
d1 = self.aedtapp.modeler.layers.layers[self.aedtapp.modeler.layers.layer_id("Diel3")]
assert d1.material == "fr4_epoxy"
assert d1.thickness == "1.0mm" or d1.thickness == 1e-3
assert d1.transparency == 23
s2 = self.aedtapp.modeler.layers.layers[self.aedtapp.modeler.layers.layer_id("Top")]
assert s2.name == "Top"
assert s2.type == "signal"
Expand Down Expand Up @@ -683,3 +678,7 @@ def test_96_change_nets_visibility(self):
assert not hfss3d.modeler.change_net_visibility(["test1, test2"])
assert not hfss3d.modeler.change_net_visibility(visible="")
assert not hfss3d.modeler.change_net_visibility(visible=0)

def test_97_mesh_settings(self):
assert self.aedtapp.set_meshing_settings(mesh_method="PhiPlus", enable_intersections_check=False)
assert self.aedtapp.set_meshing_settings(mesh_method="Classic", enable_intersections_check=True)
228 changes: 228 additions & 0 deletions examples/02-HFSS/Hfss3DComponent.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,228 @@
from pyaedt import Hfss, Hfss3dLayout
import os
from pyaedt.examples import download_file

###############################################################################
# Set non-graphical mode
# ~~~~~~~~~~~~~~~~~~~~~~
# Set non-graphical mode. ``"PYAEDT_NON_GRAPHICAL"`` is needed to generate
# documentation only.
# You can set ``non_graphical`` either to ``True`` or ``False``.

non_graphical = os.getenv("PYAEDT_NON_GRAPHICAL", "False").lower() in ("true", "1", "t")

###############################################################################
# Common Properties
# ~~~~~~~~~~~~~~~~~
trace_width = 0.6
trace_length = 30
diel_height = "121mil"
sig_height = "5mil"
max_steps = 3
freq = "3GHz"
desktop_version = "2022.2"
new_session = True

###############################################################################
# 3D Component Definition
# ~~~~~~~~~~~~~~~~~~~~~~~
# File to be used in the example
component3d = download_file("component_3d", "SMA_RF_Jack.a3dcomp",)
component3d

###############################################################################
# Hfss Example
# ------------
# This example will create a stackup in Hfss place a 3d component, build a ground plane, a trace,
# create excitation and solve it in Hfss.


###############################################################################
# Launch Hfss
# ~~~~~~~~~~~
#

hfss = Hfss(new_desktop_session=True, specified_version="2022.2", non_graphical=non_graphical)

hfss.solution_type = "Terminal"

###############################################################################
# Insert 3d Component
# ~~~~~~~~~~~~~~~~~~~
# To insert a 3d component we need to read parameters and then import in Hfss.

comp_param = hfss.get_components3d_vars(component3d)
comp_param
hfss.modeler.primitives.insert_3d_component(component3d, comp_param)

###############################################################################
# Add a new Stackup
# ~~~~~~~~~~~~~~~~~
# Pyaedt has a Stackup class which allows to parametrize stacked structures.

stackup = hfss.add_stackup_3d()
s1 = stackup.add_signal_layer("L1", thickness=sig_height)
d1 = stackup.add_dielectric_layer("D1", thickness=diel_height)
g1 = stackup.add_ground_layer("G1", thickness=sig_height)

###############################################################################
# Define stackup extensions
# ~~~~~~~~~~~~~~~~~~~~~~~~~~
# Define stackup elevation and size. Defines also the stackup origin.


stackup.start_position = "-131mil"
stackup.dielectric_width = "20mm"
stackup.dielectric_length = "40mm"
stackup.dielectric_y_position = "-dielectric_width/2"
stackup.dielectric_x_position = "-dielectric_length/4"

###############################################################################
# Padstack Definition
# ~~~~~~~~~~~~~~~~~~~
# Padstacks are needed to create a clearance around 3d component since
# intersections are not allowed. There will be 1 padstack for Gnd and 1 for pin.


p1 = stackup.add_padstack("gnd_via", material="cloned_copper")
p1.set_start_layer("L1")
p1.set_stop_layer("G1")
p1.set_all_antipad_value(1.3)
p1.set_all_pad_value(0)
p1.num_sides = 8
p1.add_via(-3.2, -3.2)
p1.add_via(-3.2, 3.2)
p1.add_via(3.2, -3.2)
p1.add_via(3.2, 3.2)
p2 = stackup.add_padstack("signal_via", material="cloned_copper")

p2.set_start_layer("L1")
p2.set_stop_layer("G1")
p2.set_all_antipad_value(0.7)
p2.set_all_pad_value(0)
p2.padstacks_by_layer["L1"].pad_radius = 0.3048
p2.add_via(0, 0)

###############################################################################
# Trace Definition
# ~~~~~~~~~~~~~~~~
# The trace will connect the pin to the port on layer L1.

t1 = s1.add_trace(trace_width, trace_length)
rect1 = hfss.modeler.primitives.create_rectangle(csPlane=hfss.CoordinateSystemPlane.YZPlane,
position=["0.75*dielectric_length", "-5*" + t1.width.name, "0mm"],
dimension_list=["15*" + t1.width.name, "-3*" + stackup.thickness.name])
p1 = hfss.create_wave_port_from_sheet(sheet=rect1, terminal_references="G1", portname="P1")

###############################################################################
# Set Simulation Boundaries
# ~~~~~~~~~~~~~~~~~~~~~~~~~
# Define regione and simulation boundaries.

hfss.change_material_override(True)
region = hfss.modeler.primitives.create_region([0, 0, 0, 0, 0, 100])
sheets = [i for i in region.faces]
hfss.assign_radiation_boundary_to_faces(sheets)

###############################################################################
# Create Setup
# ~~~~~~~~~~~~
# Iterations will be reduced to reduce simulation time.

setup1 = hfss.create_setup()
sweep1 = hfss.create_linear_count_sweep(setup1.name, "GHz", 0.01, 8, 1601, sweep_type="Interpolating")
setup1.props["Frequency"] = freq
setup1.props["MaximumPasses"] = max_steps

###############################################################################
# Solve Setup
# ~~~~~~~~~~~

hfss.save_project()
hfss.analyze_nominal()

###############################################################################
# Plot Results
# ~~~~~~~~~~~

traces = hfss.get_traces_for_plot(category="S")
solutions = hfss.post.get_solution_data(traces)
solutions.plot(traces, math_formula="db20")

###############################################################################
# Hfss 3D Layout Example
# ----------------------
# Previous example will be repeated this time in Hfss 3d Layout.
# Small differences are expected in layout but results should be similar.


###############################################################################
# Launch Hfss3dLayout
# ~~~~~~~~~~~~~~~~~~~
#

h3d = Hfss3dLayout(new_desktop_session=new_session, specified_version=desktop_version)

###############################################################################
# Add stackup layers
# ~~~~~~~~~~~~~~~~~~
# Add stackup layers.

l1 = h3d.modeler.layers.add_layer("L1", "signal", thickness=sig_height)
h3d.modeler.layers.add_layer("diel", "dielectric", thickness=diel_height, material="FR4_epoxy")
h3d.modeler.layers.add_layer("G1", "signal", thickness=sig_height, isnegative=True)

###############################################################################
# Place 3d Component
# ~~~~~~~~~~~~~~~~~~

comp = h3d.modeler.place_3d_component(
component3d, 1, placement_layer="G1", component_name="my_connector", pos_x=0.000, pos_y=0.000
)

###############################################################################
# Create signal net and ground planes
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Create a signal net and ground planes.

h3d["len"] = str(trace_length) + "mm"
h3d["w1"] = str(trace_width) + "mm"
line = h3d.modeler.create_line("L1", [[0, 0], ["len", 0]], lw="w1", netname="microstrip", name="microstrip")
h3d.create_edge_port(line, h3d.modeler[line].top_edge_x, iswave=True, wave_horizontal_extension=15, )

###############################################################################
# Create void on Ground plane for pin
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#
h3d.modeler.create_circle("G1", 0, 0, 0.5)

###############################################################################
# Create Setup
# ~~~~~~~~~~~~
# Iterations will be reduced to reduce simulation time.


h3d.set_meshing_settings(mesh_method="PhiPlus", enable_intersections_check=False)
h3d.edit_hfss_extents(diel_extent_horizontal_padding="0.2", air_vertical_positive_padding="0",
air_vertical_negative_padding="2", airbox_values_as_dim=False)
setup1 = h3d.create_setup()
sweep1 = h3d.create_linear_count_sweep(setup1.name, "GHz", 0.01, 8, 1601, sweep_type="Interpolating")
setup1.props["AdaptiveSettings"]["SingleFrequencyDataList"]["AdaptiveFrequencyData"]["AdaptiveFrequency"] = freq
setup1.props["AdaptiveSettings"]["SingleFrequencyDataList"]["AdaptiveFrequencyData"]["MaxPasses"] = max_steps

###############################################################################
# Solve Setup
# ~~~~~~~~~~~

h3d.analyze_nominal()

###############################################################################
# Plot Results
# ~~~~~~~~~~~

traces = h3d.get_traces_for_plot(category="S")
solutions = h3d.post.get_solution_data(traces)
solutions.plot(traces, math_formula="db20")

hfss.save_project()
hfss.release_desktop()
Loading

0 comments on commit 19b9674

Please sign in to comment.