You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
339 lines
13 KiB
339 lines
13 KiB
/**********
|
|
Copyright 1990 Regents of the University of California. All rights reserved.
|
|
Author: 1987 Thomas L. Quarles
|
|
**********/
|
|
|
|
#include "ngspice.h"
|
|
#include "ifsim.h"
|
|
#include "urcdefs.h"
|
|
#include "cktdefs.h"
|
|
#include "gendefs.h"
|
|
#include "sperror.h"
|
|
#include "suffix.h"
|
|
|
|
/* ARGSUSED */
|
|
int
|
|
URCsetup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt, int *state)
|
|
/* create the resistors/capacitors used to model the URC
|
|
*/
|
|
{
|
|
URCmodel *model = (URCmodel *)inModel;
|
|
URCinstance *here;
|
|
int rtype;
|
|
int ctype;
|
|
int dtype;
|
|
CKTnode * lowl;
|
|
CKTnode * lowr;
|
|
CKTnode * hil;
|
|
CKTnode * hir;
|
|
char *nameelt;
|
|
char *namehi;
|
|
CKTnode *nodehi;
|
|
CKTnode *nodelo;
|
|
char *namelo;
|
|
double r;
|
|
double c;
|
|
IFvalue ptemp;
|
|
double p;
|
|
double r0;
|
|
double c0;
|
|
double i0;
|
|
double r1;
|
|
double c1;
|
|
double i1;
|
|
double rd;
|
|
double wnorm;
|
|
double prop;
|
|
int i;
|
|
GENinstance *fast;
|
|
GENmodel *modfast; /* capacitor or diode model */
|
|
GENmodel *rmodfast; /* resistor model */
|
|
int error;
|
|
IFuid dioUid;
|
|
IFuid resUid;
|
|
IFuid capUid;
|
|
IFuid eltUid;
|
|
|
|
rtype = CKTtypelook("Resistor");
|
|
ctype = CKTtypelook("Capacitor");
|
|
dtype = CKTtypelook("Diode");
|
|
/* loop through all the URC models */
|
|
for( ; model != NULL; model = model->URCnextModel ) {
|
|
if(!model->URCkGiven)
|
|
model->URCk = 1.5;
|
|
if(!model->URCfmaxGiven)
|
|
model->URCfmax = 1e9;
|
|
if(!model->URCrPerLGiven)
|
|
model->URCrPerL = 1000;
|
|
if(!model->URCcPerLGiven)
|
|
model->URCcPerL = 1e-12;
|
|
|
|
/* may need to put in limits: k>=1.1, freq <=1e9, rperl >=.1 */
|
|
|
|
/* loop through all the instances of the model */
|
|
for (here = model->URCinstances; here != NULL ;
|
|
here=here->URCnextInstance)
|
|
{
|
|
p = model->URCk;
|
|
r0 = here->URClength * model->URCrPerL;
|
|
c0 = here->URClength * model->URCcPerL;
|
|
i0 = here->URClength * model->URCisPerL;
|
|
if(!here->URClumpsGiven) {
|
|
wnorm = model->URCfmax * r0 * c0 * 2.0 * M_PI;
|
|
here->URClumps=MAX(3.0,log(wnorm*(((p-1)/p)*((p-1)/p)))/log(p));
|
|
if(wnorm <35) here->URClumps=3;
|
|
/* may want to limit lumps to <= 100 or something like that */
|
|
}
|
|
r1 = (r0*(p-1))/((2*(pow(p,(double)here->URClumps)))-2);
|
|
c1 = (c0 * (p-1))/((pow(p,(double)(here->URClumps-1)))*(p+1)-2);
|
|
i1 = (i0 * (p-1))/((pow(p,(double)(here->URClumps-1)))*(p+1)-2);
|
|
rd = here->URClength * here->URClumps * model->URCrsPerL;
|
|
/* may want to check that c1 > 0 */
|
|
prop=1;
|
|
|
|
if(model->URCisPerLGiven) {
|
|
error = (*(SPfrontEnd->IFnewUid))(ckt,&dioUid,here->URCname,
|
|
"diodemod",UID_MODEL,(void **)NULL);
|
|
if(error) return(error);
|
|
modfast = (GENmodel *)NULL;
|
|
error = CKTmodCrt((void *)ckt,dtype,(void **)&modfast,
|
|
dioUid);
|
|
if(error) return(error);
|
|
ptemp.rValue = c1;
|
|
error= CKTpModName("cjo",&ptemp,ckt,dtype,dioUid,&modfast);
|
|
if(error) return(error);
|
|
ptemp.rValue = rd;
|
|
error = CKTpModName("rs",&ptemp,ckt,dtype,dioUid,&modfast);
|
|
if(error) return(error);
|
|
ptemp.rValue = i1;
|
|
error = CKTpModName("is",&ptemp,ckt,dtype,dioUid,&modfast);
|
|
if(error) return(error);
|
|
} else {
|
|
error = (*(SPfrontEnd->IFnewUid))((void *)ckt,&capUid,
|
|
here->URCname, "capmod",UID_MODEL,(void **)NULL);
|
|
if(error) return(error);
|
|
modfast = (GENmodel *)NULL;
|
|
error = CKTmodCrt((void *)ckt,ctype,(void **)&modfast,
|
|
capUid);
|
|
if(error) return(error);
|
|
}
|
|
|
|
error = (*(SPfrontEnd->IFnewUid))(ckt,&resUid,here->URCname,
|
|
"resmod",UID_MODEL,(void **)NULL);
|
|
if(error) return(error);
|
|
rmodfast = (GENmodel *)NULL;
|
|
error = CKTmodCrt((void *)ckt,rtype,(void **)&rmodfast,resUid);
|
|
if(error) return(error);
|
|
lowl = CKTnum2nod(ckt,here->URCposNode);
|
|
hir = CKTnum2nod(ckt,here->URCnegNode);
|
|
for(i=1;i<=here->URClumps;i++) {
|
|
namehi = (char *)MALLOC(10*sizeof(char));
|
|
(void)sprintf(namehi,"hi%d",i);
|
|
error = CKTmkVolt(ckt,(CKTnode**)&nodehi,here->URCname,namehi);
|
|
if(error) return(error);
|
|
hil = nodehi;
|
|
if(i==here->URClumps) {
|
|
lowr = hil;
|
|
} else {
|
|
namelo = (char *)MALLOC(10*sizeof(char));
|
|
(void)sprintf(namelo,"lo%d",i);
|
|
error = CKTmkVolt(ckt,(CKTnode**)&nodelo,here->URCname,
|
|
namelo);
|
|
if(error) return(error);
|
|
lowr = nodelo;
|
|
}
|
|
r = prop*r1;
|
|
c = prop*c1;
|
|
|
|
nameelt = (char *)MALLOC(10*sizeof(char));
|
|
(void)sprintf(nameelt,"rlo%d",i);
|
|
error = (*(SPfrontEnd->IFnewUid))(ckt,&eltUid,here->URCname,
|
|
nameelt,UID_INSTANCE, (void **)NULL);
|
|
if(error) return(error);
|
|
error = CKTcrtElt((void *)ckt,(void *)rmodfast,
|
|
(void **)&fast,eltUid);
|
|
if(error) return(error);
|
|
error = CKTbindNode((void *)ckt,(void *)fast,1,lowl);
|
|
if(error) return(error);
|
|
error = CKTbindNode((void *)ckt,(void *)fast,2,lowr);
|
|
if(error) return(error);
|
|
ptemp.rValue = r;
|
|
error = CKTpName("resistance",&ptemp,ckt,rtype,nameelt,&fast);
|
|
if(error) return(error);
|
|
fast->GENowner = here->URCowner;
|
|
|
|
nameelt = (char *)MALLOC(10*sizeof(char));
|
|
(void)sprintf(nameelt,"rhi%d",i);
|
|
error = (*(SPfrontEnd->IFnewUid))(ckt,&eltUid,here->URCname,
|
|
nameelt,UID_INSTANCE, (void **)NULL);
|
|
if(error) return(error);
|
|
error = CKTcrtElt((void *)ckt,(void *)rmodfast,
|
|
(void **)&fast,eltUid);
|
|
if(error) return(error);
|
|
error = CKTbindNode((void *)ckt,(void *)fast,1,hil);
|
|
if(error) return(error);
|
|
error = CKTbindNode((void *)ckt,(void *)fast,2,hir);
|
|
if(error) return(error);
|
|
ptemp.rValue = r;
|
|
error = CKTpName("resistance",&ptemp,ckt,rtype,nameelt,&fast);
|
|
if(error) return(error);
|
|
fast->GENowner = here->URCowner;
|
|
|
|
if(model->URCisPerLGiven) {
|
|
/* use diode */
|
|
nameelt = (char *)MALLOC(10*sizeof(char));
|
|
(void)sprintf(nameelt,"dlo%d",i);
|
|
error = (*(SPfrontEnd->IFnewUid))(ckt,&eltUid,
|
|
here->URCname,nameelt,UID_INSTANCE,
|
|
(void **)NULL);
|
|
if(error) return(error);
|
|
error = CKTcrtElt((void *)ckt,(void *)modfast,
|
|
(void **)&fast, eltUid);
|
|
if(error) return(error);
|
|
error = CKTbindNode((void *)ckt,(void *)fast,1,lowr);
|
|
if(error) return(error);
|
|
error = CKTbindNode((void *)ckt,(void *)fast,2,
|
|
(void *)CKTnum2nod(ckt, here->URCgndNode));
|
|
if(error) return(error);
|
|
ptemp.rValue = prop;
|
|
error = CKTpName("area",&ptemp,ckt,dtype,nameelt,&fast);
|
|
if(error) return(error);
|
|
fast->GENowner = here->URCowner;
|
|
} else {
|
|
/* use simple capacitor */
|
|
nameelt = (char *)MALLOC(10*sizeof(char));
|
|
(void)sprintf(nameelt,"clo%d",i);
|
|
error = (*(SPfrontEnd->IFnewUid))(ckt,&eltUid,here->URCname
|
|
,nameelt,UID_INSTANCE, (void **)NULL);
|
|
if(error) return(error);
|
|
error = CKTcrtElt((void *)ckt,(void *)modfast,
|
|
(void **)&fast, eltUid);
|
|
if(error) return(error);
|
|
error = CKTbindNode((void *)ckt,(void *)fast,1,lowr);
|
|
if(error) return(error);
|
|
error = CKTbindNode((void *)ckt,(void *)fast,2,
|
|
(void *)CKTnum2nod(ckt, here->URCgndNode));
|
|
if(error) return(error);
|
|
ptemp.rValue = c;
|
|
error = CKTpName("capacitance",&ptemp,ckt,ctype,nameelt,
|
|
&fast);
|
|
if(error) return(error);
|
|
fast->GENowner = here->URCowner;
|
|
}
|
|
|
|
if(i!=here->URClumps){
|
|
if(model->URCisPerLGiven) {
|
|
/* use diode */
|
|
nameelt = (char *)MALLOC(10*sizeof(char));
|
|
(void)sprintf(nameelt,"dhi%d",i);
|
|
error = (*(SPfrontEnd->IFnewUid))(ckt,&eltUid,
|
|
here->URCname,nameelt,UID_INSTANCE,
|
|
(void **)NULL);
|
|
if(error) return(error);
|
|
error = CKTcrtElt((void *)ckt,(void *)modfast,
|
|
(void **) &fast,eltUid);
|
|
if(error) return(error);
|
|
error = CKTbindNode((void *)ckt,(void *)fast,1,hil);
|
|
if(error) return(error);
|
|
error = CKTbindNode((void *)ckt,(void *)fast,2,
|
|
(void *)CKTnum2nod(ckt, here->URCgndNode));
|
|
if(error) return(error);
|
|
ptemp.rValue = prop;
|
|
error=CKTpName("area",&ptemp,ckt,dtype,nameelt,&fast);
|
|
if(error) return(error);
|
|
fast->GENowner = here->URCowner;
|
|
} else {
|
|
/* use simple capacitor */
|
|
nameelt = (char *)MALLOC(10*sizeof(char));
|
|
(void)sprintf(nameelt,"chi%d",i);
|
|
error = (*(SPfrontEnd->IFnewUid))(ckt,&eltUid,
|
|
here->URCname,nameelt,UID_INSTANCE,
|
|
(void **)NULL);
|
|
if(error) return(error);
|
|
error = CKTcrtElt((void *)ckt,(void *)modfast,
|
|
(void **)&fast,eltUid);
|
|
if(error) return(error);
|
|
error = CKTbindNode((void *)ckt,(void *)fast,1,hil);
|
|
if(error) return(error);
|
|
error = CKTbindNode((void *)ckt,(void *)fast,2,
|
|
(void *)CKTnum2nod(ckt, here->URCgndNode));
|
|
if(error) return(error);
|
|
ptemp.rValue = c;
|
|
error =CKTpName("capacitance",&ptemp,ckt,ctype,nameelt,
|
|
&fast);
|
|
if(error) return(error);
|
|
fast->GENowner = here->URCowner;
|
|
}
|
|
}
|
|
prop *= p;
|
|
lowl = lowr;
|
|
hir = hil;
|
|
}
|
|
}
|
|
}
|
|
return(OK);
|
|
}
|
|
|
|
int
|
|
URCunsetup(GENmodel *inModel, CKTcircuit *ckt)
|
|
{
|
|
IFuid varUid;
|
|
int error;
|
|
URCinstance *here;
|
|
URCmodel *model = (URCmodel *) inModel;
|
|
GENinstance *in;
|
|
GENmodel *modfast;
|
|
int type;
|
|
|
|
/* Delete models, devices, and intermediate nodes; */
|
|
|
|
for ( ; model; model = model->URCnextModel) {
|
|
for (here = model->URCinstances; here;
|
|
here = here->URCnextInstance)
|
|
{
|
|
if(model->URCisPerLGiven) {
|
|
/* Diodes */
|
|
error = (*(SPfrontEnd->IFnewUid))(ckt, &varUid,
|
|
here->URCname,
|
|
"diodemod",
|
|
UID_MODEL,
|
|
(void **)NULL);
|
|
} else {
|
|
/* Capacitors */
|
|
error = (*(SPfrontEnd->IFnewUid))((void *)ckt, &varUid,
|
|
here->URCname,
|
|
"capmod",
|
|
UID_MODEL,
|
|
(void **)NULL);
|
|
}
|
|
if (error && error != E_EXISTS)
|
|
return error;
|
|
|
|
modfast = NULL;
|
|
type = -1;
|
|
error = CKTfndMod(ckt, &type, (void **) &modfast, varUid);
|
|
if (error)
|
|
return error;
|
|
|
|
for (in = modfast->GENinstances; in; in = in->GENnextInstance)
|
|
CKTdltNNum(ckt, in->GENnode1);
|
|
|
|
CKTdltMod(ckt, modfast); /* Does the elements too */
|
|
|
|
/* Resistors */
|
|
error = (*(SPfrontEnd->IFnewUid))(ckt,&varUid,here->URCname,
|
|
"resmod",UID_MODEL,(void **)NULL);
|
|
if (error && error != E_EXISTS)
|
|
return error;
|
|
|
|
modfast = NULL;
|
|
type = -1;
|
|
error = CKTfndMod(ckt, &type, (void **) &modfast, varUid);
|
|
if (error)
|
|
return error;
|
|
|
|
CKTdltMod(ckt, modfast);
|
|
}
|
|
}
|
|
return OK;
|
|
}
|