Implemented the KCL verification in place of the classical SPICE3 check for the circuit currents

At the moment the used formula is not the best approach, but it avoids to rewrite every model
This commit is contained in:
Francesco Lannutti 2013-01-11 23:36:57 +01:00
parent 2d1d0e71df
commit bb99c154dd
8 changed files with 113 additions and 12 deletions

View File

@ -425,6 +425,10 @@ extern void NInzIter(CKTcircuit *, int, int);
extern int NIpred(CKTcircuit *ckt); extern int NIpred(CKTcircuit *ckt);
#endif #endif
/* KCL Verification */
extern int NIkclVerification (CKTcircuit *) ;
/********************/
extern IFfrontEnd *SPfrontEnd; extern IFfrontEnd *SPfrontEnd;
#endif #endif

View File

@ -14,6 +14,10 @@ Modified: 2000 AlansFixes
#include <math.h> #include <math.h>
#include "ngspice/complex.h" #include "ngspice/complex.h"
/* KCL Verification */
int KCLverification (SMPmatrix *, double *, double *, double, int, double, double, double) ;
/********************/
int SMPaddElt( SMPmatrix *, int , int , double ); int SMPaddElt( SMPmatrix *, int , int , double );
double * SMPmakeElt( SMPmatrix * , int , int ); double * SMPmakeElt( SMPmatrix * , int , int );
void SMPcClear( SMPmatrix *); void SMPcClear( SMPmatrix *);

View File

@ -294,4 +294,8 @@ extern void spMultTransposed(MatrixPtr,spREAL*,spREAL*,spREAL*,spREAL*);
extern void spSolve( MatrixPtr, spREAL*, spREAL*, spREAL*, spREAL* ); extern void spSolve( MatrixPtr, spREAL*, spREAL*, spREAL*, spREAL* );
extern void spSolveTransposed(MatrixPtr,spREAL*,spREAL*,spREAL*,spREAL*); extern void spSolveTransposed(MatrixPtr,spREAL*,spREAL*,spREAL*,spREAL*);
/* KCL Verification */
extern int KCL_verification (MatrixPtr, spREAL *, spREAL *, double, int, double, double, double) ;
/********************/
#endif /* spOKAY */ #endif /* spOKAY */

View File

@ -45,18 +45,6 @@ NIconvTest(CKTcircuit *ckt)
#ifdef STEPDEBUG #ifdef STEPDEBUG
printf(" non-convergence at node (type=3) %s (fabs(new-old)>tol --> fabs(%g-%g)>%g)\n",CKTnodName(ckt,i),new,old,tol); printf(" non-convergence at node (type=3) %s (fabs(new-old)>tol --> fabs(%g-%g)>%g)\n",CKTnodName(ckt,i),new,old,tol);
printf(" reltol: %g voltTol: %g (tol=reltol*(MAX(fabs(old),fabs(new))) + voltTol)\n",ckt->CKTreltol,ckt->CKTvoltTol); printf(" reltol: %g voltTol: %g (tol=reltol*(MAX(fabs(old),fabs(new))) + voltTol)\n",ckt->CKTreltol,ckt->CKTvoltTol);
#endif /* STEPDEBUG */
ckt->CKTtroubleNode = i;
ckt->CKTtroubleElt = NULL;
return(1);
}
} else {
tol = ckt->CKTreltol * (MAX(fabs(old),fabs(new))) +
ckt->CKTabstol;
if (fabs(new-old) >tol ) {
#ifdef STEPDEBUG
printf(" non-convergence at node (type=%d) %s (fabs(new-old)>tol --> fabs(%g-%g)>%g)\n",node->type,CKTnodName(ckt,i),new,old,tol);
printf(" reltol: %g abstol: %g (tol=reltol*(MAX(fabs(old),fabs(new))) + abstol)\n",ckt->CKTreltol,ckt->CKTabstol);
#endif /* STEPDEBUG */ #endif /* STEPDEBUG */
ckt->CKTtroubleNode = i; ckt->CKTtroubleNode = i;
ckt->CKTtroubleElt = NULL; ckt->CKTtroubleElt = NULL;
@ -74,3 +62,41 @@ NIconvTest(CKTcircuit *ckt)
return(0); return(0);
#endif /* NEWCONV */ #endif /* NEWCONV */
} }
/**
* Routine to Verify the KCL
*/
int NIkclVerification (CKTcircuit *ckt)
{
int i, size ;
double maximum = 0 ;
CKTnode *node ;
size = SMPmatSize (ckt->CKTmatrix) ;
node = ckt->CKTnodes ;
for (i = 1 ; i <= size ; i++)
{
if (node->type == SP_CURRENT)
{
if (maximum < fabs (ckt->CKTrhsOld [i]))
maximum = fabs (ckt->CKTrhsOld [i]) ;
}
node = node->next ;
}
node = ckt->CKTnodes ;
for (i = 1 ; i <= size ; i++)
{
if (node->type == SP_VOLTAGE)
{
if (KCLverification (ckt->CKTmatrix, ckt->CKTrhsOld, ckt->CKTrhs, ckt->CKTdiagGmin, i, ckt->CKTreltol, ckt->CKTabstol, maximum))
return 1 ;
}
node = node->next ;
}
return 0 ;
}

