From 37fe5308d347f33b4371e840f1f7ec64566c14ea Mon Sep 17 00:00:00 2001 From: h_vogt Date: Sun, 20 Dec 2015 15:17:46 +0100 Subject: [PATCH] xspice/icm/table, introduce table2d/table3d which allows to model devices based upon linear interpolation --- src/spinit.in | 1 + src/xspice/Makefile.am | 2 +- src/xspice/icm/GNUmakefile.in | 2 +- src/xspice/icm/table/mada/alloc.c | 71 +++ src/xspice/icm/table/mada/alloc.h | 23 + src/xspice/icm/table/mada/eno.c | 133 ++++ src/xspice/icm/table/mada/eno.h | 36 ++ src/xspice/icm/table/mada/eno2.c | 120 ++++ src/xspice/icm/table/mada/eno2.h | 35 ++ src/xspice/icm/table/mada/eno3.c | 142 +++++ src/xspice/icm/table/mada/eno3.h | 35 ++ src/xspice/icm/table/modpath.lst | 2 + src/xspice/icm/table/support/gettokens.c | 135 ++++ src/xspice/icm/table/support/interp.c | 183 ++++++ src/xspice/icm/table/table2D/cfunc.mod | 705 +++++++++++++++++++++ src/xspice/icm/table/table2D/ifspec.ifs | 78 +++ src/xspice/icm/table/table3D/cfunc.mod | 768 +++++++++++++++++++++++ src/xspice/icm/table/table3D/ifspec.ifs | 87 +++ src/xspice/icm/table/udnpath.lst | 0 visualc/how-to-ngspice-vstudio.txt | 1 + visualc/make-install-vngspice.bat | 2 + visualc/make-install-vngspiced.bat | 2 + visualc/spinit | 1 + visualc/spinit64 | 1 + visualc/spinitd | 1 + visualc/spinitd64 | 1 + visualc/vngspice-fftw.sln | 5 + visualc/vngspice.sln | 5 + visualc/xspice/table.vcxproj | 225 +++++++ visualc/xspice/xspice-local.sln | 2 + 30 files changed, 2802 insertions(+), 2 deletions(-) create mode 100644 src/xspice/icm/table/mada/alloc.c create mode 100644 src/xspice/icm/table/mada/alloc.h create mode 100644 src/xspice/icm/table/mada/eno.c create mode 100644 src/xspice/icm/table/mada/eno.h create mode 100644 src/xspice/icm/table/mada/eno2.c create mode 100644 src/xspice/icm/table/mada/eno2.h create mode 100644 src/xspice/icm/table/mada/eno3.c create mode 100644 src/xspice/icm/table/mada/eno3.h create mode 100644 src/xspice/icm/table/modpath.lst create mode 100644 src/xspice/icm/table/support/gettokens.c create mode 100644 src/xspice/icm/table/support/interp.c create mode 100644 src/xspice/icm/table/table2D/cfunc.mod create mode 100644 src/xspice/icm/table/table2D/ifspec.ifs create mode 100644 src/xspice/icm/table/table3D/cfunc.mod create mode 100644 src/xspice/icm/table/table3D/ifspec.ifs create mode 100644 src/xspice/icm/table/udnpath.lst create mode 100644 visualc/xspice/table.vcxproj diff --git a/src/spinit.in b/src/spinit.in index f2e19a180..305e7dfea 100644 --- a/src/spinit.in +++ b/src/spinit.in @@ -27,6 +27,7 @@ if $__flag = 0 @XSPICEINIT@ codemodel @pkglibdir@/digital.cm @XSPICEINIT@ codemodel @pkglibdir@/xtradev.cm @XSPICEINIT@ codemodel @pkglibdir@/xtraevt.cm +@XSPICEINIT@ codemodel @pkglibdir@/table.cm end unset __flag diff --git a/src/xspice/Makefile.am b/src/xspice/Makefile.am index 2a1299dcd..2718b4f79 100644 --- a/src/xspice/Makefile.am +++ b/src/xspice/Makefile.am @@ -15,7 +15,7 @@ dist-hook: rm -rf `find $(distdir)/icm -name .deps` rm -rf `find $(distdir)/icm -name *.o` rm -rf `find $(distdir)/icm -name *.cm` - for sub in analog digital spice2poly xtradev xtraevt ; do \ + for sub in analog digital spice2poly xtradev xtraevt table ; do \ rm -rf `find $(distdir)/icm/$$sub -name cmextrn.h`; \ rm -rf `find $(distdir)/icm/$$sub -name cminfo.h`; \ rm -rf `find $(distdir)/icm/$$sub -name udnextrn.h`; \ diff --git a/src/xspice/icm/GNUmakefile.in b/src/xspice/icm/GNUmakefile.in index 044a2a68f..06dbab4bf 100644 --- a/src/xspice/icm/GNUmakefile.in +++ b/src/xspice/icm/GNUmakefile.in @@ -7,7 +7,7 @@ include makedefs # The codemodels to make -CMDIRS = spice2poly digital analog xtradev xtraevt +CMDIRS = spice2poly digital analog xtradev xtraevt table all: diff --git a/src/xspice/icm/table/mada/alloc.c b/src/xspice/icm/table/mada/alloc.c new file mode 100644 index 000000000..cc0753581 --- /dev/null +++ b/src/xspice/icm/table/mada/alloc.c @@ -0,0 +1,71 @@ +/* Convenience allocation programs. */ +/* + Copyright (C) 2004 University of Texas at Austin + Copyright (C) 2007 Colorado School of Mines + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include +#include + +#include "alloc.h" +#include "ngspice/cm.h" + + +/*------------------------------------------------------------*/ +void * +sf_alloc(int n /* number of elements */, + size_t size /* size of one element */) +/*< output-checking allocation >*/ +{ + void *ptr; + + size *= (size_t) n; + + if (0 >= size) + cm_message_printf("%s: illegal allocation(%d bytes)", __FILE__, (int) size); + + ptr = malloc(size); + + if (NULL == ptr) + cm_message_printf("%s: cannot allocate %d bytes : ", __FILE__, (int) size); + + return ptr; +} + +/*------------------------------------------------------------*/ +double * +sf_doublealloc(int n /* number of elements */) +/*< float allocation >*/ +{ + return (double*) sf_alloc(n, sizeof(double)); +} + +/*------------------------------------------------------------*/ +double ** +sf_doublealloc2(int n1 /* fast dimension */, + int n2 /* slow dimension */) +/*< float 2-D allocation, out[0] points to a contiguous array >*/ +{ + int i2; + double **ptr = (double**) sf_alloc(n2, sizeof(double*)); + + ptr[0] = sf_doublealloc(n1 * n2); + for (i2 = 1; i2 < n2; i2++) + ptr[i2] = ptr[0] + i2 * n1; + + return ptr; +} diff --git a/src/xspice/icm/table/mada/alloc.h b/src/xspice/icm/table/mada/alloc.h new file mode 100644 index 000000000..24593e620 --- /dev/null +++ b/src/xspice/icm/table/mada/alloc.h @@ -0,0 +1,23 @@ +#ifndef _sf_alloc_h +#define _sf_alloc_h + + +#include +#include + + +/*------------------------------------------------------------*/ +void *sf_alloc (int n, /* number of elements */ + size_t size /* size of one element */); +/*< output-checking allocation >*/ + +/*------------------------------------------------------------*/ +double *sf_doublealloc (int n /* number of elements */); +/*< double allocation >*/ + +/*------------------------------------------------------------*/ +double **sf_doublealloc2(int n1, /* fast dimension */ + int n2 /* slow dimension */); +/*< float 2-D allocation, out[0] points to a contiguous array >*/ + +#endif diff --git a/src/xspice/icm/table/mada/eno.c b/src/xspice/icm/table/mada/eno.c new file mode 100644 index 000000000..e6fc11126 --- /dev/null +++ b/src/xspice/icm/table/mada/eno.c @@ -0,0 +1,133 @@ +/* 1-D ENO interpolation */ +/* + Copyright (C) 2004 University of Texas at Austin + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include +#include +#include + +#include "eno.h" +#include "alloc.h" + +#define SF_MAX(a,b) ((a) < (b) ? (b) : (a)) +#define SF_MIN(a,b) ((a) < (b) ? (a) : (b)) + + +struct Eno { + int order, n; + double **diff; +}; +/* concrete data type */ + +sf_eno +sf_eno_init (int order, /* interpolation order */ + int n /* data size */) +/*< Initialize interpolation object. >*/ +{ + sf_eno ent; + int i; + + ent = (sf_eno) sf_alloc(1, sizeof(*ent)); + ent->order = order; + ent->n = n; + ent->diff = (double**) sf_alloc(order, sizeof(double*)); + for (i = 0; i < order; i++) + ent->diff[i] = sf_doublealloc(n - i); + + return ent; +} + +void +sf_eno_close (sf_eno ent) +/*< Free internal storage >*/ +{ + int i; + + for (i = 0; i < ent->order; i++) + free (ent->diff[i]); + free (ent->diff); + free (ent); +} + +void +sf_eno_set (sf_eno ent, double *c /* data [n] */) +/*< Set the interpolation table. c can be changed or freed afterwords >*/ +{ + int i, j; + + for (i = 0; i < ent->n; i++) { + /* copy the initial data */ + ent->diff[0][i] = c[i]; + } + + for (j = 1; j < ent->order; j++) { + for (i = 0; i < ent->n - j; i++) { + /* compute difference tables */ + ent->diff[j][i] = ent->diff[j - 1][i + 1] - ent->diff[j - 1][i]; + } + } +} + +void sf_eno_apply (sf_eno ent, + int i, /* grid location */ + double x, /* offset from grid */ + double *f, /* output data value */ + double *f1, /* output derivative */ + der what /* flag of what to compute */) +/*< Apply interpolation >*/ +{ + int j, k, i1, i2, n; + double s, s1, y, w, g, g1; + + i2 = SF_MAX (0, SF_MIN(i, ent->n - ent->order)); + i1 = SF_MIN (i2, SF_MAX(0, i - ent->order + 2)); + + w = fabs(ent->diff[ent->order - 1][i1]); + for (j = i1 + 1; j <= i2; j++) { + g = fabs(ent->diff[ent->order - 1][j]); + if (w > g) + w = g; + } + + /* loop over starting points */ + for (g = 0., g1 = 0., n = 0, j = i1; j <= i2; j++) { + if (fabs(ent->diff[ent->order - 1][j]) > w) + continue; + n++; + + y = x + i - j; + + /* loop to compute the polynomial */ + for (s = 1., s1 = 0., k = 0; k < ent->order; k++) { + if (what != FUNC) { + g1 += s1 * ent->diff[k][j]; + s1 = (s + s1 * (y - k)) / (k + 1.); + } + if (what != DER) + g += s * ent->diff[k][j]; + s *= (y - k) / (k + 1.); + } + } + + if (what != DER) + *f = g / n; + if (what != FUNC) + *f1 = g1 / n; +} + +/* $Id: eno.c 8699 2012-07-03 22:10:38Z vovizmus $ */ diff --git a/src/xspice/icm/table/mada/eno.h b/src/xspice/icm/table/mada/eno.h new file mode 100644 index 000000000..e9cc1ffc0 --- /dev/null +++ b/src/xspice/icm/table/mada/eno.h @@ -0,0 +1,36 @@ +/* This file is automatically generated. DO NOT EDIT! */ + +#ifndef _sf_eno_h +#define _sf_eno_h + + +typedef struct Eno *sf_eno; +/* abstract data type */ + + +typedef enum {FUNC, DER, BOTH} der; +/* flag values */ + + +sf_eno sf_eno_init (int order, /* interpolation order */ + int n /* data size */); +/*< Initialize interpolation object. >*/ + + +void sf_eno_close (sf_eno ent); +/*< Free internal storage >*/ + + +void sf_eno_set (sf_eno ent, double* c /* data [n] */); +/*< Set the interpolation table. c can be changed or freed afterwords >*/ + + +void sf_eno_apply (sf_eno ent, + int i, /* grid location */ + double x, /* offset from grid */ + double *f, /* output data value */ + double *f1, /* output derivative */ + der what /* flag of what to compute */); +/*< Apply interpolation >*/ + +#endif diff --git a/src/xspice/icm/table/mada/eno2.c b/src/xspice/icm/table/mada/eno2.c new file mode 100644 index 000000000..e36adeda0 --- /dev/null +++ b/src/xspice/icm/table/mada/eno2.c @@ -0,0 +1,120 @@ +/* ENO interpolation in 2-D */ +/* + Copyright (C) 2004 University of Texas at Austin + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "eno.h" +#include "eno2.h" + +#include "alloc.h" +#include "ngspice/cm.h" + + +struct Eno2 { + int order, ng, n1, n2; + sf_eno jnt, *ent; + double *f, *f1; +}; +/* concrete data type */ + +sf_eno2 +sf_eno2_init (int order, /* interpolation order */ + int n1, int n2 /* data dimensions */) +/*< Initialize interpolation object >*/ +{ + sf_eno2 pnt; + int i2; + + pnt = (sf_eno2) sf_alloc(1, sizeof(*pnt)); + pnt->order = order; + pnt->n1 = n1; + pnt->n2 = n2; + pnt->ng = 2 * order - 2; + if (pnt->ng > pnt->n2) + cm_message_printf("%s: ng=%d is too big", __FILE__, pnt->ng); + pnt->jnt = sf_eno_init (order, pnt->ng); + pnt->f = sf_doublealloc (pnt->ng); + pnt->f1 = sf_doublealloc (pnt->ng); + pnt->ent = (sf_eno*) sf_alloc(n2, sizeof(sf_eno)); + for (i2 = 0; i2 < n2; i2++) + pnt->ent[i2] = sf_eno_init (order, n1); + + return pnt; +} + +void +sf_eno2_set (sf_eno2 pnt, double **c /* data [n2][n1] */) +/*< Set the interpolation table. c can be changed or freed afterwords. >*/ +{ + int i2; + + for (i2 = 0; i2 < pnt->n2; i2++) + sf_eno_set (pnt->ent[i2], c[i2]); +} + +void +sf_eno2_close (sf_eno2 pnt) +/*< Free internal storage >*/ +{ + int i2; + + sf_eno_close (pnt->jnt); + for (i2 = 0; i2 < pnt->n2; i2++) + sf_eno_close (pnt->ent[i2]); + free (pnt->f); + free (pnt->f1); + free (pnt->ent); + free (pnt); +} + +void +sf_eno2_apply (sf_eno2 pnt, + int i, int j, /* grid location */ + double x, double y, /* offset from grid */ + double *f, /* output data value */ + double *f1, /* output derivative [2] */ + der what /* what to compute [FUNC,DER,BOTH] */) +/*< Apply interpolation. >*/ +{ + int k, b2; + double g; + + if (j - pnt->order + 2 < 0) + b2 = 0; + else if (j + pnt->order - 1 > pnt->n2 - 1) + b2 = pnt->n2 - pnt->ng; + else + b2 = j - pnt->order + 2; + + j -= b2; + + for (k = 0; k < pnt->ng; k++) + if (what != FUNC) + sf_eno_apply (pnt->ent[b2 + k], i, x, pnt->f + k, pnt->f1 + k, BOTH); + else + sf_eno_apply (pnt->ent[b2 + k], i, x, pnt->f + k, pnt->f1 + k, FUNC); + + sf_eno_set (pnt->jnt, pnt->f); + sf_eno_apply (pnt->jnt, j, y, f, f1 + 1, what); + + if (what != FUNC) { + sf_eno_set (pnt->jnt, pnt->f1); + sf_eno_apply (pnt->jnt, j, y, f1, &g, FUNC); + } +} + +/* $Id: eno2.c 9044 2012-08-13 19:35:59Z vovizmus $ */ diff --git a/src/xspice/icm/table/mada/eno2.h b/src/xspice/icm/table/mada/eno2.h new file mode 100644 index 000000000..8da227efd --- /dev/null +++ b/src/xspice/icm/table/mada/eno2.h @@ -0,0 +1,35 @@ +/* This file is automatically generated. DO NOT EDIT! */ + +#ifndef _sf_eno2_h +#define _sf_eno2_h + + +#include "eno.h" + + +typedef struct Eno2 *sf_eno2; +/* abstract data type */ + + +sf_eno2 sf_eno2_init (int order, /* interpolation order */ + int n1, int n2 /* data dimensions */); +/*< Initialize interpolation object >*/ + + +void sf_eno2_set (sf_eno2 pnt, double **c /* data [n2][n1] */); +/*< Set the interpolation table. c can be changed or freed afterwords. >*/ + + +void sf_eno2_close (sf_eno2 pnt); +/*< Free internal storage >*/ + + +void sf_eno2_apply (sf_eno2 pnt, + int i, int j, /* grid location */ + double x, double y, /* offset from grid */ + double *f, /* output data value */ + double *f1, /* output derivative [2] */ + der what /* what to compute [FUNC,DER,BOTH] */); +/*< Apply interpolation. >*/ + +#endif diff --git a/src/xspice/icm/table/mada/eno3.c b/src/xspice/icm/table/mada/eno3.c new file mode 100644 index 000000000..81b7e7e93 --- /dev/null +++ b/src/xspice/icm/table/mada/eno3.c @@ -0,0 +1,142 @@ +/* ENO interpolation in 3-D */ +/* + Copyright (C) 2004 University of Texas at Austin + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "eno2.h" +#include "eno3.h" + +#include "alloc.h" +#include "ngspice/cm.h" + + +struct Eno3 { + int order, ng, n1, n2, n3; + sf_eno **ent; + sf_eno2 jnt; + double **f, **f1; +}; +/* concrete data type */ + +sf_eno3 +sf_eno3_init(int order, /* interpolation order */ + int n1, int n2, int n3 /* data dimensions */) +/*< Initialize interpolation object >*/ +{ + sf_eno3 pnt; + int i2, i3; + + pnt = (sf_eno3) sf_alloc (1, sizeof(*pnt)); + pnt->order = order; + pnt->n1 = n1; + pnt->n2 = n2; + pnt->n3 = n3; + pnt->ng = 2 * order - 2; + if (pnt->ng > n2 || pnt->ng > n3) + cm_message_printf("%s: ng=%d is too big", __FILE__, pnt->ng); + pnt->jnt = sf_eno2_init (order, pnt->ng, pnt->ng); + pnt->f = sf_doublealloc2 (pnt->ng, pnt->ng); + pnt->f1 = sf_doublealloc2 (pnt->ng, pnt->ng); + pnt->ent = (sf_eno**) sf_alloc (n3, sizeof(sf_eno*)); + for (i3 = 0; i3 < n3; i3++) { + pnt->ent[i3] = (sf_eno*) sf_alloc (n2, sizeof(sf_eno)); + for (i2 = 0; i2 < n2; i2++) + pnt->ent[i3][i2] = sf_eno_init (order, n1); + } + + return pnt; +} + +void +sf_eno3_set(sf_eno3 pnt, double ***c /* data [n3][n2][n1] */) +/*< Set the interpolation table. c can be changed or freed afterwords. >*/ +{ + int i2, i3; + + for (i3 = 0; i3 < pnt->n3; i3++) + for (i2 = 0; i2 < pnt->n2; i2++) + sf_eno_set (pnt->ent[i3][i2], c[i3][i2]); +} + +void +sf_eno3_close(sf_eno3 pnt) +/*< Free internal storage. >*/ +{ + int i2, i3; + + sf_eno2_close (pnt->jnt); + for (i3 = 0; i3 < pnt->n3; i3++) { + for (i2 = 0; i2 < pnt->n2; i2++) + sf_eno_close (pnt->ent[i3][i2]); + free (pnt->ent[i3]); + } + free (pnt->ent); + free (pnt->f[0]); + free (pnt->f); + free (pnt->f1[0]); + free (pnt->f1); + free (pnt); +} + +void +sf_eno3_apply(sf_eno3 pnt, + int i, int j, int k, /* grid location */ + double x, double y, double z, /* offsets from grid */ + double *f, /* output data */ + double *f1, /* output derivative [3] */ + der what /* to compute [FUNC|DER|BOTH] */) +/*< Apply interpolation. >*/ +{ + int i2, i3, b2, b3; + double g; + + if (j - pnt->order + 2 < 0) + b2 = 0; + else if (j + pnt->order - 1 > pnt->n2 - 1) + b2 = pnt->n2 - pnt->ng; + else + b2 = j - pnt->order + 2; + + j -= b2; + + + if (k - pnt->order + 2 < 0) + b3 = 0; + else if (k + pnt->order - 1 > pnt->n3 - 1) + b3 = pnt->n3 - pnt->ng; + else + b3 = k - pnt->order + 2; + + k -= b3; + + for (i3 = 0; i3 < pnt->ng; i3++) + for (i2 = 0; i2 < pnt->ng; i2++) + sf_eno_apply (pnt->ent[b3 + i3][b2 + i2], i, x, + &(pnt->f[i3][i2]), + &(pnt->f1[i3][i2]), + (what==FUNC ? FUNC : BOTH)); + + sf_eno2_set (pnt->jnt, pnt->f); + sf_eno2_apply (pnt->jnt, j, k, y, z, f, f1 + 1, what); + + if (what != FUNC) { + sf_eno2_set (pnt->jnt, pnt->f1); + sf_eno2_apply (pnt->jnt, j, k, y, z, f1, &g, FUNC); + } +} + +/* $Id: eno3.c 4148 2009-02-09 03:55:32Z sfomel $ */ diff --git a/src/xspice/icm/table/mada/eno3.h b/src/xspice/icm/table/mada/eno3.h new file mode 100644 index 000000000..6fad21b32 --- /dev/null +++ b/src/xspice/icm/table/mada/eno3.h @@ -0,0 +1,35 @@ +/* This file is automatically generated. DO NOT EDIT! */ + +#ifndef _sf_eno3_h +#define _sf_eno3_h + + +#include "eno2.h" + + +typedef struct Eno3 *sf_eno3; +/* abstract data type */ + + +sf_eno3 sf_eno3_init (int order, /* interpolation order */ + int n1, int n2, int n3 /* data dimensions */); +/*< Initialize interpolation object >*/ + + +void sf_eno3_set (sf_eno3 pnt, double ***c /* data [n3][n2][n1] */); +/*< Set the interpolation table. c can be changed or freed afterwords. >*/ + + +void sf_eno3_close (sf_eno3 pnt); +/*< Free internal storage. >*/ + + +void sf_eno3_apply (sf_eno3 pnt, + int i, int j, int k, /* grid location */ + double x, double y, double z, /* offsets from grid */ + double *f, /* output data */ + double *f1, /* output derivative [3] */ + der what /* to compute [FUNC|DER|BOTH] */); +/*< Apply interpolation. >*/ + +#endif diff --git a/src/xspice/icm/table/modpath.lst b/src/xspice/icm/table/modpath.lst new file mode 100644 index 000000000..53c945633 --- /dev/null +++ b/src/xspice/icm/table/modpath.lst @@ -0,0 +1,2 @@ +table2D +table3D diff --git a/src/xspice/icm/table/support/gettokens.c b/src/xspice/icm/table/support/gettokens.c new file mode 100644 index 000000000..4566ad932 --- /dev/null +++ b/src/xspice/icm/table/support/gettokens.c @@ -0,0 +1,135 @@ +/*=== Static CNVgettok ROUTINE ================*/ +/* +Get the next token from the input string. The input string pointer +is advanced to the following token and the token from the input +string is copied to malloced storage and a pointer to that storage +is returned. The original input string is undisturbed. +*/ + +#include +#include +#include +#include +#include + +/*=== CONSTANTS ========================*/ + +#define OK 0 +#define FAIL 1 + +/* Type definition for each possible token returned. */ +typedef enum token_type_s { CNV_NO_TOK, CNV_STRING_TOK } Cnv_Token_Type_t; + +extern char *CNVget_token(char **s, Cnv_Token_Type_t *type); + +/*=== MACROS ===========================*/ + +#if defined(__MINGW32__) || defined(_MSC_VER) +#define DIR_PATHSEP "\\" +#else +#define DIR_PATHSEP "/" +#endif + +#if defined(_MSC_VER) +#define strdup _strdup +#define snprintf _snprintf +#endif + + + +char * +CNVgettok(char **s) +{ + char *buf; /* temporary storage to copy token into */ + /*char *temp;*/ /* temporary storage to copy token into */ + char *ret_str; /* storage for returned string */ + + int i; + + /* allocate space big enough for the whole string */ + + buf = (char *) malloc(strlen(*s) + 1); + + /* skip over any white space */ + + while (isspace_c(**s) || (**s == '=') || + (**s == '(') || (**s == ')') || (**s == ',')) + (*s)++; + + /* isolate the next token */ + + switch (**s) { + + case '\0': /* End of string found */ + if (buf) + free(buf); + return NULL; + + + default: /* Otherwise, we are dealing with a */ + /* string representation of a number */ + /* or a mess o' characters. */ + i = 0; + while ( (**s != '\0') && + (! ( isspace_c(**s) || (**s == '=') || + (**s == '(') || (**s == ')') || + (**s == ',') + ) ) ) { + buf[i] = **s; + i++; + (*s)++; + } + buf[i] = '\0'; + break; + } + + /* skip over white space up to next token */ + + while (isspace_c(**s) || (**s == '=') || + (**s == '(') || (**s == ')') || (**s == ',')) + (*s)++; + + /* make a copy using only the space needed by the string length */ + + + ret_str = (char *) malloc(strlen(buf) + 1); + ret_str = strcpy(ret_str,buf); + + if (buf) free(buf); + + return ret_str; +} + + + +/*=== Static CNVget_token ROUTINE =============*/ +/* +Get the next token from the input string together with its type. +The input string pointer +is advanced to the following token and the token from the input +string is copied to malloced storage and a pointer to that storage +is returned. The original input string is undisturbed. +*/ + +char * +CNVget_token(char **s, Cnv_Token_Type_t *type) +{ + char *ret_str; /* storage for returned string */ + + /* get the token from the input line */ + ret_str = CNVgettok(s); + + /* if no next token, return */ + if (ret_str == NULL) { + *type = CNV_NO_TOK; + return NULL; + } + + /* else, determine and return token type */ + switch (*ret_str) { + default: + *type = CNV_STRING_TOK; + break; + } + return ret_str; +} diff --git a/src/xspice/icm/table/support/interp.c b/src/xspice/icm/table/support/interp.c new file mode 100644 index 000000000..3ace153b5 --- /dev/null +++ b/src/xspice/icm/table/support/interp.c @@ -0,0 +1,183 @@ +#include +#include +#include +#include +#include + +/*********************/ +/* 3d geometry types */ +/*********************/ + +typedef struct Point3Struct { /* 3d point */ + double x, y, z; + } Point3; +typedef Point3 Vector3; + +//FIXME +double BilinearInterpolation(double q11, double q12, double q21, double q22, double x1, double x2, double y1, double y2, double x, double y); + + +/* Function to find the cross over point (the point before + which elements are smaller than or equal to x and after + which greater than x) + http://www.geeksforgeeks.org/find-k-closest-elements-given-value/ */ +int +findCrossOver(double arr[], int low, int high, double x) +{ + int mid; + // Base cases + if (arr[high] <= x) // x is greater than all + return high; + if (arr[low] > x) // x is smaller than all + return low; + + // Find the middle point + mid = (low + high)/2; /* low + (high - low)/2 */ + + /* If x is same as middle element, then return mid */ + if (arr[mid] <= x && arr[mid+1] > x) + return mid; + + /* If x is greater than arr[mid], then either arr[mid + 1] + is ceiling of x or ceiling lies in arr[mid+1...high] */ + if (arr[mid] < x) + return findCrossOver(arr, mid+1, high, x); + + return findCrossOver(arr, low, mid - 1, x); +} + +/* https://helloacm.com/cc-function-to-compute-the-bilinear-interpolation/ */ +double +BilinearInterpolation(double q11, double q12, double q21, double q22, double x1, double x2, double y1, double y2, double x, double y) +{ + double x2x1, y2y1, x2x, y2y, yy1, xx1; + x2x1 = x2 - x1; + y2y1 = y2 - y1; + x2x = x2 - x; + y2y = y2 - y; + yy1 = y - y1; + xx1 = x - x1; + return 1.0 / (x2x1 * y2y1) * ( + q11 * x2x * y2y + + q21 * xx1 * y2y + + q12 * x2x * yy1 + + q22 * xx1 * yy1 + ); +} + + +/* + * C code from the article + * "Tri-linear Interpolation" + * by Steve Hill, sah@ukc.ac.uk + * in "Graphics Gems IV", Academic Press, 1994 + * + */ + +#if 0 + +double +trilinear(Point3 *p, double *d, int xsize, int ysize, int zsize, double def) +{ +# define DENS(X, Y, Z) d[(X)+xsize*((Y)+ysize*(Z))] + + int x0, y0, z0, + x1, y1, z1; + double *dp, + fx, fy, fz, + d000, d001, d010, d011, + d100, d101, d110, d111, + dx00, dx01, dx10, dx11, + dxy0, dxy1, dxyz; + + x0 = floor(p->x); + fx = p->x - x0; + y0 = floor(p->y); + fy = p->y - y0; + z0 = floor(p->z); + fz = p->z - z0; + + x1 = x0 + 1; + y1 = y0 + 1; + z1 = z0 + 1; + + if (x0 >= 0 && x1 < xsize && + y0 >= 0 && y1 < ysize && + z0 >= 0 && z1 < zsize) { + dp = &DENS(x0, y0, z0); + d000 = dp[0]; + d100 = dp[1]; + dp += xsize; + d010 = dp[0]; + d110 = dp[1]; + dp += xsize*ysize; + d011 = dp[0]; + d111 = dp[1]; + dp -= xsize; + d001 = dp[0]; + d101 = dp[1]; + } else { +# define INRANGE(X, Y, Z) \ + ((X) >= 0 && (X) < xsize && \ + (Y) >= 0 && (Y) < ysize && \ + (Z) >= 0 && (Z) < zsize) + + d000 = INRANGE(x0, y0, z0) ? DENS(x0, y0, z0) : def; + d001 = INRANGE(x0, y0, z1) ? DENS(x0, y0, z1) : def; + d010 = INRANGE(x0, y1, z0) ? DENS(x0, y1, z0) : def; + d011 = INRANGE(x0, y1, z1) ? DENS(x0, y1, z1) : def; + + d100 = INRANGE(x1, y0, z0) ? DENS(x1, y0, z0) : def; + d101 = INRANGE(x1, y0, z1) ? DENS(x1, y0, z1) : def; + d110 = INRANGE(x1, y1, z0) ? DENS(x1, y1, z0) : def; + d111 = INRANGE(x1, y1, z1) ? DENS(x1, y1, z1) : def; + } +/* linear interpolation from l (when a=0) to h (when a=1)*/ +/* (equal to (a*h)+((1-a)*l) */ +#define LERP(a,l,h) ((l)+(((h)-(l))*(a))) + + dx00 = LERP(fx, d000, d100); + dx01 = LERP(fx, d001, d101); + dx10 = LERP(fx, d010, d110); + dx11 = LERP(fx, d011, d111); + + dxy0 = LERP(fy, dx00, dx10); + dxy1 = LERP(fy, dx01, dx11); + + dxyz = LERP(fz, dxy0, dxy1); + + return dxyz; +} + +#endif + + +/* trilinear interpolation +Paul Bourke +July 1997 +http://paulbourke.net/miscellaneous/interpolation/ */ + +double +TrilinearInterpolation(double x, double y, double z, int xind, int yind, int zind, double ***td) +{ + double V000, V100, V010, V001, V101, V011, V110, V111, Vxyz; + + V000 = td[zind][yind][xind]; + V100 = td[zind][yind][xind+1]; + V010 = td[zind][yind+1][xind]; + V001 = td[zind+1][yind][xind]; + V101 = td[zind+1][yind][xind+1]; + V011 = td[zind+1][yind+1][xind]; + V110 = td[zind][yind+1][xind+1]; + V111 = td[zind+1][yind+1][xind+1]; + + Vxyz = V000 * (1 - x) * (1 - y) * (1 - z) + + V100 * x * (1 - y) * (1 - z) + + V010 * (1 - x) * y * (1 - z) + + V001 * (1 - x) * (1 - y) * z + + V101 * x * (1 - y) * z + + V011 * (1 - x) * y * z + + V110 * x * y * (1 - z) + + V111 * x * y * z; + return Vxyz; +} diff --git a/src/xspice/icm/table/table2D/cfunc.mod b/src/xspice/icm/table/table2D/cfunc.mod new file mode 100644 index 000000000..4a21b2a3f --- /dev/null +++ b/src/xspice/icm/table/table2D/cfunc.mod @@ -0,0 +1,705 @@ +/*.......1.........2.........3.........4.........5.........6.........7.........8 +================================================================================ + +FILE table2D/cfunc.mod + +Copyright 2015 +Holger Vogt + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + + +AUTHORS + + 03 Nov 2015 Holger Vogt + + +MODIFICATIONS + + +SUMMARY + + This file contains the model-specific routines used to + functionally describe the 2D table code model used + to read and interpolate a value from a 2D table from a file. + + The essentially non-oscillatory (ENO) interpolation in 2-D (eno2.c) is taken from the + Madagascar Project at http://www.ahay.org/wiki/Main_Page + Currently ENO is used only to obtain the derivatives, + the data values are obtained by bilinear interpolation. + This combination allows op convergence for some data tables (no guarantee though). + +INTERFACES + + FILE ROUTINE CALLED + + N/A N/A + + +REFERENCED FILES + + Inputs from and outputs to ARGS structure. + + +NON-STANDARD FEATURES + + NONE + +===============================================================================*/ + +/*=== INCLUDE FILES ====================*/ + +#include +#include +#include +#include +#include + +#include +#include + +#include "mada/eno2.h" + +/*=== CONSTANTS ========================*/ + +#define OK 0 +#define FAIL 1 + +/*=== MACROS ===========================*/ + +#if defined(__MINGW32__) || defined(_MSC_VER) +#define DIR_PATHSEP "\\" +#else +#define DIR_PATHSEP "/" +#endif + +#if defined(_MSC_VER) +#define strdup _strdup +#define snprintf _snprintf +#endif + +/*=== LOCAL VARIABLES & TYPEDEFS =======*/ + +struct filesource_state { + FILE *fp; + long pos; + unsigned char atend; +}; + + +typedef struct { + + int ix; /* size of array in x */ + int iy; /* size of array in y */ + + struct filesource_state *state; /* the storage array for the + filesource status. */ + int init_err; + + sf_eno2 newtable; /* the table, code borrowed from madagascar project */ + + double *xcol; /* array of floats in x */ + double *ycol; /* array of floats in y */ + + double **table; + +} Local_Data_t; + +/* Type definition for each possible token returned. */ +typedef enum token_type_s {CNV_NO_TOK, CNV_STRING_TOK} Cnv_Token_Type_t; + +typedef char line_t[82]; /* A SPICE size line. <= 80 characters plus '\n\0' */ + +/*=== FUNCTION PROTOTYPE DEFINITIONS ===*/ + +extern int findCrossOver(double arr[], int low, int high, double x); +extern double BilinearInterpolation(double q11, double q12, double q21, double q22, double x1, double x2, double y1, double y2, double x, double y); + +extern char *CNVgettok(char **s); + +/*============================================================================== + +FUNCTION cnv_get_spice_value() + +AUTHORS + + ??? Bill Kuhn + +MODIFICATIONS + + 30 Sep 1991 Jeffrey P. Murray + +SUMMARY + + This function takes as input a string token from a SPICE + deck and returns a floating point equivalent value. + +INTERFACES + + FILE ROUTINE CALLED + + N/A N/A + +RETURNED VALUE + + Returns the floating point value in pointer *p_value. Also + returns an integer representing successful completion. + +GLOBAL VARIABLES + + NONE + +NON-STANDARD FEATURES + + NONE + +==============================================================================*/ + +/*=== Static CNV_get_spice_value ROUTINE =============*/ + +/* + Function takes as input a string token from a SPICE + deck and returns a floating point equivalent value. +*/ + + +static int +cnv_get_spice_value(char *str, /* IN - The value text e.g. 1.2K */ + double *p_value) /* OUT - The numerical value */ +{ + /* the following were "int4" devices - jpm */ + size_t len; + size_t i; + int n_matched; + + line_t val_str; + + char c = ' '; + char c1; + + double scale_factor; + double value; + + /* Scan the input string looking for an alpha character that is not */ + /* 'e' or 'E'. Such a character is assumed to be an engineering */ + /* suffix as defined in the Spice 2G.6 user's manual. */ + + len = strlen(str); + if (len > sizeof(val_str) - 1) + len = sizeof(val_str) - 1; + + for (i = 0; i < len; i++) { + c = str[i]; + if (isalpha_c(c) && (c != 'E') && (c != 'e')) + break; + else if (isspace_c(c)) + break; + else + val_str[i] = c; + } + val_str[i] = '\0'; + + /* Determine the scale factor */ + + if ((i >= len) || !isalpha_c(c)) + scale_factor = 1.0; + else { + + if (isupper_c(c)) + c = tolower_c(c); + + switch (c) { + + case 't': + scale_factor = 1.0e12; + break; + + case 'g': + scale_factor = 1.0e9; + break; + + case 'k': + scale_factor = 1.0e3; + break; + + case 'u': + scale_factor = 1.0e-6; + break; + + case 'n': + scale_factor = 1.0e-9; + break; + + case 'p': + scale_factor = 1.0e-12; + break; + + case 'f': + scale_factor = 1.0e-15; + break; + + case 'm': + i++; + if (i >= len) { + scale_factor = 1.0e-3; + break; + } + c1 = str[i]; + if (!isalpha_c(c1)) { + scale_factor = 1.0e-3; + break; + } + if (islower_c(c1)) + c1 = toupper_c(c1); + if (c1 == 'E') + scale_factor = 1.0e6; + else if (c1 == 'I') + scale_factor = 25.4e-6; + else + scale_factor = 1.0e-3; + break; + + default: + scale_factor = 1.0; + } + } + + /* Convert the numeric portion to a float and multiply by the */ + /* scale factor. */ + + n_matched = sscanf(val_str, "%le", &value); + + if (n_matched < 1) { + *p_value = 0.0; + return FAIL; + } + + *p_value = value * scale_factor; + return OK; +} + + +/*============================================================================== + +FUNCTION void cm_table2D() + +AUTHORS + + 08 Nov 2015 Holger Vogt + +MODIFICATIONS + + + +SUMMARY + + This function implements 2D table code model. + +INTERFACES + + FILE ROUTINE CALLED + + N/A N/A + + +RETURNED VALUE + + Returns inputs and outputs via ARGS structure. + +GLOBAL VARIABLES + + NONE + +NON-STANDARD FEATURES + + NONE + +INPUT FILE SPEC + +* Title (comments preceded by * ignored) +* table size +ix +iy +* x row independent variables +x0 x1 x2 x3 ... xix-1 +y column independent variables +y0 y1 y2 y3 ... yiy-1 +* table +x0y0 x1y0 x2y0 ... xix-1y0 +... +x0yiy-1 x1yiy-1 x2yiy-1 ... xix-1yiy-1 + + + +==============================================================================*/ + + +/*=== CM_table2D ROUTINE ===*/ + + +void +cm_table2D(ARGS) /* structure holding parms, inputs, outputs, etc. */ +{ + int size, xind, yind; + double xval, yval, xoff, yoff, xdiff, ydiff; + double derivval[2], outval; + double q11, q12, q21, q22, x1, x2, y1, y2; + + Local_Data_t *loc; /* Pointer to local static data, not to be included + in the state vector */ + Mif_Complex_t ac_gain; + + size = PORT_SIZE(out); + if (INIT == 1) { + + int i; + int ix = 0, /* elements in a row */ + iy = 0; /* number of rows */ + double **table_data; + double tmp; + char *cFile, *cThisPtr, *cThisLine, *cThisLinePtr; + int isNewline; /* Boolean indicating we've read a CR or LF */ + size_t lFileLen; /* Length of file */ + size_t lFileRead; /* Length of file read in */ + long lIndex; /* Index into cThisLine array */ + int lLineCount; /* Current line number */ + size_t lStartPos; /* Offset of start of current line */ + size_t lTotalChars; /* Total characters read */ + int interporder; /* order of interpolation for eno */ + + /* allocate static storage for *loc */ + STATIC_VAR (locdata) = calloc(1, sizeof(Local_Data_t)); + loc = STATIC_VAR (locdata); + + /* Allocate storage for internal state */ + loc->state = (struct filesource_state*) malloc(sizeof(struct filesource_state)); + loc->ix = loc->iy = 0; + + /* open file */ + loc->state->fp = fopen_with_path(PARAM(file), "r"); + loc->state->pos = 0; + loc->state->atend = 0; + if (!loc->state->fp) { + char *lbuffer, *p; + lbuffer = getenv("NGSPICE_INPUT_DIR"); + if (lbuffer && *lbuffer) { + p = (char*) malloc(strlen(lbuffer) + strlen(DIR_PATHSEP) + strlen(PARAM(file)) + 1); + sprintf(p, "%s%s%s", lbuffer, DIR_PATHSEP, PARAM(file)); + loc->state->fp = fopen(p, "r"); + free(p); + } + } + struct stat st; + if (!loc->state->fp || fstat(fileno(loc->state->fp), &st)) { + cm_message_printf("cannot open file %s", PARAM(file)); + loc->state->atend = 1; + loc->init_err = 1; + return; + } + /* get file length */ + lFileLen = (size_t) st.st_size; + + /* create string to hold the whole file */ + cFile = calloc(lFileLen + 1, sizeof(char)); + /* create another string long enough for file manipulation */ + cThisLine = calloc(lFileLen + 1, sizeof(char)); + if (cFile == NULL || cThisLine == NULL) { + cm_message_printf("Insufficient memory to read file %s", PARAM(file)); + loc->state->atend = 1; + loc->init_err = 1; + return; + } + /* read whole file into cFile */ + lFileRead = fread(cFile, sizeof(char), lFileLen, loc->state->fp); + fclose(loc->state->fp); + /* Number of chars read may be less than lFileLen, because /r are skipt by 'fread' */ + cFile[lFileRead] = '\0'; + + cThisPtr = cFile; + cThisLinePtr = cThisLine; + lLineCount = 0L; + lTotalChars = 0L; + + while (*cThisPtr) { /* Read until reaching null char */ + + lIndex = 0L; /* Reset counters and flags */ + isNewline = 0; + lStartPos = lTotalChars; + + while (*cThisPtr) { + if (!isNewline) { /* Haven't read a LF yet */ + if (*cThisPtr == '\n') /* This char is LF */ + isNewline = 1; /* Set flag */ + } + else if (*cThisPtr != '\n') /* Already found LF */ + break; /* Done with line */ + + cThisLinePtr[lIndex++] = *cThisPtr++; /* Add char to output and increment */ + lTotalChars++; + } + + cThisLinePtr[lIndex] = '\0'; /* Terminate the string */ + lLineCount++; /* Increment the line counter */ + /* continue if comment or empty */ + if (cThisLinePtr[0] == '*' || cThisLinePtr[0] == '\n') { + lLineCount--; /* we count only real lines */ + continue; + } + + if (lLineCount == 1) { + cnv_get_spice_value(cThisLinePtr, &tmp); + loc->ix = ix = (int) tmp; + /* generate row data structure (x) */ + loc->xcol = (double*) calloc((size_t) ix, sizeof(double)); + } + else if (lLineCount == 2) { + cnv_get_spice_value(cThisLinePtr, &tmp); + loc->iy = iy = (int) tmp; + /* generate column data structure (y) */ + loc->ycol = (double*) calloc((size_t) iy, sizeof(double)); + } + else if (lLineCount == 3) { + char *token = CNVgettok(&cThisLinePtr); + i = 0; + while (token) { + if (i == ix) { + cm_message_printf("Too many numbers in x row."); + loc->init_err = 1; + return; + } + cnv_get_spice_value(token, &loc->xcol[i++]); + free(token); + token = CNVgettok(&cThisLinePtr); + } + if (i < ix) { + cm_message_printf("Not enough numbers in x row."); + loc->init_err = 1; + return; + } + } + else if (lLineCount == 4) { + char *token = CNVgettok(&cThisLinePtr); + i = 0; + while (token) { + if (i == iy) { + cm_message_printf("Too many numbers in y row."); + loc->init_err = 1; + return; + } + cnv_get_spice_value(token, &loc->ycol[i++]); + free(token); + token = CNVgettok(&cThisLinePtr); + } + if (i < iy) { + cm_message_printf("Not enough numbers in y row."); + loc->init_err = 1; + return; + } + /* jump out of while loop to read in the table */ + break; + } + } + + /* generate table core */ + interporder = PARAM(order); + /* boundary limits set to param 'order' aren't recognized, + so limit them here */ + if (interporder < 2) { + cm_message_printf("Parameter Order=%d not possible, set to minimum value 2", interporder); + interporder = 2; + } + /* int order : interpolation order, + int n1, int n2 : data dimensions */ + loc->newtable = sf_eno2_init(interporder, ix, iy); + + /* create table_data in memory */ + /* data [n2][n1] */ + table_data = calloc((size_t) iy, sizeof(double *)); + for (i = 0; i < iy; i++) + table_data[i] = calloc((size_t) ix, sizeof(double)); + + loc->table = table_data; + + /* continue reading from cFile */ + lLineCount = 0; + while (*cThisPtr) { /* Read until reaching null char */ + char *token; + + lIndex = 0L; /* Reset counters and flags */ + isNewline = 0; + lStartPos = lTotalChars; + + while (*cThisPtr) { /* Read until reaching null char */ + + if (!isNewline) { /* Haven't read a LF yet */ + if (*cThisPtr == '\n') /* This char is a LF */ + isNewline = 1; /* Set flag */ + } + + else if (*cThisPtr != '\n') /* Already found LF */ + break; /* Done with line */ + + cThisLinePtr[lIndex++] = *cThisPtr++; /* Add char to output and increment */ + lTotalChars++; + } + + cThisLinePtr[lIndex] = '\0'; /* Terminate the string */ + lLineCount++; /* Increment the line counter */ + /* continue if comment or empty */ + if (cThisLinePtr[0] == '*' || cThisLinePtr[0] == '\0') { + if (lTotalChars >= lFileLen) { + cm_message_printf("Not enough data in file %s", PARAM(file)); + loc->init_err = 1; + return; + } + lLineCount--; /* we count only real lines */ + continue; + } + token = CNVgettok(&cThisLinePtr); + i = 0; + while (token) { + double tmpval; + if (i == ix) { + cm_message_printf("Too many numbers in y row no. %d.", lLineCount); + loc->init_err = 1; + return; + } + + /* read table core from cFile, fill local static table structure table_data */ + cnv_get_spice_value(token, &tmpval); + table_data[lLineCount - 1][i++] = tmpval; + free(token); + token = CNVgettok(&cThisLinePtr); + } + if (i < ix) { + cm_message_printf("Not enough numbers in y row no. %d.", lLineCount); + loc->init_err = 1; + return; + } + } + + /* fill table data into eno2 structure */ + sf_eno2_set (loc->newtable, table_data /* data [n2][n1] */); + + /* free all the emory allocated */ + // for (i = 0; i < iy; i++) + // free(table_data[i]); + // free(table_data); + free(cFile); + free(cThisLine); + } /* end of initialization "if (INIT == 1)" */ + + loc = STATIC_VAR (locdata); + + /* return immediately if there was an initialization error */ + if (loc->init_err == 1) + return; + + /* get input x, y, + find corresponding indices, + get x and y offsets, + call interpolation function with value and derivative */ + xval = INPUT(inx); + yval = INPUT(iny); + + /* find index */ + if (xval < loc->xcol[0] || xval > loc->xcol[loc->ix - 1]) { + if (PARAM(verbose) > 0) + cm_message_printf("x value %g exceeds table limits,\n" + " please enlarge range of your table", + xval); + return; + } + if (yval < loc->ycol[0] || yval > loc->ycol[loc->iy - 1]) { + if (PARAM(verbose) > 0) + cm_message_printf("y value %g exceeds table limits,\n" + " please enlarge range of your table", + yval); + return; + } + + /* something like binary search to get the index */ + xind = findCrossOver(loc->xcol, 0, loc->ix - 1, xval); + /* find index with minimum distance between xval and row value */ + if (fabs(loc->xcol[xind + 1] - xval) < fabs(xval - loc->xcol[xind])) + xind++; + xoff = xval - loc->xcol[xind]; + yind = findCrossOver(loc->ycol, 0, loc->iy - 1, yval); + /* find index with minimum distance between yval and column value */ + if (fabs(loc->ycol[yind + 1] - yval) < fabs(yval - loc->ycol[yind])) + yind++; + yoff = yval - loc->ycol[yind]; + + /* find local difference around index of independent row and column values */ + if (xind == loc->ix - 1) + xdiff = loc->xcol[xind] - loc->xcol[xind - 1]; + else if (xind == 0) + xdiff = loc->xcol[xind + 1] - loc->xcol[xind]; + else + xdiff = 0.5 * (loc->xcol[xind + 1] - loc->xcol[xind - 1]); + + if (yind == loc->iy - 1) + ydiff = loc->ycol[yind] - loc->ycol[yind - 1]; + else if (yind == 0) + ydiff = loc->ycol[yind + 1] - loc->ycol[yind]; + else + ydiff = 0.5 * (loc->ycol[yind + 1] - loc->ycol[yind - 1]); + + /* Essentially non-oscillatory (ENO) interpolation to obtain the derivatives only. + Using outval for now yields ngspice op non-convergence */ + sf_eno2_apply (loc->newtable, + xind, yind, /* grid location */ + xoff, yoff, /* offset from grid */ + &outval, /* output data value */ + derivval, /* output derivatives [2] */ + DER /* what to compute [FUNC, DER, BOTH] */ + ); + + /* bilinear interpolation to obtain the output value */ + xind = findCrossOver(loc->xcol, 0, loc->ix - 1, xval); + yind = findCrossOver(loc->ycol, 0, loc->iy - 1, yval); + x1 = loc->xcol[xind]; + x2 = loc->xcol[xind + 1]; + y1 = loc->ycol[yind]; + y2 = loc->ycol[yind + 1]; + q11 = loc->table[yind][xind]; + q12 = loc->table[yind + 1][xind]; + q21 = loc->table[yind][xind + 1]; + q22 = loc->table[yind + 1][xind + 1]; + outval = BilinearInterpolation(q11, q12, q21, q22, x1, x2, y1, y2, xval, yval); + + if (ANALYSIS != MIF_AC) { + double xderiv, yderiv, outv; + outv = PARAM(offset) + PARAM(gain) * outval; + OUTPUT(out) = outv; + xderiv = PARAM(gain) * derivval[0] / xdiff; + PARTIAL(out, inx) = xderiv; + yderiv = PARAM(gain) * derivval[1] / ydiff; + PARTIAL(out, iny) = yderiv; + + if (PARAM(verbose) > 1) + cm_message_printf("\nI: %g, xval: %g, yval: %g, xderiv: %g, yderiv: %g", outv, xval, yval, xderiv, yderiv); + } + else { + ac_gain.real = PARAM(gain) * derivval[0] / xdiff; + ac_gain.imag= 0.0; + AC_GAIN(out, inx) = ac_gain; + ac_gain.real = PARAM(gain) * derivval[1] / ydiff; + ac_gain.imag= 0.0; + AC_GAIN(out, iny) = ac_gain; + } + +} diff --git a/src/xspice/icm/table/table2D/ifspec.ifs b/src/xspice/icm/table/table2D/ifspec.ifs new file mode 100644 index 000000000..3d982adfe --- /dev/null +++ b/src/xspice/icm/table/table2D/ifspec.ifs @@ -0,0 +1,78 @@ +/*.......1.........2.........3.........4.........5.........6.........7.........8 +================================================================================ +Copyright 2015 +Holger Vogt + +AUTHORS + + 06 Nov 2015 Holger Vogt + + +SUMMARY + + This file contains the interface specification file for the + 2D table code model. + +===============================================================================*/ + +NAME_TABLE: + +C_Function_Name: cm_table2D +Spice_Model_Name: table2d +Description: "2D table model" + + +PORT_TABLE: + +Port_Name: inx iny out +Description: "inputx" "inputy" "output" +Direction: in in out +Default_Type: v v i +Allowed_Types: [v,vd,i,id,vnam] [v,vd,i,id,vnam] [v,vd,i,id] +Vector: no no no +Vector_Bounds: - - - +Null_Allowed: no no no + + + + +PARAMETER_TABLE: + +Parameter_Name: order verbose +Description: "order" "verbose" +Data_Type: int int +Default_Value: 3 0 +Limits: [2 -] [0 2] +Vector: no no +Vector_Bounds: - - +Null_Allowed: yes yes + +PARAMETER_TABLE: + +Parameter_Name: offset gain +Description: "offset" "gain" +Data_Type: real real +Default_Value: 0.0 1.0 +Limits: - - +Vector: no no +Vector_Bounds: - - +Null_Allowed: yes yes + + +PARAMETER_TABLE: + +Parameter_Name: file +Description: "file name" +Data_Type: string +Default_Value: "2D-table-model.txt" +Limits: - +Vector: no +Vector_Bounds: - +Null_Allowed: yes + + +STATIC_VAR_TABLE: + +Static_Var_Name: locdata +Description: "local static data" +Data_Type: pointer diff --git a/src/xspice/icm/table/table3D/cfunc.mod b/src/xspice/icm/table/table3D/cfunc.mod new file mode 100644 index 000000000..5bb2054f5 --- /dev/null +++ b/src/xspice/icm/table/table3D/cfunc.mod @@ -0,0 +1,768 @@ +/*.......1.........2.........3.........4.........5.........6.........7.........8 +================================================================================ + +FILE table3D/cfunc.mod + +Copyright 2015 +Holger Vogt + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + + +AUTHORS + + 03 Nov 2015 Holger Vogt + + +MODIFICATIONS + + +SUMMARY + + This file contains the model-specific routines used to + functionally describe the 3D table code model used + to read and interpolate a value from a 3D table from a file. + + The essentially non-oscillatory (ENO) interpolation in 3-D (eno3.c) is taken from the + Madagascar Project at http://www.ahay.org/wiki/Main_Page + Currently ENO is used only to obtain the derivatives, + the data values are obtained by trilinear interpolation. + This combination allows op convergence for some data tables (no guarantee though). + +INTERFACES + + FILE ROUTINE CALLED + + N/A N/A + + +REFERENCED FILES + + Inputs from and outputs to ARGS structure. + + +NON-STANDARD FEATURES + + NONE + +===============================================================================*/ + +/*=== INCLUDE FILES ====================*/ + +#include +#include +#include +#include +#include + +#include +#include + +#include "mada/eno2.h" +#include "mada/eno3.h" + +/*=== CONSTANTS ========================*/ + +#define OK 0 +#define FAIL 1 + +/*=== MACROS ===========================*/ + +#if defined(__MINGW32__) || defined(_MSC_VER) +#define DIR_PATHSEP "\\" +#else +#define DIR_PATHSEP "/" +#endif + +#if defined(_MSC_VER) +#define strdup _strdup +#define snprintf _snprintf +#endif + +/*=== LOCAL VARIABLES & TYPEDEFS =======*/ + +struct filesource_state { + FILE *fp; + long pos; + unsigned char atend; +}; + + +typedef struct { + + int ix; /* size of array in x */ + int iy; /* size of array in y */ + int iz; /* size of array in z */ + + struct filesource_state *state; /* the storage array for the + filesource status. */ + + int init_err; + + sf_eno3 newtable; /* the table, code borrowed from madagascar project */ + + double *xcol; /* array of doubles in x */ + double *ycol; /* array of doubles in y */ + double *zcol; /* array of doubles in z */ + + double ***table; + +} Local_Data_t; + +/*********************/ +/* 3d geometry types */ +/*********************/ + +typedef char line_t[82]; /* A SPICE size line. <= 80 characters plus '\n\0' */ + +/*=== FUNCTION PROTOTYPE DEFINITIONS ===*/ + +extern int findCrossOver(double arr[], int low, int high, double x); + +extern double TrilinearInterpolation(double x, double y, double z, int xind, int yind, int zind, double ***td); + +extern char *CNVgettok(char **s); + +/*============================================================================== + +FUNCTION cnv_get_spice_value() + +AUTHORS + + ??? Bill Kuhn + +MODIFICATIONS + + 30 Sep 1991 Jeffrey P. Murray + +SUMMARY + + This function takes as input a string token from a SPICE + deck and returns a floating point equivalent value. + +INTERFACES + + FILE ROUTINE CALLED + + N/A N/A + +RETURNED VALUE + + Returns the floating point value in pointer *p_value. Also + returns an integer representing successful completion. + +GLOBAL VARIABLES + + NONE + +NON-STANDARD FEATURES + + NONE + +==============================================================================*/ + +/*=== Static CNV_get_spice_value ROUTINE =============*/ + +/* + Function takes as input a string token from a SPICE + deck and returns a floating point equivalent value. +*/ + + +static int +cnv_get_spice_value(char *str, /* IN - The value text e.g. 1.2K */ + double *p_value) /* OUT - The numerical value */ +{ + /* the following were "int4" devices - jpm */ + size_t len; + size_t i; + int n_matched; + + line_t val_str; + + char c = ' '; + char c1; + + double scale_factor; + double value; + + /* Scan the input string looking for an alpha character that is not */ + /* 'e' or 'E'. Such a character is assumed to be an engineering */ + /* suffix as defined in the Spice 2G.6 user's manual. */ + + len = strlen(str); + if (len > sizeof(val_str) - 1) + len = sizeof(val_str) - 1; + + for (i = 0; i < len; i++) { + c = str[i]; + if (isalpha_c(c) && (c != 'E') && (c != 'e')) + break; + else if (isspace_c(c)) + break; + else + val_str[i] = c; + } + val_str[i] = '\0'; + + /* Determine the scale factor */ + + if ((i >= len) || (! isalpha_c(c))) + scale_factor = 1.0; + else { + + if (isupper_c(c)) + c = tolower_c(c); + + switch (c) { + + case 't': + scale_factor = 1.0e12; + break; + + case 'g': + scale_factor = 1.0e9; + break; + + case 'k': + scale_factor = 1.0e3; + break; + + case 'u': + scale_factor = 1.0e-6; + break; + + case 'n': + scale_factor = 1.0e-9; + break; + + case 'p': + scale_factor = 1.0e-12; + break; + + case 'f': + scale_factor = 1.0e-15; + break; + + case 'm': + i++; + if (i >= len) { + scale_factor = 1.0e-3; + break; + } + c1 = str[i]; + if (!isalpha_c(c1)) { + scale_factor = 1.0e-3; + break; + } + if (islower_c(c1)) + c1 = toupper_c(c1); + if (c1 == 'E') + scale_factor = 1.0e6; + else if (c1 == 'I') + scale_factor = 25.4e-6; + else + scale_factor = 1.0e-3; + break; + + default: + scale_factor = 1.0; + } + } + + /* Convert the numeric portion to a float and multiply by the */ + /* scale factor. */ + + n_matched = sscanf(val_str, "%le", &value); + + if (n_matched < 1) { + *p_value = 0.0; + return FAIL; + } + + *p_value = value * scale_factor; + return OK; +} + + +/*============================================================================== + +FUNCTION void cm_table3D() + +AUTHORS + + 08 Nov 2015 Holger Vogt + +MODIFICATIONS + + + +SUMMARY + + This function implements 2D table code model. + +INTERFACES + + FILE ROUTINE CALLED + + N/A N/A + + +RETURNED VALUE + + Returns inputs and outputs via ARGS structure. + +GLOBAL VARIABLES + + NONE + +NON-STANDARD FEATURES + + NONE + +INPUT FILE SPEC + +* Title (comments preceded by * ignored) +* table size +ix +iy +* x row independent variables +x0 x1 x2 x3 ... xix-1 +y column independent variables +y0 y1 y2 y3 ... yiy-1 +* table +x0y0 x1y0 x2y0 ... xix-1y0 +... +x0yiy-1 x1yiy-1 x2yiy-1 ... xix-1yiy-1 + + + +==============================================================================*/ + + +/*=== CM_table3D ROUTINE ===*/ + + +void +cm_table3D(ARGS) /* structure holding parms, inputs, outputs, etc. */ +{ + int size, xind, yind, zind; + double xval, yval, zval, xoff, yoff, zoff, xdiff, ydiff, zdiff; + double derivval[3], outval; + + Local_Data_t *loc; /* Pointer to local static data, not to be included + in the state vector */ + Mif_Complex_t ac_gain; + + size = PORT_SIZE(out); + if (INIT == 1) { + + int i, j; + int ix = 0, /* elements in a row */ + iy = 0, /* number of rows */ + iz = 0; /* number of 2D tables */ + + double ***table_data; + + double tmp; + char *cFile, *cThisPtr, *cThisLine, *cThisLinePtr; + int isNewline; /* Boolean indicating we've read a CR or LF */ + size_t lFileLen; /* Length of file */ + size_t lFileRead; /* Length of file read in */ + long lIndex; /* Index into cThisLine array */ + int lLineCount; /* Current line number */ + size_t lStartPos; /* Offset of start of current line */ + size_t lTotalChars; /* Total characters read */ + int lTableCount; /* Number of tables */ + int interporder; /* order of interpolation for eno */ + + /* allocate static storage for *loc */ + STATIC_VAR (locdata) = calloc (1, sizeof(Local_Data_t)); + loc = STATIC_VAR (locdata); + + /* Allocate storage for internal state */ + loc->state = (struct filesource_state*) malloc(sizeof(struct filesource_state)); + loc->ix = loc->iy = loc->iz = 0; + loc->init_err = 0; + + /* open file */ + loc->state->fp = fopen_with_path(PARAM(file), "r"); + loc->state->pos = 0; + loc->state->atend = 0; + if (!loc->state->fp) { + char *lbuffer, *pp; + lbuffer = getenv("NGSPICE_INPUT_DIR"); + if (lbuffer && *lbuffer) { + pp = (char*) malloc(strlen(lbuffer) + strlen(DIR_PATHSEP) + strlen(PARAM(file)) + 1); + sprintf(pp, "%s%s%s", lbuffer, DIR_PATHSEP, PARAM(file)); + loc->state->fp = fopen(pp, "r"); + free(pp); + } + } + struct stat st; + if (!loc->state->fp || fstat(fileno(loc->state->fp), &st)) { + cm_message_printf("cannot open file %s", PARAM(file)); + loc->state->atend = 1; + loc->init_err = 1; + return; + } + /* get file length */ + lFileLen = (size_t) st.st_size; + + /* create string to hold the whole file */ + cFile = calloc(lFileLen + 1, sizeof(char)); + /* create another string long enough for file manipulation */ + cThisLine = calloc(lFileLen + 1, sizeof(char)); + if (cFile == NULL || cThisLine == NULL) { + cm_message_printf("Insufficient memory to read file %s", PARAM(file)); + loc->state->atend = 1; + loc->init_err = 1; + return; + } + /* read whole file into cFile */ + lFileRead = fread(cFile, sizeof(char), lFileLen, loc->state->fp); + fclose(loc->state->fp); + /* Number of chars read may be less than lFileLen, because /r are skipt by 'fread' */ + cFile[lFileRead] = '\0'; + + cThisPtr = cFile; + cThisLinePtr = cThisLine; + lLineCount = 0L; + lTotalChars = 0L; + + while (*cThisPtr) { /* Read until reaching null char */ + lIndex = 0L; /* Reset counters and flags */ + isNewline = 0; + lStartPos = lTotalChars; + + while (*cThisPtr) { /* Read until reaching null char */ + if (!isNewline) { /* Haven't read a LF yet */ + if (*cThisPtr == '\n') /* This char is a LF */ + isNewline = 1; /* Set flag */ + } + + else if (*cThisPtr != '\n') /* Already found LF */ + break; /* Done with line */ + + cThisLinePtr[lIndex++] = *cThisPtr++; /* Add char to output and increment */ + lTotalChars++; + } + + cThisLinePtr[lIndex] = '\0'; /* Terminate the string */ + lLineCount++; /* Increment the line counter */ + /* continue if comment or empty */ + if (cThisLinePtr[0] == '*' || cThisLinePtr[0] == '\n') { + lLineCount--; /* we count only real lines */ + continue; + } + if (lLineCount == 1) { + cnv_get_spice_value(cThisLinePtr, &tmp); + loc->ix = ix = (int) tmp; + /* generate row data structure (x) */ + loc->xcol = (double*) calloc((size_t) ix, sizeof(double)); + } else if (lLineCount == 2) { + cnv_get_spice_value(cThisLinePtr, &tmp); + loc->iy = iy = (int) tmp; + /* generate column data structure (y) */ + loc->ycol = (double*) calloc((size_t) iy, sizeof(double)); + } else if (lLineCount == 3) { + cnv_get_spice_value(cThisLinePtr, &tmp); + loc->iz = iz = (int) tmp; + /* generate column data structure (y) */ + loc->zcol = (double*) calloc((size_t) iz, sizeof(double)); + } else if (lLineCount == 4) { + char *token = CNVgettok(&cThisLinePtr); + i = 0; + while (token) { + if (i == ix) { + cm_message_printf("Too many numbers in x row."); + loc->init_err = 1; + return; + } + cnv_get_spice_value(token, &loc->xcol[i++]); + free(token); + token = CNVgettok(&cThisLinePtr); + } + if (i < ix) { + cm_message_printf("Not enough numbers in x row."); + loc->init_err = 1; + return; + } + } else if (lLineCount == 5) { + char *token = CNVgettok(&cThisLinePtr); + i = 0; + while (token) { + if (i == iy) { + cm_message_printf("Too many numbers in y row."); + loc->init_err = 1; + return; + } + cnv_get_spice_value(token, &loc->ycol[i++]); + free(token); + token = CNVgettok(&cThisLinePtr); + } + if (i < iy) { + cm_message_printf("Not enough numbers in y row."); + loc->init_err = 1; + return; + } + } else if (lLineCount == 6) { + char *token = CNVgettok(&cThisLinePtr); + i = 0; + while (token) { + if (i == iz) { + cm_message_printf("Too many numbers in z row."); + loc->init_err = 1; + return; + } + cnv_get_spice_value(token, &loc->zcol[i++]); + free(token); + token = CNVgettok(&cThisLinePtr); + } + if (i < iz) { + cm_message_printf("Not enough numbers in z row."); + loc->init_err = 1; + return; + } + /* jump out of while loop to read in the table */ + break; + } + } + + /* generate table core */ + interporder = PARAM(order); + /* boundary limits set to param 'order' aren't recognized, + so limit them here */ + if (interporder < 2) { + cm_message_printf("Parameter Order=%d not possible, set to minimum value 2", interporder); + interporder = 2; + } + /* int order : interpolation order, + int n1, int n2, int n3 : data dimensions */ + loc->newtable = sf_eno3_init(interporder, ix, iy, iz); + + /* create table_data in memory */ + /* data [n3][n2][n1] */ + table_data = calloc((size_t) iy, sizeof(double *)); + for (i = 0; i < iz; i++) { + table_data[i] = calloc((size_t) iy, sizeof(double *)); + for (j = 0; j < iy; j++) + table_data[i][j] = calloc((size_t) ix, sizeof(double)); + } + + loc->table = table_data; + + /* continue reading from cFile */ + for (lTableCount = 0; lTableCount < iz; lTableCount++) { + lLineCount = 0; + while (lLineCount < iy) { + char *token; + + lIndex = 0L; /* Reset counters and flags */ + isNewline = 0; + lStartPos = lTotalChars; + + /* read a line */ + while (*cThisPtr) { /* Read until reaching null char */ + if (!isNewline) { /* Haven't read a CR or LF yet */ + if (*cThisPtr == '\n') /* This char is LF */ + isNewline = 1; /* Set flag */ + } + + else if (*cThisPtr != '\n') /* Already found LF */ + break; /* Done with line */ + + cThisLinePtr[lIndex++] = *cThisPtr++; /* Add char to output and increment */ + lTotalChars++; + } + + cThisLinePtr[lIndex] = '\0'; /* Terminate the string */ + /* continue if comment or empty */ + if (cThisLinePtr[0] == '*' || cThisLinePtr[0] == '\0') { + if (lTotalChars >= lFileLen) { + cm_message_printf("Not enough data in file %s", PARAM(file)); + loc->init_err = 1; + return; + } + continue; + } + token = CNVgettok(&cThisLinePtr); + i = 0; + while (token) { + double tmpval; + + if (i == ix) { + cm_message_printf("Too many numbers in y row no. %d of table %d.", lLineCount, lTableCount); + loc->init_err = 1; + return; + } + + /* read table core from cFile, fill local static table structure table_data */ + cnv_get_spice_value(token, &tmpval); + + table_data[lTableCount][lLineCount][i++] = tmpval; + + free(token); + token = CNVgettok(&cThisLinePtr); + } + if (i < ix) { + cm_message_printf("Not enough numbers in y row no. %d of table %d.", lLineCount, lTableCount); + loc->init_err = 1; + return; + } + lLineCount++; + } + } + + /* fill table data into eno3 structure */ + + sf_eno3_set(loc->newtable, table_data /* data [n3][n2][n1] */); + + /* free all the emory allocated */ + // for (i = 0; i < iy; i++) + // free(table_data[i]); + // free(table_data); + free(cFile); + free(cThisLine); + } /* end of initialization "if (INIT == 1)" */ + + loc = STATIC_VAR (locdata); + + /* return immediately if there was an initialization error */ + if (loc->init_err == 1) + return; + + /* get input x, y, z; + find corresponding indices; + get x and y offsets; + call interpolation functions with value and derivative */ + + xval = INPUT(inx); + yval = INPUT(iny); + zval = INPUT(inz); + + /* check table ranges */ + if (xval < loc->xcol[0] || xval > loc->xcol[loc->ix - 1]) { + if (PARAM(verbose) > 0) + cm_message_printf("x value %g exceeds table limits, \nplease enlarge range of your table", xval); + return; + } + if (yval < loc->ycol[0] || yval > loc->ycol[loc->iy - 1]) { + if (PARAM(verbose) > 0) + cm_message_printf("y value %g exceeds table limits, \nplease enlarge range of your table", yval); + return; + } + if (zval < loc->zcol[0] || zval > loc->zcol[loc->iz - 1]) { + if (PARAM(verbose) > 0) + cm_message_printf("z value %g exceeds table limits, \nplease enlarge range of your table", zval); + return; + } + + /* find index */ + /* something like binary search to get the index */ + xind = findCrossOver(loc->xcol, 0, loc->ix - 1, xval); + + /* find index with minimum distance between xval and row value + if (fabs(loc->xcol[xind + 1] - xval) < fabs(xval - loc->xcol[xind])) + xind++; + */ + xoff = xval - loc->xcol[xind]; + yind = findCrossOver(loc->ycol, 0, loc->iy - 1, yval); + /* find index with minimum distance between yval and column value + if (fabs(loc->ycol[yind + 1] - yval) < fabs(yval - loc->ycol[yind])) + yind++; + */ + yoff = yval - loc->ycol[yind]; + zind = findCrossOver(loc->zcol, 0, loc->iz - 1, zval); + /* find index with minimum distance between zval and table value + if (fabs(loc->zcol[zind + 1] - zval) < fabs(zval - loc->zcol[zind])) + zind++; + */ + zoff = zval - loc->zcol[zind]; + + /* find local difference around index of independent row and column values */ + if (xind == loc->ix - 1) + xdiff = loc->xcol[xind] - loc->xcol[xind - 1]; + else if (xind == 0) + xdiff = loc->xcol[xind + 1] - loc->xcol[xind]; + else + xdiff = 0.5 * (loc->xcol[xind + 1] - loc->xcol[xind - 1]); + + if (yind == loc->iy - 1) + ydiff = loc->ycol[yind] - loc->ycol[yind - 1]; + else if (yind == 0) + ydiff = loc->ycol[yind + 1] - loc->ycol[yind]; + else + ydiff = 0.5 * (loc->ycol[yind + 1] - loc->ycol[yind - 1]); + + if (zind == loc->iz - 1) + zdiff = loc->zcol[zind] - loc->zcol[zind - 1]; + else if (zind == 0) + zdiff = loc->zcol[zind + 1] - loc->zcol[zind]; + else + zdiff = 0.5 * (loc->zcol[zind + 1] - loc->zcol[zind - 1]); + + /* Essentially non-oscillatory (ENO) interpolation to obtain the derivatives only. + Using outval for now yields ngspice op non-convergence */ + sf_eno3_apply (loc->newtable, + xind, yind, zind, /* grid location */ + xoff, yoff, zoff, /* offset from grid */ + &outval, /* output data value */ + derivval, /* output derivatives [3] */ + DER /* what to compute [FUNC, DER, BOTH] */ + ); + + + outval = TrilinearInterpolation(xoff / (loc->xcol[xind + 1] - loc->xcol[xind]), + yoff / (loc->ycol[yind + 1] - loc->ycol[yind]), + zoff / (loc->zcol[zind + 1] - loc->zcol[zind]), + xind, yind, zind, loc->table); + + if (ANALYSIS != MIF_AC) { + double xderiv, yderiv, zderiv, outv; + outv = PARAM(offset) + PARAM(gain) * outval; + OUTPUT(out) = outv; + xderiv = PARAM(gain) * derivval[0] / xdiff; + PARTIAL(out, inx) = xderiv; + yderiv = PARAM(gain) * derivval[1] / ydiff; + PARTIAL(out, iny) = yderiv; + zderiv = PARAM(gain) * derivval[2] / zdiff; + PARTIAL(out, inz) = zderiv; + + if (PARAM(verbose) > 1) + cm_message_printf("\nI: %g, xval: %g, yval: %g, zval: %g, xderiv: %g, yderiv: %g, zderiv: %g", outv, xval, yval, zval, xderiv, yderiv, zderiv); + } else { + ac_gain.real = PARAM(gain) * derivval[0] / xdiff; + ac_gain.imag= 0.0; + AC_GAIN(out, inx) = ac_gain; + ac_gain.real = PARAM(gain) * derivval[1] / ydiff; + ac_gain.imag= 0.0; + AC_GAIN(out, iny) = ac_gain; + } +} + + +/* These includes add functions from extra source code files, + * still using the standard XSPICE procedure of cmpp-ing cfunc.mod + * and then only compiling the resulting *.c file. + */ + +#include "../support/gettokens.c" /* reading tokens */ +#include "../support/interp.c" /* 2D and 3D linear interpolation */ +#include "../mada/alloc.c" /* eno interpolation from madagascar project */ +#include "../mada/eno.c" /* eno interpolation from madagascar project */ +#include "../mada/eno2.c" /* eno interpolation from madagascar project */ +#include "../mada/eno3.c" /* eno interpolation from madagascar project */ diff --git a/src/xspice/icm/table/table3D/ifspec.ifs b/src/xspice/icm/table/table3D/ifspec.ifs new file mode 100644 index 000000000..452f63921 --- /dev/null +++ b/src/xspice/icm/table/table3D/ifspec.ifs @@ -0,0 +1,87 @@ +/*.......1.........2.........3.........4.........5.........6.........7.........8 +================================================================================ +Copyright 2015 +Holger Vogt + +AUTHORS + + 06 Nov 2015 Holger Vogt + + +SUMMARY + + This file contains the interface specification file for the + 3D table code model. + +===============================================================================*/ + +NAME_TABLE: + +C_Function_Name: cm_table3D +Spice_Model_Name: table3d +Description: "3D table model" + + +PORT_TABLE: + +Port_Name: inx iny inz +Description: "inputx" "inputy" "inputz" +Direction: in in in +Default_Type: v v v +Allowed_Types: [v,vd,i,id,vnam] [v,vd,i,id,vnam] [v,vd,i,id,vnam] +Vector: no no no +Vector_Bounds: - - - +Null_Allowed: no no no + +PORT_TABLE: + +Port_Name: out +Description: "output" +Direction: out +Default_Type: i +Allowed_Types: [v,vd,i,id] +Vector: no +Vector_Bounds: - +Null_Allowed: no + + +PARAMETER_TABLE: + +Parameter_Name: order verbose +Description: "order" "verbose" +Data_Type: int int +Default_Value: 3 0 +Limits: [2 -] [0 2] +Vector: no no +Vector_Bounds: - - +Null_Allowed: yes yes + +PARAMETER_TABLE: + +Parameter_Name: offset gain +Description: "offset" "gain" +Data_Type: real real +Default_Value: 0.0 1.0 +Limits: - - +Vector: no no +Vector_Bounds: - - +Null_Allowed: yes yes + + +PARAMETER_TABLE: + +Parameter_Name: file +Description: "file name" +Data_Type: string +Default_Value: "3D-table-model.txt" +Limits: - +Vector: no +Vector_Bounds: - +Null_Allowed: yes + + +STATIC_VAR_TABLE: + +Static_Var_Name: locdata +Description: "local static data" +Data_Type: pointer diff --git a/src/xspice/icm/table/udnpath.lst b/src/xspice/icm/table/udnpath.lst new file mode 100644 index 000000000..e69de29bb diff --git a/visualc/how-to-ngspice-vstudio.txt b/visualc/how-to-ngspice-vstudio.txt index 251b97c01..83c2bf1b0 100644 --- a/visualc/how-to-ngspice-vstudio.txt +++ b/visualc/how-to-ngspice-vstudio.txt @@ -42,6 +42,7 @@ C:\Spice\ spice2poly.cm extradev.cm extravt.cm + table.cm share\ ngspice scripts\ diff --git a/visualc/make-install-vngspice.bat b/visualc/make-install-vngspice.bat index e95d26e26..c232de528 100644 --- a/visualc/make-install-vngspice.bat +++ b/visualc/make-install-vngspice.bat @@ -17,6 +17,7 @@ mkdir %dst%\share\ngspice\scripts copy "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\redist\x86\Microsoft.VC140.OPENMP\vcomp140.dll" %dst%\bin\ copy %cmsrc%\analog.cm %dst%\lib\ngspice\analog.cm copy %cmsrc%\digital.cm %dst%\lib\ngspice\digital.cm +copy %cmsrc%\table.cm %dst%\lib\ngspice\table.cm copy %cmsrc%\xtraevt.cm %dst%\lib\ngspice\xtraevt.cm copy %cmsrc%\xtradev.cm %dst%\lib\ngspice\xtradev.cm copy %cmsrc%\spice2poly.cm %dst%\lib\ngspice\spice2poly.cm @@ -45,6 +46,7 @@ mkdir %dst%\share\ngspice\scripts copy "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\redist\x64\Microsoft.VC140.OPENMP\vcomp140.dll" %dst%\bin\ copy %cmsrc%\analog64.cm %dst%\lib\ngspice\analog.cm copy %cmsrc%\digital64.cm %dst%\lib\ngspice\digital.cm +copy %cmsrc%\table64.cm %dst%\lib\ngspice\table.cm copy %cmsrc%\xtraevt64.cm %dst%\lib\ngspice\xtraevt.cm copy %cmsrc%\xtradev64.cm %dst%\lib\ngspice\xtradev.cm copy %cmsrc%\spice2poly64.cm %dst%\lib\ngspice\spice2poly.cm diff --git a/visualc/make-install-vngspiced.bat b/visualc/make-install-vngspiced.bat index 0c49a86e5..f455c5f6b 100644 --- a/visualc/make-install-vngspiced.bat +++ b/visualc/make-install-vngspiced.bat @@ -17,6 +17,7 @@ mkdir %dst%\share\ngspice\scripts copy "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\redist\x86\Microsoft.VC140.OPENMP\vcomp140.dll" %dst%\bin\ copy %cmsrc%\analog.cm %dst%\lib\ngspice\analog.cm copy %cmsrc%\digital.cm %dst%\lib\ngspice\digital.cm +copy %cmsrc%\table.cm %dst%\lib\ngspice\table.cm copy %cmsrc%\xtraevt.cm %dst%\lib\ngspice\xtraevt.cm copy %cmsrc%\xtradev.cm %dst%\lib\ngspice\xtradev.cm copy %cmsrc%\spice2poly.cm %dst%\lib\ngspice\spice2poly.cm @@ -45,6 +46,7 @@ mkdir %dst%\share\ngspice\scripts copy "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\redist\x64\Microsoft.VC140.OPENMP\vcomp140.dll" %dst%\bin\ copy %cmsrc%\analog64.cm %dst%\lib\ngspice\analog.cm copy %cmsrc%\digital64.cm %dst%\lib\ngspice\digital.cm +copy %cmsrc%\table64.cm %dst%\lib\ngspice\table.cm copy %cmsrc%\xtraevt64.cm %dst%\lib\ngspice\xtraevt.cm copy %cmsrc%\xtradev64.cm %dst%\lib\ngspice\xtradev.cm copy %cmsrc%\spice2poly64.cm %dst%\lib\ngspice\spice2poly.cm diff --git a/visualc/spinit b/visualc/spinit index d93537eae..8e4832c80 100644 --- a/visualc/spinit +++ b/visualc/spinit @@ -27,6 +27,7 @@ if $__flag = 0 codemodel C:/Spice/lib/ngspice/digital.cm codemodel C:/Spice/lib/ngspice/xtradev.cm codemodel C:/Spice/lib/ngspice/xtraevt.cm + codemodel C:/Spice/lib/ngspice/table.cm end unset __flag diff --git a/visualc/spinit64 b/visualc/spinit64 index a52b216f8..47809f090 100644 --- a/visualc/spinit64 +++ b/visualc/spinit64 @@ -27,6 +27,7 @@ if $__flag = 0 codemodel C:/Spice64/lib/ngspice/digital.cm codemodel C:/Spice64/lib/ngspice/xtradev.cm codemodel C:/Spice64/lib/ngspice/xtraevt.cm + codemodel C:/Spice64/lib/ngspice/table.cm end unset __flag diff --git a/visualc/spinitd b/visualc/spinitd index 5cbe5872e..e52d0ff54 100644 --- a/visualc/spinitd +++ b/visualc/spinitd @@ -27,6 +27,7 @@ if $__flag = 0 codemodel C:/Spiced/lib/ngspice/digital.cm codemodel C:/Spiced/lib/ngspice/xtradev.cm codemodel C:/Spiced/lib/ngspice/xtraevt.cm + codemodel C:/Spiced/lib/ngspice/table.cm end unset __flag diff --git a/visualc/spinitd64 b/visualc/spinitd64 index 58794c67b..b4a7f3ed4 100644 --- a/visualc/spinitd64 +++ b/visualc/spinitd64 @@ -27,6 +27,7 @@ if $__flag = 0 codemodel C:/Spice64d/lib/ngspice/digital.cm codemodel C:/Spice64d/lib/ngspice/xtradev.cm codemodel C:/Spice64d/lib/ngspice/xtraevt.cm + codemodel C:/Spice64d/lib/ngspice/table.cm end unset __flag diff --git a/visualc/vngspice-fftw.sln b/visualc/vngspice-fftw.sln index b1c0cd6fa..a8ad6cb88 100644 --- a/visualc/vngspice-fftw.sln +++ b/visualc/vngspice-fftw.sln @@ -31,6 +31,11 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "spice2poly", "xspice\spice2 {7C865696-FA10-43AE-A20B-22AE72A165E2} = {7C865696-FA10-43AE-A20B-22AE72A165E2} EndProjectSection EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "table", "xspice\table.vcxproj", "{7A6473F5-AFED-4910-88D2-6204DA829832}" + ProjectSection(ProjectDependencies) = postProject + {7C865696-FA10-43AE-A20B-22AE72A165E2} = {7C865696-FA10-43AE-A20B-22AE72A165E2} + EndProjectSection +EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xtradev", "xspice\xtradev.vcxproj", "{4BB60215-9A09-4192-9DB6-1A0CA823AFCA}" ProjectSection(ProjectDependencies) = postProject {7C865696-FA10-43AE-A20B-22AE72A165E2} = {7C865696-FA10-43AE-A20B-22AE72A165E2} diff --git a/visualc/vngspice.sln b/visualc/vngspice.sln index 09af29248..d090c5b9f 100644 --- a/visualc/vngspice.sln +++ b/visualc/vngspice.sln @@ -31,6 +31,11 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "spice2poly", "xspice\spice2 {7C865696-FA10-43AE-A20B-22AE72A165E2} = {7C865696-FA10-43AE-A20B-22AE72A165E2} EndProjectSection EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "table", "xspice\table.vcxproj", "{7A6473F5-AFED-4910-88D2-6204DA829832}" + ProjectSection(ProjectDependencies) = postProject + {7C865696-FA10-43AE-A20B-22AE72A165E2} = {7C865696-FA10-43AE-A20B-22AE72A165E2} + EndProjectSection +EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xtradev", "xspice\xtradev.vcxproj", "{4BB60215-9A09-4192-9DB6-1A0CA823AFCA}" ProjectSection(ProjectDependencies) = postProject {7C865696-FA10-43AE-A20B-22AE72A165E2} = {7C865696-FA10-43AE-A20B-22AE72A165E2} diff --git a/visualc/xspice/table.vcxproj b/visualc/xspice/table.vcxproj new file mode 100644 index 000000000..6d3d134d6 --- /dev/null +++ b/visualc/xspice/table.vcxproj @@ -0,0 +1,225 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + table + {7A6473F5-AFED-4910-88D2-6204DA829832} + icmanalog + 8.1 + + + + DynamicLibrary + NotSet + v140 + + + DynamicLibrary + NotSet + true + v140 + + + DynamicLibrary + NotSet + v140 + + + DynamicLibrary + MultiByte + true + v140 + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.40219.1 + .cm + $(SolutionDir)codemodels\$(Platform)\$(Configuration)\ + $(SolutionDir)xspice\intermediate\$(ProjectName)\$(Platform)\$(Configuration)\ + + + true + false + + + false + + + $(ProjectName)64 + true + false + + + $(ProjectName)64 + false + + + + generate cfunc.c and ifspec.c files + call .\aux-cfunc.bat $(ProjectName) + + + + + Disabled + icm\$(ProjectName);..\src\include;..\..\src\include;%(AdditionalIncludeDirectories) + _CRT_SECURE_NO_DEPRECATE;CIDER;%(PreprocessorDefinitions) + false + + + Default + MultiThreadedDebug + false + Level4 + ProgramDatabase + CompileAsC + true + + + true + + + Windows + false + false + + + $(TargetDir)$(TargetName).lib + MachineX86 + + + + + MaxSpeed + true + icm\$(ProjectName);..\src\include;..\..\src\include;%(AdditionalIncludeDirectories) + _CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) + + + MultiThreaded + true + Level4 + ProgramDatabase + CompileAsC + true + + + true + true + true + false + $(TargetDir)$(TargetName).lib + MachineX86 + UseLinkTimeCodeGeneration + + + + + X64 + + + Disabled + icm\$(ProjectName);..\src\include;..\..\src\include;%(AdditionalIncludeDirectories) + _CRT_SECURE_NO_DEPRECATE;CIDER;%(PreprocessorDefinitions) + false + + + Default + MultiThreadedDebug + false + Level4 + ProgramDatabase + CompileAsC + + + true + + + Windows + false + false + + + $(TargetDir)$(TargetName).lib + MachineX64 + + + + + X64 + + + MaxSpeed + true + icm\$(ProjectName);..\src\include;..\..\src\include;%(AdditionalIncludeDirectories) + _CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions) + + + MultiThreaded + true + Level4 + ProgramDatabase + CompileAsC + + + true + true + true + false + $(TargetDir)$(TargetName).lib + MachineX64 + + + + + ..\..\src\xspice\icm\$(ProjectName);..\..\src\xspice\%(RelativeDir);%(AdditionalIncludeDirectories) + + + + ..\..\src\xspice\icm\$(ProjectName);..\..\src\xspice\%(RelativeDir);%(AdditionalIncludeDirectories) + + + + + + + + + + + + + + \ No newline at end of file diff --git a/visualc/xspice/xspice-local.sln b/visualc/xspice/xspice-local.sln index 393e21e4e..97257de91 100644 --- a/visualc/xspice/xspice-local.sln +++ b/visualc/xspice/xspice-local.sln @@ -7,6 +7,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xtraevt", "xtraevt.vcxproj" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xtradev", "xtradev.vcxproj", "{4BB60215-9A09-4192-9DB6-1A0CA823AFCA}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "table", "table.vcxproj", "{7A6473F5-AFED-4910-88D2-6204DA829832}" +EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "spice2poly", "spice2poly.vcxproj", "{D701EA0E-B8B0-41D6-A90E-A0D8233F15FB}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "digital", "digital.vcxproj", "{9ABEC5F2-F6C6-41DE-88AB-02460A07F46E}"