pyedb 0.43.0__py3-none-any.whl → 0.45.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 +1 -1
- pyedb/configuration/cfg_boundaries.py +21 -15
- pyedb/configuration/cfg_components.py +8 -8
- pyedb/configuration/cfg_general.py +14 -6
- pyedb/configuration/cfg_modeler.py +8 -0
- pyedb/configuration/cfg_operations.py +40 -1
- pyedb/configuration/cfg_package_definition.py +41 -1
- pyedb/configuration/cfg_padstacks.py +611 -256
- pyedb/configuration/cfg_pin_groups.py +1 -1
- pyedb/configuration/cfg_ports_sources.py +234 -66
- pyedb/configuration/cfg_s_parameter_models.py +81 -1
- pyedb/configuration/cfg_setup.py +167 -33
- pyedb/configuration/cfg_stackup.py +44 -0
- pyedb/configuration/configuration.py +13 -3
- pyedb/dotnet/database/cell/primitive/path.py +12 -0
- pyedb/dotnet/database/edb_data/design_options.py +19 -1
- pyedb/dotnet/database/edb_data/padstacks_data.py +9 -4
- pyedb/dotnet/database/geometry/point_data.py +26 -0
- pyedb/dotnet/database/geometry/polygon_data.py +13 -2
- pyedb/dotnet/database/nets.py +13 -3
- pyedb/dotnet/database/padstack.py +6 -2
- pyedb/dotnet/database/utilities/simulation_setup.py +7 -17
- pyedb/dotnet/database/utilities/siwave_simulation_setup.py +30 -0
- pyedb/dotnet/edb.py +41 -18
- pyedb/grpc/database/components.py +2 -3
- pyedb/grpc/database/definition/component_def.py +15 -0
- pyedb/grpc/database/definition/component_pin.py +1 -1
- pyedb/grpc/database/definition/materials.py +27 -0
- pyedb/grpc/database/definition/package_def.py +20 -2
- pyedb/grpc/database/definition/padstack_def.py +5 -2
- pyedb/grpc/database/hfss.py +10 -1
- pyedb/grpc/database/hierarchy/component.py +4 -2
- pyedb/grpc/database/hierarchy/pingroup.py +12 -8
- pyedb/grpc/database/layers/layer.py +28 -0
- pyedb/grpc/database/layers/stackup_layer.py +281 -40
- pyedb/grpc/database/layout/layout.py +12 -6
- pyedb/grpc/database/layout_validation.py +2 -2
- pyedb/grpc/database/modeler.py +8 -8
- pyedb/grpc/database/padstacks.py +15 -9
- pyedb/grpc/database/ports/ports.py +3 -3
- pyedb/grpc/database/primitive/bondwire.py +3 -3
- pyedb/grpc/database/primitive/circle.py +1 -1
- pyedb/grpc/database/primitive/padstack_instance.py +13 -3
- pyedb/grpc/database/primitive/path.py +2 -2
- pyedb/grpc/database/primitive/polygon.py +3 -3
- pyedb/grpc/database/primitive/primitive.py +1 -1
- pyedb/grpc/database/primitive/rectangle.py +2 -2
- pyedb/grpc/database/simulation_setup/hfss_simulation_setup.py +78 -30
- pyedb/grpc/database/simulation_setup/siwave_simulation_setup.py +73 -30
- pyedb/grpc/database/simulation_setup/sweep_data.py +12 -1
- pyedb/grpc/database/siwave.py +10 -1
- pyedb/grpc/database/source_excitations.py +19 -9
- pyedb/grpc/database/stackup.py +26 -10
- pyedb/grpc/database/terminal/bundle_terminal.py +3 -3
- pyedb/grpc/database/terminal/edge_terminal.py +95 -2
- pyedb/grpc/database/terminal/padstack_instance_terminal.py +42 -2
- pyedb/grpc/database/terminal/pingroup_terminal.py +48 -2
- pyedb/grpc/database/terminal/point_terminal.py +10 -1
- pyedb/grpc/database/terminal/terminal.py +4 -4
- pyedb/grpc/database/utility/hfss_extent_info.py +14 -10
- pyedb/grpc/edb.py +21 -17
- pyedb/grpc/edb_init.py +19 -15
- pyedb/grpc/rpc_session.py +11 -8
- pyedb/misc/misc.py +13 -0
- {pyedb-0.43.0.dist-info → pyedb-0.45.0.dist-info}/METADATA +6 -6
- {pyedb-0.43.0.dist-info → pyedb-0.45.0.dist-info}/RECORD +68 -68
- {pyedb-0.43.0.dist-info → pyedb-0.45.0.dist-info}/LICENSE +0 -0
- {pyedb-0.43.0.dist-info → pyedb-0.45.0.dist-info}/WHEEL +0 -0
pyedb/configuration/cfg_setup.py
CHANGED
|
@@ -32,6 +32,59 @@ class CfgSetup:
|
|
|
32
32
|
"""
|
|
33
33
|
|
|
34
34
|
class Common:
|
|
35
|
+
class Grpc:
|
|
36
|
+
def __init__(self, parent):
|
|
37
|
+
self.parent = parent
|
|
38
|
+
|
|
39
|
+
def apply_freq_sweep(self, edb_setup):
|
|
40
|
+
for i in self.parent.parent.freq_sweep:
|
|
41
|
+
f_set = []
|
|
42
|
+
freq_string = []
|
|
43
|
+
for f in i.get("frequencies", []):
|
|
44
|
+
if isinstance(f, dict):
|
|
45
|
+
increment = f.get("increment", f.get("points", f.get("samples", f.get("step"))))
|
|
46
|
+
f_set.append([f["distribution"], f["start"], f["stop"], increment])
|
|
47
|
+
else:
|
|
48
|
+
freq_string.append(f)
|
|
49
|
+
discrete_sweep = True
|
|
50
|
+
if i["type"] == "interpolation":
|
|
51
|
+
discrete_sweep = False
|
|
52
|
+
if freq_string:
|
|
53
|
+
for _sweep in freq_string:
|
|
54
|
+
_sw = _sweep.split(" ")
|
|
55
|
+
edb_setup.add_sweep(
|
|
56
|
+
name=i["name"],
|
|
57
|
+
distribution=_sw[0],
|
|
58
|
+
start_freq=_sw[1],
|
|
59
|
+
stop_freq=_sw[2],
|
|
60
|
+
step=_sw[3],
|
|
61
|
+
discrete=discrete_sweep,
|
|
62
|
+
)
|
|
63
|
+
else:
|
|
64
|
+
edb_setup.add_sweep(i["name"], frequency_set=f_set, discrete=discrete_sweep)
|
|
65
|
+
|
|
66
|
+
class DotNet(Grpc):
|
|
67
|
+
def __init__(self, parent):
|
|
68
|
+
super().__init__(parent)
|
|
69
|
+
|
|
70
|
+
@staticmethod
|
|
71
|
+
def set_frequency_string(sweep, freq_string):
|
|
72
|
+
sweep.frequency_string = freq_string
|
|
73
|
+
|
|
74
|
+
def apply_freq_sweep(self, edb_setup):
|
|
75
|
+
for i in self.parent.parent.freq_sweep:
|
|
76
|
+
f_set = []
|
|
77
|
+
freq_string = []
|
|
78
|
+
for f in i.get("frequencies", []):
|
|
79
|
+
if isinstance(f, dict):
|
|
80
|
+
increment = f.get("increment", f.get("points", f.get("samples", f.get("step"))))
|
|
81
|
+
f_set.append([f["distribution"], f["start"], f["stop"], increment])
|
|
82
|
+
else:
|
|
83
|
+
freq_string.append(f)
|
|
84
|
+
sweep = edb_setup.add_sweep(i["name"], frequency_set=f_set, sweep_type=i["type"])
|
|
85
|
+
if len(freq_string) > 0:
|
|
86
|
+
self.parent.api.set_frequency_string(sweep, freq_string)
|
|
87
|
+
|
|
35
88
|
@property
|
|
36
89
|
def pyedb_obj(self):
|
|
37
90
|
return self.parent.pyedb_obj
|
|
@@ -39,24 +92,17 @@ class CfgSetup:
|
|
|
39
92
|
def __init__(self, parent):
|
|
40
93
|
self.parent = parent
|
|
41
94
|
self.pedb = parent.pedb
|
|
95
|
+
if self.pedb.grpc:
|
|
96
|
+
self.api = self.Grpc(self)
|
|
97
|
+
else:
|
|
98
|
+
self.api = self.DotNet(self)
|
|
42
99
|
|
|
43
100
|
def _retrieve_parameters_from_edb_common(self):
|
|
44
101
|
self.parent.name = self.pyedb_obj.name
|
|
45
102
|
self.parent.type = self.pyedb_obj.type
|
|
46
103
|
|
|
47
104
|
def _apply_freq_sweep(self, edb_setup):
|
|
48
|
-
|
|
49
|
-
f_set = []
|
|
50
|
-
freq_string = []
|
|
51
|
-
for f in i.get("frequencies", []):
|
|
52
|
-
if isinstance(f, dict):
|
|
53
|
-
increment = f.get("increment", f.get("points", f.get("samples", f.get("step"))))
|
|
54
|
-
f_set.append([f["distribution"], f["start"], f["stop"], increment])
|
|
55
|
-
else:
|
|
56
|
-
freq_string.append(f)
|
|
57
|
-
sweep = edb_setup.add_sweep(i["name"], frequency_set=f_set, sweep_type=i["type"])
|
|
58
|
-
if len(freq_string) > 0:
|
|
59
|
-
sweep.frequency_string = freq_string
|
|
105
|
+
self.api.apply_freq_sweep(edb_setup)
|
|
60
106
|
|
|
61
107
|
class Grpc(Common):
|
|
62
108
|
def __init__(self, parent):
|
|
@@ -148,9 +194,8 @@ class CfgSIwaveDCSetup(CfgSetup):
|
|
|
148
194
|
edb_setup = self.pedb.create_siwave_dc_setup(
|
|
149
195
|
name=self.parent.name, dc_slider_position=self.parent.dc_slider_position
|
|
150
196
|
)
|
|
151
|
-
edb_setup.
|
|
152
|
-
|
|
153
|
-
edb_setup.dc_ir_settings.export_dc_thermal_data = dc_ir_settings["export_dc_thermal_data"]
|
|
197
|
+
edb_setup.settings.dc.dc_slider_pos = self.parent.dc_slider_position
|
|
198
|
+
edb_setup.settings.export_dc_thermal_data = self.parent.dc_ir_settings.get("export_dc_thermal_data", False)
|
|
154
199
|
|
|
155
200
|
def retrieve_parameters_from_edb(self):
|
|
156
201
|
self._retrieve_parameters_from_edb_common()
|
|
@@ -163,6 +208,14 @@ class CfgSIwaveDCSetup(CfgSetup):
|
|
|
163
208
|
def __init__(self, parent):
|
|
164
209
|
super().__init__(parent)
|
|
165
210
|
|
|
211
|
+
def set_parameters_to_edb(self):
|
|
212
|
+
edb_setup = self.pedb.create_siwave_dc_setup(
|
|
213
|
+
name=self.parent.name, dc_slider_position=self.parent.dc_slider_position
|
|
214
|
+
)
|
|
215
|
+
edb_setup.dc_settings.dc_slider_position = self.parent.dc_slider_position
|
|
216
|
+
dc_ir_settings = self.parent.dc_ir_settings
|
|
217
|
+
edb_setup.dc_ir_settings.export_dc_thermal_data = dc_ir_settings.get("export_dc_thermal_data", False)
|
|
218
|
+
|
|
166
219
|
def __init__(self, pedb, pyedb_obj, **kwargs):
|
|
167
220
|
super().__init__(pedb, pyedb_obj, **kwargs)
|
|
168
221
|
self.type = "siwave_dc"
|
|
@@ -202,6 +255,57 @@ class CfgHFSSSetup(CfgSetup):
|
|
|
202
255
|
net_layer_list=i.get("nets_layers_list", {}),
|
|
203
256
|
)
|
|
204
257
|
|
|
258
|
+
def retrieve_parameters_from_edb(self):
|
|
259
|
+
self._retrieve_parameters_from_edb_common()
|
|
260
|
+
single_frequency_adaptive_solution = self.pyedb_obj.settings.general.single_frequency_adaptive_solution
|
|
261
|
+
self.parent.f_adapt = single_frequency_adaptive_solution.adaptive_frequency
|
|
262
|
+
self.parent.max_num_passes = single_frequency_adaptive_solution.max_passes
|
|
263
|
+
self.parent.max_mag_delta_s = float(single_frequency_adaptive_solution.max_delta)
|
|
264
|
+
self.parent.freq_sweep = []
|
|
265
|
+
setup_sweeps = self.sort_sweep_data(self.pyedb_obj.sweep_data)
|
|
266
|
+
for setup_name, sweeps in setup_sweeps.items():
|
|
267
|
+
sw_name = sweeps[0].name
|
|
268
|
+
sw_type = sweeps[0].type.name.lower().split("_")[0]
|
|
269
|
+
freq_strings = [f.frequency_string for f in sweeps]
|
|
270
|
+
self.parent.freq_sweep.append({"name": sw_name, "type": sw_type, "frequencies": freq_strings})
|
|
271
|
+
|
|
272
|
+
self.parent.mesh_operations = []
|
|
273
|
+
from ansys.edb.core.simulation_setup.mesh_operation import (
|
|
274
|
+
LengthMeshOperation as GrpcLengthMeshOperation,
|
|
275
|
+
)
|
|
276
|
+
|
|
277
|
+
for mesh_op in self.pyedb_obj.mesh_operations:
|
|
278
|
+
if isinstance(mesh_op, GrpcLengthMeshOperation):
|
|
279
|
+
mop_type = "length"
|
|
280
|
+
else:
|
|
281
|
+
mop_type = "skin"
|
|
282
|
+
self.parent.mesh_operations.append(
|
|
283
|
+
{
|
|
284
|
+
"name": mesh_op.name,
|
|
285
|
+
"type": mop_type,
|
|
286
|
+
"max_elements": mesh_op.max_elements,
|
|
287
|
+
"max_length": mesh_op.max_length,
|
|
288
|
+
"restrict_length": mesh_op.restrict_max_length,
|
|
289
|
+
"refine_inside": mesh_op.refine_inside,
|
|
290
|
+
"nets_layers_list": mesh_op.net_layer_info,
|
|
291
|
+
}
|
|
292
|
+
)
|
|
293
|
+
|
|
294
|
+
@staticmethod
|
|
295
|
+
def sort_sweep_data(sweep_data):
|
|
296
|
+
"""grpc sweep data contains all sweeps for each setup, we need to sort thwm by setup"""
|
|
297
|
+
setups = {}
|
|
298
|
+
for sweep in sweep_data:
|
|
299
|
+
if sweep.name not in setups:
|
|
300
|
+
setups[sweep.name] = [sweep]
|
|
301
|
+
else:
|
|
302
|
+
setups[sweep.name].append(sweep)
|
|
303
|
+
return setups
|
|
304
|
+
|
|
305
|
+
class DotNet(Grpc):
|
|
306
|
+
def __init__(self, parent):
|
|
307
|
+
super().__init__(parent)
|
|
308
|
+
|
|
205
309
|
def retrieve_parameters_from_edb(self):
|
|
206
310
|
self._retrieve_parameters_from_edb_common()
|
|
207
311
|
adaptive_frequency_data_list = list(self.pyedb_obj.adaptive_settings.adaptive_frequency_data_list)[0]
|
|
@@ -226,10 +330,6 @@ class CfgHFSSSetup(CfgSetup):
|
|
|
226
330
|
}
|
|
227
331
|
)
|
|
228
332
|
|
|
229
|
-
class DotNet(Grpc):
|
|
230
|
-
def __init__(self, parent):
|
|
231
|
-
super().__init__(parent)
|
|
232
|
-
|
|
233
333
|
def __init__(self, pedb, pyedb_obj, **kwargs):
|
|
234
334
|
super().__init__(pedb, pyedb_obj, **kwargs)
|
|
235
335
|
self.type = "hfss"
|
|
@@ -254,9 +354,56 @@ class CfgHFSSSetup(CfgSetup):
|
|
|
254
354
|
|
|
255
355
|
|
|
256
356
|
class CfgSetups:
|
|
357
|
+
class Grpc:
|
|
358
|
+
def __init__(self, parent):
|
|
359
|
+
self.parent = parent
|
|
360
|
+
self._pedb = parent.pedb
|
|
361
|
+
|
|
362
|
+
def retrieve_parameters_from_edb(self):
|
|
363
|
+
self.parent.setups = []
|
|
364
|
+
for _, setup in self._pedb.setups.items():
|
|
365
|
+
if setup.type.name.lower() == "hfss":
|
|
366
|
+
hfss = CfgHFSSSetup(self._pedb, setup)
|
|
367
|
+
hfss.api.retrieve_parameters_from_edb()
|
|
368
|
+
self.parent.setups.append(hfss)
|
|
369
|
+
elif setup.type.name.lower() == "si_wave_dcir":
|
|
370
|
+
siwave_dc = CfgSIwaveDCSetup(self._pedb, setup)
|
|
371
|
+
siwave_dc.api.retrieve_parameters_from_edb()
|
|
372
|
+
self.parent.setups.append(siwave_dc)
|
|
373
|
+
elif setup.type.name.lower() == "si_wave":
|
|
374
|
+
siwave_ac = CfgSIwaveACSetup(self._pedb, setup)
|
|
375
|
+
siwave_ac.api.retrieve_parameters_from_edb()
|
|
376
|
+
self.parent.setups.append(siwave_ac)
|
|
377
|
+
elif setup.type.name.lower() == "raptor_x":
|
|
378
|
+
pass
|
|
379
|
+
|
|
380
|
+
class DotNet(Grpc):
|
|
381
|
+
def __init__(self, parent):
|
|
382
|
+
super().__init__(parent)
|
|
383
|
+
|
|
384
|
+
def retrieve_parameters_from_edb(self):
|
|
385
|
+
self.parent.setups = []
|
|
386
|
+
for _, setup in self._pedb.setups.items():
|
|
387
|
+
if setup.type == "hfss":
|
|
388
|
+
hfss = CfgHFSSSetup(self._pedb, setup)
|
|
389
|
+
hfss.api.retrieve_parameters_from_edb()
|
|
390
|
+
self.parent.setups.append(hfss)
|
|
391
|
+
elif setup.type == "siwave_dc":
|
|
392
|
+
siwave_dc = CfgSIwaveDCSetup(self._pedb, setup)
|
|
393
|
+
siwave_dc.api.retrieve_parameters_from_edb()
|
|
394
|
+
self.parent.setups.append(siwave_dc)
|
|
395
|
+
elif setup.type == "siwave_ac":
|
|
396
|
+
siwave_ac = CfgSIwaveACSetup(self._pedb, setup)
|
|
397
|
+
siwave_ac.api.retrieve_parameters_from_edb()
|
|
398
|
+
self.parent.setups.append(siwave_ac)
|
|
399
|
+
|
|
257
400
|
def __init__(self, pedb, setups_data):
|
|
258
401
|
self.pedb = pedb
|
|
259
402
|
self.setups = []
|
|
403
|
+
if self.pedb.grpc:
|
|
404
|
+
self.api = self.Grpc(self)
|
|
405
|
+
else:
|
|
406
|
+
self.api = self.DotNet(self)
|
|
260
407
|
for stp in setups_data:
|
|
261
408
|
if stp["type"].lower() == "hfss":
|
|
262
409
|
self.setups.append(CfgHFSSSetup(self.pedb, None, **stp))
|
|
@@ -273,17 +420,4 @@ class CfgSetups:
|
|
|
273
420
|
return [i.to_dict() for i in self.setups]
|
|
274
421
|
|
|
275
422
|
def retrieve_parameters_from_edb(self):
|
|
276
|
-
self.
|
|
277
|
-
for _, setup in self.pedb.setups.items():
|
|
278
|
-
if setup.type == "hfss":
|
|
279
|
-
hfss = CfgHFSSSetup(self.pedb, setup)
|
|
280
|
-
hfss.api.retrieve_parameters_from_edb()
|
|
281
|
-
self.setups.append(hfss)
|
|
282
|
-
elif setup.type == "siwave_dc":
|
|
283
|
-
siwave_dc = CfgSIwaveDCSetup(self.pedb, setup)
|
|
284
|
-
siwave_dc.api.retrieve_parameters_from_edb()
|
|
285
|
-
self.setups.append(siwave_dc)
|
|
286
|
-
elif setup.type == "siwave_ac":
|
|
287
|
-
siwave_ac = CfgSIwaveACSetup(self.pedb, setup)
|
|
288
|
-
siwave_ac.api.retrieve_parameters_from_edb()
|
|
289
|
-
self.setups.append(siwave_ac)
|
|
423
|
+
self.api.retrieve_parameters_from_edb()
|
|
@@ -164,6 +164,50 @@ class CfgStackup:
|
|
|
164
164
|
def __init__(self, parent):
|
|
165
165
|
super().__init__(parent)
|
|
166
166
|
|
|
167
|
+
def __apply_layers(self):
|
|
168
|
+
"""Apply layer settings to the current design"""
|
|
169
|
+
layers = list()
|
|
170
|
+
layers.extend(self.parent.layers)
|
|
171
|
+
|
|
172
|
+
removal_list = []
|
|
173
|
+
lc_signal_layers = []
|
|
174
|
+
for name, obj in self._pedb.stackup.all_layers.items():
|
|
175
|
+
if obj.type == "dielectric":
|
|
176
|
+
removal_list.append(name)
|
|
177
|
+
elif obj.type == "signal":
|
|
178
|
+
lc_signal_layers.append(obj.id)
|
|
179
|
+
for l in removal_list:
|
|
180
|
+
self._pedb.stackup.remove_layer(l)
|
|
181
|
+
|
|
182
|
+
# update all signal layers
|
|
183
|
+
id_name = {i[0]: i[1] for i in self._pedb.stackup.layers_by_id}
|
|
184
|
+
signal_idx = 0
|
|
185
|
+
for l in layers:
|
|
186
|
+
if l.type == "signal":
|
|
187
|
+
layer_id = lc_signal_layers[signal_idx]
|
|
188
|
+
layer_name = id_name[layer_id]
|
|
189
|
+
attrs = l.get_attributes()
|
|
190
|
+
self._pedb.stackup.layers[layer_name].update(**attrs)
|
|
191
|
+
signal_idx = signal_idx + 1
|
|
192
|
+
|
|
193
|
+
# add all dielectric layers. Dielectric layers must be added last. Otherwise,
|
|
194
|
+
# dielectric layer will occupy signal and document layer id.
|
|
195
|
+
prev_layer_clone = None
|
|
196
|
+
l = layers.pop(0)
|
|
197
|
+
if l.type == "signal":
|
|
198
|
+
prev_layer_clone = self._pedb.stackup.layers[l.name]
|
|
199
|
+
else:
|
|
200
|
+
attrs = l.get_attributes()
|
|
201
|
+
prev_layer_clone = self._pedb.stackup.add_layer_top(**attrs)
|
|
202
|
+
for idx, l in enumerate(layers):
|
|
203
|
+
if l.type == "dielectric":
|
|
204
|
+
attrs = l.get_attributes()
|
|
205
|
+
prev_layer_clone = self._pedb.stackup.add_layer_below(
|
|
206
|
+
base_layer_name=prev_layer_clone.name, **attrs
|
|
207
|
+
)
|
|
208
|
+
elif l.type == "signal":
|
|
209
|
+
prev_layer_clone = self._pedb.stackup.layers[l.name]
|
|
210
|
+
|
|
167
211
|
def __init__(self, pedb: Edb, data):
|
|
168
212
|
self._pedb = pedb
|
|
169
213
|
if self._pedb.grpc:
|
|
@@ -205,6 +205,8 @@ class Configuration:
|
|
|
205
205
|
self.parent.cfg_data.components.retrieve_parameters_from_edb()
|
|
206
206
|
components = []
|
|
207
207
|
for i in self.parent.cfg_data.components.components:
|
|
208
|
+
if i.type == "io":
|
|
209
|
+
components.append(i.get_attributes())
|
|
208
210
|
components.append(i.get_attributes())
|
|
209
211
|
|
|
210
212
|
if kwargs.get("components", False):
|
|
@@ -306,6 +308,14 @@ class Configuration:
|
|
|
306
308
|
file_path = file_path if isinstance(file_path, Path) else Path(file_path)
|
|
307
309
|
file_path = file_path.with_suffix(".json") if file_path.suffix == "" else file_path
|
|
308
310
|
|
|
311
|
+
for comp in data["components"]:
|
|
312
|
+
for key, value in comp.items():
|
|
313
|
+
try:
|
|
314
|
+
json.dumps(value)
|
|
315
|
+
print(f"Key '{key}' is serializable.")
|
|
316
|
+
except TypeError as e:
|
|
317
|
+
print(f"Key '{key}' failed: {e}")
|
|
318
|
+
|
|
309
319
|
with open(file_path, "w") as f:
|
|
310
320
|
if file_path.suffix == ".json":
|
|
311
321
|
json.dump(data, f, ensure_ascii=False, indent=4)
|
|
@@ -472,9 +482,6 @@ class Configuration:
|
|
|
472
482
|
# Configure package definitions
|
|
473
483
|
self.cfg_data.package_definitions.apply()
|
|
474
484
|
|
|
475
|
-
# Configure operations
|
|
476
|
-
self.cfg_data.operations.apply()
|
|
477
|
-
|
|
478
485
|
# Modeler
|
|
479
486
|
self.cfg_data.modeler.apply()
|
|
480
487
|
|
|
@@ -484,6 +491,9 @@ class Configuration:
|
|
|
484
491
|
# Configure probes
|
|
485
492
|
self.cfg_data.probes.apply()
|
|
486
493
|
|
|
494
|
+
# Configure operations
|
|
495
|
+
self.cfg_data.operations.apply()
|
|
496
|
+
|
|
487
497
|
return True
|
|
488
498
|
|
|
489
499
|
def _load_stackup(self):
|
|
@@ -341,6 +341,18 @@ class Path(Primitive):
|
|
|
341
341
|
polygon_data = self._edb.geometry.polygon_data.dotnetobj(convert_py_list_to_net_list(points), False)
|
|
342
342
|
self._edb_object.SetCenterLine(polygon_data)
|
|
343
343
|
|
|
344
|
+
def get_center_line_polygon_data(self):
|
|
345
|
+
"""Gets center lines of the path as a PolygonData object."""
|
|
346
|
+
edb_object = self._edb_object.GetCenterLine()
|
|
347
|
+
return self._pedb.pedb_class.database.geometry.polygon_data.PolygonData(self._pedb, edb_object=edb_object)
|
|
348
|
+
|
|
349
|
+
def set_center_line_polygon_data(self, polygon_data):
|
|
350
|
+
"""Sets center lines of the path from a PolygonData object."""
|
|
351
|
+
if not self._edb_object.SetCenterLine(polygon_data._edb_object):
|
|
352
|
+
raise ValueError
|
|
353
|
+
else:
|
|
354
|
+
return True
|
|
355
|
+
|
|
344
356
|
@property
|
|
345
357
|
def corner_style(self):
|
|
346
358
|
""":class:`PathCornerType`: Path's corner style."""
|
|
@@ -19,6 +19,7 @@
|
|
|
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
|
+
import warnings
|
|
22
23
|
|
|
23
24
|
|
|
24
25
|
class EdbDesignOptions:
|
|
@@ -51,8 +52,25 @@ class EdbDesignOptions:
|
|
|
51
52
|
``True`` if antipad is always on, ``False`` otherwise.
|
|
52
53
|
|
|
53
54
|
"""
|
|
54
|
-
|
|
55
|
+
warnings.warn("Use new property :func:`anti_pads_always_on` instead.", DeprecationWarning)
|
|
56
|
+
return self.anti_pads_always_on
|
|
55
57
|
|
|
56
58
|
@antipads_always_on.setter
|
|
57
59
|
def antipads_always_on(self, value):
|
|
60
|
+
self.anti_pads_always_on = value
|
|
61
|
+
|
|
62
|
+
@property
|
|
63
|
+
def anti_pads_always_on(self):
|
|
64
|
+
"""Whether to always turn on antipad.
|
|
65
|
+
|
|
66
|
+
Returns
|
|
67
|
+
-------
|
|
68
|
+
bool
|
|
69
|
+
``True`` if antipad is always on, ``False`` otherwise.
|
|
70
|
+
|
|
71
|
+
"""
|
|
72
|
+
return self._active_cell.GetAntiPadsAlwaysOn()
|
|
73
|
+
|
|
74
|
+
@anti_pads_always_on.setter
|
|
75
|
+
def anti_pads_always_on(self, value):
|
|
58
76
|
self._active_cell.SetAntiPadsAlwaysOn(value)
|
|
@@ -35,6 +35,7 @@ from pyedb.dotnet.database.general import (
|
|
|
35
35
|
snake_to_pascal,
|
|
36
36
|
)
|
|
37
37
|
from pyedb.dotnet.database.geometry.polygon_data import PolygonData
|
|
38
|
+
from pyedb.generic.data_handlers import float_units
|
|
38
39
|
from pyedb.generic.general_methods import generate_unique_name
|
|
39
40
|
from pyedb.modeler.geometry_operators import GeometryOperators
|
|
40
41
|
|
|
@@ -1958,15 +1959,18 @@ class EDBPadstackInstance(Primitive):
|
|
|
1958
1959
|
pad_shape = padstack_pad.geometry_type
|
|
1959
1960
|
params = padstack_pad.parameters_values
|
|
1960
1961
|
polygon_data = padstack_pad._polygon_data_dotnet
|
|
1962
|
+
pad_offset = [float_units(padstack_pad.offset_x), float_units(padstack_pad.offset_y)]
|
|
1961
1963
|
|
|
1962
1964
|
def _rotate(p):
|
|
1963
1965
|
x = p[0] * math.cos(rotation) - p[1] * math.sin(rotation)
|
|
1964
1966
|
y = p[0] * math.sin(rotation) + p[1] * math.cos(rotation)
|
|
1965
1967
|
return [x, y]
|
|
1966
1968
|
|
|
1967
|
-
def _translate(p):
|
|
1968
|
-
|
|
1969
|
-
|
|
1969
|
+
def _translate(p, t=None):
|
|
1970
|
+
if t is None:
|
|
1971
|
+
t = padstack_center
|
|
1972
|
+
x = p[0] + t[0]
|
|
1973
|
+
y = p[1] + t[1]
|
|
1970
1974
|
return [x, y]
|
|
1971
1975
|
|
|
1972
1976
|
rect = None
|
|
@@ -2092,7 +2096,8 @@ class EDBPadstackInstance(Primitive):
|
|
|
2092
2096
|
|
|
2093
2097
|
if rect is None or len(rect) != 4:
|
|
2094
2098
|
return False
|
|
2095
|
-
|
|
2099
|
+
offset_rect = [_translate(p, _rotate(pad_offset)) for p in rect]
|
|
2100
|
+
path = self._pedb.modeler.Shape("polygon", points=offset_rect)
|
|
2096
2101
|
pdata = self._pedb.modeler.shape_to_polygon_data(path)
|
|
2097
2102
|
new_rect = []
|
|
2098
2103
|
for point in pdata.Points:
|
|
@@ -35,3 +35,29 @@ class PointData:
|
|
|
35
35
|
self._pedb.edb_value(x),
|
|
36
36
|
self._pedb.edb_value(y),
|
|
37
37
|
)
|
|
38
|
+
|
|
39
|
+
@property
|
|
40
|
+
def x(self):
|
|
41
|
+
"""X value of point."""
|
|
42
|
+
return self._edb_object.X.ToString()
|
|
43
|
+
|
|
44
|
+
@x.setter
|
|
45
|
+
def x(self, value):
|
|
46
|
+
self._edb_object.X = self._pedb.edb_value(value)
|
|
47
|
+
|
|
48
|
+
@property
|
|
49
|
+
def x_evaluated(self):
|
|
50
|
+
return self._edb_object.X.ToDouble()
|
|
51
|
+
|
|
52
|
+
@property
|
|
53
|
+
def y(self):
|
|
54
|
+
"""Y value of point."""
|
|
55
|
+
return self._edb_object.Y.ToString()
|
|
56
|
+
|
|
57
|
+
@y.setter
|
|
58
|
+
def y(self, value):
|
|
59
|
+
self._edb_object.Y = self._pedb.edb_value(value)
|
|
60
|
+
|
|
61
|
+
@property
|
|
62
|
+
def y_evaluated(self):
|
|
63
|
+
return self._edb_object.Y.ToDouble()
|
|
@@ -89,8 +89,10 @@ class PolygonData:
|
|
|
89
89
|
def create_from_points(self, points, closed=True):
|
|
90
90
|
list_of_point_data = []
|
|
91
91
|
for pt in points:
|
|
92
|
-
list_of_point_data.append(PointData(self._pedb, x=pt[0], y=pt[1]))
|
|
93
|
-
return self._pedb.edb_api.geometry.api_class.PolygonData(
|
|
92
|
+
list_of_point_data.append(PointData(self._pedb, x=pt[0], y=pt[1])._edb_object)
|
|
93
|
+
return self._pedb.edb_api.geometry.api_class.PolygonData(
|
|
94
|
+
convert_py_list_to_net_list(list_of_point_data), closed
|
|
95
|
+
)
|
|
94
96
|
|
|
95
97
|
def create_from_bounding_box(self, points):
|
|
96
98
|
bbox = BBox(self._pedb, point_1=points[0], point_2=points[1])
|
|
@@ -133,3 +135,12 @@ class PolygonData:
|
|
|
133
135
|
def point_in_polygon(self, x: Union[str, float], y: Union[str, float]) -> bool:
|
|
134
136
|
"""Determines whether a point is inside the polygon."""
|
|
135
137
|
return self._edb_object.PointInPolygon(self._pedb.point_data(x, y))
|
|
138
|
+
|
|
139
|
+
def get_point(self, index):
|
|
140
|
+
"""Gets the point at the index as a PointData object."""
|
|
141
|
+
edb_object = self._edb_object.GetPoint(index)
|
|
142
|
+
return self._pedb.pedb_class.database.geometry.point_data.PointData(self._pedb, edb_object)
|
|
143
|
+
|
|
144
|
+
def set_point(self, index, point_data):
|
|
145
|
+
"""Sets the point at the index from a PointData object."""
|
|
146
|
+
self._edb_object.SetPoint(index, point_data)
|
pyedb/dotnet/database/nets.py
CHANGED
|
@@ -308,11 +308,21 @@ class EdbNets(CommonNets):
|
|
|
308
308
|
val_value = cmp.rlc_values
|
|
309
309
|
if refdes in exception_list:
|
|
310
310
|
pass
|
|
311
|
-
elif
|
|
311
|
+
elif (
|
|
312
|
+
val_type == "Inductor"
|
|
313
|
+
and self._pedb.edb_value(val_value[1]).ToDouble() <= self._pedb.edb_value(inductor_below).ToDouble()
|
|
314
|
+
):
|
|
312
315
|
pass
|
|
313
|
-
elif
|
|
316
|
+
elif (
|
|
317
|
+
val_type == "Resistor"
|
|
318
|
+
and self._pedb.edb_value(val_value[0]).ToDouble() <= self._pedb.edb_value(resistor_below).ToDouble()
|
|
319
|
+
):
|
|
314
320
|
pass
|
|
315
|
-
elif
|
|
321
|
+
elif (
|
|
322
|
+
val_type == "Capacitor"
|
|
323
|
+
and self._pedb.edb_value(val_value[2]).ToDouble()
|
|
324
|
+
>= self._pedb.edb_value(capacitor_above).ToDouble()
|
|
325
|
+
):
|
|
316
326
|
pass
|
|
317
327
|
else:
|
|
318
328
|
continue
|
|
@@ -1153,7 +1153,7 @@ class EdbPadstacks(object):
|
|
|
1153
1153
|
Name of the net. The default is ``""``.
|
|
1154
1154
|
via_name : str, optional
|
|
1155
1155
|
The default is ``""``.
|
|
1156
|
-
rotation : float, optional
|
|
1156
|
+
rotation : float, str, optional
|
|
1157
1157
|
Rotation of the padstack in degrees. The default
|
|
1158
1158
|
is ``0``.
|
|
1159
1159
|
fromlayer :
|
|
@@ -1175,7 +1175,11 @@ class EdbPadstacks(object):
|
|
|
1175
1175
|
padstack = self.definitions[pad].edb_padstack
|
|
1176
1176
|
position = self._edb.geometry.point_data(position[0], position[1])
|
|
1177
1177
|
net = self._pedb.nets.find_or_create_net(net_name)
|
|
1178
|
-
rotation =
|
|
1178
|
+
rotation = (
|
|
1179
|
+
self._get_edb_value(rotation * math.pi / 180)
|
|
1180
|
+
if not isinstance(rotation, str)
|
|
1181
|
+
else self._get_edb_value(rotation)
|
|
1182
|
+
)
|
|
1179
1183
|
sign_layers_values = {i: v for i, v in self._pedb.stackup.signal_layers.items()}
|
|
1180
1184
|
sign_layers = list(sign_layers_values.keys())
|
|
1181
1185
|
if not fromlayer:
|
|
@@ -96,8 +96,6 @@ class SimulationSetup(object):
|
|
|
96
96
|
if self._edb_object:
|
|
97
97
|
self._name = self._edb_object.GetName()
|
|
98
98
|
|
|
99
|
-
self._sweep_list = {}
|
|
100
|
-
|
|
101
99
|
@property
|
|
102
100
|
def sim_setup_info(self):
|
|
103
101
|
return SimSetupInfo(self._pedb, sim_setup=self, edb_object=self._edb_object.GetSimSetupInfo())
|
|
@@ -239,7 +237,7 @@ class SimulationSetup(object):
|
|
|
239
237
|
"""List of frequency sweeps."""
|
|
240
238
|
return {i.name: i for i in self.sim_setup_info.sweep_data_list}
|
|
241
239
|
|
|
242
|
-
def add_sweep(self, name, frequency_set: list = None, sweep_type: str = "interpolation", **kwargs):
|
|
240
|
+
def add_sweep(self, name: str = None, frequency_set: list = None, sweep_type: str = "interpolation", **kwargs):
|
|
243
241
|
"""Add frequency sweep.
|
|
244
242
|
|
|
245
243
|
Parameters
|
|
@@ -292,15 +290,7 @@ class SimulationSetup(object):
|
|
|
292
290
|
sweep_data: SweepData
|
|
293
291
|
"""
|
|
294
292
|
warnings.warn("Use new property :func:`add_sweep_data` instead.", DeprecationWarning)
|
|
295
|
-
self.
|
|
296
|
-
edb_setup_info = self.sim_setup_info
|
|
297
|
-
|
|
298
|
-
if self._setup_type in ["kSIwave", "kHFSS", "kRaptorX", "kHFSSPI"]:
|
|
299
|
-
for _, v in self._sweep_list.items():
|
|
300
|
-
edb_setup_info.SweepDataList.Add(v._edb_object)
|
|
301
|
-
|
|
302
|
-
self._edb_object = self._set_edb_setup_info(edb_setup_info)
|
|
303
|
-
self._update_setup()
|
|
293
|
+
return self.sim_setup_info.add_sweep_data(sweep_data)
|
|
304
294
|
|
|
305
295
|
def delete_frequency_sweep(self, sweep_data):
|
|
306
296
|
"""Delete a frequency sweep.
|
|
@@ -310,17 +300,17 @@ class SimulationSetup(object):
|
|
|
310
300
|
sweep_data : EdbFrequencySweep.
|
|
311
301
|
"""
|
|
312
302
|
name = sweep_data.name
|
|
313
|
-
if name in self.
|
|
314
|
-
self.
|
|
303
|
+
if name in self.sweeps:
|
|
304
|
+
self.sweeps.pop(name)
|
|
315
305
|
|
|
316
306
|
fsweep = []
|
|
317
|
-
if self.
|
|
318
|
-
fsweep = [val for key, val in self.
|
|
307
|
+
if self.sweeps:
|
|
308
|
+
fsweep = [val for key, val in self.sweeps.items() if not key == name]
|
|
319
309
|
self.sim_setup_info._edb_object.SweepDataList.Clear()
|
|
320
310
|
for i in fsweep:
|
|
321
311
|
self.sim_setup_info._edb_object.SweepDataList.Add(i._edb_object)
|
|
322
312
|
self._update_setup()
|
|
323
|
-
return
|
|
313
|
+
return False if name in self.sweeps else True
|
|
324
314
|
|
|
325
315
|
def add_frequency_sweep(self, name=None, frequency_sweep=None):
|
|
326
316
|
"""Add frequency sweep.
|
|
@@ -95,6 +95,8 @@ class SiwaveSimulationSetup(SimulationSetup):
|
|
|
95
95
|
self._edb_object = self._simulation_setup_builder(sim_setup_info._edb_object)
|
|
96
96
|
self._update_setup()
|
|
97
97
|
|
|
98
|
+
self._siwave_sweeps_list = []
|
|
99
|
+
|
|
98
100
|
def create(self, name=None):
|
|
99
101
|
"""Create a SIwave SYZ setup.
|
|
100
102
|
|
|
@@ -248,6 +250,34 @@ class SiwaveSimulationSetup(SimulationSetup):
|
|
|
248
250
|
self._edb_object = self._set_edb_setup_info(edb_setup_info)
|
|
249
251
|
self._update_setup()
|
|
250
252
|
|
|
253
|
+
def add_sweep(self, name: str = None, frequency_set: list = None, sweep_type: str = "interpolation", **kwargs):
|
|
254
|
+
"""Add frequency sweep.
|
|
255
|
+
|
|
256
|
+
Parameters
|
|
257
|
+
----------
|
|
258
|
+
name : str, optional
|
|
259
|
+
Name of the frequency sweep. The default is ``None``.
|
|
260
|
+
frequency_set : list, optional
|
|
261
|
+
List of frequency points. The default is ``None``.
|
|
262
|
+
sweep_type : str, optional
|
|
263
|
+
Sweep type. The default is ``"interpolation"``. Options are ``"discrete"``,"discrete"``.
|
|
264
|
+
Returns
|
|
265
|
+
-------
|
|
266
|
+
|
|
267
|
+
Examples
|
|
268
|
+
--------
|
|
269
|
+
>>> setup1 = edbapp.create_siwave_syz_setup("setup1")
|
|
270
|
+
>>> setup1.add_sweep(name="sw1", frequency_set=["linear count", "1MHz", "100MHz", 10])
|
|
271
|
+
"""
|
|
272
|
+
sweep_data = SimulationSetup.add_sweep(self, name, frequency_set, sweep_type, **kwargs)
|
|
273
|
+
self._siwave_sweeps_list.append(sweep_data)
|
|
274
|
+
return sweep_data
|
|
275
|
+
|
|
276
|
+
@property
|
|
277
|
+
def sweeps(self):
|
|
278
|
+
"""List of frequency sweeps."""
|
|
279
|
+
return {i.name: i for i in self._siwave_sweeps_list}
|
|
280
|
+
|
|
251
281
|
|
|
252
282
|
class SiwaveDCSimulationSetup(SimulationSetup):
|
|
253
283
|
"""Manages EDB methods for SIwave DC simulation setup."""
|