gm/Id — Intent

Design intent for the gm/Id sizer, as an explicit three-level hierarchy.

In the gm/Id methodology the transconductance efficiency gm/Id of a device is a design choice that selects its inversion region (strong ~5–8 /V, moderate ~10–16 /V, weak ~18–25 /V). This module makes the intent behind those choices explicit and layered, so the sizing flow reads top-down:

Circuit intent (spec) ── SizingSpec: gain, GBW, PM, swing, power …

│ (the what; lives in shared.models) ▼

Functional-block intent ── BlockIntent: per building block, the role,

│ gm/Id region, L multiple and the rationale. ▼

Transistor intent ── TransistorIntent: the block intent resolved

onto each device (role, gm/Id, L, block, why).

The middle layer is the tunable one and the extension point: each functional building block carries its own gm/Id region and a human-readable reason, and a caller (or a future optimizer) can override a single block’s region while the rest fall back to the defaults below.

A functional building block is not the same as an FBR slot: one slot can hold devices of different roles (e.g. a gain stage’s signal driver and its current-source load both live in the second_stage slot). So a block is keyed by (slot, role) via functional_block(), matching the design-intent taxonomy (input stage, gain stage, active load, tail source, …).

Design-intent table (defaults):

Building block

gm/Id (1/V)

Design intent

Input stage

solved

Diff voltage → current: high gm, low noise, matching

Gain stage

solved

Increase voltage gain while keeping stability

Output stage

solved

Drive load capacitance and provide slew current

Active / stage load

10 (strong-ish)

Mirror current accurately with high output resistance

Tail current source

10 (strong-ish)

Set bias current with saturation headroom and high rout

Bias generator

10 (strong-ish)

Generate stable, low-sensitivity bias currents

CMFB

10 (strong-ish)

Regulate the output common-mode voltage

Cascode

8 (strong)

Increase output resistance with a small Vdsat

“solved” = gm/Id is not a free knob for signal devices; it is set to gm_required / Id to meet the spec (see GmIdModel.geometry_for()).

class circuitgenome.sizer.gmid.intent.BlockIntent(role, gm_id, l_mult, rationale)[source]

Bases: object

Design intent for one functional building block (Level 2).

Parameters:
  • role (str) – the sizing role — SIGNAL (gm solved from the spec), CURRENT_SOURCE or CASCODE.

  • gm_id (float | None) – target gm/Id in 1/V, or None when it is solved from the gm requirement (all signal blocks). This is the one free knob a caller or optimizer overrides per block.

  • l_mult (float) – channel length as a multiple of length.min.

  • rationale (str) – why this region/length — surfaced in the sizing result so the choice is explainable, not implicit.

role: str
gm_id: float | None
l_mult: float
rationale: str
class circuitgenome.sizer.gmid.intent.TransistorIntent(ref, block, role, gm_id, l_mult, rationale)[source]

Bases: object

A block intent resolved onto a single device (Level 3).

The per-device design intent that drives GmIdModel.geometry_for(): the resolved role/gm_id/l_mult plus the functional block it came from and the rationale for reporting.

Parameters:
ref: str
block: str
role: str
gm_id: float | None
l_mult: float
rationale: str
circuitgenome.sizer.gmid.intent.functional_block(slot, is_signal, is_cascode)[source]

Functional-building-block name for a device in slot with its role.

Signal takes precedence (a cascode is never a signal device), matching the role assignment the sizer used before this registry existed.

Parameters:
Return type:

str

