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 */
|
||||
|
||||
#define SAMETIME(a,b) (fabs((a)-(b))<= TIMETOL * PW)
|
||||
#define TIMETOL 1e-7
|
||||
|
||||
int
|
||||
VSRCaccept(CKTcircuit *ckt, GENmodel *inModel)
|
||||
/* set up the breakpoint table. */
|
||||
|
|
@ -51,7 +48,6 @@ VSRCaccept(CKTcircuit *ckt, GENmodel *inModel)
|
|||
case PULSE: {
|
||||
|
||||
double TD, TR, TF, PW, PER;
|
||||
double tshift;
|
||||
double time = 0.;
|
||||
double basetime = 0;
|
||||
double tmax = 1e99;
|
||||
|
|
@ -79,7 +75,6 @@ VSRCaccept(CKTcircuit *ckt, GENmodel *inModel)
|
|||
|
||||
/* offset time by delay */
|
||||
time = ckt->CKTtime - TD;
|
||||
tshift = TD;
|
||||
|
||||
if (newcompat.xs) {
|
||||
/* normalize phase to 0 - 360° */
|
||||
|
|
@ -90,71 +85,55 @@ VSRCaccept(CKTcircuit *ckt, GENmodel *inModel)
|
|||
while (deltat > 0)
|
||||
deltat -= PER;
|
||||
time += deltat;
|
||||
tshift = TD - deltat;
|
||||
}
|
||||
else if (PHASE > 0.0) {
|
||||
} else if (PHASE > 0.0) {
|
||||
tmax = PHASE * PER;
|
||||
if (time > tmax)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!newcompat.xs && time > tmax) {
|
||||
/* Do nothing */
|
||||
}
|
||||
else {
|
||||
if (ckt->CKTtime >= here->VSRCbreak_time) {
|
||||
double wait;
|
||||
|
||||
if (time >= PER) {
|
||||
/* repeating signal - figure out where we are */
|
||||
/* in period */
|
||||
/* Repeating signal: where in period are we? */
|
||||
|
||||
basetime = PER * floor(time / PER);
|
||||
time -= basetime;
|
||||
}
|
||||
|
||||
if (time <= 0.0 || time >= TR + PW + TF) {
|
||||
if (ckt->CKTbreak && SAMETIME(time, 0.0)) {
|
||||
error = CKTsetBreak(ckt, basetime + TR + tshift);
|
||||
if (error) return(error);
|
||||
}
|
||||
else if (ckt->CKTbreak && SAMETIME(TR + PW + TF, time)) {
|
||||
error = CKTsetBreak(ckt, basetime + PER + tshift);
|
||||
if (error) return(error);
|
||||
}
|
||||
else if (ckt->CKTbreak && (time == -tshift)) {
|
||||
error = CKTsetBreak(ckt, basetime + tshift);
|
||||
if (error) return(error);
|
||||
}
|
||||
else if (ckt->CKTbreak && SAMETIME(PER, time)) {
|
||||
error = CKTsetBreak(ckt, basetime + tshift + TR + PER);
|
||||
if (error) return(error);
|
||||
}
|
||||
}
|
||||
else if (time >= TR && time <= TR + PW) {
|
||||
if (ckt->CKTbreak && SAMETIME(time, TR)) {
|
||||
error = CKTsetBreak(ckt, basetime + tshift + TR + PW);
|
||||
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);
|
||||
}
|
||||
/* Set next breakpoint. */
|
||||
|
||||
if (time < 0.0) {
|
||||
/* Await first pulse */
|
||||
|
||||
wait = -time;
|
||||
} else if (time < TR) {
|
||||
/* Wait for end of rise. */
|
||||
|
||||
wait = TR - time;
|
||||
} else if (time < TR + PW) {
|
||||
/* Wait for fall. */
|
||||
|
||||
wait = TR + PW - time;
|
||||
} else if (time < TR + PW + TF) {
|
||||
/* Wait for end of fall. */
|
||||
|
||||
wait = TR + PW + TF - time;
|
||||
} else {
|
||||
/* Wait for next pulse. */
|
||||
wait = PER - time;
|
||||
}
|
||||
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;
|
||||
|
|
@ -179,25 +158,46 @@ VSRCaccept(CKTcircuit *ckt, GENmodel *inModel)
|
|||
}
|
||||
break;
|
||||
|
||||
case PWL: {
|
||||
int i;
|
||||
if(ckt->CKTtime < *(here->VSRCcoeffs)) {
|
||||
if(ckt->CKTbreak) {
|
||||
error = CKTsetBreak(ckt,*(here->VSRCcoeffs));
|
||||
break;
|
||||
case PWL:
|
||||
if (ckt->CKTtime >= here->VSRCbreak_time) {
|
||||
double time, end, period;
|
||||
int i;
|
||||
|
||||
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++) {
|
||||
if ( ckt->CKTbreak && AlmostEqualUlps(*(here->VSRCcoeffs+2*i), ckt->CKTtime, 3 ) ) {
|
||||
error = CKTsetBreak(ckt, *(here->VSRCcoeffs+2*i+2));
|
||||
if(error) return(error);
|
||||
goto bkptset;
|
||||
|
||||
for (i = 0;
|
||||
i < here->VSRCfunctionOrder;
|
||||
i += 2) {
|
||||
if (here->VSRCcoeffs[i] > time) {
|
||||
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;
|
||||
}
|
||||
|
||||
/**** tansient noise routines:
|
||||
/**** transient noise routines:
|
||||
VNoi2 2 0 DC 0 TRNOISE(10n 0.5n 0 0n) : generate gaussian distributed noise
|
||||
rms value, time step, 0 0
|
||||
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: {
|
||||
|
||||
|
||||
struct trnoise_state *state = here -> VSRCtrnoise_state;
|
||||
double TS = state -> TS;
|
||||
double RTSAM = state ->RTSAM;
|
||||
|
|
@ -220,61 +221,55 @@ VSRCaccept(CKTcircuit *ckt, GENmodel *inModel)
|
|||
fftFree();
|
||||
}
|
||||
#endif
|
||||
|
||||
if(ckt->CKTbreak) {
|
||||
|
||||
int n = (int) floor(ckt->CKTtime / TS + 0.5);
|
||||
volatile double nearest = n * TS;
|
||||
|
||||
if(AlmostEqualUlps(nearest, ckt->CKTtime, 3)) {
|
||||
/* carefull calculate `next'
|
||||
* make sure it is really identical
|
||||
* with the next calculated `nearest' value
|
||||
*/
|
||||
volatile double next = (n+1) * TS;
|
||||
error = CKTsetBreak(ckt, next);
|
||||
if(error)
|
||||
return(error);
|
||||
}
|
||||
if (TS > 0 && ckt->CKTtime >= here->VSRCbreak_time) {
|
||||
if (here->VSRCbreak_time < 0.0)
|
||||
here->VSRCbreak_time = TS;
|
||||
else
|
||||
here->VSRCbreak_time += TS;
|
||||
error = CKTsetBreak(ckt, here->VSRCbreak_time);
|
||||
if (error)
|
||||
return(error);
|
||||
here->VSRCbreak_time -= ckt->CKTminBreak;
|
||||
}
|
||||
|
||||
if (RTSAM > 0) {
|
||||
double RTScapTime = state->RTScapTime;
|
||||
double RTSemTime = state->RTSemTime;
|
||||
double RTSCAPT = state->RTSCAPT;
|
||||
double RTSEMT = state->RTSEMT;
|
||||
if (RTSAM <= 0)
|
||||
break; /* No shot noise. */
|
||||
|
||||
if (ckt->CKTtime == 0) {
|
||||
/* initialzing here again needed for repeated calls to tran command */
|
||||
state->RTScapTime = RTScapTime = exprand(RTSCAPT);
|
||||
state->RTSemTime = RTSemTime = RTScapTime + exprand(RTSEMT);
|
||||
if (ckt->CKTtime == 0) {
|
||||
/* initialzing here again needed for repeated calls to tran command */
|
||||
state->RTScapTime = exprand(state->RTSCAPT);
|
||||
state->RTSemTime =
|
||||
state->RTScapTime + exprand(state->RTSEMT);
|
||||
error = CKTsetBreak(ckt, state->RTScapTime);
|
||||
if(error)
|
||||
return(error);
|
||||
break;
|
||||
}
|
||||
|
||||
if (ckt->CKTbreak) {
|
||||
error = CKTsetBreak(ckt, RTScapTime);
|
||||
if(error)
|
||||
return(error);
|
||||
}
|
||||
}
|
||||
/* Break handling code ends a timestep close to
|
||||
* the requested time.
|
||||
*/
|
||||
|
||||
if(AlmostEqualUlps(RTScapTime, ckt->CKTtime, 3)) {
|
||||
if (ckt->CKTbreak) {
|
||||
error = CKTsetBreak(ckt, RTSemTime);
|
||||
if(error)
|
||||
return(error);
|
||||
}
|
||||
}
|
||||
if (ckt->CKTtime >=
|
||||
state->RTScapTime - ckt->CKTminBreak &&
|
||||
ckt->CKTtime <=
|
||||
state->RTScapTime + ckt->CKTminBreak) {
|
||||
error = CKTsetBreak(ckt, state->RTSemTime);
|
||||
if(error)
|
||||
return(error);
|
||||
}
|
||||
|
||||
if(AlmostEqualUlps(RTSemTime, ckt->CKTtime, 3)) {
|
||||
/* new values */
|
||||
RTScapTime = here -> VSRCtrnoise_state ->RTScapTime = ckt->CKTtime + exprand(RTSCAPT);
|
||||
here -> VSRCtrnoise_state ->RTSemTime = RTScapTime + exprand(RTSEMT);
|
||||
if (ckt->CKTtime >=
|
||||
state->RTSemTime - ckt->CKTminBreak) {
|
||||
/* new values */
|
||||
|
||||
if (ckt->CKTbreak) {
|
||||
error = CKTsetBreak(ckt, RTScapTime);
|
||||
if(error)
|
||||
return(error);
|
||||
}
|
||||
}
|
||||
state->RTScapTime =
|
||||
ckt->CKTtime + exprand(state->RTSCAPT);
|
||||
state->RTSemTime =
|
||||
state->RTScapTime + exprand(state->RTSEMT);
|
||||
error = CKTsetBreak(ckt, state->RTScapTime);
|
||||
if(error)
|
||||
return(error);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
|
@ -286,30 +281,22 @@ VSRCaccept(CKTcircuit *ckt, GENmodel *inModel)
|
|||
|
||||
if (ckt->CKTtime == 0 && TD > 0) {
|
||||
error = CKTsetBreak(ckt, TD);
|
||||
here->VSRCbreak_time = TD;
|
||||
if (error)
|
||||
return(error);
|
||||
break;
|
||||
}
|
||||
|
||||
double time = ckt->CKTtime - TD;
|
||||
|
||||
if (time < 0) break;
|
||||
|
||||
if(ckt->CKTbreak) {
|
||||
|
||||
int n = (int) floor(time / TS + 0.5);
|
||||
volatile double nearest = n * TS;
|
||||
|
||||
if(AlmostEqualUlps(nearest, time, 10)) {
|
||||
/* 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);
|
||||
}
|
||||
if (ckt->CKTtime >= here->VSRCbreak_time) {
|
||||
if (here->VSRCbreak_time < 0.0)
|
||||
here->VSRCbreak_time = TS;
|
||||
else
|
||||
here->VSRCbreak_time += TS;
|
||||
error = CKTsetBreak(ckt, here->VSRCbreak_time);
|
||||
if (error)
|
||||
return(error);
|
||||
here->VSRCbreak_time -= ckt->CKTminBreak;
|
||||
state->value = trrandom_state_get(state);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
|
@ -323,7 +310,6 @@ VSRCaccept(CKTcircuit *ckt, GENmodel *inModel)
|
|||
|
||||
} // switch
|
||||
} // if ... else
|
||||
bkptset: ;
|
||||
} // for
|
||||
} // for
|
||||
|
||||
|
|
|
|||
|
|
@ -50,6 +50,7 @@ typedef struct sVSRCinstance {
|
|||
int VSRCfunctionType; /* code number of function type for source */
|
||||
int VSRCfunctionOrder; /* order of the function for the source */
|
||||
int VSRCrBreakpt; /* pwl repeat breakpoint index */
|
||||
double VSRCbreak_time; /* time of most-recent breakpoint */
|
||||
double *VSRCcoeffs; /* pointer to array of coefficients */
|
||||
|
||||
double VSRCdcValue; /* DC and TRANSIENT value of source */
|
||||
|
|
|
|||
|
|
@ -298,43 +298,45 @@ VSRCload(GENmodel *inModel, CKTcircuit *ckt)
|
|||
break;
|
||||
|
||||
case PWL: {
|
||||
int i = 0, num_repeat = 0, ii = 0;
|
||||
double foo, repeat_time = 0, end_time, breakpt_time, itime;
|
||||
int i;
|
||||
double end_time, itime;
|
||||
|
||||
time -= here->VSRCrdelay;
|
||||
|
||||
if(time < *(here->VSRCcoeffs)) {
|
||||
foo = *(here->VSRCcoeffs + 1) ;
|
||||
value = foo;
|
||||
goto loadDone;
|
||||
if (time < here->VSRCcoeffs[0]) {
|
||||
value = here->VSRCcoeffs[1];
|
||||
value = value;
|
||||
break;
|
||||
}
|
||||
|
||||
do {
|
||||
for(i=ii ; i<(here->VSRCfunctionOrder/2)-1; i++ ) {
|
||||
itime = *(here->VSRCcoeffs+2*i);
|
||||
if ( AlmostEqualUlps(itime+repeat_time, time, 3 )) {
|
||||
foo = *(here->VSRCcoeffs+2*i+1);
|
||||
value = foo;
|
||||
goto loadDone;
|
||||
} else if ( (*(here->VSRCcoeffs+2*i)+repeat_time < time)
|
||||
&& (*(here->VSRCcoeffs+2*(i+1))+repeat_time > time) ) {
|
||||
foo = *(here->VSRCcoeffs+2*i+1) + (((time-(*(here->VSRCcoeffs+2*i)+repeat_time))/
|
||||
(*(here->VSRCcoeffs+2*(i+1)) - *(here->VSRCcoeffs+2*i))) *
|
||||
(*(here->VSRCcoeffs+2*i+3) - *(here->VSRCcoeffs+2*i+1)));
|
||||
value = foo;
|
||||
goto loadDone;
|
||||
}
|
||||
end_time =
|
||||
here->VSRCcoeffs[here->VSRCfunctionOrder - 2];
|
||||
if (time > end_time) {
|
||||
double period;
|
||||
|
||||
if (here->VSRCrGiven) {
|
||||
/* Repeating. */
|
||||
|
||||
period = end_time -
|
||||
here->VSRCcoeffs[here->VSRCrBreakpt];
|
||||
time -= period * floor(time / period);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
foo = *(here->VSRCcoeffs+ here->VSRCfunctionOrder-1) ;
|
||||
value = foo;
|
||||
}
|
||||
|
||||
if ( !here->VSRCrGiven ) goto loadDone;
|
||||
|
||||
end_time = *(here->VSRCcoeffs + here->VSRCfunctionOrder-2);
|
||||
breakpt_time = *(here->VSRCcoeffs + here->VSRCrBreakpt);
|
||||
repeat_time = end_time + (end_time - breakpt_time)*num_repeat++ - breakpt_time;
|
||||
ii = here->VSRCrBreakpt/2;
|
||||
} while ( here->VSRCrGiven );
|
||||
for (i = 2; i < here->VSRCfunctionOrder; i += 2) {
|
||||
itime = here->VSRCcoeffs[i];
|
||||
if (itime >= time) {
|
||||
time -= here->VSRCcoeffs[i - 2];
|
||||
time /= here->VSRCcoeffs[i] -
|
||||
here->VSRCcoeffs[i - 2];
|
||||
value = here->VSRCcoeffs[i - 1];
|
||||
value += time *
|
||||
( here->VSRCcoeffs[i + 1] -
|
||||
here->VSRCcoeffs[i - 1]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -418,7 +420,6 @@ VNoi3 3 0 DC 0 TRNOISE(0 0 0 0 15m 22u 50u) : generate RTS noise
|
|||
|
||||
} // switch
|
||||
} // else (line 48)
|
||||
loadDone:
|
||||
|
||||
/* gtri - begin - wbk - modify for supply ramping option */
|
||||
#ifdef XSPICE_EXP
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ VSRCsetup(SMPmatrix *matrix, GENmodel *inModel, CKTcircuit *ckt, int *state)
|
|||
for (here = VSRCinstances(model); here != NULL ;
|
||||
here=VSRCnextInstance(here)) {
|
||||
|
||||
here->VSRCbreak_time = -1.0; // To set initial breakpoint
|
||||
if(here->VSRCposNode == here->VSRCnegNode) {
|
||||
SPfrontEnd->IFerrorf (ERR_FATAL,
|
||||
"instance %s is a shorted VSRC", here->VSRCname);
|
||||
|
|
|
|||
Loading…
Reference in New Issue