Enhance sensitivity analysis with an option to choose the parameters
to be varied. Shell-style wildcards ("*?") are supported.
This commit is contained in:
parent
c30bc423ba
commit
abc3fceb7e
|
|
@ -18,15 +18,11 @@ Modified: 2000 AlanFixes
|
|||
/* #define ASDEBUG */
|
||||
#ifdef ASDEBUG
|
||||
#define DEBUG(X) if ((X) < Sens_Debug)
|
||||
int Sens_Debug = 0;
|
||||
char SF1[] = "res";
|
||||
char SF2[] = "dc";
|
||||
char SF3[] = "bf";
|
||||
static int Sens_Debug = 0;
|
||||
#endif
|
||||
|
||||
char* Sfilter = NULL;
|
||||
double Sens_Delta = 0.000001;
|
||||
double Sens_Abs_Delta = 0.000001;
|
||||
static double Sens_Delta = 0.000001;
|
||||
static double Sens_Abs_Delta = 0.000001;
|
||||
|
||||
static int sens_setp(sgen* sg, CKTcircuit* ckt, IFvalue* val);
|
||||
static int sens_load(sgen* sg, CKTcircuit* ckt, int is_dc);
|
||||
|
|
@ -34,6 +30,42 @@ static int sens_temp(sgen* sg, CKTcircuit* ckt);
|
|||
static int count_steps(int type, double low, double high, int steps, double* stepsize);
|
||||
static double inc_freq(double freq, int type, double step_size);
|
||||
|
||||
char **Sens_filter;
|
||||
|
||||
/* Match a potential vector name against a filter string. */
|
||||
|
||||
static int scan(char *filter, char *name)
|
||||
{
|
||||
while (*filter && *name) {
|
||||
if (*filter == '*') {
|
||||
if (!filter[1])
|
||||
return 1; // Terminal '*' matches all.
|
||||
while (*name && !scan(filter + 1, name))
|
||||
++name;
|
||||
return *name != '\0';
|
||||
}
|
||||
if (*filter == *name || *filter == '?')
|
||||
++name, ++filter;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Match if both strings exhausted. */
|
||||
|
||||
return !*name && (!*filter || (*filter == '*' && !filter[1]));
|
||||
}
|
||||
|
||||
static int check_filter(char *name)
|
||||
{
|
||||
char **pp, *filter;
|
||||
|
||||
for (pp = Sens_filter; (filter = *pp); pp++) {
|
||||
if (scan(filter, name))
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define save_context(thing, place) { \
|
||||
place = thing; \
|
||||
}
|
||||
|
|
@ -75,7 +107,7 @@ int sens_sens(CKTcircuit* ckt, int restart)
|
|||
|
||||
static int size;
|
||||
static double* delta_I, * delta_iI,
|
||||
* delta_I_delta_Y, * delta_iI_delta_Y;
|
||||
* delta_I_delta_Y, * delta_iI_delta_Y;
|
||||
sgen* sg;
|
||||
static double freq;
|
||||
static int nfreqs;
|
||||
|
|
@ -90,14 +122,13 @@ int sens_sens(CKTcircuit* ckt, int restart)
|
|||
int (*fn) (SMPmatrix*, GENmodel*, CKTcircuit*, int*);
|
||||
static int is_dc;
|
||||
int k, j, n;
|
||||
int num_vars, branch_eq = 0;
|
||||
int num_vars, branch_eq = 0;
|
||||
runDesc* sen_data = NULL;
|
||||
char namebuf[513];
|
||||
IFuid* output_names, freq_name;
|
||||
IFuid *vec_names, *output_names, freq_name;
|
||||
int bypass;
|
||||
int type;
|
||||
double* saved_rhs = NULL,
|
||||
* saved_irhs = NULL;
|
||||
* saved_irhs = NULL;
|
||||
SMPmatrix* saved_matrix = NULL;
|
||||
|
||||
#ifdef KLU
|
||||
|
|
@ -185,31 +216,53 @@ int sens_sens(CKTcircuit* ckt, int restart)
|
|||
if (!num_vars)
|
||||
return OK; /* XXXX Should be E_ something */
|
||||
|
||||
k = 0;
|
||||
output_names = TMALLOC(IFuid, num_vars);
|
||||
k = 0;
|
||||
num_vars = 0;
|
||||
for (sg = sgen_init(ckt, is_dc); sg; sgen_next(&sg)) {
|
||||
char namebuf[513];
|
||||
|
||||
if (!sg->is_instparam) {
|
||||
sprintf(namebuf, "%s:%s",
|
||||
sg->instance->GENname,
|
||||
sg->ptable[sg->param].keyword);
|
||||
snprintf(namebuf, sizeof namebuf, "%s:%s",
|
||||
sg->instance->GENname,
|
||||
sg->ptable[sg->param].keyword);
|
||||
}
|
||||
else if ((sg->ptable[sg->param].dataType
|
||||
& IF_PRINCIPAL) && sg->is_principle == 1)
|
||||
{
|
||||
sprintf(namebuf, "%s", sg->instance->GENname);
|
||||
snprintf(namebuf, sizeof namebuf, "%s", sg->instance->GENname);
|
||||
}
|
||||
else {
|
||||
sprintf(namebuf, "%s_%s",
|
||||
sg->instance->GENname,
|
||||
sg->ptable[sg->param].keyword);
|
||||
snprintf(namebuf, sizeof namebuf, "%s_%s",
|
||||
sg->instance->GENname,
|
||||
sg->ptable[sg->param].keyword);
|
||||
}
|
||||
|
||||
SPfrontEnd->IFnewUid(ckt,
|
||||
output_names + k, NULL,
|
||||
namebuf, UID_OTHER, NULL);
|
||||
/* Check against the filter list. */
|
||||
|
||||
if (!Sens_filter || check_filter(namebuf)) {
|
||||
num_vars++;
|
||||
SPfrontEnd->IFnewUid(ckt, output_names + k, NULL,
|
||||
namebuf, UID_OTHER, NULL);
|
||||
}
|
||||
k += 1;
|
||||
}
|
||||
if (num_vars == k) {
|
||||
vec_names = output_names;
|
||||
} else {
|
||||
if (!num_vars) {
|
||||
FREE(output_names);
|
||||
return OK;
|
||||
}
|
||||
|
||||
/* Make a non-sparse array of names for OUTpBeginPlot(). */
|
||||
|
||||
vec_names = TMALLOC(IFuid, num_vars);
|
||||
for (i = 0, j = 0; j < num_vars; ++i) {
|
||||
if (output_names[i])
|
||||
vec_names[j++] = output_names[i];
|
||||
}
|
||||
}
|
||||
if (is_dc) {
|
||||
type = IF_REAL;
|
||||
freq_name = NULL;
|
||||
|
|
@ -221,15 +274,18 @@ int sens_sens(CKTcircuit* ckt, int restart)
|
|||
"frequency", UID_OTHER, NULL);
|
||||
}
|
||||
|
||||
error = SPfrontEnd->OUTpBeginPlot(
|
||||
ckt, ckt->CKTcurJob,
|
||||
ckt->CKTcurJob->JOBname,
|
||||
freq_name, IF_REAL,
|
||||
num_vars, output_names, type, &sen_data);
|
||||
if (error)
|
||||
error = SPfrontEnd->OUTpBeginPlot(ckt, ckt->CKTcurJob,
|
||||
ckt->CKTcurJob->JOBname,
|
||||
freq_name, IF_REAL,
|
||||
num_vars, vec_names,
|
||||
type, &sen_data);
|
||||
if (vec_names != output_names)
|
||||
FREE(vec_names);
|
||||
if (error) {
|
||||
err:
|
||||
FREE(output_names);
|
||||
return error;
|
||||
|
||||
FREE(output_names);
|
||||
}
|
||||
if (is_dc) {
|
||||
output_values = TMALLOC(double, num_vars);
|
||||
output_cvalues = NULL;
|
||||
|
|
@ -305,7 +361,8 @@ int sens_sens(CKTcircuit* ckt, int restart)
|
|||
|
||||
if (SPfrontEnd->IFpauseTest()) {
|
||||
/* XXX Save State */
|
||||
return E_PAUSE;
|
||||
error = E_PAUSE;
|
||||
goto err;
|
||||
}
|
||||
|
||||
for (j = 0; j < size; j++) {
|
||||
|
|
@ -322,13 +379,13 @@ int sens_sens(CKTcircuit* ckt, int restart)
|
|||
/* XXX Free old states */
|
||||
error = CKTunsetup(ckt);
|
||||
if (error)
|
||||
return error;
|
||||
goto err;
|
||||
|
||||
/* XXX ckt->CKTmatrix->SPmatrix = Y; */
|
||||
|
||||
error = CKTsetup(ckt);
|
||||
if (error)
|
||||
return error;
|
||||
goto err;
|
||||
|
||||
#ifdef notdef
|
||||
for (j = 0; j <= ckt->CKTmaxOrder + 1; j++) {
|
||||
|
|
@ -338,10 +395,10 @@ int sens_sens(CKTcircuit* ckt, int restart)
|
|||
#endif
|
||||
error = CKTtemp(ckt);
|
||||
if (error)
|
||||
return error;
|
||||
goto err;
|
||||
error = CKTload(ckt); /* INITSMSIGS */
|
||||
if (error)
|
||||
return error;
|
||||
goto err;
|
||||
|
||||
#ifdef KLU
|
||||
if (ckt->CKTmatrix->CKTkluMODE)
|
||||
|
|
@ -363,7 +420,7 @@ int sens_sens(CKTcircuit* ckt, int restart)
|
|||
|
||||
error = NIacIter(ckt);
|
||||
if (error)
|
||||
return error;
|
||||
goto err;
|
||||
|
||||
#ifdef notdef
|
||||
/* XXX Why? */
|
||||
|
|
@ -389,10 +446,13 @@ int sens_sens(CKTcircuit* ckt, int restart)
|
|||
ckt->CKTmatrix = delta_Y;
|
||||
|
||||
/* calc. effect of each param */
|
||||
|
||||
k = 0;
|
||||
for (sg = sgen_init(ckt, is_dc /* job->plist */);
|
||||
sg; sgen_next(&sg))
|
||||
{
|
||||
|
||||
if (!output_names[k++])
|
||||
continue; // Ignore filtered parameters.
|
||||
#ifdef ASDEBUG
|
||||
DEBUG(2) {
|
||||
printf("E/iE: %x/%x; delta_I/iI: %x/%x\n",
|
||||
|
|
@ -486,7 +546,7 @@ int sens_sens(CKTcircuit* ckt, int restart)
|
|||
#endif
|
||||
if (sens_load(sg, ckt, is_dc)) {
|
||||
if (error && error != E_BADPARM)
|
||||
return error; /* XXX */
|
||||
goto err;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -521,7 +581,7 @@ int sens_sens(CKTcircuit* ckt, int restart)
|
|||
|
||||
sens_setp(sg, ckt, &nvalue);
|
||||
if (error && error != E_BADPARM)
|
||||
return error;
|
||||
goto err;
|
||||
|
||||
SMPconstMult(delta_Y, -1.0);
|
||||
|
||||
|
|
@ -709,7 +769,6 @@ int sens_sens(CKTcircuit* ckt, int restart)
|
|||
|
||||
release_context(ckt->CKTrhs, saved_rhs);
|
||||
release_context(ckt->CKTirhs, saved_irhs);
|
||||
|
||||
release_context(ckt->CKTmatrix, saved_matrix);
|
||||
|
||||
if (is_dc)
|
||||
|
|
@ -724,6 +783,7 @@ int sens_sens(CKTcircuit* ckt, int restart)
|
|||
freq = inc_freq(freq, job->step_type, step_size);
|
||||
|
||||
}
|
||||
FREE(output_names);
|
||||
|
||||
SPfrontEnd->OUTendPlot(sen_data);
|
||||
|
||||
|
|
|
|||
|
|
@ -9,14 +9,10 @@ Copyright 1991 Regents of the University of California. All rights reserved.
|
|||
#include "ngspice/ifsim.h"
|
||||
#include "ngspice/sensgen.h"
|
||||
|
||||
/* Used by sensitivity code in cktsens.c */
|
||||
|
||||
extern char *Sfilter;
|
||||
|
||||
int set_model(sgen *);
|
||||
int set_param(sgen *);
|
||||
int set_inst(sgen *);
|
||||
int set_dev(sgen *);
|
||||
static int set_model(sgen *);
|
||||
static int set_param(sgen *);
|
||||
static int set_inst(sgen *);
|
||||
static int set_dev(sgen *);
|
||||
|
||||
sgen *
|
||||
sgen_init(CKTcircuit *ckt, int is_dc)
|
||||
|
|
@ -176,33 +172,30 @@ sgen_next(sgen **xsg)
|
|||
return 1;
|
||||
}
|
||||
|
||||
int set_inst(sgen *sg)
|
||||
static int set_inst(sgen *sg)
|
||||
{
|
||||
NG_IGNORE(sg);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int set_model(sgen *sg)
|
||||
static int set_model(sgen *sg)
|
||||
{
|
||||
NG_IGNORE(sg);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int set_dev(sgen *sg)
|
||||
static int set_dev(sgen *sg)
|
||||
{
|
||||
NG_IGNORE(sg);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int set_param(sgen *sg)
|
||||
static int set_param(sgen *sg)
|
||||
{
|
||||
IFvalue ifval;
|
||||
|
||||
if (!sg->ptable[sg->param].keyword)
|
||||
return 0;
|
||||
if (Sfilter && strncmp(sg->ptable[sg->param].keyword, Sfilter,
|
||||
strlen(Sfilter)))
|
||||
return 0;
|
||||
if ((sg->ptable[sg->param].dataType &
|
||||
(IF_SET|IF_ASK|IF_REAL|IF_VECTOR|IF_REDUNDANT|IF_NONSENSE))
|
||||
!= (IF_SET|IF_ASK|IF_REAL))
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ Modified: 2000 AlansFixes
|
|||
#include "ngspice/ngspice.h"
|
||||
#include <stdio.h>
|
||||
#include "ngspice/ifsim.h"
|
||||
#include "ngspice/iferrmsg.h"
|
||||
#include "ngspice/inpdefs.h"
|
||||
#include "ngspice/inpmacs.h"
|
||||
#include "ngspice/fteext.h"
|
||||
|
|
@ -438,6 +439,7 @@ dot_sens(char *line, CKTcircuit *ckt, INPtables *tab, struct card *current,
|
|||
{
|
||||
char *name; /* the resistor's name */
|
||||
int error; /* error code temporary */
|
||||
int filters, fidx; /* Filter allocation and index. */
|
||||
IFvalue ptemp; /* a value structure to package resistance into */
|
||||
IFvalue *parm; /* a pointer to a value struct for function returns */
|
||||
int which; /* which analysis we are performing */
|
||||
|
|
@ -446,6 +448,9 @@ dot_sens(char *line, CKTcircuit *ckt, INPtables *tab, struct card *current,
|
|||
CKTnode *node1; /* the first node's node pointer */
|
||||
CKTnode *node2; /* the second node's node pointer */
|
||||
char *steptype; /* ac analysis, type of stepping function */
|
||||
char *cp; /* Scan for filters. */
|
||||
|
||||
extern char **Sens_filter; /* cktsens.c */
|
||||
|
||||
which = ft_find_analysis("SENS");
|
||||
if (which == -1) {
|
||||
|
|
@ -456,9 +461,10 @@ dot_sens(char *line, CKTcircuit *ckt, INPtables *tab, struct card *current,
|
|||
IFC(newAnalysis, (ckt, which, "Sensitivity Analysis", &foo, task));
|
||||
|
||||
/* Format is:
|
||||
* .sens <output>
|
||||
* .sens <output> [<filter strings>]
|
||||
* + [ac [dec|lin|oct] <pts> <low freq> <high freq> | dc ]
|
||||
*/
|
||||
|
||||
/* Get the output voltage or current */
|
||||
INPgetTok(&line, &name, 0);
|
||||
/* name is now either V or I or a serious error */
|
||||
|
|
@ -495,12 +501,44 @@ dot_sens(char *line, CKTcircuit *ckt, INPtables *tab, struct card *current,
|
|||
return 0;
|
||||
}
|
||||
|
||||
INPgetTok(&line, &name, 1);
|
||||
if (name && !strcmp(name, "pct")) {
|
||||
ptemp.iValue = 1;
|
||||
GCA(INPapName, (ckt, which, foo, "pct", &ptemp));
|
||||
INPgetTok(&line, &name, 1);
|
||||
/* Scan for filters for the parameter names to be varied.
|
||||
* INPgetTok() breaks on '*' so scan by hand.
|
||||
*/
|
||||
|
||||
if (Sens_filter)
|
||||
FREE(Sens_filter);
|
||||
fidx = 0;
|
||||
filters = -1; // Ensure room for NULL.
|
||||
name = NULL;
|
||||
while (*line && *line > ' ')
|
||||
++line;
|
||||
for (;;) {
|
||||
int l;
|
||||
|
||||
while (*line && *line <= ' ')
|
||||
++line;
|
||||
if (!*line)
|
||||
break;
|
||||
cp = line;
|
||||
while (*cp && *cp > ' ')
|
||||
++cp;
|
||||
l = (int)(cp - line);
|
||||
name = TMALLOC(char, l + 1);
|
||||
strncpy(name, line, l);
|
||||
name[l] = 0;
|
||||
line = cp;
|
||||
if (!strcmp(name, "ac") || !strcmp(name, "dc"))
|
||||
break;
|
||||
if (fidx >= filters)
|
||||
Sens_filter = TREALLOC(char *, Sens_filter, filters + 8);
|
||||
filters += 8;
|
||||
Sens_filter[fidx++] = name;
|
||||
name = NULL;
|
||||
}
|
||||
if (Sens_filter) {
|
||||
Sens_filter[fidx] = NULL;
|
||||
}
|
||||
|
||||
if (name && !strcmp(name, "ac")) {
|
||||
INPgetTok(&line, &steptype, 1); /* get DEC, OCT, or LIN */
|
||||
ptemp.iValue = 1;
|
||||
|
|
@ -515,9 +553,10 @@ dot_sens(char *line, CKTcircuit *ckt, INPtables *tab, struct card *current,
|
|||
} else if (name && *name && strcmp(name, "dc")) {
|
||||
/* Bad flag */
|
||||
LITERR("Syntax error: 'ac' or 'dc' expected.\n");
|
||||
return 0;
|
||||
}
|
||||
return (0);
|
||||
if (name)
|
||||
FREE(name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue