pyedb 0.10.dev0__py3-none-any.whl → 0.11.2__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 +115 -0
- pyedb/configuration/cfg_components.py +205 -0
- pyedb/configuration/cfg_data.py +38 -15
- pyedb/configuration/cfg_general.py +34 -0
- pyedb/{dotnet/sim_setup_data/data/siw_dc_ir_settings.py → configuration/cfg_nets.py} +18 -21
- pyedb/configuration/cfg_padstacks.py +125 -0
- pyedb/configuration/cfg_pin_groups.py +58 -0
- pyedb/configuration/cfg_ports_sources.py +164 -0
- pyedb/configuration/cfg_s_parameter_models.py +60 -0
- pyedb/configuration/cfg_setup.py +201 -0
- pyedb/configuration/cfg_spice_models.py +49 -0
- pyedb/configuration/configuration.py +37 -532
- pyedb/dotnet/edb.py +37 -8
- pyedb/dotnet/edb_core/components.py +43 -0
- pyedb/dotnet/edb_core/edb_data/hfss_pi_simulation_setup_data.py +465 -0
- pyedb/dotnet/edb_core/edb_data/nets_data.py +6 -2
- pyedb/dotnet/edb_core/edb_data/padstacks_data.py +17 -1
- pyedb/dotnet/edb_core/edb_data/raptor_x_simulation_setup_data.py +0 -4
- pyedb/dotnet/edb_core/edb_data/siwave_simulation_setup_data.py +4 -2
- pyedb/dotnet/edb_core/edb_data/sources.py +21 -5
- pyedb/dotnet/edb_core/edb_data/terminals.py +2 -1
- pyedb/dotnet/edb_core/layout.py +13 -8
- pyedb/dotnet/edb_core/nets.py +7 -3
- pyedb/dotnet/edb_core/padstack.py +23 -3
- pyedb/dotnet/edb_core/sim_setup_data/__init__.py +3 -0
- pyedb/dotnet/edb_core/sim_setup_data/data/__init__.py +3 -0
- pyedb/dotnet/edb_core/sim_setup_data/data/siw_dc_ir_settings.py +235 -0
- pyedb/dotnet/edb_core/siwave.py +2 -1
- pyedb/dotnet/edb_core/stackup.py +45 -33
- pyedb/dotnet/edb_core/utilities/simulation_setup.py +21 -5
- pyedb/generic/plot.py +6 -5
- pyedb/siwave.py +32 -6
- pyedb/siwave_core/icepak.py +153 -0
- {pyedb-0.10.dev0.dist-info → pyedb-0.11.2.dist-info}/METADATA +6 -6
- {pyedb-0.10.dev0.dist-info → pyedb-0.11.2.dist-info}/RECORD +38 -25
- pyedb/configuration/cfg_ports.py +0 -149
- {pyedb-0.10.dev0.dist-info → pyedb-0.11.2.dist-info}/LICENSE +0 -0
- {pyedb-0.10.dev0.dist-info → pyedb-0.11.2.dist-info}/WHEEL +0 -0
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
# Copyright (C) 2023 - 2024 ANSYS, Inc. and/or its affiliates.
|
|
2
|
+
# SPDX-License-Identifier: MIT
|
|
3
|
+
#
|
|
4
|
+
#
|
|
5
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
# of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
# in the Software without restriction, including without limitation the rights
|
|
8
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
# copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
# furnished to do so, subject to the following conditions:
|
|
11
|
+
#
|
|
12
|
+
# The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
# copies or substantial portions of the Software.
|
|
14
|
+
#
|
|
15
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
# SOFTWARE.
|
|
22
|
+
|
|
23
|
+
from pyedb.generic.general_methods import pyedb_function_handler
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class CfgCircuitElement:
|
|
27
|
+
@property
|
|
28
|
+
def pedb(self):
|
|
29
|
+
"""Edb."""
|
|
30
|
+
return self._pdata.pedb
|
|
31
|
+
|
|
32
|
+
@pyedb_function_handler
|
|
33
|
+
def __init__(self, pdata, **kwargs):
|
|
34
|
+
self._pdata = pdata
|
|
35
|
+
self._data = kwargs
|
|
36
|
+
self.name = kwargs.get("name", None)
|
|
37
|
+
self.type = kwargs.get("type", None)
|
|
38
|
+
self.reference_designator = kwargs.get("reference_designator", None)
|
|
39
|
+
self.distributed = kwargs.get("distributed", False)
|
|
40
|
+
self.pos_term_info = kwargs.get("positive_terminal", None) # {"pin" : "A1"}
|
|
41
|
+
self.neg_term_info = kwargs.get("negative_terminal", None)
|
|
42
|
+
|
|
43
|
+
@pyedb_function_handler
|
|
44
|
+
def _create(self):
|
|
45
|
+
"""Create step 1."""
|
|
46
|
+
pos_term_info = self.pos_term_info
|
|
47
|
+
if pos_term_info:
|
|
48
|
+
pos_type, pos_value = [[i, j] for i, j in pos_term_info.items()][0]
|
|
49
|
+
pos_objs = dict()
|
|
50
|
+
if self.type == "coax":
|
|
51
|
+
pins = self._get_pins(pos_type, pos_value)
|
|
52
|
+
pins = {f"{self.name}_{self.reference_designator}": i for _, i in pins.items()}
|
|
53
|
+
pos_objs.update(pins)
|
|
54
|
+
elif pos_type == "pin_group":
|
|
55
|
+
pos_objs[pos_value] = self.pedb.siwave.pin_groups[pos_value]
|
|
56
|
+
elif not self.distributed:
|
|
57
|
+
# get pins
|
|
58
|
+
pins = self._get_pins(pos_type, pos_value) # terminal type pin or net
|
|
59
|
+
# create pin group
|
|
60
|
+
pin_group = self._create_pin_group(pins)
|
|
61
|
+
pos_objs.update(pin_group)
|
|
62
|
+
else:
|
|
63
|
+
# get pins
|
|
64
|
+
pins = self._get_pins(pos_type, pos_value) # terminal type pin or net or pin group
|
|
65
|
+
pos_objs.update(pins)
|
|
66
|
+
self._elem_num = len(pos_objs)
|
|
67
|
+
|
|
68
|
+
self.pos_terminals = {i: j.create_terminal(i) for i, j in pos_objs.items()}
|
|
69
|
+
|
|
70
|
+
neg_term_info = self.neg_term_info
|
|
71
|
+
self.neg_terminal = None
|
|
72
|
+
if neg_term_info:
|
|
73
|
+
neg_type, neg_value = [[i, j] for i, j in neg_term_info.items()][0]
|
|
74
|
+
if neg_type == "pin_group":
|
|
75
|
+
pin_group = {neg_value: self.pedb.siwave.pin_groups[neg_value]}
|
|
76
|
+
else:
|
|
77
|
+
# Get pins
|
|
78
|
+
pins = self._get_pins(neg_type, neg_value) # terminal type pin or net
|
|
79
|
+
# create pin group
|
|
80
|
+
pin_group = self._create_pin_group(pins, True)
|
|
81
|
+
self.neg_terminal = [j.create_terminal(i) if not j.terminal else j.terminal for i, j in pin_group.items()][
|
|
82
|
+
0
|
|
83
|
+
]
|
|
84
|
+
|
|
85
|
+
@pyedb_function_handler
|
|
86
|
+
def _get_pins(self, terminal_type, terminal_value):
|
|
87
|
+
terminal_value = terminal_value if isinstance(terminal_value, list) else [terminal_value]
|
|
88
|
+
|
|
89
|
+
def get_pin_obj(pin_name):
|
|
90
|
+
return {pin_name: self._pdata.edb_comps[self.reference_designator].pins[pin_name]}
|
|
91
|
+
|
|
92
|
+
pins = dict()
|
|
93
|
+
if terminal_type == "pin":
|
|
94
|
+
for i in terminal_value:
|
|
95
|
+
pins.update(get_pin_obj(i))
|
|
96
|
+
else:
|
|
97
|
+
if terminal_type == "net":
|
|
98
|
+
temp = self._pdata.pedb.components.get_pins(self.reference_designator, terminal_value[0])
|
|
99
|
+
elif terminal_type == "pin_group":
|
|
100
|
+
pin_group = self.pedb.siwave.pin_groups[terminal_value[0]]
|
|
101
|
+
temp = pin_group.pins
|
|
102
|
+
pins.update({f"{self.reference_designator}_{terminal_value[0]}_{i}": j for i, j in temp.items()})
|
|
103
|
+
return pins
|
|
104
|
+
|
|
105
|
+
@pyedb_function_handler
|
|
106
|
+
def _create_pin_group(self, pins, is_ref=False):
|
|
107
|
+
if is_ref:
|
|
108
|
+
pg_name = f"pg_{self.name}_{self.reference_designator}_ref"
|
|
109
|
+
else:
|
|
110
|
+
pg_name = f"pg_{self.name}_{self.reference_designator}"
|
|
111
|
+
pin_names = [i.pin_number for i in pins.values()]
|
|
112
|
+
name, temp = self._pdata.pedb.siwave.create_pin_group(self.reference_designator, pin_names, pg_name)
|
|
113
|
+
return {name: temp}
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
class CfgPort(CfgCircuitElement):
|
|
117
|
+
"""Manage port."""
|
|
118
|
+
|
|
119
|
+
CFG_PORT_TYPE = {"circuit": [str], "coax": [str]}
|
|
120
|
+
|
|
121
|
+
@pyedb_function_handler
|
|
122
|
+
def __init__(self, pdata, **kwargs):
|
|
123
|
+
super().__init__(pdata, **kwargs)
|
|
124
|
+
|
|
125
|
+
@pyedb_function_handler
|
|
126
|
+
def create(self):
|
|
127
|
+
"""Create port."""
|
|
128
|
+
self._create()
|
|
129
|
+
is_circuit_port = True if self.type == "circuit" else False
|
|
130
|
+
circuit_elements = []
|
|
131
|
+
for _, j in self.pos_terminals.items():
|
|
132
|
+
elem = self.pedb.create_port(j, self.neg_terminal, is_circuit_port)
|
|
133
|
+
if not self.distributed:
|
|
134
|
+
elem.name = self.name
|
|
135
|
+
circuit_elements.append(elem)
|
|
136
|
+
return circuit_elements
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
class CfgSources(CfgCircuitElement):
|
|
140
|
+
CFG_SOURCE_TYPE = {"current": [int, float], "voltage": [int, float]}
|
|
141
|
+
|
|
142
|
+
@pyedb_function_handler
|
|
143
|
+
def __init__(self, pdata, **kwargs):
|
|
144
|
+
super().__init__(pdata, **kwargs)
|
|
145
|
+
|
|
146
|
+
self.magnitude = kwargs.get("magnitude", 0.001)
|
|
147
|
+
|
|
148
|
+
@pyedb_function_handler
|
|
149
|
+
def create(self):
|
|
150
|
+
"""Create sources."""
|
|
151
|
+
self._create()
|
|
152
|
+
is_circuit_port = True if self.type == "circuit" else False
|
|
153
|
+
circuit_elements = []
|
|
154
|
+
method = self.pedb.create_current_source if self.type == "current" else self.pedb.create_voltage_source
|
|
155
|
+
for _, j in self.pos_terminals.items():
|
|
156
|
+
elem = method(j, self.neg_terminal)
|
|
157
|
+
if not self.distributed:
|
|
158
|
+
elem.name = self.name
|
|
159
|
+
elem.magnitude = self.magnitude
|
|
160
|
+
else:
|
|
161
|
+
elem.name = f"{self.name}_{elem.name}"
|
|
162
|
+
elem.magnitude = self.magnitude / self._elem_num
|
|
163
|
+
circuit_elements.append(elem)
|
|
164
|
+
return circuit_elements
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# Copyright (C) 2023 - 2024 ANSYS, Inc. and/or its affiliates.
|
|
2
|
+
# SPDX-License-Identifier: MIT
|
|
3
|
+
#
|
|
4
|
+
#
|
|
5
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
# of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
# in the Software without restriction, including without limitation the rights
|
|
8
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
# copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
# furnished to do so, subject to the following conditions:
|
|
11
|
+
#
|
|
12
|
+
# The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
# copies or substantial portions of the Software.
|
|
14
|
+
#
|
|
15
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
# SOFTWARE.
|
|
22
|
+
|
|
23
|
+
from pathlib import Path
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class CfgSParameterModel:
|
|
27
|
+
def __init__(self, pdata, path_lib, sparam_dict):
|
|
28
|
+
self._pedb = pdata.pedb
|
|
29
|
+
self.path_libraries = path_lib
|
|
30
|
+
self._sparam_dict = sparam_dict
|
|
31
|
+
self.name = self._sparam_dict.get("name", "")
|
|
32
|
+
self.component_definition = self._sparam_dict.get("component_definition", "")
|
|
33
|
+
self.file_path = self._sparam_dict.get("file_path", "")
|
|
34
|
+
self.apply_to_all = self._sparam_dict.get("apply_to_all", False)
|
|
35
|
+
self.components = self._sparam_dict.get("components", [])
|
|
36
|
+
self.reference_net = self._sparam_dict.get("reference_net", "")
|
|
37
|
+
self.reference_net_per_component = self._sparam_dict.get("reference_net_per_component", {})
|
|
38
|
+
|
|
39
|
+
def apply(self):
|
|
40
|
+
fpath = self.file_path
|
|
41
|
+
if not Path(fpath).anchor:
|
|
42
|
+
fpath = str(Path(self.path_libraries) / fpath)
|
|
43
|
+
comp_def = self._pedb.definitions.component[self.component_definition]
|
|
44
|
+
comp_def.add_n_port_model(fpath, self.name)
|
|
45
|
+
comp_list = dict()
|
|
46
|
+
if self.apply_to_all:
|
|
47
|
+
comp_list.update(
|
|
48
|
+
{refdes: comp for refdes, comp in comp_def.components.items() if refdes not in self.components}
|
|
49
|
+
)
|
|
50
|
+
else:
|
|
51
|
+
comp_list.update(
|
|
52
|
+
{refdes: comp for refdes, comp in comp_def.components.items() if refdes in self.components}
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
for refdes, comp in comp_list.items():
|
|
56
|
+
if refdes in self.reference_net_per_component:
|
|
57
|
+
ref_net = self.reference_net_per_component[refdes]
|
|
58
|
+
else:
|
|
59
|
+
ref_net = self.reference_net
|
|
60
|
+
comp.use_s_parameter_model(self.name, reference_net=ref_net)
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
# Copyright (C) 2023 - 2024 ANSYS, Inc. and/or its affiliates.
|
|
2
|
+
# SPDX-License-Identifier: MIT
|
|
3
|
+
#
|
|
4
|
+
#
|
|
5
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
# of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
# in the Software without restriction, including without limitation the rights
|
|
8
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
# copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
# furnished to do so, subject to the following conditions:
|
|
11
|
+
#
|
|
12
|
+
# The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
# copies or substantial portions of the Software.
|
|
14
|
+
#
|
|
15
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
# SOFTWARE.
|
|
22
|
+
|
|
23
|
+
from enum import Enum
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class FrequencySweep:
|
|
27
|
+
def __init__(self, sweep_dict=None):
|
|
28
|
+
self._sweep_dict = sweep_dict
|
|
29
|
+
self.name = "PyEDB_sweep"
|
|
30
|
+
self.type = self.SweepType.INTERPOLATING
|
|
31
|
+
self.distribution = [self.Distribution()]
|
|
32
|
+
if sweep_dict:
|
|
33
|
+
self.name = self._sweep_dict.get("name", "PyEDB_sweep")
|
|
34
|
+
frequencies = self._sweep_dict.get("frequencies", None)
|
|
35
|
+
self._map_sweep_type()
|
|
36
|
+
self.distribution = [self.Distribution(dist) for dist in frequencies]
|
|
37
|
+
|
|
38
|
+
class SweepType(Enum):
|
|
39
|
+
INTERPOLATING = 0
|
|
40
|
+
DISCRETE = 1
|
|
41
|
+
|
|
42
|
+
class Distribution:
|
|
43
|
+
def __init__(self, distribution_dict=None):
|
|
44
|
+
self.type = self.DistributionType.LINEAR_STEP
|
|
45
|
+
self.start = "0GHz"
|
|
46
|
+
self.stop = "10GHz"
|
|
47
|
+
self.step = "10MHz"
|
|
48
|
+
self.count = 100
|
|
49
|
+
if distribution_dict:
|
|
50
|
+
self.map(distribution_dict)
|
|
51
|
+
|
|
52
|
+
class DistributionType(Enum):
|
|
53
|
+
LINEAR_STEP = 0
|
|
54
|
+
LINEAR_COUNT = 1
|
|
55
|
+
LOG_SCALE = 2
|
|
56
|
+
|
|
57
|
+
def map(self, distribution_dict):
|
|
58
|
+
distribution_type = distribution_dict.get("distribution", "linear step")
|
|
59
|
+
if distribution_type == "linear step":
|
|
60
|
+
self.type = self.DistributionType.LINEAR_STEP
|
|
61
|
+
elif distribution_type == "linear count":
|
|
62
|
+
self.type = self.DistributionType.LINEAR_COUNT
|
|
63
|
+
elif distribution_type == "log scale":
|
|
64
|
+
self.type = self.DistributionType.LOG_SCALE
|
|
65
|
+
else:
|
|
66
|
+
self.type = self.DistributionType.LINEAR_STEP
|
|
67
|
+
self.start = distribution_dict.get("start", "OGHz")
|
|
68
|
+
self.stop = distribution_dict.get("stop", "10GHz")
|
|
69
|
+
self.step = distribution_dict.get("step", "10MHz")
|
|
70
|
+
self.count = distribution_dict.get("count", 100)
|
|
71
|
+
|
|
72
|
+
def _map_sweep_type(self):
|
|
73
|
+
if self._sweep_dict.get("type", "discrete"):
|
|
74
|
+
self.type = self.SweepType.DISCRETE
|
|
75
|
+
else:
|
|
76
|
+
self.type = self.SweepType.INTERPOLATING
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
class CfgDcSetup:
|
|
80
|
+
def __init__(self):
|
|
81
|
+
self.dc_slider_position = 1
|
|
82
|
+
self.dcir_settings = DcIrSettings()
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
class DcIrSettings:
|
|
86
|
+
def __init__(self):
|
|
87
|
+
self.export_dc_thermal_data = True
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
class CfgSetup:
|
|
91
|
+
def __init__(self, pdata, setup_dict=None):
|
|
92
|
+
self._pedb = pdata.pedb
|
|
93
|
+
self._setup_dict = None
|
|
94
|
+
self.name = "PyEDB_setup"
|
|
95
|
+
self.type = self.SetupType.HFSS
|
|
96
|
+
self.f_adapt = "5GHz"
|
|
97
|
+
self.max_num_passes = 30
|
|
98
|
+
self.max_mag_delta_s = 0.02
|
|
99
|
+
self.sweeps = [FrequencySweep()]
|
|
100
|
+
self.dc_settings = CfgDcSetup()
|
|
101
|
+
self.si_slider_position = 1
|
|
102
|
+
self.pi_slider_position = 1
|
|
103
|
+
if setup_dict:
|
|
104
|
+
self._setup_dict = setup_dict
|
|
105
|
+
self.name = setup_dict.get("name", "PyEDB_setup")
|
|
106
|
+
self._map_setup_type(setup_dict.get("type", None))
|
|
107
|
+
self.f_adapt = setup_dict.get("f_adapt", "5GHz")
|
|
108
|
+
self.max_mag_delta_s = setup_dict.get("max_mag_delta_s", 0.02)
|
|
109
|
+
if setup_dict.get("freq_sweep", None):
|
|
110
|
+
self.sweeps = [FrequencySweep(sweep) for sweep in setup_dict.get("freq_sweep", None)]
|
|
111
|
+
else:
|
|
112
|
+
self.sweeps = []
|
|
113
|
+
self.dc_settings.dc_slider_position = setup_dict.get("dc_slider_position", 1)
|
|
114
|
+
if setup_dict.get("dc_ir_settings", None):
|
|
115
|
+
dc_ir_dict = setup_dict.get("dc_ir_settings")
|
|
116
|
+
self.dc_settings.dcir_settings.export_dc_thermal_data = dc_ir_dict.get("export_dc_thermal_data", True)
|
|
117
|
+
|
|
118
|
+
def _map_setup_type(self, setup_type):
|
|
119
|
+
if setup_type.upper() == "HFSS":
|
|
120
|
+
self.type = self.SetupType.HFSS
|
|
121
|
+
elif setup_type.upper() == "HFSS_PI":
|
|
122
|
+
self.type = self.SetupType.HFSS_PI
|
|
123
|
+
elif setup_type.upper() == "SIWAVE_SYZ":
|
|
124
|
+
self.type = self.SetupType.SIWAVE_SYZ
|
|
125
|
+
elif setup_type.upper() == "SIWAVE_DC":
|
|
126
|
+
self.type = self.SetupType.SIWAVE_DC
|
|
127
|
+
elif setup_type.upper() == "RAPTORX":
|
|
128
|
+
self.type = self.SetupType.RAPTORX
|
|
129
|
+
elif setup_type.upper() == "Q3D":
|
|
130
|
+
self.type = self.SetupType.Q3D
|
|
131
|
+
else:
|
|
132
|
+
self.type = self.SetupType.HFSS
|
|
133
|
+
|
|
134
|
+
class SetupType(Enum):
|
|
135
|
+
HFSS = 0
|
|
136
|
+
SIWAVE_SYZ = 1
|
|
137
|
+
SIWAVE_DC = 2
|
|
138
|
+
HFSS_PI = 3
|
|
139
|
+
RAPTORX = 4
|
|
140
|
+
Q3D = 5
|
|
141
|
+
|
|
142
|
+
def apply(self):
|
|
143
|
+
edb_setup = None
|
|
144
|
+
if self.type == self.SetupType.SIWAVE_DC:
|
|
145
|
+
if self.name not in self._pedb.setups:
|
|
146
|
+
edb_setup = self._pedb.create_siwave_dc_setup(self.name)
|
|
147
|
+
self._pedb.logger.info("Setup {} created.".format(self.name))
|
|
148
|
+
else:
|
|
149
|
+
self._pedb.logger.warning("Setup {} already existing. Editing it.".format(self.name))
|
|
150
|
+
edb_setup = self._pedb.setups[self.name]
|
|
151
|
+
edb_setup.set_dc_slider(self.dc_settings.dc_slider_position)
|
|
152
|
+
# TODO add DCIR settings in EDB setup
|
|
153
|
+
elif self.type == self.SetupType.HFSS:
|
|
154
|
+
if self.name not in self._pedb.setups:
|
|
155
|
+
edb_setup = self._pedb.create_hfss_setup(self.name)
|
|
156
|
+
self._pedb.logger.info("Setup {} created.".format(self.name))
|
|
157
|
+
else:
|
|
158
|
+
self._pedb.logger.warning("Setup {} already existing. Editing it.".format(self.name))
|
|
159
|
+
edb_setup = self._pedb.setups[self.name]
|
|
160
|
+
if not edb_setup.set_solution_single_frequency(self.f_adapt, self.max_num_passes, self.max_mag_delta_s):
|
|
161
|
+
self._pedb.logger.errur(f"Failed to create HFSS simulation setup {self.name}")
|
|
162
|
+
elif self.type == self.SetupType.SIWAVE_SYZ:
|
|
163
|
+
if self.name not in self._pedb.setups:
|
|
164
|
+
edb_setup = self._pedb.create_siwave_syz_setup(self.name)
|
|
165
|
+
self._pedb.logger.info("Setup {} created.".format(self.name))
|
|
166
|
+
else:
|
|
167
|
+
self._pedb.logger.warning("Setup {} already existing. Editing it.".format(self.name))
|
|
168
|
+
edb_setup = self._pedb.setups[self.name]
|
|
169
|
+
edb_setup.si_slider_position = self.si_slider_position
|
|
170
|
+
edb_setup.pi_slider_position = self.pi_slider_position
|
|
171
|
+
for sweep in self.sweeps:
|
|
172
|
+
for dist in sweep.distribution:
|
|
173
|
+
freqs = []
|
|
174
|
+
if dist.type == dist.DistributionType.LINEAR_STEP:
|
|
175
|
+
freqs.append(
|
|
176
|
+
[
|
|
177
|
+
"linear scale",
|
|
178
|
+
self._pedb.edb_value(dist.start).ToString(),
|
|
179
|
+
self._pedb.edb_value(dist.stop).ToString(),
|
|
180
|
+
self._pedb.edb_value(dist.step).ToString(),
|
|
181
|
+
]
|
|
182
|
+
)
|
|
183
|
+
elif dist.type == dist.DistributionType.LINEAR_COUNT:
|
|
184
|
+
freqs.append(
|
|
185
|
+
[
|
|
186
|
+
"linear count",
|
|
187
|
+
self._pedb.edb_value(dist.start).ToString(),
|
|
188
|
+
self._pedb.edb_value(dist.stop).ToString(),
|
|
189
|
+
int(dist.count),
|
|
190
|
+
]
|
|
191
|
+
)
|
|
192
|
+
elif dist.type == dist.DistributionType.LOG_SCALE:
|
|
193
|
+
freqs.append(
|
|
194
|
+
[
|
|
195
|
+
"log scale",
|
|
196
|
+
self._pedb.edb_value(dist.start).ToString(),
|
|
197
|
+
self._pedb.edb_value(dist.stop).ToString(),
|
|
198
|
+
int(dist.count),
|
|
199
|
+
]
|
|
200
|
+
)
|
|
201
|
+
edb_setup.add_frequency_sweep(sweep.name, frequency_sweep=freqs)
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# Copyright (C) 2023 - 2024 ANSYS, Inc. and/or its affiliates.
|
|
2
|
+
# SPDX-License-Identifier: MIT
|
|
3
|
+
#
|
|
4
|
+
#
|
|
5
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
# of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
# in the Software without restriction, including without limitation the rights
|
|
8
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
# copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
# furnished to do so, subject to the following conditions:
|
|
11
|
+
#
|
|
12
|
+
# The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
# copies or substantial portions of the Software.
|
|
14
|
+
#
|
|
15
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
# SOFTWARE.
|
|
22
|
+
|
|
23
|
+
from pathlib import Path
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class CfgSpiceModel:
|
|
27
|
+
def __init__(self, pdata, path_lib, spice_dict):
|
|
28
|
+
self._pedb = pdata.pedb
|
|
29
|
+
self.path_libraries = path_lib
|
|
30
|
+
self._spice_dict = spice_dict
|
|
31
|
+
self.name = self._spice_dict.get("name", "")
|
|
32
|
+
self.component_definition = self._spice_dict.get("component_definition", "")
|
|
33
|
+
self.file_path = self._spice_dict.get("file_path", "")
|
|
34
|
+
self.sub_circuit_name = self._spice_dict.get("sub_circuit_name", "")
|
|
35
|
+
self.apply_to_all = self._spice_dict.get("apply_to_all", True)
|
|
36
|
+
self.components = list(self._spice_dict.get("components", []))
|
|
37
|
+
|
|
38
|
+
def apply(self):
|
|
39
|
+
"""Apply Spice model on layout."""
|
|
40
|
+
if not Path(self.file_path).anchor:
|
|
41
|
+
fpath = str(Path(self.path_libraries) / self.file_path)
|
|
42
|
+
comps = self._pedb.components.definitions[self.component_definition].components
|
|
43
|
+
if self.apply_to_all:
|
|
44
|
+
for ref_des, comp in comps.items():
|
|
45
|
+
comp.assign_spice_model(fpath, self.name, self.sub_circuit_name)
|
|
46
|
+
else:
|
|
47
|
+
for ref_des, comp in comps.items():
|
|
48
|
+
if ref_des in self.components:
|
|
49
|
+
comp.assign_spice_model(fpath, self.name, self.sub_circuit_name)
|