Added the temperature dependency in the recovery phase and let the target long term prediction time be specified by the input netlist

This commit is contained in:
Francesco Lannutti 2016-06-12 00:12:08 +02:00
parent a3534e2954
commit 76ff8c31f2
12 changed files with 156 additions and 107 deletions

View File

@ -283,6 +283,10 @@ struct CKTcircuit {
/* SP: 100609 */
#endif
#ifdef RELAN
double CKTtargetFitting ;
#endif
unsigned int CKTisLinear:1; /* flag to indicate that the circuit
contains only linear elements */
unsigned int CKTnoopac:1; /* flag to indicate that OP will not be evaluated

View File

@ -17,13 +17,15 @@ typedef struct {
double RELANstep ;
double RELANmaxStep ;
double RELANinitTime ;
double RELANtarget ;
long RELANmode ;
runDesc *RELANplot ;
} RELANan ;
#define RELAN_TSTART 1
#define RELAN_TSTOP 2
#define RELAN_TSTEP 3
#define RELAN_TMAX 4
#define RELAN_UIC 5
#define RELAN_TARGET 1
#define RELAN_TMAX 2
#define RELAN_TSTART 3
#define RELAN_TSTEP 4
#define RELAN_TSTOP 5
#define RELAN_UIC 6
#endif

View File

@ -17,17 +17,20 @@ RELANaskQuest (CKTcircuit *ckt, JOB *anal, int which, IFvalue *value)
switch (which)
{
case RELAN_TARGET:
value->rValue = job->RELANtarget ;
break ;
case RELAN_TMAX:
value->rValue = job->RELANmaxStep ;
break ;
case RELAN_TSTART:
value->rValue = job->RELANinitTime ;
break ;
case RELAN_TSTOP:
value->rValue = job->RELANfinalTime ;
break ;
case RELAN_TSTEP:
value->rValue = job->RELANstep ;
break ;
case RELAN_TMAX:
value->rValue = job->RELANmaxStep ;
case RELAN_TSTOP:
value->rValue = job->RELANfinalTime ;
break ;
case RELAN_UIC:
if (job->RELANmode & MODEUIC) {

View File

@ -12,10 +12,11 @@ RELANinit (CKTcircuit *ckt, JOB *anal)
{
RELANan *job = (RELANan *) anal ;
ckt->CKTinitTime = job->RELANinitTime ;
ckt->CKTfinalTime = job->RELANfinalTime ;
ckt->CKTstep = job->RELANstep ;
ckt->CKTmaxStep = job->RELANmaxStep ;
ckt->CKTinitTime = job->RELANinitTime ;
ckt->CKTfinalTime = job->RELANfinalTime ;
ckt->CKTstep = job->RELANstep ;
ckt->CKTmaxStep = job->RELANmaxStep ;
ckt->CKTtargetFitting = job->RELANtarget ;
if (ckt->CKTmaxStep == 0)
{

View File

@ -19,6 +19,12 @@ RELANsetParm (CKTcircuit *ckt, JOB *anal, int which, IFvalue *value)
switch (which)
{
case RELAN_TARGET:
job->RELANtarget = value->rValue ;
break ;
case RELAN_TMAX:
job->RELANmaxStep = value->rValue ;
break ;
case RELAN_TSTART:
if (value->rValue >= job->RELANfinalTime)
{
@ -28,15 +34,6 @@ RELANsetParm (CKTcircuit *ckt, JOB *anal, int which, IFvalue *value)
}
job->RELANinitTime = value->rValue ;
break ;
case RELAN_TSTOP:
if (value->rValue <= 0.0)
{
errMsg = copy ("TST0P is invalid, must be greater than zero.") ;
job->RELANfinalTime = 1.0 ;
return (E_PARMVAL) ;
}
job->RELANfinalTime = value->rValue ;
break ;
case RELAN_TSTEP:
if (value->rValue <= 0.0)
{
@ -46,8 +43,14 @@ RELANsetParm (CKTcircuit *ckt, JOB *anal, int which, IFvalue *value)
}
job->RELANstep = value->rValue ;
break ;
case RELAN_TMAX:
job->RELANmaxStep = value->rValue ;
case RELAN_TSTOP:
if (value->rValue <= 0.0)
{
errMsg = copy ("TST0P is invalid, must be greater than zero.") ;
job->RELANfinalTime = 1.0 ;
return (E_PARMVAL) ;
}
job->RELANfinalTime = value->rValue ;
break ;
case RELAN_UIC:
if (value->iValue)
@ -64,11 +67,12 @@ RELANsetParm (CKTcircuit *ckt, JOB *anal, int which, IFvalue *value)
static IFparm RELANparms [] = {
{ "relan_aging_start", RELAN_TSTART, IF_SET|IF_REAL, "starting time" },
{ "relan_aging_stop", RELAN_TSTOP, IF_SET|IF_REAL, "ending time" },
{ "relan_aging_step", RELAN_TSTEP, IF_SET|IF_REAL, "time step" },
{ "relan_aging_max", RELAN_TMAX, IF_SET|IF_REAL, "maximum time step" },
{ "uic", RELAN_UIC, IF_SET|IF_FLAG, "use initial conditions" },
{ "relan_aging_long_term_target", RELAN_TARGET, IF_SET|IF_REAL, "long term prediction target in seconds" },
{ "relan_aging_max", RELAN_TMAX, IF_SET|IF_REAL, "maximum time step" },
{ "relan_aging_start", RELAN_TSTART, IF_SET|IF_REAL, "starting time" },
{ "relan_aging_step", RELAN_TSTEP, IF_SET|IF_REAL, "time step" },
{ "relan_aging_stop", RELAN_TSTOP, IF_SET|IF_REAL, "ending time" },
{ "uic", RELAN_UIC, IF_SET|IF_FLAG, "use initial conditions" },
} ;
SPICEanalysis RELANinfo = {

View File

@ -39,8 +39,6 @@ endif
AM_CPPFLAGS = @AM_CPPFLAGS@ -I$(top_srcdir)/src/include
AM_CFLAGS = $(STATIC)
AM_LDFLAGS = -lgsl -lgslcblas
MAINTAINERCLEANFILES = Makefile.in
EXTRA_DIST = B4TERMS_OF_USE

View File

@ -7,9 +7,6 @@ Author: 2015 Francesco Lannutti - July 2015
#include "bsim4def.h"
#include "ngspice/sperror.h"
#include <gsl/gsl_fit.h>
#include <gsl/gsl_linalg.h>
static int
BSIM4reliability_internal (BSIM4instance *here, CKTcircuit *ckt, unsigned int mode)
{
@ -126,7 +123,7 @@ BSIM4reliability_internal (BSIM4instance *here, CKTcircuit *ckt, unsigned int mo
here->relStruct->IsON = 1 ;
// Calculate Aging - Giogio Liatis' Model
ret = RELMODELcalculateAging ((GENinstance *)here, here->BSIM4modPtr->BSIM4modType, delta, 1e-12, 0) ;
ret = RELMODELcalculateAging ((GENinstance *)here, here->BSIM4modPtr->BSIM4modType, ckt, delta, 1e-12, 0) ;
if (ret == 1)
{
return (E_INTERN) ;
@ -148,7 +145,7 @@ BSIM4reliability_internal (BSIM4instance *here, CKTcircuit *ckt, unsigned int mo
here->relStruct->IsON = 0 ;
// Calculate Aging - Giorgio Liatis' Model
ret = RELMODELcalculateAging ((GENinstance *)here, here->BSIM4modPtr->BSIM4modType, delta, 1e-12, 1) ;
ret = RELMODELcalculateAging ((GENinstance *)here, here->BSIM4modPtr->BSIM4modType, ckt, delta, 1e-12, 1) ;
if (ret == 1)
{
return (E_INTERN) ;
@ -176,7 +173,7 @@ BSIM4reliability_internal (BSIM4instance *here, CKTcircuit *ckt, unsigned int mo
here->relStruct->IsON = 1 ;
// Calculate Aging - Giorgio Liatis' Model
ret = RELMODELcalculateAging ((GENinstance *)here, here->BSIM4modPtr->BSIM4modType, delta, 1e-12, 1) ;
ret = RELMODELcalculateAging ((GENinstance *)here, here->BSIM4modPtr->BSIM4modType, ckt, delta, 1e-12, 1) ;
if (ret == 1)
{
return (E_INTERN) ;
@ -193,7 +190,7 @@ BSIM4reliability_internal (BSIM4instance *here, CKTcircuit *ckt, unsigned int mo
here->relStruct->IsON = 1 ;
// Calculate Aging - Giogio Liatis' Model
ret = RELMODELcalculateAging ((GENinstance *)here, here->BSIM4modPtr->BSIM4modType, delta, 1e-12, 0) ;
ret = RELMODELcalculateAging ((GENinstance *)here, here->BSIM4modPtr->BSIM4modType, ckt, delta, 1e-12, 0) ;
if (ret == 1)
{
return (E_INTERN) ;
@ -215,7 +212,7 @@ BSIM4reliability_internal (BSIM4instance *here, CKTcircuit *ckt, unsigned int mo
here->relStruct->IsON = 0 ;
// Calculate Aging - Giorgio Liatis' Model
ret = RELMODELcalculateAging ((GENinstance *)here, here->BSIM4modPtr->BSIM4modType, delta, 1e-12, 1) ;
ret = RELMODELcalculateAging ((GENinstance *)here, here->BSIM4modPtr->BSIM4modType, ckt, delta, 1e-12, 1) ;
if (ret == 1)
{
return (E_INTERN) ;
@ -232,7 +229,7 @@ BSIM4reliability_internal (BSIM4instance *here, CKTcircuit *ckt, unsigned int mo
here->relStruct->IsON = 0 ;
// Calculate Aging - Giogio Liatis' Model
ret = RELMODELcalculateAging ((GENinstance *)here, here->BSIM4modPtr->BSIM4modType, delta, 1e-12, 0) ;
ret = RELMODELcalculateAging ((GENinstance *)here, here->BSIM4modPtr->BSIM4modType, ckt, delta, 1e-12, 0) ;
if (ret == 1)
{
return (E_INTERN) ;
@ -272,9 +269,9 @@ BSIM4reliability_internal (BSIM4instance *here, CKTcircuit *ckt, unsigned int mo
{
/* The model behavior is periodic - Use Fourier basis fitting */
double *deltaVthFit, f, factor_for_2pi, *fitting_matrix, target, *timeFit ;
double *deltaVthFit, *timeFit ;
RELMODELrelList *current ;
unsigned int columns, i, j, number_of_modes, number_of_periods, rows, size ;
unsigned int i, number_of_periods ;
/* Count how many deltaVth we have */
i = 0 ;
@ -299,72 +296,17 @@ BSIM4reliability_internal (BSIM4instance *here, CKTcircuit *ckt, unsigned int mo
current = current->next ;
}
/* Generate the fitting matrix */
number_of_periods = here->relStruct->semiPeriods / 2 ;
number_of_modes = 10 * (number_of_periods + 1) ;
rows = i ;
columns = 2 * number_of_modes + 1 ;
size = rows * columns ;
fitting_matrix = TMALLOC (double, size) ;
factor_for_2pi = 2 * 3.14159265359 / (timeFit [rows - 1] - timeFit [0]) ;
for (i = 0 ; i < rows ; i++)
{
/* The first element of every row is equal to 1 */
fitting_matrix [columns * i] = 1 ;
/* The odd elements of every row are cos(x) */
for (j = 0 ; j < number_of_modes ; j++)
{
fitting_matrix [columns * i + 2 * j + 1] = cos ((j + 1) * timeFit [i] * factor_for_2pi) ;
}
/* The even elements of every row are sin(x) */
for (j = 1 ; j <= number_of_modes ; j++)
{
fitting_matrix [columns * i + 2 * j] = sin (j * timeFit [i] * factor_for_2pi) ;
}
}
gsl_matrix_view m = gsl_matrix_view_array (fitting_matrix, rows, columns) ;
gsl_vector_view b = gsl_vector_view_array (deltaVthFit, rows) ;
gsl_vector *tau = gsl_vector_alloc (MIN (rows, columns)) ;
gsl_vector *x = gsl_vector_alloc (columns) ;
gsl_vector *residual = gsl_vector_alloc (rows) ;
gsl_linalg_QR_decomp (&m.matrix, tau) ;
gsl_linalg_QR_lssolve (&m.matrix, tau, &b.vector, x, residual) ;
target = 315360000.0 ;
f = gsl_vector_get (x, 0) ;
/* The odd elements of every row are cos(x) */
for (j = 0 ; j < number_of_modes ; j++)
{
f += gsl_vector_get (x, 2 * j + 1) * cos ((j + 1) * target * factor_for_2pi) ;
}
/* The even elements of every row are sin(x) */
for (j = 1 ; j <= number_of_modes ; j++)
{
f += gsl_vector_get (x, 2 * j) * sin (j * target * factor_for_2pi) ;
}
printf ("\n\nExtrapolation at 10 years:\n\t\t\t\tDeltaVth: %-.9gmV\n\n\n\n", f * 1000) ;
/* Assign the extrapolated DeltaVth to the model */
here->relStruct->deltaVth = f ;
RELMODELcalculateFitting (i, number_of_periods, ckt->CKTtargetFitting, timeFit, deltaVthFit, &here->relStruct->deltaVth) ;
gsl_vector_free (tau) ;
gsl_vector_free (x) ;
gsl_vector_free (residual) ;
FREE (timeFit) ;
FREE (deltaVthFit) ;
} else {
if (here->relStruct->deltaVth > 0)
{
ret = RELMODELcalculateAging ((GENinstance *)here, here->BSIM4modPtr->BSIM4modType, 315360000.0, 0, 1) ;
ret = RELMODELcalculateAging ((GENinstance *)here, here->BSIM4modPtr->BSIM4modType, ckt, 315360000.0, 0, 1) ;
if (ret == 1)
{
return (E_INTERN) ;

View File

@ -6,6 +6,7 @@ if RELAN_WANTED
librelmodel_la_SOURCES = \
relmodel.c \
relmodelcalcaging.c \
relmodelcalcfitting.c \
relmodelmask.c \
relmodelmpar.c \
relmodeldefs.h \
@ -20,4 +21,6 @@ endif
AM_CPPFLAGS = @AM_CPPFLAGS@ -I$(top_srcdir)/src/include
AM_CFLAGS = $(STATIC)
AM_LDFLAGS = -lgsl -lgslcblas
MAINTAINERCLEANFILES = Makefile.in

View File

@ -47,9 +47,10 @@ listInsert (RELMODELrelList **list, double time, double deltaVth)
}
int
RELMODELcalculateAging (GENinstance *inInstance, int modType, double t_aging, double t_step, unsigned int stress_or_recovery)
RELMODELcalculateAging (GENinstance *inInstance, int modType, CKTcircuit *ckt, double t_aging, double t_step, unsigned int stress_or_recovery)
{
double A, i, Nt ;
double A, i, Nt, R ;
double b, qFI ;
BSIM4instance *here ;
RELMODELmodel *relmodel ;
@ -79,7 +80,7 @@ RELMODELcalculateAging (GENinstance *inInstance, int modType, double t_aging, do
{
here->relStruct->deltaVth = Nt * A * pow (log (1 + pow (((t_aging + here->relStruct->t_star) / relmodel->RELMODELtau_0), relmodel->RELMODELbeta)), 2) ;
} else {
here->relStruct->deltaVth = (CHARGE / (4 * CONSTepsZero * 1e-9 * relmodel->RELMODELeps_hk)) * Nt * pow (here->BSIM4modPtr->BSIM4toxe * 1e9, 2) ;
here->relStruct->deltaVth = (CHARGE / (4 * CONSTepsZero * 1e-9 * relmodel->RELMODELeps_hk)) * Nt * pow (here->BSIM4modPtr->BSIM4toxe * 1e9, 2) ;
}
} else {
for (i = 0 ; i < t_aging ; i += t_step)
@ -94,7 +95,15 @@ RELMODELcalculateAging (GENinstance *inInstance, int modType, double t_aging, do
}
here->relStruct->deltaVthMax = here->relStruct->deltaVth ;
} else {
here->relStruct->deltaVth = here->relStruct->deltaVthMax * log (1 + (1.718 / (1 + pow ((i / relmodel->RELMODELtau_e), relmodel->RELMODELbeta1)))) ;
/* Without Temperature Dependency */
// here->relStruct->deltaVth = here->relStruct->deltaVthMax * log (1 + (1.718 / (1 + pow ((i / relmodel->RELMODELtau_e), relmodel->RELMODELbeta1)))) ;
/* With Temperature Dependency */
// b = 5.621 * 1.2e6 ;
b = 0.706 ;
qFI = 1.03 ;
R = b * pow (ckt->CKTtemp, 2) * exp (-qFI / (relmodel->RELMODELk_b * ckt->CKTtemp)) ; // R = b * pow (T, 2) * exp (-qFI/kT) ;
here->relStruct->deltaVth = (1 - R) * here->relStruct->deltaVthMax * (1 - log (1 + (1.718 / (1 + pow ((i / relmodel->RELMODELtau_e), relmodel->RELMODELbeta1))))) ;
}
/* Insert 'here->relStruct->deltaVth' into the list for the later fitting */

View File

@ -0,0 +1,79 @@
/**********
Author: Francesco Lannutti - June 2016
**********/
#include "ngspice/ngspice.h"
#include "relmodeldefs.h"
#include "ngspice/sperror.h"
#include <gsl/gsl_fit.h>
#include <gsl/gsl_linalg.h>
int
RELMODELcalculateFitting (unsigned int rows, unsigned int number_of_periods, double target, double *timeFit, double *deltaVthFit, double *result)
{
double f, factor_for_2pi, *fitting_matrix ;
unsigned int columns, i, j, number_of_modes, size ;
/* Generate the fitting matrix */
number_of_modes = 10 * (number_of_periods + 1) ;
columns = 2 * number_of_modes + 1 ;
size = rows * columns ;
fitting_matrix = TMALLOC (double, size) ;
factor_for_2pi = 2 * M_PI / (timeFit [rows - 1] - timeFit [0]) ;
for (i = 0 ; i < rows ; i++)
{
/* The first element of every row is equal to 1 */
fitting_matrix [columns * i] = 1 ;
/* The odd elements of every row are cos(x) */
for (j = 0 ; j < number_of_modes ; j++)
{
fitting_matrix [columns * i + 2 * j + 1] = cos ((j + 1) * timeFit [i] * factor_for_2pi) ;
}
/* The even elements of every row are sin(x) */
for (j = 1 ; j <= number_of_modes ; j++)
{
fitting_matrix [columns * i + 2 * j] = sin (j * timeFit [i] * factor_for_2pi) ;
}
}
gsl_matrix_view m = gsl_matrix_view_array (fitting_matrix, rows, columns) ;
gsl_vector_view b = gsl_vector_view_array (deltaVthFit, rows) ;
gsl_vector *tau = gsl_vector_alloc (MIN (rows, columns)) ;
gsl_vector *x = gsl_vector_alloc (columns) ;
gsl_vector *residual = gsl_vector_alloc (rows) ;
gsl_linalg_QR_decomp (&m.matrix, tau) ;
gsl_linalg_QR_lssolve (&m.matrix, tau, &b.vector, x, residual) ;
f = gsl_vector_get (x, 0) ;
/* The odd elements of every row are cos(x) */
for (j = 0 ; j < number_of_modes ; j++)
{
f += gsl_vector_get (x, 2 * j + 1) * cos ((j + 1) * target * factor_for_2pi) ;
}
/* The even elements of every row are sin(x) */
for (j = 1 ; j <= number_of_modes ; j++)
{
f += gsl_vector_get (x, 2 * j) * sin (j * target * factor_for_2pi) ;
}
fprintf (stderr, "\n\nExtrapolation at %-.9g seconds:\n\t\t\t\tDeltaVth: %-.9gmV\n\n\n\n", target, f * 1000) ;
*result = f ;
gsl_vector_free (tau) ;
gsl_vector_free (x) ;
gsl_vector_free (residual) ;
FREE (fitting_matrix) ;
return (OK) ;
}

View File

@ -2,7 +2,8 @@
Author: Francesco Lannutti - July 2015
**********/
extern int RELMODELcalculateAging (GENinstance *, int, double, double, unsigned int) ;
extern int RELMODELcalculateAging (GENinstance *, int, CKTcircuit *, double, double, unsigned int) ;
extern int RELMODELcalculateFitting (unsigned int, unsigned int, double, double *, double *, double *) ;
extern int RELMODELmAsk (CKTcircuit *, GENmodel *, int, IFvalue *) ;
extern int RELMODELmDelete (GENmodel **, IFuid, GENmodel *) ;
extern int RELMODELmParam (int, IFvalue *, GENmodel *) ;

View File

@ -634,6 +634,9 @@ dot_relan (char *line, void *ckt, INPtables *tab, card *current, void *task, voi
}
IFC (newAnalysis, (ckt, which, "Reliability Analysis", &foo, task)) ;
parm = INPgetValue (ckt, &line, IF_REAL, tab) ;
GCA (INPapName, (ckt, which, foo, "relan_aging_long_term_target", parm)) ;
parm = INPgetValue (ckt, &line, IF_REAL, tab) ;
GCA (INPapName, (ckt, which, foo, "relan_aging_step", parm)) ;