diff --git a/src/frontend/inp.c b/src/frontend/inp.c index e75ec93cf..ea9833868 100644 --- a/src/frontend/inp.c +++ b/src/frontend/inp.c @@ -59,7 +59,7 @@ static void inp_parse_temper_trees(void); static wordlist *inp_savecurrents(struct line *deck, struct line *options, wordlist *wl, wordlist *controls); -static void eval_agauss_bsource(struct line *deck); +static void eval_agauss_bsource(struct line *deck, char *fcn); void line_free_x(struct line *deck, bool recurse); void create_circbyline(char *line); @@ -611,7 +611,10 @@ inp_spsource(FILE *fp, bool comfile, char *filename, bool intfile) inp_parse_temper(deck); /* replace agauss(x,y,z) in each b-line by suitable value */ - eval_agauss_bsource(deck); + static char *statfcn[] = { "agauss", "gauss", "aunif", "unif", "limit" }; + int ii; + for (ii = 0; ii < 5; ii++) + eval_agauss_bsource(deck, statfcn[ii]); /* If user wants all currents saved (.options savecurrents), add .save to wl_first with all terminal currents available on selected devices */ @@ -1692,7 +1695,38 @@ agauss(double nominal_val, double abs_variation, double sigma) } -/* Second step to enable agauss in professional parameter decks: +static double +gauss(double nominal_val, double rel_variation, double sigma) +{ + double stdvar; + stdvar = nominal_val * rel_variation / sigma; + return (nominal_val + stdvar * gauss0()); +} + + +static double +unif(double nominal_val, double rel_variation) +{ + return (nominal_val + nominal_val * rel_variation * drand()); +} + + +static double +aunif(double nominal_val, double abs_variation) +{ + return (nominal_val + abs_variation * drand()); +} + + +static double +limit(double nominal_val, double abs_variation) +{ + return (nominal_val + (drand() > 0 ? abs_variation : -1. * abs_variation)); +} + + +/* Second step to enable functions agauss, gauss, aunif, unif, limit + * in professional parameter decks: * agauss has been preserved by replacement operation of .func * (function inp_fix_agauss_in_param() in inpcom.c). * After subcircuit expansion, agauss may be still existing in b-lines, @@ -1705,7 +1739,7 @@ agauss(double nominal_val, double abs_variation, double sigma) */ static void -eval_agauss_bsource(struct line *deck) +eval_agauss_bsource(struct line *deck, char *fcn) { struct line *card; double x, y, z, val; @@ -1732,7 +1766,7 @@ eval_agauss_bsource(struct line *deck) if (*curr_line != 'b') continue; - while ((ap = search_identifier(curr_line, "agauss", curr_line)) != NULL) { + while ((ap = search_identifier(curr_line, fcn, curr_line)) != NULL) { char *lparen, *rparen, *begstr, *contstr = NULL, *new_line, *midstr; char *tmp1str, *tmp2str, *delstr; int nerror; @@ -1752,10 +1786,35 @@ eval_agauss_bsource(struct line *deck) delstr = tmp2str = gettok(&tmp1str); y = INPevaluate(&tmp2str, &nerror, 1); tfree(delstr); - delstr = tmp2str = gettok(&tmp1str); - z = INPevaluate(&tmp2str, &nerror, 1); - tfree(delstr); - val = agauss(x, y, z); + if (cieq(fcn, "agauss")) { + delstr = tmp2str = gettok(&tmp1str); + z = INPevaluate(&tmp2str, &nerror, 1); + tfree(delstr); + val = agauss(x, y, z); + } + else if (cieq(fcn, "gauss")) { + delstr = tmp2str = gettok(&tmp1str); + z = INPevaluate(&tmp2str, &nerror, 1); + tfree(delstr); + val = gauss(x, y, z); + } + else if (cieq(fcn, "aunif")) { + val = aunif(x, y); + } + else if (cieq(fcn, "unif")) { + val = unif(x, y); + } + else if (cieq(fcn, "limit")) { + val = limit(x, y); + } + else { + fprintf(cp_err, "ERROR: Unknown function %s, cannot evaluate\n", fcn); + tfree(begstr); + tfree(contstr); + tfree(midstr); + return; + } + new_line = tprintf("%s%g%s", begstr, val, contstr); tfree(card->li_line); curr_line = card->li_line = new_line; diff --git a/src/frontend/inpcom.c b/src/frontend/inpcom.c index 034e5a580..6ca0efd1f 100644 --- a/src/frontend/inpcom.c +++ b/src/frontend/inpcom.c @@ -141,7 +141,7 @@ static void replace_token(char *string, char *token, int where, int total); static void inp_add_series_resistor(struct line *deck); static void subckt_params_to_param(struct line *deck); static void inp_fix_temper_in_param(struct line *deck); -static void inp_fix_agauss_in_param(struct line *deck); +static void inp_fix_agauss_in_param(struct line *deck, char *fcn); static char *inp_spawn_brace(char *s); @@ -518,7 +518,11 @@ inp_readall(FILE *fp, char *dir_name, bool comfile, bool intfile) rv . line_number = inp_split_multi_param_lines(working, rv . line_number); inp_fix_macro_param_func_paren_io(working); - inp_fix_agauss_in_param(working); + + static char *statfcn[] = { "agauss", "gauss", "aunif", "unif", "limit" }; + int ii; + for (ii = 0; ii < 5; ii++) + inp_fix_agauss_in_param(working, statfcn[ii]); inp_fix_temper_in_param(working); @@ -6117,8 +6121,9 @@ inp_fix_temper_in_param(struct line *deck) } -/* Convert .param lines containing function 'agauss' into .func lines: -* .param xxx1 = 'agauss()' ---> .func xxx1() 'agauss()' +/* Convert .param lines containing function 'agauss' and others +* (function name handed over by *fcn), into .func lines: +* .param xxx1 = 'aunif()' ---> .func xxx1() 'aunif()' * Add info about the functions (name, subcircuit depth, number of * subckt) to linked list new_func. * Then scan new_func, for each xxx1 scan all lines of deck, @@ -6131,7 +6136,7 @@ inp_fix_temper_in_param(struct line *deck) */ static void -inp_fix_agauss_in_param(struct line *deck) +inp_fix_agauss_in_param(struct line *deck, char *fcn) { int skip_control = 0, subckt_depth = 0, j, *sub_count; char *funcbody, *funcname; @@ -6185,7 +6190,7 @@ inp_fix_agauss_in_param(struct line *deck) char *p, *temper, *equal_ptr, *lhs_b, *lhs_e; - temper = search_identifier(curr_line, "agauss", curr_line); + temper = search_identifier(curr_line, fcn, curr_line); if (!temper) continue; @@ -6218,9 +6223,9 @@ inp_fix_agauss_in_param(struct line *deck) if (temper < equal_ptr) { fprintf(stderr, - "Error: you cannot assign a value to TEMPER\n" + "Error: you cannot assign a value to %s\n" " Line no. %d, %s\n", - card->li_linenum, curr_line); + fcn, card->li_linenum, curr_line); controlled_exit(EXIT_BAD); }