From 01fb0ac18ba817baf30d1faa7512a128088ff862 Mon Sep 17 00:00:00 2001 From: dwarning Date: Tue, 5 Oct 2021 22:23:28 +0200 Subject: [PATCH] introduce IBE and IBC model parameter for more accurate current calculation --- src/spicelib/devices/bjt/bjt.c | 2 ++ src/spicelib/devices/bjt/bjtdefs.h | 8 ++++++++ src/spicelib/devices/bjt/bjtdset.c | 21 +++++++++++---------- src/spicelib/devices/bjt/bjtload.c | 21 +++++++++++---------- src/spicelib/devices/bjt/bjtmask.c | 6 ++++++ src/spicelib/devices/bjt/bjtmpar.c | 8 ++++++++ src/spicelib/devices/bjt/bjtsetup.c | 19 ++++++------------- src/spicelib/devices/bjt/bjttemp.c | 8 ++++++++ 8 files changed, 60 insertions(+), 33 deletions(-) diff --git a/src/spicelib/devices/bjt/bjt.c b/src/spicelib/devices/bjt/bjt.c index a82239890..38d9e816c 100644 --- a/src/spicelib/devices/bjt/bjt.c +++ b/src/spicelib/devices/bjt/bjt.c @@ -82,6 +82,8 @@ IFparm BJTmPTable[] = { /* model parameters */ IOP("tnom", BJT_MOD_TNOM, IF_REAL, "Parameter measurement temperature"), IOPR("tref", BJT_MOD_TNOM, IF_REAL, "Parameter measurement temperature"), IOP("is", BJT_MOD_IS, IF_REAL, "Saturation Current"), + IOP("ibe", BJT_MOD_IBE, IF_REAL, "Base-Emitter saturation Current"), + IOP("ibc", BJT_MOD_IBC, IF_REAL, "Base-Collector saturation Current"), IOP("bf", BJT_MOD_BF, IF_REAL, "Ideal forward beta"), IOP("nf", BJT_MOD_NF, IF_REAL, "Forward emission coefficient"), IOP("vaf", BJT_MOD_VAF, IF_REAL, "Forward Early voltage"), diff --git a/src/spicelib/devices/bjt/bjtdefs.h b/src/spicelib/devices/bjt/bjtdefs.h index eed3bee87..49336136f 100644 --- a/src/spicelib/devices/bjt/bjtdefs.h +++ b/src/spicelib/devices/bjt/bjtdefs.h @@ -60,6 +60,8 @@ typedef struct sBJTinstance { double BJTtemp; /* instance temperature */ double BJTdtemp; /* instance delta temperature from circuit */ double BJTtSatCur; /* temperature adjusted saturation current */ + double BJTBEtSatCur; /* temperature adjusted saturation current */ + double BJTBCtSatCur; /* temperature adjusted saturation current */ double BJTtBetaF; /* temperature adjusted forward beta */ double BJTtBetaR; /* temperature adjusted reverse beta */ double BJTtBEleakCur; /* temperature adjusted B-E leakage current */ @@ -371,6 +373,8 @@ typedef struct sBJTmodel { /* model structure for a bjt */ double BJTtnom; /* nominal temperature */ double BJTsatCur; /* input - don't use */ + double BJTBEsatCur; + double BJTBCsatCur; double BJTbetaF; /* input - don't use */ double BJTemissionCoeffF; double BJTearlyVoltF; @@ -505,6 +509,8 @@ typedef struct sBJTmodel { /* model structure for a bjt */ unsigned BJTsubsGiven : 1; unsigned BJTtnomGiven : 1; unsigned BJTsatCurGiven : 1; + unsigned BJTBEsatCurGiven : 1; + unsigned BJTBCsatCurGiven : 1; unsigned BJTbetaFGiven : 1; unsigned BJTemissionCoeffFGiven : 1; unsigned BJTearlyVoltFGiven : 1; @@ -659,6 +665,8 @@ enum { BJT_MOD_NPN = 101, BJT_MOD_PNP, BJT_MOD_IS, + BJT_MOD_IBE, + BJT_MOD_IBC, BJT_MOD_BF, BJT_MOD_NF, BJT_MOD_VAF, diff --git a/src/spicelib/devices/bjt/bjtdset.c b/src/spicelib/devices/bjt/bjtdset.c index 69c6aa429..7ad0cc129 100644 --- a/src/spicelib/devices/bjt/bjtdset.c +++ b/src/spicelib/devices/bjt/bjtdset.c @@ -35,7 +35,7 @@ int BJTdSetup(GENmodel *inModel, CKTcircuit *ckt) double cbe; double cben; double cdis; - double csat; + double csatbe, csatbc; double ctot; double czbc; double czbcf2; @@ -153,7 +153,8 @@ int BJTdSetup(GENmodel *inModel, CKTcircuit *ckt) /* * dc model paramters */ - csat=here->BJTtSatCur*here->BJTarea * here->BJTm; + csatbe=here->BJTBEtSatCur*here->BJTarea * here->BJTm; + csatbc=here->BJTBCtSatCur*here->BJTarea * here->BJTm; rbpr=here->BJTtminBaseResist/(here->BJTarea * here->BJTm); rbpi=here->BJTtbaseResist/(here->BJTarea * here->BJTm)-rbpr; oik=here->BJTtinvRollOffF/(here->BJTarea * here->BJTm); @@ -228,9 +229,9 @@ int BJTdSetup(GENmodel *inModel, CKTcircuit *ckt) vtn=vt*here->BJTtemissionCoeffF; if(vbe > -5*vtn){ evbe=exp(vbe/vtn); - cbe=csat*(evbe-1)+ckt->CKTgmin*vbe; - gbe=csat*evbe/vtn+ckt->CKTgmin; - gbe2 = csat*evbe/vtn/vtn; + cbe=csatbe*(evbe-1)+ckt->CKTgmin*vbe; + gbe=csatbe*evbe/vtn+ckt->CKTgmin; + gbe2 = csatbe*evbe/vtn/vtn; gbe3 = gbe2/vtn; /* note - these are actually derivs, not Taylor @@ -247,7 +248,7 @@ int BJTdSetup(GENmodel *inModel, CKTcircuit *ckt) gben3=gben2/vte; } } else { - gbe = -csat/vbe+ckt->CKTgmin; + gbe = -csatbe/vbe+ckt->CKTgmin; gbe2=gbe3=gben2=gben3=0; cbe=gbe*vbe; gben = -c2/vbe; @@ -256,9 +257,9 @@ int BJTdSetup(GENmodel *inModel, CKTcircuit *ckt) vtn=vt*here->BJTtemissionCoeffR; if(vbc > -5*vtn) { evbc=exp(vbc/vtn); - cbc=csat*(evbc-1)+ckt->CKTgmin*vbc; - gbc=csat*evbc/vtn+ckt->CKTgmin; - gbc2=csat*evbc/vtn/vtn; + cbc=csatbc*(evbc-1)+ckt->CKTgmin*vbc; + gbc=csatbc*evbc/vtn+ckt->CKTgmin; + gbc2=csatbc*evbc/vtn/vtn; gbc3=gbc2/vtn; if (c4 == 0) { cbcn=0; @@ -272,7 +273,7 @@ int BJTdSetup(GENmodel *inModel, CKTcircuit *ckt) gbcn3=gbcn2/vtc; } } else { - gbc = -csat/vbc+ckt->CKTgmin; + gbc = -csatbc/vbc+ckt->CKTgmin; gbc2=gbc3=0; cbc = gbc*vbc; gbcn = -c4/vbc; diff --git a/src/spicelib/devices/bjt/bjtload.c b/src/spicelib/devices/bjt/bjtload.c index ca14ff620..9e94bd389 100644 --- a/src/spicelib/devices/bjt/bjtload.c +++ b/src/spicelib/devices/bjt/bjtload.c @@ -53,7 +53,7 @@ BJTload(GENmodel *inModel, CKTcircuit *ckt) double geqsub; double ceqsub; double cex; - double csat; + double csatbe, csatbc; double csubsat; double ctot; double czbc; @@ -172,7 +172,8 @@ BJTload(GENmodel *inModel, CKTcircuit *ckt) /* * dc model paramters */ - csat=here->BJTtSatCur*here->BJTarea; + csatbe=here->BJTBEtSatCur*here->BJTarea; + csatbc=here->BJTBCtSatCur*here->BJTarea; csubsat=here->BJTtSubSatCur*here->BJTarea; rbpr=here->BJTtminBaseResist/here->BJTarea; rbpi=here->BJTtbaseResist/here->BJTarea-rbpr; @@ -451,13 +452,13 @@ next1: vtn=vt*here->BJTtemissionCoeffF; if(vbe >= -3*vtn){ evbe=exp(vbe/vtn); - cbe=csat*(evbe-1); - gbe=csat*evbe/vtn; + cbe=csatbe*(evbe-1); + gbe=csatbe*evbe/vtn; } else { arg=3*vtn/(vbe*CONSTe); arg = arg * arg * arg; - cbe = -csat*(1+arg); - gbe = csat*3*arg/vbe; + cbe = -csatbe*(1+arg); + gbe = csatbe*3*arg/vbe; } if (c2 == 0) { cben=0; @@ -481,13 +482,13 @@ next1: vtn=vt*here->BJTtemissionCoeffF; if(vbc >= -3*vtn) { evbc=exp(vbc/vtn); - cbc=csat*(evbc-1); - gbc=csat*evbc/vtn; + cbc=csatbc*(evbc-1); + gbc=csatbc*evbc/vtn; } else { arg=3*vtn/(vbc*CONSTe); arg = arg * arg * arg; - cbc = -csat*(1+arg); - gbc = csat*3*arg/vbc; + cbc = -csatbc*(1+arg); + gbc = csatbc*3*arg/vbc; } if (c4 == 0) { cbcn=0; diff --git a/src/spicelib/devices/bjt/bjtmask.c b/src/spicelib/devices/bjt/bjtmask.c index 72fc7a029..cf7670642 100644 --- a/src/spicelib/devices/bjt/bjtmask.c +++ b/src/spicelib/devices/bjt/bjtmask.c @@ -42,6 +42,12 @@ BJTmAsk(CKTcircuit *ckt, GENmodel *instPtr, int which, IFvalue *value) case BJT_MOD_IS: value->rValue = here->BJTsatCur; return(OK); + case BJT_MOD_IBE: + value->rValue = here->BJTBEsatCur; + return(OK); + case BJT_MOD_IBC: + value->rValue = here->BJTBCsatCur; + return(OK); case BJT_MOD_BF: value->rValue = here->BJTbetaF; return(OK); diff --git a/src/spicelib/devices/bjt/bjtmpar.c b/src/spicelib/devices/bjt/bjtmpar.c index 6a74a17b3..1d13155d0 100644 --- a/src/spicelib/devices/bjt/bjtmpar.c +++ b/src/spicelib/devices/bjt/bjtmpar.c @@ -46,6 +46,14 @@ BJTmParam(int param, IFvalue *value, GENmodel *inModel) mods->BJTsatCur = value->rValue; mods->BJTsatCurGiven = TRUE; break; + case BJT_MOD_IBE: + mods->BJTBEsatCur = value->rValue; + mods->BJTBEsatCurGiven = TRUE; + break; + case BJT_MOD_IBC: + mods->BJTBCsatCur = value->rValue; + mods->BJTBCsatCurGiven = TRUE; + break; case BJT_MOD_BF: mods->BJTbetaF = value->rValue; mods->BJTbetaFGiven = TRUE; diff --git a/src/spicelib/devices/bjt/bjtsetup.c b/src/spicelib/devices/bjt/bjtsetup.c index cf09d6f1b..2aa38b9c6 100644 --- a/src/spicelib/devices/bjt/bjtsetup.c +++ b/src/spicelib/devices/bjt/bjtsetup.c @@ -47,6 +47,12 @@ BJTsetup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt, int *states) if(!model->BJTsatCurGiven) { model->BJTsatCur = 1e-16; } + if(!model->BJTBEsatCurGiven) { + model->BJTBEsatCur = model->BJTsatCur; + } + if(!model->BJTBCsatCurGiven) { + model->BJTBCsatCur = model->BJTsatCur; + } if(!model->BJTbetaFGiven) { model->BJTbetaF = 100; } @@ -396,19 +402,6 @@ BJTsetup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt, int *states) model->BJTteMax = 1e99; } - -/* - * COMPATABILITY WARNING! - * special note: for backward compatability to much older models, spice 2G - * implemented a special case which checked if B-E leakage saturation - * current was >1, then it was instead a the B-E leakage saturation current - * divided by IS, and multiplied it by IS at this point. This was not - * handled correctly in the 2G code, and there is some question on its - * reasonability, since it is also undocumented, so it has been left out - * here. It could easily be added with 1 line. (The same applies to the B-C - * leakage saturation current). TQ 6/29/84 - */ - /* loop through all the instances of the model */ for (here = BJTinstances(model); here != NULL ; here=BJTnextInstance(here)) { diff --git a/src/spicelib/devices/bjt/bjttemp.c b/src/spicelib/devices/bjt/bjttemp.c index a290a171a..58e7461c1 100644 --- a/src/spicelib/devices/bjt/bjttemp.c +++ b/src/spicelib/devices/bjt/bjttemp.c @@ -146,6 +146,14 @@ BJTtemp(GENmodel *inModel, CKTcircuit *ckt) if ((model->BJTtlev == 0) || (model->BJTtlev == 1)) { factor = exp(factlog); here->BJTtSatCur = model->BJTsatCur * factor; + if (model->BJTBEsatCurGiven) { + factor = exp(factlog / model->BJTemissionCoeffF); + here->BJTBEtSatCur = model->BJTBEsatCur * factor; + } + if (model->BJTBCsatCurGiven) { + factor = exp(factlog / model->BJTemissionCoeffR); + here->BJTBCtSatCur = model->BJTBCsatCur * factor; + } if (model->BJTsubSatCurGiven) here->BJTtSubSatCur = model->BJTsubSatCur * factor; } else if (model->BJTtlev == 3) {