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
-
136src/spicelib/devices/vsrc/vsrcacld.c
-
17src/spicelib/devices/vsrc/vsrcask.c
-
44src/spicelib/devices/vsrc/vsrcdefs.h
-
4src/spicelib/devices/vsrc/vsrcext.h
-
41src/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