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.
853 lines
22 KiB
853 lines
22 KiB
/**********
|
|
Copyright 1990 Regents of the University of California. All rights reserved.
|
|
Author: 1990 Jaijeet S. Roychowdhury
|
|
**********/
|
|
|
|
#include "ngspice/ngspice.h"
|
|
#include "ngspice/cktdefs.h"
|
|
#include "ltradefs.h"
|
|
#include "ngspice/trandefs.h"
|
|
#include "ngspice/sperror.h"
|
|
#include "ngspice/suffix.h"
|
|
|
|
int
|
|
LTRAload(GENmodel *inModel, CKTcircuit *ckt)
|
|
/*
|
|
* load the appropriate values for the current timepoint into the sparse
|
|
* matrix and the right-hand-side vector
|
|
*/
|
|
{
|
|
LTRAmodel *model = (LTRAmodel *) inModel;
|
|
LTRAinstance *here;
|
|
double t1=0.0, t2=0.0, t3=0.0;
|
|
double qf1=0.0, qf2=0.0, qf3=0.0;
|
|
double lf2, lf3;
|
|
double v1d = 0.0, v2d = 0.0, i1d = 0.0, i2d = 0.0;
|
|
double dummy1=0.0, dummy2=0.0;
|
|
int isaved = 0;
|
|
unsigned tdover = 0;
|
|
int i;
|
|
double max = 0.0, min = 0.0;
|
|
|
|
/* loop through all the transmission line models */
|
|
for (; model != NULL; model = model->LTRAnextModel) {
|
|
|
|
if (ckt->CKTmode & MODEDC) {
|
|
switch (model->LTRAspecialCase) {
|
|
|
|
case LTRA_MOD_RG:
|
|
dummy1 = model->LTRAlength * sqrt(model->LTRAresist *
|
|
model->LTRAconduct);
|
|
dummy2 = exp(-dummy1);
|
|
dummy1 = exp(dummy1); /* LTRA warning: may overflow! */
|
|
model->LTRAcoshlrootGR = 0.5 * (dummy1 + dummy2);
|
|
|
|
if (model->LTRAconduct <= 1.0e-10) { /* hack! */
|
|
model->LTRArRsLrGRorG = model->LTRAlength *
|
|
model->LTRAresist;
|
|
} else {
|
|
model->LTRArRsLrGRorG = 0.5 * (dummy1 -
|
|
dummy2) * sqrt(model->LTRAresist /
|
|
model->LTRAconduct);
|
|
}
|
|
|
|
if (model->LTRAresist <= 1.0e-10) { /* hack! */
|
|
model->LTRArGsLrGRorR = model->LTRAlength *
|
|
model->LTRAconduct;
|
|
} else {
|
|
model->LTRArGsLrGRorR = 0.5 * (dummy1 -
|
|
dummy2) * sqrt(model->LTRAconduct /
|
|
model->LTRAresist);
|
|
}
|
|
break;
|
|
|
|
case LTRA_MOD_RC:
|
|
case LTRA_MOD_LC:
|
|
case LTRA_MOD_RLC:
|
|
|
|
/* simple resistor-like behaviour */
|
|
/* nothing to set up */
|
|
break;
|
|
|
|
default:
|
|
return (E_BADPARM);
|
|
} /* switch */
|
|
} else {
|
|
|
|
if ((ckt->CKTmode & MODEINITTRAN) ||
|
|
(ckt->CKTmode & MODEINITPRED)) {
|
|
switch (model->LTRAspecialCase) {
|
|
|
|
case LTRA_MOD_RLC:
|
|
case LTRA_MOD_LC:
|
|
|
|
if (ckt->CKTtime > model->LTRAtd) {
|
|
tdover = 1;
|
|
} else {
|
|
tdover = 0;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
|
|
switch (model->LTRAspecialCase) {
|
|
case LTRA_MOD_RLC:
|
|
/*
|
|
* set up lists of values of the functions at the necessary
|
|
* timepoints.
|
|
*/
|
|
|
|
|
|
/*
|
|
* set up coefficient lists LTRAh1dashCoeffs, LTRAh2Coeffs,
|
|
* LTRAh3dashCoeffs for current timepoint
|
|
*/
|
|
|
|
/*
|
|
* NOTE: h1, h2 and h3 here actually refer to h1tilde, h2tilde,
|
|
* h3tilde in the paper
|
|
*/
|
|
|
|
/*
|
|
* Note: many function evaluations are saved by doing the following
|
|
* all together in one procedure
|
|
*/
|
|
|
|
(void)
|
|
LTRArlcCoeffsSetup(&(model->LTRAh1dashFirstCoeff),
|
|
&(model->LTRAh2FirstCoeff),
|
|
&(model->LTRAh3dashFirstCoeff),
|
|
model->LTRAh1dashCoeffs, model->LTRAh2Coeffs,
|
|
model->LTRAh3dashCoeffs, model->LTRAmodelListSize,
|
|
model->LTRAtd, model->LTRAalpha, model->LTRAbeta,
|
|
ckt->CKTtime, ckt->CKTtimePoints, ckt->CKTtimeIndex,
|
|
model->LTRAchopReltol, &(model->LTRAauxIndex));
|
|
|
|
|
|
case LTRA_MOD_LC:
|
|
|
|
/* setting up the coefficients for interpolation */
|
|
if (tdover) { /* serious hack -fix! */
|
|
for (i = ckt->CKTtimeIndex; i >= 0; i--) {
|
|
if (*(ckt->CKTtimePoints + i) <
|
|
ckt->CKTtime - model->LTRAtd) {
|
|
break;
|
|
}
|
|
}
|
|
#ifdef LTRADEBUG
|
|
if (i == ckt->CKTtimeIndex) {
|
|
fprintf(stdout, "LTRAload: Warning: timestep larger than delay of line\n");
|
|
fprintf(stdout, " Time now: %g\n\n", ckt->CKTtime);
|
|
}
|
|
#endif
|
|
|
|
if (i == ckt->CKTtimeIndex)
|
|
i--;
|
|
|
|
/*#ifdef LTRADEBUG*/
|
|
if ((i == -1)) {
|
|
#ifdef LTRADEBUG
|
|
printf("LTRAload: mistake: cannot find delayed timepoint\n");
|
|
return E_INTERN;
|
|
#else
|
|
return E_INTERN;
|
|
#endif
|
|
}
|
|
|
|
isaved = i;
|
|
|
|
t2 = *(ckt->CKTtimePoints + i);
|
|
t3 = *(ckt->CKTtimePoints + i + 1);
|
|
|
|
if ((i != 0) && ((model->LTRAhowToInterp ==
|
|
LTRA_MOD_QUADINTERP) || (model->LTRAhowToInterp ==
|
|
LTRA_MOD_MIXEDINTERP))) {
|
|
/* quadratic interpolation */
|
|
t1 = *(ckt->CKTtimePoints + i - 1);
|
|
|
|
LTRAquadInterp(ckt->CKTtime - model->LTRAtd,
|
|
t1, t2, t3, &qf1, &qf2, &qf3);
|
|
|
|
}
|
|
if ((i == 0) || (model->LTRAhowToInterp ==
|
|
LTRA_MOD_MIXEDINTERP) || (model->LTRAhowToInterp
|
|
== LTRA_MOD_LININTERP)) { /* linear interpolation */
|
|
|
|
LTRAlinInterp(ckt->CKTtime - model->LTRAtd,
|
|
t2, t3, &lf2, &lf3);
|
|
}
|
|
}
|
|
/* interpolation coefficients set-up */
|
|
|
|
break;
|
|
|
|
case LTRA_MOD_RC:
|
|
|
|
/*
|
|
* set up lists of values of the coefficients at the necessary
|
|
* timepoints.
|
|
*/
|
|
|
|
|
|
/*
|
|
* set up coefficient lists LTRAh1dashCoeffs, LTRAh2Coeffs,
|
|
* LTRAh3dashCoeffs for current timepoint
|
|
*/
|
|
|
|
/*
|
|
* Note: many function evaluations are saved by doing the following
|
|
* all together in one procedure
|
|
*/
|
|
|
|
|
|
(void)
|
|
LTRArcCoeffsSetup(&(model->LTRAh1dashFirstCoeff),
|
|
&(model->LTRAh2FirstCoeff),
|
|
&(model->LTRAh3dashFirstCoeff),
|
|
model->LTRAh1dashCoeffs, model->LTRAh2Coeffs,
|
|
model->LTRAh3dashCoeffs, model->LTRAmodelListSize,
|
|
model->LTRAcByR, model->LTRArclsqr, ckt->CKTtime,
|
|
ckt->CKTtimePoints, ckt->CKTtimeIndex, model->LTRAchopReltol);
|
|
|
|
break;
|
|
|
|
case LTRA_MOD_RG:
|
|
break;
|
|
default:
|
|
return (E_BADPARM);
|
|
}
|
|
}
|
|
}
|
|
/* loop through all the instances of the model */
|
|
for (here = model->LTRAinstances; here != NULL;
|
|
here = here->LTRAnextInstance) {
|
|
|
|
if ((ckt->CKTmode & MODEDC) ||
|
|
(model->LTRAspecialCase == LTRA_MOD_RG)) {
|
|
|
|
switch (model->LTRAspecialCase) {
|
|
|
|
case LTRA_MOD_RG:
|
|
*(here->LTRAibr1Pos1Ptr) += 1.0;
|
|
*(here->LTRAibr1Neg1Ptr) -= 1.0;
|
|
*(here->LTRAibr1Pos2Ptr) -= model->LTRAcoshlrootGR;
|
|
*(here->LTRAibr1Neg2Ptr) += model->LTRAcoshlrootGR;
|
|
*(here->LTRAibr1Ibr2Ptr) += (1 + ckt->CKTgmin) *
|
|
model->LTRArRsLrGRorG;
|
|
|
|
*(here->LTRAibr2Ibr2Ptr) += model->LTRAcoshlrootGR;
|
|
*(here->LTRAibr2Pos2Ptr) -= (1 + ckt->CKTgmin) *
|
|
model->LTRArGsLrGRorR;
|
|
*(here->LTRAibr2Neg2Ptr) += (1 + ckt->CKTgmin) *
|
|
model->LTRArGsLrGRorR;
|
|
*(here->LTRAibr2Ibr1Ptr) += 1.0;
|
|
|
|
*(here->LTRApos1Ibr1Ptr) += 1.0;
|
|
*(here->LTRAneg1Ibr1Ptr) -= 1.0;
|
|
*(here->LTRApos2Ibr2Ptr) += 1.0;
|
|
*(here->LTRAneg2Ibr2Ptr) -= 1.0;
|
|
|
|
here->LTRAinput1 = here->LTRAinput2 = 0.0;
|
|
|
|
/*
|
|
* Somewhere else, we have fixed the matrix with zero entries so
|
|
* that SMPpreOrder doesn't have fits
|
|
*/
|
|
|
|
break;
|
|
|
|
case LTRA_MOD_LC:
|
|
case LTRA_MOD_RLC:
|
|
case LTRA_MOD_RC: /* load a simple resistor */
|
|
|
|
*(here->LTRApos1Ibr1Ptr) += 1.0;
|
|
*(here->LTRAneg1Ibr1Ptr) -= 1.0;
|
|
*(here->LTRApos2Ibr2Ptr) += 1.0;
|
|
*(here->LTRAneg2Ibr2Ptr) -= 1.0;
|
|
|
|
*(here->LTRAibr1Ibr1Ptr) += 1.0;
|
|
*(here->LTRAibr1Ibr2Ptr) += 1.0;
|
|
*(here->LTRAibr2Pos1Ptr) += 1.0;
|
|
*(here->LTRAibr2Pos2Ptr) -= 1.0;
|
|
*(here->LTRAibr2Ibr1Ptr) -= model->LTRAresist * model->LTRAlength;
|
|
|
|
here->LTRAinput1 = here->LTRAinput2 = 0.0;
|
|
break;
|
|
|
|
|
|
default:
|
|
return (E_BADPARM);
|
|
}
|
|
|
|
} else {
|
|
/* all cases other than DC or the RG case */
|
|
|
|
/* first timepoint after zero */
|
|
if (ckt->CKTmode & MODEINITTRAN) {
|
|
if (!(ckt->CKTmode & MODEUIC)) {
|
|
|
|
here->LTRAinitVolt1 =
|
|
(*(ckt->CKTrhsOld + here->LTRAposNode1)
|
|
- *(ckt->CKTrhsOld + here->LTRAnegNode1));
|
|
here->LTRAinitVolt2 =
|
|
(*(ckt->CKTrhsOld + here->LTRAposNode2)
|
|
- *(ckt->CKTrhsOld + here->LTRAnegNode2));
|
|
here->LTRAinitCur1 = *(ckt->CKTrhsOld + here->LTRAbrEq1);
|
|
here->LTRAinitCur2 = *(ckt->CKTrhsOld + here->LTRAbrEq2);
|
|
}
|
|
}
|
|
/* matrix loading - done every time LTRAload is called */
|
|
switch (model->LTRAspecialCase) {
|
|
|
|
case LTRA_MOD_RLC:
|
|
/* loading for convolution parts' first terms */
|
|
|
|
dummy1 = model->LTRAadmit * model->LTRAh1dashFirstCoeff;
|
|
*(here->LTRAibr1Pos1Ptr) += dummy1;
|
|
*(here->LTRAibr1Neg1Ptr) -= dummy1;
|
|
*(here->LTRAibr2Pos2Ptr) += dummy1;
|
|
*(here->LTRAibr2Neg2Ptr) -= dummy1;
|
|
/* end loading for convolution parts' first terms */
|
|
|
|
case LTRA_MOD_LC:
|
|
/*
|
|
* this section loads for the parts of the equations that resemble
|
|
* the lossless equations
|
|
*/
|
|
|
|
*(here->LTRAibr1Pos1Ptr) += model->LTRAadmit;
|
|
*(here->LTRAibr1Neg1Ptr) -= model->LTRAadmit;
|
|
*(here->LTRAibr1Ibr1Ptr) -= 1.0;
|
|
*(here->LTRApos1Ibr1Ptr) += 1.0;
|
|
*(here->LTRAneg1Ibr1Ptr) -= 1.0;
|
|
|
|
*(here->LTRAibr2Pos2Ptr) += model->LTRAadmit;
|
|
*(here->LTRAibr2Neg2Ptr) -= model->LTRAadmit;
|
|
*(here->LTRAibr2Ibr2Ptr) -= 1.0;
|
|
*(here->LTRApos2Ibr2Ptr) += 1.0;
|
|
*(here->LTRAneg2Ibr2Ptr) -= 1.0;
|
|
|
|
/* loading for lossless-like parts over */
|
|
break;
|
|
|
|
case LTRA_MOD_RC:
|
|
|
|
/*
|
|
* this section loads for the parts of the equations that have no
|
|
* convolution
|
|
*/
|
|
|
|
*(here->LTRAibr1Ibr1Ptr) -= 1.0;
|
|
*(here->LTRApos1Ibr1Ptr) += 1.0;
|
|
*(here->LTRAneg1Ibr1Ptr) -= 1.0;
|
|
|
|
*(here->LTRAibr2Ibr2Ptr) -= 1.0;
|
|
*(here->LTRApos2Ibr2Ptr) += 1.0;
|
|
*(here->LTRAneg2Ibr2Ptr) -= 1.0;
|
|
|
|
/* loading for non-convolution parts over */
|
|
/* loading for convolution parts' first terms */
|
|
|
|
dummy1 = model->LTRAh1dashFirstCoeff;
|
|
*(here->LTRAibr1Pos1Ptr) += dummy1;
|
|
*(here->LTRAibr1Neg1Ptr) -= dummy1;
|
|
*(here->LTRAibr2Pos2Ptr) += dummy1;
|
|
*(here->LTRAibr2Neg2Ptr) -= dummy1;
|
|
|
|
dummy1 = model->LTRAh2FirstCoeff;
|
|
*(here->LTRAibr1Ibr2Ptr) -= dummy1;
|
|
*(here->LTRAibr2Ibr1Ptr) -= dummy1;
|
|
|
|
dummy1 = model->LTRAh3dashFirstCoeff;
|
|
*(here->LTRAibr1Pos2Ptr) -= dummy1;
|
|
*(here->LTRAibr1Neg2Ptr) += dummy1;
|
|
*(here->LTRAibr2Pos1Ptr) -= dummy1;
|
|
*(here->LTRAibr2Neg1Ptr) += dummy1;
|
|
|
|
/* end loading for convolution parts' first terms */
|
|
|
|
|
|
break;
|
|
default:
|
|
return (E_BADPARM);
|
|
}
|
|
|
|
|
|
/* INITPRED - first NR iteration of each timepoint */
|
|
/* set up LTRAinputs - to go into the RHS of the circuit equations */
|
|
|
|
if (ckt->CKTmode & (MODEINITPRED | MODEINITTRAN)) {
|
|
|
|
here->LTRAinput1 = here->LTRAinput2 = 0.0;
|
|
|
|
switch (model->LTRAspecialCase) {
|
|
|
|
case LTRA_MOD_LC:
|
|
case LTRA_MOD_RLC:
|
|
|
|
if (tdover) {
|
|
/* have to interpolate values */
|
|
|
|
if ((isaved != 0) &&
|
|
((model->LTRAhowToInterp ==
|
|
LTRA_MOD_QUADINTERP) ||
|
|
(model->LTRAhowToInterp ==
|
|
LTRA_MOD_MIXEDINTERP))) {
|
|
|
|
v1d = *(here->LTRAv1 + isaved - 1) * qf1
|
|
+ *(here->LTRAv1 + isaved) * qf2
|
|
+ *(here->LTRAv1 + isaved + 1) * qf3;
|
|
|
|
max = MAX(*(here->LTRAv1 + isaved - 1),
|
|
*(here->LTRAv1 + isaved));
|
|
max = MAX(max, *(here->LTRAv1 + isaved + 1));
|
|
min = MIN(*(here->LTRAv1 + isaved - 1),
|
|
*(here->LTRAv1 + isaved));
|
|
min = MIN(min, *(here->LTRAv1 + isaved + 1));
|
|
|
|
}
|
|
if ((model->LTRAhowToInterp ==
|
|
LTRA_MOD_LININTERP) || (isaved == 0) ||
|
|
((isaved != 0) &&
|
|
((model->LTRAhowToInterp ==
|
|
LTRA_MOD_QUADINTERP) ||
|
|
(model->LTRAhowToInterp ==
|
|
LTRA_MOD_MIXEDINTERP)) &&
|
|
((v1d > max) || (v1d < min)))) {
|
|
|
|
|
|
if ((isaved != 0) &&
|
|
(model->LTRAhowToInterp ==
|
|
LTRA_MOD_QUADINTERP)) {
|
|
#ifdef LTRADEBUG
|
|
fprintf(stdout, "LTRAload: warning: interpolated v1 is out of range after timepoint %d\n", ckt->CKTtimeIndex);
|
|
fprintf(stdout, " values: %1.8g %1.8g %1.8g; interpolated: %1.8g\n",
|
|
*(here->LTRAv1 + isaved - 1),
|
|
*(here->LTRAv1 + isaved),
|
|
*(here->LTRAv1 + isaved + 1),
|
|
v1d);
|
|
fprintf(stdout, " timepoints are: %1.8g %1.8g %1.8g %1.8g\n", t1, t2, t3, ckt->CKTtime - model->LTRAtd);
|
|
#endif
|
|
} else {
|
|
|
|
v1d = *(here->LTRAv1 + isaved) * lf2
|
|
+ *(here->LTRAv1 + isaved + 1) *
|
|
lf3;
|
|
}
|
|
|
|
}
|
|
if ((isaved != 0) &&
|
|
((model->LTRAhowToInterp ==
|
|
LTRA_MOD_QUADINTERP) ||
|
|
(model->LTRAhowToInterp ==
|
|
LTRA_MOD_MIXEDINTERP))) {
|
|
|
|
i1d = *(here->LTRAi1 + isaved - 1) * qf1
|
|
+ *(here->LTRAi1 + isaved) * qf2
|
|
+ *(here->LTRAi1 + isaved + 1) * qf3;
|
|
|
|
max = MAX(*(here->LTRAi1 + isaved - 1),
|
|
*(here->LTRAi1 + isaved));
|
|
max = MAX(max, *(here->LTRAi1 + isaved + 1));
|
|
min = MIN(*(here->LTRAi1 + isaved - 1),
|
|
*(here->LTRAi1 + isaved));
|
|
min = MIN(min, *(here->LTRAi1 + isaved + 1));
|
|
|
|
}
|
|
if ((model->LTRAhowToInterp ==
|
|
LTRA_MOD_LININTERP) || (isaved == 0) ||
|
|
((isaved != 0) &&
|
|
((model->LTRAhowToInterp ==
|
|
LTRA_MOD_QUADINTERP) ||
|
|
(model->LTRAhowToInterp ==
|
|
LTRA_MOD_MIXEDINTERP)) &&
|
|
((i1d > max) || (i1d < min)))) {
|
|
|
|
|
|
if ((isaved != 0) &&
|
|
(model->LTRAhowToInterp ==
|
|
LTRA_MOD_QUADINTERP)) {
|
|
#ifdef LTRADEBUG
|
|
fprintf(stdout, "LTRAload: warning: interpolated i1 is out of range after timepoint %d\n", ckt->CKTtimeIndex);
|
|
fprintf(stdout, " values: %1.8g %1.8g %1.8g; interpolated: %1.8g\n",
|
|
*(here->LTRAi1 + isaved - 1),
|
|
*(here->LTRAi1 + isaved),
|
|
*(here->LTRAi1 + isaved + 1),
|
|
i1d);
|
|
fprintf(stdout, " timepoints are: %1.8g %1.8g %1.8g %1.8g\n", t1, t2, t3, ckt->CKTtime - model->LTRAtd);
|
|
#endif
|
|
} else {
|
|
|
|
i1d = *(here->LTRAi1 + isaved) * lf2
|
|
+ *(here->LTRAi1 + isaved + 1) *
|
|
lf3;
|
|
}
|
|
|
|
}
|
|
if ((isaved != 0) &&
|
|
((model->LTRAhowToInterp ==
|
|
LTRA_MOD_QUADINTERP) ||
|
|
(model->LTRAhowToInterp ==
|
|
LTRA_MOD_MIXEDINTERP))) {
|
|
|
|
v2d = *(here->LTRAv2 + isaved - 1) * qf1
|
|
+ *(here->LTRAv2 + isaved) * qf2
|
|
+ *(here->LTRAv2 + isaved + 1) * qf3;
|
|
|
|
max = MAX(*(here->LTRAv2 + isaved - 1),
|
|
*(here->LTRAv2 + isaved));
|
|
max = MAX(max, *(here->LTRAv2 + isaved + 1));
|
|
min = MIN(*(here->LTRAv2 + isaved - 1),
|
|
*(here->LTRAv2 + isaved));
|
|
min = MIN(min, *(here->LTRAv2 + isaved + 1));
|
|
|
|
}
|
|
if ((model->LTRAhowToInterp ==
|
|
LTRA_MOD_LININTERP) || (isaved == 0) ||
|
|
((isaved != 0) &&
|
|
((model->LTRAhowToInterp ==
|
|
LTRA_MOD_QUADINTERP) ||
|
|
(model->LTRAhowToInterp ==
|
|
LTRA_MOD_MIXEDINTERP)) &&
|
|
((v2d > max) || (v2d < min)))) {
|
|
|
|
|
|
if ((isaved != 0) &&
|
|
(model->LTRAhowToInterp ==
|
|
LTRA_MOD_QUADINTERP)) {
|
|
#ifdef LTRADEBUG
|
|
fprintf(stdout, "LTRAload: warning: interpolated v2 is out of range after timepoint %d\n", ckt->CKTtimeIndex);
|
|
fprintf(stdout, " values: %1.8g %1.8g %1.8g; interpolated: %1.8g\n",
|
|
*(here->LTRAv2 + isaved - 1),
|
|
*(here->LTRAv2 + isaved),
|
|
*(here->LTRAv2 + isaved + 1),
|
|
v2d);
|
|
fprintf(stdout, " timepoints are: %1.8g %1.8g %1.8g %1.8g\n", t1, t2, t3, ckt->CKTtime - model->LTRAtd);
|
|
#endif
|
|
} else {
|
|
|
|
v2d = *(here->LTRAv2 + isaved) * lf2
|
|
+ *(here->LTRAv2 + isaved + 1) *
|
|
lf3;
|
|
}
|
|
|
|
}
|
|
if ((isaved != 0) &&
|
|
((model->LTRAhowToInterp ==
|
|
LTRA_MOD_QUADINTERP) ||
|
|
(model->LTRAhowToInterp ==
|
|
LTRA_MOD_MIXEDINTERP))) {
|
|
|
|
i2d = *(here->LTRAi2 + isaved - 1) * qf1
|
|
+ *(here->LTRAi2 + isaved) * qf2
|
|
+ *(here->LTRAi2 + isaved + 1) * qf3;
|
|
|
|
max = MAX(*(here->LTRAi2 + isaved - 1),
|
|
*(here->LTRAi2 + isaved));
|
|
max = MAX(max, *(here->LTRAi2 + isaved + 1));
|
|
min = MIN(*(here->LTRAi2 + isaved - 1),
|
|
*(here->LTRAi2 + isaved));
|
|
min = MIN(min, *(here->LTRAi2 + isaved + 1));
|
|
|
|
}
|
|
if ((model->LTRAhowToInterp ==
|
|
LTRA_MOD_LININTERP) || (isaved == 0) ||
|
|
((isaved != 0) &&
|
|
((model->LTRAhowToInterp ==
|
|
LTRA_MOD_QUADINTERP) ||
|
|
(model->LTRAhowToInterp ==
|
|
LTRA_MOD_MIXEDINTERP)) &&
|
|
((i2d > max) || (i2d < min)))) {
|
|
|
|
|
|
if ((isaved != 0) &&
|
|
(model->LTRAhowToInterp ==
|
|
LTRA_MOD_QUADINTERP)) {
|
|
#ifdef LTRADEBUG
|
|
fprintf(stdout, "LTRAload: warning: interpolated i2 is out of range after timepoint %d\n", ckt->CKTtimeIndex);
|
|
fprintf(stdout, " values: %1.8g %1.8g %1.8g; interpolated: %1.8g\n",
|
|
*(here->LTRAi2 + isaved - 1),
|
|
*(here->LTRAi2 + isaved),
|
|
*(here->LTRAi2 + isaved + 1),
|
|
i2d);
|
|
fprintf(stdout, " timepoints are: %1.8g %1.8g %1.8g %1.8g\n", t1, t2, t3, ckt->CKTtime - model->LTRAtd);
|
|
#endif
|
|
} else {
|
|
|
|
i2d = *(here->LTRAi2 + isaved) * lf2
|
|
+ *(here->LTRAi2 + isaved + 1) *
|
|
lf3;
|
|
}
|
|
|
|
}
|
|
}
|
|
/* interpolation done */
|
|
break;
|
|
|
|
case LTRA_MOD_RC:
|
|
break;
|
|
|
|
default:
|
|
return (E_BADPARM);
|
|
}
|
|
|
|
switch (model->LTRAspecialCase) {
|
|
case LTRA_MOD_RLC:
|
|
|
|
/* begin convolution parts */
|
|
|
|
/* convolution of h1dash with v1 and v2 */
|
|
/* the matrix has already been loaded above */
|
|
|
|
dummy1 = dummy2 = 0.0;
|
|
for (i = /* model->LTRAh1dashIndex */ ckt->CKTtimeIndex; i > 0; i--) {
|
|
if (*(model->LTRAh1dashCoeffs + i) != 0.0) {
|
|
dummy1 += *(model->LTRAh1dashCoeffs
|
|
+ i) * (*(here->LTRAv1 + i) -
|
|
here->LTRAinitVolt1);
|
|
dummy2 += *(model->LTRAh1dashCoeffs
|
|
+ i) * (*(here->LTRAv2 + i) -
|
|
here->LTRAinitVolt2);
|
|
}
|
|
}
|
|
|
|
dummy1 += here->LTRAinitVolt1 *
|
|
model->LTRAintH1dash;
|
|
dummy2 += here->LTRAinitVolt2 *
|
|
model->LTRAintH1dash;
|
|
|
|
dummy1 -= here->LTRAinitVolt1 *
|
|
model->LTRAh1dashFirstCoeff;
|
|
dummy2 -= here->LTRAinitVolt2 *
|
|
model->LTRAh1dashFirstCoeff;
|
|
|
|
here->LTRAinput1 -= dummy1 * model->LTRAadmit;
|
|
here->LTRAinput2 -= dummy2 * model->LTRAadmit;
|
|
|
|
/* end convolution of h1dash with v1 and v2 */
|
|
|
|
/* convolution of h2 with i2 and i1 */
|
|
|
|
dummy1 = dummy2 = 0.0;
|
|
if (tdover) {
|
|
|
|
/* the term for ckt->CKTtime - model->LTRAtd */
|
|
|
|
dummy1 = (i2d - here->LTRAinitCur2) *
|
|
model->LTRAh2FirstCoeff;
|
|
dummy2 = (i1d - here->LTRAinitCur1) *
|
|
model->LTRAh2FirstCoeff;
|
|
|
|
/* the rest of the convolution */
|
|
|
|
for (i = /* model->LTRAh2Index */ model->LTRAauxIndex; i > 0; i--) {
|
|
|
|
if (*(model->LTRAh2Coeffs + i) != 0.0) {
|
|
dummy1 += *(model->LTRAh2Coeffs
|
|
+ i) * (*(here->LTRAi2 + i) -
|
|
here->LTRAinitCur2);
|
|
dummy2 += *(model->LTRAh2Coeffs
|
|
+ i) * (*(here->LTRAi1 + i) -
|
|
here->LTRAinitCur1);
|
|
}
|
|
}
|
|
}
|
|
/* the initial-condition terms */
|
|
|
|
dummy1 += here->LTRAinitCur2 *
|
|
model->LTRAintH2;
|
|
dummy2 += here->LTRAinitCur1 *
|
|
model->LTRAintH2;
|
|
|
|
here->LTRAinput1 += dummy1;
|
|
here->LTRAinput2 += dummy2;
|
|
|
|
/* end convolution of h2 with i2 and i1 */
|
|
|
|
/* convolution of h3dash with v2 and v1 */
|
|
|
|
/* the term for ckt->CKTtime - model->LTRAtd */
|
|
|
|
dummy1 = dummy2 = 0.0;
|
|
if (tdover) {
|
|
|
|
dummy1 = (v2d - here->LTRAinitVolt2) *
|
|
model->LTRAh3dashFirstCoeff;
|
|
dummy2 = (v1d - here->LTRAinitVolt1) *
|
|
model->LTRAh3dashFirstCoeff;
|
|
|
|
/* the rest of the convolution */
|
|
|
|
for (i = /* model->LTRAh3dashIndex */ model->LTRAauxIndex; i > 0; i--) {
|
|
if (*(model->LTRAh3dashCoeffs + i) != 0.0) {
|
|
dummy1 += *(model->LTRAh3dashCoeffs
|
|
+ i) * (*(here->LTRAv2 + i) -
|
|
here->LTRAinitVolt2);
|
|
dummy2 += *(model->LTRAh3dashCoeffs
|
|
+ i) * (*(here->LTRAv1 + i) -
|
|
here->LTRAinitVolt1);
|
|
}
|
|
}
|
|
}
|
|
/* the initial-condition terms */
|
|
|
|
dummy1 += here->LTRAinitVolt2 *
|
|
model->LTRAintH3dash;
|
|
dummy2 += here->LTRAinitVolt1 *
|
|
model->LTRAintH3dash;
|
|
|
|
here->LTRAinput1 += model->LTRAadmit * dummy1;
|
|
here->LTRAinput2 += model->LTRAadmit * dummy2;
|
|
|
|
/* end convolution of h3dash with v2 and v1 */
|
|
|
|
case LTRA_MOD_LC:
|
|
/* begin lossless-like parts */
|
|
|
|
if (!tdover) {
|
|
|
|
here->LTRAinput1 += model->LTRAattenuation *
|
|
(here->LTRAinitVolt2 * model->LTRAadmit +
|
|
here->LTRAinitCur2);
|
|
here->LTRAinput2 += model->LTRAattenuation *
|
|
(here->LTRAinitVolt1 * model->LTRAadmit +
|
|
here->LTRAinitCur1);
|
|
|
|
} else {
|
|
|
|
here->LTRAinput1 += model->LTRAattenuation *
|
|
(v2d * model->LTRAadmit + i2d);
|
|
here->LTRAinput2 += model->LTRAattenuation *
|
|
(v1d * model->LTRAadmit + i1d);
|
|
|
|
}
|
|
|
|
/* end lossless-like parts */
|
|
break;
|
|
|
|
case LTRA_MOD_RC:
|
|
|
|
|
|
/* begin convolution parts */
|
|
|
|
/* convolution of h1dash with v1 and v2 */
|
|
/* the matrix has already been loaded above */
|
|
|
|
dummy1 = 0.0;
|
|
dummy2 = 0.0;
|
|
for (i = ckt->CKTtimeIndex; i > 0; i--) {
|
|
if (*(model->LTRAh1dashCoeffs + i) != 0.0) {
|
|
dummy1 += *(model->LTRAh1dashCoeffs
|
|
+ i) * (*(here->LTRAv1 + i) -
|
|
here->LTRAinitVolt1);
|
|
dummy2 += *(model->LTRAh1dashCoeffs
|
|
+ i) * (*(here->LTRAv2 + i) -
|
|
here->LTRAinitVolt2);
|
|
}
|
|
}
|
|
|
|
/* the initial condition terms */
|
|
|
|
dummy1 += here->LTRAinitVolt1 *
|
|
model->LTRAintH1dash;
|
|
dummy2 += here->LTRAinitVolt2 *
|
|
model->LTRAintH1dash;
|
|
|
|
/*
|
|
* the constant contributed by the init condition and the latest
|
|
* timepoint
|
|
*/
|
|
|
|
dummy1 -= here->LTRAinitVolt1 *
|
|
model->LTRAh1dashFirstCoeff;
|
|
dummy2 -= here->LTRAinitVolt2 *
|
|
model->LTRAh1dashFirstCoeff;
|
|
|
|
here->LTRAinput1 -= dummy1;
|
|
here->LTRAinput2 -= dummy2;
|
|
|
|
/* end convolution of h1dash with v1 and v2 */
|
|
|
|
|
|
/* convolution of h2 with i2 and i1 */
|
|
|
|
dummy1 = dummy2 = 0.0;
|
|
|
|
for (i = ckt->CKTtimeIndex; i > 0; i--) {
|
|
if (*(model->LTRAh2Coeffs + i) != 0.0) {
|
|
dummy1 += *(model->LTRAh2Coeffs
|
|
+ i) * (*(here->LTRAi2 + i) -
|
|
here->LTRAinitCur2);
|
|
dummy2 += *(model->LTRAh2Coeffs
|
|
+ i) * (*(here->LTRAi1 + i) -
|
|
here->LTRAinitCur1);
|
|
}
|
|
}
|
|
|
|
/* the initial-condition terms */
|
|
|
|
dummy1 += here->LTRAinitCur2 *
|
|
model->LTRAintH2;
|
|
dummy2 += here->LTRAinitCur1 *
|
|
model->LTRAintH2;
|
|
|
|
dummy1 -= here->LTRAinitCur2 *
|
|
model->LTRAh2FirstCoeff;
|
|
dummy2 -= here->LTRAinitCur1 *
|
|
model->LTRAh2FirstCoeff;
|
|
|
|
here->LTRAinput1 += dummy1;
|
|
here->LTRAinput2 += dummy2;
|
|
|
|
/* end convolution of h2 with i2 and i1 */
|
|
|
|
/* convolution of h3dash with v2 and v1 */
|
|
|
|
|
|
dummy1 = dummy2 = 0.0;
|
|
|
|
|
|
for (i = ckt->CKTtimeIndex; i > 0; i--) {
|
|
if (*(model->LTRAh3dashCoeffs + i) != 0.0) {
|
|
dummy1 += *(model->LTRAh3dashCoeffs
|
|
+ i) * (*(here->LTRAv2 + i) -
|
|
here->LTRAinitVolt2);
|
|
dummy2 += *(model->LTRAh3dashCoeffs
|
|
+ i) * (*(here->LTRAv1 + i) -
|
|
here->LTRAinitVolt1);
|
|
}
|
|
}
|
|
|
|
/* the initial-condition terms */
|
|
|
|
dummy1 += here->LTRAinitVolt2 *
|
|
model->LTRAintH3dash;
|
|
dummy2 += here->LTRAinitVolt1 *
|
|
model->LTRAintH3dash;
|
|
|
|
dummy1 -= here->LTRAinitVolt2 *
|
|
model->LTRAh3dashFirstCoeff;
|
|
dummy2 -= here->LTRAinitVolt1 *
|
|
model->LTRAh3dashFirstCoeff;
|
|
|
|
here->LTRAinput1 += dummy1;
|
|
here->LTRAinput2 += dummy2;
|
|
|
|
/* end convolution of h3dash with v2 and v1 */
|
|
|
|
break;
|
|
|
|
default:
|
|
return (E_BADPARM);
|
|
}
|
|
}
|
|
/* load the RHS - done every time this routine is called */
|
|
|
|
*(ckt->CKTrhs + here->LTRAbrEq1) += here->LTRAinput1;
|
|
*(ckt->CKTrhs + here->LTRAbrEq2) += here->LTRAinput2;
|
|
|
|
}
|
|
}
|
|
}
|
|
return (OK);
|
|
}
|