Added new syntax to the the resistor card to support HSpice style temperature dependence (from Hitoshi Tanaka <HDA01055@nifty.com>)
This commit is contained in:
parent
d96ec87987
commit
1facfd764d
11
ChangeLog
11
ChangeLog
|
|
@ -1,3 +1,14 @@
|
|||
2005-05-09 Steven Borley <steven.borley@virgin.net>
|
||||
|
||||
* Added new syntax to the the resistor card to support HSpice style
|
||||
temperature dependence (from Hitoshi Tanaka <HDA01055@nifty.com>).
|
||||
Syntax forms now include:
|
||||
Rxxx <n1> n2> <val> TC=<val1>
|
||||
Rxxx <n1> n2> <val> TC1=<val1>
|
||||
Rxxx <n1> n2> <val> TC1=<val1> TC2=<val2>
|
||||
Rxxx <n1> n2> <val> TC=<val1> <val2>
|
||||
The the first pair are equivalent, and the last pair are equivalent.
|
||||
|
||||
2005-05-07 Steven Borley <steven.borley@virgin.net>
|
||||
|
||||
* Added support for the BSD licensed editline library
|
||||
|
|
|
|||
|
|
@ -754,6 +754,10 @@ fileInit_pass2(runDesc *run)
|
|||
type = SV_TIME;
|
||||
else if (cieq(name, "frequency"))
|
||||
type = SV_FREQUENCY;
|
||||
else if (cieq(name, "temp-sweep")) /* Added by H.T */
|
||||
type = SV_TEMP;
|
||||
else if (cieq(name, "res-sweep")) /* Added by H.T */
|
||||
type = SV_RES;
|
||||
else
|
||||
type = SV_VOLTAGE;
|
||||
|
||||
|
|
@ -899,6 +903,10 @@ plotInit(runDesc *run)
|
|||
v->v_type = SV_TIME;
|
||||
else if (cieq(v->v_name, "frequency"))
|
||||
v->v_type = SV_FREQUENCY;
|
||||
else if (cieq(v->v_name, "temp-sweep")) /* Added by H.T */
|
||||
v->v_type = SV_TEMP;
|
||||
else if (cieq(v->v_name, "res-sweep")) /* Added by H.T */
|
||||
v->v_type = SV_RES;
|
||||
else
|
||||
v->v_type = SV_VOLTAGE;
|
||||
v->v_length = 0;
|
||||
|
|
|
|||
|
|
@ -616,6 +616,10 @@ plotit(wordlist *wl, char *hcopy, char *devname)
|
|||
d->v_scale = d;
|
||||
}
|
||||
|
||||
/* The following line displays the unit at the time of
|
||||
temp-sweep and res-sweep. This may not be a so good solution. by H.T */
|
||||
if(!strcmp(vecs->v_scale->v_name,"temp-sweep")) vecs->v_scale->v_type=14;
|
||||
if(!strcmp(vecs->v_scale->v_name,"res-sweep")) vecs->v_scale->v_type=15;
|
||||
|
||||
/* See if the log flag is set anywhere... */
|
||||
if (!gfound) {
|
||||
|
|
|
|||
|
|
@ -45,6 +45,10 @@ struct type types[NUMTYPES] = {
|
|||
{ "pole", NULL } ,
|
||||
{ "zero", NULL } ,
|
||||
{ "s-param", NULL } ,
|
||||
{ "temp-sweep", "Celsius" } ,/* Added by HT */
|
||||
|
||||
{ "res-sweep", "Ohm" } ,/* Added by HT */
|
||||
|
||||
} ;
|
||||
|
||||
/* The stuff for plot names. */
|
||||
|
|
@ -73,8 +77,8 @@ struct plotab plotabs[NUMPLOTTYPES] = {
|
|||
{ "spect", "spect" },
|
||||
} ;
|
||||
|
||||
int notypes = 14;
|
||||
int noplotabs = 18;
|
||||
int notypes = 15;/* change 14 to 15 by H.T*/
|
||||
int noplotabs = 20;/* change 18 to 20 by H.T*/
|
||||
|
||||
/* A command to define types for vectors and plots. This will generally
|
||||
* be used in the Command: field of the rawfile.
|
||||
|
|
|
|||
|
|
@ -13,7 +13,9 @@ enum simulation_types {
|
|||
SV_INPUT_NOISE,
|
||||
SV_POLE,
|
||||
SV_ZERO,
|
||||
SV_SPARAM
|
||||
SV_SPARAM,
|
||||
SV_TEMP,
|
||||
SV_RES
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -19,6 +19,9 @@ IFparm RESpTable[] = { /* parameters */
|
|||
IOPQU( "l", RES_LENGTH, IF_REAL, "Length"),
|
||||
IOPZU( "w", RES_WIDTH, IF_REAL, "Width"),
|
||||
IOPU( "m", RES_M, IF_REAL, "Multiplication factor"),
|
||||
IOPU( "tc", RES_TC1, IF_REAL, "First order temp. coefficient"),
|
||||
IOPU( "tc1", RES_TC1, IF_REAL, "First order temp. coefficient"),
|
||||
IOPU( "tc2", RES_TC2, IF_REAL, "Second order temp. coefficient"),
|
||||
IOPU( "scale", RES_SCALE, IF_REAL, "Scale factor"),
|
||||
IOP( "noisy", RES_NOISY, IF_INTEGER, "Resistor generate noise"),
|
||||
IP( "sens_resist", RES_RESIST_SENS, IF_FLAG,
|
||||
|
|
|
|||
|
|
@ -64,6 +64,12 @@ RESask(CKTcircuit *ckt, GENinstance *inst, int which, IFvalue *value,
|
|||
case RES_M:
|
||||
value->rValue = fast->RESm;
|
||||
return(OK);
|
||||
case RES_TC1:
|
||||
value->rValue = fast->REStc1;
|
||||
return(OK);
|
||||
case RES_TC2:
|
||||
value->rValue = fast->REStc2;
|
||||
return(OK);
|
||||
case RES_NOISY:
|
||||
value->iValue = fast->RESnoisy;
|
||||
return(OK);
|
||||
|
|
|
|||
|
|
@ -41,6 +41,8 @@ typedef struct sRESinstance {
|
|||
double RESlength; /* length of the resistor */
|
||||
double RESscale; /* Scale factor */
|
||||
double RESm; /* Multiplicity factor for this instance */
|
||||
double REStc1; /* first temperature coefficient of resistors */
|
||||
double REStc2; /* second temperature coefficient of resistors */
|
||||
int RESnoisy; /* Set if the resistor generates noise */
|
||||
double *RESposPosptr; /* pointer to sparse matrix diagonal at
|
||||
* (positive,positive) */
|
||||
|
|
@ -59,6 +61,8 @@ typedef struct sRESinstance {
|
|||
/* serban */
|
||||
unsigned RESacresGiven : 1; /* indicates AC value specified */
|
||||
unsigned RESmGiven : 1; /* indicates M parameter specified */
|
||||
unsigned REStc1Given : 1; /* indicates tc1 parameter specified */
|
||||
unsigned REStc2Given : 1; /* indicates tc2 parameter specified */
|
||||
unsigned RESnoisyGiven : 1; /* indicates if noisy is specified */
|
||||
int RESsenParmNo; /* parameter # for sensitivity use;
|
||||
* set equal to 0 if not a design parameter*/
|
||||
|
|
@ -75,7 +79,7 @@ typedef struct sRESinstance {
|
|||
#ifndef NONOISE
|
||||
double RESnVar[NSTATVARS][RESNSRCS];
|
||||
#else /* NONOISE */
|
||||
double **RESnVar;
|
||||
double **RESnVar;
|
||||
#endif /* NONOISE */
|
||||
|
||||
} RESinstance ;
|
||||
|
|
@ -127,7 +131,9 @@ typedef struct sRESmodel { /* model structure for a resistor */
|
|||
#define RES_SCALE 13 /* pn */
|
||||
#define RES_DTEMP 14 /* pn */
|
||||
#define RES_NOISY 15 /* pn */
|
||||
|
||||
/* tanaka */
|
||||
#define RES_TC1 16
|
||||
#define RES_TC2 17
|
||||
|
||||
/* model parameters */
|
||||
#define RES_MOD_TC1 101
|
||||
|
|
|
|||
|
|
@ -17,7 +17,8 @@ RESload(GENmodel *inModel, CKTcircuit *ckt)
|
|||
{
|
||||
RESmodel *model = (RESmodel *)inModel;
|
||||
double m;
|
||||
|
||||
double difference;
|
||||
double factor;
|
||||
|
||||
|
||||
/* loop through all the resistor models */
|
||||
|
|
@ -26,19 +27,27 @@ RESload(GENmodel *inModel, CKTcircuit *ckt)
|
|||
|
||||
/* loop through all the instances of the model */
|
||||
for (here = model->RESinstances; here != NULL ;
|
||||
here = here->RESnextInstance) {
|
||||
|
||||
if (here->RESowner != ARCHme) continue;
|
||||
|
||||
here->REScurrent = (*(ckt->CKTrhsOld+here->RESposNode) -
|
||||
*(ckt->CKTrhsOld+here->RESnegNode)) * here->RESconduct;
|
||||
|
||||
m = here->RESm;
|
||||
here = here->RESnextInstance) {
|
||||
|
||||
*(here->RESposPosptr) += m * here->RESconduct;
|
||||
*(here->RESnegNegptr) += m * here->RESconduct;
|
||||
*(here->RESposNegptr) -= m * here->RESconduct;
|
||||
*(here->RESnegPosptr) -= m * here->RESconduct;
|
||||
if(!here->REStc1Given) here->REStc1 = 0.0;
|
||||
if(!here->REStc2Given) here->REStc2 = 0.0;
|
||||
if(!here->RESmGiven) here->RESm = 1.0;
|
||||
|
||||
if (here->RESowner != ARCHme) continue;
|
||||
|
||||
here->REScurrent = (*(ckt->CKTrhsOld+here->RESposNode) -
|
||||
*(ckt->CKTrhsOld+here->RESnegNode)) * here->RESconduct;
|
||||
|
||||
difference = (here->REStemp + here->RESdtemp) - 300.15;
|
||||
factor = 1.0 + (here->REStc1)*difference +
|
||||
(here->REStc2)*difference*difference;
|
||||
|
||||
m = (here->RESm)/factor;
|
||||
|
||||
*(here->RESposPosptr) += m * here->RESconduct;
|
||||
*(here->RESnegNegptr) += m * here->RESconduct;
|
||||
*(here->RESposNegptr) -= m * here->RESconduct;
|
||||
*(here->RESnegPosptr) -= m * here->RESconduct;
|
||||
}
|
||||
}
|
||||
return(OK);
|
||||
|
|
@ -52,6 +61,8 @@ RESacload(GENmodel *inModel, CKTcircuit *ckt)
|
|||
{
|
||||
RESmodel *model = (RESmodel *)inModel;
|
||||
double m;
|
||||
double difference;
|
||||
double factor;
|
||||
|
||||
/* loop through all the resistor models */
|
||||
for( ; model != NULL; model = model->RESnextModel ) {
|
||||
|
|
@ -60,10 +71,18 @@ RESacload(GENmodel *inModel, CKTcircuit *ckt)
|
|||
/* loop through all the instances of the model */
|
||||
for (here = model->RESinstances; here != NULL ;
|
||||
here = here->RESnextInstance) {
|
||||
|
||||
if(!here->REStc1Given) here->REStc1 = 0.0;
|
||||
if(!here->REStc2Given) here->REStc2 = 0.0;
|
||||
if(!here->RESmGiven) here->RESm = 1.0;
|
||||
|
||||
if (here->RESowner != ARCHme) continue;
|
||||
|
||||
m = here->RESm;
|
||||
difference = (here->REStemp + here->RESdtemp) - 300.15;
|
||||
factor = 1.0 + (here->REStc1)*difference +
|
||||
(here->REStc2)*difference*difference;
|
||||
|
||||
m = (here->RESm)/factor;
|
||||
|
||||
if(here->RESacresGiven) {
|
||||
*(here->RESposPosptr) += m * here->RESacConduct;
|
||||
|
|
|
|||
|
|
@ -26,10 +26,6 @@ RESparam(int param, IFvalue *value, GENinstance *inst, IFvalue *select)
|
|||
break;
|
||||
case RES_RESIST:
|
||||
here->RESresist = value->rValue;
|
||||
if (!here->RESmGiven)
|
||||
here->RESm = 1.0;
|
||||
if (!here->RESacresGiven)
|
||||
here->RESacResist = value->rValue;
|
||||
here->RESresGiven = TRUE;
|
||||
break;
|
||||
case RES_ACRESIST:
|
||||
|
|
@ -55,6 +51,14 @@ RESparam(int param, IFvalue *value, GENinstance *inst, IFvalue *select)
|
|||
here->RESm = value->rValue;
|
||||
here->RESmGiven = TRUE;
|
||||
break;
|
||||
case RES_TC1:
|
||||
here->REStc1 = value->rValue;
|
||||
here->REStc1Given = TRUE;
|
||||
break;
|
||||
case RES_TC2:
|
||||
here->REStc2 = value->rValue;
|
||||
here->REStc2Given = TRUE;
|
||||
break;
|
||||
case RES_NOISY:
|
||||
here->RESnoisy = value->iValue;
|
||||
here->RESnoisyGiven = TRUE;
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ Modified: 2000 AlanSfixes
|
|||
#include "cktdefs.h"
|
||||
#include "resdefs.h"
|
||||
#include "sperror.h"
|
||||
|
||||
extern int fbreak;
|
||||
|
||||
int
|
||||
REStemp(GENmodel *inModel, CKTcircuit *ckt)
|
||||
|
|
@ -28,7 +28,10 @@ REStemp(GENmodel *inModel, CKTcircuit *ckt)
|
|||
|
||||
/* loop through all the resistor models */
|
||||
for( ; model != NULL; model = model->RESnextModel ) {
|
||||
|
||||
#ifdef WIN32
|
||||
WaitForIdle();
|
||||
if(fbreak) break;
|
||||
#endif
|
||||
/* Default Value Processing for Resistor Models */
|
||||
if(!model->REStnomGiven) model->REStnom = ckt->CKTnomTemp;
|
||||
if(!model->RESsheetResGiven) model->RESsheetRes = 0.0;
|
||||
|
|
|
|||
|
|
@ -15,13 +15,16 @@ Remarks: This code is based on a version written by Serban Popescu which
|
|||
#include "fteext.h"
|
||||
#include "inp.h"
|
||||
|
||||
/* undefine to add tracing to this file */
|
||||
/*#define TRACE*/
|
||||
|
||||
void INP2R(void *ckt, INPtables * tab, card * current)
|
||||
{
|
||||
/* parse a resistor card */
|
||||
/* Rname <node> <node> [<val>][<mname>][w=<val>][l=<val>][ac=<val>] */
|
||||
|
||||
int mytype; /* the type we determine resistors are */
|
||||
int type = 0; /* the type the model says it is */
|
||||
int type = 0; /* the type the model says it is */
|
||||
char *line; /* the part of the current line left to parse */
|
||||
char *saveline; /* ... just in case we need to go back... */
|
||||
char *name; /* the resistor's name */
|
||||
|
|
@ -41,25 +44,120 @@ void INP2R(void *ckt, INPtables * tab, card * current)
|
|||
double leadval; /* actual value of unlabeled number */
|
||||
IFuid uid; /* uid for default model */
|
||||
|
||||
char *s,*t;/* Temporary buffer and pointer for translation */
|
||||
int i;
|
||||
|
||||
#ifdef TRACE
|
||||
printf("In INP2R()\n");
|
||||
printf(" Current line: %s\n",current->line);
|
||||
#endif
|
||||
|
||||
mytype = INPtypelook("Resistor");
|
||||
if (mytype < 0) {
|
||||
LITERR("Device type Resistor not supported by this binary\n");
|
||||
return;
|
||||
}
|
||||
line = current->line;
|
||||
INPgetTok(&line, &name, 1);
|
||||
INPgetTok(&line, &name, 1); /* Rname */
|
||||
INPinsert(&name, tab);
|
||||
INPgetNetTok(&line, &nname1, 1);
|
||||
INPgetNetTok(&line, &nname1, 1); /* <node> */
|
||||
INPtermInsert(ckt, &nname1, tab, &node1);
|
||||
INPgetNetTok(&line, &nname2, 1);
|
||||
INPgetNetTok(&line, &nname2, 1); /* <node> */
|
||||
INPtermInsert(ckt, &nname2, tab, &node2);
|
||||
val = INPevaluate(&line, &error1, 1);
|
||||
val = INPevaluate(&line, &error1, 1); /* [<val>] */
|
||||
/* either not a number -> model, or
|
||||
* follows a number, so must be a model name
|
||||
* -> MUST be a model name (or null)
|
||||
*/
|
||||
|
||||
|
||||
saveline = line; /* save then old pointer */
|
||||
|
||||
#ifdef TRACE
|
||||
printf("Begining tc=xxx yyyy search and translation in '%s'\n", line);
|
||||
#endif /* TRACE */
|
||||
|
||||
/* This routine translates "tc=xxx yyy" to "tc=xxx tc2=yyy".
|
||||
This is a re-write of the routine originally proposed by Hitoshi tanaka.
|
||||
In my version we simply look for the first occurence of 'tc' followed
|
||||
by '=' followed by two numbers. If we find it then we splice in "tc2=".
|
||||
sjb - 2005-05-09 */
|
||||
for(s=line; *s; s++) { /* scan the remainder of the line */
|
||||
|
||||
/* reject anything other than "tc" */
|
||||
if(*s!='t') continue;
|
||||
s++;
|
||||
if(*s!='c') continue;
|
||||
s++;
|
||||
|
||||
/* skip any white space */
|
||||
while(isspace(*s)) s++;
|
||||
|
||||
/* reject if not '=' */
|
||||
if(*s!='=') continue;
|
||||
s++;
|
||||
|
||||
/* skip any white space */
|
||||
while(isspace(*s)) s++;
|
||||
|
||||
/* if we now have +, - or a decimal digit then assume we have a number,
|
||||
otherwise reject */
|
||||
if((*s!='+') && (*s!='-') && !isdigit(*s)) continue;
|
||||
s++;
|
||||
|
||||
/* look for next white space or null */
|
||||
while(!isspace(*s) && *s) s++;
|
||||
|
||||
/* reject whole line if null (i.e not white space) */
|
||||
if(*s==0) break;
|
||||
s++;
|
||||
|
||||
/* remember this location in the line.
|
||||
Note that just before this location is a white space character. */
|
||||
t = s;
|
||||
|
||||
/* skip any additional white space */
|
||||
while(isspace(*s)) s++;
|
||||
|
||||
/* if we now have +, - or a decimal digit then assume we have the
|
||||
second number, otherwise reject */
|
||||
if((*s!='+') && (*s!='-') && !isdigit(*s)) continue;
|
||||
|
||||
/* if we get this far we have met all are criterea,
|
||||
so now we splice in a "tc2=" at the location remembered above. */
|
||||
|
||||
/* first alocate memory for the new longer line */
|
||||
i = strlen(current->line); /* length of existing line */
|
||||
line = tmalloc(i + 4 + 1); /* alocate enough for "tc2=" & terminating NULL */
|
||||
if(line == NULL) {
|
||||
/* failed to allocate memory so we recover rather crudely
|
||||
by rejecting the translation */
|
||||
line = saveline;
|
||||
break;
|
||||
}
|
||||
|
||||
/* copy first part of line */
|
||||
i -= strlen(t);
|
||||
strncpy(line,current->line,i);
|
||||
line[i]=0; /* terminate */
|
||||
|
||||
/* add "tc2=" */
|
||||
strcat(line, "tc2=");
|
||||
|
||||
/* add rest of line */
|
||||
strcat(line, t);
|
||||
|
||||
/* calculate our saveline position in the new line */
|
||||
saveline = line + (saveline - current->line);
|
||||
|
||||
/* replace old line with new */
|
||||
tfree(current->line);
|
||||
current->line = line;
|
||||
line = saveline;
|
||||
}
|
||||
|
||||
#ifdef TRACE
|
||||
printf("(Translated) Res line: %s\n",current->line);
|
||||
#endif
|
||||
|
||||
INPgetTok(&line, &model, 1);
|
||||
|
||||
|
|
@ -72,7 +170,7 @@ void INP2R(void *ckt, INPtables * tab, card * current)
|
|||
current->error = INPgetMod(ckt, model, &thismodel, tab);
|
||||
if (thismodel != NULL) {
|
||||
if (mytype != thismodel->INPmodType) {
|
||||
LITERR("incorrect model type");
|
||||
LITERR("incorrect model type for resistor");
|
||||
return;
|
||||
}
|
||||
mdfast = thismodel->INPmodfast;
|
||||
|
|
@ -116,5 +214,6 @@ void INP2R(void *ckt, INPtables * tab, card * current)
|
|||
ptemp.rValue = leadval;
|
||||
GCA(INPpName, ("resistance", &ptemp, ckt, type, fast));
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue