From 5b2a9474fa8fb0a7f9fb883d24a87a9d45922d89 Mon Sep 17 00:00:00 2001 From: Holger Vogt Date: Sat, 9 Nov 2019 16:26:36 +0100 Subject: [PATCH] Replace B source pwl by XSPICE PWL Controlled Source that has smooth rounded and differentiable corners. Microchip or On-Semi OpAmps that needed gmin and source stepping for operating point calculation now converge without, others like MCP6001 that generally refused to converge are o.k. now. Reason is the heavily used Gxxx n1 n2 TABLE {expression} = (x0, y0) (x1, y1) (x2, y2) from the OpAmp models. --- src/frontend/inpcom.c | 161 ++++++++++++++++++++---------------------- 1 file changed, 76 insertions(+), 85 deletions(-) diff --git a/src/frontend/inpcom.c b/src/frontend/inpcom.c index 3423dac1b..9263b8148 100644 --- a/src/frontend/inpcom.c +++ b/src/frontend/inpcom.c @@ -161,7 +161,8 @@ static struct nscope *inp_add_levels(struct card *deck); static struct card_assoc *find_subckt(struct nscope *scope, const char *name); static void inp_rem_levels(struct nscope *root); static void inp_rem_unused_models(struct nscope *root, struct card *deck); -static struct modellist *inp_find_model(struct nscope *scope, const char *name); +static struct modellist *inp_find_model( + struct nscope *scope, const char *name); void tprint(struct card *deck); static struct card *pspice_compat(struct card *newcard); @@ -1001,9 +1002,8 @@ struct inp_read_t inp_read( * double quotes are printed. */ { char *s; - if (ciprefix("plot", buffer) || - ciprefix("gnuplot", buffer) || - ciprefix("hardcopy", buffer)) { + if (ciprefix("plot", buffer) || ciprefix("gnuplot", buffer) || + ciprefix("hardcopy", buffer)) { /* lower case excluded for tokens following title, xlabel, * ylabel. tokens may contain spaces, then they have to be * enclosed in quotes. keywords and tokens have to be @@ -1067,8 +1067,8 @@ struct inp_read_t inp_read( } } else if (ciprefix("print", buffer) || - ciprefix("eprint", buffer) || - ciprefix("asciiplot", buffer)) { + ciprefix("eprint", buffer) || + ciprefix("asciiplot", buffer)) { /* lower case excluded for tokens following output redirection * '>' */ bool redir = FALSE; @@ -1082,28 +1082,25 @@ struct inp_read_t inp_read( } /* no lower case letters for lines beginning with: */ else if (!ciprefix("write", buffer) && - !ciprefix("wrdata", buffer) && - !ciprefix(".lib", buffer) && - !ciprefix(".inc", buffer) && - !ciprefix("codemodel", buffer) && - !ciprefix("echo", buffer) && - !ciprefix("shell", buffer) && - !ciprefix("source", buffer) && - !ciprefix("load", buffer) && - !ciprefix("setcs", buffer)) { + !ciprefix("wrdata", buffer) && + !ciprefix(".lib", buffer) && !ciprefix(".inc", buffer) && + !ciprefix("codemodel", buffer) && + !ciprefix("echo", buffer) && !ciprefix("shell", buffer) && + !ciprefix("source", buffer) && + !ciprefix("load", buffer) && !ciprefix("setcs", buffer)) { /* lower case for all other lines */ for (s = buffer; *s && (*s != '\n'); s++) *s = tolower_c(*s); } - else - { - /* s points to end of buffer for all cases not treated so far */ + else { + /* s points to end of buffer for all cases not treated so far + */ for (s = buffer; *s && (*s != '\n'); s++) ; } - + /* add Inp_Path to sourcepath variable */ - if (cieq(buffer, "set") || cieq(buffer, "setcs")) { + if (cieq(buffer, "set") || cieq(buffer, "setcs")) { char *p = strstr(buffer, "sourcepath"); if (p) { p = strchr(buffer, ')'); @@ -2318,8 +2315,8 @@ void inp_casefix(char *string) { #ifdef HAVE_CTYPE_H /* single non-printable character */ - if(string && !isspace_c(*string) && !isprint_c(*string) && - (string[1] == '\0' || isspace_c(string[1]))) { + if (string && !isspace_c(*string) && !isprint_c(*string) && + (string[1] == '\0' || isspace_c(string[1]))) { *string = '*'; return; } @@ -3044,8 +3041,7 @@ static void inp_fix_inst_calls_for_numparam( if (found_mult_param(num_inst_params, inst_param_names)) { struct card_assoc *a = find_subckt(c->level, subckt_name); - if (a) - { + if (a) { int num_subckt_params = inp_get_params(a->line->line, subckt_param_names, subckt_param_values); @@ -4804,16 +4800,17 @@ static void inp_compat(struct card *card) /* Gxxx n1 n2 TABLE {expression} = (x0, y0) (x1, y1) (x2, y2) --> - Gxxx n1 n2 int1 0 1 - BGxxx int1 0 V = pwl (expression, x0-(x2-x0)/2, y0, x0, y0, x1, - y1, x2, y2, x2+(x2-x0)/2, y2) + Gxxx n1 n2 Gxxx_int1 0 1 + BGxxx Gxxx_int2 0 v = expression + aGxxx %v(Gxxx_int2) %v(Gxxx_int1) xfer_Gxxx + .model xfer_Gxxx pwl(x_array=[x0 x1 x2] + y_array=[y0 y1 y2] + input_domain=0.1 fraction=TRUE) */ if ((str_ptr = strstr(curr_line, "table")) != NULL) { - char *expression, *firstno, *ffirstno, *ffirstnof, *secondno, - *midline, *lastno, *lastnof, *lastlastno; + char *expression, *firstno, *secondno; char *m_ptr, *m_token; - double fnumber, lnumber, delta; - int nerror; + char xar[1024], yar[1024]; cut_line = curr_line; /* title and nodes */ title_tok = gettok(&cut_line); @@ -4866,56 +4863,45 @@ static void inp_compat(struct card *card) *str_ptr = ' '; if ((str_ptr = strchr(cut_line, '}')) != NULL) *str_ptr = ' '; - /* get first two numbers to establish extrapolation */ - str_ptr = cut_line; - ffirstnof = ffirstno = gettok_node(&cut_line); - if (!ffirstno) { - fprintf(stderr, "Error: bad syntax in line %d\n %s\n", - card->linenum_orig, card->line); - controlled_exit(EXIT_BAD); - } - firstno = copy(ffirstno); - fnumber = INPevaluate(&ffirstno, &nerror, TRUE); - secondno = gettok_node(&cut_line); - midline = cut_line; - cut_line = strrchr(str_ptr, '('); - /* replace '(' with ',' and ')' with ' ' */ - for (; *str_ptr; str_ptr++) - if (*str_ptr == '(') - *str_ptr = ','; - else if (*str_ptr == ')') - *str_ptr = ' '; - /* scan for last two numbers */ - lastnof = lastno = gettok_node(&cut_line); - lnumber = INPevaluate(&lastno, &nerror, FALSE); - /* check for max-min and take half the difference for delta */ - delta = (lnumber - fnumber) / 2.; - lastlastno = gettok_node(&cut_line); - if (!secondno || (*midline == '\0') || (delta <= 0.) || - !lastlastno) { - fprintf(stderr, "Error: bad syntax in line %d\n %s\n", - card->linenum_orig, card->line); - controlled_exit(EXIT_BAD); - } - /* BGxxx int1 0 V = pwl (expression, x0-(x2-x0)/2, y0, x0, y0, - * x1, y1, x2, y2, x2+(x2-x0)/2, y2) */ - ckt_array[1] = tprintf("b%s %s_int1 0 v = pwl(%s, %e, %s, " - "%s, %s, %s, %e, %s)", - title_tok, title_tok, expression, fnumber - delta, - secondno, firstno, secondno, midline, lnumber + delta, - lastlastno); - // comment out current variable e line + /* GD51 50 51 gd51_int1 0 1 + BGD51 gd51_int2 0 v = V(50,51) + agd51 %v(gd51_int2) %v(gd51_int1) xfer_gd51 + .model xfer_gd51 pwl(x_array=[-10 0 1m 2m 3m] + + y_array=[-1n 0 1m 1 100] + + input_domain=0.1 fraction=TRUE) + */ + ckt_array[1] = tprintf("b%s %s_int2 0 v = %s", title_tok, + title_tok, expression); + ckt_array[2] = tprintf("a%s %%v(%s_int2) %%v(%s_int1) xfer_%s", + title_tok, title_tok, title_tok, title_tok); + /* (x0, y0) (x1, y1) (x2, y2) to x0 x1 x2, y0 y1 y2 */ + xar[0] = '\0'; + yar[0] = '\0'; + while (*cut_line != '\0') { + firstno = gettok_node(&cut_line); + secondno = gettok_node(&cut_line); + if ((!firstno && secondno) || (firstno && !secondno)) { + fprintf(stderr, "Error: Missing token in %s\n", + curr_line); + break; + } + else if (!firstno && !secondno) + continue; + strcat(xar, firstno); + strcat(xar, " "); + strcat(yar, secondno); + strcat(yar, " "); + tfree(firstno); + tfree(secondno); + } + ckt_array[3] = tprintf(".model xfer_%s pwl(x_array=[%s] y_array=[%s] input_domain=0.1 fraction=TRUE)", title_tok, xar, yar); + // comment out current variable g line *(card->line) = '*'; - // insert new B source line immediately after current line - for (i = 0; i < 2; i++) + // insert new lines immediately after current line + for (i = 0; i < 4; i++) card = insert_new_line(card, ckt_array[i], 0, 0); - tfree(firstno); - tfree(ffirstnof); - tfree(secondno); - tfree(lastnof); - tfree(lastlastno); tfree(expression); tfree(title_tok); tfree(node1); @@ -7466,8 +7452,9 @@ static struct card *pspice_compat(struct card *oldcard) char *ntok = nexttok(cut_line); ntok = nexttok(ntok); ntok = nexttok(ntok); - if (!ntok || *ntok == '\0'){ - fprintf(stderr, "Error: Missing token in line %d:\n%s\n", card->linenum, cut_line); + if (!ntok || *ntok == '\0') { + fprintf(stderr, "Error: Missing token in line %d:\n%s\n", + card->linenum, cut_line); fprintf(stderr, " Please correct the input file\n"); if (ft_stricterror) controlled_exit(1); @@ -7573,8 +7560,8 @@ static struct card *pspice_compat(struct card *oldcard) } /* replace T_ABS by temp, T_REL_GLOBAL by dtemp, and T_MEASURED by TNOM - in .model cards. What about T_REL_LOCAL ? T_REL_LOCAL is used in conjunction with AKO - and is not yet implemented. */ + in .model cards. What about T_REL_LOCAL ? T_REL_LOCAL is used in + conjunction with AKO and is not yet implemented. */ for (card = newcard; card; card = card->nextcard) { char *cut_line = card->line; if (ciprefix(".model", cut_line)) { @@ -7673,7 +7660,8 @@ static struct card *pspice_compat(struct card *oldcard) continue; } cut_line = nexttok(cut_line); // model name - if (cut_line && *cut_line && atof(cut_line) > 0.0) { // size of area + if (cut_line && *cut_line && + atof(cut_line) > 0.0) { // size of area char *tmpstr1 = copy_substring(card->line, cut_line); char *tmpstr2 = tprintf("%s area=%s", tmpstr1, cut_line); tfree(tmpstr1); @@ -8199,7 +8187,8 @@ static void add_subckt(struct nscope *scope, struct card *subckt_line) char *n = skip_ws(skip_non_ws(subckt_line->line)); char *name = copy_substring(n, skip_non_ws(n)); if (find_subckt_1(scope, name)) { - fprintf(stderr, "Warning: redefinition of .subckt %s, ignored\n", name); + fprintf(stderr, "Warning: redefinition of .subckt %s, ignored\n", + name); /* rename the redefined subcircuit */ *n = '_'; } @@ -8221,7 +8210,8 @@ struct modellist { }; -static struct modellist *inp_find_model_1(struct nscope *scope, const char *name) +static struct modellist *inp_find_model_1( + struct nscope *scope, const char *name) { struct modellist *p = scope->models; for (; p; p = p->next) @@ -8231,7 +8221,8 @@ static struct modellist *inp_find_model_1(struct nscope *scope, const char *name } -static struct modellist *inp_find_model(struct nscope *scope, const char *name) +static struct modellist *inp_find_model( + struct nscope *scope, const char *name) { for (; scope; scope = scope->next) { struct modellist *p = inp_find_model_1(scope, name);