From 6359b7b41f8f4008f732be3086716a786bc3bc7f Mon Sep 17 00:00:00 2001 From: dwarning Date: Sun, 28 Jan 2024 10:08:29 +0100 Subject: [PATCH] mos1...3: add nlev=3 mode channel thermal noise --- src/spicelib/devices/mos1/mos1.c | 3 ++- src/spicelib/devices/mos1/mos1defs.h | 3 +++ src/spicelib/devices/mos1/mos1mask.c | 3 +++ src/spicelib/devices/mos1/mos1mpar.c | 4 ++++ src/spicelib/devices/mos1/mos1noi.c | 28 +++++++++++++++++++++++++++- src/spicelib/devices/mos1/mos1set.c | 3 +++ src/spicelib/devices/mos2/mos2.c | 3 ++- src/spicelib/devices/mos2/mos2defs.h | 3 +++ src/spicelib/devices/mos2/mos2mask.c | 3 +++ src/spicelib/devices/mos2/mos2mpar.c | 4 ++++ src/spicelib/devices/mos2/mos2noi.c | 28 +++++++++++++++++++++++++++- src/spicelib/devices/mos2/mos2set.c | 3 +++ src/spicelib/devices/mos3/mos3.c | 3 ++- src/spicelib/devices/mos3/mos3defs.h | 3 +++ src/spicelib/devices/mos3/mos3mask.c | 3 +++ src/spicelib/devices/mos3/mos3mpar.c | 4 ++++ src/spicelib/devices/mos3/mos3noi.c | 28 +++++++++++++++++++++++++++- src/spicelib/devices/mos3/mos3set.c | 3 +++ 18 files changed, 126 insertions(+), 6 deletions(-) diff --git a/src/spicelib/devices/mos1/mos1.c b/src/spicelib/devices/mos1/mos1.c index f7931a530..beaa11bc0 100644 --- a/src/spicelib/devices/mos1/mos1.c +++ b/src/spicelib/devices/mos1/mos1.c @@ -149,7 +149,8 @@ IFparm MOS1mPTable[] = { /* model parameters */ IOP("tnom", MOS1_MOD_TNOM, IF_REAL ,"Parameter measurement temperature"), IOP("kf", MOS1_MOD_KF, IF_REAL ,"Flicker noise coefficient"), IOP("af", MOS1_MOD_AF, IF_REAL ,"Flicker noise exponent"), - IOP("nlev", MOS1_MOD_NLEV, IF_INTEGER ,"Noise model selection") + IOP("nlev", MOS1_MOD_NLEV, IF_INTEGER ,"Noise model selection"), + IOP("gdsnoi", MOS1_MOD_GDSNOI, IF_REAL ,"Channel shot noise coefficient") }; char *MOS1names[] = { diff --git a/src/spicelib/devices/mos1/mos1defs.h b/src/spicelib/devices/mos1/mos1defs.h index 231388ac0..6103b23ba 100644 --- a/src/spicelib/devices/mos1/mos1defs.h +++ b/src/spicelib/devices/mos1/mos1defs.h @@ -384,6 +384,7 @@ typedef struct sMOS1model { /* model structure for a resistor */ double MOS1fNcoef; double MOS1fNexp; int MOS1nlev; + double MOS1gdsnoi; unsigned MOS1typeGiven :1; unsigned MOS1latDiffGiven :1; @@ -417,6 +418,7 @@ typedef struct sMOS1model { /* model structure for a resistor */ unsigned MOS1fNcoefGiven :1; unsigned MOS1fNexpGiven :1; unsigned MOS1nlevGiven :1; + unsigned MOS1gdsnoiGiven :1; } MOS1model; @@ -486,6 +488,7 @@ enum { MOS1_MOD_KF, MOS1_MOD_AF, MOS1_MOD_NLEV, + MOS1_MOD_GDSNOI, MOS1_MOD_TYPE, }; diff --git a/src/spicelib/devices/mos1/mos1mask.c b/src/spicelib/devices/mos1/mos1mask.c index 903983103..e0c610c56 100644 --- a/src/spicelib/devices/mos1/mos1mask.c +++ b/src/spicelib/devices/mos1/mos1mask.c @@ -108,6 +108,9 @@ MOS1mAsk(CKTcircuit *ckt, GENmodel *inst, int which, IFvalue *value) case MOS1_MOD_NLEV: value->iValue = model->MOS1nlev; return(OK); + case MOS1_MOD_GDSNOI: + value->rValue = model->MOS1gdsnoi; + return(OK); case MOS1_MOD_TYPE: if (model->MOS1type > 0) value->sValue = "nmos"; diff --git a/src/spicelib/devices/mos1/mos1mpar.c b/src/spicelib/devices/mos1/mos1mpar.c index 82a5dc714..d849626ff 100644 --- a/src/spicelib/devices/mos1/mos1mpar.c +++ b/src/spicelib/devices/mos1/mos1mpar.c @@ -151,6 +151,10 @@ MOS1mParam(int param, IFvalue *value, GENmodel *inModel) model->MOS1nlev = value->iValue; model->MOS1nlevGiven = TRUE; break; + case MOS1_MOD_GDSNOI: + model->MOS1gdsnoi = value->rValue; + model->MOS1gdsnoiGiven = TRUE; + break; default: return(E_BADPARM); } diff --git a/src/spicelib/devices/mos1/mos1noi.c b/src/spicelib/devices/mos1/mos1noi.c index 9d78dd47e..ec7801963 100644 --- a/src/spicelib/devices/mos1/mos1noi.c +++ b/src/spicelib/devices/mos1/mos1noi.c @@ -35,6 +35,7 @@ MOS1noise(int mode, int operation, GENmodel * genmodel, CKTcircuit * ckt, double noizDens[MOS1NSRCS]; double lnNdens[MOS1NSRCS]; int i; + double vgs, vds, vgd, vgst, alpha, beta, Sid; /* define the names of the noise sources */ @@ -102,9 +103,34 @@ MOS1noise(int mode, int operation, GENmodel * genmodel, CKTcircuit * ckt, ckt, THERMNOISE, inst->MOS1sNodePrime, inst->MOS1sNode, inst->MOS1sourceConductance); + if (model->MOS1nlev < 3) { + + Sid = 2.0 / 3.0 * fabs(inst->MOS1gm); + + } else { + vds = *(ckt->CKTstate0 + inst->MOS1vds); + vgs = *(ckt->CKTstate0 + inst->MOS1vgs); + vgd = vgs - vds; + beta = inst->MOS1tTransconductance * inst->MOS1m * + inst->MOS1w/(inst->MOS1l - 2 * model->MOS1latDiff); + + vgst=(inst->MOS1mode==1?vgs:vgd) - model->MOS1type*inst->MOS1von; + if (vgst > 0) { + if (vgst <= (vds*inst->MOS1mode)) { + /* saturation region */ + alpha = 0.0; + } else { + /* linear region */ + alpha = 1.0 - (vds*inst->MOS1mode/(model->MOS1type*inst->MOS1vdsat)); + } + } + double betap = beta*(1.0+model->MOS1lambda*(vds*inst->MOS1mode)); + Sid = 2.0 / 3.0 * betap * vgst * (1.0+alpha+alpha*alpha) / (1.0+alpha) * model->MOS1gdsnoi; + } + NevalSrc( & noizDens[MOS1IDNOIZ], & lnNdens[MOS1IDNOIZ], ckt, THERMNOISE, inst->MOS1dNodePrime, inst->MOS1sNodePrime, - (2.0 / 3.0 * fabs(inst->MOS1gm))); + Sid); NevalSrc( & noizDens[MOS1FLNOIZ], NULL, ckt, N_GAIN, inst->MOS1dNodePrime, inst->MOS1sNodePrime, diff --git a/src/spicelib/devices/mos1/mos1set.c b/src/spicelib/devices/mos1/mos1set.c index 313926e55..912e029a9 100644 --- a/src/spicelib/devices/mos1/mos1set.c +++ b/src/spicelib/devices/mos1/mos1set.c @@ -90,6 +90,9 @@ MOS1setup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt, if(!model->MOS1nlevGiven) { model->MOS1nlev = 2; } + if(!model->MOS1gdsnoiGiven) { + model->MOS1gdsnoi = 1; + } /* loop through all the instances of the model */ for (here = MOS1instances(model); here != NULL ; diff --git a/src/spicelib/devices/mos2/mos2.c b/src/spicelib/devices/mos2/mos2.c index 040895297..bc577da61 100644 --- a/src/spicelib/devices/mos2/mos2.c +++ b/src/spicelib/devices/mos2/mos2.c @@ -157,7 +157,8 @@ IFparm MOS2mPTable[] = { /* model parameters */ IOPU("tnom", MOS2_MOD_TNOM, IF_REAL ,"Parameter measurement temperature"), IOP("kf", MOS2_MOD_KF, IF_REAL ,"Flicker noise coefficient"), IOP("af", MOS2_MOD_AF, IF_REAL ,"Flicker noise exponent"), - IOP("nlev", MOS2_MOD_NLEV, IF_INTEGER ,"Noise model selection") + IOP("nlev", MOS2_MOD_NLEV, IF_INTEGER ,"Noise model selection"), + IOP("gdsnoi", MOS2_MOD_GDSNOI, IF_REAL ,"Channel shot noise coefficient") }; char *MOS2names[] = { diff --git a/src/spicelib/devices/mos2/mos2defs.h b/src/spicelib/devices/mos2/mos2defs.h index bcce92f49..8a1fc8ce1 100644 --- a/src/spicelib/devices/mos2/mos2defs.h +++ b/src/spicelib/devices/mos2/mos2defs.h @@ -391,6 +391,7 @@ typedef struct sMOS2model { /* model structure for a resistor */ double MOS2fNcoef; double MOS2fNexp; int MOS2nlev; + double MOS2gdsnoi; double MOS2narrowFactor; /* delta */ double MOS2critFieldExp; /* uexp */ @@ -439,6 +440,7 @@ typedef struct sMOS2model { /* model structure for a resistor */ unsigned MOS2fNcoefGiven :1; unsigned MOS2fNexpGiven :1; unsigned MOS2nlevGiven :1; + unsigned MOS2gdsnoiGiven :1; } MOS2model; @@ -577,6 +579,7 @@ enum { MOS2_MOD_KF = 139, MOS2_MOD_AF, MOS2_MOD_NLEV, + MOS2_MOD_GDSNOI, MOS2_MOD_TYPE, }; diff --git a/src/spicelib/devices/mos2/mos2mask.c b/src/spicelib/devices/mos2/mos2mask.c index 7cc54359f..ff125669e 100644 --- a/src/spicelib/devices/mos2/mos2mask.c +++ b/src/spicelib/devices/mos2/mos2mask.c @@ -133,6 +133,9 @@ MOS2mAsk(CKTcircuit *ckt, GENmodel *inModel, int param, case MOS2_MOD_NLEV: value->iValue = model->MOS2nlev; break; + case MOS2_MOD_GDSNOI: + value->rValue = model->MOS2gdsnoi; + return(OK); case MOS2_MOD_TYPE: if (model->MOS2type > 0) value->sValue = "nmos"; diff --git a/src/spicelib/devices/mos2/mos2mpar.c b/src/spicelib/devices/mos2/mos2mpar.c index 175858cbb..7c8f3dc15 100644 --- a/src/spicelib/devices/mos2/mos2mpar.c +++ b/src/spicelib/devices/mos2/mos2mpar.c @@ -182,6 +182,10 @@ MOS2mParam(int param, IFvalue *value, GENmodel *inModel) model->MOS2nlev = value->iValue; model->MOS2nlevGiven = TRUE; break; + case MOS2_MOD_GDSNOI: + model->MOS2gdsnoi = value->rValue; + model->MOS2gdsnoiGiven = TRUE; + break; default: return(E_BADPARM); } diff --git a/src/spicelib/devices/mos2/mos2noi.c b/src/spicelib/devices/mos2/mos2noi.c index 90da7b2d1..fdbcc3dbc 100644 --- a/src/spicelib/devices/mos2/mos2noi.c +++ b/src/spicelib/devices/mos2/mos2noi.c @@ -34,6 +34,7 @@ MOS2noise(int mode, int operation, GENmodel * genmodel, CKTcircuit * ckt, double noizDens[MOS2NSRCS]; double lnNdens[MOS2NSRCS]; int i; + double vgs, vds, vgd, vgst, alpha, beta, Sid; /* define the names of the noise sources */ @@ -91,9 +92,34 @@ MOS2noise(int mode, int operation, GENmodel * genmodel, CKTcircuit * ckt, ckt, THERMNOISE, inst->MOS2sNodePrime, inst->MOS2sNode, inst->MOS2sourceConductance); + if (model->MOS2nlev < 3) { + + Sid = 2.0 / 3.0 * fabs(inst->MOS2gm); + + } else { + vds = *(ckt->CKTstate0 + inst->MOS2vds); + vgs = *(ckt->CKTstate0 + inst->MOS2vgs); + vgd = vgs - vds; + beta = inst->MOS2tTransconductance * inst->MOS2m * + inst->MOS2w/(inst->MOS2l - 2 * model->MOS2latDiff); + + vgst=(inst->MOS2mode==1?vgs:vgd) - model->MOS2type*inst->MOS2von; + if (vgst > 0) { + if (vgst <= (vds*inst->MOS2mode)) { + /* saturation region */ + alpha = 0.0; + } else { + /* linear region */ + alpha = 1.0 - (vds*inst->MOS2mode/(model->MOS2type*inst->MOS2vdsat)); + } + } + double betap = beta*(1.0+model->MOS2lambda*(vds*inst->MOS2mode)); + Sid = 2.0 / 3.0 * betap * vgst * (1.0+alpha+alpha*alpha) / (1.0+alpha) * model->MOS2gdsnoi; + } + NevalSrc( & noizDens[MOS2IDNOIZ], & lnNdens[MOS2IDNOIZ], ckt, THERMNOISE, inst->MOS2dNodePrime, inst->MOS2sNodePrime, - (2.0 / 3.0 * fabs(inst->MOS2gm))); + Sid); NevalSrc( & noizDens[MOS2FLNOIZ], NULL, ckt, N_GAIN, inst->MOS2dNodePrime, inst->MOS2sNodePrime, diff --git a/src/spicelib/devices/mos2/mos2set.c b/src/spicelib/devices/mos2/mos2set.c index 9f8e9eac6..34e58bef5 100644 --- a/src/spicelib/devices/mos2/mos2set.c +++ b/src/spicelib/devices/mos2/mos2set.c @@ -119,6 +119,9 @@ MOS2setup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt, int *states) if(!model->MOS2nlevGiven) { model->MOS2nlev = 2; } + if(!model->MOS2gdsnoiGiven) { + model->MOS2gdsnoi = 1; + } /* loop through all the instances of the model */ for (here = MOS2instances(model); here != NULL ; diff --git a/src/spicelib/devices/mos3/mos3.c b/src/spicelib/devices/mos3/mos3.c index 72d738eb2..a7f2cdf81 100644 --- a/src/spicelib/devices/mos3/mos3.c +++ b/src/spicelib/devices/mos3/mos3.c @@ -157,7 +157,8 @@ IFparm MOS3mPTable[] = { /* model parameters */ IOPU("tnom", MOS3_MOD_TNOM, IF_REAL ,"Parameter measurement temperature"), IOP("kf", MOS3_MOD_KF, IF_REAL ,"Flicker noise coefficient"), IOP("af", MOS3_MOD_AF, IF_REAL ,"Flicker noise exponent"), - IOP("nlev", MOS3_MOD_NLEV, IF_INTEGER ,"Noise model selection") + IOP("nlev", MOS3_MOD_NLEV, IF_INTEGER ,"Noise model selection"), + IOP("gdsnoi", MOS3_MOD_GDSNOI, IF_REAL ,"Channel shot noise coefficient") }; char *MOS3names[] = { diff --git a/src/spicelib/devices/mos3/mos3defs.h b/src/spicelib/devices/mos3/mos3defs.h index 7ce5f4bfb..42b79faa4 100644 --- a/src/spicelib/devices/mos3/mos3defs.h +++ b/src/spicelib/devices/mos3/mos3defs.h @@ -401,6 +401,7 @@ typedef struct sMOS3model { /* model structure for a resistor */ double MOS3fNcoef; double MOS3fNexp; int MOS3nlev; + double MOS3gdsnoi; unsigned MOS3typeGiven :1; unsigned MOS3latDiffGiven :1; @@ -444,6 +445,7 @@ typedef struct sMOS3model { /* model structure for a resistor */ unsigned MOS3fNcoefGiven :1; unsigned MOS3fNexpGiven :1; unsigned MOS3nlevGiven :1; + unsigned MOS3gdsnoiGiven :1; } MOS3model; @@ -583,6 +585,7 @@ enum { MOS3_MOD_KF, MOS3_MOD_AF, MOS3_MOD_NLEV, + MOS3_MOD_GDSNOI, MOS3_MOD_TYPE, MOS3_MOD_XL, MOS3_MOD_WD, diff --git a/src/spicelib/devices/mos3/mos3mask.c b/src/spicelib/devices/mos3/mos3mask.c index 1dac927d4..355362111 100644 --- a/src/spicelib/devices/mos3/mos3mask.c +++ b/src/spicelib/devices/mos3/mos3mask.c @@ -157,6 +157,9 @@ MOS3mAsk(CKTcircuit *ckt, GENmodel *inModel, int which, IFvalue *value) case MOS3_MOD_NLEV: value->iValue = model->MOS3nlev; return(OK); + case MOS3_MOD_GDSNOI: + value->rValue = model->MOS3gdsnoi; + return(OK); case MOS3_MOD_TYPE: if (model->MOS3type > 0) value->sValue = "nmos"; diff --git a/src/spicelib/devices/mos3/mos3mpar.c b/src/spicelib/devices/mos3/mos3mpar.c index 890d0b4bb..aa6f678c3 100644 --- a/src/spicelib/devices/mos3/mos3mpar.c +++ b/src/spicelib/devices/mos3/mos3mpar.c @@ -195,6 +195,10 @@ MOS3mParam(int param, IFvalue *value, GENmodel *inModel) model->MOS3nlev = value->iValue; model->MOS3nlevGiven = TRUE; break; + case MOS3_MOD_GDSNOI: + model->MOS3gdsnoi = value->rValue; + model->MOS3gdsnoiGiven = TRUE; + break; default: return(E_BADPARM); } diff --git a/src/spicelib/devices/mos3/mos3noi.c b/src/spicelib/devices/mos3/mos3noi.c index b6e79bba7..7caa11e47 100644 --- a/src/spicelib/devices/mos3/mos3noi.c +++ b/src/spicelib/devices/mos3/mos3noi.c @@ -34,6 +34,7 @@ MOS3noise(int mode, int operation, GENmodel * genmodel, CKTcircuit * ckt, double noizDens[MOS3NSRCS]; double lnNdens[MOS3NSRCS]; int i; + double vgs, vds, vgd, vgst, alpha, beta, Sid; /* define the names of the noise sources */ @@ -91,9 +92,34 @@ MOS3noise(int mode, int operation, GENmodel * genmodel, CKTcircuit * ckt, ckt, THERMNOISE, inst->MOS3sNodePrime, inst->MOS3sNode, inst->MOS3sourceConductance); + if (model->MOS3nlev < 3) { + + Sid = 2.0 / 3.0 * fabs(inst->MOS3gm); + + } else { + vds = *(ckt->CKTstate0 + inst->MOS3vds); + vgs = *(ckt->CKTstate0 + inst->MOS3vgs); + vgd = vgs - vds; + beta = inst->MOS3tTransconductance * inst->MOS3m * + inst->MOS3w/(inst->MOS3l - 2 * model->MOS3latDiff); + + vgst=(inst->MOS3mode==1?vgs:vgd) - model->MOS3type*inst->MOS3von; + if (vgst > 0) { + if (vgst <= (vds*inst->MOS3mode)) { + /* saturation region */ + alpha = 0.0; + } else { + /* linear region */ + alpha = 1.0 - (vds*inst->MOS3mode/(model->MOS3type*inst->MOS3vdsat)); + } + } + double betap = beta; + Sid = 2.0 / 3.0 * betap * vgst * (1.0+alpha+alpha*alpha) / (1.0+alpha) * model->MOS3gdsnoi; + } + NevalSrc( & noizDens[MOS3IDNOIZ], & lnNdens[MOS3IDNOIZ], ckt, THERMNOISE, inst->MOS3dNodePrime, inst->MOS3sNodePrime, - (2.0 / 3.0 * fabs(inst->MOS3gm))); + Sid); NevalSrc( & noizDens[MOS3FLNOIZ], NULL, ckt, N_GAIN, inst->MOS3dNodePrime, inst->MOS3sNodePrime, diff --git a/src/spicelib/devices/mos3/mos3set.c b/src/spicelib/devices/mos3/mos3set.c index 8fc6a2de1..5a947de33 100644 --- a/src/spicelib/devices/mos3/mos3set.c +++ b/src/spicelib/devices/mos3/mos3set.c @@ -142,6 +142,9 @@ MOS3setup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt, int *states) if(!model->MOS3nlevGiven) { model->MOS3nlev = 2; } + if(!model->MOS3gdsnoiGiven) { + model->MOS3gdsnoi = 1; + } /* loop through all the instances of the model */ for (here = MOS3instances(model); here != NULL ;