Browse Source

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.
pre-master-46
Giles Atkinson 3 years ago
committed by Holger Vogt
parent
commit
ad5bb9eb8d
  1. 274
      src/spicelib/devices/vsrc/vsrcacct.c
  2. 1
      src/spicelib/devices/vsrc/vsrcdefs.h
  3. 65
      src/spicelib/devices/vsrc/vsrcload.c
  4. 1
      src/spicelib/devices/vsrc/vsrcset.c

274
src/spicelib/devices/vsrc/vsrcacct.c

@ -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 (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(ckt->CKTbreak) {
int n = (int) floor(ckt->CKTtime / TS + 0.5);
volatile double nearest = n * TS;
if (RTSAM <= 0)
break; /* No shot noise. */
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 (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 (RTSAM > 0) {
double RTScapTime = state->RTScapTime;
double RTSemTime = state->RTSemTime;
double RTSCAPT = state->RTSCAPT;
double RTSEMT = state->RTSEMT;
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->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

1
src/spicelib/devices/vsrc/vsrcdefs.h

@ -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 */

65
src/spicelib/devices/vsrc/vsrcload.c

@ -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;
}
}
foo = *(here->VSRCcoeffs+ here->VSRCfunctionOrder-1) ;
value = foo;
end_time =
here->VSRCcoeffs[here->VSRCfunctionOrder - 2];
if (time > end_time) {
double period;
if ( !here->VSRCrGiven ) goto loadDone;
if (here->VSRCrGiven) {
/* Repeating. */
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 );
period = end_time -
here->VSRCcoeffs[here->VSRCrBreakpt];
time -= period * floor(time / period);
} else {
break;
}
}
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

1
src/spicelib/devices/vsrc/vsrcset.c

@ -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…
Cancel
Save