Hybrid Optimizer
The hybrid optimizer converts user-level LNA or PA specifications into concrete device sizes, passive values, matching-network elements, and geometry-aware inductor or CPWD choices. It combines analytical circuit equations with dataset-backed inverse design models, then maps the selected values back into the SPICE netlist used by the rest of COmPOSER.
Entry Point
Run the optimizer through the shared driver. The driver reads the design config, calls the selected LNA or PA sizing script, stores the best design under the project directory, and annotates the unsized netlist.
python3 perform_initial_sizing.py --config EXAMPLES/LNA_1/config.json
python3 perform_initial_sizing.py --config EXAMPLES/PA_1/config.json
Required Config Keys
| Key | What It Controls |
|---|---|
stage_1_sizer |
Selects lna_stage_1_sizer.py or pa_stage_1_sizer.py. |
stage_1_config |
Points to circuit-class constants, sweep settings, thresholds, and fallback values. |
stage_1_mapping_script |
Usually map_initial_size_to_netlist.py; writes optimizer results into SPICE annotations. |
stage_1_map_file |
Maps JSON output keys such as GATE_IND_L or Stage_1_Size to netlist instances. |
design_requirements |
Defines frequency and circuit targets, including LNA NF/gain/BW/S11/power or PA gain/p_sat_db. |
datasets |
Provides the spiral-inductor dataset and, for LNA matching, the CPWD dataset. |
What the Driver Does
- Creates
<project_name>/stage_1/. - Runs the selected script with
--config,--out-json, and--out-csv. - Writes
best_<topcell>_design.jsonandall_<topcell>_designs.csv. - Calls
map_initial_size_to_netlist.pyto annotatedesign.input_unsized_netlist. - Writes the sized netlist to
design.input_netlist, which is consumed by netlist parsing and primitive generation.
Shared Modeling Idea
The optimizer does not choose passives as abstract circuit numbers only. For inductors, PRIMITIVE_OPTIMIZERS/optimize_inductor.py loads the spiral-inductor dataset, trains or reuses the RF estimator and k-nearest-neighbor inverse model, and returns a realizable geometry with predicted Inductance, Peak Q, Peak Q Freq, and SRF.
The scripts use analytical equations to identify target passive values, then call optimize_specs_multi_variant(...) to pull those values back into the layout-realizable data manifold.
LNA Hybrid Optimizer
The LNA path uses lna_stage_1_sizer.py with a design-specific file such as EXAMPLES/LNA_1/lna_stage_1_config.json. It targets a cascode LNA with source degeneration, input matching, output matching, and optional interstage matching for higher-frequency cases.
| Input Group | Examples | Purpose |
|---|---|---|
| Design targets | freq_ghz, nf_req_db, gain_req_db, bw_req_ghz, s11_req_db, pwr_req_mw |
Define the performance envelope the optimizer scores against. |
| Device constants | cgs, cd, gm, rin, rgate, ft, power_unit |
Parameterize the analytical LNA equations. |
| Sweeps | rin, z2, theta2 |
Control input-resistance and CPWD matching exploration. |
| Model data | spiral_inductor, cpwd |
Selects realizable inductor and CPWD geometries. |
The LNA script first computes candidate transistor multiplicities from the NF, gain, bandwidth, and power limits. It uses the same equation structure implemented in the code, including the minimum-size estimate and polynomial roots for combined NF/gain/BW constraints.
Nmin = ft / (freq * Rin) * sqrt(Rgate / noise_denominator)
Qout_required = freq / bandwidth
Pdc = power_unit * size
For each candidate size and input resistance, it then solves the source-degeneration inductance, computes the gate inductor required for input resonance, and computes the drain inductor required for output resonance.
Ls -> source degeneration from the quadratic roots
Lg -> 1 / (omega^2 * Cgs * size) adjusted by Ls
Ld -> 1 / (omega^2 * (Cd * size + Cload))
Each inductor target is passed to the inductor optimizer. The returned geometry and predicted Q/SRF are used immediately to adjust matching behavior, so the selected values remain tied to realizable passive layouts.
Input matching is handled with a CPWD sweep. The script forms the transformed input impedance, computes S11, filters candidates that satisfy the S11 and imaginary-impedance limits, then uses optimize_cpwd.py to pick the shortest realizable CPWD geometry for the selected beta_l and Char_Imp.
The final LNA table contains NF, gain, S11, bandwidth, DC power, passive values, passive geometries, and optional interstage values. A hinge-penalty score selects the best row, preferring low NF and power while penalizing missed gain, bandwidth, S11, or power targets.
PA Hybrid Optimizer
The PA path uses pa_stage_1_sizer.py with a file such as EXAMPLES/PA_1/pa_stage_1_config.json. It targets a Class-A PA, estimates the number of stages, sizes the final stage from the saturation-power target, and constructs matching elements between stages and at the output.
| Input Group | Examples | Purpose |
|---|---|---|
| Design targets | freq_ghz, gain_req_db, p_sat_db |
Set the operating frequency, required gain, and output-power target. |
| Device constants | cgs, cd, gm, rgate, rs_fixed, vdsat, ft |
Define stage gain, loading, and impedance estimates. |
| Search controls | size_last_search_start, size_last_search_stop, error_threshold, stage_gain_factor |
Control final-stage sizing and stage-count exploration. |
| Passive model data | spiral_inductor, em_l_border |
Converts large shunt-inductor targets into geometry-aware inductor choices. |
The PA optimizer computes the stage count from required gain and per-stage gain, then estimates the last-stage transistor size from the saturation-power requirement.
stages = ceil(gain_req / (10 * log10(stage_gain_factor * (ft / freq)^2)))
size_last ~= size_last_coeff * 10^(p_sat_req / 10)
The script refines size_last with a search loop, checks that the output load condition is valid, and derives a stage-size ladder. Each earlier stage is scaled from the previous one using stage_step, capped to keep the drive progression reasonable.
After stage sizing, the PA optimizer walks through the matching matrix. For the output stage it computes the final load transformation to 50 ohms; for intermediate stages it compares the previous stage source impedance with the current stage load and chooses the appropriate shunt/series matching structure.
Whenever a required shunt inductor exceeds em_l_border, the script queries the inductor optimizer, obtains SRF-aware geometry, and adjusts the companion capacitance so the matching network remains consistent with the realizable passive. The exported JSON contains stage sizes, matching-stage shunt inductors, series capacitors, shunt capacitors, and the final-stage sizing parameters.
Outputs Used by the Next Stage
The JSON output is intentionally shaped for map_initial_size_to_netlist.py. The mapping file supports two modes:
json_list: copies one or more design JSON keys into a netlist annotation.regex_extract: extracts values from formatted strings such as12*1um/60nm.
After mapping, parse_netlist.py reads the sized netlist and generates the primitive layout blocks used by placement and routing.