From 1381d71cb1debcf8ddd5d751354a650d64405eb6 Mon Sep 17 00:00:00 2001 From: dwarning Date: Tue, 23 Jan 2024 14:55:08 +0100 Subject: [PATCH] selectable flicker noise models for mos1...3 --- 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 | 46 +++++++++++++++++++++++----- 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 | 46 +++++++++++++++++++++++----- 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 | 46 +++++++++++++++++++++++----- src/spicelib/devices/mos3/mos3set.c | 3 ++ 18 files changed, 162 insertions(+), 24 deletions(-) diff --git a/src/spicelib/devices/mos1/mos1.c b/src/spicelib/devices/mos1/mos1.c index 54bee5f79..f7931a530 100644 --- a/src/spicelib/devices/mos1/mos1.c +++ b/src/spicelib/devices/mos1/mos1.c @@ -148,7 +148,8 @@ IFparm MOS1mPTable[] = { /* model parameters */ IOP("nss", MOS1_MOD_NSS, IF_REAL ,"Surface state density"), 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("af", MOS1_MOD_AF, IF_REAL ,"Flicker noise exponent"), + IOP("nlev", MOS1_MOD_NLEV, IF_INTEGER ,"Noise model selection") }; char *MOS1names[] = { diff --git a/src/spicelib/devices/mos1/mos1defs.h b/src/spicelib/devices/mos1/mos1defs.h index b6fc299b3..231388ac0 100644 --- a/src/spicelib/devices/mos1/mos1defs.h +++ b/src/spicelib/devices/mos1/mos1defs.h @@ -383,6 +383,7 @@ typedef struct sMOS1model { /* model structure for a resistor */ double MOS1surfaceMobility; /* input - use tSurfMob */ double MOS1fNcoef; double MOS1fNexp; + int MOS1nlev; unsigned MOS1typeGiven :1; unsigned MOS1latDiffGiven :1; @@ -415,6 +416,7 @@ typedef struct sMOS1model { /* model structure for a resistor */ unsigned MOS1tnomGiven :1; unsigned MOS1fNcoefGiven :1; unsigned MOS1fNexpGiven :1; + unsigned MOS1nlevGiven :1; } MOS1model; @@ -483,6 +485,7 @@ enum { MOS1_MOD_TNOM, MOS1_MOD_KF, MOS1_MOD_AF, + MOS1_MOD_NLEV, MOS1_MOD_TYPE, }; diff --git a/src/spicelib/devices/mos1/mos1mask.c b/src/spicelib/devices/mos1/mos1mask.c index 494392609..c04522f71 100644 --- a/src/spicelib/devices/mos1/mos1mask.c +++ b/src/spicelib/devices/mos1/mos1mask.c @@ -105,6 +105,9 @@ MOS1mAsk(CKTcircuit *ckt, GENmodel *inst, int which, IFvalue *value) case MOS1_MOD_NSS: value->rValue = model->MOS1surfaceStateDensity; return(OK); + case MOS1_MOD_NLEV: + value->iValue = model->MOS1nlev; + 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 1986e1750..728fd06d0 100644 --- a/src/spicelib/devices/mos1/mos1mpar.c +++ b/src/spicelib/devices/mos1/mos1mpar.c @@ -147,6 +147,10 @@ MOS1mParam(int param, IFvalue *value, GENmodel *inModel) model->MOS1fNexp = value->rValue; model->MOS1fNexpGiven = TRUE; break; + case MOS1_MOD_NLEV: + model->MOS1nlev = value->iValue; + model->MOS1nlevGiven = TRUE; + break; default: return(E_BADPARM); } diff --git a/src/spicelib/devices/mos1/mos1noi.c b/src/spicelib/devices/mos1/mos1noi.c index 07fed16d3..93b93749c 100644 --- a/src/spicelib/devices/mos1/mos1noi.c +++ b/src/spicelib/devices/mos1/mos1noi.c @@ -10,6 +10,7 @@ Modified: 2000 AlansFixes #include "ngspice/iferrmsg.h" #include "ngspice/noisedef.h" #include "ngspice/suffix.h" +#include "ngspice/compatmode.h" /* * MOS1noise (mode, operation, firstModel, ckt, data, OnDens) @@ -108,13 +109,44 @@ MOS1noise(int mode, int operation, GENmodel * genmodel, CKTcircuit * ckt, NevalSrc( & noizDens[MOS1FLNOIZ], NULL, ckt, N_GAIN, inst -> MOS1dNodePrime, inst -> MOS1sNodePrime, (double) 0.0); - noizDens[MOS1FLNOIZ] *= model -> MOS1fNcoef * - exp(model -> MOS1fNexp * - log(MAX(fabs(inst -> MOS1cd), N_MINLOG))) / - (data -> freq * - inst -> MOS1w * - (inst -> MOS1l - 2 * model -> MOS1latDiff) * - coxSquared); + if (newcompat.s3) { + noizDens[MOS1FLNOIZ] *= model -> MOS1fNcoef * + exp(model -> MOS1fNexp * + log(MAX(fabs(inst -> MOS1cd), N_MINLOG))) / + (data -> freq * + inst -> MOS1w * + (inst -> MOS1l - 2 * model -> MOS1latDiff) * + coxSquared); + } else { + switch (model -> MOS1nlev) { + case 0: + noizDens[MOS1FLNOIZ] *= model -> MOS1fNcoef * + exp(model -> MOS1fNexp * + log(MAX(fabs(inst -> MOS1cd), N_MINLOG))) / + (data -> freq * + (inst -> MOS1l - 2 * model -> MOS1latDiff) * + (inst -> MOS1l - 2 * model -> MOS1latDiff) * + sqrt(coxSquared)); + break; + case 1: + noizDens[MOS1FLNOIZ] *= model -> MOS1fNcoef * + exp(model -> MOS1fNexp * + log(MAX(fabs(inst -> MOS1cd), N_MINLOG))) / + (data -> freq * + inst -> MOS1w * + (inst -> MOS1l - 2 * model -> MOS1latDiff) * + sqrt(coxSquared)); + break; + case 2: case 3: + noizDens[MOS1FLNOIZ] *= model -> MOS1fNcoef * + inst -> MOS1gm * inst -> MOS1gm / + (pow(data -> freq, model -> MOS1fNexp) * + inst -> MOS1w * + (inst -> MOS1l - 2 * model -> MOS1latDiff) * + sqrt(coxSquared)); + break; + } + } lnNdens[MOS1FLNOIZ] = log(MAX(noizDens[MOS1FLNOIZ], N_MINLOG)); diff --git a/src/spicelib/devices/mos1/mos1set.c b/src/spicelib/devices/mos1/mos1set.c index 6912cbe71..65ba81311 100644 --- a/src/spicelib/devices/mos1/mos1set.c +++ b/src/spicelib/devices/mos1/mos1set.c @@ -87,6 +87,9 @@ MOS1setup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt, if(!model->MOS1fNexpGiven) { model->MOS1fNexp = 1; } + if(!model->MOS1nlevGiven) { + model->MOS1nlev = 2; + } /* 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 d36a08147..040895297 100644 --- a/src/spicelib/devices/mos2/mos2.c +++ b/src/spicelib/devices/mos2/mos2.c @@ -156,7 +156,8 @@ IFparm MOS2mPTable[] = { /* model parameters */ IOP("nfs", MOS2_MOD_NFS, IF_REAL ,"Fast surface state density"), 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("af", MOS2_MOD_AF, IF_REAL ,"Flicker noise exponent"), + IOP("nlev", MOS2_MOD_NLEV, IF_INTEGER ,"Noise model selection") }; char *MOS2names[] = { diff --git a/src/spicelib/devices/mos2/mos2defs.h b/src/spicelib/devices/mos2/mos2defs.h index bf59484d2..bcce92f49 100644 --- a/src/spicelib/devices/mos2/mos2defs.h +++ b/src/spicelib/devices/mos2/mos2defs.h @@ -390,6 +390,7 @@ typedef struct sMOS2model { /* model structure for a resistor */ double MOS2surfaceMobility; double MOS2fNcoef; double MOS2fNexp; + int MOS2nlev; double MOS2narrowFactor; /* delta */ double MOS2critFieldExp; /* uexp */ @@ -437,6 +438,7 @@ typedef struct sMOS2model { /* model structure for a resistor */ unsigned MOS2channelChargeGiven :1; /* neff */ unsigned MOS2fNcoefGiven :1; unsigned MOS2fNexpGiven :1; + unsigned MOS2nlevGiven :1; } MOS2model; @@ -574,6 +576,7 @@ enum { enum { MOS2_MOD_KF = 139, MOS2_MOD_AF, + MOS2_MOD_NLEV, MOS2_MOD_TYPE, }; diff --git a/src/spicelib/devices/mos2/mos2mask.c b/src/spicelib/devices/mos2/mos2mask.c index b3cfda751..9e149ea72 100644 --- a/src/spicelib/devices/mos2/mos2mask.c +++ b/src/spicelib/devices/mos2/mos2mask.c @@ -130,6 +130,9 @@ MOS2mAsk(CKTcircuit *ckt, GENmodel *inModel, int param, case MOS2_MOD_AF: value->rValue = model->MOS2fNexp; break; + case MOS2_MOD_NLEV: + value->iValue = model->MOS2nlev; + break; 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 49967db0a..97fb101a0 100644 --- a/src/spicelib/devices/mos2/mos2mpar.c +++ b/src/spicelib/devices/mos2/mos2mpar.c @@ -178,6 +178,10 @@ MOS2mParam(int param, IFvalue *value, GENmodel *inModel) model->MOS2fNexp = value->rValue; model->MOS2fNexpGiven = TRUE; break; + case MOS2_MOD_NLEV: + model->MOS2nlev = value->iValue; + model->MOS2nlevGiven = TRUE; + break; default: return(E_BADPARM); } diff --git a/src/spicelib/devices/mos2/mos2noi.c b/src/spicelib/devices/mos2/mos2noi.c index 1b47ab19c..94dfbdf79 100644 --- a/src/spicelib/devices/mos2/mos2noi.c +++ b/src/spicelib/devices/mos2/mos2noi.c @@ -10,6 +10,7 @@ Modified: 2000 AlansFixes #include "ngspice/iferrmsg.h" #include "ngspice/noisedef.h" #include "ngspice/suffix.h" +#include "ngspice/compatmode.h" /* * MOS2noise (mode, operation, firstModel, ckt, data, OnDens) @@ -97,13 +98,44 @@ MOS2noise(int mode, int operation, GENmodel * genmodel, CKTcircuit * ckt, NevalSrc( & noizDens[MOS2FLNOIZ], NULL, ckt, N_GAIN, inst -> MOS2dNodePrime, inst -> MOS2sNodePrime, (double) 0.0); - noizDens[MOS2FLNOIZ] *= model -> MOS2fNcoef * - exp(model -> MOS2fNexp * - log(MAX(fabs(inst -> MOS2cd), N_MINLOG))) / - (data -> freq * - inst -> MOS2w * - (inst -> MOS2l - 2 * model -> MOS2latDiff) * - model -> MOS2oxideCapFactor * model -> MOS2oxideCapFactor); + if (newcompat.s3) { + noizDens[MOS2FLNOIZ] *= model -> MOS2fNcoef * + exp(model -> MOS2fNexp * + log(MAX(fabs(inst -> MOS2cd), N_MINLOG))) / + (data -> freq * + inst -> MOS2w * + (inst -> MOS2l - 2 * model -> MOS2latDiff) * + model -> MOS2oxideCapFactor * model -> MOS2oxideCapFactor); + } else { + switch (model -> MOS2nlev) { + case 0: + noizDens[MOS2FLNOIZ] *= model -> MOS2fNcoef * + exp(model -> MOS2fNexp * + log(MAX(fabs(inst -> MOS2cd), N_MINLOG))) / + (data -> freq * + (inst -> MOS2l - 2 * model -> MOS2latDiff) * + (inst -> MOS2l - 2 * model -> MOS2latDiff) * + model -> MOS2oxideCapFactor); + break; + case 1: + noizDens[MOS2FLNOIZ] *= model -> MOS2fNcoef * + exp(model -> MOS2fNexp * + log(MAX(fabs(inst -> MOS2cd), N_MINLOG))) / + (data -> freq * + inst -> MOS2w * + (inst -> MOS2l - 2 * model -> MOS2latDiff) * + model -> MOS2oxideCapFactor); + break; + case 2: case 3: + noizDens[MOS2FLNOIZ] *= model -> MOS2fNcoef * + inst -> MOS2gm * inst -> MOS2gm / + (pow(data -> freq, model -> MOS2fNexp) * + inst -> MOS2w * + (inst -> MOS2l - 2 * model -> MOS2latDiff) * + model -> MOS2oxideCapFactor); + break; + } + } lnNdens[MOS2FLNOIZ] = log(MAX(noizDens[MOS2FLNOIZ], N_MINLOG)); diff --git a/src/spicelib/devices/mos2/mos2set.c b/src/spicelib/devices/mos2/mos2set.c index 3c3acfd4d..b23be6d1f 100644 --- a/src/spicelib/devices/mos2/mos2set.c +++ b/src/spicelib/devices/mos2/mos2set.c @@ -116,6 +116,9 @@ MOS2setup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt, int *states) if(!model->MOS2fNexpGiven) { model->MOS2fNexp = 1; } + if(!model->MOS2nlevGiven) { + model->MOS2nlev = 2; + } /* 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 553840366..72d738eb2 100644 --- a/src/spicelib/devices/mos3/mos3.c +++ b/src/spicelib/devices/mos3/mos3.c @@ -156,7 +156,8 @@ IFparm MOS3mPTable[] = { /* model parameters */ IOP("kappa", MOS3_MOD_KAPPA, IF_REAL ,"Kappa"), 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("af", MOS3_MOD_AF, IF_REAL ,"Flicker noise exponent"), + IOP("nlev", MOS3_MOD_NLEV, IF_INTEGER ,"Noise model selection") }; char *MOS3names[] = { diff --git a/src/spicelib/devices/mos3/mos3defs.h b/src/spicelib/devices/mos3/mos3defs.h index 7e4c9aba4..7ce5f4bfb 100644 --- a/src/spicelib/devices/mos3/mos3defs.h +++ b/src/spicelib/devices/mos3/mos3defs.h @@ -400,6 +400,7 @@ typedef struct sMOS3model { /* model structure for a resistor */ double MOS3kappa; /* kappa */ double MOS3fNcoef; double MOS3fNexp; + int MOS3nlev; unsigned MOS3typeGiven :1; unsigned MOS3latDiffGiven :1; @@ -442,6 +443,7 @@ typedef struct sMOS3model { /* model structure for a resistor */ unsigned MOS3tnomGiven :1; /* Tnom was given? */ unsigned MOS3fNcoefGiven :1; unsigned MOS3fNexpGiven :1; + unsigned MOS3nlevGiven :1; } MOS3model; @@ -580,6 +582,7 @@ enum { MOS3_MOD_TNOM, MOS3_MOD_KF, MOS3_MOD_AF, + MOS3_MOD_NLEV, 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 d66c89029..9f870ec9b 100644 --- a/src/spicelib/devices/mos3/mos3mask.c +++ b/src/spicelib/devices/mos3/mos3mask.c @@ -154,6 +154,9 @@ MOS3mAsk(CKTcircuit *ckt, GENmodel *inst, int which, IFvalue *value) case MOS3_MOD_AF: value->rValue = here->MOS3fNexp; return(OK); + case MOS3_MOD_NLEV: + value->iValue = here->MOS3nlev; + return(OK); case MOS3_MOD_TYPE: if (here->MOS3type > 0) value->sValue = "nmos"; diff --git a/src/spicelib/devices/mos3/mos3mpar.c b/src/spicelib/devices/mos3/mos3mpar.c index 8b4a57e87..1564410b0 100644 --- a/src/spicelib/devices/mos3/mos3mpar.c +++ b/src/spicelib/devices/mos3/mos3mpar.c @@ -191,6 +191,10 @@ MOS3mParam(int param, IFvalue *value, GENmodel *inModel) model->MOS3fNexp = value->rValue; model->MOS3fNexpGiven = TRUE; break; + case MOS3_MOD_NLEV: + model->MOS3nlev = value->iValue; + model->MOS3nlevGiven = TRUE; + break; default: return(E_BADPARM); } diff --git a/src/spicelib/devices/mos3/mos3noi.c b/src/spicelib/devices/mos3/mos3noi.c index 6265dec93..33d8bd344 100644 --- a/src/spicelib/devices/mos3/mos3noi.c +++ b/src/spicelib/devices/mos3/mos3noi.c @@ -10,6 +10,7 @@ Modified: 2000 AlansFixes #include "ngspice/iferrmsg.h" #include "ngspice/noisedef.h" #include "ngspice/suffix.h" +#include "ngspice/compatmode.h" /* * MOS3noise (mode, operation, firstModel, ckt, data, OnDens) @@ -97,13 +98,44 @@ MOS3noise(int mode, int operation, GENmodel * genmodel, CKTcircuit * ckt, NevalSrc( & noizDens[MOS3FLNOIZ], NULL, ckt, N_GAIN, inst -> MOS3dNodePrime, inst -> MOS3sNodePrime, (double) 0.0); - noizDens[MOS3FLNOIZ] *= model -> MOS3fNcoef * - exp(model -> MOS3fNexp * - log(MAX(fabs(inst -> MOS3cd), N_MINLOG))) / - (data -> freq * - (inst -> MOS3w - 2 * model -> MOS3widthNarrow) * - (inst -> MOS3l - 2 * model -> MOS3latDiff) * - model -> MOS3oxideCapFactor * model -> MOS3oxideCapFactor); + if (newcompat.s3) { + noizDens[MOS3FLNOIZ] *= model -> MOS3fNcoef * + exp(model -> MOS3fNexp * + log(MAX(fabs(inst -> MOS3cd), N_MINLOG))) / + (data -> freq * + (inst -> MOS3w - 2 * model -> MOS3widthNarrow) * + (inst -> MOS3l - 2 * model -> MOS3latDiff) * + model -> MOS3oxideCapFactor * model -> MOS3oxideCapFactor); + } else { + switch (model -> MOS3nlev) { + case 0: + noizDens[MOS3FLNOIZ] *= model -> MOS3fNcoef * + exp(model -> MOS3fNexp * + log(MAX(fabs(inst -> MOS3cd), N_MINLOG))) / + (data -> freq * + (inst -> MOS3l - 2 * model -> MOS3latDiff) * + (inst -> MOS3l - 2 * model -> MOS3latDiff) * + model -> MOS3oxideCapFactor); + break; + case 1: + noizDens[MOS3FLNOIZ] *= model -> MOS3fNcoef * + exp(model -> MOS3fNexp * + log(MAX(fabs(inst -> MOS3cd), N_MINLOG))) / + (data -> freq * + (inst -> MOS3w - 2 * model -> MOS3widthNarrow) * + (inst -> MOS3l - 2 * model -> MOS3latDiff) * + model -> MOS3oxideCapFactor); + break; + case 2: case 3: + noizDens[MOS3FLNOIZ] *= model -> MOS3fNcoef * + inst -> MOS3gm * inst -> MOS3gm / + (pow(data -> freq, model -> MOS3fNexp) * + (inst -> MOS3w - 2 * model -> MOS3widthNarrow) * + (inst -> MOS3l - 2 * model -> MOS3latDiff) * + model -> MOS3oxideCapFactor); + break; + } + } lnNdens[MOS3FLNOIZ] = log(MAX(noizDens[MOS3FLNOIZ], N_MINLOG)); diff --git a/src/spicelib/devices/mos3/mos3set.c b/src/spicelib/devices/mos3/mos3set.c index 4432ba461..d494f8434 100644 --- a/src/spicelib/devices/mos3/mos3set.c +++ b/src/spicelib/devices/mos3/mos3set.c @@ -139,6 +139,9 @@ MOS3setup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt, int *states) if(!model->MOS3fNexpGiven) { model->MOS3fNexp = 1; } + if(!model->MOS3nlevGiven) { + model->MOS3nlev = 2; + } /* loop through all the instances of the model */ for (here = MOS3instances(model); here != NULL ;