Fix Bug #607 -
"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:
parent
50a9daf24a
commit
ad5bb9eb8d
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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 */
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue