int MOS3dSetup(GENmodel *inModel, CKTcircuit *ckt) /* actually load the current value into the * sparse matrix previously provided */ { MOS3model *model = (MOS3model *)inModel; MOS3instance *here; double Beta; double DrainSatCur; double EffectiveLength; double EffectiveWidth; double GateBulkOverlapCap; double GateDrainOverlapCap; double GateSourceOverlapCap; double OxideCap; double SourceSatCur; double arg; double cdrain; double evbs; double sarg; double sargsw; double lvgs; double vbd; double vbs; double vds; double vdsat; double vgb; double vgd; double vgs; double von; double lcapgs2,lcapgs3; /* total gate-source capacitance */ double lcapgd2,lcapgd3; /* total gate-drain capacitance */ double lcapgb2,lcapgb3; /* total gate-bulk capacitance */ double lgbs, lgbs2, lgbs3; double lgbd, lgbd2, lgbd3; double gm2, gb2, gds2, gmb, gmds, gbds; double gm3, gb3, gds3, gm2ds, gm2b, gb2ds, gbds2, gmb2, gmds2, gmbds; double lcapbd, lcapbd2, lcapbd3; double lcapbs, lcapbs2, lcapbs3; double ebd; double vt; /* vt at instance temperature */ Dderivs d_cdrain; /* loop through all the MOS3 device models */ for( ; model != NULL; model = MOS3nextModel(model)) { /* loop through all the instances of the model */ for (here = MOS3instances(model); here != NULL ; here=MOS3nextInstance(here)) { vt = CONSTKoverQ * here->MOS3temp; /* first, we compute a few useful values - these could be * pre-computed, but for historical reasons are still done * here. They may be moved at the expense of instance size */ EffectiveWidth=here->MOS3w-2*model->MOS3widthNarrow+ model->MOS3widthAdjust; EffectiveLength=here->MOS3l - 2*model->MOS3latDiff+ model->MOS3lengthAdjust; if( (here->MOS3tSatCurDens == 0) || (here->MOS3drainArea == 0) || (here->MOS3sourceArea == 0)) { DrainSatCur = here->MOS3m * here->MOS3tSatCur; SourceSatCur = here->MOS3m * here->MOS3tSatCur; } else { DrainSatCur = here->MOS3tSatCurDens * here->MOS3m * here->MOS3drainArea; SourceSatCur = here->MOS3tSatCurDens * here->MOS3m * here->MOS3sourceArea; } GateSourceOverlapCap = model->MOS3gateSourceOverlapCapFactor * here->MOS3m * EffectiveWidth; GateDrainOverlapCap = model->MOS3gateDrainOverlapCapFactor * here->MOS3m * EffectiveWidth; GateBulkOverlapCap = model->MOS3gateBulkOverlapCapFactor * here->MOS3m * EffectiveLength; Beta = here->MOS3tTransconductance * here->MOS3m * EffectiveWidth/EffectiveLength; OxideCap = model->MOS3oxideCapFactor * EffectiveLength * here->MOS3m * EffectiveWidth; /* * ok - now to do the start-up operations * * we must get values for vbs, vds, and vgs from somewhere * so we either predict them or recover them from last iteration * These are the two most common cases - either a prediction * step or the general iteration step and they * share some code, so we put them first - others later on */ /* general iteration */ vbs = model->MOS3type * ( *(ckt->CKTrhsOld+here->MOS3bNode) - *(ckt->CKTrhsOld+here->MOS3sNodePrime)); vgs = model->MOS3type * ( *(ckt->CKTrhsOld+here->MOS3gNode) - *(ckt->CKTrhsOld+here->MOS3sNodePrime)); vds = model->MOS3type * ( *(ckt->CKTrhsOld+here->MOS3dNodePrime) - *(ckt->CKTrhsOld+here->MOS3sNodePrime)); /* now some common crunching for some more useful quantities */ /* * now all the preliminaries are over - we can start doing the * real work */ vbd = vbs - vds; vgd = vgs - vds; vgb = vgs - vbs; /* bulk-source and bulk-drain doides * here we just evaluate the ideal diode current and the * correspoinding derivative (conductance). */ if(vbs <= 0) { lgbs = SourceSatCur/vt; lgbs += ckt->CKTgmin; lgbs2 = lgbs3 = 0; } else { evbs = exp(MIN(MAX_EXP_ARG,vbs/vt)); lgbs = SourceSatCur*evbs/vt + ckt->CKTgmin; lgbs2 = model->MOS3type *0.5 * (lgbs - ckt->CKTgmin)/vt; lgbs3 = model->MOS3type *lgbs2/(vt*3); } if(vbd <= 0) { lgbd = DrainSatCur/vt; lgbd += ckt->CKTgmin; lgbd2 = lgbd3 = 0; } else { ebd = exp(MIN(MAX_EXP_ARG,vbd/vt)); lgbd = DrainSatCur*ebd/vt +ckt->CKTgmin; lgbd2 = model->MOS3type *0.5 * (lgbd - ckt->CKTgmin)/vt; lgbd3 = model->MOS3type *lgbd2/(vt*3); } /* now to determine whether the user was able to correctly * identify the source and drain of his device */ if(vds >= 0) { /* normal mode */ here->MOS3mode = 1; } else { /* inverse mode */ here->MOS3mode = -1; } { /* * subroutine moseq3(vds,vbs,vgs,gm,gds,gmbs, * qg,qc,qb,cggb,cgdb,cgsb,cbgb,cbdb,cbsb) */ /* * this routine evaluates the drain current, its derivatives and * the charges associated with the gate, channel and bulk * for mosfets based on semi-empirical equations */ /* common /mosarg/ vto,beta,gamma,phi,phib,cox,xnsub,xnfs,xd,xj,xld, 1 xlamda,uo,uexp,vbp,utra,vmax,xneff,xl,xw,vbi,von,vdsat,qspof, 2 beta0,beta1,cdrain,xqco,xqc,fnarrw,fshort,lev common /status/ omega,time,delta,delold(7),ag(7),vt,xni,egfet, 1 xmu,sfactr,mode,modedc,icalc,initf,method,iord,maxord,noncon, 2 iterno,itemno,nosolv,modac,ipiv,ivmflg,ipostp,iscrch,iofile common /knstnt/ twopi,xlog2,xlog10,root2,rad,boltz,charge,ctok, 1 gmin,reltol,abstol,vntol,trtol,chgtol,eps0,epssil,epsox, 2 pivtol,pivrel */ /* equivalence (xlamda,alpha),(vbp,theta),(uexp,eta),(utra,xkappa)*/ double coeff0 = 0.0631353e0; double coeff1 = 0.8013292e0; double coeff2 = -0.01110777e0; double oneoverxl; /* 1/effective length */ double eta; /* eta from model after length factor */ double phibs; /* phi - vbs */ double sqphbs; /* square root of phibs */ double sqphis; /* square root of phi */ double wps; double oneoverxj; /* 1/junction depth */ double xjonxl; /* junction depth/effective length */ double djonxj; double wponxj; double arga; double argb; double argc; double gammas; double fbodys; double fbody; double onfbdy; double qbonco; double vbix; double wconxj; double vth; double csonco; double cdonco; double vgsx; double onfg; double fgate; double us; double xn = 0.0; double vdsc; double onvdsc = 0.0; double vdsx; double cdnorm; double cdo; double fdrain = 0.0; double gdsat; double cdsat; double emax; double delxl; double dlonxl; double xlfact; double ondvt; double onxn; double wfact; double fshort; double lvds, lvbs, lvbd; Dderivs d_onxn, d_ondvt, d_wfact, d_MOS3gds; Dderivs d_emax, d_delxl, d_dlonxl, d_xlfact; Dderivs d_cdonco, d_fdrain, d_cdsat, d_gdsat; Dderivs d_vdsx, d_cdo, d_cdnorm, d_Beta, d_dummy; Dderivs d_vdsc, d_onvdsc, d_arga, d_argb; Dderivs d_onfg, d_fgate, d_us, d_vgsx; Dderivs d_von, d_xn, d_vth, d_onfbdy, d_qbonco, d_vbix; Dderivs d_argc, d_fshort, d_gammas, d_fbodys, d_fbody; Dderivs d_wps, d_wconxj, d_wponxj; Dderivs d_phibs, d_sqphbs; Dderivs d_p, d_q, d_r, d_zero, d_vdsat; /* * bypasses the computation of charges */ if (here->MOS3mode == 1) { lvgs = vgs; lvds = vds; lvbs = vbs; lvbd = vbd; } else { lvgs = vgd; lvds = -vds; lvbs = vbd; lvbd = vbs; } /* * reference cdrain equations to source and * charge equations to bulk */ d_p.value = 0.0; d_p.d1_p = 1.0; d_p.d1_q = 0.0; d_p.d1_r = 0.0; d_p.d2_p2 = 0.0; d_p.d2_q2 = 0.0; d_p.d2_r2 = 0.0; d_p.d2_pq = 0.0; d_p.d2_qr = 0.0; d_p.d2_pr = 0.0; d_p.d3_p3 = 0.0; d_p.d3_q3 = 0.0; d_p.d3_r3 = 0.0; d_p.d3_p2r = 0.0; d_p.d3_p2q = 0.0; d_p.d3_q2r = 0.0; d_p.d3_pq2 = 0.0; d_p.d3_pr2 = 0.0; d_p.d3_qr2 = 0.0; d_p.d3_pqr = 0.0; EqualDeriv(&d_q,&d_p); EqualDeriv(&d_r,&d_p); EqualDeriv(&d_zero,&d_p); d_q.d1_p = d_r.d1_p = d_zero.d1_p = 0.0; d_q.d1_q = d_r.d1_r = 1.0; vdsat = 0.0; EqualDeriv(&d_vdsat,&d_zero); oneoverxl = 1.0/EffectiveLength;/*const*/ eta = model->MOS3eta * 8.15e-22/(model->MOS3oxideCapFactor* EffectiveLength*EffectiveLength*EffectiveLength);/*const*/ /* *.....square root term */ if ( lvbs <= 0.0 ) { phibs = here->MOS3tPhi-lvbs; EqualDeriv(&d_phibs,&d_q); d_phibs.value = lvbs; TimesDeriv(&d_phibs,&d_phibs,-1.0); d_phibs.value += here->MOS3tPhi; sqphbs = sqrt(phibs); SqrtDeriv(&d_sqphbs,&d_phibs); } else { sqphis = sqrt(here->MOS3tPhi);/*const*/ /*sqphs3 = here->MOS3tPhi*sqphis;const*/ sqphbs = sqphis/(1.0+lvbs/ (here->MOS3tPhi+here->MOS3tPhi)); EqualDeriv(&d_sqphbs,&d_q); d_sqphbs.value = lvbs; TimesDeriv(&d_sqphbs,&d_sqphbs,1/(here->MOS3tPhi+here->MOS3tPhi)); d_sqphbs.value += 1.0; InvDeriv(&d_sqphbs,&d_sqphbs); TimesDeriv(&d_sqphbs,&d_sqphbs,sqphis); phibs = sqphbs*sqphbs; MultDeriv(&d_phibs,&d_sqphbs,&d_sqphbs); } /* *.....short channel effect factor */ if ( (model->MOS3junctionDepth != 0.0) && (model->MOS3coeffDepLayWidth != 0.0) ) { wps = model->MOS3coeffDepLayWidth*sqphbs; TimesDeriv(&d_wps,&d_sqphbs,model->MOS3coeffDepLayWidth); oneoverxj = 1.0/model->MOS3junctionDepth;/*const*/ xjonxl = model->MOS3junctionDepth*oneoverxl;/*const*/ djonxj = model->MOS3latDiff*oneoverxj;/*const*/ wponxj = wps*oneoverxj; TimesDeriv(&d_wponxj,&d_wps,oneoverxj); wconxj = coeff0+coeff1*wponxj+coeff2*wponxj*wponxj; TimesDeriv(&d_wconxj,&d_wponxj,coeff2); d_wconxj.value += coeff1; MultDeriv(&d_wconxj,&d_wconxj,&d_wponxj); d_wconxj.value += coeff0; arga = wconxj + djonxj; EqualDeriv(&d_arga,&d_wconxj); d_arga.value += djonxj; argc = wponxj/(1.0+wponxj); EqualDeriv(&d_argc,&d_wponxj); d_argc.value += 1.0; InvDeriv(&d_argc,&d_argc); MultDeriv(&d_argc,&d_argc,&d_wponxj); argb = sqrt(1.0-argc*argc); MultDeriv(&d_argb,&d_argc,&d_argc); TimesDeriv(&d_argb,&d_argb,-1.0); d_argb.value += 1.0; SqrtDeriv(&d_argb,&d_argb); fshort = 1.0-xjonxl*(arga*argb-djonxj); MultDeriv(&d_fshort,&d_arga,&d_argb); d_fshort.value -= djonxj; TimesDeriv(&d_fshort,&d_fshort,-xjonxl); d_fshort.value += 1.0; } else { fshort = 1.0; EqualDeriv(&d_fshort,&d_zero); d_fshort.value = 1.0; } /* *.....body effect */ gammas = model->MOS3gamma*fshort; TimesDeriv(&d_gammas,&d_fshort,model->MOS3gamma); fbodys = 0.5*gammas/(sqphbs+sqphbs); DivDeriv(&d_fbodys,&d_gammas,&d_sqphbs); TimesDeriv(&d_fbodys,&d_fbodys,0.25); fbody = fbodys+model->MOS3narrowFactor/EffectiveWidth; EqualDeriv(&d_fbody,&d_fbodys); d_fbody.value += fbody - fbodys; onfbdy = 1.0/(1.0+fbody); EqualDeriv(&d_onfbdy,&d_fbody); d_onfbdy.value += 1.0; InvDeriv(&d_onfbdy,&d_onfbdy); qbonco =gammas*sqphbs+model->MOS3narrowFactor*phibs/EffectiveWidth; EqualDeriv(&d_dummy,&d_phibs); TimesDeriv(&d_dummy,&d_dummy,model->MOS3narrowFactor*EffectiveWidth); MultDeriv(&d_qbonco,&d_gammas,&d_sqphbs); PlusDeriv(&d_qbonco,&d_qbonco,&d_dummy); /* *.....static feedback effect */ vbix = here->MOS3tVbi*model->MOS3type-eta*(lvds); EqualDeriv(&d_vbix,&d_r); d_vbix.value = vbix; d_vbix.d1_r = -eta; /* *.....threshold voltage */ vth = vbix+qbonco; PlusDeriv(&d_vth,&d_vbix,&d_qbonco); /* *.....joint weak inversion and strong inversion */ von = vth; EqualDeriv(&d_von,&d_vth); if ( model->MOS3fastSurfaceStateDensity != 0.0 ) { csonco = CHARGE*model->MOS3fastSurfaceStateDensity * 1e4 /*(cm**2/m**2)*/ *EffectiveLength*EffectiveWidth * here->MOS3m/OxideCap; /*const*/ cdonco = 0.5*qbonco/phibs; DivDeriv(&d_cdonco,&d_qbonco,&d_phibs); TimesDeriv(&d_cdonco,&d_cdonco,0.5); xn = 1.0+csonco+cdonco; EqualDeriv(&d_xn,&d_cdonco); d_xn.value += 1.0 + csonco; von = vth+vt*xn; TimesDeriv(&d_von,&d_xn,vt); PlusDeriv(&d_von,&d_von,&d_vth); } else { /* *.....cutoff region */ if ( lvgs <= von ) { cdrain = 0.0; EqualDeriv(&d_cdrain,&d_zero); goto innerline1000; } } /* *.....device is on */ vgsx = MAX(lvgs,von); if (lvgs >= von) { EqualDeriv(&d_vgsx,&d_p); d_vgsx.value = lvgs; } else { EqualDeriv(&d_vgsx,&d_von); } /* *.....mobility modulation by gate voltage */ onfg = 1.0+model->MOS3theta*(vgsx-vth); TimesDeriv(&d_onfg,&d_vth,-1.0); PlusDeriv(&d_onfg,&d_onfg,&d_vgsx); TimesDeriv(&d_onfg,&d_onfg,model->MOS3theta); d_onfg.value += 1.0; fgate = 1.0/onfg; InvDeriv(&d_fgate,&d_onfg); us = here->MOS3tSurfMob * 1e-4 /*(m**2/cm**2)*/ *fgate; TimesDeriv(&d_us,&d_fgate,here->MOS3tSurfMob * 1e-4); /* *.....saturation voltage */ vdsat = (vgsx-vth)*onfbdy; TimesDeriv(&d_vdsat,&d_vth, -1.0); PlusDeriv(&d_vdsat,&d_vdsat,&d_vgsx); MultDeriv(&d_vdsat,&d_vdsat,&d_onfbdy); if ( model->MOS3maxDriftVel <= 0.0 ) { } else { vdsc = EffectiveLength*model->MOS3maxDriftVel/us; InvDeriv(&d_vdsc,&d_us); TimesDeriv(&d_vdsc,&d_vdsc,EffectiveLength*model->MOS3maxDriftVel); onvdsc = 1.0/vdsc; InvDeriv(&d_onvdsc,&d_vdsc); arga = (vgsx-vth)*onfbdy; /* note arga = vdsat at this point */ EqualDeriv(&d_arga,&d_vdsat); argb = sqrt(arga*arga+vdsc*vdsc); MultDeriv(&d_dummy,&d_arga,&d_arga); MultDeriv(&d_argb,&d_vdsc,&d_vdsc); PlusDeriv(&d_argb,&d_argb,&d_dummy); SqrtDeriv(&d_argb,&d_argb); vdsat = arga+vdsc-argb; TimesDeriv(&d_vdsat,&d_argb,-1.0); PlusDeriv(&d_vdsat,&d_vdsat,&d_vdsc); PlusDeriv(&d_vdsat,&d_vdsat,&d_arga); } /* *.....current factors in linear region */ vdsx = MIN((lvds),vdsat); if (lvds < vdsat) { EqualDeriv(&d_vdsx,&d_r); d_vdsx.value = lvds; } else { EqualDeriv(&d_vdsx,&d_vdsat); } if ( vdsx == 0.0 ) goto line900; cdo = vgsx-vth-0.5*(1.0+fbody)*vdsx; EqualDeriv(&d_cdo,&d_fbody); d_cdo.value += 1.0; MultDeriv(&d_cdo,&d_cdo,&d_vdsx); TimesDeriv(&d_cdo,&d_cdo,0.5); PlusDeriv(&d_cdo,&d_cdo,&d_vth); TimesDeriv(&d_cdo,&d_cdo,-1.0); PlusDeriv(&d_cdo,&d_cdo,&d_vgsx); /* *.....normalized drain current */ cdnorm = cdo*vdsx; MultDeriv(&d_cdnorm,&d_cdo,&d_vdsx); /* *.....drain current without velocity saturation effect */ /* Beta is a constant till now */ Beta = Beta*fgate; TimesDeriv(&d_Beta,&d_fgate,Beta); cdrain = Beta*cdnorm; MultDeriv(&d_cdrain,&d_Beta,&d_cdnorm); /* *.....velocity saturation factor */ if ( model->MOS3maxDriftVel != 0.0 ) { fdrain = 1.0/(1.0+vdsx*onvdsc); MultDeriv(&d_fdrain,&d_vdsx,&d_onvdsc); d_fdrain.value += 1.0; InvDeriv(&d_fdrain,&d_fdrain); /* *.....drain current */ cdrain = fdrain*cdrain; MultDeriv(&d_cdrain,&d_cdrain,&d_fdrain); Beta = Beta*fdrain; MultDeriv(&d_Beta,&d_Beta,&d_fdrain); } /* *.....channel length modulation */ if ( (lvds) <= vdsat ) goto line700; if ( model->MOS3maxDriftVel == 0.0 ) goto line510; if (model->MOS3alpha == 0.0) goto line700; cdsat = cdrain; EqualDeriv(&d_cdsat,&d_cdrain); gdsat = cdsat*(1.0-fdrain)*onvdsc; TimesDeriv(&d_dummy,&d_fdrain,-1.0); d_dummy.value += 1.0; MultDeriv(&d_gdsat,&d_cdsat,&d_dummy); MultDeriv(&d_gdsat,&d_gdsat,&d_onvdsc); gdsat = MAX(1.0e-12,gdsat); if (gdsat == 1.0e-12) { EqualDeriv(&d_gdsat,&d_zero); d_gdsat.value = gdsat; } emax = cdsat*oneoverxl/gdsat; DivDeriv(&d_emax,&d_cdsat,&d_gdsat); TimesDeriv(&d_emax,&d_emax,oneoverxl); arga = 0.5*emax*model->MOS3alpha; TimesDeriv(&d_arga,&d_emax,0.5*model->MOS3alpha); argc = model->MOS3kappa*model->MOS3alpha;/*const*/ argb = sqrt(arga*arga+argc*((lvds)-vdsat)); TimesDeriv(&d_dummy,&d_vdsat,-1.0); d_dummy.value += lvds; d_dummy.d1_r += 1.0; TimesDeriv(&d_argb,&d_dummy,argc); MultDeriv(&d_dummy,&d_arga,&d_arga); PlusDeriv(&d_argb,&d_argb,&d_dummy); SqrtDeriv(&d_argb,&d_argb); delxl = argb-arga; TimesDeriv(&d_delxl,&d_arga,-1.0); PlusDeriv(&d_delxl,&d_argb,&d_delxl); goto line520; line510: delxl = sqrt(model->MOS3kappa*((lvds)-vdsat)*model->MOS3alpha); TimesDeriv(&d_delxl,&d_vdsat,-1.0); d_delxl.value += lvds; d_delxl.d1_r += 1.0; TimesDeriv(&d_delxl,&d_delxl,model->MOS3kappa*model->MOS3alpha); SqrtDeriv(&d_delxl,&d_delxl); /* *.....punch through approximation */ line520: if ( delxl > (0.5*EffectiveLength) ) { delxl = EffectiveLength - (EffectiveLength*EffectiveLength/ delxl*0.25); InvDeriv(&d_delxl,&d_delxl); TimesDeriv(&d_delxl,&d_delxl,-EffectiveLength*EffectiveLength*0.25); d_delxl.value += EffectiveLength; } /* *.....saturation region */ dlonxl = delxl*oneoverxl; TimesDeriv(&d_dlonxl,&d_delxl,oneoverxl); xlfact = 1.0/(1.0-dlonxl); TimesDeriv(&d_xlfact,&d_dlonxl,-1.0); d_xlfact.value += 1.0; InvDeriv(&d_xlfact,&d_xlfact); cdrain = cdrain*xlfact; MultDeriv(&d_cdrain,&d_cdrain,&d_xlfact); /* *.....finish strong inversion case */ line700: if ( lvgs < von ) { /* *.....weak inversion */ onxn = 1.0/xn; InvDeriv(&d_onxn,&d_xn); ondvt = onxn/vt; TimesDeriv(&d_ondvt,&d_onxn,1/vt); wfact = exp( (lvgs-von)*ondvt ); TimesDeriv(&d_wfact,&d_von,-1.0); d_wfact.value += lvgs; d_wfact.d1_p += 1.0; MultDeriv(&d_wfact,&d_wfact,&d_ondvt); ExpDeriv(&d_wfact,&d_wfact); cdrain = cdrain*wfact; MultDeriv(&d_cdrain,&d_cdrain,&d_wfact); } /* *.....charge computation */ goto innerline1000; /* *.....special case of vds = 0.0d0 */ line900: Beta = Beta*fgate; /* Beta is still a constant */ TimesDeriv(&d_Beta,&d_fgate,Beta); cdrain = 0.0; EqualDeriv(&d_cdrain,&d_zero); here->MOS3gds = Beta*(vgsx-vth); TimesDeriv(&d_MOS3gds,&d_vth,-1.0); PlusDeriv(&d_MOS3gds,&d_MOS3gds,&d_vgsx); MultDeriv(&d_MOS3gds,&d_MOS3gds,&d_Beta); if ( (model->MOS3fastSurfaceStateDensity != 0.0) && (lvgs < von) ) { here->MOS3gds *=exp((lvgs-von)/(vt*xn)); TimesDeriv(&d_dummy,&d_von,-1.0); d_dummy.value += lvgs; d_dummy.d1_p += 1.0; DivDeriv(&d_dummy,&d_dummy,&d_xn); TimesDeriv(&d_dummy,&d_dummy,1/vt); ExpDeriv(&d_dummy,&d_dummy); MultDeriv(&d_MOS3gds,&d_MOS3gds,&d_dummy); } d_cdrain.d1_r = d_MOS3gds.value; d_cdrain.d2_r2 = d_MOS3gds.d1_r; d_cdrain.d3_r3 = d_MOS3gds.d2_r2; innerline1000:; /* *.....done */ } /* * COMPUTE EQUIVALENT DRAIN CURRENT SOURCE */ /* * now we do the hard part of the bulk-drain and bulk-source * diode - we evaluate the non-linear capacitance and * charge * * the basic equations are not hard, but the implementation * is somewhat long in an attempt to avoid log/exponential * evaluations */ /* * charge storage elements * *.. bulk-drain and bulk-source depletion capacitances */ if (vbs < here->MOS3tDepCap){ arg=1-vbs/here->MOS3tBulkPot; /* * the following block looks somewhat long and messy, * but since most users use the default grading * coefficients of .5, and sqrt is MUCH faster than an * exp(log()) we use this special case code to buy time. * (as much as 10% of total job time!) */ if(model->MOS3bulkJctBotGradingCoeff == model->MOS3bulkJctSideGradingCoeff) { if(model->MOS3bulkJctBotGradingCoeff == .5) { sarg = sargsw = 1/sqrt(arg); } else { sarg = sargsw = exp(-model->MOS3bulkJctBotGradingCoeff* log(arg)); } } else { if(model->MOS3bulkJctBotGradingCoeff == .5) { sarg = 1/sqrt(arg); } else { sarg = exp(-model->MOS3bulkJctBotGradingCoeff* log(arg)); } if(model->MOS3bulkJctSideGradingCoeff == .5) { sargsw = 1/sqrt(arg); } else { sargsw =exp(-model->MOS3bulkJctSideGradingCoeff* log(arg)); } } lcapbs=here->MOS3Cbs*sarg+ here->MOS3Cbssw*sargsw; lcapbs2 = model->MOS3type*0.5/here->MOS3tBulkPot*( here->MOS3Cbs*model->MOS3bulkJctBotGradingCoeff* sarg/arg + here->MOS3Cbssw* model->MOS3bulkJctSideGradingCoeff*sargsw/arg); lcapbs3 = here->MOS3Cbs*sarg* model->MOS3bulkJctBotGradingCoeff* (model->MOS3bulkJctBotGradingCoeff+1); lcapbs3 += here->MOS3Cbssw*sargsw* model->MOS3bulkJctSideGradingCoeff* (model->MOS3bulkJctSideGradingCoeff+1); lcapbs3 = lcapbs3/(6*here->MOS3tBulkPot* here->MOS3tBulkPot*arg*arg); } else { /* *(ckt->CKTstate0 + here->MOS3qbs)= here->MOS3f4s + vbs*(here->MOS3f2s+vbs*(here->MOS3f3s/2));*/ lcapbs=here->MOS3f2s+here->MOS3f3s*vbs; lcapbs2 = 0.5*here->MOS3f3s; lcapbs3 = 0; } if (vbd < here->MOS3tDepCap) { arg=1-vbd/here->MOS3tBulkPot; /* * the following block looks somewhat long and messy, * but since most users use the default grading * coefficients of .5, and sqrt is MUCH faster than an * exp(log()) we use this special case code to buy time. * (as much as 10% of total job time!) */ if(model->MOS3bulkJctBotGradingCoeff == .5 && model->MOS3bulkJctSideGradingCoeff == .5) { sarg = sargsw = 1/sqrt(arg); } else { if(model->MOS3bulkJctBotGradingCoeff == .5) { sarg = 1/sqrt(arg); } else { sarg = exp(-model->MOS3bulkJctBotGradingCoeff* log(arg)); } if(model->MOS3bulkJctSideGradingCoeff == .5) { sargsw = 1/sqrt(arg); } else { sargsw =exp(-model->MOS3bulkJctSideGradingCoeff* log(arg)); } } lcapbd=here->MOS3Cbd*sarg+ here->MOS3Cbdsw*sargsw; lcapbd2 = model->MOS3type*0.5/here->MOS3tBulkPot*( here->MOS3Cbd*model->MOS3bulkJctBotGradingCoeff* sarg/arg + here->MOS3Cbdsw* model->MOS3bulkJctSideGradingCoeff*sargsw/arg); lcapbd3 = here->MOS3Cbd*sarg* model->MOS3bulkJctBotGradingCoeff* (model->MOS3bulkJctBotGradingCoeff+1); lcapbd3 += here->MOS3Cbdsw*sargsw* model->MOS3bulkJctSideGradingCoeff* (model->MOS3bulkJctSideGradingCoeff+1); lcapbd3 = lcapbd3/(6*here->MOS3tBulkPot* here->MOS3tBulkPot*arg*arg); } else { lcapbd=here->MOS3f2d + vbd * here->MOS3f3d; lcapbd2=0.5*here->MOS3f3d; lcapbd3=0; } /* * meyer's capacitor model */ /* * the meyer capacitance equations are in DEVqmeyer * these expressions are derived from those equations. * these expressions are incorrect; they assume just one * controlling variable for each charge storage element * while actually there are several; the MOS3 small * signal ac linear model is also wrong because it * ignores controlled capacitive elements. these can be * corrected (as can the linear ss ac model) if the * expressions for the charge are available */ { double phi; double cox; double vddif; double vddif1; double vddif2; double vgst; /* von, lvgs and vdsat have already been adjusted for possible source-drain interchange */ vgst = lvgs -von; phi = here->MOS3tPhi; cox = OxideCap; if (vgst <= -phi) { lcapgb2=lcapgb3=lcapgs2=lcapgs3=lcapgd2=lcapgd3=0; } else if (vgst <= -phi/2) { lcapgb2= -cox/(4*phi); lcapgb3=lcapgs2=lcapgs3=lcapgd2=lcapgd3=0; } else if (vgst <= 0) { lcapgb2= -cox/(4*phi); lcapgb3=lcapgs3=lcapgd2=lcapgd3=0; lcapgs2 = cox/(3*phi); } else { /* the MOS3modes are around because vds has not been adjusted */ if (vdsat <= here->MOS3mode*vds) { lcapgb2=lcapgb3=lcapgs2=lcapgs3=lcapgd2=lcapgd3=0; } else { vddif = 2.0*vdsat-here->MOS3mode*vds; vddif1 = vdsat-here->MOS3mode*vds/*-1.0e-12*/; vddif2 = vddif*vddif; lcapgd2 = -vdsat*here->MOS3mode*vds*cox/(3*vddif*vddif2); lcapgd3 = - here->MOS3mode*vds*cox*(vddif - 6*vdsat)/(9*vddif2*vddif2); lcapgs2 = -vddif1*here->MOS3mode*vds*cox/(3*vddif*vddif2); lcapgs3 = - here->MOS3mode*vds*cox*(vddif - 6*vddif1)/(9*vddif2*vddif2); lcapgb2=lcapgb3=0; } } } /* the b-s and b-d diodes need no processing ... */ here->capbs2 = lcapbs2; here->capbs3 = lcapbs3; here->capbd2 = lcapbd2; here->capbd3 = lcapbd3; here->gbs2 = lgbs2; here->gbs3 = lgbs3; here->gbd2 = lgbd2; here->gbd3 = lgbd3; here->capgb2 = model->MOS3type*lcapgb2; here->capgb3 = lcapgb3; /* * process to get Taylor coefficients, taking into * account type and mode. */ gm2 = d_cdrain.d2_p2; gb2 = d_cdrain.d2_q2; gds2 = d_cdrain.d2_r2; gmb = d_cdrain.d2_pq; gbds = d_cdrain.d2_qr; gmds = d_cdrain.d2_pr; gm3 = d_cdrain.d3_p3; gb3 = d_cdrain.d3_q3; gds3 = d_cdrain.d3_r3; gm2ds = d_cdrain.d3_p2r; gm2b = d_cdrain.d3_p2q; gb2ds = d_cdrain.d3_q2r; gmb2 = d_cdrain.d3_pq2; gmds2 = d_cdrain.d3_pr2; gbds2 = d_cdrain.d3_qr2; gmbds = d_cdrain.d3_pqr; if (here->MOS3mode == 1) { /* normal mode - no source-drain interchange */ here->cdr_x2 = gm2; here->cdr_y2 = gb2;; here->cdr_z2 = gds2;; here->cdr_xy = gmb; here->cdr_yz = gbds; here->cdr_xz = gmds; here->cdr_x3 = gm3; here->cdr_y3 = gb3; here->cdr_z3 = gds3; here->cdr_x2z = gm2ds; here->cdr_x2y = gm2b; here->cdr_y2z = gb2ds; here->cdr_xy2 = gmb2; here->cdr_xz2 = gmds2; here->cdr_yz2 = gbds2; here->cdr_xyz = gmbds; /* the gate caps have been divided and made into Taylor coeffs., but not adjusted for type */ here->capgs2 = model->MOS3type*lcapgs2; here->capgs3 = lcapgs3; here->capgd2 = model->MOS3type*lcapgd2; here->capgd3 = lcapgd3; } else { /* * inverse mode - source and drain interchanged */ here->cdr_x2 = -gm2; here->cdr_y2 = -gb2; here->cdr_z2 = -(gm2 + gb2 + gds2 + 2*(gmb + gmds + gbds)); here->cdr_xy = -gmb; here->cdr_yz = gmb + gb2 + gbds; here->cdr_xz = gm2 + gmb + gmds; here->cdr_x3 = -gm3; here->cdr_y3 = -gb3; here->cdr_z3 = gm3 + gb3 + gds3 + 3*(gm2b + gm2ds + gmb2 + gb2ds + gmds2 + gbds2) + 6*gmbds ; here->cdr_x2z = gm3 + gm2b + gm2ds; here->cdr_x2y = -gm2b; here->cdr_y2z = gmb2 + gb3 + gb2ds; here->cdr_xy2 = -gmb2; here->cdr_xz2 = -(gm3 + 2*(gm2b + gm2ds + gmbds) + gmb2 + gmds2); here->cdr_yz2 = -(gb3 + 2*(gmb2 + gb2ds + gmbds) + gm2b + gbds2); here->cdr_xyz = gm2b + gmb2 + gmbds; here->capgs2 = model->MOS3type*lcapgd2; here->capgs3 = lcapgd3; here->capgd2 = model->MOS3type*lcapgs2; here->capgd3 = lcapgs3; } /* now to adjust for type and multiply by factors to convert to Taylor coeffs. */ here->cdr_x2 = 0.5*model->MOS3type*here->cdr_x2; here->cdr_y2 = 0.5*model->MOS3type*here->cdr_y2; here->cdr_z2 = 0.5*model->MOS3type*here->cdr_z2; here->cdr_xy = model->MOS3type*here->cdr_xy; here->cdr_yz = model->MOS3type*here->cdr_yz; here->cdr_xz = model->MOS3type*here->cdr_xz; here->cdr_x3 = here->cdr_x3/6.; here->cdr_y3 = here->cdr_y3/6.; here->cdr_z3 = here->cdr_z3/6.; here->cdr_x2z = 0.5*here->cdr_x2z; here->cdr_x2y = 0.5*here->cdr_x2y; here->cdr_y2z = 0.5*here->cdr_y2z; here->cdr_xy2 = 0.5*here->cdr_xy2; here->cdr_xz2 = 0.5*here->cdr_xz2; here->cdr_yz2 = 0.5*here->cdr_yz2; } } return(OK); }
int MESdSetup(GENmodel *inModel, CKTcircuit *ckt) /* actually load the current resistance value into the * sparse matrix previously provided */ { MESmodel *model = (MESmodel*)inModel; MESinstance *here; double afact; double beta; double betap; double cdrain; double cg; double cgd; double csat; double czgd; double czgs; double denom; double evgd; double evgs; double gdpr; double gspr; double invdenom; double lfact; double phib; double prod; double vcap; double vcrit; double vds; double vgd; double vgs; double vgst; double vto; double lggd1; double lggd2; double lggd3; double lggs1; double lggs2; double lggs3; Dderivs d_cdrain, d_qgs, d_qgd; Dderivs d_p, d_q, d_r, d_zero; /* loop through all the models */ for( ; model != NULL; model = model->MESnextModel ) { /* loop through all the instances of the model */ for (here = model->MESinstances; here != NULL ; here=here->MESnextInstance) { /* * dc model parameters */ beta = model->MESbeta * here->MESm * here->MESarea; gdpr = model->MESdrainConduct * here->MESm * here->MESarea; gspr = model->MESsourceConduct * here->MESm * here->MESarea; csat = model->MESgateSatCurrent * here->MESm * here->MESarea; vcrit = model->MESvcrit; vto = model->MESthreshold; /* * initialization */ /* * compute new nonlinear branch voltages */ vgs = model->MEStype* (*(ckt->CKTrhsOld+ here->MESgateNode)- *(ckt->CKTrhsOld+ here->MESsourcePrimeNode)); vgd = model->MEStype* (*(ckt->CKTrhsOld+here->MESgateNode)- *(ckt->CKTrhsOld+ here->MESdrainPrimeNode)); /* * determine dc current and derivatives */ vds = vgs-vgd; if (vgs <= -5*CONSTvt0) { lggs1 = -csat/vgs+ckt->CKTgmin; lggs2=lggs3=0; cg = lggs1*vgs; } else { evgs = exp(vgs/CONSTvt0); lggs1 = csat*evgs/CONSTvt0+ckt->CKTgmin; lggs2 = (lggs1-ckt->CKTgmin)/(CONSTvt0*2); lggs3 = lggs2/(3*CONSTvt0); cg = csat*(evgs-1)+ckt->CKTgmin*vgs; } if (vgd <= -5*CONSTvt0) { lggd1 = -csat/vgd+ckt->CKTgmin; lggd2=lggd3=0; cgd = lggd1*vgd; } else { evgd = exp(vgd/CONSTvt0); lggd1 = csat*evgd/CONSTvt0+ckt->CKTgmin; lggd2 = (lggd1-ckt->CKTgmin)/(CONSTvt0*2); lggd3 = lggd2/(3*CONSTvt0); cgd = csat*(evgd-1)+ckt->CKTgmin*vgd; } cg = cg+cgd; /* * compute drain current and derivitives for normal mode */ /* until now, we were using the real vgs, vgd, and vds */ { /* converting (temporarily) to local vgs, vgd, and vds */ double vgsreal=vgs; double vgdreal=vgd; double vdsreal=vds; Dderivs d_afact, d_lfact; Dderivs d_betap, d_denom, d_invdenom; Dderivs d_prod; Dderivs d_vgst; if (vdsreal < 0.0) { vgs = vgdreal; vgd = vgsreal; vds = -vdsreal; here->MESmode = -1; /* source-drain interchange */ } else here->MESmode = 1; d_p.value = 0.0; d_p.d1_p = 1.0; d_p.d1_q = 0.0; d_p.d1_r = 0.0; d_p.d2_p2 = 0.0; d_p.d2_q2 = 0.0; d_p.d2_r2 = 0.0; d_p.d2_pq = 0.0; d_p.d2_qr = 0.0; d_p.d2_pr = 0.0; d_p.d3_p3 = 0.0; d_p.d3_q3 = 0.0; d_p.d3_r3 = 0.0; d_p.d3_p2r = 0.0; d_p.d3_p2q = 0.0; d_p.d3_q2r = 0.0; d_p.d3_pq2 = 0.0; d_p.d3_pr2 = 0.0; d_p.d3_qr2 = 0.0; d_p.d3_pqr = 0.0; EqualDeriv(&d_q,&d_p); EqualDeriv(&d_r,&d_p); EqualDeriv(&d_zero,&d_p); d_q.d1_p = d_r.d1_p = d_zero.d1_p = 0.0; d_q.d1_q = d_r.d1_r = 1.0; d_p.value = vgs; d_r.value = vds; /* p =vgs; q= nothing in particular ; r = vds */ vgst = vgs-model->MESthreshold; EqualDeriv(&d_vgst,&d_p); d_vgst.value = vgst; /* * normal mode, cutoff region */ if (vgst <= 0) { cdrain = 0; EqualDeriv(&d_cdrain,&d_zero); } else { prod = 1 + model->MESlModulation * vds; TimesDeriv(&d_prod,&d_r,model->MESlModulation); d_prod.value = prod; betap = beta * prod; TimesDeriv(&d_betap,&d_prod,beta); denom = 1 + model->MESb * vgst; TimesDeriv(&d_denom,&d_vgst,model->MESb); d_denom.value = denom; invdenom = 1 / denom; InvDeriv(&d_invdenom,&d_denom); /* * normal mode, saturation region */ cdrain = betap * vgst * vgst * invdenom; MultDeriv(&d_cdrain,&d_betap,&d_vgst); MultDeriv(&d_cdrain,&d_cdrain,&d_vgst); MultDeriv(&d_cdrain,&d_cdrain,&d_invdenom); if (vds < ( 3 / model->MESalpha ) ) { /* * normal mode, linear region */ afact = 1 - model->MESalpha * vds / 3; TimesDeriv(&d_afact,&d_r,-model->MESalpha/3.0); d_afact.value = afact; lfact = 1 - afact * afact * afact; CubeDeriv(&d_lfact,&d_afact); TimesDeriv(&d_lfact,&d_lfact,-1.0); d_lfact.value += 1.0; cdrain = betap*vgst*vgst*invdenom*lfact; MultDeriv(&d_cdrain,&d_betap,&d_vgst); MultDeriv(&d_cdrain,&d_cdrain,&d_vgst); MultDeriv(&d_cdrain,&d_cdrain,&d_invdenom); MultDeriv(&d_cdrain,&d_cdrain,&d_lfact); } } /* converting back to real vgs, vgd, vds */ if (here->MESmode == -1) { vgs = vgsreal; vgd = vgdreal; vds = vdsreal; } } /* * charge storage elements */ { /* code block */ czgs = model->MEScapGS * here->MESm * here->MESarea; czgd = model->MEScapGD * here->MESm * here->MESarea; phib = model->MESgatePotential; vcap = 1 / model->MESalpha; /* * qgga = qggnew(vgs,vgd,phib,vcap,vto,czgs,czgd,&cgsna,&cgdna); */ /* function qggnew - private, used by MESload*/ { double veroot,veff1,veff2,del,vnroot,vnew1,vnew3,vmax,ext; double qroot,par1,cfact,cplus,cminus; Dderivs d_vnroot; Dderivs d_cgsnew, d_cgdnew, d_dummy, d_dummy2; Dderivs d_ext, d_qroot, d_par1, d_cfact, d_cplus, d_cminus; Dderivs d_veroot, d_veff1, d_veff2, d_vnew1, d_vnew3; /* now p=vgs, q=vgd, r= nothing */ d_q.value = vgd; d_p.value = vgs; veroot = sqrt( (vgs - vgd) * (vgs - vgd) + vcap*vcap ); TimesDeriv(&d_veroot,&d_q,-1.0); PlusDeriv(&d_veroot,&d_veroot,&d_p); MultDeriv(&d_veroot,&d_veroot,&d_veroot); d_veroot.value += vcap*vcap; SqrtDeriv(&d_veroot,&d_veroot); veff1 = 0.5 * (vgs + vgd + veroot); PlusDeriv(&d_veff1,&d_veroot,&d_p); PlusDeriv(&d_veff1,&d_veff1,&d_q); TimesDeriv(&d_veff1,&d_veff1,0.5); veff2 = veff1 - veroot; TimesDeriv(&d_veff2,&d_veroot,-1.0); PlusDeriv(&d_veff2,&d_veff2,&d_veff1); del = 0.2;/*const*/ vnroot = sqrt( (veff1 - vto)*(veff1 - vto) + del * del ); EqualDeriv(&d_vnroot,&d_veff1); d_vnroot.value -= vto; MultDeriv(&d_vnroot,&d_vnroot,&d_vnroot); d_vnroot.value += del*del; SqrtDeriv(&d_vnroot,&d_vnroot); vnew1 = 0.5 * (veff1 + vto + vnroot); PlusDeriv(&d_vnew1,&d_veff1,&d_vnroot); d_vnew1.value += vto; TimesDeriv(&d_vnew1,&d_vnew1,0.5); vnew3 = vnew1; EqualDeriv(&d_vnew3,&d_vnew1); vmax = 0.5;/*const*/ if ( vnew1 < vmax ) { ext=0; EqualDeriv(&d_ext,&d_zero); } else { vnew1 = vmax; EqualDeriv(&d_vnew1,&d_zero); d_vnew1.value = vmax; ext = (vnew3 - vmax)/sqrt(1 - vmax/phib); EqualDeriv(&d_ext,&d_vnew3); d_ext.value -= vmax; TimesDeriv(&d_ext,&d_ext,1/sqrt(1 - vmax/phib)); } qroot = sqrt(1 - vnew1/phib); TimesDeriv(&d_qroot,&d_vnew1,-1/phib); d_qroot.value += 1.0; SqrtDeriv(&d_qroot,&d_qroot); /* * qggval = czgs * (2*phib*(1-qroot) + ext) + czgd*veff2; */ par1 = 0.5 * ( 1 + (veff1-vto)/vnroot); EqualDeriv(&d_par1,&d_veff1); d_par1.value -= vto; DivDeriv(&d_par1,&d_par1,&d_vnroot); d_par1.value += 1.0; TimesDeriv(&d_par1,&d_par1,0.5); cfact = (vgs- vgd)/veroot; TimesDeriv(&d_cfact,&d_q,-1.0); PlusDeriv(&d_cfact,&d_cfact,&d_p); DivDeriv(&d_cfact,&d_cfact,&d_veroot); cplus = 0.5 * (1 + cfact); TimesDeriv(&d_cplus,&d_cfact,0.5); d_cplus.value += 0.5; cminus = cplus - cfact; TimesDeriv(&d_cminus,&d_cfact,-0.5); d_cminus.value += 0.5; /* *cgsnew = czgs/qroot*par1*cplus + czgd*cminus; *cgdnew = czgs/qroot*par1*cminus + czgd*cplus; * * assuming qgs = vgs*cgsnew * and qgd = vgd*cgsnew * * This is probably wrong but then so is the a.c. analysis * routine and everything else * */ MultDeriv(&d_dummy,&d_qroot,&d_par1); InvDeriv(&d_dummy,&d_dummy); TimesDeriv(&d_dummy,&d_dummy,czgs); TimesDeriv(&d_cgsnew,&d_cminus,czgd); MultDeriv(&d_dummy2,&d_dummy,&d_cplus); PlusDeriv(&d_cgsnew,&d_cgsnew,&d_dummy2); TimesDeriv(&d_cgdnew,&d_cplus,czgd); MultDeriv(&d_dummy2,&d_dummy,&d_cminus); PlusDeriv(&d_cgdnew,&d_cgdnew,&d_dummy2); MultDeriv(&d_qgs,&d_cgsnew,&d_p); MultDeriv(&d_qgd,&d_cgdnew,&d_q); } } if (here->MESmode == 1) { /* normal mode - no source-drain interchange */ here->cdr_x = d_cdrain.d1_p; here->cdr_z = d_cdrain.d1_r; here->cdr_x2 = d_cdrain.d2_p2; here->cdr_z2 = d_cdrain.d2_r2; here->cdr_xz = d_cdrain.d2_pr; here->cdr_x3 = d_cdrain.d3_p3; here->cdr_z3 = d_cdrain.d3_r3;; here->cdr_x2z = d_cdrain.d3_p2r; here->cdr_xz2 = d_cdrain.d3_pr2; } else { /* * inverse mode - source and drain interchanged */ here->cdr_x = -d_cdrain.d1_p; here->cdr_z = d_cdrain.d1_p + d_cdrain.d1_r; here->cdr_x2 = -d_cdrain.d2_p2; here->cdr_z2 = -(d_cdrain.d2_p2 + d_cdrain.d2_r2 + 2*d_cdrain.d2_pr); here->cdr_xz = d_cdrain.d2_p2 + d_cdrain.d2_pr; here->cdr_x3 = -d_cdrain.d3_p3; here->cdr_z3 = d_cdrain.d3_p3 + d_cdrain.d3_r3 + 3*(d_cdrain.d3_p2r + d_cdrain.d3_pr2 ) ; here->cdr_x2z = d_cdrain.d3_p3 + d_cdrain.d3_p2r; here->cdr_xz2 = -(d_cdrain.d3_p3 + 2*d_cdrain.d3_p2r + d_cdrain.d3_pr2); } /* now to adjust for type and multiply by factors to convert to Taylor coeffs. */ here->cdr_x2 = 0.5*model->MEStype*here->cdr_x2; here->cdr_z2 = 0.5*model->MEStype*here->cdr_z2; here->cdr_xz = model->MEStype*here->cdr_xz; here->cdr_x3 = here->cdr_x3/6.; here->cdr_z3 = here->cdr_z3/6.; here->cdr_x2z = 0.5*here->cdr_x2z; here->cdr_xz2 = 0.5*here->cdr_xz2; here->ggs3 = lggs3; here->ggd3 = lggd3; here->ggs2 = model->MEStype*lggs2; here->ggd2 = model->MEStype*lggd2; here->qgs_x2 = 0.5*model->MEStype*d_qgs.d2_p2; here->qgs_y2 = 0.5*model->MEStype*d_qgs.d2_q2; here->qgs_xy = model->MEStype*d_qgs.d2_pq; here->qgs_x3 = d_qgs.d3_p3/6.; here->qgs_y3 = d_qgs.d3_q3/6.; here->qgs_x2y = 0.5*d_qgs.d3_p2q; here->qgs_xy2 = 0.5*d_qgs.d3_pq2; here->qgd_x2 = 0.5*model->MEStype*d_qgd.d2_p2; here->qgd_y2 = 0.5*model->MEStype*d_qgd.d2_q2; here->qgd_xy = model->MEStype*d_qgd.d2_pq; here->qgd_x3 = d_qgd.d3_p3/6.; here->qgd_y3 = d_qgd.d3_q3/6.; here->qgd_x2y = 0.5*d_qgd.d3_p2q; here->qgd_xy2 = 0.5*d_qgd.d3_pq2; } } return(OK); }