pyedb 0.6.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 +15 -16
- pyedb/dotnet/edb_core/cell/hierarchy/model.py +17 -0
- pyedb/dotnet/edb_core/components.py +11 -11
- pyedb/dotnet/edb_core/configuration.py +346 -77
- 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 +8 -3
- 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 +26 -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/hfss.py +1 -1
- pyedb/dotnet/edb_core/layout.py +94 -31
- pyedb/dotnet/edb_core/materials.py +637 -541
- pyedb/dotnet/edb_core/nets.py +5 -5
- 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.6.0.dist-info → pyedb-0.7.1.dist-info}/METADATA +31 -53
- {pyedb-0.6.0.dist-info → pyedb-0.7.1.dist-info}/RECORD +35 -32
- /pyedb/dotnet/edb_core/{edb_data → utilities}/simulation_setup.py +0 -0
- {pyedb-0.6.0.dist-info → pyedb-0.7.1.dist-info}/LICENSE +0 -0
- {pyedb-0.6.0.dist-info → pyedb-0.7.1.dist-info}/WHEEL +0 -0
|
@@ -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:
|
|
@@ -41,15 +37,17 @@ class Configuration:
|
|
|
41
37
|
self._pedb = pedb
|
|
42
38
|
self._components = self._pedb.components.components
|
|
43
39
|
self.data = {}
|
|
40
|
+
self._s_parameter_library = ""
|
|
41
|
+
self._spice_model_library = ""
|
|
44
42
|
|
|
45
43
|
@pyedb_function_handler
|
|
46
44
|
def load(self, config_file, append=True, apply_file=False, output_file=None, open_at_the_end=True):
|
|
47
|
-
"""Import configuration settings from a
|
|
45
|
+
"""Import configuration settings from a configure file.
|
|
48
46
|
|
|
49
47
|
Parameters
|
|
50
48
|
----------
|
|
51
|
-
config_file : str
|
|
52
|
-
Full path to
|
|
49
|
+
config_file : str, dict
|
|
50
|
+
Full path to configure file in JSON or TOML format. Dictionary is also supported.
|
|
53
51
|
append : bool, optional
|
|
54
52
|
Whether if the new file will append to existing properties or the properties will be cleared before import.
|
|
55
53
|
Default is ``True`` to keep stored properties
|
|
@@ -65,12 +63,29 @@ class Configuration:
|
|
|
65
63
|
dict
|
|
66
64
|
Config dictionary.
|
|
67
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
|
|
68
76
|
|
|
69
|
-
|
|
70
|
-
if not append:
|
|
77
|
+
if not append: # pragma: no cover
|
|
71
78
|
self.data = {}
|
|
72
79
|
for k, v in data.items():
|
|
73
|
-
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
|
|
74
89
|
if apply_file:
|
|
75
90
|
original_file = self._pedb.edbpath
|
|
76
91
|
if output_file:
|
|
@@ -92,9 +107,30 @@ class Configuration:
|
|
|
92
107
|
self._pedb.logger.error("No data loaded. Please load a configuration file.")
|
|
93
108
|
return False
|
|
94
109
|
|
|
110
|
+
# Configure general settings
|
|
111
|
+
if "general" in self.data:
|
|
112
|
+
self._load_general()
|
|
113
|
+
|
|
114
|
+
# Configure boundary settings
|
|
115
|
+
if "boundaries" in self.data:
|
|
116
|
+
self._load_boundaries()
|
|
117
|
+
|
|
118
|
+
# Configure nets
|
|
119
|
+
if "nets" in self.data:
|
|
120
|
+
self._load_nets()
|
|
121
|
+
|
|
122
|
+
# Configure components
|
|
95
123
|
if "components" in self.data:
|
|
96
124
|
self._load_components()
|
|
97
125
|
|
|
126
|
+
# Configure padstacks
|
|
127
|
+
if "padstacks" in self.data:
|
|
128
|
+
self._load_padstacks()
|
|
129
|
+
|
|
130
|
+
# Configure pin groups
|
|
131
|
+
if "pin_groups" in self.data:
|
|
132
|
+
self._load_pin_groups()
|
|
133
|
+
|
|
98
134
|
# Configure ports
|
|
99
135
|
if "ports" in self.data:
|
|
100
136
|
self._load_ports()
|
|
@@ -115,6 +151,18 @@ class Configuration:
|
|
|
115
151
|
if "s_parameters" in self.data:
|
|
116
152
|
self._load_s_parameter()
|
|
117
153
|
|
|
154
|
+
# Configure SPICE models
|
|
155
|
+
if "spice_models" in self.data:
|
|
156
|
+
self._load_spice_models()
|
|
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
|
+
|
|
118
166
|
return True
|
|
119
167
|
|
|
120
168
|
@pyedb_function_handler
|
|
@@ -122,7 +170,7 @@ class Configuration:
|
|
|
122
170
|
"""Imports component information from json."""
|
|
123
171
|
|
|
124
172
|
for comp in self.data["components"]:
|
|
125
|
-
|
|
173
|
+
ref_designator = comp["reference_designator"]
|
|
126
174
|
part_type = comp["part_type"].lower()
|
|
127
175
|
if part_type == "resistor":
|
|
128
176
|
part_type = "Resistor"
|
|
@@ -137,7 +185,7 @@ class Configuration:
|
|
|
137
185
|
else:
|
|
138
186
|
part_type = "Other"
|
|
139
187
|
|
|
140
|
-
comp_layout = self._components[
|
|
188
|
+
comp_layout = self._components[ref_designator]
|
|
141
189
|
comp_layout.type = part_type
|
|
142
190
|
|
|
143
191
|
if part_type in ["Resistor", "Capacitor", "Inductor"]:
|
|
@@ -213,7 +261,7 @@ class Configuration:
|
|
|
213
261
|
height = solder_ball_properties["height"]
|
|
214
262
|
|
|
215
263
|
self._pedb.components.set_solder_ball(
|
|
216
|
-
component=
|
|
264
|
+
component=ref_designator,
|
|
217
265
|
sball_diam=diameter,
|
|
218
266
|
sball_mid_diam=mid_diameter,
|
|
219
267
|
sball_height=height,
|
|
@@ -229,38 +277,50 @@ class Configuration:
|
|
|
229
277
|
"""Imports port information from json."""
|
|
230
278
|
for port in self.data["ports"]:
|
|
231
279
|
port_type = port["type"]
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
if "
|
|
236
|
-
|
|
237
|
-
port_name = "
|
|
238
|
-
pos_terminal =
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
280
|
+
|
|
281
|
+
positive_terminal_json = port["positive_terminal"]
|
|
282
|
+
pos_terminal = ""
|
|
283
|
+
if "pin_group" in positive_terminal_json:
|
|
284
|
+
pin_group = self._pedb.siwave.pin_groups[positive_terminal_json["pin_group"]]
|
|
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
|
+
|
|
288
|
+
else:
|
|
289
|
+
ref_designator = port["reference_designator"]
|
|
290
|
+
comp_layout = self._components[ref_designator]
|
|
291
|
+
|
|
292
|
+
if "pin" in positive_terminal_json:
|
|
293
|
+
pin_name = positive_terminal_json["pin"]
|
|
294
|
+
port_name = "{}_{}".format(ref_designator, pin_name) if "name" not in port else port["name"]
|
|
295
|
+
pos_terminal = comp_layout.pins[pin_name].get_terminal(port_name, True)
|
|
296
|
+
else: # Net
|
|
297
|
+
net_name = positive_terminal_json["net"]
|
|
298
|
+
port_name = "{}_{}".format(ref_designator, net_name) if "name" not in port else port["name"]
|
|
299
|
+
if port_type == "circuit":
|
|
300
|
+
pg_name = "pg_{}".format(port_name)
|
|
301
|
+
_, pg = self._pedb.siwave.create_pin_group_on_net(ref_designator, net_name, pg_name)
|
|
302
|
+
pos_terminal = pg.get_terminal(port_name, True)
|
|
303
|
+
else: # Coax port
|
|
304
|
+
for _, p in comp_layout.pins.items():
|
|
305
|
+
if p.net_name == net_name:
|
|
306
|
+
pos_terminal = p.get_terminal(port_name, True)
|
|
307
|
+
break
|
|
251
308
|
|
|
252
309
|
if port_type == "circuit":
|
|
253
|
-
|
|
254
|
-
if "
|
|
255
|
-
|
|
256
|
-
|
|
310
|
+
negative_terminal_json = port["negative_terminal"]
|
|
311
|
+
if "pin_group" in negative_terminal_json:
|
|
312
|
+
pin_group = self._pedb.siwave.pin_groups[negative_terminal_json["pin_group"]]
|
|
313
|
+
neg_terminal = pin_group.get_terminal(pin_group.name + "_ref", True)
|
|
314
|
+
elif "pin" in negative_terminal_json:
|
|
315
|
+
pin_name = negative_terminal_json["pin"]
|
|
316
|
+
port_name = "{}_{}_ref".format(ref_designator, pin_name)
|
|
257
317
|
neg_terminal = comp_layout.pins[pin_name].get_terminal(port_name, True)
|
|
258
318
|
else:
|
|
259
|
-
net_name =
|
|
260
|
-
port_name = "{}_{}_ref".format(
|
|
319
|
+
net_name = negative_terminal_json["net"]
|
|
320
|
+
port_name = "{}_{}_ref".format(ref_designator, net_name)
|
|
261
321
|
pg_name = "pg_{}".format(port_name)
|
|
262
322
|
if pg_name not in self._pedb.siwave.pin_groups:
|
|
263
|
-
_, pg = self._pedb.siwave.create_pin_group_on_net(
|
|
323
|
+
_, pg = self._pedb.siwave.create_pin_group_on_net(ref_designator, net_name, pg_name)
|
|
264
324
|
else:
|
|
265
325
|
pg = self._pedb.siwave.pin_groups[pg_name]
|
|
266
326
|
neg_terminal = pg.get_terminal(port_name, True)
|
|
@@ -275,36 +335,47 @@ class Configuration:
|
|
|
275
335
|
|
|
276
336
|
for src in self.data["sources"]:
|
|
277
337
|
src_type = src["type"]
|
|
278
|
-
refdes = src["reference_designator"]
|
|
279
338
|
name = src["name"]
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
339
|
+
|
|
340
|
+
positive_terminal_json = src["positive_terminal"]
|
|
341
|
+
if "pin_group" in positive_terminal_json:
|
|
342
|
+
pin_group = self._pedb.siwave.pin_groups[positive_terminal_json["pin_group"]]
|
|
343
|
+
pos_terminal = pin_group.get_terminal(pin_group.name, True)
|
|
344
|
+
else:
|
|
345
|
+
ref_designator = src["reference_designator"]
|
|
346
|
+
comp_layout = self._components[ref_designator]
|
|
347
|
+
|
|
348
|
+
if "pin" in positive_terminal_json:
|
|
349
|
+
pin_name = positive_terminal_json["pin"]
|
|
350
|
+
src_name = name
|
|
351
|
+
pos_terminal = comp_layout.pins[pin_name].get_terminal(src_name, True)
|
|
352
|
+
elif "net" in positive_terminal_json: # Net
|
|
353
|
+
net_name = positive_terminal_json["net"]
|
|
354
|
+
src_name = "{}_{}".format(ref_designator, net_name)
|
|
355
|
+
pg_name = "pg_{}".format(src_name)
|
|
356
|
+
_, pg = self._pedb.siwave.create_pin_group_on_net(ref_designator, net_name, pg_name)
|
|
357
|
+
pos_terminal = pg.get_terminal(src_name, True)
|
|
358
|
+
|
|
359
|
+
negative_terminal_json = src["negative_terminal"]
|
|
360
|
+
if "pin_group" in negative_terminal_json:
|
|
361
|
+
pin_group = self._pedb.siwave.pin_groups[negative_terminal_json["pin_group"]]
|
|
362
|
+
neg_terminal = pin_group.get_terminal(pin_group.name + "_ref", True)
|
|
363
|
+
else:
|
|
364
|
+
ref_designator = src["reference_designator"]
|
|
365
|
+
comp_layout = self._components[ref_designator]
|
|
366
|
+
if "pin" in negative_terminal_json:
|
|
367
|
+
pin_name = negative_terminal_json["pin"]
|
|
368
|
+
src_name = name + "_ref"
|
|
369
|
+
neg_terminal = comp_layout.pins[pin_name].get_terminal(src_name, True)
|
|
370
|
+
elif "net" in negative_terminal_json:
|
|
371
|
+
net_name = negative_terminal_json["net"]
|
|
372
|
+
src_name = name + "_ref"
|
|
373
|
+
pg_name = "pg_{}".format(src_name)
|
|
374
|
+
if pg_name not in self._pedb.siwave.pin_groups:
|
|
375
|
+
_, pg = self._pedb.siwave.create_pin_group_on_net(ref_designator, net_name, pg_name)
|
|
376
|
+
else: # pragma no cover
|
|
377
|
+
pg = self._pedb.siwave.pin_groups[pg_name]
|
|
378
|
+
neg_terminal = pg.get_terminal(src_name, True)
|
|
308
379
|
|
|
309
380
|
if src_type == "voltage":
|
|
310
381
|
src_obj = self._pedb.create_voltage_source(pos_terminal, neg_terminal)
|
|
@@ -349,7 +420,10 @@ class Configuration:
|
|
|
349
420
|
else:
|
|
350
421
|
self._pedb.logger.warning("Setup {} already existing. Editing it.".format(name))
|
|
351
422
|
edb_setup = self._pedb.setups[name]
|
|
352
|
-
|
|
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"]
|
|
353
427
|
|
|
354
428
|
if "freq_sweep" in setup:
|
|
355
429
|
for fsweep in setup["freq_sweep"]:
|
|
@@ -430,15 +504,210 @@ class Configuration:
|
|
|
430
504
|
|
|
431
505
|
for sp in self.data["s_parameters"]:
|
|
432
506
|
fpath = sp["file_path"]
|
|
507
|
+
if not Path(fpath).anchor:
|
|
508
|
+
fpath = str(Path(self._s_parameter_library) / fpath)
|
|
433
509
|
sp_name = sp["name"]
|
|
434
510
|
comp_def_name = sp["component_definition"]
|
|
435
511
|
comp_def = self._pedb.definitions.component[comp_def_name]
|
|
436
512
|
comp_def.add_n_port_model(fpath, sp_name)
|
|
513
|
+
comp_list = dict()
|
|
514
|
+
if sp["apply_to_all"]:
|
|
515
|
+
comp_list.update(
|
|
516
|
+
{refdes: comp for refdes, comp in comp_def.components.items() if refdes not in sp["components"]}
|
|
517
|
+
)
|
|
518
|
+
else:
|
|
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)
|
|
530
|
+
|
|
531
|
+
@pyedb_function_handler
|
|
532
|
+
def _load_spice_models(self):
|
|
533
|
+
"""Imports SPICE information from json."""
|
|
534
|
+
|
|
535
|
+
for sp in self.data["spice_models"]:
|
|
536
|
+
fpath = sp["file_path"]
|
|
537
|
+
if not Path(fpath).anchor:
|
|
538
|
+
fpath = str(Path(self._spice_model_library) / fpath)
|
|
539
|
+
sp_name = sp["name"]
|
|
540
|
+
sub_circuit_name = sp.get("sub_circuit_name", None)
|
|
541
|
+
comp_def_name = sp["component_definition"]
|
|
542
|
+
comp_def = self._pedb.definitions.component[comp_def_name]
|
|
543
|
+
comps = comp_def.components
|
|
437
544
|
if sp["apply_to_all"]:
|
|
438
|
-
for refdes, comp in
|
|
545
|
+
for refdes, comp in comps.items():
|
|
439
546
|
if refdes not in sp["components"]:
|
|
440
|
-
comp.
|
|
547
|
+
comp.assign_spice_model(fpath, sp_name, sub_circuit_name)
|
|
441
548
|
else:
|
|
442
|
-
for refdes, comp in
|
|
549
|
+
for refdes, comp in comps.items():
|
|
443
550
|
if refdes in sp["components"]:
|
|
444
|
-
comp.
|
|
551
|
+
comp.assign_spice_model(fpath, sp_name, sub_circuit_name)
|
|
552
|
+
|
|
553
|
+
@pyedb_function_handler
|
|
554
|
+
def _load_pin_groups(self):
|
|
555
|
+
"""Imports pin groups information from JSON."""
|
|
556
|
+
for pg in self.data["pin_groups"]:
|
|
557
|
+
name = pg["name"]
|
|
558
|
+
ref_designator = pg["reference_designator"]
|
|
559
|
+
if "pins" in pg:
|
|
560
|
+
self._pedb.siwave.create_pin_group(ref_designator, pg["pins"], name)
|
|
561
|
+
elif "net" in pg:
|
|
562
|
+
self._pedb.siwave.create_pin_group_on_net(ref_designator, pg["net"], name)
|
|
563
|
+
|
|
564
|
+
@pyedb_function_handler
|
|
565
|
+
def _load_nets(self):
|
|
566
|
+
"""Imports nets information from JSON."""
|
|
567
|
+
nets = self._pedb.nets.nets
|
|
568
|
+
for i in self.data["nets"]["power_ground_nets"]:
|
|
569
|
+
nets[i].is_power_ground = True
|
|
570
|
+
|
|
571
|
+
for i in self.data["nets"]["signal_nets"]:
|
|
572
|
+
nets[i].is_power_ground = False
|
|
573
|
+
|
|
574
|
+
@pyedb_function_handler
|
|
575
|
+
def _load_general(self):
|
|
576
|
+
"""Imports general information from JSON."""
|
|
577
|
+
general = self.data["general"]
|
|
578
|
+
if "s_parameter_library" in general:
|
|
579
|
+
self._s_parameter_library = general["s_parameter_library"]
|
|
580
|
+
if "spice_model_library" in general:
|
|
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
|
|
@@ -24,7 +24,7 @@ import logging
|
|
|
24
24
|
import re
|
|
25
25
|
import warnings
|
|
26
26
|
|
|
27
|
-
from pyedb.dotnet.edb_core.cell.hierarchy.model import PinPairModel
|
|
27
|
+
from pyedb.dotnet.edb_core.cell.hierarchy.model import PinPairModel, SPICEModel
|
|
28
28
|
from pyedb.dotnet.edb_core.definition.package_def import PackageDef
|
|
29
29
|
from pyedb.dotnet.edb_core.edb_data.padstacks_data import EDBPadstackInstance
|
|
30
30
|
from pyedb.generic.general_methods import is_ironpython
|
|
@@ -222,6 +222,8 @@ class EDBComponent(object):
|
|
|
222
222
|
model_type = edb_object.ToString().split(".")[-1]
|
|
223
223
|
if model_type == "PinPairModel":
|
|
224
224
|
return PinPairModel(self._pedb, edb_object)
|
|
225
|
+
elif model_type == "SPICEModel":
|
|
226
|
+
return SPICEModel(self._pedb, edb_object)
|
|
225
227
|
|
|
226
228
|
@model.setter
|
|
227
229
|
def model(self, value):
|
|
@@ -373,7 +375,7 @@ class EDBComponent(object):
|
|
|
373
375
|
|
|
374
376
|
@property
|
|
375
377
|
def solder_ball_diameter(self):
|
|
376
|
-
"""Solder ball diameter"""
|
|
378
|
+
"""Solder ball diameter."""
|
|
377
379
|
if "GetSolderBallProperty" in dir(self.component_property):
|
|
378
380
|
result = self.component_property.GetSolderBallProperty().GetDiameter()
|
|
379
381
|
succeed = result[0]
|
|
@@ -848,6 +850,7 @@ class EDBComponent(object):
|
|
|
848
850
|
@property
|
|
849
851
|
def is_top_mounted(self):
|
|
850
852
|
"""Check if a component is mounted on top or bottom of the layout.
|
|
853
|
+
|
|
851
854
|
Returns
|
|
852
855
|
-------
|
|
853
856
|
bool
|
|
@@ -912,7 +915,7 @@ class EDBComponent(object):
|
|
|
912
915
|
return True
|
|
913
916
|
|
|
914
917
|
@pyedb_function_handler()
|
|
915
|
-
def assign_spice_model(self, file_path, name=None):
|
|
918
|
+
def assign_spice_model(self, file_path, name=None, sub_circuit_name=None):
|
|
916
919
|
"""Assign Spice model to this component.
|
|
917
920
|
|
|
918
921
|
Parameters
|
|
@@ -940,6 +943,8 @@ class EDBComponent(object):
|
|
|
940
943
|
model = self._edb.cell.hierarchy._hierarchy.SPICEModel()
|
|
941
944
|
model.SetModelPath(file_path)
|
|
942
945
|
model.SetModelName(name)
|
|
946
|
+
if sub_circuit_name:
|
|
947
|
+
model.SetSubCkt(sub_circuit_name)
|
|
943
948
|
terminal = 1
|
|
944
949
|
for pn in pinNames:
|
|
945
950
|
model.AddTerminalPinPair(pn, str(terminal))
|