View File

@ -37,6 +37,9 @@ NIiter(CKTcircuit *ckt, int maxIter)
CKTnode *node; /* current matrix entry */ CKTnode *node; /* current matrix entry */
double diff, maxdiff, damp_factor, *OldCKTstate0=NULL; double diff, maxdiff, damp_factor, *OldCKTstate0=NULL;
/* KCL_verified */
int KCL_verified ;
if ( maxIter < 100 ) maxIter = 100; /* some convergence issues that get resolved by increasing max iter */ if ( maxIter < 100 ) maxIter = 100; /* some convergence issues that get resolved by increasing max iter */
iterno=0; iterno=0;
@ -110,6 +113,16 @@ NIiter(CKTcircuit *ckt, int maxIter)
ckt->CKTniState |= NISHOULDREORDER; ckt->CKTniState |= NISHOULDREORDER;
} }
/* KCL Verification */
if ((ckt->CKTnoncon == 0) && (iterno != 1))
{
KCL_verified = NIkclVerification (ckt) ;
if (KCL_verified) /* NOT VERIFIED */
ckt->CKTnoncon = 1 ;
else
ckt->CKTnoncon = 0 ;
}
if(ckt->CKTniState & NISHOULDREORDER) { if(ckt->CKTniState & NISHOULDREORDER) {
startTime = SPfrontEnd->IFseconds(); startTime = SPfrontEnd->IFseconds();
error = SMPreorder(ckt->CKTmatrix,ckt->CKTpivotAbsTol, error = SMPreorder(ckt->CKTmatrix,ckt->CKTpivotAbsTol,

View File

@ -9,6 +9,7 @@ libsparse_la_SOURCES = \
spdefs.h \ spdefs.h \
spextra.c \ spextra.c \
spfactor.c \ spfactor.c \
spkirch.c \
spoutput.c \ spoutput.c \
spsmp.c \ spsmp.c \
spsolve.c \ spsolve.c \

View File

@ -0,0 +1,41 @@
/**
* Routine to Verify the KCL
*/
#include <math.h>
#define spINSIDE_SPARSE
#include "spconfig.h"
#include "ngspice/spmatrix.h"
#include "spdefs.h"
int KCL_verification (MatrixPtr Matrix, spREAL *rhsOld, spREAL *rhs, double gmin, int i, double RelTol, double AbsTol, double maximum)
{
ElementPtr element ;
spREAL current ;
current = 0 ;
#ifdef TRANSLATE
element = Matrix->FirstInRow [Matrix->ExtToIntRowMap [i]] ;
#else
element = Matrix->FirstInRow [i] ;
#endif
/* A*x */
while (element != NULL)
{
current += element->Real * rhsOld [Matrix->IntToExtColMap [element->Col]] ;
element = element->NextInRow ;
}
#ifdef TRANSLATE
current += gmin * rhsOld [Matrix->IntToExtColMap [Matrix->Diag [Matrix->ExtToIntRowMap [i]]->Col]] ;
#else
current += gmin * rhsOld [Matrix->IntToExtColMap [Matrix->Diag [i]->Col]] ;
#endif
if (fabs (current - rhs [i]) > RelTol * maximum + AbsTol)
return 1 ;
return 0 ;
}

View File

@ -108,6 +108,14 @@ extern double logb(double);
static void LoadGmin(SMPmatrix *eMatrix, double Gmin); static void LoadGmin(SMPmatrix *eMatrix, double Gmin);
/**
* Routine to Verify the KCL
*/
int
KCLverification (SMPmatrix *Matrix, double *rhsOld, double *rhs, double gmin, int i, double RelTol, double AbsTol, double maximum)
{
return KCL_verification (Matrix, rhsOld, rhs, gmin, i, RelTol, AbsTol, maximum) ;
}
/* /*
* SMPaddElt() * SMPaddElt()