From afdf6ee134e8c83a88a21eadc3276ec9b5b3512f Mon Sep 17 00:00:00 2001 From: h_vogt Date: Sat, 16 Oct 2010 12:05:09 +0000 Subject: [PATCH] new command wrs2p --- ChangeLog | 6 ++ examples/control_structs/s-param.cir | 116 ++++++++++++++++++++++ src/frontend/commands.c | 43 ++++---- src/frontend/postcoms.c | 143 +++++++++++++++++++++++++++ src/frontend/postcoms.h | 1 + src/frontend/rawfile.c | 102 +++++++++++++++++++ src/frontend/rawfile.h | 1 + src/include/fteext.h | 2 + 8 files changed, 391 insertions(+), 23 deletions(-) create mode 100644 examples/control_structs/s-param.cir diff --git a/ChangeLog b/ChangeLog index 44845b355..1d06006a5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2010-10-15 Holger Vogt + * examples/control_structs/s-param.cir new example + * commands.c, postcoms.h, postcoms.c, rawfile.h, rawfile.c + fteext.h: new command wrs2p, write a s-parameter file + using Touchstone vers. 1 format. + 2010-10-15 Holger Vogt * src/ciderlib/input/output.c : #include "../misc/tilde.h" * inpcom.c: line 2800ff, allow -.5 token diff --git a/examples/control_structs/s-param.cir b/examples/control_structs/s-param.cir new file mode 100644 index 000000000..08b09289d --- /dev/null +++ b/examples/control_structs/s-param.cir @@ -0,0 +1,116 @@ +Test for Scattering Parameters +** Two ports +** Examples: Bipolar, Tschebyschef, RC + +.param Rbase=50 Vbias_in=0 Vbias_out=0 + +*** The two-port circuit: +** port 1: in 0 +** port 2: out 0 +** Bias on both ports through resistor Rbase (to obtain operating point) + +** Example RF Bipolar mrf5711 +** VCE 1 V, IE = 5mA +** QXXXXXXX nc nb ne +** model obtained from +** http://141.69.160.32/~krausg/Spice_Model_CD/Vendor%20List/Motorola/Spice/RFBJT/ +*.include MRF5711.lib +*XMRF5711 out in e MRF5711 +*Ie e 0 5m +*Ce e 0 1 + +** Example Tschebyschef Low Pass filter +C1 in 0 33.2p +L1 in 2 99.2n +C2 2 0 57.2p +L2 2 out 99.2n +C3 out 0 33.2p + +** Example RC +** see +** http://www.allenhollister.com/allen/files/scatteringparameters.pdf +*R2 in out 10 +*C1 out int5 30p +*R1 int5 0 10 + +*** End of circuit + + +** The following subcircuit to be changed only by an experienced user! + +*** Driver and readout +X1 in out S22 S12 S_PARAM + +.SUBCKT S_PARAM 22 66 5 7 +* Resistors emulate switches with Ron=0.001 and Roff=1e12 +* to switch driver to input and readout to output (and vice versa, see below) +RS1 22 2 0.001 +RS2 66 6 0.001 +RS3 22 6 1e12 +RS4 66 2 1e12 +*Driver +Vacdc 1 0 DC 'Vbias_in' AC 1 $ ac voltage and dc bias at input (applied through load resistor) +R1 1 2 'Rbase' +E1 3 0 2 0 2 $ amplify in port ac voltage by 2 +Vac 3 4 DC 0 AC 1 $ subtract driving ac voltage +R_loop 4 5 0.001 +R3 5 0 1 $ ground return for measure node 5 +*Readout +E2 7 0 6 0 2 $ amplify out port ac voltage by 2 +R4 6 8 'Rbase' $ load resistor at output (ac) +Vdc 8 0 DC 'Vbias_out' AC 0 $ dc bias at output (applied through load resistor) +.ends + +** Check the two ac lines below for being equal! +.control +set noaskquit +set filetype=ascii +** measurement for s11 and s21 +op +** save bias voltages to vector +let Vdcnew=V(X1.1) $ former Vacdc +let Vacdcnew=v(X1.8) $ former Vdc +*ac lin 20 0.1G 2G $ use for bip transistor +ac lin 100 2.5MEG 250MEG $ use for Tschebyschef +*ac lin 101 1k 10G $ use for RC +** switch input and output +alter R.X1.RS1=1e12 +alter R.X1.RS2=1e12 +alter R.X1.RS3=0.001 +alter R.X1.RS4=0.001 +** switch bias voltages between in and out +alter V.X1.Vacdc DC=op1.Vacdcnew +alter V.X1.Vdc DC=op1.Vdcnew +** measurement for s12 and s22 +op +*ac lin 20 0.1G 2G $ use for bip transistor +ac lin 100 2.5MEG 250MEG $ use for Tschebyschef +*ac lin 101 1 10G $ use for RC +let s11=ac1.s22 +let s21=ac1.s12 +settype s-param S11 S21 S22 S12 + +let S11db = db(s11) +let S12db = db(s12) +let S21db = db(s21) +let S22db = db(s22) +settype decibel S11db S21db S22db S12db + +let P11=180*ph(s11)/pi +let P21=180*ph(s21)/pi +let P22=180*ph(S22)/pi +let P12=180*ph(S12)/pi +settype phase P11 P21 P22 P12 + +let Rbase=@R.X1.R4[Resistance] +settype impedance Rbase + +*plot s11db s21db S22db S12db ylimit -50 0 xlog $ used with RC +plot s11db s21db S22db S12db ylimit -0.5 0 $ used with Tschebyschef +plot P11 P21 P22 P12 +plot smithgrid S11 S12 +*wrdata s3046 mag(S11) P11 mag(S21) P21 mag(S22) P22 mag(S12) P12 $ write simple table +wrs2p s3046.s2p $ write touchstone vers. 1 file s3046.s2p +.endc + +.end \ No newline at end of file diff --git a/src/frontend/commands.c b/src/frontend/commands.c index 717e02f06..23217e981 100644 --- a/src/frontend/commands.c +++ b/src/frontend/commands.c @@ -71,29 +71,18 @@ /* gtri - end - wbk - add include files */ #endif -/* Information about spice commands (strucct comm). */ - /* The name of the command. */ -// char *co_comname; - /* The function that handles the command. */ -// void (*co_func) (wordlist *wl); - /* These can't be used from nutmeg. */ -// bool co_spiceonly; - /* Is this a "major" command? */ -// bool co_major; - /* Bitmasks for command completion. */ -// long co_cctypes[4]; - /* print help message on this environment mask */ -// unsigned int co_env; - /* minimum number of arguments required */ -// int co_minargs; - /* maximum number of arguments allowed */ -// int co_maxargs; - /* The fn that prompts the user. */ -// void (*co_argfn) (wordlist *wl, struct comm *command); - /* When these are printed, printf(string, av[0]) .. */ -// char *co_help; - -/* Bool fields: spiceonly, major */ +/* Information about spice commands (struct comm). */ + +// char *co_comname; /* The name of the command. */ +// void (*co_func) (wordlist *wl); /* The function that handles the command. */ +// bool co_spiceonly; /* These can't be used from nutmeg. */ +// bool co_major; /* Is this a "major" command? */ +// long co_cctypes[4]; /* Bitmasks for command completion. */ +// unsigned int co_env; /* print help message on this environment mask */ +// int co_minargs; /* minimum number of arguments required */ +// int co_maxargs; /* maximum number of arguments allowed */ +// void (*co_argfn) (wordlist *wl, struct comm *command); /* The fn that prompts the user. */ +// char *co_help; /* When these are printed, printf(string, av[0]) .. */ struct comm spcp_coms[] = { { "let", com_let, FALSE, TRUE, @@ -189,6 +178,10 @@ struct comm spcp_coms[] = { { 1, 041000, 041000, 041000 }, E_DEFHMASK, 2, LOTS, NULL, "file plotargs : Send plot data to file." } , + { "wrs2p", com_write_sparam, FALSE, TRUE, + { 1, 041000, 041000, 041000 }, E_DEFHMASK, 0, LOTS, + NULL, + "file : Send s-param data to file." } , { "hardcopy", com_hardcopy, FALSE, TRUE, { 1, 041000, 041000, 041000 }, E_DEFHMASK, 0, LOTS, NULL, @@ -605,6 +598,10 @@ struct comm nutcp_coms[] = { { 1, 041000, 041000, 041000 }, E_DEFHMASK, 2, LOTS, NULL, "file plotargs : Send plot data to file." } , + { "wrs2p", com_write_sparam, FALSE, TRUE, + { 1, 041000, 041000, 041000 }, E_DEFHMASK, 0, LOTS, + NULL, + "file : Send s-param data to file." } , { "hardcopy", com_hardcopy, FALSE, TRUE, { 1, 041000, 041000, 041000 }, E_DEFHMASK, 0, LOTS, NULL, diff --git a/src/frontend/postcoms.c b/src/frontend/postcoms.c index be55184ec..96f1de647 100644 --- a/src/frontend/postcoms.c +++ b/src/frontend/postcoms.c @@ -524,6 +524,149 @@ com_write(wordlist *wl) return; } +/* Write scattering parameters into a file with Touchstone File Format Version 1 +with command wrs2p file . +Format info from http://www.eda.org/ibis/touchstone_ver2.0/touchstone_ver2_0.pdf +See example 13 on page 15: Two port, ASCII, real-imaginary +Check if S11, S21, S12, S22 and frequency vectors are available +Check if vector Rbase is available +Call spar_write() + */ + +void +com_write_sparam(wordlist *wl) +{ + char *file; + char* sbuf[6]; + wordlist *wl_sparam; + struct pnode *n; + struct dvec *d, *vecs = NULL, *lv = NULL, *end, *vv, *Rbasevec=NULL; + struct pnode *names; + bool scalefound, appendwrite=FALSE; + struct plot *tpl, newplot; + double Rbaseval; + + if (wl) { + file = wl->wl_word; + } else + file = "s_param.s2p"; + /* generate wordlist with all vectors required*/ + sbuf[0] = "frequency"; + sbuf[1] = "S11"; + sbuf[2] = "S21"; + sbuf[3] = "S12"; + sbuf[4] = "S22"; + sbuf[5] = NULL; + wl_sparam = wl_build(sbuf); + + names = ft_getpnames(wl_sparam, TRUE); + if (names == NULL) + return; + for (n = names; n; n = n->pn_next) { + d = ft_evaluate(n); + if (!d) + return; + if (vecs) + lv->v_link2 = d; + else + vecs = d; + for (lv = d; lv->v_link2; lv = lv->v_link2) + ; + } + Rbasevec = vec_get("Rbase"); + if (Rbasevec) + Rbaseval = Rbasevec->v_realdata[0]; + else { + fprintf(stderr, "Error: No Rbase vector given\n"); + return; + } + + /* Now we have to write them out plot by plot. */ + + while (vecs) { + tpl = vecs->v_plot; + tpl->pl_written = TRUE; + end = NULL; + bcopy(tpl, &newplot, sizeof (struct plot)); + scalefound = FALSE; + + /* Figure out how many vectors are in this plot. Also look + * for the scale, or a copy of it, which may have a different + * name. + */ + for (d = vecs; d; d = d->v_link2) { + if (d->v_plot == tpl) { + vv = vec_copy(d); + /* Note that since we are building a new plot + * we don't want to vec_new this one... + */ + vv->v_name = vec_basename(vv); + + if (end) + end->v_next = vv; + else + end = newplot.pl_dvecs = vv; + end = vv; + + if (vec_eq(d, tpl->pl_scale)) { + newplot.pl_scale = vv; + scalefound = TRUE; + } + } + } + end->v_next = NULL; + + /* Maybe we shouldn't make sure that the default scale is + * present if nobody uses it. + */ + if (!scalefound) { + newplot.pl_scale = vec_copy(tpl->pl_scale); + newplot.pl_scale->v_next = newplot.pl_dvecs; + newplot.pl_dvecs = newplot.pl_scale; + } + + /* Now let's go through and make sure that everything that + * has its own scale has it in the plot. + */ + for (;;) { + scalefound = FALSE; + for (d = newplot.pl_dvecs; d; d = d->v_next) { + if (d->v_scale) { + for (vv = newplot.pl_dvecs; vv; vv = + vv->v_next) + if (vec_eq(vv, d->v_scale)) + break; + /* We have to grab it... */ + vv = vec_copy(d->v_scale); + vv->v_next = newplot.pl_dvecs; + newplot.pl_dvecs = vv; + scalefound = TRUE; + } + } + if (!scalefound) + break; + /* Otherwise loop through again... */ + } + + spar_write(file, &newplot, Rbaseval); + + /* Now throw out the vectors we have written already... */ + for (d = vecs, lv = NULL; d; d = d->v_link2) + if (d->v_plot == tpl) { + if (lv) { + lv->v_link2 = d->v_link2; + d = lv; + } else + vecs = d->v_link2; + } else + lv = d; + /* If there are more plots we want them appended... */ + appendwrite = TRUE; + } + return; +} + + /* If the named vectors have more than 1 dimension, then consider * to be a collection of one or more matrices. This command transposes * each named matrix. diff --git a/src/frontend/postcoms.h b/src/frontend/postcoms.h index 6703cc4fc..18c6a864c 100644 --- a/src/frontend/postcoms.h +++ b/src/frontend/postcoms.h @@ -11,6 +11,7 @@ void com_unlet(wordlist *wl); void com_load(wordlist *wl); void com_print(wordlist *wl); void com_write(wordlist *wl); +void com_write_sparam(wordlist *wl); void com_transpose(wordlist *wl); void com_setscale(wordlist *wl); void com_display(wordlist *wl); diff --git a/src/frontend/rawfile.c b/src/frontend/rawfile.c index 3d77fb78e..350c9b358 100644 --- a/src/frontend/rawfile.c +++ b/src/frontend/rawfile.c @@ -740,3 +740,105 @@ fixdims(struct dvec *v, char *s) } return; } + +/* Write a s-param file according to format Touchstone Vers. 1. */ + +void +spar_write(char *name, struct plot *pl, double Rbaseval) +{ + FILE *fp; + bool realflag = TRUE; + int length, numdims, dims[MAXDIMS]; + int i, j, prec; + struct dvec *v, *lv; + + /* Why bother printing out an empty plot? */ + if (!pl->pl_dvecs) { + fprintf(cp_err, "Error writing s2p: plot is empty, nothing written.\n"); + return; + } + + if (raw_prec != -1) + prec = raw_prec; + else + prec = 6; + + numdims = length = 0; + for (v = pl->pl_dvecs; v; v = v->v_next) { + + /* All vectors have to have same length, + only dimension 1 is allowed */ + if (length == 0) {length = v->v_length;} + if (length != v->v_length) { + fprintf(stderr,"Error writing s2p: lentgth of vector %s differs from length of vector 'frequency'\n", + v->v_name); + return; + } + if (v->v_numdims != 1) { + fprintf(stderr,"Error writing s2p: Dimension of vector %s greater than 1\n",v->v_name); + return; + } + + /* Find the length and dimensions of the longest vector + * in the plot. + * Be paranoid and assume somewhere we may have + * forgotten to set the dimensions of 1-D vectors. + + if (v->v_numdims <= 1) { + v->v_numdims = 1; + v->v_dims[0] = v->v_length; + } + if (v->v_length > length) { + length = v->v_length; + numdims = v->v_numdims; + for (j = 0; j < numdims; j++) { + dims[j] = v->v_dims[j]; + } + }*/ + } + + if (!(fp = fopen(name, "w"))) { + perror(name); + return; + } + + fprintf(fp, "!2-port S-parameter file\n"); + fprintf(fp, "!Title: %s\n", pl->pl_title); + fprintf(fp, "!Generated by ngspice at %s\n", pl->pl_date); + fprintf(fp, "# Hz S RI R %g\n", Rbaseval); + fprintf(fp, "!%-*.5s %-*.5s %-*.5s %-*.5s %-*.5s %-*.5s %-*.5s %-*.5s %-*.5s\n", + prec+8,"freq", + prec+8,"ReS11",prec+8,"ImS11",prec+8,"ReS21",prec+8,"ImS21", + prec+8,"ReS12",prec+8,"ImS12",prec+8,"ReS22",prec+8,"ImS22"); + + /* Before we write the stuff out, make sure that the scale is the first + * in the list. + */ + for (lv = NULL, v = pl->pl_dvecs; v != pl->pl_scale; v = v->v_next) + lv = v; + if (lv) { + lv->v_next = v->v_next; + v->v_next = pl->pl_dvecs; + pl->pl_dvecs = v; + } + + /* print frequency first as real value, the real and imag part of + S11, S21, S12, S22 respectively */ + for (i = 0; i < length; i++) { + for (v = pl->pl_dvecs; v; v = v->v_next) { + if (i < v->v_length) { + if (cieq(v->v_name, "frequency")) + fprintf(fp, "% .*e ", prec, + realpart(&v->v_compdata[i])); + else + fprintf(fp, "% .*e % .*e ", prec, + realpart(&v->v_compdata[i]), + prec, + imagpart(&v->v_compdata[i])); + } + } + (void) putc('\n', fp); + } + (void) fclose(fp); + return; +} diff --git a/src/frontend/rawfile.h b/src/frontend/rawfile.h index c3411a957..b8e2c34cc 100644 --- a/src/frontend/rawfile.h +++ b/src/frontend/rawfile.h @@ -7,6 +7,7 @@ #define RAWFILE_H_INCLUDED void raw_write(char *name, struct plot *pl, bool app, bool binary); +void spar_write(char *name, struct plot *pl, double val); struct plot * raw_read(char *name); diff --git a/src/include/fteext.h b/src/include/fteext.h index 432a153c2..494019223 100644 --- a/src/include/fteext.h +++ b/src/include/fteext.h @@ -324,6 +324,7 @@ extern void com_unlet(wordlist *wl); extern void com_load(wordlist *wl); extern void com_print(wordlist *wl); extern void com_write(wordlist *wl); +extern void com_write_sparam(wordlist *wl); extern void com_destroy(wordlist *wl); extern void com_splot(wordlist *wl); extern void com_setscale(wordlist *wl); @@ -332,6 +333,7 @@ extern void com_transpose(wordlist *wl); /* rawfile.c */ extern int raw_prec; extern void raw_write(char *name, struct plot *pl, bool app, bool binary); +extern void spar_write(char *name, struct plot *pl, double val); extern struct plot *raw_read(char *name); /* meas.c */