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.
224 lines
5.5 KiB
224 lines
5.5 KiB
/*============================================================================
|
|
FILE MIFtrunc.c
|
|
|
|
MEMBER OF process XSPICE
|
|
|
|
Copyright 1991
|
|
Georgia Tech Research Corporation
|
|
Atlanta, Georgia 30332
|
|
All Rights Reserved
|
|
|
|
PROJECT A-8503
|
|
|
|
AUTHORS
|
|
|
|
9/12/91 Bill Kuhn
|
|
|
|
MODIFICATIONS
|
|
|
|
<date> <person name> <nature of modifications>
|
|
|
|
SUMMARY
|
|
|
|
This file contains the function called by SPICE to check truncation
|
|
error of an integration state used by a code model.
|
|
|
|
INTERFACES
|
|
|
|
MIFtrunc()
|
|
|
|
REFERENCED FILES
|
|
|
|
None.
|
|
|
|
NON-STANDARD FEATURES
|
|
|
|
None.
|
|
|
|
============================================================================*/
|
|
|
|
/* #include "prefix.h" */
|
|
#include "ngspice/ngspice.h"
|
|
#include <stdio.h>
|
|
#include "ngspice/cktdefs.h"
|
|
#include "ngspice/sperror.h"
|
|
|
|
//#include "util.h"
|
|
#include <math.h>
|
|
|
|
#include "ngspice/mifproto.h"
|
|
#include "ngspice/mifparse.h"
|
|
#include "ngspice/mifdefs.h"
|
|
#include "ngspice/mifcmdat.h"
|
|
|
|
/* #include "suffix.h" */
|
|
|
|
|
|
|
|
static void MIFterr(Mif_Intgr_t *intgr, CKTcircuit *ckt, double *timeStep);
|
|
|
|
|
|
|
|
/*
|
|
MIFtrunc
|
|
|
|
This function is called by the CKTtrunc() driver function to
|
|
check numerical integration truncation error of any integrals
|
|
associated with instances of a particular code model type. It
|
|
traverses all models of that type and all instances of each
|
|
model. For each instance, it looks in the instance structure to
|
|
determine if any variables allocated by cm_analog_alloc() have been used
|
|
in a call to cm_analog_integrate(). If so, the truncation error of that
|
|
integration is computed and used to set the maximum delta allowed
|
|
for the current timestep.
|
|
*/
|
|
|
|
|
|
int
|
|
MIFtrunc(
|
|
GENmodel *inModel, /* The head of the model list */
|
|
CKTcircuit *ckt, /* The circuit structure */
|
|
double *timeStep) /* The timestep delta */
|
|
{
|
|
|
|
MIFmodel *model;
|
|
MIFinstance *here;
|
|
|
|
int i;
|
|
|
|
|
|
/* Setup for access into MIF specific model data */
|
|
model = (MIFmodel *) inModel;
|
|
|
|
|
|
/* loop through all models of this type */
|
|
for( ; model != NULL; model = model->MIFnextModel) {
|
|
|
|
/* Loop through all instances of this model */
|
|
for(here = model->MIFinstances; here != NULL; here = here->MIFnextInstance) {
|
|
|
|
/* Loop through all integration states on the instance */
|
|
for(i = 0; i < here->num_intgr; i++) {
|
|
|
|
/* Limit timeStep according to truncation error */
|
|
MIFterr(&(here->intgr[i]), ckt, timeStep);
|
|
|
|
} /* end for number of integration states */
|
|
} /* end for all instances */
|
|
} /* end for all models of this type */
|
|
|
|
|
|
return(OK);
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* Copyright (c) 1985 Thomas L. Quarles
|
|
*
|
|
* This is a modified version of the function CKTterr(). It limits
|
|
* timeStep according to computed truncation error.
|
|
*
|
|
* Modifications are Copyright 1991 Georgia Tech Research Institute
|
|
*
|
|
*/
|
|
|
|
|
|
static void MIFterr(
|
|
Mif_Intgr_t *intgr,
|
|
CKTcircuit *ckt,
|
|
double *timeStep)
|
|
{
|
|
double volttol;
|
|
double chargetol;
|
|
double tol;
|
|
double del;
|
|
double diff[8];
|
|
double deltmp[8];
|
|
double factor;
|
|
|
|
int i;
|
|
int j;
|
|
|
|
static double gearCoeff[] = {
|
|
.5,
|
|
.2222222222,
|
|
.1363636364,
|
|
.096,
|
|
.07299270073,
|
|
.05830903790
|
|
};
|
|
static double trapCoeff[] = {
|
|
.5,
|
|
.08333333333
|
|
};
|
|
|
|
/* Define new local variables. Dimension = number of states in ckt struct */
|
|
char *byte_aligned_state_ptr;
|
|
double *state_ptr[8];
|
|
|
|
|
|
/* Set state pointers to the (possibly byte-aligned) states */
|
|
for(i = 0; i < 8; i++) {
|
|
byte_aligned_state_ptr = (char *) ckt->CKTstates[i];
|
|
byte_aligned_state_ptr += intgr->byte_index;
|
|
state_ptr[i] = (double *) byte_aligned_state_ptr;
|
|
}
|
|
|
|
/* Modify computation of volttol to not include current from previous timestep */
|
|
/* which is unavailable in this implementation. Note that this makes the */
|
|
/* the overall trunction error timestep smaller (which is better accuracy) */
|
|
|
|
/* Old code */
|
|
/*
|
|
volttol = ckt->CKTabstol + ckt->CKTreltol *
|
|
MAX( fabs(ckt->CKTstate0[ccap]), fabs(ckt->CKTstate1[ccap]));
|
|
*/
|
|
|
|
/* New code */
|
|
volttol = ckt->CKTabstol + ckt->CKTreltol * fabs(*(state_ptr[0]) - *(state_ptr[1]))
|
|
/ ckt->CKTdelta;
|
|
|
|
/* Modify remaining references to qcap to access byte-aligned MIF state */
|
|
/* Otherwise, remaining code is same as SPICE3C1 ... */
|
|
|
|
chargetol = MAX(fabs(*(state_ptr[0])),fabs(*(state_ptr[1])));
|
|
chargetol = ckt->CKTreltol * MAX(chargetol,ckt->CKTchgtol)/ckt->CKTdelta;
|
|
tol = MAX(volttol,chargetol);
|
|
/* now divided differences */
|
|
for(i=ckt->CKTorder+1;i>=0;i--) {
|
|
diff[i] = *(state_ptr[i]);
|
|
}
|
|
for(i=0 ; i <= ckt->CKTorder ; i++) {
|
|
deltmp[i] = ckt->CKTdeltaOld[i];
|
|
}
|
|
j = ckt->CKTorder;
|
|
for (;;) {
|
|
for(i=0;i <= j;i++) {
|
|
diff[i] = (diff[i] - diff[i+1])/deltmp[i];
|
|
}
|
|
if (--j < 0) break;
|
|
for(i=0;i <= j;i++) {
|
|
deltmp[i] = deltmp[i+1] + ckt->CKTdeltaOld[i];
|
|
}
|
|
}
|
|
switch(ckt->CKTintegrateMethod) {
|
|
case GEAR:
|
|
default:
|
|
factor = gearCoeff[ckt->CKTorder-1];
|
|
break;
|
|
|
|
case TRAPEZOIDAL:
|
|
factor = trapCoeff[ckt->CKTorder - 1] ;
|
|
break;
|
|
}
|
|
del = ckt->CKTtrtol * tol/MAX(ckt->CKTabstol,factor * fabs(diff[0]));
|
|
if(ckt->CKTorder == 2) {
|
|
del = sqrt(del);
|
|
} else if (ckt->CKTorder > 2) {
|
|
del = exp(log(del)/ckt->CKTorder);
|
|
}
|
|
*timeStep = MIN(*timeStep,del);
|
|
return;
|
|
|
|
}
|