Compensation Compatibility

Compensation inversion-parity compatibility filter for enumerate_circuits().

Every compensation variant in the library is Miller-family: it couples its in port to its out port through a capacitor (directly, through a nulling resistor, or via an internal series node). Wired across a stage chain, that coupling is negative feedback – pole splitting – only when the wrapped chain is inverting. Around a non-inverting chain with gain the same capacitor is positive feedback: the AC response develops a right-half-plane character and gain/GBW/PM become unmeasurable (issue #114: differential_ota_second_stage, two cascaded common-source stages, PM measured 270-281 deg with every compensation variant).

The parity of a chain is the number of common-source inversions along its in -> out device path:

  • a common-source hop (signal enters a gate, exits the drain) inverts;

  • a follower hop (signal enters a gate, exits the source) does not invert – and contributes no gain, so a Miller capacitor around a pure follower chain is bootstrapped to C*(1-A) ~ 0: useless but benign, NOT positive feedback. Followers are therefore deliberately allowed (a strict odd-parity rule would ban them and undo issue #110).

The reject condition is a chain whose total inversion count is a positive even number – non-inverting with gain. This also covers composite chains: in the nested-Miller 3-stage topologies comp1 wraps the second+third stage cascade (net_mid1 -> out), where two common-source stages compose to the same positive-feedback structure (standard NMC requires a non-inverting second stage and an inverting output stage).

The check is structural (actual device terminal references, no YAML tags, same approach as second_stage): a stage variant’s inversion count is computed by walking gate-to-drain / gate-to-source hops from its in port, and chains are composed by following second_stage-category slots’ in/out nets between the compensation slot’s in and out nets. Anything unclassifiable (a compensation variant that does not couple in to out, a chain the walk cannot follow, a stage with no device gating in) imposes no constraint.

circuitgenome.synthesizer.compatibility.compensation.stage_inversions(variant)[source]

Return the number of common-source inversions along variant’s in -> out device chain, or None if the chain cannot be followed (no device gates in, a dangling hop, or a cycle).

Each hop enters a MOSFET gate; leaving through the drain counts one inversion (common source), leaving through the source counts none (follower). A diode-connected device (d == g == net) is skipped at a fork – it terminates a branch (e.g. a current-mirror master) rather than carrying the signal forward – so the walk follows the mirror-output device instead. common_source_nmos/common_source_pmos -> 1, common_drain_pmos/common_drain_nmos -> 0, differential_ota_second_stage -> 2, noninverting_stage_nmos/noninverting_stage_pmos -> 2 (CS inversion + current-mirror inversion).

Parameters:

variant (ModuleVariant)

Return type:

int | None

circuitgenome.synthesizer.compatibility.compensation.is_compensation_compatible(topology, variant_map)[source]

Return False if any compensation slot that couples its in and out nets wraps a stage chain whose total inversion count is a positive even number – non-inverting with gain, i.e. positive feedback through the compensation network (see the module docstring for the electrical rationale).

Parameters:
Return type:

bool