diff --git a/src/spicelib/devices/vsrc/vsrcacct.c b/src/spicelib/devices/vsrc/vsrcacct.c index 1ec386681..0be45f8e2 100644 --- a/src/spicelib/devices/vsrc/vsrcacct.c +++ b/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(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 diff --git a/src/spicelib/devices/vsrc/vsrcdefs.h b/src/spicelib/devices/vsrc/vsrcdefs.h index 15c8b6951..346e75552 100644 --- a/src/spicelib/devices/vsrc/vsrcdefs.h +++ b/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 */ diff --git a/src/spicelib/devices/vsrc/vsrcload.c b/src/spicelib/devices/vsrc/vsrcload.c index beee1c99c..a4d4f73c6 100644 --- a/src/spicelib/devices/vsrc/vsrcload.c +++ b/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; - } + 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 diff --git a/src/spicelib/devices/vsrc/vsrcset.c b/src/spicelib/devices/vsrc/vsrcset.c index 18d7764b7..3659e9755 100644 --- a/src/spicelib/devices/vsrc/vsrcset.c +++ b/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);