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.

Files changed (128) hide show
  1. pyedb/__init__.py +17 -0
  2. pyedb/dotnet/__init__.py +0 -0
  3. pyedb/dotnet/application/Variables.py +2261 -0
  4. pyedb/dotnet/application/__init__.py +0 -0
  5. pyedb/dotnet/clr_module.py +103 -0
  6. pyedb/dotnet/edb.py +4237 -0
  7. pyedb/dotnet/edb_core/__init__.py +1 -0
  8. pyedb/dotnet/edb_core/cell/__init__.py +0 -0
  9. pyedb/dotnet/edb_core/cell/hierarchy/__init__.py +0 -0
  10. pyedb/dotnet/edb_core/cell/hierarchy/model.py +66 -0
  11. pyedb/dotnet/edb_core/components.py +2669 -0
  12. pyedb/dotnet/edb_core/configuration.py +423 -0
  13. pyedb/dotnet/edb_core/definition/__init__.py +0 -0
  14. pyedb/dotnet/edb_core/definition/component_def.py +166 -0
  15. pyedb/dotnet/edb_core/definition/component_model.py +30 -0
  16. pyedb/dotnet/edb_core/definition/definition_obj.py +18 -0
  17. pyedb/dotnet/edb_core/definition/definitions.py +12 -0
  18. pyedb/dotnet/edb_core/dotnet/__init__.py +0 -0
  19. pyedb/dotnet/edb_core/dotnet/database.py +1218 -0
  20. pyedb/dotnet/edb_core/dotnet/layout.py +238 -0
  21. pyedb/dotnet/edb_core/dotnet/primitive.py +1517 -0
  22. pyedb/dotnet/edb_core/edb_data/__init__.py +0 -0
  23. pyedb/dotnet/edb_core/edb_data/components_data.py +938 -0
  24. pyedb/dotnet/edb_core/edb_data/connectable.py +113 -0
  25. pyedb/dotnet/edb_core/edb_data/control_file.py +1268 -0
  26. pyedb/dotnet/edb_core/edb_data/design_options.py +35 -0
  27. pyedb/dotnet/edb_core/edb_data/edbvalue.py +45 -0
  28. pyedb/dotnet/edb_core/edb_data/hfss_extent_info.py +330 -0
  29. pyedb/dotnet/edb_core/edb_data/hfss_simulation_setup_data.py +1607 -0
  30. pyedb/dotnet/edb_core/edb_data/layer_data.py +576 -0
  31. pyedb/dotnet/edb_core/edb_data/nets_data.py +281 -0
  32. pyedb/dotnet/edb_core/edb_data/obj_base.py +19 -0
  33. pyedb/dotnet/edb_core/edb_data/padstacks_data.py +2080 -0
  34. pyedb/dotnet/edb_core/edb_data/ports.py +287 -0
  35. pyedb/dotnet/edb_core/edb_data/primitives_data.py +1397 -0
  36. pyedb/dotnet/edb_core/edb_data/simulation_configuration.py +2914 -0
  37. pyedb/dotnet/edb_core/edb_data/simulation_setup.py +716 -0
  38. pyedb/dotnet/edb_core/edb_data/siwave_simulation_setup_data.py +1205 -0
  39. pyedb/dotnet/edb_core/edb_data/sources.py +514 -0
  40. pyedb/dotnet/edb_core/edb_data/terminals.py +632 -0
  41. pyedb/dotnet/edb_core/edb_data/utilities.py +148 -0
  42. pyedb/dotnet/edb_core/edb_data/variables.py +91 -0
  43. pyedb/dotnet/edb_core/general.py +181 -0
  44. pyedb/dotnet/edb_core/hfss.py +1646 -0
  45. pyedb/dotnet/edb_core/layout.py +1244 -0
  46. pyedb/dotnet/edb_core/layout_validation.py +272 -0
  47. pyedb/dotnet/edb_core/materials.py +939 -0
  48. pyedb/dotnet/edb_core/net_class.py +335 -0
  49. pyedb/dotnet/edb_core/nets.py +1215 -0
  50. pyedb/dotnet/edb_core/padstack.py +1389 -0
  51. pyedb/dotnet/edb_core/siwave.py +1427 -0
  52. pyedb/dotnet/edb_core/stackup.py +2703 -0
  53. pyedb/edb_logger.py +396 -0
  54. pyedb/generic/__init__.py +0 -0
  55. pyedb/generic/constants.py +1063 -0
  56. pyedb/generic/data_handlers.py +320 -0
  57. pyedb/generic/design_types.py +104 -0
  58. pyedb/generic/filesystem.py +150 -0
  59. pyedb/generic/general_methods.py +1535 -0
  60. pyedb/generic/plot.py +1840 -0
  61. pyedb/generic/process.py +285 -0
  62. pyedb/generic/settings.py +224 -0
  63. pyedb/ipc2581/__init__.py +0 -0
  64. pyedb/ipc2581/bom/__init__.py +0 -0
  65. pyedb/ipc2581/bom/bom.py +21 -0
  66. pyedb/ipc2581/bom/bom_item.py +32 -0
  67. pyedb/ipc2581/bom/characteristics.py +37 -0
  68. pyedb/ipc2581/bom/refdes.py +16 -0
  69. pyedb/ipc2581/content/__init__.py +0 -0
  70. pyedb/ipc2581/content/color.py +38 -0
  71. pyedb/ipc2581/content/content.py +55 -0
  72. pyedb/ipc2581/content/dictionary_color.py +29 -0
  73. pyedb/ipc2581/content/dictionary_fill.py +28 -0
  74. pyedb/ipc2581/content/dictionary_line.py +30 -0
  75. pyedb/ipc2581/content/entry_color.py +13 -0
  76. pyedb/ipc2581/content/entry_line.py +14 -0
  77. pyedb/ipc2581/content/fill.py +15 -0
  78. pyedb/ipc2581/content/layer_ref.py +10 -0
  79. pyedb/ipc2581/content/standard_geometries_dictionary.py +72 -0
  80. pyedb/ipc2581/ecad/__init__.py +0 -0
  81. pyedb/ipc2581/ecad/cad_data/__init__.py +0 -0
  82. pyedb/ipc2581/ecad/cad_data/assembly_drawing.py +26 -0
  83. pyedb/ipc2581/ecad/cad_data/cad_data.py +37 -0
  84. pyedb/ipc2581/ecad/cad_data/component.py +41 -0
  85. pyedb/ipc2581/ecad/cad_data/drill.py +30 -0
  86. pyedb/ipc2581/ecad/cad_data/feature.py +54 -0
  87. pyedb/ipc2581/ecad/cad_data/layer.py +41 -0
  88. pyedb/ipc2581/ecad/cad_data/layer_feature.py +151 -0
  89. pyedb/ipc2581/ecad/cad_data/logical_net.py +32 -0
  90. pyedb/ipc2581/ecad/cad_data/outline.py +25 -0
  91. pyedb/ipc2581/ecad/cad_data/package.py +104 -0
  92. pyedb/ipc2581/ecad/cad_data/padstack_def.py +38 -0
  93. pyedb/ipc2581/ecad/cad_data/padstack_hole_def.py +24 -0
  94. pyedb/ipc2581/ecad/cad_data/padstack_instance.py +62 -0
  95. pyedb/ipc2581/ecad/cad_data/padstack_pad_def.py +26 -0
  96. pyedb/ipc2581/ecad/cad_data/path.py +89 -0
  97. pyedb/ipc2581/ecad/cad_data/phy_net.py +80 -0
  98. pyedb/ipc2581/ecad/cad_data/pin.py +31 -0
  99. pyedb/ipc2581/ecad/cad_data/polygon.py +169 -0
  100. pyedb/ipc2581/ecad/cad_data/profile.py +40 -0
  101. pyedb/ipc2581/ecad/cad_data/stackup.py +31 -0
  102. pyedb/ipc2581/ecad/cad_data/stackup_group.py +42 -0
  103. pyedb/ipc2581/ecad/cad_data/stackup_layer.py +21 -0
  104. pyedb/ipc2581/ecad/cad_data/step.py +275 -0
  105. pyedb/ipc2581/ecad/cad_header.py +33 -0
  106. pyedb/ipc2581/ecad/ecad.py +19 -0
  107. pyedb/ipc2581/ecad/spec.py +46 -0
  108. pyedb/ipc2581/history_record.py +37 -0
  109. pyedb/ipc2581/ipc2581.py +387 -0
  110. pyedb/ipc2581/logistic_header.py +25 -0
  111. pyedb/misc/__init__.py +0 -0
  112. pyedb/misc/aedtlib_personalib_install.py +14 -0
  113. pyedb/misc/downloads.py +322 -0
  114. pyedb/misc/misc.py +67 -0
  115. pyedb/misc/pyedb.runtimeconfig.json +13 -0
  116. pyedb/misc/siw_feature_config/__init__.py +0 -0
  117. pyedb/misc/siw_feature_config/emc/__init__.py +0 -0
  118. pyedb/misc/siw_feature_config/emc/component_tags.py +46 -0
  119. pyedb/misc/siw_feature_config/emc/net_tags.py +37 -0
  120. pyedb/misc/siw_feature_config/emc/tag_library.py +62 -0
  121. pyedb/misc/siw_feature_config/emc/xml_generic.py +78 -0
  122. pyedb/misc/siw_feature_config/emc_rule_checker_settings.py +179 -0
  123. pyedb/misc/utilities.py +27 -0
  124. pyedb/modeler/geometry_operators.py +2082 -0
  125. pyedb-0.2.0.dist-info/LICENSE +21 -0
  126. pyedb-0.2.0.dist-info/METADATA +208 -0
  127. pyedb-0.2.0.dist-info/RECORD +128 -0
  128. 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)