AN-04 — A nonlinear FET model from a reference kit
A transistor that already has a model in another simulator's design kit can become a ComposedFET by sampling that model and fitting what it gives. Which runs to make in the source simulator, which plane to sample at and how to get there, what each Model Composer step does with the result, and how to check the model against the kit it came from.
When this note applies
A transistor often already has a good model: the one in a foundry's or a vendor's design kit, written for another
simulator. That model can be the reference for a circuitRF model. Sample it the way a lab would measure a device,
hand the samples to Model Composer, and the result is a .cmodel that a schematic
places as a ComposedFET and that DC, S-parameters, harmonic balance and
loadpull all use.
Sampled data is better than measured data in three ways, and the flow below is built around all three:
- It is noise-free and as dense as you like. A grid of every 0.1 V costs seconds, not a week on a probe station.
- It can be taken where no instrument can reach: at the core's own terminals, inside the pads, inductances and resistances, and with self-heating switched off.
- It can be repeated at will, so the same benches can be run on the kit and on the fitted model and the two compared point for point.
The work that takes longest is not the fit. It is deciding what to export from the source simulator and getting it out in a form the composer reads. Most of this note is about that.
The flow
Two kinds of run come out of the source simulator, and they have different jobs:
| Runs | Become | Used for |
|---|---|---|
| DC I–V, small-signal Y or S at every DC bias, at one or more temperatures | One SimulatedTables data set |
Fitting the currents and the charges |
| Power sweeps, two-tone sweeps, loadpull | LargeSignal data sets |
Validation only — never fitted |
Keeping the large-signal runs out of the fit is what makes them a fair test: the model has never seen them.
What to run in the source simulator
Use one test bench per run, with the kit's transistor at the size you want as the base, and nothing else in it but bias and ports.
| Run | Analysis | Sweep | What to save |
|---|---|---|---|
| I–V | DC | Vgs inside Vds, inside temperature when there are several | Vgs, Vds and the gate and drain currents at every point |
| Small-signal | S-parameters at every bias of the DC sweep | One low frequency for the charges (a few hundred MHz to 1 GHz); add a span only if the network is to be checked | Y (or S) of the two-port, gate port 1, drain port 2, source grounded |
| Capacitances (optional) | The core's operating-point capacitances, where the simulator reports them | The same bias grid | cgs, cgd, cds and optionally cm, or the matrix C |
| Large-signal (for validation) | Harmonic balance: power sweep at the operating bias; loadpull at the frequencies you care about | Drive up into compression | The power sweep as a CSV; the loadpull as a file the composer reads (.spl, .lpcwave or a CSV) |
Ranges. Sample wider than the circuit will ever go: from 2 V below pinch-off to well into forward gate conduction, and from 0 V (or slightly negative) to beyond the peak drain swing. A model is continued linearly past the edge of its data, and that continuation is not the device. Sampled points cost nothing; the bias table gives the steps.
Settings in the source simulator. Three matter, and each one gives a model that looks right at the operating point and is wrong elsewhere when it is missed:
- Self-heating off for every fitting run — the kit's thermal resistance set to zero, or its thermal switch off. The composer fits isothermal currents, at the temperature of each run, and adds the heating itself on the Thermal step. Data that already contains heating would be heated twice.
- Traps and dispersion off, unless you mean to model them. A DC sweep with them on and a small-signal analysis with them frozen describe two different devices.
- Stay inside the kit's valid range. Many kit models clamp their inputs outside it, and the clamped region samples as flat data that the fit then reproduces faithfully.
Temperature. Run the DC and small-signal sweeps at two or more temperatures, spanning the junction temperatures
the circuit will reach under drive (the ambient plus the heating). The model then takes T as an input, follows the
run's temp, and self-heating becomes available.
Choosing the plane, and the negative network
The composer always fits the core: the intrinsic gate, drain and source, inside the pads, inductances and series resistances. A kit device is that core wrapped in its own extrinsic network, and the samples can be taken on either side of it.
| Plane | How to sample | In the composer |
|---|---|---|
| Intrinsic — preferred | Record the core's internal node voltages, if the kit exposes them; or wrap the kit device in its negative network, as drawn | ReferencePlane=intrinsic. The network holds the kit's values, all locked; nothing is fitted to it |
| Device | Sample at the kit device's terminals, as it is | ReferencePlane=device, with a six-pin network holding the kit's values, locked; the composer removes it |
Why intrinsic is preferred. At the intrinsic plane the points lie exactly on the grid you swept, and the network
plays no part in the fit: it is exported with the core exactly as the kit has it. At the device plane the composer
removes the network with a DC solve carrying the sampled currents, so the intrinsic points move off the grid and every
Table constituent must re-grid them. Either way the network values come from the kit, not from a fit: a fit can only
find values the data can tell apart, and the kit already knows them.
Building the negative network. Take the kit's extrinsic network from its model card or documentation and draw it again in the source simulator's bench, between each port and the kit device's terminal:
- Read it from the core outwards. What sits next to the core in the kit sits next to the port in the copy. For a
two-shell network — pad capacitance, inductance, inner capacitance, resistance, from the terminal in — the copy is
−R,−Cinner,−L,−Cpad, from the port in. - Negate every value, the mutuals included. A source resistance and inductance that both loops share go in the source lead, negated, in the same place.
- Use it in DC and small-signal analyses only. Negative elements are exact in a linear analysis and make the bench non-passive, so they have no place in harmonic balance or a transient. The large-signal validation runs use the kit device as it is.
- At DC only the resistances matter. The
−Rcancels the kit's own drop, so the core sees exactly the port's voltage, and the I–V grid you sweep is the intrinsic grid. - A value that depends on temperature must be negated at each temperature you run.
If the kit's network values are not published, sample at the device plane instead and let the
Network step fit them cold-FET and multi-bias. That needs S over a
frequency span, and the two cold biases (Vds = 0 V, pinched off and with the gate forward-biased).
Writing the tables
The composer reads a simulator's tables as named arrays: a MATLAB .mat (written by MATLAB, or by Python with
scipy.io.savemat) or a NumPy .npz (numpy.savez). Name the arrays as you like. Every array, its unit and the
layouts the import accepts are in File formats.
A simulator that saves a binary simulation dataset (.ds) needs none of the writing below: import that file as
it is. Its arrays are named after the analysis that produced them, Group.Variable — DC1.Vgs, DC1.VD.i, SP1.S —
and a DC block and an S block swept over the same biases combine into one data set. The map is written by those names
(A binary simulation dataset):
circuitrf model import kit.cmc kit_sweep.ds --as SimulatedTables --map DC1.Vgs=vgs --map DC1.Vds=vds --map -DC1.VD.i=id --map -DC1.VG.i=ig --map SP1.freq=freq --map SP1.S=S --condition ReferencePlane=intrinsic
The - in front of the two currents reads them negated, because a bias source's current is recorded flowing into the
source, out of the device.
What the file holds. For the runs above, swept as Vgs from −5 to 2 V in 0.1 V steps (71 values), Vds from 0 to 40 V in 0.5 V steps (81), at 25, 85 and 150 °C, with Y at 1 GHz:
| Array | Shape | Unit | Holds |
|---|---|---|---|
vgs |
71 | V | The Vgs sweep values |
vds |
81 | V | The Vds sweep values |
T |
3 | °C | The temperatures |
id, ig |
71 × 81 × 3 | A | The DC currents at each Vgs, Vds and T, positive into the terminal |
freq |
1 | Hz | The small-signal frequency |
Y |
71 × 81 × 3 × 1 × 2 × 2 | S, complex | Y at each bias and frequency: gate port 1, drain port 2 |
cgs, cgd, cds (optional) |
71 × 81 × 3 | F | The core's operating-point capacitances |
The import lists the arrays of the file you pick in that form, before anything is mapped:
cds 71 × 81 × 3
cgd 71 × 81 × 3
cgs 71 × 81 × 3
freq 1
id 71 × 81 × 3
ig 71 × 81 × 3
T 3
vds 81
vgs 71
Y 71 × 81 × 3 × 1 × 2 × 2 complex
From Python, with the results gathered into arrays of those shapes:
import numpy as np
# vgs (71,), vds (81,), T (3,), freq (1,); id, ig (71, 81, 3) in A; Y (71, 81, 3, 1, 2, 2) complex, in S
np.savez("kit_tables.npz", vgs=vgs, vds=vds, T=T, id=id, ig=ig, freq=freq, Y=Y)
From MATLAB, the 2 × 2 matrix may come first, as MATLAB code usually has it — Y(i, j, f, g, d, t), shaped
2 × 2 × 1 × 71 × 81 × 3:
save('kit_tables.mat', 'vgs', 'vds', 'T', 'id', 'ig', 'freq', 'Y')
The import works out the layout from the shapes, and says how it read any array not in the documented order. The axes
of a grid may come in any order; a table at one frequency needs no frequency axis. A flat list with one value per point
(as a simulator's own export often is) reads too: vgs, vds, T, id and ig each 71 × 81 × 3 = 17,253 long, and
Y 17,253 × 1 × 2 × 2. With the names above, or any of the usual spellings (Vg, Ids, Temp, freq_GHz), the import
maps the arrays itself.
At the device plane, the file is the same with Y over a frequency span: freq 20 long and Y 71 × 81 × 3 × 20 ×
2 × 2. A sweep that also wrote the two cold biases as separate runs can go in a second file, or a Touchstone folder.
Things to check before importing; the import warns about the first three when it sees them (What the import checks):
- Signs. Currents are positive into the terminal. A simulator that reports the drain current flowing out gives
a model with negative transconductance. Map such an array with a leading
-to read it negated:-DC1.VD.i=id. - The port order. Gate is port 1, drain port 2, source grounded.
- Units. Arrays are read in SI and °C. A frequency in GHz, currents in mA or temperatures in kelvin need their unit
in the map:
freq:GHz,id:mA,T:K. - The base size. Note the kit device's finger count and unit gate width: they become
N0andW0, and every instance scales from them (Periphery scaling). Sample at a size from the middle of the range you will use.
In Model Composer, step by step
Tools ▸ Model Composer…, choose Active, and import the .npz, .mat or .ds on the Data step as
Simulated tables. The map field fills itself from the array names; check it against the arrays listed beside it.
For a .ds with a DC block and an S block, complete it with each quantity's Group.Variable name. The steps then
run in order; for kit data some of them have nothing to do.
| Step | For kit data |
|---|---|
| Data | Import the tables as Simulated tables: map each array, and state ReferencePlane and, for a single temperature, AmbientC. Import each large-signal run as Large signal. Set N0 and W0 to the sampled device's. |
| Pads | None. A simulated device has no probe pads. |
| Network | Pick a stock network or open a six-pin .csch of the kit's own, type the kit's values, and lock every one. Set each value's scaling rule. With every value locked, the fit holds them. |
| Current | Id and Ig. The ANN default suits most kits; see below when it does not. |
| Charge | Qg and Qd, from Y, or from the capacitance table if that is what you saved. The default trains an ANN on the capacitances alone. |
| Thermal | Turn self-heating on and type the kit's Rth and Cth (or its thermal ladder), since the data was sampled isothermal. Extraction needs pulsed data that a kit does not give. |
| Traps | None, unless the kit models them and you sampled them as the reference describes. |
| Check | Check Charge Conservation. A kit's own charges can fail it; the model's must pass. |
| Validate | Run all. Each large-signal set is compared at its own bench (below). |
| Export | Writes the .cmodel. VA writes the same model as Verilog-A source for another simulator. |
When the defaults are not enough
The defaults are chosen for a measured device over an ordinary bias range: a two-layer network of 8 tanh neurons
per constituent, and a relative weighting floored at 10 % of the largest current. A kit sampled over a wide range —
deep pinch-off to forward conduction, several temperatures, tens of thousands of points — asks more of a fit than
that. Look at the fit before changing anything:
- The status line after a fit gives each constituent's held-out error and its training domain, e.g.
Id: ANN 2×8 · held-out 0.8 % · domain 412 pts. When an ANN's held-out error passes 2 % of the current's range on more than 2,000 training points, it adds the next size up:2×8 under-fits 24,000 points: try 2×16, or a Table. - The Error tab on the Current step maps model minus data over the bias plane. An error concentrated in one corner — subthreshold, the knee, the hot end — says which lever to pull.
- The Gm and Gds tabs compare the data's own derivatives with the model's. Harmonic balance runs on the derivatives, so a current that fits in value and not in slope still drives badly.
Then, one lever at a time:
| Symptom | Try |
|---|---|
| Held-out error high everywhere | A larger network on the method picker (more neurons, or a third layer), more iterations, or more restarts on the step |
| Subthreshold current poor | Lower Id floor on the Current step (IdFloor, a fraction of the largest current), so small currents count for more |
| Small gate currents lost | Lower Ig floor on the Current step (IgFloor), the level below which Ig is fitted on a linear rather than a logarithmic scale |
| The knee or the hot end poor | More points there in the source simulator; a sampled grid can always be made finer |
| Every ANN size leaves a residual | A Table constituent: on gridded kit data it is the samples themselves (below) |
| An equation template does not fit | Expected over a wide range: the templates are for compact, few-parameter models. Use an ANN or a Table |
Table re-gridding. When the points do not lie on a grid, a Table constituent samples a smooth function of them
onto its grid and fits a spline to that. The function is an ANN trained on the points by default, or a radial-basis
interpolant (RBF) through them. The RBF solves one dense system over every point, so its memory grows with the
square of the point count and its time with the cube: 1,000 points take a tenth of a second, 4,000 about 11 s, 5,000
about 22 s. Above 5,000 points the fit refuses before it starts and names the ANN instead. A dense kit sweep is
usually a grid, and then no re-grid happens at all.
Checking the model against the kit
The validation is only as fair as the benches on the two sides are equal. A difference in the bench reads as a difference in the model.
- The same bench, both sides. The same bias, the same source and load terminations at every harmonic, the same
frequency and drive plan, the same compression point. Show testbench on the Validate step writes each item's
.cnl, and the Model Validation Report names its benches intestbenches/, so the circuitRF side is on record. - The same thermal state. Validate with self-heating on in both simulators, at the kit's own thermal resistance. The isothermal data trained the core; the validation tests the model as a designer will use it.
- A loadpull at compression, not drive by drive. The Validate step compares each load at the same gain compression (3 dB by default), so a model that compresses a little earlier is not marked wrong at every drive level.
- Loads near the edge of stability. A load at which the source simulator's drive-up does not converge, or turns back on itself, is a statement about that load, not about either model. Leave it out of both sides or run both at a source impedance that keeps the input passive.
- Bias S at the terminals. Place the exported model and the kit device side by side in one S-parameter bench at a few biases. The core was fitted inside the network; this checks the two together.
When a comparison disagrees, the dashed loop in the flow goes back into the composer — a step's settings, a
network value, Rth — not back to the source simulator, unless the data itself was short.
Tables on the kit's own grid
Intrinsic-plane tables from a kit lie exactly on the swept Vgs × Vds (× T) grid, and for those the Table method
is the route to take. When a constituent's training points form a complete grid, every combination present once, the
fit uses the samples themselves as the table: a tensor-product cubic spline through them, with no network to train
and no re-grid, and no Re-grid setting consulted. The status line says so, e.g. Id: Table on the data's own 101 × 121 × 5 grid, 10 vgs line(s) held out. The held-out points are whole grid lines along Vgs, so the training
points stay a grid and the held-out error still measures the table between lines, comparably with the other
methods. The Charge step does the same with capacitances on a grid: each is splined through its own samples and
integrated on that grid.
A grid with a hole, from an excluded point or a sample the source simulator did not converge, is re-gridded instead,
and the status line names the missing sites: Id: the data is a 101 × 121 grid missing 1 site(s) — (vgs -1, vds 2) — so it is re-gridded. Re-run that sample, or accept the re-grid.
Writing the .cmodel by hand remains the route for a law the composer cannot fit: a .cmodel is an open format
(Writing a .cmodel), a Table constituent is a
tensor-product cubic spline on a grid of sites, and the network, the scaling rules and the thermal model go in the
same file. circuitrf check reads it back.
The composer remains the place to check such a model. circuitrf model validate kit.cmc --model kit.cmodel
compares it with a document's data exactly as the Validate step compares a fitted one, and circuitrf model check-charge on a .cnl that places it checks its charges.
The same flow headless
Every step is a circuitrf model noun, the same functions the window calls (Model Composer in the
CLI):
circuitrf model new kit.cmc --kind active --network gan-two-shell --fingers 4 --unit-width "125 um"
circuitrf model import kit.cmc kit_tables.npz --as SimulatedTables --condition ReferencePlane=intrinsic
circuitrf model fit kit.cmc --step all
circuitrf model check-charge kit.cmc
circuitrf model validate kit.cmc
circuitrf model export kit.cmc -o kit.cmodel
circuitrf model export kit.cmc -o kit.va
The network's values and locks are part of the .cmc, which is JSON (File formats);
type them in the window's Values table, or write them into the document, before fit.
Checklist
- Self-heating off and traps off in every fitting run; the temperatures span the junction temperatures the circuit reaches.
- The I–V grid runs from below pinch-off into forward gate conduction and past the peak drain swing.
- Y or S at every DC bias, at a low frequency for the charges.
- The plane is stated:
intrinsicthrough the kit's internal nodes or its negative network, ordevicewith the kit's network in the composer. - The kit's network values are typed and locked, each with its scaling rule.
- Currents are positive into the terminal; gate is port 1, drain port 2.
N0andW0are the sampled device's.- The kit's
RthandCthare typed on the Thermal step. - Large-signal runs are imported as Large signal, for validation only, and both simulators run the same benches.