You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1607 lines
60 KiB
1607 lines
60 KiB
/**********
|
|
Author: 2010-05 Stefano Perticaroli ``spertica''
|
|
First Review: 2012-02 Francesco Lannutti and Stefano Perticaroli ``spertica''
|
|
Second Review: 2012-10 Stefano Perticaroli ``spertica'' and Francesco Lannutti
|
|
**********/
|
|
|
|
/* Include files for the PSS analysis */
|
|
#include "ngspice/ngspice.h"
|
|
#include "ngspice/cktdefs.h"
|
|
#include "cktaccept.h"
|
|
#include "ngspice/pssdefs.h"
|
|
#include "ngspice/sperror.h"
|
|
#include "ngspice/fteext.h"
|
|
|
|
#ifdef XSPICE
|
|
/* gtri - add - wbk - Add headers */
|
|
#include "ngspice/miftypes.h"
|
|
|
|
#include "ngspice/evt.h"
|
|
#include "ngspice/mif.h"
|
|
#include "ngspice/evtproto.h"
|
|
#include "ngspice/ipctiein.h"
|
|
/* gtri - end - wbk - Add headers */
|
|
#endif
|
|
|
|
#ifdef CLUSTER
|
|
#include "ngspice/cluster.h"
|
|
#endif
|
|
|
|
#ifdef HAS_WINDOWS /* hvogt 10.03.99, nach W. Mues */
|
|
void SetAnalyse(char * Analyse, int Percent);
|
|
#endif
|
|
|
|
|
|
#define INIT_STATS() \
|
|
do { \
|
|
startTime = SPfrontEnd->IFseconds(); \
|
|
startIters = ckt->CKTstat->STATnumIter; \
|
|
startdTime = ckt->CKTstat->STATdecompTime; \
|
|
startsTime = ckt->CKTstat->STATsolveTime; \
|
|
startlTime = ckt->CKTstat->STATloadTime; \
|
|
startkTime = ckt->CKTstat->STATsyncTime; \
|
|
} while(0)
|
|
|
|
#define UPDATE_STATS(analysis) \
|
|
do { \
|
|
ckt->CKTcurrentAnalysis = analysis; \
|
|
ckt->CKTstat->STATtranTime += SPfrontEnd->IFseconds() - startTime; \
|
|
ckt->CKTstat->STATtranIter += ckt->CKTstat->STATnumIter - startIters; \
|
|
ckt->CKTstat->STATtranDecompTime += ckt->CKTstat->STATdecompTime - startdTime; \
|
|
ckt->CKTstat->STATtranSolveTime += ckt->CKTstat->STATsolveTime - startsTime; \
|
|
ckt->CKTstat->STATtranLoadTime += ckt->CKTstat->STATloadTime - startlTime; \
|
|
ckt->CKTstat->STATtranSyncTime += ckt->CKTstat->STATsyncTime - startkTime; \
|
|
} while(0)
|
|
|
|
|
|
/* Define some useful macro */
|
|
#define HISTORY 1024
|
|
#define GF_LAST 313
|
|
|
|
|
|
static int
|
|
DFT(long int, int, double *, double *, double *, double, double *, double *, double *, double *, double *);
|
|
|
|
|
|
int
|
|
DCpss(CKTcircuit *ckt,
|
|
int restart) /* forced restart flag */
|
|
{
|
|
PSSan *job = (PSSan *) ckt->CKTcurJob;
|
|
|
|
int i;
|
|
double olddelta;
|
|
double delta;
|
|
double newdelta;
|
|
double *temp;
|
|
double startdTime;
|
|
double startsTime;
|
|
double startlTime;
|
|
double startkTime;
|
|
double startTime;
|
|
int startIters;
|
|
int converged;
|
|
int firsttime;
|
|
int error;
|
|
int save_order;
|
|
long save_mode;
|
|
IFuid timeUid;
|
|
IFuid *nameList;
|
|
int numNames;
|
|
double maxstepsize = 0.0;
|
|
|
|
int ltra_num;
|
|
CKTnode *node;
|
|
#ifdef XSPICE
|
|
/* gtri - add - wbk - 12/19/90 - Add IPC stuff */
|
|
Ipc_Boolean_t ipc_firsttime = IPC_TRUE;
|
|
Ipc_Boolean_t ipc_secondtime = IPC_FALSE;
|
|
Ipc_Boolean_t ipc_delta_cut = IPC_FALSE;
|
|
double ipc_last_time = 0.0;
|
|
double ipc_last_delta = 0.0;
|
|
/* gtri - end - wbk - 12/19/90 - Add IPC stuff */
|
|
#endif
|
|
#ifdef CLUSTER
|
|
int redostep;
|
|
#endif
|
|
|
|
/* New variables */
|
|
int j, oscnNode;
|
|
IFuid freqUid;
|
|
|
|
enum {STABILIZATION, SHOOTING, PSS} pss_state = STABILIZATION;
|
|
|
|
double err = 0, predsum = 0 ;
|
|
double time_temp = 0, gf_history [HISTORY], rr_history [HISTORY], predsum_history [HISTORY], nextstep ;
|
|
int msize, shooting_cycle_counter = 0;
|
|
double *RHS_copy_se, *RHS_copy_der, *RHS_derivative, *pred, err_0 = HUGE_VAL ;
|
|
double time_err_min_1 = 0, time_err_min_0 = 0, err_min_0 = HUGE_VAL, err_min_1 = 0 ;
|
|
double err_1 = 0, err_max = HUGE_VAL ;
|
|
int pss_points_cycle = 0, dynamic_test = 0 ;
|
|
double gf_last_0 = HUGE_VAL, gf_last_1 = GF_LAST ;
|
|
double thd = 0 ;
|
|
double *psstimes, *pssvalues;
|
|
double *RHS_max, *RHS_min, *err_conv ;
|
|
|
|
/* Francesco Lannutti's MOD */
|
|
/* Stuff needed by frequency estimation reiteration, based on the DFT result */
|
|
int position;
|
|
double max_freq;
|
|
|
|
|
|
/* Print some useful information */
|
|
fprintf (stderr, "Periodic Steady State Analysis Started\n\n") ;
|
|
fprintf (stderr, "PSS Guessed Frequency %g\n", ckt->CKTguessedFreq) ;
|
|
fprintf (stderr, "PSS Points %ld\n", ckt->CKTpsspoints) ;
|
|
fprintf (stderr, "PSS Harmonics number %d\n", ckt->CKTharms) ;
|
|
fprintf (stderr, "PSS Steady Coefficient %g\n", ckt->CKTsteady_coeff) ;
|
|
fprintf (stderr, "PSS sc_iter %d\n", ckt->CKTsc_iter) ;
|
|
fprintf (stderr, "PSS Stabilization Time %g\n", ckt->CKTstabTime) ;
|
|
|
|
|
|
oscnNode = job->PSSoscNode->number ;
|
|
|
|
|
|
/* Variables and memory initialization */
|
|
|
|
for (i = 0 ; i < HISTORY ; i++)
|
|
{
|
|
rr_history [i] = 0.0 ;
|
|
gf_history [i] = 0.0 ;
|
|
}
|
|
|
|
msize = SMPmatSize (ckt->CKTmatrix) ;
|
|
RHS_copy_se = TMALLOC (double, msize) ; /* Set the current RHS reference for next Shooting Evaluation */
|
|
RHS_copy_der = TMALLOC (double, msize) ; /* Used to compute current Derivative */
|
|
RHS_derivative = TMALLOC (double, msize) ;
|
|
pred = TMALLOC (double, msize) ;
|
|
RHS_max = TMALLOC (double, msize) ;
|
|
RHS_min = TMALLOC (double, msize) ;
|
|
err_conv = TMALLOC (double, msize) ;
|
|
|
|
for (i = 0 ; i < msize ; i++)
|
|
{
|
|
RHS_copy_se [i] = 0.0 ;
|
|
RHS_copy_der [i] = 0.0 ;
|
|
RHS_derivative [i] = 0.0 ;
|
|
pred [i] = 0.0 ;
|
|
}
|
|
|
|
psstimes = TMALLOC (double, ckt->CKTpsspoints + 1) ;
|
|
pssvalues = TMALLOC (double, msize * (ckt->CKTpsspoints + 1)) ;
|
|
|
|
for (i = 0 ; i < ckt->CKTpsspoints + 1 ; i++)
|
|
psstimes [i] = 0.0 ;
|
|
|
|
for (i = 0 ; i < msize * (ckt->CKTpsspoints + 1) ; i++)
|
|
pssvalues [i] = 0.0 ;
|
|
|
|
/* Delta timestep and circuit time setup */
|
|
delta = ckt->CKTstep ;
|
|
ckt->CKTtime = ckt->CKTinitTime ;
|
|
ckt->CKTfinalTime = ckt->CKTstabTime ;
|
|
|
|
/* Starting PSS Algorithm, based on Transient Analysis */
|
|
if(restart || ckt->CKTtime == 0) {
|
|
delta = MIN (1 / ckt->CKTguessedFreq / 100, ckt->CKTstep) ;
|
|
|
|
#ifdef STEPDEBUG
|
|
fprintf (stderr, "delta = %g finalTime/200: %g CKTstep: %g\n", delta, ckt->CKTfinalTime / 200, ckt->CKTstep) ;
|
|
#endif
|
|
/* begin LTRA code addition */
|
|
if (ckt->CKTtimePoints != NULL)
|
|
FREE(ckt->CKTtimePoints);
|
|
|
|
if (ckt->CKTstep >= ckt->CKTmaxStep)
|
|
maxstepsize = ckt->CKTstep;
|
|
else
|
|
maxstepsize = ckt->CKTmaxStep;
|
|
|
|
ckt->CKTsizeIncr = 10;
|
|
ckt->CKTtimeIndex = -1; /* before the DC soln has been stored */
|
|
ckt->CKTtimeListSize = (int)(1 / ckt->CKTguessedFreq / maxstepsize + 0.5);
|
|
ltra_num = CKTtypelook("LTRA");
|
|
if (ltra_num >= 0 && ckt->CKThead[ltra_num] != NULL)
|
|
ckt->CKTtimePoints = NEWN(double, ckt->CKTtimeListSize);
|
|
/* end LTRA code addition */
|
|
|
|
/* Breakpoints initialization */
|
|
if(ckt->CKTbreaks) FREE(ckt->CKTbreaks);
|
|
ckt->CKTbreaks = TMALLOC(double, 2);
|
|
if(ckt->CKTbreaks == NULL) return(E_NOMEM);
|
|
ckt->CKTbreaks[0] = 0;
|
|
ckt->CKTbreaks[1] = ckt->CKTfinalTime;
|
|
ckt->CKTbreakSize = 2;
|
|
|
|
#ifdef XSPICE
|
|
/* gtri - begin - wbk - 12/19/90 - Modify setting of CKTminBreak */
|
|
/* if (ckt->CKTminBreak == 0)
|
|
ckt->CKTminBreak = ckt->CKTmaxStep * 5e-5 ; */
|
|
|
|
/* Set to 10 times delmin for ATESSE 1 compatibity */
|
|
if(ckt->CKTminBreak==0) ckt->CKTminBreak = 10.0 * ckt->CKTdelmin;
|
|
/* gtri - end - wbk - 12/19/90 - Modify setting of CKTminBreak */
|
|
#else
|
|
/* Minimum Breakpoint Setup */
|
|
if(ckt->CKTminBreak==0) ckt->CKTminBreak=ckt->CKTmaxStep*5e-5;
|
|
#endif
|
|
|
|
#ifdef XSPICE
|
|
/* gtri - add - wbk - 12/19/90 - Add IPC stuff and set anal_init and anal_type */
|
|
/* Tell the beginPlot routine what mode we're in */
|
|
g_ipc.anal_type = IPC_ANAL_TRAN;
|
|
|
|
/* Tell the code models what mode we're in */
|
|
g_mif_info.circuit.anal_type = MIF_DC;
|
|
|
|
g_mif_info.circuit.anal_init = MIF_TRUE;
|
|
/* gtri - end - wbk */
|
|
#endif
|
|
|
|
/* Time Domain plot start and prepared to be filled in later */
|
|
error = CKTnames(ckt,&numNames,&nameList);
|
|
if(error) return(error);
|
|
SPfrontEnd->IFnewUid (ckt, &timeUid, NULL,
|
|
"time", UID_OTHER, NULL);
|
|
error = SPfrontEnd->OUTpBeginPlot (
|
|
ckt, ckt->CKTcurJob,
|
|
"Time Domain Periodic Steady State Analysis",
|
|
timeUid, IF_REAL,
|
|
numNames, nameList, IF_REAL, &(job->PSSplot_td));
|
|
tfree(nameList);
|
|
if(error) return(error);
|
|
|
|
/* Time initialization for Transient Analysis */
|
|
ckt->CKTtime = 0;
|
|
ckt->CKTdelta = 0;
|
|
ckt->CKTbreak = 1;
|
|
firsttime = 1;
|
|
save_mode = (ckt->CKTmode&MODEUIC) | MODETRANOP | MODEINITJCT;
|
|
save_order = ckt->CKTorder;
|
|
|
|
#ifdef XSPICE
|
|
/* gtri - begin - wbk - set a breakpoint at end of supply ramping time */
|
|
/* must do this after CKTtime set to 0 above */
|
|
if(ckt->enh->ramp.ramptime > 0.0)
|
|
CKTsetBreak(ckt, ckt->enh->ramp.ramptime);
|
|
/* gtri - end - wbk - set a breakpoint at end of supply ramping time */
|
|
|
|
/* gtri - begin - wbk - Call EVTop if event-driven instances exist */
|
|
if(ckt->evt->counts.num_insts != 0) {
|
|
/* use new DCOP algorithm */
|
|
converged = EVTop(ckt,
|
|
(ckt->CKTmode & MODEUIC) | MODETRANOP | MODEINITJCT,
|
|
(ckt->CKTmode & MODEUIC) | MODETRANOP | MODEINITFLOAT,
|
|
ckt->CKTdcMaxIter,
|
|
MIF_TRUE);
|
|
EVTdump(ckt, IPC_ANAL_DCOP, 0.0);
|
|
|
|
EVTop_save(ckt, MIF_FALSE, 0.0);
|
|
|
|
/* gtri - end - wbk - Call EVTop if event-driven instances exist */
|
|
} else
|
|
#endif
|
|
|
|
/* Looking for a working Operating Point */
|
|
converged = CKTop(ckt,
|
|
(ckt->CKTmode & MODEUIC) | MODETRANOP | MODEINITJCT,
|
|
(ckt->CKTmode & MODEUIC) | MODETRANOP | MODEINITFLOAT,
|
|
ckt->CKTdcMaxIter);
|
|
|
|
#ifdef STEPDEBUG
|
|
if(converged != 0) {
|
|
fprintf(stdout,"\nTransient solution failed -\n");
|
|
CKTncDump(ckt);
|
|
/* CKTnode *node;
|
|
double new, old, tol;
|
|
int i=1;
|
|
|
|
fprintf(stdout,"\nTransient solution failed -\n\n");
|
|
fprintf(stdout,"Last Node Voltages\n");
|
|
fprintf(stdout,"------------------\n\n");
|
|
fprintf(stdout,"%-30s %20s %20s\n", "Node", "Last Voltage",
|
|
"Previous Iter");
|
|
fprintf(stdout,"%-30s %20s %20s\n", "----", "------------",
|
|
"-------------");
|
|
for(node=ckt->CKTnodes->next;node;node=node->next) {
|
|
if (strstr(node->name, "#branch") || !strstr(node->name, "#")) {
|
|
new = *((ckt->CKTrhsOld) + i ) ;
|
|
old = *((ckt->CKTrhs) + i ) ;
|
|
fprintf(stdout,"%-30s %20g %20g", node->name, new, old);
|
|
if(node->type == 3) {
|
|
tol = ckt->CKTreltol * (MAX(fabs(old),fabs(new))) +
|
|
ckt->CKTvoltTol;
|
|
} else {
|
|
tol = ckt->CKTreltol * (MAX(fabs(old),fabs(new))) +
|
|
ckt->CKTabstol;
|
|
}
|
|
if (fabs(new-old) >tol ) {
|
|
fprintf(stdout," *");
|
|
}
|
|
fprintf(stdout,"\n");
|
|
}
|
|
i++;
|
|
} */
|
|
fprintf(stdout,"\n");
|
|
fflush(stdout);
|
|
} else if (!ft_noacctprint && !ft_noinitprint) {
|
|
fprintf(stdout,"\nInitial Transient Solution\n");
|
|
fprintf(stdout,"--------------------------\n\n");
|
|
fprintf(stdout,"%-30s %15s\n", "Node", "Voltage");
|
|
fprintf(stdout,"%-30s %15s\n", "----", "-------");
|
|
for(node=ckt->CKTnodes->next;node;node=node->next) {
|
|
if (strstr(node->name, "#branch") || !strstr(node->name, "#"))
|
|
fprintf(stdout,"%-30s %15g\n", node->name,
|
|
ckt->CKTrhsOld[node->number]);
|
|
}
|
|
fprintf(stdout,"\n");
|
|
fflush(stdout);
|
|
}
|
|
#endif
|
|
|
|
/* If no convergence reached - NO valid Operating Point */
|
|
if(converged != 0) return(converged);
|
|
#ifdef XSPICE
|
|
/* gtri - add - wbk - 12/19/90 - Add IPC stuff */
|
|
|
|
/* Send the operating point results for Mspice compatibility */
|
|
if(g_ipc.enabled) {
|
|
ipc_send_dcop_prefix();
|
|
CKTdump(ckt, 0.0, job->PSSplot_td);
|
|
ipc_send_dcop_suffix();
|
|
}
|
|
|
|
/* gtri - end - wbk */
|
|
|
|
/* gtri - add - wbk - 12/19/90 - set anal_init and anal_type */
|
|
|
|
g_mif_info.circuit.anal_init = MIF_TRUE;
|
|
|
|
/* Tell the code models what mode we're in */
|
|
g_mif_info.circuit.anal_type = MIF_TRAN;
|
|
|
|
/* gtri - end - wbk */
|
|
|
|
/* gtri - begin - wbk - Add Breakpoint stuff */
|
|
|
|
/* Initialize the temporary breakpoint variables to infinity */
|
|
g_mif_info.breakpoint.current = HUGE_VAL;
|
|
g_mif_info.breakpoint.last = HUGE_VAL;
|
|
|
|
/* gtri - end - wbk - Add Breakpoint stuff */
|
|
#endif
|
|
ckt->CKTstat->STATtimePts ++;
|
|
|
|
/* Setting Integration Order to Backward Euler */
|
|
ckt->CKTorder = 1;
|
|
|
|
/* Copying the maxStep to every deltaOld */
|
|
for(i=0;i<7;i++) {
|
|
ckt->CKTdeltaOld[i]=ckt->CKTmaxStep;
|
|
}
|
|
|
|
/* Setting DELTA */
|
|
ckt->CKTdelta = delta;
|
|
#ifdef STEPDEBUG
|
|
fprintf (stderr, "delta initialized to %g\n", ckt->CKTdelta);
|
|
#endif
|
|
|
|
ckt->CKTsaveDelta = ckt->CKTfinalTime/50;
|
|
|
|
ckt->CKTmode = (ckt->CKTmode&MODEUIC) | MODETRAN | MODEINITTRAN;
|
|
/* Changing Circuit MODE */
|
|
/* modeinittran set here */
|
|
ckt->CKTag[0]=ckt->CKTag[1]=0;
|
|
|
|
/* State0 copied into State1 - DEPRECATED LEGACY function - to be replaced with memmove() */
|
|
bcopy(ckt->CKTstate0, ckt->CKTstate1,
|
|
(size_t) ckt->CKTnumStates * sizeof(double));
|
|
|
|
/* Statistics Initialization using a macro at the beginning of this code */
|
|
INIT_STATS();
|
|
#ifdef CLUSTER
|
|
CLUsetup(ckt);
|
|
#endif
|
|
} else {
|
|
/* saj As traninit resets CKTmode */
|
|
ckt->CKTmode = (ckt->CKTmode&MODEUIC) | MODETRAN | MODEINITPRED;
|
|
/* saj */
|
|
INIT_STATS();
|
|
if(ckt->CKTminBreak==0) ckt->CKTminBreak=ckt->CKTmaxStep*5e-5;
|
|
firsttime=0;
|
|
/* To get rawfile working saj*/
|
|
error = SPfrontEnd->OUTpBeginPlot (
|
|
NULL, NULL,
|
|
NULL,
|
|
NULL, 0,
|
|
666, NULL, 666, &(job->PSSplot_td));
|
|
if(error) {
|
|
fprintf(stderr, "Couldn't relink rawfile\n");
|
|
return error;
|
|
}
|
|
/* end saj*/
|
|
|
|
/* Skip nextTime if it isn't the firsttime! :) */
|
|
goto resume;
|
|
}
|
|
|
|
/* 650 */
|
|
nextTime:
|
|
|
|
/* begin LTRA code addition */
|
|
if (ckt->CKTtimePoints) {
|
|
ckt->CKTtimeIndex++;
|
|
if (ckt->CKTtimeIndex >= ckt->CKTtimeListSize) {
|
|
/* need more space */
|
|
int need;
|
|
if (pss_state == STABILIZATION)
|
|
need = (int) ceil((ckt->CKTstabTime - ckt->CKTtime) / maxstepsize ) ;
|
|
else
|
|
need = (int) ceil((time_temp + 1 / ckt->CKTguessedFreq - ckt->CKTtime) / maxstepsize) ;
|
|
|
|
if (need < ckt->CKTsizeIncr)
|
|
need = ckt->CKTsizeIncr;
|
|
ckt->CKTtimeListSize += need;
|
|
ckt->CKTtimePoints = TREALLOC(double, ckt->CKTtimePoints, ckt->CKTtimeListSize);
|
|
ckt->CKTsizeIncr = (int) ceil(1.4 * ckt->CKTsizeIncr);
|
|
}
|
|
ckt->CKTtimePoints[ckt->CKTtimeIndex] = ckt->CKTtime;
|
|
}
|
|
/* end LTRA code addition */
|
|
|
|
/* Check for the timepoint acceptance */
|
|
error = CKTaccept(ckt);
|
|
/* check if current breakpoint is outdated; if so, clear */
|
|
if (ckt->CKTtime > ckt->CKTbreaks[0]) CKTclrBreak(ckt);
|
|
|
|
/*
|
|
* Breakpoint handling scheme:
|
|
* When a timepoint t is accepted (by CKTaccept), clear all previous
|
|
* breakpoints, because they will never be needed again.
|
|
*
|
|
* t may itself be a breakpoint, or indistinguishably close. DON'T
|
|
* clear t itself; recognise it as a breakpoint and act accordingly
|
|
*
|
|
* if t is not a breakpoint, limit the timestep so that the next
|
|
* breakpoint is not crossed
|
|
*/
|
|
|
|
#ifdef STEPDEBUG
|
|
fprintf (stderr, "Delta %g accepted at time %g (finaltime: %g)\n", ckt->CKTdelta, ckt->CKTtime, ckt->CKTfinalTime) ;
|
|
fflush(stdout);
|
|
#endif /* STEPDEBUG */
|
|
ckt->CKTstat->STATaccepted ++;
|
|
ckt->CKTbreak = 0;
|
|
/* XXX Error will cause single process to bail. */
|
|
if(error) {
|
|
UPDATE_STATS(DOING_TRAN);
|
|
return(error);
|
|
}
|
|
#ifdef XSPICE
|
|
/* gtri - modify - wbk - 12/19/90 - Send IPC stuff */
|
|
|
|
if(g_ipc.enabled) {
|
|
|
|
if (pss_state == PSS)
|
|
{
|
|
/* Send event-driven results */
|
|
EVTdump(ckt, IPC_ANAL_TRAN, 0.0);
|
|
|
|
/* Then follow with analog results... */
|
|
|
|
/* Test to see if delta was cut by a breakpoint, */
|
|
/* a non-convergence, or a too large truncation error */
|
|
if(ipc_firsttime)
|
|
ipc_delta_cut = IPC_FALSE;
|
|
else if(ckt->CKTtime < (ipc_last_time + (0.999 * ipc_last_delta)))
|
|
ipc_delta_cut = IPC_TRUE;
|
|
else
|
|
ipc_delta_cut = IPC_FALSE;
|
|
|
|
/* Record the data required to check for delta cuts */
|
|
ipc_last_time = ckt->CKTtime;
|
|
ipc_last_delta = MIN(ckt->CKTdelta, ckt->CKTmaxStep);
|
|
|
|
/* Send results data if time since last dump is greater */
|
|
/* than 'mintime', or if first or second timepoints, */
|
|
/* or if delta was cut */
|
|
if( (ckt->CKTtime >= (g_ipc.mintime + g_ipc.last_time)) ||
|
|
ipc_firsttime || ipc_secondtime || ipc_delta_cut ) {
|
|
|
|
ipc_send_data_prefix(ckt->CKTtime);
|
|
CKTdump(ckt, ckt->CKTtime, job->PSSplot_td);
|
|
ipc_send_data_suffix();
|
|
|
|
if(ipc_firsttime) {
|
|
ipc_firsttime = IPC_FALSE;
|
|
ipc_secondtime = IPC_TRUE;
|
|
} else if(ipc_secondtime) {
|
|
ipc_secondtime = IPC_FALSE;
|
|
}
|
|
|
|
g_ipc.last_time = ckt->CKTtime;
|
|
}
|
|
}
|
|
} else
|
|
/* gtri - modify - wbk - 12/19/90 - Send IPC stuff */
|
|
#endif
|
|
#ifdef CLUSTER
|
|
if (pss_state == PSS)
|
|
CLUoutput(ckt);
|
|
#endif
|
|
|
|
if (pss_state == PSS)
|
|
{
|
|
nextstep = time_temp + 1 / ckt->CKTguessedFreq * ((double)(pss_points_cycle) / (double)ckt->CKTpsspoints) ;
|
|
|
|
/* If in_pss, store data for Time Domain Plot and gather ordered data for FFT computing */
|
|
if ((AlmostEqualUlps (ckt->CKTtime, nextstep, 10)) || (ckt->CKTtime > time_temp + 1 / ckt->CKTguessedFreq))
|
|
{
|
|
|
|
#ifdef STEPDEBUG
|
|
fprintf (stderr, "IN_PSS: time point accepted in evolution for FFT calculations.\n") ;
|
|
fprintf (stderr, "Circuit time %1.15g, final time %1.15g, point index %d and total requested points %ld\n",
|
|
ckt->CKTtime, nextstep, pss_points_cycle, ckt->CKTpsspoints) ;
|
|
#endif
|
|
|
|
CKTdump (ckt, ckt->CKTtime, job->PSSplot_td) ;
|
|
|
|
/* Store the Time Base for the DFT */
|
|
psstimes [pss_points_cycle] = ckt->CKTtime ;
|
|
|
|
/* Store values for the FFT calculation */
|
|
for (i = 1 ; i <= msize ; i++)
|
|
pssvalues [i - 1 + pss_points_cycle * msize] = ckt->CKTrhsOld [i] ;
|
|
|
|
/* Update PSS counter cycle, used to stop the entire algorithm */
|
|
pss_points_cycle++ ;
|
|
|
|
/* Set the next BreakPoint for PSS */
|
|
CKTsetBreak (ckt, time_temp + (1 / ckt->CKTguessedFreq) * ((double)(pss_points_cycle) / (double)ckt->CKTpsspoints)) ;
|
|
|
|
#ifdef STEPDEBUG
|
|
fprintf (stderr, "Next breakpoint set in: %1.15g\n", time_temp + 1 / ckt->CKTguessedFreq * ((double)(pss_points_cycle) / (double)ckt->CKTpsspoints)) ;
|
|
#endif
|
|
|
|
} else {
|
|
/* Algo can enter here but should do nothing */
|
|
|
|
#ifdef STEPDEBUG
|
|
fprintf (stderr, "IN_PSS: time point accepted in evolution but dropped for FFT calculations\n") ;
|
|
#endif
|
|
|
|
}
|
|
}
|
|
|
|
#ifdef XSPICE
|
|
/* gtri - begin - wbk - Update event queues/data for accepted timepoint */
|
|
/* Note: this must be done AFTER sending results to SI so it can't */
|
|
/* go next to CKTaccept() above */
|
|
if(ckt->evt->counts.num_insts > 0)
|
|
EVTaccept(ckt, ckt->CKTtime);
|
|
/* gtri - end - wbk - Update event queues/data for accepted timepoint */
|
|
#endif
|
|
ckt->CKTstat->STAToldIter = ckt->CKTstat->STATnumIter;
|
|
|
|
/* ***********************************/
|
|
/* ******* SHOOTING CODE BLOCK *******/
|
|
/* ***********************************/
|
|
switch(pss_state) {
|
|
|
|
case STABILIZATION:
|
|
{
|
|
/* Test if stabTime has been reached */
|
|
if (AlmostEqualUlps (ckt->CKTtime, ckt->CKTstabTime, 100))
|
|
{
|
|
time_temp = ckt->CKTtime ;
|
|
|
|
/* Set the new Final Time - This is important because the last breakpoint is always CKTfinalTime */
|
|
ckt->CKTfinalTime = time_temp + 2 / ckt->CKTguessedFreq ;
|
|
fprintf (stderr, "Exiting from stabilization\n") ;
|
|
fprintf (stderr, "Time of first shooting evaluation will be %1.10g\n", time_temp + 1 / ckt->CKTguessedFreq) ;
|
|
|
|
/* Next time is no more in stabilization - Unset the flag */
|
|
pss_state = SHOOTING;
|
|
|
|
/* Save the RHS_copy_der as the NEW CKTrhsOld */
|
|
for (i = 1 ; i <= msize ; i++)
|
|
RHS_copy_der [i - 1] = ckt->CKTrhsOld [i] ;
|
|
|
|
/* Print RHS on exiting from stabilization */
|
|
fprintf (stderr, "RHS on exiting from stabilization: ") ;
|
|
for (i = 1 ; i <= msize ; i++)
|
|
{
|
|
RHS_copy_se [i - 1] = ckt->CKTrhsOld [i] ;
|
|
fprintf (stderr, "%-15g ", RHS_copy_se [i - 1]) ;
|
|
}
|
|
fprintf (stderr, "\n") ;
|
|
|
|
/* RHS_max and RHS_min initialization - HUGE_VAL is the maximum machine error */
|
|
for (i = 0 ; i < msize ; i++)
|
|
{
|
|
RHS_max [i] = -HUGE_VAL ;
|
|
RHS_min [i] = HUGE_VAL ;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case SHOOTING:
|
|
{
|
|
/* Calculation of error norms of RHS solution of every accepted nextTime */
|
|
err = 0 ;
|
|
for (i = 0 ; i < msize ; i++)
|
|
{
|
|
/* Save max per node or branch of every estimated period */
|
|
if (RHS_max [i] < ckt->CKTrhsOld [i + 1])
|
|
RHS_max [i] = ckt->CKTrhsOld [i + 1] ;
|
|
|
|
/* Save min per node or branch of every estimated period */
|
|
if (RHS_min [i] > ckt->CKTrhsOld [i + 1])
|
|
RHS_min [i] = ckt->CKTrhsOld [i + 1] ;
|
|
|
|
/* CKTrhsOld is the last CORRECT value of RHS */
|
|
err_conv [i] = ckt->CKTrhsOld [i + 1] - RHS_copy_se [i] ;
|
|
err += err_conv [i] * err_conv [i] ;
|
|
|
|
/* Compute and store derivative */
|
|
RHS_derivative [i] = (ckt->CKTrhsOld [i + 1] - RHS_copy_der [i]) / ckt->CKTdelta ;
|
|
|
|
/* Save the RHS_copy_der as the NEW CKTrhsOld */
|
|
RHS_copy_der [i] = ckt->CKTrhsOld [i + 1] ;
|
|
|
|
#ifdef STEPDEBUG
|
|
fprintf (stderr, "Pred is so high or so low! Diff is: %g\n", err_conv [i]) ;
|
|
#endif
|
|
|
|
}
|
|
err = sqrt (err) ;
|
|
|
|
/* Start frequency estimation */
|
|
if ((err < err_0) && (ckt->CKTtime >= time_temp + 0.5 / ckt->CKTguessedFreq)) /* far enough from time temp... */
|
|
{
|
|
if (err < err_min_0)
|
|
{
|
|
err_min_1 = err_min_0 ; /* store previous minimum of RHS vector error */
|
|
err_min_0 = err ; /* store minimum of RHS vector error */
|
|
time_err_min_1 = time_err_min_0 ; /* store previous minimum of RHS vector error time */
|
|
time_err_min_0 = ckt->CKTtime ; /* store minimum of RHS vector error time */
|
|
}
|
|
}
|
|
err_0 = err ;
|
|
|
|
if ((err > err_1) && (ckt->CKTtime >= time_temp + 0.1 / ckt->CKTguessedFreq)) /* far enough from time temp... */
|
|
{
|
|
if (err > err_max)
|
|
err_max = err ; /* store maximum of RHS vector error */
|
|
}
|
|
err_1 = err ;
|
|
|
|
|
|
/* *************************************** */
|
|
/* ********** Breakpoint update ********** */
|
|
/* *************************************** */
|
|
|
|
/* Force the tran analysis to evaluate requested breakpoints. Breakpoints are even more closer as
|
|
the next occurence of guessed period is approaching. La lunga notte dei robot viventi... */
|
|
|
|
double offset, interval, nextBreak ;
|
|
int i ;
|
|
|
|
if ((ckt->CKTtime > time_temp + (1 / ckt->CKTguessedFreq) * 0.995) && (ckt->CKTtime <= time_temp + (1 / ckt->CKTguessedFreq)))
|
|
{
|
|
offset = time_temp + (1 / ckt->CKTguessedFreq) * 0.995 ;
|
|
interval = (1 / ckt->CKTguessedFreq) * (1 - 0.995) * (ckt->CKTsteady_coeff / 10) ;
|
|
i = (int)((ckt->CKTtime - offset) / interval) ;
|
|
nextBreak = offset + (i + 1) * interval ;
|
|
CKTsetBreak (ckt, nextBreak) ;
|
|
}
|
|
else if ((ckt->CKTtime > time_temp + (1 / ckt->CKTguessedFreq) * 0.8) && (ckt->CKTtime <= time_temp + (1 / ckt->CKTguessedFreq) * 0.995))
|
|
{
|
|
offset = time_temp + (1 / ckt->CKTguessedFreq) * 0.8 ;
|
|
interval = (1 / ckt->CKTguessedFreq) * (0.995 - 0.8) * (ckt->CKTsteady_coeff / 5) ;
|
|
i = (int)((ckt->CKTtime - offset) / interval) ;
|
|
nextBreak = offset + (i + 1) * interval ;
|
|
CKTsetBreak (ckt, nextBreak) ;
|
|
}
|
|
else if ((ckt->CKTtime > time_temp + (1 / ckt->CKTguessedFreq) * 0.5) && (ckt->CKTtime <= time_temp + (1 / ckt->CKTguessedFreq) * 0.8))
|
|
{
|
|
offset = time_temp + (1 / ckt->CKTguessedFreq) * 0.5 ;
|
|
interval = (1 / ckt->CKTguessedFreq) * (0.8 - 0.5) * (ckt->CKTsteady_coeff / 3) ;
|
|
i = (int)((ckt->CKTtime - offset) / interval) ;
|
|
nextBreak = offset + (i + 1) * interval ;
|
|
CKTsetBreak (ckt, nextBreak) ;
|
|
}
|
|
else if ((ckt->CKTtime > time_temp + (1 / ckt->CKTguessedFreq) * 0.1) && (ckt->CKTtime <= time_temp + (1 / ckt->CKTguessedFreq) * 0.5))
|
|
{
|
|
offset = time_temp + (1 / ckt->CKTguessedFreq) * 0.1 ;
|
|
interval = (1 / ckt->CKTguessedFreq) * (0.5 - 0.1) * (ckt->CKTsteady_coeff / 2) ;
|
|
i = (int)((ckt->CKTtime - offset) / interval) ;
|
|
nextBreak = offset + (i + 1) * interval ;
|
|
CKTsetBreak (ckt, nextBreak) ;
|
|
}
|
|
else if ((ckt->CKTtime > time_temp) && (ckt->CKTtime <= time_temp + (1 / ckt->CKTguessedFreq) * 0.1))
|
|
{
|
|
offset = time_temp ;
|
|
interval = (1 / ckt->CKTguessedFreq) * (0.1) * (ckt->CKTsteady_coeff) ;
|
|
i = (int)((ckt->CKTtime - offset) / interval) ;
|
|
nextBreak = offset + (i + 1) * interval ;
|
|
CKTsetBreak (ckt, nextBreak) ;
|
|
} else {
|
|
fprintf (stderr, "Strange behavior\n\n") ;
|
|
fprintf (stderr, "CKTtime: %g\ntime_temp: %g\n\n", ckt->CKTtime, time_temp) ;
|
|
}
|
|
|
|
/* *************************************** */
|
|
/* ******* END Breakpoint update ********* */
|
|
/* *************************************** */
|
|
|
|
|
|
/* If evolution is near shooting... */
|
|
if ((AlmostEqualUlps (ckt->CKTtime, time_temp + 1 / ckt->CKTguessedFreq, 10)) || (ckt->CKTtime > time_temp + 1 / ckt->CKTguessedFreq))
|
|
{
|
|
/* Calculation of error norms of RHS solution of every accepted nextTime */
|
|
predsum = 0 ;
|
|
for (i = 0 ; i < msize ; i++)
|
|
{
|
|
/* Pitagora ha sempre ragione!!! :))) */
|
|
/* pred is treated as FREQUENCY to avoid numerical overflow when derivative is close to ZERO */
|
|
pred [i] = RHS_derivative [i] / err_conv [i] ;
|
|
|
|
#ifdef STEPDEBUG
|
|
fprintf (stderr, "Pred is so high or so low! Diff is: %g\n", err_conv [i]) ;
|
|
#endif
|
|
|
|
if ((fabs (pred [i]) > 1.0e6 * ckt->CKTguessedFreq) || (err_conv [i] == 0))
|
|
{
|
|
if (pred [i] > 0)
|
|
pred [i] = 1.0e6 * ckt->CKTguessedFreq ;
|
|
else
|
|
pred [i] = -1.0e6 * ckt->CKTguessedFreq ;
|
|
}
|
|
|
|
predsum += pred [i] ;
|
|
|
|
#ifdef STEPDEBUG
|
|
fprintf (stderr, "Predsum in time before to be divided by dynamic_test has value %g\n", 1 / predsum) ;
|
|
fprintf (stderr, "Current Diff: %g, Derivative: %g, Frequency Projection: %g\n", err_conv [i], RHS_derivative [i], pred [i]) ;
|
|
#endif
|
|
|
|
}
|
|
|
|
int excessive_err_nodes = 0 ;
|
|
|
|
if (shooting_cycle_counter == 0)
|
|
{
|
|
/* If first time in shooting we warn about that ! */
|
|
fprintf (stderr, "In shooting...\n") ;
|
|
}
|
|
|
|
//#ifdef STEPDEBUG
|
|
/* For debugging purpose */
|
|
fprintf (stderr, "\n----------------\n") ;
|
|
fprintf (stderr, "Shooting cycle iteration number: %3d ||", shooting_cycle_counter) ;
|
|
|
|
if (shooting_cycle_counter > 0)
|
|
fprintf (stderr, " rr: %g || predsum: %g\n", rr_history [shooting_cycle_counter - 1], 1 / predsum) ;
|
|
else
|
|
fprintf (stderr, " rr: %g || predsum: %g\n", 0.0, 1 / predsum) ;
|
|
|
|
// fprintf (stderr, "Print of dynamically consistent nodes voltages or branches currents:\n") ;
|
|
/* --------------------- */
|
|
//#endif
|
|
|
|
for (i = 0, node = ckt->CKTnodes->next ; node ; i++, node = node->next)
|
|
{
|
|
/* Voltage Node */
|
|
if (!strstr (node->name, "#"))
|
|
{
|
|
if (fabs (err_conv [i]) > (fabs (RHS_max [i] - RHS_min [i]) * ckt->CKTreltol + ckt->CKTvoltTol) *
|
|
ckt->CKTtrtol * ckt->CKTsteady_coeff)
|
|
{
|
|
excessive_err_nodes++ ;
|
|
}
|
|
|
|
/* If the dynamic is below 10uV, it's dropped */
|
|
if (fabs (RHS_max [i] - RHS_min [i]) > 10 * 1e-6)
|
|
{
|
|
dynamic_test++ ; /* test on voltage dynamic consistence */
|
|
}
|
|
|
|
/* Current Node */
|
|
} else {
|
|
if (fabs (err_conv [i]) > (fabs (RHS_max [i] - RHS_min [i]) * ckt->CKTreltol + ckt->CKTabstol) *
|
|
ckt->CKTtrtol * ckt->CKTsteady_coeff)
|
|
{
|
|
excessive_err_nodes++ ;
|
|
}
|
|
|
|
/* If the dynamic is below 10nA, it's dropped */
|
|
if (fabs (RHS_max [i] - RHS_min [i]) > 10 * 1e-9)
|
|
{
|
|
dynamic_test++ ; /* test on current dynamic consistence */
|
|
}
|
|
}
|
|
}
|
|
|
|
if (dynamic_test == 0)
|
|
{
|
|
/* Test for dynamic existence */
|
|
fprintf (stderr, "No detectable dynamic on voltages nodes or currents branches. PSS analysis aborted\n") ;
|
|
|
|
/* Terminates plot in Time Domain and frees the allocated memory */
|
|
SPfrontEnd->OUTendPlot (job->PSSplot_td) ;
|
|
FREE (RHS_copy_se) ;
|
|
FREE (RHS_copy_der) ;
|
|
FREE (RHS_max) ;
|
|
FREE (RHS_min) ;
|
|
FREE (psstimes) ;
|
|
FREE (pssvalues) ;
|
|
return (E_PANIC) ; /* to be corrected with definition of new error macro in iferrmsg.h */
|
|
}
|
|
else if ((time_err_min_0 - time_temp) < 0)
|
|
{
|
|
/* Something has gone wrong... */
|
|
fprintf (stderr, "Cannot find a minimum for error vector in estimated period. Try to adjust tstab! PSS analysis aborted\n") ;
|
|
|
|
/* Terminates plot in Time Domain and frees the allocated memory */
|
|
SPfrontEnd->OUTendPlot (job->PSSplot_td) ;
|
|
FREE (RHS_copy_se) ;
|
|
FREE (RHS_copy_der) ;
|
|
FREE (RHS_max) ;
|
|
FREE (RHS_min) ;
|
|
FREE (psstimes) ;
|
|
FREE (pssvalues) ;
|
|
return (E_PANIC) ; /* to be corrected with definition of new error macro in iferrmsg.h */
|
|
}
|
|
|
|
//#ifdef STEPDEBUG
|
|
// fprintf (stderr, "Global Convergence Error reference: %g, Time Projection: %g.\n",
|
|
// err_conv_ref / dynamic_test, predsum) ;
|
|
//#endif
|
|
|
|
/* Take the mean value of time prediction trough the dynamic test variable - predsum becomes TIME */
|
|
predsum = 1 / (predsum * dynamic_test) ;
|
|
|
|
/* Store the predsum history as absolute value */
|
|
predsum_history [shooting_cycle_counter] = fabs (predsum) ;
|
|
|
|
/***********************************/
|
|
/*** FREQUENCY ESTIMATION UPDATE ***/
|
|
/***********************************/
|
|
if ((err_min_0 == err) || (err_min_0 == HUGE_VAL))
|
|
{
|
|
/* Enters here if guessed frequency is higher than the 'real' value */
|
|
ckt->CKTguessedFreq = 1 / (1 / ckt->CKTguessedFreq + fabs (predsum)) ;
|
|
|
|
#ifdef STEPDEBUG
|
|
fprintf (stderr, "Frequency DOWN: est per %g, err min %g, err min 1 %g, err max %g, err %g\n",
|
|
time_err_min_0 - time_temp, err_min_0, err_min_1, err_max, err) ;
|
|
#endif
|
|
|
|
} else {
|
|
/* Enters here if guessed frequency is lower than the 'real' value */
|
|
ckt->CKTguessedFreq = 1 / (time_err_min_0 - time_temp) ;
|
|
|
|
#ifdef STEPDEBUG
|
|
fprintf (stderr, "Frequency UP: est per %g, err min %g, err min 1 %g, err max %g, err %g\n",
|
|
time_err_min_0 - time_temp, err_min_0, err_min_1, err_max, err) ;
|
|
#endif
|
|
|
|
}
|
|
|
|
/* Temporary variables to store previous occurrence of guessed frequency */
|
|
gf_last_1 = gf_last_0 ;
|
|
gf_last_0 = ckt->CKTguessedFreq ;
|
|
|
|
/* Next evaluation of shooting will be updated time (time_temp) summed to updated guessed period */
|
|
time_temp = ckt->CKTtime ;
|
|
|
|
/* Store error history */
|
|
rr_history [shooting_cycle_counter] = err ;
|
|
gf_history [shooting_cycle_counter] = ckt->CKTguessedFreq ;
|
|
shooting_cycle_counter++ ;
|
|
|
|
fprintf (stderr, "Updated guessed frequency: %1.10lg .\n", ckt->CKTguessedFreq) ;
|
|
fprintf (stderr, "Next shooting evaluation time is %1.10g and current time is %1.10g.\n",
|
|
time_temp + 1 / ckt->CKTguessedFreq, ckt->CKTtime) ;
|
|
|
|
/* Restore maximum and minimum error for next search */
|
|
err_min_0 = HUGE_VAL ;
|
|
err_max = -HUGE_VAL ;
|
|
err_0 = HUGE_VAL ;
|
|
err_1 = -HUGE_VAL ;
|
|
dynamic_test = 0 ;
|
|
|
|
/* Reset actual RHS reference for next shooting evaluation */
|
|
for (i = 1 ; i <= msize ; i++)
|
|
RHS_copy_se [i - 1] = ckt->CKTrhsOld [i] ;
|
|
|
|
#ifdef STEPDEBUG
|
|
fprintf (stderr, "RHS on new shooting cycle: ") ;
|
|
for (i = 0 ; i < msize ; i++)
|
|
fprintf (stderr, "%-15g ", RHS_copy_se [i]) ;
|
|
fprintf (stderr, "\n") ;
|
|
#endif
|
|
|
|
for (i = 0 ; i < msize ; i++)
|
|
{
|
|
/* Reset max and min per node or branch on every shooting cycle */
|
|
RHS_max [i] = -HUGE_VAL ;
|
|
RHS_min [i] = HUGE_VAL ;
|
|
}
|
|
|
|
fprintf (stderr, "----------------\n\n") ;
|
|
|
|
/* Shooting Exit Condition */
|
|
if ((shooting_cycle_counter > ckt->CKTsc_iter) || (excessive_err_nodes == 0))
|
|
{
|
|
int k ;
|
|
double minimum ;
|
|
|
|
pss_state = PSS ;
|
|
|
|
#ifdef STEPDEBUG
|
|
fprintf (stderr, "\nFrequency estimation (FE) and RHS period residual (PR) evolution\n") ;
|
|
#endif
|
|
|
|
// minimum = rr_history [0] ;
|
|
minimum = predsum_history [0] ;
|
|
k = 0 ;
|
|
for (i = 0 ; i < shooting_cycle_counter ; i++)
|
|
{
|
|
/* Print some statistics */
|
|
fprintf (stderr, "%-3d -> FE: %-15.10g || RR: %15.10g", i, gf_history [i], rr_history [i]) ;
|
|
|
|
/* Take the minimum residual iteration */
|
|
// if (minimum > rr_history [i])
|
|
if (minimum > predsum_history [i])
|
|
{
|
|
// minimum = rr_history [i] ;
|
|
minimum = predsum_history [i] ;
|
|
k = i ;
|
|
}
|
|
fprintf (stderr, " || predsum/dynamic_test: %15.10g || minimum: %15.10g\n", predsum_history [i], minimum) ;
|
|
}
|
|
|
|
if (excessive_err_nodes == 0) /* SHOOTING has converged */
|
|
ckt->CKTguessedFreq = gf_history [shooting_cycle_counter - 1] ;
|
|
else
|
|
ckt->CKTguessedFreq = gf_history [k] ;
|
|
|
|
/* Save the current Time */
|
|
time_temp = ckt->CKTtime ;
|
|
|
|
/* Set the new Final Time - This is important because the last breakpoint is always CKTfinalTime */
|
|
ckt->CKTfinalTime = time_temp + 1 / ckt->CKTguessedFreq ;
|
|
|
|
/* Dump the first PSS point for the FFT */
|
|
CKTdump (ckt, ckt->CKTtime, job->PSSplot_td) ;
|
|
psstimes [pss_points_cycle] = ckt->CKTtime ;
|
|
for (i = 1 ; i <= msize ; i++)
|
|
pssvalues [i - 1 + pss_points_cycle * msize] = ckt->CKTrhsOld [i] ;
|
|
|
|
/* Update the PSS points counter and set the next Breakpoint */
|
|
pss_points_cycle++ ;
|
|
CKTsetBreak (ckt, time_temp + (1 / ckt->CKTguessedFreq) * ((double)(pss_points_cycle) / (double)ckt->CKTpsspoints)) ;
|
|
|
|
if (excessive_err_nodes == 0)
|
|
fprintf (stderr, "\nConvergence reached. Final circuit time is %1.10g seconds (iteration n° %d) and predicted fundamental frequency is %15.10g Hz\n", ckt->CKTtime, shooting_cycle_counter - 1, ckt->CKTguessedFreq) ;
|
|
else
|
|
fprintf (stderr, "\nConvergence not reached. However the most near convergence iteration has predicted (iteration %d) a fundamental frequency of %15.10g Hz\n", k, ckt->CKTguessedFreq) ;
|
|
|
|
#ifdef STEPDEBUG
|
|
fprintf (stderr, "time_temp %g\n", time_temp) ;
|
|
fprintf (stderr, "IN_PSS: FIRST time point accepted in evolution for FFT calculations\n") ;
|
|
fprintf (stderr, "Circuit time %1.15g, final time %1.15g, point index %d and total requested points %ld\n",
|
|
ckt->CKTtime, time_temp + 1 / ckt->CKTguessedFreq * ((double)(pss_points_cycle) / (double)ckt->CKTpsspoints),
|
|
pss_points_cycle, ckt->CKTpsspoints) ;
|
|
fprintf (stderr, "Next breakpoint set in: %1.15g\n",
|
|
time_temp + 1 / ckt->CKTguessedFreq * ((double)(pss_points_cycle) / (double)ckt->CKTpsspoints)) ;
|
|
#endif
|
|
|
|
} else {
|
|
/* Set the new Final Time - This is important because the last breakpoint is always CKTfinalTime */
|
|
ckt->CKTfinalTime = time_temp + 1 / ckt->CKTguessedFreq ;
|
|
|
|
/* Set next the breakpoint */
|
|
CKTsetBreak (ckt, time_temp + 1 / ckt->CKTguessedFreq) ;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case PSS:
|
|
{
|
|
/* The algorithm enters here when in_pss is set */
|
|
|
|
#ifdef STEPDEBUG
|
|
fprintf (stderr, "ttemp %1.15g, final_time %1.15g, current_time %1.15g\n", time_temp, time_temp + 1 / ckt->CKTguessedFreq, ckt->CKTtime) ;
|
|
#endif
|
|
|
|
if ((pss_points_cycle == ckt->CKTpsspoints + 1) || (ckt->CKTtime > ckt->CKTfinalTime))
|
|
{
|
|
double *pssfreqs = TMALLOC (double, ckt->CKTharms);
|
|
double *pssmags = TMALLOC (double, ckt->CKTharms);
|
|
double *pssphases = TMALLOC (double, ckt->CKTharms);
|
|
double *pssnmags = TMALLOC (double, ckt->CKTharms);
|
|
double *pssnphases = TMALLOC (double, ckt->CKTharms);
|
|
double *pssValues = TMALLOC (double, ckt->CKTpsspoints + 1);
|
|
double *pssResults = TMALLOC (double, msize * ckt->CKTharms);
|
|
|
|
/* End plot in Time Domain */
|
|
SPfrontEnd->OUTendPlot (job->PSSplot_td) ;
|
|
|
|
/* Frequency Plot Creation */
|
|
error = CKTnames (ckt, &numNames, &nameList) ;
|
|
if (error)
|
|
return (error) ;
|
|
SPfrontEnd->IFnewUid (ckt, &freqUid, NULL, "frequency", UID_OTHER, NULL) ;
|
|
error = SPfrontEnd->OUTpBeginPlot (ckt, ckt->CKTcurJob, "Frequency Domain Periodic Steady State Analysis",
|
|
freqUid, IF_REAL, numNames, nameList, IF_REAL, &(job->PSSplot_fd)) ;
|
|
tfree (nameList) ;
|
|
SPfrontEnd->OUTattributes (job->PSSplot_fd, NULL, PLOT_COMB, NULL) ;
|
|
|
|
/* ******************** */
|
|
/* Starting DFT on data */
|
|
/* ******************** */
|
|
for (i = 0 ; i < msize ; i++)
|
|
{
|
|
for (j = 0 ; j < ckt->CKTpsspoints ; j++)
|
|
pssValues [j] = pssvalues [j * msize + i] ;
|
|
|
|
DFT (ckt->CKTpsspoints, ckt->CKTharms, &thd, psstimes, pssValues, ckt->CKTguessedFreq,
|
|
pssfreqs, pssmags, pssphases, pssnmags, pssnphases) ;
|
|
|
|
for (j = 0 ; j < ckt->CKTharms ; j++)
|
|
pssResults [j * msize + i] = pssmags [j] ;
|
|
}
|
|
|
|
for (j = 0 ; j < ckt->CKTharms ; j++)
|
|
{
|
|
for (i = 0 ; i < msize ; i++)
|
|
ckt->CKTrhsOld [i + 1] = pssResults [j * msize + i] ;
|
|
|
|
CKTdump (ckt, pssfreqs [j], job->PSSplot_fd) ;
|
|
}
|
|
/* ****************** */
|
|
/* Ending DFT on data */
|
|
/* ****************** */
|
|
|
|
/* Terminates plot in Frequency Domain and frees the allocated memory */
|
|
SPfrontEnd->OUTendPlot (job->PSSplot_fd) ;
|
|
|
|
|
|
|
|
/* Francesco Lannutti's MOD */
|
|
|
|
/* Verify the frequency found */
|
|
max_freq = pssResults [msize] ; /* max_freq = pssResults [1 * msize + 0] ; */
|
|
position = 1 ;
|
|
for (j = 1 ; j < ckt->CKTharms ; j++)
|
|
{
|
|
for (i = 0 ; i < msize ; i++)
|
|
{
|
|
if (max_freq < pssResults [j * msize + i])
|
|
{
|
|
max_freq = pssResults [j * msize + i] ;
|
|
position = j ;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (pssfreqs [position] != ckt->CKTguessedFreq)
|
|
{
|
|
ckt->CKTguessedFreq = pssfreqs [position] ;
|
|
fprintf (stderr, "The predicted fundamental frequency is incorrect.\nRelaunching the analysis...\n\n") ;
|
|
fprintf (stderr, "The new guessed fundamental frequency is: %.6g\n\n", ckt->CKTguessedFreq) ;
|
|
DCpss (ckt, 1) ;
|
|
}
|
|
/****************************/
|
|
|
|
|
|
FREE (pssResults) ;
|
|
FREE (pssValues) ;
|
|
FREE (pssnphases) ;
|
|
FREE (pssnmags) ;
|
|
FREE (pssphases) ;
|
|
FREE (pssmags) ;
|
|
FREE (pssfreqs) ;
|
|
|
|
FREE (RHS_copy_se) ;
|
|
FREE (RHS_copy_der) ;
|
|
FREE (RHS_max) ;
|
|
FREE (RHS_min) ;
|
|
FREE (psstimes) ;
|
|
FREE (pssvalues) ;
|
|
return (OK) ;
|
|
}
|
|
}
|
|
break;
|
|
|
|
} /* switch(pss_state) */
|
|
|
|
/* ********************************** */
|
|
/* **** END SHOOTING CODE BLOCK ***** */
|
|
/* ********************************** */
|
|
|
|
if(SPfrontEnd->IFpauseTest()) {
|
|
/* user requested pause... */
|
|
UPDATE_STATS(DOING_TRAN);
|
|
return(E_PAUSE);
|
|
}
|
|
/* RESUME */
|
|
resume:
|
|
#ifdef STEPDEBUG
|
|
if( (ckt->CKTdelta <= ckt->CKTfinalTime/50) &&
|
|
(ckt->CKTdelta <= ckt->CKTmaxStep)) {
|
|
;
|
|
} else {
|
|
if(ckt->CKTfinalTime/50<ckt->CKTmaxStep) {
|
|
fprintf (stderr, "limited by Tstop/50\n");
|
|
} else {
|
|
fprintf (stderr, "limited by Tmax == %g\n", ckt->CKTmaxStep);
|
|
}
|
|
}
|
|
#endif
|
|
#ifdef HAS_WINDOWS
|
|
if (ckt->CKTtime == 0.)
|
|
SetAnalyse( "tran init", 0);
|
|
else if ((pss_state != PSS) && (shooting_cycle_counter > 0))
|
|
SetAnalyse("shooting", shooting_cycle_counter) ;
|
|
else
|
|
SetAnalyse( "tran", (int)((ckt->CKTtime * 1000.) / ckt->CKTfinalTime));
|
|
#endif
|
|
ckt->CKTdelta =
|
|
MIN(ckt->CKTdelta,ckt->CKTmaxStep);
|
|
#ifdef XSPICE
|
|
/* gtri - begin - wbk - Cut integration order if first timepoint after breakpoint */
|
|
/* if(ckt->CKTtime == g_mif_info.breakpoint.last) */
|
|
if ( AlmostEqualUlps( ckt->CKTtime, g_mif_info.breakpoint.last, 100 ) )
|
|
ckt->CKTorder = 1;
|
|
/* gtri - end - wbk - Cut integration order if first timepoint after breakpoint */
|
|
|
|
#endif
|
|
|
|
/* are we at a breakpoint, or indistinguishably close? */
|
|
/* if ((ckt->CKTtime == ckt->CKTbreaks[0]) || (ckt->CKTbreaks[0] - */
|
|
if (ckt->CKTbreaks [0] - ckt->CKTtime <= ckt->CKTdelmin)
|
|
{
|
|
/*if ( AlmostEqualUlps( ckt->CKTtime, ckt->CKTbreaks[0], 100 ) || (ckt->CKTbreaks[0] -
|
|
* (ckt->CKTtime) <= ckt->CKTdelmin)) {*/
|
|
/* first timepoint after a breakpoint - cut integration order */
|
|
/* and limit timestep to .1 times minimum of time to next breakpoint,
|
|
* and previous timestep
|
|
*/
|
|
ckt->CKTorder = 1;
|
|
#ifdef STEPDEBUG
|
|
if( (ckt->CKTdelta > .1*ckt->CKTsaveDelta) ||
|
|
(ckt->CKTdelta > .1*(ckt->CKTbreaks[1] - ckt->CKTbreaks[0])) ) {
|
|
if(ckt->CKTsaveDelta < (ckt->CKTbreaks[1] - ckt->CKTbreaks[0])) {
|
|
fprintf (stderr, "limited by pre-breakpoint delta (saveDelta: %1.10g, nxt_breakpt: %1.10g, curr_breakpt: %1.10g and CKTtime: %1.10g\n",
|
|
ckt->CKTsaveDelta, ckt->CKTbreaks [1], ckt->CKTbreaks [0], ckt->CKTtime) ;
|
|
} else {
|
|
fprintf (stderr, "limited by next breakpoint\n") ;
|
|
fprintf (stderr, "(saveDelta: %1.10g, Delta: %1.10g, CKTtime: %1.10g and delmin: %1.10g\n",
|
|
ckt->CKTsaveDelta, ckt->CKTdelta, ckt->CKTtime, ckt->CKTdelmin) ;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if (ckt->CKTbreaks [1] - ckt->CKTbreaks [0] == 0)
|
|
ckt->CKTdelta = ckt->CKTdelmin ;
|
|
else
|
|
ckt->CKTdelta = MIN (ckt->CKTdelta, .1 * MIN (ckt->CKTsaveDelta,
|
|
ckt->CKTbreaks[1] - ckt->CKTbreaks[0]));
|
|
|
|
if(firsttime) {
|
|
ckt->CKTdelta /= 10;
|
|
#ifdef STEPDEBUG
|
|
fprintf(stderr, "delta cut for initial timepoint\n");
|
|
#endif
|
|
}
|
|
|
|
#ifdef XSPICE
|
|
}
|
|
|
|
/* gtri - begin - wbk - Add Breakpoint stuff */
|
|
|
|
if(ckt->CKTtime + ckt->CKTdelta >= g_mif_info.breakpoint.current) {
|
|
/* If next time > temporary breakpoint, force it to the breakpoint */
|
|
/* And mark that timestep was set by temporary breakpoint */
|
|
ckt->CKTsaveDelta = ckt->CKTdelta;
|
|
ckt->CKTdelta = g_mif_info.breakpoint.current - ckt->CKTtime;
|
|
g_mif_info.breakpoint.last = ckt->CKTtime + ckt->CKTdelta;
|
|
} else {
|
|
/* Else, mark that timestep was not set by temporary breakpoint */
|
|
g_mif_info.breakpoint.last = HUGE_VAL;
|
|
}
|
|
|
|
/* gtri - end - wbk - Add Breakpoint stuff */
|
|
|
|
/* gtri - begin - wbk - Modify Breakpoint stuff */
|
|
/* Throw out any permanent breakpoint times <= current time */
|
|
for (;;) {
|
|
#ifdef STEPDEBUG
|
|
fprintf (stderr, " brk_pt: %g ckt_time: %g ckt_min_break: %g\n", ckt->CKTbreaks [0], ckt->CKTtime, ckt->CKTminBreak) ;
|
|
#endif
|
|
if(AlmostEqualUlps(ckt->CKTbreaks[0], ckt->CKTtime, 100) ||
|
|
ckt->CKTbreaks[0] <= ckt->CKTtime + ckt->CKTminBreak) {
|
|
fprintf (stderr, "throwing out permanent breakpoint times <= current time (brk pt: %g)\n", ckt->CKTbreaks [0]) ;
|
|
fprintf (stderr, "ckt_time: %g ckt_min_break: %g\n", ckt->CKTtime, ckt->CKTminBreak) ;
|
|
CKTclrBreak(ckt);
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
/* Force the breakpoint if appropriate */
|
|
if(ckt->CKTtime + ckt->CKTdelta > ckt->CKTbreaks[0]) {
|
|
ckt->CKTbreak = 1;
|
|
ckt->CKTsaveDelta = ckt->CKTdelta;
|
|
ckt->CKTdelta = ckt->CKTbreaks[0] - ckt->CKTtime;
|
|
}
|
|
|
|
/* gtri - end - wbk - Modify Breakpoint stuff */
|
|
#else /* !XSPICE */
|
|
|
|
/* don't want to get below delmin for no reason */
|
|
ckt->CKTdelta = MAX(ckt->CKTdelta, ckt->CKTdelmin*2.0);
|
|
}
|
|
else if(ckt->CKTtime + ckt->CKTdelta >= ckt->CKTbreaks[0]) {
|
|
ckt->CKTsaveDelta = ckt->CKTdelta;
|
|
ckt->CKTdelta = ckt->CKTbreaks[0] - ckt->CKTtime;
|
|
/* fprintf (stderr, "delta cut to %g to hit breakpoint\n" ,ckt->CKTdelta) ; */
|
|
fflush(stdout);
|
|
ckt->CKTbreak = 1; /* why? the current pt. is not a bkpt. */
|
|
}
|
|
#ifdef CLUSTER
|
|
if(!CLUsync(ckt->CKTtime,&ckt->CKTdelta,0)) {
|
|
fprintf (stderr, "Sync error!\n");
|
|
exit(0);
|
|
}
|
|
#endif
|
|
|
|
#endif /* XSPICE */
|
|
|
|
#ifdef XSPICE
|
|
/* gtri - begin - wbk - Do event solution */
|
|
|
|
if(ckt->evt->counts.num_insts > 0) {
|
|
|
|
/* if time = 0 and op_alternate was specified as false during */
|
|
/* dcop analysis, call any changed instances to let them */
|
|
/* post their outputs with their associated delays */
|
|
if((ckt->CKTtime == 0.0) && (! ckt->evt->options.op_alternate))
|
|
EVTiter(ckt);
|
|
|
|
/* while there are events on the queue with event time <= next */
|
|
/* projected analog time, process them */
|
|
while((g_mif_info.circuit.evt_step = EVTnext_time(ckt))
|
|
<= (ckt->CKTtime + ckt->CKTdelta)) {
|
|
|
|
/* Initialize temp analog bkpt to infinity */
|
|
g_mif_info.breakpoint.current = HUGE_VAL;
|
|
|
|
/* Pull items off queue and process them */
|
|
EVTdequeue(ckt, g_mif_info.circuit.evt_step);
|
|
EVTiter(ckt);
|
|
|
|
/* If any instances have forced an earlier */
|
|
/* next analog time, cut the delta */
|
|
if(ckt->CKTbreaks[0] < g_mif_info.breakpoint.current)
|
|
if(ckt->CKTbreaks[0] > ckt->CKTtime + ckt->CKTminBreak)
|
|
g_mif_info.breakpoint.current = ckt->CKTbreaks[0];
|
|
if(g_mif_info.breakpoint.current < ckt->CKTtime + ckt->CKTdelta) {
|
|
/* Breakpoint must be > last accepted timepoint */
|
|
/* and >= current event time */
|
|
if(g_mif_info.breakpoint.current > ckt->CKTtime + ckt->CKTminBreak &&
|
|
g_mif_info.breakpoint.current >= g_mif_info.circuit.evt_step) {
|
|
ckt->CKTsaveDelta = ckt->CKTdelta;
|
|
ckt->CKTdelta = g_mif_info.breakpoint.current - ckt->CKTtime;
|
|
g_mif_info.breakpoint.last = ckt->CKTtime + ckt->CKTdelta;
|
|
}
|
|
}
|
|
|
|
} /* end while next event time <= next analog time */
|
|
} /* end if there are event instances */
|
|
|
|
/* gtri - end - wbk - Do event solution */
|
|
#endif
|
|
|
|
/* What is that??? */
|
|
for(i=5; i>=0; i--)
|
|
ckt->CKTdeltaOld[i+1] = ckt->CKTdeltaOld[i];
|
|
ckt->CKTdeltaOld[0] = ckt->CKTdelta;
|
|
|
|
temp = ckt->CKTstates[ckt->CKTmaxOrder+1];
|
|
for(i=ckt->CKTmaxOrder;i>=0;i--) {
|
|
ckt->CKTstates[i+1] = ckt->CKTstates[i];
|
|
}
|
|
ckt->CKTstates[0] = temp;
|
|
|
|
/* 600 */
|
|
for (;;) {
|
|
#ifdef CLUSTER
|
|
redostep = 1;
|
|
#endif
|
|
#ifdef XSPICE
|
|
/* gtri - add - wbk - 4/17/91 - Fix Berkeley bug */
|
|
/* This is needed here to allow CAPask to output currents */
|
|
/* during Transient analysis. A grep for CKTcurrentAnalysis */
|
|
/* indicates that it should not hurt anything else ... */
|
|
|
|
ckt->CKTcurrentAnalysis = DOING_TRAN;
|
|
|
|
/* gtri - end - wbk - 4/17/91 - Fix Berkeley bug */
|
|
#endif
|
|
olddelta=ckt->CKTdelta;
|
|
/* time abort? */
|
|
ckt->CKTtime += ckt->CKTdelta;
|
|
#ifdef CLUSTER
|
|
CLUinput(ckt);
|
|
#endif
|
|
ckt->CKTdeltaOld[0]=ckt->CKTdelta;
|
|
NIcomCof(ckt);
|
|
#ifdef PREDICTOR
|
|
error = NIpred(ckt);
|
|
#endif /* PREDICTOR */
|
|
save_mode = ckt->CKTmode;
|
|
save_order = ckt->CKTorder;
|
|
#ifdef XSPICE
|
|
/* gtri - begin - wbk - Add Breakpoint stuff */
|
|
|
|
/* Initialize temporary breakpoint to infinity */
|
|
g_mif_info.breakpoint.current = HUGE_VAL;
|
|
|
|
/* gtri - end - wbk - Add Breakpoint stuff */
|
|
|
|
|
|
/* gtri - begin - wbk - add convergence problem reporting flags */
|
|
/* delta is forced to equal delmin on last attempt near line 650 */
|
|
if(ckt->CKTdelta <= ckt->CKTdelmin)
|
|
ckt->enh->conv_debug.last_NIiter_call = MIF_TRUE;
|
|
else
|
|
ckt->enh->conv_debug.last_NIiter_call = MIF_FALSE;
|
|
/* gtri - begin - wbk - add convergence problem reporting flags */
|
|
|
|
|
|
/* gtri - begin - wbk - Call all hybrids */
|
|
|
|
/* gtri - begin - wbk - Set evt_step */
|
|
|
|
if(ckt->evt->counts.num_insts > 0) {
|
|
g_mif_info.circuit.evt_step = ckt->CKTtime;
|
|
}
|
|
/* gtri - end - wbk - Set evt_step */
|
|
#endif
|
|
|
|
converged = NIiter(ckt,ckt->CKTtranMaxIter);
|
|
|
|
#ifdef XSPICE
|
|
if(ckt->evt->counts.num_insts > 0) {
|
|
g_mif_info.circuit.evt_step = ckt->CKTtime;
|
|
EVTcall_hybrids(ckt);
|
|
}
|
|
/* gtri - end - wbk - Call all hybrids */
|
|
|
|
#endif
|
|
ckt->CKTstat->STATtimePts ++;
|
|
ckt->CKTmode = (ckt->CKTmode&MODEUIC)|MODETRAN | MODEINITPRED;
|
|
if(firsttime) {
|
|
for(i=0;i<ckt->CKTnumStates;i++) {
|
|
ckt->CKTstate2[i] = ckt->CKTstate1[i];
|
|
ckt->CKTstate3[i] = ckt->CKTstate1[i];
|
|
}
|
|
}
|
|
/* txl, cpl addition */
|
|
if (converged == 1111) {
|
|
return(converged);
|
|
}
|
|
|
|
#ifdef STEPDEBUG
|
|
if (pss_state == PSS)
|
|
fprintf (stderr, "pss_state: %d, converged: %d\n", pss_state, converged) ;
|
|
#endif
|
|
if(converged != 0) {
|
|
#ifndef CLUSTER
|
|
ckt->CKTtime = ckt->CKTtime -ckt->CKTdelta;
|
|
ckt->CKTstat->STATrejected ++;
|
|
#endif
|
|
ckt->CKTdelta = ckt->CKTdelta/8;
|
|
#ifdef STEPDEBUG
|
|
fprintf (stderr, "delta cut to %g for non-convergance\n", ckt->CKTdelta) ;
|
|
fflush(stdout);
|
|
#endif
|
|
if(firsttime) {
|
|
ckt->CKTmode = (ckt->CKTmode&MODEUIC) | MODETRAN | MODEINITTRAN;
|
|
}
|
|
ckt->CKTorder = 1;
|
|
|
|
#ifdef XSPICE
|
|
/* gtri - begin - wbk - Add Breakpoint stuff */
|
|
|
|
/* Force backup if temporary breakpoint is < current time */
|
|
} else if(g_mif_info.breakpoint.current < ckt->CKTtime) {
|
|
ckt->CKTsaveDelta = ckt->CKTdelta;
|
|
ckt->CKTtime -= ckt->CKTdelta;
|
|
ckt->CKTdelta = g_mif_info.breakpoint.current - ckt->CKTtime;
|
|
g_mif_info.breakpoint.last = ckt->CKTtime + ckt->CKTdelta;
|
|
|
|
if(firsttime) {
|
|
ckt->CKTmode = (ckt->CKTmode&MODEUIC)|MODETRAN | MODEINITTRAN;
|
|
}
|
|
ckt->CKTorder = 1;
|
|
|
|
/* gtri - end - wbk - Add Breakpoint stuff */
|
|
#endif
|
|
|
|
} else {
|
|
if (firsttime) {
|
|
firsttime = 0;
|
|
#ifndef CLUSTER
|
|
goto nextTime; /* no check on
|
|
* first time point
|
|
*/
|
|
#else
|
|
redostep = 0;
|
|
goto chkStep;
|
|
#endif
|
|
}
|
|
newdelta = ckt->CKTdelta;
|
|
error = CKTtrunc(ckt,&newdelta);
|
|
if(error) {
|
|
UPDATE_STATS(DOING_TRAN);
|
|
return(error);
|
|
}
|
|
if(newdelta > .9 * ckt->CKTdelta) {
|
|
if((ckt->CKTorder == 1) && (ckt->CKTmaxOrder > 1)) { /* don't rise the order for backward Euler */
|
|
newdelta = ckt->CKTdelta;
|
|
ckt->CKTorder = 2;
|
|
error = CKTtrunc(ckt,&newdelta);
|
|
if(error) {
|
|
UPDATE_STATS(DOING_TRAN);
|
|
return(error);
|
|
}
|
|
if(newdelta <= 1.05 * ckt->CKTdelta) {
|
|
ckt->CKTorder = 1;
|
|
}
|
|
}
|
|
/* time point OK - 630 */
|
|
ckt->CKTdelta = newdelta;
|
|
#ifdef NDEV
|
|
/* show a time process indicator, by Gong Ding, gdiso@ustc.edu */
|
|
if(ckt->CKTtime/ckt->CKTfinalTime*100<10.0)
|
|
fprintf (stderr, "%%%3.2lf\b\b\b\b\b", ckt->CKTtime / ckt->CKTfinalTime * 100) ;
|
|
else if(ckt->CKTtime/ckt->CKTfinalTime*100<100.0)
|
|
fprintf (stderr, "%%%4.2lf\b\b\b\b\b\b", ckt->CKTtime / ckt->CKTfinalTime * 100) ;
|
|
else
|
|
fprintf (stderr, "%%%5.2lf\b\b\b\b\b\b\b", ckt->CKTtime / ckt->CKTfinalTime * 100) ;
|
|
fflush(stdout);
|
|
#endif
|
|
|
|
#ifdef STEPDEBUG
|
|
fprintf (stderr, "delta set to truncation error result: %g. Point accepted at CKTtime: %g\n", ckt->CKTdelta, ckt->CKTtime) ;
|
|
fflush(stdout);
|
|
#endif
|
|
|
|
#ifndef CLUSTER
|
|
/* go to 650 - trapezoidal */
|
|
goto nextTime;
|
|
#else
|
|
redostep = 0;
|
|
goto chkStep;
|
|
#endif
|
|
} else { /* newdelta <= .9 * ckt->CKTdelta */
|
|
#ifndef CLUSTER
|
|
ckt->CKTtime = ckt->CKTtime -ckt->CKTdelta;
|
|
ckt->CKTstat->STATrejected ++;
|
|
#endif
|
|
ckt->CKTdelta = newdelta;
|
|
#ifdef STEPDEBUG
|
|
fprintf (stderr, "delta set to truncation error result:point rejected\n") ;
|
|
#endif
|
|
}
|
|
}
|
|
|
|
if (ckt->CKTdelta <= ckt->CKTdelmin) {
|
|
if (olddelta > ckt->CKTdelmin) {
|
|
ckt->CKTdelta = ckt->CKTdelmin;
|
|
#ifdef STEPDEBUG
|
|
fprintf (stderr, "delta at delmin\n");
|
|
#endif
|
|
} else {
|
|
UPDATE_STATS(DOING_TRAN);
|
|
errMsg = CKTtrouble(ckt, "Timestep too small");
|
|
return(E_TIMESTEP);
|
|
}
|
|
}
|
|
#ifdef XSPICE
|
|
/* gtri - begin - wbk - Do event backup */
|
|
|
|
if(ckt->evt->counts.num_insts > 0)
|
|
EVTbackup(ckt, ckt->CKTtime + ckt->CKTdelta);
|
|
|
|
/* gtri - end - wbk - Do event backup */
|
|
#endif
|
|
#ifdef CLUSTER
|
|
chkStep:
|
|
if(CLUsync(ckt->CKTtime,&ckt->CKTdelta,redostep)){
|
|
goto nextTime;
|
|
} else {
|
|
ckt->CKTtime -= olddelta;
|
|
ckt->CKTstat->STATrejected ++;
|
|
}
|
|
#endif
|
|
}
|
|
/* NOTREACHED */
|
|
}
|
|
|
|
static int
|
|
DFT
|
|
(
|
|
long int ndata, /* number of entries in the Time and Value arrays */
|
|
int numFreq, /* number of harmonics to calculate */
|
|
double *thd, /* total harmonic distortion (percent) to be returned */
|
|
double *Time, /* times at which the voltage/current values were measured */
|
|
double *Value, /* voltage or current vector whose transform is desired */
|
|
double FundFreq, /* the fundamental frequency of the analysis */
|
|
double *Freq, /* the frequency value of the various harmonics */
|
|
double *Mag, /* the Magnitude of the fourier transform */
|
|
double *Phase, /* the Phase of the fourier transform */
|
|
double *nMag, /* the normalized magnitude of the transform: nMag (fund) = 1 */
|
|
double *nPhase /* the normalized phase of the transform: Nphase (fund) = 0 */
|
|
)
|
|
{
|
|
/* Note: we can consider these as a set of arrays. The sizes are:
|
|
* Time [ndata], Value [ndata], Freq [numFreq], Mag [numfreq],
|
|
* Phase [numfreq], nMag [numfreq], nPhase [numfreq]
|
|
*
|
|
* The arrays must all be allocated by the caller.
|
|
* The Time and Value array must be reasonably distributed over at
|
|
* least one full period of the fundamental Frequency for the
|
|
* fourier transform to be useful. The function will take the
|
|
* last period of the frequency as data for the transform.
|
|
*
|
|
* We are assuming that the caller has provided exactly one period
|
|
* of the fundamental frequency. */
|
|
int i, j;
|
|
double tmp;
|
|
|
|
NG_IGNORE (Time);
|
|
|
|
/* clear output/computation arrays */
|
|
|
|
for (i = 0; i < numFreq; i++) {
|
|
Mag [i] = 0;
|
|
Phase [i] = 0;
|
|
}
|
|
|
|
for (i = 0; i < ndata; i++) {
|
|
for (j = 0; j < numFreq; j++) {
|
|
Mag [j] += (Value [i] * sin (j * 2.0 * M_PI * i / ((double)ndata)));
|
|
Phase [j] += (Value [i] * cos (j * 2.0 * M_PI * i / ((double)ndata)));
|
|
}
|
|
}
|
|
|
|
Mag [0] = Phase [0] / (double)ndata;
|
|
Phase [0] = 0;
|
|
nMag [0] = 0;
|
|
nPhase [0] = 0;
|
|
Freq [0] = 0;
|
|
*thd = 0;
|
|
|
|
for (i = 1; i < numFreq; i++) {
|
|
tmp = Mag [i] * 2.0 / (double)ndata;
|
|
Phase [i] *= 2.0 / (double)ndata;
|
|
Freq [i] = i * FundFreq;
|
|
Mag [i] = sqrt (tmp * tmp + Phase [i] * Phase [i]);
|
|
Phase [i] = atan2 (Phase [i], tmp) * 180.0 / M_PI;
|
|
nMag [i] = Mag [i] / Mag [1];
|
|
nPhase [i] = Phase [i] - Phase [1];
|
|
if (i > 1)
|
|
*thd += nMag [i] * nMag [i];
|
|
}
|
|
|
|
*thd = 100 * sqrt (*thd);
|
|
return (OK);
|
|
}
|