Browse Source
S parameter simulation
S parameter simulation
Command '.sp' arbitrary number of ports ports made with modified VSRC Patch provided by Alessio Cacciatori https://sourceforge.net/p/ngspice/discussion/127605/thread/7a2655c86f/pre-master-46
committed by
Holger Vogt
31 changed files with 3336 additions and 31 deletions
-
21examples/sp/sp1.cir
-
8src/frontend/commands.c
-
11src/frontend/runcoms.c
-
3src/frontend/runcoms.h
-
81src/frontend/shyu.c
-
9src/frontend/spiceif.c
-
10src/include/ngspice/acdefs.h
-
41src/include/ngspice/cktdefs.h
-
3src/include/ngspice/ipc.h
-
51src/include/ngspice/spdefs.h
-
1325src/maths/dense/dense.c
-
103src/maths/dense/dense.h
-
76src/maths/ni/niaciter.c
-
15src/spicelib/analysis/analysis.c
-
10src/spicelib/analysis/cktdest.c
-
108src/spicelib/analysis/cktspdum.c
-
736src/spicelib/analysis/span.c
-
73src/spicelib/analysis/spaskq.c
-
114src/spicelib/analysis/spsetp.c
-
9src/spicelib/devices/cktinit.c
-
7src/spicelib/devices/vsrc/vsrc.c
-
114src/spicelib/devices/vsrc/vsrcacld.c
-
17src/spicelib/devices/vsrc/vsrcask.c
-
44src/spicelib/devices/vsrc/vsrcdefs.h
-
4src/spicelib/devices/vsrc/vsrcext.h
-
33src/spicelib/devices/vsrc/vsrcload.c
-
45src/spicelib/devices/vsrc/vsrcpar.c
-
43src/spicelib/devices/vsrc/vsrcset.c
-
90src/spicelib/devices/vsrc/vsrctemp.c
-
114src/spicelib/parser/inp2dot.c
-
19visualc/vngspice.vcxproj
@ -0,0 +1,21 @@ |
|||
Example of VSRC as power ports |
|||
* |
|||
* |
|||
V1 in 0 dc 0 ac 1 portnum 1 z0 100 pwr 0.001 freq 2.3e9 |
|||
*V1 in 0 dc 1 ac 1 |
|||
Rpt in x 100 |
|||
C1 x 0 1e-9 |
|||
*Vx x 0 0 |
|||
R2 x out 10 |
|||
V2 out 0 dc 0 ac 0 portnum 2 z0 50 pwr 0.002 freq 3.2e9 |
|||
*V2 out 0 dc 0 ac 0 |
|||
|
|||
.sp lin 100 1e8 1e9 1 |
|||
|
|||
.control |
|||
run |
|||
plot S_1_1 S_1_2 S_2_1 |
|||
plot S_2_2 |
|||
.endc |
|||
|
|||
.end |
|||
@ -0,0 +1,51 @@ |
|||
/********** |
|||
Copyright 1990 Regents of the University of California. All rights reserved. |
|||
Author: 1985 Thomas L. Quarles |
|||
**********/ |
|||
|
|||
#ifndef ngspice_SPDEFS_H |
|||
#define ngspice_SPDEFS_H |
|||
|
|||
#include "ngspice/jobdefs.h" |
|||
|
|||
#ifdef RFSPICE |
|||
/* structure used to describe an AC analysis to be performed */ |
|||
|
|||
typedef struct { |
|||
int JOBtype; |
|||
JOB *JOBnextJob; /* pointer to next thing to do */ |
|||
char *JOBname; /* name of this job */ |
|||
double SPstartFreq; |
|||
double SPstopFreq; |
|||
double SPfreqDelta; /* multiplier for decade/octave stepping, */ |
|||
/* step for linear steps. */ |
|||
double SPsaveFreq; /* frequency at which we left off last time*/ |
|||
int SPstepType; /* values described below */ |
|||
int SPnumberSteps; |
|||
|
|||
unsigned SPdoNoise : 1; /* Flag to indicate if SP noise must be calculated*/ |
|||
|
|||
unsigned int SPnoiseInput; |
|||
unsigned int SPnoiseOutput; |
|||
} SPAN; |
|||
|
|||
/* available step types: XXX should be somewhere else */ |
|||
#ifndef ngspice_ACDEFS_H |
|||
enum { |
|||
DECADE = 1, |
|||
OCTAVE, |
|||
LINEAR, |
|||
}; |
|||
#endif |
|||
|
|||
enum { |
|||
SP_DEC = 1, |
|||
SP_OCT, |
|||
SP_LIN, |
|||
SP_START, |
|||
SP_STOP, |
|||
SP_STEPS, |
|||
SP_DONOISE, |
|||
}; |
|||
#endif |
|||
#endif |
|||
1325
src/maths/dense/dense.c
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
@ -0,0 +1,103 @@ |
|||
#ifndef ngspice_DENSE_MATRIX_H |
|||
#define ngspice_DENSE_MATRIX_H |
|||
|
|||
|
|||
typedef struct cplx |
|||
{ |
|||
double re; |
|||
double im; |
|||
}cplx; |
|||
|
|||
typedef struct Mat{ |
|||
double** d; |
|||
int row; |
|||
int col; |
|||
}Mat; |
|||
|
|||
typedef struct CMat { |
|||
cplx** d; |
|||
int row; |
|||
int col; |
|||
}CMat; |
|||
|
|||
|
|||
typedef struct MatList{ |
|||
Mat* mat; |
|||
struct MatList* next; |
|||
}MatList; |
|||
|
|||
extern void showmat(Mat* A); |
|||
extern void showcmat(CMat* A); |
|||
extern CMat* newcmat(int r, int c, double dr, double di); |
|||
extern CMat* newcmatnoinit(int r, int c); |
|||
extern Mat* newmat(int r, int c, double d); |
|||
extern Mat* newmatnoinit(int r, int c); |
|||
extern void freecmat(CMat* A); |
|||
extern void freemat(Mat* A); |
|||
extern CMat* ceye(int n); |
|||
extern Mat* eye(int n); |
|||
extern Mat* zeros(int r, int c); |
|||
extern CMat* czeros(int r, int c); |
|||
extern Mat* ones(int r, int c); |
|||
extern CMat* cones(int r, int c); |
|||
extern Mat* randm(int r, int c, double l, double u); |
|||
extern CMat* randcm(int r, int c, double l, double u); |
|||
extern double get(Mat* M, int r, int c); |
|||
extern cplx getcplx(CMat* M, int r, int c); |
|||
extern void set(Mat* M, int r, int c, double d); |
|||
extern void setc(CMat* M, int r, int c, cplx d); |
|||
extern Mat* scalarmultiply(Mat* M, double c); |
|||
extern CMat* cscalarmultiply(CMat* M, double c); |
|||
extern CMat* complexmultiply(CMat* M, cplx c); |
|||
extern Mat* sum(Mat* A, Mat* B); |
|||
extern CMat* csum(CMat* A, CMat* B); |
|||
extern Mat* minus(Mat* A, Mat* B); |
|||
extern CMat* cminus(CMat* A, CMat* B); |
|||
extern Mat* submat(Mat* A, int r1, int r2, int c1, int c2); |
|||
extern void submat2(Mat* A, Mat* B, int r1, int r2, int c1, int c2); |
|||
extern CMat* subcmat(CMat* A, int r1, int r2, int c1, int c2); |
|||
extern void subcmat2(CMat* A, CMat* B, int r1, int r2, int c1, int c2); |
|||
extern Mat* multiply(Mat* A, Mat* B); |
|||
extern CMat* cmultiply(CMat* A, CMat* B); |
|||
extern Mat* removerow(Mat* A, int r); |
|||
extern Mat* removecol(Mat* A, int c); |
|||
extern void removerow2(Mat* A, Mat* B, int r); |
|||
extern void removecol2(Mat* A, Mat* B, int c); |
|||
extern CMat* cremoverow(CMat* A, int r); |
|||
extern CMat* cremovecol(CMat* A, int c); |
|||
extern void cremoverow2(CMat* A, CMat* B, int r); |
|||
extern void cremovecol2(CMat* A, CMat* B, int c); |
|||
extern Mat* transpose(Mat* A); |
|||
extern CMat* ctranspose(CMat* A); |
|||
extern double trace(Mat* A); |
|||
extern cplx ctrace(CMat* A); |
|||
extern Mat* adjoint(Mat* A); |
|||
extern CMat* cadjoint(CMat* A); |
|||
extern Mat* inverse(Mat* A); |
|||
extern CMat* cinverse(CMat* A); |
|||
extern Mat* copyvalue(Mat* A); |
|||
extern CMat* copycvalue(CMat* A); |
|||
extern Mat* copyvalue(Mat* A); |
|||
extern CMat* copycvalue(CMat* A); |
|||
extern Mat* triinverse(Mat* A); |
|||
extern CMat* ctriinverse(CMat* A); |
|||
extern Mat* rowechelon(Mat* A); |
|||
extern CMat* crowechelon(CMat* A); |
|||
extern Mat* hconcat(Mat* A, Mat* B); |
|||
extern CMat* chconcat(CMat* A, CMat* B); |
|||
extern Mat* vconcat(Mat* A, Mat* B); |
|||
extern CMat* cvconcat(CMat* A, CMat* B); |
|||
extern double norm(Mat* A); |
|||
extern double cnorm(CMat* A); |
|||
extern Mat* nullmat(Mat* A); |
|||
extern MatList* lu(Mat* A); |
|||
extern double innermultiply(Mat* a, Mat* b); |
|||
extern MatList* qr(Mat* A); |
|||
extern int complexmultiplydest(CMat* M, cplx c, CMat* dest); |
|||
extern int cinversedest(CMat* A, CMat* dest); |
|||
extern int copycvaluedest(CMat* A, CMat* dest); |
|||
extern int cmultiplydest(CMat* A, CMat* B, CMat* dest); |
|||
|
|||
|
|||
|
|||
#endif |
|||
@ -0,0 +1,108 @@ |
|||
/********** |
|||
Copyright 1990 Regents of the University of California. All rights reserved. |
|||
Author: 1985 Thomas L. Quarles |
|||
**********/ |
|||
|
|||
/* CKTspDump(ckt,freq,file) |
|||
* this is a simple program to dump the complex rhs vector |
|||
* into the rawfile. |
|||
*/ |
|||
|
|||
#include "ngspice/ngspice.h" |
|||
#include "ngspice/smpdefs.h" |
|||
#include "ngspice/cktdefs.h" |
|||
#include "ngspice/iferrmsg.h" |
|||
#include "ngspice/ifsim.h" |
|||
#include "vsrc/vsrcdefs.h" |
|||
|
|||
unsigned int CKTmatrixIndex(CKTcircuit* ckt, unsigned int source, unsigned int dest) |
|||
{ |
|||
return source * ckt->CKTportCount + dest; |
|||
}; |
|||
|
|||
int CKTspCalcSMatrix(CKTcircuit* ckt) |
|||
{ |
|||
CMat* Ainv = cinverse(ckt->CKTAmat); |
|||
if (Ainv == NULL) return (E_NOMEM); |
|||
cmultiplydest(ckt->CKTBmat, Ainv, ckt->CKTSmat); |
|||
freecmat(Ainv); |
|||
return (OK); |
|||
} |
|||
|
|||
int CKTspCalcPowerWave(CKTcircuit* ckt) |
|||
{ |
|||
double* rhsold = ckt->CKTrhsOld; |
|||
double* irhsold = ckt->CKTirhsOld; |
|||
int col = ckt->CKTactivePort - 1; |
|||
for (int port = 0; port < ckt->CKTportCount; port++) |
|||
{ |
|||
VSRCinstance* pSrc = (VSRCinstance*)(ckt->CKTrfPorts[port]); |
|||
int row = pSrc->VSRCportNum - 1; |
|||
double zi = pSrc->VSRCportZ0; |
|||
double iReal = -rhsold[pSrc->VSRCbranch]; |
|||
double iImag = -irhsold[pSrc->VSRCbranch]; |
|||
|
|||
double vReal = rhsold[pSrc->VSRCposNode] - rhsold[pSrc->VSRCnegNode]; |
|||
double vImag = irhsold[pSrc->VSRCposNode] - irhsold[pSrc->VSRCnegNode]; |
|||
// Forward wave (a) of i-th port, real (r) and imag (i) |
|||
cplx a; |
|||
a.re = pSrc->VSRCki * (vReal + zi * iReal); |
|||
a.im = pSrc->VSRCki * (vImag + zi * iImag); |
|||
|
|||
// Scattered wave (b) of i-th port, real (r) and imag (i) |
|||
cplx b; |
|||
b.re = pSrc->VSRCki * (vReal - zi * iReal); |
|||
b.im = pSrc->VSRCki * (vImag - zi * iImag); |
|||
|
|||
// fill in A and B matrices |
|||
setc(ckt->CKTAmat, row, col, a); |
|||
setc(ckt->CKTBmat, row, col, b); |
|||
|
|||
} |
|||
return (OK); |
|||
} |
|||
|
|||
int |
|||
CKTspDump(CKTcircuit *ckt, double freq, runDesc *plot) |
|||
{ |
|||
double *rhsold; |
|||
double *irhsold; |
|||
int i; |
|||
IFcomplex *data; |
|||
IFvalue freqData; |
|||
IFvalue valueData; |
|||
|
|||
rhsold = ckt->CKTrhsOld; |
|||
irhsold = ckt->CKTirhsOld; |
|||
freqData.rValue = freq; |
|||
unsigned int extraSPdataCount = ckt->CKTportCount * ckt->CKTportCount; |
|||
valueData.v.numValue = ckt->CKTmaxEqNum - 1 + extraSPdataCount; |
|||
|
|||
data = TMALLOC(IFcomplex, ckt->CKTmaxEqNum - 1 + extraSPdataCount); |
|||
valueData.v.vec.cVec = data; |
|||
for (i=0;i<ckt->CKTmaxEqNum-1;i++) { |
|||
data[i].real = rhsold[i+1]; |
|||
data[i].imag = irhsold[i+1]; |
|||
} |
|||
|
|||
if (ckt->CKTrfPorts ) |
|||
{ |
|||
// Cycle thru all ports |
|||
for (unsigned int pdest = 0; pdest < ckt->CKTportCount; pdest++) |
|||
{ |
|||
for (unsigned int psource = 0; psource < ckt->CKTportCount; psource++) |
|||
{ |
|||
unsigned int nPlot = ckt->CKTmaxEqNum - 1 + CKTmatrixIndex(ckt, pdest, psource); |
|||
cplx sij = ckt->CKTSmat->d[pdest][psource]; |
|||
data[nPlot].real = sij.re; |
|||
data[nPlot].imag = sij.im; |
|||
} |
|||
} |
|||
} |
|||
|
|||
|
|||
SPfrontEnd->OUTpData(plot, &freqData, &valueData); |
|||
|
|||
FREE(data); |
|||
return(OK); |
|||
} |
|||
@ -0,0 +1,736 @@ |
|||
/* |
|||
**** |
|||
* Alessio Cacciatori 2021 |
|||
**** |
|||
*/ |
|||
#include "ngspice/ngspice.h" |
|||
#include "ngspice/cktdefs.h" |
|||
#include "ngspice/spdefs.h" |
|||
#include "ngspice/devdefs.h" |
|||
#include "ngspice/sperror.h" |
|||
|
|||
#ifdef XSPICE |
|||
#include "ngspice/evt.h" |
|||
#include "ngspice/enh.h" |
|||
/* gtri - add - wbk - 12/19/90 - Add headers */ |
|||
#include "ngspice/mif.h" |
|||
#include "ngspice/evtproto.h" |
|||
#include "ngspice/ipctiein.h" |
|||
/* gtri - end - wbk */ |
|||
#endif |
|||
|
|||
|
|||
|
|||
|
|||
#ifdef RFSPICE |
|||
#include "vsrc/vsrcext.h" |
|||
#include "../maths/dense/dense.h" |
|||
|
|||
#define INIT_STATS() \ |
|||
do { \ |
|||
startTime = SPfrontEnd->IFseconds(); \ |
|||
startdTime = ckt->CKTstat->STATdecompTime; \ |
|||
startsTime = ckt->CKTstat->STATsolveTime; \ |
|||
startlTime = ckt->CKTstat->STATloadTime; \ |
|||
startkTime = ckt->CKTstat->STATsyncTime; \ |
|||
} while(0) |
|||
|
|||
#define UPDATE_STATS(analysis) \ |
|||
do { \ |
|||
ckt->CKTcurrentAnalysis = analysis; \ |
|||
ckt->CKTstat->STATacTime += SPfrontEnd->IFseconds() - startTime; \ |
|||
ckt->CKTstat->STATacDecompTime += ckt->CKTstat->STATdecompTime - startdTime; \ |
|||
ckt->CKTstat->STATacSolveTime += ckt->CKTstat->STATsolveTime - startsTime; \ |
|||
ckt->CKTstat->STATacLoadTime += ckt->CKTstat->STATloadTime - startlTime; \ |
|||
ckt->CKTstat->STATacSyncTime += ckt->CKTstat->STATsyncTime - startkTime; \ |
|||
} while(0) |
|||
|
|||
|
|||
|
|||
int |
|||
CKTspnoise(CKTcircuit * ckt, int mode, int operation, Ndata * data) |
|||
{ |
|||
NOISEAN* job = (NOISEAN*)ckt->CKTcurJob; |
|||
|
|||
double outNdens; |
|||
int i; |
|||
IFvalue outData; /* output variable (points to list of outputs)*/ |
|||
IFvalue refVal; /* reference variable (always 0)*/ |
|||
int error; |
|||
|
|||
outNdens = 0.0; |
|||
|
|||
/* let each device decide how many and what type of noise sources it has */ |
|||
|
|||
for (i = 0; i < DEVmaxnum; i++) { |
|||
if (DEVices[i] && DEVices[i]->DEVnoise && ckt->CKThead[i]) { |
|||
error = DEVices[i]->DEVnoise(mode, operation, ckt->CKThead[i], |
|||
ckt, data, &outNdens); |
|||
if (error) return (error); |
|||
} |
|||
} |
|||
|
|||
switch (operation) { |
|||
|
|||
case N_OPEN: |
|||
|
|||
/* take care of the noise for the circuit as a whole */ |
|||
|
|||
switch (mode) { |
|||
|
|||
case N_DENS: |
|||
|
|||
data->namelist = TREALLOC(IFuid, data->namelist, data->numPlots + 1); |
|||
|
|||
SPfrontEnd->IFnewUid(ckt, &(data->namelist[data->numPlots++]), |
|||
NULL, "onoise_spectrum", UID_OTHER, NULL); |
|||
|
|||
data->namelist = TREALLOC(IFuid, data->namelist, data->numPlots + 1); |
|||
|
|||
SPfrontEnd->IFnewUid(ckt, &(data->namelist[data->numPlots++]), |
|||
NULL, "inoise_spectrum", UID_OTHER, NULL); |
|||
|
|||
/* we've added two more plots */ |
|||
|
|||
data->outpVector = |
|||
TMALLOC(double, data->numPlots); |
|||
data->squared_value = |
|||
data->squared ? NULL : TMALLOC(char, data->numPlots); |
|||
break; |
|||
|
|||
case INT_NOIZ: |
|||
|
|||
data->namelist = TREALLOC(IFuid, data->namelist, data->numPlots + 1); |
|||
SPfrontEnd->IFnewUid(ckt, &(data->namelist[data->numPlots++]), |
|||
NULL, "onoise_total", UID_OTHER, NULL); |
|||
|
|||
data->namelist = TREALLOC(IFuid, data->namelist, data->numPlots + 1); |
|||
SPfrontEnd->IFnewUid(ckt, &(data->namelist[data->numPlots++]), |
|||
NULL, "inoise_total", UID_OTHER, NULL); |
|||
/* we've added two more plots */ |
|||
|
|||
data->outpVector = |
|||
TMALLOC(double, data->numPlots); |
|||
data->squared_value = |
|||
data->squared ? NULL : TMALLOC(char, data->numPlots); |
|||
break; |
|||
|
|||
default: |
|||
return (E_INTERN); |
|||
} |
|||
|
|||
break; |
|||
|
|||
case N_CALC: |
|||
|
|||
switch (mode) { |
|||
|
|||
case N_DENS: |
|||
if ((job->NStpsSm == 0) |
|||
|| data->prtSummary) |
|||
{ |
|||
data->outpVector[data->outNumber++] = outNdens; |
|||
data->outpVector[data->outNumber++] = |
|||
(outNdens * data->GainSqInv); |
|||
|
|||
refVal.rValue = data->freq; /* the reference is the freq */ |
|||
if (!data->squared) |
|||
for (i = 0; i < data->outNumber; i++) |
|||
if (data->squared_value[i]) |
|||
data->outpVector[i] = sqrt(data->outpVector[i]); |
|||
outData.v.numValue = data->outNumber; /* vector number */ |
|||
outData.v.vec.rVec = data->outpVector; /* vector of outputs */ |
|||
SPfrontEnd->OUTpData(data->NplotPtr, &refVal, &outData); |
|||
} |
|||
break; |
|||
|
|||
case INT_NOIZ: |
|||
data->outpVector[data->outNumber++] = data->outNoiz; |
|||
data->outpVector[data->outNumber++] = data->inNoise; |
|||
if (!data->squared) |
|||
for (i = 0; i < data->outNumber; i++) |
|||
if (data->squared_value[i]) |
|||
data->outpVector[i] = sqrt(data->outpVector[i]); |
|||
outData.v.vec.rVec = data->outpVector; /* vector of outputs */ |
|||
outData.v.numValue = data->outNumber; /* vector number */ |
|||
SPfrontEnd->OUTpData(data->NplotPtr, &refVal, &outData); |
|||
break; |
|||
|
|||
default: |
|||
return (E_INTERN); |
|||
} |
|||
break; |
|||
|
|||
case N_CLOSE: |
|||
SPfrontEnd->OUTendPlot(data->NplotPtr); |
|||
FREE(data->namelist); |
|||
FREE(data->outpVector); |
|||
FREE(data->squared_value); |
|||
break; |
|||
|
|||
default: |
|||
return (E_INTERN); |
|||
} |
|||
return (OK); |
|||
} |
|||
|
|||
|
|||
void |
|||
NInspIter(CKTcircuit * ckt, int posDrive, int negDrive) |
|||
{ |
|||
int i; |
|||
|
|||
/* clear out the right hand side vector */ |
|||
|
|||
for (i = 0; i <= SMPmatSize(ckt->CKTmatrix); i++) { |
|||
ckt->CKTrhs[i] = 0.0; |
|||
ckt->CKTirhs[i] = 0.0; |
|||
} |
|||
|
|||
ckt->CKTrhs[posDrive] = 1.0; /* apply unit current excitation */ |
|||
ckt->CKTrhs[negDrive] = -1.0; |
|||
SMPcaSolve(ckt->CKTmatrix, ckt->CKTrhs, ckt->CKTirhs, ckt->CKTrhsSpare, |
|||
ckt->CKTirhsSpare); |
|||
|
|||
ckt->CKTrhs[0] = 0.0; |
|||
ckt->CKTirhs[0] = 0.0; |
|||
} |
|||
|
|||
|
|||
int |
|||
SPan(CKTcircuit *ckt, int restart) |
|||
{ |
|||
|
|||
|
|||
SPAN *job = (SPAN *) ckt->CKTcurJob; |
|||
|
|||
double freq; |
|||
double freqTol; /* tolerence parameter for finding final frequency */ |
|||
double startdTime; |
|||
double startsTime; |
|||
double startlTime; |
|||
double startkTime; |
|||
double startTime; |
|||
int error; |
|||
int numNames; |
|||
int i; |
|||
IFuid *nameList; /* va: tmalloc'ed list of names */ |
|||
IFuid freqUid; |
|||
static runDesc *spPlot = NULL; |
|||
runDesc *plot = NULL; |
|||
|
|||
double* rhswoPorts = NULL; |
|||
double* irhswoPorts = NULL; |
|||
int* portPosNodes = NULL; |
|||
int* portNegNodes = NULL; |
|||
|
|||
|
|||
if (ckt->CKTportCount == 0) |
|||
{ |
|||
fprintf(stderr, "No RF Port is present\n"); |
|||
return (E_PARMVAL); |
|||
} |
|||
|
|||
|
|||
|
|||
if (ckt->CKTAmat != NULL) freecmat(ckt->CKTAmat); |
|||
if (ckt->CKTBmat != NULL) freecmat(ckt->CKTBmat); |
|||
if (ckt->CKTSmat != NULL) freecmat(ckt->CKTSmat); |
|||
|
|||
ckt->CKTAmat = newcmat(ckt->CKTportCount, ckt->CKTportCount, 0.0, 0.0); |
|||
if (ckt->CKTAmat == NULL) |
|||
return (E_NOMEM); |
|||
ckt->CKTBmat = newcmat(ckt->CKTportCount, ckt->CKTportCount, 0.0, 0.0); |
|||
if (ckt->CKTBmat == NULL) |
|||
return (3); |
|||
|
|||
ckt->CKTSmat = newcmat(ckt->CKTportCount, ckt->CKTportCount, 0.0, 0.0); |
|||
if (ckt->CKTSmat == NULL) |
|||
return (E_NOMEM); |
|||
|
|||
#ifdef XSPICE |
|||
/* gtri - add - wbk - 12/19/90 - Add IPC stuff and anal_init and anal_type */ |
|||
|
|||
/* Tell the beginPlot routine what mode we're in */ |
|||
|
|||
// For now, let's keep this as IPC_ANAL_AC (TBD) |
|||
g_ipc.anal_type = IPC_ANAL_AC; |
|||
|
|||
/* Tell the code models what mode we're in */ |
|||
g_mif_info.circuit.anal_type = MIF_DC; |
|||
g_mif_info.circuit.anal_init = MIF_TRUE; |
|||
|
|||
/* gtri - end - wbk */ |
|||
#endif |
|||
|
|||
/* start at beginning */ |
|||
if (job->SPsaveFreq == 0 || restart) { |
|||
if (job->SPnumberSteps < 1) |
|||
job->SPnumberSteps = 1; |
|||
|
|||
switch (job->SPstepType) { |
|||
|
|||
case DECADE: |
|||
if (job->SPstartFreq <= 0) { |
|||
fprintf(stderr, "ERROR: AC startfreq <= 0\n"); |
|||
return E_PARMVAL; |
|||
} |
|||
job->SPfreqDelta = |
|||
exp(log(10.0)/job->SPnumberSteps); |
|||
break; |
|||
case OCTAVE: |
|||
if (job->SPstartFreq <= 0) { |
|||
fprintf(stderr, "ERROR: AC startfreq <= 0\n"); |
|||
return E_PARMVAL; |
|||
} |
|||
job->SPfreqDelta = |
|||
exp(log(2.0)/job->SPnumberSteps); |
|||
break; |
|||
case LINEAR: |
|||
if (job->SPnumberSteps-1 > 1) |
|||
job->SPfreqDelta = |
|||
(job->SPstopFreq - |
|||
job->SPstartFreq) / |
|||
(job->SPnumberSteps - 1); |
|||
else |
|||
/* Patch from: Richard McRoberts |
|||
* This patch is for a rather pathological case: |
|||
* a linear step with only one point */ |
|||
job->SPfreqDelta = 0; |
|||
break; |
|||
default: |
|||
return(E_BADPARM); |
|||
} |
|||
#ifdef XSPICE |
|||
/* gtri - begin - wbk - Call EVTop if event-driven instances exist */ |
|||
|
|||
if(ckt->evt->counts.num_insts != 0) { |
|||
error = EVTop(ckt, |
|||
(ckt->CKTmode & MODEUIC) | MODEDCOP | MODEINITJCT, |
|||
(ckt->CKTmode & MODEUIC) | MODEDCOP | MODEINITFLOAT, |
|||
ckt->CKTdcMaxIter, |
|||
MIF_TRUE); |
|||
EVTdump(ckt, IPC_ANAL_DCOP, 0.0); |
|||
EVTop_save(ckt, MIF_TRUE, 0.0); |
|||
} |
|||
else |
|||
#endif |
|||
/* If no event-driven instances, do what SPICE normally does */ |
|||
if (!ckt->CKTnoopac) { /* skip OP if option NOOPAC is set and circuit is linear */ |
|||
error = CKTop(ckt, |
|||
(ckt->CKTmode & MODEUIC) | MODEDCOP | MODEINITJCT, |
|||
(ckt->CKTmode & MODEUIC) | MODEDCOP | MODEINITFLOAT, |
|||
ckt->CKTdcMaxIter); |
|||
|
|||
if(error){ |
|||
fprintf(stdout,"\nAC operating point failed -\n"); |
|||
CKTncDump(ckt); |
|||
return(error); |
|||
} |
|||
} |
|||
else |
|||
fprintf(stdout,"\n Linear circuit, option noopac given: no OP analysis\n"); |
|||
|
|||
#ifdef XSPICE |
|||
/* gtri - add - wbk - 12/19/90 - Add IPC stuff */ |
|||
|
|||
/* Send the operating point results for Mspice compatibility */ |
|||
if(g_ipc.enabled) |
|||
{ |
|||
/* Call CKTnames to get names of nodes/branches used by |
|||
BeginPlot */ |
|||
/* Probably should free nameList after this block since |
|||
called again... */ |
|||
error = CKTnames(ckt,&numNames,&nameList); |
|||
if(error) return(error); |
|||
|
|||
/* We have to do a beginPlot here since the data to return is |
|||
* different for the DCOP than it is for the AC analysis. |
|||
* Moreover the begin plot has not even been done yet at this |
|||
* point... |
|||
*/ |
|||
SPfrontEnd->OUTpBeginPlot (ckt, ckt->CKTcurJob, |
|||
ckt->CKTcurJob->JOBname, |
|||
NULL, IF_REAL, |
|||
numNames, nameList, IF_REAL, |
|||
&spPlot); |
|||
txfree(nameList); |
|||
|
|||
ipc_send_dcop_prefix(); |
|||
CKTdump(ckt, 0.0, spPlot); |
|||
ipc_send_dcop_suffix(); |
|||
|
|||
SPfrontEnd->OUTendPlot (spPlot); |
|||
} |
|||
/* gtri - end - wbk */ |
|||
#endif |
|||
|
|||
ckt->CKTmode = (ckt->CKTmode & MODEUIC) | MODEDCOP | MODEINITSMSIG; |
|||
error = CKTload(ckt); |
|||
if(error) return(error); |
|||
|
|||
error = CKTnames(ckt,&numNames,&nameList); |
|||
if(error) return(error); |
|||
|
|||
if (ckt->CKTkeepOpInfo) { |
|||
/* Dump operating point. */ |
|||
error = SPfrontEnd->OUTpBeginPlot (ckt, ckt->CKTcurJob, |
|||
"AC Operating Point", |
|||
NULL, IF_REAL, |
|||
numNames, nameList, IF_REAL, |
|||
&plot); |
|||
if(error) return(error); |
|||
CKTdump(ckt, 0.0, plot); |
|||
SPfrontEnd->OUTendPlot (plot); |
|||
plot = NULL; |
|||
} |
|||
|
|||
unsigned int extraSPdataLength = ckt->CKTportCount * ckt->CKTportCount; |
|||
nameList = (IFuid*)TREALLOC(IFuid, nameList, numNames + extraSPdataLength); |
|||
|
|||
|
|||
// Create UIDs |
|||
for (unsigned int dest = 1; dest <= ckt->CKTportCount; dest++) |
|||
for (unsigned int j = 1; j <= ckt->CKTportCount; j++) |
|||
{ |
|||
char tmpBuf[32]; |
|||
sprintf(tmpBuf, "S_%d_%d", dest, j); |
|||
|
|||
SPfrontEnd->IFnewUid(ckt, &(nameList[numNames++]), NULL, tmpBuf, UID_OTHER, NULL); |
|||
} |
|||
|
|||
SPfrontEnd->IFnewUid (ckt, &freqUid, NULL, "frequency", UID_OTHER, NULL); |
|||
error = SPfrontEnd->OUTpBeginPlot (ckt, ckt->CKTcurJob, |
|||
ckt->CKTcurJob->JOBname, |
|||
freqUid, IF_REAL, |
|||
numNames, nameList, IF_COMPLEX, |
|||
&spPlot); |
|||
|
|||
|
|||
|
|||
tfree(nameList); |
|||
if(error) return(error); |
|||
|
|||
if (job->SPstepType != LINEAR) { |
|||
SPfrontEnd->OUTattributes (spPlot, NULL, OUT_SCALE_LOG, NULL); |
|||
} |
|||
freq = job->SPstartFreq; |
|||
|
|||
} else { /* continue previous analysis */ |
|||
freq = job->SPsaveFreq; |
|||
job->SPsaveFreq = 0; /* clear the 'old' frequency */ |
|||
/* fix resume? saj, indeed !*/ |
|||
error = SPfrontEnd->OUTpBeginPlot (NULL, NULL, |
|||
NULL, |
|||
NULL, 0, |
|||
666, NULL, 666, |
|||
&spPlot); |
|||
/* saj*/ |
|||
} |
|||
|
|||
switch (job->SPstepType) { |
|||
case DECADE: |
|||
case OCTAVE: |
|||
freqTol = job->SPfreqDelta * |
|||
job->SPstopFreq * ckt->CKTreltol; |
|||
break; |
|||
case LINEAR: |
|||
freqTol = job->SPfreqDelta * ckt->CKTreltol; |
|||
break; |
|||
default: |
|||
return(E_BADPARM); |
|||
} |
|||
|
|||
|
|||
#ifdef XSPICE |
|||
/* gtri - add - wbk - 12/19/90 - Set anal_init and anal_type */ |
|||
|
|||
g_mif_info.circuit.anal_init = MIF_TRUE; |
|||
|
|||
/* Tell the code models what mode we're in */ |
|||
g_mif_info.circuit.anal_type = MIF_AC; |
|||
|
|||
/* gtri - end - wbk */ |
|||
#endif |
|||
|
|||
INIT_STATS(); |
|||
|
|||
ckt->CKTcurrentAnalysis = DOING_AC; |
|||
|
|||
ckt->CKTactivePort = 0; |
|||
/* main loop through all scheduled frequencies */ |
|||
while (freq <= job->SPstopFreq + freqTol) { |
|||
|
|||
unsigned int activePort = 0; |
|||
// |
|||
if (SPfrontEnd->IFpauseTest()) { |
|||
/* user asked us to pause via an interrupt */ |
|||
job->SPsaveFreq = freq; |
|||
return(E_PAUSE); |
|||
} |
|||
ckt->CKTomega = 2.0 * M_PI * freq; |
|||
|
|||
/* Update opertating point, if variable 'hertz' is given */ |
|||
if (ckt->CKTvarHertz) { |
|||
#ifdef XSPICE |
|||
/* Call EVTop if event-driven instances exist */ |
|||
|
|||
if (ckt->evt->counts.num_insts != 0) { |
|||
error = EVTop(ckt, |
|||
(ckt->CKTmode & MODEUIC) | MODEDCOP | MODEINITJCT, |
|||
(ckt->CKTmode & MODEUIC) | MODEDCOP | MODEINITFLOAT, |
|||
ckt->CKTdcMaxIter, |
|||
MIF_TRUE); |
|||
EVTdump(ckt, IPC_ANAL_DCOP, 0.0); |
|||
EVTop_save(ckt, MIF_TRUE, 0.0); |
|||
} |
|||
else |
|||
#endif |
|||
// If no event-driven instances, do what SPICE normally does |
|||
error = CKTop(ckt, |
|||
(ckt->CKTmode & MODEUIC) | MODEDCOP | MODEINITJCT, |
|||
(ckt->CKTmode & MODEUIC) | MODEDCOP | MODEINITFLOAT, |
|||
ckt->CKTdcMaxIter); |
|||
|
|||
if (error) { |
|||
fprintf(stdout, "\nAC operating point failed -\n"); |
|||
CKTncDump(ckt); |
|||
return(error); |
|||
} |
|||
ckt->CKTmode = (ckt->CKTmode & MODEUIC) | MODEDCOP | MODEINITSMSIG; |
|||
error = CKTload(ckt); |
|||
if (error) return(error); |
|||
} |
|||
// Let's sweep thru all available ports to build Y matrix |
|||
// Y_ij = I_i / V_j | V_k!=j = 0 |
|||
// (we have only to modify rhs) |
|||
|
|||
int vsrcLookupType = CKTtypelook("Vsource"); |
|||
int vsrcRoot = -1; |
|||
|
|||
// Get VSRCs root model |
|||
if (ckt->CKTVSRCid == -1) |
|||
{ |
|||
for (i = 0; i < DEVmaxnum; i++) { |
|||
if (DEVices[i] && DEVices[i]->DEVacLoad && ckt->CKThead[i] && ckt->CKThead[i]->GENmodType == vsrcLookupType) { |
|||
|
|||
vsrcRoot = i; |
|||
break; |
|||
} |
|||
} |
|||
if (vsrcRoot == -1) |
|||
return (E_NOMOD); |
|||
|
|||
ckt->CKTVSRCid = vsrcRoot; |
|||
} |
|||
else |
|||
vsrcRoot = ckt->CKTVSRCid; |
|||
|
|||
if (rhswoPorts == NULL) |
|||
rhswoPorts = (double*)TREALLOC(double, rhswoPorts, ckt->CKTmaxEqNum); |
|||
if (irhswoPorts == NULL) |
|||
irhswoPorts = (double*)TREALLOC(double, irhswoPorts, ckt->CKTmaxEqNum); |
|||
|
|||
ckt->CKTmode = (ckt->CKTmode & MODEUIC) | MODESP; |
|||
// Pre-load everything but RF Ports (these will be updated in the next cycle). |
|||
error = NIspPreload(ckt); |
|||
if (error) return (error); |
|||
|
|||
// error = VSRCsaveNPData(ckt->CKThead[vsrcRoot]); |
|||
// if (error) return (error); |
|||
|
|||
//Keep a backup copy |
|||
memcpy(rhswoPorts, ckt->CKTrhs, ckt->CKTmaxEqNum * sizeof(double)); |
|||
memcpy(rhswoPorts, ckt->CKTirhs, ckt->CKTmaxEqNum * sizeof(double)); |
|||
|
|||
for (activePort = 1; activePort <= ckt->CKTportCount; activePort++) |
|||
{ |
|||
// Copy the backup RHS into CKT's RHS |
|||
memcpy(ckt->CKTrhs, rhswoPorts, ckt->CKTmaxEqNum * sizeof(double)); |
|||
memcpy(ckt->CKTirhs, irhswoPorts, ckt->CKTmaxEqNum * sizeof(double)); |
|||
ckt->CKTactivePort = activePort; |
|||
|
|||
// Update only VSRCs |
|||
error = VSRCspupdate(ckt->CKThead[vsrcRoot], ckt); |
|||
if (error) |
|||
{ |
|||
tfree(rhswoPorts); |
|||
tfree(irhswoPorts); |
|||
return(error); |
|||
} |
|||
|
|||
error = NIspSolve(ckt); |
|||
if (error) { |
|||
tfree(rhswoPorts); |
|||
tfree(irhswoPorts); |
|||
UPDATE_STATS(DOING_AC); |
|||
return(error); |
|||
} |
|||
|
|||
|
|||
#ifdef WANT_SENSE2 |
|||
if (ckt->CKTsenInfo && (ckt->CKTsenInfo->SENmode & ACSEN)) { |
|||
long save; |
|||
int save1; |
|||
|
|||
save = ckt->CKTmode; |
|||
ckt->CKTmode = (ckt->CKTmode & MODEUIC) | MODEDCOP | MODEINITSMSIG; |
|||
save1 = ckt->CKTsenInfo->SENmode; |
|||
ckt->CKTsenInfo->SENmode = ACSEN; |
|||
if (freq == job->SPstartFreq) { |
|||
ckt->CKTsenInfo->SENacpertflag = 1; |
|||
} |
|||
else { |
|||
ckt->CKTsenInfo->SENacpertflag = 0; |
|||
} |
|||
error = CKTsenAC(ckt); |
|||
if (error) |
|||
return (error); |
|||
ckt->CKTmode = save; |
|||
ckt->CKTsenInfo->SENmode = save1; |
|||
} |
|||
#endif |
|||
|
|||
// We have done 1 activated port. |
|||
error = CKTspCalcPowerWave(ckt); |
|||
|
|||
|
|||
} //active ports cycle |
|||
|
|||
// Now we can calculate the full S-Matrix |
|||
CKTspCalcSMatrix(ckt); |
|||
|
|||
#ifdef XSPICE |
|||
/* gtri - modify - wbk - 12/19/90 - Send IPC stuff */ |
|||
|
|||
if (g_ipc.enabled) |
|||
ipc_send_data_prefix(freq); |
|||
|
|||
error = CKTspDump(ckt, freq, spPlot); |
|||
|
|||
if (g_ipc.enabled) |
|||
ipc_send_data_suffix(); |
|||
|
|||
/* gtri - modify - wbk - 12/19/90 - Send IPC stuff */ |
|||
#else |
|||
error = CKTspDump(ckt, freq, acPlot); |
|||
#endif |
|||
if (error) { |
|||
UPDATE_STATS(DOING_AC); |
|||
tfree(rhswoPorts); |
|||
tfree(irhswoPorts); |
|||
return(error); |
|||
} |
|||
|
|||
|
|||
/* |
|||
* Now go with noise cycle, if required |
|||
*/ |
|||
|
|||
#ifdef NOISE_AVAILABLE |
|||
|
|||
// To be completed |
|||
if (job->SPdoNoise) |
|||
{ |
|||
if (portPosNodes == NULL) |
|||
{ |
|||
portPosNodes = TMALLOC(int, ckt->CKTportCount); |
|||
portNegNodes = TMALLOC(int, ckt->CKTportCount); |
|||
VSRCgetActivePortNodes(ckt->CKThead[vsrcRoot], ckt, portPosNodes, portNegNodes); |
|||
} |
|||
|
|||
static Ndata* data; |
|||
|
|||
double realVal; |
|||
double imagVal; |
|||
int error; |
|||
int posOutNode; |
|||
int negOutNode; |
|||
//Keep a backup copy |
|||
memcpy(rhswoPorts, ckt->CKTrhs, ckt->CKTmaxEqNum * sizeof(double)); |
|||
memcpy(rhswoPorts, ckt->CKTirhs, ckt->CKTmaxEqNum * sizeof(double)); |
|||
|
|||
for (activePort = 0; activePort < ckt->CKTportCount; activePort++) |
|||
{ |
|||
/* the frequency will NOT be stored in array[0] as before; instead, |
|||
* it will be given in refVal.rValue (see later) |
|||
*/ |
|||
// Copy the backup RHS into CKT's RHS |
|||
memcpy(ckt->CKTrhs, rhswoPorts, ckt->CKTmaxEqNum * sizeof(double)); |
|||
memcpy(ckt->CKTirhs, irhswoPorts, ckt->CKTmaxEqNum * sizeof(double)); |
|||
ckt->CKTactivePort = activePort+1; |
|||
|
|||
posOutNode = portPosNodes[activePort]; |
|||
negOutNode = portNegNodes[activePort]; |
|||
NInspIter(ckt, posOutNode, negOutNode); /* solve the adjoint system */ |
|||
|
|||
/* now we use the adjoint system to calculate the noise |
|||
* contributions of each generator in the circuit |
|||
*/ |
|||
|
|||
error = CKTspnoise(ckt, N_DENS, N_CALC, data); |
|||
if (error) |
|||
{ |
|||
tfree(portPosNodes); tfree(portNegNodes); |
|||
return(error); |
|||
} |
|||
} |
|||
} |
|||
#endif |
|||
/* increment frequency */ |
|||
|
|||
switch (job->SPstepType) { |
|||
case DECADE: |
|||
case OCTAVE: |
|||
|
|||
/* inserted again 14.12.2001 */ |
|||
#ifdef HAS_PROGREP |
|||
{ |
|||
double endfreq = job->SPstopFreq; |
|||
double startfreq = job->SPstartFreq; |
|||
endfreq = log(endfreq); |
|||
if (startfreq == 0.0) |
|||
startfreq = 1e-12; |
|||
startfreq = log(startfreq); |
|||
|
|||
if (freq > 0.0) |
|||
SetAnalyse("sp", (int)((log(freq) - startfreq) * 1000.0 / (endfreq - startfreq))); |
|||
} |
|||
#endif |
|||
|
|||
freq *= job->SPfreqDelta; |
|||
if (job->SPfreqDelta == 1) goto endsweep; |
|||
break; |
|||
case LINEAR: |
|||
|
|||
#ifdef HAS_PROGREP |
|||
{ |
|||
double endfreq = job->SPstopFreq; |
|||
double startfreq = job->SPstartFreq; |
|||
SetAnalyse("sp", (int)((freq - startfreq) * 1000.0 / (endfreq - startfreq))); |
|||
} |
|||
#endif |
|||
|
|||
freq += job->SPfreqDelta; |
|||
if (job->SPfreqDelta == 0) goto endsweep; |
|||
break; |
|||
default: |
|||
tfree(rhswoPorts); |
|||
tfree(irhswoPorts); |
|||
tfree(portPosNodes); tfree(portNegNodes); |
|||
return(E_INTERN); |
|||
|
|||
} |
|||
} |
|||
endsweep: |
|||
SPfrontEnd->OUTendPlot (spPlot); |
|||
spPlot = NULL; |
|||
UPDATE_STATS(0); |
|||
tfree(rhswoPorts); |
|||
tfree(irhswoPorts); |
|||
tfree(portPosNodes); tfree(portNegNodes); |
|||
return(0); |
|||
} |
|||
|
|||
|
|||
#endif |
|||
@ -0,0 +1,73 @@ |
|||
/********** |
|||
Copyright 1990 Regents of the University of California. All rights reserved. |
|||
Author: 1985 Thomas L. Quarles |
|||
**********/ |
|||
/* |
|||
*/ |
|||
|
|||
#include "ngspice/ngspice.h" |
|||
#include "ngspice/ifsim.h" |
|||
#include "ngspice/iferrmsg.h" |
|||
#include "ngspice/spdefs.h" |
|||
#include "ngspice/cktdefs.h" |
|||
|
|||
|
|||
/* ARGSUSED */ |
|||
int |
|||
SPaskQuest(CKTcircuit *ckt, JOB *anal, int which, IFvalue *value) |
|||
{ |
|||
SPAN *job = (SPAN *) anal; |
|||
|
|||
NG_IGNORE(ckt); |
|||
|
|||
switch(which) { |
|||
|
|||
case SP_START: |
|||
value->rValue = job->SPstartFreq; |
|||
break; |
|||
|
|||
case SP_STOP: |
|||
value->rValue = job->SPstopFreq ; |
|||
break; |
|||
|
|||
case SP_STEPS: |
|||
value->iValue = job->SPnumberSteps; |
|||
break; |
|||
|
|||
case SP_DEC: |
|||
if (job->SPstepType == DECADE) { |
|||
value->iValue=1; |
|||
} else { |
|||
value->iValue=0; |
|||
} |
|||
break; |
|||
|
|||
case SP_OCT: |
|||
if (job->SPstepType == OCTAVE) { |
|||
value->iValue=1; |
|||
} else { |
|||
value->iValue=0; |
|||
} |
|||
break; |
|||
|
|||
case SP_LIN: |
|||
if (job->SPstepType == LINEAR) { |
|||
value->iValue=1; |
|||
} else { |
|||
value->iValue=0; |
|||
} |
|||
break; |
|||
|
|||
case SP_DONOISE: |
|||
if (job->SPdoNoise) |
|||
value->iValue = 1; |
|||
else |
|||
value->iValue = 0; |
|||
break; |
|||
|
|||
default: |
|||
return(E_BADPARM); |
|||
} |
|||
return(OK); |
|||
} |
|||
|
|||
@ -0,0 +1,114 @@ |
|||
/********** |
|||
Copyright 1990 Regents of the University of California. All rights reserved. |
|||
Author: 1985 Thomas L. Quarles |
|||
**********/ |
|||
|
|||
#include "ngspice/ngspice.h" |
|||
#include "ngspice/ifsim.h" |
|||
#include "ngspice/iferrmsg.h" |
|||
#include "ngspice/spdefs.h" |
|||
#include "ngspice/cktdefs.h" |
|||
|
|||
#include "analysis.h" |
|||
|
|||
/* ARGSUSED */ |
|||
int |
|||
SPsetParm(CKTcircuit *ckt, JOB *anal, int which, IFvalue *value) |
|||
{ |
|||
SPAN *job = (SPAN *) anal; |
|||
|
|||
NG_IGNORE(ckt); |
|||
|
|||
switch(which) { |
|||
|
|||
case SP_START: |
|||
if (value->rValue < 0.0) { |
|||
errMsg = copy("Frequency of < 0 is invalid for AC start"); |
|||
job->SPstartFreq = 1.0; |
|||
return(E_PARMVAL); |
|||
} |
|||
|
|||
job->SPstartFreq = value->rValue; |
|||
break; |
|||
|
|||
case SP_STOP: |
|||
if (value->rValue < 0.0) { |
|||
errMsg = copy("Frequency of < 0 is invalid for AC stop"); |
|||
job->SPstartFreq = 1.0; |
|||
return(E_PARMVAL); |
|||
} |
|||
|
|||
job->SPstopFreq = value->rValue; |
|||
break; |
|||
|
|||
case SP_STEPS: |
|||
job->SPnumberSteps = value->iValue; |
|||
break; |
|||
|
|||
case SP_DEC: |
|||
if(value->iValue) { |
|||
job->SPstepType = DECADE; |
|||
} else { |
|||
if (job->SPstepType == DECADE) { |
|||
job->SPstepType = 0; |
|||
} |
|||
} |
|||
break; |
|||
|
|||
case SP_OCT: |
|||
if(value->iValue) { |
|||
job->SPstepType = OCTAVE; |
|||
} else { |
|||
if (job->SPstepType == OCTAVE) { |
|||
job->SPstepType = 0; |
|||
} |
|||
} |
|||
break; |
|||
|
|||
case SP_LIN: |
|||
if(value->iValue) { |
|||
job->SPstepType = LINEAR; |
|||
} else { |
|||
if (job->SPstepType == LINEAR) { |
|||
job->SPstepType = 0; |
|||
} |
|||
} |
|||
break; |
|||
|
|||
case SP_DONOISE: |
|||
job->SPdoNoise = value->iValue == 1; |
|||
break; |
|||
|
|||
default: |
|||
return(E_BADPARM); |
|||
} |
|||
return(OK); |
|||
} |
|||
|
|||
|
|||
static IFparm SPparms[] = { |
|||
{ "start", SP_START, IF_SET|IF_ASK|IF_REAL, "starting frequency" }, |
|||
{ "stop", SP_STOP, IF_SET|IF_ASK|IF_REAL, "ending frequency" }, |
|||
{ "numsteps", SP_STEPS,IF_SET|IF_ASK|IF_INTEGER, "number of frequencies"}, |
|||
{ "dec", SP_DEC, IF_SET|IF_FLAG, "step by decades" }, |
|||
{ "oct", SP_OCT, IF_SET|IF_FLAG, "step by octaves" }, |
|||
{ "lin", SP_LIN, IF_SET|IF_FLAG, "step linearly" }, |
|||
{"donoise", SP_DONOISE, IF_SET | IF_FLAG | IF_INTEGER, "do SP noise"} |
|||
}; |
|||
|
|||
SPICEanalysis SPinfo = { |
|||
{ |
|||
"SP", |
|||
"S-Parameters analysis", |
|||
|
|||
NUMELEMS(SPparms), |
|||
SPparms |
|||
}, |
|||
sizeof(SPAN), |
|||
FREQUENCYDOMAIN, |
|||
1, |
|||
SPsetParm, |
|||
SPaskQuest, |
|||
NULL, |
|||
SPan |
|||
}; |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue