Skip to content

Conversation

@das-dias
Copy link
Contributor

@das-dias das-dias commented Jan 24, 2026

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:

  • Provide a parametrized layout cell and generation notebook for a single-stage 160 GHz LNA and a four-stage cascaded implementation with GDS export.
  • Introduce reusable capacitor and guard-ring passive layout generators tailored to the IHP sg13g2 PDK, including RF MIM and MOM variants.
  • Add QUCS-S schematics and data for the LNA main design and an equivalent π-model to support simulation and analysis of the 160 GHz LNA.

Documentation:

  • Document the 160 GHz LNA example design, its performance targets, and repository structure in a dedicated README within the example directory, plus notes on the QUCS-S schematics and modeling approach.

@sourcery-ai
Copy link

sourcery-ai bot commented Jan 24, 2026

Reviewer's Guide

Adds 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 factory

classDiagram

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
Loading

Class diagram for capacitor and guard ring layout factories

classDiagram

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
Loading

Flow diagram for 160GHz LNA example design generation

flowchart 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
Loading

File-Level Changes

Change Details Files
Introduce a reusable parametrized factory for a single 160 GHz LNA stage and a notebook that instantiates a 4‑stage cascaded LNA and writes GDS output.
  • Define gf.cell lna_160g_stage that composes rf MIM capacitors, NPN BJT, Rhigh/Rsil resistors, via stacks, stubs, tapers, and labeled RF/power/ground/bias ports using IHP PDK layers.
  • Use explicit local constants instead of magic numbers to control device spacing, dimensions, and via configurations for the LNA layout routing.
  • Add a notebook script that activates the IHP PDK, instantiates four lna_160g_stage variants with different capacitor and transistor parameters, adds an additional output MIM cap, and writes the generated layout to GDS.
examples/design_examples/ihp_160g_lna/design_data/factory/lna.py
examples/design_examples/ihp_160g_lna/design_data/factory/lna_notebook.ipynb
Provide parametrized RF/MIM/MOM capacitor generators and a guard-ring utility used by the LNA factory.
  • Implement cmom (MOM capacitor) with design-rule‑aware metal stacks, via stacking, cap marker/nofill layers, pin/label generation, and capacitance extraction helper cmom_extractor.
  • Implement cmim (MIM capacitor) with DRC checks, grid snapping, bottom/top plate construction, via array between MIM and top metal, nofill/marker layers, labeling, and CbCapCalc‑based capacitance annotation.
  • Implement rfcmim as an RF‑optimized MIM capacitor that wraps cmim with added p‑well block, p+ guard ring created via guard_ring(), QRC‑exclusion layers, TIE_LOW pin, and metadata.
  • Implement guard_ring() to build P+/N+ guard rings around a bbox or path using gdsfactory Paths, with correct active/psd/nsd/nwell regions, contact arrays, and design‑rule‑based spacing.
  • Add small self-test / example code under main for cmom and rfcmim to validate capacitance scaling.
examples/design_examples/ihp_160g_lna/design_data/factory/capacitors.py
examples/design_examples/ihp_160g_lna/design_data/factory/passives.py
Add Qucs‑S schematics, simulation control, and documentation for the 160 GHz LNA including a π‑model replacement for S‑parameter blocks.
  • Add main LNA schematic using IHP npn13G2 devices, RF MIM capacitors, resistors/inductors, chokes, S‑parameter blocks for distributed elements, and extensive decoupling/bias networks, with DC, SP, and post‑processing (NutmegEq) analyses configured.
  • Add an equivalent π‑model schematic that replaces S2P blocks with explicit lumped elements to enable Ngspice noise figure simulations, along with a .dat.ngspice result file.
  • Add a README explaining the use of the π‑model vs. the S2P‑based main schematic and Ngspice limitations.
  • Include an INCLSCR block that pulls in IHP PDK ngspice model libraries and preloads the r3_cmc OSDI model.
examples/design_examples/ihp_160g_lna/design_data/qucs-s/160GHz_LNA(MAIN).sch
examples/design_examples/ihp_160g_lna/design_data/qucs-s/160GHz_LNA_pi_model.sch
examples/design_examples/ihp_160g_lna/design_data/qucs-s/160GHz_LNA_pi_model.dat.ngspice
examples/design_examples/ihp_160g_lna/design_data/qucs-s/README.md
Document the example and integrate technology / configuration artifacts for use with the IHP PDK and KLayout.
  • Add a top-level README describing the 160 GHz LNA performance, pointing to the full tapeout repo, and outlining the structure of design_data and doc directories.
  • Add an (initially empty) .gitmodules file at the example root as a placeholder for future submodule-based integration of the full tapeout data.
  • Add a KLayout layer properties file (sg13g2.lyp) under tech/klayout for viewing the generated GDS with appropriate layer coloring/naming.
examples/design_examples/ihp_160g_lna/README.md
examples/design_examples/ihp_160g_lna/.gitmodules
examples/design_examples/ihp_160g_lna/tech/klayout/sg13g2.lyp

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link

@sourcery-ai sourcery-ai bot left a 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/... 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.
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>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment on lines +166 to +167
assert botmetal in ordered_metals, "{botmetal} not it available layers: {_ordered_metals}"
assert topmetal in ordered_metals, "{topmetal} not it available layers: {_ordered_metals}"
Copy link

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,
Copy link

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.

Comment on lines +88 to +97
# 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
Copy link

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_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.


**Repository Contents**
* `design_data`:
- `qucs-s` includes the schematic for parsing component parameters,
Copy link

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).

Suggested change
- `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
Copy link

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.

Suggested change
- `factory` includes the factories for automatic parametrized generation of the layout
- `factory` includes the factories for automated parameterized layout generation

@das-dias
Copy link
Contributor Author

Glad timezones don't matter for submitting PRs. This sourcery-ai thingy is amazing btw

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant