-
Notifications
You must be signed in to change notification settings - Fork 9
Added example design of 160GHz LNA from IHP April 2025 Tapeout (without .git/modules integration) #71
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
Reviewer's GuideAdds a complete example design for a 160 GHz narrowband LNA in IHP 130 nm technology, including parametrized layout factories (PCell-style) for a single LNA stage and RF capacitors, guard-ring utilities, schematic/simulation data in Qucs-S, and documentation, all integrated directly under examples/design_examples without git submodules. Class diagram for 160GHz LNA stage layout factoryclassDiagram
class LNA160GStageFactory {
+Component lna_160g_stage(
npn_emitter_width,
npn_emitter_length,
m,
rows,
rfcmim_width,
rfcmim_length,
rfcmim_width2,
rfcmim_length2,
ymax_ref,
emitter_stub_length,
output_stub_length,
bias_con_length,
layer_metal1draw,
layer_metal2pin,
layer_metal2draw,
layer_metal2label,
layer_metal5draw,
layer_metal5pin,
layer_topmetal1draw,
layer_topmetal1pin,
layer_topmetal1label,
layer_topmetal2draw,
layer_topmetal2pin,
layer_topmetal2label,
model
)
}
class RFcmimFactory {
+Component rfcmim(
width,
length,
layer_pwellblock,
layer_metal5,
layer_mim,
layer_vmim,
layer_topmetal1,
layer_cap_mark,
layer_m4nofill,
layer_m5nofill,
layer_tm1nofill,
layer_tm2nofill,
layer_activ,
layer_cont,
layer_metal1,
layer_psd,
layer_activnoqrc,
layer_metal1noqrc,
layer_metal2noqrc,
layer_metal3noqrc,
layer_metal4noqrc,
layer_metal5noqrc,
layer_topmetal1noqrc,
layer_text,
layer_metal1pin,
layer_metal5pin,
layer_topmetal1pin,
layer_metal5label,
layer_topmetal1label,
layer_metal1label,
model
)
}
class Npn13G2 {
+Device npn13G2(emitter_width,emitter_length,Nx)
}
class Rhigh {
+Device rhigh(dx,dy,model)
}
class Rsil {
+Device rsil(dx,dy)
}
class ViaStack {
+Component via_stack(
bottom_layer,
top_layer,
vn_columns,
vn_rows,
vt1_columns,
vt1_rows,
vt2_columns,
vt2_rows
)
}
class GdsfactoryComponent {
+rectangle(size,layer)
+taper(width1,width2,length,layer)
+shapes_L(width,size,layer,port_type)
}
LNA160GStageFactory --> RFcmimFactory : uses_input_output_caps
LNA160GStageFactory --> Npn13G2 : places_active_device
LNA160GStageFactory --> Rhigh : uses_bias_resistor
LNA160GStageFactory --> Rsil : uses_load_resistor
LNA160GStageFactory --> ViaStack : creates_via_stacks
LNA160GStageFactory --> GdsfactoryComponent : routes_and_pads
RFcmimFactory --> GdsfactoryComponent : builds_mim_stack
RFcmimFactory --> ViaStack : adds_via_array
Class diagram for capacitor and guard ring layout factoriesclassDiagram
class CmomExtractor {
+float cmom_extractor(
nfingers,
length,
spacing,
min_width,
mom_metals,
fringe_field_factor,
interlayer_dielectric
)
}
class CmomFactory {
+Component cmom(
nfingers,
length,
spacing,
botmetal,
topmetal,
layer_metal1,
layer_metal2,
layer_metal3,
layer_metal4,
layer_metal5,
layer_metal1pin,
layer_metal2pin,
layer_metal3pin,
layer_metal4pin,
layer_metal5pin,
layer_metal1label,
layer_metal2label,
layer_metal3label,
layer_metal4label,
layer_metal5label,
layer_metal1nofill,
layer_metal2nofill,
layer_metal3nofill,
layer_metal4nofill,
layer_metal5nofill,
layer_cap_mark,
layer_text,
model
)
}
class CmimFactory {
+Component cmim(
width,
length,
layer_metal5,
layer_mim,
layer_vmim,
layer_topmetal1,
layer_cap_mark,
layer_m4nofill,
layer_m5nofill,
layer_tm1nofill,
layer_tm2nofill,
layer_text,
layer_metal5label,
layer_topmetal1label,
layer_metal5pin,
layer_topmetal1pin,
model
)
}
class RFcmimFactory {
+Component rfcmim(
width,
length,
layer_pwellblock,
layer_metal5,
layer_mim,
layer_vmim,
layer_topmetal1,
layer_cap_mark,
layer_m4nofill,
layer_m5nofill,
layer_tm1nofill,
layer_tm2nofill,
layer_activ,
layer_cont,
layer_metal1,
layer_psd,
layer_activnoqrc,
layer_metal1noqrc,
layer_metal2noqrc,
layer_metal3noqrc,
layer_metal4noqrc,
layer_metal5noqrc,
layer_topmetal1noqrc,
layer_text,
layer_metal1pin,
layer_metal5pin,
layer_topmetal1pin,
layer_metal5label,
layer_topmetal1label,
layer_metal1label,
model
)
}
class GuardRingFactory {
+Component guard_ring(
width,
guardRingSpacing,
guardRingType,
bbox,
path,
layer_activ,
layer_cont,
layer_metal1,
layer_psd,
layer_nwell,
layer_nsd
)
}
class ViaArray {
+Component via_array(
via_type,
via_size,
via_spacing,
via_enclosure,
columns,
rows
)
}
class TechRules {
+float metal1_width
+float metal1_spacing
+float metal2_width
+float metal2_spacing
+float metal3_width
+float metal3_spacing
+float metal4_width
+float metal4_spacing
+float metal5_width
+float metal5_spacing
+float mim_min_size
+float mim_cap_density
+float cont_size
+float cont_spacing
+float cont_enc_active
+float cont_enc_metal
+float grid
}
class GdsfactoryComponent {
+rectangle(size,layer)
+bbox(component,layer)
+Path()
+taper(width1,width2,length,layer)
}
CmomFactory --> CmomExtractor : computes_capacitance
CmomFactory --> TechRules : uses_design_rules
CmomFactory --> GdsfactoryComponent : draws_fingers_and_pads
CmomFactory --> ViaArray : adds_stack_vias
CmimFactory --> TechRules : uses_mim_rules
CmimFactory --> GdsfactoryComponent : draws_mim_and_pads
CmimFactory --> ViaArray : places_vmim_array
RFcmimFactory --> CmimFactory : wraps_cmim_core
RFcmimFactory --> GuardRingFactory : adds_p_guard_ring
RFcmimFactory --> GdsfactoryComponent : adds_logic_nofill_layers
GuardRingFactory --> TechRules : uses_guard_ring_rules
GuardRingFactory --> GdsfactoryComponent : extrudes_paths
GuardRingFactory --> ViaArray : places_contact_taps
Flow diagram for 160GHz LNA example design generationflowchart LR
subgraph DesignEnvironment
PDK[IHPPDK.activate]
LNAFactory[lna_160g_stage in lna_py]
CapFactories[cmom cmim rfcmim in capacitors_py]
PassiveFactories[guard_ring in passives_py]
Notebook[lna_notebook_ipynb]
end
subgraph LayoutOutput
GDSDir[gds directory]
GDSLNA[ihp_160g_lna_gds]
GDSFactoryGen[ihp_160g_lna_factory_gen_gds]
end
subgraph SchematicsAndModels
QucsMain[160GHz_LNA_MAIN_sch]
QucsPi[160GHz_LNA_pi_model_sch]
SpiceData[ngspice data and models]
end
Notebook --> PDK
Notebook --> LNAFactory
Notebook --> CapFactories
Notebook --> PassiveFactories
LNAFactory --> CapFactories
LNAFactory --> PassiveFactories
LNAFactory --> GDSLNA
CapFactories --> GDSLNA
PassiveFactories --> GDSLNA
LNAFactory --> GDSFactoryGen
GDSLNA --> GDSDir
GDSFactoryGen --> GDSDir
QucsMain --> SpiceData
QucsPi --> SpiceData
QucsMain --> LNAFactory
QucsPi --> CapFactories
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey - I've found 5 issues, and left some high level feedback:
- The QUCS-S schematics and INCLSCR blocks are full of hard-coded absolute Windows paths (e.g.
C:/Users/nsl/...andC:/S2P files/...), which will break for other users and CI; consider switching to project-relative paths or a configurable include mechanism instead. - The
lna_160g_stageimplementation is duplicated almost verbatim in bothlna_notebook.ipynbandlna.py; it would be more maintainable if the notebook imported and exercised the code fromlna.pyrather than embedding a separate copy.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- The QUCS-S schematics and INCLSCR blocks are full of hard-coded absolute Windows paths (e.g. `C:/Users/nsl/...` and `C:/S2P files/...`), which will break for other users and CI; consider switching to project-relative paths or a configurable include mechanism instead.
- The `lna_160g_stage` implementation is duplicated almost verbatim in both `lna_notebook.ipynb` and `lna.py`; it would be more maintainable if the notebook imported and exercised the code from `lna.py` rather than embedding a separate copy.
## Individual Comments
### Comment 1
<location> `examples/design_examples/ihp_160g_lna/design_data/factory/capacitors.py:166-167` </location>
<code_context>
+
+ ordered_metals = list(metals.keys())
+ #ordered_vias = [lay for lay in ordered_layers if "via" in lay]
+ assert botmetal in ordered_metals, "{botmetal} not it available layers: {_ordered_metals}"
+ assert topmetal in ordered_metals, "{topmetal} not it available layers: {_ordered_metals}"
+ mom_metals = ordered_metals[
+ ordered_metals.index(botmetal) : ordered_metals.index(topmetal)+1
</code_context>
<issue_to_address>
**issue (bug_risk):** Assertion error messages use literal `{botmetal}` / `{_ordered_metals}` instead of actual values and reference an undefined name.
These asserts will always show the literal text (`"{botmetal}"`, `"{_ordered_metals}"`) instead of the actual values, and there’s a typo in the message (“not it”). To get useful messages, use f-strings and the real variable name:
```python
assert botmetal in ordered_metals, f"{botmetal} not in available layers: {ordered_metals}"
assert topmetal in ordered_metals, f"{topmetal} not in available layers: {ordered_metals}"
```
</issue_to_address>
### Comment 2
<location> `examples/design_examples/ihp_160g_lna/design_data/factory/passives.py:22` </location>
<code_context>
+ guardRingSpacing: float = 0.14,
+ guardRingType: Literal["psub", 'nwell'] = "psub",
+ bbox: Union[tuple[Point, Point], None] = None,
+ path: Union[List[tuple[Point, Point]], None] = None,
+ layer_activ: LayerSpec = "Activdrawing",
+ layer_cont: LayerSpec = "Contdrawing",
</code_context>
<issue_to_address>
**suggestion:** The `path` type annotation doesn’t match how it’s used later and may be misleading.
The code and docstring use `path` as a sequence of points passed directly to `gf.path.Path(path)`, but the type is `List[tuple[Point, Point]]`, i.e., segments `((x, y), (x, y))`. Updating this to `List[Point]` (and adjusting the docstring) would better reflect actual usage and avoid misuse.
Suggested implementation:
```python
guardRingType: Literal["psub", 'nwell'] = "psub",
bbox: Union[tuple[Point, Point], None] = None,
path: Union[List[Point], None] = None,
layer_activ: LayerSpec = "Activdrawing",
```
```python
"""
Create an N-Well (NW) and N-Plus (NP) or a P-Plus (PP)
guard ring around a boundary box, or, if `bbox` is not provided,
along a provided `path` defined as a sequence of points.
```
</issue_to_address>
### Comment 3
<location> `examples/design_examples/ihp_160g_lna/design_data/factory/lna.py:88-97` </location>
<code_context>
+
+ # Constants - Avoiding magic numbers
+
+ # Spacing and Positioning
+ NPN_SPACING = 0.6
+ NPN_Y_OFFSET = 5.0
+ RSIL_Y_OFFSET = 1.7
+ VBB_PAD_SIZE = 5.0
+ VBB_X_OFFSET = 5.0
+
+ # Component Dimensions
+ RHIGH_DY = 6.0
+ RHIGH_DX = 1.9
+ RSIL_DX = 7.5
+ RSIL_DY = 5.0
+ GND_STUB_WIDTH = 15.0
+ GND_STUB_HEIGHT = 3.9
+ STUB_WIDTH = 3.0
+ OUT_STUB_WIDTH = 9.0
+
+ # Via Configuration
+ VIA2_VBB_COLS = 5
+ VIA_RHIGH_P2_COLS = 4
+ NPN_TERM_VIA_COLS = 3
+ NPN_COL_X_OFFSET = 0.645
+
+ # Routing and Taper Dimensions
+ COL_RSIL_Y_OFFSET = 2.0
+ OUT_STUB_STAGE_W1 = 4.0
+ TAPER_LENGTH_SHORT = 3.0
+
+ rfmim1 = c.add_ref(
</code_context>
<issue_to_address>
**suggestion:** Several local constants (e.g., `NPN_SPACING`, `RSIL_DX`, `GND_STUB_WIDTH`) are defined but not used, while equivalent literals appear later in the code.
The constants look good, but the layout code still uses raw values like `0.6`, `7.5`, `15.0`, `3.0`, etc., instead of these names. That means updating the constants won’t actually change the geometry. Please either replace the matching literals with the defined constants, or remove any constants that truly aren’t needed to avoid drift between the definitions and the implemented layout.
Suggested implementation:
```python
# Constants - Avoiding magic numbers
# Spacing and Positioning
NPN_SPACING = 0.6
NPN_Y_OFFSET = 5.0
RSIL_Y_OFFSET = 1.7
VBB_PAD_SIZE = 5.0
VBB_X_OFFSET = 5.0
# Component Dimensions
RHIGH_DY = 6.0
RHIGH_DX = 1.9
RSIL_DX = 7.5
RSIL_DY = 5.0
GND_STUB_WIDTH = 15.0
GND_STUB_HEIGHT = 3.9
STUB_WIDTH = 3.0
OUT_STUB_WIDTH = 9.0
# Via Configuration
VIA2_VBB_COLS = 5
VIA_RHIGH_P2_COLS = 4
NPN_TERM_VIA_COLS = 3
NPN_COL_X_OFFSET = 0.645
# Routing and Taper Dimensions
COL_RSIL_Y_OFFSET = 2.0
OUT_STUB_STAGE_W1 = 4.0
TAPER_LENGTH_SHORT = 3.0
rfmim1 = c.add_ref(
rfcmim(width=rfcmim_width, length=rfcmim_length))
rhigh1 = c.add_ref(
cells.resistors.rhigh(dy=RHIGH_DY, dx=RHIGH_DX, model="rhigh"))
rhigh1.xmin = rfmim1.xmax + NPN_SPACING
rhigh1.ymax = rfmim1.ymax if ymax_ref is None else ymax_ref
rfnpn1 = c.add_ref(
cells2.npn13G2(emitter_width=npn_emitter_width, emitter_length=npn_emitter_length, Nx=m))
rfnpn1.rotate(-90)
rfnpn1.xmin = rfmim1.xmax + NPN_SPACING
```
To fully implement the suggestion across the file, you should also:
1. Search the remainder of `lna.py` for remaining literal uses of the declared constants (e.g. `7.5`, `5.0`, `15.0`, `3.0`, `9.0`, `3.9`, `2.0`, `4.0`, `3.0`, `0.645`, etc.) in layout and geometry expressions.
2. Replace each of those literals with the corresponding named constant (`RSIL_DX`, `RSIL_DY`, `GND_STUB_WIDTH`, `STUB_WIDTH`, `OUT_STUB_WIDTH`, `GND_STUB_HEIGHT`, `COL_RSIL_Y_OFFSET`, `OUT_STUB_STAGE_W1`, `TAPER_LENGTH_SHORT`, `NPN_COL_X_OFFSET`, etc.) where the numeric value and meaning match.
3. Remove any constants that remain completely unused after this cleanup to avoid drift between defined and effective layout parameters.
</issue_to_address>
### Comment 4
<location> `examples/design_examples/ihp_160g_lna/README.md:7` </location>
<code_context>
+
+**Repository Contents**
+* `design_data`:
+ - `qucs-s` includes the schematic for parsing component parameters,
+ - `gds` includes the layout
+ - `factory` includes the factories for automatic parametrized generation of the layout
</code_context>
<issue_to_address>
**issue (typo):** There appears to be an extra space between "schematic" and "for".
Change "schematic for" to "schematic for" (single space).
```suggestion
- `qucs-s` includes the schematic for parsing component parameters,
```
</issue_to_address>
### Comment 5
<location> `examples/design_examples/ihp_160g_lna/README.md:9` </location>
<code_context>
+* `design_data`:
+ - `qucs-s` includes the schematic for parsing component parameters,
+ - `gds` includes the layout
+ - `factory` includes the factories for automatic parametrized generation of the layout
+
+* `160GHz_LNA/doc`: Contains detailed specifications and design documentation.
</code_context>
<issue_to_address>
**suggestion (typo):** The phrase "automatic parametrized generation" reads awkwardly; consider rephrasing for clarity.
Consider alternatives like "factories for automated parameterized layout generation" or "factories for automatically parameterizing layout generation" to keep the meaning while improving the flow.
```suggestion
- `factory` includes the factories for automated parameterized layout generation
```
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
| assert botmetal in ordered_metals, "{botmetal} not it available layers: {_ordered_metals}" | ||
| assert topmetal in ordered_metals, "{topmetal} not it available layers: {_ordered_metals}" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
issue (bug_risk): Assertion error messages use literal {botmetal} / {_ordered_metals} instead of actual values and reference an undefined name.
These asserts will always show the literal text ("{botmetal}", "{_ordered_metals}") instead of the actual values, and there’s a typo in the message (“not it”). To get useful messages, use f-strings and the real variable name:
assert botmetal in ordered_metals, f"{botmetal} not in available layers: {ordered_metals}"
assert topmetal in ordered_metals, f"{topmetal} not in available layers: {ordered_metals}"| guardRingSpacing: float = 0.14, | ||
| guardRingType: Literal["psub", 'nwell'] = "psub", | ||
| bbox: Union[tuple[Point, Point], None] = None, | ||
| path: Union[List[tuple[Point, Point]], None] = None, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
suggestion: The path type annotation doesn’t match how it’s used later and may be misleading.
The code and docstring use path as a sequence of points passed directly to gf.path.Path(path), but the type is List[tuple[Point, Point]], i.e., segments ((x, y), (x, y)). Updating this to List[Point] (and adjusting the docstring) would better reflect actual usage and avoid misuse.
Suggested implementation:
guardRingType: Literal["psub", 'nwell'] = "psub",
bbox: Union[tuple[Point, Point], None] = None,
path: Union[List[Point], None] = None,
layer_activ: LayerSpec = "Activdrawing", """
Create an N-Well (NW) and N-Plus (NP) or a P-Plus (PP)
guard ring around a boundary box, or, if `bbox` is not provided,
along a provided `path` defined as a sequence of points.| # Spacing and Positioning | ||
| NPN_SPACING = 0.6 | ||
| NPN_Y_OFFSET = 5.0 | ||
| RSIL_Y_OFFSET = 1.7 | ||
| VBB_PAD_SIZE = 5.0 | ||
| VBB_X_OFFSET = 5.0 | ||
|
|
||
| # Component Dimensions | ||
| RHIGH_DY = 6.0 | ||
| RHIGH_DX = 1.9 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
suggestion: Several local constants (e.g., NPN_SPACING, RSIL_DX, GND_STUB_WIDTH) are defined but not used, while equivalent literals appear later in the code.
The constants look good, but the layout code still uses raw values like 0.6, 7.5, 15.0, 3.0, etc., instead of these names. That means updating the constants won’t actually change the geometry. Please either replace the matching literals with the defined constants, or remove any constants that truly aren’t needed to avoid drift between the definitions and the implemented layout.
Suggested implementation:
# Constants - Avoiding magic numbers
# Spacing and Positioning
NPN_SPACING = 0.6
NPN_Y_OFFSET = 5.0
RSIL_Y_OFFSET = 1.7
VBB_PAD_SIZE = 5.0
VBB_X_OFFSET = 5.0
# Component Dimensions
RHIGH_DY = 6.0
RHIGH_DX = 1.9
RSIL_DX = 7.5
RSIL_DY = 5.0
GND_STUB_WIDTH = 15.0
GND_STUB_HEIGHT = 3.9
STUB_WIDTH = 3.0
OUT_STUB_WIDTH = 9.0
# Via Configuration
VIA2_VBB_COLS = 5
VIA_RHIGH_P2_COLS = 4
NPN_TERM_VIA_COLS = 3
NPN_COL_X_OFFSET = 0.645
# Routing and Taper Dimensions
COL_RSIL_Y_OFFSET = 2.0
OUT_STUB_STAGE_W1 = 4.0
TAPER_LENGTH_SHORT = 3.0
rfmim1 = c.add_ref(
rfcmim(width=rfcmim_width, length=rfcmim_length))
rhigh1 = c.add_ref(
cells.resistors.rhigh(dy=RHIGH_DY, dx=RHIGH_DX, model="rhigh"))
rhigh1.xmin = rfmim1.xmax + NPN_SPACING
rhigh1.ymax = rfmim1.ymax if ymax_ref is None else ymax_ref
rfnpn1 = c.add_ref(
cells2.npn13G2(emitter_width=npn_emitter_width, emitter_length=npn_emitter_length, Nx=m))
rfnpn1.rotate(-90)
rfnpn1.xmin = rfmim1.xmax + NPN_SPACINGTo fully implement the suggestion across the file, you should also:
- Search the remainder of
lna.pyfor remaining literal uses of the declared constants (e.g.7.5,5.0,15.0,3.0,9.0,3.9,2.0,4.0,3.0,0.645, etc.) in layout and geometry expressions. - Replace each of those literals with the corresponding named constant (
RSIL_DX,RSIL_DY,GND_STUB_WIDTH,STUB_WIDTH,OUT_STUB_WIDTH,GND_STUB_HEIGHT,COL_RSIL_Y_OFFSET,OUT_STUB_STAGE_W1,TAPER_LENGTH_SHORT,NPN_COL_X_OFFSET, etc.) where the numeric value and meaning match. - Remove any constants that remain completely unused after this cleanup to avoid drift between defined and effective layout parameters.
|
|
||
| **Repository Contents** | ||
| * `design_data`: | ||
| - `qucs-s` includes the schematic for parsing component parameters, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
issue (typo): There appears to be an extra space between "schematic" and "for".
Change "schematic for" to "schematic for" (single space).
| - `qucs-s` includes the schematic for parsing component parameters, | |
| - `qucs-s` includes the schematic for parsing component parameters, |
| * `design_data`: | ||
| - `qucs-s` includes the schematic for parsing component parameters, | ||
| - `gds` includes the layout | ||
| - `factory` includes the factories for automatic parametrized generation of the layout |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
suggestion (typo): The phrase "automatic parametrized generation" reads awkwardly; consider rephrasing for clarity.
Consider alternatives like "factories for automated parameterized layout generation" or "factories for automatically parameterizing layout generation" to keep the meaning while improving the flow.
| - `factory` includes the factories for automatic parametrized generation of the layout | |
| - `factory` includes the factories for automated parameterized layout generation |
|
Glad timezones don't matter for submitting PRs. This sourcery-ai thingy is amazing btw |
The chip design data is added directly to the main IHP repo under examples/design_examples.
Summary by Sourcery
Add an example 160 GHz narrowband LNA design in IHP 130nm technology, including parametrized layout factories, passive device generators, and QUCS-S schematics/models for simulation.
New Features:
Documentation: