"DC Source with Pulse stops pulsing half way through simulation".
Do not require breakpoints to be hit almost exactly before scheduling
the next one.  That may cause the next breakpoint to be lost.
This commit is contained in:
Giles Atkinson 2023-04-03 19:12:51 +01:00 committed by Holger Vogt
parent 50a9daf24a
commit ad5bb9eb8d
4 changed files with 165 additions and 176 deletions

View File

@ -19,9 +19,6 @@ extern void fftFree(void);
extern bool ft_ngdebug; /* some additional debug info printed */ extern bool ft_ngdebug; /* some additional debug info printed */
#define SAMETIME(a,b) (fabs((a)-(b))<= TIMETOL * PW)
#define TIMETOL 1e-7
int int
VSRCaccept(CKTcircuit *ckt, GENmodel *inModel) VSRCaccept(CKTcircuit *ckt, GENmodel *inModel)
/* set up the breakpoint table. */ /* set up the breakpoint table. */
@ -51,7 +48,6 @@ VSRCaccept(CKTcircuit *ckt, GENmodel *inModel)
case PULSE: { case PULSE: {
double TD, TR, TF, PW, PER; double TD, TR, TF, PW, PER;
double tshift;
double time = 0.; double time = 0.;
double basetime = 0; double basetime = 0;
double tmax = 1e99; double tmax = 1e99;
@ -79,7 +75,6 @@ VSRCaccept(CKTcircuit *ckt, GENmodel *inModel)
/* offset time by delay */ /* offset time by delay */
time = ckt->CKTtime - TD; time = ckt->CKTtime - TD;
tshift = TD;
if (newcompat.xs) { if (newcompat.xs) {
/* normalize phase to 0 - 360° */ /* normalize phase to 0 - 360° */
@ -90,71 +85,55 @@ VSRCaccept(CKTcircuit *ckt, GENmodel *inModel)
while (deltat > 0) while (deltat > 0)
deltat -= PER; deltat -= PER;
time += deltat; time += deltat;
tshift = TD - deltat; } else if (PHASE > 0.0) {
}
else if (PHASE > 0.0) {
tmax = PHASE * PER; tmax = PHASE * PER;
if (time > tmax)
break;
} }
if (!newcompat.xs && time > tmax) { if (ckt->CKTtime >= here->VSRCbreak_time) {
/* Do nothing */ double wait;
}
else {
if (time >= PER) { if (time >= PER) {
/* repeating signal - figure out where we are */ /* Repeating signal: where in period are we? */
/* in period */
basetime = PER * floor(time / PER); basetime = PER * floor(time / PER);
time -= basetime; time -= basetime;
} }
if (time <= 0.0 || time >= TR + PW + TF) { /* Set next breakpoint. */
if (ckt->CKTbreak && SAMETIME(time, 0.0)) {
error = CKTsetBreak(ckt, basetime + TR + tshift); if (time < 0.0) {
if (error) return(error); /* Await first pulse */
}
else if (ckt->CKTbreak && SAMETIME(TR + PW + TF, time)) { wait = -time;
error = CKTsetBreak(ckt, basetime + PER + tshift); } else if (time < TR) {
if (error) return(error); /* Wait for end of rise. */
}
else if (ckt->CKTbreak && (time == -tshift)) { wait = TR - time;
error = CKTsetBreak(ckt, basetime + tshift); } else if (time < TR + PW) {
if (error) return(error); /* Wait for fall. */
}
else if (ckt->CKTbreak && SAMETIME(PER, time)) { wait = TR + PW - time;
error = CKTsetBreak(ckt, basetime + tshift + TR + PER); } else if (time < TR + PW + TF) {
if (error) return(error); /* Wait for end of fall. */
}
} wait = TR + PW + TF - time;
else if (time >= TR && time <= TR + PW) { } else {
if (ckt->CKTbreak && SAMETIME(time, TR)) { /* Wait for next pulse. */
error = CKTsetBreak(ckt, basetime + tshift + TR + PW); wait = PER - time;
if (error) return(error);
}
else if (ckt->CKTbreak && SAMETIME(TR + PW, time)) {
error = CKTsetBreak(ckt, basetime + tshift + TR + PW + TF);
if (error) return(error);
}
}
else if (time > 0 && time < TR) {
if (ckt->CKTbreak && SAMETIME(time, 0)) {
error = CKTsetBreak(ckt, basetime + tshift + TR);
if (error) return(error);
}
else if (ckt->CKTbreak && SAMETIME(time, TR)) {
error = CKTsetBreak(ckt, basetime + tshift + TR + PW);
if (error) return(error);
}
}
else { /* time > TR + PW && < TR + PW + TF */
if (ckt->CKTbreak && SAMETIME(time, TR + PW)) {
error = CKTsetBreak(ckt, basetime + tshift + TR + PW + TF);
if (error) return(error);
}
else if (ckt->CKTbreak && SAMETIME(time, TR + PW + TF)) {
error = CKTsetBreak(ckt, basetime + tshift + PER);
if (error) return(error);
}
} }
here->VSRCbreak_time = ckt->CKTtime + wait;
error = CKTsetBreak(ckt, here->VSRCbreak_time);
if (error)
return error;
/* If a timestep ends just before the break time,
* the break request may be ignored.
* Set threshold for requesting following break.
*/
here->VSRCbreak_time -= ckt->CKTminBreak;
} }
} }
break; break;
@ -179,25 +158,46 @@ VSRCaccept(CKTcircuit *ckt, GENmodel *inModel)
} }
break; break;
case PWL: { case PWL:
int i; if (ckt->CKTtime >= here->VSRCbreak_time) {
if(ckt->CKTtime < *(here->VSRCcoeffs)) { double time, end, period;
if(ckt->CKTbreak) { int i;
error = CKTsetBreak(ckt,*(here->VSRCcoeffs));
break; time = ckt->CKTtime - here->VSRCrdelay;
end =
here->VSRCcoeffs[here->VSRCfunctionOrder - 2];
if (time > end) {
if (here->VSRCrGiven) {
/* Repeating. */
period = end -
here->VSRCcoeffs[here->VSRCrBreakpt];
time -= period * floor(time / period);
} else {
here->VSRCbreak_time = ckt->CKTfinalTime;
break;
}
} }
}
for(i=0;i<(here->VSRCfunctionOrder/2)-1;i++) { for (i = 0;
if ( ckt->CKTbreak && AlmostEqualUlps(*(here->VSRCcoeffs+2*i), ckt->CKTtime, 3 ) ) { i < here->VSRCfunctionOrder;
error = CKTsetBreak(ckt, *(here->VSRCcoeffs+2*i+2)); i += 2) {
if(error) return(error); if (here->VSRCcoeffs[i] > time) {
goto bkptset; here->VSRCbreak_time =
ckt->CKTtime +
here->VSRCcoeffs[i] - time;
error = CKTsetBreak(ckt,
here->VSRCbreak_time);
if (error)
return error;
here->VSRCbreak_time -= ckt->CKTminBreak;
break;
}
} }
} }
break; break;
}
/**** tansient noise routines: /**** transient noise routines:
VNoi2 2 0 DC 0 TRNOISE(10n 0.5n 0 0n) : generate gaussian distributed noise VNoi2 2 0 DC 0 TRNOISE(10n 0.5n 0 0n) : generate gaussian distributed noise
rms value, time step, 0 0 rms value, time step, 0 0
VNoi1 1 0 DC 0 TRNOISE(0n 0.5n 1 10n) : generate 1/f noise VNoi1 1 0 DC 0 TRNOISE(0n 0.5n 1 10n) : generate 1/f noise
@ -205,6 +205,7 @@ VSRCaccept(CKTcircuit *ckt, GENmodel *inModel)
*/ */
case TRNOISE: { case TRNOISE: {
struct trnoise_state *state = here -> VSRCtrnoise_state; struct trnoise_state *state = here -> VSRCtrnoise_state;
double TS = state -> TS; double TS = state -> TS;
double RTSAM = state ->RTSAM; double RTSAM = state ->RTSAM;
@ -220,61 +221,55 @@ VSRCaccept(CKTcircuit *ckt, GENmodel *inModel)
fftFree(); fftFree();
} }
#endif #endif
if (TS > 0 && ckt->CKTtime >= here->VSRCbreak_time) {
if(ckt->CKTbreak) { if (here->VSRCbreak_time < 0.0)
here->VSRCbreak_time = TS;
int n = (int) floor(ckt->CKTtime / TS + 0.5); else
volatile double nearest = n * TS; here->VSRCbreak_time += TS;
error = CKTsetBreak(ckt, here->VSRCbreak_time);
if(AlmostEqualUlps(nearest, ckt->CKTtime, 3)) { if (error)
/* carefull calculate `next' return(error);
* make sure it is really identical here->VSRCbreak_time -= ckt->CKTminBreak;
* with the next calculated `nearest' value
*/
volatile double next = (n+1) * TS;
error = CKTsetBreak(ckt, next);
if(error)
return(error);
}
} }
if (RTSAM > 0) { if (RTSAM <= 0)
double RTScapTime = state->RTScapTime; break; /* No shot noise. */
double RTSemTime = state->RTSemTime;
double RTSCAPT = state->RTSCAPT;
double RTSEMT = state->RTSEMT;
if (ckt->CKTtime == 0) { if (ckt->CKTtime == 0) {
/* initialzing here again needed for repeated calls to tran command */ /* initialzing here again needed for repeated calls to tran command */
state->RTScapTime = RTScapTime = exprand(RTSCAPT); state->RTScapTime = exprand(state->RTSCAPT);
state->RTSemTime = RTSemTime = RTScapTime + exprand(RTSEMT); state->RTSemTime =
state->RTScapTime + exprand(state->RTSEMT);
error = CKTsetBreak(ckt, state->RTScapTime);
if(error)
return(error);
break;
}
if (ckt->CKTbreak) { /* Break handling code ends a timestep close to
error = CKTsetBreak(ckt, RTScapTime); * the requested time.
if(error) */
return(error);
}
}
if(AlmostEqualUlps(RTScapTime, ckt->CKTtime, 3)) { if (ckt->CKTtime >=
if (ckt->CKTbreak) { state->RTScapTime - ckt->CKTminBreak &&
error = CKTsetBreak(ckt, RTSemTime); ckt->CKTtime <=
if(error) state->RTScapTime + ckt->CKTminBreak) {
return(error); error = CKTsetBreak(ckt, state->RTSemTime);
} if(error)
} return(error);
}
if(AlmostEqualUlps(RTSemTime, ckt->CKTtime, 3)) { if (ckt->CKTtime >=
/* new values */ state->RTSemTime - ckt->CKTminBreak) {
RTScapTime = here -> VSRCtrnoise_state ->RTScapTime = ckt->CKTtime + exprand(RTSCAPT); /* new values */
here -> VSRCtrnoise_state ->RTSemTime = RTScapTime + exprand(RTSEMT);
if (ckt->CKTbreak) { state->RTScapTime =
error = CKTsetBreak(ckt, RTScapTime); ckt->CKTtime + exprand(state->RTSCAPT);
if(error) state->RTSemTime =
return(error); state->RTScapTime + exprand(state->RTSEMT);
} error = CKTsetBreak(ckt, state->RTScapTime);
} if(error)
return(error);
} }
} }
break; break;
@ -286,30 +281,22 @@ VSRCaccept(CKTcircuit *ckt, GENmodel *inModel)
if (ckt->CKTtime == 0 && TD > 0) { if (ckt->CKTtime == 0 && TD > 0) {
error = CKTsetBreak(ckt, TD); error = CKTsetBreak(ckt, TD);
here->VSRCbreak_time = TD;
if (error) if (error)
return(error); return(error);
break;
} }
double time = ckt->CKTtime - TD; if (ckt->CKTtime >= here->VSRCbreak_time) {
if (here->VSRCbreak_time < 0.0)
if (time < 0) break; here->VSRCbreak_time = TS;
else
if(ckt->CKTbreak) { here->VSRCbreak_time += TS;
error = CKTsetBreak(ckt, here->VSRCbreak_time);
int n = (int) floor(time / TS + 0.5); if (error)
volatile double nearest = n * TS; return(error);
here->VSRCbreak_time -= ckt->CKTminBreak;
if(AlmostEqualUlps(nearest, time, 10)) { state->value = trrandom_state_get(state);
/* carefully calculate `next'
* make sure it is really identical
* with the next calculated `nearest' value
*/
volatile double next = (n+1) * TS + TD;
error = CKTsetBreak(ckt, next);
if(error)
return(error);
state->value = trrandom_state_get(state);
}
} }
} }
break; break;
@ -323,7 +310,6 @@ VSRCaccept(CKTcircuit *ckt, GENmodel *inModel)
} // switch } // switch
} // if ... else } // if ... else
bkptset: ;
} // for } // for
} // for } // for

