From 18478380ad9afb4c7371e9f745a03af991c8bdd9 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Fri, 27 Aug 2021 18:20:16 +0200 Subject: [PATCH] Revise the SOA and add new parameters: pd_max id_max idr_max te_max rth_ext derating rth_ext is currently not used --- src/spicelib/devices/vdmos/vdmos.c | 4 +- src/spicelib/devices/vdmos/vdmosdefs.h | 18 +++- src/spicelib/devices/vdmos/vdmosmask.c | 20 +++++ src/spicelib/devices/vdmos/vdmosmpar.c | 24 ++++++ src/spicelib/devices/vdmos/vdmosset.c | 18 ++++ src/spicelib/devices/vdmos/vdmossoachk.c | 105 +++++++++++++++++++++-- 6 files changed, 181 insertions(+), 8 deletions(-) diff --git a/src/spicelib/devices/vdmos/vdmos.c b/src/spicelib/devices/vdmos/vdmos.c index 3ef7834ee..3fc352631 100644 --- a/src/spicelib/devices/vdmos/vdmos.c +++ b/src/spicelib/devices/vdmos/vdmos.c @@ -140,8 +140,10 @@ IFparm VDMOSmPTable[] = { /* model parameters */ IOP("vgdr_max", VDMOS_MOD_VGDR_MAX, IF_REAL, "maximum voltage G-D branch"), IOP("pd_max", VDMOS_MOD_PD_MAX, IF_REAL, "maximum device power dissipation"), IOP("id_max", VDMOS_MOD_ID_MAX, IF_REAL, "maximum drain/source current"), - IOP("idr_max", VDMOS_MOD_IB_MAX, IF_REAL, "maximum drain/source reverse current"), + IOP("idr_max", VDMOS_MOD_IDR_MAX, IF_REAL, "maximum drain/source reverse current"), IOP("te_max", VDMOS_MOD_TE_MAX, IF_REAL, "maximum temperature"), + IOP("rth_ext", VDMOS_MOD_RTH_EXT, IF_REAL, "thermal resistance case to ambient, incl. heat sink"), + IOP("derating", VDMOS_MOD_DERATING, IF_REAL, "thermal derating for power"), }; char *VDMOSnames[] = { diff --git a/src/spicelib/devices/vdmos/vdmosdefs.h b/src/spicelib/devices/vdmos/vdmosdefs.h index 12762fb7e..a7450a98c 100644 --- a/src/spicelib/devices/vdmos/vdmosdefs.h +++ b/src/spicelib/devices/vdmos/vdmosdefs.h @@ -39,7 +39,7 @@ typedef struct sVDMOSinstance { #define VDMOSname gen.GENname #define VDMOSstates gen.GENstate - const int VDMOSdNode; /* number of the gate node of the mosfet */ + const int VDMOSdNode; /* number of the drain node of the mosfet */ const int VDMOSgNode; /* number of the gate node of the mosfet */ const int VDMOSsNode; /* number of the source node of the mosfet */ int VDMOStempNode; /* number of the temperature node of the mosfet */ @@ -361,6 +361,12 @@ typedef struct sVDMOSmodel { /* model structure for a resistor */ double VDMOSvdsMax; double VDMOSvgsrMax; double VDMOSvgdrMax; + double VDMOSid_max; + double VDMOSidr_max; + double VDMOSpd_max; + double VDMOSrth_ext; + double VDMOSte_max; + double VDMOSderating; unsigned VDMOStypeGiven :1; unsigned VDMOSdrainResistanceGiven :1; @@ -424,6 +430,12 @@ typedef struct sVDMOSmodel { /* model structure for a resistor */ unsigned VDMOSvdsMaxGiven :1; unsigned VDMOSvgsrMaxGiven :1; unsigned VDMOSvgdrMaxGiven :1; + unsigned VDMOSrth_extGiven :1; + unsigned VDMOSpd_maxGiven :1; + unsigned VDMOSte_maxGiven :1; + unsigned VDMOSid_maxGiven :1; + unsigned VDMOSidr_maxGiven :1; + unsigned VDMOSderatingGiven :1; } VDMOSmodel; #ifndef NMOS @@ -510,8 +522,10 @@ enum { VDMOS_MOD_VGDR_MAX, VDMOS_MOD_PD_MAX, VDMOS_MOD_ID_MAX, - VDMOS_MOD_IB_MAX, + VDMOS_MOD_IDR_MAX, VDMOS_MOD_TE_MAX, + VDMOS_MOD_RTH_EXT, + VDMOS_MOD_DERATING, }; /* device questions */ diff --git a/src/spicelib/devices/vdmos/vdmosmask.c b/src/spicelib/devices/vdmos/vdmosmask.c index 78ca21747..67fd12bf6 100644 --- a/src/spicelib/devices/vdmos/vdmosmask.c +++ b/src/spicelib/devices/vdmos/vdmosmask.c @@ -182,6 +182,7 @@ VDMOSmAsk(CKTcircuit *ckt, GENmodel *inst, int which, IFvalue *value) case VDMOS_MOD_TKSUBTHRES2: value->rValue = model->VDMOStksubthres2; return(OK); + /* SOA */ case VDMOS_MOD_VGS_MAX: value->rValue = model->VDMOSvgsMax; return(OK); @@ -197,6 +198,25 @@ VDMOSmAsk(CKTcircuit *ckt, GENmodel *inst, int which, IFvalue *value) case VDMOS_MOD_VGDR_MAX: value->rValue = model->VDMOSvgdrMax; return(OK); + case VDMOS_MOD_PD_MAX: + value->rValue = model->VDMOSpd_max; + return(OK); + case VDMOS_MOD_ID_MAX: + value->rValue = model->VDMOSid_max; + return(OK); + case VDMOS_MOD_IDR_MAX: + value->rValue = model->VDMOSidr_max; + return(OK); + case VDMOS_MOD_TE_MAX: + value->rValue = model->VDMOSte_max; + return(OK); + case VDMOS_MOD_RTH_EXT: + value->rValue = model->VDMOSrth_ext; + return(OK); + case VDMOS_MOD_DERATING: + value->rValue = model->VDMOSderating; + return(OK); + default: return(E_BADPARM); } diff --git a/src/spicelib/devices/vdmos/vdmosmpar.c b/src/spicelib/devices/vdmos/vdmosmpar.c index ccb3a4cf4..20ad96aa6 100644 --- a/src/spicelib/devices/vdmos/vdmosmpar.c +++ b/src/spicelib/devices/vdmos/vdmosmpar.c @@ -262,6 +262,30 @@ VDMOSmParam(int param, IFvalue *value, GENmodel *inModel) model->VDMOSvgdrMax = value->rValue; model->VDMOSvgdrMaxGiven = TRUE; break; + case VDMOS_MOD_PD_MAX: + model->VDMOSpd_max = value->rValue; + model->VDMOSpd_maxGiven = TRUE; + break; + case VDMOS_MOD_ID_MAX: + model->VDMOSid_max = value->rValue; + model->VDMOSid_maxGiven = TRUE; + break; + case VDMOS_MOD_IDR_MAX: + model->VDMOSidr_max = value->rValue; + model->VDMOSidr_maxGiven = TRUE; + break; + case VDMOS_MOD_TE_MAX: + model->VDMOSte_max = value->rValue; + model->VDMOSte_maxGiven = TRUE; + break; + case VDMOS_MOD_RTH_EXT: + model->VDMOSrth_ext = value->rValue; + model->VDMOSrth_extGiven = TRUE; + break; + case VDMOS_MOD_DERATING: + model->VDMOSderating = value->rValue; + model->VDMOSderatingGiven = TRUE; + break; default: return(E_BADPARM); } diff --git a/src/spicelib/devices/vdmos/vdmosset.c b/src/spicelib/devices/vdmos/vdmosset.c index 46e6f43d1..6d7661d11 100644 --- a/src/spicelib/devices/vdmos/vdmosset.c +++ b/src/spicelib/devices/vdmos/vdmosset.c @@ -190,6 +190,24 @@ VDMOSsetup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt, if (!model->VDMOSvgdrMaxGiven) model->VDMOSvgdrMax = 1e99; + if (!model->VDMOSpd_maxGiven) + model->VDMOSpd_max = 1e99; + + if (!model->VDMOSid_maxGiven) + model->VDMOSpd_max = 1e99; + + if (!model->VDMOSidr_maxGiven) + model->VDMOSidr_max = 1e99; + + if (!model->VDMOSte_maxGiven) + model->VDMOSte_max = 1e99; + + if (!model->VDMOSderatingGiven) + model->VDMOSderating = 0; + + if (!model->VDMOSrth_extGiven) + model->VDMOSrth_ext = model->VDMOSrthca; + if (!model->VDMOSqsResistanceGiven) model->VDMOSqsResistance = 0.0; diff --git a/src/spicelib/devices/vdmos/vdmossoachk.c b/src/spicelib/devices/vdmos/vdmossoachk.c index d47164965..e3a6008fb 100644 --- a/src/spicelib/devices/vdmos/vdmossoachk.c +++ b/src/spicelib/devices/vdmos/vdmossoachk.c @@ -19,12 +19,21 @@ VDMOSsoaCheck(CKTcircuit *ckt, GENmodel *inModel) VDMOSinstance *here; double vgs, vgd, vds; /* actual mos voltages */ int maxwarns; - static int warns_vgs = 0, warns_vgd = 0, warns_vds = 0; + static int warns_vgs = 0, warns_vgd = 0, warns_vds = 0, warns_id = 0, warns_idr = 0, warns_pd = 0, warns_te = 0; + double id; /* current VDMOS current */ + double idr; /* current reverse diode current */ + double pd; /* current VDMOS power dissipation */ + double pd_max; /* maximum VDMOS power */ + double te; /* current VDMOS temperature */ if (!ckt) { warns_vgs = 0; warns_vgd = 0; warns_vds = 0; + warns_id = 0; + warns_idr = 0; + warns_pd = 0; + warns_te = 0; return OK; } @@ -35,13 +44,13 @@ VDMOSsoaCheck(CKTcircuit *ckt, GENmodel *inModel) for (here = VDMOSinstances(model); here; here = VDMOSnextInstance(here)) { vgs = ckt->CKTrhsOld [here->VDMOSgNode] - - ckt->CKTrhsOld [here->VDMOSsNodePrime]; + ckt->CKTrhsOld [here->VDMOSsNode]; vgd = ckt->CKTrhsOld [here->VDMOSgNode] - - ckt->CKTrhsOld [here->VDMOSdNodePrime]; + ckt->CKTrhsOld [here->VDMOSdNode]; - vds = ckt->CKTrhsOld [here->VDMOSdNodePrime] - - ckt->CKTrhsOld [here->VDMOSsNodePrime]; + vds = ckt->CKTrhsOld [here->VDMOSdNode] - + ckt->CKTrhsOld [here->VDMOSsNode]; if (!model->VDMOSvgsrMaxGiven) { if (fabs(vgs) > model->VDMOSvgsMax) @@ -135,6 +144,92 @@ VDMOSsoaCheck(CKTcircuit *ckt, GENmodel *inModel) warns_vds++; } + /* max. drain current */ + id = fabs(here->VDMOScd); + if (model->VDMOSid_maxGiven && id > fabs(model->VDMOSid_max)) + if (warns_id < maxwarns) { + soa_printf(ckt, (GENinstance*)here, + "Id=%.4g A at Vd=%.4g V has exceeded Id_max=%.4g A\n", + id, vds, model->VDMOSid_max); + warns_id++; + } + + /* max. reverse current */ + idr = fabs(*(ckt->CKTstate0 + here->VDIOcurrent) * -1. + here->VDMOScd); + if (model->VDMOSidr_maxGiven && idr > fabs(model->VDMOSidr_max)) + if (warns_idr < maxwarns) { + soa_printf(ckt, (GENinstance*)here, + "Idr=%.4g A at Vd=%.4g V has exceeded Idr_max=%.4g A\n", + fabs(idr), vds, model->VDMOSidr_max); + warns_idr++; + } + + pd = fabs((id + idr) * vds); + pd += fabs(*(ckt->CKTstate0 + here->VDMOScqgd) * + (*(ckt->CKTrhsOld + here->VDMOSgNode) - + *(ckt->CKTrhsOld + here->VDMOSdNode))); + pd += fabs(*(ckt->CKTstate0 + here->VDMOScqgs) * + (*(ckt->CKTrhsOld + here->VDMOSgNode) - + *(ckt->CKTrhsOld + here->VDMOSsNode))); + + /* Calculate max power including derating: + up to tnom the derating is zero, + at maximum temp allowed the derating is 100%. + Device temperature by self-heating or given externally. */ + if (here->VDMOSthermal && model->VDMOSderatingGiven && model->VDMOSpd_maxGiven + && model->VDMOSte_maxGiven && model->VDMOStnomGiven) { + te = ckt->CKTrhsOld[here->VDMOStcaseNode]; + if (te < model->VDMOStnom - CONSTCtoK) + pd_max = model->VDMOSpd_max; + else { + pd_max = model->VDMOSpd_max - (te - model->VDMOStnom + CONSTCtoK) * model->VDMOSderating; + pd_max = (pd_max > 0) ? pd_max : 0.; + } + if (pd > pd_max) + if (warns_pd < maxwarns) { + soa_printf(ckt, (GENinstance*)here, + "Pd=%.4g W at Vd=%.4g V and Te=%.4g C has exceeded Pd_max=%.4g W\n", + pd, vds, te, pd_max); + warns_pd++; + } + if (te > model->VDMOSte_max) + if (warns_te < maxwarns) { + soa_printf(ckt, (GENinstance*)here, + "Te=%.4g C at Vd=%.4g V has exceeded te_max=%.4g C\n", + te, vds, model->VDMOSte_max); + warns_te++; + } + + } + /* Derating of max allowed power dissipation, without self-heating, + external temp given by .temp (global) or instance parameter 'temp', + therefore no temperature limits are calculated */ + else if (!here->VDMOSthermal && model->VDMOSderatingGiven && model->VDMOSpd_maxGiven && model->VDMOStnomGiven) { + if (here->VDMOStemp < model->VDMOStnom) + pd_max = model->VDMOSpd_max; + else { + pd_max = model->VDMOSpd_max - (here->VDMOStemp - model->VDMOStnom) * model->VDMOSderating; + pd_max = (pd_max > 0) ? pd_max : 0.; + } + if (pd > pd_max) + if (warns_pd < maxwarns) { + soa_printf(ckt, (GENinstance*)here, + "Pd=%.4g W at Vd=%.4g V and Te=%.4g C has exceeded Pd_max=%.4g W\n", + pd, vds, here->VDMOStemp - CONSTCtoK, pd_max); + warns_pd++; + } + } + /* No derating, max power is fixed by model parameter pd_max */ + else { + pd_max = model->VDMOSpd_max; + if (pd > pd_max) + if (warns_pd < maxwarns) { + soa_printf(ckt, (GENinstance*)here, + "Pd=%.4g W at Vd=%.4g V has exceeded Pd_max=%.4g W\n", + pd, vds, pd_max); + warns_pd++; + } + } } }