initial loop analysis code

This commit is contained in:
Florian Ballenegger 2020-09-03 15:08:40 +02:00
parent a0389bb547
commit 4f076ed210
8 changed files with 201 additions and 1 deletions

View File

@ -70,6 +70,10 @@ AC_ARG_ENABLE([adms],
AC_ARG_ENABLE([pss],
[AS_HELP_STRING([--enable-pss], [Enable PSS Analysis, (experimental)])])
# --enable-loopana: enable Loop Analysis
AC_ARG_ENABLE([loopana],
[AS_HELP_STRING([--enable-loopana], [Enable Loop Analysis])])
# --enable-relpath: Relative path for binary and data. Default is "no".
# ngspice shared may want relative paths for spinit etc.
AC_ARG_ENABLE([relpath],
@ -967,6 +971,11 @@ if test "x$enable_pss" = xyes; then
AC_DEFINE([WITH_PSS], [], [Define if you want PSS analysis])
AC_MSG_RESULT([WARNING: PSS analysis enabled])
fi
if test "x$enable_loopana" = xyes; then
AC_DEFINE([WITH_LOOPANA], [], [Define if you want LOOP analysis])
AC_MSG_RESULT([WARNING: LOOP analysis enabled])
fi
if test "x$enable_blktmsdebug" = xyes; then
AC_DEFINE([D_DBG_BLOCKTIMES], [], [Define if we want debug distortion analysis (BLOCKTIMES)])
AC_MSG_RESULT([WARNING: Distortion analysis debug *D_DBG_BLOCKTIMES* is enabled])
@ -1059,6 +1068,8 @@ AM_CONDITIONAL([NUMDEV_WANTED], [test "x$enable_cider" = xyes])
AM_CONDITIONAL([PSS_WANTED], [test "x$enable_pss" = xyes])
AM_CONDITIONAL([LOOPANA_WANTED], [test "x$enable_loopana" = xyes])
AM_CONDITIONAL([SENSE2_WANTED], [test "x$enable_sense2" = xyes])
# adms option

View File

@ -220,6 +220,9 @@ if_run(CKTcircuit *ckt, char *what, wordlist *args, INPtables *tab)
/* SP: Steady State Analysis */
|| eq(what, "pss")
/* SP */
#endif
#ifdef WITH_LOOPANA
|| eq(what, "loop")
#endif
)
{
@ -335,6 +338,9 @@ if_run(CKTcircuit *ckt, char *what, wordlist *args, INPtables *tab)
/* SP: Steady State Analysis */
(eq(what, "pss")) ||
/* SP */
#endif
#ifdef WITH_LOOPANA
(eq(what, "loop")) ||
#endif
(eq(what, "run")))
{

View File

@ -86,7 +86,9 @@ static struct plotab plotabs[NUMPLOTTYPES] = {
{ "sp", "sp", FALSE, FALSE },
{ "harm", "harm", FALSE, FALSE },
{ "spect", "spect", FALSE, FALSE },
{ "pss", "periodic", FALSE, FALSE }
{ "pss", "periodic", FALSE, FALSE },
{ "loop", "loop", FALSE, FALSE },
};

View File

@ -106,6 +106,12 @@ libckt_la_SOURCES += \
psssetp.c
endif
if LOOPANA_WANTED
libckt_la_SOURCES += \
loopan.c \
loopsetp.c \
loopaskq.c
endif
AM_CPPFLAGS = @AM_CPPFLAGS@ -I$(top_srcdir)/src/include -I$(top_srcdir)/src/spicelib/devices
AM_CFLAGS = $(STATIC)

View File

@ -20,6 +20,10 @@ extern SPICEanalysis SENSinfo;
extern SPICEanalysis PSSinfo;
#endif
#ifdef WITH_LOOPANA
extern SPICEanalysis LOOPinfo;
#endif
#ifdef WANT_SENSE2
extern SPICEanalysis SEN2info;
#endif
@ -38,6 +42,9 @@ SPICEanalysis *analInfo[] = {
#ifdef WITH_PSS
&PSSinfo,
#endif
#ifdef WITH_LOOPANA
&LOOPinfo,
#endif
#ifdef WANT_SENSE2
&SEN2info,
#endif

View File

@ -10,6 +10,9 @@ struct SPICEanalysis {
int (*askQuest)(CKTcircuit *ckt, JOB *anal, int which, IFvalue *value);
int (*an_init)(CKTcircuit *ckt, JOB *job);
int (*an_func)(CKTcircuit *ckt, int restart);
#ifdef WITH_LOOPANA
int (*an_preset)(CKTcircuit *ckt, JOB *job);
#endif
};

View File

@ -156,6 +156,20 @@ CKTdoJob(CKTcircuit *ckt, int reset, TSKtask *task)
/* gtri - end - 12/12/90 */
#endif
#ifdef WITH_LOOPANA
/* add opportunity to modify the circuit before CKTsetup */
/* Note that it must be done in a benign way in order not to */
/* affect others analysis */
for (i = 0; i < ANALmaxnum; i++)
for (job = task->jobs; job; job = job->JOBnextJob)
if (job->JOBtype == i)
if (!error)
{
if (analInfo[i]->an_preset)
error = analInfo[i]->an_preset (ckt, job);
}
#endif
if (!error)
error = CKTsetup(ckt);

View File

@ -14,6 +14,21 @@ Modified: 2000 AlansFixes
#include "ngspice/cpdefs.h"
#include "ngspice/tskdefs.h"
/* F.B. 2020
parse additionnal parameters in the form key=val.
Use analysis INFO IFparm list to check if key is recognized and
the type of val.
*/
static int
dot_params(char *line, CKTcircuit *ckt, int ana, JOB* job)
{
char *name; /* the resistor's name */
while(*line)
{
}
}
static int
dot_noise(char *line, CKTcircuit *ckt, INPtables *tab, struct card *current,
TSKtask *task, CKTnode *gnode, JOB *foo)
@ -553,6 +568,137 @@ dot_sens2(char *line, CKTcircuit *ckt, INPtables *tab, struct card *current,
}
#endif
#ifdef WITH_LOOPANA
int
dot_loop(char *line, void *ckt, INPtables *tab, struct card *current,
void *task, void *gnode, JOB *foo)
{
int error; /* error code temporary */
IFvalue ptemp; /* a value structure to package resistance into */
IFvalue *parm; /* a pointer to a value struct for function returns */
char *nname; /* the oscNode name */
CKTnode *nnode; /* the oscNode node */
int which; /* which analysis we are performing */
char *word; /* something to stick a word of input into */
char *steptype; /* type of stepping function */
char *name; /* a name */
static char* probesparams[2]={"probe","probe-"};
static char* probenumparams[2]={"portnum","portnum-"};
static char* probenameparams[2]={"portname","portname-"};
static char* dirparams[2]={"dir","dir-"};
NG_IGNORE(gnode);
/* .loop probe {DEC OCT LIN} NP FSTART FSTOP */
/* @M2(#2) @M2:gate:into
*/
which = ft_find_analysis("LOOP");
if (which == -1) {
LITERR("Loop analysis unsupported.\n");
return (0);
}
IFC(newAnalysis, (ckt, which, "Loop gain analysis", &foo, task));
for(int diff=0;diff<2;diff++)
{
INPgetTok(&line, &name, 1);
INPinsert(&name, tab);
if(0) printf("loop probe element is %s\n", name);
ptemp.uValue = name;
GCA(INPapName, (ckt, which, foo, probesparams[diff], &ptemp));
if(*line=='/')
{
INPgetTok(&line, &name, 1); /* eat / */
tfree(name);
INPgetTok(&line, &name, 1);
if(*name== '#') {
if(0) printf("port number %d\n",atoi(&name[1]));
ptemp.iValue = atoi(&name[1]);
tfree(name);
GCA(INPapName, (ckt, which, foo, probenumparams[diff], &ptemp));
} else {
if(0) printf("port name %s\n",name);
ptemp.uValue = name;
GCA(INPapName, (ckt, which, foo, probenameparams[diff], &ptemp));
}
}
if(*line=='/')
{
INPgetTok(&line, &name, 1); /* eat / */
tfree(name);
INPgetTok(&line, &name, 1);
if(strcmp(name, "in")==0 || strcmp(name, "into")==0
|| strcmp(name, "to")==0 ) {
if(0) printf("into\n");
ptemp.iValue = 1;
GCA(INPapName, (ckt, which, foo, dirparams[diff], &ptemp));
} else if(strcmp(name, "out")==0 || strcmp(name, "from")==0
|| strcmp(name, "outfrom")==0) {
if(0) printf("out\n");
ptemp.iValue = 2;
GCA(INPapName, (ckt, which, foo, dirparams[diff], &ptemp));
} else
printf("syntax error for .loop, expect direction, got %s\n", name);
tfree(name);
}
if(*line != '+') break;
INPgetTok(&line, &name, 1); tfree(name); /* eat the + and start again*/
}
INPgetTok(&line, &steptype, 1);
ptemp.iValue = 1;
GCA(INPapName, (ckt, which, foo, steptype, &ptemp));
tfree(steptype);
parm = INPgetValue(ckt, &line, IF_INTEGER, tab); /* number of points */
GCA(INPapName, (ckt, which, foo, "numsteps", parm));
parm = INPgetValue(ckt, &line, IF_REAL, tab); /* fstart */
GCA(INPapName, (ckt, which, foo, "start", parm));
parm = INPgetValue(ckt, &line, IF_REAL, tab); /* fstop */
GCA(INPapName, (ckt, which, foo, "stop", parm));
if(*line)
{
/* input & output follows for transfert function calculations */
INPgetTok(&line, &name, 1);
INPinsert(&name, tab);
ptemp.uValue = name;
GCA(INPapName, (ckt, which, foo, "insrc", &ptemp));
INPgetTok(&line, &name, 1);
if(strcmp(name,"v")==0 && *line=='(')
{
/* v(pos,neg) format */
tfree(name);
INPgetNetTok(&line, &name, 0);
INPtermInsert(ckt, &name, tab, &ptemp.nValue);
GCA(INPapName, (ckt, which, foo, "outpos", &ptemp));
if(*line==',') {
INPgetNetTok(&line, &name, 1);
INPtermInsert(ckt, &name, tab, &ptemp.nValue);
GCA(INPapName, (ckt, which, foo, "outneg", &ptemp));
} else {
ptemp.nValue = gnode;
GCA(INPapName, (ckt, which, foo, "outneg", &ptemp));
}
}
else
{
INPinsert(&name, tab);
ptemp.uValue = name;
GCA(INPapName, (ckt, which, foo, "outsrc", &ptemp));
}
}
return (0);
}
#endif
#ifdef WITH_PSS
/*SP: Steady State Analyis */
static int
@ -699,6 +845,11 @@ INP2dot(CKTcircuit *ckt, INPtables *tab, struct card *current, TSKtask *task, CK
rtn = dot_pss(line, ckt, tab, current, task, gnode, foo);
goto quit;
/* SP */
#endif
#ifdef WITH_LOOPANA
} else if ((strcmp(token, ".loop") == 0)) {
rtn = dot_loop(line, ckt, tab, current, task, gnode, foo);
goto quit;
#endif
} else if ((strcmp(token, ".subckt") == 0) ||
(strcmp(token, ".ends") == 0)) {