pyedb 0.27.0__py3-none-any.whl → 0.29.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.
- pyedb/__init__.py +1 -1
- pyedb/configuration/cfg_boundaries.py +44 -74
- pyedb/configuration/cfg_common.py +1 -1
- pyedb/configuration/cfg_components.py +31 -105
- pyedb/configuration/cfg_data.py +4 -9
- pyedb/configuration/cfg_operations.py +19 -13
- pyedb/configuration/cfg_padstacks.py +66 -89
- pyedb/configuration/cfg_pin_groups.py +7 -8
- pyedb/configuration/cfg_ports_sources.py +4 -2
- pyedb/configuration/cfg_s_parameter_models.py +85 -29
- pyedb/configuration/configuration.py +48 -13
- pyedb/dotnet/application/Variables.py +43 -41
- pyedb/dotnet/edb.py +12 -4
- pyedb/dotnet/edb_core/cell/hierarchy/component.py +199 -0
- pyedb/dotnet/edb_core/cell/layout.py +4 -1
- pyedb/dotnet/edb_core/cell/primitive/primitive.py +2 -0
- pyedb/dotnet/edb_core/cell/terminal/pingroup_terminal.py +3 -3
- pyedb/dotnet/edb_core/cell/terminal/terminal.py +4 -3
- pyedb/dotnet/edb_core/definition/component_def.py +17 -1
- pyedb/dotnet/edb_core/definition/component_model.py +0 -4
- pyedb/dotnet/edb_core/edb_data/hfss_extent_info.py +3 -3
- pyedb/dotnet/edb_core/edb_data/nets_data.py +10 -7
- pyedb/dotnet/edb_core/edb_data/padstacks_data.py +301 -45
- pyedb/dotnet/edb_core/edb_data/primitives_data.py +2 -2
- pyedb/dotnet/edb_core/general.py +11 -0
- pyedb/dotnet/edb_core/layout_validation.py +3 -3
- pyedb/dotnet/edb_core/modeler.py +5 -2
- pyedb/dotnet/edb_core/nets.py +162 -181
- pyedb/edb_logger.py +1 -1
- pyedb/siwave.py +33 -7
- {pyedb-0.27.0.dist-info → pyedb-0.29.0.dist-info}/METADATA +5 -5
- {pyedb-0.27.0.dist-info → pyedb-0.29.0.dist-info}/RECORD +34 -34
- {pyedb-0.27.0.dist-info → pyedb-0.29.0.dist-info}/LICENSE +0 -0
- {pyedb-0.27.0.dist-info → pyedb-0.29.0.dist-info}/WHEEL +0 -0
|
@@ -47,10 +47,10 @@ class PinGroupTerminal(Terminal):
|
|
|
47
47
|
-------
|
|
48
48
|
:class:`pyedb.dotnet.edb_core.edb_data.terminals.PinGroupTerminal`
|
|
49
49
|
"""
|
|
50
|
-
net_obj = self._pedb.
|
|
50
|
+
net_obj = self._pedb.layout.find_net_by_name(net_name)
|
|
51
51
|
term = self._pedb.edb_api.cell.terminal.PinGroupTerminal.Create(
|
|
52
52
|
self._pedb.active_layout,
|
|
53
|
-
net_obj.
|
|
53
|
+
net_obj._edb_object,
|
|
54
54
|
name,
|
|
55
55
|
self._pedb.siwave.pin_groups[pin_group_name]._edb_object,
|
|
56
56
|
is_ref,
|
|
@@ -60,7 +60,7 @@ class PinGroupTerminal(Terminal):
|
|
|
60
60
|
msg = f"Failed to create terminal. "
|
|
61
61
|
if name in self._pedb.terminals:
|
|
62
62
|
msg += f"Terminal {name} already exists."
|
|
63
|
-
raise
|
|
63
|
+
raise ValueError(msg)
|
|
64
64
|
else:
|
|
65
65
|
return term
|
|
66
66
|
|
|
@@ -223,9 +223,10 @@ class Terminal(Connectable):
|
|
|
223
223
|
"""Get reference terminal."""
|
|
224
224
|
|
|
225
225
|
edb_terminal = self._edb_object.GetReferenceTerminal()
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
226
|
+
if not edb_terminal.IsNull():
|
|
227
|
+
return self._pedb.terminals[edb_terminal.GetName()]
|
|
228
|
+
else:
|
|
229
|
+
return None
|
|
229
230
|
|
|
230
231
|
@ref_terminal.setter
|
|
231
232
|
def ref_terminal(self, value):
|
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
import os
|
|
24
24
|
|
|
25
25
|
from pyedb.dotnet.edb_core.definition.component_model import NPortComponentModel
|
|
26
|
+
from pyedb.dotnet.edb_core.general import convert_py_list_to_net_list
|
|
26
27
|
from pyedb.dotnet.edb_core.utilities.obj_base import ObjBase
|
|
27
28
|
|
|
28
29
|
|
|
@@ -171,7 +172,7 @@ class EDBComponentDef(ObjBase):
|
|
|
171
172
|
def component_models(self):
|
|
172
173
|
temp = {}
|
|
173
174
|
for i in list(self._edb_object.GetComponentModels()):
|
|
174
|
-
temp_type = i.ToString().split(".")[
|
|
175
|
+
temp_type = i.ToString().split(".")[-1]
|
|
175
176
|
if temp_type == "NPortComponentModel":
|
|
176
177
|
edb_object = NPortComponentModel(self._pedb, i)
|
|
177
178
|
temp[edb_object.name] = edb_object
|
|
@@ -197,3 +198,18 @@ class EDBComponentDef(ObjBase):
|
|
|
197
198
|
footprint_cell = self._pedb._active_cell.cell.Create(self._pedb.active_db, cell_type, name)
|
|
198
199
|
edb_object = self._pedb.edb_api.definition.ComponentDef.Create(self._pedb.active_db, name, footprint_cell)
|
|
199
200
|
return EDBComponentDef(self._pedb, edb_object)
|
|
201
|
+
|
|
202
|
+
def get_properties(self):
|
|
203
|
+
data = {}
|
|
204
|
+
temp = []
|
|
205
|
+
for i in list(self._edb_object.ComponentDefPins):
|
|
206
|
+
temp.append(i.GetName())
|
|
207
|
+
data["pin_order"] = temp
|
|
208
|
+
return data
|
|
209
|
+
|
|
210
|
+
def set_properties(self, **kwargs):
|
|
211
|
+
pin_order = kwargs.get("pin_order")
|
|
212
|
+
if pin_order:
|
|
213
|
+
old = {i.GetName(): i for i in list(self._edb_object.ComponentDefPins)}
|
|
214
|
+
temp = convert_py_list_to_net_list([old[str(i)] for i in pin_order])
|
|
215
|
+
self._edb_object.ReorderPins(temp)
|
|
@@ -30,10 +30,6 @@ class ComponentModel(ObjBase):
|
|
|
30
30
|
super().__init__(pedb, edb_object)
|
|
31
31
|
self._model_type_mapping = {"PinPairModel": self._pedb.edb_api.cell}
|
|
32
32
|
|
|
33
|
-
def name(self):
|
|
34
|
-
"""Name of the component model."""
|
|
35
|
-
return self._edb_object.GetName()
|
|
36
|
-
|
|
37
33
|
|
|
38
34
|
class NPortComponentModel(ComponentModel):
|
|
39
35
|
"""Class for n-port component models."""
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
|
|
23
23
|
from pyedb.dotnet.edb_core.edb_data.edbvalue import EdbValue
|
|
24
24
|
from pyedb.dotnet.edb_core.edb_data.primitives_data import cast
|
|
25
|
-
from pyedb.dotnet.edb_core.general import convert_pytuple_to_nettuple
|
|
25
|
+
from pyedb.dotnet.edb_core.general import convert_pytuple_to_nettuple, pascal_to_snake
|
|
26
26
|
|
|
27
27
|
|
|
28
28
|
class HfssExtentInfo:
|
|
@@ -192,7 +192,7 @@ class HfssExtentInfo:
|
|
|
192
192
|
@property
|
|
193
193
|
def dielectric_extent_type(self):
|
|
194
194
|
"""Dielectric extent type."""
|
|
195
|
-
return self._edb_hfss_extent_info.DielectricExtentType.ToString()
|
|
195
|
+
return pascal_to_snake(self._edb_hfss_extent_info.DielectricExtentType.ToString())
|
|
196
196
|
|
|
197
197
|
@dielectric_extent_type.setter
|
|
198
198
|
def dielectric_extent_type(self, value):
|
|
@@ -204,7 +204,7 @@ class HfssExtentInfo:
|
|
|
204
204
|
@property
|
|
205
205
|
def extent_type(self):
|
|
206
206
|
"""Extent type."""
|
|
207
|
-
return self._edb_hfss_extent_info.ExtentType.ToString()
|
|
207
|
+
return pascal_to_snake(self._edb_hfss_extent_info.ExtentType.ToString())
|
|
208
208
|
|
|
209
209
|
@extent_type.setter
|
|
210
210
|
def extent_type(self, value):
|
|
@@ -19,7 +19,6 @@
|
|
|
19
19
|
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
20
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
21
|
# SOFTWARE.
|
|
22
|
-
|
|
23
22
|
from pyedb.dotnet.edb_core.dotnet.database import (
|
|
24
23
|
DifferentialPairDotNet,
|
|
25
24
|
ExtendedNetDotNet,
|
|
@@ -58,7 +57,10 @@ class EDBNetsData(NetDotNet):
|
|
|
58
57
|
-------
|
|
59
58
|
list of :class:`pyedb.dotnet.edb_core.edb_data.primitives_data.EDBPrimitives`
|
|
60
59
|
"""
|
|
61
|
-
|
|
60
|
+
from pyedb.dotnet.edb_core.cell.layout import primitive_cast
|
|
61
|
+
|
|
62
|
+
return [primitive_cast(self._app, i) for i in self.net_object.Primitives]
|
|
63
|
+
# return [self._app.layout.find_object_by_id(i.GetId()) for i in self.net_object.Primitives]
|
|
62
64
|
|
|
63
65
|
@property
|
|
64
66
|
def padstack_instances(self):
|
|
@@ -67,10 +69,11 @@ class EDBNetsData(NetDotNet):
|
|
|
67
69
|
Returns
|
|
68
70
|
-------
|
|
69
71
|
list of :class:`pyedb.dotnet.edb_core.edb_data.padstacks_data.EDBPadstackInstance`"""
|
|
70
|
-
name = self.name
|
|
71
|
-
return [
|
|
72
|
-
|
|
73
|
-
]
|
|
72
|
+
# name = self.name
|
|
73
|
+
# return [
|
|
74
|
+
# EDBPadstackInstance(i, self._app) for i in self.net_object.PadstackInstances if i.GetNet().GetName() == name
|
|
75
|
+
# ]
|
|
76
|
+
return [EDBPadstackInstance(i, self._app) for i in self.net_object.PadstackInstances]
|
|
74
77
|
|
|
75
78
|
@property
|
|
76
79
|
def components(self):
|
|
@@ -133,7 +136,7 @@ class EDBNetsData(NetDotNet):
|
|
|
133
136
|
Whether to show the plot or not. Default is `True`.
|
|
134
137
|
"""
|
|
135
138
|
|
|
136
|
-
self._app.nets.plot(
|
|
139
|
+
return self._app.nets.plot(
|
|
137
140
|
self.name,
|
|
138
141
|
layers=layers,
|
|
139
142
|
show_legend=show_legend,
|
|
@@ -29,7 +29,12 @@ from pyedb.dotnet.clr_module import String
|
|
|
29
29
|
from pyedb.dotnet.edb_core.cell.primitive.primitive import Primitive
|
|
30
30
|
from pyedb.dotnet.edb_core.dotnet.database import PolygonDataDotNet
|
|
31
31
|
from pyedb.dotnet.edb_core.edb_data.edbvalue import EdbValue
|
|
32
|
-
from pyedb.dotnet.edb_core.general import
|
|
32
|
+
from pyedb.dotnet.edb_core.general import (
|
|
33
|
+
PadGeometryTpe,
|
|
34
|
+
convert_py_list_to_net_list,
|
|
35
|
+
pascal_to_snake,
|
|
36
|
+
snake_to_pascal,
|
|
37
|
+
)
|
|
33
38
|
from pyedb.generic.general_methods import generate_unique_name
|
|
34
39
|
from pyedb.modeler.geometry_operators import GeometryOperators
|
|
35
40
|
|
|
@@ -406,19 +411,231 @@ class EDBPadstack(object):
|
|
|
406
411
|
>>> edb_padstack = edb.padstacks.definitions["MyPad"]
|
|
407
412
|
"""
|
|
408
413
|
|
|
414
|
+
PAD_SHAPE_PARAMETERS = {
|
|
415
|
+
"circle": ["diameter"],
|
|
416
|
+
"square": ["size"],
|
|
417
|
+
"rectangle": ["x_size", "y_size"],
|
|
418
|
+
"oval": ["x_size", "y_size", "corner_radius"],
|
|
419
|
+
"bullet": ["x_size", "y_size", "corner_radius"],
|
|
420
|
+
"round45": ["inner", "channel_width", "isolation_gap"],
|
|
421
|
+
"round90": ["inner", "channel_width", "isolation_gap"],
|
|
422
|
+
"no_geometry": [],
|
|
423
|
+
}
|
|
424
|
+
|
|
409
425
|
def __init__(self, edb_padstack, ppadstack):
|
|
426
|
+
self._edb_object = edb_padstack
|
|
410
427
|
self.edb_padstack = edb_padstack
|
|
411
428
|
self._ppadstack = ppadstack
|
|
412
|
-
self.pad_by_layer = {}
|
|
413
|
-
self.antipad_by_layer = {}
|
|
414
|
-
self.thermalpad_by_layer = {}
|
|
415
429
|
self._bounding_box = []
|
|
416
430
|
self._hole_params = None
|
|
431
|
+
|
|
432
|
+
@property
|
|
433
|
+
def pad_by_layer(self):
|
|
434
|
+
"""Regular pad property."""
|
|
435
|
+
temp = {}
|
|
436
|
+
for layer in self.via_layers:
|
|
437
|
+
temp[layer] = EDBPadProperties(self._edb_object, layer, 0, self)
|
|
438
|
+
return temp
|
|
439
|
+
|
|
440
|
+
@property
|
|
441
|
+
def antipad_by_layer(self):
|
|
442
|
+
"""Anti pad property."""
|
|
443
|
+
temp = {}
|
|
417
444
|
for layer in self.via_layers:
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
445
|
+
temp[layer] = EDBPadProperties(self._edb_object, layer, 1, self)
|
|
446
|
+
return temp
|
|
447
|
+
|
|
448
|
+
@property
|
|
449
|
+
def thermalpad_by_layer(self):
|
|
450
|
+
"""Thermal pad property."""
|
|
451
|
+
temp = {}
|
|
452
|
+
for layer in self.via_layers:
|
|
453
|
+
temp[layer] = EDBPadProperties(self._edb_object, layer, 2, self)
|
|
454
|
+
return temp
|
|
455
|
+
|
|
456
|
+
@property
|
|
457
|
+
def _padstack_def_data(self):
|
|
458
|
+
"""Get padstack definition data.
|
|
459
|
+
|
|
460
|
+
Returns
|
|
461
|
+
-------
|
|
462
|
+
|
|
463
|
+
"""
|
|
464
|
+
pstack_data = self._edb_object.GetData()
|
|
465
|
+
return self._edb.definition.PadstackDefData(pstack_data)
|
|
466
|
+
|
|
467
|
+
@_padstack_def_data.setter
|
|
468
|
+
def _padstack_def_data(self, value):
|
|
469
|
+
self._edb_object.SetData(value)
|
|
470
|
+
|
|
471
|
+
@property
|
|
472
|
+
def pad_parameters(self) -> dict:
|
|
473
|
+
"""Pad parameters.
|
|
474
|
+
|
|
475
|
+
Returns
|
|
476
|
+
-------
|
|
477
|
+
dict
|
|
478
|
+
params = {
|
|
479
|
+
'regular_pad': [
|
|
480
|
+
{'layer_name': '1_Top', 'shape': 'circle', 'offset_x': '0.1mm', 'offset_y': '0', 'rotation': '0',
|
|
481
|
+
'diameter': '0.5mm'}
|
|
482
|
+
],
|
|
483
|
+
'anti_pad': [
|
|
484
|
+
{'layer_name': '1_Top', 'shape': 'circle', 'offset_x': '0', 'offset_y': '0', 'rotation': '0',
|
|
485
|
+
'diameter': '1mm'}
|
|
486
|
+
],
|
|
487
|
+
'thermal_pad': [
|
|
488
|
+
{'layer_name': '1_Top', 'shape': 'round90', 'offset_x': '0', 'offset_y': '0', 'rotation': '0',
|
|
489
|
+
'inner': '1mm', 'channel_width': '0.2mm', 'isolation_gap': '0.3mm'},
|
|
490
|
+
],
|
|
491
|
+
'hole': [
|
|
492
|
+
{'layer_name': '1_Top', 'shape': 'circle', 'offset_x': '0', 'offset_y': '0', 'rotation': '0',
|
|
493
|
+
'diameter': '0.1499997mm'},
|
|
494
|
+
]
|
|
495
|
+
}
|
|
496
|
+
"""
|
|
497
|
+
pdef_data = self._padstack_def_data
|
|
498
|
+
pad_type_list = [
|
|
499
|
+
self._ppadstack._pedb._edb.Definition.PadType.RegularPad,
|
|
500
|
+
self._ppadstack._pedb._edb.Definition.PadType.AntiPad,
|
|
501
|
+
self._ppadstack._pedb._edb.Definition.PadType.ThermalPad,
|
|
502
|
+
self._ppadstack._pedb._edb.Definition.PadType.Hole,
|
|
503
|
+
]
|
|
504
|
+
data = {}
|
|
505
|
+
for pad_type in pad_type_list:
|
|
506
|
+
pad_type_name = pascal_to_snake(pad_type.ToString())
|
|
507
|
+
temp_list = []
|
|
508
|
+
for lyr_name in list(pdef_data.GetLayerNames()):
|
|
509
|
+
result = pdef_data.GetPadParametersValue(lyr_name, pad_type)
|
|
510
|
+
_, pad_shape, params, offset_x, offset_y, rotation = result
|
|
511
|
+
pad_shape = pascal_to_snake(pad_shape.ToString())
|
|
512
|
+
|
|
513
|
+
pad_params = {}
|
|
514
|
+
pad_params["layer_name"] = lyr_name
|
|
515
|
+
pad_params["shape"] = pad_shape
|
|
516
|
+
pad_params["offset_x"] = offset_x.ToString()
|
|
517
|
+
pad_params["offset_y"] = offset_y.ToString()
|
|
518
|
+
pad_params["rotation"] = rotation.ToString()
|
|
519
|
+
|
|
520
|
+
for idx, i in enumerate(self.PAD_SHAPE_PARAMETERS[pad_shape]):
|
|
521
|
+
pad_params[i] = params[idx].ToString()
|
|
522
|
+
temp_list.append(pad_params)
|
|
523
|
+
data[pad_type_name] = temp_list
|
|
524
|
+
return data
|
|
525
|
+
|
|
526
|
+
@pad_parameters.setter
|
|
527
|
+
def pad_parameters(self, params: dict):
|
|
528
|
+
original_params = self.pad_parameters
|
|
529
|
+
pdef_data = self._padstack_def_data
|
|
530
|
+
|
|
531
|
+
pad_type_list = [
|
|
532
|
+
self._ppadstack._pedb._edb.Definition.PadType.RegularPad,
|
|
533
|
+
self._ppadstack._pedb._edb.Definition.PadType.AntiPad,
|
|
534
|
+
self._ppadstack._pedb._edb.Definition.PadType.ThermalPad,
|
|
535
|
+
self._ppadstack._pedb._edb.Definition.PadType.Hole,
|
|
536
|
+
]
|
|
537
|
+
for pad_type in pad_type_list:
|
|
538
|
+
pad_type_name = pascal_to_snake(pad_type.ToString())
|
|
539
|
+
rpp = params.get(pad_type_name, [])
|
|
540
|
+
for idx, layer_data in enumerate(rpp):
|
|
541
|
+
# Get geometry type from kwargs
|
|
542
|
+
p = layer_data.get("shape")
|
|
543
|
+
temp_param = []
|
|
544
|
+
|
|
545
|
+
# Handle Circle geometry type
|
|
546
|
+
if p == pascal_to_snake(self._ppadstack._pedb._edb.Definition.PadGeometryType.Circle.ToString()):
|
|
547
|
+
temp_param.append(layer_data["diameter"])
|
|
548
|
+
pad_shape = self._ppadstack._pedb._edb.Definition.PadGeometryType.Circle
|
|
549
|
+
|
|
550
|
+
# Handle Square geometry type
|
|
551
|
+
elif p == pascal_to_snake(self._ppadstack._pedb._edb.Definition.PadGeometryType.Square.ToString()):
|
|
552
|
+
temp_param.append(layer_data["size"])
|
|
553
|
+
pad_shape = self._ppadstack._pedb._edb.Definition.PadGeometryType.Square
|
|
554
|
+
|
|
555
|
+
elif p == pascal_to_snake(self._ppadstack._pedb._edb.Definition.PadGeometryType.Rectangle.ToString()):
|
|
556
|
+
temp_param.append(layer_data["x_size"])
|
|
557
|
+
temp_param.append(layer_data["y_size"])
|
|
558
|
+
pad_shape = self._ppadstack._pedb._edb.Definition.PadGeometryType.Rectangle
|
|
559
|
+
|
|
560
|
+
# Handle Oval geometry type
|
|
561
|
+
elif p == pascal_to_snake(self._ppadstack._pedb._edb.Definition.PadGeometryType.Oval.ToString()):
|
|
562
|
+
temp_param.append(layer_data["x_size"])
|
|
563
|
+
temp_param.append(layer_data["y_size"])
|
|
564
|
+
temp_param.append(layer_data["corner_radius"])
|
|
565
|
+
pad_shape = self._ppadstack._pedb._edb.Definition.PadGeometryType.Oval
|
|
566
|
+
|
|
567
|
+
# Handle Bullet geometry type
|
|
568
|
+
elif p == pascal_to_snake(self._ppadstack._pedb._edb.Definition.PadGeometryType.Bullet.ToString()):
|
|
569
|
+
temp_param.append(layer_data["x_size"])
|
|
570
|
+
temp_param.append(layer_data["y_size"])
|
|
571
|
+
temp_param.append(layer_data["corner_radius"])
|
|
572
|
+
pad_shape = self._ppadstack._pedb._edb.Definition.PadGeometryType.Bullet
|
|
573
|
+
|
|
574
|
+
# Handle Round45 geometry type
|
|
575
|
+
elif p == pascal_to_snake(self._ppadstack._pedb._edb.Definition.PadGeometryType.Round45.ToString()):
|
|
576
|
+
temp_param.append(layer_data["inner"])
|
|
577
|
+
temp_param.append(layer_data["channel_width"])
|
|
578
|
+
temp_param.append(layer_data["isolation_gap"])
|
|
579
|
+
pad_shape = self._ppadstack._pedb._edb.Definition.PadGeometryType.Round45
|
|
580
|
+
|
|
581
|
+
# Handle Round90 geometry type
|
|
582
|
+
elif p == pascal_to_snake(self._ppadstack._pedb._edb.Definition.PadGeometryType.Round90.ToString()):
|
|
583
|
+
temp_param.append(layer_data["inner"])
|
|
584
|
+
temp_param.append(layer_data["channel_width"])
|
|
585
|
+
temp_param.append(layer_data["isolation_gap"])
|
|
586
|
+
pad_shape = self._ppadstack._pedb._edb.Definition.PadGeometryType.Round90
|
|
587
|
+
elif p == pascal_to_snake(self._ppadstack._pedb._edb.Definition.PadGeometryType.NoGeometry.ToString()):
|
|
588
|
+
continue
|
|
589
|
+
|
|
590
|
+
# Set pad parameters for the current layer
|
|
591
|
+
default = original_params[pad_type_name]
|
|
592
|
+
pdef_data.SetPadParameters(
|
|
593
|
+
layer_data["layer_name"],
|
|
594
|
+
pad_type,
|
|
595
|
+
pad_shape,
|
|
596
|
+
convert_py_list_to_net_list([self._ppadstack._pedb.edb_value(i) for i in temp_param]),
|
|
597
|
+
self._ppadstack._pedb.edb_value(layer_data.get("offset_x", default[idx].get("offset_x", 0))),
|
|
598
|
+
self._ppadstack._pedb.edb_value(layer_data.get("offset_y", default[idx].get("offset_y", 0))),
|
|
599
|
+
self._ppadstack._pedb.edb_value(layer_data.get("rotation", default[idx].get("rotation", 0))),
|
|
600
|
+
)
|
|
601
|
+
self._padstack_def_data = pdef_data
|
|
602
|
+
|
|
603
|
+
@property
|
|
604
|
+
def hole_parameters(self):
|
|
605
|
+
pdef_data = self._padstack_def_data
|
|
606
|
+
_, hole_shape, params, offset_x, offset_y, rotation = pdef_data.GetHoleParametersValue()
|
|
607
|
+
hole_shape = pascal_to_snake(hole_shape.ToString())
|
|
608
|
+
|
|
609
|
+
hole_params = {}
|
|
610
|
+
hole_params["shape"] = hole_shape
|
|
611
|
+
for idx, i in enumerate(self.PAD_SHAPE_PARAMETERS[hole_shape]):
|
|
612
|
+
hole_params[i] = params[idx].ToString()
|
|
613
|
+
hole_params["offset_x"] = offset_x.ToString()
|
|
614
|
+
hole_params["offset_y"] = offset_y.ToString()
|
|
615
|
+
hole_params["rotation"] = rotation.ToString()
|
|
616
|
+
return hole_params
|
|
617
|
+
|
|
618
|
+
@hole_parameters.setter
|
|
619
|
+
def hole_parameters(self, params: dict):
|
|
620
|
+
original_params = self.hole_parameters
|
|
621
|
+
pdef_data = self._padstack_def_data
|
|
622
|
+
|
|
623
|
+
temp_param = []
|
|
624
|
+
shape = params["shape"]
|
|
625
|
+
if shape == "no_geometry":
|
|
626
|
+
return # .net api doesn't tell how to set no_geometry shape.
|
|
627
|
+
for idx, i in enumerate(self.PAD_SHAPE_PARAMETERS[shape]):
|
|
628
|
+
temp_param.append(params[i])
|
|
629
|
+
pedb_shape = getattr(self._ppadstack._pedb._edb.Definition.PadGeometryType, snake_to_pascal(shape))
|
|
630
|
+
|
|
631
|
+
pdef_data.SetHoleParameters(
|
|
632
|
+
pedb_shape,
|
|
633
|
+
convert_py_list_to_net_list([self._ppadstack._pedb.edb_value(i) for i in temp_param]),
|
|
634
|
+
self._ppadstack._pedb.edb_value(params.get("offset_x", original_params.get("offset_x", 0))),
|
|
635
|
+
self._ppadstack._pedb.edb_value(params.get("offset_y", original_params.get("offset_y", 0))),
|
|
636
|
+
self._ppadstack._pedb.edb_value(params.get("rotation", original_params.get("rotation", 0))),
|
|
637
|
+
)
|
|
638
|
+
self._padstack_def_data = pdef_data
|
|
422
639
|
|
|
423
640
|
@property
|
|
424
641
|
def instances(self):
|
|
@@ -455,7 +672,7 @@ class EDBPadstack(object):
|
|
|
455
672
|
list
|
|
456
673
|
List of layers.
|
|
457
674
|
"""
|
|
458
|
-
return self.
|
|
675
|
+
return self._padstack_def_data.GetLayerNames()
|
|
459
676
|
|
|
460
677
|
@property
|
|
461
678
|
def via_start_layer(self):
|
|
@@ -488,7 +705,7 @@ class EDBPadstack(object):
|
|
|
488
705
|
return self._hole_params
|
|
489
706
|
|
|
490
707
|
@property
|
|
491
|
-
def
|
|
708
|
+
def _hole_parameters(self):
|
|
492
709
|
"""Hole parameters.
|
|
493
710
|
|
|
494
711
|
Returns
|
|
@@ -496,8 +713,7 @@ class EDBPadstack(object):
|
|
|
496
713
|
list
|
|
497
714
|
List of the hole parameters.
|
|
498
715
|
"""
|
|
499
|
-
|
|
500
|
-
return self._hole_parameters
|
|
716
|
+
return self.hole_params[2]
|
|
501
717
|
|
|
502
718
|
@property
|
|
503
719
|
def hole_diameter(self):
|
|
@@ -540,7 +756,7 @@ class EDBPadstack(object):
|
|
|
540
756
|
if not hole_type:
|
|
541
757
|
hole_type = self.hole_type
|
|
542
758
|
if not params:
|
|
543
|
-
params = self.
|
|
759
|
+
params = self._hole_parameters
|
|
544
760
|
if isinstance(params, list):
|
|
545
761
|
params = convert_py_list_to_net_list(params)
|
|
546
762
|
if not offsetx:
|
|
@@ -709,14 +925,13 @@ class EDBPadstack(object):
|
|
|
709
925
|
str
|
|
710
926
|
Material of the hole.
|
|
711
927
|
"""
|
|
712
|
-
return self.
|
|
928
|
+
return self._padstack_def_data.GetMaterial()
|
|
713
929
|
|
|
714
930
|
@material.setter
|
|
715
931
|
def material(self, materialname):
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
self.edb_padstack.SetData(newPadstackDefinitionData)
|
|
932
|
+
pdef_data = self._padstack_def_data
|
|
933
|
+
pdef_data.SetMaterial(materialname)
|
|
934
|
+
self._padstack_def_data = pdef_data
|
|
720
935
|
|
|
721
936
|
@property
|
|
722
937
|
def padstack_instances(self):
|
|
@@ -736,36 +951,15 @@ class EDBPadstack(object):
|
|
|
736
951
|
-------
|
|
737
952
|
str
|
|
738
953
|
Possible returned values are ``"through"``, ``"begin_on_upper_pad"``,
|
|
739
|
-
``"end_on_lower_pad"``, ``"upper_pad_to_lower_pad"``, and ``"
|
|
954
|
+
``"end_on_lower_pad"``, ``"upper_pad_to_lower_pad"``, and ``"unknown_range"``.
|
|
740
955
|
"""
|
|
741
|
-
|
|
742
|
-
hole_ange_type = int(cloned_padstackdef_data.GetHoleRange())
|
|
743
|
-
if hole_ange_type == 0: # pragma no cover
|
|
744
|
-
return "through"
|
|
745
|
-
elif hole_ange_type == 1: # pragma no cover
|
|
746
|
-
return "begin_on_upper_pad"
|
|
747
|
-
elif hole_ange_type == 2: # pragma no cover
|
|
748
|
-
return "end_on_lower_pad"
|
|
749
|
-
elif hole_ange_type == 3: # pragma no cover
|
|
750
|
-
return "upper_pad_to_lower_pad"
|
|
751
|
-
else: # pragma no cover
|
|
752
|
-
return "undefined"
|
|
956
|
+
return pascal_to_snake(self._padstack_def_data.GetHoleRange().ToString())
|
|
753
957
|
|
|
754
958
|
@hole_range.setter
|
|
755
959
|
def hole_range(self, value):
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
cloned_padstackdef_data.SetHoleRange(self._edb.definition.PadstackHoleRange.Through)
|
|
760
|
-
elif value == "begin_on_upper_pad": # pragma no cover
|
|
761
|
-
cloned_padstackdef_data.SetHoleRange(self._edb.definition.PadstackHoleRange.BeginOnUpperPad)
|
|
762
|
-
elif value == "end_on_lower_pad": # pragma no cover
|
|
763
|
-
cloned_padstackdef_data.SetHoleRange(self._edb.definition.PadstackHoleRange.EndOnLowerPad)
|
|
764
|
-
elif value == "upper_pad_to_lower_pad": # pragma no cover
|
|
765
|
-
cloned_padstackdef_data.SetHoleRange(self._edb.definition.PadstackHoleRange.UpperPadToLowerPad)
|
|
766
|
-
else: # pragma no cover
|
|
767
|
-
return
|
|
768
|
-
self.edb_padstack.SetData(cloned_padstackdef_data)
|
|
960
|
+
pdef_data = self._padstack_def_data
|
|
961
|
+
pdef_data.SetHoleRange(getattr(self._edb.definition.PadstackHoleRange, snake_to_pascal(value)))
|
|
962
|
+
self._padstack_def_data = pdef_data
|
|
769
963
|
|
|
770
964
|
def convert_to_3d_microvias(self, convert_only_signal_vias=True, hole_wall_angle=15, delete_padstack_def=True):
|
|
771
965
|
"""Convert actual padstack instance to microvias 3D Objects with a given aspect ratio.
|
|
@@ -984,7 +1178,7 @@ class EDBPadstack(object):
|
|
|
984
1178
|
)
|
|
985
1179
|
new_padstack_definition_data.SetHoleParameters(
|
|
986
1180
|
self.hole_type,
|
|
987
|
-
self.
|
|
1181
|
+
self._hole_parameters,
|
|
988
1182
|
self._get_edb_value(self.hole_offset_x),
|
|
989
1183
|
self._get_edb_value(self.hole_offset_y),
|
|
990
1184
|
self._get_edb_value(self.hole_rotation),
|
|
@@ -1128,6 +1322,18 @@ class EDBPadstack(object):
|
|
|
1128
1322
|
self.edb_padstack.SetData(new_padstack_data)
|
|
1129
1323
|
return True
|
|
1130
1324
|
|
|
1325
|
+
def set_properties(self, **kwargs):
|
|
1326
|
+
for k in ["hole_plating_thickness", "material", "hole_range", "pad_parameters", "hole_parameters"]:
|
|
1327
|
+
value = kwargs.get(k, False)
|
|
1328
|
+
if value:
|
|
1329
|
+
setattr(self, k, value)
|
|
1330
|
+
|
|
1331
|
+
def get_properties(self):
|
|
1332
|
+
kwargs = {}
|
|
1333
|
+
for k in ["hole_plating_thickness", "material", "hole_range", "pad_parameters", "hole_parameters"]:
|
|
1334
|
+
kwargs[k] = getattr(self, k)
|
|
1335
|
+
return kwargs
|
|
1336
|
+
|
|
1131
1337
|
|
|
1132
1338
|
class EDBPadstackInstance(Primitive):
|
|
1133
1339
|
"""Manages EDB functionalities for a padstack.
|
|
@@ -1466,6 +1672,56 @@ class EDBPadstackInstance(Primitive):
|
|
|
1466
1672
|
else:
|
|
1467
1673
|
return
|
|
1468
1674
|
|
|
1675
|
+
@property
|
|
1676
|
+
def backdrill_parameters(self):
|
|
1677
|
+
data = {}
|
|
1678
|
+
flag, drill_to_layer, offset, diameter = self._edb_object.GetBackDrillParametersLayerValue(
|
|
1679
|
+
self._pedb.edb_api.cell.layer("", self._pedb.edb_api.cell.layer_type.SignalLayer),
|
|
1680
|
+
self._pedb.edb_value(0),
|
|
1681
|
+
self._pedb.edb_value(0.0),
|
|
1682
|
+
True,
|
|
1683
|
+
)
|
|
1684
|
+
if flag:
|
|
1685
|
+
if drill_to_layer.GetName():
|
|
1686
|
+
data["from_bottom"] = {
|
|
1687
|
+
"drill_to_layer": drill_to_layer.GetName(),
|
|
1688
|
+
"diameter": diameter.ToString(),
|
|
1689
|
+
"stub_length": offset.ToString(),
|
|
1690
|
+
}
|
|
1691
|
+
flag, drill_to_layer, offset, diameter = self._edb_object.GetBackDrillParametersLayerValue(
|
|
1692
|
+
self._pedb.edb_api.cell.layer("", self._pedb.edb_api.cell.layer_type.SignalLayer),
|
|
1693
|
+
self._pedb.edb_value(0),
|
|
1694
|
+
self._pedb.edb_value(0.0),
|
|
1695
|
+
False,
|
|
1696
|
+
)
|
|
1697
|
+
if flag:
|
|
1698
|
+
if drill_to_layer.GetName():
|
|
1699
|
+
data["from_top"] = {
|
|
1700
|
+
"drill_to_layer": drill_to_layer.GetName(),
|
|
1701
|
+
"diameter": diameter.ToString(),
|
|
1702
|
+
"stub_length": offset.ToString(),
|
|
1703
|
+
}
|
|
1704
|
+
return data
|
|
1705
|
+
|
|
1706
|
+
@backdrill_parameters.setter
|
|
1707
|
+
def backdrill_parameters(self, params):
|
|
1708
|
+
from_bottom = params.get("from_bottom")
|
|
1709
|
+
if from_bottom:
|
|
1710
|
+
self._edb_object.SetBackDrillParameters(
|
|
1711
|
+
self._pedb.stackup.layers[from_bottom.get("drill_to_layer")]._edb_object,
|
|
1712
|
+
self._pedb.edb_value(from_bottom.get("stub_length")),
|
|
1713
|
+
self._pedb.edb_value(from_bottom.get("diameter")),
|
|
1714
|
+
True,
|
|
1715
|
+
)
|
|
1716
|
+
from_top = params.get("from_top")
|
|
1717
|
+
if from_top:
|
|
1718
|
+
self._edb_object.SetBackDrillParameters(
|
|
1719
|
+
self._pedb.stackup.layers[from_top.get("drill_to_layer")]._edb_object,
|
|
1720
|
+
self._pedb.edb_value(from_top.get("stub_length")),
|
|
1721
|
+
self._pedb.edb_value(from_top.get("diameter")),
|
|
1722
|
+
False,
|
|
1723
|
+
)
|
|
1724
|
+
|
|
1469
1725
|
def set_backdrill_bottom(self, drill_depth, drill_diameter, offset=0.0):
|
|
1470
1726
|
"""Set backdrill from bottom.
|
|
1471
1727
|
|
|
@@ -158,7 +158,7 @@ class EdbPolygon(Primitive):
|
|
|
158
158
|
|
|
159
159
|
Examples
|
|
160
160
|
--------
|
|
161
|
-
>>> edbapp =
|
|
161
|
+
>>> edbapp = ansys.aedt.core.Edb("myproject.aedb")
|
|
162
162
|
>>> top_layer_polygon = [poly for poly in edbapp.modeler.polygons if poly.layer_name == "Top Layer"]
|
|
163
163
|
>>> for polygon in top_layer_polygon:
|
|
164
164
|
>>> polygon.move(vector=["2mm", "100um"])
|
|
@@ -191,7 +191,7 @@ class EdbPolygon(Primitive):
|
|
|
191
191
|
|
|
192
192
|
Examples
|
|
193
193
|
--------
|
|
194
|
-
>>> edbapp =
|
|
194
|
+
>>> edbapp = ansys.aedt.core.Edb("myproject.aedb")
|
|
195
195
|
>>> top_layer_polygon = [poly for poly in edbapp.modeler.polygons if poly.layer_name == "Top Layer"]
|
|
196
196
|
>>> for polygon in top_layer_polygon:
|
|
197
197
|
>>> polygon.rotate(angle=45)
|
pyedb/dotnet/edb_core/general.py
CHANGED
|
@@ -28,6 +28,7 @@ This module contains EDB general methods and related methods.
|
|
|
28
28
|
from __future__ import absolute_import # noreorder
|
|
29
29
|
|
|
30
30
|
import logging
|
|
31
|
+
import re
|
|
31
32
|
|
|
32
33
|
from pyedb.dotnet.clr_module import Dictionary, List, Tuple
|
|
33
34
|
|
|
@@ -140,6 +141,16 @@ def convert_net_list_to_py_list(netlist):
|
|
|
140
141
|
return pylist
|
|
141
142
|
|
|
142
143
|
|
|
144
|
+
def pascal_to_snake(s):
|
|
145
|
+
# Convert PascalCase to snake_case
|
|
146
|
+
return re.sub(r"(?<!^)(?=[A-Z])", "_", s).lower()
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
def snake_to_pascal(s):
|
|
150
|
+
# Split the string at underscores and capitalize the first letter of each part
|
|
151
|
+
return "".join(word.capitalize() for word in s.split("_"))
|
|
152
|
+
|
|
153
|
+
|
|
143
154
|
class PadGeometryTpe(Enum): # pragma: no cover
|
|
144
155
|
Circle = 1
|
|
145
156
|
Square = 2
|
|
@@ -190,9 +190,9 @@ class LayoutValidation:
|
|
|
190
190
|
l1 = objs[0].get_connected_object_id_set()
|
|
191
191
|
l1.append(objs[0].id)
|
|
192
192
|
repetition = False
|
|
193
|
-
for
|
|
194
|
-
if set(l1).intersection(
|
|
195
|
-
net_groups.append([i for i in l1 if i not in
|
|
193
|
+
for id_by_net in net_groups:
|
|
194
|
+
if set(l1).intersection(id_by_net):
|
|
195
|
+
net_groups.append([i for i in l1 if i not in id_by_net])
|
|
196
196
|
repetition = True
|
|
197
197
|
if not repetition:
|
|
198
198
|
net_groups.append(l1)
|
pyedb/dotnet/edb_core/modeler.py
CHANGED
|
@@ -1460,6 +1460,9 @@ class Modeler(object):
|
|
|
1460
1460
|
self._pedb.active_layout, name, convert_py_list_to_net_list(pins)
|
|
1461
1461
|
)
|
|
1462
1462
|
if obj.IsNull():
|
|
1463
|
-
|
|
1464
|
-
|
|
1463
|
+
raise RuntimeError(f"Failed to create pin group {name}.")
|
|
1464
|
+
else:
|
|
1465
|
+
net_obj = [i.GetNet() for i in pins if not i.GetNet().IsNull()]
|
|
1466
|
+
if net_obj:
|
|
1467
|
+
obj.SetNet(net_obj[0])
|
|
1465
1468
|
return self._pedb.siwave.pin_groups[name]
|