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

📄 interp.c

📁 spice中支持多层次元件模型仿真的可单独运行的插件源码
💻 C
字号:
/**********Copyright 1990 Regents of the University of California.  All rights reserved.Author: 1985 Wayne A. Christopher, U. C. Berkeley CAD Group **********//* * Polynomial interpolation code. */#include "spice.h"#include "cpdefs.h"#include "ftedefs.h"#include "ftedata.h"#include "suffix.h"/* Interpolate data from oscale to nscale. data is assumed to be olen long, * ndata will be nlen long. Returns false if the scales are too strange * to deal with.  Note that we are guaranteed that either both scales are * strictly increasing or both are strictly decreasing. */static int putinterval();void lincopy();static void printmat();boolft_interpolate(data, ndata, oscale, olen, nscale, nlen, degree)    double *data, *ndata, *oscale, *nscale;{    double *result, *scratch, *xdata, *ydata;    int sign, lastone, i, l;    if ((olen < 2) || (nlen < 2)) {        fprintf(cp_err, "Error: lengths too small to interpolate.\n");        return (false);    }    if ((degree < 1) || (degree > olen)) {        fprintf(cp_err, "Error: degree is %d, can't interpolate.\n",                degree);        return (false);    }    if (oscale[1] < oscale[0])        sign = -1;    else        sign = 1;    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));    /* Deal with the first degree pieces. */    bcopy((char *) data, (char *) ydata, (degree + 1) * sizeof (double));    bcopy((char *) oscale, (char *) xdata, (degree + 1) * sizeof (double));    while (!ft_polyfit(xdata, ydata, result, degree, scratch)) {        /* If it doesn't work this time, bump the interpolation         * degree down by one.         */        if (--degree == 0) {            fprintf(cp_err, "ft_interpolate: Internal Error.\n");            return (false);        }    }    /* Add this part of the curve. What we do is evaluate the polynomial     * at those points between the last one and the one that is greatest,     * without being greater than the leftmost old scale point, or least     * if the scale is decreasing at the end of the interval we are looking     * at.     */    lastone = -1;    for (i = 0; i < degree; i++) {        lastone = putinterval(result, degree, ndata, lastone,                     nscale, nlen, xdata[i], sign);    }    /* Now plot the rest, piece by piece. l is the      * last element under consideration.     */    for (l = degree + 1; l < olen; 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];        }        ydata[i] = data[l];        xdata[i] = oscale[l];        while (!ft_polyfit(xdata, ydata, result, degree, scratch)) {            if (--degree == 0) {                fprintf(cp_err,                     "interpolate: Internal Error.\n");                return (false);            }        }        lastone = putinterval(result, degree, ndata, lastone,                     nscale, nlen, xdata[i], sign);    }    if (lastone < nlen - 1) /* ??? */	ndata[nlen - 1] = data[olen - 1];    tfree(scratch);    tfree(xdata);    tfree(ydata);    tfree(result);    return (true);}/* Takes n = (degree+1) doubles, and fills in result with the n coefficients  * of the polynomial that will fit them. It also takes a pointer to an * array of n ^ 2 + n doubles to use for scratch -- we want to make this * fast and avoid doing mallocs for each call. */boolft_polyfit(xdata, ydata, result, degree, scratch)    double *xdata, *ydata, *result, *scratch;    int	degree;{    register double *mat1 = scratch;    register int l, k, j, i;    register int n = degree + 1;    register double *mat2 = scratch + n * n;	/* XXX These guys are hacks! */    double d;/*fprintf(cp_err, "n = %d, xdata = ( ", n);   for (i = 0; i < n; i++)    fprintf(cp_err, "%G ", xdata[i]);   fprintf(cp_err, ")\n");   fprintf(cp_err, "ydata = ( ");   for (i = 0; i < n; i++)    fprintf(cp_err, "%G ", ydata[i]);   fprintf(cp_err, ")\n");*/    bzero((char *) result, n * sizeof(double));    bzero((char *) mat1, n * n * sizeof (double));    bcopy((char *) ydata, (char *) mat2, n * sizeof (double));    /* Fill in the matrix with x^k for 0 <= k <= degree for each point */    l = 0;    for (i = 0; i < n; i++) {	d = 1.0;        for (j = 0; j < n; j++) {            mat1[l] = d;	    d *= xdata[i];            l += 1;        }    }    /* Do Gauss-Jordan elimination on mat1. */    for (i = 0; i < n; i++) {      int lindex;      double largest;        /* choose largest pivot */        for (j=i, largest = mat1[i * n + i], lindex = i; j < n; j++) {          if (fabs(mat1[j * n + i]) > largest) {            largest = fabs(mat1[j * n + i]);            lindex = j;          }        }        if (lindex != i) {          /* swap rows i and lindex */          for (k = 0; k < n; k++) {            d = mat1[i * n + k];            mat1[i * n + k] = mat1[lindex * n + k];            mat1[lindex * n + k] = d;          }          d = mat2[i];          mat2[i] = mat2[lindex];          mat2[lindex] = d;        }#ifdef notdef        if (mat1[i * n + i] == 0.0)            for (j = i; j < n; j++)                if (mat1[j * n + i] != 0.0) {                    /* Swap rows i and j. */                    for (k = 0; k < n; k++) {                        d = mat1[i * n + k];                        mat1[i * n + k] =                            mat1[j * n + k];                        mat1[j * n + k] = d;                    }                    d = mat2[i];                    mat2[i] = mat2[j];                    mat2[j] = d;                    break;                }#endif        /* Make sure we have a non-zero pivot. */        if (mat1[i * n + i] == 0.0) {            /* this should be rotated. */            return (false);        }        for (j = i + 1; j < n; j++) {            d = mat1[j * n + i] / mat1[i * n + i];            for (k = 0; k < n; k++)                mat1[j * n + k] -= d * mat1[i * n + k];            mat2[j] -= d * mat2[i];        }    }    for (i = n - 1; i > 0; i--)        for (j = i - 1; j >= 0; j--) {            d = mat1[j * n + i] / mat1[i * n + i];            for (k = 0; k < n; k++)                mat1[j * n + k] -=                         d * mat1[i * n + k];            mat2[j] -= d * mat2[i];        }        /* Now write the stuff into the result vector. */    for (i = 0; i < n; i++) {        result[i] = mat2[i] / mat1[i * n + i];        /* printf(cp_err, "result[%d] = %G\n", i, result[i]);*/    }#define ABS_TOL 0.001#define REL_TOL 0.001    /* Let's check and make sure the coefficients are ok.  If they aren't,     * just return false.  This is not the best way to do it.     */    for (i = 0; i < n; i++) {        d = ft_peval(xdata[i], result, degree);        if (fabs(d - ydata[i]) > ABS_TOL) {            /*            fprintf(cp_err,                "Error: polyfit: x = %le, y = %le, int = %le\n",                    xdata[i], ydata[i], d);            printmat("mat1", mat1, n, n);            printmat("mat2", mat2, n, 1);            */            return (false);        } else if (fabs(d - ydata[i]) / (fabs(d) > ABS_TOL ? fabs(d) :                ABS_TOL) > REL_TOL) {            /*            fprintf(cp_err,                "Error: polyfit: x = %le, y = %le, int = %le\n",                    xdata[i], ydata[i], d);            printmat("mat1", mat1, n, n);            printmat("mat2", mat2, n, 1);            */            return (false);        }    }    return (true);}/* Returns the index of the last element that was calculated. oval is the * value of the old scale at the end of the interval that is being interpolated * from, and sign is 1 if the old scale was increasing, and -1 if it was * decreasing. */static intputinterval(poly, degree, nvec, last, nscale, nlen, oval, sign)    double *poly, *nvec, *nscale, oval;{    int end, i;    /* See how far we have to go. */    for (end = last + 1; end < nlen; end++)        if (nscale[end] * sign > oval * sign)            break;    end--;    for (i = last + 1; i <= end; i++)        nvec[i] = ft_peval(nscale[i], poly, degree);    return (end);}static 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;}doubleft_peval(x, coeffs, degree)	double	x, *coeffs;	int	degree;{	double	y;	int	i;	if (!coeffs)		return 0.0;	/* XXX Should not happen */	y = coeffs[degree];	/* there are (degree+1) coeffs */	for (i = degree - 1; i >= 0; i--) {		y *= x;		y += coeffs[i];	}	return y;}#ifdef notdefXXX The following code is rediculous/* This should be a macro or be asm coded if possible. */doubleft_peval(pt, coeffs, degree)    double pt, *coeffs;    register int degree;{    register int i, j;    double d = 0.0, f;    /* fprintf(cp_err, "peval ");     for (i = 0; i <= degree; i++)         fprintf(cp_err, "%G ", coeffs[i]);    fprintf(cp_err, "at %G", pt);    */    for (i = 0; i <= degree; i++) {        f = 1.0;        for (j = 0; j < i; j++)            f *= pt;        d += f * coeffs[i];    }    /* fprintf(cp_err, " = %G\n", d);*/    return (d);}#endifvoidlincopy(ov, newscale, newlen, oldscale)    struct dvec *ov, *oldscale;    double *newscale;    int newlen;{    struct dvec *v;    double *nd;    if (!isreal(ov)) {        fprintf(cp_err, "Warning: %s is not real\n", ov->v_name);        return;    }    if (ov->v_length < oldscale->v_length) {        fprintf(cp_err, "Warning: %s is too short\n", ov->v_name);        return;    }    v = alloc(struct dvec);    v->v_name = copy(ov->v_name);    v->v_type = ov->v_type;    v->v_flags = ov->v_flags;    v->v_flags |= VF_PERMANENT;    v->v_length = newlen;    nd = (double *) tmalloc(newlen * sizeof (double));    if (!ft_interpolate(ov->v_realdata, nd, oldscale->v_realdata,            oldscale->v_length, newscale, newlen, 1)) {        fprintf(cp_err, "Error: can't interpolate %s\n", ov->v_name);        return;    }    v->v_realdata = nd;    vec_new(v);    return;}voidft_polyderiv(coeffs, degree)	double	*coeffs;	int	degree;{	int	i;	for (i = 0; i < degree; i++) {		coeffs[i] = (i + 1) * coeffs[i + 1];	}}

⌨️ 快捷键说明

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