⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 plotcurv.c

📁 spice中支持多层次元件模型仿真的可单独运行的插件源码
💻 C
字号:
/**********Copyright 1990 Regents of the University of California.  All rights reserved.Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group **********//* * Curve plotting routines and general (non-graphics) plotting things. */#include "spice.h"#include "cpdefs.h"#include "ftedefs.h"#include "ftedata.h"#include "ftegraph.h"#include "ftedbgra.h"#include "suffix.h"static void plotinterval();/* Plot the vector v, with scale xs.  If we are doing curve-fitting, then * do some tricky stuff. */voidft_graf(v, xs, nostart)    struct dvec *v, *xs;    bool nostart;{    int degree, gridsize, length;    register int i, j, l;    double *scratch, *result, *gridbuf, *mm;    register double *xdata, *ydata;    bool rot, increasing;    double dx, dy, lx = 0, ly = 0;    int	dir;    /* if already started, use saved degree */    if (nostart) {      degree = currentgraph->degree;    } else {        if (!cp_getvar("polydegree", VT_NUM, (char *) &degree))            degree = 1;        currentgraph->degree = degree;    }    if (degree > v->v_length)        degree = v->v_length;    if (degree < 1) {        fprintf(cp_err, "Error: polydegree is %d, can't plot...\n",                degree);        return;    }    if (!cp_getvar("gridsize", VT_NUM, (char *) &gridsize))        gridsize = 0;    if ((gridsize < 0) || (gridsize > 10000)) {        fprintf(cp_err, "Error: bad grid size %d\n", gridsize);        return;    }    if (gridsize && xs) {      if( isreal(xs) ) {        increasing = (xs->v_realdata[0] < xs->v_realdata[1]);        for (i = 0; i < xs->v_length - 1; i++)            if (increasing != (xs->v_realdata[i] <                     xs->v_realdata[i + 1])) {                fprintf(cp_err,         "Warning: scale not monotonic, gridsize not relevant.\n");                gridsize = 0;                break;            }       } else {        increasing = (realpart (&xs->v_compdata[0]) < 				realpart( &xs->v_compdata[1]));        for (i = 0; i < xs->v_length - 1; i++)            if (increasing != (realpart( &xs->v_compdata[i]) <                     		realpart( &xs->v_compdata[i + 1]))) {                fprintf(cp_err,         "Warning: scale not monotonic, gridsize not relevant.\n");                gridsize = 0;                break;            }       }    }    if (!nostart)        gr_start(v);    /* Do the one value case */    if (!xs) {        for (i = 0; i < v->v_length; i++) {/* We should do the one - point case too! *	Important for pole-zero for example */	    if( v->v_length == 1 ) {		j = 0;	    } else {		j = i-1;		if( i == 0 )			continue;	   }            if (isreal(v)) {                /* This isn't good but we may as well do                 * something useful.                 */                gr_point(v, v->v_realdata[i],                    v->v_realdata[i],                    v->v_realdata[j],                    v->v_realdata[j], (j==i ? 1 : i));            } else {                gr_point(v, realpart(&v->v_compdata[i]),                    imagpart(&v->v_compdata[i]),                    realpart(&v->v_compdata[j]),                    imagpart(&v->v_compdata[j]), (j==i ? 1 : i));            }	}        gr_end(v);        return;    }    xs->v_flags |= VF_PERMANENT;    /* First check the simple case, where we don't have to do any      * interpolation.     */    if ((degree == 1) && (gridsize == 0)) {	dir = 0;        for (i = 0, j = v->v_length; i < j; i++) {            dx = isreal(xs) ? xs->v_realdata[i] :                     realpart(&xs->v_compdata[i]);            dy = isreal(v) ? v->v_realdata[i] :                     realpart(&v->v_compdata[i]);	    if (i == 0 || (dir > 0 ? lx > dx : dir < 0 ? lx < dx : 0)		&& xs->v_plot->pl_scale == xs)	    {		gr_point(v, dx, dy, lx, ly, 0);	    } else {		gr_point(v, dx, dy, lx, ly, i);		if (!dir)		    dir = lx > dx ? -1 : lx < dx ? 1 : 0;	    }            lx = dx;            ly = dy;        }        if (v->v_length == 1)            gr_point(v, dx, dy, lx, ly, 1);        gr_end(v);        return;    }    if (gridsize < degree + 1)        gridsize = 0;    if (gridsize) {        /* This is done quite differently from what we do below... */        gridbuf = (double *) tmalloc(gridsize * sizeof (double));        result = (double *) tmalloc(gridsize * sizeof (double));        if (isreal(v))            ydata = v->v_realdata;        else {            ydata = (double *) tmalloc(v->v_length *                     sizeof (double));            for (i = 0; i < v->v_length; i++)                ydata[i] = realpart(&v->v_compdata[i]);        }        if (isreal(xs))            xdata = xs->v_realdata;        else {            xdata = (double *) tmalloc(xs->v_length *                     sizeof (double));            for (i = 0; i < xs->v_length; i++)                xdata[i] = realpart(&xs->v_compdata[i]);        }                mm = ft_minmax(xs, true);        dx = (mm[1] - mm[0]) / gridsize;        if (increasing)            for (i = 0, dy = mm[0]; i < gridsize; i++, dy += dx)                gridbuf[i] = dy;        else            for (i = 0, dy = mm[1]; i < gridsize; i++, dy -= dx)                gridbuf[i] = dy;        if (!ft_interpolate(ydata, result, xdata, v->v_length, gridbuf,                gridsize, degree)) {            fprintf(cp_err, "Error: can't put %s on gridsize %d\n",                    v->v_name, gridsize);            return;        }        /* Now this is a problem.  There's no way that we can         * figure out where to put the tic marks to correspond with         * the actual data...         */        for (i = 0; i < gridsize; i++)            gr_point(v, gridbuf[i], result[i], gridbuf[i ? (i - 1)                    : i], result[i ? (i - 1) : i], -1);        gr_end(v);        tfree(gridbuf);        tfree(result);        if (!isreal(v))            tfree(ydata);        if (!isreal(xs))            tfree(xdata);        return;    }    /* We need to do curve fitting now. First get some scratch      * space     */    scratch = (double *) tmalloc((degree + 1) * (degree + 2) *             sizeof (double));    result = (double *) tmalloc((degree + 1) * sizeof (double));    xdata = (double *) tmalloc((degree + 1) * sizeof (double));    ydata = (double *) tmalloc((degree + 1) * sizeof (double));    /* Plot the first degree segments... */    if (isreal(v))        bcopy((char *) v->v_realdata, (char *) ydata,                 (degree + 1) * sizeof (double));    else        for (i = 0; i <= degree; i++)            ydata[i] = realpart(&v->v_compdata[i]);    if (isreal(xs))        bcopy((char *) xs->v_realdata, (char *) xdata,                 (degree + 1) * sizeof (double));    else        for (i = 0; i <= degree; i++)            xdata[i] = realpart(&xs->v_compdata[i]);    rot = false;    while (!ft_polyfit(xdata, ydata, result, degree, scratch)) {        /* Rotate the coordinate system 90 degrees and try again.         * If it doesn't work this time, bump the interpolation         * degree down by one...         */        if (ft_polyfit(ydata, xdata, result, degree, scratch)) {            rot = true;            break;        }        if (--degree == 0) {            fprintf(cp_err, "plotcurve: Internal Error: ack...\n");            return;        }    }    /* Plot this part of the curve... */    for (i = 0; i < degree; i++)        if (rot)            plotinterval(v, ydata[i], ydata[i + 1], result, degree,                    true);        else            plotinterval(v, xdata[i], xdata[i + 1], result, degree,                    false);    /* Now plot the rest, piece by piece... l is the      * last element under consideration.     */    length = v->v_length;    for (l = degree + 1; l < length; l++) {        /* Shift the old stuff by one and get another value. */        for (i = 0; i < degree; i++) {            xdata[i] = xdata[i + 1];            ydata[i] = ydata[i + 1];        }        if (isreal(v))            ydata[i] = v->v_realdata[l];        else            ydata[i] = realpart(&v->v_compdata[l]);        if (isreal(xs))            xdata[i] = xs->v_realdata[l];        else            xdata[i] = realpart(&xs->v_compdata[l]);        rot = false;        while (!ft_polyfit(xdata, ydata, result, degree, scratch)) {            if (ft_polyfit(ydata, xdata, result, degree, scratch)) {                rot = true;                break;            }            if (--degree == 0) {                fprintf(cp_err,                     "plotcurve: Internal Error: ack...\n");                return;            }        }        if (rot)            plotinterval(v, ydata[degree - 1], ydata[degree],                     result, degree, true);        else            plotinterval(v, xdata[degree - 1], xdata[degree],                    result, degree, false);    }    tfree(scratch);    tfree(xdata);    tfree(ydata);    tfree(result);    gr_end(v);    return;}#define GRANULARITY 10static voidplotinterval(v, lo, hi, coeffs, degree, rotated)    struct dvec *v;    double lo, hi;    register double *coeffs;    bool rotated;{    double incr, dx, dy, lx, ly;    register int i;    int steps;    /*    fprintf(cp_err, "plotinterval(%s, %G, %G, [ ", v->v_name, lo, hi);    for (i = 0; i <= degree; i++)        fprintf(cp_err, "%G ", coeffs[i]);    fprintf(cp_err, "], %d, %s)\n\r", degree, rotated ? "true" : "false");    */    /* This is a problem -- how do we know what granularity to use?  If     * the guy cares about this he will use gridsize.     */    if (!cp_getvar("polysteps", VT_NUM, (char *) &steps))        steps = GRANULARITY;    incr = (hi - lo) / (double) (steps + 1);    dx = lo + incr;    lx = lo;    ly = ft_peval(lo, coeffs, degree);    for (i = 0; i <= steps; i++, dx += incr) {        dy = ft_peval(dx, coeffs, degree);        if (rotated)            gr_point(v, dy, dx, ly, lx, -1);        else            gr_point(v, dx, dy, lx, ly, -1);        lx = dx;        ly = dy;        /* fprintf(cp_err, "plot (%G, %G)\n\r", dx, dy); */    }    return;}#ifdef notdefstatic voidprintmat(name, mat, m, n)    char *name;    double *mat;{    int i, j;    printf("\n\r=== Matrix: %s ===\n\r", name);    for (i = 0; i < m; i++) {        printf(" | ");        for (j = 0; j < n; j++)            printf("%G ", mat[i * n + j]);        printf("|\n\r");    }    printf("===\n\r");    return;}#endif

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -