diff --git a/examples/various/compose-examples.cir b/examples/various/compose-examples.cir new file mode 100644 index 000000000..25206cee4 --- /dev/null +++ b/examples/various/compose-examples.cir @@ -0,0 +1,32 @@ +compose examples + +.control +compose vec1 values (-3) (-5) 4 6 +echo $&vec1 +echo +compose vec2 values (-3) (-5*PI) 4 6*e +echo $&vec2 +echo +compose vec3 start=-3 stop=7 step = 2 +echo $&vec3 +echo +compose vec4 start=-3 stop=7 step = 2 lin=19 +*warning, step is ignored +echo $&vec4 +echo +compose vec5 dec=3 start=0.1 stop=10 +echo $&vec5 +echo +compose vec6 dec=3 start=-0.1 stop=10 +*error, value is negative +echo $&vec6 +echo +compose vec7 log=3 start=0.1 stop=10 +echo $&vec7 +echo +compose vec8 gauss=10 mean=1 sd=0.2 +echo $&vec8 +echo +.endc + +.end diff --git a/src/frontend/com_compose.c b/src/frontend/com_compose.c index d76ef3ba7..f91f8f9d9 100644 --- a/src/frontend/com_compose.c +++ b/src/frontend/com_compose.c @@ -8,11 +8,13 @@ #include "ngspice/pnode.h" #include "ngspice/fteext.h" #include "ngspice/cpextern.h" +#include "ngspice/randnumb.h" #include "quote.h" #include "com_compose.h" #include "completion.h" +#include /* log10 */ /* Copy the data from a vector into a buffer with larger dimensions. */ static void @@ -62,25 +64,21 @@ dimxpand(struct dvec *v, int *newdims, double *data) * The possible parms are: * start The value at which the vector should start. * stop The value at which the vector should end. - * step The difference between sucessive elements. + * step The difference between successive elements. * lin The number of points, linearly spaced. * log The number of points, logarithmically spaced. * dec The number of points per decade, logarithmically spaced. + * oct The number of points per octave, logarithmically spaced. * center Where to center the range of points. * span The size of the range of points. - * unif ?? * gauss The number of points in the gaussian distribution. - * mean The mean value for the gaussian dist. - * sd The standard deviation for the gauss. dist. - * random The number of randomly selected points. - * pool The name of a vector (must be already defined) to get - * random values -- default is 'unitvec(npoints)' + * mean The mean value for the gaussian or uniform distributions. + * sd The standard deviation for the gaussian distribution. + * unif The number of points in the uniform distribution. * * The case 'compose name values val val ...' takes the values and creates a - * new vector -- the vals may be arbitrary expressions. - * - * NOTE: most of this doesn't work -- there will be plenty of unused variable - * lint messages... + * new vector -- the vals may be arbitrary expressions. Negative vals have to + * be put into brackets, like (-1.6). */ void @@ -90,20 +88,19 @@ com_compose(wordlist *wl) double stop = 0.0; double step = 0.0; double lin = 0.0; - double center; - double span; - double mean, sd; + double center = 0.0; + double span = 0.0; + double mean = 0.0; + double sd = 0.0; bool startgiven = FALSE, stopgiven = FALSE, stepgiven = FALSE; bool lingiven = FALSE; - bool loggiven = FALSE, decgiven = FALSE, gaussgiven = FALSE; - bool randmgiven = FALSE; + bool loggiven = FALSE, decgiven = FALSE, octgiven = FALSE, gaussgiven = FALSE; + bool unifgiven = FALSE; bool spangiven = FALSE; bool centergiven = FALSE; bool meangiven = FALSE; - bool poolgiven = FALSE; bool sdgiven = FALSE; - int log, dec, gauss, randm; - char *pool; + int log = 0, dec = 0, oct = 0, gauss = 0, unif = 0; int i; char *s, *var, *val; @@ -116,7 +113,6 @@ com_compose(wordlist *wl) int dims[MAXDIMS]; struct dvec *result, *vecs = NULL, *v, *lv = NULL; struct pnode *pn, *names = NULL; - bool reverse = FALSE; char *resname = cp_unquote(wl->wl_word); @@ -152,7 +148,7 @@ com_compose(wordlist *wl) dim = (vecs->v_length > 1) ? 1 : 0; if (dim == MAXDIMS) { - fprintf(cp_err, "Error: max dimensionality is %d\n", + fprintf(cp_err, "Error: compose -> max dimensionality is %d\n", MAXDIMS); goto done; } @@ -170,7 +166,7 @@ com_compose(wordlist *wl) i = (v->v_length > 1) ? 1 : 0; if (i != dim) { fprintf(cp_err, - "Error: all vectors must be of the same dimensionality\n"); + "Error: compose -> all vectors must be of the same dimensionality\n"); goto done; } length++; @@ -249,7 +245,7 @@ com_compose(wordlist *wl) val = wl->wl_word; wl = wl->wl_next; } else { - fprintf(cp_err, "Error: bad syntax\n"); + fprintf(cp_err, "Error: compose -> bad syntax\n"); goto done; } } else { @@ -260,7 +256,7 @@ com_compose(wordlist *wl) val = wl->wl_word; if (*val != '=') { fprintf(cp_err, - "Error: bad syntax\n"); + "Error: compose -> bad syntax\n"); goto done; } val++; @@ -270,13 +266,13 @@ com_compose(wordlist *wl) val = wl->wl_word; } else { fprintf(cp_err, - "Error: bad syntax\n"); + "Error: compose -> bad syntax\n"); goto done; } } wl = wl->wl_next; } else { - fprintf(cp_err, "Error: bad syntax\n"); + fprintf(cp_err, "Error: compose -> bad syntax\n"); goto done; } } @@ -284,7 +280,7 @@ com_compose(wordlist *wl) startgiven = TRUE; if ((td = ft_numparse(&val, FALSE)) == NULL) { fprintf(cp_err, - "Error: bad parm %s = %s\n", var, val); + "Error: compose -> bad parm %s = %s\n", var, val); goto done; } start = *td; @@ -292,7 +288,7 @@ com_compose(wordlist *wl) stopgiven = TRUE; if ((td = ft_numparse(&val, FALSE)) == NULL) { fprintf(cp_err, - "Error: bad parm %s = %s\n", var, val); + "Error: compose -> bad parm %s = %s\n", var, val); goto done; } stop = *td; @@ -300,7 +296,7 @@ com_compose(wordlist *wl) stepgiven = TRUE; if ((td = ft_numparse(&val, FALSE)) == NULL) { fprintf(cp_err, - "Error: bad parm %s = %s\n", var, val); + "Error: compose -> bad parm %s = %s\n", var, val); goto done; } step = *td; @@ -308,7 +304,7 @@ com_compose(wordlist *wl) centergiven = TRUE; if ((td = ft_numparse(&val, FALSE)) == NULL) { fprintf(cp_err, - "Error: bad parm %s = %s\n", var, val); + "Error: compose -> bad parm %s = %s\n", var, val); goto done; } center = *td; @@ -316,7 +312,7 @@ com_compose(wordlist *wl) spangiven = TRUE; if ((td = ft_numparse(&val, FALSE)) == NULL) { fprintf(cp_err, - "Error: bad parm %s = %s\n", var, val); + "Error: compose -> bad parm %s = %s\n", var, val); goto done; } span = *td; @@ -324,7 +320,7 @@ com_compose(wordlist *wl) meangiven = TRUE; if ((td = ft_numparse(&val, FALSE)) == NULL) { fprintf(cp_err, - "Error: bad parm %s = %s\n", var, val); + "Error: compose -> bad parm %s = %s\n", var, val); goto done; } mean = *td; @@ -332,7 +328,7 @@ com_compose(wordlist *wl) sdgiven = TRUE; if ((td = ft_numparse(&val, FALSE)) == NULL) { fprintf(cp_err, - "Error: bad parm %s = %s\n", var, val); + "Error: compose -> bad parm %s = %s\n", var, val); goto done; } sd = *td; @@ -340,7 +336,7 @@ com_compose(wordlist *wl) lingiven = TRUE; if ((td = ft_numparse(&val, FALSE)) == NULL) { fprintf(cp_err, - "Error: bad parm %s = %s\n", var, val); + "Error: compose -> bad parm %s = %s\n", var, val); goto done; } lin = *td; @@ -348,7 +344,7 @@ com_compose(wordlist *wl) loggiven = TRUE; if ((td = ft_numparse(&val, FALSE)) == NULL) { fprintf(cp_err, - "Error: bad parm %s = %s\n", var, val); + "Error: compose -> bad parm %s = %s\n", var, val); goto done; } log = (int)(*td); @@ -356,64 +352,72 @@ com_compose(wordlist *wl) decgiven = TRUE; if ((td = ft_numparse(&val, FALSE)) == NULL) { fprintf(cp_err, - "Error: bad parm %s = %s\n", var, val); + "Error: compose -> bad parm %s = %s\n", var, val); goto done; } dec = (int)(*td); + } else if (cieq(var, "oct")) { + octgiven = TRUE; + if ((td = ft_numparse(&val, FALSE)) == NULL) { + fprintf(cp_err, + "Error: compose -> bad parm %s = %s\n", var, val); + goto done; + } + oct = (int)(*td); } else if (cieq(var, "gauss")) { gaussgiven = TRUE; if ((td = ft_numparse(&val, FALSE)) == NULL) { fprintf(cp_err, - "Error: bad parm %s = %s\n", var, val); + "Error: compose -> bad parm %s = %s\n", var, val); goto done; } gauss = (int)(*td); - } else if (cieq(var, "random")) { - randmgiven = TRUE; + } else if (cieq(var, "unif")) { + unifgiven = TRUE; if ((td = ft_numparse(&val, FALSE)) == NULL) { fprintf(cp_err, - "Error: bad parm %s = %s\n", var, val); + "Error: compose -> bad parm %s = %s\n", var, val); goto done; } - randm = (int)(*td); - } else if (cieq(var, "pool")) { - poolgiven = TRUE; - pool = val; + unif = (int)(*td); + } else { + fprintf(cp_err, "Error: compose -> bad parm %s\n", var); + goto done; } } -#ifdef LINT - /* XXX Now, doesn't this look just a little suspicious */ - if (centergiven || spangiven || meangiven || sdgiven || poolgiven) - j = k = l = m = q = inds = center + span + mean + sd + - log + dec + gauss + randm + pool; -#endif /* Now see what we have... start and stop are pretty much - * compatible with everything... + * compatible with everything (except gauss)... */ + if (centergiven && spangiven && !startgiven && !stopgiven) { + start = center - span/2.0; + stop = center + span/2.0; + startgiven = TRUE; + stopgiven = TRUE; + } + if (stepgiven && (step == 0.0)) { - fprintf(cp_err, "Error: step cannot = 0.0\n"); + fprintf(cp_err, "Error: compose -> step cannot = 0.0\n"); goto done; } - if (startgiven && stopgiven && (start > stop)) { - SWAP(double, start, stop); - reverse = TRUE; - } - - if (lingiven + loggiven + decgiven + randmgiven + gaussgiven > 1) { + if (lingiven + loggiven + decgiven + octgiven + unifgiven + gaussgiven > 1) { fprintf(cp_err, - "Error: can have at most one of (lin, log, dec, random, gauss)\n"); + "Error: compose -> can have at most one of (lin, log, dec, oct, unif, gauss)\n"); goto done; - } else if (lingiven + loggiven + decgiven + randmgiven + gaussgiven == 0) { + } else if (lingiven + loggiven + decgiven + octgiven + unifgiven + gaussgiven == 0) { /* Hmm, if we have a start, stop, and step we're ok. */ if (startgiven && stopgiven && stepgiven) { lingiven = TRUE; - lin = (stop - start) / step + 1; + /* Ensure that step has the right sign */ + if ((stop - start > 0) != (step > 0)) { + step = -step; + } + lin = (stop - start) / step + 1.; stepgiven = FALSE; /* Problems below... */ } else { fprintf(cp_err, - "Error: either one of (lin, log, dec, random, gauss) must be given, or all\n"); + "Error: compose -> either one of (lin, log, dec, oct, unif, gauss) must be given, or all\n"); fprintf(cp_err, "\tof (start, stop, and step) must be given.\n"); goto done; @@ -422,49 +426,140 @@ com_compose(wordlist *wl) if (lingiven) { /* Create a linear sweep... */ + if (lin <= 0) { + fprintf(cp_err, + "Error: compose -> The number of linearly spaced points, lin, must be positive.\n"); + goto done; + } length = (int)lin; data = TMALLOC(double, length); if (stepgiven && startgiven && stopgiven) { - if (step != (stop - start) / lin * (reverse ? -1 : 1)) { + if (step != (stop - start) / (lin - 1.0)) { fprintf(cp_err, - "Warning: bad step -- should be %g\n", - (stop - start) / lin * (reverse ? -1 : 1)); + "Warning: compose -> bad step -- should be %g. ", + (stop - start) / (lin - 1.0)); + fprintf(cp_err, + "Specify only three out of start, stop, step, lin.\n"); stepgiven = FALSE; } } if (!startgiven) { if (stopgiven && stepgiven) - start = stop - step * lin; + start = stop - step * (lin - 1.0); else if (stopgiven) - start = stop - lin; + start = stop - lin + 1.0; else start = 0; startgiven = TRUE; } if (!stopgiven) { if (stepgiven) - stop = start + lin * step; + stop = start + step * (lin - 1.0); else - stop = start + lin; + stop = start + lin - 1.; stopgiven = TRUE; } if (!stepgiven) { - step = (stop - start) / lin; + step = (stop - start) / (lin - 1.0); } - if (reverse) - for (i = 0, tt = stop; i < length; i++, tt -= step) - data[i] = tt; - else - for (i = 0, tt = start; i < length; i++, tt += step) - data[i] = tt; + for (i = 0, tt = start; i < length; i++, tt += step) + data[i] = tt; - } else if (loggiven || decgiven) { + } else if (loggiven || decgiven || octgiven) { /* Create a log sweep... */ - } else if (randmgiven) { - /* Create a set of random values... */ + if (centergiven && spangiven) { + if (center <= span/2.0) { + fprintf(cp_err, + "Error: compose -> center must be greater than span/2\n"); + goto done; + } + if ((center <= 0) || (span <= 0)) { + fprintf(cp_err, + "Error: compose -> center and span must be greater than 0\n"); + goto done; + } + } + else if (startgiven && stopgiven) { + if ((start <= 0) || (stop <= 0)) { + fprintf(cp_err, + "Error: compose -> start and stop must be greater than 0\n"); + goto done; + } + } + else { + fprintf(cp_err, + "Error: compose -> start and stop or center and span needed in case of log, dec or oct\n"); + goto done; + } + if (decgiven) { + log = (int)round(dec * log10(stop / start)) + 1; + } else if (octgiven) { + log = (int)round(oct * log10(stop / start) / log10(2)) + 1; + } + + length = log; + data = TMALLOC(double, length); + + data[0] = start; + for (i = 0; i < length; i++) + data[i] = start * pow(stop/start, (double)i/(log-1.0)); + + } else if (unifgiven) { + /* Create a set of uniform distributed values... */ + if (startgiven || stopgiven) { + if (!startgiven || !stopgiven) { + fprintf(cp_err, + "Error: compose -> For uniform distribution (start, stop) can be only given as bundle.\n"); + goto done; + } + if (meangiven || spangiven) { + fprintf(cp_err, + "Error: compose -> For uniform distribution (start, stop) can't be mixed with mean or span.\n"); + goto done; + } + mean = (start + stop) / 2.0; + span = fabs(stop - start); + meangiven = TRUE; + spangiven = TRUE; + } + if (unif <= 0) { + fprintf(cp_err, + "Error: compose -> The number of uniformly distributed points, unif, must be positive.\n"); + goto done; + } + if (!meangiven) { + /* Use mean default value 0.5 */ + mean = 0.5; + } + if (!spangiven) { + /* Use span default value 1.0 */ + span = 1.0; + } + length = unif; + data = TMALLOC(double, length); + for (i = 0; i < length; i++) + data[i] = mean + span * 0.5 * drand(); + } else if (gaussgiven) { /* Create a gaussian distribution... */ + if (gauss <= 0) { + fprintf(cp_err, + "Error: compose -> The number of Gaussian distributed points, gauss, must be positive.\n"); + goto done; + } + if (!meangiven) { + /* Use mean default value 0 */ + mean = 0; + } + if (!sdgiven) { + /* Use sd default value 1.0 */ + sd = 1.0; + } + length = gauss; + data = TMALLOC(double, length); + for (i = 0; i < length; i++) + data[i] = mean + sd * gauss1(); } }