pyedb 0.7.0__py3-none-any.whl → 0.7.1__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 +1 -1
- pyedb/dotnet/clr_module.py +1 -1
- pyedb/dotnet/edb.py +6 -7
- pyedb/dotnet/edb_core/components.py +11 -11
- pyedb/dotnet/edb_core/configuration.py +199 -24
- pyedb/dotnet/edb_core/definition/component_def.py +9 -0
- pyedb/dotnet/edb_core/definition/package_def.py +27 -0
- pyedb/dotnet/edb_core/edb_data/components_data.py +2 -1
- pyedb/dotnet/edb_core/edb_data/hfss_extent_info.py +14 -13
- pyedb/dotnet/edb_core/edb_data/hfss_simulation_setup_data.py +2 -2
- pyedb/dotnet/edb_core/edb_data/layer_data.py +8 -3
- pyedb/dotnet/edb_core/edb_data/padstacks_data.py +6 -5
- pyedb/dotnet/edb_core/edb_data/primitives_data.py +12 -11
- pyedb/dotnet/edb_core/edb_data/siwave_simulation_setup_data.py +1 -1
- pyedb/dotnet/edb_core/edb_data/sources.py +10 -0
- pyedb/dotnet/edb_core/layout.py +59 -0
- pyedb/dotnet/edb_core/materials.py +637 -541
- pyedb/dotnet/edb_core/padstack.py +57 -6
- pyedb/dotnet/edb_core/siwave.py +9 -2
- pyedb/dotnet/edb_core/stackup.py +108 -94
- pyedb/dotnet/edb_core/utilities/__init__.py +3 -0
- pyedb/dotnet/edb_core/utilities/heatsink.py +69 -0
- pyedb/exceptions.py +6 -0
- pyedb/generic/filesystem.py +7 -3
- pyedb/generic/general_methods.py +4 -0
- pyedb/generic/process.py +4 -1
- pyedb/generic/settings.py +10 -0
- {pyedb-0.7.0.dist-info → pyedb-0.7.1.dist-info}/METADATA +31 -53
- {pyedb-0.7.0.dist-info → pyedb-0.7.1.dist-info}/RECORD +32 -29
- /pyedb/dotnet/edb_core/{edb_data → utilities}/simulation_setup.py +0 -0
- {pyedb-0.7.0.dist-info → pyedb-0.7.1.dist-info}/LICENSE +0 -0
- {pyedb-0.7.0.dist-info → pyedb-0.7.1.dist-info}/WHEEL +0 -0
pyedb/__init__.py
CHANGED
pyedb/dotnet/clr_module.py
CHANGED
|
@@ -83,7 +83,7 @@ except ImportError: # pragma: no cover
|
|
|
83
83
|
)
|
|
84
84
|
edb_initialized = False
|
|
85
85
|
elif sys.version[0] == 3 and sys.version[1] < 7:
|
|
86
|
-
warnings.warn("EDB requires Linux Python 3.
|
|
86
|
+
warnings.warn("EDB requires Linux Python 3.8 or later.")
|
|
87
87
|
_clr = None
|
|
88
88
|
String = None
|
|
89
89
|
Double = None
|
pyedb/dotnet/edb.py
CHANGED
|
@@ -848,12 +848,11 @@ class Edb(Database):
|
|
|
848
848
|
Examples
|
|
849
849
|
--------
|
|
850
850
|
>>> from pyedb.dotnet.edb import Edb
|
|
851
|
-
>>> edbapp = Edb(
|
|
852
|
-
>>> edbapp.materials
|
|
853
|
-
>>> edbapp.materials.add_debye_material("
|
|
854
|
-
>>> edbapp.materials.add_djordjevicsarkar_material("
|
|
851
|
+
>>> edbapp = Edb()
|
|
852
|
+
>>> edbapp.materials.add_material("air", permittivity=1.0)
|
|
853
|
+
>>> edbapp.materials.add_debye_material("debye_mat", 5, 3, 0.02, 0.05, 1e5, 1e9)
|
|
854
|
+
>>> edbapp.materials.add_djordjevicsarkar_material("djord_mat", 3.3, 0.02, 3.3)
|
|
855
855
|
"""
|
|
856
|
-
|
|
857
856
|
if not self._materials and self.active_db:
|
|
858
857
|
self._materials = Materials(self)
|
|
859
858
|
return self._materials
|
|
@@ -4142,8 +4141,8 @@ class Edb(Database):
|
|
|
4142
4141
|
loss_tg_variable = "$loss_tangent_{}".format(mat_name)
|
|
4143
4142
|
loss_tg_variable = self._clean_string_for_variable_name(loss_tg_variable)
|
|
4144
4143
|
if not loss_tg_variable in self.variables:
|
|
4145
|
-
self.add_design_variable(loss_tg_variable, material.
|
|
4146
|
-
material.
|
|
4144
|
+
self.add_design_variable(loss_tg_variable, material.dielectric_loss_tangent)
|
|
4145
|
+
material.dielectric_loss_tangent = loss_tg_variable
|
|
4147
4146
|
parameters.append(loss_tg_variable)
|
|
4148
4147
|
else:
|
|
4149
4148
|
sigma_variable = "$sigma_{}".format(mat_name)
|
|
@@ -1408,7 +1408,7 @@ class Components(object):
|
|
|
1408
1408
|
|
|
1409
1409
|
@pyedb_function_handler()
|
|
1410
1410
|
def create_rlc_component(
|
|
1411
|
-
self, pins, component_name="", r_value=
|
|
1411
|
+
self, pins, component_name="", r_value=None, c_value=None, l_value=None, is_parallel=False
|
|
1412
1412
|
): # pragma: no cover
|
|
1413
1413
|
"""Create physical Rlc component.
|
|
1414
1414
|
|
|
@@ -1454,9 +1454,9 @@ class Components(object):
|
|
|
1454
1454
|
placement_layer=None,
|
|
1455
1455
|
component_part_name=None,
|
|
1456
1456
|
is_rlc=False,
|
|
1457
|
-
r_value=
|
|
1458
|
-
c_value=
|
|
1459
|
-
l_value=
|
|
1457
|
+
r_value=None,
|
|
1458
|
+
c_value=None,
|
|
1459
|
+
l_value=None,
|
|
1460
1460
|
is_parallel=False,
|
|
1461
1461
|
):
|
|
1462
1462
|
"""Create a component from pins.
|
|
@@ -1523,21 +1523,21 @@ class Components(object):
|
|
|
1523
1523
|
if is_rlc and len(pins) == 2:
|
|
1524
1524
|
rlc = self._edb.utility.utility.Rlc()
|
|
1525
1525
|
rlc.IsParallel = is_parallel
|
|
1526
|
-
if r_value:
|
|
1526
|
+
if r_value is None:
|
|
1527
|
+
rlc.REnabled = False
|
|
1528
|
+
else:
|
|
1527
1529
|
rlc.REnabled = True
|
|
1528
1530
|
rlc.R = self._get_edb_value(r_value)
|
|
1531
|
+
if l_value is None:
|
|
1532
|
+
rlc.LEnabled = False
|
|
1529
1533
|
else:
|
|
1530
|
-
rlc.REnabled = False
|
|
1531
|
-
if l_value:
|
|
1532
1534
|
rlc.LEnabled = True
|
|
1533
1535
|
rlc.L = self._get_edb_value(l_value)
|
|
1536
|
+
if c_value is None:
|
|
1537
|
+
rlc.CEnabled = False
|
|
1534
1538
|
else:
|
|
1535
|
-
rlc.LEnabled = False
|
|
1536
|
-
if c_value:
|
|
1537
1539
|
rlc.CEnabled = True
|
|
1538
1540
|
rlc.C = self._get_edb_value(c_value)
|
|
1539
|
-
else:
|
|
1540
|
-
rlc.CEnabled = False
|
|
1541
1541
|
if rlc.REnabled and not rlc.CEnabled and not rlc.CEnabled:
|
|
1542
1542
|
new_cmp.SetComponentType(self._edb.definition.ComponentType.Resistor)
|
|
1543
1543
|
elif rlc.CEnabled and not rlc.REnabled and not rlc.LEnabled:
|
|
@@ -21,17 +21,13 @@
|
|
|
21
21
|
# SOFTWARE.
|
|
22
22
|
|
|
23
23
|
import json
|
|
24
|
+
import os
|
|
24
25
|
from pathlib import Path
|
|
25
26
|
|
|
26
|
-
|
|
27
|
-
|
|
27
|
+
import toml
|
|
28
28
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
with open(config_file, "r") as f:
|
|
32
|
-
return json.load(f)
|
|
33
|
-
elif isinstance(config_file, dict):
|
|
34
|
-
return config_file
|
|
29
|
+
from pyedb.dotnet.edb_core.definition.package_def import PackageDef
|
|
30
|
+
from pyedb.generic.general_methods import pyedb_function_handler
|
|
35
31
|
|
|
36
32
|
|
|
37
33
|
class Configuration:
|
|
@@ -46,12 +42,12 @@ class Configuration:
|
|
|
46
42
|
|
|
47
43
|
@pyedb_function_handler
|
|
48
44
|
def load(self, config_file, append=True, apply_file=False, output_file=None, open_at_the_end=True):
|
|
49
|
-
"""Import configuration settings from a
|
|
45
|
+
"""Import configuration settings from a configure file.
|
|
50
46
|
|
|
51
47
|
Parameters
|
|
52
48
|
----------
|
|
53
|
-
config_file : str
|
|
54
|
-
Full path to
|
|
49
|
+
config_file : str, dict
|
|
50
|
+
Full path to configure file in JSON or TOML format. Dictionary is also supported.
|
|
55
51
|
append : bool, optional
|
|
56
52
|
Whether if the new file will append to existing properties or the properties will be cleared before import.
|
|
57
53
|
Default is ``True`` to keep stored properties
|
|
@@ -67,12 +63,29 @@ class Configuration:
|
|
|
67
63
|
dict
|
|
68
64
|
Config dictionary.
|
|
69
65
|
"""
|
|
66
|
+
if isinstance(config_file, dict):
|
|
67
|
+
data = config_file
|
|
68
|
+
elif os.path.isfile(config_file):
|
|
69
|
+
with open(config_file, "r") as f:
|
|
70
|
+
if config_file.endswith(".json"):
|
|
71
|
+
data = json.load(f)
|
|
72
|
+
elif config_file.endswith(".toml"):
|
|
73
|
+
data = toml.load(f)
|
|
74
|
+
else: # pragma: no cover
|
|
75
|
+
return False
|
|
70
76
|
|
|
71
|
-
|
|
72
|
-
if not append:
|
|
77
|
+
if not append: # pragma: no cover
|
|
73
78
|
self.data = {}
|
|
74
79
|
for k, v in data.items():
|
|
75
|
-
self.data
|
|
80
|
+
if k in self.data:
|
|
81
|
+
if isinstance(v, list):
|
|
82
|
+
self.data[k].extend(v)
|
|
83
|
+
elif isinstance(v, dict): # pragma: no cover
|
|
84
|
+
self.data[k].update(v)
|
|
85
|
+
else: # pragma: no cover
|
|
86
|
+
self.data[k] = v
|
|
87
|
+
else:
|
|
88
|
+
self.data[k] = v
|
|
76
89
|
if apply_file:
|
|
77
90
|
original_file = self._pedb.edbpath
|
|
78
91
|
if output_file:
|
|
@@ -98,6 +111,10 @@ class Configuration:
|
|
|
98
111
|
if "general" in self.data:
|
|
99
112
|
self._load_general()
|
|
100
113
|
|
|
114
|
+
# Configure boundary settings
|
|
115
|
+
if "boundaries" in self.data:
|
|
116
|
+
self._load_boundaries()
|
|
117
|
+
|
|
101
118
|
# Configure nets
|
|
102
119
|
if "nets" in self.data:
|
|
103
120
|
self._load_nets()
|
|
@@ -106,6 +123,10 @@ class Configuration:
|
|
|
106
123
|
if "components" in self.data:
|
|
107
124
|
self._load_components()
|
|
108
125
|
|
|
126
|
+
# Configure padstacks
|
|
127
|
+
if "padstacks" in self.data:
|
|
128
|
+
self._load_padstacks()
|
|
129
|
+
|
|
109
130
|
# Configure pin groups
|
|
110
131
|
if "pin_groups" in self.data:
|
|
111
132
|
self._load_pin_groups()
|
|
@@ -134,6 +155,14 @@ class Configuration:
|
|
|
134
155
|
if "spice_models" in self.data:
|
|
135
156
|
self._load_spice_models()
|
|
136
157
|
|
|
158
|
+
# Configure package definitions
|
|
159
|
+
if "package_definitions" in self.data:
|
|
160
|
+
self._load_package_def()
|
|
161
|
+
|
|
162
|
+
# Configure operations
|
|
163
|
+
if "operations" in self.data:
|
|
164
|
+
self._load_operations()
|
|
165
|
+
|
|
137
166
|
return True
|
|
138
167
|
|
|
139
168
|
@pyedb_function_handler
|
|
@@ -253,18 +282,20 @@ class Configuration:
|
|
|
253
282
|
pos_terminal = ""
|
|
254
283
|
if "pin_group" in positive_terminal_json:
|
|
255
284
|
pin_group = self._pedb.siwave.pin_groups[positive_terminal_json["pin_group"]]
|
|
256
|
-
|
|
285
|
+
port_name = pin_group.name if "name" not in port else port["name"]
|
|
286
|
+
pos_terminal = pin_group.get_terminal(port_name, True)
|
|
287
|
+
|
|
257
288
|
else:
|
|
258
289
|
ref_designator = port["reference_designator"]
|
|
259
290
|
comp_layout = self._components[ref_designator]
|
|
260
291
|
|
|
261
292
|
if "pin" in positive_terminal_json:
|
|
262
293
|
pin_name = positive_terminal_json["pin"]
|
|
263
|
-
port_name = "{}_{}".format(ref_designator, pin_name)
|
|
294
|
+
port_name = "{}_{}".format(ref_designator, pin_name) if "name" not in port else port["name"]
|
|
264
295
|
pos_terminal = comp_layout.pins[pin_name].get_terminal(port_name, True)
|
|
265
296
|
else: # Net
|
|
266
297
|
net_name = positive_terminal_json["net"]
|
|
267
|
-
port_name = "{}_{}".format(ref_designator, net_name)
|
|
298
|
+
port_name = "{}_{}".format(ref_designator, net_name) if "name" not in port else port["name"]
|
|
268
299
|
if port_type == "circuit":
|
|
269
300
|
pg_name = "pg_{}".format(port_name)
|
|
270
301
|
_, pg = self._pedb.siwave.create_pin_group_on_net(ref_designator, net_name, pg_name)
|
|
@@ -389,7 +420,10 @@ class Configuration:
|
|
|
389
420
|
else:
|
|
390
421
|
self._pedb.logger.warning("Setup {} already existing. Editing it.".format(name))
|
|
391
422
|
edb_setup = self._pedb.setups[name]
|
|
392
|
-
|
|
423
|
+
if "si_slider_position" in setup:
|
|
424
|
+
edb_setup.si_slider_position = setup["si_slider_position"]
|
|
425
|
+
if "pi_slider_position" in setup:
|
|
426
|
+
edb_setup.pi_slider_position = setup["pi_slider_position"]
|
|
393
427
|
|
|
394
428
|
if "freq_sweep" in setup:
|
|
395
429
|
for fsweep in setup["freq_sweep"]:
|
|
@@ -476,14 +510,23 @@ class Configuration:
|
|
|
476
510
|
comp_def_name = sp["component_definition"]
|
|
477
511
|
comp_def = self._pedb.definitions.component[comp_def_name]
|
|
478
512
|
comp_def.add_n_port_model(fpath, sp_name)
|
|
513
|
+
comp_list = dict()
|
|
479
514
|
if sp["apply_to_all"]:
|
|
480
|
-
|
|
481
|
-
if refdes not in sp["components"]
|
|
482
|
-
|
|
515
|
+
comp_list.update(
|
|
516
|
+
{refdes: comp for refdes, comp in comp_def.components.items() if refdes not in sp["components"]}
|
|
517
|
+
)
|
|
483
518
|
else:
|
|
484
|
-
|
|
485
|
-
if refdes in sp["components"]
|
|
486
|
-
|
|
519
|
+
comp_list.update(
|
|
520
|
+
{refdes: comp for refdes, comp in comp_def.components.items() if refdes in sp["components"]}
|
|
521
|
+
)
|
|
522
|
+
|
|
523
|
+
for refdes, comp in comp_list.items():
|
|
524
|
+
if "reference_net_per_component" in sp:
|
|
525
|
+
ref_net_per_comp = sp["reference_net_per_component"]
|
|
526
|
+
ref_net = ref_net_per_comp[refdes] if refdes in ref_net_per_comp else sp["reference_net"]
|
|
527
|
+
else:
|
|
528
|
+
ref_net = sp["reference_net"]
|
|
529
|
+
comp.use_s_parameter_model(sp_name, reference_net=ref_net)
|
|
487
530
|
|
|
488
531
|
@pyedb_function_handler
|
|
489
532
|
def _load_spice_models(self):
|
|
@@ -536,3 +579,135 @@ class Configuration:
|
|
|
536
579
|
self._s_parameter_library = general["s_parameter_library"]
|
|
537
580
|
if "spice_model_library" in general:
|
|
538
581
|
self._spice_model_library = general["spice_model_library"]
|
|
582
|
+
|
|
583
|
+
@pyedb_function_handler
|
|
584
|
+
def _load_boundaries(self):
|
|
585
|
+
"""Imports boundary information from JSON."""
|
|
586
|
+
boundaries = self.data["boundaries"]
|
|
587
|
+
|
|
588
|
+
open_region = boundaries.get("open_region", None)
|
|
589
|
+
if open_region:
|
|
590
|
+
self._pedb.hfss.hfss_extent_info.use_open_region = open_region
|
|
591
|
+
|
|
592
|
+
open_region_type = boundaries.get("open_region_type", None)
|
|
593
|
+
if open_region_type:
|
|
594
|
+
self._pedb.hfss.hfss_extent_info.open_region_type = open_region_type
|
|
595
|
+
|
|
596
|
+
pml_visible = boundaries.get("pml_visible", None)
|
|
597
|
+
if pml_visible:
|
|
598
|
+
self._pedb.hfss.hfss_extent_info.is_pml_visible = pml_visible
|
|
599
|
+
|
|
600
|
+
pml_operation_frequency = boundaries.get("pml_operation_frequency", None)
|
|
601
|
+
if pml_operation_frequency:
|
|
602
|
+
self._pedb.hfss.hfss_extent_info.operating_freq = pml_operation_frequency
|
|
603
|
+
|
|
604
|
+
pml_radiation_factor = boundaries.get("pml_radiation_factor", None)
|
|
605
|
+
if pml_radiation_factor:
|
|
606
|
+
self._pedb.hfss.hfss_extent_info.radiation_level = pml_radiation_factor
|
|
607
|
+
|
|
608
|
+
dielectric_extents_type = boundaries.get("dielectric_extents_type", None)
|
|
609
|
+
if dielectric_extents_type:
|
|
610
|
+
self._pedb.hfss.hfss_extent_info.extent_type = dielectric_extents_type
|
|
611
|
+
|
|
612
|
+
dielectric_base_polygon = boundaries.get("dielectric_base_polygon", None)
|
|
613
|
+
if dielectric_base_polygon:
|
|
614
|
+
self._pedb.hfss.hfss_extent_info.dielectric_base_polygon = dielectric_base_polygon
|
|
615
|
+
|
|
616
|
+
horizontal_padding = boundaries.get("horizontal_padding", None)
|
|
617
|
+
if horizontal_padding:
|
|
618
|
+
self._pedb.hfss.hfss_extent_info.dielectric_extent_size = horizontal_padding
|
|
619
|
+
|
|
620
|
+
honor_primitives_on_dielectric_layers = boundaries.get("honor_primitives_on_dielectric_layers", None)
|
|
621
|
+
if honor_primitives_on_dielectric_layers:
|
|
622
|
+
self._pedb.hfss.hfss_extent_info.honor_user_dielectric = honor_primitives_on_dielectric_layers
|
|
623
|
+
|
|
624
|
+
air_box_extents_type = boundaries.get("air_box_extents_type", None)
|
|
625
|
+
if air_box_extents_type:
|
|
626
|
+
self._pedb.hfss.hfss_extent_info.extent_type = air_box_extents_type
|
|
627
|
+
|
|
628
|
+
air_box_truncate_model_ground_layers = boundaries.get("air_box_truncate_model_ground_layers", None)
|
|
629
|
+
if air_box_truncate_model_ground_layers:
|
|
630
|
+
self._pedb.hfss.hfss_extent_info.truncate_air_box_at_ground = air_box_truncate_model_ground_layers
|
|
631
|
+
|
|
632
|
+
air_box_horizontal_padding = boundaries.get("air_box_horizontal_padding", None)
|
|
633
|
+
if air_box_horizontal_padding:
|
|
634
|
+
self._pedb.hfss.hfss_extent_info.air_box_horizontal_extent = air_box_horizontal_padding
|
|
635
|
+
|
|
636
|
+
air_box_positive_vertical_padding = boundaries.get("air_box_positive_vertical_padding", None)
|
|
637
|
+
if air_box_positive_vertical_padding:
|
|
638
|
+
self._pedb.hfss.hfss_extent_info.air_box_positive_vertical_extent = air_box_positive_vertical_padding
|
|
639
|
+
|
|
640
|
+
air_box_negative_vertical_padding = boundaries.get("air_box_negative_vertical_padding", None)
|
|
641
|
+
if air_box_positive_vertical_padding:
|
|
642
|
+
self._pedb.hfss.hfss_extent_info.air_box_negative_vertical_extent = air_box_negative_vertical_padding
|
|
643
|
+
|
|
644
|
+
@pyedb_function_handler
|
|
645
|
+
def _load_operations(self):
|
|
646
|
+
"""Imports operation information from JSON."""
|
|
647
|
+
operations = self.data["operations"]
|
|
648
|
+
cutout = operations.get("cutout", None)
|
|
649
|
+
if cutout:
|
|
650
|
+
self._pedb.cutout(**cutout)
|
|
651
|
+
|
|
652
|
+
@pyedb_function_handler
|
|
653
|
+
def _load_padstacks(self):
|
|
654
|
+
"""Imports padstack information from JSON."""
|
|
655
|
+
padstacks = self.data["padstacks"]
|
|
656
|
+
definitions = padstacks.get("definitions", None)
|
|
657
|
+
if definitions:
|
|
658
|
+
padstack_defs = self._pedb.padstacks.definitions
|
|
659
|
+
for value in definitions:
|
|
660
|
+
pdef = padstack_defs[value["name"]]
|
|
661
|
+
if "hole_diameter" in value:
|
|
662
|
+
pdef.hole_diameter = value["hole_diameter"]
|
|
663
|
+
if "hole_plating_thickness" in value:
|
|
664
|
+
pdef.hole_plating_thickness = value["hole_plating_thickness"]
|
|
665
|
+
if "hole_material" in value:
|
|
666
|
+
pdef.material = value["hole_material"]
|
|
667
|
+
if "hole_range" in value:
|
|
668
|
+
pdef.hole_range = value["hole_range"]
|
|
669
|
+
instances = padstacks.get("instances", None)
|
|
670
|
+
if instances:
|
|
671
|
+
padstack_instances = self._pedb.padstacks.instances_by_name
|
|
672
|
+
for value in instances:
|
|
673
|
+
inst = padstack_instances[value["name"]]
|
|
674
|
+
backdrill_top = value.get("backdrill_top", None)
|
|
675
|
+
if backdrill_top:
|
|
676
|
+
inst.set_backdrill_top(
|
|
677
|
+
backdrill_top["drill_to_layer"], backdrill_top["drill_diameter"], backdrill_top["stub_length"]
|
|
678
|
+
)
|
|
679
|
+
backdrill_bottom = value.get("backdrill_bottom", None)
|
|
680
|
+
if backdrill_top:
|
|
681
|
+
inst.set_backdrill_bottom(
|
|
682
|
+
backdrill_bottom["drill_to_layer"],
|
|
683
|
+
backdrill_bottom["drill_diameter"],
|
|
684
|
+
backdrill_bottom["stub_length"],
|
|
685
|
+
)
|
|
686
|
+
|
|
687
|
+
@pyedb_function_handler
|
|
688
|
+
def _load_package_def(self):
|
|
689
|
+
"""Imports package definition information from JSON."""
|
|
690
|
+
comps = self._pedb.components.components
|
|
691
|
+
for pkgd in self.data["package_definitions"]:
|
|
692
|
+
name = pkgd["name"]
|
|
693
|
+
if name in self._pedb.definitions.package:
|
|
694
|
+
self._pedb.definitions.package[name].delete()
|
|
695
|
+
package_def = PackageDef(self._pedb, name=name)
|
|
696
|
+
package_def.maximum_power = pkgd["maximum_power"]
|
|
697
|
+
package_def.therm_cond = pkgd["therm_cond"]
|
|
698
|
+
package_def.theta_jb = pkgd["theta_jb"]
|
|
699
|
+
package_def.theta_jc = pkgd["theta_jc"]
|
|
700
|
+
package_def.height = pkgd["height"]
|
|
701
|
+
|
|
702
|
+
heatsink = pkgd.get("heatsink", None)
|
|
703
|
+
if heatsink:
|
|
704
|
+
package_def.set_heatsink(
|
|
705
|
+
heatsink["fin_base_height"],
|
|
706
|
+
heatsink["fin_height"],
|
|
707
|
+
heatsink["fin_orientation"],
|
|
708
|
+
heatsink["fin_spacing"],
|
|
709
|
+
heatsink["fin_thickness"],
|
|
710
|
+
)
|
|
711
|
+
json_comps = pkgd["components"] if isinstance(pkgd["components"], list) else [pkgd["components"]]
|
|
712
|
+
for i in json_comps:
|
|
713
|
+
comps[i].package_def = name
|
|
@@ -152,6 +152,15 @@ class EDBComponentDef(ObjBase):
|
|
|
152
152
|
comp.assign_spice_model(file_path, model_name)
|
|
153
153
|
return True
|
|
154
154
|
|
|
155
|
+
@property
|
|
156
|
+
def reference_file(self):
|
|
157
|
+
ref_files = []
|
|
158
|
+
for comp_model in self._comp_model:
|
|
159
|
+
model_type = str(comp_model.GetComponentModelType())
|
|
160
|
+
if model_type == "NPortComponentModel" or model_type == "DynamicLinkComponentModel":
|
|
161
|
+
ref_files.append(comp_model.GetReferenceFile())
|
|
162
|
+
return ref_files
|
|
163
|
+
|
|
155
164
|
@property
|
|
156
165
|
def component_models(self):
|
|
157
166
|
temp = {}
|
|
@@ -67,6 +67,11 @@ class PackageDef(ObjBase):
|
|
|
67
67
|
edb_object.SetExteriorBoundary(polygon)
|
|
68
68
|
return edb_object
|
|
69
69
|
|
|
70
|
+
@pyedb_function_handler
|
|
71
|
+
def delete(self):
|
|
72
|
+
"""Delete a package definition object from the database."""
|
|
73
|
+
return self._edb_object.Delete()
|
|
74
|
+
|
|
70
75
|
@property
|
|
71
76
|
def maximum_power(self):
|
|
72
77
|
"""Maximum power of the package."""
|
|
@@ -116,3 +121,25 @@ class PackageDef(ObjBase):
|
|
|
116
121
|
def height(self, value):
|
|
117
122
|
value = self._pedb.edb_value(value)
|
|
118
123
|
self._edb_object.SetHeight(value)
|
|
124
|
+
|
|
125
|
+
@pyedb_function_handler
|
|
126
|
+
def set_heatsink(self, fin_base_height, fin_height, fin_orientation, fin_spacing, fin_thickness):
|
|
127
|
+
from pyedb.dotnet.edb_core.utilities.heatsink import HeatSink
|
|
128
|
+
|
|
129
|
+
heatsink = HeatSink(self._pedb)
|
|
130
|
+
heatsink.fin_base_height = fin_base_height
|
|
131
|
+
heatsink.fin_height = fin_height
|
|
132
|
+
heatsink.fin_orientation = fin_orientation
|
|
133
|
+
heatsink.fin_spacing = fin_spacing
|
|
134
|
+
heatsink.fin_thickness = fin_thickness
|
|
135
|
+
self._edb_object.SetHeatSink(heatsink._edb_object)
|
|
136
|
+
|
|
137
|
+
@property
|
|
138
|
+
def heatsink(self):
|
|
139
|
+
from pyedb.dotnet.edb_core.utilities.heatsink import HeatSink
|
|
140
|
+
|
|
141
|
+
flag, edb_object = self._edb_object.GetHeatSink()
|
|
142
|
+
if flag:
|
|
143
|
+
return HeatSink(self._pedb, edb_object)
|
|
144
|
+
else:
|
|
145
|
+
return None
|
|
@@ -375,7 +375,7 @@ class EDBComponent(object):
|
|
|
375
375
|
|
|
376
376
|
@property
|
|
377
377
|
def solder_ball_diameter(self):
|
|
378
|
-
"""Solder ball diameter"""
|
|
378
|
+
"""Solder ball diameter."""
|
|
379
379
|
if "GetSolderBallProperty" in dir(self.component_property):
|
|
380
380
|
result = self.component_property.GetSolderBallProperty().GetDiameter()
|
|
381
381
|
succeed = result[0]
|
|
@@ -850,6 +850,7 @@ class EDBComponent(object):
|
|
|
850
850
|
@property
|
|
851
851
|
def is_top_mounted(self):
|
|
852
852
|
"""Check if a component is mounted on top or bottom of the layout.
|
|
853
|
+
|
|
853
854
|
Returns
|
|
854
855
|
-------
|
|
855
856
|
bool
|
|
@@ -39,14 +39,14 @@ class HfssExtentInfo:
|
|
|
39
39
|
self._pedb = pedb
|
|
40
40
|
|
|
41
41
|
self._hfss_extent_info_type = {
|
|
42
|
-
"
|
|
43
|
-
"
|
|
44
|
-
"
|
|
45
|
-
"
|
|
42
|
+
"bounding_box": self._pedb.edb_api.utility.utility.HFSSExtentInfoType.BoundingBox,
|
|
43
|
+
"conforming": self._pedb.edb_api.utility.utility.HFSSExtentInfoType.Conforming,
|
|
44
|
+
"convexHull": self._pedb.edb_api.utility.utility.HFSSExtentInfoType.ConvexHull,
|
|
45
|
+
"polygon": self._pedb.edb_api.utility.utility.HFSSExtentInfoType.Polygon,
|
|
46
46
|
}
|
|
47
47
|
self._open_region_type = {
|
|
48
|
-
"
|
|
49
|
-
"
|
|
48
|
+
"radiation": self._pedb.edb_api.utility.utility.OpenRegionType.Radiation,
|
|
49
|
+
"pml": self._pedb.edb_api.utility.utility.OpenRegionType.PML,
|
|
50
50
|
}
|
|
51
51
|
|
|
52
52
|
@pyedb_function_handler()
|
|
@@ -195,18 +195,19 @@ class HfssExtentInfo:
|
|
|
195
195
|
@property
|
|
196
196
|
def dielectric_extent_type(self):
|
|
197
197
|
"""Dielectric extent type."""
|
|
198
|
-
return self._edb_hfss_extent_info.DielectricExtentType.ToString()
|
|
198
|
+
return self._edb_hfss_extent_info.DielectricExtentType.ToString().lower()
|
|
199
199
|
|
|
200
200
|
@dielectric_extent_type.setter
|
|
201
201
|
def dielectric_extent_type(self, value):
|
|
202
|
+
value = "bounding_box" if value == "BoundingBox" else value
|
|
202
203
|
info = self._edb_hfss_extent_info
|
|
203
|
-
info.DielectricExtentType = self._hfss_extent_info_type[value]
|
|
204
|
+
info.DielectricExtentType = self._hfss_extent_info_type[value.lower()]
|
|
204
205
|
self._update_hfss_extent_info(info)
|
|
205
206
|
|
|
206
207
|
@property
|
|
207
208
|
def extent_type(self):
|
|
208
209
|
"""Extent type."""
|
|
209
|
-
return self._edb_hfss_extent_info.ExtentType.ToString()
|
|
210
|
+
return self._edb_hfss_extent_info.ExtentType.ToString().lower()
|
|
210
211
|
|
|
211
212
|
@extent_type.setter
|
|
212
213
|
def extent_type(self, value):
|
|
@@ -239,17 +240,17 @@ class HfssExtentInfo:
|
|
|
239
240
|
@property
|
|
240
241
|
def open_region_type(self):
|
|
241
242
|
"""Open region type."""
|
|
242
|
-
return self._edb_hfss_extent_info.OpenRegionType.ToString()
|
|
243
|
+
return self._edb_hfss_extent_info.OpenRegionType.ToString().lower()
|
|
243
244
|
|
|
244
245
|
@open_region_type.setter
|
|
245
246
|
def open_region_type(self, value):
|
|
246
247
|
info = self._edb_hfss_extent_info
|
|
247
|
-
info.OpenRegionType = self._open_region_type[value]
|
|
248
|
+
info.OpenRegionType = self._open_region_type[value.lower()]
|
|
248
249
|
self._update_hfss_extent_info(info)
|
|
249
250
|
|
|
250
251
|
@property
|
|
251
252
|
def operating_freq(self):
|
|
252
|
-
"""Operating frequency.
|
|
253
|
+
"""PML Operating frequency.
|
|
253
254
|
|
|
254
255
|
Returns
|
|
255
256
|
-------
|
|
@@ -266,7 +267,7 @@ class HfssExtentInfo:
|
|
|
266
267
|
|
|
267
268
|
@property
|
|
268
269
|
def radiation_level(self):
|
|
269
|
-
"""Radiation level."""
|
|
270
|
+
"""PML Radiation level to calculate the thickness of boundary."""
|
|
270
271
|
return EdbValue(self._edb_hfss_extent_info.RadiationLevel)
|
|
271
272
|
|
|
272
273
|
@radiation_level.setter
|
|
@@ -21,11 +21,11 @@
|
|
|
21
21
|
# SOFTWARE.
|
|
22
22
|
|
|
23
23
|
from pyedb.dotnet.clr_module import Tuple
|
|
24
|
-
from pyedb.dotnet.edb_core.
|
|
24
|
+
from pyedb.dotnet.edb_core.general import convert_py_list_to_net_list
|
|
25
|
+
from pyedb.dotnet.edb_core.utilities.simulation_setup import (
|
|
25
26
|
BaseSimulationSetup,
|
|
26
27
|
EdbFrequencySweep,
|
|
27
28
|
)
|
|
28
|
-
from pyedb.dotnet.edb_core.general import convert_py_list_to_net_list
|
|
29
29
|
from pyedb.generic.general_methods import generate_unique_name, pyedb_function_handler
|
|
30
30
|
|
|
31
31
|
|
|
@@ -553,6 +553,7 @@ class StackupLayerEdbClass(LayerEdbClass):
|
|
|
553
553
|
dict_out[k[1:]] = v
|
|
554
554
|
return dict_out
|
|
555
555
|
|
|
556
|
+
# TODO: This method might need some refactoring
|
|
556
557
|
def _load_layer(self, layer):
|
|
557
558
|
if layer:
|
|
558
559
|
self.color = layer["color"]
|
|
@@ -560,13 +561,17 @@ class StackupLayerEdbClass(LayerEdbClass):
|
|
|
560
561
|
if isinstance(layer["material"], str):
|
|
561
562
|
self.material = layer["material"]
|
|
562
563
|
else:
|
|
563
|
-
|
|
564
|
-
|
|
564
|
+
material_data = layer["material"]
|
|
565
|
+
if material_data is not None:
|
|
566
|
+
self._pclass._pedb.materials.add_material(**material_data)
|
|
567
|
+
self.material = layer["material"]["name"]
|
|
565
568
|
if layer["dielectric_fill"]:
|
|
566
569
|
if isinstance(layer["dielectric_fill"], str):
|
|
567
570
|
self.dielectric_fill = layer["dielectric_fill"]
|
|
568
571
|
else:
|
|
569
|
-
|
|
572
|
+
dielectric_data = layer["dielectric_fill"]
|
|
573
|
+
if dielectric_data is not None:
|
|
574
|
+
self._pclass._pedb.materials.add_material(**dielectric_data)
|
|
570
575
|
self.dielectric_fill = layer["dielectric_fill"]["name"]
|
|
571
576
|
self.thickness = layer["thickness"]
|
|
572
577
|
self.etch_factor = layer["etch_factor"]
|
|
@@ -688,6 +688,7 @@ class EDBPadstack(object):
|
|
|
688
688
|
float
|
|
689
689
|
Thickness of the hole plating if present.
|
|
690
690
|
"""
|
|
691
|
+
value = self._get_edb_value(value).ToDouble()
|
|
691
692
|
hr = 200 * float(value) / float(self.hole_properties[0])
|
|
692
693
|
self.hole_plating_ratio = hr
|
|
693
694
|
|
|
@@ -808,13 +809,13 @@ class EDBPadstack(object):
|
|
|
808
809
|
if convert_only_signal_vias:
|
|
809
810
|
signal_nets = [i for i in list(self._ppadstack._pedb.nets.signal_nets.keys())]
|
|
810
811
|
topl, topz, bottoml, bottomz = self._ppadstack._pedb.stackup.stackup_limits(True)
|
|
811
|
-
|
|
812
|
+
if self.via_start_layer in layers:
|
|
812
813
|
start_elevation = layers[self.via_start_layer].lower_elevation
|
|
813
|
-
|
|
814
|
+
else:
|
|
814
815
|
start_elevation = layers[self.instances[0].start_layer].lower_elevation
|
|
815
|
-
|
|
816
|
-
stop_elevation = layers[self.
|
|
817
|
-
|
|
816
|
+
if self.via_stop_layer in layers:
|
|
817
|
+
stop_elevation = layers[self.via_stop_layer].upper_elevation
|
|
818
|
+
else:
|
|
818
819
|
stop_elevation = layers[self.instances[0].stop_layer].upper_elevation
|
|
819
820
|
|
|
820
821
|
diel_thick = abs(start_elevation - stop_elevation)
|