circuitRF Application Note

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:

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

Reference kit its own model, its own simulator Sampled tables DC I–V, Y, per T .mat Model Composer fit and check .cmc ComposedFET the model .cmodel Validate and report the same benches in both simulators power sweeps, loadpull refit
The whole flow. Small-signal and DC samples of the kit become the model; large-signal runs of the kit judge it. The dashed path is the loop: a validation that disagrees sends you back to a step in the composer, not to the source simulator.

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:

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.

port negative copy −Rg −Ci −Lg −Cp kit's network Cp Lg Ci Rg core kit device device plane intrinsic plane together an identity: the port's V and I are the core's
Sampling at the intrinsic plane when the kit gives no access to its internal nodes. The negative copy is the kit's own extrinsic network read from the core outwards, every value negated; cascaded with the real one it is the identity, at DC and at every frequency. One side of the gate is drawn; the drain and source are treated the same way.
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:

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

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.

Data tables, and large-signal Pads None Network kit's values, all locked Current Id, Ig: ANN or Table Charge Qg, Qd from Y or C table Thermal kit's Rth, Cth, typed Traps None Check charge conservation Validate against the kit's runs Export .cmodel, or .va
The steps of an active document, with what each does for kit data. Dashed steps have nothing to do; the two outlined in the accent colour are where the fitting happens and where the settings are worth a look.
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:

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.

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