From 91ab0a3c748b4c19b10c14f6385cffc20480049a Mon Sep 17 00:00:00 2001 From: dwarning Date: Fri, 31 May 2013 14:19:05 +0200 Subject: [PATCH] parser/*.c: implement a signed power function `pwr' for controlled sources --- src/include/ngspice/inpptree.h | 9 ++--- src/spicelib/parser/ifeval.c | 1 + src/spicelib/parser/inpptree.c | 64 +++++++++++++++++++++++++++++++--- src/spicelib/parser/inpxx.h | 1 + src/spicelib/parser/ptfuncs.c | 9 +++++ 5 files changed, 76 insertions(+), 8 deletions(-) diff --git a/src/include/ngspice/inpptree.h b/src/include/ngspice/inpptree.h index 53781d2af..77804890d 100644 --- a/src/include/ngspice/inpptree.h +++ b/src/include/ngspice/inpptree.h @@ -123,10 +123,11 @@ void INPptPrint(char *str, IFparseTree * ptree); #define PTF_GE0 28 #define PTF_LE0 29 #define PTF_POW 30 -#define PTF_MIN 31 -#define PTF_MAX 32 -#define PTF_CEIL 33 -#define PTF_FLOOR 34 +#define PTF_PWR 31 +#define PTF_MIN 32 +#define PTF_MAX 33 +#define PTF_CEIL 34 +#define PTF_FLOOR 35 /* The following things are used by the parser -- these are the token types the * lexer returns. diff --git a/src/spicelib/parser/ifeval.c b/src/spicelib/parser/ifeval.c index e3fcca3da..416ae1091 100644 --- a/src/spicelib/parser/ifeval.c +++ b/src/spicelib/parser/ifeval.c @@ -94,6 +94,7 @@ PTeval(INPparseNode * tree, double gmin, double *res, double *vals) switch(tree->funcnum) { case PTF_POW: + case PTF_PWR: case PTF_MIN: case PTF_MAX: err = PTeval(tree->left->left, gmin, &r1, vals); diff --git a/src/spicelib/parser/inpptree.c b/src/spicelib/parser/inpptree.c index 85d739e90..4ec91ded3 100644 --- a/src/spicelib/parser/inpptree.c +++ b/src/spicelib/parser/inpptree.c @@ -29,6 +29,7 @@ static INPparseNode *mksnode(const char *string, void *ckt); static INPparseNode *PTdifferentiate(INPparseNode * p, int varnum); static void free_tree(INPparseNode *); +static void printTree(INPparseNode *); /* @@ -167,6 +168,7 @@ static struct func { { "ge0", PTF_GE0, (void(*)(void)) PTge0}, { "le0", PTF_LE0, (void(*)(void)) PTle0}, { "pow", PTF_POW, (void(*)(void)) PTpower}, + { "pwr", PTF_PWR, (void(*)(void)) PTpwr}, { "min", PTF_MIN, (void(*)(void)) PTmin}, { "max", PTF_MAX, (void(*)(void)) PTmax}, } ; @@ -523,8 +525,6 @@ static INPparseNode *PTdifferentiate(INPparseNode * p, int varnum) INPparseNode *b = p->left->right; int comparison = (p->funcnum == PTF_MIN) ? PTF_LT0 : PTF_GT0; #ifdef TRACE - extern void printTree(INPparseNode *); - printf("debug: %s, PTF_MIN: ", __func__); printTree(p); printf("\n"); @@ -568,6 +568,11 @@ static INPparseNode *PTdifferentiate(INPparseNode * p, int varnum) mkb(PT_POWER, p->left->left, mkcon(p->left->right->constant - 1))), arg1); +#ifdef TRACE + printf("pow, %s, returns; ", __func__); + printTree(newp); + printf("\n"); +#endif } else { /* * D(f^g) = D(exp(g*ln(f))) @@ -587,6 +592,59 @@ static INPparseNode *PTdifferentiate(INPparseNode * p, int varnum) return mkfirst(newp, p); } + break; + + case PTF_PWR: + { + /* + pwr(a,b) + p->left: ',' p->left->left: a p->left->right: b + */ + + if (p->left->right->type == PT_CONSTANT) { + /* + * f(a,b) = signum(a) * abs(a)^b + * D(f(a,b)) = signum(a) * abs(a)^b * b / a + * + */ + arg1 = PTdifferentiate(p->left->left, varnum); + + newp = mkb(PT_TIMES, + mkf(PTF_SGN, p->left->left), + mkb(PT_DIVIDE, mkb(PT_TIMES, + mkcon(p->left->right->constant), + mkb(PT_POWER, + mkf(PTF_ABS, p->left->left), + mkcon(p->left->right->constant))), + p->left->left)); +#ifdef TRACE + printf("pwr, %s, returns; ", __func__); + printTree(newp); + printf("\n"); +#endif + } else { + /* + * f(g) = signum(a) * abs(a)^g + * D(f^g) = signum(a) * D(exp(g*ln(f))) + * = signum(a) * exp(g*ln(f)) * D(g*ln(f)) + * = signum(a) * exp(g*ln(f)) * (D(g)*ln(f) + g*D(f)/f) + */ + arg1 = PTdifferentiate(p->left->left, varnum); + arg2 = PTdifferentiate(p->left->right, varnum); + + newp = mkb(PT_TIMES, + mkf(PTF_SGN, p->left->left), + mkb(PT_TIMES, mkf(PTF_EXP, mkb(PT_TIMES, + p->left->right, mkf(PTF_LN, + p->left->left))), + mkb(PT_PLUS, + mkb(PT_TIMES, p->left->right, + mkb(PT_DIVIDE, arg1, p->left->left)), + mkb(PT_TIMES, arg2, mkf(PTF_LN, p->left->left))))); + } + return mkfirst(newp, p); + } + default: fprintf(stderr, "Internal Error: bad function # %d\n", p->funcnum); @@ -1387,8 +1445,6 @@ void free_tree(INPparseNode *pt) /* Debugging stuff. */ -void printTree(INPparseNode *); - void INPptPrint(char *str, IFparseTree * ptree) { int i; diff --git a/src/spicelib/parser/inpxx.h b/src/spicelib/parser/inpxx.h index 1a26ed4a1..491e3b42c 100644 --- a/src/spicelib/parser/inpxx.h +++ b/src/spicelib/parser/inpxx.h @@ -43,6 +43,7 @@ double PTminus(double arg1, double arg2); double PTtimes(double arg1, double arg2); double PTdivide(double arg1, double arg2); double PTpower(double arg1, double arg2); +double PTpwr(double arg1, double arg2); double PTacos(double arg); double PTacosh(double arg); double PTasin(double arg); diff --git a/src/spicelib/parser/ptfuncs.c b/src/spicelib/parser/ptfuncs.c index 9ff1dbcb8..2eef347c1 100644 --- a/src/spicelib/parser/ptfuncs.c +++ b/src/spicelib/parser/ptfuncs.c @@ -83,6 +83,15 @@ PTpower(double arg1, double arg2) return (pow(arg1, arg2)); } +double +PTpwr(double arg1, double arg2) +{ + if (arg1 < 0.0) + return (-pow(-arg1, arg2)); + else + return (pow(arg1, arg2)); +} + double PTmin(double arg1, double arg2) {