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,1215 @@
|
|
|
1
|
+
from __future__ import absolute_import # noreorder
|
|
2
|
+
|
|
3
|
+
import math
|
|
4
|
+
import os
|
|
5
|
+
import time
|
|
6
|
+
import warnings
|
|
7
|
+
|
|
8
|
+
from pyedb.dotnet.edb_core.edb_data.nets_data import EDBNetsData
|
|
9
|
+
from pyedb.generic.constants import CSS4_COLORS
|
|
10
|
+
from pyedb.generic.general_methods import (
|
|
11
|
+
generate_unique_name,
|
|
12
|
+
is_ironpython,
|
|
13
|
+
pyedb_function_handler,
|
|
14
|
+
)
|
|
15
|
+
from pyedb.modeler.geometry_operators import GeometryOperators
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class EdbNets(object):
|
|
19
|
+
"""Manages EDB methods for nets management accessible from `Edb.nets` property.
|
|
20
|
+
|
|
21
|
+
Examples
|
|
22
|
+
--------
|
|
23
|
+
>>> from pyedb.dotnet.edb import Edb
|
|
24
|
+
>>> edbapp = Edb("myaedbfolder", edbversion="2021.2")
|
|
25
|
+
>>> edb_nets = edbapp.nets
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
@pyedb_function_handler()
|
|
29
|
+
def __getitem__(self, name):
|
|
30
|
+
"""Get a net from the Edb project.
|
|
31
|
+
|
|
32
|
+
Parameters
|
|
33
|
+
----------
|
|
34
|
+
name : str, int
|
|
35
|
+
|
|
36
|
+
Returns
|
|
37
|
+
-------
|
|
38
|
+
:class:` :class:`pyedb.dotnet.edb_core.edb_data.nets_data.EDBNetsData`
|
|
39
|
+
|
|
40
|
+
"""
|
|
41
|
+
if name in self.nets:
|
|
42
|
+
return self.nets[name]
|
|
43
|
+
self._pedb.logger.error("Component or definition not found.")
|
|
44
|
+
return
|
|
45
|
+
|
|
46
|
+
@pyedb_function_handler()
|
|
47
|
+
def __contains__(self, name):
|
|
48
|
+
"""Determine if a net is named ``name`` or not.
|
|
49
|
+
|
|
50
|
+
Parameters
|
|
51
|
+
----------
|
|
52
|
+
name : str
|
|
53
|
+
|
|
54
|
+
Returns
|
|
55
|
+
-------
|
|
56
|
+
bool
|
|
57
|
+
``True`` when one of the net is named ``name``, ``False`` otherwise.
|
|
58
|
+
|
|
59
|
+
"""
|
|
60
|
+
return name in self.nets
|
|
61
|
+
|
|
62
|
+
def __init__(self, p_edb):
|
|
63
|
+
self._pedb = p_edb
|
|
64
|
+
self._nets_by_comp_dict = {}
|
|
65
|
+
self._comps_by_nets_dict = {}
|
|
66
|
+
|
|
67
|
+
@property
|
|
68
|
+
def _edb(self):
|
|
69
|
+
""" """
|
|
70
|
+
return self._pedb.edb_api
|
|
71
|
+
|
|
72
|
+
@property
|
|
73
|
+
def _active_layout(self):
|
|
74
|
+
""" """
|
|
75
|
+
return self._pedb.active_layout
|
|
76
|
+
|
|
77
|
+
@property
|
|
78
|
+
def _layout(self):
|
|
79
|
+
""" """
|
|
80
|
+
return self._pedb.layout
|
|
81
|
+
|
|
82
|
+
@property
|
|
83
|
+
def _cell(self):
|
|
84
|
+
""" """
|
|
85
|
+
return self._pedb.cell
|
|
86
|
+
|
|
87
|
+
@property
|
|
88
|
+
def db(self):
|
|
89
|
+
"""Db object."""
|
|
90
|
+
return self._pedb.active_db
|
|
91
|
+
|
|
92
|
+
@property
|
|
93
|
+
def _logger(self):
|
|
94
|
+
"""Edb logger."""
|
|
95
|
+
return self._pedb.logger
|
|
96
|
+
|
|
97
|
+
@property
|
|
98
|
+
def nets(self):
|
|
99
|
+
"""Nets.
|
|
100
|
+
|
|
101
|
+
Returns
|
|
102
|
+
-------
|
|
103
|
+
dict[str, :class:`pyedb.dotnet.edb_core.edb_data.nets_data.EDBNetsData`]
|
|
104
|
+
Dictionary of nets.
|
|
105
|
+
"""
|
|
106
|
+
|
|
107
|
+
temp = {}
|
|
108
|
+
for net in self._layout.nets:
|
|
109
|
+
temp[net.name] = EDBNetsData(net.api_object, self._pedb)
|
|
110
|
+
return temp
|
|
111
|
+
|
|
112
|
+
@property
|
|
113
|
+
def netlist(self):
|
|
114
|
+
"""Return the cell netlist.
|
|
115
|
+
|
|
116
|
+
Returns
|
|
117
|
+
-------
|
|
118
|
+
list
|
|
119
|
+
Net names.
|
|
120
|
+
"""
|
|
121
|
+
return list(self.nets.keys())
|
|
122
|
+
|
|
123
|
+
@property
|
|
124
|
+
def signal_nets(self):
|
|
125
|
+
"""Signal nets.
|
|
126
|
+
|
|
127
|
+
.. deprecated:: 0.6.62
|
|
128
|
+
Use :func:`signal` instead.
|
|
129
|
+
|
|
130
|
+
Returns
|
|
131
|
+
-------
|
|
132
|
+
dict[str, :class:`pyedb.dotnet.edb_core.edb_data.EDBNetsData`]
|
|
133
|
+
Dictionary of signal nets.
|
|
134
|
+
"""
|
|
135
|
+
warnings.warn("Use :func:`signal` instead.", DeprecationWarning)
|
|
136
|
+
return self.signal
|
|
137
|
+
|
|
138
|
+
@property
|
|
139
|
+
def power_nets(self):
|
|
140
|
+
"""Power nets.
|
|
141
|
+
|
|
142
|
+
.. deprecated:: 0.6.62
|
|
143
|
+
Use :func:`power` instead.
|
|
144
|
+
|
|
145
|
+
Returns
|
|
146
|
+
-------
|
|
147
|
+
dict[str, :class:`pyedb.dotnet.edb_core.edb_data.EDBNetsData`]
|
|
148
|
+
Dictionary of power nets.
|
|
149
|
+
"""
|
|
150
|
+
warnings.warn("Use :func:`power` instead.", DeprecationWarning)
|
|
151
|
+
return self.power
|
|
152
|
+
|
|
153
|
+
@property
|
|
154
|
+
def signal(self):
|
|
155
|
+
"""Signal nets.
|
|
156
|
+
|
|
157
|
+
Returns
|
|
158
|
+
-------
|
|
159
|
+
dict[str, :class:`pyedb.dotnet.edb_core.edb_data.EDBNetsData`]
|
|
160
|
+
Dictionary of signal nets.
|
|
161
|
+
"""
|
|
162
|
+
nets = {}
|
|
163
|
+
for net, value in self.nets.items():
|
|
164
|
+
if not value.IsPowerGround():
|
|
165
|
+
nets[net] = value
|
|
166
|
+
return nets
|
|
167
|
+
|
|
168
|
+
@property
|
|
169
|
+
def power(self):
|
|
170
|
+
"""Power nets.
|
|
171
|
+
|
|
172
|
+
Returns
|
|
173
|
+
-------
|
|
174
|
+
dict[str, :class:`pyedb.dotnet.edb_core.edb_data.EDBNetsData`]
|
|
175
|
+
Dictionary of power nets.
|
|
176
|
+
"""
|
|
177
|
+
nets = {}
|
|
178
|
+
for net, value in self.nets.items():
|
|
179
|
+
if value.IsPowerGround():
|
|
180
|
+
nets[net] = value
|
|
181
|
+
return nets
|
|
182
|
+
|
|
183
|
+
@pyedb_function_handler()
|
|
184
|
+
def eligible_power_nets(self, threshold=0.3):
|
|
185
|
+
"""Return a list of nets calculated by area to be eligible for PWR/Ground net classification.
|
|
186
|
+
It uses the same algorithm implemented in SIwave.
|
|
187
|
+
|
|
188
|
+
Parameters
|
|
189
|
+
----------
|
|
190
|
+
threshold : float, optional
|
|
191
|
+
Area ratio used by the ``get_power_ground_nets`` method.
|
|
192
|
+
|
|
193
|
+
Returns
|
|
194
|
+
-------
|
|
195
|
+
list of :class:`pyedb.dotnet.edb_core.edb_data.EDBNetsData`
|
|
196
|
+
"""
|
|
197
|
+
pwr_gnd_nets = []
|
|
198
|
+
for net in self._layout.nets[:]:
|
|
199
|
+
total_plane_area = 0.0
|
|
200
|
+
total_trace_area = 0.0
|
|
201
|
+
for primitive in net.Primitives:
|
|
202
|
+
if primitive.GetPrimitiveType() == self._edb.cell.primitive.PrimitiveType.Bondwire:
|
|
203
|
+
continue
|
|
204
|
+
if primitive.GetPrimitiveType() != self._edb.cell.primitive.PrimitiveType.Path:
|
|
205
|
+
total_plane_area += float(primitive.GetPolygonData().Area())
|
|
206
|
+
else:
|
|
207
|
+
total_trace_area += float(primitive.GetPolygonData().Area())
|
|
208
|
+
if total_plane_area == 0.0:
|
|
209
|
+
continue
|
|
210
|
+
if total_trace_area == 0.0:
|
|
211
|
+
pwr_gnd_nets.append(EDBNetsData(net.api_object, self._pedb))
|
|
212
|
+
continue
|
|
213
|
+
if total_plane_area > 0.0 and total_trace_area > 0.0:
|
|
214
|
+
if total_plane_area / (total_plane_area + total_trace_area) > threshold:
|
|
215
|
+
pwr_gnd_nets.append(EDBNetsData(net.api_object, self._pedb))
|
|
216
|
+
return pwr_gnd_nets
|
|
217
|
+
|
|
218
|
+
@property
|
|
219
|
+
def nets_by_components(self):
|
|
220
|
+
# type: () -> dict
|
|
221
|
+
"""Get all nets for each component instance."""
|
|
222
|
+
for comp, i in self._pedb.components.instances.items():
|
|
223
|
+
self._nets_by_comp_dict[comp] = i.nets
|
|
224
|
+
return self._nets_by_comp_dict
|
|
225
|
+
|
|
226
|
+
@property
|
|
227
|
+
def components_by_nets(self):
|
|
228
|
+
# type: () -> dict
|
|
229
|
+
"""Get all component instances grouped by nets."""
|
|
230
|
+
for comp, i in self._pedb.components.instances.items():
|
|
231
|
+
for n in i.nets:
|
|
232
|
+
if n in self._comps_by_nets_dict:
|
|
233
|
+
self._comps_by_nets_dict[n].append(comp)
|
|
234
|
+
else:
|
|
235
|
+
self._comps_by_nets_dict[n] = [comp]
|
|
236
|
+
return self._comps_by_nets_dict
|
|
237
|
+
|
|
238
|
+
@pyedb_function_handler()
|
|
239
|
+
def generate_extended_nets(
|
|
240
|
+
self,
|
|
241
|
+
resistor_below=10,
|
|
242
|
+
inductor_below=1,
|
|
243
|
+
capacitor_above=1,
|
|
244
|
+
exception_list=None,
|
|
245
|
+
include_signal=True,
|
|
246
|
+
include_power=True,
|
|
247
|
+
):
|
|
248
|
+
# type: (int | float, int | float, int |float, list, bool, bool) -> list
|
|
249
|
+
"""Get extended net and associated components.
|
|
250
|
+
|
|
251
|
+
Parameters
|
|
252
|
+
----------
|
|
253
|
+
resistor_below : int, float, optional
|
|
254
|
+
Threshold of resistor value. Search extended net across resistors which has value lower than the threshold.
|
|
255
|
+
inductor_below : int, float, optional
|
|
256
|
+
Threshold of inductor value. Search extended net across inductances which has value lower than the
|
|
257
|
+
threshold.
|
|
258
|
+
capacitor_above : int, float, optional
|
|
259
|
+
Threshold of capacitor value. Search extended net across capacitors which has value higher than the
|
|
260
|
+
threshold.
|
|
261
|
+
exception_list : list, optional
|
|
262
|
+
List of components to bypass when performing threshold checks. Components
|
|
263
|
+
in the list are considered as serial components. The default is ``None``.
|
|
264
|
+
include_signal : str, optional
|
|
265
|
+
Whether to generate extended signal nets. The default is ``True``.
|
|
266
|
+
include_power : str, optional
|
|
267
|
+
Whether to generate extended power nets. The default is ``True``.
|
|
268
|
+
|
|
269
|
+
Returns
|
|
270
|
+
-------
|
|
271
|
+
list
|
|
272
|
+
List of all extended nets.
|
|
273
|
+
|
|
274
|
+
Examples
|
|
275
|
+
--------
|
|
276
|
+
>>> from pyedb import Edb
|
|
277
|
+
>>> app = Edb()
|
|
278
|
+
>>> app.nets.get_extended_nets()
|
|
279
|
+
"""
|
|
280
|
+
if exception_list is None:
|
|
281
|
+
exception_list = []
|
|
282
|
+
_extended_nets = []
|
|
283
|
+
_nets = self.nets
|
|
284
|
+
all_nets = list(_nets.keys())[:]
|
|
285
|
+
net_dicts = self._comps_by_nets_dict if self._comps_by_nets_dict else self.components_by_nets
|
|
286
|
+
comp_dict = self._nets_by_comp_dict if self._nets_by_comp_dict else self.nets_by_components
|
|
287
|
+
|
|
288
|
+
def get_net_list(net_name, _net_list):
|
|
289
|
+
comps = []
|
|
290
|
+
if net_name in net_dicts:
|
|
291
|
+
comps = net_dicts[net_name]
|
|
292
|
+
|
|
293
|
+
for vals in comps:
|
|
294
|
+
refdes = vals
|
|
295
|
+
cmp = self._pedb.components.instances[refdes]
|
|
296
|
+
is_enabled = cmp.is_enabled
|
|
297
|
+
if not is_enabled:
|
|
298
|
+
continue
|
|
299
|
+
val_type = cmp.type
|
|
300
|
+
if val_type not in ["Inductor", "Resistor", "Capacitor"]:
|
|
301
|
+
continue
|
|
302
|
+
|
|
303
|
+
val_value = cmp.rlc_values
|
|
304
|
+
if refdes in exception_list:
|
|
305
|
+
pass
|
|
306
|
+
elif val_type == "Inductor" and val_value[1] < inductor_below:
|
|
307
|
+
pass
|
|
308
|
+
elif val_type == "Resistor" and val_value[0] < resistor_below:
|
|
309
|
+
pass
|
|
310
|
+
elif val_type == "Capacitor" and val_value[2] > capacitor_above:
|
|
311
|
+
pass
|
|
312
|
+
else:
|
|
313
|
+
continue
|
|
314
|
+
|
|
315
|
+
for net in comp_dict[refdes]:
|
|
316
|
+
if net not in _net_list:
|
|
317
|
+
_net_list.append(net)
|
|
318
|
+
get_net_list(net, _net_list)
|
|
319
|
+
|
|
320
|
+
while len(all_nets) > 0:
|
|
321
|
+
new_ext = [all_nets[0]]
|
|
322
|
+
get_net_list(new_ext[0], new_ext)
|
|
323
|
+
all_nets = [i for i in all_nets if i not in new_ext]
|
|
324
|
+
_extended_nets.append(new_ext)
|
|
325
|
+
|
|
326
|
+
if len(new_ext) > 1:
|
|
327
|
+
i = new_ext[0]
|
|
328
|
+
for i in new_ext:
|
|
329
|
+
if not i.lower().startswith("unnamed"):
|
|
330
|
+
break
|
|
331
|
+
|
|
332
|
+
is_power = False
|
|
333
|
+
for i in new_ext:
|
|
334
|
+
is_power = is_power or _nets[i].is_power_ground
|
|
335
|
+
|
|
336
|
+
if is_power:
|
|
337
|
+
if include_power:
|
|
338
|
+
self._pedb.extended_nets.create(i, new_ext)
|
|
339
|
+
else: # pragma: no cover
|
|
340
|
+
pass
|
|
341
|
+
else:
|
|
342
|
+
if include_signal:
|
|
343
|
+
self._pedb.extended_nets.create(i, new_ext)
|
|
344
|
+
else: # pragma: no cover
|
|
345
|
+
pass
|
|
346
|
+
|
|
347
|
+
return _extended_nets
|
|
348
|
+
|
|
349
|
+
@staticmethod
|
|
350
|
+
def _eval_arc_points(p1, p2, h, n=6, tol=1e-12):
|
|
351
|
+
"""Get the points of the arc.
|
|
352
|
+
|
|
353
|
+
Parameters
|
|
354
|
+
----------
|
|
355
|
+
p1 : list
|
|
356
|
+
Arc starting point.
|
|
357
|
+
p2 : list
|
|
358
|
+
Arc ending point.
|
|
359
|
+
h : float
|
|
360
|
+
Arc height.
|
|
361
|
+
n : int
|
|
362
|
+
Number of points to generate along the arc.
|
|
363
|
+
tol : float
|
|
364
|
+
Geometric tolerance.
|
|
365
|
+
|
|
366
|
+
Returns
|
|
367
|
+
-------
|
|
368
|
+
list
|
|
369
|
+
points generated along the arc.
|
|
370
|
+
"""
|
|
371
|
+
# fmt: off
|
|
372
|
+
if abs(h) < tol:
|
|
373
|
+
return [], []
|
|
374
|
+
elif h > 0:
|
|
375
|
+
reverse = False
|
|
376
|
+
x1 = p1[0]
|
|
377
|
+
y1 = p1[1]
|
|
378
|
+
x2 = p2[0]
|
|
379
|
+
y2 = p2[1]
|
|
380
|
+
else:
|
|
381
|
+
reverse = True
|
|
382
|
+
x1 = p2[0]
|
|
383
|
+
y1 = p2[1]
|
|
384
|
+
x2 = p1[0]
|
|
385
|
+
y2 = p1[1]
|
|
386
|
+
h *= -1
|
|
387
|
+
xa = (x2 - x1) / 2
|
|
388
|
+
ya = (y2 - y1) / 2
|
|
389
|
+
xo = x1 + xa
|
|
390
|
+
yo = y1 + ya
|
|
391
|
+
a = math.sqrt(xa ** 2 + ya ** 2)
|
|
392
|
+
if a < tol:
|
|
393
|
+
return [], []
|
|
394
|
+
r = (a ** 2) / (2 * h) + h / 2
|
|
395
|
+
if abs(r - a) < tol:
|
|
396
|
+
b = 0
|
|
397
|
+
th = 2 * math.asin(1) # chord angle
|
|
398
|
+
else:
|
|
399
|
+
b = math.sqrt(r ** 2 - a ** 2)
|
|
400
|
+
th = 2 * math.asin(a / r) # chord angle
|
|
401
|
+
|
|
402
|
+
# center of the circle
|
|
403
|
+
xc = xo + b * ya / a
|
|
404
|
+
yc = yo - b * xa / a
|
|
405
|
+
|
|
406
|
+
alpha = math.atan2((y1 - yc), (x1 - xc))
|
|
407
|
+
xr = []
|
|
408
|
+
yr = []
|
|
409
|
+
for i in range(n):
|
|
410
|
+
i += 1
|
|
411
|
+
dth = (i / (n + 1)) * th
|
|
412
|
+
xi = xc + r * math.cos(alpha - dth)
|
|
413
|
+
yi = yc + r * math.sin(alpha - dth)
|
|
414
|
+
xr.append(xi)
|
|
415
|
+
yr.append(yi)
|
|
416
|
+
|
|
417
|
+
if reverse:
|
|
418
|
+
xr.reverse()
|
|
419
|
+
yr.reverse()
|
|
420
|
+
# fmt: on
|
|
421
|
+
return xr, yr
|
|
422
|
+
|
|
423
|
+
def _get_points_for_plot(self, my_net_points):
|
|
424
|
+
"""
|
|
425
|
+
Get the points to be plot
|
|
426
|
+
"""
|
|
427
|
+
# fmt: off
|
|
428
|
+
x = []
|
|
429
|
+
y = []
|
|
430
|
+
for i, point in enumerate(my_net_points):
|
|
431
|
+
# point = my_net_points[i]
|
|
432
|
+
if not point.IsArc():
|
|
433
|
+
x.append(point.X.ToDouble())
|
|
434
|
+
y.append(point.Y.ToDouble())
|
|
435
|
+
# i += 1
|
|
436
|
+
else:
|
|
437
|
+
arc_h = point.GetArcHeight().ToDouble()
|
|
438
|
+
p1 = [my_net_points[i - 1].X.ToDouble(), my_net_points[i - 1].Y.ToDouble()]
|
|
439
|
+
if i + 1 < len(my_net_points):
|
|
440
|
+
p2 = [my_net_points[i + 1].X.ToDouble(), my_net_points[i + 1].Y.ToDouble()]
|
|
441
|
+
else:
|
|
442
|
+
p2 = [my_net_points[0].X.ToDouble(), my_net_points[0].Y.ToDouble()]
|
|
443
|
+
x_arc, y_arc = self._eval_arc_points(p1, p2, arc_h)
|
|
444
|
+
x.extend(x_arc)
|
|
445
|
+
y.extend(y_arc)
|
|
446
|
+
# i += 1
|
|
447
|
+
# fmt: on
|
|
448
|
+
return x, y
|
|
449
|
+
|
|
450
|
+
@pyedb_function_handler()
|
|
451
|
+
def get_plot_data(
|
|
452
|
+
self,
|
|
453
|
+
nets,
|
|
454
|
+
layers=None,
|
|
455
|
+
color_by_net=False,
|
|
456
|
+
outline=None,
|
|
457
|
+
plot_components_on_top=False,
|
|
458
|
+
plot_components_on_bottom=False,
|
|
459
|
+
):
|
|
460
|
+
"""Return List of points for Matplotlib 2D Chart.
|
|
461
|
+
|
|
462
|
+
Parameters
|
|
463
|
+
----------
|
|
464
|
+
nets : str, list
|
|
465
|
+
Name of the net or list of nets to plot. If `None` all nets will be plotted.
|
|
466
|
+
layers : str, list, optional
|
|
467
|
+
Name of the layers to include in the plot. If `None` all the signal layers will be considered.
|
|
468
|
+
color_by_net : bool, optional
|
|
469
|
+
If ``True`` the plot will be colored by net.
|
|
470
|
+
If ``False`` the plot will be colored by layer. (default)
|
|
471
|
+
outline : list, optional
|
|
472
|
+
List of points of the outline to plot.
|
|
473
|
+
plot_components_on_top : bool, optional
|
|
474
|
+
If ``True`` the components placed on top layer are plotted.
|
|
475
|
+
If ``False`` the components are not plotted. (default)
|
|
476
|
+
If nets and/or layers is specified, only the components belonging to the specified nets/layers are plotted.
|
|
477
|
+
plot_components_on_bottom : bool, optional
|
|
478
|
+
If ``True`` the components placed on bottom layer are plotted.
|
|
479
|
+
If ``False`` the components are not plotted. (default)
|
|
480
|
+
If nets and/or layers is specified, only the components belonging to the specified nets/layers are plotted.
|
|
481
|
+
|
|
482
|
+
Returns
|
|
483
|
+
-------
|
|
484
|
+
List, str: list of data to be used in plot.
|
|
485
|
+
In case of remote session it will be returned a string that could be converted \
|
|
486
|
+
to list using ast.literal_eval().
|
|
487
|
+
"""
|
|
488
|
+
start_time = time.time()
|
|
489
|
+
if not nets:
|
|
490
|
+
nets = list(self.nets.keys())
|
|
491
|
+
if isinstance(nets, str):
|
|
492
|
+
nets = [nets]
|
|
493
|
+
if not layers:
|
|
494
|
+
layers = list(self._pedb.stackup.signal_layers.keys())
|
|
495
|
+
if isinstance(layers, str):
|
|
496
|
+
layers = [layers]
|
|
497
|
+
color_index = 0
|
|
498
|
+
objects_lists = []
|
|
499
|
+
label_colors = {}
|
|
500
|
+
n_label = 0
|
|
501
|
+
max_labels = 10
|
|
502
|
+
|
|
503
|
+
if outline:
|
|
504
|
+
xt = [i[0] for i in outline]
|
|
505
|
+
yt = [i[1] for i in outline]
|
|
506
|
+
xc, yc = GeometryOperators.orient_polygon(xt, yt, clockwise=True)
|
|
507
|
+
vertices = [(i, j) for i, j in zip(xc, yc)]
|
|
508
|
+
codes = [2 for _ in vertices]
|
|
509
|
+
codes[0] = 1
|
|
510
|
+
vertices.append((0, 0))
|
|
511
|
+
codes.append(79)
|
|
512
|
+
objects_lists.append([vertices, codes, "b", "Outline", 1.0, 1.5, "contour"])
|
|
513
|
+
n_label += 1
|
|
514
|
+
top_layer = list(self._pedb.stackup.signal_layers.keys())[0]
|
|
515
|
+
bottom_layer = list(self._pedb.stackup.signal_layers.keys())[-1]
|
|
516
|
+
if plot_components_on_top or plot_components_on_bottom:
|
|
517
|
+
nc = 0
|
|
518
|
+
for comp in self._pedb.components.components.values():
|
|
519
|
+
if not comp.is_enabled:
|
|
520
|
+
continue
|
|
521
|
+
net_names = comp.nets
|
|
522
|
+
if nets and not any([i in nets for i in net_names]):
|
|
523
|
+
continue
|
|
524
|
+
layer_name = comp.placement_layer
|
|
525
|
+
if layer_name not in layers:
|
|
526
|
+
continue
|
|
527
|
+
if plot_components_on_top and layer_name == top_layer:
|
|
528
|
+
component_color = (184 / 255, 115 / 255, 51 / 255) # this is the color used in AEDT
|
|
529
|
+
label = "Component on top layer"
|
|
530
|
+
elif plot_components_on_bottom and layer_name == bottom_layer:
|
|
531
|
+
component_color = (41 / 255, 171 / 255, 135 / 255) # 41, 171, 135
|
|
532
|
+
label = "Component on bottom layer"
|
|
533
|
+
else:
|
|
534
|
+
continue
|
|
535
|
+
cbb = comp.bounding_box
|
|
536
|
+
x = [cbb[0], cbb[0], cbb[2], cbb[2]]
|
|
537
|
+
y = [cbb[1], cbb[3], cbb[3], cbb[1]]
|
|
538
|
+
vertices = [(i, j) for i, j in zip(x, y)]
|
|
539
|
+
codes = [2 for _ in vertices]
|
|
540
|
+
codes[0] = 1
|
|
541
|
+
vertices.append((0, 0))
|
|
542
|
+
codes.append(79)
|
|
543
|
+
if label not in label_colors:
|
|
544
|
+
label_colors[label] = component_color
|
|
545
|
+
objects_lists.append([vertices, codes, label_colors[label], label, 1.0, 2.0, "contour"])
|
|
546
|
+
n_label += 1
|
|
547
|
+
else:
|
|
548
|
+
objects_lists.append([vertices, codes, label_colors[label], None, 1.0, 2.0, "contour"])
|
|
549
|
+
nc += 1
|
|
550
|
+
self._logger.debug("Plotted {} component(s)".format(nc))
|
|
551
|
+
|
|
552
|
+
for path in self._pedb.modeler.paths:
|
|
553
|
+
if path.is_void:
|
|
554
|
+
continue
|
|
555
|
+
net_name = path.net_name
|
|
556
|
+
layer_name = path.layer_name
|
|
557
|
+
if nets and (net_name not in nets or layer_name not in layers):
|
|
558
|
+
continue
|
|
559
|
+
try:
|
|
560
|
+
x, y = path.points()
|
|
561
|
+
except ValueError:
|
|
562
|
+
x = None
|
|
563
|
+
if not x:
|
|
564
|
+
continue
|
|
565
|
+
create_label = False
|
|
566
|
+
if not color_by_net:
|
|
567
|
+
label = "Layer " + layer_name
|
|
568
|
+
if label not in label_colors:
|
|
569
|
+
try:
|
|
570
|
+
color = path.layer.GetColor()
|
|
571
|
+
c = (
|
|
572
|
+
float(color.Item1 / 255),
|
|
573
|
+
float(color.Item2 / 255),
|
|
574
|
+
float(color.Item3 / 255),
|
|
575
|
+
)
|
|
576
|
+
except:
|
|
577
|
+
c = list(CSS4_COLORS.keys())[color_index]
|
|
578
|
+
color_index += 1
|
|
579
|
+
if color_index >= len(CSS4_COLORS):
|
|
580
|
+
color_index = 0
|
|
581
|
+
label_colors[label] = c
|
|
582
|
+
create_label = True
|
|
583
|
+
else:
|
|
584
|
+
label = "Net " + net_name
|
|
585
|
+
if label not in label_colors:
|
|
586
|
+
label_colors[label] = list(CSS4_COLORS.keys())[color_index]
|
|
587
|
+
color_index += 1
|
|
588
|
+
if color_index >= len(CSS4_COLORS):
|
|
589
|
+
color_index = 0
|
|
590
|
+
create_label = True
|
|
591
|
+
|
|
592
|
+
if create_label and n_label <= max_labels:
|
|
593
|
+
objects_lists.append([x, y, label_colors[label], label, 0.4, "fill"])
|
|
594
|
+
n_label += 1
|
|
595
|
+
else:
|
|
596
|
+
objects_lists.append([x, y, label_colors[label], None, 0.4, "fill"])
|
|
597
|
+
|
|
598
|
+
for poly in self._pedb.modeler.polygons:
|
|
599
|
+
if poly.is_void:
|
|
600
|
+
continue
|
|
601
|
+
net_name = poly.net_name
|
|
602
|
+
layer_name = poly.layer_name
|
|
603
|
+
if nets and (net_name != "" and net_name not in nets or layer_name not in layers):
|
|
604
|
+
continue
|
|
605
|
+
xt, yt = poly.points()
|
|
606
|
+
if not xt:
|
|
607
|
+
continue
|
|
608
|
+
x, y = GeometryOperators.orient_polygon(xt, yt, clockwise=True)
|
|
609
|
+
vertices = [(i, j) for i, j in zip(x, y)]
|
|
610
|
+
codes = [2 for _ in vertices]
|
|
611
|
+
codes[0] = 1
|
|
612
|
+
vertices.append((0, 0))
|
|
613
|
+
codes.append(79)
|
|
614
|
+
|
|
615
|
+
for void in poly.voids:
|
|
616
|
+
xvt, yvt = void.points()
|
|
617
|
+
if xvt:
|
|
618
|
+
xv, yv = GeometryOperators.orient_polygon(xvt, yvt, clockwise=False)
|
|
619
|
+
tmpV = [(i, j) for i, j in zip(xv, yv)]
|
|
620
|
+
vertices.extend(tmpV)
|
|
621
|
+
tmpC = [2 for _ in tmpV]
|
|
622
|
+
tmpC[0] = 1
|
|
623
|
+
codes.extend(tmpC)
|
|
624
|
+
vertices.append((0, 0))
|
|
625
|
+
codes.append(79)
|
|
626
|
+
|
|
627
|
+
create_label = False
|
|
628
|
+
if not color_by_net:
|
|
629
|
+
label = "Layer " + layer_name
|
|
630
|
+
if label not in label_colors:
|
|
631
|
+
try:
|
|
632
|
+
color = poly.GetLayer().GetColor()
|
|
633
|
+
c = (
|
|
634
|
+
float(color.Item1 / 255),
|
|
635
|
+
float(color.Item2 / 255),
|
|
636
|
+
float(color.Item3 / 255),
|
|
637
|
+
)
|
|
638
|
+
except:
|
|
639
|
+
c = list(CSS4_COLORS.keys())[color_index]
|
|
640
|
+
color_index += 1
|
|
641
|
+
if color_index >= len(CSS4_COLORS):
|
|
642
|
+
color_index = 0
|
|
643
|
+
label_colors[label] = c
|
|
644
|
+
create_label = True
|
|
645
|
+
else:
|
|
646
|
+
label = "Net " + net_name
|
|
647
|
+
if label not in label_colors:
|
|
648
|
+
label_colors[label] = list(CSS4_COLORS.keys())[color_index]
|
|
649
|
+
color_index += 1
|
|
650
|
+
if color_index >= len(CSS4_COLORS):
|
|
651
|
+
color_index = 0
|
|
652
|
+
create_label = True
|
|
653
|
+
|
|
654
|
+
if create_label and n_label <= max_labels:
|
|
655
|
+
if layer_name == "Outline":
|
|
656
|
+
objects_lists.append([vertices, codes, label_colors[label], label, 1.0, 2.0, "contour"])
|
|
657
|
+
else:
|
|
658
|
+
objects_lists.append([vertices, codes, label_colors[label], label, 0.4, "path"])
|
|
659
|
+
n_label += 1
|
|
660
|
+
else:
|
|
661
|
+
if layer_name == "Outline":
|
|
662
|
+
objects_lists.append([vertices, codes, label_colors[label], None, 1.0, 2.0, "contour"])
|
|
663
|
+
else:
|
|
664
|
+
objects_lists.append([vertices, codes, label_colors[label], None, 0.4, "path"])
|
|
665
|
+
|
|
666
|
+
for circle in self._pedb.modeler.circles:
|
|
667
|
+
if circle.is_void:
|
|
668
|
+
continue
|
|
669
|
+
net_name = circle.net_name
|
|
670
|
+
layer_name = circle.layer_name
|
|
671
|
+
if nets and (net_name not in nets or layer_name not in layers):
|
|
672
|
+
continue
|
|
673
|
+
x, y = circle.points()
|
|
674
|
+
if not x:
|
|
675
|
+
continue
|
|
676
|
+
create_label = False
|
|
677
|
+
if not color_by_net:
|
|
678
|
+
label = "Layer " + layer_name
|
|
679
|
+
if label not in label_colors:
|
|
680
|
+
try:
|
|
681
|
+
color = circle.layer.GetColor()
|
|
682
|
+
c = (
|
|
683
|
+
float(color.Item1 / 255),
|
|
684
|
+
float(color.Item2 / 255),
|
|
685
|
+
float(color.Item3 / 255),
|
|
686
|
+
)
|
|
687
|
+
except:
|
|
688
|
+
c = list(CSS4_COLORS.keys())[color_index]
|
|
689
|
+
color_index += 1
|
|
690
|
+
if color_index >= len(CSS4_COLORS):
|
|
691
|
+
color_index = 0
|
|
692
|
+
label_colors[label] = c
|
|
693
|
+
create_label = True
|
|
694
|
+
else:
|
|
695
|
+
label = "Net " + net_name
|
|
696
|
+
if label not in label_colors:
|
|
697
|
+
label_colors[label] = list(CSS4_COLORS.keys())[color_index]
|
|
698
|
+
color_index += 1
|
|
699
|
+
if color_index >= len(CSS4_COLORS):
|
|
700
|
+
color_index = 0
|
|
701
|
+
create_label = True
|
|
702
|
+
|
|
703
|
+
if create_label and n_label <= max_labels:
|
|
704
|
+
objects_lists.append([x, y, label_colors[label], label, 0.4, "fill"])
|
|
705
|
+
n_label += 1
|
|
706
|
+
else:
|
|
707
|
+
objects_lists.append([x, y, label_colors[label], None, 0.4, "fill"])
|
|
708
|
+
|
|
709
|
+
for rect in self._pedb.modeler.rectangles:
|
|
710
|
+
if rect.is_void:
|
|
711
|
+
continue
|
|
712
|
+
net_name = rect.net_name
|
|
713
|
+
layer_name = rect.layer_name
|
|
714
|
+
if nets and (net_name not in nets or layer_name not in layers):
|
|
715
|
+
continue
|
|
716
|
+
x, y = rect.points()
|
|
717
|
+
if not x:
|
|
718
|
+
continue
|
|
719
|
+
create_label = False
|
|
720
|
+
if not color_by_net:
|
|
721
|
+
label = "Layer " + layer_name
|
|
722
|
+
if label not in label_colors:
|
|
723
|
+
try:
|
|
724
|
+
color = rect.layer.GetColor()
|
|
725
|
+
c = (
|
|
726
|
+
float(color.Item1 / 255),
|
|
727
|
+
float(color.Item2 / 255),
|
|
728
|
+
float(color.Item3 / 255),
|
|
729
|
+
)
|
|
730
|
+
except:
|
|
731
|
+
c = list(CSS4_COLORS.keys())[color_index]
|
|
732
|
+
color_index += 1
|
|
733
|
+
if color_index >= len(CSS4_COLORS):
|
|
734
|
+
color_index = 0
|
|
735
|
+
label_colors[label] = c
|
|
736
|
+
create_label = True
|
|
737
|
+
else:
|
|
738
|
+
label = "Net " + net_name
|
|
739
|
+
if label not in label_colors:
|
|
740
|
+
label_colors[label] = list(CSS4_COLORS.keys())[color_index]
|
|
741
|
+
color_index += 1
|
|
742
|
+
if color_index >= len(CSS4_COLORS):
|
|
743
|
+
color_index = 0
|
|
744
|
+
create_label = True
|
|
745
|
+
|
|
746
|
+
if create_label and n_label <= max_labels:
|
|
747
|
+
objects_lists.append([x, y, label_colors[label], label, 0.4, "fill"])
|
|
748
|
+
n_label += 1
|
|
749
|
+
else:
|
|
750
|
+
objects_lists.append([x, y, label_colors[label], None, 0.4, "fill"])
|
|
751
|
+
|
|
752
|
+
end_time = time.time() - start_time
|
|
753
|
+
self._logger.info("Nets Point Generation time %s seconds", round(end_time, 3))
|
|
754
|
+
if os.getenv("PYAEDT_SERVER_AEDT_PATH", None):
|
|
755
|
+
return str(objects_lists)
|
|
756
|
+
else:
|
|
757
|
+
return objects_lists
|
|
758
|
+
|
|
759
|
+
@pyedb_function_handler()
|
|
760
|
+
def classify_nets(self, power_nets=None, signal_nets=None):
|
|
761
|
+
"""Reassign power/ground or signal nets based on list of nets.
|
|
762
|
+
|
|
763
|
+
Parameters
|
|
764
|
+
----------
|
|
765
|
+
power_nets : str, list, optional
|
|
766
|
+
List of power nets to assign. Default is `None`.
|
|
767
|
+
signal_nets : str, list, optional
|
|
768
|
+
List of signal nets to assign. Default is `None`.
|
|
769
|
+
|
|
770
|
+
Returns
|
|
771
|
+
-------
|
|
772
|
+
bool
|
|
773
|
+
``True`` when successful, ``False`` when failed.
|
|
774
|
+
"""
|
|
775
|
+
if isinstance(power_nets, str):
|
|
776
|
+
power_nets = []
|
|
777
|
+
elif not power_nets:
|
|
778
|
+
power_nets = []
|
|
779
|
+
if isinstance(signal_nets, str):
|
|
780
|
+
signal_nets = []
|
|
781
|
+
elif not signal_nets:
|
|
782
|
+
signal_nets = []
|
|
783
|
+
for net in power_nets:
|
|
784
|
+
if net in self.nets:
|
|
785
|
+
self.nets[net].net_object.SetIsPowerGround(True)
|
|
786
|
+
for net in signal_nets:
|
|
787
|
+
if net in self.nets:
|
|
788
|
+
self.nets[net].net_object.SetIsPowerGround(False)
|
|
789
|
+
return True
|
|
790
|
+
|
|
791
|
+
@pyedb_function_handler()
|
|
792
|
+
def plot(
|
|
793
|
+
self,
|
|
794
|
+
nets=None,
|
|
795
|
+
layers=None,
|
|
796
|
+
color_by_net=False,
|
|
797
|
+
show_legend=True,
|
|
798
|
+
save_plot=None,
|
|
799
|
+
outline=None,
|
|
800
|
+
size=(2000, 1000),
|
|
801
|
+
plot_components_on_top=False,
|
|
802
|
+
plot_components_on_bottom=False,
|
|
803
|
+
):
|
|
804
|
+
"""Plot a Net to Matplotlib 2D Chart.
|
|
805
|
+
|
|
806
|
+
Parameters
|
|
807
|
+
----------
|
|
808
|
+
nets : str, list, optional
|
|
809
|
+
Name of the net or list of nets to plot. If ``None`` all nets will be plotted.
|
|
810
|
+
layers : str, list, optional
|
|
811
|
+
Name of the layers to include in the plot. If ``None`` all the signal layers will be considered.
|
|
812
|
+
color_by_net : bool, optional
|
|
813
|
+
If ``True`` the plot will be colored by net.
|
|
814
|
+
If ``False`` the plot will be colored by layer. (default)
|
|
815
|
+
show_legend : bool, optional
|
|
816
|
+
If ``True`` the legend is shown in the plot. (default)
|
|
817
|
+
If ``False`` the legend is not shown.
|
|
818
|
+
save_plot : str, optional
|
|
819
|
+
If ``None`` the plot will be shown.
|
|
820
|
+
If a file path is specified the plot will be saved to such file.
|
|
821
|
+
outline : list, optional
|
|
822
|
+
List of points of the outline to plot.
|
|
823
|
+
size : tuple, int, optional
|
|
824
|
+
Image size in pixel (width, height). Default value is ``(2000, 1000)``
|
|
825
|
+
plot_components_on_top : bool, optional
|
|
826
|
+
If ``True`` the components placed on top layer are plotted.
|
|
827
|
+
If ``False`` the components are not plotted. (default)
|
|
828
|
+
If nets and/or layers is specified, only the components belonging to the specified nets/layers are plotted.
|
|
829
|
+
plot_components_on_bottom : bool, optional
|
|
830
|
+
If ``True`` the components placed on bottom layer are plotted.
|
|
831
|
+
If ``False`` the components are not plotted. (default)
|
|
832
|
+
If nets and/or layers is specified, only the components belonging to the specified nets/layers are plotted.
|
|
833
|
+
"""
|
|
834
|
+
if is_ironpython:
|
|
835
|
+
self._logger.warning("Plot functionalities are enabled only in CPython.")
|
|
836
|
+
return False
|
|
837
|
+
from pyedb.generic.plot import plot_matplotlib
|
|
838
|
+
|
|
839
|
+
object_lists = self.get_plot_data(
|
|
840
|
+
nets,
|
|
841
|
+
layers,
|
|
842
|
+
color_by_net,
|
|
843
|
+
outline,
|
|
844
|
+
plot_components_on_top,
|
|
845
|
+
plot_components_on_bottom,
|
|
846
|
+
)
|
|
847
|
+
|
|
848
|
+
if isinstance(size, int): # pragma: no cover
|
|
849
|
+
board_size_x, board_size_y = self._pedb.get_statistics().layout_size
|
|
850
|
+
fig_size_x = size
|
|
851
|
+
fig_size_y = board_size_y * fig_size_x / board_size_x
|
|
852
|
+
size = (fig_size_x, fig_size_y)
|
|
853
|
+
|
|
854
|
+
plot_matplotlib(
|
|
855
|
+
plot_data=object_lists,
|
|
856
|
+
size=size,
|
|
857
|
+
show_legend=show_legend,
|
|
858
|
+
xlabel="X (m)",
|
|
859
|
+
ylabel="Y (m)",
|
|
860
|
+
title=self._pedb.active_cell.GetName(),
|
|
861
|
+
snapshot_path=save_plot,
|
|
862
|
+
axis_equal=True,
|
|
863
|
+
)
|
|
864
|
+
|
|
865
|
+
@pyedb_function_handler()
|
|
866
|
+
def is_power_gound_net(self, netname_list):
|
|
867
|
+
"""Determine if one of the nets in a list is power or ground.
|
|
868
|
+
|
|
869
|
+
Parameters
|
|
870
|
+
----------
|
|
871
|
+
netname_list : list
|
|
872
|
+
List of net names.
|
|
873
|
+
|
|
874
|
+
Returns
|
|
875
|
+
-------
|
|
876
|
+
bool
|
|
877
|
+
``True`` when one of the net names is ``"power"`` or ``"ground"``, ``False`` otherwise.
|
|
878
|
+
"""
|
|
879
|
+
if isinstance(netname_list, str):
|
|
880
|
+
netname_list = [netname_list]
|
|
881
|
+
power_nets_names = list(self.power_nets.keys())
|
|
882
|
+
for netname in netname_list:
|
|
883
|
+
if netname in power_nets_names:
|
|
884
|
+
return True
|
|
885
|
+
return False
|
|
886
|
+
|
|
887
|
+
@pyedb_function_handler()
|
|
888
|
+
def get_dcconnected_net_list(self, ground_nets=["GND"], res_value=0.001):
|
|
889
|
+
"""Get the nets connected to the direct current through inductors.
|
|
890
|
+
|
|
891
|
+
.. note::
|
|
892
|
+
Only inductors are considered.
|
|
893
|
+
|
|
894
|
+
Parameters
|
|
895
|
+
----------
|
|
896
|
+
ground_nets : list, optional
|
|
897
|
+
List of ground nets. The default is ``["GND"]``.
|
|
898
|
+
|
|
899
|
+
Returns
|
|
900
|
+
-------
|
|
901
|
+
list
|
|
902
|
+
List of nets connected to DC through inductors.
|
|
903
|
+
"""
|
|
904
|
+
temp_list = []
|
|
905
|
+
for _, comp_obj in self._pedb.components.inductors.items():
|
|
906
|
+
numpins = comp_obj.numpins
|
|
907
|
+
|
|
908
|
+
if numpins == 2:
|
|
909
|
+
nets = comp_obj.nets
|
|
910
|
+
if not set(nets).intersection(set(ground_nets)):
|
|
911
|
+
temp_list.append(set(nets))
|
|
912
|
+
else:
|
|
913
|
+
pass
|
|
914
|
+
for _, comp_obj in self._pedb.components.resistors.items():
|
|
915
|
+
numpins = comp_obj.numpins
|
|
916
|
+
|
|
917
|
+
if numpins == 2 and self._pedb._decompose_variable_value(comp_obj.res_value) <= res_value:
|
|
918
|
+
nets = comp_obj.nets
|
|
919
|
+
if not set(nets).intersection(set(ground_nets)):
|
|
920
|
+
temp_list.append(set(nets))
|
|
921
|
+
else:
|
|
922
|
+
pass
|
|
923
|
+
dcconnected_net_list = []
|
|
924
|
+
|
|
925
|
+
while not not temp_list:
|
|
926
|
+
s = temp_list.pop(0)
|
|
927
|
+
interseciton_flag = False
|
|
928
|
+
for i in temp_list:
|
|
929
|
+
if not not s.intersection(i):
|
|
930
|
+
i.update(s)
|
|
931
|
+
interseciton_flag = True
|
|
932
|
+
|
|
933
|
+
if not interseciton_flag:
|
|
934
|
+
dcconnected_net_list.append(s)
|
|
935
|
+
|
|
936
|
+
return dcconnected_net_list
|
|
937
|
+
|
|
938
|
+
@pyedb_function_handler()
|
|
939
|
+
def get_powertree(self, power_net_name, ground_nets):
|
|
940
|
+
"""Retrieve the power tree.
|
|
941
|
+
|
|
942
|
+
Parameters
|
|
943
|
+
----------
|
|
944
|
+
power_net_name : str
|
|
945
|
+
Name of the power net.
|
|
946
|
+
ground_nets :
|
|
947
|
+
|
|
948
|
+
|
|
949
|
+
Returns
|
|
950
|
+
-------
|
|
951
|
+
|
|
952
|
+
"""
|
|
953
|
+
flag_in_ng = False
|
|
954
|
+
net_group = []
|
|
955
|
+
for ng in self.get_dcconnected_net_list(ground_nets):
|
|
956
|
+
if power_net_name in ng:
|
|
957
|
+
flag_in_ng = True
|
|
958
|
+
net_group.extend(ng)
|
|
959
|
+
break
|
|
960
|
+
|
|
961
|
+
if not flag_in_ng:
|
|
962
|
+
net_group.append(power_net_name)
|
|
963
|
+
|
|
964
|
+
component_list = []
|
|
965
|
+
rats = self._pedb.components.get_rats()
|
|
966
|
+
for net in net_group:
|
|
967
|
+
for el in rats:
|
|
968
|
+
if net in el["net_name"]:
|
|
969
|
+
i = 0
|
|
970
|
+
for n in el["net_name"]:
|
|
971
|
+
if n == net:
|
|
972
|
+
df = [el["refdes"][i], el["pin_name"][i], net]
|
|
973
|
+
component_list.append(df)
|
|
974
|
+
i += 1
|
|
975
|
+
|
|
976
|
+
component_type = []
|
|
977
|
+
for el in component_list:
|
|
978
|
+
refdes = el[0]
|
|
979
|
+
comp_type = self._pedb.components._cmp[refdes].type
|
|
980
|
+
component_type.append(comp_type)
|
|
981
|
+
el.append(comp_type)
|
|
982
|
+
|
|
983
|
+
comp_partname = self._pedb.components._cmp[refdes].partname
|
|
984
|
+
el.append(comp_partname)
|
|
985
|
+
pins = self._pedb.components.get_pin_from_component(component=refdes, netName=el[2])
|
|
986
|
+
el.append("-".join([i.GetName() for i in pins]))
|
|
987
|
+
|
|
988
|
+
component_list_columns = [
|
|
989
|
+
"refdes",
|
|
990
|
+
"pin_name",
|
|
991
|
+
"net_name",
|
|
992
|
+
"component_type",
|
|
993
|
+
"component_partname",
|
|
994
|
+
"pin_list",
|
|
995
|
+
]
|
|
996
|
+
return component_list, component_list_columns, net_group
|
|
997
|
+
|
|
998
|
+
@pyedb_function_handler()
|
|
999
|
+
def get_net_by_name(self, net_name):
|
|
1000
|
+
"""Find a net by name."""
|
|
1001
|
+
edb_net = self._edb.cell.net.find_by_name(self._active_layout, net_name)
|
|
1002
|
+
if edb_net is not None:
|
|
1003
|
+
return edb_net
|
|
1004
|
+
|
|
1005
|
+
@pyedb_function_handler()
|
|
1006
|
+
def delete_nets(self, netlist):
|
|
1007
|
+
"""Delete one or more nets from EDB.
|
|
1008
|
+
|
|
1009
|
+
.. deprecated:: 0.6.62
|
|
1010
|
+
Use :func:`delete` method instead.
|
|
1011
|
+
|
|
1012
|
+
Parameters
|
|
1013
|
+
----------
|
|
1014
|
+
netlist : str or list
|
|
1015
|
+
One or more nets to delete.
|
|
1016
|
+
|
|
1017
|
+
Returns
|
|
1018
|
+
-------
|
|
1019
|
+
list
|
|
1020
|
+
List of nets that were deleted.
|
|
1021
|
+
|
|
1022
|
+
Examples
|
|
1023
|
+
--------
|
|
1024
|
+
|
|
1025
|
+
>>> deleted_nets = edb_core.nets.delete(["Net1","Net2"])
|
|
1026
|
+
"""
|
|
1027
|
+
warnings.warn("Use :func:`delete` method instead.", DeprecationWarning)
|
|
1028
|
+
return self.delete(netlist=netlist)
|
|
1029
|
+
|
|
1030
|
+
@pyedb_function_handler()
|
|
1031
|
+
def delete(self, netlist):
|
|
1032
|
+
"""Delete one or more nets from EDB.
|
|
1033
|
+
|
|
1034
|
+
Parameters
|
|
1035
|
+
----------
|
|
1036
|
+
netlist : str or list
|
|
1037
|
+
One or more nets to delete.
|
|
1038
|
+
|
|
1039
|
+
Returns
|
|
1040
|
+
-------
|
|
1041
|
+
list
|
|
1042
|
+
List of nets that were deleted.
|
|
1043
|
+
|
|
1044
|
+
Examples
|
|
1045
|
+
--------
|
|
1046
|
+
|
|
1047
|
+
>>> deleted_nets = edb_core.nets.delete(["Net1","Net2"])
|
|
1048
|
+
"""
|
|
1049
|
+
if isinstance(netlist, str):
|
|
1050
|
+
netlist = [netlist]
|
|
1051
|
+
|
|
1052
|
+
self._pedb.modeler.delete_primitives(netlist)
|
|
1053
|
+
self._pedb.padstacks.delete_padstack_instances(netlist)
|
|
1054
|
+
|
|
1055
|
+
nets_deleted = []
|
|
1056
|
+
|
|
1057
|
+
for i in self._pedb.nets.nets.values():
|
|
1058
|
+
if i.name in netlist:
|
|
1059
|
+
i.net_object.Delete()
|
|
1060
|
+
nets_deleted.append(i.name)
|
|
1061
|
+
return nets_deleted
|
|
1062
|
+
|
|
1063
|
+
@pyedb_function_handler()
|
|
1064
|
+
def find_or_create_net(self, net_name="", start_with="", contain="", end_with=""):
|
|
1065
|
+
"""Find or create the net with the given name in the layout.
|
|
1066
|
+
|
|
1067
|
+
Parameters
|
|
1068
|
+
----------
|
|
1069
|
+
net_name : str, optional
|
|
1070
|
+
Name of the net to find or create. The default is ``""``.
|
|
1071
|
+
|
|
1072
|
+
start_with : str, optional
|
|
1073
|
+
All net name starting with the string. Not case-sensitive.
|
|
1074
|
+
|
|
1075
|
+
contain : str, optional
|
|
1076
|
+
All net name containing the string. Not case-sensitive.
|
|
1077
|
+
|
|
1078
|
+
end_with : str, optional
|
|
1079
|
+
All net name ending with the string. Not case-sensitive.
|
|
1080
|
+
|
|
1081
|
+
Returns
|
|
1082
|
+
-------
|
|
1083
|
+
object
|
|
1084
|
+
Net Object.
|
|
1085
|
+
"""
|
|
1086
|
+
if not net_name and not start_with and not contain and not end_with:
|
|
1087
|
+
net_name = generate_unique_name("NET_")
|
|
1088
|
+
net = self._edb.cell.net.create(self._active_layout, net_name)
|
|
1089
|
+
return net
|
|
1090
|
+
else:
|
|
1091
|
+
if not start_with and not contain and not end_with:
|
|
1092
|
+
net = self._edb.cell.net.find_by_name(self._active_layout, net_name)
|
|
1093
|
+
if net.IsNull():
|
|
1094
|
+
net = self._edb.cell.net.create(self._active_layout, net_name)
|
|
1095
|
+
return net
|
|
1096
|
+
elif start_with:
|
|
1097
|
+
nets_found = [
|
|
1098
|
+
self.nets[net].net_object for net in list(self.nets.keys()) if net.lower().startswith(start_with)
|
|
1099
|
+
]
|
|
1100
|
+
return nets_found
|
|
1101
|
+
elif start_with and end_with:
|
|
1102
|
+
nets_found = [
|
|
1103
|
+
self.nets[net].net_object
|
|
1104
|
+
for net in list(self.nets.keys())
|
|
1105
|
+
if net.lower().startswith(start_with) and net.lower().endswith(end_with)
|
|
1106
|
+
]
|
|
1107
|
+
return nets_found
|
|
1108
|
+
elif start_with and contain and end_with:
|
|
1109
|
+
nets_found = [
|
|
1110
|
+
self.nets[net].net_object
|
|
1111
|
+
for net in list(self.nets.keys())
|
|
1112
|
+
if net.lower().startswith(start_with) and net.lower().endswith(end_with) and contain in net.lower()
|
|
1113
|
+
]
|
|
1114
|
+
return nets_found
|
|
1115
|
+
elif start_with and contain:
|
|
1116
|
+
nets_found = [
|
|
1117
|
+
self.nets[net].net_object
|
|
1118
|
+
for net in list(self.nets.keys())
|
|
1119
|
+
if net.lower().startswith(start_with) and contain in net.lower()
|
|
1120
|
+
]
|
|
1121
|
+
return nets_found
|
|
1122
|
+
elif contain and end_with:
|
|
1123
|
+
nets_found = [
|
|
1124
|
+
self.nets[net].net_object
|
|
1125
|
+
for net in list(self.nets.keys())
|
|
1126
|
+
if net.lower().endswith(end_with) and contain in net.lower()
|
|
1127
|
+
]
|
|
1128
|
+
return nets_found
|
|
1129
|
+
elif end_with and not start_with and not contain:
|
|
1130
|
+
nets_found = [
|
|
1131
|
+
self.nets[net].net_object for net in list(self.nets.keys()) if net.lower().endswith(end_with)
|
|
1132
|
+
]
|
|
1133
|
+
return nets_found
|
|
1134
|
+
elif contain and not start_with and not end_with:
|
|
1135
|
+
nets_found = [self.nets[net].net_object for net in list(self.nets.keys()) if contain in net.lower()]
|
|
1136
|
+
return nets_found
|
|
1137
|
+
|
|
1138
|
+
@pyedb_function_handler()
|
|
1139
|
+
def is_net_in_component(self, component_name, net_name):
|
|
1140
|
+
"""Check if a net belongs to a component.
|
|
1141
|
+
|
|
1142
|
+
Parameters
|
|
1143
|
+
----------
|
|
1144
|
+
component_name : str
|
|
1145
|
+
Name of the component.
|
|
1146
|
+
net_name : str
|
|
1147
|
+
Name of the net.
|
|
1148
|
+
|
|
1149
|
+
Returns
|
|
1150
|
+
-------
|
|
1151
|
+
bool
|
|
1152
|
+
``True`` if the net is found in component pins.
|
|
1153
|
+
|
|
1154
|
+
"""
|
|
1155
|
+
if component_name not in self._pedb.components.components:
|
|
1156
|
+
return False
|
|
1157
|
+
for net in self._pedb.components.components[component_name].nets:
|
|
1158
|
+
if net_name == net:
|
|
1159
|
+
return True
|
|
1160
|
+
return False
|
|
1161
|
+
|
|
1162
|
+
@pyedb_function_handler()
|
|
1163
|
+
def find_and_fix_disjoint_nets(
|
|
1164
|
+
self, net_list=None, keep_only_main_net=False, clean_disjoints_less_than=0.0, order_by_area=False
|
|
1165
|
+
):
|
|
1166
|
+
"""Find and fix disjoint nets from a given netlist.
|
|
1167
|
+
|
|
1168
|
+
.. deprecated::
|
|
1169
|
+
Use new property :func:`edb.layout_validation.disjoint_nets` instead.
|
|
1170
|
+
|
|
1171
|
+
Parameters
|
|
1172
|
+
----------
|
|
1173
|
+
net_list : str, list, optional
|
|
1174
|
+
List of nets on which check disjoints. If `None` is provided then the algorithm will loop on all nets.
|
|
1175
|
+
keep_only_main_net : bool, optional
|
|
1176
|
+
Remove all secondary nets other than principal one (the one with more objects in it). Default is `False`.
|
|
1177
|
+
clean_disjoints_less_than : bool, optional
|
|
1178
|
+
Clean all disjoint nets with area less than specified area in square meters. Default is `0.0` to disable it.
|
|
1179
|
+
order_by_area : bool, optional
|
|
1180
|
+
Whether if the naming order has to be by number of objects (fastest) or area (slowest but more accurate).
|
|
1181
|
+
Default is ``False``.
|
|
1182
|
+
|
|
1183
|
+
Returns
|
|
1184
|
+
-------
|
|
1185
|
+
List
|
|
1186
|
+
New nets created.
|
|
1187
|
+
|
|
1188
|
+
Examples
|
|
1189
|
+
--------
|
|
1190
|
+
|
|
1191
|
+
>>> renamed_nets = edb_core.nets.find_and_fix_disjoint_nets(["GND","Net2"])
|
|
1192
|
+
"""
|
|
1193
|
+
warnings.warn("Use new function :func:`edb.layout_validation.disjoint_nets` instead.", DeprecationWarning)
|
|
1194
|
+
return self._pedb.layout_validation.disjoint_nets(
|
|
1195
|
+
net_list, keep_only_main_net, clean_disjoints_less_than, order_by_area
|
|
1196
|
+
)
|
|
1197
|
+
|
|
1198
|
+
@pyedb_function_handler()
|
|
1199
|
+
def merge_nets_polygons(self, net_list):
|
|
1200
|
+
"""Convert paths from net into polygons, evaluate all connected polygons and perform the merge.
|
|
1201
|
+
|
|
1202
|
+
Parameters
|
|
1203
|
+
----------
|
|
1204
|
+
net_list : str or list[str]
|
|
1205
|
+
Net name of list of net name.
|
|
1206
|
+
|
|
1207
|
+
Returns
|
|
1208
|
+
-------
|
|
1209
|
+
bool
|
|
1210
|
+
``True`` when successful, ``False`` when failed.
|
|
1211
|
+
|
|
1212
|
+
"""
|
|
1213
|
+
if isinstance(net_list, str):
|
|
1214
|
+
net_list = [net_list]
|
|
1215
|
+
return self._pedb.modeler.unite_polygons_on_layer(net_list=net_list)
|