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,1427 @@
|
|
|
1
|
+
"""
|
|
2
|
+
This module contains these classes: ``CircuitPort``, ``CurrentSource``, ``EdbSiwave``,
|
|
3
|
+
``PinGroup``, ``ResistorSource``, ``Source``, ``SourceType``, and ``VoltageSource``.
|
|
4
|
+
"""
|
|
5
|
+
import os
|
|
6
|
+
import time
|
|
7
|
+
|
|
8
|
+
from pyedb.dotnet.edb_core.edb_data.simulation_configuration import (
|
|
9
|
+
SimulationConfiguration,
|
|
10
|
+
SourceType,
|
|
11
|
+
)
|
|
12
|
+
from pyedb.dotnet.edb_core.edb_data.sources import (
|
|
13
|
+
CircuitPort,
|
|
14
|
+
CurrentSource,
|
|
15
|
+
DCTerminal,
|
|
16
|
+
PinGroup,
|
|
17
|
+
ResistorSource,
|
|
18
|
+
VoltageSource,
|
|
19
|
+
)
|
|
20
|
+
from pyedb.dotnet.edb_core.general import convert_py_list_to_net_list
|
|
21
|
+
from pyedb.generic.constants import SolverType, SweepType
|
|
22
|
+
from pyedb.generic.general_methods import (
|
|
23
|
+
_retry_ntimes,
|
|
24
|
+
generate_unique_name,
|
|
25
|
+
pyedb_function_handler,
|
|
26
|
+
)
|
|
27
|
+
from pyedb.modeler.geometry_operators import GeometryOperators
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class EdbSiwave(object):
|
|
31
|
+
"""Manages EDB methods related to Siwave Setup accessible from `Edb.siwave` property.
|
|
32
|
+
|
|
33
|
+
Parameters
|
|
34
|
+
----------
|
|
35
|
+
edb_class : :class:`pyedb.edb.Edb`
|
|
36
|
+
Inherited parent object.
|
|
37
|
+
|
|
38
|
+
Examples
|
|
39
|
+
--------
|
|
40
|
+
>>> from pyedb import Edb
|
|
41
|
+
>>> edbapp = Edb("myaedbfolder", edbversion="2021.2")
|
|
42
|
+
>>> edb_siwave = edbapp.siwave
|
|
43
|
+
"""
|
|
44
|
+
|
|
45
|
+
def __init__(self, p_edb):
|
|
46
|
+
self._pedb = p_edb
|
|
47
|
+
|
|
48
|
+
@property
|
|
49
|
+
def _edb(self):
|
|
50
|
+
"""EDB."""
|
|
51
|
+
return self._pedb.edb_api
|
|
52
|
+
|
|
53
|
+
def _get_edb_value(self, value):
|
|
54
|
+
"""Get the Edb value."""
|
|
55
|
+
return self._pedb.edb_value(value)
|
|
56
|
+
|
|
57
|
+
@property
|
|
58
|
+
def _logger(self):
|
|
59
|
+
"""EDB."""
|
|
60
|
+
return self._pedb.logger
|
|
61
|
+
|
|
62
|
+
@property
|
|
63
|
+
def _active_layout(self):
|
|
64
|
+
"""Active layout."""
|
|
65
|
+
return self._pedb.active_layout
|
|
66
|
+
|
|
67
|
+
@property
|
|
68
|
+
def _layout(self):
|
|
69
|
+
"""Active layout."""
|
|
70
|
+
return self._pedb.layout
|
|
71
|
+
|
|
72
|
+
@property
|
|
73
|
+
def _cell(self):
|
|
74
|
+
"""Cell."""
|
|
75
|
+
return self._pedb.active_cell
|
|
76
|
+
|
|
77
|
+
@property
|
|
78
|
+
def _db(self):
|
|
79
|
+
""" """
|
|
80
|
+
return self._pedb.active_db
|
|
81
|
+
|
|
82
|
+
@property
|
|
83
|
+
def excitations(self):
|
|
84
|
+
"""Get all excitations."""
|
|
85
|
+
return self._pedb.excitations
|
|
86
|
+
|
|
87
|
+
@property
|
|
88
|
+
def sources(self):
|
|
89
|
+
"""Get all sources."""
|
|
90
|
+
return self._pedb.sources
|
|
91
|
+
|
|
92
|
+
@property
|
|
93
|
+
def probes(self):
|
|
94
|
+
"""Get all probes."""
|
|
95
|
+
return self._pedb.probes
|
|
96
|
+
|
|
97
|
+
@property
|
|
98
|
+
def pin_groups(self):
|
|
99
|
+
"""All Layout Pin groups.
|
|
100
|
+
|
|
101
|
+
Returns
|
|
102
|
+
-------
|
|
103
|
+
list
|
|
104
|
+
List of all layout pin groups.
|
|
105
|
+
"""
|
|
106
|
+
_pingroups = {}
|
|
107
|
+
for el in self._layout.pin_groups:
|
|
108
|
+
_pingroups[el.GetName()] = PinGroup(el.GetName(), el, self._pedb)
|
|
109
|
+
return _pingroups
|
|
110
|
+
|
|
111
|
+
@pyedb_function_handler()
|
|
112
|
+
def _create_terminal_on_pins(self, source):
|
|
113
|
+
"""Create a terminal on pins.
|
|
114
|
+
|
|
115
|
+
Parameters
|
|
116
|
+
----------
|
|
117
|
+
source : VoltageSource, CircuitPort, CurrentSource or ResistorSource
|
|
118
|
+
Name of the source.
|
|
119
|
+
|
|
120
|
+
"""
|
|
121
|
+
pos_pin = source.positive_node.node_pins
|
|
122
|
+
neg_pin = source.negative_node.node_pins
|
|
123
|
+
|
|
124
|
+
res, fromLayer_pos, toLayer_pos = pos_pin.GetLayerRange()
|
|
125
|
+
res, fromLayer_neg, toLayer_neg = neg_pin.GetLayerRange()
|
|
126
|
+
|
|
127
|
+
pos_pingroup_terminal = _retry_ntimes(
|
|
128
|
+
10,
|
|
129
|
+
self._edb.cell.terminal.PadstackInstanceTerminal.Create,
|
|
130
|
+
self._active_layout,
|
|
131
|
+
pos_pin.GetNet(),
|
|
132
|
+
pos_pin.GetName(),
|
|
133
|
+
pos_pin,
|
|
134
|
+
toLayer_pos,
|
|
135
|
+
)
|
|
136
|
+
time.sleep(0.5)
|
|
137
|
+
neg_pingroup_terminal = _retry_ntimes(
|
|
138
|
+
20,
|
|
139
|
+
self._edb.cell.terminal.PadstackInstanceTerminal.Create,
|
|
140
|
+
self._active_layout,
|
|
141
|
+
neg_pin.GetNet(),
|
|
142
|
+
neg_pin.GetName(),
|
|
143
|
+
neg_pin,
|
|
144
|
+
toLayer_neg,
|
|
145
|
+
)
|
|
146
|
+
if source.source_type in [SourceType.CoaxPort, SourceType.CircPort, SourceType.LumpedPort]:
|
|
147
|
+
pos_pingroup_terminal.SetBoundaryType(self._edb.cell.terminal.BoundaryType.PortBoundary)
|
|
148
|
+
neg_pingroup_terminal.SetBoundaryType(self._edb.cell.terminal.BoundaryType.PortBoundary)
|
|
149
|
+
pos_pingroup_terminal.SetImpedance(self._get_edb_value(source.impedance))
|
|
150
|
+
if source.source_type == SourceType.CircPort:
|
|
151
|
+
pos_pingroup_terminal.SetIsCircuitPort(True)
|
|
152
|
+
neg_pingroup_terminal.SetIsCircuitPort(True)
|
|
153
|
+
pos_pingroup_terminal.SetReferenceTerminal(neg_pingroup_terminal)
|
|
154
|
+
try:
|
|
155
|
+
pos_pingroup_terminal.SetName(source.name)
|
|
156
|
+
except:
|
|
157
|
+
name = generate_unique_name(source.name)
|
|
158
|
+
pos_pingroup_terminal.SetName(name)
|
|
159
|
+
self._logger.warning("%s already exists. Renaming to %s", source.name, name)
|
|
160
|
+
elif source.source_type == SourceType.Isource:
|
|
161
|
+
pos_pingroup_terminal.SetBoundaryType(self._edb.cell.terminal.BoundaryType.kCurrentSource)
|
|
162
|
+
neg_pingroup_terminal.SetBoundaryType(self._edb.cell.terminal.BoundaryType.kCurrentSource)
|
|
163
|
+
pos_pingroup_terminal.SetSourceAmplitude(self._get_edb_value(source.magnitude))
|
|
164
|
+
pos_pingroup_terminal.SetSourcePhase(self._get_edb_value(source.phase))
|
|
165
|
+
pos_pingroup_terminal.SetReferenceTerminal(neg_pingroup_terminal)
|
|
166
|
+
try:
|
|
167
|
+
pos_pingroup_terminal.SetName(source.name)
|
|
168
|
+
except Exception as e:
|
|
169
|
+
name = generate_unique_name(source.name)
|
|
170
|
+
pos_pingroup_terminal.SetName(name)
|
|
171
|
+
self._logger.warning("%s already exists. Renaming to %s", source.name, name)
|
|
172
|
+
|
|
173
|
+
elif source.source_type == SourceType.Vsource:
|
|
174
|
+
pos_pingroup_terminal.SetBoundaryType(self._edb.cell.terminal.BoundaryType.kVoltageSource)
|
|
175
|
+
neg_pingroup_terminal.SetBoundaryType(self._edb.cell.terminal.BoundaryType.kVoltageSource)
|
|
176
|
+
pos_pingroup_terminal.SetSourceAmplitude(self._get_edb_value(source.magnitude))
|
|
177
|
+
pos_pingroup_terminal.SetSourcePhase(self._get_edb_value(source.phase))
|
|
178
|
+
pos_pingroup_terminal.SetReferenceTerminal(neg_pingroup_terminal)
|
|
179
|
+
try:
|
|
180
|
+
pos_pingroup_terminal.SetName(source.name)
|
|
181
|
+
except:
|
|
182
|
+
name = generate_unique_name(source.name)
|
|
183
|
+
pos_pingroup_terminal.SetName(name)
|
|
184
|
+
self._logger.warning("%s already exists. Renaming to %s", source.name, name)
|
|
185
|
+
|
|
186
|
+
elif source.source_type == SourceType.Rlc:
|
|
187
|
+
pos_pingroup_terminal.SetBoundaryType(self._edb.cell.terminal.BoundaryType.RlcBoundary)
|
|
188
|
+
neg_pingroup_terminal.SetBoundaryType(self._edb.cell.terminal.BoundaryType.RlcBoundary)
|
|
189
|
+
pos_pingroup_terminal.SetReferenceTerminal(neg_pingroup_terminal)
|
|
190
|
+
pos_pingroup_terminal.SetSourceAmplitude(self._get_edb_value(source.rvalue))
|
|
191
|
+
Rlc = self._edb.utility.utility.Rlc()
|
|
192
|
+
Rlc.CEnabled = False
|
|
193
|
+
Rlc.LEnabled = False
|
|
194
|
+
Rlc.REnabled = True
|
|
195
|
+
Rlc.R = self._get_edb_value(source.rvalue)
|
|
196
|
+
pos_pingroup_terminal.SetRlcBoundaryParameters(Rlc)
|
|
197
|
+
try:
|
|
198
|
+
pos_pingroup_terminal.SetName(source.name)
|
|
199
|
+
except:
|
|
200
|
+
name = generate_unique_name(source.name)
|
|
201
|
+
pos_pingroup_terminal.SetName(name)
|
|
202
|
+
self._logger.warning("%s already exists. Renaming to %s", source.name, name)
|
|
203
|
+
else:
|
|
204
|
+
pass
|
|
205
|
+
return pos_pingroup_terminal.GetName()
|
|
206
|
+
|
|
207
|
+
@pyedb_function_handler()
|
|
208
|
+
def create_circuit_port_on_pin(self, pos_pin, neg_pin, impedance=50, port_name=None):
|
|
209
|
+
"""Create a circuit port on a pin.
|
|
210
|
+
|
|
211
|
+
Parameters
|
|
212
|
+
----------
|
|
213
|
+
pos_pin : Object
|
|
214
|
+
Edb Pin
|
|
215
|
+
neg_pin : Object
|
|
216
|
+
Edb Pin
|
|
217
|
+
impedance : float
|
|
218
|
+
Port Impedance
|
|
219
|
+
port_name : str, optional
|
|
220
|
+
Port Name
|
|
221
|
+
|
|
222
|
+
Returns
|
|
223
|
+
-------
|
|
224
|
+
str
|
|
225
|
+
Port 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.siwave.create_circuit_port_on_pin(pins[0], pins[1], 50, "port_name")
|
|
234
|
+
"""
|
|
235
|
+
circuit_port = CircuitPort()
|
|
236
|
+
circuit_port.positive_node.net = pos_pin.GetNet().GetName()
|
|
237
|
+
circuit_port.negative_node.net = neg_pin.GetNet().GetName()
|
|
238
|
+
circuit_port.impedance = impedance
|
|
239
|
+
|
|
240
|
+
if not port_name:
|
|
241
|
+
port_name = "Port_{}_{}_{}_{}".format(
|
|
242
|
+
pos_pin.GetComponent().GetName(),
|
|
243
|
+
pos_pin.GetNet().GetName(),
|
|
244
|
+
neg_pin.GetComponent().GetName(),
|
|
245
|
+
neg_pin.GetNet().GetName(),
|
|
246
|
+
)
|
|
247
|
+
circuit_port.name = port_name
|
|
248
|
+
circuit_port.positive_node.component_node = pos_pin.GetComponent()
|
|
249
|
+
circuit_port.positive_node.node_pins = pos_pin
|
|
250
|
+
circuit_port.negative_node.component_node = neg_pin.GetComponent()
|
|
251
|
+
circuit_port.negative_node.node_pins = neg_pin
|
|
252
|
+
return self._create_terminal_on_pins(circuit_port)
|
|
253
|
+
|
|
254
|
+
def create_port_between_pin_and_layer(
|
|
255
|
+
self, component_name=None, pins_name=None, layer_name=None, reference_net=None, impedance=50.0
|
|
256
|
+
):
|
|
257
|
+
"""Create circuit port between pin and a reference layer.
|
|
258
|
+
|
|
259
|
+
Parameters
|
|
260
|
+
----------
|
|
261
|
+
component_name : str
|
|
262
|
+
Component name. The default is ``None``.
|
|
263
|
+
pins_name : str
|
|
264
|
+
Pin name or list of pin names. The default is ``None``.
|
|
265
|
+
layer_name : str
|
|
266
|
+
Layer name. The default is ``None``.
|
|
267
|
+
reference_net : str
|
|
268
|
+
Reference net name. The default is ``None``.
|
|
269
|
+
impedance : float, optional
|
|
270
|
+
Port impedance. The default is ``50.0`` in ohms.
|
|
271
|
+
|
|
272
|
+
Returns
|
|
273
|
+
-------
|
|
274
|
+
PadstackInstanceTerminal
|
|
275
|
+
Created terminal.
|
|
276
|
+
|
|
277
|
+
"""
|
|
278
|
+
if not pins_name:
|
|
279
|
+
pins_name = []
|
|
280
|
+
if pins_name:
|
|
281
|
+
if not isinstance(pins_name, list): # pragma no cover
|
|
282
|
+
pins_name = [pins_name]
|
|
283
|
+
if not reference_net:
|
|
284
|
+
self._logger.info("no reference net provided, searching net {} instead.".format(layer_name))
|
|
285
|
+
reference_net = self._pedb.nets.get_net_by_name(layer_name)
|
|
286
|
+
if not reference_net: # pragma no cover
|
|
287
|
+
self._logger.error("reference net {} not found.".format(layer_name))
|
|
288
|
+
return False
|
|
289
|
+
else:
|
|
290
|
+
if not isinstance(reference_net, self._edb.cell.net.net): # pragma no cover
|
|
291
|
+
reference_net = self._pedb.nets.get_net_by_name(reference_net)
|
|
292
|
+
if not reference_net:
|
|
293
|
+
self._logger.error("Net {} not found".format(reference_net))
|
|
294
|
+
return False
|
|
295
|
+
for pin_name in pins_name: # pragma no cover
|
|
296
|
+
pin = [
|
|
297
|
+
pin
|
|
298
|
+
for pin in self._pedb.padstacks.get_pinlist_from_component_and_net(component_name)
|
|
299
|
+
if pin.GetName() == pin_name
|
|
300
|
+
][0]
|
|
301
|
+
term_name = "{}_{}_{}".format(pin.GetComponent().GetName(), pin.GetNet().GetName(), pin.GetName())
|
|
302
|
+
res, start_layer, stop_layer = pin.GetLayerRange()
|
|
303
|
+
if res:
|
|
304
|
+
pin_instance = pin._edb_padstackinstance
|
|
305
|
+
positive_terminal = self._edb.cell.terminal.PadstackInstanceTerminal.Create(
|
|
306
|
+
self._active_layout, pin_instance.GetNet(), term_name, pin_instance, start_layer
|
|
307
|
+
)
|
|
308
|
+
positive_terminal.SetBoundaryType(self._edb.cell.terminal.BoundaryType.PortBoundary)
|
|
309
|
+
positive_terminal.SetImpedance(self._edb.utility.value(impedance))
|
|
310
|
+
positive_terminal.SetIsCircuitPort(True)
|
|
311
|
+
pos = self._pedb.components.get_pin_position(pin_instance)
|
|
312
|
+
position = self._edb.geometry.point_data(
|
|
313
|
+
self._edb.utility.value(pos[0]), self._edb.utility.value(pos[1])
|
|
314
|
+
)
|
|
315
|
+
negative_terminal = self._edb.cell.terminal.PointTerminal.Create(
|
|
316
|
+
self._active_layout,
|
|
317
|
+
reference_net.net_obj,
|
|
318
|
+
"{}_ref".format(term_name),
|
|
319
|
+
position,
|
|
320
|
+
self._pedb.stackup.signal_layers[layer_name]._edb_layer,
|
|
321
|
+
)
|
|
322
|
+
negative_terminal.SetBoundaryType(self._edb.cell.terminal.BoundaryType.PortBoundary)
|
|
323
|
+
negative_terminal.SetImpedance(self._edb.utility.value(impedance))
|
|
324
|
+
negative_terminal.SetIsCircuitPort(True)
|
|
325
|
+
if positive_terminal.SetReferenceTerminal(negative_terminal):
|
|
326
|
+
self._logger.info("Port {} successfully created".format(term_name))
|
|
327
|
+
return positive_terminal
|
|
328
|
+
return False
|
|
329
|
+
|
|
330
|
+
@pyedb_function_handler()
|
|
331
|
+
def create_voltage_source_on_pin(self, pos_pin, neg_pin, voltage_value=3.3, phase_value=0, source_name=""):
|
|
332
|
+
"""Create a voltage source.
|
|
333
|
+
|
|
334
|
+
Parameters
|
|
335
|
+
----------
|
|
336
|
+
pos_pin : Object
|
|
337
|
+
Positive Pin.
|
|
338
|
+
neg_pin : Object
|
|
339
|
+
Negative Pin.
|
|
340
|
+
voltage_value : float, optional
|
|
341
|
+
Value for the voltage. The default is ``3.3``.
|
|
342
|
+
phase_value : optional
|
|
343
|
+
Value for the phase. The default is ``0``.
|
|
344
|
+
source_name : str, optional
|
|
345
|
+
Name of the source. The default is ``""``.
|
|
346
|
+
|
|
347
|
+
Returns
|
|
348
|
+
-------
|
|
349
|
+
str
|
|
350
|
+
Source Name.
|
|
351
|
+
|
|
352
|
+
Examples
|
|
353
|
+
--------
|
|
354
|
+
|
|
355
|
+
>>> from pyedb import Edb
|
|
356
|
+
>>> edbapp = Edb("myaedbfolder", "project name", "release version")
|
|
357
|
+
>>> pins = edbapp.components.get_pin_from_component("U2A5")
|
|
358
|
+
>>> edbapp.siwave.create_voltage_source_on_pin(pins[0], pins[1], 50, "source_name")
|
|
359
|
+
"""
|
|
360
|
+
|
|
361
|
+
voltage_source = VoltageSource()
|
|
362
|
+
voltage_source.positive_node.net = pos_pin.GetNet().GetName()
|
|
363
|
+
voltage_source.negative_node.net = neg_pin.GetNet().GetName()
|
|
364
|
+
voltage_source.magnitude = voltage_value
|
|
365
|
+
voltage_source.phase = phase_value
|
|
366
|
+
if not source_name:
|
|
367
|
+
source_name = "VSource_{}_{}_{}_{}".format(
|
|
368
|
+
pos_pin.GetComponent().GetName(),
|
|
369
|
+
pos_pin.GetNet().GetName(),
|
|
370
|
+
neg_pin.GetComponent().GetName(),
|
|
371
|
+
neg_pin.GetNet().GetName(),
|
|
372
|
+
)
|
|
373
|
+
voltage_source.name = source_name
|
|
374
|
+
voltage_source.positive_node.component_node = pos_pin.GetComponent()
|
|
375
|
+
voltage_source.positive_node.node_pins = pos_pin
|
|
376
|
+
voltage_source.negative_node.component_node = neg_pin.GetComponent()
|
|
377
|
+
voltage_source.negative_node.node_pins = pos_pin
|
|
378
|
+
return self._create_terminal_on_pins(voltage_source)
|
|
379
|
+
|
|
380
|
+
@pyedb_function_handler()
|
|
381
|
+
def create_current_source_on_pin(self, pos_pin, neg_pin, current_value=0.1, phase_value=0, source_name=""):
|
|
382
|
+
"""Create a current source.
|
|
383
|
+
|
|
384
|
+
Parameters
|
|
385
|
+
----------
|
|
386
|
+
pos_pin : Object
|
|
387
|
+
Positive pin.
|
|
388
|
+
neg_pin : Object
|
|
389
|
+
Negative pin.
|
|
390
|
+
current_value : float, optional
|
|
391
|
+
Value for the current. The default is ``0.1``.
|
|
392
|
+
phase_value : optional
|
|
393
|
+
Value for the phase. The default is ``0``.
|
|
394
|
+
source_name : str, optional
|
|
395
|
+
Name of the source. The default is ``""``.
|
|
396
|
+
|
|
397
|
+
Returns
|
|
398
|
+
-------
|
|
399
|
+
str
|
|
400
|
+
Source Name.
|
|
401
|
+
|
|
402
|
+
Examples
|
|
403
|
+
--------
|
|
404
|
+
|
|
405
|
+
>>> from pyedb import Edb
|
|
406
|
+
>>> edbapp = Edb("myaedbfolder", "project name", "release version")
|
|
407
|
+
>>> pins = edbapp.components.get_pin_from_component("U2A5")
|
|
408
|
+
>>> edbapp.siwave.create_current_source_on_pin(pins[0], pins[1], 50, "source_name")
|
|
409
|
+
"""
|
|
410
|
+
current_source = CurrentSource()
|
|
411
|
+
current_source.positive_node.net = pos_pin.GetNet().GetName()
|
|
412
|
+
current_source.negative_node.net = neg_pin.GetNet().GetName()
|
|
413
|
+
current_source.magnitude = current_value
|
|
414
|
+
current_source.phase = phase_value
|
|
415
|
+
if not source_name:
|
|
416
|
+
source_name = "ISource_{}_{}_{}_{}".format(
|
|
417
|
+
pos_pin.GetComponent().GetName(),
|
|
418
|
+
pos_pin.GetNet().GetName(),
|
|
419
|
+
neg_pin.GetComponent().GetName(),
|
|
420
|
+
neg_pin.GetNet().GetName(),
|
|
421
|
+
)
|
|
422
|
+
current_source.name = source_name
|
|
423
|
+
current_source.positive_node.component_node = pos_pin.GetComponent()
|
|
424
|
+
current_source.positive_node.node_pins = pos_pin
|
|
425
|
+
current_source.negative_node.component_node = neg_pin.GetComponent()
|
|
426
|
+
current_source.negative_node.node_pins = neg_pin
|
|
427
|
+
return self._create_terminal_on_pins(current_source)
|
|
428
|
+
|
|
429
|
+
@pyedb_function_handler()
|
|
430
|
+
def create_resistor_on_pin(self, pos_pin, neg_pin, rvalue=1, resistor_name=""):
|
|
431
|
+
"""Create a Resistor boundary between two given pins..
|
|
432
|
+
|
|
433
|
+
Parameters
|
|
434
|
+
----------
|
|
435
|
+
pos_pin : Object
|
|
436
|
+
Positive Pin.
|
|
437
|
+
neg_pin : Object
|
|
438
|
+
Negative Pin.
|
|
439
|
+
rvalue : float, optional
|
|
440
|
+
Resistance value. The default is ``1``.
|
|
441
|
+
resistor_name : str, optional
|
|
442
|
+
Name of the resistor. The default is ``""``.
|
|
443
|
+
|
|
444
|
+
Returns
|
|
445
|
+
-------
|
|
446
|
+
str
|
|
447
|
+
Name of the resistor.
|
|
448
|
+
|
|
449
|
+
Examples
|
|
450
|
+
--------
|
|
451
|
+
|
|
452
|
+
>>> from pyedb import Edb
|
|
453
|
+
>>> edbapp = Edb("myaedbfolder", "project name", "release version")
|
|
454
|
+
>>> pins =edbapp.components.get_pin_from_component("U2A5")
|
|
455
|
+
>>> edbapp.siwave.create_resistor_on_pin(pins[0], pins[1],50,"res_name")
|
|
456
|
+
"""
|
|
457
|
+
resistor = ResistorSource()
|
|
458
|
+
resistor.positive_node.net = pos_pin.GetNet().GetName()
|
|
459
|
+
resistor.negative_node.net = neg_pin.GetNet().GetName()
|
|
460
|
+
resistor.rvalue = rvalue
|
|
461
|
+
if not resistor_name:
|
|
462
|
+
resistor_name = "Res_{}_{}_{}_{}".format(
|
|
463
|
+
pos_pin.GetComponent().GetName(),
|
|
464
|
+
pos_pin.GetNet().GetName(),
|
|
465
|
+
neg_pin.GetComponent().GetName(),
|
|
466
|
+
neg_pin.GetNet().GetName(),
|
|
467
|
+
)
|
|
468
|
+
resistor.name = resistor_name
|
|
469
|
+
resistor.positive_node.component_node = pos_pin.GetComponent()
|
|
470
|
+
resistor.positive_node.node_pins = pos_pin
|
|
471
|
+
resistor.negative_node.component_node = neg_pin.GetComponent()
|
|
472
|
+
resistor.negative_node.node_pins = neg_pin
|
|
473
|
+
return self._create_terminal_on_pins(resistor)
|
|
474
|
+
|
|
475
|
+
@pyedb_function_handler()
|
|
476
|
+
def _check_gnd(self, component_name):
|
|
477
|
+
negative_net_name = None
|
|
478
|
+
if self._pedb.nets.is_net_in_component(component_name, "GND"):
|
|
479
|
+
negative_net_name = "GND"
|
|
480
|
+
elif self._pedb.nets.is_net_in_component(component_name, "PGND"):
|
|
481
|
+
negative_net_name = "PGND"
|
|
482
|
+
elif self._pedb.nets.is_net_in_component(component_name, "AGND"):
|
|
483
|
+
negative_net_name = "AGND"
|
|
484
|
+
elif self._pedb.nets.is_net_in_component(component_name, "DGND"):
|
|
485
|
+
negative_net_name = "DGND"
|
|
486
|
+
if not negative_net_name:
|
|
487
|
+
raise ValueError("No GND, PGND, AGND, DGND found. Please setup the negative net name manually.")
|
|
488
|
+
return negative_net_name
|
|
489
|
+
|
|
490
|
+
@pyedb_function_handler()
|
|
491
|
+
def create_circuit_port_on_net(
|
|
492
|
+
self,
|
|
493
|
+
positive_component_name,
|
|
494
|
+
positive_net_name,
|
|
495
|
+
negative_component_name=None,
|
|
496
|
+
negative_net_name=None,
|
|
497
|
+
impedance_value=50,
|
|
498
|
+
port_name="",
|
|
499
|
+
):
|
|
500
|
+
"""Create a circuit port on a NET.
|
|
501
|
+
|
|
502
|
+
It groups all pins belonging to the specified net and then applies the port on PinGroups.
|
|
503
|
+
|
|
504
|
+
Parameters
|
|
505
|
+
----------
|
|
506
|
+
positive_component_name : str
|
|
507
|
+
Name of the positive component.
|
|
508
|
+
positive_net_name : str
|
|
509
|
+
Name of the positive net.
|
|
510
|
+
negative_component_name : str, optional
|
|
511
|
+
Name of the negative component. The default is ``None``, in which case the name of
|
|
512
|
+
the positive net is assigned.
|
|
513
|
+
negative_net_name : str, optional
|
|
514
|
+
Name of the negative net name. The default is ``None`` which will look for GND Nets.
|
|
515
|
+
impedance_value : float, optional
|
|
516
|
+
Port impedance value. The default is ``50``.
|
|
517
|
+
port_name : str, optional
|
|
518
|
+
Name of the port. The default is ``""``.
|
|
519
|
+
|
|
520
|
+
Returns
|
|
521
|
+
-------
|
|
522
|
+
str
|
|
523
|
+
The name of the port.
|
|
524
|
+
|
|
525
|
+
Examples
|
|
526
|
+
--------
|
|
527
|
+
|
|
528
|
+
>>> from pyedb import Edb
|
|
529
|
+
>>> edbapp = Edb("myaedbfolder", "project name", "release version")
|
|
530
|
+
>>> edbapp.siwave.create_circuit_port_on_net("U2A5", "V1P5_S3", "U2A5", "GND", 50, "port_name")
|
|
531
|
+
"""
|
|
532
|
+
if not negative_component_name:
|
|
533
|
+
negative_component_name = positive_component_name
|
|
534
|
+
if not negative_net_name:
|
|
535
|
+
negative_net_name = self._check_gnd(negative_component_name)
|
|
536
|
+
circuit_port = CircuitPort()
|
|
537
|
+
circuit_port.positive_node.net = positive_net_name
|
|
538
|
+
circuit_port.negative_node.net = negative_net_name
|
|
539
|
+
circuit_port.impedance = impedance_value
|
|
540
|
+
pos_node_cmp = self._pedb.components.get_component_by_name(positive_component_name)
|
|
541
|
+
neg_node_cmp = self._pedb.components.get_component_by_name(negative_component_name)
|
|
542
|
+
pos_node_pins = self._pedb.components.get_pin_from_component(positive_component_name, positive_net_name)
|
|
543
|
+
neg_node_pins = self._pedb.components.get_pin_from_component(negative_component_name, negative_net_name)
|
|
544
|
+
if port_name == "":
|
|
545
|
+
port_name = "Port_{}_{}_{}_{}".format(
|
|
546
|
+
positive_component_name,
|
|
547
|
+
positive_net_name,
|
|
548
|
+
negative_component_name,
|
|
549
|
+
negative_net_name,
|
|
550
|
+
)
|
|
551
|
+
circuit_port.name = port_name
|
|
552
|
+
circuit_port.positive_node.component_node = pos_node_cmp
|
|
553
|
+
circuit_port.positive_node.node_pins = pos_node_pins
|
|
554
|
+
circuit_port.negative_node.component_node = neg_node_cmp
|
|
555
|
+
circuit_port.negative_node.node_pins = neg_node_pins
|
|
556
|
+
return self.create_pin_group_terminal(circuit_port)
|
|
557
|
+
|
|
558
|
+
@pyedb_function_handler()
|
|
559
|
+
def create_voltage_source_on_net(
|
|
560
|
+
self,
|
|
561
|
+
positive_component_name,
|
|
562
|
+
positive_net_name,
|
|
563
|
+
negative_component_name=None,
|
|
564
|
+
negative_net_name=None,
|
|
565
|
+
voltage_value=3.3,
|
|
566
|
+
phase_value=0,
|
|
567
|
+
source_name="",
|
|
568
|
+
):
|
|
569
|
+
"""Create a voltage source.
|
|
570
|
+
|
|
571
|
+
Parameters
|
|
572
|
+
----------
|
|
573
|
+
positive_component_name : str
|
|
574
|
+
Name of the positive component.
|
|
575
|
+
positive_net_name : str
|
|
576
|
+
Name of the positive net.
|
|
577
|
+
negative_component_name : str, optional
|
|
578
|
+
Name of the negative component. The default is ``None``, in which case the name of
|
|
579
|
+
the positive net is assigned.
|
|
580
|
+
negative_net_name : str, optional
|
|
581
|
+
Name of the negative net name. The default is ``None`` which will look for GND Nets.
|
|
582
|
+
voltage_value : float, optional
|
|
583
|
+
Value for the voltage. The default is ``3.3``.
|
|
584
|
+
phase_value : optional
|
|
585
|
+
Value for the phase. The default is ``0``.
|
|
586
|
+
source_name : str, optional
|
|
587
|
+
Name of the source. The default is ``""``.
|
|
588
|
+
|
|
589
|
+
Returns
|
|
590
|
+
-------
|
|
591
|
+
str
|
|
592
|
+
The name of the source.
|
|
593
|
+
|
|
594
|
+
Examples
|
|
595
|
+
--------
|
|
596
|
+
|
|
597
|
+
>>> from pyedb import Edb
|
|
598
|
+
>>> edbapp = Edb("myaedbfolder", "project name", "release version")
|
|
599
|
+
>>> edb.siwave.create_voltage_source_on_net("U2A5","V1P5_S3","U2A5","GND",3.3,0,"source_name")
|
|
600
|
+
"""
|
|
601
|
+
if not negative_component_name:
|
|
602
|
+
negative_component_name = positive_component_name
|
|
603
|
+
if not negative_net_name:
|
|
604
|
+
negative_net_name = self._check_gnd(negative_component_name)
|
|
605
|
+
voltage_source = VoltageSource()
|
|
606
|
+
voltage_source.positive_node.net = positive_net_name
|
|
607
|
+
voltage_source.negative_node.net = negative_net_name
|
|
608
|
+
voltage_source.magnitude = voltage_value
|
|
609
|
+
voltage_source.phase = phase_value
|
|
610
|
+
pos_node_cmp = self._pedb.components.get_component_by_name(positive_component_name)
|
|
611
|
+
neg_node_cmp = self._pedb.components.get_component_by_name(negative_component_name)
|
|
612
|
+
pos_node_pins = self._pedb.components.get_pin_from_component(positive_component_name, positive_net_name)
|
|
613
|
+
neg_node_pins = self._pedb.components.get_pin_from_component(negative_component_name, negative_net_name)
|
|
614
|
+
|
|
615
|
+
if source_name == "":
|
|
616
|
+
source_name = "Vsource_{}_{}_{}_{}".format(
|
|
617
|
+
positive_component_name,
|
|
618
|
+
positive_net_name,
|
|
619
|
+
negative_component_name,
|
|
620
|
+
negative_net_name,
|
|
621
|
+
)
|
|
622
|
+
voltage_source.name = source_name
|
|
623
|
+
voltage_source.positive_node.component_node = pos_node_cmp
|
|
624
|
+
voltage_source.positive_node.node_pins = pos_node_pins
|
|
625
|
+
voltage_source.negative_node.component_node = neg_node_cmp
|
|
626
|
+
voltage_source.negative_node.node_pins = neg_node_pins
|
|
627
|
+
return self.create_pin_group_terminal(voltage_source)
|
|
628
|
+
|
|
629
|
+
@pyedb_function_handler()
|
|
630
|
+
def create_current_source_on_net(
|
|
631
|
+
self,
|
|
632
|
+
positive_component_name,
|
|
633
|
+
positive_net_name,
|
|
634
|
+
negative_component_name=None,
|
|
635
|
+
negative_net_name=None,
|
|
636
|
+
current_value=0.1,
|
|
637
|
+
phase_value=0,
|
|
638
|
+
source_name="",
|
|
639
|
+
):
|
|
640
|
+
"""Create a current source.
|
|
641
|
+
|
|
642
|
+
Parameters
|
|
643
|
+
----------
|
|
644
|
+
positive_component_name : str
|
|
645
|
+
Name of the positive component.
|
|
646
|
+
positive_net_name : str
|
|
647
|
+
Name of the positive net.
|
|
648
|
+
negative_component_name : str, optional
|
|
649
|
+
Name of the negative component. The default is ``None``, in which case the name of
|
|
650
|
+
the positive net is assigned.
|
|
651
|
+
negative_net_name : str, optional
|
|
652
|
+
Name of the negative net name. The default is ``None`` which will look for GND Nets.
|
|
653
|
+
current_value : float, optional
|
|
654
|
+
Value for the current. The default is ``0.1``.
|
|
655
|
+
phase_value : optional
|
|
656
|
+
Value for the phase. The default is ``0``.
|
|
657
|
+
source_name : str, optional
|
|
658
|
+
Name of the source. The default is ``""``.
|
|
659
|
+
|
|
660
|
+
Returns
|
|
661
|
+
-------
|
|
662
|
+
str
|
|
663
|
+
The name of the source.
|
|
664
|
+
|
|
665
|
+
Examples
|
|
666
|
+
--------
|
|
667
|
+
|
|
668
|
+
>>> from pyedb import Edb
|
|
669
|
+
>>> edbapp = Edb("myaedbfolder", "project name", "release version")
|
|
670
|
+
>>> edb.siwave.create_current_source_on_net("U2A5", "V1P5_S3", "U2A5", "GND", 0.1, 0, "source_name")
|
|
671
|
+
"""
|
|
672
|
+
if not negative_component_name:
|
|
673
|
+
negative_component_name = positive_component_name
|
|
674
|
+
if not negative_net_name:
|
|
675
|
+
negative_net_name = self._check_gnd(negative_component_name)
|
|
676
|
+
current_source = CurrentSource()
|
|
677
|
+
current_source.positive_node.net = positive_net_name
|
|
678
|
+
current_source.negative_node.net = negative_net_name
|
|
679
|
+
current_source.magnitude = current_value
|
|
680
|
+
current_source.phase = phase_value
|
|
681
|
+
pos_node_cmp = self._pedb.components.get_component_by_name(positive_component_name)
|
|
682
|
+
neg_node_cmp = self._pedb.components.get_component_by_name(negative_component_name)
|
|
683
|
+
pos_node_pins = self._pedb.components.get_pin_from_component(positive_component_name, positive_net_name)
|
|
684
|
+
neg_node_pins = self._pedb.components.get_pin_from_component(negative_component_name, negative_net_name)
|
|
685
|
+
|
|
686
|
+
if source_name == "":
|
|
687
|
+
source_name = "Port_{}_{}_{}_{}".format(
|
|
688
|
+
positive_component_name,
|
|
689
|
+
positive_net_name,
|
|
690
|
+
negative_component_name,
|
|
691
|
+
negative_net_name,
|
|
692
|
+
)
|
|
693
|
+
current_source.name = source_name
|
|
694
|
+
current_source.positive_node.component_node = pos_node_cmp
|
|
695
|
+
current_source.positive_node.node_pins = pos_node_pins
|
|
696
|
+
current_source.negative_node.component_node = neg_node_cmp
|
|
697
|
+
current_source.negative_node.node_pins = neg_node_pins
|
|
698
|
+
return self.create_pin_group_terminal(current_source)
|
|
699
|
+
|
|
700
|
+
@pyedb_function_handler()
|
|
701
|
+
def create_dc_terminal(
|
|
702
|
+
self,
|
|
703
|
+
component_name,
|
|
704
|
+
net_name,
|
|
705
|
+
source_name="",
|
|
706
|
+
):
|
|
707
|
+
"""Create a dc terminal.
|
|
708
|
+
|
|
709
|
+
Parameters
|
|
710
|
+
----------
|
|
711
|
+
component_name : str
|
|
712
|
+
Name of the positive component.
|
|
713
|
+
net_name : str
|
|
714
|
+
Name of the positive net.
|
|
715
|
+
|
|
716
|
+
source_name : str, optional
|
|
717
|
+
Name of the source. The default is ``""``.
|
|
718
|
+
|
|
719
|
+
Returns
|
|
720
|
+
-------
|
|
721
|
+
str
|
|
722
|
+
The name of the source.
|
|
723
|
+
|
|
724
|
+
Examples
|
|
725
|
+
--------
|
|
726
|
+
|
|
727
|
+
>>> from pyedb import Edb
|
|
728
|
+
>>> edbapp = Edb("myaedbfolder", "project name", "release version")
|
|
729
|
+
>>> edb.siwave.create_dc_terminal("U2A5", "V1P5_S3", "source_name")
|
|
730
|
+
"""
|
|
731
|
+
|
|
732
|
+
dc_source = DCTerminal()
|
|
733
|
+
dc_source.positive_node.net = net_name
|
|
734
|
+
pos_node_cmp = self._pedb.components.get_component_by_name(component_name)
|
|
735
|
+
pos_node_pins = self._pedb.components.get_pin_from_component(component_name, net_name)
|
|
736
|
+
|
|
737
|
+
if source_name == "":
|
|
738
|
+
source_name = "DC_{}_{}".format(
|
|
739
|
+
component_name,
|
|
740
|
+
net_name,
|
|
741
|
+
)
|
|
742
|
+
dc_source.name = source_name
|
|
743
|
+
dc_source.positive_node.component_node = pos_node_cmp
|
|
744
|
+
dc_source.positive_node.node_pins = pos_node_pins
|
|
745
|
+
return self.create_pin_group_terminal(dc_source)
|
|
746
|
+
|
|
747
|
+
@pyedb_function_handler()
|
|
748
|
+
def create_exec_file(
|
|
749
|
+
self, add_dc=False, add_ac=False, add_syz=False, export_touchstone=False, touchstone_file_path=""
|
|
750
|
+
):
|
|
751
|
+
"""Create an executable file.
|
|
752
|
+
|
|
753
|
+
Parameters
|
|
754
|
+
----------
|
|
755
|
+
add_dc : bool, optional
|
|
756
|
+
Whether to add the DC option in the EXE file. The default is ``False``.
|
|
757
|
+
add_ac : bool, optional
|
|
758
|
+
Whether to add the AC option in the EXE file. The default is
|
|
759
|
+
``False``.
|
|
760
|
+
add_syz : bool, optional
|
|
761
|
+
Whether to add the SYZ option in the EXE file
|
|
762
|
+
export_touchstone : bool, optional
|
|
763
|
+
Add the Touchstone file export option in the EXE file.
|
|
764
|
+
The default is ``False``.
|
|
765
|
+
touchstone_file_path : str, optional
|
|
766
|
+
File path for the Touchstone file. The default is ``""``. When no path is
|
|
767
|
+
specified and ``export_touchstone=True``, the path for the project is
|
|
768
|
+
used.
|
|
769
|
+
"""
|
|
770
|
+
workdir = os.path.dirname(self._pedb.edbpath)
|
|
771
|
+
file_name = os.path.join(workdir, os.path.splitext(os.path.basename(self._pedb.edbpath))[0] + ".exec")
|
|
772
|
+
if os.path.isfile(file_name):
|
|
773
|
+
os.remove(file_name)
|
|
774
|
+
with open(file_name, "w") as f:
|
|
775
|
+
if add_ac:
|
|
776
|
+
f.write("ExecAcSim\n")
|
|
777
|
+
if add_dc:
|
|
778
|
+
f.write("ExecDcSim\n")
|
|
779
|
+
if add_syz:
|
|
780
|
+
f.write("ExecSyzSim\n")
|
|
781
|
+
if export_touchstone:
|
|
782
|
+
if touchstone_file_path: # pragma no cover
|
|
783
|
+
f.write('ExportTouchstone "{}"\n'.format(touchstone_file_path))
|
|
784
|
+
else: # pragma no cover
|
|
785
|
+
touchstone_file_path = os.path.join(
|
|
786
|
+
workdir, os.path.splitext(os.path.basename(self._pedb.edbpath))[0] + "_touchstone"
|
|
787
|
+
)
|
|
788
|
+
f.write('ExportTouchstone "{}"\n'.format(touchstone_file_path))
|
|
789
|
+
f.write("SaveSiw\n")
|
|
790
|
+
|
|
791
|
+
return True if os.path.exists(file_name) else False
|
|
792
|
+
|
|
793
|
+
@pyedb_function_handler()
|
|
794
|
+
def add_siwave_syz_analysis(
|
|
795
|
+
self,
|
|
796
|
+
accuracy_level=1,
|
|
797
|
+
decade_count=10,
|
|
798
|
+
sweeptype=1,
|
|
799
|
+
start_freq=1,
|
|
800
|
+
stop_freq=1e9,
|
|
801
|
+
step_freq=1e6,
|
|
802
|
+
discrete_sweep=False,
|
|
803
|
+
):
|
|
804
|
+
"""Add a SIwave AC analysis to EDB.
|
|
805
|
+
|
|
806
|
+
Parameters
|
|
807
|
+
----------
|
|
808
|
+
accuracy_level : int, optional
|
|
809
|
+
Level of accuracy of SI slider. The default is ``1``.
|
|
810
|
+
decade_count : int
|
|
811
|
+
The default is ``10``. The value for this parameter is used for these sweep types:
|
|
812
|
+
linear count and decade count.
|
|
813
|
+
This parameter is alternative to ``step_freq``, which is used for a linear scale sweep.
|
|
814
|
+
sweeptype : int, optional
|
|
815
|
+
Type of the sweep. The default is ``1``. Options are:
|
|
816
|
+
|
|
817
|
+
- ``0``: linear count
|
|
818
|
+
- ``1``: linear scale
|
|
819
|
+
- ``2``: loc scale
|
|
820
|
+
start_freq : float, optional
|
|
821
|
+
Starting frequency. The default is ``1``.
|
|
822
|
+
stop_freq : float, optional
|
|
823
|
+
Stopping frequency. The default is ``1e9``.
|
|
824
|
+
step_freq : float, optional
|
|
825
|
+
Frequency size of the step. The default is ``1e6``.
|
|
826
|
+
discrete_sweep : bool, optional
|
|
827
|
+
Whether the sweep is discrete. The default is ``False``.
|
|
828
|
+
|
|
829
|
+
Returns
|
|
830
|
+
-------
|
|
831
|
+
:class:`pyedb.dotnet.edb_core.edb_data.siwave_simulation_setup_data.SiwaveSYZSimulationSetup`
|
|
832
|
+
Setup object class.
|
|
833
|
+
"""
|
|
834
|
+
setup = self._pedb.create_siwave_syz_setup()
|
|
835
|
+
sweep = "linear count"
|
|
836
|
+
if sweeptype == 2:
|
|
837
|
+
sweep = "log scale"
|
|
838
|
+
elif sweeptype == 0:
|
|
839
|
+
sweep = "linear scale"
|
|
840
|
+
start_freq = self._pedb.number_with_units(start_freq, "Hz")
|
|
841
|
+
stop_freq = self._pedb.number_with_units(stop_freq, "Hz")
|
|
842
|
+
third_arg = int(decade_count)
|
|
843
|
+
if sweeptype == 0:
|
|
844
|
+
third_arg = self._pedb.number_with_units(step_freq, "Hz")
|
|
845
|
+
setup.si_slider_position = int(accuracy_level)
|
|
846
|
+
sweep = setup.add_frequency_sweep(
|
|
847
|
+
frequency_sweep=[
|
|
848
|
+
[sweep, start_freq, stop_freq, third_arg],
|
|
849
|
+
]
|
|
850
|
+
)
|
|
851
|
+
if discrete_sweep:
|
|
852
|
+
sweep.freq_sweep_type = "kDiscreteSweep"
|
|
853
|
+
|
|
854
|
+
self.create_exec_file(add_ac=True)
|
|
855
|
+
return setup
|
|
856
|
+
|
|
857
|
+
@pyedb_function_handler()
|
|
858
|
+
def add_siwave_dc_analysis(self, name=None):
|
|
859
|
+
"""Add a Siwave DC analysis in EDB.
|
|
860
|
+
|
|
861
|
+
If a setup is present, it is deleted and replaced with
|
|
862
|
+
actual settings.
|
|
863
|
+
|
|
864
|
+
.. note::
|
|
865
|
+
Source Reference to Ground settings works only from 2021.2
|
|
866
|
+
|
|
867
|
+
Parameters
|
|
868
|
+
----------
|
|
869
|
+
name : str, optional
|
|
870
|
+
Setup name.
|
|
871
|
+
|
|
872
|
+
Returns
|
|
873
|
+
-------
|
|
874
|
+
:class:`pyedb.dotnet.edb_core.edb_data.siwave_simulation_setup_data.SiwaveDCSimulationSetup`
|
|
875
|
+
Setup object class.
|
|
876
|
+
|
|
877
|
+
Examples
|
|
878
|
+
--------
|
|
879
|
+
>>> from pyedb import Edb
|
|
880
|
+
>>> edb = Edb("pathtoaedb", edbversion="2021.2")
|
|
881
|
+
>>> edb.siwave.add_siwave_ac_analysis()
|
|
882
|
+
>>> edb.siwave.add_siwave_dc_analysis2("my_setup")
|
|
883
|
+
|
|
884
|
+
"""
|
|
885
|
+
setup = self._pedb.create_siwave_dc_setup(name)
|
|
886
|
+
self.create_exec_file(add_dc=True)
|
|
887
|
+
return setup
|
|
888
|
+
|
|
889
|
+
@pyedb_function_handler()
|
|
890
|
+
def create_pin_group_terminal(self, source):
|
|
891
|
+
"""Create a pin group terminal.
|
|
892
|
+
|
|
893
|
+
Parameters
|
|
894
|
+
----------
|
|
895
|
+
source : VoltageSource, CircuitPort, CurrentSource, DCTerminal or ResistorSource
|
|
896
|
+
Name of the source.
|
|
897
|
+
|
|
898
|
+
"""
|
|
899
|
+
if source.name in [i.GetName() for i in self._layout.terminals]:
|
|
900
|
+
source.name = generate_unique_name(source.name, n=3)
|
|
901
|
+
self._logger.warning("Port already exists with same name. Renaming to {}".format(source.name))
|
|
902
|
+
pos_pin_group = self._pedb.components.create_pingroup_from_pins(source.positive_node.node_pins)
|
|
903
|
+
pos_node_net = self._pedb.nets.get_net_by_name(source.positive_node.net)
|
|
904
|
+
|
|
905
|
+
pos_pingroup_term_name = source.name
|
|
906
|
+
pos_pingroup_terminal = _retry_ntimes(
|
|
907
|
+
10,
|
|
908
|
+
self._edb.cell.terminal.PinGroupTerminal.Create,
|
|
909
|
+
self._active_layout,
|
|
910
|
+
pos_node_net.net_obj,
|
|
911
|
+
pos_pingroup_term_name,
|
|
912
|
+
pos_pin_group,
|
|
913
|
+
False,
|
|
914
|
+
)
|
|
915
|
+
time.sleep(0.5)
|
|
916
|
+
if source.negative_node.node_pins:
|
|
917
|
+
neg_pin_group = self._pedb.components.create_pingroup_from_pins(source.negative_node.node_pins)
|
|
918
|
+
neg_node_net = self._pedb.nets.get_net_by_name(source.negative_node.net)
|
|
919
|
+
neg_pingroup_term_name = source.name + "_N"
|
|
920
|
+
neg_pingroup_terminal = _retry_ntimes(
|
|
921
|
+
20,
|
|
922
|
+
self._edb.cell.terminal.PinGroupTerminal.Create,
|
|
923
|
+
self._active_layout,
|
|
924
|
+
neg_node_net.net_obj,
|
|
925
|
+
neg_pingroup_term_name,
|
|
926
|
+
neg_pin_group,
|
|
927
|
+
False,
|
|
928
|
+
)
|
|
929
|
+
|
|
930
|
+
if source.source_type in [SourceType.CoaxPort, SourceType.CircPort, SourceType.LumpedPort]:
|
|
931
|
+
pos_pingroup_terminal.SetBoundaryType(self._edb.cell.terminal.BoundaryType.PortBoundary)
|
|
932
|
+
neg_pingroup_terminal.SetBoundaryType(self._edb.cell.terminal.BoundaryType.PortBoundary)
|
|
933
|
+
pos_pingroup_terminal.SetSourceAmplitude(self._get_edb_value(source.impedance))
|
|
934
|
+
if source.source_type == SourceType.CircPort:
|
|
935
|
+
pos_pingroup_terminal.SetIsCircuitPort(True)
|
|
936
|
+
neg_pingroup_terminal.SetIsCircuitPort(True)
|
|
937
|
+
pos_pingroup_terminal.SetReferenceTerminal(neg_pingroup_terminal)
|
|
938
|
+
try:
|
|
939
|
+
pos_pingroup_terminal.SetName(source.name)
|
|
940
|
+
except:
|
|
941
|
+
name = generate_unique_name(source.name)
|
|
942
|
+
pos_pingroup_terminal.SetName(name)
|
|
943
|
+
self._logger.warning("%s already exists. Renaming to %s", source.name, name)
|
|
944
|
+
|
|
945
|
+
elif source.source_type == SourceType.Isource:
|
|
946
|
+
pos_pingroup_terminal.SetBoundaryType(self._edb.cell.terminal.BoundaryType.kCurrentSource)
|
|
947
|
+
neg_pingroup_terminal.SetBoundaryType(self._edb.cell.terminal.BoundaryType.kCurrentSource)
|
|
948
|
+
pos_pingroup_terminal.SetSourceAmplitude(self._get_edb_value(source.magnitude))
|
|
949
|
+
pos_pingroup_terminal.SetSourcePhase(self._edb.utility.value(source.phase))
|
|
950
|
+
pos_pingroup_terminal.SetReferenceTerminal(neg_pingroup_terminal)
|
|
951
|
+
try:
|
|
952
|
+
pos_pingroup_terminal.SetName(source.name)
|
|
953
|
+
except Exception as e:
|
|
954
|
+
name = generate_unique_name(source.name)
|
|
955
|
+
pos_pingroup_terminal.SetName(name)
|
|
956
|
+
self._logger.warning("%s already exists. Renaming to %s", source.name, name)
|
|
957
|
+
|
|
958
|
+
elif source.source_type == SourceType.Vsource:
|
|
959
|
+
pos_pingroup_terminal.SetBoundaryType(self._edb.cell.terminal.BoundaryType.kVoltageSource)
|
|
960
|
+
neg_pingroup_terminal.SetBoundaryType(self._edb.cell.terminal.BoundaryType.kVoltageSource)
|
|
961
|
+
pos_pingroup_terminal.SetSourceAmplitude(self._get_edb_value(source.magnitude))
|
|
962
|
+
pos_pingroup_terminal.SetSourcePhase(self._get_edb_value(source.phase))
|
|
963
|
+
pos_pingroup_terminal.SetReferenceTerminal(neg_pingroup_terminal)
|
|
964
|
+
try:
|
|
965
|
+
pos_pingroup_terminal.SetName(source.name)
|
|
966
|
+
except:
|
|
967
|
+
name = generate_unique_name(source.name)
|
|
968
|
+
pos_pingroup_terminal.SetName(name)
|
|
969
|
+
self._logger.warning("%s already exists. Renaming to %s", source.name, name)
|
|
970
|
+
|
|
971
|
+
elif source.source_type == SourceType.Rlc:
|
|
972
|
+
pos_pingroup_terminal.SetBoundaryType(self._edb.cell.terminal.BoundaryType.RlcBoundary)
|
|
973
|
+
neg_pingroup_terminal.SetBoundaryType(self._edb.cell.terminal.BoundaryType.RlcBoundary)
|
|
974
|
+
pos_pingroup_terminal.SetReferenceTerminal(neg_pingroup_terminal)
|
|
975
|
+
pos_pingroup_terminal.SetSourceAmplitude(self._get_edb_value(source.rvalue))
|
|
976
|
+
Rlc = self._edb.utility.utility.Rlc()
|
|
977
|
+
Rlc.CEnabled = False
|
|
978
|
+
Rlc.LEnabled = False
|
|
979
|
+
Rlc.REnabled = True
|
|
980
|
+
Rlc.R = self._get_edb_value(source.rvalue)
|
|
981
|
+
pos_pingroup_terminal.SetRlcBoundaryParameters(Rlc)
|
|
982
|
+
elif source.source_type == SourceType.DcTerminal:
|
|
983
|
+
pos_pingroup_terminal.SetBoundaryType(self._edb.cell.terminal.BoundaryType.kDcTerminal)
|
|
984
|
+
else:
|
|
985
|
+
pass
|
|
986
|
+
return pos_pingroup_terminal.GetName()
|
|
987
|
+
|
|
988
|
+
@pyedb_function_handler()
|
|
989
|
+
def configure_siw_analysis_setup(self, simulation_setup=None, delete_existing_setup=True):
|
|
990
|
+
"""Configure Siwave analysis setup.
|
|
991
|
+
|
|
992
|
+
Parameters
|
|
993
|
+
----------
|
|
994
|
+
simulation_setup :
|
|
995
|
+
Edb_DATA.SimulationConfiguration object.
|
|
996
|
+
|
|
997
|
+
Returns
|
|
998
|
+
-------
|
|
999
|
+
bool
|
|
1000
|
+
``True`` when successful, ``False`` when failed.
|
|
1001
|
+
"""
|
|
1002
|
+
|
|
1003
|
+
if not isinstance(simulation_setup, SimulationConfiguration): # pragma: no cover
|
|
1004
|
+
return False
|
|
1005
|
+
if simulation_setup.solver_type == SolverType.SiwaveSYZ: # pragma: no cover
|
|
1006
|
+
simsetup_info = self._pedb.simsetupdata.SimSetupInfo[self._pedb.simsetupdata.SIwave.SIWSimulationSettings]()
|
|
1007
|
+
simsetup_info.Name = simulation_setup.setup_name
|
|
1008
|
+
simsetup_info.SimulationSettings.AdvancedSettings.PerformERC = False
|
|
1009
|
+
simsetup_info.SimulationSettings.UseCustomSettings = True
|
|
1010
|
+
if simulation_setup.mesh_freq: # pragma: no cover
|
|
1011
|
+
if isinstance(simulation_setup.mesh_freq, str):
|
|
1012
|
+
simsetup_info.SimulationSettings.UseCustomSettings = True
|
|
1013
|
+
simsetup_info.SimulationSettings.AdvancedSettings.MeshAutoMatic = False
|
|
1014
|
+
simsetup_info.SimulationSettings.AdvancedSettings.MeshFrequency = simulation_setup.mesh_freq
|
|
1015
|
+
else:
|
|
1016
|
+
self._logger.warning("Meshing frequency value must be a string with units")
|
|
1017
|
+
if simulation_setup.include_inter_plane_coupling: # pragma: no cover
|
|
1018
|
+
simsetup_info.SimulationSettings.AdvancedSettings.IncludeInterPlaneCoupling = (
|
|
1019
|
+
simulation_setup.include_inter_plane_coupling
|
|
1020
|
+
)
|
|
1021
|
+
if abs(simulation_setup.xtalk_threshold): # pragma: no cover
|
|
1022
|
+
simsetup_info.SimulationSettings.AdvancedSettings.XtalkThreshold = str(simulation_setup.xtalk_threshold)
|
|
1023
|
+
if simulation_setup.min_void_area: # pragma: no cover
|
|
1024
|
+
simsetup_info.SimulationSettings.AdvancedSettings.MinVoidArea = simulation_setup.min_void_area
|
|
1025
|
+
if simulation_setup.min_pad_area_to_mesh: # pragma: no cover
|
|
1026
|
+
simsetup_info.SimulationSettings.AdvancedSettings.MinPadAreaToMesh = (
|
|
1027
|
+
simulation_setup.min_pad_area_to_mesh
|
|
1028
|
+
)
|
|
1029
|
+
if simulation_setup.min_plane_area_to_mesh: # pragma: no cover
|
|
1030
|
+
simsetup_info.SimulationSettings.AdvancedSettings.MinPlaneAreaToMesh = (
|
|
1031
|
+
simulation_setup.min_plane_area_to_mesh
|
|
1032
|
+
)
|
|
1033
|
+
if simulation_setup.snap_length_threshold: # pragma: no cover
|
|
1034
|
+
simsetup_info.SimulationSettings.AdvancedSettings.SnapLengthThreshold = (
|
|
1035
|
+
simulation_setup.snap_length_threshold
|
|
1036
|
+
)
|
|
1037
|
+
if simulation_setup.return_current_distribution: # pragma: no cover
|
|
1038
|
+
simsetup_info.SimulationSettings.AdvancedSettings.ReturnCurrentDistribution = (
|
|
1039
|
+
simulation_setup.return_current_distribution
|
|
1040
|
+
)
|
|
1041
|
+
if simulation_setup.ignore_non_functional_pads: # pragma: no cover
|
|
1042
|
+
simsetup_info.SimulationSettings.AdvancedSettings.IgnoreNonFunctionalPads = (
|
|
1043
|
+
simulation_setup.ignore_non_functional_pads
|
|
1044
|
+
)
|
|
1045
|
+
if simulation_setup.min_void_area: # pragma: no cover
|
|
1046
|
+
simsetup_info.SimulationSettings.DCAdvancedSettings.DcMinVoidAreaToMesh = simulation_setup.min_void_area
|
|
1047
|
+
try:
|
|
1048
|
+
if simulation_setup.add_frequency_sweep:
|
|
1049
|
+
self._logger.info("Adding frequency sweep")
|
|
1050
|
+
sweep = self._pedb.simsetupdata.SweepData(simulation_setup.sweep_name)
|
|
1051
|
+
sweep.IsDiscrete = False # need True for package??
|
|
1052
|
+
sweep.UseQ3DForDC = simulation_setup.use_q3d_for_dc
|
|
1053
|
+
sweep.RelativeSError = simulation_setup.relative_error
|
|
1054
|
+
sweep.InterpUsePortImpedance = False
|
|
1055
|
+
sweep.EnforceCausality = (GeometryOperators.parse_dim_arg(simulation_setup.start_freq) - 0) < 1e-9
|
|
1056
|
+
sweep.EnforcePassivity = simulation_setup.enforce_passivity
|
|
1057
|
+
sweep.PassivityTolerance = simulation_setup.passivity_tolerance
|
|
1058
|
+
sweep.Frequencies.Clear()
|
|
1059
|
+
if simulation_setup.sweep_type == SweepType.LogCount: # pragma: no cover
|
|
1060
|
+
self._setup_decade_count_sweep(
|
|
1061
|
+
sweep,
|
|
1062
|
+
simulation_setup.start_freq,
|
|
1063
|
+
simulation_setup.stop_freq,
|
|
1064
|
+
simulation_setup.decade_count,
|
|
1065
|
+
)
|
|
1066
|
+
else:
|
|
1067
|
+
sweep.Frequencies = self._pedb.simsetupdata.SweepData.SetFrequencies(
|
|
1068
|
+
simulation_setup.start_freq, simulation_setup.stop_freq, simulation_setup.step_freq
|
|
1069
|
+
)
|
|
1070
|
+
simsetup_info.SweepDataList.Add(sweep)
|
|
1071
|
+
else:
|
|
1072
|
+
self._logger.info("Adding frequency sweep disabled")
|
|
1073
|
+
except Exception as err:
|
|
1074
|
+
self._logger.error("Exception in sweep configuration: {0}.".format(err))
|
|
1075
|
+
edb_sim_setup = self._edb.utility.utility.SIWaveSimulationSetup(simsetup_info)
|
|
1076
|
+
for setup in self._cell.SimulationSetups:
|
|
1077
|
+
self._cell.DeleteSimulationSetup(setup.GetName())
|
|
1078
|
+
self._logger.warning("Setup {} has been deleted".format(setup.GetName()))
|
|
1079
|
+
return self._cell.AddSimulationSetup(edb_sim_setup)
|
|
1080
|
+
if simulation_setup.solver_type == SolverType.SiwaveDC: # pragma: no cover
|
|
1081
|
+
dcir_setup = self._pedb.simsetupdata.SimSetupInfo[
|
|
1082
|
+
self._pedb.simsetupdata.SIwave.SIWDCIRSimulationSettings
|
|
1083
|
+
]()
|
|
1084
|
+
dcir_setup.Name = simulation_setup.setup_name
|
|
1085
|
+
dcir_setup.SimulationSettings.DCSettings.ComputeInductance = simulation_setup.dc_compute_inductance
|
|
1086
|
+
dcir_setup.SimulationSettings.DCSettings.ContactRadius = simulation_setup.dc_contact_radius
|
|
1087
|
+
dcir_setup.SimulationSettings.DCSettings.DCSliderPos = simulation_setup.dc_slide_position
|
|
1088
|
+
dcir_setup.SimulationSettings.DCSettings.PlotJV = simulation_setup.dc_plot_jv
|
|
1089
|
+
dcir_setup.SimulationSettings.DCSettings.UseDCCustomSettings = simulation_setup.dc_use_dc_custom_settings
|
|
1090
|
+
dcir_setup.SimulationSettings.DCAdvancedSettings.DcMinPlaneAreaToMesh = (
|
|
1091
|
+
simulation_setup.dc_min_plane_area_to_mesh
|
|
1092
|
+
)
|
|
1093
|
+
dcir_setup.SimulationSettings.DCAdvancedSettings.DcMinVoidAreaToMesh = (
|
|
1094
|
+
simulation_setup.dc_min_void_area_to_mesh
|
|
1095
|
+
)
|
|
1096
|
+
dcir_setup.SimulationSettings.DCAdvancedSettings.EnergyError = simulation_setup.dc_error_energy
|
|
1097
|
+
dcir_setup.SimulationSettings.DCAdvancedSettings.MaxInitMeshEdgeLength = (
|
|
1098
|
+
simulation_setup.dc_max_init_mesh_edge_length
|
|
1099
|
+
)
|
|
1100
|
+
dcir_setup.SimulationSettings.DCAdvancedSettings.MaxNumPasses = simulation_setup.dc_max_num_pass
|
|
1101
|
+
dcir_setup.SimulationSettings.DCAdvancedSettings.MeshBws = simulation_setup.dc_mesh_bondwires
|
|
1102
|
+
dcir_setup.SimulationSettings.DCAdvancedSettings.MeshVias = simulation_setup.dc_mesh_vias
|
|
1103
|
+
dcir_setup.SimulationSettings.DCAdvancedSettings.MinNumPasses = simulation_setup.dc_min_num_pass
|
|
1104
|
+
dcir_setup.SimulationSettings.DCAdvancedSettings.NumBwSides = simulation_setup.dc_num_bondwire_sides
|
|
1105
|
+
dcir_setup.SimulationSettings.DCAdvancedSettings.NumViaSides = simulation_setup.dc_num_via_sides
|
|
1106
|
+
dcir_setup.SimulationSettings.DCAdvancedSettings.PercentLocalRefinement = (
|
|
1107
|
+
simulation_setup.dc_percent_local_refinement
|
|
1108
|
+
)
|
|
1109
|
+
dcir_setup.SimulationSettings.DCAdvancedSettings.PerformAdaptiveRefinement = (
|
|
1110
|
+
simulation_setup.dc_perform_adaptive_refinement
|
|
1111
|
+
)
|
|
1112
|
+
dcir_setup.SimulationSettings.DCAdvancedSettings.RefineBws = simulation_setup.dc_refine_bondwires
|
|
1113
|
+
dcir_setup.SimulationSettings.DCAdvancedSettings.RefineVias = simulation_setup.dc_refine_vias
|
|
1114
|
+
|
|
1115
|
+
dcir_setup.SimulationSettings.DCIRSettings.DCReportConfigFile = simulation_setup.dc_report_config_file
|
|
1116
|
+
dcir_setup.SimulationSettings.DCIRSettings.DCReportShowActiveDevices = (
|
|
1117
|
+
simulation_setup.dc_report_show_Active_devices
|
|
1118
|
+
)
|
|
1119
|
+
dcir_setup.SimulationSettings.DCIRSettings.ExportDCThermalData = simulation_setup.dc_export_thermal_data
|
|
1120
|
+
dcir_setup.SimulationSettings.DCIRSettings.FullDCReportPath = simulation_setup.dc_full_report_path
|
|
1121
|
+
dcir_setup.SimulationSettings.DCIRSettings.IcepakTempFile = simulation_setup.dc_icepak_temp_file
|
|
1122
|
+
dcir_setup.SimulationSettings.DCIRSettings.ImportThermalData = simulation_setup.dc_import_thermal_data
|
|
1123
|
+
dcir_setup.SimulationSettings.DCIRSettings.PerPinResPath = simulation_setup.dc_per_pin_res_path
|
|
1124
|
+
dcir_setup.SimulationSettings.DCIRSettings.PerPinUsePinFormat = simulation_setup.dc_per_pin_use_pin_format
|
|
1125
|
+
dcir_setup.SimulationSettings.DCIRSettings.UseLoopResForPerPin = (
|
|
1126
|
+
simulation_setup.dc_use_loop_res_for_per_pin
|
|
1127
|
+
)
|
|
1128
|
+
dcir_setup.SimulationSettings.DCIRSettings.ViaReportPath = simulation_setup.dc_via_report_path
|
|
1129
|
+
dcir_setup.SimulationSettings.DCIRSettings.SourceTermsToGround = simulation_setup.dc_source_terms_to_ground
|
|
1130
|
+
dcir_setup.Name = simulation_setup.setup_name
|
|
1131
|
+
sim_setup = self._edb.utility.utility.SIWaveDCIRSimulationSetup(dcir_setup)
|
|
1132
|
+
for setup in self._cell.SimulationSetups:
|
|
1133
|
+
self._cell.DeleteSimulationSetup(setup.GetName())
|
|
1134
|
+
self._logger.warning("Setup {} has been delete".format(setup.GetName()))
|
|
1135
|
+
return self._cell.AddSimulationSetup(sim_setup)
|
|
1136
|
+
|
|
1137
|
+
@pyedb_function_handler()
|
|
1138
|
+
def _setup_decade_count_sweep(self, sweep, start_freq, stop_freq, decade_count):
|
|
1139
|
+
import math
|
|
1140
|
+
|
|
1141
|
+
start_f = GeometryOperators.parse_dim_arg(start_freq)
|
|
1142
|
+
if start_f == 0.0:
|
|
1143
|
+
start_f = 10
|
|
1144
|
+
self._logger.warning(
|
|
1145
|
+
"Decade count sweep does not support a DC value. Defaulting starting frequency to 10Hz."
|
|
1146
|
+
)
|
|
1147
|
+
|
|
1148
|
+
stop_f = GeometryOperators.parse_dim_arg(stop_freq)
|
|
1149
|
+
decade_cnt = GeometryOperators.parse_dim_arg(decade_count)
|
|
1150
|
+
freq = start_f
|
|
1151
|
+
sweep.Frequencies.Add(str(freq))
|
|
1152
|
+
while freq < stop_f:
|
|
1153
|
+
freq = freq * math.pow(10, 1.0 / decade_cnt)
|
|
1154
|
+
sweep.Frequencies.Add(str(freq))
|
|
1155
|
+
|
|
1156
|
+
@pyedb_function_handler()
|
|
1157
|
+
def create_rlc_component(
|
|
1158
|
+
self,
|
|
1159
|
+
pins,
|
|
1160
|
+
component_name="",
|
|
1161
|
+
r_value=1.0,
|
|
1162
|
+
c_value=1e-9,
|
|
1163
|
+
l_value=1e-9,
|
|
1164
|
+
is_parallel=False,
|
|
1165
|
+
):
|
|
1166
|
+
"""Create physical Rlc component.
|
|
1167
|
+
|
|
1168
|
+
Parameters
|
|
1169
|
+
----------
|
|
1170
|
+
pins : list[Edb.Primitive.PadstackInstance]
|
|
1171
|
+
List of EDB pins, length must be 2, since only 2 pins component are currently supported.
|
|
1172
|
+
|
|
1173
|
+
component_name : str
|
|
1174
|
+
Component name.
|
|
1175
|
+
|
|
1176
|
+
r_value : float
|
|
1177
|
+
Resistor value.
|
|
1178
|
+
|
|
1179
|
+
c_value : float
|
|
1180
|
+
Capacitance value.
|
|
1181
|
+
|
|
1182
|
+
l_value : float
|
|
1183
|
+
Inductor value.
|
|
1184
|
+
|
|
1185
|
+
is_parallel : bool
|
|
1186
|
+
Using parallel model when ``True``, series when ``False``.
|
|
1187
|
+
|
|
1188
|
+
Returns
|
|
1189
|
+
-------
|
|
1190
|
+
class:`pyedb.dotnet.edb_core.components.Components`
|
|
1191
|
+
Created EDB component.
|
|
1192
|
+
|
|
1193
|
+
"""
|
|
1194
|
+
return self._pedb.components.create(
|
|
1195
|
+
pins,
|
|
1196
|
+
component_name=component_name,
|
|
1197
|
+
is_rlc=True,
|
|
1198
|
+
r_value=r_value,
|
|
1199
|
+
c_value=c_value,
|
|
1200
|
+
l_value=l_value,
|
|
1201
|
+
is_parallel=is_parallel,
|
|
1202
|
+
) # pragma no cover
|
|
1203
|
+
|
|
1204
|
+
@pyedb_function_handler()
|
|
1205
|
+
def create_pin_group(self, reference_designator, pin_numbers, group_name=None):
|
|
1206
|
+
"""Create pin group on the component.
|
|
1207
|
+
|
|
1208
|
+
Parameters
|
|
1209
|
+
----------
|
|
1210
|
+
reference_designator : str
|
|
1211
|
+
References designator of the component.
|
|
1212
|
+
pin_numbers : int, str, list
|
|
1213
|
+
List of pin names.
|
|
1214
|
+
group_name : str, optional
|
|
1215
|
+
Name of the pin group.
|
|
1216
|
+
|
|
1217
|
+
Returns
|
|
1218
|
+
-------
|
|
1219
|
+
PinGroup
|
|
1220
|
+
"""
|
|
1221
|
+
if not isinstance(pin_numbers, list):
|
|
1222
|
+
pin_numbers = [pin_numbers]
|
|
1223
|
+
pin_numbers = [str(p) for p in pin_numbers]
|
|
1224
|
+
if group_name is None:
|
|
1225
|
+
group_name = self._edb.cell.hierarchy.pin_group.GetUniqueName(self._active_layout)
|
|
1226
|
+
comp = self._pedb.components.components[reference_designator]
|
|
1227
|
+
pins = [pin.pin for name, pin in comp.pins.items() if name in pin_numbers]
|
|
1228
|
+
edb_pingroup = self._edb.cell.hierarchy.pin_group.Create(
|
|
1229
|
+
self._active_layout, group_name, convert_py_list_to_net_list(pins)
|
|
1230
|
+
)
|
|
1231
|
+
|
|
1232
|
+
if edb_pingroup.IsNull(): # pragma: no cover
|
|
1233
|
+
return False
|
|
1234
|
+
else:
|
|
1235
|
+
edb_pingroup.SetNet(pins[0].GetNet())
|
|
1236
|
+
return group_name, self.pin_groups[group_name]
|
|
1237
|
+
|
|
1238
|
+
@pyedb_function_handler()
|
|
1239
|
+
def create_pin_group_on_net(self, reference_designator, net_name, group_name=None):
|
|
1240
|
+
"""Create pin group on component by net name.
|
|
1241
|
+
|
|
1242
|
+
Parameters
|
|
1243
|
+
----------
|
|
1244
|
+
reference_designator : str
|
|
1245
|
+
References designator of the component.
|
|
1246
|
+
net_name : str
|
|
1247
|
+
Name of the net.
|
|
1248
|
+
group_name : str, optional
|
|
1249
|
+
Name of the pin group. The default value is ``None``.
|
|
1250
|
+
|
|
1251
|
+
Returns
|
|
1252
|
+
-------
|
|
1253
|
+
PinGroup
|
|
1254
|
+
"""
|
|
1255
|
+
pins = self._pedb.components.get_pin_from_component(reference_designator, net_name)
|
|
1256
|
+
pin_names = [p.GetName() for p in pins]
|
|
1257
|
+
return self.create_pin_group(reference_designator, pin_names, group_name)
|
|
1258
|
+
|
|
1259
|
+
@pyedb_function_handler()
|
|
1260
|
+
def create_current_source_on_pin_group(
|
|
1261
|
+
self, pos_pin_group_name, neg_pin_group_name, magnitude=1, phase=0, name=None
|
|
1262
|
+
):
|
|
1263
|
+
"""Create current source between two pin groups.
|
|
1264
|
+
|
|
1265
|
+
Parameters
|
|
1266
|
+
----------
|
|
1267
|
+
pos_pin_group_name : str
|
|
1268
|
+
Name of the positive pin group.
|
|
1269
|
+
neg_pin_group_name : str
|
|
1270
|
+
Name of the negative pin group.
|
|
1271
|
+
magnitude : int, float, optional
|
|
1272
|
+
Magnitude of the source.
|
|
1273
|
+
phase : int, float, optional
|
|
1274
|
+
Phase of the source
|
|
1275
|
+
|
|
1276
|
+
Returns
|
|
1277
|
+
-------
|
|
1278
|
+
bool
|
|
1279
|
+
|
|
1280
|
+
"""
|
|
1281
|
+
pos_pin_group = self.pin_groups[pos_pin_group_name]
|
|
1282
|
+
pos_terminal = pos_pin_group.create_current_source_terminal(magnitude, phase)
|
|
1283
|
+
if name:
|
|
1284
|
+
pos_terminal.SetName(name)
|
|
1285
|
+
else:
|
|
1286
|
+
name = generate_unique_name("isource")
|
|
1287
|
+
pos_terminal.SetName(name)
|
|
1288
|
+
neg_pin_group_name = self.pin_groups[neg_pin_group_name]
|
|
1289
|
+
neg_terminal = neg_pin_group_name.create_current_source_terminal()
|
|
1290
|
+
neg_terminal.SetName(name + "_ref")
|
|
1291
|
+
pos_terminal.SetReferenceTerminal(neg_terminal)
|
|
1292
|
+
return True
|
|
1293
|
+
|
|
1294
|
+
@pyedb_function_handler()
|
|
1295
|
+
def create_voltage_source_on_pin_group(
|
|
1296
|
+
self, pos_pin_group_name, neg_pin_group_name, magnitude=1, phase=0, name=None, impedance=0.001
|
|
1297
|
+
):
|
|
1298
|
+
"""Create voltage source between two pin groups.
|
|
1299
|
+
|
|
1300
|
+
Parameters
|
|
1301
|
+
----------
|
|
1302
|
+
pos_pin_group_name : str
|
|
1303
|
+
Name of the positive pin group.
|
|
1304
|
+
neg_pin_group_name : str
|
|
1305
|
+
Name of the negative pin group.
|
|
1306
|
+
magnitude : int, float, optional
|
|
1307
|
+
Magnitude of the source.
|
|
1308
|
+
phase : int, float, optional
|
|
1309
|
+
Phase of the source
|
|
1310
|
+
|
|
1311
|
+
Returns
|
|
1312
|
+
-------
|
|
1313
|
+
bool
|
|
1314
|
+
|
|
1315
|
+
"""
|
|
1316
|
+
pos_pin_group = self.pin_groups[pos_pin_group_name]
|
|
1317
|
+
pos_terminal = pos_pin_group.create_voltage_source_terminal(magnitude, phase, impedance)
|
|
1318
|
+
if name:
|
|
1319
|
+
pos_terminal.SetName(name)
|
|
1320
|
+
else:
|
|
1321
|
+
name = generate_unique_name("vsource")
|
|
1322
|
+
pos_terminal.SetName(name)
|
|
1323
|
+
neg_pin_group_name = self.pin_groups[neg_pin_group_name]
|
|
1324
|
+
neg_terminal = neg_pin_group_name.create_voltage_source_terminal(magnitude, phase)
|
|
1325
|
+
neg_terminal.SetName(name + "_ref")
|
|
1326
|
+
pos_terminal.SetReferenceTerminal(neg_terminal)
|
|
1327
|
+
return True
|
|
1328
|
+
|
|
1329
|
+
@pyedb_function_handler()
|
|
1330
|
+
def create_voltage_probe_on_pin_group(self, probe_name, pos_pin_group_name, neg_pin_group_name, impedance=1000000):
|
|
1331
|
+
"""Create voltage probe between two pin groups.
|
|
1332
|
+
|
|
1333
|
+
Parameters
|
|
1334
|
+
----------
|
|
1335
|
+
probe_name : str
|
|
1336
|
+
Name of the probe.
|
|
1337
|
+
pos_pin_group_name : str
|
|
1338
|
+
Name of the positive pin group.
|
|
1339
|
+
neg_pin_group_name : str
|
|
1340
|
+
Name of the negative pin group.
|
|
1341
|
+
impedance : int, float, optional
|
|
1342
|
+
Phase of the source.
|
|
1343
|
+
|
|
1344
|
+
Returns
|
|
1345
|
+
-------
|
|
1346
|
+
bool
|
|
1347
|
+
|
|
1348
|
+
"""
|
|
1349
|
+
pos_pin_group = self.pin_groups[pos_pin_group_name]
|
|
1350
|
+
pos_terminal = pos_pin_group.create_voltage_probe_terminal(impedance)
|
|
1351
|
+
if probe_name:
|
|
1352
|
+
pos_terminal.SetName(probe_name)
|
|
1353
|
+
else:
|
|
1354
|
+
probe_name = generate_unique_name("vprobe")
|
|
1355
|
+
pos_terminal.SetName(probe_name)
|
|
1356
|
+
neg_pin_group_name = self.pin_groups[neg_pin_group_name]
|
|
1357
|
+
neg_terminal = neg_pin_group_name.create_voltage_probe_terminal()
|
|
1358
|
+
neg_terminal.SetName(probe_name + "_ref")
|
|
1359
|
+
pos_terminal.SetReferenceTerminal(neg_terminal)
|
|
1360
|
+
return not pos_terminal.IsNull()
|
|
1361
|
+
|
|
1362
|
+
@pyedb_function_handler()
|
|
1363
|
+
def create_circuit_port_on_pin_group(self, pos_pin_group_name, neg_pin_group_name, impedance=50, name=None):
|
|
1364
|
+
"""Create a port between two pin groups.
|
|
1365
|
+
|
|
1366
|
+
Parameters
|
|
1367
|
+
----------
|
|
1368
|
+
pos_pin_group_name : str
|
|
1369
|
+
Name of the positive pin group.
|
|
1370
|
+
neg_pin_group_name : str
|
|
1371
|
+
Name of the negative pin group.
|
|
1372
|
+
impedance : int, float, optional
|
|
1373
|
+
Impedance of the port. Default is ``50``.
|
|
1374
|
+
name : str, optional
|
|
1375
|
+
Port name.
|
|
1376
|
+
|
|
1377
|
+
Returns
|
|
1378
|
+
-------
|
|
1379
|
+
bool
|
|
1380
|
+
|
|
1381
|
+
"""
|
|
1382
|
+
pos_pin_group = self.pin_groups[pos_pin_group_name]
|
|
1383
|
+
pos_terminal = pos_pin_group.create_port_terminal(impedance)
|
|
1384
|
+
if name: # pragma: no cover
|
|
1385
|
+
pos_terminal.SetName(name)
|
|
1386
|
+
else:
|
|
1387
|
+
name = generate_unique_name("port")
|
|
1388
|
+
pos_terminal.SetName(name)
|
|
1389
|
+
neg_pin_group_name = self.pin_groups[neg_pin_group_name]
|
|
1390
|
+
neg_terminal = neg_pin_group_name.create_port_terminal(impedance)
|
|
1391
|
+
neg_terminal.SetName(name + "_ref")
|
|
1392
|
+
pos_terminal.SetReferenceTerminal(neg_terminal)
|
|
1393
|
+
return True
|
|
1394
|
+
|
|
1395
|
+
@pyedb_function_handler
|
|
1396
|
+
def place_voltage_probe(
|
|
1397
|
+
self,
|
|
1398
|
+
name,
|
|
1399
|
+
positive_net_name,
|
|
1400
|
+
positive_location,
|
|
1401
|
+
positive_layer,
|
|
1402
|
+
negative_net_name,
|
|
1403
|
+
negative_location,
|
|
1404
|
+
negative_layer,
|
|
1405
|
+
):
|
|
1406
|
+
"""Place a voltage probe between two points.
|
|
1407
|
+
|
|
1408
|
+
Parameters
|
|
1409
|
+
----------
|
|
1410
|
+
name : str,
|
|
1411
|
+
Name of the probe.
|
|
1412
|
+
positive_net_name : str
|
|
1413
|
+
Name of the positive net.
|
|
1414
|
+
positive_location : list
|
|
1415
|
+
Location of the positive terminal.
|
|
1416
|
+
positive_layer : str,
|
|
1417
|
+
Layer of the positive terminal.
|
|
1418
|
+
negative_net_name : str,
|
|
1419
|
+
Name of the negative net.
|
|
1420
|
+
negative_location : list
|
|
1421
|
+
Location of the negative terminal.
|
|
1422
|
+
negative_layer : str
|
|
1423
|
+
Layer of the negative terminal.
|
|
1424
|
+
"""
|
|
1425
|
+
p_terminal = self._pedb.get_point_terminal(name, positive_net_name, positive_location, positive_layer)
|
|
1426
|
+
n_terminal = self._pedb.get_point_terminal(name + "_ref", negative_net_name, negative_location, negative_layer)
|
|
1427
|
+
return self._pedb.create_voltage_probe(p_terminal, n_terminal)
|