@vessel-dsp/compiler 0.18.1 → 0.21.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/compile.d.ts +16 -0
- package/dist/compile.d.ts.map +1 -1
- package/dist/compile.js +93 -12
- package/dist/compile.js.map +1 -1
- package/dist/device-laws.d.ts +60 -1
- package/dist/device-laws.d.ts.map +1 -1
- package/dist/device-laws.js +230 -4
- package/dist/device-laws.js.map +1 -1
- package/dist/fixtures/circuits.d.ts +40 -0
- package/dist/fixtures/circuits.d.ts.map +1 -1
- package/dist/fixtures/circuits.js +477 -0
- package/dist/fixtures/circuits.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/link.d.ts.map +1 -1
- package/dist/link.js +4 -3
- package/dist/link.js.map +1 -1
- package/dist/lower.d.ts.map +1 -1
- package/dist/lower.js +10 -0
- package/dist/lower.js.map +1 -1
- package/dist/netlist.d.ts.map +1 -1
- package/dist/netlist.js +92 -1
- package/dist/netlist.js.map +1 -1
- package/dist/part-catalog.d.ts.map +1 -1
- package/dist/part-catalog.js +24 -0
- package/dist/part-catalog.js.map +1 -1
- package/dist/registry-data/bjt.d.ts.map +1 -1
- package/dist/registry-data/bjt.js +1422 -21
- package/dist/registry-data/bjt.js.map +1 -1
- package/dist/registry-data/diode.d.ts.map +1 -1
- package/dist/registry-data/diode.js +293 -0
- package/dist/registry-data/diode.js.map +1 -1
- package/dist/registry-data/index.d.ts +1 -1
- package/dist/registry-data/index.d.ts.map +1 -1
- package/dist/registry-data/index.js.map +1 -1
- package/dist/registry-data/jfet.d.ts.map +1 -1
- package/dist/registry-data/jfet.js +79 -0
- package/dist/registry-data/jfet.js.map +1 -1
- package/dist/registry-data/led.d.ts.map +1 -1
- package/dist/registry-data/led.js +16 -0
- package/dist/registry-data/led.js.map +1 -1
- package/dist/registry-data/loader.d.ts +19 -1
- package/dist/registry-data/loader.d.ts.map +1 -1
- package/dist/registry-data/loader.js +32 -1
- package/dist/registry-data/loader.js.map +1 -1
- package/dist/registry-data/mosfet.d.ts.map +1 -1
- package/dist/registry-data/mosfet.js +12 -0
- package/dist/registry-data/mosfet.js.map +1 -1
- package/dist/registry-data/schema.d.ts +14 -1
- package/dist/registry-data/schema.d.ts.map +1 -1
- package/dist/registry-data/schema.js +6 -2
- package/dist/registry-data/schema.js.map +1 -1
- package/dist/registry-data/zener.d.ts.map +1 -1
- package/dist/registry-data/zener.js +68 -0
- package/dist/registry-data/zener.js.map +1 -1
- package/dist/registry.d.ts +9 -0
- package/dist/registry.d.ts.map +1 -1
- package/dist/registry.js.map +1 -1
- package/dist/types.d.ts +82 -2
- package/dist/types.d.ts.map +1 -1
- package/package.json +2 -2
package/dist/device-laws.js
CHANGED
|
@@ -25,6 +25,135 @@ import { GROUND } from "./types.js";
|
|
|
25
25
|
import { LED_COLOUR_RECORD_ID } from "./registry-data/led.js";
|
|
26
26
|
/** Room-temperature thermal voltage; the diode law needs a reference somewhere. */
|
|
27
27
|
export const THERMAL_VOLTAGE = 0.025_852;
|
|
28
|
+
/**
|
|
29
|
+
* The absolute temperature every registry fit is referred to, in kelvin.
|
|
30
|
+
*
|
|
31
|
+
* Fitted saturation currents and the engine thermal-voltage constant are stated at
|
|
32
|
+
* this temperature (`THERMAL_VOLTAGE` is kT/q at 300 K, not 273.15 + 27), so the
|
|
33
|
+
* ambient-temperature fold scales relative to it and ngspice parity sets
|
|
34
|
+
* `tnom=26.85` to match. With no ambient option the compile stamps exactly today's
|
|
35
|
+
* numbers: the fold is skipped outright below a 1e-9 K band around this value, so
|
|
36
|
+
* the default path shares no arithmetic with the scaled one.
|
|
37
|
+
*/
|
|
38
|
+
export const REFERENCE_TEMPERATURE_KELVIN = 300;
|
|
39
|
+
/** Offset between the compile option's Celsius and the fold's kelvin. */
|
|
40
|
+
const CELSIUS_TO_KELVIN = 273.15;
|
|
41
|
+
/** Boltzmann constant, J/K (exact, SI). */
|
|
42
|
+
const BOLTZMANN_JOULES_PER_KELVIN = 1.380_649e-23;
|
|
43
|
+
/** Elementary charge, C (exact, SI). */
|
|
44
|
+
const ELEMENTARY_CHARGE_COULOMBS = 1.602_176_634e-19;
|
|
45
|
+
/**
|
|
46
|
+
* Bandgap energy per junction material, in eV: the ngspice defaults for the
|
|
47
|
+
* matching device kinds (silicon diode/BJT 1.11, germanium 0.67, Schottky barrier
|
|
48
|
+
* 0.69). An LED junction is a III-V the three-material law does not cover; LEDs run
|
|
49
|
+
* the silicon bandgap and the material-default notice says so.
|
|
50
|
+
*/
|
|
51
|
+
const BANDGAP_ELECTRON_VOLTS = {
|
|
52
|
+
silicon: 1.11,
|
|
53
|
+
germanium: 0.67,
|
|
54
|
+
schottky: 0.69,
|
|
55
|
+
};
|
|
56
|
+
/** The saturation-current temperature exponent (SPICE XTI), shared by all three. */
|
|
57
|
+
const SATURATION_TEMPERATURE_EXPONENT = 3;
|
|
58
|
+
/**
|
|
59
|
+
* The compile option's Celsius as an absolute temperature, validated.
|
|
60
|
+
*
|
|
61
|
+
* Throws a `RangeError` naming the option for a non-finite value or anything below
|
|
62
|
+
* absolute zero: an option is a programmer error, not a source refusal, so it
|
|
63
|
+
* propagates rather than becoming a pedal-shaped answer.
|
|
64
|
+
*/
|
|
65
|
+
export function kelvinFromAmbientCelsius(celsius) {
|
|
66
|
+
if (!Number.isFinite(celsius)) {
|
|
67
|
+
throw new RangeError(`ambientTemperatureC ${String(celsius)} is not a finite temperature in degrees Celsius`);
|
|
68
|
+
}
|
|
69
|
+
if (celsius < -CELSIUS_TO_KELVIN) {
|
|
70
|
+
throw new RangeError(`ambientTemperatureC ${String(celsius)} is below absolute zero (-273.15 C)`);
|
|
71
|
+
}
|
|
72
|
+
return celsius + CELSIUS_TO_KELVIN;
|
|
73
|
+
}
|
|
74
|
+
/** Whether the fold changes any number: outside a 1e-9 K band around 300 K. */
|
|
75
|
+
export function ambientTemperatureScalesJunction(kelvin) {
|
|
76
|
+
return (Math.abs(kelvin - REFERENCE_TEMPERATURE_KELVIN) > 1e-9 &&
|
|
77
|
+
Number.isFinite(kelvin));
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* The SPICE temperature ratio a junction saturation current scales by, relative to
|
|
81
|
+
* the 300 K reference the registry fits are referred to:
|
|
82
|
+
* `Is(T) = Is * (T/Tnom)^(XTI/N) * exp((Eg*q/(N*k)) * (1/Tnom - 1/T))` with XTI = 3.
|
|
83
|
+
* `n` is the junction's own emission coefficient (1 for a BJT or OTA bias diode).
|
|
84
|
+
*/
|
|
85
|
+
function saturationCurrentRatio(emissionCoefficient, material, kelvin) {
|
|
86
|
+
const bandgapJoules = BANDGAP_ELECTRON_VOLTS[material] * ELEMENTARY_CHARGE_COULOMBS;
|
|
87
|
+
const slope = bandgapJoules /
|
|
88
|
+
(emissionCoefficient * BOLTZMANN_JOULES_PER_KELVIN);
|
|
89
|
+
return ((kelvin / REFERENCE_TEMPERATURE_KELVIN) **
|
|
90
|
+
(SATURATION_TEMPERATURE_EXPONENT / emissionCoefficient) *
|
|
91
|
+
Math.exp(slope * (1 / REFERENCE_TEMPERATURE_KELVIN - 1 / kelvin)));
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Fold one finished diode law to the ambient temperature: `thermalVoltage` scales
|
|
95
|
+
* with T (today's constant is kT/q at 300 K) and `saturationCurrent` follows the
|
|
96
|
+
* SPICE law above with the junction's own emission coefficient. Series resistance
|
|
97
|
+
* and breakdown voltage carry no temperature model and are kept as stated.
|
|
98
|
+
*/
|
|
99
|
+
function diodeLawAtAmbientTemperature(law, material, kelvin) {
|
|
100
|
+
return {
|
|
101
|
+
...law,
|
|
102
|
+
thermalVoltage: law.thermalVoltage * (kelvin / REFERENCE_TEMPERATURE_KELVIN),
|
|
103
|
+
saturationCurrent: law.saturationCurrent *
|
|
104
|
+
saturationCurrentRatio(law.emissionCoefficient, material, kelvin),
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Fold one finished BJT law to the ambient temperature: as the diode fold, with
|
|
109
|
+
* the Ebers-Moll ideality of 1. The excess collector-base leakage is a junction
|
|
110
|
+
* prefactor beyond the ideal reverse current, so it scales with the same ratio;
|
|
111
|
+
* betas carry no temperature model and are kept as stated.
|
|
112
|
+
*/
|
|
113
|
+
function bjtLawAtAmbientTemperature(law, material, kelvin) {
|
|
114
|
+
const ratio = saturationCurrentRatio(1, material, kelvin);
|
|
115
|
+
return {
|
|
116
|
+
...law,
|
|
117
|
+
thermalVoltage: law.thermalVoltage * (kelvin / REFERENCE_TEMPERATURE_KELVIN),
|
|
118
|
+
saturationCurrent: law.saturationCurrent * ratio,
|
|
119
|
+
leakageAmps: law.leakageAmps * ratio,
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Fold one finished OTA law to the ambient temperature: the four-terminal bias
|
|
124
|
+
* diode is a silicon junction with ideality 1. A law that states no bias-diode
|
|
125
|
+
* pair (a sections entry carrying transconductance only) gains the scaled class
|
|
126
|
+
* defaults the lowering would otherwise stamp at 300 K, so the program carries
|
|
127
|
+
* the temperature rather than the lowering re-defaulting it.
|
|
128
|
+
*/
|
|
129
|
+
function otaLawAtAmbientTemperature(law, kelvin) {
|
|
130
|
+
const ratio = saturationCurrentRatio(1, "silicon", kelvin);
|
|
131
|
+
return {
|
|
132
|
+
...law,
|
|
133
|
+
saturationCurrent: (law.saturationCurrent ?? 1e-12) * ratio,
|
|
134
|
+
thermalVoltage: (law.thermalVoltage ?? THERMAL_VOLTAGE) *
|
|
135
|
+
(kelvin / REFERENCE_TEMPERATURE_KELVIN),
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* A part's junction material for the temperature fold: the registry entry's typed
|
|
140
|
+
* `material` for the exact folded part id -- the same rung the law refinement
|
|
141
|
+
* uses -- or null when no entry states one. Null means the silicon default, which
|
|
142
|
+
* the compile records (`material-default-silicon`); it is never inferred from the
|
|
143
|
+
* part number or any prose.
|
|
144
|
+
*/
|
|
145
|
+
export function registryMaterialFor(registry, partNumber) {
|
|
146
|
+
if (partNumber === null) {
|
|
147
|
+
return null;
|
|
148
|
+
}
|
|
149
|
+
const folded = foldPartId(partNumber);
|
|
150
|
+
for (const entry of registry.entries) {
|
|
151
|
+
if (entry.partIds.some((id) => foldPartId(id) === folded)) {
|
|
152
|
+
return entry.material ?? null;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
return null;
|
|
156
|
+
}
|
|
28
157
|
/**
|
|
29
158
|
* Closed and open switch resistances. Not arbitrary: the ratio sets the matrix
|
|
30
159
|
* condition number, so 1e-2 to 1e9 is chosen to be electrically indistinguishable
|
|
@@ -107,6 +236,18 @@ export const SILICON_FORWARD_BETA = 100;
|
|
|
107
236
|
*/
|
|
108
237
|
export const JFET_DEFAULT_THRESHOLD_VOLTS = -2;
|
|
109
238
|
export const JFET_DEFAULT_TRANSCONDUCTANCE = 1e-3;
|
|
239
|
+
/**
|
|
240
|
+
* A discrete MOSFET's body-diode class defaults, stamped when the registry
|
|
241
|
+
* record for the exact part types no body parameters (no shipped record does
|
|
242
|
+
* today). The values are ngspice's own MOS bulk-diode defaults (IS 1e-14 A,
|
|
243
|
+
* N 1) by value, deliberately: the deck emitter carries the same pair on its
|
|
244
|
+
* explicit diode, so the two consoles agree by construction rather than by a
|
|
245
|
+
* fit. A silicon PN junction either way; the name is separate from
|
|
246
|
+
* `SILICON_SATURATION_CURRENT` so the body default reads beside the fet law.
|
|
247
|
+
* Named by `fet-law-default-parameters`, never stamped silently.
|
|
248
|
+
*/
|
|
249
|
+
export const MOSFET_BODY_SATURATION_CURRENT = 1e-14;
|
|
250
|
+
export const MOSFET_BODY_EMISSION_COEFFICIENT = 1;
|
|
110
251
|
/**
|
|
111
252
|
* A winding's DC resistance, in the three states the source can be in.
|
|
112
253
|
*
|
|
@@ -598,7 +739,7 @@ function zenerRailDerivations(netlist, registry, nodeToVoltage, devicesTouchingN
|
|
|
598
739
|
}
|
|
599
740
|
return derived;
|
|
600
741
|
}
|
|
601
|
-
export function attachDeviceLaws(netlist, registry) {
|
|
742
|
+
export function attachDeviceLaws(netlist, registry, options) {
|
|
602
743
|
const regulatedBase = registrySuppliedVoltages(netlist, registry);
|
|
603
744
|
const nodeToVoltage = buildNodeToVoltageMap(netlist, regulatedBase);
|
|
604
745
|
const devicesTouchingNode = deviceCountByNode(netlist);
|
|
@@ -653,6 +794,10 @@ export function attachDeviceLaws(netlist, registry) {
|
|
|
653
794
|
internalNodes.set(key, node);
|
|
654
795
|
return node;
|
|
655
796
|
};
|
|
797
|
+
// The ambient temperature in kelvin this compile folds to. Absent means the
|
|
798
|
+
// 300 K reference: the junction fold and the thermistor resistance both land
|
|
799
|
+
// exactly on today's numbers (the fold is skipped outright near 300 K).
|
|
800
|
+
const ambientKelvin = options?.ambientKelvin ?? REFERENCE_TEMPERATURE_KELVIN;
|
|
656
801
|
const devices = [];
|
|
657
802
|
const resolutions = [];
|
|
658
803
|
for (const device of netlist.devices) {
|
|
@@ -664,7 +809,7 @@ export function attachDeviceLaws(netlist, registry) {
|
|
|
664
809
|
}
|
|
665
810
|
if (expanded === null) {
|
|
666
811
|
devices.push(device);
|
|
667
|
-
resolutions.push(resolveDevice(device, registry, rails, supply, taperByControl, mainsFrequencyHz, devicesTouchingNode, nodeToVoltage, netlist));
|
|
812
|
+
resolutions.push(resolveDevice(device, registry, rails, supply, taperByControl, mainsFrequencyHz, devicesTouchingNode, nodeToVoltage, netlist, ambientKelvin));
|
|
668
813
|
continue;
|
|
669
814
|
}
|
|
670
815
|
for (const [section, resolution] of expanded) {
|
|
@@ -678,9 +823,44 @@ export function attachDeviceLaws(netlist, registry) {
|
|
|
678
823
|
devices,
|
|
679
824
|
nodes: internalNodes.size === 0 ? netlist.nodes : [...netlist.nodes, ...internalNodes.values()],
|
|
680
825
|
},
|
|
681
|
-
resolutions,
|
|
826
|
+
resolutions: foldAmbientTemperature(devices, resolutions, registry, ambientKelvin),
|
|
682
827
|
};
|
|
683
828
|
}
|
|
829
|
+
/**
|
|
830
|
+
* Fold the ambient temperature into every finished junction law, at compile time.
|
|
831
|
+
*
|
|
832
|
+
* With no ambient (or within a 1e-9 K band of 300 K) the resolutions pass through
|
|
833
|
+
* untouched -- the same array contents, so every program is byte-identical to
|
|
834
|
+
* today's. Otherwise each diode, BJT and OTA law is replaced by its scaled copy;
|
|
835
|
+
* every other outcome (macro, open, unsupported, non-junction laws) is returned as
|
|
836
|
+
* is. The runtime, the `Program` shape and both consoles are untouched: the option
|
|
837
|
+
* changes the numbers written into the stamps and nothing else.
|
|
838
|
+
*/
|
|
839
|
+
function foldAmbientTemperature(devices, resolutions, registry, ambientKelvin) {
|
|
840
|
+
const kelvin = ambientKelvin;
|
|
841
|
+
if (!ambientTemperatureScalesJunction(kelvin)) {
|
|
842
|
+
return resolutions;
|
|
843
|
+
}
|
|
844
|
+
const byId = new Map(devices.map((device) => [device.id, device]));
|
|
845
|
+
return resolutions.map((resolution) => {
|
|
846
|
+
if (resolution.outcome !== "law") {
|
|
847
|
+
return resolution;
|
|
848
|
+
}
|
|
849
|
+
const law = resolution.law;
|
|
850
|
+
if (law.kind !== "diode" && law.kind !== "bjt" && law.kind !== "ota") {
|
|
851
|
+
return resolution;
|
|
852
|
+
}
|
|
853
|
+
const material = registryMaterialFor(registry, byId.get(resolution.device)?.identity.partNumber ?? null) ??
|
|
854
|
+
"silicon";
|
|
855
|
+
if (law.kind === "diode") {
|
|
856
|
+
return { ...resolution, law: diodeLawAtAmbientTemperature(law, material, kelvin) };
|
|
857
|
+
}
|
|
858
|
+
if (law.kind === "bjt") {
|
|
859
|
+
return { ...resolution, law: bjtLawAtAmbientTemperature(law, material, kelvin) };
|
|
860
|
+
}
|
|
861
|
+
return { ...resolution, law: otaLawAtAmbientTemperature(law, kelvin) };
|
|
862
|
+
});
|
|
863
|
+
}
|
|
684
864
|
/**
|
|
685
865
|
* A multi-section part as one device per section, or `null` when the part is not multi-section.
|
|
686
866
|
*
|
|
@@ -2343,7 +2523,7 @@ function packageDeviceParameters(device, registry) {
|
|
|
2343
2523
|
}
|
|
2344
2524
|
return parameters;
|
|
2345
2525
|
}
|
|
2346
|
-
function resolveDevice(device, registry, rails, supply, taperByControl, mainsFrequencyHz, devicesTouchingNode, nodeToVoltage, netlist) {
|
|
2526
|
+
function resolveDevice(device, registry, rails, supply, taperByControl, mainsFrequencyHz, devicesTouchingNode, nodeToVoltage, netlist, ambientKelvin = REFERENCE_TEMPERATURE_KELVIN) {
|
|
2347
2527
|
// A component declared as one transistor that is really several devices in one shell. Opened
|
|
2348
2528
|
// rather than stamped, for the reason `isNonExecutableIcSupportShell` opens an IC shell: there
|
|
2349
2529
|
// is no single device here to describe, and a transistor law would invent one. Reported by
|
|
@@ -2469,6 +2649,39 @@ function resolveDevice(device, registry, rails, supply, taperByControl, mainsFre
|
|
|
2469
2649
|
law: { kind: "conductance", siemens: 1 / ohms },
|
|
2470
2650
|
};
|
|
2471
2651
|
}
|
|
2652
|
+
case "thermistor": {
|
|
2653
|
+
// An NTC disc at the ambient temperature: `R(T) = R_ref * exp(Beta *
|
|
2654
|
+
// (1/T - 1/T_ref))`, folded here at compile time like the junction fold
|
|
2655
|
+
// above, and stamped as the conductance a resistor of that value takes.
|
|
2656
|
+
// Beta 0 folds to exactly R_ref (exp(0) is 1), so the negative control
|
|
2657
|
+
// compiles to the same program as the same-valued resistor.
|
|
2658
|
+
//
|
|
2659
|
+
// **No self-heating.** The resistance is a function of the ambient
|
|
2660
|
+
// alone: the current through the disc does not warm it. A thermistor
|
|
2661
|
+
// that heats under load needs a thermal state the program does not have.
|
|
2662
|
+
const referenceOhms = device.parameters.referenceOhms ?? 0;
|
|
2663
|
+
const beta = device.parameters.betaKelvin ?? 0;
|
|
2664
|
+
const referenceKelvin = device.parameters.referenceKelvin ?? 298.15;
|
|
2665
|
+
if (device.nodes.length !== 2) {
|
|
2666
|
+
return unsupported(device, `thermistor has ${device.nodes.length} terminals, not the two a polarity-free disc carries`);
|
|
2667
|
+
}
|
|
2668
|
+
if (!(referenceOhms > 0) ||
|
|
2669
|
+
!Number.isFinite(beta) ||
|
|
2670
|
+
beta < 0 ||
|
|
2671
|
+
!(referenceKelvin > 0)) {
|
|
2672
|
+
return unsupported(device, "thermistor carries no usable Resistance, Beta or reference temperature");
|
|
2673
|
+
}
|
|
2674
|
+
const ohms = referenceOhms *
|
|
2675
|
+
Math.exp(beta * (1 / ambientKelvin - 1 / referenceKelvin));
|
|
2676
|
+
if (!(ohms > 0) || !Number.isFinite(ohms)) {
|
|
2677
|
+
return unsupported(device, "thermistor folds to a non-positive resistance at this ambient temperature");
|
|
2678
|
+
}
|
|
2679
|
+
return {
|
|
2680
|
+
outcome: "law",
|
|
2681
|
+
device: device.id,
|
|
2682
|
+
law: { kind: "conductance", siemens: 1 / ohms },
|
|
2683
|
+
};
|
|
2684
|
+
}
|
|
2472
2685
|
case "potentiometer": {
|
|
2473
2686
|
const ohms = device.parameters.ohms ?? 0;
|
|
2474
2687
|
if (!(ohms > 0)) {
|
|
@@ -2945,6 +3158,13 @@ function resolveDevice(device, registry, rails, supply, taperByControl, mainsFre
|
|
|
2945
3158
|
// number only. This shares the `fet` law kind with JFET entries; part
|
|
2946
3159
|
// ids are disjoint across the two classes, so a lookup by exact folded
|
|
2947
3160
|
// part id cannot cross from one to the other.
|
|
3161
|
+
//
|
|
3162
|
+
// **MOSFET is decided by the declared `kind`, read here.** This `case`
|
|
3163
|
+
// is the law selection the compiler already makes from the device's
|
|
3164
|
+
// typed kind: `kind: mosfet` lowers here, `kind: jfet` to the case
|
|
3165
|
+
// above. No part-number prose is read (a `2N7000` string never decides
|
|
3166
|
+
// anything), and the registry class is not consulted for the decision
|
|
3167
|
+
// either -- it only refines the numbers once the kind has decided.
|
|
2948
3168
|
const catalogued = registryLawFor(registry, device.identity.partNumber, "fet");
|
|
2949
3169
|
const entry = catalogued !== null && catalogued.kind === "fet" ? catalogued : null;
|
|
2950
3170
|
return {
|
|
@@ -2963,6 +3183,12 @@ function resolveDevice(device, registry, rails, supply, taperByControl, mainsFre
|
|
|
2963
3183
|
gateSaturationCurrent: entry?.gateSaturationCurrent ?? 0,
|
|
2964
3184
|
gateOnsetVolts: entry?.gateOnsetVolts ?? 0,
|
|
2965
3185
|
gateScaleVolts: entry?.gateScaleVolts ?? 1,
|
|
3186
|
+
// The body diode. Read from the registry entry only (a MOSFET
|
|
3187
|
+
// gate/body refinement is never a per-device document value, the
|
|
3188
|
+
// same rule the gate terms above follow), else the class
|
|
3189
|
+
// defaults, which `fet-law-default-parameters` names.
|
|
3190
|
+
bodySaturationCurrent: entry?.bodySaturationCurrent ?? MOSFET_BODY_SATURATION_CURRENT,
|
|
3191
|
+
bodyEmissionCoefficient: entry?.bodyEmissionCoefficient ?? MOSFET_BODY_EMISSION_COEFFICIENT,
|
|
2966
3192
|
},
|
|
2967
3193
|
};
|
|
2968
3194
|
}
|