pyedb 0.2.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of pyedb might be problematic. Click here for more details.
- pyedb/__init__.py +17 -0
- pyedb/dotnet/__init__.py +0 -0
- pyedb/dotnet/application/Variables.py +2261 -0
- pyedb/dotnet/application/__init__.py +0 -0
- pyedb/dotnet/clr_module.py +103 -0
- pyedb/dotnet/edb.py +4237 -0
- pyedb/dotnet/edb_core/__init__.py +1 -0
- pyedb/dotnet/edb_core/cell/__init__.py +0 -0
- pyedb/dotnet/edb_core/cell/hierarchy/__init__.py +0 -0
- pyedb/dotnet/edb_core/cell/hierarchy/model.py +66 -0
- pyedb/dotnet/edb_core/components.py +2669 -0
- pyedb/dotnet/edb_core/configuration.py +423 -0
- pyedb/dotnet/edb_core/definition/__init__.py +0 -0
- pyedb/dotnet/edb_core/definition/component_def.py +166 -0
- pyedb/dotnet/edb_core/definition/component_model.py +30 -0
- pyedb/dotnet/edb_core/definition/definition_obj.py +18 -0
- pyedb/dotnet/edb_core/definition/definitions.py +12 -0
- pyedb/dotnet/edb_core/dotnet/__init__.py +0 -0
- pyedb/dotnet/edb_core/dotnet/database.py +1218 -0
- pyedb/dotnet/edb_core/dotnet/layout.py +238 -0
- pyedb/dotnet/edb_core/dotnet/primitive.py +1517 -0
- pyedb/dotnet/edb_core/edb_data/__init__.py +0 -0
- pyedb/dotnet/edb_core/edb_data/components_data.py +938 -0
- pyedb/dotnet/edb_core/edb_data/connectable.py +113 -0
- pyedb/dotnet/edb_core/edb_data/control_file.py +1268 -0
- pyedb/dotnet/edb_core/edb_data/design_options.py +35 -0
- pyedb/dotnet/edb_core/edb_data/edbvalue.py +45 -0
- pyedb/dotnet/edb_core/edb_data/hfss_extent_info.py +330 -0
- pyedb/dotnet/edb_core/edb_data/hfss_simulation_setup_data.py +1607 -0
- pyedb/dotnet/edb_core/edb_data/layer_data.py +576 -0
- pyedb/dotnet/edb_core/edb_data/nets_data.py +281 -0
- pyedb/dotnet/edb_core/edb_data/obj_base.py +19 -0
- pyedb/dotnet/edb_core/edb_data/padstacks_data.py +2080 -0
- pyedb/dotnet/edb_core/edb_data/ports.py +287 -0
- pyedb/dotnet/edb_core/edb_data/primitives_data.py +1397 -0
- pyedb/dotnet/edb_core/edb_data/simulation_configuration.py +2914 -0
- pyedb/dotnet/edb_core/edb_data/simulation_setup.py +716 -0
- pyedb/dotnet/edb_core/edb_data/siwave_simulation_setup_data.py +1205 -0
- pyedb/dotnet/edb_core/edb_data/sources.py +514 -0
- pyedb/dotnet/edb_core/edb_data/terminals.py +632 -0
- pyedb/dotnet/edb_core/edb_data/utilities.py +148 -0
- pyedb/dotnet/edb_core/edb_data/variables.py +91 -0
- pyedb/dotnet/edb_core/general.py +181 -0
- pyedb/dotnet/edb_core/hfss.py +1646 -0
- pyedb/dotnet/edb_core/layout.py +1244 -0
- pyedb/dotnet/edb_core/layout_validation.py +272 -0
- pyedb/dotnet/edb_core/materials.py +939 -0
- pyedb/dotnet/edb_core/net_class.py +335 -0
- pyedb/dotnet/edb_core/nets.py +1215 -0
- pyedb/dotnet/edb_core/padstack.py +1389 -0
- pyedb/dotnet/edb_core/siwave.py +1427 -0
- pyedb/dotnet/edb_core/stackup.py +2703 -0
- pyedb/edb_logger.py +396 -0
- pyedb/generic/__init__.py +0 -0
- pyedb/generic/constants.py +1063 -0
- pyedb/generic/data_handlers.py +320 -0
- pyedb/generic/design_types.py +104 -0
- pyedb/generic/filesystem.py +150 -0
- pyedb/generic/general_methods.py +1535 -0
- pyedb/generic/plot.py +1840 -0
- pyedb/generic/process.py +285 -0
- pyedb/generic/settings.py +224 -0
- pyedb/ipc2581/__init__.py +0 -0
- pyedb/ipc2581/bom/__init__.py +0 -0
- pyedb/ipc2581/bom/bom.py +21 -0
- pyedb/ipc2581/bom/bom_item.py +32 -0
- pyedb/ipc2581/bom/characteristics.py +37 -0
- pyedb/ipc2581/bom/refdes.py +16 -0
- pyedb/ipc2581/content/__init__.py +0 -0
- pyedb/ipc2581/content/color.py +38 -0
- pyedb/ipc2581/content/content.py +55 -0
- pyedb/ipc2581/content/dictionary_color.py +29 -0
- pyedb/ipc2581/content/dictionary_fill.py +28 -0
- pyedb/ipc2581/content/dictionary_line.py +30 -0
- pyedb/ipc2581/content/entry_color.py +13 -0
- pyedb/ipc2581/content/entry_line.py +14 -0
- pyedb/ipc2581/content/fill.py +15 -0
- pyedb/ipc2581/content/layer_ref.py +10 -0
- pyedb/ipc2581/content/standard_geometries_dictionary.py +72 -0
- pyedb/ipc2581/ecad/__init__.py +0 -0
- pyedb/ipc2581/ecad/cad_data/__init__.py +0 -0
- pyedb/ipc2581/ecad/cad_data/assembly_drawing.py +26 -0
- pyedb/ipc2581/ecad/cad_data/cad_data.py +37 -0
- pyedb/ipc2581/ecad/cad_data/component.py +41 -0
- pyedb/ipc2581/ecad/cad_data/drill.py +30 -0
- pyedb/ipc2581/ecad/cad_data/feature.py +54 -0
- pyedb/ipc2581/ecad/cad_data/layer.py +41 -0
- pyedb/ipc2581/ecad/cad_data/layer_feature.py +151 -0
- pyedb/ipc2581/ecad/cad_data/logical_net.py +32 -0
- pyedb/ipc2581/ecad/cad_data/outline.py +25 -0
- pyedb/ipc2581/ecad/cad_data/package.py +104 -0
- pyedb/ipc2581/ecad/cad_data/padstack_def.py +38 -0
- pyedb/ipc2581/ecad/cad_data/padstack_hole_def.py +24 -0
- pyedb/ipc2581/ecad/cad_data/padstack_instance.py +62 -0
- pyedb/ipc2581/ecad/cad_data/padstack_pad_def.py +26 -0
- pyedb/ipc2581/ecad/cad_data/path.py +89 -0
- pyedb/ipc2581/ecad/cad_data/phy_net.py +80 -0
- pyedb/ipc2581/ecad/cad_data/pin.py +31 -0
- pyedb/ipc2581/ecad/cad_data/polygon.py +169 -0
- pyedb/ipc2581/ecad/cad_data/profile.py +40 -0
- pyedb/ipc2581/ecad/cad_data/stackup.py +31 -0
- pyedb/ipc2581/ecad/cad_data/stackup_group.py +42 -0
- pyedb/ipc2581/ecad/cad_data/stackup_layer.py +21 -0
- pyedb/ipc2581/ecad/cad_data/step.py +275 -0
- pyedb/ipc2581/ecad/cad_header.py +33 -0
- pyedb/ipc2581/ecad/ecad.py +19 -0
- pyedb/ipc2581/ecad/spec.py +46 -0
- pyedb/ipc2581/history_record.py +37 -0
- pyedb/ipc2581/ipc2581.py +387 -0
- pyedb/ipc2581/logistic_header.py +25 -0
- pyedb/misc/__init__.py +0 -0
- pyedb/misc/aedtlib_personalib_install.py +14 -0
- pyedb/misc/downloads.py +322 -0
- pyedb/misc/misc.py +67 -0
- pyedb/misc/pyedb.runtimeconfig.json +13 -0
- pyedb/misc/siw_feature_config/__init__.py +0 -0
- pyedb/misc/siw_feature_config/emc/__init__.py +0 -0
- pyedb/misc/siw_feature_config/emc/component_tags.py +46 -0
- pyedb/misc/siw_feature_config/emc/net_tags.py +37 -0
- pyedb/misc/siw_feature_config/emc/tag_library.py +62 -0
- pyedb/misc/siw_feature_config/emc/xml_generic.py +78 -0
- pyedb/misc/siw_feature_config/emc_rule_checker_settings.py +179 -0
- pyedb/misc/utilities.py +27 -0
- pyedb/modeler/geometry_operators.py +2082 -0
- pyedb-0.2.0.dist-info/LICENSE +21 -0
- pyedb-0.2.0.dist-info/METADATA +208 -0
- pyedb-0.2.0.dist-info/RECORD +128 -0
- pyedb-0.2.0.dist-info/WHEEL +4 -0
|
@@ -0,0 +1,1646 @@
|
|
|
1
|
+
"""
|
|
2
|
+
This module contains the ``EdbHfss`` class.
|
|
3
|
+
"""
|
|
4
|
+
import math
|
|
5
|
+
|
|
6
|
+
from pyedb.dotnet.edb_core.edb_data.hfss_extent_info import HfssExtentInfo
|
|
7
|
+
from pyedb.dotnet.edb_core.edb_data.ports import BundleWavePort, WavePort
|
|
8
|
+
from pyedb.dotnet.edb_core.edb_data.primitives_data import EDBPrimitives
|
|
9
|
+
from pyedb.dotnet.edb_core.edb_data.simulation_configuration import (
|
|
10
|
+
SimulationConfiguration,
|
|
11
|
+
)
|
|
12
|
+
from pyedb.dotnet.edb_core.general import (
|
|
13
|
+
convert_py_list_to_net_list,
|
|
14
|
+
convert_pytuple_to_nettuple,
|
|
15
|
+
)
|
|
16
|
+
from pyedb.generic.constants import RadiationBoxType, SweepType
|
|
17
|
+
from pyedb.generic.general_methods import (
|
|
18
|
+
generate_unique_name,
|
|
19
|
+
is_ironpython,
|
|
20
|
+
pyedb_function_handler,
|
|
21
|
+
)
|
|
22
|
+
from pyedb.modeler.geometry_operators import GeometryOperators
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class EdbHfss(object):
|
|
26
|
+
"""Manages EDB method to configure Hfss setup accessible from `Edb.hfss` property.
|
|
27
|
+
|
|
28
|
+
Examples
|
|
29
|
+
--------
|
|
30
|
+
>>> from pyedb import Edb
|
|
31
|
+
>>> edbapp = Edb("myaedbfolder")
|
|
32
|
+
>>> edb_hfss = edb_3dedbapp.hfss
|
|
33
|
+
"""
|
|
34
|
+
|
|
35
|
+
def __init__(self, p_edb):
|
|
36
|
+
self._pedb = p_edb
|
|
37
|
+
|
|
38
|
+
@property
|
|
39
|
+
def hfss_extent_info(self):
|
|
40
|
+
"""HFSS extent information."""
|
|
41
|
+
return HfssExtentInfo(self._pedb)
|
|
42
|
+
|
|
43
|
+
@property
|
|
44
|
+
def _logger(self):
|
|
45
|
+
return self._pedb.logger
|
|
46
|
+
|
|
47
|
+
@property
|
|
48
|
+
def _edb(self):
|
|
49
|
+
"""EDB object.
|
|
50
|
+
|
|
51
|
+
Returns
|
|
52
|
+
-------
|
|
53
|
+
Ansys.Ansoft.Edb
|
|
54
|
+
"""
|
|
55
|
+
return self._pedb.edb_api
|
|
56
|
+
|
|
57
|
+
@property
|
|
58
|
+
def _active_layout(self):
|
|
59
|
+
return self._pedb.active_layout
|
|
60
|
+
|
|
61
|
+
@property
|
|
62
|
+
def _layout(self):
|
|
63
|
+
return self._pedb.layout
|
|
64
|
+
|
|
65
|
+
@property
|
|
66
|
+
def _cell(self):
|
|
67
|
+
return self._pedb.cell
|
|
68
|
+
|
|
69
|
+
@property
|
|
70
|
+
def _db(self):
|
|
71
|
+
return self._pedb.active_db
|
|
72
|
+
|
|
73
|
+
@property
|
|
74
|
+
def excitations(self):
|
|
75
|
+
"""Get all excitations."""
|
|
76
|
+
return self._pedb.excitations
|
|
77
|
+
|
|
78
|
+
@property
|
|
79
|
+
def sources(self):
|
|
80
|
+
"""Get all sources."""
|
|
81
|
+
return self._pedb.sources
|
|
82
|
+
|
|
83
|
+
@property
|
|
84
|
+
def probes(self):
|
|
85
|
+
"""Get all probes."""
|
|
86
|
+
return self._pedb.probes
|
|
87
|
+
|
|
88
|
+
def _get_edb_value(self, value):
|
|
89
|
+
return self._pedb.edb_value(value)
|
|
90
|
+
|
|
91
|
+
@pyedb_function_handler()
|
|
92
|
+
def _create_edge_terminal(self, prim_id, point_on_edge, terminal_name=None, is_ref=False):
|
|
93
|
+
"""Create an edge terminal.
|
|
94
|
+
|
|
95
|
+
Parameters
|
|
96
|
+
----------
|
|
97
|
+
prim_id : int
|
|
98
|
+
Primitive ID.
|
|
99
|
+
point_on_edge : list
|
|
100
|
+
Coordinate of the point to define the edge terminal.
|
|
101
|
+
The point must be on the target edge but not on the two
|
|
102
|
+
ends of the edge.
|
|
103
|
+
terminal_name : str, optional
|
|
104
|
+
Name of the terminal. The default is ``None``, in which case the
|
|
105
|
+
default name is assigned.
|
|
106
|
+
is_ref : bool, optional
|
|
107
|
+
Whether it is a reference terminal. The default is ``False``.
|
|
108
|
+
|
|
109
|
+
Returns
|
|
110
|
+
-------
|
|
111
|
+
Edb.Cell.Terminal.EdgeTerminal
|
|
112
|
+
"""
|
|
113
|
+
if not terminal_name:
|
|
114
|
+
terminal_name = generate_unique_name("Terminal_")
|
|
115
|
+
if isinstance(point_on_edge, (list, tuple)):
|
|
116
|
+
point_on_edge = self._edb.geometry.point_data(
|
|
117
|
+
self._get_edb_value(point_on_edge[0]), self._get_edb_value(point_on_edge[1])
|
|
118
|
+
)
|
|
119
|
+
if hasattr(prim_id, "GetId"):
|
|
120
|
+
prim = prim_id
|
|
121
|
+
else:
|
|
122
|
+
prim = [i for i in self._pedb.modeler.primitives if i.id == prim_id][0].primitive_object
|
|
123
|
+
pos_edge = self._edb.cell.terminal.PrimitiveEdge.Create(prim, point_on_edge)
|
|
124
|
+
pos_edge = convert_py_list_to_net_list(pos_edge, self._edb.cell.terminal.Edge)
|
|
125
|
+
return self._edb.cell.terminal.EdgeTerminal.Create(
|
|
126
|
+
prim.GetLayout(), prim.GetNet(), terminal_name, pos_edge, isRef=is_ref
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
@pyedb_function_handler()
|
|
130
|
+
def get_trace_width_for_traces_with_ports(self):
|
|
131
|
+
"""Retrieve the trace width for traces with ports.
|
|
132
|
+
|
|
133
|
+
Returns
|
|
134
|
+
-------<
|
|
135
|
+
dict
|
|
136
|
+
Dictionary of trace width data.
|
|
137
|
+
"""
|
|
138
|
+
nets = {}
|
|
139
|
+
for net in self._pedb.excitations_nets:
|
|
140
|
+
smallest = self._pedb.nets[net].get_smallest_trace_width()
|
|
141
|
+
if smallest < 1e10:
|
|
142
|
+
nets[net] = self._pedb.nets[net].get_smallest_trace_width()
|
|
143
|
+
return nets
|
|
144
|
+
|
|
145
|
+
@pyedb_function_handler()
|
|
146
|
+
def create_circuit_port_on_pin(self, pos_pin, neg_pin, impedance=50, port_name=None):
|
|
147
|
+
"""Create Circuit Port on Pin.
|
|
148
|
+
|
|
149
|
+
Parameters
|
|
150
|
+
----------
|
|
151
|
+
pos_pin : Object
|
|
152
|
+
Edb Pin
|
|
153
|
+
neg_pin : Object
|
|
154
|
+
Edb Pin
|
|
155
|
+
impedance : float
|
|
156
|
+
Port Impedance
|
|
157
|
+
port_name : str, optional
|
|
158
|
+
Port Name
|
|
159
|
+
|
|
160
|
+
>>> from pyedb import Edb
|
|
161
|
+
>>> edbapp = Edb("myaedbfolder", "project name", "release version")
|
|
162
|
+
>>> pins =edbapp.components.get_pin_from_component("U2A5")
|
|
163
|
+
>>> edbapp.hfss.create_circuit_port_on_pin(pins[0], pins[1],50,"port_name")
|
|
164
|
+
|
|
165
|
+
Returns
|
|
166
|
+
-------
|
|
167
|
+
str
|
|
168
|
+
Port Name.
|
|
169
|
+
|
|
170
|
+
"""
|
|
171
|
+
return self._pedb.siwave.create_circuit_port_on_pin(pos_pin, neg_pin, impedance, port_name)
|
|
172
|
+
|
|
173
|
+
@pyedb_function_handler()
|
|
174
|
+
def create_voltage_source_on_pin(self, pos_pin, neg_pin, voltage_value=3.3, phase_value=0, source_name=""):
|
|
175
|
+
"""Create a voltage source.
|
|
176
|
+
|
|
177
|
+
Parameters
|
|
178
|
+
----------
|
|
179
|
+
pos_pin : Object
|
|
180
|
+
Positive Pin.
|
|
181
|
+
neg_pin : Object
|
|
182
|
+
Negative Pin.
|
|
183
|
+
voltage_value : float, optional
|
|
184
|
+
Value for the voltage. The default is ``3.3``.
|
|
185
|
+
phase_value : optional
|
|
186
|
+
Value for the phase. The default is ``0``.
|
|
187
|
+
source_name : str, optional
|
|
188
|
+
Name of the source. The default is ``""``.
|
|
189
|
+
|
|
190
|
+
Returns
|
|
191
|
+
-------
|
|
192
|
+
str
|
|
193
|
+
Source Name.
|
|
194
|
+
|
|
195
|
+
Examples
|
|
196
|
+
--------
|
|
197
|
+
|
|
198
|
+
>>> from pyedb import Edb
|
|
199
|
+
>>> edbapp = Edb("myaedbfolder", "project name", "release version")
|
|
200
|
+
>>> pins =edbapp.components.get_pin_from_component("U2A5")
|
|
201
|
+
>>> edbapp.hfss.create_voltage_source_on_pin(pins[0], pins[1],50,"source_name")
|
|
202
|
+
"""
|
|
203
|
+
return self._pedb.siwave.create_voltage_source_on_pin(pos_pin, neg_pin, voltage_value, phase_value, source_name)
|
|
204
|
+
|
|
205
|
+
@pyedb_function_handler()
|
|
206
|
+
def create_current_source_on_pin(self, pos_pin, neg_pin, current_value=0.1, phase_value=0, source_name=""):
|
|
207
|
+
"""Create a current source.
|
|
208
|
+
|
|
209
|
+
Parameters
|
|
210
|
+
----------
|
|
211
|
+
pos_pin : Object
|
|
212
|
+
Positive Pin.
|
|
213
|
+
neg_pin : Object
|
|
214
|
+
Negative Pin.
|
|
215
|
+
current_value : float, optional
|
|
216
|
+
Value for the current. The default is ``0.1``.
|
|
217
|
+
phase_value : optional
|
|
218
|
+
Value for the phase. The default is ``0``.
|
|
219
|
+
source_name : str, optional
|
|
220
|
+
Name of the source. The default is ``""``.
|
|
221
|
+
|
|
222
|
+
Returns
|
|
223
|
+
-------
|
|
224
|
+
str
|
|
225
|
+
Source Name.
|
|
226
|
+
|
|
227
|
+
Examples
|
|
228
|
+
--------
|
|
229
|
+
|
|
230
|
+
>>> from pyedb import Edb
|
|
231
|
+
>>> edbapp = Edb("myaedbfolder", "project name", "release version")
|
|
232
|
+
>>> pins =edbapp.components.get_pin_from_component("U2A5")
|
|
233
|
+
>>> edbapp.hfss.create_current_source_on_pin(pins[0], pins[1],50,"source_name")
|
|
234
|
+
"""
|
|
235
|
+
|
|
236
|
+
return self._pedb.siwave.create_current_source_on_pin(pos_pin, neg_pin, current_value, phase_value, source_name)
|
|
237
|
+
|
|
238
|
+
@pyedb_function_handler()
|
|
239
|
+
def create_resistor_on_pin(self, pos_pin, neg_pin, rvalue=1, resistor_name=""):
|
|
240
|
+
"""Create a Resistor boundary between two given pins.
|
|
241
|
+
|
|
242
|
+
Parameters
|
|
243
|
+
----------
|
|
244
|
+
pos_pin : Object
|
|
245
|
+
Positive Pin.
|
|
246
|
+
neg_pin : Object
|
|
247
|
+
Negative Pin.
|
|
248
|
+
rvalue : float, optional
|
|
249
|
+
Resistance value. The default is ``1``.
|
|
250
|
+
resistor_name : str, optional
|
|
251
|
+
Name of the resistor. The default is ``""``.
|
|
252
|
+
|
|
253
|
+
Returns
|
|
254
|
+
-------
|
|
255
|
+
str
|
|
256
|
+
Name of the Resistor.
|
|
257
|
+
|
|
258
|
+
Examples
|
|
259
|
+
--------
|
|
260
|
+
|
|
261
|
+
>>> from pyedb import Edb
|
|
262
|
+
>>> edbapp = Edb("myaedbfolder", "project name", "release version")
|
|
263
|
+
>>> pins =edbapp.components.get_pin_from_component("U2A5")
|
|
264
|
+
>>> edbapp.hfss.create_resistor_on_pin(pins[0], pins[1],50,"res_name")
|
|
265
|
+
"""
|
|
266
|
+
return self._pedb.siwave.create_resistor_on_pin(pos_pin, neg_pin, rvalue, resistor_name)
|
|
267
|
+
|
|
268
|
+
@pyedb_function_handler()
|
|
269
|
+
def create_circuit_port_on_net(
|
|
270
|
+
self,
|
|
271
|
+
positive_component_name,
|
|
272
|
+
positive_net_name,
|
|
273
|
+
negative_component_name=None,
|
|
274
|
+
negative_net_name="GND",
|
|
275
|
+
impedance_value=50,
|
|
276
|
+
port_name="",
|
|
277
|
+
):
|
|
278
|
+
"""Create a circuit port on a NET.
|
|
279
|
+
It groups all pins belonging to the specified net and then applies the port on PinGroups.
|
|
280
|
+
|
|
281
|
+
Parameters
|
|
282
|
+
----------
|
|
283
|
+
positive_component_name : str
|
|
284
|
+
Name of the positive component.
|
|
285
|
+
positive_net_name : str
|
|
286
|
+
Name of the positive net.
|
|
287
|
+
negative_component_name : str, optional
|
|
288
|
+
Name of the negative component. The default is ``None``, in which case the name of
|
|
289
|
+
the positive net is assigned.
|
|
290
|
+
negative_net_name : str, optional
|
|
291
|
+
Name of the negative net name. The default is ``"GND"``.
|
|
292
|
+
impedance_value : float, optional
|
|
293
|
+
Port impedance value. The default is ``50``.
|
|
294
|
+
port_name : str, optional
|
|
295
|
+
Name of the port. The default is ``""``.
|
|
296
|
+
|
|
297
|
+
Returns
|
|
298
|
+
-------
|
|
299
|
+
str
|
|
300
|
+
The name of the port.
|
|
301
|
+
|
|
302
|
+
Examples
|
|
303
|
+
--------
|
|
304
|
+
>>> from pyedb import Edb
|
|
305
|
+
>>> edbapp = Edb("myaedbfolder", "project name", "release version")
|
|
306
|
+
>>> edbapp.hfss.create_circuit_port_on_net("U2A5", "V1P5_S3", "U2A5", "GND", 50, "port_name")
|
|
307
|
+
"""
|
|
308
|
+
return self._pedb.siwave.create_circuit_port_on_net(
|
|
309
|
+
positive_component_name,
|
|
310
|
+
positive_net_name,
|
|
311
|
+
negative_component_name,
|
|
312
|
+
negative_net_name,
|
|
313
|
+
impedance_value,
|
|
314
|
+
port_name,
|
|
315
|
+
)
|
|
316
|
+
|
|
317
|
+
@pyedb_function_handler()
|
|
318
|
+
def create_voltage_source_on_net(
|
|
319
|
+
self,
|
|
320
|
+
positive_component_name,
|
|
321
|
+
positive_net_name,
|
|
322
|
+
negative_component_name=None,
|
|
323
|
+
negative_net_name="GND",
|
|
324
|
+
voltage_value=3.3,
|
|
325
|
+
phase_value=0,
|
|
326
|
+
source_name="",
|
|
327
|
+
):
|
|
328
|
+
"""Create a voltage source.
|
|
329
|
+
|
|
330
|
+
Parameters
|
|
331
|
+
----------
|
|
332
|
+
positive_component_name : str
|
|
333
|
+
Name of the positive component.
|
|
334
|
+
positive_net_name : str
|
|
335
|
+
Name of the positive net.
|
|
336
|
+
negative_component_name : str, optional
|
|
337
|
+
Name of the negative component. The default is ``None``, in which case the name of
|
|
338
|
+
the positive net is assigned.
|
|
339
|
+
negative_net_name : str, optional
|
|
340
|
+
Name of the negative net. The default is ``"GND"``.
|
|
341
|
+
voltage_value : float, optional
|
|
342
|
+
Value for the voltage. The default is ``3.3``.
|
|
343
|
+
phase_value : optional
|
|
344
|
+
Value for the phase. The default is ``0``.
|
|
345
|
+
source_name : str, optional
|
|
346
|
+
Name of the source. The default is ``""``.
|
|
347
|
+
|
|
348
|
+
Returns
|
|
349
|
+
-------
|
|
350
|
+
str
|
|
351
|
+
Source Name.
|
|
352
|
+
|
|
353
|
+
Examples
|
|
354
|
+
--------
|
|
355
|
+
|
|
356
|
+
>>> from pyedb import Edb
|
|
357
|
+
>>> edbapp = Edb("myaedbfolder", "project name", "release version")
|
|
358
|
+
>>> edb.hfss.create_voltage_source_on_net("U2A5", "V1P5_S3", "U2A5", "GND", 3.3, 0, "source_name")
|
|
359
|
+
"""
|
|
360
|
+
return self._pedb.siwave.create_voltage_source_on_net(
|
|
361
|
+
positive_component_name,
|
|
362
|
+
positive_net_name,
|
|
363
|
+
negative_component_name,
|
|
364
|
+
negative_net_name,
|
|
365
|
+
voltage_value,
|
|
366
|
+
phase_value,
|
|
367
|
+
source_name,
|
|
368
|
+
)
|
|
369
|
+
|
|
370
|
+
@pyedb_function_handler()
|
|
371
|
+
def create_current_source_on_net(
|
|
372
|
+
self,
|
|
373
|
+
positive_component_name,
|
|
374
|
+
positive_net_name,
|
|
375
|
+
negative_component_name=None,
|
|
376
|
+
negative_net_name="GND",
|
|
377
|
+
current_value=0.1,
|
|
378
|
+
phase_value=0,
|
|
379
|
+
source_name="",
|
|
380
|
+
):
|
|
381
|
+
"""Create a current source.
|
|
382
|
+
|
|
383
|
+
Parameters
|
|
384
|
+
----------
|
|
385
|
+
positive_component_name : str
|
|
386
|
+
Name of the positive component.
|
|
387
|
+
positive_net_name : str
|
|
388
|
+
Name of the positive net.
|
|
389
|
+
negative_component_name : str, optional
|
|
390
|
+
Name of the negative component. The default is ``None``, in which case the name of
|
|
391
|
+
the positive net is assigned.
|
|
392
|
+
negative_net_name : str, optional
|
|
393
|
+
Name of the negative net. The default is ``"GND"``.
|
|
394
|
+
current_value : float, optional
|
|
395
|
+
Value for the current. The default is ``0.1``.
|
|
396
|
+
phase_value : optional
|
|
397
|
+
Value for the phase. The default is ``0``.
|
|
398
|
+
source_name : str, optional
|
|
399
|
+
Name of the source. The default is ``""``.
|
|
400
|
+
|
|
401
|
+
Returns
|
|
402
|
+
-------
|
|
403
|
+
str
|
|
404
|
+
Source Name.
|
|
405
|
+
|
|
406
|
+
Examples
|
|
407
|
+
--------
|
|
408
|
+
|
|
409
|
+
>>> from pyedb import Edb
|
|
410
|
+
>>> edbapp = Edb("myaedbfolder", "project name", "release version")
|
|
411
|
+
>>> edb.hfss.create_current_source_on_net("U2A5", "V1P5_S3", "U2A5", "GND", 0.1, 0, "source_name")
|
|
412
|
+
"""
|
|
413
|
+
return self._pedb.siwave.create_current_source_on_net(
|
|
414
|
+
positive_component_name,
|
|
415
|
+
positive_net_name,
|
|
416
|
+
negative_component_name,
|
|
417
|
+
negative_net_name,
|
|
418
|
+
current_value,
|
|
419
|
+
phase_value,
|
|
420
|
+
source_name,
|
|
421
|
+
)
|
|
422
|
+
|
|
423
|
+
@pyedb_function_handler()
|
|
424
|
+
def create_coax_port_on_component(self, ref_des_list, net_list):
|
|
425
|
+
"""Create a coaxial port on a component or component list on a net or net list.
|
|
426
|
+
The name of the new coaxial port is automatically assigned.
|
|
427
|
+
|
|
428
|
+
Parameters
|
|
429
|
+
----------
|
|
430
|
+
ref_des_list : list, str
|
|
431
|
+
List of one or more reference designators.
|
|
432
|
+
|
|
433
|
+
net_list : list, str
|
|
434
|
+
List of one or more nets.
|
|
435
|
+
|
|
436
|
+
Returns
|
|
437
|
+
-------
|
|
438
|
+
bool
|
|
439
|
+
``True`` when successful, ``False`` when failed.
|
|
440
|
+
|
|
441
|
+
"""
|
|
442
|
+
coax = []
|
|
443
|
+
if not isinstance(ref_des_list, list):
|
|
444
|
+
ref_des_list = [ref_des_list]
|
|
445
|
+
if not isinstance(net_list, list):
|
|
446
|
+
net_list = [net_list]
|
|
447
|
+
for ref in ref_des_list:
|
|
448
|
+
for _, py_inst in self._pedb.components.components[ref].pins.items():
|
|
449
|
+
if py_inst.net_name in net_list and py_inst.is_pin:
|
|
450
|
+
port_name = "{}_{}_{}".format(ref, py_inst.net_name, py_inst.pin.GetName())
|
|
451
|
+
(
|
|
452
|
+
res,
|
|
453
|
+
from_layer_pos,
|
|
454
|
+
to_layer_pos,
|
|
455
|
+
) = py_inst.pin.GetLayerRange()
|
|
456
|
+
if (
|
|
457
|
+
res
|
|
458
|
+
and from_layer_pos
|
|
459
|
+
and self._edb.cell.terminal.PadstackInstanceTerminal.Create(
|
|
460
|
+
self._active_layout,
|
|
461
|
+
py_inst.pin.GetNet(),
|
|
462
|
+
port_name,
|
|
463
|
+
py_inst.pin,
|
|
464
|
+
to_layer_pos,
|
|
465
|
+
)
|
|
466
|
+
):
|
|
467
|
+
coax.append(port_name)
|
|
468
|
+
return coax
|
|
469
|
+
|
|
470
|
+
@pyedb_function_handler()
|
|
471
|
+
def create_differential_wave_port(
|
|
472
|
+
self,
|
|
473
|
+
positive_primitive_id,
|
|
474
|
+
positive_points_on_edge,
|
|
475
|
+
negative_primitive_id,
|
|
476
|
+
negative_points_on_edge,
|
|
477
|
+
port_name=None,
|
|
478
|
+
horizontal_extent_factor=5,
|
|
479
|
+
vertical_extent_factor=3,
|
|
480
|
+
pec_launch_width="0.01mm",
|
|
481
|
+
):
|
|
482
|
+
"""Create a differential wave port.
|
|
483
|
+
|
|
484
|
+
Parameters
|
|
485
|
+
----------
|
|
486
|
+
positive_primitive_id : int, EDBPrimitives
|
|
487
|
+
Primitive ID of the positive terminal.
|
|
488
|
+
positive_points_on_edge : list
|
|
489
|
+
Coordinate of the point to define the edge terminal.
|
|
490
|
+
The point must be close to the target edge but not on the two
|
|
491
|
+
ends of the edge.
|
|
492
|
+
negative_primitive_id : int, EDBPrimitives
|
|
493
|
+
Primitive ID of the negative terminal.
|
|
494
|
+
negative_points_on_edge : list
|
|
495
|
+
Coordinate of the point to define the edge terminal.
|
|
496
|
+
The point must be close to the target edge but not on the two
|
|
497
|
+
ends of the edge.
|
|
498
|
+
port_name : str, optional
|
|
499
|
+
Name of the port. The default is ``None``.
|
|
500
|
+
horizontal_extent_factor : int, float, optional
|
|
501
|
+
Horizontal extent factor. The default value is ``5``.
|
|
502
|
+
vertical_extent_factor : int, float, optional
|
|
503
|
+
Vertical extent factor. The default value is ``3``.
|
|
504
|
+
pec_launch_width : str, optional
|
|
505
|
+
Launch Width of PEC. The default value is ``"0.01mm"``.
|
|
506
|
+
|
|
507
|
+
Returns
|
|
508
|
+
-------
|
|
509
|
+
tuple
|
|
510
|
+
The tuple contains: (port_name, pyedb.dotnet.edb_core.edb_data.sources.ExcitationDifferential).
|
|
511
|
+
|
|
512
|
+
Examples
|
|
513
|
+
--------
|
|
514
|
+
>>> edb.hfss.create_differential_wave_port(0, ["-50mm", "-0mm"], 1, ["-50mm", "-0.2mm"])
|
|
515
|
+
"""
|
|
516
|
+
if not port_name:
|
|
517
|
+
port_name = generate_unique_name("diff")
|
|
518
|
+
|
|
519
|
+
if isinstance(positive_primitive_id, EDBPrimitives):
|
|
520
|
+
positive_primitive_id = positive_primitive_id.id
|
|
521
|
+
|
|
522
|
+
if isinstance(negative_primitive_id, EDBPrimitives):
|
|
523
|
+
negative_primitive_id = negative_primitive_id.id
|
|
524
|
+
|
|
525
|
+
_, pos_term = self.create_wave_port(
|
|
526
|
+
positive_primitive_id,
|
|
527
|
+
positive_points_on_edge,
|
|
528
|
+
horizontal_extent_factor=horizontal_extent_factor,
|
|
529
|
+
vertical_extent_factor=vertical_extent_factor,
|
|
530
|
+
pec_launch_width=pec_launch_width,
|
|
531
|
+
)
|
|
532
|
+
_, neg_term = self.create_wave_port(
|
|
533
|
+
negative_primitive_id,
|
|
534
|
+
negative_points_on_edge,
|
|
535
|
+
horizontal_extent_factor=horizontal_extent_factor,
|
|
536
|
+
vertical_extent_factor=vertical_extent_factor,
|
|
537
|
+
pec_launch_width=pec_launch_width,
|
|
538
|
+
)
|
|
539
|
+
edb_list = convert_py_list_to_net_list(
|
|
540
|
+
[pos_term._edb_object, neg_term._edb_object], self._edb.cell.terminal.Terminal
|
|
541
|
+
)
|
|
542
|
+
_edb_boundle_terminal = self._edb.cell.terminal.BundleTerminal.Create(edb_list)
|
|
543
|
+
# _edb_boundle_terminal.SetName("Wave_"+port_name)
|
|
544
|
+
pos_term._edb_object.SetName(port_name)
|
|
545
|
+
return port_name, BundleWavePort(self._pedb, _edb_boundle_terminal)
|
|
546
|
+
|
|
547
|
+
@pyedb_function_handler()
|
|
548
|
+
def create_bundle_wave_port(
|
|
549
|
+
self,
|
|
550
|
+
primitives_id,
|
|
551
|
+
points_on_edge,
|
|
552
|
+
port_name=None,
|
|
553
|
+
horizontal_extent_factor=5,
|
|
554
|
+
vertical_extent_factor=3,
|
|
555
|
+
pec_launch_width="0.01mm",
|
|
556
|
+
):
|
|
557
|
+
"""Create a bundle wave port.
|
|
558
|
+
|
|
559
|
+
Parameters
|
|
560
|
+
----------
|
|
561
|
+
primitives_id : list
|
|
562
|
+
Primitive ID of the positive terminal.
|
|
563
|
+
points_on_edge : list
|
|
564
|
+
Coordinate of the point to define the edge terminal.
|
|
565
|
+
The point must be close to the target edge but not on the two
|
|
566
|
+
ends of the edge.
|
|
567
|
+
port_name : str, optional
|
|
568
|
+
Name of the port. The default is ``None``.
|
|
569
|
+
horizontal_extent_factor : int, float, optional
|
|
570
|
+
Horizontal extent factor. The default value is ``5``.
|
|
571
|
+
vertical_extent_factor : int, float, optional
|
|
572
|
+
Vertical extent factor. The default value is ``3``.
|
|
573
|
+
pec_launch_width : str, optional
|
|
574
|
+
Launch Width of PEC. The default value is ``"0.01mm"``.
|
|
575
|
+
|
|
576
|
+
Returns
|
|
577
|
+
-------
|
|
578
|
+
tuple
|
|
579
|
+
The tuple contains: (port_name, pyedb.egacy.edb_core.edb_data.sources.ExcitationDifferential).
|
|
580
|
+
|
|
581
|
+
Examples
|
|
582
|
+
--------
|
|
583
|
+
>>> edb.hfss.create_bundle_wave_port(0, ["-50mm", "-0mm"], 1, ["-50mm", "-0.2mm"])
|
|
584
|
+
"""
|
|
585
|
+
if not port_name:
|
|
586
|
+
port_name = generate_unique_name("bundle_port")
|
|
587
|
+
|
|
588
|
+
if isinstance(primitives_id[0], EDBPrimitives):
|
|
589
|
+
primitives_id = [i.id for i in primitives_id]
|
|
590
|
+
|
|
591
|
+
terminals = []
|
|
592
|
+
_port_name = port_name
|
|
593
|
+
for p_id, loc in list(zip(primitives_id, points_on_edge)):
|
|
594
|
+
_, term = self.create_wave_port(
|
|
595
|
+
p_id,
|
|
596
|
+
loc,
|
|
597
|
+
port_name=_port_name,
|
|
598
|
+
horizontal_extent_factor=horizontal_extent_factor,
|
|
599
|
+
vertical_extent_factor=vertical_extent_factor,
|
|
600
|
+
pec_launch_width=pec_launch_width,
|
|
601
|
+
)
|
|
602
|
+
_port_name = None
|
|
603
|
+
terminals.append(term)
|
|
604
|
+
|
|
605
|
+
edb_list = convert_py_list_to_net_list([i._edb_object for i in terminals], self._edb.cell.terminal.Terminal)
|
|
606
|
+
_edb_bundle_terminal = self._edb.cell.terminal.BundleTerminal.Create(edb_list)
|
|
607
|
+
return port_name, BundleWavePort(self._pedb, _edb_bundle_terminal)
|
|
608
|
+
|
|
609
|
+
@pyedb_function_handler()
|
|
610
|
+
def create_hfss_ports_on_padstack(self, pinpos, portname=None):
|
|
611
|
+
"""Create an HFSS port on a padstack.
|
|
612
|
+
|
|
613
|
+
Parameters
|
|
614
|
+
----------
|
|
615
|
+
pinpos :
|
|
616
|
+
Position of the pin.
|
|
617
|
+
|
|
618
|
+
portname : str, optional
|
|
619
|
+
Name of the port. The default is ``None``.
|
|
620
|
+
|
|
621
|
+
Returns
|
|
622
|
+
-------
|
|
623
|
+
bool
|
|
624
|
+
``True`` when successful, ``False`` when failed.
|
|
625
|
+
"""
|
|
626
|
+
res, fromLayer_pos, toLayer_pos = pinpos.GetLayerRange()
|
|
627
|
+
|
|
628
|
+
if not portname:
|
|
629
|
+
portname = generate_unique_name("Port_" + pinpos.GetNet().GetName())
|
|
630
|
+
edbpointTerm_pos = self._edb.cell.terminal.PadstackInstanceTerminal.Create(
|
|
631
|
+
self._active_layout, pinpos.GetNet(), portname, pinpos, toLayer_pos
|
|
632
|
+
)
|
|
633
|
+
if edbpointTerm_pos:
|
|
634
|
+
return True
|
|
635
|
+
else:
|
|
636
|
+
return False
|
|
637
|
+
|
|
638
|
+
@pyedb_function_handler()
|
|
639
|
+
def create_edge_port_on_polygon(
|
|
640
|
+
self,
|
|
641
|
+
polygon=None,
|
|
642
|
+
reference_polygon=None,
|
|
643
|
+
terminal_point=None,
|
|
644
|
+
reference_point=None,
|
|
645
|
+
reference_layer=None,
|
|
646
|
+
port_name=None,
|
|
647
|
+
port_impedance=50.0,
|
|
648
|
+
force_circuit_port=False,
|
|
649
|
+
):
|
|
650
|
+
"""Create lumped port between two edges from two different polygons. Can also create a vertical port when
|
|
651
|
+
the reference layer name is only provided. When a port is created between two edge from two polygons which don't
|
|
652
|
+
belong to the same layer, a circuit port will be automatically created instead of lumped. To enforce the circuit
|
|
653
|
+
port instead of lumped,use the boolean force_circuit_port.
|
|
654
|
+
|
|
655
|
+
Parameters
|
|
656
|
+
----------
|
|
657
|
+
polygon : The EDB polygon object used to assign the port.
|
|
658
|
+
Edb.Cell.Primitive.Polygon object.
|
|
659
|
+
|
|
660
|
+
reference_polygon : The EDB polygon object used to define the port reference.
|
|
661
|
+
Edb.Cell.Primitive.Polygon object.
|
|
662
|
+
|
|
663
|
+
terminal_point : The coordinate of the point to define the edge terminal of the port. This point must be
|
|
664
|
+
located on the edge of the polygon where the port has to be placed. For instance taking the middle point
|
|
665
|
+
of an edge is a good practice but any point of the edge should be valid. Taking a corner might cause unwanted
|
|
666
|
+
port location.
|
|
667
|
+
list[float, float] with values provided in meter.
|
|
668
|
+
|
|
669
|
+
reference_point : same as terminal_point but used for defining the reference location on the edge.
|
|
670
|
+
list[float, float] with values provided in meter.
|
|
671
|
+
|
|
672
|
+
reference_layer : Name used to define port reference for vertical ports.
|
|
673
|
+
str the layer name.
|
|
674
|
+
|
|
675
|
+
port_name : Name of the port.
|
|
676
|
+
str.
|
|
677
|
+
|
|
678
|
+
port_impedance : port impedance value. Default value is 50 Ohms.
|
|
679
|
+
float, impedance value.
|
|
680
|
+
|
|
681
|
+
force_circuit_port ; used to force circuit port creation instead of lumped. Works for vertical and coplanar
|
|
682
|
+
ports.
|
|
683
|
+
|
|
684
|
+
Examples
|
|
685
|
+
--------
|
|
686
|
+
|
|
687
|
+
>>> edb_path = path_to_edb
|
|
688
|
+
>>> edb = Edb(edb_path)
|
|
689
|
+
>>> poly_list = [poly for poly in list(edb.layout.primitives) if poly.GetPrimitiveType() == 2]
|
|
690
|
+
>>> port_poly = [poly for poly in poly_list if poly.GetId() == 17][0]
|
|
691
|
+
>>> ref_poly = [poly for poly in poly_list if poly.GetId() == 19][0]
|
|
692
|
+
>>> port_location = [-65e-3, -13e-3]
|
|
693
|
+
>>> ref_location = [-63e-3, -13e-3]
|
|
694
|
+
>>> edb.hfss.create_edge_port_on_polygon(polygon=port_poly, reference_polygon=ref_poly,
|
|
695
|
+
>>> terminal_point=port_location, reference_point=ref_location)
|
|
696
|
+
|
|
697
|
+
"""
|
|
698
|
+
if not polygon:
|
|
699
|
+
self._logger.error("No polygon provided for port {} creation".format(port_name))
|
|
700
|
+
return False
|
|
701
|
+
if reference_layer:
|
|
702
|
+
reference_layer = self._pedb.stackup.signal_layers[reference_layer]._edb_layer
|
|
703
|
+
if not reference_layer:
|
|
704
|
+
self._logger.error("Specified layer for port {} creation was not found".format(port_name))
|
|
705
|
+
if not isinstance(terminal_point, list):
|
|
706
|
+
self._logger.error("Terminal point must be a list of float with providing the point location in meter")
|
|
707
|
+
return False
|
|
708
|
+
terminal_point = self._edb.geometry.point_data(
|
|
709
|
+
self._get_edb_value(terminal_point[0]), self._get_edb_value(terminal_point[1])
|
|
710
|
+
)
|
|
711
|
+
if reference_point and isinstance(reference_point, list):
|
|
712
|
+
reference_point = self._edb.geometry.point_data(
|
|
713
|
+
self._get_edb_value(reference_point[0]), self._get_edb_value(reference_point[1])
|
|
714
|
+
)
|
|
715
|
+
if not port_name:
|
|
716
|
+
port_name = generate_unique_name("Port_")
|
|
717
|
+
edge = self._edb.cell.terminal.PrimitiveEdge.Create(polygon.prim_obj, terminal_point)
|
|
718
|
+
edges = convert_py_list_to_net_list(edge, self._edb.cell.terminal.Edge)
|
|
719
|
+
edge_term = self._edb.cell.terminal.EdgeTerminal.Create(
|
|
720
|
+
polygon.GetLayout(), polygon.GetNet(), port_name, edges, isRef=False
|
|
721
|
+
)
|
|
722
|
+
if force_circuit_port:
|
|
723
|
+
edge_term.SetIsCircuitPort(True)
|
|
724
|
+
else:
|
|
725
|
+
edge_term.SetIsCircuitPort(False)
|
|
726
|
+
|
|
727
|
+
if port_impedance:
|
|
728
|
+
edge_term.SetImpedance(self._pedb.edb_value(port_impedance))
|
|
729
|
+
edge_term.SetName(port_name)
|
|
730
|
+
if reference_polygon and reference_point:
|
|
731
|
+
ref_edge = self._edb.cell.terminal.PrimitiveEdge.Create(reference_polygon.prim_obj, reference_point)
|
|
732
|
+
ref_edges = convert_py_list_to_net_list(ref_edge, self._edb.cell.terminal.Edge)
|
|
733
|
+
ref_edge_term = self._edb.cell.terminal.EdgeTerminal.Create(
|
|
734
|
+
reference_polygon.GetLayout(), reference_polygon.GetNet(), port_name + "_ref", ref_edges, isRef=True
|
|
735
|
+
)
|
|
736
|
+
if reference_layer:
|
|
737
|
+
ref_edge_term.SetReferenceLayer(reference_layer)
|
|
738
|
+
if force_circuit_port:
|
|
739
|
+
ref_edge_term.SetIsCircuitPort(True)
|
|
740
|
+
else:
|
|
741
|
+
ref_edge_term.SetIsCircuitPort(False)
|
|
742
|
+
|
|
743
|
+
if port_impedance:
|
|
744
|
+
ref_edge_term.SetImpedance(self._pedb.edb_value(port_impedance))
|
|
745
|
+
edge_term.SetReferenceTerminal(ref_edge_term)
|
|
746
|
+
return True
|
|
747
|
+
|
|
748
|
+
@pyedb_function_handler()
|
|
749
|
+
def create_wave_port(
|
|
750
|
+
self,
|
|
751
|
+
prim_id,
|
|
752
|
+
point_on_edge,
|
|
753
|
+
port_name=None,
|
|
754
|
+
impedance=50,
|
|
755
|
+
horizontal_extent_factor=5,
|
|
756
|
+
vertical_extent_factor=3,
|
|
757
|
+
pec_launch_width="0.01mm",
|
|
758
|
+
):
|
|
759
|
+
"""Create a wave port.
|
|
760
|
+
|
|
761
|
+
Parameters
|
|
762
|
+
----------
|
|
763
|
+
prim_id : int, EDBPrimitives
|
|
764
|
+
Primitive ID.
|
|
765
|
+
point_on_edge : list
|
|
766
|
+
Coordinate of the point to define the edge terminal.
|
|
767
|
+
The point must be on the target edge but not on the two
|
|
768
|
+
ends of the edge.
|
|
769
|
+
port_name : str, optional
|
|
770
|
+
Name of the port. The default is ``None``.
|
|
771
|
+
impedance : int, float, optional
|
|
772
|
+
Impedance of the port. The default value is ``50``.
|
|
773
|
+
horizontal_extent_factor : int, float, optional
|
|
774
|
+
Horizontal extent factor. The default value is ``5``.
|
|
775
|
+
vertical_extent_factor : int, float, optional
|
|
776
|
+
Vertical extent factor. The default value is ``3``.
|
|
777
|
+
pec_launch_width : str, optional
|
|
778
|
+
Launch Width of PEC. The default value is ``"0.01mm"``.
|
|
779
|
+
|
|
780
|
+
Returns
|
|
781
|
+
-------
|
|
782
|
+
tuple
|
|
783
|
+
The tuple contains: (Port name, pyedb.dotnet.edb_core.edb_data.sources.Excitation).
|
|
784
|
+
|
|
785
|
+
Examples
|
|
786
|
+
--------
|
|
787
|
+
>>> edb.hfss.create_wave_port(0, ["-50mm", "-0mm"])
|
|
788
|
+
"""
|
|
789
|
+
if not port_name:
|
|
790
|
+
port_name = generate_unique_name("Terminal_")
|
|
791
|
+
|
|
792
|
+
if isinstance(prim_id, EDBPrimitives):
|
|
793
|
+
prim_id = prim_id.id
|
|
794
|
+
|
|
795
|
+
pos_edge_term = self._create_edge_terminal(prim_id, point_on_edge, port_name)
|
|
796
|
+
pos_edge_term.SetImpedance(self._pedb.edb_value(impedance))
|
|
797
|
+
|
|
798
|
+
wave_port = WavePort(self._pedb, pos_edge_term)
|
|
799
|
+
wave_port.horizontal_extent_factor = horizontal_extent_factor
|
|
800
|
+
wave_port.vertical_extent_factor = vertical_extent_factor
|
|
801
|
+
wave_port.pec_launch_width = pec_launch_width
|
|
802
|
+
wave_port.hfss_type = "Wave"
|
|
803
|
+
wave_port.do_renormalize = True
|
|
804
|
+
if pos_edge_term:
|
|
805
|
+
return port_name, wave_port
|
|
806
|
+
else:
|
|
807
|
+
return False
|
|
808
|
+
|
|
809
|
+
@pyedb_function_handler()
|
|
810
|
+
def create_edge_port_vertical(
|
|
811
|
+
self,
|
|
812
|
+
prim_id,
|
|
813
|
+
point_on_edge,
|
|
814
|
+
port_name=None,
|
|
815
|
+
impedance=50,
|
|
816
|
+
reference_layer=None,
|
|
817
|
+
hfss_type="Gap",
|
|
818
|
+
horizontal_extent_factor=5,
|
|
819
|
+
vertical_extent_factor=3,
|
|
820
|
+
pec_launch_width="0.01mm",
|
|
821
|
+
):
|
|
822
|
+
"""Create a vertical edge port.
|
|
823
|
+
|
|
824
|
+
Parameters
|
|
825
|
+
----------
|
|
826
|
+
prim_id : int
|
|
827
|
+
Primitive ID.
|
|
828
|
+
point_on_edge : list
|
|
829
|
+
Coordinate of the point to define the edge terminal.
|
|
830
|
+
The point must be on the target edge but not on the two
|
|
831
|
+
ends of the edge.
|
|
832
|
+
port_name : str, optional
|
|
833
|
+
Name of the port. The default is ``None``.
|
|
834
|
+
impedance : int, float, optional
|
|
835
|
+
Impedance of the port. The default value is ``50``.
|
|
836
|
+
reference_layer : str, optional
|
|
837
|
+
Reference layer of the port. The default is ``None``.
|
|
838
|
+
hfss_type : str, optional
|
|
839
|
+
Type of the port. The default value is ``"Gap"``. Options are ``"Gap"``, ``"Wave"``.
|
|
840
|
+
horizontal_extent_factor : int, float, optional
|
|
841
|
+
Horizontal extent factor. The default value is ``5``.
|
|
842
|
+
vertical_extent_factor : int, float, optional
|
|
843
|
+
Vertical extent factor. The default value is ``3``.
|
|
844
|
+
radial_extent_factor : int, float, optional
|
|
845
|
+
Radial extent factor. The default value is ``0``.
|
|
846
|
+
pec_launch_width : str, optional
|
|
847
|
+
Launch Width of PEC. The default value is ``"0.01mm"``.
|
|
848
|
+
|
|
849
|
+
Returns
|
|
850
|
+
-------
|
|
851
|
+
str
|
|
852
|
+
Port name.
|
|
853
|
+
"""
|
|
854
|
+
if not port_name:
|
|
855
|
+
port_name = generate_unique_name("Terminal_")
|
|
856
|
+
pos_edge_term = self._create_edge_terminal(prim_id, point_on_edge, port_name)
|
|
857
|
+
pos_edge_term.SetImpedance(self._pedb.edb_value(impedance))
|
|
858
|
+
if reference_layer:
|
|
859
|
+
reference_layer = self._pedb.stackup.signal_layers[reference_layer]._edb_layer
|
|
860
|
+
pos_edge_term.SetReferenceLayer(reference_layer)
|
|
861
|
+
|
|
862
|
+
prop = ", ".join(
|
|
863
|
+
[
|
|
864
|
+
"HFSS('HFSS Type'='{}'".format(hfss_type),
|
|
865
|
+
" Orientation='Vertical'",
|
|
866
|
+
" 'Layer Alignment'='Upper'",
|
|
867
|
+
" 'Horizontal Extent Factor'='{}'".format(horizontal_extent_factor),
|
|
868
|
+
" 'Vertical Extent Factor'='{}'".format(vertical_extent_factor),
|
|
869
|
+
" 'PEC Launch Width'='{}')".format(pec_launch_width),
|
|
870
|
+
]
|
|
871
|
+
)
|
|
872
|
+
pos_edge_term.SetProductSolverOption(
|
|
873
|
+
self._pedb.edb_api.ProductId.Designer,
|
|
874
|
+
"HFSS",
|
|
875
|
+
prop,
|
|
876
|
+
)
|
|
877
|
+
if pos_edge_term:
|
|
878
|
+
return port_name, self._pedb.hfss.excitations[port_name]
|
|
879
|
+
else:
|
|
880
|
+
return False
|
|
881
|
+
|
|
882
|
+
@pyedb_function_handler()
|
|
883
|
+
def create_edge_port_horizontal(
|
|
884
|
+
self,
|
|
885
|
+
prim_id,
|
|
886
|
+
point_on_edge,
|
|
887
|
+
ref_prim_id=None,
|
|
888
|
+
point_on_ref_edge=None,
|
|
889
|
+
port_name=None,
|
|
890
|
+
impedance=50,
|
|
891
|
+
layer_alignment="Upper",
|
|
892
|
+
):
|
|
893
|
+
"""Create a horizontal edge port.
|
|
894
|
+
|
|
895
|
+
Parameters
|
|
896
|
+
----------
|
|
897
|
+
prim_id : int
|
|
898
|
+
Primitive ID.
|
|
899
|
+
point_on_edge : list
|
|
900
|
+
Coordinate of the point to define the edge terminal.
|
|
901
|
+
The point must be on the target edge but not on the two
|
|
902
|
+
ends of the edge.
|
|
903
|
+
ref_prim_id : int, optional
|
|
904
|
+
Reference primitive ID. The default is ``None``.
|
|
905
|
+
point_on_ref_edge : list, optional
|
|
906
|
+
Coordinate of the point to define the reference edge
|
|
907
|
+
terminal. The point must be on the target edge but not
|
|
908
|
+
on the two ends of the edge. The default is ``None``.
|
|
909
|
+
port_name : str, optional
|
|
910
|
+
Name of the port. The default is ``None``.
|
|
911
|
+
impedance : int, float, optional
|
|
912
|
+
Impedance of the port. The default value is ``50``.
|
|
913
|
+
layer_alignment : str, optional
|
|
914
|
+
Layer alignment. The default value is ``Upper``. Options are ``"Upper"``, ``"Lower"``.
|
|
915
|
+
|
|
916
|
+
Returns
|
|
917
|
+
-------
|
|
918
|
+
str
|
|
919
|
+
Name of the port.
|
|
920
|
+
"""
|
|
921
|
+
pos_edge_term = self._create_edge_terminal(prim_id, point_on_edge, port_name)
|
|
922
|
+
neg_edge_term = self._create_edge_terminal(ref_prim_id, point_on_ref_edge, port_name + "_ref", is_ref=True)
|
|
923
|
+
|
|
924
|
+
pos_edge_term.SetImpedance(self._pedb.edb_value(impedance))
|
|
925
|
+
pos_edge_term.SetReferenceTerminal(neg_edge_term)
|
|
926
|
+
if not layer_alignment == "Upper":
|
|
927
|
+
layer_alignment = "Lower"
|
|
928
|
+
pos_edge_term.SetProductSolverOption(
|
|
929
|
+
self._pedb.edb_api.ProductId.Designer,
|
|
930
|
+
"HFSS",
|
|
931
|
+
"HFSS('HFSS Type'='Gap(coax)', Orientation='Horizontal', 'Layer Alignment'='{}')".format(layer_alignment),
|
|
932
|
+
)
|
|
933
|
+
if pos_edge_term:
|
|
934
|
+
return port_name
|
|
935
|
+
else:
|
|
936
|
+
return False
|
|
937
|
+
|
|
938
|
+
@pyedb_function_handler()
|
|
939
|
+
def create_lumped_port_on_net(
|
|
940
|
+
self, nets=None, reference_layer=None, return_points_only=False, digit_resolution=6, at_bounding_box=True
|
|
941
|
+
):
|
|
942
|
+
"""Create an edge port on nets. This command looks for traces and polygons on the
|
|
943
|
+
nets and tries to assign vertical lumped port.
|
|
944
|
+
|
|
945
|
+
Parameters
|
|
946
|
+
----------
|
|
947
|
+
nets : list, optional
|
|
948
|
+
List of nets, str or Edb net.
|
|
949
|
+
|
|
950
|
+
reference_layer : str, Edb layer.
|
|
951
|
+
Name or Edb layer object.
|
|
952
|
+
|
|
953
|
+
return_points_only : bool, optional
|
|
954
|
+
Use this boolean when you want to return only the points from the edges and not creating ports. Default
|
|
955
|
+
value is ``False``.
|
|
956
|
+
|
|
957
|
+
digit_resolution : int, optional
|
|
958
|
+
The number of digits carried for the edge location accuracy. The default value is ``6``.
|
|
959
|
+
|
|
960
|
+
at_bounding_box : bool
|
|
961
|
+
When ``True`` will keep the edges from traces at the layout bounding box location. This is recommended when
|
|
962
|
+
a cutout has been performed before and lumped ports have to be created on ending traces. Default value is
|
|
963
|
+
``True``.
|
|
964
|
+
|
|
965
|
+
Returns
|
|
966
|
+
-------
|
|
967
|
+
bool
|
|
968
|
+
``True`` when successful, ``False`` when failed.
|
|
969
|
+
"""
|
|
970
|
+
if not isinstance(nets, list):
|
|
971
|
+
if isinstance(nets, str):
|
|
972
|
+
nets = [self._edb.cell.net.find_by_name(self._active_layout, nets)]
|
|
973
|
+
elif isinstance(nets, self._edb.cell.net.net):
|
|
974
|
+
nets = [nets]
|
|
975
|
+
else:
|
|
976
|
+
temp_nets = []
|
|
977
|
+
for nn in nets:
|
|
978
|
+
if isinstance(nn, str):
|
|
979
|
+
temp_nets.append(self._edb.cell.net.find_by_name(self._active_layout, nn))
|
|
980
|
+
elif isinstance(nn, self._edb.cell.net.net):
|
|
981
|
+
temp_nets.append(nn)
|
|
982
|
+
nets = temp_nets
|
|
983
|
+
port_created = False
|
|
984
|
+
if nets:
|
|
985
|
+
edges_pts = []
|
|
986
|
+
if isinstance(reference_layer, str):
|
|
987
|
+
try:
|
|
988
|
+
reference_layer = self._pedb.stackup.signal_layers[reference_layer]._edb_layer
|
|
989
|
+
except:
|
|
990
|
+
raise Exception("Failed to get the layer {}".format(reference_layer))
|
|
991
|
+
if not isinstance(reference_layer, self._edb.Cell.ILayerReadOnly):
|
|
992
|
+
return False
|
|
993
|
+
layout = nets[0].GetLayout()
|
|
994
|
+
layout_bbox = self._pedb.get_conformal_polygon_from_netlist(self._pedb.nets.netlist)
|
|
995
|
+
layout_extent_segments = [pt for pt in list(layout_bbox.GetArcData()) if pt.IsSegment()]
|
|
996
|
+
first_pt = layout_extent_segments[0]
|
|
997
|
+
layout_extent_points = [
|
|
998
|
+
[first_pt.Start.X.ToDouble(), first_pt.End.X.ToDouble()],
|
|
999
|
+
[first_pt.Start.Y.ToDouble(), first_pt.End.Y.ToDouble()],
|
|
1000
|
+
]
|
|
1001
|
+
for segment in layout_extent_segments[1:]:
|
|
1002
|
+
end_point = (segment.End.X.ToDouble(), segment.End.Y.ToDouble())
|
|
1003
|
+
layout_extent_points[0].append(end_point[0])
|
|
1004
|
+
layout_extent_points[1].append(end_point[1])
|
|
1005
|
+
for net in nets:
|
|
1006
|
+
net_primitives = self._pedb.nets[net.name].primitives
|
|
1007
|
+
net_paths = [pp for pp in net_primitives if pp.type == "Path"]
|
|
1008
|
+
for path in net_paths:
|
|
1009
|
+
trace_path_pts = list(path.center_line.Points)
|
|
1010
|
+
port_name = "{}_{}".format(net.name, path.GetId())
|
|
1011
|
+
for pt in trace_path_pts:
|
|
1012
|
+
_pt = [
|
|
1013
|
+
round(pt.X.ToDouble(), digit_resolution),
|
|
1014
|
+
round(pt.Y.ToDouble(), digit_resolution),
|
|
1015
|
+
]
|
|
1016
|
+
if at_bounding_box:
|
|
1017
|
+
if GeometryOperators.point_in_polygon(_pt, layout_extent_points) == 0:
|
|
1018
|
+
if return_points_only:
|
|
1019
|
+
edges_pts.append(_pt)
|
|
1020
|
+
else:
|
|
1021
|
+
term = self._create_edge_terminal(path.id, pt, port_name) # pragma no cover
|
|
1022
|
+
term.SetReferenceLayer(reference_layer) # pragma no cover
|
|
1023
|
+
port_created = True
|
|
1024
|
+
else:
|
|
1025
|
+
if return_points_only: # pragma: no cover
|
|
1026
|
+
edges_pts.append(_pt)
|
|
1027
|
+
else:
|
|
1028
|
+
term = self._create_edge_terminal(path.id, pt, port_name)
|
|
1029
|
+
term.SetReferenceLayer(reference_layer)
|
|
1030
|
+
port_created = True
|
|
1031
|
+
net_poly = [pp for pp in net_primitives if pp.type == "Polygon"]
|
|
1032
|
+
for poly in net_poly:
|
|
1033
|
+
poly_segment = [aa for aa in poly.arcs if aa.is_segment]
|
|
1034
|
+
for segment in poly_segment:
|
|
1035
|
+
if (
|
|
1036
|
+
GeometryOperators.point_in_polygon(
|
|
1037
|
+
[segment.mid_point.X.ToDouble(), segment.mid_point.Y.ToDouble()], layout_extent_points
|
|
1038
|
+
)
|
|
1039
|
+
== 0
|
|
1040
|
+
):
|
|
1041
|
+
if return_points_only:
|
|
1042
|
+
edges_pts.append(segment.mid_point)
|
|
1043
|
+
else:
|
|
1044
|
+
port_name = "{}_{}".format(net.name, poly.GetId())
|
|
1045
|
+
term = self._create_edge_terminal(
|
|
1046
|
+
poly.id, segment.mid_point, port_name
|
|
1047
|
+
) # pragma no cover
|
|
1048
|
+
term.SetReferenceLayer(reference_layer) # pragma no cover
|
|
1049
|
+
port_created = True
|
|
1050
|
+
if return_points_only:
|
|
1051
|
+
return edges_pts
|
|
1052
|
+
return port_created
|
|
1053
|
+
|
|
1054
|
+
@pyedb_function_handler()
|
|
1055
|
+
def create_vertical_circuit_port_on_clipped_traces(self, nets=None, reference_net=None, user_defined_extent=None):
|
|
1056
|
+
"""Create an edge port on clipped signal traces.
|
|
1057
|
+
|
|
1058
|
+
Parameters
|
|
1059
|
+
----------
|
|
1060
|
+
nets : list, optional
|
|
1061
|
+
String of one net or EDB net or a list of multiple nets or EDB nets.
|
|
1062
|
+
|
|
1063
|
+
reference_net : str, Edb net.
|
|
1064
|
+
Name or EDB reference net.
|
|
1065
|
+
|
|
1066
|
+
user_defined_extent : [x, y], EDB PolygonData
|
|
1067
|
+
Use this point list or PolygonData object to check if ports are at this polygon border.
|
|
1068
|
+
|
|
1069
|
+
Returns
|
|
1070
|
+
-------
|
|
1071
|
+
[[str]]
|
|
1072
|
+
Nested list of str, with net name as first value, X value for point at border, Y value for point at border,
|
|
1073
|
+
and terminal name.
|
|
1074
|
+
"""
|
|
1075
|
+
if not isinstance(nets, list):
|
|
1076
|
+
if isinstance(nets, str):
|
|
1077
|
+
nets = list(self._pedb.nets.signal.values())
|
|
1078
|
+
else:
|
|
1079
|
+
nets = [self._pedb.nets.signal[net] for net in nets]
|
|
1080
|
+
if nets:
|
|
1081
|
+
if isinstance(reference_net, str):
|
|
1082
|
+
reference_net = self._pedb.nets[reference_net]
|
|
1083
|
+
if not reference_net:
|
|
1084
|
+
self._logger.error("No reference net provided for creating port")
|
|
1085
|
+
return False
|
|
1086
|
+
if user_defined_extent:
|
|
1087
|
+
if isinstance(user_defined_extent, self._edb.Geometry.PolygonData):
|
|
1088
|
+
_points = [pt for pt in list(user_defined_extent.Points)]
|
|
1089
|
+
_x = []
|
|
1090
|
+
_y = []
|
|
1091
|
+
for pt in _points:
|
|
1092
|
+
if pt.X.ToDouble() < 1e100 and pt.Y.ToDouble() < 1e100:
|
|
1093
|
+
_x.append(pt.X.ToDouble())
|
|
1094
|
+
_y.append(pt.Y.ToDouble())
|
|
1095
|
+
user_defined_extent = [_x, _y]
|
|
1096
|
+
terminal_info = []
|
|
1097
|
+
for net in nets:
|
|
1098
|
+
net_polygons = [
|
|
1099
|
+
pp
|
|
1100
|
+
for pp in net.primitives
|
|
1101
|
+
if pp.GetPrimitiveType() == self._edb.cell.primitive.PrimitiveType.Polygon
|
|
1102
|
+
]
|
|
1103
|
+
for poly in net_polygons:
|
|
1104
|
+
mid_points = [[arc.mid_point.X.ToDouble(), arc.mid_point.Y.ToDouble()] for arc in poly.arcs]
|
|
1105
|
+
for mid_point in mid_points:
|
|
1106
|
+
if GeometryOperators.point_in_polygon(mid_point, user_defined_extent) == 0:
|
|
1107
|
+
port_name = generate_unique_name("{}_{}".format(poly.GetNet().GetName(), poly.GetId()))
|
|
1108
|
+
term = self._create_edge_terminal(poly.GetId(), mid_point, port_name) # pragma no cover
|
|
1109
|
+
if not term.IsNull():
|
|
1110
|
+
self._logger.info("Terminal {} created".format(term.GetName()))
|
|
1111
|
+
term.SetIsCircuitPort(True)
|
|
1112
|
+
terminal_info.append(
|
|
1113
|
+
[poly.GetNet().GetName(), mid_point[0], mid_point[1], term.GetName()]
|
|
1114
|
+
)
|
|
1115
|
+
mid_pt_data = self._edb.geometry.point_data(
|
|
1116
|
+
self._edb.utility.value(mid_point[0]), self._edb.utility.value(mid_point[1])
|
|
1117
|
+
)
|
|
1118
|
+
ref_prim = [
|
|
1119
|
+
prim
|
|
1120
|
+
for prim in reference_net.primitives
|
|
1121
|
+
if prim.polygon_data.edb_api.PointInPolygon(mid_pt_data)
|
|
1122
|
+
]
|
|
1123
|
+
if not ref_prim:
|
|
1124
|
+
self._logger.warning("no reference primitive found, trying to extend scanning area")
|
|
1125
|
+
scanning_zone = [
|
|
1126
|
+
(mid_point[0] - mid_point[0] * 1e-3, mid_point[1] - mid_point[1] * 1e-3),
|
|
1127
|
+
(mid_point[0] - mid_point[0] * 1e-3, mid_point[1] + mid_point[1] * 1e-3),
|
|
1128
|
+
(mid_point[0] + mid_point[0] * 1e-3, mid_point[1] + mid_point[1] * 1e-3),
|
|
1129
|
+
(mid_point[0] + mid_point[0] * 1e-3, mid_point[1] - mid_point[1] * 1e-3),
|
|
1130
|
+
]
|
|
1131
|
+
for new_point in scanning_zone:
|
|
1132
|
+
mid_pt_data = self._edb.geometry.point_data(
|
|
1133
|
+
self._edb.utility.value(new_point[0]), self._edb.utility.value(new_point[1])
|
|
1134
|
+
)
|
|
1135
|
+
ref_prim = [
|
|
1136
|
+
prim
|
|
1137
|
+
for prim in reference_net.primitives
|
|
1138
|
+
if prim.polygon_data.edb_api.PointInPolygon(mid_pt_data)
|
|
1139
|
+
]
|
|
1140
|
+
if ref_prim:
|
|
1141
|
+
self._logger.info("Reference primitive found")
|
|
1142
|
+
break
|
|
1143
|
+
if not ref_prim:
|
|
1144
|
+
self._logger.error("Failed to collect valid reference primitives for terminal")
|
|
1145
|
+
if ref_prim:
|
|
1146
|
+
reference_layer = ref_prim[0].layer
|
|
1147
|
+
if term.SetReferenceLayer(reference_layer): # pragma no cover
|
|
1148
|
+
self._logger.info("Port {} created".format(port_name))
|
|
1149
|
+
return terminal_info
|
|
1150
|
+
return False
|
|
1151
|
+
|
|
1152
|
+
@pyedb_function_handler()
|
|
1153
|
+
def get_layout_bounding_box(self, layout=None, digit_resolution=6):
|
|
1154
|
+
"""Evaluate the layout bounding box.
|
|
1155
|
+
|
|
1156
|
+
Parameters
|
|
1157
|
+
----------
|
|
1158
|
+
layout :
|
|
1159
|
+
Edb layout.
|
|
1160
|
+
|
|
1161
|
+
digit_resolution : int, optional
|
|
1162
|
+
Digit Resolution. The default value is ``6``.
|
|
1163
|
+
|
|
1164
|
+
Returns
|
|
1165
|
+
-------
|
|
1166
|
+
list
|
|
1167
|
+
[lower left corner X, lower left corner, upper right corner X, upper right corner Y].
|
|
1168
|
+
"""
|
|
1169
|
+
if layout == None:
|
|
1170
|
+
return False
|
|
1171
|
+
layout_obj_instances = layout.GetLayoutInstance().GetAllLayoutObjInstances()
|
|
1172
|
+
tuple_list = []
|
|
1173
|
+
for lobj in layout_obj_instances.Items:
|
|
1174
|
+
lobj_bbox = lobj.GetLayoutInstanceContext().GetBBox(False)
|
|
1175
|
+
tuple_list.append(lobj_bbox)
|
|
1176
|
+
_bbox = self._edb.geometry.polygon_data.get_bbox_of_boxes(tuple_list)
|
|
1177
|
+
layout_bbox = [
|
|
1178
|
+
round(_bbox.Item1.X.ToDouble(), digit_resolution),
|
|
1179
|
+
round(_bbox.Item1.Y.ToDouble(), digit_resolution),
|
|
1180
|
+
round(_bbox.Item2.X.ToDouble(), digit_resolution),
|
|
1181
|
+
round(_bbox.Item2.Y.ToDouble(), digit_resolution),
|
|
1182
|
+
]
|
|
1183
|
+
return layout_bbox
|
|
1184
|
+
|
|
1185
|
+
@pyedb_function_handler()
|
|
1186
|
+
def configure_hfss_extents(self, simulation_setup=None):
|
|
1187
|
+
"""Configure the HFSS extent box.
|
|
1188
|
+
|
|
1189
|
+
Parameters
|
|
1190
|
+
----------
|
|
1191
|
+
simulation_setup :
|
|
1192
|
+
Edb_DATA.SimulationConfiguration object
|
|
1193
|
+
|
|
1194
|
+
Returns
|
|
1195
|
+
-------
|
|
1196
|
+
bool
|
|
1197
|
+
True when succeeded, False when failed.
|
|
1198
|
+
"""
|
|
1199
|
+
|
|
1200
|
+
if not isinstance(simulation_setup, SimulationConfiguration):
|
|
1201
|
+
self._logger.error(
|
|
1202
|
+
"Configure HFSS extent requires edb_data.simulation_configuration.SimulationConfiguration object"
|
|
1203
|
+
)
|
|
1204
|
+
return False
|
|
1205
|
+
hfss_extent = self._edb.utility.utility.HFSSExtentInfo()
|
|
1206
|
+
if simulation_setup.radiation_box == RadiationBoxType.BoundingBox:
|
|
1207
|
+
hfss_extent.ExtentType = self._edb.utility.utility.HFSSExtentInfoType.BoundingBox
|
|
1208
|
+
elif simulation_setup.radiation_box == RadiationBoxType.Conformal:
|
|
1209
|
+
hfss_extent.ExtentType = self._edb.utility.utility.HFSSExtentInfoType.Conforming
|
|
1210
|
+
else:
|
|
1211
|
+
hfss_extent.ExtentType = self._edb.utility.utility.HFSSExtentInfoType.ConvexHull
|
|
1212
|
+
hfss_extent.DielectricExtentSize = convert_pytuple_to_nettuple(
|
|
1213
|
+
(simulation_setup.dielectric_extent, simulation_setup.use_dielectric_extent_multiple)
|
|
1214
|
+
)
|
|
1215
|
+
hfss_extent.AirBoxHorizontalExtent = convert_pytuple_to_nettuple(
|
|
1216
|
+
(simulation_setup.airbox_horizontal_extent, simulation_setup.use_airbox_horizontal_extent_multiple)
|
|
1217
|
+
)
|
|
1218
|
+
hfss_extent.AirBoxNegativeVerticalExtent = convert_pytuple_to_nettuple(
|
|
1219
|
+
(
|
|
1220
|
+
simulation_setup.airbox_negative_vertical_extent,
|
|
1221
|
+
simulation_setup.use_airbox_negative_vertical_extent_multiple,
|
|
1222
|
+
)
|
|
1223
|
+
)
|
|
1224
|
+
hfss_extent.AirBoxPositiveVerticalExtent = convert_pytuple_to_nettuple(
|
|
1225
|
+
(
|
|
1226
|
+
simulation_setup.airbox_positive_vertical_extent,
|
|
1227
|
+
simulation_setup.use_airbox_positive_vertical_extent_multiple,
|
|
1228
|
+
)
|
|
1229
|
+
)
|
|
1230
|
+
hfss_extent.HonorUserDielectric = simulation_setup.honor_user_dielectric
|
|
1231
|
+
hfss_extent.TruncateAirBoxAtGround = simulation_setup.truncate_airbox_at_ground
|
|
1232
|
+
hfss_extent.UseOpenRegion = simulation_setup.use_radiation_boundary
|
|
1233
|
+
self._layout.cell.SetHFSSExtentInfo(hfss_extent) # returns void
|
|
1234
|
+
return True
|
|
1235
|
+
|
|
1236
|
+
@pyedb_function_handler()
|
|
1237
|
+
def configure_hfss_analysis_setup(self, simulation_setup=None):
|
|
1238
|
+
"""
|
|
1239
|
+
Configure HFSS analysis setup.
|
|
1240
|
+
|
|
1241
|
+
Parameters
|
|
1242
|
+
----------
|
|
1243
|
+
simulation_setup :
|
|
1244
|
+
Edb_DATA.SimulationConfiguration object
|
|
1245
|
+
|
|
1246
|
+
Returns
|
|
1247
|
+
-------
|
|
1248
|
+
bool
|
|
1249
|
+
True when succeeded, False when failed.
|
|
1250
|
+
"""
|
|
1251
|
+
if not isinstance(simulation_setup, SimulationConfiguration):
|
|
1252
|
+
self._logger.error(
|
|
1253
|
+
"Configure HFSS analysis requires and edb_data.simulation_configuration.SimulationConfiguration object \
|
|
1254
|
+
as argument"
|
|
1255
|
+
)
|
|
1256
|
+
return False
|
|
1257
|
+
adapt = self._pedb.simsetupdata.AdaptiveFrequencyData()
|
|
1258
|
+
adapt.AdaptiveFrequency = simulation_setup.mesh_freq
|
|
1259
|
+
adapt.MaxPasses = int(simulation_setup.max_num_passes)
|
|
1260
|
+
adapt.MaxDelta = str(simulation_setup.max_mag_delta_s)
|
|
1261
|
+
simsetup_info = self._pedb.simsetupdata.SimSetupInfo[self._pedb.simsetupdata.HFSSSimulationSettings]()
|
|
1262
|
+
simsetup_info.Name = simulation_setup.setup_name
|
|
1263
|
+
|
|
1264
|
+
simsetup_info.SimulationSettings.CurveApproxSettings.ArcAngle = simulation_setup.arc_angle
|
|
1265
|
+
simsetup_info.SimulationSettings.CurveApproxSettings.UseArcToChordError = (
|
|
1266
|
+
simulation_setup.use_arc_to_chord_error
|
|
1267
|
+
)
|
|
1268
|
+
simsetup_info.SimulationSettings.CurveApproxSettings.ArcToChordError = simulation_setup.arc_to_chord_error
|
|
1269
|
+
if is_ironpython:
|
|
1270
|
+
simsetup_info.SimulationSettings.AdaptiveSettings.AdaptiveFrequencyDataList.Clear()
|
|
1271
|
+
simsetup_info.SimulationSettings.AdaptiveSettings.AdaptiveFrequencyDataList.Add(adapt)
|
|
1272
|
+
else:
|
|
1273
|
+
simsetup_info.SimulationSettings.AdaptiveSettings.AdaptiveFrequencyDataList = convert_py_list_to_net_list(
|
|
1274
|
+
[adapt]
|
|
1275
|
+
)
|
|
1276
|
+
simsetup_info.SimulationSettings.InitialMeshSettings.LambdaRefine = simulation_setup.do_lambda_refinement
|
|
1277
|
+
if simulation_setup.mesh_sizefactor > 0.0:
|
|
1278
|
+
simsetup_info.SimulationSettings.InitialMeshSettings.MeshSizefactor = simulation_setup.mesh_sizefactor
|
|
1279
|
+
simsetup_info.SimulationSettings.InitialMeshSettings.LambdaRefine = False
|
|
1280
|
+
simsetup_info.SimulationSettings.AdaptiveSettings.MaxRefinePerPass = 30
|
|
1281
|
+
simsetup_info.SimulationSettings.AdaptiveSettings.MinPasses = simulation_setup.min_num_passes
|
|
1282
|
+
simsetup_info.SimulationSettings.AdaptiveSettings.MinConvergedPasses = 1
|
|
1283
|
+
simsetup_info.SimulationSettings.HFSSSolverSettings.OrderBasis = simulation_setup.basis_order
|
|
1284
|
+
simsetup_info.SimulationSettings.HFSSSolverSettings.UseHFSSIterativeSolver = False
|
|
1285
|
+
simsetup_info.SimulationSettings.DefeatureSettings.UseDefeature = False # set True when using defeature ratio
|
|
1286
|
+
simsetup_info.SimulationSettings.DefeatureSettings.UseDefeatureAbsLength = simulation_setup.defeature_layout
|
|
1287
|
+
simsetup_info.SimulationSettings.DefeatureSettings.DefeatureAbsLength = simulation_setup.defeature_abs_length
|
|
1288
|
+
|
|
1289
|
+
try:
|
|
1290
|
+
if simulation_setup.add_frequency_sweep:
|
|
1291
|
+
self._logger.info("Adding frequency sweep")
|
|
1292
|
+
sweep = self._pedb.simsetupdata.SweepData(simulation_setup.sweep_name)
|
|
1293
|
+
sweep.IsDiscrete = False
|
|
1294
|
+
sweep.UseQ3DForDC = simulation_setup.use_q3d_for_dc
|
|
1295
|
+
sweep.RelativeSError = simulation_setup.relative_error
|
|
1296
|
+
sweep.InterpUsePortImpedance = False
|
|
1297
|
+
sweep.EnforceCausality = simulation_setup.enforce_causality
|
|
1298
|
+
# sweep.EnforceCausality = False
|
|
1299
|
+
sweep.EnforcePassivity = simulation_setup.enforce_passivity
|
|
1300
|
+
sweep.PassivityTolerance = simulation_setup.passivity_tolerance
|
|
1301
|
+
sweep.Frequencies.Clear()
|
|
1302
|
+
|
|
1303
|
+
if simulation_setup.sweep_type == SweepType.LogCount: # setup_info.SweepType == 'DecadeCount'
|
|
1304
|
+
self._setup_decade_count_sweep(
|
|
1305
|
+
sweep,
|
|
1306
|
+
str(simulation_setup.start_freq),
|
|
1307
|
+
str(simulation_setup.stop_freq),
|
|
1308
|
+
str(simulation_setup.decade_count),
|
|
1309
|
+
) # Added DecadeCount as a new attribute
|
|
1310
|
+
|
|
1311
|
+
else:
|
|
1312
|
+
sweep.Frequencies = self._pedb.simsetupdata.SweepData.SetFrequencies(
|
|
1313
|
+
simulation_setup.start_freq,
|
|
1314
|
+
simulation_setup.stop_freq,
|
|
1315
|
+
simulation_setup.step_freq,
|
|
1316
|
+
)
|
|
1317
|
+
|
|
1318
|
+
simsetup_info.SweepDataList.Add(sweep)
|
|
1319
|
+
else:
|
|
1320
|
+
self._logger.info("Adding frequency sweep disabled")
|
|
1321
|
+
|
|
1322
|
+
except Exception as err:
|
|
1323
|
+
self._logger.error("Exception in Sweep configuration: {0}".format(err))
|
|
1324
|
+
|
|
1325
|
+
sim_setup = self._edb.utility.utility.HFSSSimulationSetup(simsetup_info)
|
|
1326
|
+
for setup in self._layout.cell.SimulationSetups:
|
|
1327
|
+
self._layout.cell.DeleteSimulationSetup(setup.GetName())
|
|
1328
|
+
self._logger.warning("Setup {} has been deleted".format(setup.GetName()))
|
|
1329
|
+
return self._layout.cell.AddSimulationSetup(sim_setup)
|
|
1330
|
+
|
|
1331
|
+
def _setup_decade_count_sweep(self, sweep, start_freq="1", stop_freq="1MHz", decade_count="10"):
|
|
1332
|
+
start_f = GeometryOperators.parse_dim_arg(start_freq)
|
|
1333
|
+
if start_f == 0.0:
|
|
1334
|
+
start_f = 10
|
|
1335
|
+
self._logger.warning("Decade Count sweep does not support DC value, defaulting starting frequency to 10Hz")
|
|
1336
|
+
|
|
1337
|
+
stop_f = GeometryOperators.parse_dim_arg(stop_freq)
|
|
1338
|
+
decade_cnt = GeometryOperators.parse_dim_arg(decade_count)
|
|
1339
|
+
freq = start_f
|
|
1340
|
+
sweep.Frequencies.Add(str(freq))
|
|
1341
|
+
|
|
1342
|
+
while freq < stop_f:
|
|
1343
|
+
freq = freq * math.pow(10, 1.0 / decade_cnt)
|
|
1344
|
+
sweep.Frequencies.Add(str(freq))
|
|
1345
|
+
|
|
1346
|
+
@pyedb_function_handler()
|
|
1347
|
+
def trim_component_reference_size(self, simulation_setup=None, trim_to_terminals=False):
|
|
1348
|
+
"""Trim the common component reference to the minimally acceptable size.
|
|
1349
|
+
|
|
1350
|
+
Parameters
|
|
1351
|
+
----------
|
|
1352
|
+
simulation_setup :
|
|
1353
|
+
Edb_DATA.SimulationConfiguration object
|
|
1354
|
+
|
|
1355
|
+
trim_to_terminals :
|
|
1356
|
+
bool.
|
|
1357
|
+
True, reduce the reference to a box covering only the active terminals (i.e. those with
|
|
1358
|
+
ports).
|
|
1359
|
+
False, reduce the reference to the minimal size needed to cover all pins
|
|
1360
|
+
|
|
1361
|
+
Returns
|
|
1362
|
+
-------
|
|
1363
|
+
bool
|
|
1364
|
+
True when succeeded, False when failed.
|
|
1365
|
+
"""
|
|
1366
|
+
|
|
1367
|
+
if not isinstance(simulation_setup, SimulationConfiguration):
|
|
1368
|
+
self._logger.error(
|
|
1369
|
+
"Trim component reference size requires an edb_data.simulation_configuration.SimulationConfiguration \
|
|
1370
|
+
object as argument"
|
|
1371
|
+
)
|
|
1372
|
+
return False
|
|
1373
|
+
|
|
1374
|
+
if not simulation_setup.components: # pragma: no cover
|
|
1375
|
+
return
|
|
1376
|
+
|
|
1377
|
+
layout = self._cell.GetLayout()
|
|
1378
|
+
l_inst = layout.GetLayoutInstance()
|
|
1379
|
+
|
|
1380
|
+
for inst in simulation_setup.components: # pragma: no cover
|
|
1381
|
+
comp = self._pedb.edb_api.cell.hierarchy.component.FindByName(layout, inst)
|
|
1382
|
+
if comp.IsNull():
|
|
1383
|
+
continue
|
|
1384
|
+
|
|
1385
|
+
terms_bbox_pts = self._get_terminals_bbox(comp, l_inst, trim_to_terminals)
|
|
1386
|
+
if not terms_bbox_pts:
|
|
1387
|
+
continue
|
|
1388
|
+
|
|
1389
|
+
terms_bbox = self._edb.geometry.polygon_data.create_from_bbox(terms_bbox_pts)
|
|
1390
|
+
|
|
1391
|
+
if trim_to_terminals:
|
|
1392
|
+
# Remove any pins that aren't interior to the Terminals bbox
|
|
1393
|
+
pin_list = [
|
|
1394
|
+
obj
|
|
1395
|
+
for obj in list(comp.LayoutObjs)
|
|
1396
|
+
if obj.GetObjType() == self._edb.cell.layout_object_type.PadstackInstance
|
|
1397
|
+
]
|
|
1398
|
+
for pin in pin_list:
|
|
1399
|
+
loi = l_inst.GetLayoutObjInstance(pin, None)
|
|
1400
|
+
bb_c = loi.GetCenter()
|
|
1401
|
+
if not terms_bbox.PointInPolygon(bb_c):
|
|
1402
|
+
comp.RemoveMember(pin)
|
|
1403
|
+
|
|
1404
|
+
# Set the port property reference size
|
|
1405
|
+
cmp_prop = comp.GetComponentProperty().Clone()
|
|
1406
|
+
port_prop = cmp_prop.GetPortProperty().Clone()
|
|
1407
|
+
port_prop.SetReferenceSizeAuto(False)
|
|
1408
|
+
port_prop.SetReferenceSize(
|
|
1409
|
+
terms_bbox_pts.Item2.X.ToDouble() - terms_bbox_pts.Item1.X.ToDouble(),
|
|
1410
|
+
terms_bbox_pts.Item2.Y.ToDouble() - terms_bbox_pts.Item1.Y.ToDouble(),
|
|
1411
|
+
)
|
|
1412
|
+
cmp_prop.SetPortProperty(port_prop)
|
|
1413
|
+
comp.SetComponentProperty(cmp_prop)
|
|
1414
|
+
return True
|
|
1415
|
+
|
|
1416
|
+
@pyedb_function_handler()
|
|
1417
|
+
def set_coax_port_attributes(self, simulation_setup=None):
|
|
1418
|
+
"""Set coaxial port attribute with forcing default impedance to 50 Ohms and adjusting the coaxial extent radius.
|
|
1419
|
+
|
|
1420
|
+
Parameters
|
|
1421
|
+
----------
|
|
1422
|
+
simulation_setup :
|
|
1423
|
+
Edb_DATA.SimulationConfiguration object.
|
|
1424
|
+
|
|
1425
|
+
Returns
|
|
1426
|
+
-------
|
|
1427
|
+
bool
|
|
1428
|
+
True when succeeded, False when failed.
|
|
1429
|
+
"""
|
|
1430
|
+
|
|
1431
|
+
if not isinstance(simulation_setup, SimulationConfiguration):
|
|
1432
|
+
self._logger.error(
|
|
1433
|
+
"Set coax port attribute requires an edb_data.simulation_configuration.SimulationConfiguration object \
|
|
1434
|
+
as argument."
|
|
1435
|
+
)
|
|
1436
|
+
return False
|
|
1437
|
+
net_names = [net.name for net in self._layout.nets if not net.IsPowerGround()]
|
|
1438
|
+
if simulation_setup.components and isinstance(simulation_setup.components[0], str):
|
|
1439
|
+
cmp_names = (
|
|
1440
|
+
simulation_setup.components
|
|
1441
|
+
if simulation_setup.components
|
|
1442
|
+
else [gg.GetName() for gg in self._layout.groups]
|
|
1443
|
+
)
|
|
1444
|
+
elif (
|
|
1445
|
+
simulation_setup.components
|
|
1446
|
+
and isinstance(simulation_setup.components[0], dict)
|
|
1447
|
+
and "refdes" in simulation_setup.components[0]
|
|
1448
|
+
):
|
|
1449
|
+
cmp_names = [cmp["refdes"] for cmp in simulation_setup.components]
|
|
1450
|
+
else:
|
|
1451
|
+
cmp_names = []
|
|
1452
|
+
ii = 0
|
|
1453
|
+
for cc in cmp_names:
|
|
1454
|
+
cmp = self._pedb.edb_api.cell.hierarchy.component.FindByName(self._active_layout, cc)
|
|
1455
|
+
if cmp.IsNull():
|
|
1456
|
+
self._logger.warning("RenamePorts: could not find component {0}".format(cc))
|
|
1457
|
+
continue
|
|
1458
|
+
terms = [
|
|
1459
|
+
obj for obj in list(cmp.LayoutObjs) if obj.GetObjType() == self._edb.cell.layout_object_type.Terminal
|
|
1460
|
+
]
|
|
1461
|
+
for nn in net_names:
|
|
1462
|
+
for tt in [term for term in terms if term.GetNet().GetName() == nn]:
|
|
1463
|
+
if not tt.SetImpedance(self._pedb.edb_value("50ohm")):
|
|
1464
|
+
self._logger.warning("Could not set terminal {0} impedance as 50ohm".format(tt.GetName()))
|
|
1465
|
+
continue
|
|
1466
|
+
ii += 1
|
|
1467
|
+
|
|
1468
|
+
if not simulation_setup.use_default_coax_port_radial_extension:
|
|
1469
|
+
# Set the Radial Extent Factor
|
|
1470
|
+
typ = cmp.GetComponentType()
|
|
1471
|
+
if typ in [
|
|
1472
|
+
self._edb.definition.ComponentType.Other,
|
|
1473
|
+
self._edb.definition.ComponentType.IC,
|
|
1474
|
+
self._edb.definition.ComponentType.IO,
|
|
1475
|
+
]:
|
|
1476
|
+
cmp_prop = cmp.GetComponentProperty().Clone()
|
|
1477
|
+
(
|
|
1478
|
+
success,
|
|
1479
|
+
diam1,
|
|
1480
|
+
diam2,
|
|
1481
|
+
) = cmp_prop.GetSolderBallProperty().GetDiameter()
|
|
1482
|
+
if success and diam1 and diam2 > 0: # pragma: no cover
|
|
1483
|
+
option = (
|
|
1484
|
+
"HFSS('HFSS Type'='**Invalid**', "
|
|
1485
|
+
"Orientation='**Invalid**', "
|
|
1486
|
+
"'Layer Alignment'='Upper', "
|
|
1487
|
+
"'Horizontal Extent Factor'='5', "
|
|
1488
|
+
"'Vertical Extent Factor'='3', "
|
|
1489
|
+
"'Radial Extent Factor'='0.25', "
|
|
1490
|
+
"'PEC Launch Width'='0mm')"
|
|
1491
|
+
)
|
|
1492
|
+
for tt in terms:
|
|
1493
|
+
tt.SetProductSolverOption(self._edb.edb_api.ProductId.Designer, "HFSS", option)
|
|
1494
|
+
return True
|
|
1495
|
+
|
|
1496
|
+
@pyedb_function_handler()
|
|
1497
|
+
def _get_terminals_bbox(self, comp, l_inst, terminals_only):
|
|
1498
|
+
terms_loi = []
|
|
1499
|
+
if terminals_only:
|
|
1500
|
+
term_list = [
|
|
1501
|
+
obj for obj in list(comp.LayoutObjs) if obj.GetObjType() == self._edb.cell.layout_object_type.Terminal
|
|
1502
|
+
]
|
|
1503
|
+
for tt in term_list:
|
|
1504
|
+
success, p_inst, lyr = tt.GetParameters()
|
|
1505
|
+
if success and lyr:
|
|
1506
|
+
loi = l_inst.GetLayoutObjInstance(p_inst, None)
|
|
1507
|
+
terms_loi.append(loi)
|
|
1508
|
+
else:
|
|
1509
|
+
pin_list = [
|
|
1510
|
+
obj
|
|
1511
|
+
for obj in list(comp.LayoutObjs)
|
|
1512
|
+
if obj.GetObjType() == self._edb.cell.layout_object_type.PadstackInstance
|
|
1513
|
+
]
|
|
1514
|
+
for pi in pin_list:
|
|
1515
|
+
loi = l_inst.GetLayoutObjInstance(pi, None)
|
|
1516
|
+
terms_loi.append(loi)
|
|
1517
|
+
|
|
1518
|
+
if len(terms_loi) == 0:
|
|
1519
|
+
return None
|
|
1520
|
+
|
|
1521
|
+
terms_bbox = []
|
|
1522
|
+
for loi in terms_loi:
|
|
1523
|
+
# Need to account for the coax port dimension
|
|
1524
|
+
bb = loi.GetBBox()
|
|
1525
|
+
ll = [bb.Item1.X.ToDouble(), bb.Item1.Y.ToDouble()]
|
|
1526
|
+
ur = [bb.Item2.X.ToDouble(), bb.Item2.Y.ToDouble()]
|
|
1527
|
+
# dim = 0.26 * max(abs(UR[0]-LL[0]), abs(UR[1]-LL[1])) # 0.25 corresponds to the default 0.5
|
|
1528
|
+
# Radial Extent Factor, so set slightly larger to avoid validation errors
|
|
1529
|
+
dim = 0.30 * max(abs(ur[0] - ll[0]), abs(ur[1] - ll[1])) # 0.25 corresponds to the default 0.5
|
|
1530
|
+
terms_bbox.append(
|
|
1531
|
+
self._edb.geometry.polygon_data.dotnetobj(ll[0] - dim, ll[1] - dim, ur[0] + dim, ur[1] + dim)
|
|
1532
|
+
)
|
|
1533
|
+
return self._edb.geometry.polygon_data.get_bbox_of_polygons(terms_bbox)
|
|
1534
|
+
|
|
1535
|
+
@pyedb_function_handler()
|
|
1536
|
+
def get_ports_number(self):
|
|
1537
|
+
"""Return the total number of excitation ports in a layout.
|
|
1538
|
+
|
|
1539
|
+
Parameters
|
|
1540
|
+
----------
|
|
1541
|
+
None
|
|
1542
|
+
|
|
1543
|
+
Returns
|
|
1544
|
+
-------
|
|
1545
|
+
int
|
|
1546
|
+
Number of ports.
|
|
1547
|
+
|
|
1548
|
+
"""
|
|
1549
|
+
terms = [term for term in self._layout.terminals if int(term.GetBoundaryType()) == 0]
|
|
1550
|
+
return len([i for i in terms if not i.IsReferenceTerminal()])
|
|
1551
|
+
|
|
1552
|
+
@pyedb_function_handler()
|
|
1553
|
+
def layout_defeaturing(self, simulation_setup=None):
|
|
1554
|
+
"""Defeature the layout by reducing the number of points for polygons based on surface deviation criteria.
|
|
1555
|
+
|
|
1556
|
+
Parameters
|
|
1557
|
+
----------
|
|
1558
|
+
simulation_setup : Edb_DATA.SimulationConfiguration object
|
|
1559
|
+
|
|
1560
|
+
Returns
|
|
1561
|
+
-------
|
|
1562
|
+
bool
|
|
1563
|
+
``True`` when successful, ``False`` when failed.
|
|
1564
|
+
|
|
1565
|
+
"""
|
|
1566
|
+
if not isinstance(simulation_setup, SimulationConfiguration):
|
|
1567
|
+
self._logger.error(
|
|
1568
|
+
"Layout defeaturing requires an edb_data.simulation_configuration.SimulationConfiguration object."
|
|
1569
|
+
)
|
|
1570
|
+
return False
|
|
1571
|
+
self._logger.info("Starting Layout Defeaturing")
|
|
1572
|
+
polygon_list = self._pedb.modeler.polygons
|
|
1573
|
+
polygon_with_voids = self._pedb.core_layout.get_poly_with_voids(polygon_list)
|
|
1574
|
+
self._logger.info("Number of polygons with voids found: {0}".format(str(polygon_with_voids.Count)))
|
|
1575
|
+
for _poly in polygon_list:
|
|
1576
|
+
voids_from_current_poly = _poly.Voids
|
|
1577
|
+
new_poly_data = self._pedb.core_layout.defeature_polygon(setup_info=simulation_setup, poly=_poly)
|
|
1578
|
+
_poly.SetPolygonData(new_poly_data)
|
|
1579
|
+
if len(voids_from_current_poly) > 0:
|
|
1580
|
+
for void in voids_from_current_poly:
|
|
1581
|
+
void_data = void.GetPolygonData()
|
|
1582
|
+
if void_data.Area() < float(simulation_setup.minimum_void_surface):
|
|
1583
|
+
void.Delete()
|
|
1584
|
+
self._logger.warning(
|
|
1585
|
+
"Defeaturing Polygon {0}: Deleting Void {1} area is lower than the minimum criteria".format(
|
|
1586
|
+
str(_poly.GetId()), str(void.GetId())
|
|
1587
|
+
)
|
|
1588
|
+
)
|
|
1589
|
+
else:
|
|
1590
|
+
self._logger.info(
|
|
1591
|
+
"Defeaturing polygon {0}: void {1}".format(str(_poly.GetId()), str(void.GetId()))
|
|
1592
|
+
)
|
|
1593
|
+
new_void_data = self._pedb.core_layout.defeature_polygon(
|
|
1594
|
+
setup_info=simulation_setup, poly=void_data
|
|
1595
|
+
)
|
|
1596
|
+
void.SetPolygonData(new_void_data)
|
|
1597
|
+
|
|
1598
|
+
return True
|
|
1599
|
+
|
|
1600
|
+
@pyedb_function_handler()
|
|
1601
|
+
def create_rlc_boundary_on_pins(self, positive_pin=None, negative_pin=None, rvalue=0.0, lvalue=0.0, cvalue=0.0):
|
|
1602
|
+
"""Create hfss rlc boundary on pins.
|
|
1603
|
+
|
|
1604
|
+
Parameters
|
|
1605
|
+
----------
|
|
1606
|
+
positive_pin : Positive pin.
|
|
1607
|
+
Edb.Cell.Primitive.PadstackInstance
|
|
1608
|
+
|
|
1609
|
+
negative_pin : Negative pin.
|
|
1610
|
+
Edb.Cell.Primitive.PadstackInstance
|
|
1611
|
+
|
|
1612
|
+
rvalue : Resistance value
|
|
1613
|
+
|
|
1614
|
+
lvalue : Inductance value
|
|
1615
|
+
|
|
1616
|
+
cvalue . Capacitance value.
|
|
1617
|
+
|
|
1618
|
+
Returns
|
|
1619
|
+
-------
|
|
1620
|
+
bool
|
|
1621
|
+
``True`` when successful, ``False`` when failed.
|
|
1622
|
+
|
|
1623
|
+
"""
|
|
1624
|
+
|
|
1625
|
+
if positive_pin and negative_pin:
|
|
1626
|
+
positive_pin_term = self._pedb.components._create_terminal(positive_pin)
|
|
1627
|
+
negative_pin_term = self._pedb.components._create_terminal(negative_pin)
|
|
1628
|
+
positive_pin_term.SetBoundaryType(self._edb.cell.terminal.BoundaryType.RlcBoundary)
|
|
1629
|
+
negative_pin_term.SetBoundaryType(self._edb.cell.terminal.BoundaryType.RlcBoundary)
|
|
1630
|
+
rlc = self._edb.utility.utility.Rlc()
|
|
1631
|
+
rlc.IsParallel = True
|
|
1632
|
+
rlc.REnabled = True
|
|
1633
|
+
rlc.LEnabled = True
|
|
1634
|
+
rlc.CEnabled = True
|
|
1635
|
+
rlc.R = self._get_edb_value(rvalue)
|
|
1636
|
+
rlc.L = self._get_edb_value(lvalue)
|
|
1637
|
+
rlc.C = self._get_edb_value(cvalue)
|
|
1638
|
+
positive_pin_term.SetRlcBoundaryParameters(rlc)
|
|
1639
|
+
term_name = "{}_{}_{}".format(
|
|
1640
|
+
positive_pin.GetComponent().GetName(), positive_pin.GetNet().GetName(), positive_pin.GetName()
|
|
1641
|
+
)
|
|
1642
|
+
positive_pin_term.SetName(term_name)
|
|
1643
|
+
negative_pin_term.SetName("{}_ref".format(term_name))
|
|
1644
|
+
positive_pin_term.SetReferenceTerminal(negative_pin_term)
|
|
1645
|
+
return True
|
|
1646
|
+
return False # pragma no cover
|