pa-64
This commit is contained in:
parent
b54bf483fb
commit
262781618a
|
|
@ -225,6 +225,10 @@ struct comm spcp_coms[] = {
|
|||
{ 1, 041000, 041000, 041000 }, E_DEFHMASK, 0, LOTS,
|
||||
NULL,
|
||||
"file : Send s-param data to file." } ,
|
||||
{ "wrsnp", com_write_sparam, FALSE, TRUE,
|
||||
{ 1, 041000, 041000, 041000 }, E_DEFHMASK, 0, LOTS,
|
||||
NULL,
|
||||
"file : Send N-port s-param data to a Touchstone file." } ,
|
||||
{ "hardcopy", com_hardcopy, FALSE, TRUE,
|
||||
{ 1, 041000, 041000, 041000 }, E_DEFHMASK, 0, LOTS,
|
||||
NULL,
|
||||
|
|
@ -776,6 +780,10 @@ struct comm nutcp_coms[] = {
|
|||
{ 1, 041000, 041000, 041000 }, E_DEFHMASK, 0, LOTS,
|
||||
NULL,
|
||||
"file : Send s-param data to file." } ,
|
||||
{ "wrsnp", com_write_sparam, FALSE, TRUE,
|
||||
{ 1, 041000, 041000, 041000 }, E_DEFHMASK, 0, LOTS,
|
||||
NULL,
|
||||
"file : Send N-port s-param data to a Touchstone file." } ,
|
||||
{ "hardcopy", com_hardcopy, FALSE, TRUE,
|
||||
{ 1, 041000, 041000, 041000 }, E_DEFHMASK, 0, LOTS,
|
||||
NULL,
|
||||
|
|
|
|||
|
|
@ -744,13 +744,92 @@ done:
|
|||
}
|
||||
|
||||
|
||||
/* Enhancement-64: write an N-port Touchstone v1 file (.sNp) directly from
|
||||
the S_i_j vectors of the current .sp plot. Layout per the Touchstone 1.x
|
||||
spec: `# Hz S RI R <Rbase>` option line; for N >= 3 the matrix is
|
||||
row-major with at most FOUR complex pairs per data line and every matrix
|
||||
row starting on a new line (the first row follows the frequency value);
|
||||
a 1-port is a single pair per line. (The classic 2-port S11 S21 S12 S22
|
||||
column order is handled by the original spar_write() path.) */
|
||||
static void
|
||||
spar_write_np(const char *file, int nports, double Rbaseval)
|
||||
{
|
||||
struct dvec *freqv = vec_get("frequency");
|
||||
struct dvec **sv;
|
||||
FILE *fp;
|
||||
int i, j, k, npts, prec, inrow;
|
||||
|
||||
if (!freqv) {
|
||||
fprintf(stderr, "Error: no frequency vector (run a .sp analysis first)\n");
|
||||
return;
|
||||
}
|
||||
npts = freqv->v_length;
|
||||
prec = 6;
|
||||
|
||||
sv = TMALLOC(struct dvec *, (size_t) (nports * nports));
|
||||
for (i = 0; i < nports; i++)
|
||||
for (j = 0; j < nports; j++) {
|
||||
char nb[40];
|
||||
(void) sprintf(nb, "S_%d_%d", i + 1, j + 1);
|
||||
sv[i * nports + j] = vec_get(nb);
|
||||
if (!sv[i * nports + j] || sv[i * nports + j]->v_length != npts) {
|
||||
fprintf(stderr, "Error: vector %s missing or of wrong length\n", nb);
|
||||
tfree(sv);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if ((fp = fopen(file, "w")) == NULL) {
|
||||
perror(file);
|
||||
tfree(sv);
|
||||
return;
|
||||
}
|
||||
|
||||
fprintf(fp, "!%d-port S-parameter file\n", nports);
|
||||
fprintf(fp, "!Title: %s\n", freqv->v_plot ? freqv->v_plot->pl_title : "");
|
||||
fprintf(fp, "!Generated by ngspice at %s\n",
|
||||
freqv->v_plot ? freqv->v_plot->pl_date : "");
|
||||
fprintf(fp, "# Hz S RI R %g\n", Rbaseval);
|
||||
|
||||
for (k = 0; k < npts; k++) {
|
||||
double f = isreal(freqv) ? freqv->v_realdata[k]
|
||||
: realpart(freqv->v_compdata[k]);
|
||||
fprintf(fp, "% .*e", prec, f);
|
||||
for (i = 0; i < nports; i++) {
|
||||
if (i > 0)
|
||||
fprintf(fp, "%*s", prec + 9, ""); /* align continuation rows */
|
||||
inrow = 0;
|
||||
for (j = 0; j < nports; j++) {
|
||||
struct dvec *v = sv[i * nports + j];
|
||||
double re = isreal(v) ? v->v_realdata[k]
|
||||
: realpart(v->v_compdata[k]);
|
||||
double im = isreal(v) ? 0.0
|
||||
: imagpart(v->v_compdata[k]);
|
||||
if (inrow == 4) { /* max 4 pairs per line */
|
||||
fprintf(fp, "\n%*s", prec + 9, "");
|
||||
inrow = 0;
|
||||
}
|
||||
fprintf(fp, " % .*e % .*e", prec, re, prec, im);
|
||||
inrow++;
|
||||
}
|
||||
fprintf(fp, "\n"); /* each matrix row on its own line */
|
||||
}
|
||||
}
|
||||
|
||||
(void) fclose(fp);
|
||||
fprintf(stdout, "%d-port S-parameters written to %s\n", nports, file);
|
||||
tfree(sv);
|
||||
}
|
||||
|
||||
|
||||
/* Write scattering parameters into a file with Touchstone File Format Version 1
|
||||
with command wrs2p file .
|
||||
with command wrs2p file (2 ports) or wrsnp file (any port count).
|
||||
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 S_1_1, S_2_1, S_1_2, S_2_2 and frequency vectors are available
|
||||
Check if vector Rbase is available
|
||||
Call spar_write()
|
||||
Check if vector Rbase is available (the .sp analysis publishes it since
|
||||
Enhancement-64, so no manual `let Rbase = ...` is needed anymore)
|
||||
Call spar_write() (2-port) or spar_write_np() (N-port)
|
||||
*/
|
||||
|
||||
void
|
||||
|
|
@ -766,12 +845,42 @@ com_write_sparam(wordlist *wl)
|
|||
struct plot *tpl, newplot;
|
||||
double Rbaseval;
|
||||
|
||||
int nports = 0;
|
||||
|
||||
if (wl)
|
||||
file = wl->wl_word;
|
||||
else
|
||||
file = "s_param.s2p";
|
||||
|
||||
fprintf(stderr, "Note: only 2 ports 1 and 2 are supported by wrs2p\n");
|
||||
/* Enhancement-64: how many ports does the current sp plot hold? */
|
||||
while (nports < 99) {
|
||||
char nb[40];
|
||||
(void) sprintf(nb, "S_%d_%d", nports + 1, nports + 1);
|
||||
if (!vec_get(nb))
|
||||
break;
|
||||
nports++;
|
||||
}
|
||||
if (nports == 0) {
|
||||
fprintf(stderr, "Error: no S-parameter vectors found (run a .sp analysis first)\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Enhancement-64: the sp analysis publishes Rbase (the ports'
|
||||
reference resistance); a user-defined `let Rbase = ...` still
|
||||
overrides. The sp plot is complex, so read either data form. */
|
||||
Rbasevec = vec_get("Rbase");
|
||||
if (Rbasevec) {
|
||||
Rbaseval = isreal(Rbasevec) ? Rbasevec->v_realdata[0]
|
||||
: realpart(Rbasevec->v_compdata[0]);
|
||||
} else {
|
||||
fprintf(stderr, "Error: No Rbase vector given\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (nports != 2) {
|
||||
spar_write_np(file, nports, Rbaseval);
|
||||
return;
|
||||
}
|
||||
|
||||
/* generate wordlist with all vectors required*/
|
||||
sbuf[0] = "frequency";
|
||||
|
|
@ -800,14 +909,6 @@ com_write_sparam(wordlist *wl)
|
|||
;
|
||||
}
|
||||
|
||||
Rbasevec = vec_get("Rbase");
|
||||
if (Rbasevec) {
|
||||
Rbaseval = Rbasevec->v_realdata[0];
|
||||
} else {
|
||||
fprintf(stderr, "Error: No Rbase vector given\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Now we have to write them out plot by plot. */
|
||||
|
||||
while (vecs) {
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -128,7 +128,8 @@ CKTspDump(CKTcircuit *ckt, double freq, runDesc *plot, int doNoise)
|
|||
rhsold = ckt->CKTrhsOld;
|
||||
irhsold = ckt->CKTirhsOld;
|
||||
freqData.rValue = freq;
|
||||
int extraSPdataCount = 3* ckt->CKTportCount * ckt->CKTportCount;
|
||||
/* Enhancement-64: +1 for the Rbase vector */
|
||||
int extraSPdataCount = 3* ckt->CKTportCount * ckt->CKTportCount + 1;
|
||||
valueData.v.numValue = ckt->CKTmaxEqNum - 1 + extraSPdataCount;
|
||||
|
||||
int datasize = ckt->CKTmaxEqNum - 1 + extraSPdataCount;
|
||||
|
|
@ -189,6 +190,17 @@ CKTspDump(CKTcircuit *ckt, double freq, runDesc *plot, int doNoise)
|
|||
}
|
||||
}
|
||||
|
||||
/* Enhancement-64: reference resistance of the ports (matches the
|
||||
"Rbase" UID registered after the Z block in span.c). Read z0
|
||||
straight from port 1 -- the refPortY0 global is only set on the
|
||||
noise path. */
|
||||
{
|
||||
VSRCinstance *refPort = (VSRCinstance *) (ckt->CKTrfPorts[0]);
|
||||
data[nPlot].real = refPort->VSRCportZ0;
|
||||
data[nPlot].imag = 0.0;
|
||||
nPlot++;
|
||||
}
|
||||
|
||||
if (doNoise)
|
||||
{
|
||||
// Put Cy data
|
||||
|
|
|
|||
|
|
@ -390,11 +390,10 @@ SPan(CKTcircuit* ckt, int restart)
|
|||
controlled_exit(EXIT_BAD);
|
||||
}
|
||||
|
||||
if (ckt->CKTportCount == 1)
|
||||
{
|
||||
fprintf(stderr, "\nError: Only one RF Port is found, we need at least two!\n");
|
||||
controlled_exit(EXIT_BAD);
|
||||
}
|
||||
/* Enhancement-64: a single port is a perfectly good S-parameter
|
||||
measurement (reflection, .s1p); the matrix machinery below is
|
||||
N-general, so the old hard error was over-strict. The 2-port-only
|
||||
noise-parameter block stays gated on CKTportCount == 2. */
|
||||
|
||||
#ifdef XSPICE
|
||||
/* Tell the code models what mode we're in */
|
||||
|
|
@ -497,7 +496,9 @@ SPan(CKTcircuit* ckt, int restart)
|
|||
plot = NULL;
|
||||
}
|
||||
|
||||
int extraSPdataLength = 3 * ckt->CKTportCount * ckt->CKTportCount;
|
||||
/* Enhancement-64: +1 for the Rbase vector (the ports' reference
|
||||
resistance) so wrs2p/wrsnp work without a manual `let Rbase` */
|
||||
int extraSPdataLength = 3 * ckt->CKTportCount * ckt->CKTportCount + 1;
|
||||
if (job->SPdoNoise)
|
||||
{
|
||||
extraSPdataLength += ckt->CKTportCount * ckt->CKTportCount; // Add Cy
|
||||
|
|
@ -538,6 +539,11 @@ SPan(CKTcircuit* ckt, int restart)
|
|||
SPfrontEnd->IFnewUid(ckt, &(nameList[numNames++]), NULL, tmpBuf, UID_OTHER, NULL);
|
||||
}
|
||||
|
||||
/* Enhancement-64: publish the reference resistance of the ports as
|
||||
a vector, so the Touchstone writers can label the file header
|
||||
(`# Hz S RI R <Rbase>`) without user intervention. */
|
||||
SPfrontEnd->IFnewUid(ckt, &(nameList[numNames++]), NULL, "Rbase", UID_OTHER, NULL);
|
||||
|
||||
// Add noise related output, if needed
|
||||
if (job->SPdoNoise)
|
||||
{
|
||||
|
|
|
|||
Loading…
Reference in New Issue