From a52a87ddd8cf1d2bd9e8fdd7d8e119212f091a50 Mon Sep 17 00:00:00 2001 From: pnenzi Date: Tue, 9 Oct 2007 08:44:49 +0000 Subject: [PATCH] Added "r" option to vsrc, aliased some parameters on r and c, added safe floating point comparison (from Phil Barker) --- AUTHORS | 3 +- ChangeLog | 10 ++++++ src/spicelib/devices/cap/cap.c | 2 ++ src/spicelib/devices/res/res.c | 3 ++ src/spicelib/devices/res/resparam.c | 21 +++++++++++++ src/spicelib/devices/vsrc/vsrc.c | 3 +- src/spicelib/devices/vsrc/vsrcacct.c | 40 ++++++++++++++++------- src/spicelib/devices/vsrc/vsrcask.c | 3 ++ src/spicelib/devices/vsrc/vsrcdefs.h | 10 ++++-- src/spicelib/devices/vsrc/vsrcload.c | 47 ++++++++++++++++------------ src/spicelib/devices/vsrc/vsrcpar.c | 15 +++++++++ 11 files changed, 121 insertions(+), 36 deletions(-) diff --git a/AUTHORS b/AUTHORS index e14434e4f..9411cf768 100644 --- a/AUTHORS +++ b/AUTHORS @@ -11,7 +11,8 @@ The following people have contributed in some way: Vera Albrecht , Cecil Aswell , Giles C. Billingsley, -Steven Borley +Phil Barker , +Steven Borley , Stuart Brorson , Mansun Chan, Wayne A. Christopher, diff --git a/ChangeLog b/ChangeLog index a72de3b3e..8038bb658 100644 --- a/ChangeLog +++ b/ChangeLog @@ -9,6 +9,16 @@ * src/frontend/subckt.c: allow for .ic, .nodeset names to be embedded in a subckt;enhanced subckt.c to created appropriate node names for flattened simulation netlist (Phil Barker). + * src/spicelib/devices/cap/cap.c: aliased capacitance parameter with "c" + and "cap" (patch from Phil Barker). + * src/spicelib/devices/res/res.c: aliased some parameters. Originally got + the patch from Phil Barker but used IOPR (redundant) instead of IOPZ. + * src/spicelib/devices/res/resparam.c: Added fix for zero valued + resistors (Phil Barker). + * src/spicelib/devices/vsrc/{vsrc.c, vsrcacct.c, vsrcask.c, vsrcdefs.h, + vsrcload.c, vsrcpar.c, vsrctemp.c}: Added "repeat" parameter to the + PWL model. + 2007-10-08 Paolo Nenzi * src/main.c, src/frontend/{spiceif.c, spiceif.h, subckt.c}, diff --git a/src/spicelib/devices/cap/cap.c b/src/spicelib/devices/cap/cap.c index 53482a6bc..d667fa010 100644 --- a/src/spicelib/devices/cap/cap.c +++ b/src/spicelib/devices/cap/cap.c @@ -11,6 +11,8 @@ Modified: September 2003 - Paolo Nenzi IFparm CAPpTable[] = { /* parameters */ IOPAP("capacitance", CAP_CAP, IF_REAL, "Device capacitance"), + IOPAP("cap", CAP_CAP, IF_REAL, "Device capacitance"), + IOPAP("c", CAP_CAP, IF_REAL, "Device capacitance"), IOPAU("ic", CAP_IC, IF_REAL, "Initial capacitor voltage"), IOPZU("temp", CAP_TEMP, IF_REAL, "Instance operating temperature"), IOPZ( "dtemp", CAP_DTEMP, IF_REAL, diff --git a/src/spicelib/devices/res/res.c b/src/spicelib/devices/res/res.c index 8e635602e..e231dd5fb 100644 --- a/src/spicelib/devices/res/res.c +++ b/src/spicelib/devices/res/res.c @@ -41,10 +41,13 @@ IFparm RESpTable[] = { /* parameters */ IFparm RESmPTable[] = { /* model parameters */ IOPQ( "rsh", RES_MOD_RSH, IF_REAL,"Sheet resistance"), IOPZ( "narrow", RES_MOD_NARROW, IF_REAL,"Narrowing of resistor"), + IOPZ( "dw", RES_MOD_NARROW, IF_REAL,"Narrowing of resistor"), IOPZ( "short", RES_MOD_SHORT, IF_REAL,"Shortening of resistor"), + IOPZ( "dlr", RES_MOD_SHORT, IF_REAL,"Shortening of resistor"), IOPQ( "tc1", RES_MOD_TC1, IF_REAL,"First order temp. coefficient"), IOPQO( "tc2", RES_MOD_TC2, IF_REAL,"Second order temp. coefficient"), IOPX( "defw", RES_MOD_DEFWIDTH, IF_REAL,"Default device width"), + IOPX( "w", RES_MOD_DEFWIDTH, IF_REAL,"Default device width"), IOPQ( "kf", RES_MOD_KF, IF_REAL,"Flicker noise coefficient"), IOPQ( "af", RES_MOD_AF, IF_REAL,"Flicker noise exponent"), IOPXU( "tnom", RES_MOD_TNOM, IF_REAL,"Parameter measurement temperature"), diff --git a/src/spicelib/devices/res/resparam.c b/src/spicelib/devices/res/resparam.c index 1c19c6d17..059e7c308 100644 --- a/src/spicelib/devices/res/resparam.c +++ b/src/spicelib/devices/res/resparam.c @@ -4,12 +4,29 @@ Author: 1985 Thomas L. Quarles Modified: Apr 2000 - Paolo Nenzi **********/ +#include #include "ngspice.h" #include "const.h" #include "ifsim.h" #include "resdefs.h" #include "sperror.h" +// Initial AlmostEqualULPs version - fast and simple, but +// some limitations. +static bool AlmostEqualUlps(float A, float B, int maxUlps) +{ + assert(sizeof(float) == sizeof(int)); + + if (A == B) + return TRUE; + + int intDiff = abs(*(int*)&A - *(int*)&B); + + if (intDiff <= maxUlps) + return TRUE; + + return FALSE; +} int RESparam(int param, IFvalue *value, GENinstance *inst, IFvalue *select) @@ -25,6 +42,10 @@ RESparam(int param, IFvalue *value, GENinstance *inst, IFvalue *select) here->RESdtempGiven = TRUE; break; case RES_RESIST: + /* 0 valued resistor causes ngspice to hang -- can't solve for initial voltage */ + if ( AlmostEqualUlps( value->rValue, 0, 3 ) ) value->rValue = 0.001; /* 0.0001 should be sufficiently small */ + /* it's the value that smartspice uses */ + here->RESresist = value->rValue; here->RESresGiven = TRUE; break; diff --git a/src/spicelib/devices/vsrc/vsrc.c b/src/spicelib/devices/vsrc/vsrc.c index c73da4d67..e1ba52a62 100644 --- a/src/spicelib/devices/vsrc/vsrc.c +++ b/src/spicelib/devices/vsrc/vsrc.c @@ -31,7 +31,8 @@ IFparm VSRCpTable[] = { /* parameters */ OP ("i", VSRC_CURRENT, IF_REAL, "Voltage source current"), OP ("p", VSRC_POWER, IF_REAL, "Instantaneous power"), IP ("distof1", VSRC_D_F1, IF_REALVEC,"f1 input for distortion"), - IP ("distof2", VSRC_D_F2, IF_REALVEC,"f2 input for distortion") + IP ("distof2", VSRC_D_F2, IF_REALVEC,"f2 input for distortion"), + IP ("r", VSRC_R, IF_REAL, "pwl repeat value") }; char *VSRCnames[] = { diff --git a/src/spicelib/devices/vsrc/vsrcacct.c b/src/spicelib/devices/vsrc/vsrcacct.c index ac0edc5bb..89f7f3914 100644 --- a/src/spicelib/devices/vsrc/vsrcacct.c +++ b/src/spicelib/devices/vsrc/vsrcacct.c @@ -3,6 +3,7 @@ Copyright 1990 Regents of the University of California. All rights reserved. Author: 1985 Thomas L. Quarles **********/ +#include #include "ngspice.h" #include "cktdefs.h" #include "vsrcdefs.h" @@ -10,6 +11,27 @@ Author: 1985 Thomas L. Quarles #include "sperror.h" #include "suffix.h" +#define SAMETIME(a,b) (fabs((a)-(b))<= TIMETOL * PW) +#define TIMETOL 1e-7 + +// Initial AlmostEqualULPs version - fast and simple, but +// some limitations. +static bool AlmostEqualUlps(float A, float B, int maxUlps) +{ + assert(sizeof(float) == sizeof(int)); + + if (A == B) + return TRUE; + + int intDiff = abs(*(int*)&A - *(int*)&B); + + if (intDiff <= maxUlps) + return TRUE; + + return FALSE; +} + + int VSRCaccept(CKTcircuit *ckt, GENmodel *inModel) /* set up the breakpoint table. @@ -38,9 +60,6 @@ VSRCaccept(CKTcircuit *ckt, GENmodel *inModel) case PULSE: { -#define SAMETIME(a,b) (fabs((a)-(b))<= TIMETOL * PW) -#define TIMETOL 1e-7 - double TD, TR, TF, PW, PER; /* gtri - begin - wbk - add PHASE parameter */ #ifdef XSPICE @@ -170,14 +189,13 @@ VSRCaccept(CKTcircuit *ckt, GENmodel *inModel) } } for(i=0;i<(here->VSRCfunctionOrder/2)-1;i++) { - if((*(here->VSRCcoeffs+2*i)==ckt->CKTtime)) { - if(ckt->CKTbreak) { - error = CKTsetBreak(ckt, - *(here->VSRCcoeffs+2*i+2)); - if(error) return(error); - } - goto bkptset; - } + //if((*(here->VSRCcoeffs+2*i)==ckt->CKTtime)) { + // if(ckt->CKTbreak) { + if ( ckt->CKTbreak && AlmostEqualUlps(*(here->VSRCcoeffs+2*i), ckt->CKTtime, 3 ) ) { + error = CKTsetBreak(ckt, *(here->VSRCcoeffs+2*i+2)); + if(error) return(error); + goto bkptset; + } } break; } diff --git a/src/spicelib/devices/vsrc/vsrcask.c b/src/spicelib/devices/vsrc/vsrcask.c index 639709e90..5b4ce56af 100644 --- a/src/spicelib/devices/vsrc/vsrcask.c +++ b/src/spicelib/devices/vsrc/vsrcask.c @@ -75,6 +75,9 @@ VSRCask(CKTcircuit *ckt, GENinstance *inst, int which, IFvalue *value, IFvalue * case VSRC_AC_IMAG: value->rValue = here->VSRCacImag; return (OK); + case VSRC_R: + value->rValue = here->VSRCr; + return (OK); case VSRC_FCN_ORDER: value->rValue = here->VSRCfunctionOrder; return (OK); diff --git a/src/spicelib/devices/vsrc/vsrcdefs.h b/src/spicelib/devices/vsrc/vsrcdefs.h index 28c836b6e..1ecf87680 100644 --- a/src/spicelib/devices/vsrc/vsrcdefs.h +++ b/src/spicelib/devices/vsrc/vsrcdefs.h @@ -33,6 +33,7 @@ typedef struct sVSRCinstance { int VSRCfunctionType; /* code number of function type for source */ int VSRCfunctionOrder; /* order of the function for the source */ + int VSRCrBreakpt; /* pwl repeat breakpoint index */ double *VSRCcoeffs; /* pointer to array of coefficients */ double VSRCdcValue; /* DC and TRANSIENT value of source */ @@ -48,6 +49,7 @@ typedef struct sVSRCinstance { double VSRCdF1phase; /* distortion f1 phase */ double VSRCdF2phase; /* distortion f2 phase */ + double VSRCr; /* pwl repeat */ double *VSRCposIbrptr; /* pointer to sparse matrix element at * (positive node, branch equation) */ double *VSRCnegIbrptr; /* pointer to sparse matrix element at @@ -64,9 +66,10 @@ typedef struct sVSRCinstance { unsigned VSRCacPGiven :1 ; /* flag to indicate ac phase given */ unsigned VSRCfuncTGiven :1 ; /* flag to indicate function type given */ unsigned VSRCcoeffsGiven :1 ; /* flag to indicate function coeffs given */ - unsigned VSRCdGiven :1 ; /* flag to indicate source is a disto input */ - unsigned VSRCdF1given :1; /* flag to indicate source is an f1 dist input */ - unsigned VSRCdF2given :1; /* flag to indicate source is an f2 dist input */ + unsigned VSRCdGiven :1 ; /* flag to indicate source is a disto input */ + unsigned VSRCdF1given :1; /* flag to indicate source is an f1 dist input */ + unsigned VSRCdF2given :1; /* flag to indicate source is an f2 dist input */ + unsigned VSRCrGiven :1; /* flag to indicate repeating pwl */ } VSRCinstance ; @@ -115,6 +118,7 @@ typedef struct sVSRCmodel { #define VSRC_D_F2 21 #define VSRC_AM 22 +#define VSRC_R 23 /* model parameters */ diff --git a/src/spicelib/devices/vsrc/vsrcload.c b/src/spicelib/devices/vsrc/vsrcload.c index 02e3e03ed..e2e81791a 100644 --- a/src/spicelib/devices/vsrc/vsrcload.c +++ b/src/spicelib/devices/vsrc/vsrcload.c @@ -286,32 +286,39 @@ VSRCload(GENmodel *inModel, CKTcircuit *ckt) } break; case PWL: { - int i; - double foo; + int i = 0, num_repeat = 0; + double foo, repeat_time = 0, end_time, breakpt_time; if(time < *(here->VSRCcoeffs)) { foo = *(here->VSRCcoeffs + 1) ; value = foo; goto loadDone; } - for(i=0;i<(here->VSRCfunctionOrder/2)-1;i++) { - if((*(here->VSRCcoeffs+2*i)==time)) { - foo = *(here->VSRCcoeffs+2*i+1); - value = foo; - goto loadDone; - } else if((*(here->VSRCcoeffs+2*i)VSRCcoeffs+2*(i+1)) >time)) { - foo = *(here->VSRCcoeffs+2*i+1) + - (((time-*(here->VSRCcoeffs+2*i))/ - (*(here->VSRCcoeffs+2*(i+1)) - - *(here->VSRCcoeffs+2*i))) * - (*(here->VSRCcoeffs+2*i+3) - - *(here->VSRCcoeffs+2*i+1))); - value = foo; - goto loadDone; + + do { + for( ; i<(here->VSRCfunctionOrder/2)-1; i++ ) { + + if ( fabs( (*(here->VSRCcoeffs+2*i)+repeat_time) - time ) < 1e-20 ) { + foo = *(here->VSRCcoeffs+2*i+1); + value = foo; + goto loadDone; + } else if ( (*(here->VSRCcoeffs+2*i)+repeat_time < time) && (*(here->VSRCcoeffs+2*(i+1))+repeat_time > time) ) { + foo = *(here->VSRCcoeffs+2*i+1) + (((time-(*(here->VSRCcoeffs+2*i)+repeat_time))/ + (*(here->VSRCcoeffs+2*(i+1)) - *(here->VSRCcoeffs+2*i))) * + (*(here->VSRCcoeffs+2*i+3) - *(here->VSRCcoeffs+2*i+1))); + value = foo; + goto loadDone; } - } - foo = *(here->VSRCcoeffs+ here->VSRCfunctionOrder-1) ; - value = foo; + } + foo = *(here->VSRCcoeffs+ here->VSRCfunctionOrder-1) ; + value = foo; + + if ( !here->VSRCrGiven ) goto loadDone; + + end_time = *(here->VSRCcoeffs + here->VSRCfunctionOrder-2); + breakpt_time = *(here->VSRCcoeffs + here->VSRCrBreakpt); + repeat_time = end_time + (end_time - breakpt_time)*num_repeat++ - breakpt_time; + i = here->VSRCrBreakpt - 1; + } while ( here->VSRCrGiven ); break; } } diff --git a/src/spicelib/devices/vsrc/vsrcpar.c b/src/spicelib/devices/vsrc/vsrcpar.c index c59c35426..6f40f7d0d 100644 --- a/src/spicelib/devices/vsrc/vsrcpar.c +++ b/src/spicelib/devices/vsrc/vsrcpar.c @@ -85,6 +85,21 @@ VSRCparam(int param, IFvalue *value, GENinstance *inst, IFvalue *select) } } + break; + case VSRC_R: + here->VSRCr = value->rValue; + here->VSRCrGiven = TRUE; + + for ( i = 0; i < here->VSRCfunctionOrder; i += 2 ) { + here->VSRCrBreakpt = i; + if ( here->VSRCr == *(here->VSRCcoeffs+i) ) break; + } + + if ( here->VSRCr != *(here->VSRCcoeffs+here->VSRCrBreakpt) ) { + fprintf(stderr, "ERROR: repeat value %g for pwl voltage source does not match breakpoint!\n", here->VSRCr ); + return ( E_PARMVAL ); + } + break; case VSRC_SFFM: here->VSRCfunctionType = SFFM;