new command wrs2p
This commit is contained in:
parent
32c134f481
commit
afdf6ee134
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
Loading…
Reference in New Issue