circuitgenome.sizer.gmid.intent.resolve_transistor_intents(all_transistors, cascode_refs, block_intents={'active_load': BlockIntent(role='current_source', gm_id=10.0, l_mult=4.0, rationale='First-stage active current-mirror load: replicate current accurately with high output resistance. Strong-ish inversion (low gm/Id) for headroom and rout; a long L raises rout.'), 'bias_generator': BlockIntent(role='current_source', gm_id=10.0, l_mult=4.0, rationale='Generate stable, low-sensitivity reference currents for the mirrors it drives. Strong inversion, long L to match those mirrors.'), 'cascode': BlockIntent(role='cascode', gm_id=8.0, l_mult=3.0, rationale='Increase output resistance while preserving the stacked headroom. Strong inversion for a small Vdsat; a moderate L.'), 'cmfb': BlockIntent(role='current_source', gm_id=10.0, l_mult=4.0, rationale='Common-mode feedback devices: regulate the output common-mode voltage. (Resistive-sense averaging is set separately by cmfb_sense_r.)'), 'current_source': BlockIntent(role='current_source', gm_id=10.0, l_mult=4.0, rationale='Generic current source: accurate current with high output resistance. Strong-ish inversion, long L.'), 'gain_stage': BlockIntent(role='signal', gm_id=None, l_mult=2.0, rationale='Increase voltage gain while maintaining stability. gm/Id is solved from the required gm; L favours a gain/ft balance.'), 'input_stage': BlockIntent(role='signal', gm_id=None, l_mult=2.0, rationale='Convert the differential input voltage to current with high gm, low noise and good matching. gm/Id is solved to meet GBW/gain (moderate inversion); a small L multiple balances gain and ft.'), 'output_stage': BlockIntent(role='signal', gm_id=None, l_mult=2.0, rationale='Drive the load capacitance and provide slew current. gm/Id is solved from the required gm.'), 'stage_load': BlockIntent(role='current_source', gm_id=10.0, l_mult=4.0, rationale='Current-source load of a gain/output stage: high output resistance for gain. Strong-ish inversion, long L.'), 'tail_current': BlockIntent(role='current_source', gm_id=10.0, l_mult=4.0, rationale='Tail current source: set the input-pair bias current with adequate saturation headroom and high rout. A low gm/Id (strong inversion) maximises the headroom.')})[source]

Resolve the block registry onto every device (Level 2 → Level 3).

Parameters:
Return type:

dict[str, TransistorIntent]

class circuitgenome.sizer.gmid.intent.GmIdIntent(block_intents=<factory>, signal_gm_id=14.0, current_source_gm_id=10.0, cascode_gm_id=8.0, signal_l_mult=2.0, current_source_l_mult=4.0, cascode_l_mult=3.0, degeneration_factor=0.5, cmfb_sense_r=1000000.0)[source]

Bases: object

Circuit-wide gm/Id knobs that are not per building block.

The per-block gm/Id and L choices live in block_intents (defaulting to DEFAULT_BLOCK_INTENTS); the role-level fields here remain the fallback the device model uses for its pre-geometry gds estimate (via GmIdPolicy), and the two resistor knobs configure the resistor network the block registry does not cover. To retune a single building block, pass a copy of block_intents with that entry replaced.

Parameters:
  • block_intents (dict[str, BlockIntent]) – per-functional-block design intent (Level 2).

  • signal_gm_id (float) – nominal signal gm/Id for the pre-geometry gds estimate.

  • current_source_gm_id (float) – fallback current-source gm/Id.

  • cascode_gm_id (float) – fallback cascode gm/Id.

  • cascode_l_mult (float) – fallback L multiples per role.

  • degeneration_factor (float) – gm1·R for a source-degenerated input pair — sets each degeneration resistor to factor/gm1 and the effective input transconductance to gm1/(1+factor) (0 = no degeneration).

  • cmfb_sense_r (float) – resistance (Ω) of each resistive-sense CMFB averager resistor — large so it doesn’t load the differential output.

  • signal_l_mult (float)

  • current_source_l_mult (float)

  • cascode_l_mult

block_intents: dict[str, BlockIntent]
signal_gm_id: float = 14.0
current_source_gm_id: float = 10.0
cascode_gm_id: float = 8.0
signal_l_mult: float = 2.0
current_source_l_mult: float = 4.0
cascode_l_mult: float = 3.0
degeneration_factor: float = 0.5
cmfb_sense_r: float = 1000000.0