View File

@ -50,6 +50,7 @@ typedef struct sVSRCinstance {
int VSRCfunctionType; /* code number of function type for source */ int VSRCfunctionType; /* code number of function type for source */
int VSRCfunctionOrder; /* order of the function for the source */ int VSRCfunctionOrder; /* order of the function for the source */
int VSRCrBreakpt; /* pwl repeat breakpoint index */ int VSRCrBreakpt; /* pwl repeat breakpoint index */
double VSRCbreak_time; /* time of most-recent breakpoint */
double *VSRCcoeffs; /* pointer to array of coefficients */ double *VSRCcoeffs; /* pointer to array of coefficients */
double VSRCdcValue; /* DC and TRANSIENT value of source */ double VSRCdcValue; /* DC and TRANSIENT value of source */

View File

@ -298,43 +298,45 @@ VSRCload(GENmodel *inModel, CKTcircuit *ckt)
break; break;
case PWL: { case PWL: {
int i = 0, num_repeat = 0, ii = 0; int i;
double foo, repeat_time = 0, end_time, breakpt_time, itime; double end_time, itime;
time -= here->VSRCrdelay; time -= here->VSRCrdelay;
if (time < here->VSRCcoeffs[0]) {
if(time < *(here->VSRCcoeffs)) { value = here->VSRCcoeffs[1];
foo = *(here->VSRCcoeffs + 1) ; value = value;
value = foo; break;
goto loadDone;
} }
do { end_time =
for(i=ii ; i<(here->VSRCfunctionOrder/2)-1; i++ ) { here->VSRCcoeffs[here->VSRCfunctionOrder - 2];
itime = *(here->VSRCcoeffs+2*i); if (time > end_time) {
if ( AlmostEqualUlps(itime+repeat_time, time, 3 )) { double period;
foo = *(here->VSRCcoeffs+2*i+1);
value = foo; if (here->VSRCrGiven) {
goto loadDone; /* Repeating. */
} else if ( (*(here->VSRCcoeffs+2*i)+repeat_time < time)
&& (*(here->VSRCcoeffs+2*(i+1))+repeat_time > time) ) { period = end_time -
foo = *(here->VSRCcoeffs+2*i+1) + (((time-(*(here->VSRCcoeffs+2*i)+repeat_time))/ here->VSRCcoeffs[here->VSRCrBreakpt];
(*(here->VSRCcoeffs+2*(i+1)) - *(here->VSRCcoeffs+2*i))) * time -= period * floor(time / period);
(*(here->VSRCcoeffs+2*i+3) - *(here->VSRCcoeffs+2*i+1))); } else {
value = foo; break;
goto loadDone;
}
} }
foo = *(here->VSRCcoeffs+ here->VSRCfunctionOrder-1) ; }
value = foo;
if ( !here->VSRCrGiven ) goto loadDone; for (i = 2; i < here->VSRCfunctionOrder; i += 2) {
itime = here->VSRCcoeffs[i];
end_time = *(here->VSRCcoeffs + here->VSRCfunctionOrder-2); if (itime >= time) {
breakpt_time = *(here->VSRCcoeffs + here->VSRCrBreakpt); time -= here->VSRCcoeffs[i - 2];
repeat_time = end_time + (end_time - breakpt_time)*num_repeat++ - breakpt_time; time /= here->VSRCcoeffs[i] -
ii = here->VSRCrBreakpt/2; here->VSRCcoeffs[i - 2];
} while ( here->VSRCrGiven ); value = here->VSRCcoeffs[i - 1];
value += time *
( here->VSRCcoeffs[i + 1] -
here->VSRCcoeffs[i - 1]);
break;
}
}
break; break;
} }
@ -418,7 +420,6 @@ VNoi3 3 0 DC 0 TRNOISE(0 0 0 0 15m 22u 50u) : generate RTS noise
} // switch } // switch
} // else (line 48) } // else (line 48)
loadDone:
/* gtri - begin - wbk - modify for supply ramping option */ /* gtri - begin - wbk - modify for supply ramping option */
#ifdef XSPICE_EXP #ifdef XSPICE_EXP

View File

@ -31,6 +31,7 @@ VSRCsetup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt, int *state)
for (here = VSRCinstances(model); here != NULL ; for (here = VSRCinstances(model); here != NULL ;
here=VSRCnextInstance(here)) { here=VSRCnextInstance(here)) {
here->VSRCbreak_time = -1.0; // To set initial breakpoint
if(here->VSRCposNode == here->VSRCnegNode) { if(here->VSRCposNode == here->VSRCnegNode) {
SPfrontEnd->IFerrorf (ERR_FATAL, SPfrontEnd->IFerrorf (ERR_FATAL,
"instance %s is a shorted VSRC", here->VSRCname); "instance %s is a shorted VSRC", here->VSRCname);