diff --git a/src/spicelib/devices/vdmos/vdmosload.c b/src/spicelib/devices/vdmos/vdmosload.c index a322cb989..f0a4e8ee2 100644 --- a/src/spicelib/devices/vdmos/vdmosload.c +++ b/src/spicelib/devices/vdmos/vdmosload.c @@ -15,9 +15,7 @@ VDMOS: 2018 Holger Vogt #include "ngspice/suffix.h" static double -cweakinv(double sl, double shift, double vgst, double vds, double lambda, double beta, double vt, double mtr); -static double -cweakinv2(double sl, double shift, double vgst, double vds, double lambda, double beta, double vt, double mtr); +cweakinv2(double sl, double shift, double vgst, double vds, double lambda, double beta, double vt, double mtr, double theta); int @@ -282,59 +280,83 @@ VDMOSload(GENmodel *inModel, CKTcircuit *ckt) */ double betap; double vgst; - double onfg, fgate, Betam, dfgdvg; von = (model->VDMOSvt0*model->VDMOStype); vgst = (here->VDMOSmode == 1 ? vgs : vgd) - von; vdsat = MAX(vgst, 0); - onfg = 1.0+model->VDMOStheta*vgst; - fgate = 1.0/onfg; - Betam = Beta * fgate; - dfgdvg = -model->VDMOStheta*fgate*fgate; - /* drain current including subthreshold current - * numerical differentiation for gd and gm with a delta of 2 mV */ - if (model->VDMOSksubthresGiven && (here->VDMOSmode == 1)) { - double delta = 0.001; - cdrain = cweakinv(model->VDMOSksubthres, model->VDMOSsubshift, vgst, vds, model->VDMOSlambda, - Betam, vt, model->VDMOSmtr); - /* gd */ - double vds1 = vds + delta; - double cdrp = cweakinv(model->VDMOSksubthres, model->VDMOSsubshift, vgst, vds1, model->VDMOSlambda, - Betam, vt, model->VDMOSmtr); - vds1 = vds - delta; - double cdrm = cweakinv(model->VDMOSksubthres, model->VDMOSsubshift, vgst, vds1, model->VDMOSlambda, - Betam, vt, model->VDMOSmtr); - here->VDMOSgds = (cdrp - cdrm) / (2. * delta); - /* gm */ - double vgst1 = vgst + delta; - cdrp = cweakinv(model->VDMOSksubthres, model->VDMOSsubshift, vgst1, vds, model->VDMOSlambda, - Betam, vt, model->VDMOSmtr); - vgst1 = vgst - delta; - cdrm = cweakinv(model->VDMOSksubthres, model->VDMOSsubshift, vgst1, vds, model->VDMOSlambda, - Betam, vt, model->VDMOSmtr); - here->VDMOSgm = (cdrp - cdrm) / (2. * delta) * fgate + dfgdvg * cdrain; + if (model->VDMOSksubthresGiven) { + /* Alternative simple weak inversion model, according to https://www.anasoft.co.uk/MOS1Model.htm + * Scale the voltage overdrive vgst logarithmically in weak inversion. + * Best fits LTSPICE curves with shift=0 + * Drain current including subthreshold current */ + + double t0, t1, t2, t3, t4, t5, t6; + double slope = model->VDMOSksubthres; + double lambda = model->VDMOSlambda; + double theta = model->VDMOStheta; + double shift = model->VDMOSsubshift; + double mtr = model->VDMOSmtr; + + /* scale vds with mtr (except with lambda) */ + double vdss = vds*mtr*here->VDMOSmode; + t0 = 1 + lambda*vds*here->VDMOSmode; + t1 = 1 + theta*vgs; + betap = Beta*t0/t1; + + vgst = slope * log(1 + exp((vgst - shift) / slope)); + + if (vgst <= vdss) { + /* saturation region */ + cdrain = betap*vgst*vgst*0.5; + t2 = exp((vgst-shift)/slope); + t3 = Beta*slope*t2*log(t2+1)*t0/(t1*(t2+1)); + t4 = Beta*slope*slope*theta*log((t2+1)*(t2+1))*t0/(2*t1*t1); + here->VDMOSgm = t3-t4; + t3 = Beta*slope*slope*log((t2+1)*(t2+1))*lambda; + t4 = 2*t1; + here->VDMOSgds = t3/t4; + } + else { + /* linear region */ + cdrain = betap * vdss * (vgst - 0.5 * vdss); + t3 = exp((vgst-shift)/slope); + t4 = Beta*vdss*t3*t0/(t1*(t3+1)); + t5 = Beta*vdss*theta*(slope*log(t3+1)-0.5*vdss)*t0/(t1*t1); + here->VDMOSgm = t4-t5; + t4 = Beta*mtr*(slope*log(t3+1)-0.5*vdss)*t0/t1; + t5 = Beta*0.5*mtr*vdss*t0/t1; + t6 = Beta*vdss*(slope*log(t3+1)-0.5*vdss)*lambda/t1; + here->VDMOSgds = t4-t5+t6; + } } - else if (model->VDMOSsubslGiven && (here->VDMOSmode == 1)) { + else if (model->VDMOSsubslGiven) { + /* numerical differentiation for gd and gm with a delta of 2 mV */ + double vdsm = vds * here->VDMOSmode; double delta = 0.001; - cdrain = cweakinv2(model->VDMOSsubsl, model->VDMOSsubshift, vgst, vds, model->VDMOSlambda, - Betam, vt, model->VDMOSmtr); + cdrain = cweakinv2(model->VDMOSsubsl, model->VDMOSsubshift, vgst, vdsm, model->VDMOSlambda, + Beta, vt, model->VDMOSmtr, model->VDMOStheta); /* gd */ - double vds1 = vds + delta; + double vds1 = vdsm + delta; double cdrp = cweakinv2(model->VDMOSsubsl, model->VDMOSsubshift, vgst, vds1, model->VDMOSlambda, - Betam, vt, model->VDMOSmtr); - vds1 = vds - delta; + Beta, vt, model->VDMOSmtr, model->VDMOStheta); + vds1 = vdsm - delta; double cdrm = cweakinv2(model->VDMOSsubsl, model->VDMOSsubshift, vgst, vds1, model->VDMOSlambda, - Betam, vt, model->VDMOSmtr); + Beta, vt, model->VDMOSmtr, model->VDMOStheta); here->VDMOSgds = (cdrp - cdrm) / (2. * delta); /* gm */ double vgst1 = vgst + delta; - cdrp = cweakinv2(model->VDMOSsubsl, model->VDMOSsubshift, vgst1, vds, model->VDMOSlambda, - Betam, vt, model->VDMOSmtr); + cdrp = cweakinv2(model->VDMOSsubsl, model->VDMOSsubshift, vgst1, vdsm, model->VDMOSlambda, + Beta, vt, model->VDMOSmtr, model->VDMOStheta); vgst1 = vgst - delta; - cdrm = cweakinv2(model->VDMOSsubsl, model->VDMOSsubshift, vgst1, vds, model->VDMOSlambda, - Betam, vt, model->VDMOSmtr); - here->VDMOSgm = (cdrp - cdrm) / (2. * delta) * fgate + dfgdvg * cdrain; + cdrm = cweakinv2(model->VDMOSsubsl, model->VDMOSsubshift, vgst1, vdsm, model->VDMOSlambda, + Beta, vt, model->VDMOSmtr, model->VDMOStheta); + here->VDMOSgm = (cdrp - cdrm) / (2. * delta); } else { + double onfg, fgate, Betam, dfgdvg; + onfg = 1.0+model->VDMOStheta*vgst; + fgate = 1.0/onfg; + Betam = Beta * fgate; + dfgdvg = -model->VDMOStheta*fgate*fgate; if (vgst <= 0) { /* * cutoff region @@ -805,43 +827,17 @@ scalef(double nf2, double vgst) */ static double -cweakinv2(double slope, double shift, double vgst, double vds, double lambda, double beta, double vt, double mtr) +cweakinv2(double slope, double shift, double vgst, double vds, double lambda, double beta, double vt, double mtr, double theta) { + double betam = beta / (1.0+theta*vgst); vgst += shift * (1 - scalef(0.5, vgst)); double n = slope / 2.3 / 0.0256; /* Tsividis, p. 208 */ double n1 = n + (1 - n) * scalef(0.7, vgst); /* n < n1 < 1 */ double first = log(1 + exp(vgst / (2 * n1 * vt))); double second = log(1 + exp((vgst - vds * mtr * n1) / (2 * n1 * vt))); double cds = - beta * n1 * 2 * vt * vt * (1 + scalef(1, vgst) * lambda * vds) * + betam * n1 * 2 * vt * vt * (1 + scalef(1, vgst) * lambda * vds) * (first * first - second * second); return cds; } - -/* Alternative simple weak inversion model, according to https://www.anasoft.co.uk/MOS1Model.htm - * Scale the voltage overdrive vgst logarithmically in weak inversion. - * Best fits LTSPICE curves with shift=0 - */ - -static double -cweakinv(double slope, double shift, double vgst, double vds, double lambda, double beta, double vt, double mtr) -{ - NG_IGNORE(vt); - double cdrain, betap; - vgst = slope * log(1 + exp((vgst - shift) / slope)); - - betap = beta*(1 + lambda*vds); - /* scale vds with mtr (except with lambda) */ - - if (vgst <= vds * mtr) { - /* saturation region */ - cdrain = betap*vgst*vgst*.5; - } - else { - /* linear region */ - cdrain = betap * vds * mtr * - (vgst - .5 * vds * mtr); - } - return cdrain; -}