Create Substrate
This example shows how to create a simple substrate in your library
# Copyright Keysight Technologies 2024 - 2024
import keysight.ads.de as de
from keysight.ads import subst as substrate
# Example usage:
# wrk = de.open_workspace(path_to_workspace)
# lib = wrk.open_library("MyLibrary_lib", path_to_library, de.LibraryMode.SHARED)
# make_simple_substrate(lib, "my_substrate")
def make_simple_substrate(library: de.Library, subst_name: str) -> None:
assert not library.is_read_only
# Start by creating an "empty" substrate.
subst = substrate.create_substrate(library, subst_name)
assert substrate.substrate_exists(library, subst_name)
assert not subst.is_read_only
assert subst.is_writable
# See what materials are available
if False:
names = substrate.get_conductor_names(library)
assert len(names) != 0
names = substrate.get_semiconductor_names(library)
names = substrate.get_superconductor_names(library)
names = substrate.get_dielectric_names(library)
names = substrate.get_roughness_names(library)
# If you need to specify a list of purposes to ignore, use this
if True:
subst.purposes_to_exclude = ["Dummy"]
assert not subst.purposes_to_include
else:
subst.purposes_to_include = ["Drawing"]
assert not subst.purposes_to_exclude
# This substrate will have two infinite materials and three interfaces
assert len(subst.materials) == 2
assert len(subst.interfaces) == 3
assert subst.materials[0].is_infinite_material
top_material_index = subst.top_material_index
assert subst.materials[top_material_index].is_infinite_material
assert not subst.has_top_cover
interface0 = subst.interfaces[0]
assert not interface0.is_cover
assert interface0.is_non_cover_placeholder
# Convert the bottom interface to a cover
if False:
# The hard way
interface0.purpose = substrate.InterfaceItem.Purpose.COVER
interface0.material_name = "PERFECT_CONDUCTOR"
else:
interface0.convert_to_cover()
interface0.thickness_expr = "0.0123" # just so we can identify this interface
assert interface0.is_cover
assert not interface0.is_non_cover_placeholder
assert subst.has_bottom_cover
material0 = subst.materials[0]
# Since the bottom interface is now a cover, material0 won't be infinite
assert not material0.is_infinite_material
material0.thickness_expr = "100"
material0.thickness_unit = substrate.Unit.MICRON
material0.material_name = "SiliconNitride"
interface1 = subst.interfaces[1]
if True:
# You can specify interface by index
layer = subst.insert_layer(1, de.ProcessRole.CONDUCTOR)
else:
# You can can also pass interfaces
layer = subst.insert_layer(interface1, de.ProcessRole.CONDUCTOR)
layer.layer_number = 2
layer.material_name = "Au"
layer.thickness_expr = "0.01"
layer.thickness_unit = substrate.Unit.MIL
# The layer item can represent a sheet that neither expands nor intrudes into the material.
assert layer.sheet is True
layer.sheet = False
layer.expand = True # Otherwise we intrude
# Note that setting is_above to False sets the thickness negative
layer.is_above = False # so it expands the material below the interface
assert layer.thickness_expr == "-0.01"
subst.save_substrate()
if True:
# This will leave the bottom material and layer alone
subst.insert_material_and_interface_above(1)
elif False:
# This will shove the layer up to interface 2 and the bottom material up to material 1
subst.insert_material_and_interface_above(0)
else:
# This will shove the layer up to interface 2
subst.insert_material_and_interface_below(1)
# There is now one more material and one more interface than before
assert len(subst.materials) == 3
assert len(subst.interfaces) == 4
material1 = subst.materials[1]
material1.material_name = "Alumina"
subst.save_substrate()
# If we set the thickness of the top material, it won't
# be relevant because there is no top cover so the material is infinite.
material2 = subst.materials[2]
material2.thickness_expr = "2000"
material2.thickness_unit = substrate.Unit.MICRON
assert material2.is_infinite_material
subst.save_substrate()
# If we add one more material and interface, material2 won't be infinite.
subst.insert_material_and_interface_below(3)
assert not material2.is_infinite_material
assert material2.thickness == 2000
if False:
# The basic function...
via = subst.insert_via(1, 2, de.ProcessRole.CONDUCTOR_VIA)
elif False:
# You can specify interface by index
via = subst.insert_conductor_via(1, 2)
else:
# You can can also pass interfaces
interface2 = subst.interfaces[2]
via = subst.insert_conductor_via(interface1, interface2)
via.layer_number = 2 # cond2
via.material_name = "nicr"
assert via.process_role == de.ProcessRole.CONDUCTOR_VIA
via.is_plating_enabled = True
via.plating_dielectric_material_name = "SiliconNitride"
via.plating_thickness = 0.1
via.plating_thickness_unit = substrate.Unit.MILLIMETER
subst.save_substrate()
nested_subst = subst.insert_substrate(interface2)
nested_subst.set_library_and_substrate_names(library.name, "empty")
assert nested_subst.library_name == library.name
assert nested_subst.substrate_name == "empty"
# There are three choices for alignment
if False:
nested_subst.align_type = substrate.SubstrateItem.AlignType.BOTTOM
elif False:
nested_subst.align_type = substrate.SubstrateItem.AlignType.TOP
else:
nested_subst.align_type = substrate.SubstrateItem.AlignType.LAYER
# When aligning with a layer, we have to specify which part of the layer aligns
nested_subst.alignment_position = substrate.SubstrateItem.AlignPosition.TOP_OF_LAYER
nested_subst.align_layer_name = "cond2"
subst.save_substrate()
# If you don't need it any more, you can delete it
if False:
substrate.delete_substrate(library, subst_name)